plugins exts CHANGE ext parsing isolated into a callback

Lots of refactoring and finishing up included.
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index 21d7539..9eedecf 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -33,11 +33,10 @@
 #include "xml.h"
 #include "xpath.h"
 
-static void lysc_extension_free(struct lysf_ctx *ctx, struct lysc_ext **ext);
 static void lysc_node_free_(struct lysf_ctx *ctx, struct lysc_node *node);
 
 void
-lysp_qname_free(struct ly_ctx *ctx, struct lysp_qname *qname)
+lysp_qname_free(const struct ly_ctx *ctx, struct lysp_qname *qname)
 {
     if (qname) {
         lydict_remove(ctx, qname->str);
@@ -70,13 +69,12 @@
 lysp_ext_instance_free(struct lysf_ctx *ctx, struct lysp_ext_instance *ext)
 {
     struct lysp_stmt *stmt, *next;
-    struct lysp_node *node, *next_node;
 
     lydict_remove(ctx->ctx, ext->name);
     lydict_remove(ctx->ctx, ext->argument);
     ly_free_prefix_data(ext->format, ext->prefix_data);
-    LY_LIST_FOR_SAFE(ext->parsed, next_node, node) {
-        lysp_node_free(ctx, node);
+    if (ext->record && ext->record->plugin.pfree) {
+        ext->record->plugin.pfree(ctx->ctx, ext);
     }
 
     LY_LIST_FOR_SAFE(ext->child, next, stmt) {
@@ -164,6 +162,29 @@
 }
 
 /**
+ * @brief Free the compiled extension definition and NULL the provided pointer.
+ *
+ * @param[in] ctx Free context.
+ * @param[in,out] ext Compiled extension definition to be freed.
+ */
+static void
+lysc_extension_free(struct lysf_ctx *ctx, struct lysc_ext **ext)
+{
+    if (ly_set_contains(&ctx->ext_set, *ext, NULL)) {
+        /* already freed and only referenced again in this module */
+        return;
+    }
+
+    /* remember this extension to be freed, nothing to do on error */
+    (void)ly_set_add(&ctx->ext_set, *ext, 0, NULL);
+
+    /* recursive exts free */
+    FREE_ARRAY(ctx, (*ext)->exts, lysc_ext_instance_free);
+
+    *ext = NULL;
+}
+
+/**
  * @brief Free the parsed ext structure.
  *
  * @param[in] ctx Free context.
@@ -637,34 +658,11 @@
     free(module);
 }
 
-/**
- * @brief Free the compiled extension definition and NULL the provided pointer.
- *
- * @param[in] ctx Free context.
- * @param[in,out] ext Compiled extension definition to be freed.
- */
-static void
-lysc_extension_free(struct lysf_ctx *ctx, struct lysc_ext **ext)
-{
-    if (ly_set_contains(&ctx->ext_set, *ext, NULL)) {
-        /* already freed and only referenced again in this module */
-        return;
-    }
-
-    /* remember this extension to be freed, nothing to do on error */
-    (void)ly_set_add(&ctx->ext_set, *ext, 0, NULL);
-
-    /* recursive exts free */
-    FREE_ARRAY(ctx, (*ext)->exts, lysc_ext_instance_free);
-
-    *ext = NULL;
-}
-
 void
 lysc_ext_instance_free(struct lysf_ctx *ctx, struct lysc_ext_instance *ext)
 {
-    if (ext->def && ext->def->plugin && ext->def->plugin->free) {
-        ext->def->plugin->free(ctx->ctx, ext);
+    if (ext->def && ext->def->plugin && ext->def->plugin->cfree) {
+        ext->def->plugin->cfree(ctx->ctx, ext);
     }
     lydict_remove(ctx->ctx, ext->argument);
     FREE_ARRAY(ctx, ext->exts, lysc_ext_instance_free);
@@ -1354,10 +1352,11 @@
 }
 
 LIBYANG_API_DEF void
-lyplg_ext_instance_substatements_free(struct ly_ctx *ctx, struct lysc_ext_substmt *substmts)
+lyplg_ext_pfree_instance_substatements(const struct ly_ctx *ctx, struct lysp_ext_substmt *substmts)
 {
     LY_ARRAY_COUNT_TYPE u;
-    struct lysf_ctx fctx = {.ctx = ctx};
+    struct lysf_ctx fctx = {.ctx = (struct ly_ctx *)ctx};
+    ly_bool node_free;
 
     LY_ARRAY_FOR(substmts, u) {
         if (!substmts[u].storage) {
@@ -1365,42 +1364,240 @@
         }
 
         switch (substmts[u].stmt) {
+        case LY_STMT_NOTIFICATION:
+        case LY_STMT_INPUT:
+        case LY_STMT_OUTPUT:
         case LY_STMT_ACTION:
+        case LY_STMT_RPC:
         case LY_STMT_ANYDATA:
         case LY_STMT_ANYXML:
-        case LY_STMT_CONTAINER:
+        case LY_STMT_AUGMENT:
+        case LY_STMT_CASE:
         case LY_STMT_CHOICE:
+        case LY_STMT_CONTAINER:
+        case LY_STMT_GROUPING:
         case LY_STMT_LEAF:
         case LY_STMT_LEAF_LIST:
         case LY_STMT_LIST:
-        case LY_STMT_NOTIFICATION:
-        case LY_STMT_RPC: {
-            struct lysc_node *child, *child_next;
+        case LY_STMT_USES: {
+            struct lysp_node *child, *child_next;
 
-            LY_LIST_FOR_SAFE(*((struct lysc_node **)substmts[u].storage), child_next, child) {
-                lysc_node_free_(&fctx, child);
+            LY_LIST_FOR_SAFE(*((struct lysp_node **)substmts[u].storage), child_next, child) {
+                node_free = (child->nodetype & (LYS_INPUT | LYS_OUTPUT)) ? 1 : 0;
+                lysp_node_free(&fctx, child);
+                if (node_free) {
+                    free(child);
+                }
             }
             *((struct lysc_node **)substmts[u].storage) = NULL;
             break;
         }
-        case LY_STMT_GROUPING: {
-            struct lysp_node_grp *grp, *grp_next;
-
-            LY_LIST_FOR_SAFE(*((struct lysp_node_grp **)substmts[u].storage), grp_next, grp) {
-                lysp_node_free(&fctx, &grp->node);
-            }
+        case LY_STMT_BASE:
+            /* multiple strings */
+            FREE_ARRAY(ctx, **(const char ***)substmts[u].storage, lydict_remove);
             break;
-        }
-        case LY_STMT_USES:
+
+        case LY_STMT_BIT:
+        case LY_STMT_ENUM:
+            /* single enum */
+            lysp_type_enum_free(&fctx, *(struct lysp_type_enum **)substmts[u].storage);
+            break;
+
+        case LY_STMT_DEVIATE:
+            /* single deviate */
+            lysp_deviate_free(&fctx, *(struct lysp_deviate **)substmts[u].storage);
+            break;
+
+        case LY_STMT_DEVIATION:
+            /* single deviation */
+            lysp_deviation_free(&fctx, *(struct lysp_deviation **)substmts[u].storage);
+            break;
+
+        case LY_STMT_EXTENSION:
+            /* single extension */
+            lysp_ext_free(&fctx, *(struct lysp_ext **)substmts[u].storage);
+            break;
+
+        case LY_STMT_EXTENSION_INSTANCE:
+            /* multiple extension instances */
+            FREE_ARRAY(&fctx, *(struct lysp_ext_instance **)substmts[u].storage, lysp_ext_instance_free);
+            break;
+
+        case LY_STMT_FEATURE:
+            /* multiple features */
+            FREE_ARRAY(&fctx, *(struct lysp_feature **)substmts[u].storage, lysp_feature_free);
+            break;
+
+        case LY_STMT_IDENTITY:
+            /* multiple identities */
+            FREE_ARRAY(&fctx, *(struct lysp_ident **)substmts[u].storage, lysp_ident_free);
+            break;
+
+        case LY_STMT_IMPORT:
+            /* multiple imports */
+            FREE_ARRAY(&fctx, *(struct lysp_import **)substmts[u].storage, lysp_import_free);
+            break;
+
+        case LY_STMT_INCLUDE:
+            /* multiple includes */
+            FREE_ARRAY(&fctx, *(struct lysp_include **)substmts[u].storage, lysp_include_free);
+            break;
+
+        case LY_STMT_REFINE:
+            /* multiple refines */
+            FREE_ARRAY(&fctx, *(struct lysp_refine **)substmts[u].storage, lysp_refine_free);
+            break;
+
+        case LY_STMT_REVISION:
+            /* multiple revisions */
+            FREE_ARRAY(&fctx, *(struct lysp_revision **)substmts[u].storage, lysp_revision_free);
+            break;
+
         case LY_STMT_CONFIG:
+        case LY_STMT_FRACTION_DIGITS:
+        case LY_STMT_MANDATORY:
+        case LY_STMT_MAX_ELEMENTS:
+        case LY_STMT_MIN_ELEMENTS:
+        case LY_STMT_ORDERED_BY:
+        case LY_STMT_POSITION:
+        case LY_STMT_REQUIRE_INSTANCE:
         case LY_STMT_STATUS:
+        case LY_STMT_VALUE:
+        case LY_STMT_YANG_VERSION:
+        case LY_STMT_YIN_ELEMENT:
             /* nothing to do */
             break;
+
+        case LY_STMT_ARGUMENT:
+        case LY_STMT_BELONGS_TO:
         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_MODIFIER:
+        case LY_STMT_NAMESPACE:
+        case LY_STMT_ORGANIZATION:
+        case LY_STMT_PREFIX:
+        case LY_STMT_PRESENCE:
+        case LY_STMT_REFERENCE:
+        case LY_STMT_REVISION_DATE:
+        case LY_STMT_UNITS:
+            /* single string */
+            lydict_remove(ctx, *(const char **)substmts[u].storage);
+            break;
+
+        case LY_STMT_LENGTH:
+        case LY_STMT_MUST:
+        case LY_STMT_PATTERN:
+        case LY_STMT_RANGE:
+            /* multiple restrictions */
+            FREE_ARRAY(&fctx, *(struct lysp_restr **)substmts[u].storage, lysp_restr_free);
+            break;
+
+        case LY_STMT_WHEN:
+            /* multiple whens */
+            FREE_ARRAY(&fctx, *(struct lysp_when **)substmts[u].storage, lysp_when_free);
+            break;
+
+        case LY_STMT_PATH:
+            /* single expression */
+            lyxp_expr_free(ctx, *(struct lyxp_expr **)substmts[u].storage);
+            break;
+
+        case LY_STMT_DEFAULT:
+        case LY_STMT_IF_FEATURE:
+        case LY_STMT_UNIQUE:
+            /* multiple qnames */
+            FREE_ARRAY(ctx, *(struct lysp_qname **)substmts[u].storage, lysp_qname_free);
+            break;
+
+        case LY_STMT_TYPEDEF:
+            /* multiple typedefs */
+            FREE_ARRAY(&fctx, *(struct lysp_tpdf **)substmts[u].storage, lysp_tpdf_free);
+            break;
+
+        case LY_STMT_TYPE: {
+            /* single type */
+            struct lysp_type **type_p = substmts[u].storage;
+
+            lysp_type_free(&fctx, *type_p);
+            free(*type_p);
+            break;
+        }
+        case LY_STMT_MODULE:
+        case LY_STMT_SUBMODULE:
+            /* single (sub)module */
+            lysp_module_free(&fctx, *(struct lysp_module **)substmts[u].storage);
+            break;
+
+        default:
+            LOGINT(ctx);
+        }
+    }
+
+    LY_ARRAY_FREE(substmts);
+}
+
+LIBYANG_API_DEF void
+lyplg_ext_cfree_instance_substatements(const struct ly_ctx *ctx, struct lysc_ext_substmt *substmts)
+{
+    LY_ARRAY_COUNT_TYPE u;
+    struct lysf_ctx fctx = {.ctx = (struct ly_ctx *)ctx};
+    ly_bool node_free;
+
+    LY_ARRAY_FOR(substmts, u) {
+        if (!substmts[u].storage) {
+            continue;
+        }
+
+        switch (substmts[u].stmt) {
+        case LY_STMT_NOTIFICATION:
+        case LY_STMT_INPUT:
+        case LY_STMT_OUTPUT:
+        case LY_STMT_ACTION:
+        case LY_STMT_RPC:
+        case LY_STMT_ANYDATA:
+        case LY_STMT_ANYXML:
+        case LY_STMT_CASE:
+        case LY_STMT_CHOICE:
+        case LY_STMT_CONTAINER:
+        case LY_STMT_LEAF:
+        case LY_STMT_LEAF_LIST:
+        case LY_STMT_LIST: {
+            struct lysc_node *child, *child_next;
+
+            LY_LIST_FOR_SAFE(*((struct lysc_node **)substmts[u].storage), child_next, child) {
+                node_free = (child->nodetype & (LYS_INPUT | LYS_OUTPUT)) ? 1 : 0;
+                lysc_node_free_(&fctx, child);
+                if (node_free) {
+                    free(child);
+                }
+            }
+            *((struct lysc_node **)substmts[u].storage) = NULL;
+            break;
+        }
+        case LY_STMT_USES:
+        case LY_STMT_CONFIG:
+        case LY_STMT_FRACTION_DIGITS:
+        case LY_STMT_MANDATORY:
+        case LY_STMT_MAX_ELEMENTS:
+        case LY_STMT_MIN_ELEMENTS:
+        case LY_STMT_ORDERED_BY:
+        case LY_STMT_POSITION:
+        case LY_STMT_REQUIRE_INSTANCE:
+        case LY_STMT_STATUS:
+        case LY_STMT_VALUE:
+            /* nothing to do */
+            break;
+
+        case LY_STMT_ARGUMENT:
+        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_MODIFIER:
         case LY_STMT_NAMESPACE:
         case LY_STMT_ORGANIZATION:
         case LY_STMT_PRESENCE:
@@ -1412,44 +1609,88 @@
             lydict_remove(ctx, str);
             break;
         }
+        case LY_STMT_BIT:
+        case LY_STMT_ENUM: {
+            /* sized array */
+            struct lysc_type_bitenum_item *items = *((struct lysc_type_bitenum_item **)substmts[u].storage);
+
+            FREE_ARRAY(&fctx, items, lysc_enum_item_free);
+            break;
+        }
+        case LY_STMT_LENGTH:
+        case LY_STMT_RANGE: {
+            /* single item */
+            struct lysc_range *range = *((struct lysc_range **)substmts[u].storage);
+
+            lysc_range_free(&fctx, range);
+            break;
+        }
         case LY_STMT_MUST: {
-            /* multiple items */
+            /* sized array */
             struct lysc_must *musts = *((struct lysc_must **)substmts[u].storage);
 
             FREE_ARRAY(&fctx, musts, lysc_must_free);
             break;
         }
-        case LY_STMT_IF_FEATURE: {
-            struct lysc_iffeature *iff = *((struct lysc_iffeature **)substmts[u].storage);
-
-            if (!iff) {
-                break;
-            }
-            /* multiple items */
-            FREE_ARRAY(&fctx, iff, lysc_iffeature_free);
+        case LY_STMT_WHEN:
+            /* single item, expects a pointer */
+            lysc_when_free(&fctx, substmts[u].storage);
             break;
-        }
-        case LY_STMT_TYPEDEF: {
-            struct lysp_tpdf *tpdf = *((struct lysp_tpdf **)substmts[u].storage);
 
-            if (!tpdf) {
-                break;
-            }
-            /* always an array */
-            FREE_ARRAY(&fctx, tpdf, lysp_tpdf_free);
+        case LY_STMT_PATTERN: {
+            /* sized array of pointers */
+            struct lysc_pattern **patterns = *((struct lysc_pattern ***)substmts[u].storage);
+
+            FREE_ARRAY(&fctx, patterns, lysc_pattern_free);
             break;
         }
         case LY_STMT_TYPE: {
             /* single item */
             struct lysc_type *type = *((struct lysc_type **)substmts[u].storage);
 
-            if (!type) {
-                break;
-            }
             lysc_type_free(&fctx, type);
             break;
         }
-        /* TODO other statements */
+        case LY_STMT_IDENTITY: {
+            /* sized array */
+            struct lysc_ident *idents = *((struct lysc_ident **)substmts[u].storage);
+
+            FREE_ARRAY(&fctx, idents, lysc_ident_free);
+            break;
+        }
+        case LY_STMT_EXTENSION_INSTANCE: {
+            /* sized array */
+            struct lysc_ext_instance *exts = *((struct lysc_ext_instance **)substmts[u].storage);
+
+            FREE_ARRAY(&fctx, exts, lysc_ext_instance_free);
+            break;
+        }
+        case LY_STMT_AUGMENT:
+        case LY_STMT_BASE:
+        case LY_STMT_BELONGS_TO:
+        case LY_STMT_DEFAULT:
+        case LY_STMT_DEVIATE:
+        case LY_STMT_DEVIATION:
+        case LY_STMT_EXTENSION:
+        case LY_STMT_FEATURE:
+        case LY_STMT_GROUPING:
+        case LY_STMT_IF_FEATURE:
+        case LY_STMT_IMPORT:
+        case LY_STMT_INCLUDE:
+        case LY_STMT_MODULE:
+        case LY_STMT_PATH:
+        case LY_STMT_PREFIX:
+        case LY_STMT_REFINE:
+        case LY_STMT_REVISION:
+        case LY_STMT_REVISION_DATE:
+        case LY_STMT_SUBMODULE:
+        case LY_STMT_TYPEDEF:
+        case LY_STMT_UNIQUE:
+        case LY_STMT_YANG_VERSION:
+        case LY_STMT_YIN_ELEMENT:
+            /* it is not possible to compile these statements */
+            break;
+
         default:
             LOGINT(ctx);
         }