plugins exts CHANGE ext parsing isolated into a callback

Lots of refactoring and finishing up included.
diff --git a/src/context.c b/src/context.c
index 735f589..47e63d4 100644
--- a/src/context.c
+++ b/src/context.c
@@ -606,45 +606,13 @@
     return LY_SUCCESS;
 }
 
-static void
-lysc_node_clear_all_priv(struct lys_module *mod)
-{
-    LY_ARRAY_COUNT_TYPE u, v;
-
-    if (!mod->compiled) {
-        return;
-    }
-
-    /* set NULL for all ::lysc_node.priv pointers in module */
-    lysc_module_dfs_full(mod, lysc_node_clear_priv_dfs_cb, NULL);
-
-    /* only lys_compile_extension_instance()
-     * can set ::lysp_ext_instance.parsed
-     */
-    if (mod->parsed) {
-        struct lysp_ext_instance *exts_p;
-
-        exts_p = mod->parsed->exts;
-        LY_ARRAY_FOR(exts_p, u) {
-            if (exts_p[u].parsed) {
-                /* lys_compile_extension_instance() was called */
-                struct lysc_ext_substmt *substmts;
-                struct lysc_node *root;
-
-                /* set NULL for all ::lysc_node.priv pointers in extensions */
-                substmts = mod->compiled->exts[u].substmts;
-                LY_ARRAY_FOR(substmts, v) {
-                    root = *(struct lysc_node **)substmts[v].storage;
-                    lysc_tree_dfs_full(root, lysc_node_clear_priv_dfs_cb, NULL);
-                }
-            }
-        }
-    }
-}
-
 LIBYANG_API_DEF LY_ERR
 ly_ctx_unset_options(struct ly_ctx *ctx, uint16_t option)
 {
+    LY_ARRAY_COUNT_TYPE u, v;
+    const struct lysc_ext_instance *ext;
+    struct lysc_node *root;
+
     LY_CHECK_ARG_RET(ctx, ctx, LY_EINVAL);
     LY_CHECK_ERR_RET(option & LY_CTX_NO_YANGLIBRARY, LOGARG(ctx, option), LY_EINVAL);
 
@@ -654,7 +622,24 @@
 
         index = 0;
         while ((mod = ly_ctx_get_module_iter(ctx, &index))) {
-            lysc_node_clear_all_priv(mod);
+            if (!mod->compiled) {
+                continue;
+            }
+
+            /* set NULL for all ::lysc_node.priv pointers in module */
+            lysc_module_dfs_full(mod, lysc_node_clear_priv_dfs_cb, NULL);
+
+            /* set NULL for all ::lysc_node.priv pointers in compiled extension instances */
+            LY_ARRAY_FOR(mod->compiled->exts, u) {
+                ext = &mod->compiled->exts[u];
+                LY_ARRAY_FOR(ext->substmts, v) {
+                    if (ext->substmts[v].stmt & LY_STMT_DATA_NODE_MASK) {
+                        LY_LIST_FOR(*(struct lysc_node **)ext->substmts[v].storage, root) {
+                            lysc_tree_dfs_full(root, lysc_node_clear_priv_dfs_cb, NULL);
+                        }
+                    }
+                }
+            }
         }
     }
 
diff --git a/src/diff.c b/src/diff.c
index 80b939c..4ef9115 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -1157,7 +1157,7 @@
         ret = 0;
         if (parent_node) {
             if (match->flags & LYD_EXT) {
-                ret = lyd_insert_ext(parent_node, match);
+                ret = lyplg_ext_insert(parent_node, match);
             } else {
                 ret = lyd_insert_child(parent_node, match);
             }
diff --git a/src/log.c b/src/log.c
index 915b6e5..d13d327 100644
--- a/src/log.c
+++ b/src/log.c
@@ -1,9 +1,10 @@
 /**
  * @file log.c
  * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief Logger routines implementations
  *
- * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
+ * Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
@@ -33,6 +34,7 @@
 #include "tree_data.h"
 #include "tree_data_internal.h"
 #include "tree_schema.h"
+#include "tree_schema_internal.h"
 
 ATOMIC_T ly_ll = (uint_fast32_t)LY_LLWRN;
 ATOMIC_T ly_log_opts = (uint_fast32_t)(LY_LOLOG | LY_LOSTORE_LAST);
@@ -666,28 +668,74 @@
     va_end(ap);
 }
 
-LIBYANG_API_DEF void
-lyplg_ext_log(const struct lysc_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err_no, const char *path, const char *format, ...)
+/**
+ * @brief Print a log message from an extension plugin callback.
+ *
+ * @param[in] ctx libyang context to store the error record. If not provided, the error is just printed.
+ * @param[in] plugin_name Name of the plugin generating the message.
+ * @param[in] level Log message level (error, warning, etc.)
+ * @param[in] err_no Error type code.
+ * @param[in] path Optional path of the error.
+ * @param[in] format Format string to print.
+ * @param[in] ap Var arg list for @p format.
+ */
+static void
+ly_ext_log(const struct ly_ctx *ctx, const char *plugin_name, LY_LOG_LEVEL level, LY_ERR err_no, const char *path,
+        const char *format, va_list ap)
 {
-    va_list ap;
     char *plugin_msg;
-    int ret;
 
     if (ATOMIC_LOAD_RELAXED(ly_ll) < level) {
         return;
     }
-    ret = asprintf(&plugin_msg, "Extension plugin \"%s\": %s", ext->def->plugin->id, format);
-    if (ret == -1) {
-        LOGMEM(ext->module->ctx);
+    if (asprintf(&plugin_msg, "Ext plugin \"%s\": %s", plugin_name, format) == -1) {
+        LOGMEM(ctx);
         return;
     }
 
+    log_vprintf(ctx, level, (level == LY_LLERR ? LY_EPLUGIN : 0) | err_no, LYVE_OTHER, path ? strdup(path) : NULL, NULL,
+            plugin_msg, ap);
+    free(plugin_msg);
+}
+
+LIBYANG_API_DEF void
+lyplg_ext_parse_log(const struct lysp_ctx *pctx, const struct lysp_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err_no,
+        const char *format, ...)
+{
+    va_list ap;
+    char *path = NULL;
+
+    if (ATOMIC_LOAD_RELAXED(path_flag)) {
+        ly_vlog_build_path(PARSER_CTX(pctx), &path);
+    }
+
     va_start(ap, format);
-    log_vprintf(ext->module->ctx, level, (level == LY_LLERR ? LY_EPLUGIN : 0) | err_no, LYVE_OTHER,
-            path ? strdup(path) : NULL, NULL, plugin_msg, ap);
+    ly_ext_log(PARSER_CTX(pctx), ext->record->plugin.id, level, err_no, path, format, ap);
     va_end(ap);
 
-    free(plugin_msg);
+    free(path);
+}
+
+LIBYANG_API_DEF void
+lyplg_ext_compile_log(const struct lysc_ctx *cctx, const struct lysc_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err_no,
+        const char *format, ...)
+{
+    va_list ap;
+
+    va_start(ap, format);
+    ly_ext_log(ext->module->ctx, ext->def->plugin->id, level, err_no, cctx ? cctx->path : NULL, format, ap);
+    va_end(ap);
+}
+
+LIBYANG_API_DEF void
+lyplg_ext_compile_log_path(const char *path, const struct lysc_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err_no,
+        const char *format, ...)
+{
+    va_list ap;
+
+    va_start(ap, format);
+    ly_ext_log(ext->module->ctx, ext->def->plugin->id, level, err_no, path, format, ap);
+    va_end(ap);
 }
 
 /**
diff --git a/src/log.h b/src/log.h
index 6afd2e7..f1fde4c 100644
--- a/src/log.h
+++ b/src/log.h
@@ -1,9 +1,10 @@
 /**
  * @file log.h
  * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief Logger manipulation routines and error definitions.
  *
- * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
+ * Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
diff --git a/src/parser_common.c b/src/parser_common.c
index 4a0e421..809ed86 100644
--- a/src/parser_common.c
+++ b/src/parser_common.c
@@ -46,6 +46,7 @@
 #include "parser_data.h"
 #include "path.h"
 #include "plugins_exts/metadata.h"
+#include "schema_features.h"
 #include "set.h"
 #include "tree.h"
 #include "tree_data.h"
@@ -286,6 +287,62 @@
     return LY_SUCCESS;
 }
 
+void
+lys_parser_fill_filepath(struct ly_ctx *ctx, struct ly_in *in, const char **filepath)
+{
+    char path[PATH_MAX];
+
+#ifndef __APPLE__
+    char proc_path[32];
+    int len;
+#endif
+
+    LY_CHECK_ARG_RET(NULL, ctx, in, filepath, );
+    if (*filepath) {
+        /* filepath already set */
+        return;
+    }
+
+    switch (in->type) {
+    case LY_IN_FILEPATH:
+        if (realpath(in->method.fpath.filepath, path) != NULL) {
+            lydict_insert(ctx, path, 0, filepath);
+        } else {
+            lydict_insert(ctx, in->method.fpath.filepath, 0, filepath);
+        }
+
+        break;
+    case LY_IN_FD:
+#ifdef __APPLE__
+        if (fcntl(in->method.fd, F_GETPATH, path) != -1) {
+            lydict_insert(ctx, path, 0, filepath);
+        }
+#elif defined _WIN32
+        HANDLE h = _get_osfhandle(in->method.fd);
+        FILE_NAME_INFO info;
+        if (GetFileInformationByHandleEx(h, FileNameInfo, &info, sizeof info)) {
+            char *buf = calloc(info.FileNameLength + 1 /* trailing NULL */, MB_CUR_MAX);
+            len = wcstombs(buf, info.FileName, info.FileNameLength * MB_CUR_MAX);
+            lydict_insert(ctx, buf, len, filepath);
+        }
+#else
+        /* get URI if there is /proc */
+        sprintf(proc_path, "/proc/self/fd/%d", in->method.fd);
+        if ((len = readlink(proc_path, path, PATH_MAX - 1)) > 0) {
+            lydict_insert(ctx, path, len, filepath);
+        }
+#endif
+        break;
+    case LY_IN_MEMORY:
+    case LY_IN_FILE:
+        /* nothing to do */
+        break;
+    default:
+        LOGINT(ctx);
+        break;
+    }
+}
+
 static LY_ERR lysp_stmt_container(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_node *parent,
         struct lysp_node **siblings);
 static LY_ERR lysp_stmt_choice(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_node *parent,
@@ -337,7 +394,6 @@
  * @param[in] insubstmt The statement this extension instance is a substatement of.
  * @param[in] insubstmt_index Index of the keyword instance this extension instance is a substatement of.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -377,11 +433,11 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-lysp_stmt_text_field(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, uint32_t substmt_index,
-        const char **value, enum yang_arg arg, struct lysp_ext_instance **exts)
+lysp_stmt_text_field(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, uint32_t substmt_index, const char **value,
+        enum yang_arg arg, struct lysp_ext_instance **exts)
 {
     if (*value) {
-        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(stmt->kw));
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, lyplg_ext_stmt2str(stmt->kw));
         return LY_EVALID;
     }
 
@@ -394,7 +450,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, stmt->kw, substmt_index, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), ly_stmt2str(stmt->kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), lyplg_ext_stmt2str(stmt->kw));
             return LY_EVALID;
         }
     }
@@ -413,8 +469,8 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-lysp_stmt_qnames(struct lysp_ctx *ctx, const struct lysp_stmt *stmt,
-        struct lysp_qname **qnames, enum yang_arg arg, struct lysp_ext_instance **exts)
+lysp_stmt_qnames(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_qname **qnames, enum yang_arg arg,
+        struct lysp_ext_instance **exts)
 {
     struct lysp_qname *item;
 
@@ -431,7 +487,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, stmt->kw, LY_ARRAY_COUNT(*qnames) - 1, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), ly_stmt2str(stmt->kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), lyplg_ext_stmt2str(stmt->kw));
             return LY_EVALID;
         }
     }
@@ -450,8 +506,8 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-lysp_stmt_text_fields(struct lysp_ctx *ctx, const struct lysp_stmt *stmt,
-        const char ***texts, enum yang_arg arg, struct lysp_ext_instance **exts)
+lysp_stmt_text_fields(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, const char ***texts, enum yang_arg arg,
+        struct lysp_ext_instance **exts)
 {
     const char **item;
 
@@ -467,7 +523,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, stmt->kw, LY_ARRAY_COUNT(*texts) - 1, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), ly_stmt2str(stmt->kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), lyplg_ext_stmt2str(stmt->kw));
             return LY_EVALID;
         }
     }
@@ -513,7 +569,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_STATUS, 0, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "status");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "status");
             return LY_EVALID;
         }
     }
@@ -560,7 +616,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_WHEN, 0, &when->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "when");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "when");
             return LY_EVALID;
         }
     }
@@ -604,7 +660,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_CONFIG, 0, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "config");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "config");
             return LY_EVALID;
         }
     }
@@ -650,7 +706,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_MANDATORY, 0, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "mandatory");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "mandatory");
             return LY_EVALID;
         }
     }
@@ -692,7 +748,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, stmt->kw, 0, &restr->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), ly_stmt2str(stmt->kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), lyplg_ext_stmt2str(stmt->kw));
             return LY_EVALID;
         }
     }
@@ -772,8 +828,8 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, stmt->kw, 0, &any->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw),
-                    (any->nodetype & LYS_ANYDATA) == LYS_ANYDATA ? ly_stmt2str(LY_STMT_ANYDATA) : ly_stmt2str(LY_STMT_ANYXML));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw),
+                    (any->nodetype & LYS_ANYDATA) == LYS_ANYDATA ? lyplg_ext_stmt2str(LY_STMT_ANYDATA) : lyplg_ext_stmt2str(LY_STMT_ANYXML));
             return LY_EVALID;
         }
     }
@@ -802,7 +858,7 @@
     unsigned long long int unum = 0;
 
     if (*flags & LYS_SET_VALUE) {
-        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(stmt->kw));
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, lyplg_ext_stmt2str(stmt->kw));
         return LY_EVALID;
     }
     *flags |= LYS_SET_VALUE;
@@ -812,7 +868,7 @@
     arg_len = strlen(stmt->arg);
     if (!arg_len || (stmt->arg[0] == '+') || ((stmt->arg[0] == '0') && (arg_len > 1)) ||
             ((stmt->kw == LY_STMT_POSITION) && !strncmp(stmt->arg, "-0", 2))) {
-        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(stmt->kw));
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, lyplg_ext_stmt2str(stmt->kw));
         goto error;
     }
 
@@ -820,23 +876,23 @@
     if (stmt->kw == LY_STMT_VALUE) {
         num = strtoll(stmt->arg, &ptr, LY_BASE_DEC);
         if ((num < INT64_C(-2147483648)) || (num > INT64_C(2147483647))) {
-            LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(stmt->kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, lyplg_ext_stmt2str(stmt->kw));
             goto error;
         }
     } else {
         unum = strtoull(stmt->arg, &ptr, LY_BASE_DEC);
         if (unum > UINT64_C(4294967295)) {
-            LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(stmt->kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, lyplg_ext_stmt2str(stmt->kw));
             goto error;
         }
     }
     /* we have not parsed the whole argument */
     if ((size_t)(ptr - stmt->arg) != arg_len) {
-        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(stmt->kw));
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, lyplg_ext_stmt2str(stmt->kw));
         goto error;
     }
     if (errno == ERANGE) {
-        LOGVAL_PARSER(ctx, LY_VCODE_OOB, arg_len, stmt->arg, ly_stmt2str(stmt->kw));
+        LOGVAL_PARSER(ctx, LY_VCODE_OOB, arg_len, stmt->arg, lyplg_ext_stmt2str(stmt->kw));
         goto error;
     }
     if (stmt->kw == LY_STMT_VALUE) {
@@ -851,7 +907,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, stmt->kw == LY_STMT_VALUE ? LY_STMT_VALUE : LY_STMT_POSITION, 0, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), ly_stmt2str(stmt->kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), lyplg_ext_stmt2str(stmt->kw));
             return LY_EVALID;
         }
     }
@@ -884,7 +940,7 @@
     } /* else nothing specific for YANG_BIT */
 
     LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), stmt->arg, 0, &enm->name));
-    CHECK_UNIQUENESS(ctx, *enums, name, ly_stmt2str(stmt->kw), enm->name);
+    CHECK_UNIQUENESS(ctx, *enums, name, lyplg_ext_stmt2str(stmt->kw), enm->name);
 
     for (const struct lysp_stmt *child = stmt->child; child; child = child->next) {
         switch (child->kw) {
@@ -892,7 +948,7 @@
             LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &enm->dsc, Y_STR_ARG, &enm->exts));
             break;
         case LY_STMT_IF_FEATURE:
-            PARSER_CHECK_STMTVER2_RET(ctx, "if-feature", ly_stmt2str(stmt->kw));
+            PARSER_CHECK_STMTVER2_RET(ctx, "if-feature", lyplg_ext_stmt2str(stmt->kw));
             LY_CHECK_RET(lysp_stmt_qnames(ctx, child, &enm->iffeatures, Y_STR_ARG, &enm->exts));
             break;
         case LY_STMT_REFERENCE:
@@ -902,23 +958,24 @@
             LY_CHECK_RET(lysp_stmt_status(ctx, child, &enm->flags, &enm->exts));
             break;
         case LY_STMT_VALUE:
-            LY_CHECK_ERR_RET(stmt->kw == LY_STMT_BIT, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw),
-                    ly_stmt2str(stmt->kw)), LY_EVALID);
+            LY_CHECK_ERR_RET(stmt->kw == LY_STMT_BIT, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw),
+                    lyplg_ext_stmt2str(stmt->kw)), LY_EVALID);
             LY_CHECK_RET(lysp_stmt_type_enum_value_pos(ctx, child, &enm->value, &enm->flags, &enm->exts));
             break;
         case LY_STMT_POSITION:
-            LY_CHECK_ERR_RET(stmt->kw == LY_STMT_ENUM, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw),
-                    ly_stmt2str(stmt->kw)), LY_EVALID);
+            LY_CHECK_ERR_RET(stmt->kw == LY_STMT_ENUM, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw),
+                    lyplg_ext_stmt2str(stmt->kw)), LY_EVALID);
             LY_CHECK_RET(lysp_stmt_type_enum_value_pos(ctx, child, &enm->value, &enm->flags, &enm->exts));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, stmt->kw, 0, &enm->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), ly_stmt2str(stmt->kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), lyplg_ext_stmt2str(stmt->kw));
             return LY_EVALID;
         }
     }
+
     return LY_SUCCESS;
 }
 
@@ -971,7 +1028,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_FRACTION_DIGITS, 0, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "fraction-digits");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "fraction-digits");
             return LY_EVALID;
         }
     }
@@ -1016,7 +1073,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_REQUIRE_INSTANCE, 0, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "require-instance");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "require-instance");
             return LY_EVALID;
         }
     }
@@ -1030,7 +1087,6 @@
  * @param[in] stmt Source statement data from the parsed extension instance.
  * @param[in,out] pat Value to write to.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1068,7 +1124,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_MODIFIER, 0, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "modifier");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "modifier");
             return LY_EVALID;
         }
     }
@@ -1126,7 +1182,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_PATTERN, 0, &restr->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "pattern");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "pattern");
             return LY_EVALID;
         }
     }
@@ -1134,6 +1190,509 @@
 }
 
 /**
+ * @brief Parse the deviate statement. Substatement of deviation statement.
+ *
+ * @param[in] ctx parser context.
+ * @param[in] stmt Source statement data from the parsed extension instance.
+ * @param[in,out] devs Array of deviates to add to.
+ * @param[in,out] exts Extension instances to add to.
+ * @return LY_ERR values.
+ */
+static LY_ERR
+lysp_stmt_deviate(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_deviate **devs, struct lysp_ext_instance **exts)
+{
+    (void)stmt;
+    (void)devs;
+    (void)exts;
+
+    /* TODO */
+    LOGERR(PARSER_CTX(ctx), LY_EINVAL, "Extension instance \"deviate\" substatement is not supported.");
+    return LY_EINVAL;
+}
+
+/**
+ * @brief Parse the deviation statement.
+ *
+ * @param[in] ctx parser context.
+ * @param[in] stmt Source statement data from the parsed extension instance.
+ * @param[in,out] deviations Array of deviations to add to.
+ * @return LY_ERR values.
+ */
+static LY_ERR
+lysp_stmt_deviation(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_deviation **deviations)
+{
+    struct lysp_deviation *dev;
+
+    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *deviations, dev, LY_EMEM);
+
+    /* store nodeid */
+    LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
+    LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), stmt->arg, 0, &dev->nodeid));
+
+    /* parse substatements */
+    for (const struct lysp_stmt *child = stmt->child; child; child = child->next) {
+        switch (child->kw) {
+        case LY_STMT_DESCRIPTION:
+            LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &dev->dsc, Y_STR_ARG, &dev->exts));
+            break;
+        case LY_STMT_DEVIATE:
+            LY_CHECK_RET(lysp_stmt_deviate(ctx, child, &dev->deviates, &dev->exts));
+            break;
+        case LY_STMT_REFERENCE:
+            LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &dev->ref, Y_STR_ARG, &dev->exts));
+            break;
+        case LY_STMT_EXTENSION_INSTANCE:
+            LY_CHECK_RET(lysp_stmt_ext(ctx, child, stmt->kw, 0, &dev->exts));
+            break;
+        default:
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), lyplg_ext_stmt2str(LY_STMT_DEVIATION));
+            return LY_EVALID;
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse the yang-version statement.
+ *
+ * @param[in] ctx parser context.
+ * @param[in] stmt Source statement data from the parsed extension instance.
+ * @param[out] version Version to write to.
+ * @param[in,out] exts Extension instances to add to.
+ * @return LY_ERR values.
+ */
+static LY_ERR
+lysp_stmt_yangver(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, uint8_t *version, struct lysp_ext_instance **exts)
+{
+    if (*version) {
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "yin-element");
+        return LY_EVALID;
+    }
+
+    /* store flag */
+    if (!strcmp(stmt->arg, "1")) {
+        *version = LYS_VERSION_1_0;
+    } else if (!strcmp(stmt->arg, "1.1")) {
+        *version = LYS_VERSION_1_1;
+    } else {
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, strlen(stmt->arg), stmt->arg, "yang-version");
+        return LY_EVALID;
+    }
+
+    /* parse substatements */
+    for (const struct lysp_stmt *child = stmt->child; child; child = child->next) {
+        switch (child->kw) {
+        case LY_STMT_EXTENSION_INSTANCE:
+            LY_CHECK_RET(lysp_stmt_ext(ctx, child, stmt->kw, 0, exts));
+            break;
+        default:
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), lyplg_ext_stmt2str(LY_STMT_YANG_VERSION));
+            return LY_EVALID;
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse the module statement.
+ *
+ * @param[in] ctx parser context.
+ * @param[in] stmt Source statement data from the parsed extension instance.
+ * @param[in,out] mod Module to fill.
+ * @return LY_ERR values.
+ */
+static LY_ERR
+lysp_stmt_module(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_module *mod)
+{
+    (void)stmt;
+    (void)mod;
+
+    /* TODO */
+    LOGERR(PARSER_CTX(ctx), LY_EINVAL, "Extension instance \"module\" substatement is not supported.");
+    return LY_EINVAL;
+}
+
+/**
+ * @brief Parse the submodule statement.
+ *
+ * @param[in] ctx parser context.
+ * @param[in] stmt Source statement data from the parsed extension instance.
+ * @param[in,out] submod Module to fill.
+ * @return LY_ERR values.
+ */
+static LY_ERR
+lysp_stmt_submodule(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_submodule *submod)
+{
+    (void)stmt;
+    (void)submod;
+
+    /* TODO */
+    LOGERR(PARSER_CTX(ctx), LY_EINVAL, "Extension instance \"submodule\" substatement is not supported.");
+    return LY_EINVAL;
+}
+
+/**
+ * @brief Parse the yin-element statement. Substatement of argument statement.
+ *
+ * @param[in] ctx parser context.
+ * @param[in] stmt Source statement data from the parsed extension instance.
+ * @param[in,out] flags Flags to write to.
+ * @param[in,out] exts Extension instances to add to.
+ * @return LY_ERR values.
+ */
+static LY_ERR
+lysp_stmt_yinelem(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, uint16_t *flags, struct lysp_ext_instance **exts)
+{
+    if (*flags & LYS_YINELEM_MASK) {
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "yin-element");
+        return LY_EVALID;
+    }
+
+    /* store flag */
+    if (!strcmp(stmt->arg, "true")) {
+        *flags |= LYS_YINELEM_TRUE;
+    } else if (!strcmp(stmt->arg, "false")) {
+        *flags |= LYS_YINELEM_FALSE;
+    } else {
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, strlen(stmt->arg), stmt->arg, "yin-element");
+        return LY_EVALID;
+    }
+
+    /* parse substatements */
+    for (const struct lysp_stmt *child = stmt->child; child; child = child->next) {
+        switch (child->kw) {
+        case LY_STMT_EXTENSION_INSTANCE:
+            LY_CHECK_RET(lysp_stmt_ext(ctx, child, stmt->kw, 0, exts));
+            break;
+        default:
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), lyplg_ext_stmt2str(LY_STMT_YIN_ELEMENT));
+            return LY_EVALID;
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse the argument statement. Substatement of extension statement.
+ *
+ * @param[in] ctx parser context.
+ * @param[in] stmt Source statement data from the parsed extension instance.
+ * @param[in,out] ex Extension to fill.
+ * @return LY_ERR values.
+ */
+static LY_ERR
+lysp_stmt_argument(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_ext *ex)
+{
+    if (ex->argname) {
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "argument");
+        return LY_EVALID;
+    }
+
+    /* store argument name */
+    LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_PREF_IDENTIF_ARG, stmt->arg));
+    LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), stmt->arg, 0, &ex->argname));
+
+    /* parse substatements */
+    for (const struct lysp_stmt *child = stmt->child; child; child = child->next) {
+        switch (child->kw) {
+        case LY_STMT_YIN_ELEMENT:
+            LY_CHECK_RET(lysp_stmt_yinelem(ctx, child, &ex->flags, &ex->exts));
+            break;
+        case LY_STMT_EXTENSION_INSTANCE:
+            LY_CHECK_RET(lysp_stmt_ext(ctx, child, stmt->kw, 0, &ex->exts));
+            break;
+        default:
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), lyplg_ext_stmt2str(LY_STMT_ARGUMENT));
+            return LY_EVALID;
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse the extension statement.
+ *
+ * @param[in] ctx parser context.
+ * @param[in] stmt Source statement data from the parsed extension instance.
+ * @param[in,out] extensions Array of extensions to add to.
+ * @return LY_ERR values.
+ */
+static LY_ERR
+lysp_stmt_extension(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_ext **extensions)
+{
+    struct lysp_ext *ex;
+
+    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *extensions, ex, LY_EMEM);
+
+    /* store name */
+    LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_IDENTIF_ARG, stmt->arg));
+    LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), stmt->arg, 0, &ex->name));
+
+    /* parse substatements */
+    for (const struct lysp_stmt *child = stmt->child; child; child = child->next) {
+        switch (child->kw) {
+        case LY_STMT_DESCRIPTION:
+            LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &ex->dsc, Y_STR_ARG, &ex->exts));
+            break;
+        case LY_STMT_REFERENCE:
+            LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &ex->ref, Y_STR_ARG, &ex->exts));
+            break;
+        case LY_STMT_STATUS:
+            LY_CHECK_RET(lysp_stmt_status(ctx, child, &ex->flags, &ex->exts));
+            break;
+        case LY_STMT_ARGUMENT:
+            LY_CHECK_RET(lysp_stmt_argument(ctx, child, ex));
+            break;
+        case LY_STMT_EXTENSION_INSTANCE:
+            LY_CHECK_RET(lysp_stmt_ext(ctx, child, stmt->kw, 0, &ex->exts));
+            break;
+        default:
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), lyplg_ext_stmt2str(LY_STMT_EXTENSION));
+            return LY_EVALID;
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse the feature statement.
+ *
+ * @param[in] ctx parser context.
+ * @param[in] stmt Source statement data from the parsed extension instance.
+ * @param[in,out] features Array of features to add to.
+ * @return LY_ERR values.
+ */
+static LY_ERR
+lysp_stmt_feature(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_feature **features)
+{
+    struct lysp_feature *feat;
+
+    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *features, feat, LY_EMEM);
+
+    /* store name */
+    LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_IDENTIF_ARG, stmt->arg));
+    LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), stmt->arg, 0, &feat->name));
+
+    /* parse substatements */
+    for (const struct lysp_stmt *child = stmt->child; child; child = child->next) {
+        switch (child->kw) {
+        case LY_STMT_DESCRIPTION:
+            LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &feat->dsc, Y_STR_ARG, &feat->exts));
+            break;
+        case LY_STMT_IF_FEATURE:
+            LY_CHECK_RET(lysp_stmt_qnames(ctx, child, &feat->iffeatures, Y_STR_ARG, &feat->exts));
+            break;
+        case LY_STMT_REFERENCE:
+            LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &feat->ref, Y_STR_ARG, &feat->exts));
+            break;
+        case LY_STMT_STATUS:
+            LY_CHECK_RET(lysp_stmt_status(ctx, child, &feat->flags, &feat->exts));
+            break;
+        case LY_STMT_EXTENSION_INSTANCE:
+            LY_CHECK_RET(lysp_stmt_ext(ctx, child, stmt->kw, 0, &feat->exts));
+            break;
+        default:
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), lyplg_ext_stmt2str(LY_STMT_FEATURE));
+            return LY_EVALID;
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse the identity statement.
+ *
+ * @param[in] ctx parser context.
+ * @param[in] stmt Source statement data from the parsed extension instance.
+ * @param[in,out] identities Array of identities to add to.
+ * @return LY_ERR values.
+ */
+static LY_ERR
+lysp_stmt_identity(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_ident **identities)
+{
+    struct lysp_ident *ident;
+
+    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *identities, ident, LY_EMEM);
+
+    /* store name */
+    LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_IDENTIF_ARG, stmt->arg));
+    LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), stmt->arg, 0, &ident->name));
+
+    /* parse substatements */
+    for (const struct lysp_stmt *child = stmt->child; child; child = child->next) {
+        switch (child->kw) {
+        case LY_STMT_DESCRIPTION:
+            LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &ident->dsc, Y_STR_ARG, &ident->exts));
+            break;
+        case LY_STMT_IF_FEATURE:
+            LY_CHECK_RET(lysp_stmt_qnames(ctx, child, &ident->iffeatures, Y_STR_ARG, &ident->exts));
+            break;
+        case LY_STMT_REFERENCE:
+            LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &ident->ref, Y_STR_ARG, &ident->exts));
+            break;
+        case LY_STMT_STATUS:
+            LY_CHECK_RET(lysp_stmt_status(ctx, child, &ident->flags, &ident->exts));
+            break;
+        case LY_STMT_BASE:
+            LY_CHECK_RET(lysp_stmt_text_fields(ctx, child, &ident->bases, Y_PREF_IDENTIF_ARG, &ident->exts));
+            break;
+        case LY_STMT_EXTENSION_INSTANCE:
+            LY_CHECK_RET(lysp_stmt_ext(ctx, child, stmt->kw, 0, &ident->exts));
+            break;
+        default:
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), lyplg_ext_stmt2str(LY_STMT_IDENTITY));
+            return LY_EVALID;
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse the import statement.
+ *
+ * @param[in] ctx parser context.
+ * @param[in] stmt Source statement data from the parsed extension instance.
+ * @param[in,out] imports Array of imports to add to.
+ * @return LY_ERR values.
+ */
+static LY_ERR
+lysp_stmt_import(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_import **imports)
+{
+    struct lysp_import *imp;
+    const char *str = NULL;
+
+    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *imports, imp, LY_EMEM);
+
+    /* store name */
+    LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_IDENTIF_ARG, stmt->arg));
+    LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), stmt->arg, 0, &imp->name));
+
+    /* parse substatements */
+    for (const struct lysp_stmt *child = stmt->child; child; child = child->next) {
+        switch (child->kw) {
+        case LY_STMT_PREFIX:
+            LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &imp->prefix, Y_IDENTIF_ARG, &imp->exts));
+            LY_CHECK_RET(lysp_check_prefix(ctx, *imports, NULL, &imp->prefix), LY_EVALID);
+            break;
+        case LY_STMT_DESCRIPTION:
+            LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &imp->dsc, Y_STR_ARG, &imp->exts));
+            break;
+        case LY_STMT_REFERENCE:
+            LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &imp->ref, Y_STR_ARG, &imp->exts));
+            break;
+        case LY_STMT_REVISION_DATE:
+            LY_CHECK_RET(lysp_stmt_text_field(ctx, stmt, 0, &str, Y_STR_ARG, &imp->exts));
+            strcpy(imp->rev, str);
+            lydict_remove(PARSER_CTX(ctx), str);
+            LY_CHECK_RET(lysp_check_date(ctx, imp->rev, LY_REV_SIZE - 1, "revision-date"));
+            break;
+        case LY_STMT_EXTENSION_INSTANCE:
+            LY_CHECK_RET(lysp_stmt_ext(ctx, child, stmt->kw, 0, &imp->exts));
+            break;
+        default:
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), lyplg_ext_stmt2str(LY_STMT_IMPORT));
+            return LY_EVALID;
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse the include statement.
+ *
+ * @param[in] ctx parser context.
+ * @param[in] stmt Source statement data from the parsed extension instance.
+ * @param[in,out] includes Array of identities to add to.
+ * @return LY_ERR values.
+ */
+static LY_ERR
+lysp_stmt_include(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_include **includes)
+{
+    struct lysp_include *inc;
+    const char *str = NULL;
+
+    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *includes, inc, LY_EMEM);
+
+    /* store name */
+    LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_IDENTIF_ARG, stmt->arg));
+    LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), stmt->arg, 0, &inc->name));
+
+    /* parse substatements */
+    for (const struct lysp_stmt *child = stmt->child; child; child = child->next) {
+        switch (child->kw) {
+        case LY_STMT_DESCRIPTION:
+            LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &inc->dsc, Y_STR_ARG, &inc->exts));
+            break;
+        case LY_STMT_REFERENCE:
+            LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &inc->ref, Y_STR_ARG, &inc->exts));
+            break;
+        case LY_STMT_REVISION_DATE:
+            LY_CHECK_RET(lysp_stmt_text_field(ctx, stmt, 0, &str, Y_STR_ARG, &inc->exts));
+            strcpy(inc->rev, str);
+            lydict_remove(PARSER_CTX(ctx), str);
+            LY_CHECK_RET(lysp_check_date(ctx, inc->rev, LY_REV_SIZE - 1, "revision-date"));
+            break;
+        case LY_STMT_EXTENSION_INSTANCE:
+            LY_CHECK_RET(lysp_stmt_ext(ctx, child, stmt->kw, 0, &inc->exts));
+            break;
+        default:
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), lyplg_ext_stmt2str(LY_STMT_INCLUDE));
+            return LY_EVALID;
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse the revision statement.
+ *
+ * @param[in] ctx parser context.
+ * @param[in] stmt Source statement data from the parsed extension instance.
+ * @param[in,out] includes Array of identities to add to.
+ * @return LY_ERR values.
+ */
+static LY_ERR
+lysp_stmt_revision(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_revision **revs)
+{
+    struct lysp_revision *rev;
+
+    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *revs, rev, LY_EMEM);
+
+    /* store date */
+    LY_CHECK_RET(lysp_check_date(ctx, stmt->arg, LY_REV_SIZE - 1, "revision"));
+    strcpy(rev->date, stmt->arg);
+
+    /* parse substatements */
+    for (const struct lysp_stmt *child = stmt->child; child; child = child->next) {
+        switch (child->kw) {
+        case LY_STMT_DESCRIPTION:
+            LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &rev->dsc, Y_STR_ARG, &rev->exts));
+            break;
+        case LY_STMT_REFERENCE:
+            LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &rev->ref, Y_STR_ARG, &rev->exts));
+            break;
+        case LY_STMT_EXTENSION_INSTANCE:
+            LY_CHECK_RET(lysp_stmt_ext(ctx, child, stmt->kw, 0, &rev->exts));
+            break;
+        default:
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), lyplg_ext_stmt2str(LY_STMT_REVISION));
+            return LY_EVALID;
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
  * @brief Parse the type statement.
  *
  * @param[in] ctx parser context.
@@ -1178,7 +1737,7 @@
             break;
         case LY_STMT_LENGTH:
             if (type->length) {
-                LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(child->kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, lyplg_ext_stmt2str(child->kw));
                 return LY_EVALID;
             }
             type->length = calloc(1, sizeof *type->length);
@@ -1201,7 +1760,7 @@
             break;
         case LY_STMT_RANGE:
             if (type->range) {
-                LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(child->kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, lyplg_ext_stmt2str(child->kw));
                 return LY_EVALID;
             }
             type->range = calloc(1, sizeof *type->range);
@@ -1223,7 +1782,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_TYPE, 0, &type->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "type");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "type");
             return LY_EVALID;
         }
     }
@@ -1296,7 +1855,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_LEAF, 0, &leaf->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "leaf");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "leaf");
             return LY_EVALID;
         }
     }
@@ -1322,8 +1881,8 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-lysp_stmt_maxelements(struct lysp_ctx *ctx, const struct lysp_stmt *stmt,
-        uint32_t *max, uint16_t *flags, struct lysp_ext_instance **exts)
+lysp_stmt_maxelements(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, uint32_t *max, uint16_t *flags,
+        struct lysp_ext_instance **exts)
 {
     size_t arg_len;
     char *ptr;
@@ -1369,7 +1928,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_MAX_ELEMENTS, 0, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "max-elements");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "max-elements");
             return LY_EVALID;
         }
     }
@@ -1385,12 +1944,11 @@
  * @param[in,out] min Value to write to.
  * @param[in,out] flags Flags to write to.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
-lysp_stmt_minelements(struct lysp_ctx *ctx, const struct lysp_stmt *stmt,
-        uint32_t *min, uint16_t *flags, struct lysp_ext_instance **exts)
+lysp_stmt_minelements(struct lysp_ctx *ctx, const struct lysp_stmt *stmt, uint32_t *min, uint16_t *flags,
+        struct lysp_ext_instance **exts)
 {
     size_t arg_len;
     char *ptr;
@@ -1430,7 +1988,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_MIN_ELEMENTS, 0, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "min-elements");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "min-elements");
             return LY_EVALID;
         }
     }
@@ -1445,7 +2003,6 @@
  * @param[in] stmt Source statement data from the parsed extension instance.
  * @param[in,out] flags Flags to write to.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1476,7 +2033,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_ORDERED_BY, 0, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "ordered-by");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "ordered-by");
             return LY_EVALID;
         }
     }
@@ -1491,7 +2048,6 @@
  * @param[in] stmt Source statement data from the parsed extension instance.
  * @param[in] parent Parent node to connect to (not into).
  * @param[in,out] siblings Siblings to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1557,7 +2113,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_LEAF_LIST, 0, &llist->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "llist");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "llist");
             return LY_EVALID;
         }
     }
@@ -1577,7 +2133,6 @@
  * @param[in] ctx parser context.
  * @param[in] stmt Source statement data from the parsed extension instance.
  * @param[in,out] refines Refines to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1628,7 +2183,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_REFINE, 0, &rf->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "refine");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "refine");
             return LY_EVALID;
         }
     }
@@ -1684,7 +2239,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_TYPEDEF, 0, &tpdf->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "typedef");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "typedef");
             return LY_EVALID;
         }
     }
@@ -1718,7 +2273,7 @@
         struct lysp_node_action_inout *inout_p)
 {
     if (inout_p->nodetype) {
-        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(stmt->kw));
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, lyplg_ext_stmt2str(stmt->kw));
         return LY_EVALID;
     }
 
@@ -1731,7 +2286,7 @@
     for (const struct lysp_stmt *child = stmt->child; child; child = child->next) {
         switch (child->kw) {
         case LY_STMT_ANYDATA:
-            PARSER_CHECK_STMTVER2_RET(ctx, "anydata", ly_stmt2str(stmt->kw));
+            PARSER_CHECK_STMTVER2_RET(ctx, "anydata", lyplg_ext_stmt2str(stmt->kw));
         /* fall through */
         case LY_STMT_ANYXML:
             LY_CHECK_RET(lysp_stmt_any(ctx, child, &inout_p->node, &inout_p->child));
@@ -1758,7 +2313,7 @@
             LY_CHECK_RET(lysp_stmt_typedef(ctx, child, &inout_p->node, &inout_p->typedefs));
             break;
         case LY_STMT_MUST:
-            PARSER_CHECK_STMTVER2_RET(ctx, "must", ly_stmt2str(stmt->kw));
+            PARSER_CHECK_STMTVER2_RET(ctx, "must", lyplg_ext_stmt2str(stmt->kw));
             LY_CHECK_RET(lysp_stmt_restrs(ctx, child, &inout_p->musts));
             break;
         case LY_STMT_GROUPING:
@@ -1768,13 +2323,13 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, stmt->kw, 0, &inout_p->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), ly_stmt2str(stmt->kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), lyplg_ext_stmt2str(stmt->kw));
             return LY_EVALID;
         }
     }
 
     if (!inout_p->child) {
-        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "data-def-stmt", ly_stmt2str(stmt->kw));
+        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "data-def-stmt", lyplg_ext_stmt2str(stmt->kw));
         return LY_EVALID;
     }
 
@@ -1837,7 +2392,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, parent ? LY_STMT_ACTION : LY_STMT_RPC, 0, &act->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), parent ? "action" : "rpc");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), parent ? "action" : "rpc");
             return LY_EVALID;
         }
     }
@@ -1935,7 +2490,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_NOTIFICATION, 0, &notif->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "notification");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "notification");
             return LY_EVALID;
         }
     }
@@ -2022,7 +2577,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_GROUPING, 0, &grp->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "grouping");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "grouping");
             return LY_EVALID;
         }
     }
@@ -2112,7 +2667,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_AUGMENT, 0, &aug->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "augment");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "augment");
             return LY_EVALID;
         }
     }
@@ -2174,7 +2729,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_USES, 0, &uses->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "uses");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "uses");
             return LY_EVALID;
         }
     }
@@ -2254,7 +2809,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_CASE, 0, &cas->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "case");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "case");
             return LY_EVALID;
         }
     }
@@ -2343,7 +2898,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_CHOICE, 0, &choice->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "choice");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "choice");
             return LY_EVALID;
         }
     }
@@ -2445,7 +3000,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_CONTAINER, 0, &cont->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "container");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "container");
             return LY_EVALID;
         }
     }
@@ -2561,7 +3116,7 @@
             LY_CHECK_RET(lysp_stmt_ext(ctx, child, LY_STMT_LIST, 0, &list->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(child->kw), "list");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(child->kw), "list");
             return LY_EVALID;
         }
     }
@@ -2569,53 +3124,74 @@
     return LY_SUCCESS;
 }
 
-LY_ERR
-lysp_stmt_parse(struct lysc_ctx *ctx, const struct lysp_stmt *stmt, void **result, struct lysp_ext_instance **exts)
+/**
+ * @brief Parse generic statement structure into a specific parsed-schema structure.
+ *
+ * @param[in] pctx Parse context of the @p stmt being processed.
+ * @param[in] stmt Generic statement structure to process.
+ * @param[out] result Specific parsed-schema structure for the given statement. For the specific type for the particular statement, check the function code.
+ * @param[in,out] exts [sized array](@ref sizedarrays) For extension instances in case of statements that do not store extension instances in their own list.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lysp_stmt_parse(struct lysp_ctx *pctx, const struct lysp_stmt *stmt, void **result, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     uint16_t flags;
-    struct lysp_ctx pctx = {0};
-    struct ly_set pmods = {0};
-    void *objs;
-
-    /* local context */
-    pctx.format = LYS_IN_YANG;
-    pctx.parsed_mods = &pmods;
-    objs = &ctx->pmod;
-    pmods.objs = objs;
-    pmods.count = 1;
-
-    LOG_LOCSET(NULL, NULL, ctx->path, NULL);
 
     switch (stmt->kw) {
+    case LY_STMT_NOTIFICATION:
+        ret = lysp_stmt_notif(pctx, stmt, NULL, (struct lysp_node_notif **)result);
+        break;
+    case LY_STMT_INPUT:
+    case LY_STMT_OUTPUT: {
+        struct lysp_node_action_inout *inout;
+
+        *result = inout = calloc(1, sizeof *inout);
+        LY_CHECK_ERR_RET(!inout, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
+        ret = lysp_stmt_inout(pctx, stmt, NULL, inout);
+        break;
+    }
     case LY_STMT_ACTION:
     case LY_STMT_RPC:
-        ret = lysp_stmt_action(&pctx, stmt, NULL, (struct lysp_node_action **)result);
+        ret = lysp_stmt_action(pctx, stmt, NULL, (struct lysp_node_action **)result);
         break;
     case LY_STMT_ANYDATA:
     case LY_STMT_ANYXML:
-        ret = lysp_stmt_any(&pctx, stmt, NULL, (struct lysp_node **)result);
+        ret = lysp_stmt_any(pctx, stmt, NULL, (struct lysp_node **)result);
         break;
     case LY_STMT_AUGMENT:
-        ret = lysp_stmt_augment(&pctx, stmt, NULL, (struct lysp_node_augment **)result);
-        break;
-    case LY_STMT_BASE:
-        ret = lysp_stmt_text_fields(&pctx, stmt, (const char ***)result, Y_PREF_IDENTIF_ARG, exts);
-        break;
-    case LY_STMT_BIT:
-    case LY_STMT_ENUM:
-        ret = lysp_stmt_type_enum(&pctx, stmt, (struct lysp_type_enum **)result);
+        ret = lysp_stmt_augment(pctx, stmt, NULL, (struct lysp_node_augment **)result);
         break;
     case LY_STMT_CASE:
-        ret = lysp_stmt_case(&pctx, stmt, NULL, (struct lysp_node **)result);
+        ret = lysp_stmt_case(pctx, stmt, NULL, (struct lysp_node **)result);
         break;
     case LY_STMT_CHOICE:
-        ret = lysp_stmt_choice(&pctx, stmt, NULL, (struct lysp_node **)result);
+        ret = lysp_stmt_choice(pctx, stmt, NULL, (struct lysp_node **)result);
         break;
-    case LY_STMT_CONFIG:
-        assert(*result);
-        ret = lysp_stmt_config(&pctx, stmt, *(uint16_t **)result, exts);
+    case LY_STMT_CONTAINER:
+        ret = lysp_stmt_container(pctx, stmt, NULL, (struct lysp_node **)result);
         break;
+    case LY_STMT_GROUPING:
+        ret = lysp_stmt_grouping(pctx, stmt, NULL, (struct lysp_node_grp **)result);
+        break;
+    case LY_STMT_LEAF:
+        ret = lysp_stmt_leaf(pctx, stmt, NULL, (struct lysp_node **)result);
+        break;
+    case LY_STMT_LEAF_LIST:
+        ret = lysp_stmt_leaflist(pctx, stmt, NULL, (struct lysp_node **)result);
+        break;
+    case LY_STMT_LIST:
+        ret = lysp_stmt_list(pctx, stmt, NULL, (struct lysp_node **)result);
+        break;
+    case LY_STMT_USES:
+        ret = lysp_stmt_uses(pctx, stmt, NULL, (struct lysp_node **)result);
+        break;
+    case LY_STMT_BASE:
+        ret = lysp_stmt_text_fields(pctx, stmt, (const char ***)result, Y_PREF_IDENTIF_ARG, exts);
+        break;
+    case LY_STMT_ARGUMENT:
+    case LY_STMT_BELONGS_TO:
     case LY_STMT_CONTACT:
     case LY_STMT_DESCRIPTION:
     case LY_STMT_ERROR_APP_TAG:
@@ -2625,177 +3201,305 @@
     case LY_STMT_ORGANIZATION:
     case LY_STMT_PRESENCE:
     case LY_STMT_REFERENCE:
+    case LY_STMT_REVISION_DATE:
     case LY_STMT_UNITS:
-        ret = lysp_stmt_text_field(&pctx, stmt, 0, (const char **)result, Y_STR_ARG, exts);
+        ret = lysp_stmt_text_field(pctx, stmt, 0, (const char **)result, Y_STR_ARG, exts);
         break;
-    case LY_STMT_CONTAINER:
-        ret = lysp_stmt_container(&pctx, stmt, NULL, (struct lysp_node **)result);
+    case LY_STMT_BIT:
+    case LY_STMT_ENUM:
+        ret = lysp_stmt_type_enum(pctx, stmt, (struct lysp_type_enum **)result);
+        break;
+    case LY_STMT_CONFIG:
+        assert(*result);
+        ret = lysp_stmt_config(pctx, stmt, *(uint16_t **)result, exts);
         break;
     case LY_STMT_DEFAULT:
     case LY_STMT_IF_FEATURE:
     case LY_STMT_UNIQUE:
-        ret = lysp_stmt_qnames(&pctx, stmt, (struct lysp_qname **)result, Y_STR_ARG, exts);
+        ret = lysp_stmt_qnames(pctx, stmt, (struct lysp_qname **)result, Y_STR_ARG, exts);
+        break;
+    case LY_STMT_DEVIATE:
+        ret = lysp_stmt_deviate(pctx, stmt, (struct lysp_deviate **)result, exts);
+        break;
+    case LY_STMT_DEVIATION:
+        ret = lysp_stmt_deviation(pctx, stmt, (struct lysp_deviation **)result);
+        break;
+    case LY_STMT_EXTENSION:
+        ret = lysp_stmt_extension(pctx, stmt, (struct lysp_ext **)result);
         break;
     case LY_STMT_EXTENSION_INSTANCE:
-        ret = lysp_stmt_ext(&pctx, stmt, LY_STMT_EXTENSION_INSTANCE, 0, exts);
+        ret = lysp_stmt_ext(pctx, stmt, LY_STMT_EXTENSION_INSTANCE, 0, (struct lysp_ext_instance **)result);
+        break;
+    case LY_STMT_FEATURE:
+        ret = lysp_stmt_feature(pctx, stmt, (struct lysp_feature **)result);
         break;
     case LY_STMT_FRACTION_DIGITS:
-        ret = lysp_stmt_type_fracdigits(&pctx, stmt, *(uint8_t **)result, exts);
-        break;
-    case LY_STMT_GROUPING:
-        ret = lysp_stmt_grouping(&pctx, stmt, NULL, (struct lysp_node_grp **)result);
-        break;
-    case LY_STMT_INPUT:
-    case LY_STMT_OUTPUT: {
-        struct lysp_node_action_inout *inout;
-
-        *result = inout = calloc(1, sizeof *inout);
-        LY_CHECK_ERR_RET(!inout, LOGMEM(ctx->ctx), LY_EMEM);
-        ret = lysp_stmt_inout(&pctx, stmt, NULL, inout);
-        break;
-    }
-    case LY_STMT_LEAF:
-        ret = lysp_stmt_leaf(&pctx, stmt, NULL, (struct lysp_node **)result);
-        break;
-    case LY_STMT_LEAF_LIST:
-        ret = lysp_stmt_leaflist(&pctx, stmt, NULL, (struct lysp_node **)result);
+        ret = lysp_stmt_type_fracdigits(pctx, stmt, *(uint8_t **)result, exts);
         break;
     case LY_STMT_LENGTH:
-    case LY_STMT_MUST:
-    case LY_STMT_RANGE:
-        ret = lysp_stmt_restrs(&pctx, stmt, (struct lysp_restr **)result);
+    case LY_STMT_RANGE: {
+        struct lysp_restr *restr;
+
+        *result = restr = calloc(1, sizeof *restr);
+        LY_CHECK_ERR_RET(!restr, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
+
+        ret = lysp_stmt_restr(pctx, stmt, restr);
         break;
-    case LY_STMT_LIST:
-        ret = lysp_stmt_list(&pctx, stmt, NULL, (struct lysp_node **)result);
+    }
+    case LY_STMT_MUST:
+        ret = lysp_stmt_restrs(pctx, stmt, (struct lysp_restr **)result);
+        break;
+    case LY_STMT_IDENTITY:
+        ret = lysp_stmt_identity(pctx, stmt, (struct lysp_ident **)result);
+        break;
+    case LY_STMT_IMPORT:
+        ret = lysp_stmt_import(pctx, stmt, (struct lysp_import **)result);
+        break;
+    case LY_STMT_INCLUDE:
+        ret = lysp_stmt_include(pctx, stmt, (struct lysp_include **)result);
         break;
     case LY_STMT_MANDATORY:
-        ret = lysp_stmt_mandatory(&pctx, stmt, *(uint16_t **)result, exts);
+        ret = lysp_stmt_mandatory(pctx, stmt, *(uint16_t **)result, exts);
         break;
     case LY_STMT_MAX_ELEMENTS:
         flags = 0;
-        ret = lysp_stmt_maxelements(&pctx, stmt, *(uint32_t **)result, &flags, exts);
+        ret = lysp_stmt_maxelements(pctx, stmt, *(uint32_t **)result, &flags, exts);
         break;
     case LY_STMT_MIN_ELEMENTS:
         flags = 0;
-        ret = lysp_stmt_minelements(&pctx, stmt, *(uint32_t **)result, &flags, exts);
+        ret = lysp_stmt_minelements(pctx, stmt, *(uint32_t **)result, &flags, exts);
         break;
     case LY_STMT_MODIFIER:
-        ret = lysp_stmt_type_pattern_modifier(&pctx, stmt, (const char **)result, exts);
+        ret = lysp_stmt_type_pattern_modifier(pctx, stmt, (const char **)result, exts);
         break;
-    case LY_STMT_NOTIFICATION:
-        ret = lysp_stmt_notif(&pctx, stmt, NULL, (struct lysp_node_notif **)result);
+    case LY_STMT_MODULE: {
+        struct lysp_module *mod;
+
+        *result = mod = calloc(1, sizeof *mod);
+        LY_CHECK_ERR_RET(!mod, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
+        ret = lysp_stmt_module(pctx, stmt, mod);
         break;
+    }
     case LY_STMT_ORDERED_BY:
-        ret = lysp_stmt_orderedby(&pctx, stmt, *(uint16_t **)result, exts);
+        ret = lysp_stmt_orderedby(pctx, stmt, *(uint16_t **)result, exts);
         break;
     case LY_STMT_PATH: {
         const char *str_path = NULL;
 
-        LY_CHECK_RET(lysp_stmt_text_field(&pctx, stmt, 0, &str_path, Y_STR_ARG, exts));
-        ret = ly_path_parse(ctx->ctx, NULL, str_path, 0, 1, LY_PATH_BEGIN_EITHER,
+        LY_CHECK_RET(lysp_stmt_text_field(pctx, stmt, 0, &str_path, Y_STR_ARG, exts));
+        ret = ly_path_parse(PARSER_CTX(pctx), NULL, str_path, 0, 1, LY_PATH_BEGIN_EITHER,
                 LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, (struct lyxp_expr **)result);
-        lydict_remove(ctx->ctx, str_path);
+        lydict_remove(PARSER_CTX(pctx), str_path);
         break;
     }
     case LY_STMT_PATTERN:
-        ret = lysp_stmt_type_pattern(&pctx, stmt, (struct lysp_restr **)result);
+        ret = lysp_stmt_type_pattern(pctx, stmt, (struct lysp_restr **)result);
         break;
     case LY_STMT_POSITION:
     case LY_STMT_VALUE:
         flags = 0;
-        ret = lysp_stmt_type_enum_value_pos(&pctx, stmt, *(int64_t **)result, &flags, exts);
+        ret = lysp_stmt_type_enum_value_pos(pctx, stmt, *(int64_t **)result, &flags, exts);
         break;
     case LY_STMT_PREFIX:
-        ret = lysp_stmt_text_field(&pctx, stmt, 0, (const char **)result, Y_IDENTIF_ARG, exts);
+        ret = lysp_stmt_text_field(pctx, stmt, 0, (const char **)result, Y_IDENTIF_ARG, exts);
         break;
     case LY_STMT_REFINE:
-        ret = lysp_stmt_refine(&pctx, stmt, (struct lysp_refine **)result);
+        ret = lysp_stmt_refine(pctx, stmt, (struct lysp_refine **)result);
         break;
     case LY_STMT_REQUIRE_INSTANCE:
         flags = 0;
-        ret = lysp_stmt_type_reqinstance(&pctx, stmt, *(uint8_t **)result, &flags, exts);
+        ret = lysp_stmt_type_reqinstance(pctx, stmt, *(uint8_t **)result, &flags, exts);
+        break;
+    case LY_STMT_REVISION:
+        ret = lysp_stmt_revision(pctx, stmt, (struct lysp_revision **)result);
         break;
     case LY_STMT_STATUS:
-        ret = lysp_stmt_status(&pctx, stmt, *(uint16_t **)result, exts);
+        ret = lysp_stmt_status(pctx, stmt, (uint16_t *)result, exts);
         break;
+    case LY_STMT_SUBMODULE: {
+        struct lysp_submodule *submod;
+
+        *result = submod = calloc(1, sizeof *submod);
+        LY_CHECK_ERR_RET(!submod, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
+        ret = lysp_stmt_submodule(pctx, stmt, submod);
+        break;
+    }
     case LY_STMT_TYPE: {
         struct lysp_type *type;
 
         *result = type = calloc(1, sizeof *type);
-        LY_CHECK_ERR_RET(!type, LOGMEM(ctx->ctx), LY_EMEM);
-        ret = lysp_stmt_type(&pctx, stmt, type);
+        LY_CHECK_ERR_RET(!type, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
+        ret = lysp_stmt_type(pctx, stmt, type);
         break;
     }
     case LY_STMT_TYPEDEF:
-        ret = lysp_stmt_typedef(&pctx, stmt, NULL, (struct lysp_tpdf **)result);
-        break;
-    case LY_STMT_USES:
-        ret = lysp_stmt_uses(&pctx, stmt, NULL, (struct lysp_node **)result);
+        ret = lysp_stmt_typedef(pctx, stmt, NULL, (struct lysp_tpdf **)result);
         break;
     case LY_STMT_WHEN:
-        ret = lysp_stmt_when(&pctx, stmt, (struct lysp_when **)result);
+        ret = lysp_stmt_when(pctx, stmt, (struct lysp_when **)result);
+        break;
+    case LY_STMT_YANG_VERSION:
+        ret = lysp_stmt_yangver(pctx, stmt, *(uint8_t **)result, exts);
+        break;
+    case LY_STMT_YIN_ELEMENT:
+        ret = lysp_stmt_yinelem(pctx, stmt, *(uint16_t **)result, exts);
         break;
     default:
-        LOGINT(ctx->ctx);
+        LOGINT(PARSER_CTX(pctx));
         return LY_EINT;
     }
 
-    LOG_LOCBACK(0, 0, 1, 0);
     return ret;
 }
 
-void
-lys_parser_fill_filepath(struct ly_ctx *ctx, struct ly_in *in, const char **filepath)
+LY_ERR
+lys_parse_ext_instance_stmt(struct lysp_ctx *pctx, struct lysp_ext_substmt *substmt, struct lysp_stmt *stmt)
 {
-    char path[PATH_MAX];
+    LY_ERR rc = LY_SUCCESS;
 
-#ifndef __APPLE__
-    char proc_path[32];
-    int len;
-#endif
-
-    LY_CHECK_ARG_RET(NULL, ctx, in, filepath, );
-    if (*filepath) {
-        /* filepath already set */
-        return;
+    if (!substmt->storage) {
+        /* nothing to parse, ignored */
+        goto cleanup;
     }
 
-    switch (in->type) {
-    case LY_IN_FILEPATH:
-        if (realpath(in->method.fpath.filepath, path) != NULL) {
-            lydict_insert(ctx, path, 0, filepath);
-        } else {
-            lydict_insert(ctx, in->method.fpath.filepath, 0, filepath);
+    switch (stmt->kw) {
+    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_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_USES: {
+        struct lysp_node **pnodes_p, *pnode = NULL;
+
+        /* parse the node */
+        LY_CHECK_GOTO(rc = lysp_stmt_parse(pctx, stmt, (void **)&pnode, NULL), cleanup);
+
+        /* usually is a linked-list of all the parsed schema nodes */
+        pnodes_p = substmt->storage;
+        while (*pnodes_p) {
+            pnodes_p = &(*pnodes_p)->next;
         }
+        *pnodes_p = pnode;
 
         break;
-    case LY_IN_FD:
-#ifdef __APPLE__
-        if (fcntl(in->method.fd, F_GETPATH, path) != -1) {
-            lydict_insert(ctx, path, 0, filepath);
-        }
-#elif defined _WIN32
-        HANDLE h = _get_osfhandle(in->method.fd);
-        FILE_NAME_INFO info;
-        if (GetFileInformationByHandleEx(h, FileNameInfo, &info, sizeof info)) {
-            char *buf = calloc(info.FileNameLength + 1 /* trailing NULL */, MB_CUR_MAX);
-            len = wcstombs(buf, info.FileName, info.FileNameLength * MB_CUR_MAX);
-            lydict_insert(ctx, buf, len, filepath);
-        }
-#else
-        /* get URI if there is /proc */
-        sprintf(proc_path, "/proc/self/fd/%d", in->method.fd);
-        if ((len = readlink(proc_path, path, PATH_MAX - 1)) > 0) {
-            lydict_insert(ctx, path, len, filepath);
-        }
-#endif
+    }
+    case LY_STMT_BASE:
+    case LY_STMT_BIT:
+    case LY_STMT_DEFAULT:
+    case LY_STMT_DEVIATE:
+    case LY_STMT_DEVIATION:
+    case LY_STMT_ENUM:
+    case LY_STMT_EXTENSION:
+    case LY_STMT_EXTENSION_INSTANCE:
+    case LY_STMT_FEATURE:
+    case LY_STMT_IDENTITY:
+    case LY_STMT_IF_FEATURE:
+    case LY_STMT_IMPORT:
+    case LY_STMT_INCLUDE:
+    case LY_STMT_MUST:
+    case LY_STMT_PATTERN:
+    case LY_STMT_REFINE:
+    case LY_STMT_REVISION:
+    case LY_STMT_TYPEDEF:
+    case LY_STMT_UNIQUE:
+        /* parse, sized array */
+        LY_CHECK_GOTO(rc = lysp_stmt_parse(pctx, stmt, substmt->storage, NULL), cleanup);
         break;
-    case LY_IN_MEMORY:
-    case LY_IN_FILE:
-        /* nothing to do */
+
+    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_FRACTION_DIGITS:
+    case LY_STMT_KEY:
+    case LY_STMT_LENGTH:
+    case LY_STMT_MANDATORY:
+    case LY_STMT_MAX_ELEMENTS:
+    case LY_STMT_MIN_ELEMENTS:
+    case LY_STMT_MODIFIER:
+    case LY_STMT_MODULE:
+    case LY_STMT_NAMESPACE:
+    case LY_STMT_ORGANIZATION:
+    case LY_STMT_PATH:
+    case LY_STMT_POSITION:
+    case LY_STMT_PREFIX:
+    case LY_STMT_PRESENCE:
+    case LY_STMT_RANGE:
+    case LY_STMT_REFERENCE:
+    case LY_STMT_REQUIRE_INSTANCE:
+    case LY_STMT_REVISION_DATE:
+    case LY_STMT_SUBMODULE:
+    case LY_STMT_TYPE:
+    case LY_STMT_UNITS:
+    case LY_STMT_VALUE:
+    case LY_STMT_WHEN:
+    case LY_STMT_YANG_VERSION:
+    case LY_STMT_YIN_ELEMENT:
+        /* single item */
+        if (*(void **)substmt->storage) {
+            LOGVAL(PARSER_CTX(pctx), LY_VCODE_DUPSTMT, stmt->stmt);
+            rc = LY_EVALID;
+            goto cleanup;
+        }
+
+        /* parse */
+        LY_CHECK_GOTO(rc = lysp_stmt_parse(pctx, stmt, substmt->storage, NULL), cleanup);
         break;
+
+    case LY_STMT_CONFIG:
+        /* single item */
+        if ((*(uint16_t *)substmt->storage) & LYS_CONFIG_MASK) {
+            LOGVAL(PARSER_CTX(pctx), LY_VCODE_DUPSTMT, stmt->stmt);
+            rc = LY_EVALID;
+            goto cleanup;
+        }
+
+        /* parse */
+        LY_CHECK_GOTO(rc = lysp_stmt_parse(pctx, stmt, substmt->storage, NULL), cleanup);
+        break;
+
+    case LY_STMT_ORDERED_BY:
+        /* single item */
+        if ((*(uint16_t *)substmt->storage) & LYS_ORDBY_MASK) {
+            LOGVAL(PARSER_CTX(pctx), LY_VCODE_DUPSTMT, stmt->stmt);
+            rc = LY_EVALID;
+            goto cleanup;
+        }
+
+        /* parse */
+        LY_CHECK_GOTO(rc = lysp_stmt_parse(pctx, stmt, substmt->storage, NULL), cleanup);
+        break;
+
+    case LY_STMT_STATUS:
+        /* single item */
+        if ((*(uint16_t *)substmt->storage) & LYS_STATUS_MASK) {
+            LOGVAL(PARSER_CTX(pctx), LY_VCODE_DUPSTMT, stmt->stmt);
+            rc = LY_EVALID;
+            goto cleanup;
+        }
+
+        /* parse */
+        LY_CHECK_GOTO(rc = lysp_stmt_parse(pctx, stmt, substmt->storage, NULL), cleanup);
+        break;
+
     default:
-        LOGINT(ctx);
-        break;
+        LOGINT(PARSER_CTX(pctx));
+        rc = LY_EINT;
+        goto cleanup;
     }
+
+cleanup:
+    return rc;
 }
diff --git a/src/parser_internal.h b/src/parser_internal.h
index 09410a0..4863145 100644
--- a/src/parser_internal.h
+++ b/src/parser_internal.h
@@ -20,6 +20,8 @@
 
 struct lyd_ctx;
 struct ly_in;
+struct lysp_ext_substmt;
+struct lysp_stmt;
 struct lysp_yang_ctx;
 struct lysp_yin_ctx;
 struct lysp_ctx;
@@ -358,4 +360,14 @@
 LY_ERR lyd_parse_set_data_flags(struct lyd_node *node, struct lyd_meta **meta, struct lyd_ctx *lydctx,
         struct lysc_ext_instance *ext);
 
+/**
+ * @brief Parse an instance extension statement.
+ *
+ * @param[in] pctx Parse context.
+ * @param[in] substmt Parsed ext instance substatement info.
+ * @param[in] stmt Parsed generic statement to process.
+ * @return LY_ERR value.
+ */
+LY_ERR lys_parse_ext_instance_stmt(struct lysp_ctx *pctx, struct lysp_ext_substmt *substmt, struct lysp_stmt *stmt);
+
 #endif /* LY_PARSER_INTERNAL_H_ */
diff --git a/src/parser_json.c b/src/parser_json.c
index 3badd6c..2565c12 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -926,7 +926,7 @@
     if (*node_p) {
         /* insert, keep first pointer correct */
         if (ext) {
-            lyd_insert_ext(parent, *node_p);
+            lyplg_ext_insert(parent, *node_p);
         } else {
             lyd_insert_node(parent, first_p, *node_p, last);
         }
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index cacda64..3daed88 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -915,7 +915,7 @@
 {
     /* insert, keep first pointer correct */
     if (parent && (LYD_CTX(parent) != LYD_CTX(node))) {
-        lyd_insert_ext(parent, node);
+        lyplg_ext_insert(parent, node);
     } else {
         lyd_insert_node(parent, first_p, node, lybctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
     }
diff --git a/src/parser_xml.c b/src/parser_xml.c
index a1fd82c..ff91715 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -868,7 +868,7 @@
     if (insert_anchor) {
         lyd_insert_after(insert_anchor, node);
     } else if (ext) {
-        LY_CHECK_GOTO(ret = lyd_insert_ext(parent, node), error);
+        LY_CHECK_GOTO(ret = lyplg_ext_insert(parent, node), error);
     } else {
         lyd_insert_node(parent, first_p, node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
     }
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 5db623d..cde230a 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -76,7 +76,7 @@
     if (KW == LY_STMT_SYNTAX_SEMICOLON) { \
         __loop_end = 1; \
     } else if (KW != LY_STMT_SYNTAX_LEFT_BRACE) { \
-        LOGVAL_PARSER(CTX, LYVE_SYNTAX_YANG, "Invalid keyword \"%s\", expected \";\" or \"{\".", ly_stmt2str(KW)); \
+        LOGVAL_PARSER(CTX, LYVE_SYNTAX_YANG, "Invalid keyword \"%s\", expected \";\" or \"{\".", lyplg_ext_stmt2str(KW)); \
         RET = LY_EVALID; \
         goto ERR_LABEL; \
     } else { \
@@ -707,7 +707,6 @@
  * @param[out] kw YANG keyword read.
  * @param[out] word_p Pointer to the keyword in the data. Useful for extension instances.
  * @param[out] word_len Length of the keyword in the data. Useful for extension instances.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -867,7 +866,6 @@
  * @param[in] word Extension instance substatement name (keyword).
  * @param[in] word_len Extension instance substatement name length.
  * @param[in,out] child Children of this extension instance to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -918,15 +916,15 @@
  * @param[in] ctx yang parser context for logging.
  * @param[in] ext_name Extension instance substatement name (keyword).
  * @param[in] ext_name_len Extension instance substatement name length.
- * @param[in] insubstmt The statement this extension instance is a substatement of.
- * @param[in] insubstmt_index Index of the keyword instance this extension instance is a substatement of.
+ * @param[in] parent Current statement parent.
+ * @param[in] parent_stmt Type of @p parent statement.
+ * @param[in] parent_stmt_index In case of several @p parent_stmt, index of the relevant @p parent statement.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_ext(struct lysp_yang_ctx *ctx, const char *ext_name, size_t ext_name_len, enum ly_stmt insubstmt,
-        LY_ARRAY_COUNT_TYPE insubstmt_index, struct lysp_ext_instance **exts)
+parse_ext(struct lysp_yang_ctx *ctx, const char *ext_name, size_t ext_name_len, const void *parent,
+        enum ly_stmt parent_stmt, LY_ARRAY_COUNT_TYPE parent_stmt_index, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -954,8 +952,9 @@
     e->format = LY_VALUE_SCHEMA;
     e->parsed = NULL;
     e->prefix_data = PARSER_CUR_PMOD(ctx);
-    e->parent_stmt = insubstmt;
-    e->parent_stmt_index = insubstmt_index;
+    e->parent = (void *)parent;
+    e->parent_stmt = parent_stmt;
+    e->parent_stmt_index = parent_stmt_index;
 
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         LY_CHECK_GOTO(ret = parse_ext_substmt(ctx, kw, word, word_len, &e->child), cleanup)
@@ -971,16 +970,16 @@
  * description, etc...
  *
  * @param[in] ctx yang parser context for logging.
- * @param[in] substmt Type of this substatement.
- * @param[in] substmt_index Index of this substatement.
+ * @param[in] parent Current statement parent.
+ * @param[in] parent_stmt Type of statement in @p value.
+ * @param[in] parent_stmt_index In case of several @p parent_stmt, index of the relevant @p parent statement.
  * @param[in,out] value Place to store the parsed value.
  * @param[in] arg Type of the YANG keyword argument (of the value).
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_text_field(struct lysp_yang_ctx *ctx, enum ly_stmt substmt, uint32_t substmt_index,
+parse_text_field(struct lysp_yang_ctx *ctx, const void *parent, enum ly_stmt parent_stmt, uint32_t parent_stmt_index,
         const char **value, enum yang_arg arg, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -989,7 +988,7 @@
     enum ly_stmt kw;
 
     if (*value) {
-        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(substmt));
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, lyplg_ext_stmt2str(parent_stmt));
         return LY_EVALID;
     }
 
@@ -1002,10 +1001,10 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, substmt, substmt_index, exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, parent, parent_stmt, parent_stmt_index, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(substmt));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), lyplg_ext_stmt2str(parent_stmt));
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
@@ -1019,20 +1018,18 @@
  * @brief Parse the yang-version statement.
  *
  * @param[in] ctx yang parser context for logging.
- * @param[out] version Storage for the parsed information.
- * @param[in,out] exts Extension instances to add to.
- *
+ * @param[in,out] mod Module to fill.
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_yangversion(struct lysp_yang_ctx *ctx, uint8_t *version, struct lysp_ext_instance **exts)
+parse_yangversion(struct lysp_yang_ctx *ctx, struct lysp_module *mod)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
     size_t word_len;
     enum ly_stmt kw;
 
-    if (*version) {
+    if (mod->version) {
         LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "yang-version");
         return LY_EVALID;
     }
@@ -1041,9 +1038,9 @@
     LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
 
     if ((word_len == 1) && !strncmp(word, "1", word_len)) {
-        *version = LYS_VERSION_1_0;
+        mod->version = LYS_VERSION_1_0;
     } else if ((word_len == ly_strlen_const("1.1")) && !strncmp(word, "1.1", word_len)) {
-        *version = LYS_VERSION_1_1;
+        mod->version = LYS_VERSION_1_1;
     } else {
         LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "yang-version");
         free(buf);
@@ -1054,10 +1051,10 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_YANG_VERSION, 0, exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, mod, LY_STMT_YANG_VERSION, 0, &mod->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yang-version");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "yang-version");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
@@ -1071,20 +1068,18 @@
  * @brief Parse the belongs-to statement.
  *
  * @param[in] ctx yang parser context for logging.
- * @param[in,out] prefix Place to store the parsed belongs-to prefix value.
- * @param[in,out] exts Extension instances to add to.
- *
+ * @param[in,out] submod Submodule to fill.
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_belongsto(struct lysp_yang_ctx *ctx, const char **prefix, struct lysp_ext_instance **exts)
+parse_belongsto(struct lysp_yang_ctx *ctx, struct lysp_submodule *submod)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
     size_t word_len;
     enum ly_stmt kw;
 
-    if (*prefix) {
+    if (submod->prefix) {
         LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "belongs-to");
         return LY_EVALID;
     }
@@ -1102,20 +1097,20 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_PREFIX:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_PREFIX, 0, prefix, Y_IDENTIF_ARG, exts));
+            LY_CHECK_RET(parse_text_field(ctx, submod->prefix, LY_STMT_PREFIX, 0, &submod->prefix, Y_IDENTIF_ARG, &submod->exts));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_BELONGS_TO, 0, exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, submod, LY_STMT_BELONGS_TO, 0, &submod->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "belongs-to");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "belongs-to");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
 
     /* mandatory substatements */
-    if (!*prefix) {
+    if (!submod->prefix) {
         LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "prefix", "belongs-to");
         return LY_EVALID;
     }
@@ -1128,9 +1123,8 @@
  * @brief Parse the revision-date statement.
  *
  * @param[in] ctx yang parser context for logging.
- * @param[in,out] rev Array to store the parsed value in.
+ * @param[in,out] rev Buffer to store the parsed value in.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1162,10 +1156,10 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_REVISION_DATE, 0, exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, rev, LY_STMT_REVISION_DATE, 0, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision-date");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "revision-date");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
@@ -1181,7 +1175,6 @@
  * @param[in] ctx yang parser context for logging.
  * @param[in] module_name Name of the module to check name collisions.
  * @param[in,out] includes Parsed includes to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1211,20 +1204,20 @@
         switch (kw) {
         case LY_STMT_DESCRIPTION:
             PARSER_CHECK_STMTVER2_RET(ctx, "description", "include");
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &inc->dsc, Y_STR_ARG, &inc->exts));
+            LY_CHECK_RET(parse_text_field(ctx, inc->dsc, LY_STMT_DESCRIPTION, 0, &inc->dsc, Y_STR_ARG, &inc->exts));
             break;
         case LY_STMT_REFERENCE:
             PARSER_CHECK_STMTVER2_RET(ctx, "reference", "include");
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &inc->ref, Y_STR_ARG, &inc->exts));
+            LY_CHECK_RET(parse_text_field(ctx, inc->ref, LY_STMT_REFERENCE, 0, &inc->ref, Y_STR_ARG, &inc->exts));
             break;
         case LY_STMT_REVISION_DATE:
             LY_CHECK_RET(parse_revisiondate(ctx, inc->rev, &inc->exts));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_INCLUDE, 0, &inc->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, inc, LY_STMT_INCLUDE, 0, &inc->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "include");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "include");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, inc->exts, ret, cleanup);
@@ -1240,7 +1233,6 @@
  * @param[in] ctx yang parser context for logging.
  * @param[in] module_prefix Prefix of the module to check prefix collisions.
  * @param[in,out] imports Parsed imports to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1261,25 +1253,25 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_PREFIX:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_PREFIX, 0, &imp->prefix, Y_IDENTIF_ARG, &imp->exts));
+            LY_CHECK_RET(parse_text_field(ctx, imp->prefix, LY_STMT_PREFIX, 0, &imp->prefix, Y_IDENTIF_ARG, &imp->exts));
             LY_CHECK_RET(lysp_check_prefix((struct lysp_ctx *)ctx, *imports, module_prefix, &imp->prefix), LY_EVALID);
             break;
         case LY_STMT_DESCRIPTION:
             PARSER_CHECK_STMTVER2_RET(ctx, "description", "import");
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &imp->dsc, Y_STR_ARG, &imp->exts));
+            LY_CHECK_RET(parse_text_field(ctx, imp->dsc, LY_STMT_DESCRIPTION, 0, &imp->dsc, Y_STR_ARG, &imp->exts));
             break;
         case LY_STMT_REFERENCE:
             PARSER_CHECK_STMTVER2_RET(ctx, "reference", "import");
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &imp->ref, Y_STR_ARG, &imp->exts));
+            LY_CHECK_RET(parse_text_field(ctx, imp->ref, LY_STMT_REFERENCE, 0, &imp->ref, Y_STR_ARG, &imp->exts));
             break;
         case LY_STMT_REVISION_DATE:
             LY_CHECK_RET(parse_revisiondate(ctx, imp->rev, &imp->exts));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_IMPORT, 0, &imp->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, imp, LY_STMT_IMPORT, 0, &imp->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "import");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "import");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, imp->exts, ret, cleanup);
@@ -1297,7 +1289,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] revs Parsed revisions to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1326,16 +1317,16 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &rev->dsc, Y_STR_ARG, &rev->exts));
+            LY_CHECK_RET(parse_text_field(ctx, rev->dsc, LY_STMT_DESCRIPTION, 0, &rev->dsc, Y_STR_ARG, &rev->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &rev->ref, Y_STR_ARG, &rev->exts));
+            LY_CHECK_RET(parse_text_field(ctx, rev->ref, LY_STMT_REFERENCE, 0, &rev->ref, Y_STR_ARG, &rev->exts));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_REVISION, 0, &rev->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, rev, LY_STMT_REVISION, 0, &rev->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "revision");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, rev->exts, ret, cleanup);
@@ -1349,15 +1340,15 @@
  * @brief Parse a generic text field that can have more instances such as base.
  *
  * @param[in] ctx yang parser context for logging.
- * @param[in] substmt Type of this substatement.
+ * @param[in] parent Current statement parent.
+ * @param[in] parent_stmt Type of @p parent statement.
  * @param[in,out] texts Parsed values to add to.
  * @param[in] arg Type of the expected argument.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_text_fields(struct lysp_yang_ctx *ctx, enum ly_stmt substmt, const char ***texts, enum yang_arg arg,
+parse_text_fields(struct lysp_yang_ctx *ctx, enum ly_stmt parent_stmt, const char ***texts, enum yang_arg arg,
         struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -1376,10 +1367,10 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, substmt, LY_ARRAY_COUNT(*texts) - 1, exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, *texts, parent_stmt, LY_ARRAY_COUNT(*texts) - 1, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(substmt));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), lyplg_ext_stmt2str(parent_stmt));
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
@@ -1393,16 +1384,15 @@
  * @brief Parse a generic text field that can have more instances such as base.
  *
  * @param[in] ctx yang parser context for logging.
- * @param[in] substmt Type of this substatement.
+ * @param[in] parent_stmt Type of statement stored in @p qnames.
  * @param[in,out] qnames Parsed qnames to add to.
  * @param[in] arg Type of the expected argument.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_qnames(struct lysp_yang_ctx *ctx, enum ly_stmt substmt, struct lysp_qname **qnames,
-        enum yang_arg arg, struct lysp_ext_instance **exts)
+parse_qnames(struct lysp_yang_ctx *ctx, enum ly_stmt parent_stmt, struct lysp_qname **qnames, enum yang_arg arg,
+        struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1421,10 +1411,10 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, substmt, LY_ARRAY_COUNT(*qnames) - 1, exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, *qnames, parent_stmt, LY_ARRAY_COUNT(*qnames) - 1, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(substmt));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), lyplg_ext_stmt2str(parent_stmt));
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
@@ -1440,7 +1430,6 @@
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] flags Flags to add to.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1473,10 +1462,10 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_CONFIG, 0, exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, flags, LY_STMT_CONFIG, 0, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "config");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "config");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
@@ -1492,7 +1481,6 @@
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] flags Flags to add to.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1525,10 +1513,10 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_MANDATORY, 0, exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, flags, LY_STMT_MANDATORY, 0, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "mandatory");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "mandatory");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
@@ -1544,7 +1532,6 @@
  * @param[in] ctx yang parser context for logging.
  * @param[in] restr_kw Type of this particular restriction.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1558,28 +1545,29 @@
     /* get value */
     LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
 
-    CHECK_NONEMPTY(ctx, word_len, ly_stmt2str(restr_kw));
+    CHECK_NONEMPTY(ctx, word_len, lyplg_ext_stmt2str(restr_kw));
     INSERT_WORD_GOTO(ctx, buf, restr->arg.str, word, word_len, ret, cleanup);
     restr->arg.mod = PARSER_CUR_PMOD(ctx);
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts));
+            LY_CHECK_RET(parse_text_field(ctx, restr->dsc, LY_STMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts));
+            LY_CHECK_RET(parse_text_field(ctx, restr->ref, LY_STMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts));
             break;
         case LY_STMT_ERROR_APP_TAG:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_ERROR_APP_TAG, 0, &restr->eapptag, Y_STR_ARG, &restr->exts));
+            LY_CHECK_RET(parse_text_field(ctx, restr, LY_STMT_ERROR_APP_TAG, 0, &restr->eapptag, Y_STR_ARG,
+                    &restr->exts));
             break;
         case LY_STMT_ERROR_MESSAGE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_ERROR_MESSAGE, 0, &restr->emsg, Y_STR_ARG, &restr->exts));
+            LY_CHECK_RET(parse_text_field(ctx, restr, LY_STMT_ERROR_MESSAGE, 0, &restr->emsg, Y_STR_ARG, &restr->exts));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, restr_kw, 0, &restr->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, restr, restr_kw, 0, &restr->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(restr_kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), lyplg_ext_stmt2str(restr_kw));
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, restr->exts, ret, cleanup);
@@ -1595,7 +1583,6 @@
  * @param[in] ctx yang parser context for logging.
  * @param[in] restr_kw Type of this particular restriction.
  * @param[in,out] restrs Restrictions to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1613,7 +1600,6 @@
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] flags Flags to add to.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1648,10 +1634,10 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_STATUS, 0, exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, flags, LY_STMT_STATUS, 0, exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "status");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "status");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
@@ -1666,7 +1652,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] when_p When pointer to parse to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -1695,16 +1680,18 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_GOTO(ret = parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &when->dsc, Y_STR_ARG, &when->exts), cleanup);
+            LY_CHECK_GOTO(ret = parse_text_field(ctx, when->dsc, LY_STMT_DESCRIPTION, 0, &when->dsc, Y_STR_ARG, &when->exts),
+                    cleanup);
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_GOTO(ret = parse_text_field(ctx, LY_STMT_REFERENCE, 0, &when->ref, Y_STR_ARG, &when->exts), cleanup);
+            LY_CHECK_GOTO(ret = parse_text_field(ctx, when->ref, LY_STMT_REFERENCE, 0, &when->ref, Y_STR_ARG, &when->exts),
+                    cleanup);
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, LY_STMT_WHEN, 0, &when->exts), cleanup);
+            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, *when_p, LY_STMT_WHEN, 0, &when->exts), cleanup);
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "when");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "when");
             ret = LY_EVALID;
             goto cleanup;
         }
@@ -1726,8 +1713,8 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in] any_kw Type of this particular keyword.
+ * @param[in] parent Node parent.
  * @param[in,out] siblings Siblings to add to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -1756,7 +1743,7 @@
             LY_CHECK_RET(parse_config(ctx, &any->flags, &any->exts));
             break;
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &any->dsc, Y_STR_ARG, &any->exts));
+            LY_CHECK_RET(parse_text_field(ctx, any->dsc, LY_STMT_DESCRIPTION, 0, &any->dsc, Y_STR_ARG, &any->exts));
             break;
         case LY_STMT_IF_FEATURE:
             LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &any->iffeatures, Y_STR_ARG, &any->exts));
@@ -1768,7 +1755,7 @@
             LY_CHECK_RET(parse_restrs(ctx, kw, &any->musts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &any->ref, Y_STR_ARG, &any->exts));
+            LY_CHECK_RET(parse_text_field(ctx, any->ref, LY_STMT_REFERENCE, 0, &any->ref, Y_STR_ARG, &any->exts));
             break;
         case LY_STMT_STATUS:
             LY_CHECK_RET(parse_status(ctx, &any->flags, &any->exts));
@@ -1777,10 +1764,10 @@
             LY_CHECK_RET(parse_when(ctx, &any->when));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, any_kw, 0, &any->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, any, any_kw, 0, &any->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(any_kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), lyplg_ext_stmt2str(any_kw));
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, any->exts, ret, cleanup);
@@ -1795,15 +1782,11 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in] val_kw Type of this particular keyword.
- * @param[in,out] value Value to write to.
- * @param[in,out] flags Flags to write to.
- * @param[in,out] exts Extension instances to add to.
- *
+ * @param[in,out] enm Structure to fill.
  * @return LY_ERR values.
  */
 LY_ERR
-parse_type_enum_value_pos(struct lysp_yang_ctx *ctx, enum ly_stmt val_kw, int64_t *value, uint16_t *flags,
-        struct lysp_ext_instance **exts)
+parse_type_enum_value_pos(struct lysp_yang_ctx *ctx, enum ly_stmt val_kw, struct lysp_type_enum *enm)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf = NULL, *word, *ptr;
@@ -1812,18 +1795,18 @@
     unsigned long long int unum = 0;
     enum ly_stmt kw;
 
-    if (*flags & LYS_SET_VALUE) {
-        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(val_kw));
+    if (enm->flags & LYS_SET_VALUE) {
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, lyplg_ext_stmt2str(val_kw));
         ret = LY_EVALID;
         goto cleanup;
     }
-    *flags |= LYS_SET_VALUE;
+    enm->flags |= LYS_SET_VALUE;
 
     /* get value */
     LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
 
     if (!word_len || (word[0] == '+') || ((word[0] == '0') && (word_len > 1)) || ((val_kw == LY_STMT_POSITION) && !strncmp(word, "-0", 2))) {
-        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, lyplg_ext_stmt2str(val_kw));
         ret = LY_EVALID;
         goto cleanup;
     }
@@ -1832,43 +1815,43 @@
     if (val_kw == LY_STMT_VALUE) {
         num = strtoll(word, &ptr, LY_BASE_DEC);
         if ((num < INT64_C(-2147483648)) || (num > INT64_C(2147483647))) {
-            LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, lyplg_ext_stmt2str(val_kw));
             ret = LY_EVALID;
             goto cleanup;
         }
     } else {
         unum = strtoull(word, &ptr, LY_BASE_DEC);
         if (unum > UINT64_C(4294967295)) {
-            LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, lyplg_ext_stmt2str(val_kw));
             ret = LY_EVALID;
             goto cleanup;
         }
     }
     /* we have not parsed the whole argument */
     if ((size_t)(ptr - word) != word_len) {
-        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, lyplg_ext_stmt2str(val_kw));
         ret = LY_EVALID;
         goto cleanup;
     }
     if (errno == ERANGE) {
-        LOGVAL_PARSER(ctx, LY_VCODE_OOB, word_len, word, ly_stmt2str(val_kw));
+        LOGVAL_PARSER(ctx, LY_VCODE_OOB, word_len, word, lyplg_ext_stmt2str(val_kw));
         ret = LY_EVALID;
         goto cleanup;
     }
     if (val_kw == LY_STMT_VALUE) {
-        *value = num;
+        enm->value = num;
     } else {
-        *value = unum;
+        enm->value = unum;
     }
 
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            ret = parse_ext(ctx, word, word_len, val_kw == LY_STMT_VALUE ? LY_STMT_VALUE : LY_STMT_POSITION, 0, exts);
+            ret = parse_ext(ctx, word, word_len, enm, val_kw, 0, &enm->exts);
             LY_CHECK_GOTO(ret, cleanup);
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(val_kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), lyplg_ext_stmt2str(val_kw));
             ret = LY_EVALID;
             goto cleanup;
         }
@@ -1886,7 +1869,6 @@
  * @param[in] ctx yang parser context for logging.
  * @param[in] enum_kw Type of this particular keyword.
  * @param[in,out] enums Enums or bits to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1908,38 +1890,38 @@
     } /* else nothing specific for YANG_BIT */
 
     INSERT_WORD_GOTO(ctx, buf, enm->name, word, word_len, ret, cleanup);
-    CHECK_UNIQUENESS(ctx, *enums, name, ly_stmt2str(enum_kw), enm->name);
+    CHECK_UNIQUENESS(ctx, *enums, name, lyplg_ext_stmt2str(enum_kw), enm->name);
 
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &enm->dsc, Y_STR_ARG, &enm->exts));
+            LY_CHECK_RET(parse_text_field(ctx, enm->dsc, LY_STMT_DESCRIPTION, 0, &enm->dsc, Y_STR_ARG, &enm->exts));
             break;
         case LY_STMT_IF_FEATURE:
-            PARSER_CHECK_STMTVER2_RET(ctx, "if-feature", ly_stmt2str(enum_kw));
+            PARSER_CHECK_STMTVER2_RET(ctx, "if-feature", lyplg_ext_stmt2str(enum_kw));
             LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &enm->iffeatures, Y_STR_ARG, &enm->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &enm->ref, Y_STR_ARG, &enm->exts));
+            LY_CHECK_RET(parse_text_field(ctx, enm->ref, LY_STMT_REFERENCE, 0, &enm->ref, Y_STR_ARG, &enm->exts));
             break;
         case LY_STMT_STATUS:
             LY_CHECK_RET(parse_status(ctx, &enm->flags, &enm->exts));
             break;
         case LY_STMT_VALUE:
-            LY_CHECK_ERR_RET(enum_kw == LY_STMT_BIT, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
-                    ly_stmt2str(enum_kw)), LY_EVALID);
-            LY_CHECK_RET(parse_type_enum_value_pos(ctx, kw, &enm->value, &enm->flags, &enm->exts));
+            LY_CHECK_ERR_RET(enum_kw == LY_STMT_BIT, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw),
+                    lyplg_ext_stmt2str(enum_kw)), LY_EVALID);
+            LY_CHECK_RET(parse_type_enum_value_pos(ctx, kw, enm));
             break;
         case LY_STMT_POSITION:
-            LY_CHECK_ERR_RET(enum_kw == LY_STMT_ENUM, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
-                    ly_stmt2str(enum_kw)), LY_EVALID);
-            LY_CHECK_RET(parse_type_enum_value_pos(ctx, kw, &enm->value, &enm->flags, &enm->exts));
+            LY_CHECK_ERR_RET(enum_kw == LY_STMT_ENUM, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw),
+                    lyplg_ext_stmt2str(enum_kw)), LY_EVALID);
+            LY_CHECK_RET(parse_type_enum_value_pos(ctx, kw, enm));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, enum_kw, 0, &enm->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, enm, enum_kw, 0, &enm->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(enum_kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), lyplg_ext_stmt2str(enum_kw));
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, enm->exts, ret, cleanup);
@@ -1953,13 +1935,11 @@
  * @brief Parse the fraction-digits statement. Substatement of type statement.
  *
  * @param[in] ctx yang parser context for logging.
- * @param[in,out] fracdig Value to write to.
- * @param[in,out] exts Extension instances to add to.
- *
+ * @param[in,out] type Type to fill.
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_type_fracdigits(struct lysp_yang_ctx *ctx, uint8_t *fracdig, struct lysp_ext_instance **exts)
+parse_type_fracdigits(struct lysp_yang_ctx *ctx, struct lysp_type *type)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf = NULL, *word, *ptr;
@@ -1967,7 +1947,7 @@
     unsigned long long int num;
     enum ly_stmt kw;
 
-    if (*fracdig) {
+    if (type->fraction_digits) {
         LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "fraction-digits");
         return LY_EVALID;
     }
@@ -1994,15 +1974,15 @@
         ret = LY_EVALID;
         goto cleanup;
     }
-    *fracdig = num;
+    type->fraction_digits = num;
 
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, LY_STMT_FRACTION_DIGITS, 0, exts), cleanup);
+            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, type, LY_STMT_FRACTION_DIGITS, 0, &type->exts), cleanup);
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "fraction-digits");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "fraction-digits");
             ret = LY_EVALID;
             goto cleanup;
         }
@@ -2018,32 +1998,28 @@
  * @brief Parse the require-instance statement. Substatement of type statement.
  *
  * @param[in] ctx yang parser context for logging.
- * @param[in,out] reqinst Value to write to.
- * @param[in,out] flags Flags to write to.
- * @param[in,out] exts Extension instances to add to.
- *
+ * @param[in,out] type Type to fill.
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_type_reqinstance(struct lysp_yang_ctx *ctx, uint8_t *reqinst, uint16_t *flags,
-        struct lysp_ext_instance **exts)
+parse_type_reqinstance(struct lysp_yang_ctx *ctx, struct lysp_type *type)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf = NULL, *word;
     size_t word_len;
     enum ly_stmt kw;
 
-    if (*flags & LYS_SET_REQINST) {
+    if (type->flags & LYS_SET_REQINST) {
         LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "require-instance");
         return LY_EVALID;
     }
-    *flags |= LYS_SET_REQINST;
+    type->flags |= LYS_SET_REQINST;
 
     /* get value */
     LY_CHECK_GOTO(ret = get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len), cleanup);
 
     if ((word_len == ly_strlen_const("true")) && !strncmp(word, "true", word_len)) {
-        *reqinst = 1;
+        type->require_instance = 1;
     } else if ((word_len != ly_strlen_const("false")) || strncmp(word, "false", word_len)) {
         LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "require-instance");
         ret = LY_EVALID;
@@ -2053,10 +2029,10 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, LY_STMT_REQUIRE_INSTANCE, 0, exts), cleanup);
+            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, type, LY_STMT_REQUIRE_INSTANCE, 0, &type->exts), cleanup);
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "require-instance");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "require-instance");
             ret = LY_EVALID;
             goto cleanup;
         }
@@ -2072,20 +2048,18 @@
  * @brief Parse the modifier statement. Substatement of type pattern statement.
  *
  * @param[in] ctx yang parser context for logging.
- * @param[in,out] pat Value to write to.
- * @param[in,out] exts Extension instances to add to.
- *
+ * @param[in,out] restr Restriction to fill.
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_type_pattern_modifier(struct lysp_yang_ctx *ctx, const char **pat, struct lysp_ext_instance **exts)
+parse_type_pattern_modifier(struct lysp_yang_ctx *ctx, struct lysp_restr *restr)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf = NULL, *word;
     size_t word_len;
     enum ly_stmt kw;
 
-    if ((*pat)[0] == LYSP_RESTR_PATTERN_NACK) {
+    if (restr->arg.str[0] == LYSP_RESTR_PATTERN_NACK) {
         LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "modifier");
         return LY_EVALID;
     }
@@ -2100,23 +2074,23 @@
     }
 
     /* replace the value in the dictionary */
-    buf = malloc(strlen(*pat) + 1);
+    buf = malloc(strlen(restr->arg.str) + 1);
     LY_CHECK_ERR_GOTO(!buf, LOGMEM(PARSER_CTX(ctx)); ret = LY_EMEM, cleanup);
-    strcpy(buf, *pat);
-    lydict_remove(PARSER_CTX(ctx), *pat);
+    strcpy(buf, restr->arg.str);
+    lydict_remove(PARSER_CTX(ctx), restr->arg.str);
 
     assert(buf[0] == LYSP_RESTR_PATTERN_ACK);
     buf[0] = LYSP_RESTR_PATTERN_NACK;
-    LY_CHECK_GOTO(ret = lydict_insert_zc(PARSER_CTX(ctx), buf, pat), cleanup);
+    LY_CHECK_GOTO(ret = lydict_insert_zc(PARSER_CTX(ctx), buf, &restr->arg.str), cleanup);
     buf = NULL;
 
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, LY_STMT_MODIFIER, 0, exts), cleanup);
+            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, restr, LY_STMT_MODIFIER, 0, &restr->exts), cleanup);
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "modifier");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "modifier");
             ret = LY_EVALID;
             goto cleanup;
         }
@@ -2133,7 +2107,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] patterns Restrictions to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2169,26 +2142,26 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts));
+            LY_CHECK_RET(parse_text_field(ctx, restr->dsc, LY_STMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts));
+            LY_CHECK_RET(parse_text_field(ctx, restr->ref, LY_STMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts));
             break;
         case LY_STMT_ERROR_APP_TAG:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_ERROR_APP_TAG, 0, &restr->eapptag, Y_STR_ARG, &restr->exts));
+            LY_CHECK_RET(parse_text_field(ctx, restr, LY_STMT_ERROR_APP_TAG, 0, &restr->eapptag, Y_STR_ARG, &restr->exts));
             break;
         case LY_STMT_ERROR_MESSAGE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_ERROR_MESSAGE, 0, &restr->emsg, Y_STR_ARG, &restr->exts));
+            LY_CHECK_RET(parse_text_field(ctx, restr, LY_STMT_ERROR_MESSAGE, 0, &restr->emsg, Y_STR_ARG, &restr->exts));
             break;
         case LY_STMT_MODIFIER:
             PARSER_CHECK_STMTVER2_RET(ctx, "modifier", "pattern");
-            LY_CHECK_RET(parse_type_pattern_modifier(ctx, &restr->arg.str, &restr->exts));
+            LY_CHECK_RET(parse_type_pattern_modifier(ctx, restr));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_PATTERN, 0, &restr->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, restr, LY_STMT_PATTERN, 0, &restr->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "pattern");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "pattern");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, restr->exts, ret, cleanup);
@@ -2203,7 +2176,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] type Type to wrote to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2243,12 +2215,12 @@
             type->flags |= LYS_SET_ENUM;
             break;
         case LY_STMT_FRACTION_DIGITS:
-            LY_CHECK_RET(parse_type_fracdigits(ctx, &type->fraction_digits, &type->exts));
+            LY_CHECK_RET(parse_type_fracdigits(ctx, type));
             type->flags |= LYS_SET_FRDIGITS;
             break;
         case LY_STMT_LENGTH:
             if (type->length) {
-                LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, lyplg_ext_stmt2str(kw));
                 return LY_EVALID;
             }
             type->length = calloc(1, sizeof *type->length);
@@ -2259,7 +2231,7 @@
             break;
         case LY_STMT_PATH:
             if (type->path) {
-                LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(LY_STMT_PATH));
+                LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, lyplg_ext_stmt2str(LY_STMT_PATH));
                 return LY_EVALID;
             }
 
@@ -2268,7 +2240,7 @@
              * care of removing the parsed value from the dictionary. But in this case, it is not possible
              * to rely on lysp_module_free because the result of the parsing is stored in a local variable.
              */
-            LY_CHECK_ERR_RET(ret = parse_text_field(ctx, LY_STMT_PATH, 0, &str_path, Y_STR_ARG, &type->exts),
+            LY_CHECK_ERR_RET(ret = parse_text_field(ctx, type, LY_STMT_PATH, 0, &str_path, Y_STR_ARG, &type->exts),
                     lydict_remove(PARSER_CTX(ctx), str_path), ret);
             ret = ly_path_parse(PARSER_CTX(ctx), NULL, str_path, 0, 1, LY_PATH_BEGIN_EITHER,
                     LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &type->path);
@@ -2283,7 +2255,7 @@
             break;
         case LY_STMT_RANGE:
             if (type->range) {
-                LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, lyplg_ext_stmt2str(kw));
                 return LY_EVALID;
             }
             type->range = calloc(1, sizeof *type->range);
@@ -2293,7 +2265,7 @@
             type->flags |= LYS_SET_RANGE;
             break;
         case LY_STMT_REQUIRE_INSTANCE:
-            LY_CHECK_RET(parse_type_reqinstance(ctx, &type->require_instance, &type->flags, &type->exts));
+            LY_CHECK_RET(parse_type_reqinstance(ctx, type));
             /* LYS_SET_REQINST checked and set inside parse_type_reqinstance() */
             break;
         case LY_STMT_TYPE:
@@ -2302,10 +2274,10 @@
             type->flags |= LYS_SET_TYPE;
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_TYPE, 0, &type->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, type, LY_STMT_TYPE, 0, &type->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "type");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "type");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, type->exts, ret, cleanup);
@@ -2320,7 +2292,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] siblings Siblings to add to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -2348,11 +2319,11 @@
             LY_CHECK_RET(parse_config(ctx, &leaf->flags, &leaf->exts));
             break;
         case LY_STMT_DEFAULT:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DEFAULT, 0, &leaf->dflt.str, Y_STR_ARG, &leaf->exts));
+            LY_CHECK_RET(parse_text_field(ctx, &leaf->dflt, LY_STMT_DEFAULT, 0, &leaf->dflt.str, Y_STR_ARG, &leaf->exts));
             leaf->dflt.mod = PARSER_CUR_PMOD(ctx);
             break;
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &leaf->dsc, Y_STR_ARG, &leaf->exts));
+            LY_CHECK_RET(parse_text_field(ctx, leaf->dsc, LY_STMT_DESCRIPTION, 0, &leaf->dsc, Y_STR_ARG, &leaf->exts));
             break;
         case LY_STMT_IF_FEATURE:
             LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &leaf->iffeatures, Y_STR_ARG, &leaf->exts));
@@ -2364,7 +2335,7 @@
             LY_CHECK_RET(parse_restrs(ctx, kw, &leaf->musts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &leaf->ref, Y_STR_ARG, &leaf->exts));
+            LY_CHECK_RET(parse_text_field(ctx, leaf->ref, LY_STMT_REFERENCE, 0, &leaf->ref, Y_STR_ARG, &leaf->exts));
             break;
         case LY_STMT_STATUS:
             LY_CHECK_RET(parse_status(ctx, &leaf->flags, &leaf->exts));
@@ -2373,16 +2344,16 @@
             LY_CHECK_RET(parse_type(ctx, &leaf->type));
             break;
         case LY_STMT_UNITS:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_UNITS, 0, &leaf->units, Y_STR_ARG, &leaf->exts));
+            LY_CHECK_RET(parse_text_field(ctx, leaf->units, LY_STMT_UNITS, 0, &leaf->units, Y_STR_ARG, &leaf->exts));
             break;
         case LY_STMT_WHEN:
             LY_CHECK_RET(parse_when(ctx, &leaf->when));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_LEAF, 0, &leaf->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, leaf, LY_STMT_LEAF, 0, &leaf->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "leaf");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "leaf");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, leaf->exts, ret, cleanup);
@@ -2405,7 +2376,6 @@
  * @param[in,out] max Value to write to.
  * @param[in,out] flags Flags to write to.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -2457,10 +2427,10 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, LY_STMT_MAX_ELEMENTS, 0, exts), cleanup);
+            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, max, LY_STMT_MAX_ELEMENTS, 0, exts), cleanup);
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "max-elements");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "max-elements");
             ret = LY_EVALID;
             goto cleanup;
         }
@@ -2479,7 +2449,6 @@
  * @param[in,out] min Value to write to.
  * @param[in,out] flags Flags to write to.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -2524,10 +2493,10 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, LY_STMT_MIN_ELEMENTS, 0, exts), cleanup);
+            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, min, LY_STMT_MIN_ELEMENTS, 0, exts), cleanup);
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "min-elements");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "min-elements");
             ret = LY_EVALID;
             goto cleanup;
         }
@@ -2543,20 +2512,18 @@
  * @brief Parse the ordered-by statement.
  *
  * @param[in] ctx yang parser context for logging.
- * @param[in,out] flags Flags to write to.
- * @param[in,out] exts Extension instances to add to.
- *
+ * @param[in,out] llist List or leaf-list to fill.
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_orderedby(struct lysp_yang_ctx *ctx, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_orderedby(struct lysp_yang_ctx *ctx, struct lysp_node *llist)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf = NULL, *word;
     size_t word_len;
     enum ly_stmt kw;
 
-    if (*flags & LYS_ORDBY_MASK) {
+    if (llist->flags & LYS_ORDBY_MASK) {
         LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "ordered-by");
         return LY_EVALID;
     }
@@ -2565,9 +2532,9 @@
     LY_CHECK_GOTO(ret = get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len), cleanup);
 
     if ((word_len == ly_strlen_const("system")) && !strncmp(word, "system", word_len)) {
-        *flags |= LYS_ORDBY_SYSTEM;
+        llist->flags |= LYS_ORDBY_SYSTEM;
     } else if ((word_len == ly_strlen_const("user")) && !strncmp(word, "user", word_len)) {
-        *flags |= LYS_ORDBY_USER;
+        llist->flags |= LYS_ORDBY_USER;
     } else {
         LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "ordered-by");
         ret = LY_EVALID;
@@ -2577,10 +2544,10 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, LY_STMT_ORDERED_BY, 0, exts), cleanup);
+            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, llist, LY_STMT_ORDERED_BY, 0, &llist->exts), cleanup);
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "ordered-by");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "ordered-by");
             ret = LY_EVALID;
             goto cleanup;
         }
@@ -2629,7 +2596,7 @@
             LY_CHECK_RET(parse_qnames(ctx, LY_STMT_DEFAULT, &llist->dflts, Y_STR_ARG, &llist->exts));
             break;
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &llist->dsc, Y_STR_ARG, &llist->exts));
+            LY_CHECK_RET(parse_text_field(ctx, llist->dsc, LY_STMT_DESCRIPTION, 0, &llist->dsc, Y_STR_ARG, &llist->exts));
             break;
         case LY_STMT_IF_FEATURE:
             LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &llist->iffeatures, Y_STR_ARG, &llist->exts));
@@ -2644,10 +2611,10 @@
             LY_CHECK_RET(parse_restrs(ctx, kw, &llist->musts));
             break;
         case LY_STMT_ORDERED_BY:
-            LY_CHECK_RET(parse_orderedby(ctx, &llist->flags, &llist->exts));
+            LY_CHECK_RET(parse_orderedby(ctx, &llist->node));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &llist->ref, Y_STR_ARG, &llist->exts));
+            LY_CHECK_RET(parse_text_field(ctx, llist->ref, LY_STMT_REFERENCE, 0, &llist->ref, Y_STR_ARG, &llist->exts));
             break;
         case LY_STMT_STATUS:
             LY_CHECK_RET(parse_status(ctx, &llist->flags, &llist->exts));
@@ -2656,16 +2623,16 @@
             LY_CHECK_RET(parse_type(ctx, &llist->type));
             break;
         case LY_STMT_UNITS:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_UNITS, 0, &llist->units, Y_STR_ARG, &llist->exts));
+            LY_CHECK_RET(parse_text_field(ctx, llist->units, LY_STMT_UNITS, 0, &llist->units, Y_STR_ARG, &llist->exts));
             break;
         case LY_STMT_WHEN:
             LY_CHECK_RET(parse_when(ctx, &llist->when));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_LEAF_LIST, 0, &llist->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, llist, LY_STMT_LEAF_LIST, 0, &llist->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "llist");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "llist");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, llist->exts, ret, cleanup);
@@ -2686,7 +2653,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] refines Refines to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2714,7 +2680,7 @@
             LY_CHECK_RET(parse_qnames(ctx, LY_STMT_DEFAULT, &rf->dflts, Y_STR_ARG, &rf->exts));
             break;
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &rf->dsc, Y_STR_ARG, &rf->exts));
+            LY_CHECK_RET(parse_text_field(ctx, rf->dsc, LY_STMT_DESCRIPTION, 0, &rf->dsc, Y_STR_ARG, &rf->exts));
             break;
         case LY_STMT_IF_FEATURE:
             PARSER_CHECK_STMTVER2_RET(ctx, "if-feature", "refine");
@@ -2733,16 +2699,16 @@
             LY_CHECK_RET(parse_mandatory(ctx, &rf->flags, &rf->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &rf->ref, Y_STR_ARG, &rf->exts));
+            LY_CHECK_RET(parse_text_field(ctx, rf->ref, LY_STMT_REFERENCE, 0, &rf->ref, Y_STR_ARG, &rf->exts));
             break;
         case LY_STMT_PRESENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_PRESENCE, 0, &rf->presence, Y_STR_ARG, &rf->exts));
+            LY_CHECK_RET(parse_text_field(ctx, rf->presence, LY_STMT_PRESENCE, 0, &rf->presence, Y_STR_ARG, &rf->exts));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_REFINE, 0, &rf->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, rf, LY_STMT_REFINE, 0, &rf->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "refine");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "refine");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, rf->exts, ret, cleanup);
@@ -2757,7 +2723,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] typedefs Typedefs to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2779,14 +2744,14 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DEFAULT:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DEFAULT, 0, &tpdf->dflt.str, Y_STR_ARG, &tpdf->exts));
+            LY_CHECK_RET(parse_text_field(ctx, &tpdf->dflt, LY_STMT_DEFAULT, 0, &tpdf->dflt.str, Y_STR_ARG, &tpdf->exts));
             tpdf->dflt.mod = PARSER_CUR_PMOD(ctx);
             break;
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &tpdf->dsc, Y_STR_ARG, &tpdf->exts));
+            LY_CHECK_RET(parse_text_field(ctx, tpdf->dsc, LY_STMT_DESCRIPTION, 0, &tpdf->dsc, Y_STR_ARG, &tpdf->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &tpdf->ref, Y_STR_ARG, &tpdf->exts));
+            LY_CHECK_RET(parse_text_field(ctx, tpdf->ref, LY_STMT_REFERENCE, 0, &tpdf->ref, Y_STR_ARG, &tpdf->exts));
             break;
         case LY_STMT_STATUS:
             LY_CHECK_RET(parse_status(ctx, &tpdf->flags, &tpdf->exts));
@@ -2795,13 +2760,13 @@
             LY_CHECK_RET(parse_type(ctx, &tpdf->type));
             break;
         case LY_STMT_UNITS:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_UNITS, 0, &tpdf->units, Y_STR_ARG, &tpdf->exts));
+            LY_CHECK_RET(parse_text_field(ctx, tpdf->units, LY_STMT_UNITS, 0, &tpdf->units, Y_STR_ARG, &tpdf->exts));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_TYPEDEF, 0, &tpdf->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, tpdf, LY_STMT_TYPEDEF, 0, &tpdf->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "typedef");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "typedef");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, tpdf->exts, ret, cleanup);
@@ -2829,7 +2794,6 @@
  * @param[in] ctx yang parser context for logging.
  * @param[in] kw Type of this particular keyword
  * @param[in,out] inout_p Input/output pointer to write to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2843,7 +2807,7 @@
     ly_bool input = &((struct lysp_node_action *)parent)->input == inout_p ? 1 : 0;
 
     if (inout_p->nodetype) {
-        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(inout_kw));
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, lyplg_ext_stmt2str(inout_kw));
         return LY_EVALID;
     }
 
@@ -2856,7 +2820,7 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_ANYDATA:
-            PARSER_CHECK_STMTVER2_RET(ctx, "anydata", ly_stmt2str(inout_kw));
+            PARSER_CHECK_STMTVER2_RET(ctx, "anydata", lyplg_ext_stmt2str(inout_kw));
         /* fall through */
         case LY_STMT_ANYXML:
             LY_CHECK_RET(parse_any(ctx, kw, (struct lysp_node *)inout_p, &inout_p->child));
@@ -2883,24 +2847,24 @@
             LY_CHECK_RET(parse_typedef(ctx, (struct lysp_node *)inout_p, &inout_p->typedefs));
             break;
         case LY_STMT_MUST:
-            PARSER_CHECK_STMTVER2_RET(ctx, "must", ly_stmt2str(inout_kw));
+            PARSER_CHECK_STMTVER2_RET(ctx, "must", lyplg_ext_stmt2str(inout_kw));
             LY_CHECK_RET(parse_restrs(ctx, kw, &inout_p->musts));
             break;
         case LY_STMT_GROUPING:
             LY_CHECK_RET(parse_grouping(ctx, (struct lysp_node *)inout_p, &inout_p->groupings));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, inout_kw, 0, &inout_p->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, inout_p, inout_kw, 0, &inout_p->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(inout_kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), lyplg_ext_stmt2str(inout_kw));
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, inout_p->exts, ret, cleanup);
     }
 
     if (!inout_p->child) {
-        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "data-def-stmt", ly_stmt2str(inout_kw));
+        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "data-def-stmt", lyplg_ext_stmt2str(inout_kw));
         return LY_EVALID;
     }
 
@@ -2913,7 +2877,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] actions Actions to add to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -2936,13 +2899,13 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &act->dsc, Y_STR_ARG, &act->exts));
+            LY_CHECK_RET(parse_text_field(ctx, act->dsc, LY_STMT_DESCRIPTION, 0, &act->dsc, Y_STR_ARG, &act->exts));
             break;
         case LY_STMT_IF_FEATURE:
             LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &act->iffeatures, Y_STR_ARG, &act->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &act->ref, Y_STR_ARG, &act->exts));
+            LY_CHECK_RET(parse_text_field(ctx, act->ref, LY_STMT_REFERENCE, 0, &act->ref, Y_STR_ARG, &act->exts));
             break;
         case LY_STMT_STATUS:
             LY_CHECK_RET(parse_status(ctx, &act->flags, &act->exts));
@@ -2962,10 +2925,10 @@
             LY_CHECK_RET(parse_grouping(ctx, (struct lysp_node *)act, &act->groupings));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, parent ? LY_STMT_ACTION : LY_STMT_RPC, 0, &act->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, act, parent ? LY_STMT_ACTION : LY_STMT_RPC, 0, &act->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), parent ? "action" : "rpc");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), parent ? "action" : "rpc");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, act->exts, ret, cleanup);
@@ -2992,7 +2955,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] notifs Notifications to add to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -3015,13 +2977,13 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &notif->dsc, Y_STR_ARG, &notif->exts));
+            LY_CHECK_RET(parse_text_field(ctx, notif->dsc, LY_STMT_DESCRIPTION, 0, &notif->dsc, Y_STR_ARG, &notif->exts));
             break;
         case LY_STMT_IF_FEATURE:
             LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &notif->iffeatures, Y_STR_ARG, &notif->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &notif->ref, Y_STR_ARG, &notif->exts));
+            LY_CHECK_RET(parse_text_field(ctx, notif->ref, LY_STMT_REFERENCE, 0, &notif->ref, Y_STR_ARG, &notif->exts));
             break;
         case LY_STMT_STATUS:
             LY_CHECK_RET(parse_status(ctx, &notif->flags, &notif->exts));
@@ -3063,10 +3025,10 @@
             LY_CHECK_RET(parse_grouping(ctx, (struct lysp_node *)notif, &notif->groupings));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_NOTIFICATION, 0, &notif->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, notif, LY_STMT_NOTIFICATION, 0, &notif->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "notification");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "notification");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, notif->exts, ret, cleanup);
@@ -3081,7 +3043,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] groupings Groupings to add to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -3104,10 +3065,10 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &grp->dsc, Y_STR_ARG, &grp->exts));
+            LY_CHECK_RET(parse_text_field(ctx, grp->dsc, LY_STMT_DESCRIPTION, 0, &grp->dsc, Y_STR_ARG, &grp->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &grp->ref, Y_STR_ARG, &grp->exts));
+            LY_CHECK_RET(parse_text_field(ctx, grp->ref, LY_STMT_REFERENCE, 0, &grp->ref, Y_STR_ARG, &grp->exts));
             break;
         case LY_STMT_STATUS:
             LY_CHECK_RET(parse_status(ctx, &grp->flags, &grp->exts));
@@ -3153,10 +3114,10 @@
             LY_CHECK_RET(parse_notif(ctx, &grp->node, &grp->notifs));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_GROUPING, 0, &grp->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, grp, LY_STMT_GROUPING, 0, &grp->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "grouping");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "grouping");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, grp->exts, ret, cleanup);
@@ -3177,7 +3138,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] augments Augments to add to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -3201,13 +3161,13 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &aug->dsc, Y_STR_ARG, &aug->exts));
+            LY_CHECK_RET(parse_text_field(ctx, aug->dsc, LY_STMT_DESCRIPTION, 0, &aug->dsc, Y_STR_ARG, &aug->exts));
             break;
         case LY_STMT_IF_FEATURE:
             LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &aug->iffeatures, Y_STR_ARG, &aug->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &aug->ref, Y_STR_ARG, &aug->exts));
+            LY_CHECK_RET(parse_text_field(ctx, aug->ref, LY_STMT_REFERENCE, 0, &aug->ref, Y_STR_ARG, &aug->exts));
             break;
         case LY_STMT_STATUS:
             LY_CHECK_RET(parse_status(ctx, &aug->flags, &aug->exts));
@@ -3253,10 +3213,10 @@
             LY_CHECK_RET(parse_notif(ctx, (struct lysp_node *)aug, &aug->notifs));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_AUGMENT, 0, &aug->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, aug, LY_STMT_AUGMENT, 0, &aug->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "augment");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "augment");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, aug->exts, ret, cleanup);
@@ -3271,7 +3231,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] siblings Siblings to add to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -3296,13 +3255,13 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &uses->dsc, Y_STR_ARG, &uses->exts));
+            LY_CHECK_RET(parse_text_field(ctx, uses->dsc, LY_STMT_DESCRIPTION, 0, &uses->dsc, Y_STR_ARG, &uses->exts));
             break;
         case LY_STMT_IF_FEATURE:
             LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &uses->iffeatures, Y_STR_ARG, &uses->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &uses->ref, Y_STR_ARG, &uses->exts));
+            LY_CHECK_RET(parse_text_field(ctx, uses->ref, LY_STMT_REFERENCE, 0, &uses->ref, Y_STR_ARG, &uses->exts));
             break;
         case LY_STMT_STATUS:
             LY_CHECK_RET(parse_status(ctx, &uses->flags, &uses->exts));
@@ -3318,10 +3277,10 @@
             LY_CHECK_RET(parse_augment(ctx, (struct lysp_node *)uses, &uses->augments));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_USES, 0, &uses->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, uses, LY_STMT_USES, 0, &uses->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "uses");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "uses");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, uses->exts, ret, cleanup);
@@ -3336,7 +3295,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] siblings Siblings to add to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -3361,13 +3319,13 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &cas->dsc, Y_STR_ARG, &cas->exts));
+            LY_CHECK_RET(parse_text_field(ctx, cas->dsc, LY_STMT_DESCRIPTION, 0, &cas->dsc, Y_STR_ARG, &cas->exts));
             break;
         case LY_STMT_IF_FEATURE:
             LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &cas->iffeatures, Y_STR_ARG, &cas->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &cas->ref, Y_STR_ARG, &cas->exts));
+            LY_CHECK_RET(parse_text_field(ctx, cas->ref, LY_STMT_REFERENCE, 0, &cas->ref, Y_STR_ARG, &cas->exts));
             break;
         case LY_STMT_STATUS:
             LY_CHECK_RET(parse_status(ctx, &cas->flags, &cas->exts));
@@ -3401,10 +3359,10 @@
             LY_CHECK_RET(parse_uses(ctx, (struct lysp_node *)cas, &cas->child));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_CASE, 0, &cas->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, cas, LY_STMT_CASE, 0, &cas->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "case");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "case");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, cas->exts, ret, cleanup);
@@ -3419,7 +3377,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] siblings Siblings to add to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -3447,7 +3404,7 @@
             LY_CHECK_RET(parse_config(ctx, &choice->flags, &choice->exts));
             break;
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &choice->dsc, Y_STR_ARG, &choice->exts));
+            LY_CHECK_RET(parse_text_field(ctx, choice->dsc, LY_STMT_DESCRIPTION, 0, &choice->dsc, Y_STR_ARG, &choice->exts));
             break;
         case LY_STMT_IF_FEATURE:
             LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &choice->iffeatures, Y_STR_ARG, &choice->exts));
@@ -3456,7 +3413,7 @@
             LY_CHECK_RET(parse_mandatory(ctx, &choice->flags, &choice->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &choice->ref, Y_STR_ARG, &choice->exts));
+            LY_CHECK_RET(parse_text_field(ctx, choice->ref, LY_STMT_REFERENCE, 0, &choice->ref, Y_STR_ARG, &choice->exts));
             break;
         case LY_STMT_STATUS:
             LY_CHECK_RET(parse_status(ctx, &choice->flags, &choice->exts));
@@ -3465,7 +3422,7 @@
             LY_CHECK_RET(parse_when(ctx, &choice->when));
             break;
         case LY_STMT_DEFAULT:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DEFAULT, 0, &choice->dflt.str, Y_PREF_IDENTIF_ARG,
+            LY_CHECK_RET(parse_text_field(ctx, &choice->dflt, LY_STMT_DEFAULT, 0, &choice->dflt.str, Y_PREF_IDENTIF_ARG,
                     &choice->exts));
             choice->dflt.mod = PARSER_CUR_PMOD(ctx);
             break;
@@ -3496,10 +3453,10 @@
             LY_CHECK_RET(parse_list(ctx, (struct lysp_node *)choice, &choice->child));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_CHOICE, 0, &choice->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, choice, LY_STMT_CHOICE, 0, &choice->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "choice");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "choice");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, choice->exts, ret, cleanup);
@@ -3514,7 +3471,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] siblings Siblings to add to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -3542,13 +3498,13 @@
             LY_CHECK_RET(parse_config(ctx, &cont->flags, &cont->exts));
             break;
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &cont->dsc, Y_STR_ARG, &cont->exts));
+            LY_CHECK_RET(parse_text_field(ctx, cont->dsc, LY_STMT_DESCRIPTION, 0, &cont->dsc, Y_STR_ARG, &cont->exts));
             break;
         case LY_STMT_IF_FEATURE:
             LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &cont->iffeatures, Y_STR_ARG, &cont->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &cont->ref, Y_STR_ARG, &cont->exts));
+            LY_CHECK_RET(parse_text_field(ctx, cont->ref, LY_STMT_REFERENCE, 0, &cont->ref, Y_STR_ARG, &cont->exts));
             break;
         case LY_STMT_STATUS:
             LY_CHECK_RET(parse_status(ctx, &cont->flags, &cont->exts));
@@ -3557,7 +3513,7 @@
             LY_CHECK_RET(parse_when(ctx, &cont->when));
             break;
         case LY_STMT_PRESENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_PRESENCE, 0, &cont->presence, Y_STR_ARG, &cont->exts));
+            LY_CHECK_RET(parse_text_field(ctx, cont->presence, LY_STMT_PRESENCE, 0, &cont->presence, Y_STR_ARG, &cont->exts));
             break;
 
         case LY_STMT_ANYDATA:
@@ -3603,10 +3559,10 @@
             LY_CHECK_RET(parse_notif(ctx, (struct lysp_node *)cont, &cont->notifs));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_CONTAINER, 0, &cont->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, cont, LY_STMT_CONTAINER, 0, &cont->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "container");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "container");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, cont->exts, ret, cleanup);
@@ -3621,7 +3577,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] siblings Siblings to add to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -3649,13 +3604,13 @@
             LY_CHECK_RET(parse_config(ctx, &list->flags, &list->exts));
             break;
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &list->dsc, Y_STR_ARG, &list->exts));
+            LY_CHECK_RET(parse_text_field(ctx, list->dsc, LY_STMT_DESCRIPTION, 0, &list->dsc, Y_STR_ARG, &list->exts));
             break;
         case LY_STMT_IF_FEATURE:
             LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &list->iffeatures, Y_STR_ARG, &list->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &list->ref, Y_STR_ARG, &list->exts));
+            LY_CHECK_RET(parse_text_field(ctx, list->ref, LY_STMT_REFERENCE, 0, &list->ref, Y_STR_ARG, &list->exts));
             break;
         case LY_STMT_STATUS:
             LY_CHECK_RET(parse_status(ctx, &list->flags, &list->exts));
@@ -3664,7 +3619,7 @@
             LY_CHECK_RET(parse_when(ctx, &list->when));
             break;
         case LY_STMT_KEY:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_KEY, 0, &list->key, Y_STR_ARG, &list->exts));
+            LY_CHECK_RET(parse_text_field(ctx, list, LY_STMT_KEY, 0, &list->key, Y_STR_ARG, &list->exts));
             break;
         case LY_STMT_MAX_ELEMENTS:
             LY_CHECK_RET(parse_maxelements(ctx, &list->max, &list->flags, &list->exts));
@@ -3673,7 +3628,7 @@
             LY_CHECK_RET(parse_minelements(ctx, &list->min, &list->flags, &list->exts));
             break;
         case LY_STMT_ORDERED_BY:
-            LY_CHECK_RET(parse_orderedby(ctx, &list->flags, &list->exts));
+            LY_CHECK_RET(parse_orderedby(ctx, &list->node));
             break;
         case LY_STMT_UNIQUE:
             LY_CHECK_RET(parse_qnames(ctx, LY_STMT_UNIQUE, &list->uniques, Y_STR_ARG, &list->exts));
@@ -3722,10 +3677,10 @@
             LY_CHECK_RET(parse_notif(ctx, (struct lysp_node *)list, &list->notifs));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_LIST, 0, &list->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, list, LY_STMT_LIST, 0, &list->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "list");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "list");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, list->exts, ret, cleanup);
@@ -3739,20 +3694,18 @@
  * @brief Parse the yin-element statement.
  *
  * @param[in] ctx yang parser context for logging.
- * @param[in,out] flags Flags to write to.
- * @param[in,out] exts Extension instances to add to.
- *
+ * @param[in,out] ext Extension to fill.
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_yinelement(struct lysp_yang_ctx *ctx, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_yinelement(struct lysp_yang_ctx *ctx, struct lysp_ext *ext)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
     size_t word_len;
     enum ly_stmt kw;
 
-    if (*flags & LYS_YINELEM_MASK) {
+    if (ext->flags & LYS_YINELEM_MASK) {
         LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "yin-element");
         return LY_EVALID;
     }
@@ -3761,9 +3714,9 @@
     LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
 
     if ((word_len == ly_strlen_const("true")) && !strncmp(word, "true", word_len)) {
-        *flags |= LYS_YINELEM_TRUE;
+        ext->flags |= LYS_YINELEM_TRUE;
     } else if ((word_len == ly_strlen_const("false")) && !strncmp(word, "false", word_len)) {
-        *flags |= LYS_YINELEM_FALSE;
+        ext->flags |= LYS_YINELEM_FALSE;
     } else {
         LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "yin-element");
         free(buf);
@@ -3774,11 +3727,11 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_YIN_ELEMENT, 0, exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, ext, LY_STMT_YIN_ELEMENT, 0, &ext->exts));
             LY_CHECK_RET(ret);
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yin-element");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "yin-element");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
@@ -3792,39 +3745,36 @@
  * @brief Parse the argument statement.
  *
  * @param[in] ctx yang parser context for logging.
- * @param[in,out] argument Value to write to.
- * @param[in,out] flags Flags to write to.
- * @param[in,out] exts Extension instances to add to.
- *
+ * @param[in,out] ext Extension to fill.
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_argument(struct lysp_yang_ctx *ctx, const char **argument, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_argument(struct lysp_yang_ctx *ctx, struct lysp_ext *ext)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
     size_t word_len;
     enum ly_stmt kw;
 
-    if (*argument) {
+    if (ext->argname) {
         LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "argument");
         return LY_EVALID;
     }
 
     /* get value */
     LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
-    INSERT_WORD_GOTO(ctx, buf, *argument, word, word_len, ret, cleanup);
+    INSERT_WORD_GOTO(ctx, buf, ext->argname, word, word_len, ret, cleanup);
 
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_YIN_ELEMENT:
-            LY_CHECK_RET(parse_yinelement(ctx, flags, exts));
+            LY_CHECK_RET(parse_yinelement(ctx, ext));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_ARGUMENT, 0, exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, ext, LY_STMT_ARGUMENT, 0, &ext->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "argument");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "argument");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
@@ -3839,7 +3789,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] extensions Extensions to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -3860,22 +3809,22 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &ex->dsc, Y_STR_ARG, &ex->exts));
+            LY_CHECK_RET(parse_text_field(ctx, ex->dsc, LY_STMT_DESCRIPTION, 0, &ex->dsc, Y_STR_ARG, &ex->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &ex->ref, Y_STR_ARG, &ex->exts));
+            LY_CHECK_RET(parse_text_field(ctx, ex->ref, LY_STMT_REFERENCE, 0, &ex->ref, Y_STR_ARG, &ex->exts));
             break;
         case LY_STMT_STATUS:
             LY_CHECK_RET(parse_status(ctx, &ex->flags, &ex->exts));
             break;
         case LY_STMT_ARGUMENT:
-            LY_CHECK_RET(parse_argument(ctx, &ex->argname, &ex->flags, &ex->exts));
+            LY_CHECK_RET(parse_argument(ctx, ex));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_EXTENSION, 0, &ex->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, ex, LY_STMT_EXTENSION, 0, &ex->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "extension");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "extension");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, ex->exts, ret, cleanup);
@@ -3890,7 +3839,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] deviates Deviates to add to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -3978,7 +3926,7 @@
             switch (dev_mod) {
             case LYS_DEV_NOT_SUPPORTED:
             case LYS_DEV_DELETE:
-                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), lyplg_ext_stmt2str(kw));
                 ret = LY_EVALID;
                 goto cleanup;
             default:
@@ -3989,11 +3937,12 @@
         case LY_STMT_DEFAULT:
             switch (dev_mod) {
             case LYS_DEV_NOT_SUPPORTED:
-                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), lyplg_ext_stmt2str(kw));
                 ret = LY_EVALID;
                 goto cleanup;
             case LYS_DEV_REPLACE:
-                LY_CHECK_GOTO(ret = parse_text_field(ctx, LY_STMT_DEFAULT, 0, &d_rpl->dflt.str, Y_STR_ARG, &d->exts), cleanup);
+                ret = parse_text_field(ctx, &d_rpl->dflt, LY_STMT_DEFAULT, 0, &d_rpl->dflt.str, Y_STR_ARG, &d->exts);
+                LY_CHECK_GOTO(ret, cleanup);
                 d_rpl->dflt.mod = PARSER_CUR_PMOD(ctx);
                 break;
             default:
@@ -4005,7 +3954,7 @@
             switch (dev_mod) {
             case LYS_DEV_NOT_SUPPORTED:
             case LYS_DEV_DELETE:
-                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), lyplg_ext_stmt2str(kw));
                 ret = LY_EVALID;
                 goto cleanup;
             default:
@@ -4017,7 +3966,7 @@
             switch (dev_mod) {
             case LYS_DEV_NOT_SUPPORTED:
             case LYS_DEV_DELETE:
-                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), lyplg_ext_stmt2str(kw));
                 ret = LY_EVALID;
                 goto cleanup;
             default:
@@ -4029,7 +3978,7 @@
             switch (dev_mod) {
             case LYS_DEV_NOT_SUPPORTED:
             case LYS_DEV_DELETE:
-                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), lyplg_ext_stmt2str(kw));
                 ret = LY_EVALID;
                 goto cleanup;
             default:
@@ -4041,7 +3990,7 @@
             switch (dev_mod) {
             case LYS_DEV_NOT_SUPPORTED:
             case LYS_DEV_REPLACE:
-                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), lyplg_ext_stmt2str(kw));
                 ret = LY_EVALID;
                 goto cleanup;
             default:
@@ -4054,12 +4003,12 @@
             case LYS_DEV_NOT_SUPPORTED:
             case LYS_DEV_ADD:
             case LYS_DEV_DELETE:
-                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), lyplg_ext_stmt2str(kw));
                 ret = LY_EVALID;
                 goto cleanup;
             default:
                 if (d_rpl->type) {
-                    LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
+                    LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, lyplg_ext_stmt2str(kw));
                     ret = LY_EVALID;
                     goto cleanup;
                 }
@@ -4073,7 +4022,7 @@
             switch (dev_mod) {
             case LYS_DEV_NOT_SUPPORTED:
             case LYS_DEV_REPLACE:
-                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), lyplg_ext_stmt2str(kw));
                 ret = LY_EVALID;
                 goto cleanup;
             default:
@@ -4084,19 +4033,19 @@
         case LY_STMT_UNITS:
             switch (dev_mod) {
             case LYS_DEV_NOT_SUPPORTED:
-                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), lyplg_ext_stmt2str(kw));
                 ret = LY_EVALID;
                 goto cleanup;
             default:
-                LY_CHECK_GOTO(ret = parse_text_field(ctx, LY_STMT_UNITS, 0, d_units, Y_STR_ARG, &d->exts), cleanup);
+                LY_CHECK_GOTO(ret = parse_text_field(ctx, *d_units, LY_STMT_UNITS, 0, d_units, Y_STR_ARG, &d->exts), cleanup);
                 break;
             }
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, LY_STMT_DEVIATE, 0, &d->exts), cleanup);
+            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, d, LY_STMT_DEVIATE, 0, &d->exts), cleanup);
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "deviate");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "deviate");
             ret = LY_EVALID;
             goto cleanup;
         }
@@ -4120,7 +4069,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] deviations Deviations to add to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -4143,19 +4091,19 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_GOTO(ret = parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &dev->dsc, Y_STR_ARG, &dev->exts), cleanup);
+            LY_CHECK_GOTO(ret = parse_text_field(ctx, dev->dsc, LY_STMT_DESCRIPTION, 0, &dev->dsc, Y_STR_ARG, &dev->exts), cleanup);
             break;
         case LY_STMT_DEVIATE:
             LY_CHECK_GOTO(ret = parse_deviate(ctx, &dev->deviates), cleanup);
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_GOTO(ret = parse_text_field(ctx, LY_STMT_REFERENCE, 0, &dev->ref, Y_STR_ARG, &dev->exts), cleanup);
+            LY_CHECK_GOTO(ret = parse_text_field(ctx, dev->ref, LY_STMT_REFERENCE, 0, &dev->ref, Y_STR_ARG, &dev->exts), cleanup);
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, LY_STMT_DEVIATION, 0, &dev->exts), cleanup);
+            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, dev, LY_STMT_DEVIATION, 0, &dev->exts), cleanup);
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "deviation");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "deviation");
             ret = LY_EVALID;
             goto cleanup;
         }
@@ -4182,7 +4130,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] features Features to add to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -4203,22 +4150,22 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &feat->dsc, Y_STR_ARG, &feat->exts));
+            LY_CHECK_RET(parse_text_field(ctx, feat->dsc, LY_STMT_DESCRIPTION, 0, &feat->dsc, Y_STR_ARG, &feat->exts));
             break;
         case LY_STMT_IF_FEATURE:
             LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &feat->iffeatures, Y_STR_ARG, &feat->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &feat->ref, Y_STR_ARG, &feat->exts));
+            LY_CHECK_RET(parse_text_field(ctx, feat->ref, LY_STMT_REFERENCE, 0, &feat->ref, Y_STR_ARG, &feat->exts));
             break;
         case LY_STMT_STATUS:
             LY_CHECK_RET(parse_status(ctx, &feat->flags, &feat->exts));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_FEATURE, 0, &feat->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, feat, LY_STMT_FEATURE, 0, &feat->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "feature");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "feature");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, feat->exts, ret, cleanup);
@@ -4233,7 +4180,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] identities Identities to add to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -4254,14 +4200,14 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &ident->dsc, Y_STR_ARG, &ident->exts));
+            LY_CHECK_RET(parse_text_field(ctx, ident->dsc, LY_STMT_DESCRIPTION, 0, &ident->dsc, Y_STR_ARG, &ident->exts));
             break;
         case LY_STMT_IF_FEATURE:
             PARSER_CHECK_STMTVER2_RET(ctx, "if-feature", "identity");
             LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &ident->iffeatures, Y_STR_ARG, &ident->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &ident->ref, Y_STR_ARG, &ident->exts));
+            LY_CHECK_RET(parse_text_field(ctx, ident->ref, LY_STMT_REFERENCE, 0, &ident->ref, Y_STR_ARG, &ident->exts));
             break;
         case LY_STMT_STATUS:
             LY_CHECK_RET(parse_status(ctx, &ident->flags, &ident->exts));
@@ -4274,10 +4220,10 @@
             LY_CHECK_RET(parse_text_fields(ctx, LY_STMT_BASE, &ident->bases, Y_PREF_IDENTIF_ARG, &ident->exts));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_IDENTITY, 0, &ident->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, ident, LY_STMT_IDENTITY, 0, &ident->exts));
             break;
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "identity");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "identity");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, ident->exts, ret, cleanup);
@@ -4292,7 +4238,6 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] mod Module to write to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -4314,7 +4259,9 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
 
 #define CHECK_ORDER(SECTION) \
-        if (mod_stmt > SECTION) {LOGVAL_PARSER(ctx, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw)); return LY_EVALID;}mod_stmt = SECTION
+        if (mod_stmt > SECTION) {\
+            LOGVAL_PARSER(ctx, LY_VCODE_INORD, lyplg_ext_stmt2str(kw), lyplg_ext_stmt2str(prev_kw)); return LY_EVALID;\
+        } mod_stmt = SECTION
 
         switch (kw) {
         /* module header */
@@ -4375,13 +4322,13 @@
         switch (kw) {
         /* module header */
         case LY_STMT_YANG_VERSION:
-            LY_CHECK_RET(parse_yangversion(ctx, &mod->version, &mod->exts));
+            LY_CHECK_RET(parse_yangversion(ctx, mod));
             break;
         case LY_STMT_NAMESPACE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_NAMESPACE, 0, &mod->mod->ns, Y_STR_ARG, &mod->exts));
+            LY_CHECK_RET(parse_text_field(ctx, mod, LY_STMT_NAMESPACE, 0, &mod->mod->ns, Y_STR_ARG, &mod->exts));
             break;
         case LY_STMT_PREFIX:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_PREFIX, 0, &mod->mod->prefix, Y_IDENTIF_ARG, &mod->exts));
+            LY_CHECK_RET(parse_text_field(ctx, mod->mod->prefix, LY_STMT_PREFIX, 0, &mod->mod->prefix, Y_IDENTIF_ARG, &mod->exts));
             break;
 
         /* linkage */
@@ -4394,16 +4341,16 @@
 
         /* meta */
         case LY_STMT_ORGANIZATION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_ORGANIZATION, 0, &mod->mod->org, Y_STR_ARG, &mod->exts));
+            LY_CHECK_RET(parse_text_field(ctx, mod, LY_STMT_ORGANIZATION, 0, &mod->mod->org, Y_STR_ARG, &mod->exts));
             break;
         case LY_STMT_CONTACT:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_CONTACT, 0, &mod->mod->contact, Y_STR_ARG, &mod->exts));
+            LY_CHECK_RET(parse_text_field(ctx, mod, LY_STMT_CONTACT, 0, &mod->mod->contact, Y_STR_ARG, &mod->exts));
             break;
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &mod->mod->dsc, Y_STR_ARG, &mod->exts));
+            LY_CHECK_RET(parse_text_field(ctx, mod->mod->dsc, LY_STMT_DESCRIPTION, 0, &mod->mod->dsc, Y_STR_ARG, &mod->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &mod->mod->ref, Y_STR_ARG, &mod->exts));
+            LY_CHECK_RET(parse_text_field(ctx, mod->mod->ref, LY_STMT_REFERENCE, 0, &mod->mod->ref, Y_STR_ARG, &mod->exts));
             break;
 
         /* revision */
@@ -4465,11 +4412,11 @@
             LY_CHECK_RET(parse_typedef(ctx, NULL, &mod->typedefs));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_MODULE, 0, &mod->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, mod, LY_STMT_MODULE, 0, &mod->exts));
             break;
 
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "module");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "module");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, mod->exts, ret, cleanup);
@@ -4523,7 +4470,7 @@
     YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
 
 #define CHECK_ORDER(SECTION) \
-        if (mod_stmt > SECTION) {LOGVAL_PARSER(ctx, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw)); return LY_EVALID;}mod_stmt = SECTION
+        if (mod_stmt > SECTION) {LOGVAL_PARSER(ctx, LY_VCODE_INORD, lyplg_ext_stmt2str(kw), lyplg_ext_stmt2str(prev_kw)); return LY_EVALID;}mod_stmt = SECTION
 
         switch (kw) {
         /* module header */
@@ -4583,10 +4530,10 @@
         switch (kw) {
         /* module header */
         case LY_STMT_YANG_VERSION:
-            LY_CHECK_RET(parse_yangversion(ctx, &submod->version, &submod->exts));
+            LY_CHECK_RET(parse_yangversion(ctx, (struct lysp_module *)submod));
             break;
         case LY_STMT_BELONGS_TO:
-            LY_CHECK_RET(parse_belongsto(ctx, &submod->prefix, &submod->exts));
+            LY_CHECK_RET(parse_belongsto(ctx, submod));
             break;
 
         /* linkage */
@@ -4603,16 +4550,16 @@
 
         /* meta */
         case LY_STMT_ORGANIZATION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_ORGANIZATION, 0, &submod->org, Y_STR_ARG, &submod->exts));
+            LY_CHECK_RET(parse_text_field(ctx, submod, LY_STMT_ORGANIZATION, 0, &submod->org, Y_STR_ARG, &submod->exts));
             break;
         case LY_STMT_CONTACT:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_CONTACT, 0, &submod->contact, Y_STR_ARG, &submod->exts));
+            LY_CHECK_RET(parse_text_field(ctx, submod, LY_STMT_CONTACT, 0, &submod->contact, Y_STR_ARG, &submod->exts));
             break;
         case LY_STMT_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &submod->dsc, Y_STR_ARG, &submod->exts));
+            LY_CHECK_RET(parse_text_field(ctx, submod->dsc, LY_STMT_DESCRIPTION, 0, &submod->dsc, Y_STR_ARG, &submod->exts));
             break;
         case LY_STMT_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &submod->ref, Y_STR_ARG, &submod->exts));
+            LY_CHECK_RET(parse_text_field(ctx, submod->ref, LY_STMT_REFERENCE, 0, &submod->ref, Y_STR_ARG, &submod->exts));
             break;
 
         /* revision */
@@ -4674,11 +4621,11 @@
             LY_CHECK_RET(parse_typedef(ctx, NULL, &submod->typedefs));
             break;
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_SUBMODULE, 0, &submod->exts));
+            LY_CHECK_RET(parse_ext(ctx, word, word_len, submod, LY_STMT_SUBMODULE, 0, &submod->exts));
             break;
 
         default:
-            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "submodule");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, lyplg_ext_stmt2str(kw), "submodule");
             return LY_EVALID;
         }
         YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, submod->exts, ret, cleanup);
@@ -4781,7 +4728,7 @@
         ret = LY_EINVAL;
         goto cleanup;
     } else if (kw != LY_STMT_SUBMODULE) {
-        LOGVAL_PARSER(*context, LY_VCODE_MOD_SUBOMD, ly_stmt2str(kw));
+        LOGVAL_PARSER(*context, LY_VCODE_MOD_SUBOMD, lyplg_ext_stmt2str(kw));
         ret = LY_EVALID;
         goto cleanup;
     }
@@ -4851,7 +4798,7 @@
         ret = LY_EINVAL;
         goto cleanup;
     } else if (kw != LY_STMT_MODULE) {
-        LOGVAL_PARSER((*context), LY_VCODE_MOD_SUBOMD, ly_stmt2str(kw));
+        LOGVAL_PARSER((*context), LY_VCODE_MOD_SUBOMD, lyplg_ext_stmt2str(kw));
         ret = LY_EVALID;
         goto cleanup;
     }
diff --git a/src/parser_yin.c b/src/parser_yin.c
index 50f2b66..7382796 100644
--- a/src/parser_yin.c
+++ b/src/parser_yin.c
@@ -104,8 +104,10 @@
 
 struct yin_subelement {
     enum ly_stmt type;      /**< type of keyword */
-    void *dest;             /**< meta infromation passed to responsible function (mostly information about where parsed subelement should be stored) */
-    uint16_t flags;         /**< describes constraints of subelement can be set to YIN_SUBELEM_MANDATORY, YIN_SUBELEM_UNIQUE, YIN_SUBELEM_FIRST, YIN_SUBELEM_VER2, and YIN_SUBELEM_DEFAULT_TEXT */
+    void *dest;             /**< meta infromation passed to responsible function (mostly information about where parsed
+                                 subelement should be stored) */
+    uint16_t flags;         /**< describes constraints of subelement can be set to YIN_SUBELEM_MANDATORY,
+                                 YIN_SUBELEM_UNIQUE, YIN_SUBELEM_FIRST, YIN_SUBELEM_VER2, and YIN_SUBELEM_DEFAULT_TEXT */
 };
 
 /* Meta information passed to yin_parse_argument function,
@@ -158,7 +160,7 @@
 };
 
 LY_ERR yin_parse_content(struct lysp_yin_ctx *ctx, struct yin_subelement *subelem_info, size_t subelem_info_size,
-        enum ly_stmt current_element, const char **text_content, struct lysp_ext_instance **exts);
+        const void *parent, enum ly_stmt parent_stmt, const char **text_content, struct lysp_ext_instance **exts);
 
 /**
  * @brief Match yang keyword from yin data.
@@ -168,13 +170,12 @@
  * @param[in] name_len Lenght of keyword name.
  * @param[in] prefix Start of keyword prefix.
  * @param[in] prefix_len Lenght of prefix.
- * @param[in] parrent Identification of parrent element, use LY_STMT_NONE for elements without parrent.
- *
+ * @param[in] parent Identification of parent element, use LY_STMT_NONE for elements without parent.
  * @return yang_keyword values.
  */
 enum ly_stmt
-yin_match_keyword(struct lysp_yin_ctx *ctx, const char *name, size_t name_len,
-        const char *prefix, size_t prefix_len, enum ly_stmt parent)
+yin_match_keyword(struct lysp_yin_ctx *ctx, const char *name, size_t name_len, const char *prefix, size_t prefix_len,
+        enum ly_stmt parent)
 {
     const char *start = NULL;
     enum ly_stmt kw = LY_STMT_NONE;
@@ -221,7 +222,6 @@
  *
  * @param[in] name String representing name.
  * @param[in] len Lenght of the name.
- *
  * @return yin_argument values.
  */
 enum yin_argument
@@ -337,8 +337,7 @@
  * @param[in] count Number of subelements.
  * @param[in] parent Parent node if any.
  * @param[out] result Allocated subelems array.
- *
- * @return LY_SUCCESS on success LY_EMEM on memmory allocation failure.
+ * @return LY_ERR values.
  */
 static LY_ERR
 subelems_allocator(struct lysp_yin_ctx *ctx, size_t count, struct lysp_node *parent,
@@ -408,7 +407,6 @@
  *
  * @param[in] ctx Yin parser context for logging.
  * @param[in] val_type Type of the input string to select method of checking character validity.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -462,7 +460,6 @@
  * @param[out] arg_val Where value of argument should be stored. Can be NULL iff arg_type is specified as YIN_ARG_NONE.
  * @param[in] val_type Type of expected value of attribute.
  * @param[in] current_element Identification of current element, used for logging.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -482,7 +479,7 @@
                 LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
             } else if (arg == arg_type) {
                 LY_CHECK_ERR_RET(found, LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_DUP_ATTR,
-                        yin_attr2str(arg), ly_stmt2str(current_element)), LY_EVALID);
+                        yin_attr2str(arg), lyplg_ext_stmt2str(current_element)), LY_EVALID);
                 found = true;
 
                 /* go to value */
@@ -492,7 +489,7 @@
                 LY_CHECK_RET(!(*arg_val), LY_EMEM);
             } else {
                 LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_UNEXP_ATTR, ctx->xmlctx->name_len,
-                        ctx->xmlctx->name, ly_stmt2str(current_element));
+                        ctx->xmlctx->name, lyplg_ext_stmt2str(current_element));
                 return LY_EVALID;
             }
         } else {
@@ -507,7 +504,7 @@
     /* anything else than Y_MAYBE_STR_ARG is mandatory */
     if ((val_type != Y_MAYBE_STR_ARG) && !found) {
         LOGVAL_PARSER((struct lysp_ctx *)ctx, LYVE_SYNTAX_YIN, "Missing mandatory attribute %s of %s element.",
-                yin_attr2str(arg_type), ly_stmt2str(current_element));
+                yin_attr2str(arg_type), lyplg_ext_stmt2str(current_element));
         return LY_EVALID;
     }
 
@@ -520,7 +517,6 @@
  * @param[in] type Type of wanted record.
  * @param[in] array_size Size of array.
  * @param[in] array Searched array.
- *
  * @return Pointer to desired record on success, NULL if element is not in the array.
  */
 static struct yin_subelement *
@@ -541,7 +537,6 @@
  * @param[in] subelem_info Array of information about subelements.
  * @param[in] subelem_info_size Size of subelem_info array.
  * @param[in] current_element Identification of element that is currently being parsed, used for logging.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -552,7 +547,7 @@
         /* if there is element that is mandatory and isn't parsed log error and return LY_EVALID */
         if ((subelem_info[i].flags & YIN_SUBELEM_MANDATORY) && !(subelem_info[i].flags & YIN_SUBELEM_PARSED)) {
             LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_MAND_SUBELEM,
-                    ly_stmt2str(subelem_info[i].type), ly_stmt2str(current_element));
+                    lyplg_ext_stmt2str(subelem_info[i].type), lyplg_ext_stmt2str(current_element));
             return LY_EVALID;
         }
     }
@@ -568,7 +563,6 @@
  * @param[in] subelem_info_size Size of subelem_info array.
  * @param[in] current_element Identification of element that is currently being parsed, used for logging.
  * @param[in] exp_first Record in subelem_info array that is expected to be defined as first subelement, used for logging.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -579,7 +573,7 @@
     for (signed char i = 0; i < subelem_info_size; ++i) {
         if (subelem_info[i].flags & YIN_SUBELEM_PARSED) {
             LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_FIRT_SUBELEM,
-                    ly_stmt2str(exp_first->type), ly_stmt2str(current_element));
+                    lyplg_ext_stmt2str(exp_first->type), lyplg_ext_stmt2str(current_element));
             return LY_EVALID;
         }
     }
@@ -592,7 +586,8 @@
  * for example prefix or namespace element.
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
- * @param[in] kw Type of current element.
+ * @param[in] parent Current statement parent.
+ * @param[in] parent_stmt Type of @p parent statement.
  * @param[out] value Where value of attribute should be stored.
  * @param[in] arg_type Expected type of attribute.
  * @param[in] arg_val_type Type of expected value of attribute.
@@ -600,33 +595,34 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_simple_element(struct lysp_yin_ctx *ctx, enum ly_stmt kw, const char **value,
+yin_parse_simple_element(struct lysp_yin_ctx *ctx, const void *parent, enum ly_stmt parent_stmt, const char **value,
         enum yin_argument arg_type, enum yang_arg arg_val_type, struct lysp_ext_instance **exts)
 {
-    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
-    LY_CHECK_RET(yin_parse_attribute(ctx, arg_type, value, arg_val_type, kw));
     struct yin_subelement subelems[] = {
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
     };
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), kw, NULL, exts);
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, arg_type, value, arg_val_type, parent_stmt));
+
+    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), parent, parent_stmt, NULL, exts);
 }
 
 /**
  * @brief Parse path element.
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
- * @param[in] kw Type of current element.
  * @param[out] type Type structure to store parsed value, flags and extension instances.
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_path(struct lysp_yin_ctx *ctx, enum ly_stmt kw, struct lysp_type *type)
+yin_parse_path(struct lysp_yin_ctx *ctx, struct lysp_type *type)
 {
     LY_ERR ret;
     const char *str_path;
 
-    LY_CHECK_RET(yin_parse_simple_element(ctx, kw, &str_path, YIN_ARG_VALUE, Y_STR_ARG, &type->exts));
+    LY_CHECK_RET(yin_parse_simple_element(ctx, type, LY_STMT_PATH, &str_path, YIN_ARG_VALUE, Y_STR_ARG, &type->exts));
+
     ret = ly_path_parse(ctx->xmlctx->ctx, NULL, str_path, 0, 1, LY_PATH_BEGIN_EITHER,
             LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &type->path);
     lydict_remove(ctx->xmlctx->ctx, str_path);
@@ -674,7 +670,7 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
     };
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_PATTERN, NULL, &restr->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), restr, LY_STMT_PATTERN, NULL, &restr->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, restr->exts, 1, NULL));
@@ -724,7 +720,7 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
     };
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_FRACTION_DIGITS, NULL, &type->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), type, LY_STMT_FRACTION_DIGITS, NULL, &type->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, type->exts, 1, NULL));
@@ -761,7 +757,7 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
     };
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_ENUM, NULL, &en->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), en, LY_STMT_ENUM, NULL, &en->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, en->exts, 1, NULL));
@@ -796,7 +792,7 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
     };
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_BIT, NULL, &en->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), en, LY_STMT_BIT, NULL, &en->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, en->exts, 1, NULL));
@@ -809,7 +805,7 @@
  * more instances, such as base or if-feature.
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
- * @param[in] kw Type of current element.
+ * @param[in] parent_stmt Type of parent statement.
  * @param[out] values Parsed values to add to.
  * @param[in] arg_type Expected type of attribute.
  * @param[in] arg_val_type Type of expected value of attribute.
@@ -817,21 +813,21 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_simple_elements(struct lysp_yin_ctx *ctx, enum ly_stmt kw, const char ***values, enum yin_argument arg_type,
-        enum yang_arg arg_val_type, struct lysp_ext_instance **exts)
+yin_parse_simple_elements(struct lysp_yin_ctx *ctx, enum ly_stmt parent_stmt, const char ***values,
+        enum yin_argument arg_type, enum yang_arg arg_val_type, struct lysp_ext_instance **exts)
 {
     const char **value;
-
-    LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, *values, value, LY_EMEM);
-    LY_ARRAY_COUNT_TYPE index = LY_ARRAY_COUNT(*values) - 1;
+    LY_ARRAY_COUNT_TYPE index = LY_ARRAY_COUNT(*values);
     struct yin_subelement subelems[] = {
         {LY_STMT_EXTENSION_INSTANCE, &index, 0}
     };
 
-    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
-    LY_CHECK_RET(yin_parse_attribute(ctx, arg_type, value, arg_val_type, kw));
+    LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, *values, value, LY_EMEM);
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), kw, NULL, exts));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, arg_type, value, arg_val_type, parent_stmt));
+
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), *values, parent_stmt, NULL, exts));
 
     return LY_SUCCESS;
 }
@@ -840,7 +836,8 @@
  * @brief Parse simple element without any special constraints and argument mapped to yin attribute.
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
- * @param[in] kw Type of current element.
+ * @param[in] parent Current statement parent.
+ * @param[in] parent_stmt Type of @p parent statement.
  * @param[in] subinfo Information about subelement, is used to determin which function should be called and where to store parsed value.
  * @param[in] arg_type Expected type of attribute.
  * @param[in] arg_val_type Type of expected value of attribute.
@@ -848,15 +845,15 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_simple_elem(struct lysp_yin_ctx *ctx, enum ly_stmt kw, struct yin_subelement *subinfo,
+yin_parse_simple_elem(struct lysp_yin_ctx *ctx, const void *parent, enum ly_stmt parent_stmt, struct yin_subelement *subinfo,
         enum yin_argument arg_type, enum yang_arg arg_val_type, struct lysp_ext_instance **exts)
 {
     if (subinfo->flags & YIN_SUBELEM_UNIQUE) {
-        LY_CHECK_RET(yin_parse_simple_element(ctx, kw, (const char **)subinfo->dest,
-                arg_type, arg_val_type, exts));
+        LY_CHECK_RET(yin_parse_simple_element(ctx, parent, parent_stmt, (const char **)subinfo->dest, arg_type,
+                arg_val_type, exts));
     } else {
-        LY_CHECK_RET(yin_parse_simple_elements(ctx, kw, (const char ***)subinfo->dest,
-                arg_type, arg_val_type, exts));
+        LY_CHECK_RET(yin_parse_simple_elements(ctx, parent_stmt, (const char ***)subinfo->dest, arg_type,
+                arg_val_type, exts));
     }
 
     return LY_SUCCESS;
@@ -866,24 +863,22 @@
  * @brief Parse base element.
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
- * @param[in] parent Identification of parent element.
+ * @param[in] parent_stmt Type of parent statement.
  * @param[out] dest Where parsed values should be stored.
  * @param[in,out] exts Extension instances to add to.
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_base(struct lysp_yin_ctx *ctx, enum ly_stmt parent, void *dest, struct lysp_ext_instance **exts)
+yin_parse_base(struct lysp_yin_ctx *ctx, enum ly_stmt parent_stmt, void *dest, struct lysp_ext_instance **exts)
 {
-    struct lysp_type *type = NULL;
+    struct lysp_type *type;
 
-    if (parent == LY_STMT_TYPE) {
+    if (parent_stmt == LY_STMT_TYPE) {
         type = (struct lysp_type *)dest;
-        LY_CHECK_RET(yin_parse_simple_elements(ctx, LY_STMT_BASE, &type->bases, YIN_ARG_NAME,
-                Y_PREF_IDENTIF_ARG, exts));
+        LY_CHECK_RET(yin_parse_simple_elements(ctx, LY_STMT_BASE, &type->bases, YIN_ARG_NAME, Y_PREF_IDENTIF_ARG, exts));
         type->flags |= LYS_SET_BASE;
-    } else if (parent == LY_STMT_IDENTITY) {
-        LY_CHECK_RET(yin_parse_simple_elements(ctx, LY_STMT_BASE, (const char ***)dest,
-                YIN_ARG_NAME, Y_PREF_IDENTIF_ARG, exts));
+    } else if (parent_stmt == LY_STMT_IDENTITY) {
+        LY_CHECK_RET(yin_parse_simple_elements(ctx, LY_STMT_BASE, (const char ***)dest, YIN_ARG_NAME, Y_PREF_IDENTIF_ARG, exts));
     } else {
         LOGINT(ctx->xmlctx->ctx);
         return LY_EINT;
@@ -920,7 +915,7 @@
     }
     lydict_remove(ctx->xmlctx->ctx, temp_val);
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_REQUIRE_INSTANCE, NULL, &type->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), type, LY_STMT_REQUIRE_INSTANCE, NULL, &type->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, type->exts, 1, NULL));
@@ -932,21 +927,22 @@
  * @brief Parse modifier element.
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] parent Current statement parent.
  * @param[in,out] pat Value to write to.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_modifier(struct lysp_yin_ctx *ctx, const char **pat, struct lysp_ext_instance **exts)
+yin_parse_modifier(struct lysp_yin_ctx *ctx, const void *parent, const char **pat, struct lysp_ext_instance **exts)
 {
-    assert(**pat == 0x06);
     const char *temp_val;
     char *modified_val;
     struct yin_subelement subelems[] = {
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
     };
 
+    assert(**pat == 0x06);
+
     LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
     LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_MODIFIER));
     if (strcmp(temp_val, "invert-match") != 0) {
@@ -967,7 +963,7 @@
     modified_val[0] = LYSP_RESTR_PATTERN_NACK;
     LY_CHECK_RET(lydict_insert_zc(ctx->xmlctx->ctx, modified_val, pat));
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_MODIFIER, NULL, exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), parent, LY_STMT_MODIFIER, NULL, exts));
 
     return LY_SUCCESS;
 }
@@ -978,11 +974,11 @@
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in] restr_kw Identificaton of element that is being parsed, can be set to LY_STMT_MUST, LY_STMT_LENGTH or LY_STMT_RANGE.
  * @param[in] restr Value to write to.
+ * @return LY_ERR values.
  */
 static LY_ERR
 yin_parse_restriction(struct lysp_yin_ctx *ctx, enum ly_stmt restr_kw, struct lysp_restr *restr)
 {
-    assert(restr_kw == LY_STMT_MUST || restr_kw == LY_STMT_LENGTH || restr_kw == LY_STMT_RANGE);
     struct yin_subelement subelems[] = {
         {LY_STMT_DESCRIPTION, &restr->dsc, YIN_SUBELEM_UNIQUE},
         {LY_STMT_ERROR_APP_TAG, &restr->eapptag, YIN_SUBELEM_UNIQUE},
@@ -993,11 +989,13 @@
     /* argument of must is called condition, but argument of length and range is called value */
     enum yin_argument arg_type = (restr_kw == LY_STMT_MUST) ? YIN_ARG_CONDITION : YIN_ARG_VALUE;
 
+    assert(restr_kw == LY_STMT_MUST || restr_kw == LY_STMT_LENGTH || restr_kw == LY_STMT_RANGE);
+
     LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
     LY_CHECK_RET(yin_parse_attribute(ctx, arg_type, &restr->arg.str, Y_STR_ARG, restr_kw));
     restr->arg.mod = PARSER_CUR_PMOD(ctx);
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), restr_kw, NULL, &restr->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), restr, restr_kw, NULL, &restr->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, restr->exts, 1, NULL));
@@ -1007,10 +1005,8 @@
 
 /**
  * @brief Parse range element.
- *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[out] type Type structure to store parsed value and flags.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1029,7 +1025,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[out] type Type structure to store parsed value and flags.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1048,7 +1043,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in,out] restrs Restrictions to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1064,19 +1058,18 @@
  * @brief Parse a node id into an array.
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
- * @param[in] kw Type of current element.
+ * @param[in] parent_stmt Type of parent statement.
  * @param[in] subinfo Information about subelement, is used to determin which function should be called and where to store parsed value.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_qname(struct lysp_yin_ctx *ctx, enum ly_stmt kw, struct yin_subelement *subinfo,
+yin_parse_qname(struct lysp_yin_ctx *ctx, enum ly_stmt parent_stmt, struct yin_subelement *subinfo,
         struct lysp_ext_instance **exts)
 {
     struct lysp_qname *qname, **qnames;
 
-    switch (kw) {
+    switch (parent_stmt) {
     case LY_STMT_DEFAULT:
         if (subinfo->flags & YIN_SUBELEM_UNIQUE) {
             qname = (struct lysp_qname *)subinfo->dest;
@@ -1085,19 +1078,21 @@
             LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, *qnames, qname, LY_EMEM);
         }
         qname->mod = PARSER_CUR_PMOD(ctx);
-        return yin_parse_simple_element(ctx, kw, &qname->str, YIN_ARG_VALUE, Y_STR_ARG, exts);
+        return yin_parse_simple_element(ctx, qname, parent_stmt, &qname->str, YIN_ARG_VALUE, Y_STR_ARG, exts);
     case LY_STMT_UNIQUE:
         assert(!(subinfo->flags & YIN_SUBELEM_UNIQUE));
+
         qnames = (struct lysp_qname **)subinfo->dest;
         LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, *qnames, qname, LY_EMEM);
         qname->mod = PARSER_CUR_PMOD(ctx);
-        return yin_parse_simple_element(ctx, kw, &qname->str, YIN_ARG_TAG, Y_STR_ARG, exts);
+        return yin_parse_simple_element(ctx, *qnames, parent_stmt, &qname->str, YIN_ARG_TAG, Y_STR_ARG, exts);
     case LY_STMT_IF_FEATURE:
         assert(!(subinfo->flags & YIN_SUBELEM_UNIQUE));
+
         qnames = (struct lysp_qname **)subinfo->dest;
         LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, *qnames, qname, LY_EMEM);
         qname->mod = PARSER_CUR_PMOD(ctx);
-        return yin_parse_simple_element(ctx, kw, &qname->str, YIN_ARG_NAME, Y_STR_ARG, exts);
+        return yin_parse_simple_element(ctx, *qnames, parent_stmt, &qname->str, YIN_ARG_NAME, Y_STR_ARG, exts);
     default:
         break;
     }
@@ -1110,13 +1105,12 @@
  * @brief Parse position or value element.
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
- * @param[in] kw Type of current element, can be set to LY_STMT_POSITION or LY_STMT_VALUE.
+ * @param[in] parent_stmt Type of parent statement.
  * @param[out] enm Enum structure to save value, flags and extension instances.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_value_pos(struct lysp_yin_ctx *ctx, enum ly_stmt kw, struct lysp_type_enum *enm)
+yin_parse_value_pos(struct lysp_yin_ctx *ctx, enum ly_stmt parent_stmt, struct lysp_type_enum *enm)
 {
     LY_ERR ret = LY_SUCCESS;
     const char *temp_val = NULL;
@@ -1124,51 +1118,51 @@
     long long int num = 0;
     unsigned long long int unum = 0;
 
-    assert(kw == LY_STMT_POSITION || kw == LY_STMT_VALUE);
+    assert(parent_stmt == LY_STMT_POSITION || parent_stmt == LY_STMT_VALUE);
 
     /* set value flag */
     enm->flags |= LYS_SET_VALUE;
 
     /* get attribute value */
     LY_CHECK_GOTO(ret = lyxml_ctx_next(ctx->xmlctx), cleanup);
-    LY_CHECK_GOTO(ret = yin_parse_attribute(ctx, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, kw), cleanup);
+    LY_CHECK_GOTO(ret = yin_parse_attribute(ctx, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, parent_stmt), cleanup);
     if (!temp_val || (temp_val[0] == '\0') || (temp_val[0] == '+') ||
-            ((temp_val[0] == '0') && (temp_val[1] != '\0')) || ((kw == LY_STMT_POSITION) && !strcmp(temp_val, "-0"))) {
-        LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", ly_stmt2str(kw));
+            ((temp_val[0] == '0') && (temp_val[1] != '\0')) || ((parent_stmt == LY_STMT_POSITION) && !strcmp(temp_val, "-0"))) {
+        LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", lyplg_ext_stmt2str(parent_stmt));
         ret = LY_EVALID;
         goto cleanup;
     }
 
     /* convert value */
     errno = 0;
-    if (kw == LY_STMT_VALUE) {
+    if (parent_stmt == LY_STMT_VALUE) {
         num = strtoll(temp_val, &ptr, LY_BASE_DEC);
         if ((num < INT64_C(-2147483648)) || (num > INT64_C(2147483647))) {
-            LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", ly_stmt2str(kw));
+            LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", lyplg_ext_stmt2str(parent_stmt));
             ret = LY_EVALID;
             goto cleanup;
         }
     } else {
         unum = strtoull(temp_val, &ptr, LY_BASE_DEC);
         if (unum > UINT64_C(4294967295)) {
-            LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", ly_stmt2str(kw));
+            LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", lyplg_ext_stmt2str(parent_stmt));
             ret = LY_EVALID;
             goto cleanup;
         }
     }
     /* check if whole argument value was converted */
     if (*ptr != '\0') {
-        LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", ly_stmt2str(kw));
+        LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", lyplg_ext_stmt2str(parent_stmt));
         ret = LY_EVALID;
         goto cleanup;
     }
     if (errno == ERANGE) {
-        LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_OOB_YIN, temp_val, "value", ly_stmt2str(kw));
+        LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_OOB_YIN, temp_val, "value", lyplg_ext_stmt2str(parent_stmt));
         ret = LY_EVALID;
         goto cleanup;
     }
     /* save correctly ternary operator can't be used because num and unum have different signes */
-    if (kw == LY_STMT_VALUE) {
+    if (parent_stmt == LY_STMT_VALUE) {
         enm->value = num;
     } else {
         enm->value = unum;
@@ -1179,7 +1173,7 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
     };
 
-    LY_CHECK_GOTO(ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), kw, NULL, &enm->exts), cleanup);
+    LY_CHECK_GOTO(ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), enm, parent_stmt, NULL, &enm->exts), cleanup);
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_GOTO(ret = ly_set_add(&ctx->ext_inst, enm->exts, 1, NULL), cleanup);
@@ -1195,7 +1189,6 @@
  * @param[in] ctx YIN parser context for logging and to store current state.
  * @param[out] submod Structure of submodule that is being parsed.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values
  */
 static LY_ERR
@@ -1217,7 +1210,7 @@
     }
     lydict_remove(ctx->xmlctx->ctx, belongsto);
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_BELONGS_TO, NULL, exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), submod, LY_STMT_BELONGS_TO, NULL, exts));
 
     return LY_SUCCESS;
 }
@@ -1227,28 +1220,30 @@
  * text element as child.
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
- * @param[in] elem_type Type of element can be set to LY_STMT_ORGANIZATION or LY_STMT_CONTACT or LY_STMT_DESCRIPTION or LY_STMT_REFERENCE.
+ * @param[in] parent Current statement parent.
+ * @param[in] parent_stmt Type of @p parent statement.
  * @param[out] value Where the content of meta element should be stored.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_meta(struct lysp_yin_ctx *ctx, enum ly_stmt elem_type, const char **value, struct lysp_ext_instance **exts)
+yin_parse_meta(struct lysp_yin_ctx *ctx, const void *parent, enum ly_stmt parent_stmt, const char **value,
+        struct lysp_ext_instance **exts)
 {
-    assert(elem_type == LY_STMT_ORGANIZATION || elem_type == LY_STMT_CONTACT || elem_type == LY_STMT_DESCRIPTION || elem_type == LY_STMT_REFERENCE);
-
     struct yin_subelement subelems[] = {
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
         {LY_STMT_ARG_TEXT, value, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE | YIN_SUBELEM_FIRST}
     };
 
+    assert(parent_stmt == LY_STMT_ORGANIZATION || parent_stmt == LY_STMT_CONTACT || parent_stmt == LY_STMT_DESCRIPTION ||
+            parent_stmt == LY_STMT_REFERENCE);
+
     /* check attributes */
     LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
-    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NONE, NULL, Y_MAYBE_STR_ARG, elem_type));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NONE, NULL, Y_MAYBE_STR_ARG, parent_stmt));
 
     /* parse content */
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), elem_type, NULL, exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), parent, parent_stmt, NULL, exts));
 
     return LY_SUCCESS;
 }
@@ -1257,13 +1252,13 @@
  * @brief Parse error-message element.
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] parent Current statement parent.
  * @param[out] value Where the content of error-message element should be stored.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_err_msg(struct lysp_yin_ctx *ctx, const char **value, struct lysp_ext_instance **exts)
+yin_parse_err_msg(struct lysp_yin_ctx *ctx, const void *parent, const char **value, struct lysp_ext_instance **exts)
 {
     struct yin_subelement subelems[] = {
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
@@ -1274,7 +1269,7 @@
     LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
     LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NONE, NULL, Y_MAYBE_STR_ARG, LY_STMT_ERROR_MESSAGE));
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_ERROR_MESSAGE, NULL, exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), parent, LY_STMT_ERROR_MESSAGE, NULL, exts));
 
     return LY_SUCCESS;
 }
@@ -1283,17 +1278,17 @@
  * @brief Parse type element.
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
- * @param[in] parent Identification of parent element.
- * @param[in,out] type Type to write to.
- *
+ * @param[in] parent_stmt Type of parent statement.
+ * @param[in,out] subinfo Information about subelement, is used to determin which function should be called and where
+ * to store parsed value.
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_type(struct lysp_yin_ctx *ctx, enum ly_stmt parent, struct yin_subelement *subinfo)
+yin_parse_type(struct lysp_yin_ctx *ctx, enum ly_stmt parent_stmt, struct yin_subelement *subinfo)
 {
     struct lysp_type *type = NULL;
 
-    if (parent == LY_STMT_DEVIATE) {
+    if (parent_stmt == LY_STMT_DEVIATE) {
         *(struct lysp_type **)subinfo->dest = calloc(1, sizeof **(struct lysp_type **)subinfo->dest);
         LY_CHECK_ERR_RET(!(*(struct lysp_type **)subinfo->dest), LOGMEM(ctx->xmlctx->ctx), LY_EMEM);
         type = *((struct lysp_type **)subinfo->dest);
@@ -1302,7 +1297,7 @@
     }
 
     /* type as child of another type */
-    if (parent == LY_STMT_TYPE) {
+    if (parent_stmt == LY_STMT_TYPE) {
         struct lysp_type *nested_type = NULL;
 
         LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, type->types, nested_type, LY_EMEM);
@@ -1328,7 +1323,7 @@
 
     LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
     LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &type->name, Y_PREF_IDENTIF_ARG, LY_STMT_TYPE));
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_TYPE, NULL, &type->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), type, LY_STMT_TYPE, NULL, &type->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, type->exts, 1, NULL));
@@ -1343,7 +1338,6 @@
  * @param[in,out] max Value to write to.
  * @param[in] flags Flags to write to.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1382,7 +1376,8 @@
         *max = num;
     }
 
-    LY_CHECK_GOTO(ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_MAX_ELEMENTS, NULL, exts), cleanup);
+    ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), max, LY_STMT_MAX_ELEMENTS, NULL, exts);
+    LY_CHECK_GOTO(ret, cleanup);
 
 cleanup:
     lydict_remove(ctx->xmlctx->ctx, temp_val);
@@ -1396,7 +1391,6 @@
  * @param[in,out] min Value to write to.
  * @param[in] flags Flags to write to.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1433,7 +1427,7 @@
     }
     *min = num;
     lydict_remove(ctx->xmlctx->ctx, temp_val);
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_MIN_ELEMENTS, NULL, exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), min, LY_STMT_MIN_ELEMENTS, NULL, exts));
 
     return LY_SUCCESS;
 }
@@ -1442,31 +1436,32 @@
  * @brief Parse min-elements or max-elements element.
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
- * @param[in] parent Identification of parent element.
- * @param[in] current Identification of current element.
+ * @param[in] parent_stmt Type of parent statement.
+ * @param[in] cur_stmt Type of current element.
  * @param[in] dest Where the parsed value and flags should be stored.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_minmax(struct lysp_yin_ctx *ctx, enum ly_stmt parent, enum ly_stmt current, void *dest)
+yin_parse_minmax(struct lysp_yin_ctx *ctx, enum ly_stmt parent_stmt, enum ly_stmt cur_stmt, void *dest)
 {
-    assert(current == LY_STMT_MAX_ELEMENTS || current == LY_STMT_MIN_ELEMENTS);
-    assert(parent == LY_STMT_LEAF_LIST || parent == LY_STMT_REFINE || parent == LY_STMT_LIST || parent == LY_STMT_DEVIATE);
     uint32_t *lim;
     uint16_t *flags;
     struct lysp_ext_instance **exts;
 
-    if (parent == LY_STMT_LEAF_LIST) {
-        lim = (current == LY_STMT_MAX_ELEMENTS) ? &((struct lysp_node_leaflist *)dest)->max : &((struct lysp_node_leaflist *)dest)->min;
+    assert(cur_stmt == LY_STMT_MAX_ELEMENTS || cur_stmt == LY_STMT_MIN_ELEMENTS);
+    assert(parent_stmt == LY_STMT_LEAF_LIST || parent_stmt == LY_STMT_REFINE || parent_stmt == LY_STMT_LIST ||
+            parent_stmt == LY_STMT_DEVIATE);
+
+    if (parent_stmt == LY_STMT_LEAF_LIST) {
+        lim = (cur_stmt == LY_STMT_MAX_ELEMENTS) ? &((struct lysp_node_leaflist *)dest)->max : &((struct lysp_node_leaflist *)dest)->min;
         flags = &((struct lysp_node_leaflist *)dest)->flags;
         exts = &((struct lysp_node_leaflist *)dest)->exts;
-    } else if (parent == LY_STMT_REFINE) {
-        lim = (current == LY_STMT_MAX_ELEMENTS) ? &((struct lysp_refine *)dest)->max : &((struct lysp_refine *)dest)->min;
+    } else if (parent_stmt == LY_STMT_REFINE) {
+        lim = (cur_stmt == LY_STMT_MAX_ELEMENTS) ? &((struct lysp_refine *)dest)->max : &((struct lysp_refine *)dest)->min;
         flags = &((struct lysp_refine *)dest)->flags;
         exts = &((struct lysp_refine *)dest)->exts;
-    } else if (parent == LY_STMT_LIST) {
-        lim = (current == LY_STMT_MAX_ELEMENTS) ? &((struct lysp_node_list *)dest)->max : &((struct lysp_node_list *)dest)->min;
+    } else if (parent_stmt == LY_STMT_LIST) {
+        lim = (cur_stmt == LY_STMT_MAX_ELEMENTS) ? &((struct lysp_node_list *)dest)->max : &((struct lysp_node_list *)dest)->min;
         flags = &((struct lysp_node_list *)dest)->flags;
         exts = &((struct lysp_node_list *)dest)->exts;
     } else {
@@ -1475,7 +1470,7 @@
         exts = ((struct minmax_dev_meta *)dest)->exts;
     }
 
-    if (current == LY_STMT_MAX_ELEMENTS) {
+    if (cur_stmt == LY_STMT_MAX_ELEMENTS) {
         LY_CHECK_RET(yin_parse_maxelements(ctx, lim, flags, exts));
     } else {
         LY_CHECK_RET(yin_parse_minelements(ctx, lim, flags, exts));
@@ -1488,13 +1483,13 @@
  * @brief Parse ordered-by element.
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] parent Current statement parent.
  * @param[out] flags Flags to write to.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_orderedby(struct lysp_yin_ctx *ctx, uint16_t *flags, struct lysp_ext_instance **exts)
+yin_parse_orderedby(struct lysp_yin_ctx *ctx, const void *parent, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     const char *temp_val;
     struct yin_subelement subelems[] = {
@@ -1515,7 +1510,7 @@
     }
     lydict_remove(ctx->xmlctx->ctx, temp_val);
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_ORDERED_BY, NULL, exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), parent, LY_STMT_ORDERED_BY, NULL, exts));
 
     return LY_SUCCESS;
 }
@@ -1524,9 +1519,8 @@
  * @brief Parse any-data or any-xml element.
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
- * @param[in] any_kw Identification of current element, can be set to LY_STMT_ANYDATA or LY_STMT_ANYXML
+ * @param[in] any_stmt Type of current statement, can be set to LY_STMT_ANYDATA or LY_STMT_ANYXML
  * @param[in] node_meta Meta information about parent node and siblings to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1555,7 +1549,7 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
     };
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), any_kw, NULL, &any->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), any, any_kw, NULL, &any->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, any->exts, 1, NULL));
@@ -1568,7 +1562,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in] node_meta Meta information about parent node and siblings to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1601,7 +1594,7 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
     };
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_LEAF, NULL, &leaf->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), leaf, LY_STMT_LEAF, NULL, &leaf->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, leaf->exts, 1, NULL));
@@ -1614,7 +1607,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in] node_meta Meta information about parent node and siblings to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1649,7 +1641,7 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
     };
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_LEAF_LIST, NULL, &llist->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), llist, LY_STMT_LEAF_LIST, NULL, &llist->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, llist->exts, 1, NULL));
@@ -1672,7 +1664,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in] typedef_meta Meta information about parent node and typedefs to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1698,7 +1689,7 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
     };
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_TYPEDEF, NULL, &tpdf->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), tpdf, LY_STMT_TYPEDEF, NULL, &tpdf->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, tpdf->exts, 1, NULL));
@@ -1717,7 +1708,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in,out] refines Refines to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1748,7 +1738,7 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
     };
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_REFINE, NULL, &rf->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), rf, LY_STMT_REFINE, NULL, &rf->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, rf->exts, 1, NULL));
@@ -1761,7 +1751,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in] node_meta Meta information about parent node and siblings to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1791,7 +1780,7 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
     };
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_USES, NULL, &uses->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), uses, LY_STMT_USES, NULL, &uses->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, uses->exts, 1, NULL));
@@ -1804,7 +1793,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in,out] revs Parsed revisions to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1834,7 +1822,7 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
     };
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_REVISION, NULL, &rev->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), rev, LY_STMT_REVISION, NULL, &rev->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, rev->exts, 1, NULL));
@@ -1847,7 +1835,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in,out] inc_meta Meta informatinou about module/submodule name and includes to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1877,7 +1864,7 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
     };
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_INCLUDE, NULL, &inc->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), inc, LY_STMT_INCLUDE, NULL, &inc->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, inc->exts, 1, NULL));
@@ -1891,7 +1878,6 @@
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in,out] rev Array to store the parsed value in.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1910,7 +1896,7 @@
     strcpy(rev, temp_rev);
     lydict_remove(ctx->xmlctx->ctx, temp_rev);
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_REVISION_DATE, NULL, exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), rev, LY_STMT_REVISION_DATE, NULL, exts));
 
     return LY_SUCCESS;
 }
@@ -1921,7 +1907,6 @@
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in,out] flags Flags to add to.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -1946,7 +1931,7 @@
     }
     lydict_remove(ctx->xmlctx->ctx, temp_val);
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_CONFIG, NULL, exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), flags, LY_STMT_CONFIG, NULL, exts));
 
     return LY_SUCCESS;
 }
@@ -1955,13 +1940,13 @@
  * @brief Parse yang-version element.
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] parent Current statement parent.
  * @param[out] version Storage for the parsed information.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_yangversion(struct lysp_yin_ctx *ctx, uint8_t *version, struct lysp_ext_instance **exts)
+yin_parse_yangversion(struct lysp_yin_ctx *ctx, const void *parent, uint8_t *version, struct lysp_ext_instance **exts)
 {
     const char *temp_version = NULL;
     struct yin_subelement subelems[] = {
@@ -1982,7 +1967,7 @@
     }
     lydict_remove(ctx->xmlctx->ctx, temp_version);
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_YANG_VERSION, NULL, exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), parent, LY_STMT_YANG_VERSION, NULL, exts));
 
     return LY_SUCCESS;
 }
@@ -1992,7 +1977,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in,out] imp_meta Meta information about prefix and imports to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2014,7 +1998,7 @@
     /* parse import attributes */
     LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
     LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_MODULE, &imp->name, Y_IDENTIF_ARG, LY_STMT_IMPORT));
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_IMPORT, NULL, &imp->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), imp, LY_STMT_IMPORT, NULL, &imp->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, imp->exts, 1, NULL));
@@ -2031,7 +2015,6 @@
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in,out] flags Flags to add to.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2056,7 +2039,7 @@
     }
     lydict_remove(ctx->xmlctx->ctx, temp_val);
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_MANDATORY, NULL, exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), flags, LY_STMT_MANDATORY, NULL, exts));
 
     return LY_SUCCESS;
 }
@@ -2067,7 +2050,6 @@
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in,out] flags Flags to add to.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2094,7 +2076,7 @@
     }
     lydict_remove(ctx->xmlctx->ctx, value);
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_STATUS, NULL, exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), flags, LY_STMT_STATUS, NULL, exts));
 
     return LY_SUCCESS;
 }
@@ -2104,6 +2086,7 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[out] when_p When pointer to parse to.
+ * @return LY_ERR values.
  */
 static LY_ERR
 yin_parse_when(struct lysp_yin_ctx *ctx, struct lysp_when **when_p)
@@ -2127,7 +2110,7 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
     };
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_WHEN, NULL, &when->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), when, LY_STMT_WHEN, NULL, &when->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, when->exts, 1, NULL));
@@ -2139,14 +2122,13 @@
  * @brief Parse yin-elemenet element.
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
- * @param[in,out] data Data to read from, always moved to currently handled position.
+ * @param[in] parent Current statement parent.
  * @param[in,out] flags Flags to add to.
- * @prama[in,out] exts Extension instances to add to.
- *
+ * @param[in,out] exts Extension instances to add to.
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_yin_element(struct lysp_yin_ctx *ctx, uint16_t *flags, struct lysp_ext_instance **exts)
+yin_parse_yin_element(struct lysp_yin_ctx *ctx, const void *parent, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     const char *temp_val = NULL;
     struct yin_subelement subelems[] = {
@@ -2167,7 +2149,7 @@
     }
     lydict_remove(ctx->xmlctx->ctx, temp_val);
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_YIN_ELEMENT, NULL, exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), parent, LY_STMT_YIN_ELEMENT, NULL, exts));
 
     return LY_SUCCESS;
 }
@@ -2175,14 +2157,14 @@
 /**
  * @brief Parse argument element.
  *
- * @param[in,out] xmlctx Xml context.
- * @param[in,out] arg_meta Meta information about destionation of parsed data.
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] parent Current statement parent.
+ * @param[in,out] arg_meta Meta information about destination of parsed data.
  * @param[in,out] exts Extension instances to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_argument(struct lysp_yin_ctx *ctx, struct yin_argument_meta *arg_meta, struct lysp_ext_instance **exts)
+yin_parse_argument(struct lysp_yin_ctx *ctx, const void *parent, struct yin_argument_meta *arg_meta, struct lysp_ext_instance **exts)
 {
     struct yin_subelement subelems[] = {
         {LY_STMT_YIN_ELEMENT, arg_meta->flags, YIN_SUBELEM_UNIQUE},
@@ -2192,7 +2174,7 @@
     LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
     LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, arg_meta->argument, Y_IDENTIF_ARG, LY_STMT_ARGUMENT));
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_ARGUMENT, NULL, exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), parent, LY_STMT_ARGUMENT, NULL, exts));
 
     return LY_SUCCESS;
 }
@@ -2202,7 +2184,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in,out] extensions Extensions to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2223,7 +2204,7 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
     };
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_EXTENSION, NULL, &ex->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), ex, LY_STMT_EXTENSION, NULL, &ex->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, ex->exts, 1, NULL));
@@ -2236,7 +2217,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in,out] features Features to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2260,7 +2240,7 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
     };
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_FEATURE, NULL, &feat->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), feat, LY_STMT_FEATURE, NULL, &feat->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, feat->exts, 1, NULL));
@@ -2273,7 +2253,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in,out] identities Identities to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2298,7 +2277,7 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
     };
 
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_IDENTITY, NULL, &ident->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), ident, LY_STMT_IDENTITY, NULL, &ident->exts));
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, ident->exts, 1, NULL));
@@ -2311,7 +2290,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in] node_meta Meta information about parent node and siblings to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2357,7 +2335,7 @@
             LY_STMT_USES, &list->child, 0,
             LY_STMT_WHEN, &list->when, YIN_SUBELEM_UNIQUE,
             LY_STMT_EXTENSION_INSTANCE, NULL, 0));
-    ret = yin_parse_content(ctx, subelems, subelems_size, LY_STMT_LIST, NULL, &list->exts);
+    ret = yin_parse_content(ctx, subelems, subelems_size, list, LY_STMT_LIST, NULL, &list->exts);
     subelems_deallocator(subelems_size, subelems);
     LY_CHECK_RET(ret);
 
@@ -2377,7 +2355,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in,out] notif_meta Meta information about parent node and notifications to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2417,7 +2394,7 @@
             LY_STMT_USES, &notif->child, 0,
             LY_STMT_EXTENSION_INSTANCE, NULL, 0));
 
-    ret = yin_parse_content(ctx, subelems, subelems_size, LY_STMT_NOTIFICATION, NULL, &notif->exts);
+    ret = yin_parse_content(ctx, subelems, subelems_size, notif, LY_STMT_NOTIFICATION, NULL, &notif->exts);
     subelems_deallocator(subelems_size, subelems);
     LY_CHECK_RET(ret);
 
@@ -2432,7 +2409,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in,out] gr_meta Meta information about parent node and groupings to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2471,7 +2447,7 @@
             LY_STMT_TYPEDEF, &grp->typedefs, 0,
             LY_STMT_USES, &grp->child, 0,
             LY_STMT_EXTENSION_INSTANCE, NULL, 0));
-    ret = yin_parse_content(ctx, subelems, subelems_size, LY_STMT_GROUPING, NULL, &grp->exts);
+    ret = yin_parse_content(ctx, subelems, subelems_size, grp, LY_STMT_GROUPING, NULL, &grp->exts);
     subelems_deallocator(subelems_size, subelems);
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
@@ -2491,7 +2467,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in] node_meta Meta information about parent node and siblings to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2534,7 +2509,7 @@
             LY_STMT_USES, &cont->child, 0,
             LY_STMT_WHEN, &cont->when, YIN_SUBELEM_UNIQUE,
             LY_STMT_EXTENSION_INSTANCE, NULL, 0));
-    ret = yin_parse_content(ctx, subelems, subelems_size, LY_STMT_CONTAINER, NULL, &cont->exts);
+    ret = yin_parse_content(ctx, subelems, subelems_size, cont, LY_STMT_CONTAINER, NULL, &cont->exts);
     subelems_deallocator(subelems_size, subelems);
     LY_CHECK_RET(ret);
 
@@ -2549,7 +2524,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in] node_meta Meta information about parent node and siblings to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2585,7 +2559,7 @@
             LY_STMT_USES, &cas->child, 0,
             LY_STMT_WHEN, &cas->when, YIN_SUBELEM_UNIQUE,
             LY_STMT_EXTENSION_INSTANCE, NULL, 0));
-    ret = yin_parse_content(ctx, subelems, subelems_size, LY_STMT_CASE, NULL, &cas->exts);
+    ret = yin_parse_content(ctx, subelems, subelems_size, cas, LY_STMT_CASE, NULL, &cas->exts);
     subelems_deallocator(subelems_size, subelems);
     LY_CHECK_RET(ret);
 
@@ -2600,7 +2574,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in] node_meta Meta information about parent node and siblings to add to.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -2640,7 +2613,7 @@
             LY_STMT_STATUS, &choice->flags, YIN_SUBELEM_UNIQUE,
             LY_STMT_WHEN, &choice->when, YIN_SUBELEM_UNIQUE,
             LY_STMT_EXTENSION_INSTANCE, NULL, 0));
-    ret = yin_parse_content(ctx, subelems, subelems_size, LY_STMT_CHOICE, NULL, &choice->exts);
+    ret = yin_parse_content(ctx, subelems, subelems_size, choice, LY_STMT_CHOICE, NULL, &choice->exts);
     subelems_deallocator(subelems_size, subelems);
     LY_CHECK_RET(ret);
 
@@ -2656,7 +2629,6 @@
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in] inout_kw Identification of input/output element.
  * @param[in] inout_meta Meta information about parent node and siblings and input/output pointer to write to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2689,7 +2661,7 @@
             LY_STMT_TYPEDEF, &inout_meta->inout_p->typedefs, 0,
             LY_STMT_USES, &inout_meta->inout_p->child, 0,
             LY_STMT_EXTENSION_INSTANCE, NULL, 0));
-    ret = yin_parse_content(ctx, subelems, subelems_size, inout_kw, NULL, &inout_meta->inout_p->exts);
+    ret = yin_parse_content(ctx, subelems, subelems_size, inout_meta->inout_p, inout_kw, NULL, &inout_meta->inout_p->exts);
     subelems_deallocator(subelems_size, subelems);
     LY_CHECK_RET(ret);
 
@@ -2697,7 +2669,7 @@
     LY_CHECK_RET(ly_set_add(&ctx->ext_inst, inout_meta->inout_p->exts, 1, NULL));
 
     if (!inout_meta->inout_p->child) {
-        LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_MISSTMT, "data-def-stmt", ly_stmt2str(inout_kw));
+        LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_MISSTMT, "data-def-stmt", lyplg_ext_stmt2str(inout_kw));
         return LY_EVALID;
     }
 
@@ -2709,7 +2681,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in] act_meta Meta information about parent node and actions to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2741,7 +2712,7 @@
             LY_STMT_STATUS, &act->flags, YIN_SUBELEM_UNIQUE,
             LY_STMT_TYPEDEF, &act->typedefs, 0,
             LY_STMT_EXTENSION_INSTANCE, NULL, 0));
-    ret = (yin_parse_content(ctx, subelems, subelems_size, kw, NULL, &act->exts));
+    ret = (yin_parse_content(ctx, subelems, subelems_size, act, kw, NULL, &act->exts));
     subelems_deallocator(subelems_size, subelems);
     LY_CHECK_RET(ret);
 
@@ -2765,7 +2736,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in] aug_meta Meta information about parent node and augments to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2806,7 +2776,7 @@
             LY_STMT_USES, &aug->child, 0,
             LY_STMT_WHEN, &aug->when, YIN_SUBELEM_UNIQUE,
             LY_STMT_EXTENSION_INSTANCE, NULL, 0));
-    ret = yin_parse_content(ctx, subelems, subelems_size, LY_STMT_AUGMENT, NULL, &aug->exts);
+    ret = yin_parse_content(ctx, subelems, subelems_size, aug, LY_STMT_AUGMENT, NULL, &aug->exts);
     subelems_deallocator(subelems_size, subelems);
     LY_CHECK_RET(ret);
 
@@ -2821,7 +2791,6 @@
  *
  * @param[in,out] ctx YIN parser context for logging and to store current state.
  * @param[in] deviates Deviates to add to.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -2862,7 +2831,7 @@
             {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
         };
 
-        ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_DEVIATE, NULL, &d->exts);
+        ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), d, LY_STMT_DEVIATE, NULL, &d->exts);
 
     } else if (dev_mod == LYS_DEV_ADD) {
         d_add = calloc(1, sizeof *d_add);
@@ -2882,7 +2851,7 @@
             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
         };
 
-        ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_DEVIATE, NULL, &d->exts);
+        ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), d, LY_STMT_DEVIATE, NULL, &d->exts);
 
     } else if (dev_mod == LYS_DEV_REPLACE) {
         d_rpl = calloc(1, sizeof *d_rpl);
@@ -2901,7 +2870,7 @@
             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
         };
 
-        ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems),  LY_STMT_DEVIATE, NULL, &d->exts);
+        ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), d, LY_STMT_DEVIATE, NULL, &d->exts);
 
     } else {
         d_del = calloc(1, sizeof *d_del);
@@ -2915,7 +2884,7 @@
             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
         };
 
-        ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_DEVIATE, NULL, &d->exts);
+        ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), d, LY_STMT_DEVIATE, NULL, &d->exts);
     }
     LY_CHECK_GOTO(ret, cleanup);
 
@@ -2961,7 +2930,8 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
     };
 
-    LY_CHECK_GOTO(ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_DEVIATION, NULL, &dev->exts), cleanup);
+    ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), dev, LY_STMT_DEVIATION, NULL, &dev->exts);
+    LY_CHECK_GOTO(ret, cleanup);
 
     /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
     LY_CHECK_GOTO(ret = ly_set_add(&ctx->ext_inst, dev->exts, 1, NULL), cleanup);
@@ -3043,28 +3013,30 @@
  * @brief Check if relative order of two keywords is valid.
  *
  * @param[in] ctx YIN parser context used for logging.
- * @param[in] kw Current keyword.
- * @param[in] next_kw Next keyword.
- * @param[in] parrent Identification of parrent element, can be se to to LY_STMT_MODULE of LY_STMT_SUBMODULE,
+ * @param[in] cur_stmt Type of current statement.
+ * @param[in] next_stmt Type of next statement.
+ * @param[in] parent_stmt Type of parent statement, can be se to to LY_STMT_MODULE of LY_STMT_SUBMODULE,
  *            because relative order is required only in module and submodule sub-elements, used for logging.
  * @return LY_SUCCESS on success and LY_EVALID if relative order is invalid.
  */
 static LY_ERR
-yin_check_relative_order(struct lysp_yin_ctx *ctx, enum ly_stmt kw, enum ly_stmt next_kw, enum ly_stmt parrent)
+yin_check_relative_order(struct lysp_yin_ctx *ctx, enum ly_stmt cur_stmt, enum ly_stmt next_stmt, enum ly_stmt parent_stmt)
 {
-    assert(parrent == LY_STMT_MODULE || parrent == LY_STMT_SUBMODULE);
     enum yang_module_stmt gr, next_gr;
 
-    if (kw == LY_STMT_EXTENSION_INSTANCE) {
+    assert(parent_stmt == LY_STMT_MODULE || parent_stmt == LY_STMT_SUBMODULE);
+
+    if (cur_stmt == LY_STMT_EXTENSION_INSTANCE) {
         /* no order defined */
         return LY_SUCCESS;
     }
 
-    LY_CHECK_RET(kw2kw_group(ctx, kw, &gr));
-    LY_CHECK_RET(kw2kw_group(ctx, next_kw, &next_gr));
+    LY_CHECK_RET(kw2kw_group(ctx, cur_stmt, &gr));
+    LY_CHECK_RET(kw2kw_group(ctx, next_stmt, &next_gr));
 
     if (gr > next_gr) {
-        LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_INORDER_YIN, ly_stmt2str(parrent), ly_stmt2str(next_kw), ly_stmt2str(kw));
+        LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_INORDER_YIN, lyplg_ext_stmt2str(parent_stmt), lyplg_ext_stmt2str(next_stmt),
+                lyplg_ext_stmt2str(cur_stmt));
         return LY_EVALID;
     }
 
@@ -3075,18 +3047,18 @@
  * @brief Parse argument of extension subelement that is classic yang keyword and not another instance of extension.
  *
  * @param[in,out] ctx Yin parser context for logging and to store current state.
- * @param[in] elem_type Type of element that is currently being parsed.
+ * @param[in] parent_stmt Type of parent statement.
  * @param[out] arg Value to write to.
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_extension_instance_arg(struct lysp_yin_ctx *ctx, enum ly_stmt elem_type, const char **arg)
+yin_parse_extension_instance_arg(struct lysp_yin_ctx *ctx, enum ly_stmt parent_stmt, const char **arg)
 {
     enum ly_stmt child;
 
     LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
 
-    switch (elem_type) {
+    switch (parent_stmt) {
     case LY_STMT_ACTION:
     case LY_STMT_ANYDATA:
     case LY_STMT_ANYXML:
@@ -3113,12 +3085,12 @@
     case LY_STMT_TYPEDEF:
     case LY_STMT_UNITS:
     case LY_STMT_USES:
-        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, arg, Y_MAYBE_STR_ARG, elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, arg, Y_MAYBE_STR_ARG, parent_stmt));
         break;
     case LY_STMT_AUGMENT:
     case LY_STMT_DEVIATION:
     case LY_STMT_REFINE:
-        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_TARGET_NODE, arg, Y_MAYBE_STR_ARG, elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_TARGET_NODE, arg, Y_MAYBE_STR_ARG, parent_stmt));
         break;
     case LY_STMT_CONFIG:
     case LY_STMT_DEFAULT:
@@ -3143,30 +3115,30 @@
     case LY_STMT_VALUE:
     case LY_STMT_YANG_VERSION:
     case LY_STMT_YIN_ELEMENT:
-        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_VALUE, arg, Y_MAYBE_STR_ARG, elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_VALUE, arg, Y_MAYBE_STR_ARG, parent_stmt));
         break;
     case LY_STMT_IMPORT:
     case LY_STMT_INCLUDE:
     case LY_STMT_BELONGS_TO:
-        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_MODULE, arg, Y_MAYBE_STR_ARG, elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_MODULE, arg, Y_MAYBE_STR_ARG, parent_stmt));
         break;
     case LY_STMT_INPUT:
     case LY_STMT_OUTPUT:
-        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NONE, arg, Y_MAYBE_STR_ARG, elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NONE, arg, Y_MAYBE_STR_ARG, parent_stmt));
         break;
     case LY_STMT_MUST:
     case LY_STMT_WHEN:
-        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_CONDITION, arg, Y_MAYBE_STR_ARG, elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_CONDITION, arg, Y_MAYBE_STR_ARG, parent_stmt));
         break;
     case LY_STMT_NAMESPACE:
-        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_URI, arg, Y_MAYBE_STR_ARG, elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_URI, arg, Y_MAYBE_STR_ARG, parent_stmt));
         break;
     case LY_STMT_REVISION:
     case LY_STMT_REVISION_DATE:
-        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_DATE, arg, Y_MAYBE_STR_ARG, elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_DATE, arg, Y_MAYBE_STR_ARG, parent_stmt));
         break;
     case LY_STMT_UNIQUE:
-        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_TAG, arg, Y_MAYBE_STR_ARG, elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_TAG, arg, Y_MAYBE_STR_ARG, parent_stmt));
         break;
     /* argument is mapped to yin element */
     case LY_STMT_CONTACT:
@@ -3175,7 +3147,7 @@
     case LY_STMT_REFERENCE:
     case LY_STMT_ERROR_MESSAGE:
         /* there shouldn't be any attribute, argument is supposed to be first subelement */
-        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NONE, arg, Y_MAYBE_STR_ARG, elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NONE, arg, Y_MAYBE_STR_ARG, parent_stmt));
 
         /* no content */
         assert(ctx->xmlctx->status == LYXML_ELEM_CONTENT);
@@ -3184,21 +3156,22 @@
         }
         if (((ctx->xmlctx->status == LYXML_ELEM_CONTENT) && !ctx->xmlctx->ws_only) || (ctx->xmlctx->status != LYXML_ELEMENT)) {
             LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_FIRT_SUBELEM,
-                    elem_type == LY_STMT_ERROR_MESSAGE ? "value" : "text", ly_stmt2str(elem_type));
+                    parent_stmt == LY_STMT_ERROR_MESSAGE ? "value" : "text", lyplg_ext_stmt2str(parent_stmt));
             return LY_EVALID;
         }
 
         /* parse child element */
-        child = yin_match_keyword(ctx, ctx->xmlctx->name, ctx->xmlctx->name_len, ctx->xmlctx->prefix, ctx->xmlctx->prefix_len, elem_type);
-        if (((elem_type == LY_STMT_ERROR_MESSAGE) && (child != LY_STMT_ARG_VALUE)) ||
-                ((elem_type != LY_STMT_ERROR_MESSAGE) && (child != LY_STMT_ARG_TEXT))) {
+        child = yin_match_keyword(ctx, ctx->xmlctx->name, ctx->xmlctx->name_len, ctx->xmlctx->prefix,
+                ctx->xmlctx->prefix_len, parent_stmt);
+        if (((parent_stmt == LY_STMT_ERROR_MESSAGE) && (child != LY_STMT_ARG_VALUE)) ||
+                ((parent_stmt != LY_STMT_ERROR_MESSAGE) && (child != LY_STMT_ARG_TEXT))) {
             LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_UNEXP_SUBELEM, ctx->xmlctx->name_len, ctx->xmlctx->name,
-                    ly_stmt2str(elem_type));
+                    lyplg_ext_stmt2str(parent_stmt));
             return LY_EVALID;
         }
         LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
 
-        /* no attributes expected? TODO */
+        /* no attributes expected */
         while (ctx->xmlctx->status == LYXML_ATTRIBUTE) {
             LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
             LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
@@ -3210,11 +3183,6 @@
 
         /* load closing tag of subelement */
         LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
-
-        /* if only subelement was parsed as argument, load also closing tag TODO what? */
-        /*if (ctx->xmlctx->status == LYXML_ELEMENT) {
-            LY_CHECK_RET(lyxml_get_element(&ctx->xmlctx, data, &prefix, &prefix_len, &name, &name_len));
-        }*/
         break;
     default:
         LOGINT(ctx->xmlctx->ctx);
@@ -3228,12 +3196,12 @@
  * @brief Parse yin element into generic structure.
  *
  * @param[in,out] ctx Yin parser context for XML context, logging, and to store current state.
- * @param[in] parent Identification of parent element.
+ * @param[in] parent_stmt Type of parent statement.
  * @param[out] element Where the element structure should be stored.
  * @return LY_ERR values.
  */
 LY_ERR
-yin_parse_element_generic(struct lysp_yin_ctx *ctx, enum ly_stmt parent, struct lysp_stmt **element)
+yin_parse_element_generic(struct lysp_yin_ctx *ctx, enum ly_stmt parent_stmt, struct lysp_stmt **element)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lysp_stmt *last = NULL, *new = NULL;
@@ -3263,13 +3231,13 @@
     }
 
     (*element)->kw = yin_match_keyword(ctx, ctx->xmlctx->name, ctx->xmlctx->name_len, ctx->xmlctx->prefix,
-            ctx->xmlctx->prefix_len, parent);
+            ctx->xmlctx->prefix_len, parent_stmt);
 
     last = (*element)->child;
     if ((*element)->kw == LY_STMT_NONE) {
         /* unrecognized element */
         LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_UNEXP_SUBELEM, ctx->xmlctx->name_len, ctx->xmlctx->name,
-                ly_stmt2str(parent));
+                lyplg_ext_stmt2str(parent_stmt));
         ret = LY_EVALID;
         goto cleanup;
     } else if ((*element)->kw != LY_STMT_EXTENSION_INSTANCE) {
@@ -3347,14 +3315,15 @@
  * @brief Parse instance of extension.
  *
  * @param[in,out] ctx Yin parser context for logging and to store current state.
- * @param[in] subelem The statement this extension instance is a subelement of.
- * @param[in] subelem_index Index of the keyword instance this extension instance is a subelement of
+ * @param[in] parent Current statement parent.
+ * @param[in] parent_stmt Type of @p parent statement.
+ * @param[in] parent_stmt_index In case of several @p parent_stmt, index of the relevant @p parent statement.
  * @param[in,out] exts Extension instance to add to.
  * @return LY_ERR values.
  */
 LY_ERR
-yin_parse_extension_instance(struct lysp_yin_ctx *ctx, enum ly_stmt subelem, LY_ARRAY_COUNT_TYPE subelem_index,
-        struct lysp_ext_instance **exts)
+yin_parse_extension_instance(struct lysp_yin_ctx *ctx, const void *parent, enum ly_stmt parent_stmt,
+        LY_ARRAY_COUNT_TYPE parent_stmt_index, struct lysp_ext_instance **exts)
 {
     struct lysp_ext_instance *e;
     struct lysp_stmt *last_subelem = NULL, *new_subelem = NULL;
@@ -3383,8 +3352,9 @@
     LY_CHECK_RET(ly_store_prefix_data(ctx->xmlctx->ctx, e->name, strlen(e->name), LY_VALUE_XML, &ctx->xmlctx->ns,
             &e->format, &e->prefix_data));
 
-    e->parent_stmt = subelem;
-    e->parent_stmt_index = subelem_index;
+    e->parent = (void *)parent;
+    e->parent_stmt = parent_stmt;
+    e->parent_stmt_index = parent_stmt_index;
 
     LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
 
@@ -3431,16 +3401,10 @@
             LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
         }
     } else if (ctx->xmlctx->value_len) {
-        /* save text content */
-        INSERT_STRING_RET(ctx->xmlctx->ctx, ctx->xmlctx->value, ctx->xmlctx->value_len, ctx->xmlctx->dynamic, e->argument);
-        LY_CHECK_RET(!e->argument, LY_EMEM);
-
-        /* store prefix data for the argument as well */
-        LY_CHECK_RET(ly_store_prefix_data(ctx->xmlctx->ctx, e->argument, strlen(e->argument), LY_VALUE_XML,
-                &ctx->xmlctx->ns, &e->format, &e->prefix_data));
-
-        /* parser next */
-        LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+        /* invalid text content */
+        LOGVAL_PARSER(ctx, LYVE_SYNTAX, "Extension instance \"%s\" with unexpected text content \".*s\".", ext_name,
+                (int)ctx->xmlctx->value_len, ctx->xmlctx->value);
+        return LY_EVALID;
     }
 
     e->parsed = NULL;
@@ -3454,18 +3418,19 @@
  * @param[in,out] ctx Yin parser context for logging and to store current state.
  * @param[in] subelem_info array of valid subelement types and meta information
  * @param[in] subelem_info_size Size of subelem_info array.
- * @param[in] current_element Type of current element.
+ * @param[in] parent Current statement parent.
+ * @param[in] parent_stmt Type of @p parent statement.
  * @param[out] text_content Where the text content of element should be stored if any. Text content is ignored if set to NULL.
  * @param[in,out] exts Extension instance to add to. Can be set to null if element cannot have extension as subelements.
  * @return LY_ERR values.
  */
 LY_ERR
 yin_parse_content(struct lysp_yin_ctx *ctx, struct yin_subelement *subelem_info, size_t subelem_info_size,
-        enum ly_stmt current_element, const char **text_content, struct lysp_ext_instance **exts)
+        const void *parent, enum ly_stmt parent_stmt, const char **text_content, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     enum LYXML_PARSER_STATUS next_status;
-    enum ly_stmt kw = LY_STMT_NONE, last_kw = LY_STMT_NONE;
+    enum ly_stmt cur_stmt = LY_STMT_NONE, last_stmt = LY_STMT_NONE;
     struct yin_subelement *subelem = NULL;
 
     assert(ctx->xmlctx->status == LYXML_ELEM_CONTENT);
@@ -3484,44 +3449,44 @@
         /* current element has subelements as content */
         while (ctx->xmlctx->status == LYXML_ELEMENT) {
             /* match keyword */
-            last_kw = kw;
-            kw = yin_match_keyword(ctx, ctx->xmlctx->name, ctx->xmlctx->name_len, ctx->xmlctx->prefix,
-                    ctx->xmlctx->prefix_len, current_element);
+            last_stmt = cur_stmt;
+            cur_stmt = yin_match_keyword(ctx, ctx->xmlctx->name, ctx->xmlctx->name_len, ctx->xmlctx->prefix,
+                    ctx->xmlctx->prefix_len, parent_stmt);
 
             /* check if this element can be child of current element */
-            subelem = get_record(kw, subelem_info_size, subelem_info);
+            subelem = get_record(cur_stmt, subelem_info_size, subelem_info);
             if (!subelem) {
-                if ((current_element == LY_STMT_DEVIATE) && isdevsub(kw)) {
-                    LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_INDEV_YIN, ly_stmt2str(kw));
+                if ((parent_stmt == LY_STMT_DEVIATE) && isdevsub(cur_stmt)) {
+                    LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_INDEV_YIN, lyplg_ext_stmt2str(cur_stmt));
                 } else {
                     LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_UNEXP_SUBELEM, ctx->xmlctx->name_len,
-                            ctx->xmlctx->name, ly_stmt2str(current_element));
+                            ctx->xmlctx->name, lyplg_ext_stmt2str(parent_stmt));
                 }
                 ret = LY_EVALID;
                 goto cleanup;
             }
 
             /* relative order is required only in module and submodule sub-elements */
-            if ((current_element == LY_STMT_MODULE) || (current_element == LY_STMT_SUBMODULE)) {
-                ret = yin_check_relative_order(ctx, last_kw, kw, current_element);
+            if ((parent_stmt == LY_STMT_MODULE) || (parent_stmt == LY_STMT_SUBMODULE)) {
+                ret = yin_check_relative_order(ctx, last_stmt, cur_stmt, parent_stmt);
                 LY_CHECK_GOTO(ret, cleanup);
             }
 
             /* flag check */
             if ((subelem->flags & YIN_SUBELEM_UNIQUE) && (subelem->flags & YIN_SUBELEM_PARSED)) {
                 /* subelement uniquenes */
-                LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_SUBELEM_REDEF, ly_stmt2str(kw), ly_stmt2str(current_element));
+                LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_SUBELEM_REDEF, lyplg_ext_stmt2str(cur_stmt), lyplg_ext_stmt2str(parent_stmt));
                 return LY_EVALID;
             }
             if (subelem->flags & YIN_SUBELEM_FIRST) {
                 /* subelement is supposed to be defined as first subelement */
-                ret = yin_check_subelem_first_constraint(ctx, subelem_info, subelem_info_size, current_element, subelem);
+                ret = yin_check_subelem_first_constraint(ctx, subelem_info, subelem_info_size, parent_stmt, subelem);
                 LY_CHECK_GOTO(ret, cleanup);
             }
             if (subelem->flags & YIN_SUBELEM_VER2) {
                 /* subelement is supported only in version 1.1 or higher */
                 if (PARSER_CUR_PMOD(ctx)->version < LYS_VERSION_1_1) {
-                    LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_INSUBELEM2, ly_stmt2str(kw), ly_stmt2str(current_element));
+                    LOGVAL_PARSER((struct lysp_ctx *)ctx, LY_VCODE_INSUBELEM2, lyplg_ext_stmt2str(cur_stmt), lyplg_ext_stmt2str(parent_stmt));
                     ret = LY_EVALID;
                     goto cleanup;
                 }
@@ -3529,10 +3494,10 @@
             /* note that element was parsed for easy uniqueness check in next iterations */
             subelem->flags |= YIN_SUBELEM_PARSED;
 
-            switch (kw) {
+            switch (cur_stmt) {
             /* call responsible function */
             case LY_STMT_EXTENSION_INSTANCE:
-                ret = yin_parse_extension_instance(ctx, current_element,
+                ret = yin_parse_extension_instance(ctx, parent, parent_stmt,
                         (subelem->dest) ? *((LY_ARRAY_COUNT_TYPE *)subelem->dest) : 0, exts);
                 break;
             case LY_STMT_ACTION:
@@ -3541,16 +3506,16 @@
                 break;
             case LY_STMT_ANYDATA:
             case LY_STMT_ANYXML:
-                ret = yin_parse_any(ctx, kw, (struct tree_node_meta *)subelem->dest);
+                ret = yin_parse_any(ctx, cur_stmt, (struct tree_node_meta *)subelem->dest);
                 break;
             case LY_STMT_ARGUMENT:
-                ret = yin_parse_argument(ctx, (struct yin_argument_meta *)subelem->dest, exts);
+                ret = yin_parse_argument(ctx, parent, (struct yin_argument_meta *)subelem->dest, exts);
                 break;
             case LY_STMT_AUGMENT:
                 ret = yin_parse_augment(ctx, (struct tree_node_meta *)subelem->dest);
                 break;
             case LY_STMT_BASE:
-                ret = yin_parse_base(ctx, current_element, subelem->dest, exts);
+                ret = yin_parse_base(ctx, parent_stmt, subelem->dest, exts);
                 break;
             case LY_STMT_BELONGS_TO:
                 ret = yin_parse_belongs_to(ctx, (struct lysp_submodule *)subelem->dest, exts);
@@ -3571,18 +3536,20 @@
             case LY_STMT_DESCRIPTION:
             case LY_STMT_ORGANIZATION:
             case LY_STMT_REFERENCE:
-                ret = yin_parse_meta(ctx, kw, (const char **)subelem->dest, exts);
+                ret = yin_parse_meta(ctx, parent, cur_stmt, (const char **)subelem->dest, exts);
                 break;
             case LY_STMT_CONTAINER:
                 ret = yin_parse_container(ctx, (struct tree_node_meta *)subelem->dest);
                 break;
             case LY_STMT_DEFAULT:
-                ret = yin_parse_qname(ctx, kw, subelem, exts);
+                ret = yin_parse_qname(ctx, cur_stmt, subelem, exts);
                 break;
             case LY_STMT_ERROR_APP_TAG:
             case LY_STMT_KEY:
+                ret = yin_parse_simple_elem(ctx, parent, cur_stmt, subelem, YIN_ARG_VALUE, Y_STR_ARG, exts);
+                break;
             case LY_STMT_PRESENCE:
-                ret = yin_parse_simple_elem(ctx, kw, subelem, YIN_ARG_VALUE, Y_STR_ARG, exts);
+                ret = yin_parse_simple_elem(ctx, *(const char **)subelem->dest, cur_stmt, subelem, YIN_ARG_VALUE, Y_STR_ARG, exts);
                 break;
             case LY_STMT_DEVIATE:
                 ret = yin_parse_deviate(ctx, (struct lysp_deviate **)subelem->dest);
@@ -3594,7 +3561,7 @@
                 ret = yin_parse_enum(ctx, (struct lysp_type *)subelem->dest);
                 break;
             case LY_STMT_ERROR_MESSAGE:
-                ret = yin_parse_err_msg(ctx, (const char **)subelem->dest, exts);
+                ret = yin_parse_err_msg(ctx, parent, (const char **)subelem->dest, exts);
                 break;
             case LY_STMT_EXTENSION:
                 ret = yin_parse_extension(ctx, (struct lysp_ext **)subelem->dest);
@@ -3613,24 +3580,24 @@
                 break;
             case LY_STMT_UNIQUE:
             case LY_STMT_IF_FEATURE:
-                ret = yin_parse_qname(ctx, kw, subelem, exts);
+                ret = yin_parse_qname(ctx, cur_stmt, subelem, exts);
                 break;
             case LY_STMT_UNITS:
-                ret = yin_parse_simple_elem(ctx, kw, subelem, YIN_ARG_NAME, Y_STR_ARG, exts);
+                ret = yin_parse_simple_elem(ctx, *(const char **)subelem->dest, cur_stmt, subelem, YIN_ARG_NAME, Y_STR_ARG, exts);
                 break;
             case LY_STMT_IMPORT:
                 ret = yin_parse_import(ctx, (struct import_meta *)subelem->dest);
                 break;
             case LY_STMT_INCLUDE:
-                if ((current_element == LY_STMT_SUBMODULE) && (PARSER_CUR_PMOD(ctx)->version == LYS_VERSION_1_1)) {
-                    LOGWRN(PARSER_CTX(ctx), "YANG version 1.1 expects all includes in main module, includes in submodules (%s) are not necessary.",
-                            ((struct lysp_submodule *)PARSER_CUR_PMOD(ctx))->name);
+                if ((parent_stmt == LY_STMT_SUBMODULE) && (PARSER_CUR_PMOD(ctx)->version == LYS_VERSION_1_1)) {
+                    LOGWRN(PARSER_CTX(ctx), "YANG version 1.1 expects all includes in main module, includes in "
+                            "submodules (%s) are not necessary.", ((struct lysp_submodule *)PARSER_CUR_PMOD(ctx))->name);
                 }
                 ret = yin_parse_include(ctx, (struct include_meta *)subelem->dest);
                 break;
             case LY_STMT_INPUT:
             case LY_STMT_OUTPUT:
-                ret = yin_parse_inout(ctx, kw, (struct inout_meta *)subelem->dest);
+                ret = yin_parse_inout(ctx, cur_stmt, (struct inout_meta *)subelem->dest);
                 break;
             case LY_STMT_LEAF:
                 ret = yin_parse_leaf(ctx, (struct tree_node_meta *)subelem->dest);
@@ -3649,35 +3616,36 @@
                 break;
             case LY_STMT_MAX_ELEMENTS:
             case LY_STMT_MIN_ELEMENTS:
-                ret = yin_parse_minmax(ctx, current_element, kw, subelem->dest);
+                ret = yin_parse_minmax(ctx, parent_stmt, cur_stmt, subelem->dest);
                 break;
             case LY_STMT_MODIFIER:
-                ret = yin_parse_modifier(ctx, (const char **)subelem->dest, exts);
+                ret = yin_parse_modifier(ctx, parent, (const char **)subelem->dest, exts);
                 break;
             case LY_STMT_MUST:
                 ret = yin_parse_must(ctx, (struct lysp_restr **)subelem->dest);
                 break;
             case LY_STMT_NAMESPACE:
-                ret = yin_parse_simple_elem(ctx, kw, subelem, YIN_ARG_URI, Y_STR_ARG, exts);
+                ret = yin_parse_simple_elem(ctx, parent, cur_stmt, subelem, YIN_ARG_URI, Y_STR_ARG, exts);
                 break;
             case LY_STMT_NOTIFICATION:
                 ret = yin_parse_notification(ctx, (struct tree_node_meta *)subelem->dest);
                 break;
             case LY_STMT_ORDERED_BY:
-                ret = yin_parse_orderedby(ctx, (uint16_t *)subelem->dest, exts);
+                ret = yin_parse_orderedby(ctx, parent, (uint16_t *)subelem->dest, exts);
                 break;
             case LY_STMT_PATH:
-                ret = yin_parse_path(ctx, kw, (struct lysp_type *)subelem->dest);
+                ret = yin_parse_path(ctx, (struct lysp_type *)subelem->dest);
                 break;
             case LY_STMT_PATTERN:
                 ret = yin_parse_pattern(ctx, (struct lysp_type *)subelem->dest);
                 break;
             case LY_STMT_VALUE:
             case LY_STMT_POSITION:
-                ret = yin_parse_value_pos(ctx, kw, (struct lysp_type_enum *)subelem->dest);
+                ret = yin_parse_value_pos(ctx, cur_stmt, (struct lysp_type_enum *)subelem->dest);
                 break;
             case LY_STMT_PREFIX:
-                ret = yin_parse_simple_elem(ctx, kw, subelem, YIN_ARG_VALUE, Y_IDENTIF_ARG, exts);
+                ret = yin_parse_simple_elem(ctx, *(const char **)subelem->dest, cur_stmt, subelem, YIN_ARG_VALUE,
+                        Y_IDENTIF_ARG, exts);
                 break;
             case LY_STMT_RANGE:
                 ret = yin_parse_range(ctx, (struct lysp_type *)subelem->dest);
@@ -3698,7 +3666,7 @@
                 ret = yin_parse_status(ctx, (uint16_t *)subelem->dest, exts);
                 break;
             case LY_STMT_TYPE:
-                ret = yin_parse_type(ctx, current_element, subelem);
+                ret = yin_parse_type(ctx, parent_stmt, subelem);
                 break;
             case LY_STMT_TYPEDEF:
                 ret = yin_parse_typedef(ctx, (struct tree_node_meta *)subelem->dest);
@@ -3710,10 +3678,10 @@
                 ret = yin_parse_when(ctx, (struct lysp_when **)subelem->dest);
                 break;
             case LY_STMT_YANG_VERSION:
-                ret = yin_parse_yangversion(ctx, (uint8_t *)subelem->dest, exts);
+                ret = yin_parse_yangversion(ctx, parent, (uint8_t *)subelem->dest, exts);
                 break;
             case LY_STMT_YIN_ELEMENT:
-                ret = yin_parse_yin_element(ctx, (uint16_t *)subelem->dest, exts);
+                ret = yin_parse_yin_element(ctx, parent, (uint16_t *)subelem->dest, exts);
                 break;
             case LY_STMT_ARG_TEXT:
             case LY_STMT_ARG_VALUE:
@@ -3723,7 +3691,7 @@
                     LY_CHECK_GOTO(ret = lyxml_ctx_next(ctx->xmlctx), cleanup);
                     LY_CHECK_GOTO(ret = lyxml_ctx_next(ctx->xmlctx), cleanup);
                 }
-                ret = yin_parse_content(ctx, NULL, 0, kw, (const char **)subelem->dest, NULL);
+                ret = yin_parse_content(ctx, NULL, 0, parent, cur_stmt, (const char **)subelem->dest, NULL);
                 break;
             default:
                 LOGINT(ctx->xmlctx->ctx);
@@ -3749,7 +3717,7 @@
     }
 
     /* mandatory subelements are checked only after whole element was succesfully parsed */
-    LY_CHECK_RET(yin_check_subelem_mandatory_constraint(ctx, subelem_info, subelem_info_size, current_element));
+    LY_CHECK_RET(yin_check_subelem_mandatory_constraint(ctx, subelem_info, subelem_info_size, parent_stmt));
 
 cleanup:
     return ret;
@@ -3804,7 +3772,7 @@
             LY_STMT_YANG_VERSION, &mod->version, YIN_SUBELEM_UNIQUE,
             LY_STMT_EXTENSION_INSTANCE, NULL, 0));
 
-    ret = yin_parse_content(ctx, subelems, subelems_size, LY_STMT_MODULE, NULL, &mod->exts);
+    ret = yin_parse_content(ctx, subelems, subelems_size, mod, LY_STMT_MODULE, NULL, &mod->exts);
     subelems_deallocator(subelems_size, subelems);
     LY_CHECK_RET(ret);
 
@@ -3871,7 +3839,7 @@
             LY_STMT_YANG_VERSION, &submod->version, YIN_SUBELEM_UNIQUE,
             LY_STMT_EXTENSION_INSTANCE, NULL, 0));
 
-    ret = yin_parse_content(ctx, subelems, subelems_size, LY_STMT_SUBMODULE, NULL, &submod->exts);
+    ret = yin_parse_content(ctx, subelems, subelems_size, submod, LY_STMT_SUBMODULE, NULL, &submod->exts);
     subelems_deallocator(subelems_size, subelems);
     LY_CHECK_RET(ret);
 
@@ -3920,11 +3888,11 @@
     kw = yin_match_keyword(*yin_ctx, (*yin_ctx)->xmlctx->name, (*yin_ctx)->xmlctx->name_len, (*yin_ctx)->xmlctx->prefix,
             (*yin_ctx)->xmlctx->prefix_len, LY_STMT_NONE);
     if (kw == LY_STMT_MODULE) {
-        LOGERR(ctx, LY_EDENIED, "Input data contains module in situation when a submodule is expected.");
+        LOGERR(ctx, LY_EDENIED, "Input data contains module when a submodule is expected.");
         ret = LY_EINVAL;
         goto cleanup;
     } else if (kw != LY_STMT_SUBMODULE) {
-        LOGVAL_PARSER((struct lysp_ctx *)*yin_ctx, LY_VCODE_MOD_SUBOMD, ly_stmt2str(kw));
+        LOGVAL_PARSER((struct lysp_ctx *)*yin_ctx, LY_VCODE_MOD_SUBOMD, lyplg_ext_stmt2str(kw));
         ret = LY_EVALID;
         goto cleanup;
     }
@@ -3950,6 +3918,7 @@
     *submod = mod_p;
 
 cleanup:
+    LOG_LOCBACK(0, 0, 0, 1);
     if (ret) {
         lysp_module_free(&fctx, (struct lysp_module *)mod_p);
         lysp_yin_ctx_free(*yin_ctx);
@@ -3987,7 +3956,7 @@
         ret = LY_EINVAL;
         goto cleanup;
     } else if (kw != LY_STMT_MODULE) {
-        LOGVAL_PARSER((struct lysp_ctx *)*yin_ctx, LY_VCODE_MOD_SUBOMD, ly_stmt2str(kw));
+        LOGVAL_PARSER((struct lysp_ctx *)*yin_ctx, LY_VCODE_MOD_SUBOMD, lyplg_ext_stmt2str(kw));
         ret = LY_EVALID;
         goto cleanup;
     }
@@ -4013,7 +3982,8 @@
     mod->parsed = mod_p;
 
 cleanup:
-    if (ret != LY_SUCCESS) {
+    LOG_LOCBACK(0, 0, 0, 1);
+    if (ret) {
         lysp_module_free(&fctx, mod_p);
         lysp_yin_ctx_free(*yin_ctx);
         *yin_ctx = NULL;
diff --git a/src/plugins_exts.c b/src/plugins_exts.c
index eb688d5..a09b72b 100644
--- a/src/plugins_exts.c
+++ b/src/plugins_exts.c
@@ -14,68 +14,544 @@
  */
 
 #include "plugins_exts.h"
-#include "plugins_exts_compile.h"
-#include "plugins_exts_print.h"
 
+#include <assert.h>
 #include <stdint.h>
+#include <stdlib.h>
 
 #include "common.h"
+#include "dict.h"
+#include "parser_internal.h"
 #include "printer_internal.h"
 #include "schema_compile.h"
+#include "schema_compile_amend.h"
+#include "schema_compile_node.h"
+#include "schema_features.h"
+#include "tree_schema_internal.h"
+
+LIBYANG_API_DEF const struct lysp_module *
+lyplg_ext_parse_get_cur_pmod(const struct lysp_ctx *pctx)
+{
+    return PARSER_CUR_PMOD(pctx);
+}
+
+LIBYANG_API_DEF LY_ERR
+lyplg_ext_parse_extension_instance(struct lysp_ctx *pctx, struct lysp_ext_instance *ext)
+{
+    LY_ERR rc = LY_SUCCESS;
+    LY_ARRAY_COUNT_TYPE u;
+    struct lysp_stmt *stmt;
+
+    /* check for invalid substatements */
+    LY_LIST_FOR(ext->child, stmt) {
+        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(PARSER_CTX(pctx), 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 : "");
+            rc = LY_EVALID;
+            goto cleanup;
+        }
+    }
+
+    /* parse all the known statements */
+    LY_ARRAY_FOR(ext->substmts, u) {
+        LY_LIST_FOR(ext->child, stmt) {
+            if (ext->substmts[u].stmt != stmt->kw) {
+                continue;
+            }
+
+            if ((rc = lys_parse_ext_instance_stmt(pctx, &ext->substmts[u], stmt))) {
+                goto cleanup;
+            }
+        }
+    }
+
+cleanup:
+    return rc;
+}
+
+/**
+ * @brief Compile an instance extension statement.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] parsed Parsed ext instance substatement structure.
+ * @param[in] ext Compiled ext instance.
+ * @param[in] substmt Compled ext instance substatement info.
+ * @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 void *parsed, struct lysc_ext_instance *ext,
+        struct lysc_ext_substmt *substmt, struct lysc_node *aug_target)
+{
+    LY_ERR rc = LY_SUCCESS;
+    ly_bool length_restr = 0;
+    LY_DATA_TYPE basetype;
+
+    /* compilation wthout any storage */
+    if (substmt->stmt == LY_STMT_IF_FEATURE) {
+        ly_bool enabled;
+
+        /* evaluate */
+        LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, parsed, &enabled), cleanup);
+        if (!enabled) {
+            /* it is disabled, remove the whole extension instance */
+            rc = LY_ENOT;
+        }
+    }
+
+    if (!substmt->storage || !parsed) {
+        /* nothing to store or nothing parsed to compile */
+        goto cleanup;
+    }
+
+    switch (substmt->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:
+    case LY_STMT_USES: {
+        const uint16_t flags;
+        struct lysp_node *pnodes, *pnode;
+        struct lysc_node *node;
+
+        lyplg_ext_get_storage(ext, LY_STMT_STATUS, (const void **)&flags);
+        pnodes = (struct lysp_node *)parsed;
+        if (aug_target) {
+            /* compile augmented nodes */
+            LY_CHECK_GOTO(rc = lys_compile_augment_children(ctx, NULL, 0, (struct lysp_node *)pnodes, aug_target, 0), cleanup);
+        } else {
+            /* compile nodes */
+            LY_LIST_FOR(pnodes, pnode) {
+                if (pnode->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
+                    /* manual compile */
+                    node = calloc(1, sizeof(struct lysc_node_action_inout));
+                    LY_CHECK_ERR_GOTO(!node, LOGMEM(ctx->ctx); rc = LY_EMEM, cleanup);
+                    LY_CHECK_GOTO(rc = lys_compile_node_action_inout(ctx, pnode, node), cleanup);
+                    LY_CHECK_GOTO(rc = lys_compile_node_connect(ctx, NULL, node), cleanup);
+                } else {
+                    /* ctx->ext substatement storage is used as the document root */
+                    LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, NULL, flags ? &flags : NULL, NULL), cleanup);
+                }
+            }
+        }
+        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:
+    case LY_STMT_REFERENCE:
+    case LY_STMT_UNITS:
+        /* just make a copy */
+        LY_CHECK_GOTO(rc = lydict_insert(ctx->ctx, parsed, 0, substmt->storage), cleanup);
+        break;
+
+    case LY_STMT_BIT:
+        basetype = LY_TYPE_BITS;
+    /* fallthrough */
+    case LY_STMT_ENUM:
+        if (substmt->stmt == LY_STMT_ENUM) {
+            basetype = LY_TYPE_ENUM;
+        }
+
+        /* compile */
+        LY_CHECK_GOTO(rc = lys_compile_type_enums(ctx, parsed, basetype, NULL, substmt->storage), cleanup);
+        break;
+
+    case LY_STMT_CONFIG: {
+        const uint16_t flags = (uintptr_t)parsed;
+
+        if (!(ctx->compile_opts & LYS_COMPILE_NO_CONFIG)) {
+            if (flags & LYS_CONFIG_MASK) {
+                /* explicitly set */
+                *(uint16_t *)substmt->storage = flags | LYS_SET_CONFIG;
+            } else if (ext->parent_stmt & LY_STMT_DATA_NODE_MASK) {
+                /* inherit */
+                *(uint16_t *)substmt->storage = ((struct lysc_node *)ext->parent)->flags & LYS_CONFIG_MASK;
+            } else {
+                /* default config */
+                *(uint16_t *)substmt->storage = LYS_CONFIG_W;
+            }
+        } /* else leave zero */
+        break;
+    }
+    case LY_STMT_MUST: {
+        const struct lysp_restr *restrs = parsed;
+        struct lysc_must *musts = *(struct lysc_must **)substmt->storage;
+
+        /* sized array */
+        COMPILE_ARRAY_GOTO(ctx, restrs, musts, lys_compile_must, rc, cleanup);
+        break;
+    }
+    case LY_STMT_WHEN: {
+        const uint16_t flags;
+        const struct lysp_when *when = parsed;
+
+        /* read compiled status */
+        lyplg_ext_get_storage(ext, LY_STMT_STATUS, (const void **)&flags);
+
+        /* compile */
+        LY_CHECK_GOTO(rc = lys_compile_when(ctx, when, flags, NULL, NULL, NULL, substmt->storage), cleanup);
+        break;
+    }
+    case LY_STMT_FRACTION_DIGITS:
+    case LY_STMT_REQUIRE_INSTANCE:
+        /* just make a copy */
+        *(uint8_t *)substmt->storage = (uintptr_t)parsed;
+        break;
+
+    case LY_STMT_MANDATORY:
+    case LY_STMT_ORDERED_BY:
+    case LY_STMT_STATUS:
+        /* just make a copy */
+        *(uint16_t *)substmt->storage = (uintptr_t)parsed;
+        break;
+
+    case LY_STMT_MAX_ELEMENTS:
+    case LY_STMT_MIN_ELEMENTS:
+        /* just make a copy */
+        *(uint32_t *)substmt->storage = (uintptr_t)parsed;
+        break;
+
+    case LY_STMT_POSITION:
+    case LY_STMT_VALUE:
+        /* just make a copy */
+        *(int64_t *)substmt->storage = (uintptr_t)parsed;
+        break;
+
+    case LY_STMT_IDENTITY:
+        /* compile */
+        LY_CHECK_GOTO(rc = lys_identity_precompile(ctx, NULL, NULL, parsed, substmt->storage), cleanup);
+        break;
+
+    case LY_STMT_LENGTH:
+        length_restr = 1;
+    /* fallthrough */
+    case LY_STMT_RANGE:
+        /* compile, use uint64 default range */
+        LY_CHECK_GOTO(rc = lys_compile_type_range(ctx, parsed, LY_TYPE_UINT64, length_restr, 0, NULL, substmt->storage),
+                cleanup);
+        break;
+
+    case LY_STMT_PATTERN:
+        /* compile */
+        LY_CHECK_GOTO(rc = lys_compile_type_patterns(ctx, parsed, NULL, substmt->storage), cleanup);
+        break;
+
+    case LY_STMT_TYPE: {
+        const uint16_t flags;
+        const char *units;
+        const struct lysp_type *ptype = parsed;
+
+        /* read compiled info */
+        lyplg_ext_get_storage(ext, LY_STMT_STATUS, (const void **)&flags);
+        lyplg_ext_get_storage(ext, LY_STMT_UNITS, (const void **)&units);
+
+        /* compile */
+        LY_CHECK_GOTO(rc = lys_compile_type(ctx, NULL, flags, ext->def->name, ptype, substmt->storage, &units, NULL), cleanup);
+        break;
+    }
+    case LY_STMT_EXTENSION_INSTANCE: {
+        struct lysp_ext_instance *extps = (struct lysp_ext_instance *)parsed;
+        struct lysc_ext_instance *exts = *(struct lysc_ext_instance **)substmt->storage;
+
+        /* compile sized array */
+        COMPILE_EXTS_GOTO(ctx, extps, exts, ext, rc, cleanup);
+        break;
+    }
+    case LY_STMT_AUGMENT:
+    case LY_STMT_GROUPING:
+    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_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:
+        LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Statement \"%s\" compilation is not supported.", lyplg_ext_stmt2str(substmt->stmt));
+        rc = LY_EVALID;
+        goto cleanup;
+
+    default:
+        LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Statement \"%s\" is not supported as an extension "
+                "(found in \"%s%s%s\") substatement.", lyplg_ext_stmt2str(substmt->stmt), ext->def->name,
+                ext->argument ? " " : "", ext->argument ? ext->argument : "");
+        rc = LY_EVALID;
+        goto cleanup;
+    }
+
+cleanup:
+    return rc;
+}
+
+static LY_ERR
+lys_compile_extension_instance_(struct lysc_ctx *ctx, const struct lysp_ext_instance *extp, struct lysc_ext_instance *ext,
+        struct lysc_node *aug_target)
+{
+    LY_ERR rc = LY_SUCCESS;
+    LY_ARRAY_COUNT_TYPE u, v;
+    enum ly_stmt stmtp;
+    const void *storagep;
+    struct ly_set storagep_compiled = {0};
+
+    /* note into the compile context that we are processing extension now */
+    ctx->ext = ext;
+
+    LY_ARRAY_FOR(extp->substmts, u) {
+        stmtp = extp->substmts[u].stmt;
+        storagep = *(void **)extp->substmts[u].storage;
+
+        if (ly_set_contains(&storagep_compiled, storagep, NULL)) {
+            /* this parsed statement has already been compiled (for example, if it is a linked list of parsed nodes) */
+            continue;
+        }
+
+        LY_ARRAY_FOR(ext->substmts, v) {
+            if (stmtp != ext->substmts[v].stmt) {
+                continue;
+            }
+
+            if ((rc = lys_compile_ext_instance_stmt(ctx, storagep, ext, &ext->substmts[v], aug_target))) {
+                goto cleanup;
+            }
+
+            /* parsed substatement compiled */
+            break;
+        }
+
+        /* compiled */
+        ly_set_add(&storagep_compiled, storagep, 1, NULL);
+    }
+
+cleanup:
+    ctx->ext = NULL;
+    ly_set_erase(&storagep_compiled, NULL);
+    return rc;
+}
+
+LIBYANG_API_DEF LY_ERR
+lyplg_ext_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
+lyplg_ext_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);
+}
 
 LIBYANG_API_DEF struct ly_ctx *
-lysc_ctx_get_ctx(const struct lysc_ctx *ctx)
+lyplg_ext_compile_get_ctx(const struct lysc_ctx *ctx)
 {
     return ctx->ctx;
 }
 
 LIBYANG_API_DEF uint32_t *
-lysc_ctx_get_options(const struct lysc_ctx *ctx)
+lyplg_ext_compile_get_options(const struct lysc_ctx *ctx)
 {
     return &((struct lysc_ctx *)ctx)->compile_opts;
 }
 
-LIBYANG_API_DEF const char *
-lysc_ctx_get_path(const struct lysc_ctx *ctx)
-{
-    return ctx->path;
-}
-
-LIBYANG_API_DEF struct ly_out **
-lys_ypr_ctx_get_out(const struct lyspr_ctx *ctx)
-{
-    return &((struct lyspr_ctx *)ctx)->out;
-}
-
-LIBYANG_API_DEF uint32_t *
-lys_ypr_ctx_get_options(const struct lyspr_ctx *ctx)
-{
-    return &((struct lyspr_ctx *)ctx)->options;
-}
-
-LIBYANG_API_DEF uint16_t *
-lys_ypr_ctx_get_level(const struct lyspr_ctx *ctx)
-{
-    return &((struct lyspr_ctx *)ctx)->level;
-}
-
 LIBYANG_API_DEF const struct lys_module *
-lysc_ctx_get_cur_mod(const struct lysc_ctx *ctx)
+lyplg_ext_compile_get_cur_mod(const struct lysc_ctx *ctx)
 {
     return ctx->cur_mod;
 }
 
 LIBYANG_API_DEF struct lysp_module *
-lysc_ctx_get_pmod(const struct lysc_ctx *ctx)
+lyplg_ext_compile_get_pmod(const struct lysc_ctx *ctx)
 {
     return ctx->pmod;
 }
 
+LIBYANG_API_DEF struct ly_out **
+lyplg_ext_print_get_out(const struct lyspr_ctx *ctx)
+{
+    return &((struct lyspr_ctx *)ctx)->out;
+}
+
+LIBYANG_API_DEF uint32_t *
+lyplg_ext_print_get_options(const struct lyspr_ctx *ctx)
+{
+    return &((struct lyspr_ctx *)ctx)->options;
+}
+
+LIBYANG_API_DEF uint16_t *
+lyplg_ext_print_get_level(const struct lyspr_ctx *ctx)
+{
+    return &((struct lyspr_ctx *)ctx)->level;
+}
+
+LIBYANG_API_DEF const char *
+lyplg_ext_stmt2str(enum ly_stmt stmt)
+{
+    if (stmt == LY_STMT_EXTENSION_INSTANCE) {
+        return "extension instance";
+    } else {
+        return stmt_attr_info[stmt].name;
+    }
+}
+
+LIBYANG_API_DEF enum ly_stmt
+lyplg_ext_nodetype2stmt(uint16_t nodetype)
+{
+    switch (nodetype) {
+    case LYS_CONTAINER:
+        return LY_STMT_CONTAINER;
+    case LYS_CHOICE:
+        return LY_STMT_CHOICE;
+    case LYS_LEAF:
+        return LY_STMT_LEAF;
+    case LYS_LEAFLIST:
+        return LY_STMT_LEAF_LIST;
+    case LYS_LIST:
+        return LY_STMT_LIST;
+    case LYS_ANYXML:
+        return LY_STMT_ANYXML;
+    case LYS_ANYDATA:
+        return LY_STMT_ANYDATA;
+    case LYS_CASE:
+        return LY_STMT_CASE;
+    case LYS_RPC:
+        return LY_STMT_RPC;
+    case LYS_ACTION:
+        return LY_STMT_ACTION;
+    case LYS_NOTIF:
+        return LY_STMT_NOTIFICATION;
+    case LYS_USES:
+        return LY_STMT_USES;
+    case LYS_INPUT:
+        return LY_STMT_INPUT;
+    case LYS_OUTPUT:
+        return LY_STMT_OUTPUT;
+    default:
+        return LY_STMT_NONE;
+    }
+}
+
+LY_ERR
+lyplg_ext_get_storage_p(const struct lysc_ext_instance *ext, int stmt, const void ***storage_p)
+{
+    LY_ARRAY_COUNT_TYPE u;
+    enum ly_stmt match = 0;
+
+    *storage_p = NULL;
+
+    if (!(stmt & LY_STMT_NODE_MASK)) {
+        /* matching a non-node statement */
+        match = stmt;
+    }
+
+    LY_ARRAY_FOR(ext->substmts, u) {
+        if ((match && (ext->substmts[u].stmt == match)) || (!match && (ext->substmts[u].stmt & stmt))) {
+            *storage_p = ext->substmts[u].storage;
+            return LY_SUCCESS;
+        }
+    }
+
+    return LY_ENOT;
+}
+
+LIBYANG_API_DEF LY_ERR
+lyplg_ext_get_storage(const struct lysc_ext_instance *ext, int stmt, const void **storage)
+{
+    LY_ERR r;
+    const void **s;
+
+    *storage = NULL;
+
+    if ((r = lyplg_ext_get_storage_p(ext, stmt, &s))) {
+        return r;
+    }
+
+    *storage = *s;
+    return LY_SUCCESS;
+}
+
+LIBYANG_API_DEF LY_ERR
+lyplg_ext_parsed_get_storage(const struct lysc_ext_instance *ext, int stmt, const void **storage)
+{
+    LY_ARRAY_COUNT_TYPE u;
+    const struct lysp_ext_instance *extp = NULL;
+    enum ly_stmt match = 0;
+
+    *storage = NULL;
+
+    /* find the parsed ext instance */
+    LY_ARRAY_FOR(ext->module->parsed->exts, u) {
+        extp = &ext->module->parsed->exts[u];
+
+        if (ext->def == extp->def->compiled) {
+            break;
+        }
+        extp = NULL;
+    }
+    assert(extp);
+
+    if (!(stmt & LY_STMT_NODE_MASK)) {
+        /* matching a non-node statement */
+        match = stmt;
+    }
+
+    /* get the substatement */
+    LY_ARRAY_FOR(extp->substmts, u) {
+        if ((match && (extp->substmts[u].stmt == match)) || (!match && (extp->substmts[u].stmt & stmt))) {
+            *storage = *(void **)extp->substmts[u].storage;
+            return LY_SUCCESS;
+        }
+    }
+
+    return LY_ENOT;
+}
+
 LIBYANG_API_DEF LY_ERR
 lyplg_ext_get_data(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, void **ext_data, ly_bool *ext_data_free)
 {
     if (!ctx->ext_clb) {
-        lyplg_ext_log(ext, LY_LLERR, LY_EINVAL, NULL, "Failed to get extension data, no callback set.");
+        lyplg_ext_compile_log(NULL, ext, LY_LLERR, LY_EINVAL, "Failed to get extension data, no callback set.");
         return LY_EINVAL;
     }
 
diff --git a/src/plugins_exts.h b/src/plugins_exts.h
index 8ac2254..dd2a369 100644
--- a/src/plugins_exts.h
+++ b/src/plugins_exts.h
@@ -23,15 +23,13 @@
 #include "tree_edit.h"
 #include "tree_schema.h"
 
-#include "plugins_exts_compile.h"
-#include "plugins_exts_print.h"
-
 struct ly_ctx;
 struct ly_in;
 struct lyd_node;
+struct lysc_ctx;
 struct lysc_ext_substmt;
 struct lysp_ctx;
-struct lysp_ext_instance;
+struct lyspr_ctx;
 
 #ifdef __cplusplus
 extern "C" {
@@ -86,7 +84,7 @@
  * specific plugin responsible to storing data value. In case the user can recognize the id string, it can access the
  * plugin specific data with the appropriate knowledge of its structure.
  *
- * Logging information from an extension plugin is possible via ::lyplg_ext_log() function
+ * Logging information from an extension plugin is possible via ::lyplg_extp_log() and ::yplg_extc_log() functions.
  */
 
 /**
@@ -106,155 +104,251 @@
 #define LYPLG_EXT_API_VERSION 6
 
 /**
- * @brief Generic test for operation statements.
+ * @brief Mask for an operation statement.
  *
- * 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.
+ * This mask matches action and RPC.
  */
-#define LY_STMT_IS_OP(STMT) (((STMT) == LY_STMT_ACTION) || ((STMT) == LY_STMT_RPC))
+#define LY_STMT_OP_MASK (LY_STMT_ACTION | LY_STMT_RPC)
 
 /**
- * @brief Generic test for schema data nodes.
+ * @brief Mask for a data node statement.
  *
- * 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.
+ * This mask 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))
+#define LY_STMT_DATA_NODE_MASK (LY_STMT_ANYDATA | LY_STMT_ANYXML | LY_STMT_CASE | LY_STMT_CHOICE | LY_STMT_CONTAINER |\
+        LY_STMT_LEAF | LY_STMT_LEAF_LIST | LY_STMT_LIST)
 
 /**
- * @brief Generic test for any schema node that maps to common ::lysc_node or ::lysp_node structures.
+ * @brief Mask for a node statement.
  *
- * 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.
+ * This mask matches notification, input, output, action, RPC, anydata, anyxml, augment, case, choice, container,
+ * grouping, leaf, leaf-list, list, and uses.
  */
-#define LY_STMT_IS_NODE(STMT) (((STMT) >= LY_STMT_NOTIFICATION) && ((STMT) <= LY_STMT_LIST))
+#define LY_STMT_NODE_MASK 0xFFFF
 
 /**
  * @brief List of YANG statements
+ *
+ * Their description mentions what types are stored for each statement. Note that extension instance storage
+ * always stores a pointer to the type, not the type itself.
  */
 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_NOTIFICATION = 0x0001,  /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_node_notif *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - `struct lysc_node_notif *` */
+    LY_STMT_INPUT = 0x0002,     /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_node_action_inout *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - `struct lysc_node_action_inout *` */
+    LY_STMT_OUTPUT = 0x0004,    /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_node_action_inout *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - `struct lysc_node_action_inout *` */
+    LY_STMT_ACTION = 0x0008,    /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_node_action *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - `struct lysc_node_action *` */
+    LY_STMT_RPC = 0x0010,       /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_node_action *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - `struct lysc_node_action *` */
+    LY_STMT_ANYDATA = 0x0020,   /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_node_anydata *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - `struct lysc_node_anydata *` */
+    LY_STMT_ANYXML = 0x0040,    /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_node_anydata *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - `struct lysc_node_anydata *` */
+    LY_STMT_AUGMENT = 0x0080,   /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_node_augment *`
+                                     ::lysc_ext_substmt.storage - not compiled
+                                     ::lysc_ext_instance.parent - `struct lysc_node *` */
+    LY_STMT_CASE = 0x0100,      /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_node_case *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - `struct lysc_node_case *` */
+    LY_STMT_CHOICE = 0x0200,    /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_node_choice *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - `struct lysc_node_choice *` */
+    LY_STMT_CONTAINER = 0x0400, /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_node_container *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - `struct lysc_node_container *` */
+    LY_STMT_GROUPING = 0x0800,  /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_node_grp *`
+                                     ::lysc_ext_substmt.storage - not compiled
+                                     ::lysc_ext_instance.parent - `struct lysc_node *` */
+    LY_STMT_LEAF = 0x1000,      /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_node_leaf *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - `struct lysc_node_leaf *` */
+    LY_STMT_LEAF_LIST = 0x2000, /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_node_leaflist *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - `struct lysc_node_leaflist *` */
+    LY_STMT_LIST = 0x4000,      /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_node_list *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - `struct lysc_node_list *` */
+    LY_STMT_USES = 0x8000,      /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_node_uses *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - `struct lysc_node *` */
 
-    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,
+    LY_STMT_ARGUMENT = 0x10000, /**< ::lysp_ext_substmt.storage - `const char *`
+                                     ::lysp_ext_instance.parent - `struct lysp_ext *`
+                                     ::lysc_ext_substmt.storage - `const char *`
+                                     ::lysc_ext_instance.parent - `struct lysc_ext *` */
+    LY_STMT_BASE = 0x20000,     /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `const char **`[]
+                                     ::lysc_ext_substmt.storage - not compiled
+                                     ::lysc_ext_instance.parent - `struct lysc_ident *` */
+    LY_STMT_BELONGS_TO = 0x30000,   /**< ::lysp_ext_substmt.storage - `const char *`
+                                     ::lysp_ext_instance.parent - `struct lysp_submodule *`
+                                     ::lysc_ext_substmt.storage - not compiled
+                                     ::lysc_ext_instance.parent - `struct lysc_module *` */
+    LY_STMT_BIT = 0x40000,      /**< ::lysp_ext_substmt.storage - `struct lysp_type_enum *`[]
+                                     ::lysp_ext_instance.parent - `struct lysp_type_enum *`
+                                     ::lysc_ext_substmt.storage - `struct lysc_type_bitenum_item *`[]
+                                     ::lysc_ext_instance.parent - `struct lysc_type_bitenum_item *` */
+    LY_STMT_CONFIG = 0x50000,   /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `uint16_t *`
+                                     ::lysc_ext_substmt.storage - `uint16_t *`
+                                     ::lysc_ext_instance.parent - `struct lysc_node *` */
+    LY_STMT_CONTACT = 0x60000,  /**< ::lysp_ext_substmt.storage - `const char *`
+                                     ::lysp_ext_instance.parent - `struct lysp_(sub)module *`
+                                     ::lysc_ext_substmt.storage - `const char *`
+                                     ::lysc_ext_instance.parent - `struct lysc_module *` */
+    LY_STMT_DEFAULT = 0x70000,  /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_qname *`
+                                     ::lysc_ext_substmt.storage - not compiled
+                                     ::lysc_ext_instance.parent - `struct lysc_node *`, `struct lysc_type *` (typedef) */
+    LY_STMT_DESCRIPTION = 0x80000,  /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `const char *`
+                                     ::lysc_ext_substmt.storage - `const char *`
+                                     ::lysc_ext_instance.parent - compiled parent statement */
+    LY_STMT_DEVIATE = 0x90000,  /**< ::lysp_ext_substmt.storage - `struct lysp_deviate *`[]
+                                     ::lysp_ext_instance.parent - `struct lysp_deviate *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - not compiled */
+    LY_STMT_DEVIATION = 0xA0000,    /**< ::lysp_ext_substmt.storage - `struct lysp_deviation *`[]
+                                     ::lysp_ext_instance.parent - `struct lysp_deviation *`
+                                     ::lysc_ext_substmt.storage - not compiled
+                                     ::lysc_ext_instance.parent - `struct lysc_node *` */
+    LY_STMT_ENUM = 0xB0000,     /**< ::lysp_ext_substmt.storage - `struct lysp_type_enum *`[]
+                                     ::lysp_ext_instance.parent - `struct lysp_type_enum *`
+                                     ::lysc_ext_substmt.storage - `struct lysc_type_bitenum_item *`[]
+                                     ::lysc_ext_instance.parent - `struct lysc_type_bitenum_item *` */
+    LY_STMT_ERROR_APP_TAG = 0xC0000,    /**< ::lysp_ext_substmt.storage - `const char *`
+                                     ::lysp_ext_instance.parent - `struct lysp_restr *`
+                                     ::lysc_ext_substmt.storage - `const char *`
+                                     ::lysc_ext_instance.parent - compiled restriction structure */
+    LY_STMT_ERROR_MESSAGE = 0xD0000,    /**< ::lysp_ext_substmt.storage - `const char *`
+                                     ::lysp_ext_instance.parent - `struct lysp_restr *`
+                                     ::lysc_ext_substmt.storage - `const char *`
+                                     ::lysc_ext_instance.parent - compiled restriction structure */
+    LY_STMT_EXTENSION = 0xE0000,    /**< ::lysp_ext_substmt.storage - `struct lysp_ext *`[]
+                                     ::lysp_ext_instance.parent - `struct lysp_ext *`
+                                     ::lysc_ext_substmt.storage - not compiled explicitly
+                                     ::lysc_ext_instance.parent - `struct lysc_ext *` */
+    LY_STMT_EXTENSION_INSTANCE = 0xF0000,   /**< ::lysp_ext_substmt.storage - `struct lysp_ext_instance *`[]
+                                     ::lysc_ext_substmt.storage - `struct lysc_ext_instance *`[] */
+    LY_STMT_FEATURE = 0x100000, /**< ::lysp_ext_substmt.storage - `struct lysp_feature *`[]
+                                     ::lysp_ext_instance.parent - `struct lysp_feature *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - not compiled */
+    LY_STMT_FRACTION_DIGITS = 0x110000, /**< ::lysp_ext_substmt.storage - `uint8_t *`
+                                     ::lysp_ext_instance.parent - `struct lysp_type *`
+                                     ::lysc_ext_substmt.storage - `uint8_t *`
+                                     ::lysc_ext_instance.parent - `struct lysc_type *` */
+    LY_STMT_IDENTITY = 0x120000,    /**< ::lysp_ext_substmt.storage - `struct lysp_ident *`[]
+                                     ::lysp_ext_instance.parent - `struct lysp_ident *`
+                                     ::lysc_ext_substmt.storage - `struct lysc_ident *`[]
+                                     ::lysc_ext_instance.parent - `struct lysc_ident *` */
+    LY_STMT_IF_FEATURE = 0x130000,  /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_qname *`[]
+                                     ::lysc_ext_substmt.storage - no storage, evaluated when compiled
+                                     ::lysc_ext_instance.parent - compiled parent statement */
+    LY_STMT_IMPORT = 0x140000,  /**< ::lysp_ext_substmt.storage - `struct lysp_import *`[]
+                                     ::lysp_ext_instance.parent - `struct lysp_import *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - not compiled */
+    LY_STMT_INCLUDE = 0x150000, /**< ::lysp_ext_substmt.storage - `struct lysp_include *`[]
+                                     ::lysp_ext_instance.parent - `struct lysp_include *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - not compiled */
+    LY_STMT_KEY = 0x160000,     /**< ::lysp_ext_substmt.storage - `const char *`
+                                     ::lysp_ext_instance.parent - `struct lysp_node_list *`
+                                     ::lysc_ext_substmt.storage - `const char *`
+                                     ::lysc_ext_instance.parent - `struct lysc_node_list *` */
+    LY_STMT_LENGTH = 0x170000,  /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_restr *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - `struct lysc_range *` */
+    LY_STMT_MANDATORY = 0x180000,   /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `uint16_t *`
+                                     ::lysc_ext_substmt.storage - `uint16_t *`
+                                     ::lysc_ext_instance.parent - `struct lysc_node *` */
+    LY_STMT_MAX_ELEMENTS = 0x190000,    /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `uint32_t *`
+                                     ::lysc_ext_substmt.storage - `uint32_t *`
+                                     ::lysc_ext_instance.parent - `struct lysc_node_list *` */
+    LY_STMT_MIN_ELEMENTS = 0x1A0000,    /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `uint32_t *`
+                                     ::lysc_ext_substmt.storage - `uint32_t *`
+                                     ::lysc_ext_instance.parent - `struct lysc_node_list *` */
+    LY_STMT_MODIFIER = 0x1B0000,    /**< ::lysp_ext_substmt.storage - `const char *`
+                                     ::lysp_ext_instance.parent - `struct lysp_restr *`
+                                     ::lysc_ext_substmt.storage - `const char *`
+                                     ::lysc_ext_instance.parent - `struct lysc_pattern *` */
+    LY_STMT_MODULE = 0x1C0000,  /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_module *`
+                                     ::lysc_ext_substmt.storage - not compiled
+                                     ::lysc_ext_instance.parent - `struct lysc_module *` */
+    LY_STMT_MUST = 0x1D0000,    /**< ::lysp_ext_substmt.storage - `struct lysp_restr *`[]
+                                     ::lysp_ext_instance.parent - `struct lysp_restr *`
+                                     ::lysc_ext_substmt.storage - `struct lysc_must *`[]
+                                     ::lysc_ext_instance.parent - `struct lysc_must *` */
+    LY_STMT_NAMESPACE = 0x1E0000,   /**< ::lysp_ext_substmt.storage - `const char *`
+                                     ::lysp_ext_instance.parent - `struct lysp_module *`
+                                     ::lysc_ext_substmt.storage - `const char *`
+                                     ::lysc_ext_instance.parent - `struct lysc_module *` */
+    LY_STMT_ORDERED_BY = 0x1F0000,  /**< ::lysp_ext_substmt.storage - `uint16_t *`
+                                     ::lysp_ext_instance.parent - `struct lysp_node *`
+                                     ::lysc_ext_substmt.storage - `uint16_t *`
+                                     ::lysc_ext_instance.parent - `struct lysc_node *` */
+    LY_STMT_ORGANIZATION = 0x200000,    /**< ::lysp_ext_substmt.storage - `const char *`
+                                     ::lysp_ext_instance.parent - `struct lysp_(sub)module *`
+                                     ::lysc_ext_substmt.storage - `const char *`
+                                     ::lysc_ext_instance.parent - `struct lysc_module *` */
+    LY_STMT_PATH = 0x210000,    /**< ::lysp_ext_substmt.storage - `struct lyxp_expr *`
+                                     ::lysp_ext_instance.parent - `struct lysp_type *`
+                                     ::lysc_ext_substmt.storage - not compiled
+                                     ::lysc_ext_instance.parent - `struct lysc_type *` */
+    LY_STMT_PATTERN = 0x220000, /**< ::lysp_ext_substmt.storage - `struct lysp_restr *`[]
+                                     ::lysp_ext_instance.parent - `struct lysp_restr *`
+                                     ::lysc_ext_substmt.storage - `struct lysc_pattern **`[]
+                                     ::lysc_ext_instance.parent - `struct lysc_pattern *` */
+    LY_STMT_POSITION = 0x230000,    /**< ::lysp_ext_substmt.storage - `int64_t *`
+                                     ::lysp_ext_instance.parent - `struct lysp_type_enum *`
+                                     ::lysc_ext_substmt.storage - `int64_t *`
+                                     ::lysc_ext_instance.parent - `struct lysc_type_bitenum_item *` */
+    LY_STMT_PREFIX = 0x240000,  /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `const char *`
+                                     ::lysc_ext_substmt.storage - not compiled
+                                     ::lysc_ext_instance.parent - `struct lysc_module *` */
+    LY_STMT_PRESENCE = 0x250000,    /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `const char *`
+                                     ::lysc_ext_substmt.storage - `const char *`
+                                     ::lysc_ext_instance.parent - `struct lysc_node_container *` */
+    LY_STMT_RANGE = 0x260000,   /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_restr *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - `struct lysc_range *` */
+    LY_STMT_REFERENCE = 0x270000,   /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `const char *`
+                                     ::lysc_ext_substmt.storage - `const char *`
+                                     ::lysc_ext_instance.parent - compiled parent statement */
+    LY_STMT_REFINE = 0x280000,  /**< ::lysp_ext_substmt.storage - `struct lysp_refine *`[]
+                                     ::lysp_ext_instance.parent - `struct lysp_refine *`
+                                     ::lysc_ext_substmt.storage - not compiled
+                                     ::lysc_ext_instance.parent - `struct lysc_node *` */
+    LY_STMT_REQUIRE_INSTANCE = 0x290000,    /**< ::lysp_ext_substmt.storage - `uint8_t *`
+                                     ::lysp_ext_instance.parent - `struct lysp_type *`
+                                     ::lysc_ext_substmt.storage - `uint8_t *`
+                                     ::lysc_ext_instance.parent - `struct lysc_type *` */
+    LY_STMT_REVISION = 0x2A0000,    /**< ::lysp_ext_substmt.storage - `struct lysp_revision *`[]
+                                     ::lysp_ext_instance.parent - `struct lysp_revision *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - not compiled */
+    LY_STMT_REVISION_DATE = 0x2B0000,   /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `const char *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - not compiled */
+    LY_STMT_STATUS = 0x2C0000,  /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `uint16_t *`
+                                     ::lysc_ext_substmt.storage - `uint16_t *`
+                                     ::lysc_ext_instance.parent - compiled parent statement */
+    LY_STMT_SUBMODULE = 0x2D0000,   /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_submodule *`
+                                     ::lysc_ext_substmt.storage - not compiled
+                                     ::lysc_ext_instance.parent - `struct lysc_module *` */
+    LY_STMT_TYPE = 0x2E0000,    /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_type *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - `struct lysc_type *` */
+    LY_STMT_TYPEDEF = 0x2F0000, /**< ::lysp_ext_substmt.storage - `struct lysp_tpdf *`[]
+                                     ::lysp_ext_instance.parent - `struct lysp_tpdf *`
+                                     ::lysc_ext_substmt.storage - not compiled
+                                     ::lysc_ext_instance.parent - `struct lysc_type *` */
+    LY_STMT_UNIQUE = 0x300000,  /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_qname *`[]
+                                     ::lysc_ext_substmt.storage - not compiled
+                                     ::lysc_ext_instance.parent - `struct lysc_node_list *` */
+    LY_STMT_UNITS = 0x310000,   /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `const char *`
+                                     ::lysc_ext_substmt.storage - `const char *`
+                                     ::lysc_ext_instance.parent - `struct lysc_node *`, `struct lysc_type *` (typedef) */
+    LY_STMT_VALUE = 0x320000,   /**< ::lysp_ext_substmt.storage - `int64_t *`
+                                     ::lysp_ext_instance.parent - `struct lysp_type_enum *`
+                                     ::lysc_ext_substmt.storage - `int64_t *`
+                                     ::lysc_ext_instance.parent - `struct lysc_type_bitenum_item *` */
+    LY_STMT_WHEN = 0x330000,    /**< ::lysp_ext_substmt.storage and ::lysp_ext_instance.parent - `struct lysp_when *`
+                                     ::lysc_ext_substmt.storage and ::lysc_ext_instance.parent - `struct lysc_when *` */
+    LY_STMT_YANG_VERSION = 0x340000,    /**< ::lysp_ext_substmt.storage - `uint8_t *`
+                                     ::lysp_ext_instance.parent - `struct lysp_(sub)module *`
+                                     ::lysc_ext_substmt.storage - not compiled
+                                     ::lysc_ext_instance.parent - `struct lysc_module *` */
+    LY_STMT_YIN_ELEMENT = 0x350000, /**< ::lysp_ext_substmt.storage - `uint16_t *`
+                                     ::lysp_ext_instance.parent - `struct lysp_ext *`
+                                     ::lysc_ext_substmt.storage - not compiled
+                                     ::lysc_ext_instance.parent - `struct lysc_ext *` */
 
     /* separated from the list of statements
      * the following tokens are part of the syntax and parsers have to work
@@ -287,57 +381,65 @@
 };
 
 /**
- * @brief YANG extension instance
+ * @brief Structure representing a parsed known YANG substatement in an extension instance.
+ */
+struct lysp_ext_substmt {
+    enum ly_stmt stmt;  /**< parsed substatement */
+    void *storage;      /**< pointer to the parsed storage of the statement according to the specific
+                             lys_ext_substmt::stmt */
+};
+
+/**
+ * @brief YANG extension parsed 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()) */
+    void *prefix_data;                      /**< format-specific data for prefix resolution (see ly_resolve_prefix()) */
+    struct lysp_ext *def;                   /**< pointer to the extension definition */
 
-    struct lysp_stmt *child;                /**< list of the extension's substatements (linked list) */
+    void *parent;                           /**< pointer to the parent statement holding the extension instance(s), use
+                                                 ::lysp_ext_instance#parent_stmt to access the value/structure */
+    enum ly_stmt parent_stmt;               /**< type of the parent statement */
+    LY_ARRAY_COUNT_TYPE parent_stmt_index;  /**< index of the stamenet in case the parent does not point to the parent
+                                                 statement directly and it is an array */
+    uint16_t flags;                         /**< ::LYS_INTERNAL value (@ref snodeflags) */
 
-    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 */
+    const struct lyplg_ext_record *record;  /**< extension definition plugin record, if any */
+    struct lysp_ext_substmt *substmts;      /**< list of supported known YANG statements with the pointer to their
+                                                 parsed data ([sized array](@ref sizedarrays)) */
+    void *parsed;                           /**< private plugin parsed data */
+    struct lysp_stmt *child;                /**< list of generic (unknown) YANG statements */
 };
 
 /**
- * @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.
+ * @brief Structure representing a compiled known YANG substatement in an extension instance.
  */
 struct lysc_ext_substmt {
-    enum ly_stmt stmt;                     /**< allowed substatement */
-    void *storage;                         /**< pointer to the storage of the compiled statement according to the specific
-                                                lysc_ext_substmt::stmt */
+    enum ly_stmt stmt;  /**< compiled substatement */
+    void *storage;      /**< pointer to the compiled storage of the statement according to the specific
+                             lys_ext_substmt::stmt */
 };
 
 /**
- * @brief YANG extension instance
+ * @brief YANG extension compiled 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 */
+    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)) */
 
-    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) */
+    void *parent;                       /**< pointer to the parent element holding the extension instance(s), use
+                                             ::lysc_ext_instance#parent_stmt to access the value/structure */
+    enum ly_stmt parent_stmt;           /**< type of the parent statement */
+    LY_ARRAY_COUNT_TYPE parent_stmt_index;  /**< index of the stamenet in case the parent does not point to the parent
+                                                 statement directly and it is an array */
+
+    struct lysc_ext_substmt *substmts;  /**< list of supported known YANG statements with the pointer to their
+                                             compiled data ([sized array](@ref sizedarrays)) */
+    void *compiled;                     /**< private plugin compiled data */
 };
 
 /**
@@ -350,7 +452,84 @@
     uint32_t plugins_extensions_apiver__ = LYPLG_EXT_API_VERSION; \
     const struct lyplg_ext_record plugins_extensions__[]
 
-typedef LY_ERR (*lyplg_ext_parse_clb)(struct lysp_ctx *pctx, struct lysp_ext_instance *p_ext);
+/*
+ * parse
+ */
+
+/**
+ * @brief Callback for parsing extension instance substatements.
+ *
+ * All known YANG substatements can easily be parsed using ::lys_parse_extension_instance.
+ *
+ * @param[in] pctx Parse context.
+ * @param[in,out] ext Parsed extension instance data.
+ * @return LY_SUCCESS on success.
+ * @return LY_ENOT if the extension instance is not supported and should be removed.
+ * @return LY_ERR error on error.
+ */
+typedef LY_ERR (*lyplg_ext_parse_clb)(struct lysp_ctx *pctx, struct lysp_ext_instance *ext);
+
+/**
+ * @brief Log a message from an extension plugin using the parsed extension instance.
+ *
+ * @param[in] pctx Parse context to use.
+ * @param[in] ext Parsed extensiopn instance.
+ * @param[in] level Log message level (error, warning, etc.)
+ * @param[in] err_no Error type code.
+ * @param[in] format Format string to print.
+ * @param[in] ... Format variable parameters.
+ */
+LIBYANG_API_DECL void lyplg_ext_parse_log(const struct lysp_ctx *pctx, const struct lysp_ext_instance *ext,
+        LY_LOG_LEVEL level, LY_ERR err_no, const char *format, ...);
+
+/**
+ * @brief Get current parsed module from a parse context.
+ *
+ * @param[in] pctx Parse context.
+ * @return Current (local) parse mod.
+ */
+LIBYANG_API_DECL const struct lysp_module *lyplg_ext_parse_get_cur_pmod(const struct lysp_ctx *pctx);
+
+/**
+ * @brief Parse substatements of an extension instance.
+ *
+ * Uses standard libyang schema compiler to transform YANG statements into the parsed schema structures. The plugins are
+ * supposed to use this function when the extension instance's substatements can be parsed in a standard way.
+ *
+ * @param[in] pctx Parse context.
+ * @param[in,out] ext Parsed extension instance with the prepared ::lysp_ext_instance.substmts array, which will be
+ * updated by storing the parsed data.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR error on error.
+ */
+LIBYANG_API_DECL LY_ERR lyplg_ext_parse_extension_instance(struct lysp_ctx *pctx, struct lysp_ext_instance *ext);
+
+/*
+ * compile
+ */
+
+/**
+ * @defgroup scflags Schema compile flags
+ *
+ * Flags to modify schema compilation process and change the way how the particular statements are being compiled. *
+ * @{
+ */
+#define LYS_COMPILE_GROUPING        0x01            /**< Compiling (validation) of a non-instantiated grouping.
+                                                      In this case not all the restrictions are checked since they can
+                                                      be valid only in the real placement of the grouping. This is
+                                                      the case of any restriction that needs to look out of the statements
+                                                      themselves, since the context is not known. */
+#define LYS_COMPILE_DISABLED        0x02            /**< Compiling a disabled subtree (by its if-features). Meaning
+                                                      it will be removed at the end of compilation and should not be
+                                                      added to any unres sets. */
+#define LYS_COMPILE_NO_CONFIG       0x04            /**< ignore config statements, neither inherit config value */
+#define LYS_COMPILE_NO_DISABLED     0x08            /**< ignore if-feature statements */
+
+#define LYS_COMPILE_RPC_INPUT       (LYS_IS_INPUT | LYS_COMPILE_NO_CONFIG)  /**< Internal option when compiling schema tree of RPC/action input */
+#define LYS_COMPILE_RPC_OUTPUT      (LYS_IS_OUTPUT | LYS_COMPILE_NO_CONFIG) /**< Internal option when compiling schema tree of RPC/action output */
+#define LYS_COMPILE_NOTIFICATION    (LYS_IS_NOTIF | LYS_COMPILE_NO_CONFIG)  /**< Internal option when compiling schema tree of Notification */
+
+/** @} scflags */
 
 /**
  * @brief Callback to compile extension from the lysp_ext_instance to the lysc_ext_instance. The later structure is generally prepared
@@ -360,15 +539,141 @@
  * function can be used to let the compilation to libyang following the standard rules for processing the YANG statements.
  *
  * @param[in] cctx Current compile context.
- * @param[in] p_ext Parsed extension instance data.
- * @param[in,out] c_ext Prepared compiled extension instance structure where an addition, extension-specific, data are
+ * @param[in] extp Parsed extension instance data.
+ * @param[in,out] ext Prepared compiled extension instance structure where an addition, extension-specific, data are
  * supposed to be placed for later use (data validation or use of external tool).
  * @return LY_SUCCESS in case of success.
- * @return LY_EVALID in case of non-conforming parsed data.
  * @return LY_ENOT in case the extension instance is not supported and should be removed.
+ * @return LY_ERR error on error.
  */
-typedef LY_ERR (*lyplg_ext_compile_clb)(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext,
-        struct lysc_ext_instance *c_ext);
+typedef LY_ERR (*lyplg_ext_compile_clb)(struct lysc_ctx *cctx, const struct lysp_ext_instance *extp,
+        struct lysc_ext_instance *ext);
+
+/**
+ * @brief Log a message from an extension plugin using the compiled extension instance.
+ *
+ * @param[in] cctx Optional compile context to generate the path from.
+ * @param[in] ext Compiled extension instance.
+ * @param[in] level Log message level (error, warning, etc.)
+ * @param[in] err_no Error type code.
+ * @param[in] format Format string to print.
+ */
+LIBYANG_API_DECL void lyplg_ext_compile_log(const struct lysc_ctx *cctx, const struct lysc_ext_instance *ext,
+        LY_LOG_LEVEL level, LY_ERR err_no, const char *format, ...);
+
+/**
+ * @brief Log a message from an extension plugin using the compiled extension instance with an explicit error path.
+ *
+ * @param[in] path Log error path to use.
+ * @param[in] ext Compiled extension instance.
+ * @param[in] level Log message level (error, warning, etc.)
+ * @param[in] err_no Error type code.
+ * @param[in] format Format string to print.
+ */
+LIBYANG_API_DECL void lyplg_ext_compile_log_path(const char *path, const struct lysc_ext_instance *ext,
+        LY_LOG_LEVEL level, LY_ERR err_no, const char *format, ...);
+
+/**
+ * @brief YANG schema compilation context getter for libyang context.
+ *
+ * @param[in] ctx YANG schema compilation context.
+ * @return libyang context connected with the compilation context.
+ */
+LIBYANG_API_DECL struct ly_ctx *lyplg_ext_compile_get_ctx(const struct lysc_ctx *ctx);
+
+/**
+ * @brief YANG schema compilation context getter for compilation options.
+ *
+ * @param[in] ctx YANG schema compilation context.
+ * @return pointer to the compilation options to allow modifying them with @ref scflags values.
+ */
+LIBYANG_API_DECL uint32_t *lyplg_ext_compile_get_options(const struct lysc_ctx *ctx);
+
+/**
+ * @brief YANG schema compilation context getter for current module.
+ *
+ * @param[in] ctx YANG schema compilation context.
+ * @return current module.
+ */
+LIBYANG_API_DECL const struct lys_module *lyplg_ext_compile_get_cur_mod(const struct lysc_ctx *ctx);
+
+/**
+ * @brief YANG schema compilation context getter for currently processed module.
+ *
+ * @param[in] ctx YANG schema compilation context.
+ * @return Currently processed module.
+ */
+LIBYANG_API_DECL struct lysp_module *lyplg_ext_compile_get_pmod(const struct lysc_ctx *ctx);
+
+/**
+ * @brief Compile substatements of an extension instance.
+ *
+ * Uses standard libyang schema compiler to transform YANG statements into the compiled schema structures. The plugins are
+ * supposed to use this function when the extension instance's substatements are supposed to be compiled in a standard way
+ * (or if just the @ref scflags are enough to modify the compilation process).
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] extp Parsed representation of the extension instance being processed.
+ * @param[in,out] ext Compiled extension instance with the prepared ::lysc_ext_instance.substmts array, which will be updated
+ * by storing the compiled data.
+ * @return LY_SUCCESS on success.
+ * @return LY_EVALID if compilation of the substatements fails.
+ * @return LY_ENOT if the extension is disabled (by if-feature) and should be ignored.
+ */
+LIBYANG_API_DECL LY_ERR lyplg_ext_compile_extension_instance(struct lysc_ctx *ctx, const struct lysp_ext_instance *extp,
+        struct lysc_ext_instance *ext);
+
+/**
+ * @brief Compile substatements of an extension instance but append all schema data nodes as augments.
+ *
+ * Similar to ::lys_compile_extension_instance().
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] extp Parsed representation of the extension instance being processed.
+ * @param[in,out] ext Compiled extension instance with the prepared ::lysc_ext_instance.substmts array, which will be updated
+ * by storing the compiled data except for schema data nodes.
+ * @param[in] aug_target Augment target node to append schema data nodes.
+ * @return LY_SUCCESS on success.
+ * @return LY_EVALID if compilation of the substatements fails.
+ * @return LY_ENOT if the extension is disabled (by if-feature) and should be ignored.
+ */
+LIBYANG_API_DECL LY_ERR lyplg_ext_compile_extension_instance_augment(struct lysc_ctx *ctx,
+        const struct lysp_ext_instance *extp, struct lysc_ext_instance *ext, struct lysc_node *aug_target);
+
+/**
+ * @brief Find augment target in an extension.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] path Absolute-schema-nodeid representing the augment target. The first segment is expected to identify
+ * the specific extension instance.
+ * @param[out] aug_ext Optional augment target extension.
+ * @param[out] aug_target Augment target compiled schema node.
+ * @return LY_ERR value.
+ */
+LIBYANG_API_DECL LY_ERR lys_compile_extension_instance_find_augment_target(struct lysc_ctx *ctx, const char *path,
+        struct lysc_ext_instance **aug_ext, struct lysc_node **aug_target);
+
+/**
+ * @brief Update path in the compile context, which is used for logging where the compilation failed.
+ *
+ * @param[in] ctx Compile context with the path.
+ * @param[in] parent_module Module of the current node's parent to check difference with the currently processed module (taken from @p ctx).
+ * @param[in] name Name of the node to update path with. If NULL, the last segment is removed. If the format is `{keyword}`, the following
+ * call updates the segment to the form `{keyword='name'}` (to remove this compound segment, 2 calls with NULL @p name must be used).
+ */
+LIBYANG_API_DECL void lysc_update_path(struct lysc_ctx *ctx, struct lys_module *parent_module, const char *name);
+
+/**
+ * @brief Duplicate the compiled extension (definition) structure.
+ *
+ * @param[in] orig The extension structure to duplicate.
+ * @return The duplicated structure to use.
+ */
+LIBYANG_API_DECL struct lysc_ext *lysc_ext_dup(struct lysc_ext *orig);
+
+/*
+ * printer
+ */
 
 /**
  * @brief Callback to print the compiled extension instance's private data in the INFO format.
@@ -382,12 +687,46 @@
 typedef LY_ERR (*lyplg_ext_schema_printer_clb)(struct lyspr_ctx *ctx, struct lysc_ext_instance *ext, ly_bool *flag);
 
 /**
- * @brief Callback to free the extension-specific data created by its compilation.
+ * @brief YANG printer context getter for output handler.
  *
- * @param[in] ctx libyang context.
- * @param[in,out] ext Compiled extension structure where the data to free are placed.
+ * @param[in] ctx YANG printer context.
+ * @return Output handler where the data are being printed. Note that the address of the handler pointer in the context is
+ * returned to allow to modify the handler.
  */
-typedef void (*lyplg_ext_free_clb)(struct ly_ctx *ctx, struct lysc_ext_instance *ext);
+LIBYANG_API_DECL struct ly_out **lyplg_ext_print_get_out(const struct lyspr_ctx *ctx);
+
+/**
+ * @brief YANG printer context getter for printer options.
+ *
+ * @param[in] ctx YANG printer context.
+ * @return pointer to the printer options to allow modifying them with @ref schemaprinterflags values.
+ */
+LIBYANG_API_DECL uint32_t *lyplg_ext_print_get_options(const struct lyspr_ctx *ctx);
+
+/**
+ * @brief YANG printer context getter for printer indentation level.
+ *
+ * @param[in] ctx YANG printer context.
+ * @return pointer to the printer's indentation level to allow modifying its value.
+ */
+LIBYANG_API_DECL uint16_t *lyplg_ext_print_get_level(const struct lyspr_ctx *ctx);
+
+/**
+ * @brief Print substatements of an extension instance
+ *
+ * Generic function to access YANG printer functions from the extension plugins (::lyplg_ext_schema_printer_clb).
+ *
+ * @param[in] ctx YANG printer context to provide output handler and other information for printing.
+ * @param[in] ext The compiled extension instance to access the extensions and substatements data.
+ * @param[in,out] flag Flag to be shared with the caller regarding the opening brackets - 0 if the '{' not yet printed,
+ * 1 otherwise.
+ */
+LIBYANG_API_DECL void lyplg_ext_print_extension_instance(struct lyspr_ctx *ctx, const struct lysc_ext_instance *ext,
+        ly_bool *flag);
+
+/*
+ * data node
+ */
 
 /**
  * @brief Callback called for all data nodes connected to the extension instance.
@@ -403,6 +742,10 @@
  */
 typedef LY_ERR (*lyplg_ext_data_node_clb)(struct lysc_ext_instance *ext, struct lyd_node *node, uint32_t validate_options);
 
+/*
+ * snode
+ */
+
 /**
  * @brief Callback for getting a schema node for a new YANG instance data described by an extension instance.
  * Needed only if the extension instance supports some nested standard YANG data.
@@ -425,6 +768,10 @@
         const struct lysc_node *sparent, const char *prefix, size_t prefix_len, LY_VALUE_FORMAT format, void *prefix_data,
         const char *name, size_t name_len, const struct lysc_node **snode);
 
+/*
+ * validate
+ */
+
 /**
  * @brief Callback for validating parsed YANG instance data described by an extension instance.
  *
@@ -443,6 +790,46 @@
 typedef LY_ERR (*lyplg_ext_data_validate_clb)(struct lysc_ext_instance *ext, struct lyd_node *sibling,
         const struct lyd_node *dep_tree, enum lyd_type data_type, uint32_t val_opts, struct lyd_node **diff);
 
+/*
+ * parse free
+ */
+
+/**
+ * @brief Callback to free the extension-specific data created by its parsing.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in,out] ext Parsed extension structure to free.
+ */
+typedef void (*lyplg_ext_parse_free_clb)(const struct ly_ctx *ctx, struct lysp_ext_instance *ext);
+
+/**
+ * @brief Free the extension instance's data parsed with ::lys_parse_extension_instance().
+ *
+ * @param[in] ctx libyang context
+ * @param[in] substmts Extension instance substatements to free.
+ */
+LIBYANG_API_DECL void lyplg_ext_pfree_instance_substatements(const struct ly_ctx *ctx, struct lysp_ext_substmt *substmts);
+
+/*
+ * compile free
+ */
+
+/**
+ * @brief Callback to free the extension-specific data created by its compilation.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in,out] ext Compiled extension structure to free.
+ */
+typedef void (*lyplg_ext_compile_free_clb)(const struct ly_ctx *ctx, struct lysc_ext_instance *ext);
+
+/**
+ * @brief Free the extension instance's data compiled with ::lys_compile_extension_instance().
+ *
+ * @param[in] ctx libyang context
+ * @param[in] substmts Extension instance substatements to free.
+ */
+LIBYANG_API_DECL void lyplg_ext_cfree_instance_substatements(const struct ly_ctx *ctx, struct lysc_ext_substmt *substmts);
+
 /**
  * @brief Extension plugin implementing various aspects of a YANG extension
  */
@@ -453,13 +840,15 @@
     lyplg_ext_compile_clb compile;          /**< callback to compile extension instance from the parsed data */
     lyplg_ext_schema_printer_clb sprinter;  /**< callback to print the compiled content (info format) of the extension
                                                  instance */
-    lyplg_ext_free_clb free;                /**< free the extension-specific data created by its compilation */
 
     lyplg_ext_data_node_clb node;           /**< callback to validate most relevant data instance for the extension
                                                  instance */
     lyplg_ext_data_snode_clb snode;         /**< callback to get schema node for nested YANG data */
     lyplg_ext_data_validate_clb validate;   /**< callback to validate parsed data instances according to the extension
                                                  definition */
+
+    lyplg_ext_parse_free_clb pfree;         /**< free the extension-specific data created by its parsing */
+    lyplg_ext_compile_free_clb cfree;       /**< free the extension-specific data created by its compilation */
 };
 
 struct lyplg_ext_record {
@@ -482,7 +871,7 @@
  * @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);
+LIBYANG_API_DECL const char *lyplg_ext_stmt2str(enum ly_stmt stmt);
 
 /**
  * @brief Convert nodetype to statement identifier
@@ -490,16 +879,31 @@
  * @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);
+LIBYANG_API_DECL enum ly_stmt lyplg_ext_nodetype2stmt(uint16_t nodetype);
 
 /**
- * @brief Free the extension instance's data compiled with ::lys_compile_extension_instance().
+ * @brief Get compiled ext instance storage for a specific statement.
  *
- * @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.
+ * @param[in] ext Compiled ext instance.
+ * @param[in] stmt Compiled statement. Can be a mask when the first match is returned, it is expected the storage is
+ * the same for all the masked statements.
+ * @param[out] storage Compiled ext instance substatement storage, NULL if was not compiled.
+ * @return LY_SUCCESS on success.
+ * @return LY_ENOT if the substatement is not supported.
  */
-LIBYANG_API_DECL void lyplg_ext_instance_substatements_free(struct ly_ctx *ctx, struct lysc_ext_substmt *substmts);
+LIBYANG_API_DECL LY_ERR lyplg_ext_get_storage(const struct lysc_ext_instance *ext, int stmt, const void **storage);
+
+/**
+ * @brief Get parsed ext instance storage for a specific statement.
+ *
+ * @param[in] ext Compiled ext instance.
+ * @param[in] stmt Parsed statement. Can be a mask when the first match is returned, it is expected the storage is
+ * the same for all the masked statements.
+ * @param[out] storage Parsed ext instance substatement storage, NULL if was not parsed.
+ * @return LY_SUCCESS on success.
+ * @return LY_ENOT if the substatement is not supported.
+ */
+LIBYANG_API_DECL LY_ERR lyplg_ext_parsed_get_storage(const struct lysc_ext_instance *ext, int stmt, const void **storage);
 
 /**
  * @brief Get specific run-time extension instance data from a callback set by ::ly_ctx_set_ext_data_clb().
@@ -522,33 +926,20 @@
  * @return LY_SUCCESS on success.
  * @return LY_ERR error on error.
  */
-LIBYANG_API_DECL LY_ERR lyd_insert_ext(struct lyd_node *parent, struct lyd_node *first);
-
-/**
- * @brief Provide a log message from an extension plugin.
- *
- * @param[in] ext Compiled extension structure providing generic information about the extension/plugin causing the message.
- * @param[in] level Log message level (error, warning, etc.)
- * @param[in] err_no Error type code.
- * @param[in] path Path relevant to the message.
- * @param[in] format Format string to print.
- */
-LIBYANG_API_DECL void lyplg_ext_log(const struct lysc_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err_no, const char *path,
-        const char *format, ...);
+LIBYANG_API_DECL LY_ERR lyplg_ext_insert(struct lyd_node *parent, struct lyd_node *first);
 
 /**
  * @brief Expand parent-reference xpath expressions
  *
- * @param ext[in] context allocated for extension
- * @param refs[out] set of lysc nodes matching parent-refernce xpaths
+ * @param[in] ext Context allocated for extension.
+ * @param[out] refs Set of schema node matching parent-reference XPaths.
  * @return LY_ERR value.
  */
 LIBYANG_API_DECL LY_ERR lyplg_ext_schema_mount_get_parent_ref(const struct lysc_ext_instance *ext, struct ly_set **refs);
 
 /**
- * @brief Allocate a new context for a particular instance of the
- * yangmnt:mount-point extension.  Caller is responsible for destroying
- * the resulting context.
+ * @brief Allocate a new context for a particular instance of the yangmnt:mount-point extension.
+ * Caller is responsible for destroying the resulting context.
  *
  * @param[in] ext Compiled extension instance.
  * @param[out] ctx A context with modules loaded from the list found in
@@ -557,22 +948,6 @@
  */
 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.
- * @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);
-
 /** @} pluginsExtensions */
 
 #ifdef __cplusplus
diff --git a/src/plugins_exts/metadata.c b/src/plugins_exts/metadata.c
index f6e1580..fc49e2c 100644
--- a/src/plugins_exts/metadata.c
+++ b/src/plugins_exts/metadata.c
@@ -1,9 +1,10 @@
 /**
  * @file metadata.c
  * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief libyang extension plugin - Metadata (RFC 7952)
  *
- * Copyright (c) 2019 CESNET, z.s.p.o.
+ * Copyright (c) 2019 - 2022 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
@@ -21,93 +22,150 @@
 #include "libyang.h"
 #include "plugins_exts.h"
 
-/**
- * @brief Representation of the compiled metadata substatements - simplify storage for the items available via
- * ::lysc_ext_substmt.
- */
-struct lyext_metadata {
-    struct lysc_type *type;            /**< type of the metadata (mandatory) */
+struct lysp_ext_metadata {
+    struct lysp_type *type;            /**< type of the metadata (mandatory) */
     const char *units;                 /**< units of the leaf's type */
-    struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
+    struct lysp_qname *iffeatures;     /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
     const char *dsc;                   /**< description */
     const char *ref;                   /**< reference */
     uint16_t flags;                    /**< [schema node flags](@ref snodeflags) - only LYS_STATUS_* values are allowed */
 };
 
+struct lysc_ext_metadata {
+    struct lysc_type *type;            /**< type of the metadata (mandatory) */
+    const char *units;                 /**< units of the leaf's type */
+    const char *dsc;                   /**< description */
+    const char *ref;                   /**< reference */
+    uint16_t flags;                    /**< [schema node flags](@ref snodeflags) - only LYS_STATUS_* values are allowed */
+};
+
+/**
+ * @brief Parse annotation extension instances.
+ *
+ * Implementation of ::lyplg_ext_parse_clb callback set as lyext_plugin::parse.
+ */
+static LY_ERR
+annotation_parse(struct lysp_ctx *pctx, struct lysp_ext_instance *ext)
+{
+    LY_ERR r;
+    struct lysp_ext_metadata *ann_pdata;
+    struct lysp_module *pmod;
+    LY_ARRAY_COUNT_TYPE u;
+
+    /* annotations can appear only at the top level of a YANG module or submodule */
+    if ((ext->parent_stmt != LY_STMT_MODULE) && (ext->parent_stmt != LY_STMT_SUBMODULE)) {
+        lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Extension %s is allowed only at the top level of a YANG module or "
+                "submodule, but it is placed in \"%s\" statement.", ext->name, lyplg_ext_stmt2str(ext->parent_stmt));
+        return LY_EVALID;
+    }
+
+    pmod = ext->parent;
+
+    /* check for duplication */
+    LY_ARRAY_FOR(pmod->exts, u) {
+        if ((&pmod->exts[u] != ext) && (pmod->exts[u].name == ext->name) && !strcmp(pmod->exts[u].argument, ext->argument)) {
+            /* duplication of the same annotation extension in a single module */
+            lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Extension %s is instantiated multiple times.", ext->name);
+            return LY_EVALID;
+        }
+    }
+
+    /* parse annotation substatements */
+    ext->parsed = ann_pdata = calloc(1, sizeof *ann_pdata);
+    if (!ann_pdata) {
+        goto emem;
+    }
+    LY_ARRAY_CREATE_GOTO(lyplg_extp_cur_pmod(pctx)->mod->ctx, ext->substmts, 6, r, emem);
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[0].stmt = LY_STMT_IF_FEATURE;
+    ext->substmts[0].storage = &ann_pdata->iffeatures;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[1].stmt = LY_STMT_UNITS;
+    ext->substmts[1].storage = &ann_pdata->units;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[2].stmt = LY_STMT_STATUS;
+    ext->substmts[2].storage = &ann_pdata->flags;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[3].stmt = LY_STMT_TYPE;
+    ext->substmts[3].storage = &ann_pdata->type;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[4].stmt = LY_STMT_DESCRIPTION;
+    ext->substmts[4].storage = &ann_pdata->dsc;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[5].stmt = LY_STMT_REFERENCE;
+    ext->substmts[5].storage = &ann_pdata->ref;
+
+    if ((r = lyplg_ext_parse_extension_instance(pctx, ext))) {
+        return r;
+    }
+
+    /* check for mandatory substatements */
+    if (!ann_pdata->type) {
+        lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Missing mandatory keyword \"type\" as a child of \"%s %s\".",
+                ext->name, ext->argument);
+        return LY_EVALID;
+    }
+
+    return LY_SUCCESS;
+
+emem:
+    lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s()).", __func__);
+    return LY_EMEM;
+}
+
 /**
  * @brief Compile annotation extension instances.
  *
  * Implementation of ::lyplg_ext_compile_clb callback set as lyext_plugin::compile.
  */
 static LY_ERR
-annotation_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext, struct lysc_ext_instance *c_ext)
+annotation_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *extp, struct lysc_ext_instance *ext)
 {
     LY_ERR ret;
-    struct lyext_metadata *annotation;
-    struct lysc_module *mod_c;
-    LY_ARRAY_COUNT_TYPE u;
-
-    /* annotations can appear only at the top level of a YANG module or submodule */
-    if ((c_ext->parent_stmt != LY_STMT_MODULE) && (c_ext->parent_stmt != LY_STMT_SUBMODULE)) {
-        lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
-                "Extension %s is allowed only at the top level of a YANG module or submodule, but it is placed in \"%s\" statement.",
-                p_ext->name, ly_stmt2str(c_ext->parent_stmt));
-        return LY_EVALID;
-    }
-    /* check mandatory argument */
-    if (!c_ext->argument) {
-        lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
-                "Extension %s is instantiated without mandatory argument representing metadata name.", p_ext->name);
-        return LY_EVALID;
-    }
-
-    mod_c = (struct lysc_module *)c_ext->parent;
-
-    /* check for duplication */
-    LY_ARRAY_FOR(mod_c->exts, u) {
-        if ((&mod_c->exts[u] != c_ext) && (mod_c->exts[u].def == c_ext->def) && !strcmp(mod_c->exts[u].argument, c_ext->argument)) {
-            /* duplication of the same annotation extension in a single module */
-            lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx), "Extension %s is instantiated multiple times.", p_ext->name);
-            return LY_EVALID;
-        }
-    }
+    struct lysc_ext_metadata *ann_cdata;
 
     /* compile annotation substatements */
-    c_ext->data = annotation = calloc(1, sizeof *annotation);
-    if (!annotation) {
+    ext->compiled = ann_cdata = calloc(1, sizeof *ann_cdata);
+    if (!ann_cdata) {
         goto emem;
     }
-    LY_ARRAY_CREATE_GOTO(lysc_ctx_get_ctx(cctx), c_ext->substmts, 6, ret, emem);
+    LY_ARRAY_CREATE_GOTO(lysc_ctx_get_ctx(cctx), ext->substmts, 6, ret, emem);
 
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[ANNOTATION_SUBSTMT_IFF].stmt = LY_STMT_IF_FEATURE;
-    c_ext->substmts[ANNOTATION_SUBSTMT_IFF].storage = &annotation->iffeatures;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[0].stmt = LY_STMT_IF_FEATURE;
+    ext->substmts[0].storage = NULL;
 
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[ANNOTATION_SUBSTMT_UNITS].stmt = LY_STMT_UNITS;
-    c_ext->substmts[ANNOTATION_SUBSTMT_UNITS].storage = &annotation->units;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[1].stmt = LY_STMT_UNITS;
+    ext->substmts[1].storage = &ann_cdata->units;
 
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[ANNOTATION_SUBSTMT_STATUS].stmt = LY_STMT_STATUS;
-    c_ext->substmts[ANNOTATION_SUBSTMT_STATUS].storage = &annotation->flags;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[2].stmt = LY_STMT_STATUS;
+    ext->substmts[2].storage = &ann_cdata->flags;
 
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[ANNOTATION_SUBSTMT_TYPE].stmt = LY_STMT_TYPE;
-    c_ext->substmts[ANNOTATION_SUBSTMT_TYPE].storage = &annotation->type;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[3].stmt = LY_STMT_TYPE;
+    ext->substmts[3].storage = &ann_cdata->type;
 
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[ANNOTATION_SUBSTMT_DSC].stmt = LY_STMT_DESCRIPTION;
-    c_ext->substmts[ANNOTATION_SUBSTMT_DSC].storage = &annotation->dsc;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[4].stmt = LY_STMT_DESCRIPTION;
+    ext->substmts[4].storage = &ann_cdata->dsc;
 
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[ANNOTATION_SUBSTMT_REF].stmt = LY_STMT_REFERENCE;
-    c_ext->substmts[ANNOTATION_SUBSTMT_REF].storage = &annotation->ref;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[5].stmt = LY_STMT_REFERENCE;
+    ext->substmts[5].storage = &ann_cdata->ref;
 
-    ret = lys_compile_extension_instance(cctx, p_ext, c_ext);
+    ret = lyplg_ext_compile_extension_instance(cctx, extp, ext);
     return ret;
 
 emem:
-    lyplg_ext_log(c_ext, LY_LLERR, LY_EMEM, lysc_ctx_get_path(cctx), "Memory allocation failed (%s()).", __func__);
+    lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s()).", __func__);
     return LY_EMEM;
 }
 
@@ -117,27 +175,43 @@
  * Implementation of ::lyplg_ext_schema_printer_clb set as ::lyext_plugin::sprinter
  */
 static LY_ERR
-annotation_schema_printer(struct lyspr_ctx *ctx, struct lysc_ext_instance *ext, ly_bool *flag)
+annotation_sprinter(struct lyspr_ctx *ctx, struct lysc_ext_instance *ext, ly_bool *flag)
 {
-    lysc_print_extension_instance(ctx, ext, flag);
+    lyplg_ext_print_extension_instance(ctx, ext, flag);
 
     return LY_SUCCESS;
 }
 
 /**
- * @brief Free annotation extension instances' data.
+ * @brief Free parsed annotation extension instance data.
  *
- * Implementation of ::lyplg_ext_free_clb callback set as ::lyext_plugin::free.
+ * Implementation of ::lyplg_ext_parse_free_clb callback set as ::lyext_plugin::pfree.
  */
 static void
-annotation_free(struct ly_ctx *ctx, struct lysc_ext_instance *ext)
+annotation_pfree(const struct ly_ctx *ctx, struct lysp_ext_instance *ext)
 {
     if (!ext->substmts) {
         return;
     }
 
-    lyplg_ext_instance_substatements_free(ctx, ext->substmts);
-    free(ext->data);
+    lyplg_ext_pfree_instance_substatements(ctx, ext->substmts);
+    free(ext->parsed);
+}
+
+/**
+ * @brief Free compiled annotation extension instance data.
+ *
+ * Implementation of ::lyplg_ext_compile_free_clb callback set as ::lyext_plugin::cfree.
+ */
+static void
+annotation_cfree(const struct ly_ctx *ctx, struct lysc_ext_instance *ext)
+{
+    if (!ext->substmts) {
+        return;
+    }
+
+    lyplg_ext_cfree_instance_substatements(ctx, ext->substmts);
+    free(ext->compiled);
 }
 
 /**
@@ -153,13 +227,15 @@
         .revision = "2016-08-05",
         .name = "annotation",
 
-        .plugin.id = "libyang 2 - metadata, version 1",
-        .plugin.compile = &annotation_compile,
-        .plugin.sprinter = &annotation_schema_printer,
-        .plugin.free = annotation_free,
+        .plugin.id = "ly2 metadata v1",
+        .plugin.parse = annotation_parse,
+        .plugin.compile = annotation_compile,
+        .plugin.sprinter = annotation_sprinter,
         .plugin.node = NULL,
         .plugin.snode = NULL,
-        .plugin.validate = NULL
+        .plugin.validate = NULL,
+        .plugin.pfree = annotation_pfree,
+        .plugin.cfree = annotation_cfree,
     },
     {0}     /* terminating zeroed record */
 };
diff --git a/src/plugins_exts/metadata.h b/src/plugins_exts/metadata.h
index 6387e1f..59ea2bf 100644
--- a/src/plugins_exts/metadata.h
+++ b/src/plugins_exts/metadata.h
@@ -23,13 +23,6 @@
 extern "C" {
 #endif
 
-#define ANNOTATION_SUBSTMT_IFF     0 /**< index for the LY_STMT_IF_FEATURE substatement in annotation's ::lysc_ext_instance.substmts */
-#define ANNOTATION_SUBSTMT_UNITS   1 /**< index for the LY_STMT_UNITS substatement in annotation's ::lysc_ext_instance.substmts */
-#define ANNOTATION_SUBSTMT_STATUS  2 /**< index for the LY_STMT_STATUS substatement in annotation's ::lysc_ext_instance.substmts */
-#define ANNOTATION_SUBSTMT_TYPE    3 /**< index for the LY_STMT_TYPE substatement in annotation's ::lysc_ext_instance.substmts */
-#define ANNOTATION_SUBSTMT_DSC     4 /**< index for the LY_STMT_DSC substatement in annotation's ::lysc_ext_instance.substmts */
-#define ANNOTATION_SUBSTMT_REF     5 /**< index for the LY_STMT_REF substatement in annotation's ::lysc_ext_instance.substmts */
-
 /**
  * @brief Metadata structure.
  *
diff --git a/src/plugins_exts/nacm.c b/src/plugins_exts/nacm.c
index a83e32b..7323cd2 100644
--- a/src/plugins_exts/nacm.c
+++ b/src/plugins_exts/nacm.c
@@ -1,9 +1,10 @@
 /**
  * @file nacm.c
  * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief libyang extension plugin - NACM (RFC 6536)
  *
- * Copyright (c) 2019 CESNET, z.s.p.o.
+ * Copyright (c) 2019 - 2022 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
@@ -16,11 +17,12 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "compat.h"
 #include "libyang.h"
 #include "plugins_exts.h"
 
 struct nacm_dfs_arg {
-    struct lysc_ext_instance *c_ext;
+    struct lysc_ext_instance *ext;
     struct lysc_node *parent;
 };
 
@@ -39,7 +41,7 @@
     if ((node != arg->parent) && !(node->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
         /* check that the node does not have its own NACM extension instance */
         LY_ARRAY_FOR(node->exts, u) {
-            if (node->exts[u].def == arg->c_ext->def) {
+            if (node->exts[u].def == arg->ext->def) {
                 /* the child already have its own NACM flag, so skip the subtree */
                 *dfs_continue = 1;
                 return LY_SUCCESS;
@@ -49,99 +51,99 @@
         /* duplicate this one to inherit it to the child */
         LY_ARRAY_NEW_GOTO(node->module->ctx, node->exts, inherited, ret, emem);
 
-        inherited->def = lysc_ext_dup(arg->c_ext->def);
+        inherited->def = lysc_ext_dup(arg->ext->def);
         inherited->parent = node;
-        inherited->parent_stmt = lys_nodetype2stmt(node->nodetype);
-        if (arg->c_ext->argument) {
-            LY_ERR ret;
-
-            if ((ret = lydict_insert(node->module->ctx, arg->c_ext->argument, strlen(arg->c_ext->argument),
-                    &inherited->argument))) {
+        inherited->parent_stmt = lyplg_ext_nodetype2stmt(node->nodetype);
+        if (arg->ext->argument) {
+            if ((ret = lydict_insert(node->module->ctx, arg->ext->argument, 0, &inherited->argument))) {
                 return ret;
             }
         }
         /* TODO duplicate extension instances */
-        inherited->data = arg->c_ext->data;
+        inherited->compiled = arg->ext->compiled;
     }
 
     return LY_SUCCESS;
 
 emem:
-    lyplg_ext_log(arg->c_ext, LY_LLERR, LY_EMEM, NULL, "Memory allocation failed (%s()).", __func__);
+    lyplg_ext_compile_log(NULL, arg->ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s()).", __func__);
     return ret;
 }
 
 /**
- * @brief Compile NAMC's extension instances.
+ * @brief Parse NACM extension instances.
  *
- * Implementation of ::lyplg_ext_compile_clb callback set as lyext_plugin::compile.
+ * Implementation of ::lyplg_ext_parse_clb callback set as lyext_plugin::parse.
  */
 static LY_ERR
-nacm_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext, struct lysc_ext_instance *c_ext)
+nacm_parse(struct lysp_ctx *pctx, struct lysp_ext_instance *ext)
 {
-    LY_ERR ret;
-    struct lysc_node *parent = NULL;
+    struct lysp_node *parent = NULL;
     LY_ARRAY_COUNT_TYPE u;
-    struct nacm_dfs_arg dfs_arg;
-
-    static const uint8_t nacm_deny_all = 1;
-    static const uint8_t nacm_deny_write = 2;
-
-    /* store the NACM flag */
-    if (!strcmp(c_ext->def->name, "default-deny-write")) {
-        c_ext->data = (void *)&nacm_deny_write;
-    } else if (!strcmp(c_ext->def->name, "default-deny-all")) {
-        c_ext->data = (void *)&nacm_deny_all;
-    } else {
-        return LY_EINT;
-    }
 
     /* check that the extension is instantiated at an allowed place - data node */
-    if (!LY_STMT_IS_NODE(c_ext->parent_stmt)) {
-        lyplg_ext_log(c_ext, LY_LLWRN, 0, lysc_ctx_get_path(cctx),
-                "Extension %s is allowed only in a data nodes, but it is placed in \"%s\" statement.",
-                p_ext->name, ly_stmt2str(c_ext->parent_stmt));
+    if (!(ext->parent_stmt & LY_STMT_NODE_MASK)) {
+        lyplg_ext_parse_log(pctx, ext, LY_LLWRN, 0, "Extension %s is allowed only in a data nodes, but it is placed in "
+                "\"%s\" statement.", ext->name, lyplg_ext_stmt2str(ext->parent_stmt));
         return LY_ENOT;
-    } else {
-        parent = (struct lysc_node *)c_ext->parent;
-        if (!(parent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE | LYS_ANYDATA |
-                LYS_CASE | LYS_RPC | LYS_ACTION | LYS_NOTIF))) {
-            /* note LYS_AUGMENT and LYS_USES is not in the list since they are not present in the compiled tree. Instead, libyang
-             * passes all their extensions to their children nodes */
-invalid_parent:
-            lyplg_ext_log(c_ext, LY_LLWRN, 0, lysc_ctx_get_path(cctx),
-                    "Extension %s is not allowed in %s statement.", p_ext->name, lys_nodetype2str(parent->nodetype));
-            return LY_ENOT;
-        }
-        if ((c_ext->data == (void *)&nacm_deny_write) && (parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF))) {
-            goto invalid_parent;
-        }
+    }
+
+    parent = ext->parent;
+    if (!(parent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE | LYS_ANYDATA |
+            LYS_CASE | LYS_RPC | LYS_ACTION | LYS_NOTIF)) || (!strcmp(strchr(ext->name, ':') + 1, "default-deny-write") &&
+            (parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)))) {
+        /* note LYS_AUGMENT and LYS_USES is not in the list since they are not present in the compiled tree. Instead, libyang
+         * passes all their extensions to their children nodes */
+        lyplg_ext_parse_log(pctx, ext, LY_LLWRN, 0, "Extension %s is not allowed in %s statement.", ext->name,
+                lys_nodetype2str(parent->nodetype));
+        return LY_ENOT;
     }
 
     /* check for duplication */
     LY_ARRAY_FOR(parent->exts, u) {
-        if ((&parent->exts[u] != c_ext) && parent->exts[u].def->plugin &&
-                (parent->exts[u].def->plugin->compile == c_ext->def->plugin->compile)) {
+        if ((&parent->exts[u] != ext) && parent->exts[u].record && (parent->exts[u].record->plugin.id == ext->record->plugin.id)) {
             /* duplication of a NACM extension on a single node
              * We check for all NACM plugins since we want to catch even the situation that there is default-deny-all
              * AND default-deny-write */
-            if (parent->exts[u].def == c_ext->def) {
-                lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
-                        "Extension %s is instantiated multiple times.", p_ext->name);
+            if (parent->exts[u].name == ext->name) {
+                lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Extension %s is instantiated multiple times.", ext->name);
             } else {
-                lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
+                lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID,
                         "Extension nacm:default-deny-write is mixed with nacm:default-deny-all.");
             }
             return LY_EVALID;
         }
     }
 
-    /* inherit the extension instance to all the children nodes */
-    dfs_arg.c_ext = c_ext;
-    dfs_arg.parent = parent;
-    ret = lysc_tree_dfs_full(parent, nacm_inherit_clb, &dfs_arg);
+    return LY_SUCCESS;
+}
 
-    return ret;
+/**
+ * @brief Compile NACM extension instances.
+ *
+ * Implementation of ::lyplg_ext_compile_clb callback set as lyext_plugin::compile.
+ */
+static LY_ERR
+nacm_compile(struct lysc_ctx *UNUSED(cctx), const struct lysp_ext_instance *UNUSED(extp), struct lysc_ext_instance *ext)
+{
+    struct nacm_dfs_arg dfs_arg;
+
+    static const uint8_t nacm_deny_all = 1;
+    static const uint8_t nacm_deny_write = 2;
+
+    /* store the NACM flag */
+    if (!strcmp(ext->def->name, "default-deny-write")) {
+        ext->compiled = (void *)&nacm_deny_write;
+    } else if (!strcmp(ext->def->name, "default-deny-all")) {
+        ext->compiled = (void *)&nacm_deny_all;
+    } else {
+        return LY_EINT;
+    }
+
+    /* inherit the extension instance to all the children nodes */
+    dfs_arg.ext = ext;
+    dfs_arg.parent = ext->parent;
+    return lysc_tree_dfs_full(ext->parent, nacm_inherit_clb, &dfs_arg);
 }
 
 /**
@@ -157,49 +159,57 @@
         .revision = "2012-02-22",
         .name = "default-deny-write",
 
-        .plugin.id = "libyang 2 - NACM, version 1",
-        .plugin.compile = &nacm_compile,
+        .plugin.id = "ly2 NACM v1",
+        .plugin.parse = nacm_parse,
+        .plugin.compile = nacm_compile,
         .plugin.sprinter = NULL,
-        .plugin.free = NULL,
         .plugin.node = NULL,
         .plugin.snode = NULL,
-        .plugin.validate = NULL
+        .plugin.validate = NULL,
+        .plugin.pfree = NULL,
+        .plugin.cfree = NULL
     }, {
         .module = "ietf-netconf-acm",
         .revision = "2018-02-14",
         .name = "default-deny-write",
 
-        .plugin.id = "libyang 2 - NACM, version 1",
-        .plugin.compile = &nacm_compile,
+        .plugin.id = "ly2 NACM v1",
+        .plugin.parse = nacm_parse,
+        .plugin.compile = nacm_compile,
         .plugin.sprinter = NULL,
-        .plugin.free = NULL,
         .plugin.node = NULL,
         .plugin.snode = NULL,
-        .plugin.validate = NULL
+        .plugin.validate = NULL,
+        .plugin.pfree = NULL,
+        .plugin.cfree = NULL
     }, {
         .module = "ietf-netconf-acm",
         .revision = "2012-02-22",
         .name = "default-deny-all",
 
-        .plugin.id = "libyang 2 - NACM, version 1",
-        .plugin.compile = &nacm_compile,
+        .plugin.id = "ly2 NACM v1",
+        .plugin.parse = nacm_parse,
+        .plugin.compile = nacm_compile,
         .plugin.sprinter = NULL,
-        .plugin.free = NULL,
         .plugin.node = NULL,
         .plugin.snode = NULL,
-        .plugin.validate = NULL
+        .plugin.validate = NULL,
+        .plugin.pfree = NULL,
+        .plugin.cfree = NULL
     }, {
         .module = "ietf-netconf-acm",
         .revision = "2018-02-14",
         .name = "default-deny-all",
 
-        .plugin.id = "libyang 2 - NACM, version 1",
-        .plugin.compile = &nacm_compile,
+        .plugin.id = "ly2 NACM v1",
+        .plugin.parse = nacm_parse,
+        .plugin.compile = nacm_compile,
         .plugin.sprinter = NULL,
-        .plugin.free = NULL,
         .plugin.node = NULL,
         .plugin.snode = NULL,
-        .plugin.validate = NULL
+        .plugin.validate = NULL,
+        .plugin.pfree = NULL,
+        .plugin.cfree = NULL
     },
     {0} /* terminating zeroed item */
 };
diff --git a/src/plugins_exts/schema_mount.c b/src/plugins_exts/schema_mount.c
index 042bebb..04679aa 100644
--- a/src/plugins_exts/schema_mount.c
+++ b/src/plugins_exts/schema_mount.c
@@ -21,6 +21,7 @@
 #include <string.h>
 
 #include "common.h"
+#include "compat.h"
 #include "dict.h"
 #include "libyang.h"
 #include "log.h"
@@ -56,68 +57,95 @@
     } inln;                             /**< inline mount points */
 };
 
-#define EXT_LOGERR_MEM_RET(ext) \
-        lyplg_ext_log(ext, LY_LLERR, LY_EMEM, NULL, "Memory allocation failed (%s:%d).", __FILE__, __LINE__); \
+#define EXT_LOGERR_MEM_RET(cctx, ext) \
+        lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s:%d).", __FILE__, __LINE__); \
         return LY_EMEM
 
-#define EXT_LOGERR_MEM_GOTO(ext, rc, label) \
-        lyplg_ext_log(ext, LY_LLERR, LY_EMEM, NULL, "Memory allocation failed (%s:%d).", __FILE__, __LINE__); \
+#define EXT_LOGERR_MEM_GOTO(cctx, ext, rc, label) \
+        lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s:%d).", __FILE__, __LINE__); \
         rc = LY_EMEM; \
         goto label
 
-#define EXT_LOGERR_INT_RET(ext) \
-        lyplg_ext_log(ext, LY_LLERR, LY_EINT, NULL, "Internal error (%s:%d).", __FILE__, __LINE__); \
+#define EXT_LOGERR_INT_RET(cctx, ext) \
+        lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EINT, "Internal error (%s:%d).", __FILE__, __LINE__); \
         return LY_EINT
 
 /**
- * @brief Check if given mount point is unique among its' siblings
+ * @brief Check if given mount point is unique among its siblings
  *
- * @param cctx Compilation context.
- * @param c_ext Compiled extension instance for checking uniqueness.
- * @param p_ext Extension instance of the mount-point for comparison.
+ * @param[in] pctx Parse context.
+ * @param[in] ext Parsed extension instance.
  * @return LY_SUCCESS if is unique;
  * @return LY_EINVAL otherwise.
  */
 static LY_ERR
-schema_mount_compile_unique_mp(struct lysc_ctx *cctx, const struct lysc_ext_instance *c_ext,
-        const struct lysp_ext_instance *p_ext)
+schema_mount_parse_unique_mp(struct lysp_ctx *pctx, const struct lysp_ext_instance *ext)
 {
-    struct lysc_ext_instance *exts;
+    struct lysp_ext_instance *exts;
     LY_ARRAY_COUNT_TYPE u;
-    struct lysc_node *parent;
+    struct lysp_node *parent;
 
-    /* check if it is the only instance of the mount-point among its' siblings */
-    parent = (struct lysc_node *)c_ext->parent;
+    /* check if it is the only instance of the mount-point among its siblings */
+    parent = ext->parent;
     exts = parent->exts;
     LY_ARRAY_FOR(exts, u) {
-        if (&exts[u] == c_ext) {
+        if (&exts[u] == ext) {
             continue;
         }
 
-        if (!strcmp(exts[u].def->module->name, "ietf-yang-schema-mount") && !strcmp(exts[u].def->name, "mount-point")) {
-            lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx), "Multiple extension \"%s\" instances.",
-                    p_ext->name);
+        if (!strcmp(exts[u].name, ext->name)) {
+            lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Multiple extension \"%s\" instances.", ext->name);
             return LY_EINVAL;
         }
     }
     return LY_SUCCESS;
 }
 
+/**
+ * @brief Schema mount parse.
+ * Checks if it can be a valid extension instance for yang schema mount.
+ *
+ * Implementation of ::lyplg_ext_parse_clb callback set as lyext_plugin::parse.
+ */
+static LY_ERR
+schema_mount_parse(struct lysp_ctx *pctx, struct lysp_ext_instance *ext)
+{
+    /* check YANG version 1.1 */
+    if (lyplg_ext_parse_get_cur_pmod(pctx)->version != LYS_VERSION_1_1) {
+        lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Extension \"%s\" instance not allowed in YANG version 1 module.",
+                ext->name);
+        return LY_EINVAL;
+    }
+
+    /* check parent nodetype */
+    if ((ext->parent_stmt != LY_STMT_CONTAINER) && (ext->parent_stmt != LY_STMT_LIST)) {
+        lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Extension \"%s\" instance allowed only in container or list statement.",
+                ext->name);
+        return LY_EINVAL;
+    }
+
+    /* check uniqueness */
+    if (schema_mount_parse_unique_mp(pctx, ext)) {
+        return LY_EINVAL;
+    }
+
+    /* nothing to actually parse */
+    return LY_SUCCESS;
+}
+
 struct lyplg_ext_sm_shared_cb_data {
     const struct lysc_ext_instance *ext;
     struct lyplg_ext_sm_shared *sm_shared;
 };
 
 static LY_ERR
-schema_mount_compile_mod_dfs_cb(struct lysc_node *node, void *data, ly_bool *dfs_continue)
+schema_mount_compile_mod_dfs_cb(struct lysc_node *node, void *data, ly_bool *UNUSED(dfs_continue))
 {
     struct lyplg_ext_sm_shared_cb_data *cb_data = data;
     struct lyplg_ext_sm *sm_data;
     struct lysc_ext_instance *exts;
     LY_ARRAY_COUNT_TYPE u;
 
-    (void)dfs_continue;
-
     if (node == cb_data->ext->parent) {
         /* parent of the current compiled extension, skip */
         return LY_SUCCESS;
@@ -129,7 +157,7 @@
         if (!strcmp(exts[u].def->module->name, "ietf-yang-schema-mount") && !strcmp(exts[u].def->name, "mount-point") &&
                 (exts[u].argument == cb_data->ext->argument)) {
             /* same mount point, break the DFS search */
-            sm_data = exts[u].data;
+            sm_data = exts[u].compiled;
             cb_data->sm_shared = sm_data->shared;
             return LY_EEXIST;
         }
@@ -164,56 +192,33 @@
  * Implementation of ::lyplg_ext_compile_clb callback set as lyext_plugin::compile.
  */
 static LY_ERR
-schema_mount_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext, struct lysc_ext_instance *c_ext)
+schema_mount_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *UNUSED(extp), struct lysc_ext_instance *ext)
 {
-    const struct lys_module *cur_mod;
     const struct lysc_node *node;
     struct lyplg_ext_sm *sm_data;
 
-    assert(!strcmp(p_ext->name, "yangmnt:mount-point"));
-
-    /* check YANG version 1.1 */
-    cur_mod = lysc_ctx_get_cur_mod(cctx);
-    if (cur_mod->parsed->version != LYS_VERSION_1_1) {
-        lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
-                "Extension \"%s\" instance not allowed in YANG version 1 module.", p_ext->name);
-        return LY_EINVAL;
-    }
-
-    /* check parent nodetype */
-    if ((p_ext->parent_stmt != LY_STMT_CONTAINER) && (p_ext->parent_stmt != LY_STMT_LIST)) {
-        lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
-                "Extension \"%s\" instance allowed only in container or list statement.", p_ext->name);
-        return LY_EINVAL;
-    }
-
-    /* check uniqueness */
-    if (schema_mount_compile_unique_mp(cctx, c_ext, p_ext)) {
-        return LY_EINVAL;
-    }
-
     /* init internal data */
     sm_data = calloc(1, sizeof *sm_data);
     if (!sm_data) {
-        EXT_LOGERR_MEM_RET(c_ext);
+        EXT_LOGERR_MEM_RET(cctx, ext);
     }
-    c_ext->data = sm_data;
+    ext->compiled = sm_data;
 
     /* find the owner module */
-    node = c_ext->parent;
+    node = ext->parent;
     while (node->parent) {
         node = node->parent;
     }
 
     /* reuse/init shared schema */
-    sm_data->shared = schema_mount_compile_find_shared(node->module, c_ext);
+    sm_data->shared = schema_mount_compile_find_shared(node->module, ext);
     if (sm_data->shared) {
         ++sm_data->shared->ref_count;
     } else {
         sm_data->shared = calloc(1, sizeof *sm_data->shared);
         if (!sm_data->shared) {
             free(sm_data);
-            EXT_LOGERR_MEM_RET(c_ext);
+            EXT_LOGERR_MEM_RET(cctx, ext);
         }
         pthread_mutex_init(&sm_data->shared->lock, NULL);
         sm_data->shared->ref_count = 1;
@@ -242,7 +247,7 @@
     /* find the mount point */
     if (asprintf(&path, "/ietf-yang-schema-mount:schema-mounts/mount-point[module='%s'][label='%s']", ext->module->name,
             ext->argument) == -1) {
-        EXT_LOGERR_MEM_RET(ext);
+        EXT_LOGERR_MEM_RET(NULL, ext);
     }
     r = ext_data ? lyd_find_path(ext_data, path, 0, &mpoint) : LY_ENOTFOUND;
     free(path);
@@ -264,7 +269,7 @@
     /* check schema-ref */
     if (lyd_find_path(mpoint, "shared-schema", 0, NULL)) {
         if (lyd_find_path(mpoint, "inline", 0, NULL)) {
-            EXT_LOGERR_INT_RET(ext);
+            EXT_LOGERR_INT_RET(NULL, ext);
         }
         *shared = 0;
     } else {
@@ -308,7 +313,7 @@
 
     /* create the context based on the data */
     if ((rc = ly_ctx_new_yldata(sdirs, ext_data, ly_ctx_get_options(ext->module->ctx), ext_ctx))) {
-        lyplg_ext_log(ext, LY_LLERR, rc, NULL, "Failed to create context for the schema-mount data.");
+        lyplg_ext_compile_log(NULL, ext, LY_LLERR, rc, "Failed to create context for the schema-mount data.");
         goto cleanup;
     }
 
@@ -348,7 +353,7 @@
 schema_mount_get_ctx_shared(struct lysc_ext_instance *ext, const struct lyd_node *ext_data, ly_bool config,
         const struct ly_ctx **ext_ctx)
 {
-    struct lyplg_ext_sm *sm_data = ext->data;
+    struct lyplg_ext_sm *sm_data = ext->compiled;
     LY_ERR ret = LY_SUCCESS, r;
     struct lyd_node *node = NULL;
     struct ly_ctx *new_ctx = NULL;
@@ -369,13 +374,14 @@
         }
     }
     if (!content_id) {
-        lyplg_ext_log(ext, LY_LLERR, LY_EVALID, NULL, "Missing \"content-id\" or \"module-set-id\" in ietf-yang-library data.");
+        lyplg_ext_compile_log(NULL, ext, LY_LLERR, LY_EVALID,
+                "Missing \"content-id\" or \"module-set-id\" in ietf-yang-library data.");
         return LY_EVALID;
     }
 
     /* LOCK */
     if ((r = pthread_mutex_lock(&sm_data->shared->lock))) {
-        lyplg_ext_log(ext, LY_LLERR, LY_ESYS, NULL, "Mutex lock failed (%s).", strerror(r));
+        lyplg_ext_compile_log(NULL, ext, LY_LLERR, LY_ESYS, "Mutex lock failed (%s).", strerror(r));
         return LY_ESYS;
     }
 
@@ -389,7 +395,7 @@
     if (i < sm_data->shared->schema_count) {
         /* schema exists already */
         if (strcmp(content_id, sm_data->shared->schemas[i].content_id)) {
-            lyplg_ext_log(ext, LY_LLERR, LY_EVALID, "/ietf-yang-library:yang-library/content-id",
+            lyplg_ext_compile_log_path("/ietf-yang-library:yang-library/content-id", ext, LY_LLERR, LY_EVALID,
                     "Shared-schema yang-library content-id \"%s\" differs from \"%s\" used previously.",
                     content_id, sm_data->shared->schemas[i].content_id);
             ret = LY_EVALID;
@@ -406,7 +412,7 @@
         mem = realloc(sm_data->shared->schemas, (i + 1) * sizeof *sm_data->shared->schemas);
         if (!mem) {
             ly_ctx_destroy(new_ctx);
-            EXT_LOGERR_MEM_GOTO(ext, ret, cleanup);
+            EXT_LOGERR_MEM_GOTO(NULL, ext, ret, cleanup);
         }
         sm_data->shared->schemas = mem;
         ++sm_data->shared->schema_count;
@@ -440,7 +446,7 @@
 schema_mount_get_ctx_inline(struct lysc_ext_instance *ext, const struct lyd_node *ext_data, ly_bool config,
         const struct ly_ctx **ext_ctx)
 {
-    struct lyplg_ext_sm *sm_data = ext->data;
+    struct lyplg_ext_sm *sm_data = ext->compiled;
     LY_ERR r;
     struct ly_ctx *new_ctx = NULL;
     uint32_t i;
@@ -459,7 +465,7 @@
     mem = realloc(sm_data->inln.schemas, (i + 1) * sizeof *sm_data->inln.schemas);
     if (!mem) {
         ly_ctx_destroy(new_ctx);
-        EXT_LOGERR_MEM_RET(ext);
+        EXT_LOGERR_MEM_RET(NULL, ext);
     }
     sm_data->inln.schemas = mem;
     ++sm_data->inln.schema_count;
@@ -497,7 +503,7 @@
     LY_LIST_FOR(ext_data, iter) {
         if (iter->flags & LYD_NEW) {
             /* must be validated for the parent-reference prefix data to be stored */
-            lyplg_ext_log(ext, LY_LLERR, LY_EINVAL, NULL, "Provided ext data have not been validated.");
+            lyplg_ext_compile_log(NULL, ext, LY_LLERR, LY_EINVAL, "Provided ext data have not been validated.");
             ret = LY_EINVAL;
             goto cleanup;
         }
@@ -566,7 +572,7 @@
     /* get all parent references of this mount point */
     if (asprintf(&path, "/ietf-yang-schema-mount:schema-mounts/mount-point[module='%s'][label='%s']"
             "/shared-schema/parent-reference", ext->module->name, ext->argument) == -1) {
-        EXT_LOGERR_MEM_GOTO(ext, ret, cleanup);
+        EXT_LOGERR_MEM_GOTO(NULL, ext, ret, cleanup);
     }
     if ((ret = lyd_find_xpath(ext_data, path, set))) {
         goto cleanup;
@@ -603,7 +609,7 @@
 
     if (!ext_data) {
         /* we expect the same ext data as before and there must be some for data to be parsed */
-        lyplg_ext_log(ext, LY_LLERR, LY_EINVAL, NULL, "No ext data provided.");
+        lyplg_ext_compile_log(NULL, ext, LY_LLERR, LY_EINVAL, "No ext data provided.");
         ret = LY_EINVAL;
         goto cleanup;
     }
@@ -625,7 +631,8 @@
         LYD_VALUE_GET(&term->value, xp_val);
         if ((ret = lyd_find_xpath4(ctx_node, ctx_node, lyxp_get_expr(xp_val->exp), xp_val->format, xp_val->prefix_data,
                 NULL, &par_set))) {
-            lyplg_ext_log(ext, LY_LLERR, ret, NULL, "Parent reference \"%s\" evaluation failed.", lyxp_get_expr(xp_val->exp));
+            lyplg_ext_compile_log(NULL, ext, LY_LLERR, ret, "Parent reference \"%s\" evaluation failed.",
+                    lyxp_get_expr(xp_val->exp));
             goto cleanup;
         }
 
@@ -759,7 +766,7 @@
 
     if (!sibling) {
         /* some data had to be parsed for this callback to be called */
-        EXT_LOGERR_INT_RET(ext);
+        EXT_LOGERR_INT_RET(NULL, ext);
     }
 
     /* get operational data with ietf-yang-library and ietf-yang-schema-mount data */
@@ -770,7 +777,7 @@
     LY_LIST_FOR(ext_data, iter) {
         if (iter->flags & LYD_NEW) {
             /* must be validated for the parent-reference prefix data to be stored */
-            lyplg_ext_log(ext, LY_LLERR, LY_EINVAL, NULL, "Provided ext data have not been validated.");
+            lyplg_ext_compile_log(NULL, ext, LY_LLERR, LY_EINVAL, "Provided ext data have not been validated.");
             ret = LY_EINVAL;
             goto cleanup;
         }
@@ -821,15 +828,15 @@
     LY_LIST_FOR(sibling, iter) {
         iter->flags |= LYD_EXT;
     }
-    lyd_insert_ext(orig_parent, sibling);
+    lyplg_ext_insert(orig_parent, sibling);
 
     if (ret) {
         /* log the error in the original context */
         err = ly_err_first(LYD_CTX(sibling));
         if (!err) {
-            lyplg_ext_log(ext, LY_LLERR, ret, NULL, "Unknown validation error (err code %d).", ret);
+            lyplg_ext_compile_log(NULL, ext, LY_LLERR, ret, "Unknown validation error (err code %d).", ret);
         } else {
-            lyplg_ext_log(ext, LY_LLERR, err->no, err->path, "%s", err->msg);
+            lyplg_ext_compile_log_path(err->path, ext, LY_LLERR, err->no, "%s", err->msg);
         }
         goto cleanup;
     }
@@ -845,7 +852,7 @@
         if ((ret = lyd_dup_single(lyd_parent(sibling), NULL, LYD_DUP_WITH_PARENTS | LYD_DUP_NO_META, &diff_parent))) {
             goto cleanup;
         }
-        if ((ret = lyd_insert_ext(diff_parent, ext_diff))) {
+        if ((ret = lyplg_ext_insert(diff_parent, ext_diff))) {
             goto cleanup;
         }
         ext_diff = NULL;
@@ -876,14 +883,14 @@
 }
 
 /**
- * @brief Schema mount free.
+ * @brief Schema mount compile free.
  *
- * Implementation of ::lyplg_ext_free_clb callback set as ::lyext_plugin::free.
+ * Implementation of ::lyplg_ext_compile_free_clb callback set as ::lyext_plugin::cfree.
  */
 static void
-schema_mount_free(struct ly_ctx *ctx, struct lysc_ext_instance *ext)
+schema_mount_cfree(const struct ly_ctx *ctx, struct lysc_ext_instance *ext)
 {
-    struct lyplg_ext_sm *sm_data = ext->data;
+    struct lyplg_ext_sm *sm_data = ext->compiled;
     uint32_t i;
 
     if (!sm_data) {
@@ -957,13 +964,15 @@
         .revision = "2019-01-14",
         .name = "mount-point",
 
-        .plugin.id = "libyang 2 - Schema Mount, version 1",
-        .plugin.compile = &schema_mount_compile,
+        .plugin.id = "ly2 schema mount v1",
+        .plugin.parse = schema_mount_parse,
+        .plugin.compile = schema_mount_compile,
         .plugin.sprinter = NULL,
-        .plugin.free = &schema_mount_free,
         .plugin.node = NULL,
-        .plugin.snode = &schema_mount_snode,
-        .plugin.validate = &schema_mount_validate
+        .plugin.snode = schema_mount_snode,
+        .plugin.validate = schema_mount_validate,
+        .plugin.pfree = NULL,
+        .plugin.cfree = schema_mount_cfree
     },
     {0} /* terminating zeroed item */
 };
diff --git a/src/plugins_exts/structure.c b/src/plugins_exts/structure.c
index 12c548c..3a0bf8a 100644
--- a/src/plugins_exts/structure.c
+++ b/src/plugins_exts/structure.c
@@ -1,7 +1,7 @@
 /**
  * @file structure.c
  * @author Michal Vasko <mvasko@cesnet.cz>
- * @brief libyang extension plugin - strcture (RFC 8791)
+ * @brief libyang extension plugin - structure (RFC 8791)
  *
  * Copyright (c) 2022 CESNET, z.s.p.o.
  *
@@ -20,16 +20,31 @@
 #include "libyang.h"
 #include "plugins_exts.h"
 
-struct lysc_ext_instance_structure {
-    struct lysc_must *musts;
+struct lysp_ext_instance_structure {
+    struct lysp_restr *musts;
     uint16_t flags;
     const char *dsc;
     const char *ref;
     struct lysp_tpdf *typedefs;
     struct lysp_node_grp *groupings;
+    struct lysp_node *child;
+};
+
+struct lysc_ext_instance_structure {
+    struct lysc_must *musts;
+    uint16_t flags;
+    const char *dsc;
+    const char *ref;
     struct lysc_node *child;
 };
 
+struct lysp_ext_instance_augment_structure {
+    uint16_t flags;
+    const char *dsc;
+    const char *ref;
+    struct lysp_node *child;
+};
+
 struct lysc_ext_instance_augment_structure {
     uint16_t flags;
     const char *dsc;
@@ -37,116 +52,206 @@
 };
 
 /**
+ * @brief Parse structure extension instances.
+ *
+ * Implementation of ::lyplg_ext_parse_clb callback set as lyext_plugin::parse.
+ */
+static LY_ERR
+structure_parse(struct lysp_ctx *pctx, struct lysp_ext_instance *ext)
+{
+    LY_ERR rc;
+    LY_ARRAY_COUNT_TYPE u;
+    struct lysp_module *pmod;
+    struct lysp_ext_instance_structure *struct_pdata;
+
+    /* structure can appear only at the top level of a YANG module or submodule */
+    if ((ext->parent_stmt != LY_STMT_MODULE) && (ext->parent_stmt != LY_STMT_SUBMODULE)) {
+        lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID,
+                "Extension %s must not be used as a non top-level statement in \"%s\" statement.", ext->name,
+                lyplg_ext_stmt2str(ext->parent_stmt));
+        return LY_EVALID;
+    }
+
+    pmod = ext->parent;
+
+    /* check for duplication */
+    LY_ARRAY_FOR(pmod->exts, u) {
+        if ((&pmod->exts[u] != ext) && (pmod->exts[u].name == ext->name) && !strcmp(pmod->exts[u].argument, ext->argument)) {
+            /* duplication of the same structure extension in a single module */
+            lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Extension %s is instantiated multiple times.", ext->name);
+            return LY_EVALID;
+        }
+    }
+
+    /* allocate the storage */
+    struct_pdata = calloc(1, sizeof *struct_pdata);
+    if (!struct_pdata) {
+        goto emem;
+    }
+    ext->parsed = struct_pdata;
+    LY_ARRAY_CREATE_GOTO(lyplg_extp_cur_pmod(pctx)->mod->ctx, ext->substmts, 14, rc, emem);
+
+    /* parse substatements */
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[0].stmt = LY_STMT_MUST;
+    ext->substmts[0].storage = &struct_pdata->musts;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[1].stmt = LY_STMT_STATUS;
+    ext->substmts[1].storage = &struct_pdata->flags;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[2].stmt = LY_STMT_DESCRIPTION;
+    ext->substmts[2].storage = &struct_pdata->dsc;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[3].stmt = LY_STMT_REFERENCE;
+    ext->substmts[3].storage = &struct_pdata->ref;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[4].stmt = LY_STMT_TYPEDEF;
+    ext->substmts[4].storage = &struct_pdata->typedefs;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[5].stmt = LY_STMT_GROUPING;
+    ext->substmts[5].storage = &struct_pdata->groupings;
+
+    /* data-def-stmt */
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[6].stmt = LY_STMT_CONTAINER;
+    ext->substmts[6].storage = &struct_pdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[7].stmt = LY_STMT_LEAF;
+    ext->substmts[7].storage = &struct_pdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[8].stmt = LY_STMT_LEAF_LIST;
+    ext->substmts[8].storage = &struct_pdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[9].stmt = LY_STMT_LIST;
+    ext->substmts[9].storage = &struct_pdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[10].stmt = LY_STMT_CHOICE;
+    ext->substmts[10].storage = &struct_pdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[11].stmt = LY_STMT_ANYDATA;
+    ext->substmts[11].storage = &struct_pdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[12].stmt = LY_STMT_ANYXML;
+    ext->substmts[12].storage = &struct_pdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[13].stmt = LY_STMT_USES;
+    ext->substmts[13].storage = &struct_pdata->child;
+
+    rc = lyplg_ext_parse_extension_instance(pctx, ext);
+    return rc;
+
+emem:
+    lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s()).", __func__);
+    return LY_EMEM;
+}
+
+/**
  * @brief Compile structure extension instances.
  *
  * Implementation of ::lyplg_ext_compile_clb callback set as lyext_plugin::compile.
  */
 static LY_ERR
-structure_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext, struct lysc_ext_instance *c_ext)
+structure_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *extp, struct lysc_ext_instance *ext)
 {
     LY_ERR rc;
-    LY_ARRAY_COUNT_TYPE u;
     struct lysc_module *mod_c;
     const struct lysc_node *child;
-    struct lysc_ext_instance_structure *struct_data;
-    uint32_t prev_options = *lysc_ctx_get_options(cctx);
+    struct lysc_ext_instance_structure *struct_cdata;
+    uint32_t prev_options = *lyplg_ext_compile_get_options(cctx);
 
-    /* structure can appear only at the top level of a YANG module or submodule */
-    if ((c_ext->parent_stmt != LY_STMT_MODULE) && (c_ext->parent_stmt != LY_STMT_SUBMODULE)) {
-        lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
-                "Extension %s must not be used as a non top-level statement in \"%s\" statement.",
-                p_ext->name, ly_stmt2str(c_ext->parent_stmt));
-        return LY_EVALID;
-    }
+    mod_c = ext->parent;
 
-    mod_c = (struct lysc_module *)c_ext->parent;
-
-    /* check identifier namespace */
-    LY_ARRAY_FOR(mod_c->exts, u) {
-        if ((&mod_c->exts[u] != c_ext) && (mod_c->exts[u].def == c_ext->def) && !strcmp(mod_c->exts[u].argument, c_ext->argument)) {
-            /* duplication of the same structure extension in a single module */
-            lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx), "Extension %s is instantiated multiple times.", p_ext->name);
-            return LY_EVALID;
-        }
-    }
+    /* check identifier namespace with the compiled nodes */
     LY_LIST_FOR(mod_c->data, child) {
-        if (!strcmp(child->name, c_ext->argument)) {
+        if (!strcmp(child->name, ext->argument)) {
             /* identifier collision */
-            lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx), "Extension %s collides "
-                    "with a %s with the same identifier.", p_ext->name, lys_nodetype2str(child->nodetype));
+            lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EVALID,  "Extension %s collides with a %s with the same identifier.",
+                    extp->name, lys_nodetype2str(child->nodetype));
             return LY_EVALID;
         }
     }
 
     /* allocate the storage */
-    struct_data = calloc(1, sizeof *struct_data);
-    if (!struct_data) {
+    struct_cdata = calloc(1, sizeof *struct_cdata);
+    if (!struct_cdata) {
         goto emem;
     }
-    c_ext->data = struct_data;
+    ext->compiled = struct_cdata;
 
     /* compile substatements */
-    LY_ARRAY_CREATE_GOTO(cctx->ctx, c_ext->substmts, 14, rc, emem);
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[0].stmt = LY_STMT_MUST;
-    c_ext->substmts[0].storage = &struct_data->musts;
+    LY_ARRAY_CREATE_GOTO(cctx->ctx, ext->substmts, 14, rc, emem);
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[0].stmt = LY_STMT_MUST;
+    ext->substmts[0].storage = &struct_cdata->musts;
 
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[1].stmt = LY_STMT_STATUS;
-    c_ext->substmts[1].storage = &struct_data->flags;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[1].stmt = LY_STMT_STATUS;
+    ext->substmts[1].storage = &struct_cdata->flags;
 
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[2].stmt = LY_STMT_DESCRIPTION;
-    c_ext->substmts[2].storage = &struct_data->dsc;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[2].stmt = LY_STMT_DESCRIPTION;
+    ext->substmts[2].storage = &struct_cdata->dsc;
 
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[3].stmt = LY_STMT_REFERENCE;
-    c_ext->substmts[3].storage = &struct_data->ref;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[3].stmt = LY_STMT_REFERENCE;
+    ext->substmts[3].storage = &struct_cdata->ref;
 
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[4].stmt = LY_STMT_TYPEDEF;
-    c_ext->substmts[4].storage = &struct_data->typedefs;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[4].stmt = LY_STMT_TYPEDEF;
+    ext->substmts[4].storage = NULL;
 
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[5].stmt = LY_STMT_GROUPING;
-    c_ext->substmts[5].storage = &struct_data->groupings;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[5].stmt = LY_STMT_GROUPING;
+    ext->substmts[5].storage = NULL;
 
     /* data-def-stmt */
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[6].stmt = LY_STMT_CONTAINER;
-    c_ext->substmts[6].storage = &struct_data->child;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[6].stmt = LY_STMT_CONTAINER;
+    ext->substmts[6].storage = &struct_cdata->child;
 
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[7].stmt = LY_STMT_LEAF;
-    c_ext->substmts[7].storage = &struct_data->child;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[7].stmt = LY_STMT_LEAF;
+    ext->substmts[7].storage = &struct_cdata->child;
 
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[8].stmt = LY_STMT_LEAF_LIST;
-    c_ext->substmts[8].storage = &struct_data->child;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[8].stmt = LY_STMT_LEAF_LIST;
+    ext->substmts[8].storage = &struct_cdata->child;
 
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[9].stmt = LY_STMT_LIST;
-    c_ext->substmts[9].storage = &struct_data->child;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[9].stmt = LY_STMT_LIST;
+    ext->substmts[9].storage = &struct_cdata->child;
 
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[10].stmt = LY_STMT_CHOICE;
-    c_ext->substmts[10].storage = &struct_data->child;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[10].stmt = LY_STMT_CHOICE;
+    ext->substmts[10].storage = &struct_cdata->child;
 
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[11].stmt = LY_STMT_ANYDATA;
-    c_ext->substmts[11].storage = &struct_data->child;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[11].stmt = LY_STMT_ANYDATA;
+    ext->substmts[11].storage = &struct_cdata->child;
 
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[12].stmt = LY_STMT_ANYXML;
-    c_ext->substmts[12].storage = &struct_data->child;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[12].stmt = LY_STMT_ANYXML;
+    ext->substmts[12].storage = &struct_cdata->child;
 
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[13].stmt = LY_STMT_USES;
-    c_ext->substmts[13].storage = &struct_data->child;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[13].stmt = LY_STMT_USES;
+    ext->substmts[13].storage = &struct_cdata->child;
 
-    *lysc_ctx_get_options(cctx) |= LYS_COMPILE_NO_CONFIG | LYS_COMPILE_NO_DISABLED;
-    rc = lys_compile_extension_instance(cctx, p_ext, c_ext);
-    *lysc_ctx_get_options(cctx) = prev_options;
+    *lyplg_ext_compile_get_options(cctx) |= LYS_COMPILE_NO_CONFIG | LYS_COMPILE_NO_DISABLED;
+    rc = lyplg_ext_compile_extension_instance(cctx, extp, ext);
+    *lyplg_ext_compile_get_options(cctx) = prev_options;
     if (rc) {
         return rc;
     }
@@ -154,134 +259,7 @@
     return LY_SUCCESS;
 
 emem:
-    lyplg_ext_log(c_ext, LY_LLERR, LY_EMEM, lysc_ctx_get_path(cctx), "Memory allocation failed (%s()).", __func__);
-    return LY_EMEM;
-}
-
-/**
- * @brief Compile augment-structure extension instances.
- *
- * Implementation of ::lyplg_ext_compile_clb callback set as lyext_plugin::compile.
- */
-static LY_ERR
-structure_aug_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext, struct lysc_ext_instance *c_ext)
-{
-    LY_ERR rc;
-    struct lysp_stmt *stmt;
-    struct lysc_node *aug_target;
-    struct lysc_ext_instance *target_ext;
-    struct lysc_ext_instance_structure *target_data;
-    struct lysc_ext_instance_augment_structure *aug_data;
-    uint32_t prev_options = *lysc_ctx_get_options(cctx), i;
-
-    /* augment-structure can appear only at the top level of a YANG module or submodule */
-    if ((c_ext->parent_stmt != LY_STMT_MODULE) && (c_ext->parent_stmt != LY_STMT_SUBMODULE)) {
-        lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
-                "Extension %s must not be used as a non top-level statement in \"%s\" statement.",
-                p_ext->name, ly_stmt2str(c_ext->parent_stmt));
-        return LY_EVALID;
-    }
-
-    /* augment-structure must define some data-def-stmt */
-    LY_LIST_FOR(p_ext->child, stmt) {
-        if (LY_STMT_IS_DATA_NODE(stmt->kw)) {
-            break;
-        }
-    }
-    if (!stmt) {
-        lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
-                "Extension %s does not define any data-def-stmt statements.", p_ext->name);
-        return LY_EVALID;
-    }
-
-    /* find the target struct ext instance */
-    if ((rc = lys_compile_extension_instance_find_augment_target(cctx, p_ext->argument, &target_ext, &aug_target))) {
-        return rc;
-    }
-
-    /* check target_ext */
-    if (strcmp(target_ext->def->name, "structure") || strcmp(target_ext->def->module->name, "ietf-yang-structure-ext")) {
-        lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
-                "Extension %s can only target extension instances of \"ietf-yang-structure-ext:structure\".", p_ext->name);
-        return LY_EVALID;
-    }
-    target_data = target_ext->data;
-
-    /* allocate the storage */
-    aug_data = calloc(1, sizeof *aug_data);
-    if (!aug_data) {
-        goto emem;
-    }
-    c_ext->data = aug_data;
-
-    /* compile substatements */
-    LY_ARRAY_CREATE_GOTO(cctx->ctx, c_ext->substmts, 12, rc, emem);
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[0].stmt = LY_STMT_STATUS;
-    c_ext->substmts[0].storage = &aug_data->flags;
-
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[1].stmt = LY_STMT_DESCRIPTION;
-    c_ext->substmts[1].storage = &aug_data->dsc;
-
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[2].stmt = LY_STMT_REFERENCE;
-    c_ext->substmts[2].storage = &aug_data->ref;
-
-    /* data-def-stmt */
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[3].stmt = LY_STMT_CONTAINER;
-    c_ext->substmts[3].storage = &target_data->child;
-
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[4].stmt = LY_STMT_LEAF;
-    c_ext->substmts[4].storage = &target_data->child;
-
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[5].stmt = LY_STMT_LEAF_LIST;
-    c_ext->substmts[5].storage = &target_data->child;
-
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[6].stmt = LY_STMT_LIST;
-    c_ext->substmts[6].storage = &target_data->child;
-
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[7].stmt = LY_STMT_CHOICE;
-    c_ext->substmts[7].storage = &target_data->child;
-
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[8].stmt = LY_STMT_ANYDATA;
-    c_ext->substmts[8].storage = &target_data->child;
-
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[9].stmt = LY_STMT_ANYXML;
-    c_ext->substmts[9].storage = &target_data->child;
-
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[10].stmt = LY_STMT_USES;
-    c_ext->substmts[10].storage = &target_data->child;
-
-    /* case */
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[11].stmt = LY_STMT_CASE;
-    c_ext->substmts[11].storage = &target_data->child;
-
-    *lysc_ctx_get_options(cctx) |= LYS_COMPILE_NO_CONFIG | LYS_COMPILE_NO_DISABLED;
-    rc = lys_compile_extension_instance_augment(cctx, p_ext, c_ext, aug_target);
-    *lysc_ctx_get_options(cctx) = prev_options;
-    if (rc) {
-        return rc;
-    }
-
-    /* data-def-statements are now part of the target extension (do not print nor free them) */
-    for (i = 0; i < 9; ++i) {
-        LY_ARRAY_DECREMENT(c_ext->substmts);
-    }
-
-    return LY_SUCCESS;
-
-emem:
-    lyplg_ext_log(c_ext, LY_LLERR, LY_EMEM, lysc_ctx_get_path(cctx), "Memory allocation failed (%s()).", __func__);
+    lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s()).", __func__);
     return LY_EMEM;
 }
 
@@ -291,22 +269,239 @@
  * Implementation of ::lyplg_ext_schema_printer_clb set as ::lyext_plugin::sprinter
  */
 static LY_ERR
-structure_schema_printer(struct lyspr_ctx *ctx, struct lysc_ext_instance *ext, ly_bool *flag)
+structure_sprinter(struct lyspr_ctx *ctx, struct lysc_ext_instance *ext, ly_bool *flag)
 {
-    lysc_print_extension_instance(ctx, ext, flag);
+    lyplg_ext_print_extension_instance(ctx, ext, flag);
     return LY_SUCCESS;
 }
 
 /**
- * @brief Free structure extension instances' data.
+ * @brief Free parsed structure extension instance data.
  *
- * Implementation of ::lyplg_clb_free_clb callback set as lyext_plugin::free.
+ * Implementation of ::lyplg_clb_parse_free_clb callback set as lyext_plugin::pfree.
  */
 static void
-structure_free(struct ly_ctx *ctx, struct lysc_ext_instance *ext)
+structure_pfree(const struct ly_ctx *ctx, struct lysp_ext_instance *ext)
 {
-    lyplg_ext_instance_substatements_free(ctx, ext->substmts);
-    free(ext->data);
+    lyplg_ext_pfree_instance_substatements(ctx, ext->substmts);
+    free(ext->parsed);
+}
+
+/**
+ * @brief Free compiled structure extension instance data.
+ *
+ * Implementation of ::lyplg_clb_compile_free_clb callback set as lyext_plugin::cfree.
+ */
+static void
+structure_cfree(const struct ly_ctx *ctx, struct lysc_ext_instance *ext)
+{
+    lyplg_ext_cfree_instance_substatements(ctx, ext->substmts);
+    free(ext->compiled);
+}
+
+/**
+ * @brief Parse augment-structure extension instances.
+ *
+ * Implementation of ::lyplg_ext_parse_clb callback set as lyext_plugin::parse.
+ */
+static LY_ERR
+structure_aug_parse(struct lysp_ctx *pctx, struct lysp_ext_instance *ext)
+{
+    LY_ERR rc;
+    struct lysp_stmt *stmt;
+    struct lysp_ext_instance_augment_structure *aug_pdata;
+
+    /* augment-structure can appear only at the top level of a YANG module or submodule */
+    if ((ext->parent_stmt != LY_STMT_MODULE) && (ext->parent_stmt != LY_STMT_SUBMODULE)) {
+        lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID,
+                "Extension %s must not be used as a non top-level statement in \"%s\" statement.", ext->name,
+                lyplg_ext_stmt2str(ext->parent_stmt));
+        return LY_EVALID;
+    }
+
+    /* augment-structure must define some data-def-stmt */
+    LY_LIST_FOR(ext->child, stmt) {
+        if (stmt->kw & LY_STMT_DATA_NODE_MASK) {
+            break;
+        }
+    }
+    if (!stmt) {
+        lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Extension %s does not define any data-def-stmt statements.",
+                ext->name);
+        return LY_EVALID;
+    }
+
+    /* allocate the storage */
+    aug_pdata = calloc(1, sizeof *aug_pdata);
+    if (!aug_pdata) {
+        goto emem;
+    }
+    ext->parsed = aug_pdata;
+    LY_ARRAY_CREATE_GOTO(lyplg_extp_cur_pmod(pctx)->mod->ctx, ext->substmts, 12, rc, emem);
+
+    /* parse substatements */
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[0].stmt = LY_STMT_STATUS;
+    ext->substmts[0].storage = &aug_pdata->flags;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[1].stmt = LY_STMT_DESCRIPTION;
+    ext->substmts[1].storage = &aug_pdata->dsc;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[2].stmt = LY_STMT_REFERENCE;
+    ext->substmts[2].storage = &aug_pdata->ref;
+
+    /* data-def-stmt */
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[3].stmt = LY_STMT_CONTAINER;
+    ext->substmts[3].storage = &aug_pdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[4].stmt = LY_STMT_LEAF;
+    ext->substmts[4].storage = &aug_pdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[5].stmt = LY_STMT_LEAF_LIST;
+    ext->substmts[5].storage = &aug_pdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[6].stmt = LY_STMT_LIST;
+    ext->substmts[6].storage = &aug_pdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[7].stmt = LY_STMT_CHOICE;
+    ext->substmts[7].storage = &aug_pdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[8].stmt = LY_STMT_ANYDATA;
+    ext->substmts[8].storage = &aug_pdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[9].stmt = LY_STMT_ANYXML;
+    ext->substmts[9].storage = &aug_pdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[10].stmt = LY_STMT_USES;
+    ext->substmts[10].storage = &aug_pdata->child;
+
+    /* case */
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[11].stmt = LY_STMT_CASE;
+    ext->substmts[11].storage = &aug_pdata->child;
+
+    rc = lyplg_ext_parse_extension_instance(pctx, ext);
+    return rc;
+
+emem:
+    lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s()).", __func__);
+    return LY_EMEM;
+}
+
+/**
+ * @brief Compile augment-structure extension instances.
+ *
+ * Implementation of ::lyplg_ext_compile_clb callback set as lyext_plugin::compile.
+ */
+static LY_ERR
+structure_aug_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *extp, struct lysc_ext_instance *ext)
+{
+    LY_ERR rc;
+    struct lysc_node *aug_target;
+    struct lysc_ext_instance *target_ext;
+    struct lysc_ext_instance_structure *target_cdata;
+    struct lysc_ext_instance_augment_structure *aug_cdata;
+    uint32_t prev_options = *lyplg_ext_compile_get_options(cctx), i;
+
+    /* find the target struct ext instance */
+    if ((rc = lys_compile_extension_instance_find_augment_target(cctx, extp->argument, &target_ext, &aug_target))) {
+        return rc;
+    }
+
+    /* check target_ext */
+    if (strcmp(target_ext->def->name, "structure") || strcmp(target_ext->def->module->name, "ietf-yang-structure-ext")) {
+        lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EVALID,
+                "Extension %s can only target extension instances of \"ietf-yang-structure-ext:structure\".", extp->name);
+        return LY_EVALID;
+    }
+    target_cdata = target_ext->compiled;
+
+    /* allocate the storage */
+    aug_cdata = calloc(1, sizeof *aug_cdata);
+    if (!aug_cdata) {
+        goto emem;
+    }
+    ext->compiled = aug_cdata;
+
+    /* compile substatements */
+    LY_ARRAY_CREATE_GOTO(cctx->ctx, ext->substmts, 12, rc, emem);
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[0].stmt = LY_STMT_STATUS;
+    ext->substmts[0].storage = &aug_cdata->flags;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[1].stmt = LY_STMT_DESCRIPTION;
+    ext->substmts[1].storage = &aug_cdata->dsc;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[2].stmt = LY_STMT_REFERENCE;
+    ext->substmts[2].storage = &aug_cdata->ref;
+
+    /* data-def-stmt */
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[3].stmt = LY_STMT_CONTAINER;
+    ext->substmts[3].storage = &target_cdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[4].stmt = LY_STMT_LEAF;
+    ext->substmts[4].storage = &target_cdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[5].stmt = LY_STMT_LEAF_LIST;
+    ext->substmts[5].storage = &target_cdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[6].stmt = LY_STMT_LIST;
+    ext->substmts[6].storage = &target_cdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[7].stmt = LY_STMT_CHOICE;
+    ext->substmts[7].storage = &target_cdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[8].stmt = LY_STMT_ANYDATA;
+    ext->substmts[8].storage = &target_cdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[9].stmt = LY_STMT_ANYXML;
+    ext->substmts[9].storage = &target_cdata->child;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[10].stmt = LY_STMT_USES;
+    ext->substmts[10].storage = &target_cdata->child;
+
+    /* case */
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[11].stmt = LY_STMT_CASE;
+    ext->substmts[11].storage = &target_cdata->child;
+
+    *lyplg_ext_compile_get_options(cctx) |= LYS_COMPILE_NO_CONFIG | LYS_COMPILE_NO_DISABLED;
+    rc = lyplg_ext_compile_extension_instance_augment(cctx, extp, ext, aug_target);
+    *lyplg_ext_compile_get_options(cctx) = prev_options;
+    if (rc) {
+        return rc;
+    }
+
+    /* data-def-statements are now part of the target extension (do not print nor free them) */
+    for (i = 0; i < 9; ++i) {
+        LY_ARRAY_DECREMENT(ext->substmts);
+    }
+
+    return LY_SUCCESS;
+
+emem:
+    lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s()).", __func__);
+    return LY_EMEM;
 }
 
 /**
@@ -322,26 +517,30 @@
         .revision = "2020-06-17",
         .name = "structure",
 
-        .plugin.id = "libyang 2 - structure, version 1",
+        .plugin.id = "ly2 structure v1",
+        .plugin.parse = structure_parse,
         .plugin.compile = structure_compile,
-        .plugin.sprinter = structure_schema_printer,
-        .plugin.free = structure_free,
+        .plugin.sprinter = structure_sprinter,
         .plugin.node = NULL,
         .plugin.snode = NULL,
-        .plugin.validate = NULL
+        .plugin.validate = NULL,
+        .plugin.pfree = structure_pfree,
+        .plugin.cfree = structure_cfree
     },
     {
         .module = "ietf-yang-structure-ext",
         .revision = "2020-06-17",
         .name = "augment-structure",
 
-        .plugin.id = "libyang 2 - structure, version 1",
+        .plugin.id = "ly2 structure v1",
+        .plugin.parse = structure_aug_parse,
         .plugin.compile = structure_aug_compile,
-        .plugin.sprinter = structure_schema_printer,
-        .plugin.free = structure_free,
+        .plugin.sprinter = structure_sprinter,
         .plugin.node = NULL,
         .plugin.snode = NULL,
-        .plugin.validate = NULL
+        .plugin.validate = NULL,
+        .plugin.pfree = NULL,
+        .plugin.cfree = structure_cfree
     },
     {0}     /* terminating zeroed record */
 };
diff --git a/src/plugins_exts/yangdata.c b/src/plugins_exts/yangdata.c
index 939709b..32229d7 100644
--- a/src/plugins_exts/yangdata.c
+++ b/src/plugins_exts/yangdata.c
@@ -1,9 +1,10 @@
 /**
  * @file yangdata.c
  * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief libyang extension plugin - yang-data (RFC 8040)
  *
- * Copyright (c) 2021 CESNET, z.s.p.o.
+ * Copyright (c) 2021 - 2022 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
@@ -19,15 +20,61 @@
 #include "libyang.h"
 #include "plugins_exts.h"
 
+static void yangdata_cfree(const struct ly_ctx *ctx, struct lysc_ext_instance *ext);
+
 /**
- * @brief Free yang-data extension instances' data.
+ * @brief Parse yang-data extension instances.
  *
- * Implementation of ::lyplg_clb_free_clb callback set as lyext_plugin::free.
+ * Implementation of ::lyplg_ext_parse_clb callback set as lyext_plugin::parse.
  */
-static void
-yangdata_free(struct ly_ctx *ctx, struct lysc_ext_instance *ext)
+static LY_ERR
+yangdata_parse(struct lysp_ctx *pctx, struct lysp_ext_instance *ext)
 {
-    lyplg_ext_instance_substatements_free(ctx, ext->substmts);
+    LY_ERR ret;
+    LY_ARRAY_COUNT_TYPE u;
+    struct lysp_module *pmod;
+
+    /* yang-data can appear only at the top level of a YANG module or submodule */
+    if ((ext->parent_stmt != LY_STMT_MODULE) && (ext->parent_stmt != LY_STMT_SUBMODULE)) {
+        lyplg_ext_parse_log(pctx, ext, LY_LLWRN, 0, "Extension %s is ignored since it appears as a non top-level statement "
+                "in \"%s\" statement.", ext->name, lyplg_ext_stmt2str(ext->parent_stmt));
+        return LY_ENOT;
+    }
+
+    pmod = ext->parent;
+
+    /* check for duplication */
+    LY_ARRAY_FOR(pmod->exts, u) {
+        if ((&pmod->exts[u] != ext) && (pmod->exts[u].name == ext->name) && !strcmp(pmod->exts[u].argument, ext->argument)) {
+            /* duplication of the same yang-data extension in a single module */
+            lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Extension %s is instantiated multiple times.", ext->name);
+            return LY_EVALID;
+        }
+    }
+
+    /* parse yang-data substatements */
+    LY_ARRAY_CREATE_GOTO(lyplg_extp_cur_pmod(pctx)->mod->ctx, ext->substmts, 3, ret, emem);
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[0].stmt = LY_STMT_CONTAINER;
+    ext->substmts[0].storage = &ext->parsed;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[1].stmt = LY_STMT_CHOICE;
+    ext->substmts[1].storage = &ext->parsed;
+
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[2].stmt = LY_STMT_USES;
+    ext->substmts[2].storage = &ext->parsed;
+
+    if ((ret = lyplg_ext_parse_extension_instance(pctx, ext))) {
+        return ret;
+    }
+
+    return LY_SUCCESS;
+
+emem:
+    lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s()).", __func__);
+    return LY_EMEM;
 }
 
 /**
@@ -36,109 +83,84 @@
  * Implementation of ::lyplg_ext_compile_clb callback set as lyext_plugin::compile.
  */
 static LY_ERR
-yangdata_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext, struct lysc_ext_instance *c_ext)
+yangdata_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *extp, struct lysc_ext_instance *ext)
 {
     LY_ERR ret;
-    LY_ARRAY_COUNT_TYPE u;
-    struct lysc_module *mod_c;
     const struct lysc_node *child;
     ly_bool valid = 1;
-    uint32_t prev_options = *lysc_ctx_get_options(cctx);
+    uint32_t prev_options = *lyplg_ext_compile_get_options(cctx);
 
-    /* yang-data can appear only at the top level of a YANG module or submodule */
-    if ((c_ext->parent_stmt != LY_STMT_MODULE) && (c_ext->parent_stmt != LY_STMT_SUBMODULE)) {
-        lyplg_ext_log(c_ext, LY_LLWRN, 0, lysc_ctx_get_path(cctx),
-                "Extension %s is ignored since it appears as a non top-level statement in \"%s\" statement.",
-                p_ext->name, ly_stmt2str(c_ext->parent_stmt));
-        return LY_ENOT;
-    }
+    /* compile yangg-data substatements */
+    LY_ARRAY_CREATE_GOTO(cctx->ctx, ext->substmts, 3, ret, emem);
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[0].stmt = LY_STMT_CONTAINER;
+    ext->substmts[0].storage = &ext->compiled;
 
-    mod_c = (struct lysc_module *)c_ext->parent;
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[1].stmt = LY_STMT_CHOICE;
+    ext->substmts[1].storage = &ext->compiled;
 
-    /* check for duplication */
-    LY_ARRAY_FOR(mod_c->exts, u) {
-        if ((&mod_c->exts[u] != c_ext) && (mod_c->exts[u].def == c_ext->def) && !strcmp(mod_c->exts[u].argument, c_ext->argument)) {
-            /* duplication of the same yang-data extension in a single module */
-            lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx), "Extension %s is instantiated multiple times.", p_ext->name);
-            return LY_EVALID;
-        }
-    }
+    LY_ARRAY_INCREMENT(ext->substmts);
+    ext->substmts[2].stmt = LY_STMT_USES;
+    ext->substmts[2].storage = &ext->compiled;
 
-    /* compile annotation substatements
-     * To let the compilation accept different statements possibly leading to the container top-level node, there are 3
-     * allowed substatements pointing to a single storage. But when compiled, the substaments list is compressed just to
-     * a single item providing the schema tree. */
-    LY_ARRAY_CREATE_GOTO(cctx->ctx, c_ext->substmts, 3, ret, emem);
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[0].stmt = LY_STMT_CONTAINER;
-    c_ext->substmts[0].storage = &c_ext->data;
-
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[1].stmt = LY_STMT_CHOICE;
-    c_ext->substmts[1].storage = &c_ext->data;
-
-    LY_ARRAY_INCREMENT(c_ext->substmts);
-    c_ext->substmts[2].stmt = LY_STMT_USES;
-    c_ext->substmts[2].storage = &c_ext->data;
-
-    *lysc_ctx_get_options(cctx) |= LYS_COMPILE_NO_CONFIG | LYS_COMPILE_NO_DISABLED;
-    ret = lys_compile_extension_instance(cctx, p_ext, c_ext);
-    *lysc_ctx_get_options(cctx) = prev_options;
-    LY_ARRAY_DECREMENT(c_ext->substmts);
-    LY_ARRAY_DECREMENT(c_ext->substmts);
+    *lyplg_ext_compile_get_options(cctx) |= LYS_COMPILE_NO_CONFIG | LYS_COMPILE_NO_DISABLED;
+    ret = lyplg_ext_compile_extension_instance(cctx, extp, ext);
+    *lyplg_ext_compile_get_options(cctx) = prev_options;
     if (ret) {
         return ret;
     }
 
     /* check that we have really just a single container data definition in the top */
-    child = *(struct lysc_node **)c_ext->substmts[0].storage;
+    child = ext->compiled;
     if (!child) {
         valid = 0;
-        lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
+        lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EVALID,
                 "Extension %s is instantiated without any top level data node, but exactly one container data node is expected.",
-                p_ext->name);
+                extp->name);
     } else if (child->next) {
         valid = 0;
-        lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
+        lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EVALID,
                 "Extension %s is instantiated with multiple top level data nodes, but only a single container data node is allowed.",
-                p_ext->name);
+                extp->name);
     } else if (child->nodetype == LYS_CHOICE) {
         /* all the choice's case are expected to result to a single container node */
+        struct lysc_module *mod_c = ext->parent;
         const struct lysc_node *snode = NULL;
 
         while ((snode = lys_getnext(snode, child, mod_c, 0))) {
             if (snode->next) {
                 valid = 0;
-                lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
+                lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EVALID,
                         "Extension %s is instantiated with multiple top level data nodes (inside a single choice's case), "
-                        "but only a single container data node is allowed.", p_ext->name);
+                        "but only a single container data node is allowed.", extp->name);
                 break;
             } else if (snode->nodetype != LYS_CONTAINER) {
                 valid = 0;
-                lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
+                lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EVALID,
                         "Extension %s is instantiated with %s top level data node (inside a choice), "
-                        "but only a single container data node is allowed.", p_ext->name, lys_nodetype2str(snode->nodetype));
+                        "but only a single container data node is allowed.", extp->name, lys_nodetype2str(snode->nodetype));
                 break;
             }
         }
     } else if (child->nodetype != LYS_CONTAINER) {
         /* via uses */
         valid = 0;
-        lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
+        lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EVALID,
                 "Extension %s is instantiated with %s top level data node, but only a single container data node is allowed.",
-                p_ext->name, lys_nodetype2str(child->nodetype));
+                extp->name, lys_nodetype2str(child->nodetype));
     }
 
     if (!valid) {
-        yangdata_free(lysc_ctx_get_ctx(cctx), c_ext);
-        c_ext->data = c_ext->substmts = NULL;
+        yangdata_cfree(lyplg_ext_compile_get_ctx(cctx), ext);
+        ext->compiled = ext->substmts = NULL;
         return LY_EVALID;
     }
 
     return LY_SUCCESS;
 
 emem:
-    lyplg_ext_log(c_ext, LY_LLERR, LY_EMEM, lysc_ctx_get_path(cctx), "Memory allocation failed (%s()).", __func__);
+    lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s()).", __func__);
     return LY_EMEM;
 }
 
@@ -150,11 +172,33 @@
 static LY_ERR
 yangdata_schema_printer(struct lyspr_ctx *ctx, struct lysc_ext_instance *ext, ly_bool *flag)
 {
-    lysc_print_extension_instance(ctx, ext, flag);
+    lyplg_ext_print_extension_instance(ctx, ext, flag);
     return LY_SUCCESS;
 }
 
 /**
+ * @brief Free parsed yang-data extension instance data.
+ *
+ * Implementation of ::lyplg_clb_parse_free_clb callback set as lyext_plugin::pfree.
+ */
+static void
+yangdata_pfree(const struct ly_ctx *ctx, struct lysp_ext_instance *ext)
+{
+    lyplg_ext_pfree_instance_substatements(ctx, ext->substmts);
+}
+
+/**
+ * @brief Free compiled yang-data extension instance data.
+ *
+ * Implementation of ::lyplg_clb_compile_free_clb callback set as lyext_plugin::cfree.
+ */
+static void
+yangdata_cfree(const struct ly_ctx *ctx, struct lysc_ext_instance *ext)
+{
+    lyplg_ext_cfree_instance_substatements(ctx, ext->substmts);
+}
+
+/**
  * @brief Plugin descriptions for the yang-data extension
  *
  * Note that external plugins are supposed to use:
@@ -167,13 +211,15 @@
         .revision = "2017-01-26",
         .name = "yang-data",
 
-        .plugin.id = "libyang 2 - yang-data, version 1",
+        .plugin.id = "ly2 yang-data v1",
+        .plugin.parse = yangdata_parse,
         .plugin.compile = yangdata_compile,
         .plugin.sprinter = yangdata_schema_printer,
-        .plugin.free = yangdata_free,
         .plugin.node = NULL,
         .plugin.snode = NULL,
-        .plugin.validate = NULL
+        .plugin.validate = NULL,
+        .plugin.pfree = yangdata_pfree,
+        .plugin.cfree = yangdata_cfree
     },
     {0}     /* terminating zeroed record */
 };
diff --git a/src/plugins_exts_compile.h b/src/plugins_exts_compile.h
deleted file mode 100644
index 0fbe43b..0000000
--- a/src/plugins_exts_compile.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/**
- * @file plugins_exts_compile.h
- * @author Radek Krejci <rkrejci@cesnet.cz>
- * @brief libyang support for YANG extensions implementation - schema compilation related items.
- *
- * Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
- *
- * This source code is licensed under BSD 3-Clause License (the "License").
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     https://opensource.org/licenses/BSD-3-Clause
- */
-
-#ifndef LY_PLUGINS_EXTS_COMPILE_H_
-#define LY_PLUGINS_EXTS_COMPILE_H_
-
-#include <stdint.h>
-
-#include "log.h"
-#include "tree_schema.h"
-
-struct ly_ctx;
-struct lysc_ctx;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @defgroup pluginsExtensionsCompile Plugins: Extensions compilation support
- * @ingroup pluginsExtensions
- *
- * Helper functions to implement extension plugin's compile callback.
- *
- * @{
- */
-
-/**
- * @defgroup scflags Schema compile flags
- *
- * Flags to modify schema compilation process and change the way how the particular statements are being compiled. *
- * @{
- */
-#define LYS_COMPILE_GROUPING        0x01            /**< Compiling (validation) of a non-instantiated grouping.
-                                                      In this case not all the restrictions are checked since they can
-                                                      be valid only in the real placement of the grouping. This is
-                                                      the case of any restriction that needs to look out of the statements
-                                                      themselves, since the context is not known. */
-#define LYS_COMPILE_DISABLED        0x02            /**< Compiling a disabled subtree (by its if-features). Meaning
-                                                      it will be removed at the end of compilation and should not be
-                                                      added to any unres sets. */
-#define LYS_COMPILE_NO_CONFIG       0x04            /**< ignore config statements, neither inherit config value */
-#define LYS_COMPILE_NO_DISABLED     0x08            /**< ignore if-feature statements */
-
-#define LYS_COMPILE_RPC_INPUT       (LYS_IS_INPUT | LYS_COMPILE_NO_CONFIG)  /**< Internal option when compiling schema tree of RPC/action input */
-#define LYS_COMPILE_RPC_OUTPUT      (LYS_IS_OUTPUT | LYS_COMPILE_NO_CONFIG) /**< Internal option when compiling schema tree of RPC/action output */
-#define LYS_COMPILE_NOTIFICATION    (LYS_IS_NOTIF | LYS_COMPILE_NO_CONFIG)  /**< Internal option when compiling schema tree of Notification */
-
-/** @} scflags */
-
-/**
- * @brief YANG schema compilation context for use in ::lyplg_ext_compile_clb callback implementation.
- *
- * The structure stores complex information connected with the schema compilation process. In the most simple case,
- * the callback is just supposed to pass the provided callback to ::lys_compile_extension_instance() functions.
- *
- * To access various items from the context, use some of the following lysc_ctx_get_* getters.
- */
-struct lysc_ctx;
-
-/**
- * @brief YANG schema compilation context getter for libyang context.
- * @param[in] ctx YANG schema compilation context.
- * @return libyang context connected with the compilation context.
- */
-LIBYANG_API_DECL struct ly_ctx *lysc_ctx_get_ctx(const struct lysc_ctx *ctx);
-
-/**
- * @brief YANG schema compilation context getter for compilation options.
- * @param[in] ctx YANG schema compilation context.
- * @return pointer to the compilation options to allow modifying them with @ref scflags values.
- */
-LIBYANG_API_DECL uint32_t *lysc_ctx_get_options(const struct lysc_ctx *ctx);
-
-/**
- * @brief YANG schema compilation context getter for path being currently processed.
- * @param[in] ctx YANG schema compilation context.
- * @return path identifying the place in schema being currently processed by the schema compiler.
- */
-LIBYANG_API_DECL const char *lysc_ctx_get_path(const struct lysc_ctx *ctx);
-
-/**
- * @brief YANG schema compilation context getter for current module.
- * @param[in] ctx YANG schema compilation context.
- * @return current module.
- */
-LIBYANG_API_DECL const struct lys_module *lysc_ctx_get_cur_mod(const struct lysc_ctx *ctx);
-
-/**
- * @brief YANG schema compilation context getter for currently processed module.
- * @param[in] ctx YANG schema compilation context.
- * @return Currently processed module.
- */
-LIBYANG_API_DECL struct lysp_module *lysc_ctx_get_pmod(const struct lysc_ctx *ctx);
-
-/**
- * @brief Compile substatements of an extension instance.
- *
- * Uses standard libyang schema compiler to transform YANG statements into the compiled schema structures. The plugins are
- * supposed to use this function when the extension instance's substatements are supposed to be compiled in a standard way
- * (or if just the @ref scflags are enough to modify the compilation process).
- *
- * @param[in] ctx Compile context.
- * @param[in] ext_p Parsed representation of the extension instance being processed.
- * @param[in,out] ext Compiled extension instance with the prepared ::lysc_ext_instance.substmts array, which will be updated
- * by storing the compiled data.
- * @return LY_SUCCESS on success.
- * @return LY_EVALID if compilation of the substatements fails.
- * @return LY_ENOT if the extension is disabled (by if-feature) and should be ignored.
- */
-LIBYANG_API_DECL LY_ERR lys_compile_extension_instance(struct lysc_ctx *ctx, const struct lysp_ext_instance *ext_p,
-        struct lysc_ext_instance *ext);
-
-/**
- * @brief Compile substatements of an extension instance but append all schema data nodes as augments.
- *
- * Similar to ::lys_compile_extension_instance().
- *
- * @param[in] ctx Compile context.
- * @param[in] ext_p Parsed representation of the extension instance being processed.
- * @param[in,out] ext Compiled extension instance with the prepared ::lysc_ext_instance.substmts array, which will be updated
- * by storing the compiled data except for schema data nodes.
- * @param[in] aug_target Augment target node to append schema data nodes.
- * @return LY_SUCCESS on success.
- * @return LY_EVALID if compilation of the substatements fails.
- * @return LY_ENOT if the extension is disabled (by if-feature) and should be ignored.
- */
-LIBYANG_API_DECL 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);
-
-/**
- * @brief Find augment target in an extension.
- *
- * @param[in] ctx Compile context.
- * @param[in] path Absolute-schema-nodeid representing the augment target. The first segment is expected to identify
- * the specific extension instance.
- * @param[out] aug_ext Optional augment target extension.
- * @param[out] aug_target Augment target compiled schema node.
- * @return LY_ERR value.
- */
-LIBYANG_API_DECL LY_ERR lys_compile_extension_instance_find_augment_target(struct lysc_ctx *ctx, const char *path,
-        struct lysc_ext_instance **aug_ext, struct lysc_node **aug_target);
-
-/**
- * @brief Update path in the compile context, which is used for logging where the compilation failed.
- *
- * @param[in] ctx Compile context with the path.
- * @param[in] parent_module Module of the current node's parent to check difference with the currently processed module (taken from @p ctx).
- * @param[in] name Name of the node to update path with. If NULL, the last segment is removed. If the format is `{keyword}`, the following
- * call updates the segment to the form `{keyword='name'}` (to remove this compound segment, 2 calls with NULL @p name must be used).
- */
-LIBYANG_API_DECL void lysc_update_path(struct lysc_ctx *ctx, struct lys_module *parent_module, const char *name);
-
-/**
- * @brief Duplicate the compiled extension (definition) structure.
- *
- * @param[in] orig The extension structure to duplicate.
- * @return The duplicated structure to use.
- */
-LIBYANG_API_DECL struct lysc_ext *lysc_ext_dup(struct lysc_ext *orig);
-
-/** @} extensions */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LY_PLUGINS_EXTS_COMPILE_H_ */
diff --git a/src/plugins_exts_print.h b/src/plugins_exts_print.h
deleted file mode 100644
index aed3b36..0000000
--- a/src/plugins_exts_print.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * @file plugins_exts_print.h
- * @author Radek Krejci <rkrejci@cesnet.cz>
- * @brief libyang support for YANG extensions implementation - schema print related items.
- *
- * Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
- *
- * This source code is licensed under BSD 3-Clause License (the "License").
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     https://opensource.org/licenses/BSD-3-Clause
- */
-
-#ifndef LY_PLUGINS_EXTS_PRINT_H_
-#define LY_PLUGINS_EXTS_PRINT_H_
-
-#include <stdint.h>
-
-#include "config.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @defgroup pluginsExtensionsPrint Plugins: Extensions printer support
- * @ingroup pluginsExtensions
- *
- * Helper functions to implement extension plugin's sprinter callback.
- *
- * @{
- */
-
-/**
- * @brief YANG printer context for use in ::lyplg_ext_schema_printer_clb callback implementation.
- *
- * The structure provides basic information how the compiled schema is supposed to be printed and where. In the most simple
- * case, the provided context is just passed into ::lysc_print_extension_instance() function which handles printing the
- * extension's substatements in the standard way.
- *
- * To access various items from the context, use some of the following lys_ypr_ctx_get_* getters.
- */
-struct lyspr_ctx;
-
-/**
- * @brief YANG printer context getter for output handler.
- * @param[in] ctx YANG printer context.
- * @return Output handler where the data are being printed. Note that the address of the handler pointer in the context is
- * returned to allow to modify the handler.
- */
-LIBYANG_API_DECL struct ly_out **lys_ypr_ctx_get_out(const struct lyspr_ctx *ctx);
-
-/**
- * @brief YANG printer context getter for printer options.
- * @param[in] ctx YANG printer context.
- * @return pointer to the printer options to allow modifying them with @ref schemaprinterflags values.
- */
-LIBYANG_API_DECL uint32_t *lys_ypr_ctx_get_options(const struct lyspr_ctx *ctx);
-
-/**
- * @brief YANG printer context getter for printer indentation level.
- * @param[in] ctx YANG printer context.
- * @return pointer to the printer's indentation level to allow modifying its value.
- */
-LIBYANG_API_DECL uint16_t *lys_ypr_ctx_get_level(const struct lyspr_ctx *ctx);
-
-/**
- * @brief Print substatements of an extension instance
- *
- * Generic function to access YANG printer functions from the extension plugins (::lyplg_ext_schema_printer_clb).
- *
- * @param[in] ctx YANG printer context to provide output handler and other information for printing.
- * @param[in] ext The compiled extension instance to access the extensions and substatements data.
- * @param[in, out] flag Flag to be shared with the caller regarding the opening brackets - 0 if the '{' not yet printed,
- * 1 otherwise.
- */
-LIBYANG_API_DECL void lysc_print_extension_instance(struct lyspr_ctx *ctx, const struct lysc_ext_instance *ext, ly_bool *flag);
-
-/** @} pluginsExtensionsPrint */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LY_PLUGINS_EXTS_PRINT_H_ */
diff --git a/src/printer_yang.c b/src/printer_yang.c
index 01ffa34..4cab943 100644
--- a/src/printer_yang.c
+++ b/src/printer_yang.c
@@ -28,7 +28,6 @@
 #include "out.h"
 #include "out_internal.h"
 #include "plugins_exts.h"
-#include "plugins_exts_print.h"
 #include "plugins_types.h"
 #include "printer_internal.h"
 #include "printer_schema.h"
@@ -246,22 +245,15 @@
 {
     struct lysp_stmt *stmt;
     ly_bool child_presence;
-    struct lysp_ext *ext_def;
 
     if ((ext->flags & LYS_INTERNAL) || (ext->parent_stmt != substmt) || (ext->parent_stmt_index != substmt_index)) {
         return;
     }
 
-    lysp_ext_find_definition(pctx->module->ctx, ext, NULL, &ext_def);
-    if (!ext_def) {
-        return;
-    }
-
     ypr_open(pctx->out, flag);
 
-    if (ext_def->argname) {
+    if (ext->def->argname) {
         ly_print_(pctx->out, "%*s%s \"", INDENT, ext->name);
-        lysp_ext_instance_resolve_argument(pctx->module->ctx, ext, ext_def);
         ypr_encode(pctx->out, ext->argument, -1);
         ly_print_(pctx->out, "\"");
     } else {
@@ -606,7 +598,7 @@
     text = ((restr->arg.str[0] != LYSP_RESTR_PATTERN_NACK) && (restr->arg.str[0] != LYSP_RESTR_PATTERN_ACK)) ?
             restr->arg.str : restr->arg.str + 1;
     singleline = strchr(text, '\n') ? 0 : 1;
-    ypr_text(pctx, ly_stmt2str(stmt), text, singleline, 0);
+    ypr_text(pctx, lyplg_ext_stmt2str(stmt), text, singleline, 0);
 
     LEVEL++;
     yprp_extension_instances(pctx, stmt, 0, restr->exts, &inner_flag);
@@ -1124,7 +1116,7 @@
     ly_print_(pctx->out, "\n%*s%s {\n", INDENT, inout->name);
     LEVEL++;
 
-    yprc_extension_instances(pctx, lys_nodetype2stmt(inout->nodetype), 0, inout->exts, NULL);
+    yprc_extension_instances(pctx, lyplg_ext_nodetype2stmt(inout->nodetype), 0, inout->exts, NULL);
     LY_ARRAY_FOR(inout->musts, u) {
         yprc_must(pctx, &inout->musts[u], NULL);
     }
@@ -1219,7 +1211,7 @@
     ly_print_(pctx->out, "%*s%s %s", INDENT, action->parent ? "action" : "rpc", action->name);
 
     LEVEL++;
-    yprp_extension_instances(pctx, lys_nodetype2stmt(action->nodetype), 0, action->exts, &flag);
+    yprp_extension_instances(pctx, lyplg_ext_nodetype2stmt(action->nodetype), 0, action->exts, &flag);
     yprp_iffeatures(pctx, action->iffeatures, action->exts, &flag);
     ypr_status(pctx, action->flags, action->exts, &flag);
     ypr_description(pctx, action->dsc, action->exts, &flag);
@@ -1258,7 +1250,7 @@
     ly_print_(pctx->out, "%*s%s %s", INDENT, action->parent ? "action" : "rpc", action->name);
 
     LEVEL++;
-    yprc_extension_instances(pctx, lys_nodetype2stmt(action->nodetype), 0, action->exts, &flag);
+    yprc_extension_instances(pctx, lyplg_ext_nodetype2stmt(action->nodetype), 0, action->exts, &flag);
     ypr_status(pctx, action->flags, action->exts, &flag);
     ypr_description(pctx, action->dsc, action->exts, &flag);
     ypr_reference(pctx, action->ref, action->exts, &flag);
@@ -1276,7 +1268,7 @@
     ly_print_(pctx->out, "%*s%s %s%s", INDENT, lys_nodetype2str(node->nodetype), node->name, flag ? "" : " {\n");
     LEVEL++;
 
-    yprp_extension_instances(pctx, lys_nodetype2stmt(node->nodetype), 0, node->exts, flag);
+    yprp_extension_instances(pctx, lyplg_ext_nodetype2stmt(node->nodetype), 0, node->exts, flag);
     yprp_when(pctx, lysp_node_when(node), flag);
     yprp_iffeatures(pctx, node->iffeatures, node->exts, flag);
 }
@@ -1290,7 +1282,7 @@
     ly_print_(pctx->out, "%*s%s %s%s", INDENT, lys_nodetype2str(node->nodetype), node->name, flag ? "" : " {\n");
     LEVEL++;
 
-    yprc_extension_instances(pctx, lys_nodetype2stmt(node->nodetype), 0, node->exts, flag);
+    yprc_extension_instances(pctx, lyplg_ext_nodetype2stmt(node->nodetype), 0, node->exts, flag);
 
     when = lysc_node_when(node);
     LY_ARRAY_FOR(when, u) {
@@ -2456,7 +2448,7 @@
 }
 
 LIBYANG_API_DEF void
-lysc_print_extension_instance(struct lyspr_ctx *ctx_generic, const struct lysc_ext_instance *ext, ly_bool *flag)
+lyplg_ext_print_extension_instance(struct lyspr_ctx *ctx_generic, const struct lysc_ext_instance *ext, ly_bool *flag)
 {
     struct lys_ypr_ctx *pctx = (struct lys_ypr_ctx *)ctx_generic;
     LY_ARRAY_COUNT_TYPE u, v;
@@ -2536,7 +2528,7 @@
         /* TODO support other substatements */
         default:
             LOGWRN(pctx->module->ctx, "Statement \"%s\" is not supported for an extension printer.",
-                    ly_stmt2str(ext->substmts[u].stmt));
+                    lyplg_ext_stmt2str(ext->substmts[u].stmt));
             break;
         }
     }
diff --git a/src/printer_yin.c b/src/printer_yin.c
index 88f9178..db54819 100644
--- a/src/printer_yin.c
+++ b/src/printer_yin.c
@@ -129,27 +129,17 @@
 {
     struct lysp_stmt *stmt;
     int8_t inner_flag;
-    struct lysp_ext *ext_def;
 
     if ((ext->flags & LYS_INTERNAL) || (ext->parent_stmt != substmt) || (ext->parent_stmt_index != substmt_index)) {
         return;
     }
 
-    lysp_ext_find_definition(pctx->module->ctx, ext, NULL, &ext_def);
-    if (!ext_def) {
-        return;
-    }
-
     ypr_close_parent(pctx, flag);
     inner_flag = 0;
 
-    if (ext_def->argname) {
-        lysp_ext_instance_resolve_argument(pctx->module->ctx, ext, ext_def);
-    }
-
-    ypr_open(pctx, ext->name, (ext_def->flags & LYS_YINELEM_TRUE) ? NULL : ext_def->argname, ext->argument, inner_flag);
+    ypr_open(pctx, ext->name, (ext->def->flags & LYS_YINELEM_TRUE) ? NULL : ext->def->argname, ext->argument, inner_flag);
     LEVEL++;
-    if (ext_def->flags & LYS_YINELEM_TRUE) {
+    if (ext->def->flags & LYS_YINELEM_TRUE) {
         const char *prefix, *name, *id;
         size_t prefix_len, name_len;
 
@@ -158,9 +148,9 @@
         /* we need to use the same namespace as for the extension instance element */
         id = ext->name;
         ly_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len);
-        ly_print_(pctx->out, "%*s<%.*s:%s>", INDENT, (int)prefix_len, prefix, ext_def->argname);
+        ly_print_(pctx->out, "%*s<%.*s:%s>", INDENT, (int)prefix_len, prefix, ext->def->argname);
         lyxml_dump_text(pctx->out, ext->argument, 0);
-        ly_print_(pctx->out, "</%.*s:%s>\n", (int)prefix_len, prefix, ext_def->argname);
+        ly_print_(pctx->out, "</%.*s:%s>\n", (int)prefix_len, prefix, ext->def->argname);
     }
     LY_LIST_FOR(ext->child, stmt) {
         if (stmt->flags & (LYS_YIN_ATTR | LYS_YIN_ARGUMENT)) {
@@ -425,7 +415,7 @@
         return;
     }
 
-    ly_print_(pctx->out, "%*s<%s %s=\"", INDENT, ly_stmt2str(stmt), attr);
+    ly_print_(pctx->out, "%*s<%s %s=\"", INDENT, lyplg_ext_stmt2str(stmt), attr);
     lyxml_dump_text(pctx->out,
             (restr->arg.str[0] != LYSP_RESTR_PATTERN_NACK && restr->arg.str[0] != LYSP_RESTR_PATTERN_ACK) ?
             restr->arg.str : &restr->arg.str[1], 1);
@@ -450,7 +440,7 @@
     ypr_reference(pctx, restr->ref, restr->exts, &inner_flag);
 
     LEVEL--;
-    ypr_close(pctx, ly_stmt2str(stmt), inner_flag);
+    ypr_close(pctx, lyplg_ext_stmt2str(stmt), inner_flag);
 }
 
 static void
@@ -657,7 +647,7 @@
     ypr_open(pctx, inout->name, NULL, NULL, *flag);
     LEVEL++;
 
-    yprp_extension_instances(pctx, lys_nodetype2stmt(inout->nodetype), 0, inout->exts, NULL);
+    yprp_extension_instances(pctx, lyplg_ext_nodetype2stmt(inout->nodetype), 0, inout->exts, NULL);
     LY_ARRAY_FOR(inout->musts, u) {
         yprp_restr(pctx, &inout->musts[u], LY_STMT_MUST, "condition", NULL);
     }
@@ -727,7 +717,7 @@
     ypr_open(pctx, action->parent ? "action" : "rpc", "name", action->name, flag);
 
     LEVEL++;
-    yprp_extension_instances(pctx, lys_nodetype2stmt(action->nodetype), 0, action->exts, &flag);
+    yprp_extension_instances(pctx, lyplg_ext_nodetype2stmt(action->nodetype), 0, action->exts, &flag);
     yprp_iffeatures(pctx, action->iffeatures, action->exts, &flag);
     ypr_status(pctx, action->flags, action->exts, &flag);
     ypr_description(pctx, action->dsc, action->exts, &flag);
@@ -756,7 +746,7 @@
     ypr_open(pctx, lys_nodetype2str(node->nodetype), "name", node->name, *flag);
     LEVEL++;
 
-    yprp_extension_instances(pctx, lys_nodetype2stmt(node->nodetype), 0, node->exts, flag);
+    yprp_extension_instances(pctx, lyplg_ext_nodetype2stmt(node->nodetype), 0, node->exts, flag);
     yprp_when(pctx, lysp_node_when(node), flag);
     yprp_iffeatures(pctx, node->iffeatures, node->exts, flag);
 }
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 */
diff --git a/src/schema_compile.h b/src/schema_compile.h
index 5d60c26..df58571 100644
--- a/src/schema_compile.h
+++ b/src/schema_compile.h
@@ -170,6 +170,16 @@
         } \
     }
 
+#define DUP_ARRAY2(CTX, PMOD, ORIG_ARRAY, NEW_ARRAY, DUP_FUNC) \
+    if (ORIG_ARRAY) { \
+        LY_ARRAY_COUNT_TYPE __u; \
+        LY_ARRAY_CREATE_RET(CTX, NEW_ARRAY, LY_ARRAY_COUNT(ORIG_ARRAY), LY_EMEM); \
+        LY_ARRAY_FOR(ORIG_ARRAY, __u) { \
+            LY_ARRAY_INCREMENT(NEW_ARRAY); \
+            LY_CHECK_RET(DUP_FUNC(CTX, PMOD, &(NEW_ARRAY)[__u], &(ORIG_ARRAY)[__u])); \
+        } \
+    }
+
 #define COMPILE_OP_ARRAY_GOTO(CTX, ARRAY_P, ARRAY_C, PARENT, FUNC, USES_STATUS, RET, GOTO) \
     if (ARRAY_P) { \
         LY_ARRAY_COUNT_TYPE __u = (ARRAY_C) ? LY_ARRAY_COUNT(ARRAY_C) : 0; \
@@ -203,7 +213,7 @@
         LY_ARRAY_CREATE_GOTO((CTX)->ctx, EXT_C, __u + LY_ARRAY_COUNT(EXTS_P), RET, GOTO); \
         LY_ARRAY_FOR(EXTS_P, __u) { \
             LY_ARRAY_INCREMENT(EXT_C); \
-            RET = lys_compile_ext(CTX, &(EXTS_P)[__u], &(EXT_C)[LY_ARRAY_COUNT(EXT_C) - 1], PARENT, NULL); \
+            RET = lys_compile_ext(CTX, &(EXTS_P)[__u], &(EXT_C)[LY_ARRAY_COUNT(EXT_C) - 1], PARENT); \
             if (RET == LY_ENOT) { \
                 LY_ARRAY_DECREMENT(EXT_C); \
                 RET = LY_SUCCESS; \
@@ -217,16 +227,31 @@
  * @brief Fill in the prepared compiled extension instance structure according to the parsed extension instance.
  *
  * @param[in] ctx Compilation context.
- * @param[in] ext_p Parsed extension instance.
+ * @param[in] extp Parsed extension instance.
  * @param[in,out] ext Prepared compiled extension instance.
  * @param[in] parent Extension instance parent.
- * @param[in] ext_mod Optional module with the extension instance extension definition, set only for internal annotations.
  * @return LY_SUCCESS on success.
  * @return LY_ENOT if the extension is disabled and should be ignored.
  * @return LY_ERR on error.
  */
-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);
+LY_ERR lys_compile_ext(struct lysc_ctx *ctx, struct lysp_ext_instance *extp, struct lysc_ext_instance *ext, void *parent);
+
+/**
+ * @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.
+ */
+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);
 
 /**
  * @brief Find and process the referenced base identities from another identity or identityref
@@ -246,15 +271,6 @@
         struct lysc_ident *ident, struct lysc_ident ***bases);
 
 /**
- * @brief Get compiled ext instance storage for a specific statement.
- *
- * @param[in] ext Compiled ext instance.
- * @param[in] stmt Stored statement.
- * @return Compiled ext instance substatement storage, NULL if substaement not supported or not stored.
- */
-const void *lys_compile_ext_instance_get_storage(const struct lysc_ext_instance *ext, enum ly_stmt stmt);
-
-/**
  * @brief Perform a complet compilation of identites in a module and all its submodules.
  *
  * @param[in] mod Module to process.
diff --git a/src/schema_compile_amend.c b/src/schema_compile_amend.c
index 6876ea4..66e6a3d 100644
--- a/src/schema_compile_amend.c
+++ b/src/schema_compile_amend.c
@@ -26,7 +26,6 @@
 #include "common.h"
 #include "dict.h"
 #include "log.h"
-#include "plugins_exts_compile.h"
 #include "schema_compile.h"
 #include "schema_compile_node.h"
 #include "schema_features.h"
@@ -343,26 +342,40 @@
 }
 
 static LY_ERR
-lysp_ext_dup(const struct ly_ctx *ctx, struct lysp_ext_instance *ext, const struct lysp_ext_instance *orig_ext)
+lysp_ext_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, struct lysp_ext_instance *ext,
+        const struct lysp_ext_instance *orig_ext)
 {
-    DUP_STRING_RET(ctx, orig_ext->name, ext->name);
-    DUP_STRING_RET(ctx, orig_ext->argument, ext->argument);
-    ext->format = orig_ext->format;
-    ext->parsed = NULL;
-    LY_CHECK_RET(ly_dup_prefix_data(ctx, orig_ext->format, orig_ext->prefix_data, &ext->prefix_data));
+    LY_ERR ret = LY_SUCCESS;
+    struct ly_set pmods = {0};
+    struct lysp_ctx pctx = {.parsed_mods = &pmods};
 
-    ext->child = NULL;
-    LY_CHECK_RET(lysp_ext_children_dup(ctx, &ext->child, orig_ext->child));
+    DUP_STRING_GOTO(ctx, orig_ext->name, ext->name, ret, cleanup);
+    DUP_STRING_GOTO(ctx, orig_ext->argument, ext->argument, ret, cleanup);
+    ext->format = orig_ext->format;
+    LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, orig_ext->format, orig_ext->prefix_data, &ext->prefix_data), cleanup);
+    ext->def = orig_ext->def;
 
     ext->parent = orig_ext->parent;
     ext->parent_stmt = orig_ext->parent_stmt;
     ext->parent_stmt_index = orig_ext->parent_stmt_index;
     ext->flags = orig_ext->flags;
-    return LY_SUCCESS;
+    ext->record = orig_ext->record;
+
+    LY_CHECK_GOTO(ret = lysp_ext_children_dup(ctx, &ext->child, orig_ext->child), cleanup);
+    if (ext->record && ext->record->plugin.parse) {
+        /* parse again */
+        LY_CHECK_GOTO(ret = ly_set_add(&pmods, pmod, 1, NULL), cleanup);
+        LY_CHECK_GOTO(ret = ext->record->plugin.parse(&pctx, ext), cleanup);
+    }
+
+cleanup:
+    ly_set_erase(&pmods, NULL);
+    return ret;
 }
 
 static LY_ERR
-lysp_restr_dup(const struct ly_ctx *ctx, struct lysp_restr *restr, const struct lysp_restr *orig_restr)
+lysp_restr_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, struct lysp_restr *restr,
+        const struct lysp_restr *orig_restr)
 {
     LY_ERR ret = LY_SUCCESS;
 
@@ -373,7 +386,7 @@
         DUP_STRING(ctx, orig_restr->eapptag, restr->eapptag, ret);
         DUP_STRING(ctx, orig_restr->dsc, restr->dsc, ret);
         DUP_STRING(ctx, orig_restr->ref, restr->ref, ret);
-        DUP_ARRAY(ctx, orig_restr->exts, restr->exts, lysp_ext_dup);
+        DUP_ARRAY2(ctx, pmod, orig_restr->exts, restr->exts, lysp_ext_dup);
     }
 
     return ret;
@@ -406,7 +419,8 @@
 }
 
 static LY_ERR
-lysp_type_enum_dup(const struct ly_ctx *ctx, struct lysp_type_enum *enm, const struct lysp_type_enum *orig_enm)
+lysp_type_enum_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, struct lysp_type_enum *enm,
+        const struct lysp_type_enum *orig_enm)
 {
     LY_ERR ret = LY_SUCCESS;
 
@@ -415,14 +429,15 @@
     DUP_STRING(ctx, orig_enm->ref, enm->ref, ret);
     enm->value = orig_enm->value;
     DUP_ARRAY(ctx, orig_enm->iffeatures, enm->iffeatures, lysp_qname_dup);
-    DUP_ARRAY(ctx, orig_enm->exts, enm->exts, lysp_ext_dup);
+    DUP_ARRAY2(ctx, pmod, orig_enm->exts, enm->exts, lysp_ext_dup);
     enm->flags = orig_enm->flags;
 
     return ret;
 }
 
 static LY_ERR
-lysp_type_dup(const struct ly_ctx *ctx, struct lysp_type *type, const struct lysp_type *orig_type)
+lysp_type_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, struct lysp_type *type,
+        const struct lysp_type *orig_type)
 {
     LY_ERR ret = LY_SUCCESS;
 
@@ -434,22 +449,22 @@
     if (orig_type->range) {
         type->range = calloc(1, sizeof *type->range);
         LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx), LY_EMEM);
-        LY_CHECK_RET(lysp_restr_dup(ctx, type->range, orig_type->range));
+        LY_CHECK_RET(lysp_restr_dup(ctx, pmod, type->range, orig_type->range));
     }
 
     if (orig_type->length) {
         type->length = calloc(1, sizeof *type->length);
         LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx), LY_EMEM);
-        LY_CHECK_RET(lysp_restr_dup(ctx, type->length, orig_type->length));
+        LY_CHECK_RET(lysp_restr_dup(ctx, pmod, type->length, orig_type->length));
     }
 
-    DUP_ARRAY(ctx, orig_type->patterns, type->patterns, lysp_restr_dup);
-    DUP_ARRAY(ctx, orig_type->enums, type->enums, lysp_type_enum_dup);
-    DUP_ARRAY(ctx, orig_type->bits, type->bits, lysp_type_enum_dup);
+    DUP_ARRAY2(ctx, pmod, orig_type->patterns, type->patterns, lysp_restr_dup);
+    DUP_ARRAY2(ctx, pmod, orig_type->enums, type->enums, lysp_type_enum_dup);
+    DUP_ARRAY2(ctx, pmod, orig_type->bits, type->bits, lysp_type_enum_dup);
     LY_CHECK_GOTO(ret = lyxp_expr_dup(ctx, orig_type->path, 0, 0, &type->path), done);
     DUP_ARRAY(ctx, orig_type->bases, type->bases, lysp_string_dup);
-    DUP_ARRAY(ctx, orig_type->types, type->types, lysp_type_dup);
-    DUP_ARRAY(ctx, orig_type->exts, type->exts, lysp_ext_dup);
+    DUP_ARRAY2(ctx, pmod, orig_type->types, type->types, lysp_type_dup);
+    DUP_ARRAY2(ctx, pmod, orig_type->exts, type->exts, lysp_ext_dup);
 
     type->pmod = orig_type->pmod;
     type->compiled = orig_type->compiled;
@@ -463,20 +478,22 @@
 }
 
 static LY_ERR
-lysp_when_dup(const struct ly_ctx *ctx, struct lysp_when *when, const struct lysp_when *orig_when)
+lysp_when_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, struct lysp_when *when,
+        const struct lysp_when *orig_when)
 {
     LY_ERR ret = LY_SUCCESS;
 
     DUP_STRING(ctx, orig_when->cond, when->cond, ret);
     DUP_STRING(ctx, orig_when->dsc, when->dsc, ret);
     DUP_STRING(ctx, orig_when->ref, when->ref, ret);
-    DUP_ARRAY(ctx, orig_when->exts, when->exts, lysp_ext_dup);
+    DUP_ARRAY2(ctx, pmod, orig_when->exts, when->exts, lysp_ext_dup);
 
     return ret;
 }
 
 static LY_ERR
-lysp_node_common_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
+lysp_node_common_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, struct lysp_node *node,
+        const struct lysp_node *orig)
 {
     LY_ERR ret = LY_SUCCESS;
 
@@ -488,20 +505,21 @@
     DUP_STRING(ctx, orig->dsc, node->dsc, ret);
     DUP_STRING(ctx, orig->ref, node->ref, ret);
     DUP_ARRAY(ctx, orig->iffeatures, node->iffeatures, lysp_qname_dup);
-    DUP_ARRAY(ctx, orig->exts, node->exts, lysp_ext_dup);
+    DUP_ARRAY2(ctx, pmod, orig->exts, node->exts, lysp_ext_dup);
 
     return ret;
 }
 
-#define DUP_PWHEN(CTX, ORIG, NEW) \
+#define DUP_PWHEN(CTX, PMOD, ORIG, NEW) \
     if (ORIG) { \
         NEW = calloc(1, sizeof *NEW); \
         LY_CHECK_ERR_RET(!NEW, LOGMEM(CTX), LY_EMEM); \
-        LY_CHECK_RET(lysp_when_dup(CTX, NEW, ORIG)); \
+        LY_CHECK_RET(lysp_when_dup(CTX, PMOD, NEW, ORIG)); \
     }
 
 static LY_ERR
-lysp_node_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
+lysp_node_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, struct lysp_node *node,
+        const struct lysp_node *orig)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lysp_node_container *cont;
@@ -529,7 +547,7 @@
             LYS_RPC | LYS_ACTION | LYS_NOTIF));
 
     /* common part */
-    LY_CHECK_RET(lysp_node_common_dup(ctx, node, orig));
+    LY_CHECK_RET(lysp_node_common_dup(ctx, pmod, node, orig));
 
     /* specific part */
     switch (node->nodetype) {
@@ -537,8 +555,8 @@
         cont = (struct lysp_node_container *)node;
         orig_cont = (const struct lysp_node_container *)orig;
 
-        DUP_PWHEN(ctx, orig_cont->when, cont->when);
-        DUP_ARRAY(ctx, orig_cont->musts, cont->musts, lysp_restr_dup);
+        DUP_PWHEN(ctx, pmod, orig_cont->when, cont->when);
+        DUP_ARRAY2(ctx, pmod, orig_cont->musts, cont->musts, lysp_restr_dup);
         DUP_STRING(ctx, orig_cont->presence, cont->presence, ret);
         /* we do not need the rest */
         break;
@@ -546,9 +564,9 @@
         leaf = (struct lysp_node_leaf *)node;
         orig_leaf = (const struct lysp_node_leaf *)orig;
 
-        DUP_PWHEN(ctx, orig_leaf->when, leaf->when);
-        DUP_ARRAY(ctx, orig_leaf->musts, leaf->musts, lysp_restr_dup);
-        LY_CHECK_RET(lysp_type_dup(ctx, &leaf->type, &orig_leaf->type));
+        DUP_PWHEN(ctx, pmod, orig_leaf->when, leaf->when);
+        DUP_ARRAY2(ctx, pmod, orig_leaf->musts, leaf->musts, lysp_restr_dup);
+        LY_CHECK_RET(lysp_type_dup(ctx, pmod, &leaf->type, &orig_leaf->type));
         DUP_STRING(ctx, orig_leaf->units, leaf->units, ret);
         LY_CHECK_RET(lysp_qname_dup(ctx, &leaf->dflt, &orig_leaf->dflt));
         break;
@@ -556,9 +574,9 @@
         llist = (struct lysp_node_leaflist *)node;
         orig_llist = (const struct lysp_node_leaflist *)orig;
 
-        DUP_PWHEN(ctx, orig_llist->when, llist->when);
-        DUP_ARRAY(ctx, orig_llist->musts, llist->musts, lysp_restr_dup);
-        LY_CHECK_RET(lysp_type_dup(ctx, &llist->type, &orig_llist->type));
+        DUP_PWHEN(ctx, pmod, orig_llist->when, llist->when);
+        DUP_ARRAY2(ctx, pmod, orig_llist->musts, llist->musts, lysp_restr_dup);
+        LY_CHECK_RET(lysp_type_dup(ctx, pmod, &llist->type, &orig_llist->type));
         DUP_STRING(ctx, orig_llist->units, llist->units, ret);
         DUP_ARRAY(ctx, orig_llist->dflts, llist->dflts, lysp_qname_dup);
         llist->min = orig_llist->min;
@@ -568,8 +586,8 @@
         list = (struct lysp_node_list *)node;
         orig_list = (const struct lysp_node_list *)orig;
 
-        DUP_PWHEN(ctx, orig_list->when, list->when);
-        DUP_ARRAY(ctx, orig_list->musts, list->musts, lysp_restr_dup);
+        DUP_PWHEN(ctx, pmod, orig_list->when, list->when);
+        DUP_ARRAY2(ctx, pmod, orig_list->musts, list->musts, lysp_restr_dup);
         DUP_STRING(ctx, orig_list->key, list->key, ret);
         /* we do not need these arrays */
         DUP_ARRAY(ctx, orig_list->uniques, list->uniques, lysp_qname_dup);
@@ -580,7 +598,7 @@
         choice = (struct lysp_node_choice *)node;
         orig_choice = (const struct lysp_node_choice *)orig;
 
-        DUP_PWHEN(ctx, orig_choice->when, choice->when);
+        DUP_PWHEN(ctx, pmod, orig_choice->when, choice->when);
         /* we do not need children */
         LY_CHECK_RET(lysp_qname_dup(ctx, &choice->dflt, &orig_choice->dflt));
         break;
@@ -588,7 +606,7 @@
         cas = (struct lysp_node_case *)node;
         orig_cas = (const struct lysp_node_case *)orig;
 
-        DUP_PWHEN(ctx, orig_cas->when, cas->when);
+        DUP_PWHEN(ctx, pmod, orig_cas->when, cas->when);
         /* we do not need children */
         break;
     case LYS_ANYDATA:
@@ -596,8 +614,8 @@
         any = (struct lysp_node_anydata *)node;
         orig_any = (const struct lysp_node_anydata *)orig;
 
-        DUP_PWHEN(ctx, orig_any->when, any->when);
-        DUP_ARRAY(ctx, orig_any->musts, any->musts, lysp_restr_dup);
+        DUP_PWHEN(ctx, pmod, orig_any->when, any->when);
+        DUP_ARRAY2(ctx, pmod, orig_any->musts, any->musts, lysp_restr_dup);
         break;
     case LYS_RPC:
     case LYS_ACTION:
@@ -613,14 +631,14 @@
         action_inout = (struct lysp_node_action_inout *)node;
         orig_action_inout = (const struct lysp_node_action_inout *)orig;
 
-        DUP_ARRAY(ctx, orig_action_inout->musts, action_inout->musts, lysp_restr_dup);
+        DUP_ARRAY2(ctx, pmod, orig_action_inout->musts, action_inout->musts, lysp_restr_dup);
         /* we do not need the rest */
         break;
     case LYS_NOTIF:
         notif = (struct lysp_node_notif *)node;
         orig_notif = (const struct lysp_node_notif *)orig;
 
-        DUP_ARRAY(ctx, orig_notif->musts, notif->musts, lysp_restr_dup);
+        DUP_ARRAY2(ctx, pmod, orig_notif->musts, notif->musts, lysp_restr_dup);
         /* we do not need the rest */
         break;
     default:
@@ -634,13 +652,15 @@
  * @brief Duplicate a single parsed node. Only attributes that are used in compilation are copied.
  *
  * @param[in] ctx libyang context.
+ * @param[in] pmod Current parsed module.
  * @param[in] pnode Node to duplicate.
  * @param[in] with_links Whether to also copy any links (child, parent pointers).
  * @param[out] dup_p Duplicated parsed node.
  * @return LY_ERR value.
  */
 static LY_ERR
-lysp_dup_single(const struct ly_ctx *ctx, const struct lysp_node *pnode, ly_bool with_links, struct lysp_node **dup_p)
+lysp_dup_single(const struct ly_ctx *ctx, const struct lysp_module *pmod, const struct lysp_node *pnode,
+        ly_bool with_links, struct lysp_node **dup_p)
 {
     LY_ERR ret = LY_SUCCESS;
     void *mem = NULL;
@@ -688,7 +708,7 @@
         LOGINT_RET(ctx);
     }
     LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
-    LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
+    LY_CHECK_GOTO(ret = lysp_node_dup(ctx, pmod, mem, pnode), cleanup);
 
     if (with_links) {
         /* copy also parent, child, action, and notification pointers */
@@ -743,18 +763,29 @@
  *
  * @param[in] ctx Compile context.
  * @param[in] rfn Refine to apply.
+ * @param[in] rfn_pmod Local module fo the refine.
  * @param[in,out] target Refine target.
  * @return LY_ERR value.
  */
 static LY_ERR
-lys_apply_refine(struct lysc_ctx *ctx, struct lysp_refine *rfn, struct lysp_node *target)
+lys_apply_refine(struct lysc_ctx *ctx, struct lysp_refine *rfn, const struct lysp_module *rfn_pmod, struct lysp_node *target)
 {
     LY_ERR ret = LY_SUCCESS;
+    struct lys_module *orig_mod = ctx->cur_mod;
+    struct lysp_module *orig_pmod = ctx->pmod;
     LY_ARRAY_COUNT_TYPE u;
     struct lysp_qname *qname;
     struct lysp_restr **musts, *must;
     uint32_t *num;
 
+    /* use module from the refine */
+    ctx->cur_mod = rfn_pmod->mod;
+    ctx->pmod = (struct lysp_module *)rfn_pmod;
+
+    /* keep the current path and add to it */
+    lysc_update_path(ctx, NULL, "{refine}");
+    lysc_update_path(ctx, NULL, rfn->nodeid);
+
     /* default value */
     if (rfn->dflts) {
         switch (target->nodetype) {
@@ -860,7 +891,7 @@
 
         LY_ARRAY_FOR(rfn->musts, u) {
             LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
-            LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &rfn->musts[u]), cleanup);
+            LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, rfn_pmod, must, &rfn->musts[u]), cleanup);
         }
     }
 
@@ -918,10 +949,15 @@
         }
     }
 
-    /* extension */
-    /* TODO refine extensions */
+    /* extension instances */
+    DUP_ARRAY2(ctx->ctx, rfn_pmod, rfn->exts, target->exts, lysp_ext_dup);
 
 cleanup:
+    ctx->cur_mod = orig_mod;
+    ctx->pmod = orig_pmod;
+
+    lysc_update_path(ctx, NULL, NULL);
+    lysc_update_path(ctx, NULL, NULL);
     return ret;
 }
 
@@ -973,7 +1009,7 @@
 
         LY_ARRAY_FOR(d->musts, u) {
             LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
-            LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &d->musts[u]), cleanup);
+            LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, ctx->pmod, must, &d->musts[u]), cleanup);
         }
     }
 
@@ -1279,7 +1315,7 @@
         }
 
         lysp_type_free(&ctx->free_ctx, &((struct lysp_node_leaf *)target)->type);
-        lysp_type_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->type, d->type);
+        lysp_type_dup(ctx->ctx, ctx->pmod, &((struct lysp_node_leaf *)target)->type, d->type);
     }
 
     /* [units-stmt] */
@@ -1415,6 +1451,65 @@
 }
 
 /**
+ * @brief Apply deviation with all its deviates.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] dev Deviation to apply.
+ * @param[in] dev_pmod Local module of the deviation.
+ * @param[in,out] target Deviation target.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_apply_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev, const struct lysp_module *dev_pmod,
+        struct lysp_node *target)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct lys_module *orig_mod = ctx->cur_mod;
+    struct lysp_module *orig_pmod = ctx->pmod;
+    char orig_path[LYSC_CTX_BUFSIZE];
+    struct lysp_deviate *d;
+
+    /* clear path and set modules */
+    strcpy(orig_path, ctx->path);
+    ctx->path_len = 1;
+    ctx->cur_mod = dev_pmod->mod;
+    ctx->pmod = (struct lysp_module *)dev_pmod;
+
+    /* generate correct path */
+    lysc_update_path(ctx, NULL, "{deviation}");
+    lysc_update_path(ctx, NULL, dev->nodeid);
+
+    LY_LIST_FOR(dev->deviates, d) {
+        switch (d->mod) {
+        case LYS_DEV_ADD:
+            ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, target);
+            break;
+        case LYS_DEV_DELETE:
+            ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, target);
+            break;
+        case LYS_DEV_REPLACE:
+            ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, target);
+            break;
+        default:
+            LOGINT(ctx->ctx);
+            ret = LY_EINT;
+        }
+        LY_CHECK_GOTO(ret, cleanup);
+    }
+
+    /* deviation extension instances */
+    DUP_ARRAY2(ctx->ctx, dev_pmod, dev->exts, target->exts, lysp_ext_dup);
+
+cleanup:
+    ctx->cur_mod = orig_mod;
+    ctx->pmod = orig_pmod;
+
+    strcpy(ctx->path, orig_path);
+    ctx->path_len = strlen(ctx->path);
+    return ret;
+}
+
+/**
  * @brief Check whether a compiled node matches a single schema nodeid name test.
  *
  * @param[in,out] node Compiled node to consider. On a match it is moved to its parent.
@@ -1606,13 +1701,8 @@
     LY_ERR ret = LY_SUCCESS;
     uint32_t i;
     LY_ARRAY_COUNT_TYPE u;
-    struct lys_module *orig_mod = ctx->cur_mod;
-    struct lysp_module *orig_pmod = ctx->pmod;
-    char orig_path[LYSC_CTX_BUFSIZE];
     struct lysc_refine *rfn;
     struct lysc_deviation *dev;
-    struct lysp_deviation *dev_p;
-    struct lysp_deviate *d;
 
     *dev_pnode = NULL;
     *not_supported = 0;
@@ -1620,7 +1710,7 @@
     for (i = 0; i < ctx->uses_rfns.count; ) {
         rfn = ctx->uses_rfns.objs[i];
 
-        if (!lysp_schema_nodeid_match(rfn->nodeid, rfn->nodeid_pmod, rfn->nodeid_ctx_node, parent, pnode, orig_mod)) {
+        if (!lysp_schema_nodeid_match(rfn->nodeid, rfn->nodeid_pmod, rfn->nodeid_ctx_node, parent, pnode, ctx->cur_mod)) {
             /* not our target node */
             ++i;
             continue;
@@ -1628,24 +1718,12 @@
 
         if (!*dev_pnode) {
             /* first refine on this node, create a copy first */
-            LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
+            LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, ctx->pmod, pnode, 1, dev_pnode), cleanup);
         }
 
-        /* use modules from the refine */
-        ctx->cur_mod = rfn->nodeid_pmod->mod;
-        ctx->pmod = (struct lysp_module *)rfn->nodeid_pmod;
-
         /* apply all the refines by changing (the copy of) the parsed node */
         LY_ARRAY_FOR(rfn->rfns, u) {
-            /* keep the current path and add to it */
-            lysc_update_path(ctx, NULL, "{refine}");
-            lysc_update_path(ctx, NULL, rfn->rfns[u]->nodeid);
-
-            /* apply refine and restore the path */
-            ret = lys_apply_refine(ctx, rfn->rfns[u], *dev_pnode);
-            lysc_update_path(ctx, NULL, NULL);
-            lysc_update_path(ctx, NULL, NULL);
-            LY_CHECK_GOTO(ret, cleanup);
+            LY_CHECK_GOTO(ret = lys_apply_refine(ctx, rfn->rfns[u], rfn->nodeid_pmod, *dev_pnode), cleanup);
         }
 
         /* refine was applied, remove it */
@@ -1658,7 +1736,7 @@
     for (i = 0; i < ctx->devs.count; ++i) {
         dev = ctx->devs.objs[i];
 
-        if (!lysp_schema_nodeid_match(dev->nodeid, dev->dev_pmods[0], NULL, parent, pnode, orig_mod)) {
+        if (!lysp_schema_nodeid_match(dev->nodeid, dev->dev_pmods[0], NULL, parent, pnode, ctx->cur_mod)) {
             /* not our target node */
             continue;
         }
@@ -1671,42 +1749,12 @@
 
         if (!*dev_pnode) {
             /* first deviation on this node, create a copy first */
-            LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
+            LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, ctx->pmod, pnode, 1, dev_pnode), cleanup);
         }
 
         /* apply all the deviates by changing (the copy of) the parsed node */
         LY_ARRAY_FOR(dev->devs, u) {
-            dev_p = dev->devs[u];
-            LY_LIST_FOR(dev_p->deviates, d) {
-                /* generate correct path */
-                strcpy(orig_path, ctx->path);
-                ctx->path_len = 1;
-                ctx->cur_mod = dev->dev_pmods[u]->mod;
-                ctx->pmod = (struct lysp_module *)dev->dev_pmods[u];
-                lysc_update_path(ctx, NULL, "{deviation}");
-                lysc_update_path(ctx, NULL, dev_p->nodeid);
-
-                switch (d->mod) {
-                case LYS_DEV_ADD:
-                    ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, *dev_pnode);
-                    break;
-                case LYS_DEV_DELETE:
-                    ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, *dev_pnode);
-                    break;
-                case LYS_DEV_REPLACE:
-                    ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, *dev_pnode);
-                    break;
-                default:
-                    LOGINT(ctx->ctx);
-                    ret = LY_EINT;
-                }
-
-                /* restore previous path */
-                strcpy(ctx->path, orig_path);
-                ctx->path_len = strlen(ctx->path);
-
-                LY_CHECK_GOTO(ret, cleanup);
-            }
+            LY_CHECK_GOTO(ret = lys_apply_deviation(ctx, dev->devs[u], dev->dev_pmods[u], *dev_pnode), cleanup);
         }
 
 dev_applied:
@@ -1719,8 +1767,6 @@
     }
 
 cleanup:
-    ctx->cur_mod = orig_mod;
-    ctx->pmod = orig_pmod;
     if (ret) {
         lysp_dev_node_free(ctx, *dev_pnode);
         *dev_pnode = NULL;
@@ -1877,6 +1923,9 @@
             child_unres_disabled);
     LY_CHECK_GOTO(rc, cleanup);
 
+    /* compile extensions into the target */
+    COMPILE_EXTS_GOTO(ctx, aug_p->exts, target->exts, target, rc, cleanup);
+
 cleanup:
     ctx->compile_opts = opt_prev;
     return rc;
diff --git a/src/schema_compile_node.c b/src/schema_compile_node.c
index 0d2fe6d..a1708b0 100644
--- a/src/schema_compile_node.c
+++ b/src/schema_compile_node.c
@@ -30,7 +30,6 @@
 #include "dict.h"
 #include "log.h"
 #include "plugins.h"
-#include "plugins_exts_compile.h"
 #include "plugins_internal.h"
 #include "plugins_types.h"
 #include "schema_compile.h"
@@ -404,7 +403,7 @@
  * @return LY_ERR value.
  */
 static LY_ERR
-lys_compile_when_(struct lysc_ctx *ctx, struct lysp_when *when_p, uint16_t parent_flags,
+lys_compile_when_(struct lysc_ctx *ctx, const struct lysp_when *when_p, uint16_t parent_flags,
         const struct lysc_node *compiled_parent, const struct lysc_node *ctx_node, struct lysc_when **when)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -432,21 +431,31 @@
 }
 
 LY_ERR
-lys_compile_when(struct lysc_ctx *ctx, struct lysp_when *when_p, uint16_t parent_flags, const struct lysc_node *compiled_parent,
-        const struct lysc_node *ctx_node, struct lysc_node *node, struct lysc_when **when_c)
+lys_compile_when(struct lysc_ctx *ctx, const struct lysp_when *when_p, uint16_t parent_flags,
+        const struct lysc_node *compiled_parent, const struct lysc_node *ctx_node, struct lysc_node *node,
+        struct lysc_when **when_c)
 {
-    struct lysc_when **new_when, ***node_when;
+    LY_ERR rc = LY_SUCCESS;
+    struct lysc_when **new_when, ***node_when, *ptr;
 
-    assert(when_p);
+    assert(when_p && (node || when_c));
 
-    /* get the when array */
-    node_when = lysc_node_when_p(node);
+    if (node) {
+        /* get the when array */
+        node_when = lysc_node_when_p(node);
 
-    /* create new when pointer */
-    LY_ARRAY_NEW_RET(ctx->ctx, *node_when, new_when, LY_EMEM);
+        /* create new when pointer */
+        LY_ARRAY_NEW_GOTO(ctx->ctx, *node_when, new_when, rc, cleanup);
+    } else {
+        /* individual when */
+        new_when = &ptr;
+        *new_when = calloc(1, sizeof **new_when);
+        LY_CHECK_ERR_GOTO(!*new_when, LOGMEM(ctx->ctx); rc = LY_EMEM, cleanup);
+    }
+
     if (!when_c || !(*when_c)) {
         /* compile when */
-        LY_CHECK_RET(lys_compile_when_(ctx, when_p, parent_flags, compiled_parent, ctx_node, new_when));
+        LY_CHECK_GOTO(rc = lys_compile_when_(ctx, when_p, parent_flags, compiled_parent, ctx_node, new_when), cleanup);
 
         /* remember the compiled when for sharing */
         if (when_c) {
@@ -461,14 +470,15 @@
     if (!(ctx->compile_opts & LYS_COMPILE_GROUPING)) {
         /* do not check "when" semantics in a grouping, but repeat the check for different node because
          * of dummy node check */
-        LY_CHECK_RET(ly_set_add(&ctx->unres->whens, node, 0, NULL));
+        LY_CHECK_GOTO(rc = ly_set_add(&ctx->unres->whens, node, 0, NULL), cleanup);
     }
 
-    return LY_SUCCESS;
+cleanup:
+    return rc;
 }
 
 LY_ERR
-lys_compile_must(struct lysc_ctx *ctx, struct lysp_restr *must_p, struct lysc_must *must)
+lys_compile_must(struct lysc_ctx *ctx, const struct lysp_restr *must_p, struct lysc_must *must)
 {
     LY_ERR ret = LY_SUCCESS;
     LY_VALUE_FORMAT format;
@@ -761,20 +771,8 @@
     return ret;
 }
 
-/**
- * @brief Compile the parsed range restriction.
- * @param[in] ctx Compile context.
- * @param[in] range_p Parsed range structure to compile.
- * @param[in] basetype Base YANG built-in type of the node with the range restriction.
- * @param[in] length_restr Flag to distinguish between range and length restrictions. Only for logging.
- * @param[in] frdigits The fraction-digits value in case of LY_TYPE_DEC64 basetype.
- * @param[in] base_range Range restriction of the type from which the current type is derived. The current
- * range restriction must be more restrictive than the base_range.
- * @param[in,out] range Pointer to the created current range structure.
- * @return LY_ERR value.
- */
-static LY_ERR
-lys_compile_type_range(struct lysc_ctx *ctx, struct lysp_restr *range_p, LY_DATA_TYPE basetype, ly_bool length_restr,
+LY_ERR
+lys_compile_type_range(struct lysc_ctx *ctx, const struct lysp_restr *range_p, LY_DATA_TYPE basetype, ly_bool length_restr,
         uint8_t frdigits, struct lysc_range *base_range, struct lysc_range **range)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -1287,8 +1285,8 @@
 }
 
 LY_ERR
-lys_compile_type_patterns(struct lysc_ctx *ctx, struct lysp_restr *patterns_p,
-        struct lysc_pattern **base_patterns, struct lysc_pattern ***patterns)
+lys_compile_type_patterns(struct lysc_ctx *ctx, const struct lysp_restr *patterns_p, struct lysc_pattern **base_patterns,
+        struct lysc_pattern ***patterns)
 {
     struct lysc_pattern **pattern;
     LY_ARRAY_COUNT_TYPE u;
@@ -1374,17 +1372,8 @@
     LY_TYPE_INT64_STR
 };
 
-/**
- * @brief Compile parsed type's enum structures (for enumeration and bits types).
- * @param[in] ctx Compile context.
- * @param[in] enums_p Array of the parsed enum structures to compile.
- * @param[in] basetype Base YANG built-in type from which the current type is derived. Only LY_TYPE_ENUM and LY_TYPE_BITS are expected.
- * @param[in] base_enums Array of the compiled enums information from the (latest) base type to check if the current enums are compatible.
- * @param[out] bitenums Newly created array of the compiled bitenums information for the current type.
- * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
- */
-static LY_ERR
-lys_compile_type_enums(struct lysc_ctx *ctx, struct lysp_type_enum *enums_p, LY_DATA_TYPE basetype,
+LY_ERR
+lys_compile_type_enums(struct lysc_ctx *ctx, const struct lysp_type_enum *enums_p, LY_DATA_TYPE basetype,
         struct lysc_type_bitenum_item *base_enums, struct lysc_type_bitenum_item **bitenums)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -1626,7 +1615,8 @@
  */
 static LY_ERR
 lys_compile_type_(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags, const char *context_name,
-        struct lysp_type *type_p, LY_DATA_TYPE basetype, const char *tpdfname, struct lysc_type *base, struct lysc_type **type)
+        struct lysp_type *type_p, LY_DATA_TYPE basetype, const char *tpdfname, const struct lysc_type *base,
+        struct lysc_type **type)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lysc_type_bin *bin;
@@ -1950,7 +1940,7 @@
 
 LY_ERR
 lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags, const char *context_name,
-        struct lysp_type *type_p, struct lysc_type **type, const char **units, struct lysp_qname **dflt)
+        const struct lysp_type *type_p, struct lysc_type **type, const char **units, struct lysp_qname **dflt)
 {
     LY_ERR ret = LY_SUCCESS;
     ly_bool dummyloops = 0;
@@ -2186,7 +2176,8 @@
         (*type)->basetype = basetype;
         (*type)->plugin = base ? base->plugin : lyplg_type_plugin_find("", NULL, ly_data_type2str[basetype]);
         LY_ATOMIC_INC_BARRIER((*type)->refcount);
-        ret = lys_compile_type_(ctx, context_pnode, context_flags, context_name, type_p, basetype, NULL, base, type);
+        ret = lys_compile_type_(ctx, context_pnode, context_flags, context_name, (struct lysp_type *)type_p, basetype,
+                NULL, base, type);
         LY_CHECK_GOTO(ret, cleanup);
     } else if ((basetype != LY_TYPE_BOOL) && (basetype != LY_TYPE_EMPTY)) {
         /* no specific restriction in leaf's type definition, copy from the base */
@@ -2325,18 +2316,7 @@
 #undef CHECK_NODE
 }
 
-/**
- * @brief Connect the node into the siblings list and check its name uniqueness. Also,
- * keep specific order of augments targetting the same node.
- *
- * @param[in] ctx Compile context
- * @param[in] parent Parent node holding the children list, in case of node from a choice's case,
- * the choice itself is expected instead of a specific case node.
- * @param[in] node Schema node to connect into the list.
- * @return LY_ERR value - LY_SUCCESS or LY_EEXIST.
- * In case of LY_EEXIST, the node is actually kept in the tree, so do not free it directly.
- */
-static LY_ERR
+LY_ERR
 lys_compile_node_connect(struct lysc_ctx *ctx, struct lysc_node *parent, struct lysc_node *node)
 {
     struct lysc_node **children, *anchor = NULL;
@@ -2443,8 +2423,7 @@
         struct lysc_node **list;
 
         if (ctx->ext) {
-            /* container matches all data nodes */
-            lysc_ext_substmt(ctx->ext, LY_STMT_CONTAINER, (void **)&list);
+            lyplg_ext_get_storage_p(ctx->ext, LY_STMT_DATA_NODE_MASK, (const void ***)&list);
         } else if (node->nodetype == LYS_RPC) {
             list = (struct lysc_node **)&ctx->cur_mod->compiled->rpcs;
         } else if (node->nodetype == LYS_NOTIF) {
@@ -2638,14 +2617,6 @@
     return ret;
 }
 
-/**
- * @brief Compile parsed action's input/output node information.
- * @param[in] ctx Compile context
- * @param[in] pnode Parsed inout node.
- * @param[in,out] node Pre-prepared structure from lys_compile_node_() with filled generic node information
- * is enriched with the inout-specific information.
- * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
- */
 LY_ERR
 lys_compile_node_action_inout(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
 {
@@ -2675,13 +2646,14 @@
 
 /**
  * @brief Compile parsed action node information.
+ *
  * @param[in] ctx Compile context
  * @param[in] pnode Parsed action node.
  * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
  * is enriched with the action-specific information.
  * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
  */
-LY_ERR
+static LY_ERR
 lys_compile_node_action(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
 {
     LY_ERR ret;
@@ -2740,7 +2712,7 @@
  * is enriched with the action-specific information.
  * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
  */
-LY_ERR
+static LY_ERR
 lys_compile_node_notif(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -3591,7 +3563,7 @@
 
     if (any->flags & LYS_CONFIG_W) {
         LOGVRB("Use of %s to define configuration data is not recommended. %s",
-                ly_stmt2str(any->nodetype == LYS_ANYDATA ? LY_STMT_ANYDATA : LY_STMT_ANYXML), ctx->path);
+                lyplg_ext_stmt2str(any->nodetype == LYS_ANYDATA ? LY_STMT_ANYDATA : LY_STMT_ANYXML), ctx->path);
     }
 done:
     return ret;
@@ -3695,7 +3667,7 @@
 {
     struct lysp_node *pnode;
     struct lysp_node_grp *grp;
-    struct lysp_node_grp * const *ext_grp;
+    const struct lysp_node_grp *ext_grp;
     LY_ARRAY_COUNT_TYPE u;
     const char *id, *name, *prefix, *local_pref;
     size_t prefix_len, name_len;
@@ -3721,8 +3693,8 @@
 
         /* if in an extension, search possible groupings in it */
         if (ctx->ext) {
-            ext_grp = lys_compile_ext_instance_get_storage(ctx->ext, LY_STMT_GROUPING);
-            if (ext_grp && (grp = match_grouping(*ext_grp, name))) {
+            lyplg_ext_parsed_get_storage(ctx->ext, LY_STMT_GROUPING, (const void **)&ext_grp);
+            if ((grp = match_grouping(ext_grp, name))) {
                 found = ctx->pmod;
             }
         }
@@ -3730,8 +3702,7 @@
         /* foreign module, find it first */
         mod = ly_resolve_prefix(ctx->ctx, prefix, prefix_len, LY_VALUE_SCHEMA, ctx->pmod);
         if (!mod) {
-            LOGVAL(ctx->ctx, LYVE_REFERENCE,
-                    "Invalid prefix used for grouping reference.", uses_p->name);
+            LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid prefix used for grouping reference.", uses_p->name);
             return LY_EVALID;
         }
         pmod = mod->parsed;
@@ -3752,8 +3723,7 @@
         }
     }
     if (!found) {
-        LOGVAL(ctx->ctx, LYVE_SEMANTICS,
-                "Grouping \"%s\" referenced by a uses statement not found.", uses_p->name);
+        LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Grouping \"%s\" referenced by a uses statement not found.", uses_p->name);
         return LY_EVALID;
     }
 
@@ -3958,6 +3928,10 @@
     }
     LY_CHECK_GOTO(rc, cleanup);
 
+    /* compile uses and grouping extensions into the parent */
+    COMPILE_EXTS_GOTO(ctx, uses_p->exts, parent->exts, parent, rc, cleanup);
+    COMPILE_EXTS_GOTO(ctx, grp->exts, parent->exts, parent, rc, cleanup);
+
 cleanup:
     /* restore previous context */
     ctx->compile_opts = opt_prev;
diff --git a/src/schema_compile_node.h b/src/schema_compile_node.h
index d1f050d..ae2ac5f 100644
--- a/src/schema_compile_node.h
+++ b/src/schema_compile_node.h
@@ -40,7 +40,7 @@
  * for the first call.
  * @return LY_ERR value.
  */
-LY_ERR lys_compile_when(struct lysc_ctx *ctx, struct lysp_when *when_p, uint16_t parent_flags,
+LY_ERR lys_compile_when(struct lysc_ctx *ctx, const struct lysp_when *when_p, uint16_t parent_flags,
         const struct lysc_node *compiled_parent, const struct lysc_node *ctx_node, struct lysc_node *node,
         struct lysc_when **when_c);
 
@@ -52,7 +52,23 @@
  * @param[in,out] must Prepared (empty) compiled must structure to fill.
  * @return LY_ERR value.
  */
-LY_ERR lys_compile_must(struct lysc_ctx *ctx, struct lysp_restr *must_p, struct lysc_must *must);
+LY_ERR lys_compile_must(struct lysc_ctx *ctx, const struct lysp_restr *must_p, struct lysc_must *must);
+
+/**
+ * @brief Compile the parsed range restriction.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] range_p Parsed range structure to compile.
+ * @param[in] basetype Base YANG built-in type of the node with the range restriction.
+ * @param[in] length_restr Flag to distinguish between range and length restrictions. Only for logging.
+ * @param[in] frdigits The fraction-digits value in case of LY_TYPE_DEC64 basetype.
+ * @param[in] base_range Range restriction of the type from which the current type is derived. The current
+ * range restriction must be more restrictive than the base_range.
+ * @param[in,out] range Pointer to the created current range structure.
+ * @return LY_ERR value.
+ */
+LY_ERR lys_compile_type_range(struct lysc_ctx *ctx, const struct lysp_restr *range_p, LY_DATA_TYPE basetype,
+        ly_bool length_restr, uint8_t frdigits, struct lysc_range *base_range, struct lysc_range **range);
 
 /**
  * @brief Checks pattern syntax.
@@ -74,10 +90,23 @@
  * @param[out] patterns Pointer to the storage for the patterns of the current type.
  * @return LY_ERR LY_SUCCESS, LY_EMEM, LY_EVALID.
  */
-LY_ERR lys_compile_type_patterns(struct lysc_ctx *ctx, struct lysp_restr *patterns_p,
+LY_ERR lys_compile_type_patterns(struct lysc_ctx *ctx, const struct lysp_restr *patterns_p,
         struct lysc_pattern **base_patterns, struct lysc_pattern ***patterns);
 
 /**
+ * @brief Compile parsed type's enum structures (for enumeration and bits types).
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] enums_p Array of the parsed enum structures to compile.
+ * @param[in] basetype Base YANG built-in type from which the current type is derived. Only LY_TYPE_ENUM and LY_TYPE_BITS are expected.
+ * @param[in] base_enums Array of the compiled enums information from the (latest) base type to check if the current enums are compatible.
+ * @param[out] bitenums Newly created array of the compiled bitenums information for the current type.
+ * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
+ */
+LY_ERR lys_compile_type_enums(struct lysc_ctx *ctx, const struct lysp_type_enum *enums_p, LY_DATA_TYPE basetype,
+        struct lysc_type_bitenum_item *base_enums, struct lysc_type_bitenum_item **bitenums);
+
+/**
  * @brief Compile information about the leaf/leaf-list's type.
  *
  * @param[in] ctx Compile context.
@@ -91,10 +120,34 @@
  * @return LY_ERR value.
  */
 LY_ERR lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags,
-        const char *context_name, struct lysp_type *type_p, struct lysc_type **type, const char **units,
+        const char *context_name, const struct lysp_type *type_p, struct lysc_type **type, const char **units,
         struct lysp_qname **dflt);
 
 /**
+ * @brief Connect the node into the siblings list and check its name uniqueness. Also,
+ * keep specific order of augments targetting the same node.
+ *
+ * @param[in] ctx Compile context
+ * @param[in] parent Parent node holding the children list, in case of node from a choice's case,
+ * the choice itself is expected instead of a specific case node.
+ * @param[in] node Schema node to connect into the list.
+ * @return LY_ERR value - LY_SUCCESS or LY_EEXIST.
+ * In case of LY_EEXIST, the node is actually kept in the tree, so do not free it directly.
+ */
+LY_ERR lys_compile_node_connect(struct lysc_ctx *ctx, struct lysc_node *parent, struct lysc_node *node);
+
+/**
+ * @brief Compile parsed action's input/output node information.
+ *
+ * @param[in] ctx Compile context
+ * @param[in] pnode Parsed inout node.
+ * @param[in,out] node Pre-prepared structure from lys_compile_node_() with filled generic node information
+ * is enriched with the inout-specific information.
+ * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
+ */
+LY_ERR lys_compile_node_action_inout(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node);
+
+/**
  * @brief Find the node according to the given descendant/absolute schema nodeid.
  * Used in unique, refine and augment statements.
  *
diff --git a/src/schema_features.c b/src/schema_features.c
index f70968f..dca998e 100644
--- a/src/schema_features.c
+++ b/src/schema_features.c
@@ -310,7 +310,7 @@
 #define LYS_IFF_RP 0x08 /**< Additional, temporary, value of @ref ifftokens: ) */
 
 static LY_ERR
-lys_compile_iffeature(const struct ly_ctx *ctx, struct lysp_qname *qname, struct lysc_iffeature *iff)
+lys_compile_iffeature(const struct ly_ctx *ctx, const struct lysp_qname *qname, struct lysc_iffeature *iff)
 {
     LY_ERR rc = LY_SUCCESS;
     const char *c = qname->str;
@@ -501,7 +501,7 @@
 }
 
 LY_ERR
-lys_eval_iffeatures(const struct ly_ctx *ctx, struct lysp_qname *iffeatures, ly_bool *enabled)
+lys_eval_iffeatures(const struct ly_ctx *ctx, const struct lysp_qname *iffeatures, ly_bool *enabled)
 {
     LY_ERR ret;
     LY_ARRAY_COUNT_TYPE u;
diff --git a/src/schema_features.h b/src/schema_features.h
index f12dc54..c73561f 100644
--- a/src/schema_features.h
+++ b/src/schema_features.h
@@ -30,7 +30,7 @@
  * @return LY_SUCCESS on success.
  * @return LY_ERR on error.
  */
-LY_ERR lys_eval_iffeatures(const struct ly_ctx *ctx, struct lysp_qname *iffeatures, ly_bool *enabled);
+LY_ERR lys_eval_iffeatures(const struct ly_ctx *ctx, const struct lysp_qname *iffeatures, ly_bool *enabled);
 
 /**
  * @brief Check whether all enabled features have their if-features satisfied.
diff --git a/src/set.c b/src/set.c
index d4836b8..1b8bfa5 100644
--- a/src/set.c
+++ b/src/set.c
@@ -76,7 +76,7 @@
 }
 
 LIBYANG_API_DEF ly_bool
-ly_set_contains(const struct ly_set *set, void *object, uint32_t *index_p)
+ly_set_contains(const struct ly_set *set, const void *object, uint32_t *index_p)
 {
     LY_CHECK_ARG_RET(NULL, set, 0);
 
@@ -95,7 +95,7 @@
 }
 
 LIBYANG_API_DEF LY_ERR
-ly_set_dup(const struct ly_set *set, void *(*duplicator)(void *obj), struct ly_set **newset_p)
+ly_set_dup(const struct ly_set *set, void *(*duplicator)(const void *obj), struct ly_set **newset_p)
 {
     struct ly_set *newset;
     uint32_t u;
@@ -126,7 +126,7 @@
 }
 
 LIBYANG_API_DEF LY_ERR
-ly_set_add(struct ly_set *set, void *object, ly_bool list, uint32_t *index_p)
+ly_set_add(struct ly_set *set, const void *object, ly_bool list, uint32_t *index_p)
 {
     void **new;
 
@@ -157,13 +157,13 @@
     if (index_p) {
         *index_p = set->count;
     }
-    set->objs[set->count++] = object;
+    set->objs[set->count++] = (void *)object;
 
     return LY_SUCCESS;
 }
 
 LIBYANG_API_DEF LY_ERR
-ly_set_merge(struct ly_set *trg, const struct ly_set *src, ly_bool list, void *(*duplicator)(void *obj))
+ly_set_merge(struct ly_set *trg, const struct ly_set *src, ly_bool list, void *(*duplicator)(const void *obj))
 {
     uint32_t u;
     void *obj;
diff --git a/src/set.h b/src/set.h
index 636d3d0..3f79916 100644
--- a/src/set.h
+++ b/src/set.h
@@ -76,7 +76,7 @@
  * @return LY_EMEM in case of memory allocation failure.
  * @return LY_EINVAL in case of invalid parameters.
  */
-LIBYANG_API_DECL LY_ERR ly_set_dup(const struct ly_set *set, void *(*duplicator)(void *obj), struct ly_set **newset_p);
+LIBYANG_API_DECL LY_ERR ly_set_dup(const struct ly_set *set, void *(*duplicator)(const void *obj), struct ly_set **newset_p);
 
 /**
  * @brief Add an object into the set
@@ -91,7 +91,7 @@
  * @return LY_EINVAL in case of invalid input parameters.
  * @return LY_EMEM in case of memory allocation failure.
  */
-LIBYANG_API_DECL LY_ERR ly_set_add(struct ly_set *set, void *object, ly_bool list, uint32_t *index_p);
+LIBYANG_API_DECL LY_ERR ly_set_add(struct ly_set *set, const void *object, ly_bool list, uint32_t *index_p);
 
 /**
  * @brief Add all objects from \p src to \p trg.
@@ -108,7 +108,7 @@
  * @return LY_EINVAL in case of invalid input parameters.
  * @return LY_EMEM in case of memory allocation failure.
  */
-LIBYANG_API_DECL LY_ERR ly_set_merge(struct ly_set *trg, const struct ly_set *src, ly_bool list, void *(*duplicator)(void *obj));
+LIBYANG_API_DECL LY_ERR ly_set_merge(struct ly_set *trg, const struct ly_set *src, ly_bool list, void *(*duplicator)(const void *obj));
 
 /**
  * @brief Learn whether the set contains the specified object.
@@ -118,7 +118,7 @@
  * @param[out] index_p Optional pointer to return index of the searched @p object.
  * @return Boolean value whether the @p object was found in the @p set.
  */
-LIBYANG_API_DECL ly_bool ly_set_contains(const struct ly_set *set, void *object, uint32_t *index_p);
+LIBYANG_API_DECL ly_bool ly_set_contains(const struct ly_set *set, const void *object, uint32_t *index_p);
 
 /**
  * @brief Remove all objects from the set, but keep the set container for further use.
diff --git a/src/tree_data.c b/src/tree_data.c
index e416ea0..ceaea54 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -732,7 +732,7 @@
 }
 
 LIBYANG_API_DEF LY_ERR
-lyd_insert_ext(struct lyd_node *parent, struct lyd_node *first)
+lyplg_ext_insert(struct lyd_node *parent, struct lyd_node *first)
 {
     struct lyd_node *iter;
 
@@ -951,14 +951,14 @@
 {
     LY_ERR ret = LY_SUCCESS;
     struct lysc_ext_instance *ant = NULL;
-    const struct lysc_type **ant_type;
+    const struct lysc_type *ant_type;
     struct lyd_meta *mt, *last;
     LY_ARRAY_COUNT_TYPE u;
 
     assert((parent || meta) && mod);
 
     LY_ARRAY_FOR(mod->compiled->exts, u) {
-        if (!strncmp(mod->compiled->exts[u].def->plugin->id, "libyang 2 - metadata", 20) &&
+        if (!strncmp(mod->compiled->exts[u].def->plugin->id, "ly2 metadata", 12) &&
                 !ly_strncmp(mod->compiled->exts[u].argument, name, name_len)) {
             /* we have the annotation definition */
             ant = &mod->compiled->exts[u];
@@ -977,8 +977,8 @@
     LY_CHECK_ERR_GOTO(!mt, LOGMEM(mod->ctx); ret = LY_EMEM, cleanup);
     mt->parent = parent;
     mt->annotation = ant;
-    ant_type = ant->substmts[ANNOTATION_SUBSTMT_TYPE].storage;
-    ret = lyd_value_store(mod->ctx, &mt->value, *ant_type, value, value_len, dynamic, format, prefix_data, hints,
+    lyplg_ext_get_storage(ant, LY_STMT_TYPE, (const void **)&ant_type);
+    ret = lyd_value_store(mod->ctx, &mt->value, ant_type, value, value_len, dynamic, format, prefix_data, hints,
             ctx_node, incomplete);
     LY_CHECK_ERR_GOTO(ret, free(mt), cleanup);
     ret = lydict_insert(mod->ctx, name, name_len, &mt->name);
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 345c5db..3be476d 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -48,98 +48,6 @@
 #include "tree_schema_internal.h"
 #include "xpath.h"
 
-/**
- * @brief information about YANG statements
- */
-struct stmt_info_s stmt_attr_info[] = {
-    [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},
-};
-
-LIBYANG_API_DEF const char *
-ly_stmt2str(enum ly_stmt stmt)
-{
-    if (stmt == LY_STMT_EXTENSION_INSTANCE) {
-        return "extension instance";
-    } else {
-        return stmt_attr_info[stmt].name;
-    }
-}
-
-
 const char * const ly_devmod_list[] = {
     [LYS_DEV_NOT_SUPPORTED] = "not-supported",
     [LYS_DEV_ADD] = "add",
@@ -232,22 +140,22 @@
  * be from an augment. If the @p ext is provided, the function is locked inside the schema tree defined in the
  * extension instance.
  *
- * ::lys_getnext_() is supposed to be called sequentially. In the first call, the \p last parameter is usually NULL
- * and function starts returning i) the first \p parent's child or ii) the first top level element specified in the
- * given extension (if provided) or iii) the first top level element of the \p module.
- * Consequent calls suppose to provide the previously returned node as the \p last parameter and still the same
- * \p parent and \p module parameters.
+ * ::lys_getnext_() is supposed to be called sequentially. In the first call, the @p last parameter is usually NULL
+ * and function starts returning i) the first @p parent's child or ii) the first top level element specified in the
+ * given extension (if provided) or iii) the first top level element of the @p module.
+ * Consequent calls suppose to provide the previously returned node as the @p last parameter and still the same
+ * @p parent and @p module parameters.
  *
  * Without options, the function is used to traverse only the schema nodes that can be paired with corresponding
- * data nodes in a data tree. By setting some \p options the behavior can be modified to the extent that
+ * data nodes in a data tree. By setting some @p options the behavior can be modified to the extent that
  * all the schema nodes are iteratively returned.
  *
  * @param[in] last Previously returned schema tree node, or NULL in case of the first call.
  * @param[in] parent Parent of the subtree where the function starts processing.
- * @param[in] module In case of iterating on top level elements, the \p parent is NULL and
+ * @param[in] module In case of iterating on top level elements, the @p parent is NULL and
  * module must be specified.
  * @param[in] ext The extension instance to provide a separate schema tree. To consider the top level elements in the tree,
- * the \p parent must be NULL. Anyway, at least one of @p parent, @p module and @p ext parameters must be specified.
+ * the @p parent must be NULL. Anyway, at least one of @p parent, @p module and @p ext parameters must be specified.
  * @param[in] options [ORed options](@ref sgetnextflags).
  * @return Next schema tree node that can be instantiated in a data tree, NULL in case there is no such element.
  */
@@ -257,7 +165,6 @@
 {
     const struct lysc_node *next = NULL;
     ly_bool action_flag = 0, notif_flag = 0;
-    struct lysc_node **data_p = NULL;
 
     LY_CHECK_ARG_RET(NULL, parent || module || ext, NULL);
 
@@ -272,8 +179,8 @@
         } else {
             /* top level data */
             if (ext) {
-                lysc_ext_substmt(ext, LY_STMT_CONTAINER /* matches all nodes */, (void **)&data_p);
-                next = last = data_p ? *data_p : NULL;
+                lyplg_ext_get_storage(ext, LY_STMT_DATA_NODE_MASK, (const void **)&last);
+                next = last;
             } else {
                 next = last = module->data;
             }
@@ -298,15 +205,13 @@
 repeat:
     if (!next) {
         /* possibly go back to parent */
-        data_p = NULL;
         if (last && (last->parent != parent)) {
             last = last->parent;
             goto next;
         } else if (!action_flag) {
             action_flag = 1;
             if (ext) {
-                lysc_ext_substmt(ext, LY_STMT_RPC /* matches also actions */, (void **)&data_p);
-                next = data_p ? *data_p : NULL;
+                lyplg_ext_get_storage(ext, LY_STMT_OP_MASK, (const void **)&next);
             } else if (parent) {
                 next = (struct lysc_node *)lysc_node_actions(parent);
             } else {
@@ -315,8 +220,7 @@
         } else if (!notif_flag) {
             notif_flag = 1;
             if (ext) {
-                lysc_ext_substmt(ext, LY_STMT_NOTIFICATION, (void **)&data_p);
-                next = data_p ? *data_p : NULL;
+                lyplg_ext_get_storage(ext, LY_STMT_NOTIFICATION, (const void **)&next);
             } else if (parent) {
                 next = (struct lysc_node *)lysc_node_notifs(parent);
             } else {
@@ -1278,6 +1182,102 @@
 }
 
 /**
+ * @brief Generate path of the given paresed node.
+ *
+ * @param[in] node Schema path of this node will be generated.
+ * @param[in] parent Build relative path only until this parent is found. If NULL, the full absolute path is printed.
+ * @return NULL in case of memory allocation error, path of the node otherwise.
+ * In case the @p buffer is NULL, the returned string is dynamically allocated and caller is responsible to free it.
+ */
+static char *
+lysp_path_until(const struct lysp_node *node, const struct lysp_node *parent, const struct lysp_module *pmod)
+{
+    const struct lysp_node *iter, *par;
+    char *path = NULL, *s;
+    const char *slash;
+    int len = 0;
+
+    for (iter = node; iter && (iter != parent) && (len >= 0); iter = iter->parent) {
+        if (parent && (iter->parent == parent)) {
+            slash = "";
+        } else {
+            slash = "/";
+        }
+
+        s = path;
+        par = iter->parent;
+        if (!par) {
+            /* print prefix */
+            len = asprintf(&path, "%s%s:%s%s", slash, pmod->mod->name, iter->name, s ? s : "");
+        } else {
+            /* prefix is the same as in parent */
+            len = asprintf(&path, "%s%s%s", slash, iter->name, s ? s : "");
+        }
+        free(s);
+    }
+
+    if (len < 0) {
+        free(path);
+        path = NULL;
+    } else if (len == 0) {
+        path = strdup("/");
+    }
+
+    return path;
+}
+
+/**
+ * @brief Build log path for a parsed extension instance.
+ *
+ * @param[in] pcxt Parse context.
+ * @param[in] ext Parsed extension instance.
+ * @param[out] path Generated path.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lysp_resolve_ext_instance_log_path(const struct lysp_ctx *pctx, const struct lysp_ext_instance *ext, char **path)
+{
+    char *buf = NULL;
+    uint32_t used = 0, size = 0;
+
+    if (ext->parent_stmt & LY_STMT_NODE_MASK) {
+        /* parsed node path */
+        buf = lysp_path_until(ext->parent, NULL, PARSER_CUR_PMOD(pctx));
+        LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
+        size = used = strlen(buf);
+
+        /* slash */
+        size += 1;
+        buf = realloc(buf, size + 1);
+        LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
+        used += sprintf(buf + used, "/");
+    } else {
+        /* module */
+        size += 1 + strlen(PARSER_CUR_PMOD(pctx)->mod->name) + 1;
+        buf = realloc(buf, size + 1);
+        LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
+        used += sprintf(buf + used, "/%s:", PARSER_CUR_PMOD(pctx)->mod->name);
+    }
+
+    /* extension name */
+    size += 12 + strlen(ext->name) + 2;
+    buf = realloc(buf, size + 1);
+    LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
+    used += sprintf(buf + used, "{extension='%s'}", ext->name);
+
+    /* extension argument */
+    if (ext->argument) {
+        size += 1 + strlen(ext->argument);
+        buf = realloc(buf, size + 1);
+        LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
+        used += sprintf(buf + used, "/%s", ext->argument);
+    }
+
+    *path = buf;
+    return LY_SUCCESS;
+}
+
+/**
  * @brief Resolve (find) all extension instance records and finish their parsing.
  *
  * @param[in] pctx Parse context with all the parsed extension instances.
@@ -1286,30 +1286,69 @@
 static LY_ERR
 lysp_resolve_ext_instance_records(struct lysp_ctx *pctx)
 {
+    LY_ERR r;
+    struct lysf_ctx fctx = {.ctx = PARSER_CTX(pctx)};
     struct lysp_ext_instance *exts, *ext;
     const struct lys_module *mod;
-    const char *ptr;
     uint32_t i;
     LY_ARRAY_COUNT_TYPE u;
+    char *path = NULL;
 
+    /* first finish parsing all extension instances ... */
     for (i = 0; i < pctx->ext_inst.count; ++i) {
         exts = pctx->ext_inst.objs[i];
         LY_ARRAY_FOR(exts, u) {
             ext = &exts[u];
 
-            /* find the extension (definition) module */
-            ptr = strchr(ext->name, ':');
-            assert(ptr);
-            mod = ly_resolve_prefix(PARSER_CTX(pctx), ext->name, ptr - ext->name, ext->format, ext->prefix_data);
-            if (!mod) {
-                LOGVAL(PARSER_CTX(pctx), LYVE_SYNTAX, "Unknown prefix \"%*.s\" used for an extension instance.",
-                        (int)(ptr - ext->name), ext->name);
-                return LY_ENOTFOUND;
-            }
+            /* find the extension definition */
+            LY_CHECK_RET(lysp_ext_find_definition(PARSER_CTX(pctx), ext, &mod, &ext->def));
+
+            /* resolve the argument, if needed */
+            LY_CHECK_RET(lysp_ext_instance_resolve_argument(PARSER_CTX(pctx), ext));
 
             /* find the extension record, if any */
-            ++ptr;
-            ext->record = lyplg_ext_record_find(mod->name, mod->revision, ptr);
+            ext->record = lyplg_ext_record_find(mod->name, mod->revision, ext->def->name);
+        }
+    }
+
+    /* ... then call the parse callback */
+    for (i = 0; i < pctx->ext_inst.count; ++i) {
+        exts = pctx->ext_inst.objs[i];
+        u = 0;
+        while (u < LY_ARRAY_COUNT(exts)) {
+            ext = &exts[u];
+            if (!ext->record || !ext->record->plugin.parse) {
+                goto next_iter;
+            }
+
+            /* set up log path */
+            if ((r = lysp_resolve_ext_instance_log_path(pctx, ext, &path))) {
+                return r;
+            }
+            LOG_LOCINIT(NULL, NULL, path, NULL);
+
+            /* parse */
+            r = ext->record->plugin.parse(pctx, ext);
+
+            LOG_LOCBACK(0, 0, 1, 0);
+            free(path);
+
+            if (r == LY_ENOT) {
+                /* instance should be ignored, remove it */
+                lysp_ext_instance_free(&fctx, ext);
+                LY_ARRAY_DECREMENT(exts);
+                if (u < LY_ARRAY_COUNT(exts)) {
+                    /* replace by the last item */
+                    *ext = exts[LY_ARRAY_COUNT(exts)];
+                } /* else if there are no more items, leave the empty array, we are not able to free it */
+                continue;
+            } else if (r) {
+                /* error */
+                return r;
+            }
+
+next_iter:
+            ++u;
         }
     }
 
@@ -1413,31 +1452,32 @@
 /**
  * @brief Add ietf-netconf metadata to the parsed module. Operation, filter, and select are added.
  *
+ * @param[in] pctx Parse context.
  * @param[in] mod Parsed module to add to.
  * @return LY_SUCCESS on success.
  * @return LY_ERR on error.
  */
 static LY_ERR
-lysp_add_internal_ietf_netconf(struct lysp_module *mod)
+lysp_add_internal_ietf_netconf(struct lysp_ctx *pctx, struct lysp_module *mod)
 {
-    struct lysp_ext_instance *ext_p;
+    struct lysp_ext_instance *extp;
     struct lysp_stmt *stmt;
     struct lysp_import *imp;
 
     /*
      * 1) edit-config's operation
      */
-    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, ext_p, LY_EMEM);
-    LY_CHECK_ERR_RET(!ext_p, LOGMEM(mod->mod->ctx), LY_EMEM);
-    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &ext_p->name));
-    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "operation", 0, &ext_p->argument));
-    ext_p->format = LY_VALUE_SCHEMA;
-    ext_p->prefix_data = mod;
-    ext_p->flags = LYS_INTERNAL;
-    ext_p->parent_stmt = LY_STMT_MODULE;
-    ext_p->parent_stmt_index = 0;
+    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, extp, LY_EMEM);
+    LY_CHECK_ERR_RET(!extp, LOGMEM(mod->mod->ctx), LY_EMEM);
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &extp->name));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "operation", 0, &extp->argument));
+    extp->format = LY_VALUE_SCHEMA;
+    extp->prefix_data = mod;
+    extp->parent = mod;
+    extp->parent_stmt = LY_STMT_MODULE;
+    extp->flags = LYS_INTERNAL;
 
-    ext_p->child = stmt = calloc(1, sizeof *ext_p->child);
+    extp->child = stmt = calloc(1, sizeof *extp->child);
     LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
     LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
     LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enumeration", 0, &stmt->arg));
@@ -1493,17 +1533,17 @@
     /*
      * 2) filter's type
      */
-    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, ext_p, LY_EMEM);
-    LY_CHECK_ERR_RET(!ext_p, LOGMEM(mod->mod->ctx), LY_EMEM);
-    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &ext_p->name));
-    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &ext_p->argument));
-    ext_p->format = LY_VALUE_SCHEMA;
-    ext_p->prefix_data = mod;
-    ext_p->flags = LYS_INTERNAL;
-    ext_p->parent_stmt = LY_STMT_MODULE;
-    ext_p->parent_stmt_index = 0;
+    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, extp, LY_EMEM);
+    LY_CHECK_ERR_RET(!extp, LOGMEM(mod->mod->ctx), LY_EMEM);
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &extp->name));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &extp->argument));
+    extp->format = LY_VALUE_SCHEMA;
+    extp->prefix_data = mod;
+    extp->parent = mod;
+    extp->parent_stmt = LY_STMT_MODULE;
+    extp->flags = LYS_INTERNAL;
 
-    ext_p->child = stmt = calloc(1, sizeof *ext_p->child);
+    extp->child = stmt = calloc(1, sizeof *extp->child);
     LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
     LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
     LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enumeration", 0, &stmt->arg));
@@ -1544,17 +1584,17 @@
     /*
      * 3) filter's select
      */
-    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, ext_p, LY_EMEM);
-    LY_CHECK_ERR_RET(!ext_p, LOGMEM(mod->mod->ctx), LY_EMEM);
-    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &ext_p->name));
-    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "select", 0, &ext_p->argument));
-    ext_p->format = LY_VALUE_SCHEMA;
-    ext_p->prefix_data = mod;
-    ext_p->flags = LYS_INTERNAL;
-    ext_p->parent_stmt = LY_STMT_MODULE;
-    ext_p->parent_stmt_index = 0;
+    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, extp, LY_EMEM);
+    LY_CHECK_ERR_RET(!extp, LOGMEM(mod->mod->ctx), LY_EMEM);
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &extp->name));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "select", 0, &extp->argument));
+    extp->format = LY_VALUE_SCHEMA;
+    extp->prefix_data = mod;
+    extp->parent = mod;
+    extp->parent_stmt = LY_STMT_MODULE;
+    extp->flags = LYS_INTERNAL;
 
-    ext_p->child = stmt = calloc(1, sizeof *ext_p->child);
+    extp->child = stmt = calloc(1, sizeof *extp->child);
     LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
     LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
     LY_CHECK_RET(lydict_insert(mod->mod->ctx, "yang_:xpath1.0", 0, &stmt->arg));
@@ -1562,15 +1602,18 @@
     stmt->prefix_data = mod;
     stmt->kw = LY_STMT_TYPE;
 
+    if (LY_ARRAY_COUNT(mod->exts) == 3) {
+        /* first extension instances */
+        LY_CHECK_RET(ly_set_add(&pctx->ext_inst, mod->exts, 1, NULL));
+    }
+
     /* create new imports for the used prefixes */
     LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
-
     LY_CHECK_RET(lydict_insert(mod->mod->ctx, "ietf-yang-metadata", 0, &imp->name));
     LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_", 0, &imp->prefix));
     imp->flags = LYS_INTERNAL;
 
     LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
-
     LY_CHECK_RET(lydict_insert(mod->mod->ctx, "ietf-yang-types", 0, &imp->name));
     LY_CHECK_RET(lydict_insert(mod->mod->ctx, "yang_", 0, &imp->prefix));
     imp->flags = LYS_INTERNAL;
@@ -1581,31 +1624,31 @@
 /**
  * @brief Add ietf-netconf-with-defaults "default" metadata to the parsed module.
  *
+ * @param[in] pctx Parse context.
  * @param[in] mod Parsed module to add to.
  * @return LY_SUCCESS on success.
  * @return LY_ERR on error.
  */
 static LY_ERR
-lysp_add_internal_ietf_netconf_with_defaults(struct lysp_module *mod)
+lysp_add_internal_ietf_netconf_with_defaults(struct lysp_ctx *pctx, struct lysp_module *mod)
 {
-    struct lysp_ext_instance *ext_p;
+    struct lysp_ext_instance *extp;
     struct lysp_stmt *stmt;
     struct lysp_import *imp;
 
     /* add new extension instance */
-    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, ext_p, LY_EMEM);
+    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, extp, LY_EMEM);
 
     /* fill in the extension instance fields */
-    LY_CHECK_ERR_RET(!ext_p, LOGMEM(mod->mod->ctx), LY_EMEM);
-    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &ext_p->name));
-    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "default", 0, &ext_p->argument));
-    ext_p->format = LY_VALUE_SCHEMA;
-    ext_p->prefix_data = mod;
-    ext_p->flags = LYS_INTERNAL;
-    ext_p->parent_stmt = LY_STMT_MODULE;
-    ext_p->parent_stmt_index = 0;
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &extp->name));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "default", 0, &extp->argument));
+    extp->format = LY_VALUE_SCHEMA;
+    extp->prefix_data = mod;
+    extp->parent = mod;
+    extp->parent_stmt = LY_STMT_MODULE;
+    extp->flags = LYS_INTERNAL;
 
-    ext_p->child = stmt = calloc(1, sizeof *ext_p->child);
+    extp->child = stmt = calloc(1, sizeof *extp->child);
     LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
     LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
     LY_CHECK_RET(lydict_insert(mod->mod->ctx, "boolean", 0, &stmt->arg));
@@ -1613,9 +1656,13 @@
     stmt->prefix_data = mod;
     stmt->kw = LY_STMT_TYPE;
 
+    if (LY_ARRAY_COUNT(mod->exts) == 1) {
+        /* first extension instance */
+        LY_CHECK_RET(ly_set_add(&pctx->ext_inst, mod->exts, 1, NULL));
+    }
+
     /* create new import for the used prefix */
     LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
-
     LY_CHECK_RET(lydict_insert(mod->mod->ctx, "ietf-yang-metadata", 0, &imp->name));
     LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_", 0, &imp->prefix));
     imp->flags = LYS_INTERNAL;
@@ -1759,9 +1806,9 @@
 
     /* add internal data in case specific modules were parsed */
     if (!strcmp(mod->name, "ietf-netconf")) {
-        LY_CHECK_GOTO(ret = lysp_add_internal_ietf_netconf(mod->parsed), cleanup);
+        LY_CHECK_GOTO(ret = lysp_add_internal_ietf_netconf(pctx, mod->parsed), cleanup);
     } else if (!strcmp(mod->name, "ietf-netconf-with-defaults")) {
-        LY_CHECK_GOTO(ret = lysp_add_internal_ietf_netconf_with_defaults(mod->parsed), cleanup);
+        LY_CHECK_GOTO(ret = lysp_add_internal_ietf_netconf_with_defaults(pctx, mod->parsed), cleanup);
     }
 
     /* add the module into newly created module set, will also be freed from there on any error */
diff --git a/src/tree_schema_common.c b/src/tree_schema_common.c
index 427d404..e82f6b9 100644
--- a/src/tree_schema_common.c
+++ b/src/tree_schema_common.c
@@ -40,6 +40,87 @@
 #include "tree_schema.h"
 #include "tree_schema_internal.h"
 
+/**
+ * @brief information about YANG statements
+ */
+struct stmt_info_s stmt_attr_info[] = {
+    [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},
+};
+
 LY_ERR
 lysp_check_prefix(struct lysp_ctx *ctx, struct lysp_import *imports, const char *module_prefix, const char **value)
 {
@@ -256,7 +337,7 @@
 {
     const char *str, *name;
     struct lysp_tpdf *typedefs;
-    const struct lysp_tpdf **ext_typedefs;
+    const struct lysp_tpdf *ext_typedefs;
     const struct lys_module *mod;
     const struct lysp_module *local_module;
     LY_ARRAY_COUNT_TYPE u, v;
@@ -300,8 +381,8 @@
 
         if (ext) {
             /* search typedefs directly in the extension */
-            ext_typedefs = (void *)lys_compile_ext_instance_get_storage(ext, LY_STMT_TYPEDEF);
-            if (ext_typedefs && (*tpdf = lysp_typedef_match(name, *ext_typedefs))) {
+            lyplg_ext_parsed_get_storage(ext, LY_STMT_TYPEDEF, (const void **)&ext_typedefs);
+            if ((*tpdf = lysp_typedef_match(name, ext_typedefs))) {
                 /* match */
                 return LY_SUCCESS;
             }
@@ -1348,43 +1429,6 @@
     }
 }
 
-LIBYANG_API_DEF enum ly_stmt
-lys_nodetype2stmt(uint16_t nodetype)
-{
-    switch (nodetype) {
-    case LYS_CONTAINER:
-        return LY_STMT_CONTAINER;
-    case LYS_CHOICE:
-        return LY_STMT_CHOICE;
-    case LYS_LEAF:
-        return LY_STMT_LEAF;
-    case LYS_LEAFLIST:
-        return LY_STMT_LEAF_LIST;
-    case LYS_LIST:
-        return LY_STMT_LIST;
-    case LYS_ANYXML:
-        return LY_STMT_ANYXML;
-    case LYS_ANYDATA:
-        return LY_STMT_ANYDATA;
-    case LYS_CASE:
-        return LY_STMT_CASE;
-    case LYS_RPC:
-        return LY_STMT_RPC;
-    case LYS_ACTION:
-        return LY_STMT_ACTION;
-    case LYS_NOTIF:
-        return LY_STMT_NOTIFICATION;
-    case LYS_USES:
-        return LY_STMT_USES;
-    case LYS_INPUT:
-        return LY_STMT_INPUT;
-    case LYS_OUTPUT:
-        return LY_STMT_OUTPUT;
-    default:
-        return LY_STMT_NONE;
-    }
-}
-
 const char *
 lys_datatype2str(LY_DATA_TYPE basetype)
 {
@@ -2092,11 +2136,8 @@
     const struct lys_module *mod = NULL;
     const struct lysp_submodule *submod;
 
-    assert(ext_def);
-
-    *ext_def = NULL;
-    if (ext_mod) {
-        *ext_mod = NULL;
+    if (ext_def) {
+        *ext_def = NULL;
     }
 
     /* parse the prefix, the nodeid was previously already parsed and checked */
@@ -2104,7 +2145,7 @@
     ly_parse_nodeid(&tmp, &prefix, &pref_len, &name, &name_len);
 
     /* get module where the extension definition should be placed */
-    mod = ly_resolve_prefix(ctx, prefix, pref_len, ext->format, ext->prefix_data);
+    *ext_mod = mod = ly_resolve_prefix(ctx, prefix, pref_len, ext->format, ext->prefix_data);
     if (!mod) {
         LOGVAL(ctx, LYVE_REFERENCE, "Invalid prefix \"%.*s\" used for extension instance identifier.", (int)pref_len, prefix);
         return LY_EVALID;
@@ -2114,6 +2155,11 @@
         return LY_EVALID;
     }
 
+    if (!ext_def) {
+        /* we are done */
+        return LY_SUCCESS;
+    }
+
     /* find the parsed extension definition there */
     LY_ARRAY_FOR(mod->parsed->extensions, v) {
         if (!strcmp(name, mod->parsed->extensions[v].name)) {
@@ -2138,25 +2184,24 @@
         return LY_EVALID;
     }
 
-    if (ext_mod) {
-        *ext_mod = mod;
-    }
     return LY_SUCCESS;
 }
 
 LY_ERR
-lysp_ext_instance_resolve_argument(struct ly_ctx *ctx, struct lysp_ext_instance *ext_p, struct lysp_ext *ext_def)
+lysp_ext_instance_resolve_argument(struct ly_ctx *ctx, struct lysp_ext_instance *ext_p)
 {
-    if (!ext_def->argname || ext_p->argument) {
+    assert(ext_p->def);
+
+    if (!ext_p->def->argname || ext_p->argument) {
         /* nothing to do */
         return LY_SUCCESS;
     }
 
     if (ext_p->format == LY_VALUE_XML) {
-        /* Schema was parsed from YIN and an argument is expected, ... */
+        /* schema was parsed from YIN and an argument is expected, ... */
         struct lysp_stmt *stmt = NULL;
 
-        if (ext_def->flags & LYS_YINELEM_TRUE) {
+        if (ext_p->def->flags & LYS_YINELEM_TRUE) {
             /* ... argument was the first XML child element */
             for (stmt = ext_p->child; stmt && (stmt->flags & LYS_YIN_ATTR); stmt = stmt->next) {}
             if (stmt) {
@@ -2167,9 +2212,9 @@
 
                 arg = stmt->stmt;
                 ly_parse_nodeid(&arg, &prefix_arg, &prefix_arg_len, &name_arg, &name_arg_len);
-                if (ly_strncmp(ext_def->argname, name_arg, name_arg_len)) {
+                if (ly_strncmp(ext_p->def->argname, name_arg, name_arg_len)) {
                     LOGVAL(ctx, LYVE_SEMANTICS, "Extension instance \"%s\" expects argument element \"%s\" as its first XML child, "
-                            "but \"%.*s\" element found.", ext_p->name, ext_def->argname, (int)name_arg_len, name_arg);
+                            "but \"%.*s\" element found.", ext_p->name, ext_p->def->argname, (int)name_arg_len, name_arg);
                     return LY_EVALID;
                 }
 
@@ -2181,15 +2226,14 @@
                 if (ly_resolve_prefix(ctx, prefix_ext, prefix_ext_len, ext_p->format, ext_p->prefix_data) !=
                         ly_resolve_prefix(ctx, prefix_arg, prefix_arg_len, stmt->format, stmt->prefix_data)) {
                     LOGVAL(ctx, LYVE_SEMANTICS, "Extension instance \"%s\" element and its argument element \"%s\" are "
-                            "expected in the same namespace, but they differ.", ext_p->name, ext_def->argname);
+                            "expected in the same namespace, but they differ.", ext_p->name, ext_p->def->argname);
                     return LY_EVALID;
                 }
             }
         } else {
-            /* ... argument was one of the XML attributes which are represented as child stmt
-             * with LYS_YIN_ATTR flag */
+            /* ... argument was one of the XML attributes which are represented as child stmt with LYS_YIN_ATTR flag */
             for (stmt = ext_p->child; stmt && (stmt->flags & LYS_YIN_ATTR); stmt = stmt->next) {
-                if (!strcmp(stmt->stmt, ext_def->argname)) {
+                if (!strcmp(stmt->stmt, ext_p->def->argname)) {
                     /* this is the extension's argument */
                     break;
                 }
@@ -2204,8 +2248,8 @@
 
     if (!ext_p->argument) {
         /* missing extension's argument */
-        LOGVAL(ctx, LYVE_SEMANTICS, "Extension instance \"%s\" misses argument %s\"%s\".",
-                ext_p->name, (ext_def->flags & LYS_YINELEM_TRUE) ? "element " : "", ext_def->argname);
+        LOGVAL(ctx, LYVE_SEMANTICS, "Extension instance \"%s\" missing argument %s\"%s\".",
+                ext_p->name, (ext_p->def->flags & LYS_YINELEM_TRUE) ? "element " : "", ext_p->def->argname);
         return LY_EVALID;
     }
 
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);
         }
diff --git a/src/tree_schema_free.h b/src/tree_schema_free.h
index 778190b..d79164b 100644
--- a/src/tree_schema_free.h
+++ b/src/tree_schema_free.h
@@ -50,7 +50,7 @@
  * @param[in] ctx libyang context.
  * @param[in] qname Qualified name to free.
  */
-void lysp_qname_free(struct ly_ctx *ctx, struct lysp_qname *qname);
+void lysp_qname_free(const struct ly_ctx *ctx, struct lysp_qname *qname);
 
 /**
  * @brief Free the parsed extension instance structure.
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index a72ae74..31b5344 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -150,6 +150,7 @@
     struct ly_set grps_nodes;        /**< Set of nodes that contain grouping(s). Invalid in case of
                                           submodule, use ::lysp_ctx.main_ctx instead. */
     struct ly_set ext_inst;          /**< parsed extension instances to finish parsing */
+
     struct ly_set *parsed_mods;      /**< (sub)modules being parsed, the last one is the current */
     struct lysp_ctx *main_ctx;       /**< This pointer must not be NULL. If this context deals with the submodule,
                                           then should be set to the context of the module to which it belongs,
@@ -166,6 +167,7 @@
     struct ly_set grps_nodes;        /**< Set of nodes that contain grouping(s). Invalid in case of
                                           submodule, use ::lysp_ctx.main_ctx instead. */
     struct ly_set ext_inst;          /**< parsed extension instances to finish parsing */
+
     struct ly_set *parsed_mods;      /**< (sub)modules being parsed, the last one is the current */
     struct lysp_ctx *main_ctx;       /**< This pointer must not be NULL. If this context deals with the submodule,
                                           then should be set to the context of the module to which it belongs,
@@ -185,6 +187,7 @@
     struct ly_set grps_nodes;        /**< Set of nodes that contain grouping(s). Invalid in case of
                                           submodule, use ::lysp_ctx.main_ctx instead. */
     struct ly_set ext_inst;          /**< parsed extension instances to finish parsing */
+
     struct ly_set *parsed_mods;      /**< (sub)modules being parsed, the last one is the current */
     struct lysp_ctx *main_ctx;       /**< This pointer must not be NULL. If this context deals with the submodule,
                                           then should be set to the context of the module to which it belongs,
@@ -193,7 +196,7 @@
 };
 
 /**
- * @brief Check that \p c is valid UTF8 code point for YANG string.
+ * @brief Check that @p c is valid UTF8 code point for YANG string.
  *
  * @param[in] ctx parser context for logging.
  * @param[in] c UTF8 code point of a character to check.
@@ -202,14 +205,14 @@
 LY_ERR lysp_check_stringchar(struct lysp_ctx *ctx, uint32_t c);
 
 /**
- * @brief Check that \p c is valid UTF8 code point for YANG identifier.
+ * @brief Check that @p c is valid UTF8 code point for YANG identifier.
  *
  * @param[in] ctx parser context for logging. If NULL, does not log.
  * @param[in] c UTF8 code point of a character to check.
  * @param[in] first Flag to check the first character of an identifier, which is more restricted.
  * @param[in,out] prefix Storage for internally used flag in case of possible prefixed identifiers:
  * 0 - colon not yet found (no prefix)
- * 1 - \p c is the colon character
+ * 1 - @p c is the colon character
  * 2 - prefix already processed, now processing the identifier
  *
  * If the identifier cannot be prefixed, NULL is expected.
@@ -449,8 +452,8 @@
  *
  * @param[in] ctx libyang context.
  * @param[in] ext Extension instance for which the definition will be searched.
- * @param[in, out] ext_mod Pointer to the module where the extension definition of the @p ext to correctly resolve prefixes.
- * @param[out] ext_def Pointer to return found extension definition.
+ * @param[out] ext_mod Module of the extension definition of @p ext.
+ * @param[out] ext_def Optional found extension definition.
  * @return LY_SUCCESS when the definition was found.
  * @return LY_EVALID when the extension instance is invalid and/or the definition not found.
  */
@@ -478,21 +481,17 @@
  * (it might come from import modules which is not yet parsed at that time). Therefore, all the attributes are stored
  * as substatements and resolving argument is postponed.
  *
- * There are 3 places which need the argument, so they resolve it when missing - YIN and YANG printers and extension instance
- * compiler.
- *
  * @param[in] ctx libyang context
  * @param[in] ext_p Parsed extension to be updated.
- * @param[in] ext_def Extension definition, found with ::lysp_ext_find_definition().
  * @return LY_ERR value.
  */
-LY_ERR lysp_ext_instance_resolve_argument(struct ly_ctx *ctx, struct lysp_ext_instance *ext_p, struct lysp_ext *ext_def);
+LY_ERR lysp_ext_instance_resolve_argument(struct ly_ctx *ctx, struct lysp_ext_instance *ext_p);
 
 /**
  * @brief Iterate over the specified type of the extension instances
  *
  * @param[in] ext ([Sized array](@ref sizedarrays)) of extensions to explore
- * @param[in] index Index in the \p ext array where to start searching (first call with 0, the consequent calls with
+ * @param[in] index Index in the @p ext array where to start searching (first call with 0, the consequent calls with
  *            the returned index increased by 1 (until the iteration is not terminated by returning LY_ARRAY_COUNT(ext).
  * @param[in] substmt The statement the extension is supposed to belong to.
  * @result index in the ext array, LY_ARRAY_COUNT(ext) value if not present.
@@ -599,17 +598,6 @@
 uint8_t lysc_iff_getop(uint8_t *list, size_t pos);
 
 /**
- * @brief Parse generic statement structure into a specific parsed-schema structure.
- *
- * @param[in] ctx The compilation context of the @p stmt being processed
- * @param[in] stmt Generic statement structure to process.
- * @param[out] result Specific parsed-schema structure for the given statement. For the specific type for the particular statement, check the function code.
- * @param[in,out] exts [sized array](@ref sizedarrays) For extension instances in case of statements that do not store extension instances in their own list.
- * @return LY_ERR value.
- */
-LY_ERR lysp_stmt_parse(struct lysc_ctx *ctx, const struct lysp_stmt *stmt, void **result, struct lysp_ext_instance **exts);
-
-/**
  * @brief match yang keyword
  *
  * @param[in,out] in Input structure, is updated.
@@ -723,4 +711,16 @@
 #define LYS_IS_SINGLE_DEP_SET(mod) \
         (!(mod)->parsed->features && (!lys_has_compiled(mod) || ((mod)->compiled && !lys_has_recompiled(mod))))
 
+/**
+ * @brief Get pointer to a compiled ext instance storage for a specific statement.
+ *
+ * @param[in] ext Compiled ext instance.
+ * @param[in] stmt Compiled statement. Can be a mask when the first match is returned, it is expected the storage is
+ * the same for all the masked statements.
+ * @param[out] storage_p Pointer to a compiled ext instance substatement storage, NULL if was not compiled.
+ * @return LY_SUCCESS on success.
+ * @return LY_ENOT if the substatement is not supported.
+ */
+LY_ERR lyplg_ext_get_storage_p(const struct lysc_ext_instance *ext, int stmt, const void ***storage_p);
+
 #endif /* LY_TREE_SCHEMA_INTERNAL_H_ */
diff --git a/src/validation.c b/src/validation.c
index 0283e19..8466147 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -345,9 +345,10 @@
             --i;
 
             struct lyd_meta *meta = meta_types->objs[i];
-            struct lysc_type *type = *(struct lysc_type **)meta->annotation->substmts[ANNOTATION_SUBSTMT_TYPE].storage;
+            struct lysc_type *type;
 
             /* validate and store the value of the metadata */
+            lyplg_ext_get_storage(meta->annotation, LY_STMT_TYPE, (const void **)&type);
             ret = lyd_value_validate_incomplete(LYD_CTX(meta->parent), type, &meta->value, meta->parent, *tree);
             LY_CHECK_RET(ret);
 
@@ -1525,6 +1526,7 @@
         struct lyd_node **diff)
 {
     const struct lyd_meta *meta;
+    const struct lysc_type *type;
     struct lyd_node *node;
 
     LYD_TREE_DFS_BEGIN(root, node) {
@@ -1539,7 +1541,8 @@
         }
 
         LY_LIST_FOR(node->meta, meta) {
-            if ((*(const struct lysc_type **)meta->annotation->substmts[ANNOTATION_SUBSTMT_TYPE].storage)->plugin->validate) {
+            lyplg_ext_get_storage(meta->annotation, LY_STMT_TYPE, (const void **)&type);
+            if (type->plugin->validate) {
                 /* metadata type resolution */
                 LY_CHECK_RET(ly_set_add(meta_types, (void *)meta, 1, NULL));
             }