plugins exts CHANGE ext parsing isolated into a callback

Lots of refactoring and finishing up included.
diff --git a/src/schema_compile.c b/src/schema_compile.c
index 5264095..f6f1b49 100644
--- a/src/schema_compile.c
+++ b/src/schema_compile.c
@@ -34,7 +34,6 @@
 #include "path.h"
 #include "plugins.h"
 #include "plugins_exts.h"
-#include "plugins_exts_compile.h"
 #include "plugins_internal.h"
 #include "plugins_types.h"
 #include "schema_compile_amend.h"
@@ -50,37 +49,43 @@
 
 /**
  * @brief Fill in the prepared compiled extensions definition structure according to the parsed extension definition.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] extp Parsed extension instance.
+ * @param[out] ext Compiled extension definition.
+ * @return LY_ERR value.
  */
 static LY_ERR
-lys_compile_extension(struct lysc_ctx *ctx, const struct lys_module *ext_mod, struct lysp_ext *ext_p,
-        const struct lyplg_ext_record *record, struct lysc_ext **ext)
+lys_compile_extension(struct lysc_ctx *ctx, struct lysp_ext_instance *extp, struct lysc_ext **ext)
 {
     LY_ERR ret = LY_SUCCESS;
+    struct lysp_ext *ep = extp->def;
 
-    if (!ext_p->compiled) {
+    if (!ep->compiled) {
         lysc_update_path(ctx, NULL, "{extension}");
-        lysc_update_path(ctx, NULL, ext_p->name);
+        lysc_update_path(ctx, NULL, ep->name);
 
         /* compile the extension definition */
-        *ext = ext_p->compiled = calloc(1, sizeof **ext);
+        *ext = ep->compiled = calloc(1, sizeof **ext);
         (*ext)->refcount = 1;
-        DUP_STRING_GOTO(ctx->ctx, ext_p->name, (*ext)->name, ret, done);
-        DUP_STRING_GOTO(ctx->ctx, ext_p->argname, (*ext)->argname, ret, done);
-        (*ext)->module = (struct lys_module *)ext_mod;
+        DUP_STRING_GOTO(ctx->ctx, ep->name, (*ext)->name, ret, cleanup);
+        DUP_STRING_GOTO(ctx->ctx, ep->argname, (*ext)->argname, ret, cleanup);
+        LY_CHECK_GOTO(ret = lysp_ext_find_definition(ctx->ctx, extp, (const struct lys_module **)&(*ext)->module, NULL),
+                cleanup);
 
         /* compile nested extensions */
-        COMPILE_EXTS_GOTO(ctx, ext_p->exts, (*ext)->exts, *ext, ret, done);
+        COMPILE_EXTS_GOTO(ctx, ep->exts, (*ext)->exts, *ext, ret, cleanup);
 
         lysc_update_path(ctx, NULL, NULL);
         lysc_update_path(ctx, NULL, NULL);
 
         /* find extension definition plugin */
-        (*ext)->plugin = record ? (struct lyplg_ext *)&record->plugin : NULL;
+        (*ext)->plugin = extp->record ? (struct lyplg_ext *)&extp->record->plugin : NULL;
     }
 
-    *ext = ext_p->compiled;
+    *ext = ep->compiled;
 
-done:
+cleanup:
     if (ret) {
         lysc_update_path(ctx, NULL, NULL);
         lysc_update_path(ctx, NULL, NULL);
@@ -89,34 +94,29 @@
 }
 
 LY_ERR
-lys_compile_ext(struct lysc_ctx *ctx, struct lysp_ext_instance *ext_p, struct lysc_ext_instance *ext, void *parent,
-        const struct lys_module *ext_mod)
+lys_compile_ext(struct lysc_ctx *ctx, struct lysp_ext_instance *extp, struct lysc_ext_instance *ext, void *parent)
 {
     LY_ERR ret = LY_SUCCESS;
-    struct lysp_ext *ext_def;
 
-    ext->parent_stmt = ext_p->parent_stmt;
-    ext->parent_stmt_index = ext_p->parent_stmt_index;
+    DUP_STRING_GOTO(ctx->ctx, extp->argument, ext->argument, ret, cleanup);
     ext->module = ctx->cur_mod;
     ext->parent = parent;
+    ext->parent_stmt = extp->parent_stmt;
+    ext->parent_stmt_index = extp->parent_stmt_index;
 
-    lysc_update_path(ctx, LY_STMT_IS_NODE(ext->parent_stmt) ? ((struct lysc_node *)ext->parent)->module : NULL, "{extension}");
-    lysc_update_path(ctx, NULL, ext_p->name);
+    lysc_update_path(ctx, (ext->parent_stmt & LY_STMT_NODE_MASK) ? ((struct lysc_node *)ext->parent)->module : NULL,
+            "{extension}");
+    lysc_update_path(ctx, NULL, extp->name);
 
-    LY_CHECK_GOTO(ret = lysp_ext_find_definition(ctx->ctx, ext_p, &ext_mod, &ext_def), cleanup);
-    LY_CHECK_GOTO(ret = lys_compile_extension(ctx, ext_mod, ext_def, ext_p->record, &ext->def), cleanup);
+    /* compile extension if not already */
+    LY_CHECK_GOTO(ret = lys_compile_extension(ctx, extp, &ext->def), cleanup);
 
-    if (ext_def->argname) {
-        LY_CHECK_GOTO(ret = lysp_ext_instance_resolve_argument(ctx->ctx, ext_p, ext_def), cleanup);
-    }
-
-    DUP_STRING_GOTO(ctx->ctx, ext_p->argument, ext->argument, ret, cleanup);
-
+    /* compile */
     if (ext->def->plugin && ext->def->plugin->compile) {
         if (ext->argument) {
             lysc_update_path(ctx, ext->module, ext->argument);
         }
-        ret = ext->def->plugin->compile(ctx, ext_p, ext);
+        ret = ext->def->plugin->compile(ctx, extp, ext);
         if (ret == LY_ENOT) {
             lysc_ext_instance_free(&ctx->free_ctx, ext);
         }
@@ -139,38 +139,6 @@
     return orig;
 }
 
-LIBYANG_API_DEF LY_ERR
-lysc_ext_substmt(const struct lysc_ext_instance *ext, enum ly_stmt substmt, void **instance_p)
-{
-    LY_ARRAY_COUNT_TYPE u;
-
-    if (instance_p) {
-        *instance_p = NULL;
-    }
-
-    LY_ARRAY_FOR(ext->substmts, u) {
-        if (LY_STMT_IS_DATA_NODE(substmt)) {
-            if (!LY_STMT_IS_DATA_NODE(ext->substmts[u].stmt)) {
-                continue;
-            }
-        } else if (LY_STMT_IS_OP(substmt)) {
-            if (!LY_STMT_IS_OP(ext->substmts[u].stmt)) {
-                continue;
-            }
-        } else if (ext->substmts[u].stmt != substmt) {
-            continue;
-        }
-
-        /* match */
-        if (instance_p) {
-            *instance_p = ext->substmts[u].storage;
-        }
-        return LY_SUCCESS;
-    }
-
-    return LY_ENOT;
-}
-
 static void
 lysc_unres_must_free(struct lysc_unres_must *m)
 {
@@ -251,21 +219,7 @@
     LOG_LOCSET(NULL, NULL, ctx->path, NULL);
 }
 
-/**
- * @brief Compile information from the identity statement
- *
- * The backlinks to the identities derived from this one are supposed to be filled later via ::lys_compile_identity_bases().
- *
- * @param[in] ctx_sc Compile context - alternative to the combination of @p ctx and @p parsed_mod.
- * @param[in] ctx libyang context.
- * @param[in] parsed_mod Module with the identities.
- * @param[in] identities_p Array of the parsed identity definitions to precompile.
- * @param[in,out] identities Pointer to the storage of the (pre)compiled identities array where the new identities are
- * supposed to be added. The storage is supposed to be initiated to NULL when the first parsed identities are going
- * to be processed.
- * @return LY_ERR value.
- */
-static LY_ERR
+LY_ERR
 lys_identity_precompile(struct lysc_ctx *ctx_sc, struct ly_ctx *ctx, struct lysp_module *parsed_mod,
         const struct lysp_ident *identities_p, struct lysc_ident **identities)
 {
@@ -445,6 +399,7 @@
 
 /**
  * @brief For the given array of identities, set the backlinks from all their base identities.
+ *
  * @param[in] ctx Compile context, not only for logging but also to get the current module to resolve prefixes.
  * @param[in] idents_p Array of identities definitions from the parsed schema structure.
  * @param[in,out] idents Array of referencing identities to which the backlinks are supposed to be set.
@@ -479,259 +434,6 @@
     return LY_SUCCESS;
 }
 
-const void *
-lys_compile_ext_instance_get_storage(const struct lysc_ext_instance *ext, enum ly_stmt stmt)
-{
-    LY_ARRAY_COUNT_TYPE u;
-
-    LY_ARRAY_FOR(ext->substmts, u) {
-        if (ext->substmts[u].stmt == stmt) {
-            return ext->substmts[u].storage;
-        }
-    }
-    return NULL;
-}
-
-/**
- * @brief Store (parse/compile) an instance extension statement.
- *
- * @param[in] ctx Compile context.
- * @param[in] ext_p Parsed ext instance.
- * @param[in] ext Compiled ext instance.
- * @param[in] substmt Compled ext instance substatement info.
- * @param[in] stmt Parsed statement to process.
- * @param[in,out] aug_target Optional augment target where to append all schema data nodes.
- * @return LY_ERR value.
- */
-static LY_ERR
-lys_compile_ext_instance_stmt(struct lysc_ctx *ctx, const struct lysp_ext_instance *ext_p, struct lysc_ext_instance *ext,
-        struct lysc_ext_substmt *substmt, struct lysp_stmt *stmt, struct lysc_node *aug_target)
-{
-    LY_ERR rc = LY_SUCCESS;
-    struct lysf_ctx fctx = {.ctx = ctx->ctx};
-    struct lysp_restr *restrs = NULL;
-    struct lysp_qname *qname = NULL;
-    struct lysp_type *ptype = NULL;
-
-    if (!substmt->storage) {
-        /* nothing to store (parse/compile) */
-        goto cleanup;
-    }
-
-    switch (stmt->kw) {
-    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 lysp_node **pnodes_p, *pnode = NULL;
-        const uint16_t *flags = lys_compile_ext_instance_get_storage(ext, LY_STMT_STATUS);
-
-        /* parse the node */
-        LY_CHECK_GOTO(rc = lysp_stmt_parse(ctx, stmt, (void **)&pnode, NULL), cleanup);
-
-        /* store it together with all the parsed schema nodes */
-        pnodes_p = &((struct lysp_ext_instance *)ext_p)->parsed;
-        while (*pnodes_p) {
-            pnodes_p = &(*pnodes_p)->next;
-        }
-        *pnodes_p = pnode;
-
-        if (aug_target) {
-            /* augment nodes */
-            ((struct lysp_ext_instance *)ext_p)->flags |= LYS_EXT_PARSED_AUGMENT;
-
-            /* compile augmented nodes */
-            LY_CHECK_GOTO(rc = lys_compile_augment_children(ctx, NULL, 0, pnode, aug_target, 0), cleanup);
-        } else {
-            /* compile nodes, ctx->ext substatement storage is used as the document root */
-            LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, NULL, flags, NULL), cleanup);
-        }
-        break;
-    }
-    case LY_STMT_GROUPING: {
-        struct lysp_node_grp **groupings_p, *grp = NULL;
-
-        /* parse the grouping */
-        LY_CHECK_GOTO(rc = lysp_stmt_parse(ctx, stmt, (void **)&grp, NULL), cleanup);
-
-        /* store it with all the other groupings */
-        groupings_p = substmt->storage;
-        while (*groupings_p) {
-            groupings_p = &(*groupings_p)->next;
-        }
-        *groupings_p = grp;
-        break;
-    }
-    case LY_STMT_CONTACT:
-    case LY_STMT_DESCRIPTION:
-    case LY_STMT_ERROR_APP_TAG:
-    case LY_STMT_ERROR_MESSAGE:
-    case LY_STMT_KEY:
-    case LY_STMT_NAMESPACE:
-    case LY_STMT_ORGANIZATION:
-    case LY_STMT_PRESENCE:
-    case LY_STMT_REFERENCE:
-    case LY_STMT_UNITS: {
-        const char **str_p;
-
-        /* single item */
-        str_p = substmt->storage;
-        if (*str_p) {
-            LOGVAL(ctx->ctx, LY_VCODE_DUPSTMT, stmt->stmt);
-            rc = LY_EVALID;
-            goto cleanup;
-        }
-
-        /* called instead of lysp_stmt_parse() to skip validation and not parse nested ext instances */
-        LY_CHECK_GOTO(rc = lydict_insert(ctx->ctx, stmt->arg, 0, str_p), cleanup);
-        break;
-    }
-    case LY_STMT_MUST: {
-        struct lysc_must **musts_p, *must;
-
-        /* parse */
-        LY_CHECK_GOTO(rc = lysp_stmt_parse(ctx, stmt, (void **)&restrs, NULL), cleanup);
-
-        /* sized array */
-        musts_p = substmt->storage;
-        LY_ARRAY_NEW_GOTO(ctx->ctx, *musts_p, must, rc, cleanup);
-
-        /* compile */
-        LY_CHECK_GOTO(rc = lys_compile_must(ctx, restrs, must), cleanup);
-        break;
-    }
-    case LY_STMT_IF_FEATURE: {
-        ly_bool enabled;
-
-        LY_CHECK_GOTO(rc = lysp_stmt_parse(ctx, stmt, (void **)&qname, NULL), cleanup);
-        LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, qname, &enabled), cleanup);
-        if (!enabled) {
-            /* it is disabled, remove the whole extension instance */
-            return LY_ENOT;
-        }
-        break;
-    }
-    case LY_STMT_STATUS:
-        /* result needs to be a pointer to pointer */
-        LY_CHECK_GOTO(rc = lysp_stmt_parse(ctx, stmt, &substmt->storage, NULL), cleanup);
-        break;
-
-    case LY_STMT_TYPEDEF:
-        /* parse */
-        LY_CHECK_GOTO(rc = lysp_stmt_parse(ctx, stmt, substmt->storage, NULL), cleanup);
-        break;
-
-    case LY_STMT_TYPE: {
-        struct lysc_type **type_p;
-        const uint16_t *flags = lys_compile_ext_instance_get_storage(ext, LY_STMT_STATUS);
-        const char **units = (void *)lys_compile_ext_instance_get_storage(ext, LY_STMT_UNITS);
-
-        /* single item */
-        type_p = substmt->storage;
-        if (*type_p) {
-            LOGVAL(ctx->ctx, LY_VCODE_DUPSTMT, stmt->stmt);
-            rc = LY_EVALID;
-            goto cleanup;
-        }
-
-        LY_CHECK_GOTO(rc = lysp_stmt_parse(ctx, stmt, (void **)&ptype, NULL), cleanup);
-        LY_CHECK_GOTO(rc = lys_compile_type(ctx, NULL, flags ? *flags : 0, ext_p->name, ptype, type_p,
-                (units && !*units) ? units : NULL, NULL), 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_p->name, ext_p->argument ? " " : "",
-                ext_p->argument ? ext_p->argument : "");
-        rc = LY_EVALID;
-        goto cleanup;
-    }
-
-cleanup:
-    FREE_ARRAY(&fctx, restrs, lysp_restr_free);
-    FREE_ARRAY(ctx->ctx, qname, lysp_qname_free);
-    lysp_type_free(&ctx->free_ctx, ptype);
-    free(ptype);
-    return rc;
-}
-
-static LY_ERR
-lys_compile_extension_instance_(struct lysc_ctx *ctx, const struct lysp_ext_instance *ext_p, struct lysc_ext_instance *ext,
-        struct lysc_node *aug_target)
-{
-    LY_ERR rc = LY_SUCCESS;
-    LY_ARRAY_COUNT_TYPE u;
-    struct lysp_stmt *stmt;
-
-    /* check for invalid substatements */
-    for (stmt = ext_p->child; stmt; stmt = stmt->next) {
-        if (stmt->flags & (LYS_YIN_ATTR | LYS_YIN_ARGUMENT)) {
-            continue;
-        }
-        LY_ARRAY_FOR(ext->substmts, u) {
-            if (ext->substmts[u].stmt == stmt->kw) {
-                break;
-            }
-        }
-        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_p->name, ext_p->argument ? " " : "", ext_p->argument ? ext_p->argument : "");
-            rc = LY_EVALID;
-            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(ext->substmts, u) {
-        for (stmt = ext_p->child; stmt; stmt = stmt->next) {
-            if (ext->substmts[u].stmt != stmt->kw) {
-                continue;
-            }
-
-            if ((rc = lys_compile_ext_instance_stmt(ctx, ext_p, ext, &ext->substmts[u], stmt, aug_target))) {
-                goto cleanup;
-            }
-        }
-    }
-
-cleanup:
-    ctx->ext = NULL;
-    return rc;
-}
-
-LIBYANG_API_DEF LY_ERR
-lys_compile_extension_instance(struct lysc_ctx *ctx, const struct lysp_ext_instance *ext_p, struct lysc_ext_instance *ext)
-{
-    LY_CHECK_ARG_RET(ctx ? ctx->ctx : NULL, ctx, ext_p, ext, LY_EINVAL);
-
-    return lys_compile_extension_instance_(ctx, ext_p, ext, NULL);
-}
-
-LIBYANG_API_DEF LY_ERR
-lys_compile_extension_instance_augment(struct lysc_ctx *ctx, const struct lysp_ext_instance *ext_p,
-        struct lysc_ext_instance *ext, struct lysc_node *aug_target)
-{
-    LY_CHECK_ARG_RET(ctx ? ctx->ctx : NULL, ctx, ext_p, ext, aug_target, LY_EINVAL);
-
-    return lys_compile_extension_instance_(ctx, ext_p, ext, aug_target);
-}
-
 /**
  * @brief Check when for cyclic dependencies.
  *
@@ -1857,7 +1559,7 @@
         LY_CHECK_GOTO(ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL), cleanup);
     }
 
-    /* extension instances */
+    /* module extension instances */
     COMPILE_EXTS_GOTO(&ctx, sp->exts, mod_c->exts, mod_c, ret, cleanup);
 
     /* the same for submodules */