schema CHANGE integrate statement parser with the compilation process

Does not cover all the statements - focused mainly for yang-data
extension, so it handles schema nodes processing.
diff --git a/src/plugins_exts.h b/src/plugins_exts.h
index 7491926..75ba83e 100644
--- a/src/plugins_exts.h
+++ b/src/plugins_exts.h
@@ -86,7 +86,7 @@
  * TODO
  * @return LY_ENOT if the extension is disabled and should be ignored.
  */
-LY_ERR lys_compile_extension_instance(struct lysc_ctx *ctx, const struct lysp_ext_instance *ext, struct lysc_ext_substmt *substmts);
+LY_ERR lys_compile_extension_instance(struct lysc_ctx *ctx, const struct lysp_ext_instance *ext_p, struct lysc_ext_instance *ext);
 
 /**
  * @brief Free the extension instance's data compiled with ::lys_compile_extension_instance().
diff --git a/src/plugins_exts_metadata.c b/src/plugins_exts_metadata.c
index 99df4f0..a099acd 100644
--- a/src/plugins_exts_metadata.c
+++ b/src/plugins_exts_metadata.c
@@ -115,7 +115,7 @@
     c_ext->substmts[ANNOTATION_SUBSTMT_REF].cardinality = LY_STMT_CARD_OPT;
     c_ext->substmts[ANNOTATION_SUBSTMT_REF].storage = &annotation->ref;
 
-    LY_CHECK_RET(lys_compile_extension_instance(cctx, p_ext, c_ext->substmts));
+    LY_CHECK_RET(lys_compile_extension_instance(cctx, p_ext, c_ext));
 
     return LY_SUCCESS;
 }
diff --git a/src/schema_compile.c b/src/schema_compile.c
index 07133d7..51ea049 100644
--- a/src/schema_compile.c
+++ b/src/schema_compile.c
@@ -619,125 +619,149 @@
 }
 
 LY_ERR
-lys_compile_extension_instance(struct lysc_ctx *ctx, const struct lysp_ext_instance *ext, struct lysc_ext_substmt *substmts)
+lys_compile_extension_instance(struct lysc_ctx *ctx, const struct lysp_ext_instance *ext_p, struct lysc_ext_instance *ext)
 {
     LY_ERR ret = LY_EVALID, r;
     LY_ARRAY_COUNT_TYPE u;
     struct lysp_stmt *stmt;
-    struct lysp_qname *iffeatures, *iffeat;
     void *parsed = NULL, **compiled = NULL;
-    ly_bool enabled;
 
     /* check for invalid substatements */
-    for (stmt = ext->child; stmt; stmt = stmt->next) {
+    for (stmt = ext_p->child; stmt; stmt = stmt->next) {
         if (stmt->flags & (LYS_YIN_ATTR | LYS_YIN_ARGUMENT)) {
             continue;
         }
-        LY_ARRAY_FOR(substmts, u) {
-            if (substmts[u].stmt == stmt->kw) {
+        LY_ARRAY_FOR(ext->substmts, u) {
+            if (ext->substmts[u].stmt == stmt->kw) {
                 break;
             }
         }
-        if (u == LY_ARRAY_COUNT(substmts)) {
+        if (u == LY_ARRAY_COUNT(ext->substmts)) {
             LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s%s%s\" extension instance.",
-                    stmt->stmt, ext->name, ext->argument ? " " : "", ext->argument ? ext->argument : "");
+                    stmt->stmt, ext_p->name, ext_p->argument ? " " : "", ext_p->argument ? ext_p->argument : "");
             goto cleanup;
         }
     }
 
     /* TODO store inherited data, e.g. status first, but mark them somehow to allow to overwrite them and not detect duplicity */
 
+    /* note into the compile context that we are processing extension now */
+    ctx->ext = ext;
+
     /* keep order of the processing the same as the order in the defined substmts,
      * the order is important for some of the statements depending on others (e.g. type needs status and units) */
-    LY_ARRAY_FOR(substmts, u) {
-        ly_bool stmt_present = 0;
 
-        for (stmt = ext->child; stmt; stmt = stmt->next) {
-            if (substmts[u].stmt != stmt->kw) {
+    LY_ARRAY_FOR(ext->substmts, u) {
+        uint64_t stmt_counter = 0;
+
+        for (stmt = ext_p->child; stmt; stmt = stmt->next) {
+            if (ext->substmts[u].stmt != stmt->kw) {
                 continue;
             }
 
-            stmt_present = 1;
-            if (substmts[u].storage) {
+            parsed = NULL;
+            stmt_counter++;
+            if (ext->substmts[u].storage) {
                 switch (stmt->kw) {
-                case LY_STMT_STATUS:
-                    assert(substmts[u].cardinality < LY_STMT_CARD_SOME);
-                    LY_CHECK_ERR_GOTO(r = lysp_stmt_parse(ctx, stmt, &substmts[u].storage, /* TODO */ NULL), ret = r, cleanup);
+                case LY_STMT_ACTION:
+                case LY_STMT_ANYDATA:
+                case LY_STMT_ANYXML:
+                case LY_STMT_CONTAINER:
+                case LY_STMT_CHOICE:
+                case LY_STMT_LEAF:
+                case LY_STMT_LEAF_LIST:
+                case LY_STMT_LIST:
+                case LY_STMT_NOTIFICATION:
+                case LY_STMT_RPC:
+                case LY_STMT_USES:
+                    r = lysp_stmt_parse(ctx, stmt, &parsed, NULL);
+                    LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
+
+                    /* set storage as an alternative document root in the compile context */
+                    r = lys_compile_node(ctx, parsed, NULL, 0, NULL);
+                    lysp_node_free(ctx->ctx, parsed);
+                    LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
                     break;
                 case LY_STMT_DESCRIPTION:
                 case LY_STMT_REFERENCE:
                 case LY_STMT_UNITS: {
-                    const char **units;
+                    const char **str_p;
 
-                    if (substmts[u].cardinality < LY_STMT_CARD_SOME) {
+                    if (ext->substmts[u].cardinality < LY_STMT_CARD_SOME) {
                         /* single item */
-                        if (*((const char **)substmts[u].storage)) {
+                        if (*((const char **)ext->substmts[u].storage)) {
                             LOGVAL(ctx->ctx, LY_VCODE_DUPSTMT, stmt->stmt);
                             goto cleanup;
                         }
-                        units = (const char **)substmts[u].storage;
+                        str_p = (const char **)ext->substmts[u].storage;
                     } else {
                         /* sized array */
-                        const char ***units_array = (const char ***)substmts[u].storage;
-                        LY_ARRAY_NEW_GOTO(ctx->ctx, *units_array, units, ret, cleanup);
+                        const char ***strings_array = (const char ***)ext->substmts[u].storage;
+                        LY_ARRAY_NEW_GOTO(ctx->ctx, *strings_array, str_p, ret, cleanup);
                     }
-                    r = lydict_insert(ctx->ctx, stmt->arg, 0, units);
+                    r = lydict_insert(ctx->ctx, stmt->arg, 0, str_p);
                     LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
                     break;
                 }
-                case LY_STMT_TYPE: {
-                    uint16_t *flags = lys_compile_extension_instance_storage(LY_STMT_STATUS, substmts);
-                    const char **units = lys_compile_extension_instance_storage(LY_STMT_UNITS, substmts);
-
-                    if (substmts[u].cardinality < LY_STMT_CARD_SOME) {
-                        /* single item */
-                        if (*(struct lysc_type **)substmts[u].storage) {
-                            LOGVAL(ctx->ctx, LY_VCODE_DUPSTMT, stmt->stmt);
-                            goto cleanup;
-                        }
-                        compiled = substmts[u].storage;
-                    } else {
-                        /* sized array */
-                        struct lysc_type ***types = (struct lysc_type ***)substmts[u].storage, **type = NULL;
-                        LY_ARRAY_NEW_GOTO(ctx->ctx, *types, type, ret, cleanup);
-                        compiled = (void *)type;
-                    }
+                case LY_STMT_IF_FEATURE: {
+                    ly_bool enabled;
 
                     r = lysp_stmt_parse(ctx, stmt, &parsed, NULL);
                     LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
-                    r = lys_compile_type(ctx, NULL, flags ? *flags : 0, ext->name, parsed, (struct lysc_type **)compiled,
-                            units && !*units ? units : NULL, NULL);
-                    lysp_type_free(ctx->ctx, parsed);
-                    free(parsed);
-                    LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
-                    break;
-                }
-                case LY_STMT_IF_FEATURE:
-                    iffeatures = NULL;
-                    LY_ARRAY_NEW_GOTO(ctx->ctx, iffeatures, iffeat, ret, cleanup);
-                    iffeat->str = stmt->arg;
-                    iffeat->mod = ctx->pmod;
-                    r = lys_eval_iffeatures(ctx->ctx, iffeatures, &enabled);
-                    LY_ARRAY_FREE(iffeatures);
+
+                    r = lys_eval_iffeatures(ctx->ctx, parsed, &enabled);
+                    FREE_ARRAY(ctx->ctx, (struct lysp_qname *)parsed, lysp_qname_free);
                     LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
                     if (!enabled) {
                         /* it is disabled, remove the whole extension instance */
                         return LY_ENOT;
                     }
                     break;
+                }
+                case LY_STMT_STATUS:
+                    assert(ext->substmts[u].cardinality < LY_STMT_CARD_SOME);
+                    LY_CHECK_ERR_GOTO(r = lysp_stmt_parse(ctx, stmt, &ext->substmts[u].storage, /* TODO */ NULL), ret = r, cleanup);
+                    break;
+                case LY_STMT_TYPE: {
+                    uint16_t *flags = lys_compile_extension_instance_storage(LY_STMT_STATUS, ext->substmts);
+                    const char **units = lys_compile_extension_instance_storage(LY_STMT_UNITS, ext->substmts);
+
+                    if (ext->substmts[u].cardinality < LY_STMT_CARD_SOME) {
+                        /* single item */
+                        if (*(struct lysc_type **)ext->substmts[u].storage) {
+                            LOGVAL(ctx->ctx, LY_VCODE_DUPSTMT, stmt->stmt);
+                            goto cleanup;
+                        }
+                        compiled = ext->substmts[u].storage;
+                    } else {
+                        /* sized array */
+                        struct lysc_type ***types = (struct lysc_type ***)ext->substmts[u].storage, **type = NULL;
+                        LY_ARRAY_NEW_GOTO(ctx->ctx, *types, type, ret, cleanup);
+                        compiled = (void *)type;
+                    }
+
+                    r = lysp_stmt_parse(ctx, stmt, &parsed, NULL);
+                    LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
+                    r = lys_compile_type(ctx, NULL, flags ? *flags : 0, ext_p->name, parsed, (struct lysc_type **)compiled,
+                            units && !*units ? units : NULL, NULL);
+                    lysp_type_free(ctx->ctx, parsed);
+                    free(parsed);
+                    LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
+                    break;
+                }
                 /* TODO support other substatements (parse stmt to lysp and then compile lysp to lysc),
                  * also note that in many statements their extensions are not taken into account  */
                 default:
                     LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Statement \"%s\" is not supported as an extension (found in \"%s%s%s\") substatement.",
-                            stmt->stmt, ext->name, ext->argument ? " " : "", ext->argument ? ext->argument : "");
+                            stmt->stmt, ext_p->name, ext_p->argument ? " " : "", ext_p->argument ? ext_p->argument : "");
                     goto cleanup;
                 }
             }
         }
 
-        if (((substmts[u].cardinality == LY_STMT_CARD_MAND) || (substmts[u].cardinality == LY_STMT_CARD_SOME)) && !stmt_present) {
+        if (((ext->substmts[u].cardinality == LY_STMT_CARD_MAND) || (ext->substmts[u].cardinality == LY_STMT_CARD_SOME)) && !stmt_counter) {
             LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Missing mandatory keyword \"%s\" as a child of \"%s%s%s\".",
-                    ly_stmt2str(substmts[u].stmt), ext->name, ext->argument ? " " : "", ext->argument ? ext->argument : "");
+                    ly_stmt2str(ext->substmts[u].stmt), ext_p->name, ext_p->argument ? " " : "", ext_p->argument ? ext_p->argument : "");
             goto cleanup;
         }
     }
@@ -745,6 +769,7 @@
     ret = LY_SUCCESS;
 
 cleanup:
+    ctx->ext = NULL;
     return ret;
 }
 
diff --git a/src/schema_compile.h b/src/schema_compile.h
index 335059c..15683e0 100644
--- a/src/schema_compile.h
+++ b/src/schema_compile.h
@@ -67,6 +67,8 @@
                                      - augment - module where the augment is defined
                                      - deviation - module where the deviation is defined
                                      - uses - module where the grouping is defined */
+    struct lysc_ext_instance *ext; /**< extension instance being processed and serving as a source for its substatements
+                                     instead of the module itself */
     struct ly_set groupings;    /**< stack for groupings circular check */
     struct ly_set tpdf_chain;
     struct ly_set disabled;     /**< set of compiled nodes whose if-feature(s) was not satisifed */
diff --git a/src/schema_compile_node.c b/src/schema_compile_node.c
index 6755377..1b00161 100644
--- a/src/schema_compile_node.c
+++ b/src/schema_compile_node.c
@@ -2201,7 +2201,9 @@
         /* top-level element */
         struct lysc_node **list;
 
-        if (node->nodetype == LYS_RPC) {
+        if (ctx->ext) {
+            lysc_ext_substmt(ctx->ext, LY_STMT_CONTAINER /* matches all data nodes */, (void **)&list, NULL);
+        } else if (node->nodetype == LYS_RPC) {
             list = (struct lysc_node **)&ctx->cur_mod->compiled->rpcs;
         } else if (node->nodetype == LYS_NOTIF) {
             list = (struct lysc_node **)&ctx->cur_mod->compiled->notifs;
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 1e7cd02..d798b5b 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -38,6 +38,7 @@
 #include "parser_internal.h"
 #include "parser_schema.h"
 #include "path.h"
+#include "plugins_exts.h"
 #include "schema_compile.h"
 #include "schema_compile_amend.h"
 #include "schema_features.h"
@@ -51,81 +52,81 @@
  * @brief information about YANG statements
  */
 struct stmt_info_s stmt_attr_info[] = {
-    {NULL,               NULL,          0},            /**< LY_STMT_NONE */
-    {"action",           "name",        STMT_FLAG_ID}, /**< LY_STMT_ACTION */
-    {"anydata",          "name",        STMT_FLAG_ID}, /**< LY_STMT_ANYDATA */
-    {"anyxml",           "name",        STMT_FLAG_ID}, /**< LY_STMT_ANYXML */
-    {"argument",         "name",        STMT_FLAG_ID}, /**< LY_STMT_ARGUMENT */
-    {"text",             NULL,          0},            /**< LY_STMT_ARG_TEXT */
-    {"value",            NULL,          0},            /**< LY_STMT_ARG_VALUE */
-    {"augment",          "target-node", STMT_FLAG_ID}, /**< LY_STMT_AUGMENT */
-    {"base",             "name",        STMT_FLAG_ID}, /**< LY_STMT_BASE */
-    {"belongs-to",       "module",      STMT_FLAG_ID}, /**< LY_STMT_BELONGS_TO */
-    {"bit",              "name",        STMT_FLAG_ID}, /**< LY_STMT_BIT */
-    {"case",             "name",        STMT_FLAG_ID}, /**< LY_STMT_CASE */
-    {"choice",           "name",        STMT_FLAG_ID}, /**< LY_STMT_CHOICE */
-    {"config",           "value",       STMT_FLAG_ID}, /**< LY_STMT_CONFIG */
-    {"contact",          "text",        STMT_FLAG_YIN},/**< LY_STMT_CONTACT */
-    {"container",        "name",        STMT_FLAG_ID}, /**< LY_STMT_CONTAINER */
-    {"default",          "value",       0},            /**< LY_STMT_DEFAULT */
-    {"description",      "text",        STMT_FLAG_YIN},/**< LY_STMT_DESCRIPTION */
-    {"deviate",          "value",       STMT_FLAG_ID}, /**< LY_STMT_DEVIATE */
-    {"deviation",        "target-node", STMT_FLAG_ID}, /**< LY_STMT_DEVIATION */
-    {"enum",             "name",        STMT_FLAG_ID}, /**< LY_STMT_ENUM */
-    {"error-app-tag",    "value",       0},            /**< LY_STMT_ERRTAG */
-    {"error-message",    "value",       STMT_FLAG_YIN},/**< LY_STMT_ERRMSG */
-    {"extension",        "name",        STMT_FLAG_ID}, /**< LY_STMT_EXTENSION */
-    {NULL,               NULL,          0},            /**< LY_STMT_EXTENSION_INSTANCE */
-    {"feature",          "name",        STMT_FLAG_ID}, /**< LY_STMT_FEATURE */
-    {"fraction-digits",  "value",       STMT_FLAG_ID}, /**< LY_STMT_FRACTION_DIGITS */
-    {"grouping",         "name",        STMT_FLAG_ID}, /**< LY_STMT_GROUPING */
-    {"identity",         "name",        STMT_FLAG_ID}, /**< LY_STMT_IDENTITY */
-    {"if-feature",       "name",        0},            /**< LY_STMT_IF_FEATURE */
-    {"import",           "module",      STMT_FLAG_ID}, /**< LY_STMT_IMPORT */
-    {"include",          "module",      STMT_FLAG_ID}, /**< LY_STMT_INCLUDE */
-    {"input",            NULL,          0},            /**< LY_STMT_INPUT */
-    {"key",              "value",       0},            /**< LY_STMT_KEY */
-    {"leaf",             "name",        STMT_FLAG_ID}, /**< LY_STMT_LEAF */
-    {"leaf-list",        "name",        STMT_FLAG_ID}, /**< LY_STMT_LEAF_LIST */
-    {"length",           "value",       0},            /**< LY_STMT_LENGTH */
-    {"list",             "name",        STMT_FLAG_ID}, /**< LY_STMT_LIST */
-    {"mandatory",        "value",       STMT_FLAG_ID}, /**< LY_STMT_MANDATORY */
-    {"max-elements",     "value",       STMT_FLAG_ID}, /**< LY_STMT_MAX_ELEMENTS */
-    {"min-elements",     "value",       STMT_FLAG_ID}, /**< LY_STMT_MIN_ELEMENTS */
-    {"modifier",         "value",       STMT_FLAG_ID}, /**< LY_STMT_MODIFIER */
-    {"module",           "name",        STMT_FLAG_ID}, /**< LY_STMT_MODULE */
-    {"must",             "condition",   0},            /**< LY_STMT_MUST */
-    {"namespace",        "uri",         0},            /**< LY_STMT_NAMESPACE */
-    {"notification",     "name",        STMT_FLAG_ID}, /**< LY_STMT_NOTIFICATION */
-    {"ordered-by",       "value",       STMT_FLAG_ID}, /**< LY_STMT_ORDERED_BY */
-    {"organization",     "text",        STMT_FLAG_YIN},/**< LY_STMT_ORGANIZATION */
-    {"output",           NULL,          0},            /**< LY_STMT_OUTPUT */
-    {"path",             "value",       0},            /**< LY_STMT_PATH */
-    {"pattern",          "value",       0},            /**< LY_STMT_PATTERN */
-    {"position",         "value",       STMT_FLAG_ID}, /**< LY_STMT_POSITION */
-    {"prefix",           "value",       STMT_FLAG_ID}, /**< LY_STMT_PREFIX */
-    {"presence",         "value",       0},            /**< LY_STMT_PRESENCE */
-    {"range",            "value",       0},            /**< LY_STMT_RANGE */
-    {"reference",        "text",        STMT_FLAG_YIN},/**< LY_STMT_REFERENCE */
-    {"refine",           "target-node", STMT_FLAG_ID}, /**< LY_STMT_REFINE */
-    {"require-instance", "value",       STMT_FLAG_ID}, /**< LY_STMT_REQUIRE_INSTANCE */
-    {"revision",         "date",        STMT_FLAG_ID}, /**< LY_STMT_REVISION */
-    {"revision-date",    "date",        STMT_FLAG_ID}, /**< LY_STMT_REVISION_DATE */
-    {"rpc",              "name",        STMT_FLAG_ID}, /**< LY_STMT_RPC */
-    {"status",           "value",       STMT_FLAG_ID}, /**< LY_STMT_STATUS */
-    {"submodule",        "name",        STMT_FLAG_ID}, /**< LY_STMT_SUBMODULE */
-    {"{",                NULL,          0},            /**< LY_STMT_SYNTAX_LEFT_BRACE */
-    {"}",                NULL,          0},            /**< LY_STMT_SYNTAX_RIGHT_BRACE */
-    {";",                NULL,          0},            /**< LY_STMT_SYNTAX_SEMICOLON */
-    {"type",             "name",        STMT_FLAG_ID}, /**< LY_STMT_TYPE */
-    {"typedef",          "name",        STMT_FLAG_ID}, /**< LY_STMT_TYPEDEF */
-    {"unique",           "tag",         0},            /**< LY_STMT_UNIQUE */
-    {"units",            "name",        0},            /**< LY_STMT_UNITS */
-    {"uses",             "name",        STMT_FLAG_ID}, /**< LY_STMT_USES */
-    {"value",            "value",       STMT_FLAG_ID}, /**< LY_STMT_VALUE */
-    {"when",             "condition",   0},            /**< LY_STMT_WHEN */
-    {"yang-version",     "value",       STMT_FLAG_ID}, /**< LY_STMT_YANG_VERSION */
-    {"yin-element",      "value",       STMT_FLAG_ID}, /**< LY_STMT_YIN_ELEMENT */
+    [LY_STMT_NONE] = {NULL, NULL, 0},
+    [LY_STMT_ACTION] = {"action", "name", STMT_FLAG_ID},
+    [LY_STMT_ANYDATA] = {"anydata", "name", STMT_FLAG_ID},
+    [LY_STMT_ANYXML] = {"anyxml", "name", STMT_FLAG_ID},
+    [LY_STMT_ARGUMENT] = {"argument", "name", STMT_FLAG_ID},
+    [LY_STMT_ARG_TEXT] = {"text", NULL, 0},
+    [LY_STMT_ARG_VALUE] = {"value", NULL, 0},
+    [LY_STMT_AUGMENT] = {"augment", "target-node", STMT_FLAG_ID},
+    [LY_STMT_BASE] = {"base", "name", STMT_FLAG_ID},
+    [LY_STMT_BELONGS_TO] = {"belongs-to", "module", STMT_FLAG_ID},
+    [LY_STMT_BIT] = {"bit", "name", STMT_FLAG_ID},
+    [LY_STMT_CASE] = {"case", "name", STMT_FLAG_ID},
+    [LY_STMT_CHOICE] = {"choice", "name", STMT_FLAG_ID},
+    [LY_STMT_CONFIG] = {"config", "value", STMT_FLAG_ID},
+    [LY_STMT_CONTACT] = {"contact", "text", STMT_FLAG_YIN},
+    [LY_STMT_CONTAINER] = {"container", "name", STMT_FLAG_ID},
+    [LY_STMT_DEFAULT] = {"default", "value", 0},
+    [LY_STMT_DESCRIPTION] = {"description", "text", STMT_FLAG_YIN},
+    [LY_STMT_DEVIATE] = {"deviate", "value", STMT_FLAG_ID},
+    [LY_STMT_DEVIATION] = {"deviation", "target-node", STMT_FLAG_ID},
+    [LY_STMT_ENUM] = {"enum", "name", STMT_FLAG_ID},
+    [LY_STMT_ERROR_APP_TAG] = {"error-app-tag", "value", 0},
+    [LY_STMT_ERROR_MESSAGE] = {"error-message", "value", STMT_FLAG_YIN},
+    [LY_STMT_EXTENSION] = {"extension", "name", STMT_FLAG_ID},
+    [LY_STMT_EXTENSION_INSTANCE] = {NULL, NULL, 0},
+    [LY_STMT_FEATURE] = {"feature", "name", STMT_FLAG_ID},
+    [LY_STMT_FRACTION_DIGITS] = {"fraction-digits", "value", STMT_FLAG_ID},
+    [LY_STMT_GROUPING] = {"grouping", "name", STMT_FLAG_ID},
+    [LY_STMT_IDENTITY] = {"identity", "name", STMT_FLAG_ID},
+    [LY_STMT_IF_FEATURE] = {"if-feature", "name", 0},
+    [LY_STMT_IMPORT] = {"import", "module", STMT_FLAG_ID},
+    [LY_STMT_INCLUDE] = {"include", "module", STMT_FLAG_ID},
+    [LY_STMT_INPUT] = {"input", NULL, 0},
+    [LY_STMT_KEY] = {"key", "value", 0},
+    [LY_STMT_LEAF] = {"leaf", "name", STMT_FLAG_ID},
+    [LY_STMT_LEAF_LIST] = {"leaf-list", "name", STMT_FLAG_ID},
+    [LY_STMT_LENGTH] = {"length", "value", 0},
+    [LY_STMT_LIST] = {"list", "name", STMT_FLAG_ID},
+    [LY_STMT_MANDATORY] = {"mandatory", "value", STMT_FLAG_ID},
+    [LY_STMT_MAX_ELEMENTS] = {"max-elements", "value", STMT_FLAG_ID},
+    [LY_STMT_MIN_ELEMENTS] = {"min-elements", "value", STMT_FLAG_ID},
+    [LY_STMT_MODIFIER] = {"modifier", "value", STMT_FLAG_ID},
+    [LY_STMT_MODULE] = {"module", "name", STMT_FLAG_ID},
+    [LY_STMT_MUST] = {"must", "condition", 0},
+    [LY_STMT_NAMESPACE] = {"namespace", "uri", 0},
+    [LY_STMT_NOTIFICATION] = {"notification", "name", STMT_FLAG_ID},
+    [LY_STMT_ORDERED_BY] = {"ordered-by", "value", STMT_FLAG_ID},
+    [LY_STMT_ORGANIZATION] = {"organization", "text", STMT_FLAG_YIN},
+    [LY_STMT_OUTPUT] = {"output", NULL, 0},
+    [LY_STMT_PATH] = {"path", "value", 0},
+    [LY_STMT_PATTERN] = {"pattern", "value", 0},
+    [LY_STMT_POSITION] = {"position", "value", STMT_FLAG_ID},
+    [LY_STMT_PREFIX] = {"prefix", "value", STMT_FLAG_ID},
+    [LY_STMT_PRESENCE] = {"presence", "value", 0},
+    [LY_STMT_RANGE] = {"range", "value", 0},
+    [LY_STMT_REFERENCE] = {"reference", "text", STMT_FLAG_YIN},
+    [LY_STMT_REFINE] = {"refine", "target-node", STMT_FLAG_ID},
+    [LY_STMT_REQUIRE_INSTANCE] = {"require-instance", "value", STMT_FLAG_ID},
+    [LY_STMT_REVISION] = {"revision", "date", STMT_FLAG_ID},
+    [LY_STMT_REVISION_DATE] = {"revision-date", "date", STMT_FLAG_ID},
+    [LY_STMT_RPC] = {"rpc", "name", STMT_FLAG_ID},
+    [LY_STMT_STATUS] = {"status", "value", STMT_FLAG_ID},
+    [LY_STMT_SUBMODULE] = {"submodule", "name", STMT_FLAG_ID},
+    [LY_STMT_SYNTAX_LEFT_BRACE] = {"{", NULL, 0},
+    [LY_STMT_SYNTAX_RIGHT_BRACE] = {"}", NULL, 0},
+    [LY_STMT_SYNTAX_SEMICOLON] = {";", NULL, 0},
+    [LY_STMT_TYPE] = {"type", "name", STMT_FLAG_ID},
+    [LY_STMT_TYPEDEF] = {"typedef", "name", STMT_FLAG_ID},
+    [LY_STMT_UNIQUE] = {"unique", "tag", 0},
+    [LY_STMT_UNITS] = {"units", "name", 0},
+    [LY_STMT_USES] = {"uses", "name", STMT_FLAG_ID},
+    [LY_STMT_VALUE] = {"value", "value", STMT_FLAG_ID},
+    [LY_STMT_WHEN] = {"when", "condition", 0},
+    [LY_STMT_YANG_VERSION] = {"yang-version", "value", STMT_FLAG_ID},
+    [LY_STMT_YIN_ELEMENT] = {"yin-element", "value", STMT_FLAG_ID},
 };
 
 const char * const ly_devmod_list[] = {
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 546c587..817e27e 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -251,37 +251,93 @@
 #define LYS_NODETYPE_MASK 0xffff  /**< Mask for nodetypes, the value is limited for 16 bits */
 
 /**
+ * @brief Generic test for operation (RPC or Action) statements.
+ */
+#define LY_STMT_IS_OP(STMT) (((STMT) == LY_STMT_ACTION) || ((STMT) == LY_STMT_RPC))
+
+/**
+ * @brief Generic test for schema node (anydata, anyxml, augment, case, choice, container, grouping,
+ * leaf, leaf-list, list and uses) statements.
+ *
+ * Covers the statements that maps to a 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).
+ *
+ * The operations (action/RPC) and notification statements are not included since they are used to be stored
+ * in a separated lists in schema node structures.
+ */
+#define LY_STMT_IS_NODE(STMT) (((STMT) >= LY_STMT_ANYDATA) && ((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_IS_OP */
     LY_STMT_ACTION,             /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node_action *`.
-                                     Note that due to compatibility with `struct lysc_node *`, the compiled actions can be actually
-                                     mixed in the linked list with other ::lysc_node based nodes if the storage is shared. */
+                                     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_IS_NODE */
     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 can be actually mixed in
-                                     the linked list with other ::lysc_node based nodes if the storage is shared. */
+                                     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 can be actually mixed in
-                                     the linked list with other ::lysc_node based nodes if the storage is shared. */
+                                     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,
+
+/* rest */
     LY_STMT_ARGUMENT,
     LY_STMT_ARG_TEXT,
     LY_STMT_ARG_VALUE,
-    LY_STMT_AUGMENT,
     LY_STMT_BASE,
     LY_STMT_BELONGS_TO,
     LY_STMT_BIT,
-    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 can be actually mixed in
-                                     the linked list with other ::lysc_node based nodes if the storage is shared. */
     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_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 can be actually mixed in
-                                     the linked list with other ::lysc_node based nodes if the storage is shared. */
     LY_STMT_DEFAULT,
-    LY_STMT_DESCRIPTION,
+    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,
@@ -291,20 +347,15 @@
     LY_STMT_EXTENSION_INSTANCE,
     LY_STMT_FEATURE,
     LY_STMT_FRACTION_DIGITS,
-    LY_STMT_GROUPING,
     LY_STMT_IDENTITY,
-    LY_STMT_IF_FEATURE,         /**< in ::lysc_ext_substmt.storage stored as a pointer to `struct lysc_iffeature` (cardinality < #LY_STMT_CARD_SOME)
-                                     or as a pointer to a [sized array](@ref sizedarrays) `struct lysc_iffeature *` */
+    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_INPUT,
     LY_STMT_KEY,
-    LY_STMT_LEAF,
-    LY_STMT_LEAF_LIST,
     LY_STMT_LENGTH,
-    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 can be actually mixed in
-                                     the linked list with other ::lysc_node based nodes if the storage is shared. */
     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,
@@ -312,7 +363,6 @@
     LY_STMT_MODULE,
     LY_STMT_MUST,
     LY_STMT_NAMESPACE,
-    LY_STMT_NOTIFICATION,
     LY_STMT_ORDERED_BY,
     LY_STMT_ORGANIZATION,
     LY_STMT_OUTPUT,
@@ -322,14 +372,12 @@
     LY_STMT_PREFIX,
     LY_STMT_PRESENCE,
     LY_STMT_RANGE,
-    LY_STMT_REFERENCE,
+    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_RPC,                /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node_action *`.
-                                     Note that due to compatibility with `struct lysc_node *`, the compiled RPCs can be actually
-                                     mixed in the linked list with other ::lysc_node based nodes if the storage is shared. */
     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_SYNTAX_SEMICOLON,
@@ -341,7 +389,6 @@
     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_USES,
     LY_STMT_VALUE,
     LY_STMT_WHEN,
     LY_STMT_YANG_VERSION,
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index 8bcfb5a..7690c98 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -997,23 +997,28 @@
         }
 
         switch (substmts[u].stmt) {
-        case LY_STMT_TYPE:
-            if (substmts[u].cardinality < LY_STMT_CARD_SOME) {
-                /* single item */
-                struct lysc_type *type = *((struct lysc_type **)substmts[u].storage);
-                if (!type) {
-                    break;
-                }
-                lysc_type_free(ctx, type);
-            } else {
-                /* multiple items */
-                struct lysc_type **types = *((struct lysc_type ***)substmts[u].storage);
-                if (!types) {
-                    break;
-                }
-                FREE_ARRAY(ctx, types, lysc_type2_free);
+        case LY_STMT_ACTION:
+        case LY_STMT_ANYDATA:
+        case LY_STMT_ANYXML:
+        case LY_STMT_CONTAINER:
+        case LY_STMT_CHOICE:
+        case LY_STMT_LEAF:
+        case LY_STMT_LEAF_LIST:
+        case LY_STMT_LIST:
+        case LY_STMT_NOTIFICATION:
+        case LY_STMT_RPC:
+        case LY_STMT_USES: {
+            struct lysc_node *child, *child_next;
+
+            LY_LIST_FOR_SAFE(*((struct lysc_node **)substmts[u].storage), child_next, child) {
+                lysc_node_free_(ctx, child);
             }
             break;
+        }
+        case LY_STMT_CONFIG:
+        case LY_STMT_STATUS:
+            /* nothing to do */
+            break;
         case LY_STMT_DESCRIPTION:
         case LY_STMT_REFERENCE:
         case LY_STMT_UNITS:
@@ -1033,10 +1038,6 @@
                 FREE_STRINGS(ctx, strs);
             }
             break;
-        case LY_STMT_STATUS:
-        case LY_STMT_CONFIG:
-            /* nothing to do */
-            break;
         case LY_STMT_IF_FEATURE: {
             struct lysc_iffeature *iff = *((struct lysc_iffeature **)substmts[u].storage);
             if (!iff) {
@@ -1051,6 +1052,23 @@
                 FREE_ARRAY(ctx, iff, lysc_iffeature_free);
             }
             break;
+        case LY_STMT_TYPE:
+            if (substmts[u].cardinality < LY_STMT_CARD_SOME) {
+                /* single item */
+                struct lysc_type *type = *((struct lysc_type **)substmts[u].storage);
+                if (!type) {
+                    break;
+                }
+                lysc_type_free(ctx, type);
+            } else {
+                /* multiple items */
+                struct lysc_type **types = *((struct lysc_type ***)substmts[u].storage);
+                if (!types) {
+                    break;
+                }
+                FREE_ARRAY(ctx, types, lysc_type2_free);
+            }
+            break;
         }
 
         /* TODO other statements */