tree schema REFACTOR move ext definitions to plugins_exts header
diff --git a/src/plugins_exts.h b/src/plugins_exts.h
index 2c264a7..33199ca 100644
--- a/src/plugins_exts.h
+++ b/src/plugins_exts.h
@@ -30,6 +30,7 @@
 struct ly_in;
 struct lyd_node;
 struct lysc_ext_substmt;
+struct lysp_ctx;
 struct lysp_ext_instance;
 
 #ifdef __cplusplus
@@ -105,6 +106,254 @@
 #define LYPLG_EXT_API_VERSION 6
 
 /**
+ * @brief Generic test for operation statements.
+ *
+ * This macro matches a subset of schema nodes that maps to common ::lysc_node or ::lysp_node structures. To match all
+ * such nodes, use ::LY_STMT_IS_NODE()
+ *
+ * This macro matches action and RPC.
+ */
+#define LY_STMT_IS_OP(STMT) (((STMT) == LY_STMT_ACTION) || ((STMT) == LY_STMT_RPC))
+
+/**
+ * @brief Generic test for schema data nodes.
+ *
+ * This macro matches a subset of schema nodes that maps to common ::lysc_node or ::lysp_node structures. To match all
+ * such nodes, use ::LY_STMT_IS_NODE()
+ *
+ * This macro matches anydata, anyxml, case, choice, container, leaf, leaf-list, and list.
+ */
+#define LY_STMT_IS_DATA_NODE(STMT) (((STMT) == LY_STMT_ANYDATA) || ((STMT) == LY_STMT_ANYXML) || \
+        ((STMT) == LY_STMT_CASE) || ((STMT) == LY_STMT_CHOICE) || ((STMT) == LY_STMT_CONTAINER) || \
+        ((STMT) == LY_STMT_LEAF) || ((STMT) == LY_STMT_LEAF_LIST) || ((STMT) == LY_STMT_LIST))
+
+/**
+ * @brief Generic test for any schema node that maps to common ::lysc_node or ::lysp_node structures.
+ *
+ * Note that the list of statements that can appear in parsed or compiled schema trees differs (e.g. no uses in compiled tree).
+ *
+ * To check for some of the subsets of this test, try ::LY_STMT_IS_DATA_NODE() or ::LY_STMT_IS_OP().
+ *
+ * This macro matches action, anydata, anyxml, augment, case, choice, container, grouping, input, leaf, leaf-list, list,
+ * notification, output, RPC and uses.
+ */
+#define LY_STMT_IS_NODE(STMT) (((STMT) >= LY_STMT_NOTIFICATION) && ((STMT) <= LY_STMT_LIST))
+
+/**
+ * @brief List of YANG statements
+ */
+enum ly_stmt {
+    LY_STMT_NONE = 0,
+
+    LY_STMT_NOTIFICATION,       /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node_notif *`.
+                                     The RPCs/Actions and Notifications are expected in a separated lists than the rest of
+                                     data definition nodes as it is done in generic structures of libyang. */
+    LY_STMT_INPUT,
+    LY_STMT_OUTPUT,
+    LY_STMT_ACTION,             /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node_action *`.
+                                     The RPCs/Actions and Notifications are expected in a separated lists than the rest of
+                                     data definition nodes as it is done in generic structures of libyang. */
+    LY_STMT_RPC,                /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node_action *`.
+                                     The RPCs/Actions and Notifications are expected in a separated lists than the rest of
+                                     data definition nodes as it is done in generic structures of libyang. */
+    LY_STMT_ANYDATA,            /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
+                                     Note that due to ::lysc_node compatibility the anydata is expected to be actually
+                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
+                                     Notifications are expected in a separated lists as it is done in generic structures
+                                     of libyang. */
+    LY_STMT_ANYXML,             /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
+                                     Note that due to ::lysc_node compatibility the anyxml is expected to be actually
+                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
+                                     Notifications are expected in a separated lists as it is done in generic structures
+                                     of libyang. */
+    LY_STMT_AUGMENT,
+    LY_STMT_CASE,               /**< TODO is it possible to compile cases without the parent choice? */
+    LY_STMT_CHOICE,             /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
+                                     Note that due to ::lysc_node compatibility the choice is expected to be actually
+                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
+                                     Notifications are expected in a separated lists as it is done in generic structures
+                                     of libyang. */
+    LY_STMT_CONTAINER,          /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
+                                     Note that due to ::lysc_node compatibility the container is expected to be actually
+                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
+                                     Notifications are expected in a separated lists as it is done in generic structures
+                                     of libyang. */
+    LY_STMT_GROUPING,
+    LY_STMT_LEAF,               /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
+                                     Note that due to ::lysc_node compatibility the leaf is expected to be actually
+                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
+                                     Notifications are expected in a separated lists as it is done in generic structures
+                                     of libyang. */
+    LY_STMT_LEAF_LIST,          /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
+                                     Note that due to ::lysc_node compatibility the leaf-list is expected to be actually
+                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
+                                     Notifications are expected in a separated lists as it is done in generic structures
+                                     of libyang. */
+    LY_STMT_LIST,               /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
+                                     Note that due to ::lysc_node compatibility the list is expected to be actually
+                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
+                                     Notifications are expected in a separated lists as it is done in generic structures
+                                     of libyang. */
+    LY_STMT_USES,
+
+    LY_STMT_ARGUMENT,
+    LY_STMT_BASE,
+    LY_STMT_BELONGS_TO,
+    LY_STMT_BIT,
+    LY_STMT_CONFIG,             /**< in ::lysc_ext_substmt.storage stored as a pointer to `uint16_t`, only cardinality < #LY_STMT_CARD_SOME is allowed */
+    LY_STMT_CONTACT,
+    LY_STMT_DEFAULT,
+    LY_STMT_DESCRIPTION,        /**< in ::lysc_ext_substmt.storage stored as a pointer to `const char *` (cardinality < #LY_STMT_CARD_SOME)
+                                     or as a pointer to a [sized array](@ref sizedarrays) `const char **` */
+    LY_STMT_DEVIATE,
+    LY_STMT_DEVIATION,
+    LY_STMT_ENUM,
+    LY_STMT_ERROR_APP_TAG,
+    LY_STMT_ERROR_MESSAGE,
+    LY_STMT_EXTENSION,
+    LY_STMT_EXTENSION_INSTANCE,
+    LY_STMT_FEATURE,
+    LY_STMT_FRACTION_DIGITS,
+    LY_STMT_IDENTITY,
+    LY_STMT_IF_FEATURE,         /**< if-feature statements are not compiled, they are evaluated and the parent statement is
+                                     preserved only in case the evaluation of all the if-feature statements is true.
+                                     Therefore there is no storage expected. */
+    LY_STMT_IMPORT,
+    LY_STMT_INCLUDE,
+    LY_STMT_KEY,
+    LY_STMT_LENGTH,
+    LY_STMT_MANDATORY,          /**< in ::lysc_ext_substmt.storage stored as a pointer to `uint16_t`, only cardinality < #LY_STMT_CARD_SOME is allowed */
+    LY_STMT_MAX_ELEMENTS,
+    LY_STMT_MIN_ELEMENTS,
+    LY_STMT_MODIFIER,
+    LY_STMT_MODULE,
+    LY_STMT_MUST,
+    LY_STMT_NAMESPACE,
+    LY_STMT_ORDERED_BY,
+    LY_STMT_ORGANIZATION,
+    LY_STMT_PATH,
+    LY_STMT_PATTERN,
+    LY_STMT_POSITION,
+    LY_STMT_PREFIX,
+    LY_STMT_PRESENCE,
+    LY_STMT_RANGE,
+    LY_STMT_REFERENCE,          /**< in ::lysc_ext_substmt.storage stored as a pointer to `const char *` (cardinality < #LY_STMT_CARD_SOME)
+                                     or as a pointer to a [sized array](@ref sizedarrays) `const char **` */
+    LY_STMT_REFINE,
+    LY_STMT_REQUIRE_INSTANCE,
+    LY_STMT_REVISION,
+    LY_STMT_REVISION_DATE,
+    LY_STMT_STATUS,             /**< in ::lysc_ext_substmt.storage stored as a pointer to `uint16_t`, only cardinality < #LY_STMT_CARD_SOME is allowed */
+    LY_STMT_SUBMODULE,
+    LY_STMT_TYPE,               /**< in ::lysc_ext_substmt.storage stored as a pointer to `struct lysc_type *` (cardinality < #LY_STMT_CARD_SOME)
+                                     or as a pointer to a [sized array](@ref sizedarrays) `struct lysc_type **` */
+    LY_STMT_TYPEDEF,
+    LY_STMT_UNIQUE,
+    LY_STMT_UNITS,              /**< in ::lysc_ext_substmt.storage stored as a pointer to `const char *` (cardinality < #LY_STMT_CARD_SOME)
+                                     or as a pointer to a [sized array](@ref sizedarrays) `const char **` */
+    LY_STMT_VALUE,
+    LY_STMT_WHEN,
+    LY_STMT_YANG_VERSION,
+    LY_STMT_YIN_ELEMENT,
+
+    /* separated from the list of statements
+     * the following tokens are part of the syntax and parsers have to work
+     * with them, but they are not a standard YANG statements
+     */
+    LY_STMT_SYNTAX_SEMICOLON,
+    LY_STMT_SYNTAX_LEFT_BRACE,
+    LY_STMT_SYNTAX_RIGHT_BRACE,
+
+    /*
+     * YIN-specific tokens, still they are part of the syntax, but not the standard statements
+     */
+    LY_STMT_ARG_TEXT,
+    LY_STMT_ARG_VALUE
+};
+
+/**
+ * @brief Possible cardinalities of the YANG statements.
+ *
+ * Used in extensions plugins to define cardinalities of the extension instance substatements.
+ */
+enum ly_stmt_cardinality {
+    LY_STMT_CARD_OPT,    /* 0..1 */
+    LY_STMT_CARD_MAND,   /* 1 */
+    LY_STMT_CARD_SOME,   /* 1..n */
+    LY_STMT_CARD_ANY     /* 0..n */
+};
+
+/**
+ * @brief Helper structure for generic storage of the extension instances content.
+ */
+struct lysp_stmt {
+    const char *stmt;                /**< identifier of the statement */
+    const char *arg;                 /**< statement's argument */
+    LY_VALUE_FORMAT format;          /**< prefix format of the identifier/argument (::LY_VALUE_XML is YIN format) */
+    void *prefix_data;               /**< Format-specific data for prefix resolution (see ly_resolve_prefix()) */
+
+    struct lysp_stmt *next;          /**< link to the next statement */
+    struct lysp_stmt *child;         /**< list of the statement's substatements (linked list) */
+    uint16_t flags;                  /**< statement flags, can be set to LYS_YIN_ATTR */
+    enum ly_stmt kw;                 /**< numeric respresentation of the stmt value */
+};
+
+/**
+ * @brief YANG extension instance
+ */
+struct lysp_ext_instance {
+    const char *name;                       /**< extension identifier, including possible prefix */
+    const char *argument;                   /**< optional value of the extension's argument */
+    LY_VALUE_FORMAT format;                 /**< prefix format of the extension name/argument (::LY_VALUE_XML is YIN format) */
+    struct lysp_node *parsed;               /**< Simply parsed (unresolved) YANG schema tree serving as a cache.
+                                                 Only ::lys_compile_extension_instance() can set this. */
+    void *prefix_data;                      /**< Format-specific data for prefix resolution
+                                                 (see ly_resolve_prefix()) */
+
+    struct lysp_stmt *child;                /**< list of the extension's substatements (linked list) */
+
+    void *parent;                           /**< pointer to the parent element holding the extension instance(s), use
+                                                 ::lysp_ext_instance#parent_stmt to access the schema element */
+    enum ly_stmt parent_stmt;               /**< value identifying placement of the extension instance */
+    LY_ARRAY_COUNT_TYPE parent_stmt_index;  /**< in case the instance is in a substatement, this identifies
+                                                 the index of that substatement in its [sized array](@ref sizedarrays) (if any) */
+    uint16_t flags;                         /**< LYS_INTERNAL value (@ref snodeflags) */
+    const struct lyplg_ext_record *record;  /**< extension defintion plugin record, if any */
+};
+
+/**
+ * @brief Description of the extension instance substatements.
+ *
+ * Provided by extensions plugins to libyang to be able to correctly compile the content of extension instances.
+ * Note that order of the defined records matters - just follow the values of ::ly_stmt and order the records from lower to higher values.
+ */
+struct lysc_ext_substmt {
+    enum ly_stmt stmt;                     /**< allowed substatement */
+    enum ly_stmt_cardinality cardinality;  /**< cardinality of the substatement */
+    void *storage;                         /**< pointer to the storage of the compiled statement according to the specific
+                                                lysc_ext_substmt::stmt and lysc_ext_substmt::cardinality */
+};
+
+/**
+ * @brief YANG extension instance
+ */
+struct lysc_ext_instance {
+    struct lysc_ext *def;            /**< pointer to the extension definition */
+    const char *argument;            /**< optional value of the extension's argument */
+    struct lys_module *module;       /**< module where the extension instantiated is defined */
+    struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+    struct lysc_ext_substmt *substmts; /**< list of allowed substatements with the storage to access the present
+                                          substatements ([sized array](@ref sizedarrays)) */
+    void *data;                      /**< private plugins's data, not used by libyang */
+
+    void *parent;                    /**< pointer to the parent element holding the extension instance(s), use
+                                          ::lysc_ext_instance#parent_stmt to access the schema element */
+    enum ly_stmt parent_stmt;        /**< value identifying placement of the extension instance in specific statement */
+    LY_ARRAY_COUNT_TYPE parent_stmt_index; /**< in case the instance is in a substatement, this identifies
+                                          the index of that substatement in its [sized array](@ref sizedarrays) (if any) */
+};
+
+/**
  * @brief Macro to define plugin information in external plugins
  *
  * Use as follows:
@@ -114,14 +363,6 @@
     uint32_t plugins_extensions_apiver__ = LYPLG_EXT_API_VERSION; \
     const struct lyplg_ext_record plugins_extensions__[]
 
-/**
- * @brief Free the extension instance's data compiled with ::lys_compile_extension_instance().
- *
- * @param[in] ctx libyang context
- * @param[in] substmts The sized array of extension instance's substatements. The whole array is freed except the storage
- * places which are expected to be covered by the extension plugin.
- */
-LIBYANG_API_DECL void lyplg_ext_instance_substatements_free(struct ly_ctx *ctx, struct lysc_ext_substmt *substmts);
 
 /**
  * @brief Callback to compile extension from the lysp_ext_instance to the lysc_ext_instance. The later structure is generally prepared
@@ -247,6 +488,39 @@
 };
 
 /**
+ * @brief Stringify statement identifier.
+ *
+ * @param[in] stmt The statement identifier to stringify.
+ * @return Constant string representation of the given @p stmt.
+ */
+LIBYANG_API_DECL const char *ly_stmt2str(enum ly_stmt stmt);
+
+/**
+ * @brief Stringify statement cardinality.
+ *
+ * @param[in] card The cardinality to stringify.
+ * @return Constant string representation of the given @p card.
+ */
+LIBYANG_API_DECL const char *ly_cardinality2str(enum ly_stmt_cardinality card);
+
+/**
+ * @brief Convert nodetype to statement identifier
+ *
+ * @param[in] nodetype Nodetype to convert.
+ * @return Statement identifier representing the given @p nodetype.
+ */
+LIBYANG_API_DECL enum ly_stmt lys_nodetype2stmt(uint16_t nodetype);
+
+/**
+ * @brief Free the extension instance's data compiled with ::lys_compile_extension_instance().
+ *
+ * @param[in] ctx libyang context
+ * @param[in] substmts The sized array of extension instance's substatements. The whole array is freed except the storage
+ * places which are expected to be covered by the extension plugin.
+ */
+LIBYANG_API_DECL void lyplg_ext_instance_substatements_free(struct ly_ctx *ctx, struct lysc_ext_substmt *substmts);
+
+/**
  * @brief Get specific run-time extension instance data from a callback set by ::ly_ctx_set_ext_data_clb().
  *
  * @param[in] ctx Context with the callback.
@@ -302,6 +576,25 @@
  */
 LIBYANG_API_DECL LY_ERR lyplg_ext_schema_mount_create_context(const struct lysc_ext_instance *ext, struct ly_ctx **ctx);
 
+/**
+ * @brief Get pointer to the storage of the specified substatement in the given extension instance.
+ *
+ * The function simplifies access into the ::lysc_ext_instance.substmts sized array.
+ *
+ * @param[in] ext Compiled extension instance to process.
+ * @param[in] substmt Extension substatement to search for.
+ * @param[out] instance_p Pointer where the storage of the @p substmt will be provided. The specific type returned depends
+ * on the @p substmt and can be found in the documentation of each ::ly_stmt value. Also note that some of the substatements
+ * (::lysc_node based or flags) can share the storage with other substatements. In case the pointer is NULL, still the return
+ * code can be used to at least know if the substatement is allowed for the extension.
+ * @param[out] cardinality_p Pointer to provide allowed cardinality of the substatements in the extension. Note that in some
+ * cases, the type of the storage depends also on the cardinality of the substatement.
+ * @return LY_SUCCESS if the @p substmt found.
+ * @return LY_ENOT in case the @p ext is not able to store (does not allow) the specified @p substmt.
+ */
+LIBYANG_API_DECL LY_ERR lysc_ext_substmt(const struct lysc_ext_instance *ext, enum ly_stmt substmt,
+        void **instance_p, enum ly_stmt_cardinality *cardinality_p);
+
 /** @} pluginsExtensions */
 
 #ifdef __cplusplus