Merge remote-tracking branch 'upstream/libyang2' into libyang2
diff --git a/src/common.h b/src/common.h
index 3a550b8..6fc0ae7 100644
--- a/src/common.h
+++ b/src/common.h
@@ -153,7 +153,7 @@
 #define LY_VCODE_INDEV       LYVE_SYNTAX_YANG, "Deviate \"%s\" does not support keyword \"%s\"."
 #define LY_VCODE_INREGEXP    LYVE_SYNTAX_YANG, "Regular expression \"%s\" is not valid (\"%s\": %s)."
 #define LY_VCODE_XP_EOE      LYVE_XPATH, "Unterminated string delimited with %c (%.15s)."
-#define LY_VCODE_XP_INEXPR   LYVE_XPATH, "Invalid expression 0x%x."
+#define LY_VCODE_XP_INEXPR   LYVE_XPATH, "Invalid character number %u of expression \'%s\'."
 
 /******************************************************************************
  * Context
@@ -184,7 +184,7 @@
  * @param[in] revision Optional revision of the submodule to find. If not specified, the latest revision is returned.
  * @return Pointer to the specified submodule if it is present in the context.
  */
-struct lysp_module *ly_ctx_get_submodule(const struct ly_ctx *ctx, const char *module, const char *submodule, const char *revision);
+struct lysp_submodule *ly_ctx_get_submodule(const struct ly_ctx *ctx, const char *module, const char *submodule, const char *revision);
 
 /******************************************************************************
  * Parsers
diff --git a/src/context.c b/src/context.c
index 66b62e5..ad3abb2 100644
--- a/src/context.c
+++ b/src/context.c
@@ -48,7 +48,7 @@
     {"ietf-inet-types", "2013-07-15", (const char*)ietf_inet_types_2013_07_15_yang, 0, LYS_IN_YANG},
     {"ietf-yang-types", "2013-07-15", (const char*)ietf_yang_types_2013_07_15_yang, 0, LYS_IN_YANG},
     /* ietf-datastores and ietf-yang-library must be right here at the end of the list! */
-    {"ietf-datastores", "2017-08-17", (const char*)ietf_datastores_2017_08_17_yang, 0, LYS_IN_YANG},
+    {"ietf-datastores", "2017-08-17", (const char*)ietf_datastores_2017_08_17_yang, 1, LYS_IN_YANG},
     {"ietf-yang-library", IETF_YANG_LIB_REV, (const char*)ietf_yang_library_2018_01_17_yang, 1, LYS_IN_YANG}
 };
 
@@ -206,9 +206,10 @@
 
     /* load internal modules */
     for (i = 0; i < ((options & LY_CTX_NOYANGLIBRARY) ? (LY_INTERNAL_MODS_COUNT - 2) : LY_INTERNAL_MODS_COUNT); i++) {
-        module = (struct lys_module *)lys_parse_mem(ctx, internal_modules[i].data, internal_modules[i].format);
+        module = (struct lys_module *)lys_parse_mem_module(ctx, internal_modules[i].data, internal_modules[i].format,
+                                                           internal_modules[i].implemented, NULL, NULL);
         LY_CHECK_ERR_GOTO(!module, rc = ly_errcode(ctx), error);
-        module->parsed->implemented = internal_modules[i].implemented;
+        LY_CHECK_GOTO((rc = lys_compile(module, 0)), error);
     }
 
     *new_ctx = ctx;
@@ -282,26 +283,21 @@
  *
  * @param[in] ctx Context where to iterate.
  * @param[in] key Key value to search for.
- * @param[in] key_offset Key's offset in struct lysp_module and struct lysc_module to get value from the context's
- * modules to match with the key.
+ * @param[in] key_offset Key's offset in struct lys_module to get value from the context's modules to match with the key.
  * @param[in,out] Iterator to pass between the function calls. On the first call, the variable is supposed to be
  * initiated to 0. After each call returning a module, the value is greater by 1 than the index of the returned
  * module in the context.
  * @return Module matching the given key, NULL if no such module found.
  */
-static const struct lys_module *
+static struct lys_module *
 ly_ctx_get_module_by_iter(const struct ly_ctx *ctx, const char *key, size_t key_offset, unsigned int *index)
 {
-    const struct lys_module *mod;
+    struct lys_module *mod;
     const char *value;
 
     for (; *index < ctx->list.count; ++(*index)) {
         mod = ctx->list.objs[*index];
-        if (mod->compiled) {
-            value = *(const char**)(((int8_t*)(mod->compiled)) + key_offset);
-        } else {
-            value = *(const char**)(((int8_t*)(mod->parsed)) + key_offset);
-        }
+        value = *(const char**)(((int8_t*)(mod)) + key_offset);
         if (!strcmp(key, value)) {
             /* increment index for the next run */
             ++(*index);
@@ -316,26 +312,25 @@
  * @brief Unifying function for ly_ctx_get_module() and ly_ctx_get_module_ns()
  * @param[in] ctx Context where to search.
  * @param[in] key Name or Namespace as a search key.
- * @param[in] key_offset Key's offset in struct lysp_module to get value from the context's modules to match with the key.
+ * @param[in] key_offset Key's offset in struct lys_module to get value from the context's modules to match with the key.
  * @param[in] revision Revision date to match. If NULL, the matching module must have no revision. To search for the latest
  * revision module, use ly_ctx_get_module_latest_by().
  * @return Matching module if any.
  */
-static const struct lys_module *
+static struct lys_module *
 ly_ctx_get_module_by(const struct ly_ctx *ctx, const char *key, size_t key_offset, const char *revision)
 {
-    const struct lys_module *mod;
+    struct lys_module *mod;
     unsigned int index = 0;
 
     while ((mod = ly_ctx_get_module_by_iter(ctx, key, key_offset, &index))) {
         if (!revision) {
-            if ((mod->compiled && !mod->compiled->revision) || (!mod->compiled && !mod->parsed->revs)) {
+            if (!mod->revision) {
                 /* found requested module without revision */
                 return mod;
             }
         } else {
-            if ((mod->compiled && mod->compiled->revision && !strcmp(mod->compiled->revision, revision)) ||
-                    (!mod->compiled && mod->parsed->revs && !strcmp(mod->parsed->revs[0].date, revision))) {
+            if (mod->revision && !strcmp(mod->revision, revision)) {
                 /* found requested module of the specific revision */
                 return mod;
             }
@@ -345,35 +340,35 @@
     return NULL;
 }
 
-API const struct lys_module *
+API struct lys_module *
 ly_ctx_get_module_ns(const struct ly_ctx *ctx, const char *ns, const char *revision)
 {
     LY_CHECK_ARG_RET(ctx, ctx, ns, NULL);
-    return ly_ctx_get_module_by(ctx, ns, offsetof(struct lysp_module, ns), revision);
+    return ly_ctx_get_module_by(ctx, ns, offsetof(struct lys_module, ns), revision);
 }
 
-API const struct lys_module *
+API struct lys_module *
 ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, const char *revision)
 {
     LY_CHECK_ARG_RET(ctx, ctx, name, NULL);
-    return ly_ctx_get_module_by(ctx, name, offsetof(struct lysp_module, name), revision);
+    return ly_ctx_get_module_by(ctx, name, offsetof(struct lys_module, name), revision);
 }
 
 /**
  * @brief Unifying function for ly_ctx_get_module_latest() and ly_ctx_get_module_latest_ns()
  * @param[in] ctx Context where to search.
  * @param[in] key Name or Namespace as a search key.
- * @param[in] key_offset Key's offset in struct lysp_module to get value from the context's modules to match with the key.
+ * @param[in] key_offset Key's offset in struct lys_module to get value from the context's modules to match with the key.
  * @return Matching module if any.
  */
-static const struct lys_module *
+static struct lys_module *
 ly_ctx_get_module_latest_by(const struct ly_ctx *ctx, const char *key, size_t key_offset)
 {
-    const struct lys_module *mod;
+    struct lys_module *mod;
     unsigned int index = 0;
 
     while ((mod = ly_ctx_get_module_by_iter(ctx, key, key_offset, &index))) {
-        if ((mod->compiled && mod->compiled->latest_revision) || (!mod->compiled && mod->parsed->latest_revision)) {
+        if (mod->latest_revision) {
             return mod;
         }
     }
@@ -381,35 +376,35 @@
     return NULL;
 }
 
-API const struct lys_module *
+API struct lys_module *
 ly_ctx_get_module_latest(const struct ly_ctx *ctx, const char *name)
 {
     LY_CHECK_ARG_RET(ctx, ctx, name, NULL);
-    return ly_ctx_get_module_latest_by(ctx, name, offsetof(struct lysp_module, name));
+    return ly_ctx_get_module_latest_by(ctx, name, offsetof(struct lys_module, name));
 }
 
-const struct lys_module *
+API struct lys_module *
 ly_ctx_get_module_latest_ns(const struct ly_ctx *ctx, const char *ns)
 {
     LY_CHECK_ARG_RET(ctx, ctx, ns, NULL);
-    return ly_ctx_get_module_latest_by(ctx, ns, offsetof(struct lysp_module, ns));
+    return ly_ctx_get_module_latest_by(ctx, ns, offsetof(struct lys_module, ns));
 }
 
 /**
  * @brief Unifying function for ly_ctx_get_module_implemented() and ly_ctx_get_module_implemented_ns()
  * @param[in] ctx Context where to search.
  * @param[in] key Name or Namespace as a search key.
- * @param[in] key_offset Key's offset in struct lysp_module to get value from the context's modules to match with the key.
+ * @param[in] key_offset Key's offset in struct lys_module to get value from the context's modules to match with the key.
  * @return Matching module if any.
  */
-static const struct lys_module *
+static struct lys_module *
 ly_ctx_get_module_implemented_by(const struct ly_ctx *ctx, const char *key, size_t key_offset)
 {
-    const struct lys_module *mod;
+    struct lys_module *mod;
     unsigned int index = 0;
 
     while ((mod = ly_ctx_get_module_by_iter(ctx, key, key_offset, &index))) {
-        if ((mod->compiled && mod->compiled->implemented) || (!mod->compiled && mod->parsed->implemented)) {
+        if (mod->implemented) {
             return mod;
         }
     }
@@ -417,21 +412,21 @@
     return NULL;
 }
 
-API const struct lys_module *
+API struct lys_module *
 ly_ctx_get_module_implemented(const struct ly_ctx *ctx, const char *name)
 {
     LY_CHECK_ARG_RET(ctx, ctx, name, NULL);
-    return ly_ctx_get_module_implemented_by(ctx, name, offsetof(struct lysp_module, name));
+    return ly_ctx_get_module_implemented_by(ctx, name, offsetof(struct lys_module, name));
 }
 
-API const struct lys_module *
+API struct lys_module *
 ly_ctx_get_module_implemented_ns(const struct ly_ctx *ctx, const char *ns)
 {
     LY_CHECK_ARG_RET(ctx, ctx, ns, NULL);
-    return ly_ctx_get_module_implemented_by(ctx, ns, offsetof(struct lysp_module, ns));
+    return ly_ctx_get_module_implemented_by(ctx, ns, offsetof(struct lys_module, ns));
 }
 
-struct lysp_module *
+struct lysp_submodule *
 ly_ctx_get_submodule(const struct ly_ctx *ctx, const char *module, const char *submodule, const char *revision)
 {
     const struct lys_module *mod;
@@ -445,7 +440,7 @@
         if (!mod->parsed) {
             continue;
         }
-        if (module && strcmp(module, mod->parsed->name)) {
+        if (module && strcmp(module, mod->name)) {
             continue;
         }
 
@@ -466,6 +461,8 @@
     return NULL;
 }
 
+/* TODO ly_ctx_load_module() via lysp_load_module() */
+
 API void
 ly_ctx_reset_latests(struct ly_ctx *ctx)
 {
@@ -474,24 +471,53 @@
 
     for (u = 0; u < ctx->list.count; ++u) {
         mod = ctx->list.objs[u];
-        if (mod->compiled && mod->compiled->latest_revision == 2) {
-            mod->compiled->latest_revision = 1;
+        if (mod->latest_revision == 2) {
+            mod->latest_revision = 1;
         }
-        if (mod->parsed) {
-            if (mod->parsed->latest_revision == 2) {
-                mod->parsed->latest_revision = 1;
-            }
-            if (mod->parsed->includes) {
-                for (v = 0; v < LY_ARRAY_SIZE(mod->parsed->includes); ++v) {
-                    if (mod->parsed->includes[v].submodule->latest_revision == 2) {
-                        mod->parsed->includes[v].submodule->latest_revision = 1;
-                    }
+        if (mod->parsed && mod->parsed->includes) {
+            for (v = 0; v < LY_ARRAY_SIZE(mod->parsed->includes); ++v) {
+                if (mod->parsed->includes[v].submodule->latest_revision == 2) {
+                    mod->parsed->includes[v].submodule->latest_revision = 1;
                 }
             }
         }
     }
 }
 
+API LY_ERR
+ly_ctx_module_implement(struct ly_ctx *ctx, struct lys_module *mod)
+{
+    struct lys_module *m;
+
+    LY_CHECK_ARG_RET(ctx, mod, LY_EINVAL);
+
+    if (mod->implemented) {
+        return LY_SUCCESS;
+    }
+
+    /* we have module from the current context */
+    m = ly_ctx_get_module_implemented(ctx, mod->name);
+    if (m) {
+        if (m != mod) {
+            /* check collision with other implemented revision */
+            LOGERR(ctx, LY_EDENIED, "Module \"%s\" is present in the context in other implemented revision (%s).",
+                   mod->name, mod->revision ? mod->revision : "module without revision");
+            return LY_EDENIED;
+        } else {
+            /* mod is already implemented */
+            return LY_SUCCESS;
+        }
+    }
+
+    /* mark the module implemented, check for collision was already done */
+    mod->implemented = 1;
+
+    /* compile the schema */
+    LY_CHECK_RET(lys_compile(mod, 0));
+
+    return LY_SUCCESS;
+}
+
 API void
 ly_ctx_destroy(struct ly_ctx *ctx, void (*private_destructor)(const struct lysc_node *node, void *priv))
 {
diff --git a/src/context.h b/src/context.h
index 8bed61b..e920cb0 100644
--- a/src/context.h
+++ b/src/context.h
@@ -63,6 +63,7 @@
                                         directory, which is by default searched automatically (despite not
                                         recursively). */
 #define LY_CTX_PREFER_SEARCHDIRS 0x20 /**< When searching for schema, prefer searchdirs instead of user callback. */
+
 /**@} contextoptions */
 
 /**
@@ -206,7 +207,7 @@
  * the schema with no revision is returned, if it is present in the context.
  * @return Pointer to the YANG module, NULL if no schema in the context follows the name and revision requirements.
  */
-const struct lys_module *ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, const char *revision);
+struct lys_module *ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, const char *revision);
 
 /**
  * @brief Get the latest revision of the YANG module specified by its name.
@@ -218,7 +219,7 @@
  * @return The latest revision of the specified YANG module in the given context, NULL if no YANG module of the
  * given name is present in the context.
  */
-const struct lys_module *ly_ctx_get_module_latest(const struct ly_ctx *ctx, const char *name);
+struct lys_module *ly_ctx_get_module_latest(const struct ly_ctx *ctx, const char *name);
 
 /**
  * @brief Get the (only) implemented YANG module specified by its name.
@@ -228,7 +229,7 @@
  * @return The only implemented YANG module revision of the given name in the given context. NULL if there is no
  * implemented module of the given name.
  */
-const struct lys_module *ly_ctx_get_module_implemented(const struct ly_ctx *ctx, const char *name);
+struct lys_module *ly_ctx_get_module_implemented(const struct ly_ctx *ctx, const char *name);
 
 /**
  * @brief Get YANG module of the given namespace and revision.
@@ -239,7 +240,7 @@
  * the schema with no revision is returned, if it is present in the context.
  * @return Pointer to the YANG module, NULL if no schema in the context follows the namespace and revision requirements.
  */
-const struct lys_module *ly_ctx_get_module_ns(const struct ly_ctx *ctx, const char *ns, const char *revision);
+struct lys_module *ly_ctx_get_module_ns(const struct ly_ctx *ctx, const char *ns, const char *revision);
 
 /**
  * @brief Get the latest revision of the YANG module specified by its namespace.
@@ -251,7 +252,7 @@
  * @return The latest revision of the specified YANG module in the given context, NULL if no YANG module of the
  * given namespace is present in the context.
  */
-const struct lys_module *ly_ctx_get_module_latest_ns(const struct ly_ctx *ctx, const char *ns);
+struct lys_module *ly_ctx_get_module_latest_ns(const struct ly_ctx *ctx, const char *ns);
 
 /**
  * @brief Get the (only) implemented YANG module specified by its namespace.
@@ -261,7 +262,7 @@
  * @return The only implemented YANG module revision of the given namespace in the given context. NULL if there is no
  * implemented module of the given namespace.
  */
-const struct lys_module *ly_ctx_get_module_implemented_ns(const struct ly_ctx *ctx, const char *ns);
+struct lys_module *ly_ctx_get_module_implemented_ns(const struct ly_ctx *ctx, const char *ns);
 
 /**
  * @brief Reset cached latest revision information of the schemas in the context.
@@ -281,6 +282,17 @@
 void ly_ctx_reset_latests(struct ly_ctx *ctx);
 
 /**
+ * @brief Make the specific module implemented.
+ *
+ * @param[in] ctx libyang context to change.
+ * @param[in] mod Module from the given context to make implemented. It is not an error
+ * to provide already implemented module, it just does nothing.
+ * @return LY_SUCCESS or LY_EDENIED in case the context contains some other revision of the
+ * same module which is already implemented.
+ */
+LY_ERR ly_ctx_module_implement(struct ly_ctx *ctx, struct lys_module *mod);
+
+/**
  * @brief Free all internal structures of the specified context.
  *
  * The function should be used before terminating the application to destroy
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 9eadc37..968bd8e 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -41,6 +41,16 @@
         (c >= 0xd0000 && c <= 0xdfffd) || (c >= 0xe0000 && c <= 0xefffd) || \
         (c >= 0xf0000 && c <= 0xffffd) || (c >= 0x100000 && c <= 0x10fffd))
 
+/**
+ * @brief Try to find object with MEMBER string matching the IDENT in the given ARRAY.
+ * Macro logs an error message and returns LY_EVALID in case of existence of a matching object.
+ *
+ * @param[in] CTX yang parser context for logging.
+ * @param[in] ARRAY [sized array](@ref sizedarrays) of a generic objects with member named MEMBER to search.
+ * @param[in] MEMBER Name of the member of the objects in the ARRAY to compare.
+ * @param[in] STMT Name of the compared YANG statements for logging.
+ * @param[in] IDENT String trying to find in the ARRAY's objects inside the MEMBER member.
+ */
 #define CHECK_UNIQUENESS(CTX, ARRAY, MEMBER, STMT, IDENT) \
     if (ARRAY) { \
         for (unsigned int u = 0; u < LY_ARRAY_SIZE(ARRAY) - 1; ++u) { \
@@ -51,11 +61,25 @@
         } \
     }
 
+/**
+ * @brief Insert WORD into the libyang context's dictionary and store as TARGET.
+ * @param[in] CTX yang parser context to access libyang context.
+ * @param[in] BUF buffer in case the word is not a constant and can be inserted directly (zero-copy)
+ * @param[out] TARGET variable where to store the pointer to the inserted value.
+ * @param[in] WORD string to store.
+ * @param[in] LEN length of the string in WORD to store.
+ */
 #define INSERT_WORD(CTX, BUF, TARGET, WORD, LEN) \
     if (BUF) {(TARGET) = lydict_insert_zc((CTX)->ctx, WORD);}\
     else {(TARGET) = lydict_insert((CTX)->ctx, WORD, LEN);}
 
-#define MOVE_INPUT(CTX, DATA, COUNT) (*(data))+=COUNT;(CTX)->indent+=COUNT
+/**
+ * @brief Move the DATA pointer by COUNT items. Also updates the indent value in yang parser context
+ * @param[in] CTX yang parser context to update its indent value.
+ * @param[in,out] DATA pointer to move
+ * @param[in] COUNT number of items for which the DATA pointer is supposed to move on.
+ */
+#define MOVE_INPUT(CTX, DATA, COUNT) (*(DATA))+=COUNT;(CTX)->indent+=COUNT
 
 /**
  * @brief Loop through all substatements providing, return if there are none.
@@ -83,8 +107,15 @@
             !ERR && (KW != YANG_RIGHT_BRACE); \
             ERR = get_keyword(CTX, DATA, &KW, &WORD, &WORD_LEN))
 
-#define YANG_CHECK_STMTVER_RET(CTX, KW, PARENT) \
-    if ((CTX)->mod->version < 2) {LOGVAL_YANG((CTX), LY_VCODE_INCHILDSTMT2, KW, PARENT); return LY_EVALID;}
+/**
+ * @brief Check module version is at least 2 (YANG 1.1) because of the keyword presence.
+ * Logs error message and returns LY_EVALID in case of module in YANG version 1.0.
+ * @param[in] CTX yang parser context to get current module and for logging.
+ * @param[in] KW keyword allowed only in YANG version 1.1 (or later) - for logging.
+ * @param[in] PARENT parent statement where the KW is present - for logging.
+ */
+#define YANG_CHECK_STMTVER2_RET(CTX, KW, PARENT) \
+    if ((CTX)->mod_version < 2) {LOGVAL_YANG((CTX), LY_VCODE_INCHILDSTMT2, KW, PARENT); return LY_EVALID;}
 
 static LY_ERR parse_container(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
 static LY_ERR parse_uses(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
@@ -890,6 +921,10 @@
         break;
     }
 
+#undef IF_KW
+#undef IF_KW_PREFIX
+#undef IF_KW_PREFIX_END
+
     if (*kw != YANG_NONE) {
         /* make sure we have the whole keyword */
         switch (**data) {
@@ -1097,19 +1132,20 @@
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] data Data to read from, always moved to currently handled character.
- * @param[in] mod Module to store the parsed information in.
+ * @param[out] version Storage for the parsed information.
+ * @param[in, out] exts Extension instances to add to.
  *
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_yangversion(struct ly_parser_ctx *ctx, const char **data, struct lysp_module *mod)
+parse_yangversion(struct ly_parser_ctx *ctx, const char **data, uint8_t *version, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
     size_t word_len;
     enum yang_keyword kw;
 
-    if (mod->version) {
+    if (*version) {
         LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "yang-version");
         return LY_EVALID;
     }
@@ -1118,9 +1154,9 @@
     LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
 
     if ((word_len == 3) && !strncmp(word, "1.0", word_len)) {
-        mod->version = LYS_VERSION_1_0;
+        *version = LYS_VERSION_1_0;
     } else if ((word_len == 3) && !strncmp(word, "1.1", word_len)) {
-        mod->version = LYS_VERSION_1_1;
+        *version = LYS_VERSION_1_1;
     } else {
         LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "yang-version");
         free(buf);
@@ -1131,7 +1167,7 @@
     YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
         switch (kw) {
         case YANG_CUSTOM:
-            LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_VERSION, 0, &mod->exts));
+            LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_VERSION, 0, exts));
             break;
         default:
             LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yang-version");
@@ -1245,13 +1281,14 @@
  * @brief Parse the include statement.
  *
  * @param[in] ctx yang parser context for logging.
+ * @param[in] module_name Name of the module to check name collisions.
  * @param[in,out] data Data to read from, always moved to currently handled character.
  * @param[in,out] includes Parsed includes to add to.
  *
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_include(struct ly_parser_ctx *ctx, const char **data, struct lysp_module *mod)
+parse_include(struct ly_parser_ctx *ctx, const char *module_name, const char **data, struct lysp_include **includes)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1259,7 +1296,7 @@
     enum yang_keyword kw;
     struct lysp_include *inc;
 
-    LY_ARRAY_NEW_RET(ctx->ctx, mod->includes, inc, LY_EMEM);
+    LY_ARRAY_NEW_RET(ctx->ctx, *includes, inc, LY_EMEM);
 
     /* get value */
     LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
@@ -1268,7 +1305,7 @@
 
     /* submodules share the namespace with the module names, so there must not be
      * a module of the same name in the context, no need for revision matching */
-    if (!strcmp(ctx->mod->name, inc->name) || ly_ctx_get_module_latest(ctx->ctx, inc->name)) {
+    if (!strcmp(module_name, inc->name) || ly_ctx_get_module_latest(ctx->ctx, inc->name)) {
         LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Name collision between module and submodule of name \"%s\".", inc->name);
         return LY_EVALID;
     }
@@ -1276,11 +1313,11 @@
     YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
         switch (kw) {
         case YANG_DESCRIPTION:
-            YANG_CHECK_STMTVER_RET(ctx, "description", "include");
+            YANG_CHECK_STMTVER2_RET(ctx, "description", "include");
             LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &inc->dsc, Y_STR_ARG, &inc->exts));
             break;
         case YANG_REFERENCE:
-            YANG_CHECK_STMTVER_RET(ctx, "reference", "include");
+            YANG_CHECK_STMTVER2_RET(ctx, "reference", "include");
             LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &inc->ref, Y_STR_ARG, &inc->exts));
             break;
         case YANG_REVISION_DATE:
@@ -1301,13 +1338,14 @@
  * @brief Parse the import statement.
  *
  * @param[in] ctx yang parser context for logging.
+ * @param[in] module_prefix Prefix of the module to check prefix collisions.
  * @param[in,out] data Data to read from, always moved to currently handled character.
  * @param[in,out] imports Parsed imports to add to.
  *
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_import(struct ly_parser_ctx *ctx, const char **data, struct lysp_module *module)
+parse_import(struct ly_parser_ctx *ctx, const char *module_prefix, const char **data, struct lysp_import **imports)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1315,7 +1353,7 @@
     enum yang_keyword kw;
     struct lysp_import *imp;
 
-    LY_ARRAY_NEW_RET(ctx->ctx, module->imports, imp, LY_EVALID);
+    LY_ARRAY_NEW_RET(ctx->ctx, *imports, imp, LY_EVALID);
 
     /* get value */
     LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
@@ -1325,14 +1363,14 @@
         switch (kw) {
         case YANG_PREFIX:
             LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_PREFIX, 0, &imp->prefix, Y_IDENTIF_ARG, &imp->exts));
-            LY_CHECK_RET(lysp_check_prefix(ctx, module, &imp->prefix), LY_EVALID);
+            LY_CHECK_RET(lysp_check_prefix(ctx, *imports, module_prefix, &imp->prefix), LY_EVALID);
             break;
         case YANG_DESCRIPTION:
-            YANG_CHECK_STMTVER_RET(ctx, "description", "import");
+            YANG_CHECK_STMTVER2_RET(ctx, "description", "import");
             LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &imp->dsc, Y_STR_ARG, &imp->exts));
             break;
         case YANG_REFERENCE:
-            YANG_CHECK_STMTVER_RET(ctx, "reference", "import");
+            YANG_CHECK_STMTVER2_RET(ctx, "reference", "import");
             LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &imp->ref, Y_STR_ARG, &imp->exts));
             break;
         case YANG_REVISION_DATE:
@@ -1928,7 +1966,7 @@
             LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &enm->dsc, Y_STR_ARG, &enm->exts));
             break;
         case YANG_IF_FEATURE:
-            YANG_CHECK_STMTVER_RET(ctx, "if-feature", ly_stmt2str(enum_kw));
+            YANG_CHECK_STMTVER2_RET(ctx, "if-feature", ly_stmt2str(enum_kw));
             LY_CHECK_RET(parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &enm->iffeatures, Y_STR_ARG, &enm->exts));
             break;
         case YANG_REFERENCE:
@@ -2172,7 +2210,7 @@
             LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_ERRMSG, 0, &restr->emsg, Y_STR_ARG, &restr->exts));
             break;
         case YANG_MODIFIER:
-            YANG_CHECK_STMTVER_RET(ctx, "modifier", "pattern");
+            YANG_CHECK_STMTVER2_RET(ctx, "modifier", "pattern");
             LY_CHECK_RET(parse_type_pattern_modifier(ctx, data, &restr->arg, &restr->exts));
             break;
         case YANG_CUSTOM:
@@ -2602,7 +2640,7 @@
             LY_CHECK_RET(parse_config(ctx, data, &llist->flags, &llist->exts));
             break;
         case YANG_DEFAULT:
-            YANG_CHECK_STMTVER_RET(ctx, "default", "leaf-list");
+            YANG_CHECK_STMTVER2_RET(ctx, "default", "leaf-list");
             LY_CHECK_RET(parse_text_fields(ctx, data, LYEXT_SUBSTMT_DEFAULT, &llist->dflts, Y_STR_ARG, &llist->exts));
             break;
         case YANG_DESCRIPTION:
@@ -2703,7 +2741,7 @@
             LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &rf->dsc, Y_STR_ARG, &rf->exts));
             break;
         case YANG_IF_FEATURE:
-            YANG_CHECK_STMTVER_RET(ctx, "if-feature", "refine");
+            YANG_CHECK_STMTVER2_RET(ctx, "if-feature", "refine");
             LY_CHECK_RET(parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &rf->iffeatures, Y_STR_ARG, &rf->exts));
             break;
         case YANG_MAX_ELEMENTS:
@@ -2841,7 +2879,7 @@
     YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
         switch (kw) {
         case YANG_ANYDATA:
-            YANG_CHECK_STMTVER_RET(ctx, "anydata", ly_stmt2str(inout_kw));
+            YANG_CHECK_STMTVER2_RET(ctx, "anydata", ly_stmt2str(inout_kw));
             /* fall through */
         case YANG_ANYXML:
             LY_CHECK_RET(parse_any(ctx, data, kw, (struct lysp_node*)inout, &inout->data));
@@ -2868,7 +2906,7 @@
             LY_CHECK_RET(parse_typedef(ctx, (struct lysp_node*)inout, data, &inout->typedefs));
             break;
         case YANG_MUST:
-            YANG_CHECK_STMTVER_RET(ctx, "must", ly_stmt2str(inout_kw));
+            YANG_CHECK_STMTVER2_RET(ctx, "must", ly_stmt2str(inout_kw));
             LY_CHECK_RET(parse_restrs(ctx, data, kw, &inout->musts));
             break;
         case YANG_GROUPING:
@@ -3008,7 +3046,7 @@
             break;
 
         case YANG_ANYDATA:
-            YANG_CHECK_STMTVER_RET(ctx, "anydata", "notification");
+            YANG_CHECK_STMTVER2_RET(ctx, "anydata", "notification");
             /* fall through */
         case YANG_ANYXML:
             LY_CHECK_RET(parse_any(ctx, data, kw, (struct lysp_node*)notif, &notif->data));
@@ -3033,7 +3071,7 @@
             break;
 
         case YANG_MUST:
-            YANG_CHECK_STMTVER_RET(ctx, "must", "notification");
+            YANG_CHECK_STMTVER2_RET(ctx, "must", "notification");
             LY_CHECK_RET(parse_restrs(ctx, data, kw, &notif->musts));
             break;
         case YANG_TYPEDEF:
@@ -3100,7 +3138,7 @@
             break;
 
         case YANG_ANYDATA:
-            YANG_CHECK_STMTVER_RET(ctx, "anydata", "grouping");
+            YANG_CHECK_STMTVER2_RET(ctx, "anydata", "grouping");
             /* fall through */
         case YANG_ANYXML:
             LY_CHECK_RET(parse_any(ctx, data, kw, (struct lysp_node*)grp, &grp->data));
@@ -3128,14 +3166,14 @@
             LY_CHECK_RET(parse_typedef(ctx, (struct lysp_node*)grp, data, &grp->typedefs));
             break;
         case YANG_ACTION:
-            YANG_CHECK_STMTVER_RET(ctx, "action", "grouping");
+            YANG_CHECK_STMTVER2_RET(ctx, "action", "grouping");
             LY_CHECK_RET(parse_action(ctx, data, (struct lysp_node*)grp, &grp->actions));
             break;
         case YANG_GROUPING:
             LY_CHECK_RET(parse_grouping(ctx, data, (struct lysp_node*)grp, &grp->groupings));
             break;
         case YANG_NOTIFICATION:
-            YANG_CHECK_STMTVER_RET(ctx, "notification", "grouping");
+            YANG_CHECK_STMTVER2_RET(ctx, "notification", "grouping");
             LY_CHECK_RET(parse_notif(ctx, data, (struct lysp_node*)grp, &grp->notifs));
             break;
         case YANG_CUSTOM:
@@ -3200,7 +3238,7 @@
             break;
 
         case YANG_ANYDATA:
-            YANG_CHECK_STMTVER_RET(ctx, "anydata", "augment");
+            YANG_CHECK_STMTVER2_RET(ctx, "anydata", "augment");
             /* fall through */
         case YANG_ANYXML:
             LY_CHECK_RET(parse_any(ctx, data, kw, (struct lysp_node*)aug, &aug->child));
@@ -3228,11 +3266,11 @@
             break;
 
         case YANG_ACTION:
-            YANG_CHECK_STMTVER_RET(ctx, "action", "augment");
+            YANG_CHECK_STMTVER2_RET(ctx, "action", "augment");
             LY_CHECK_RET(parse_action(ctx, data, (struct lysp_node*)aug, &aug->actions));
             break;
         case YANG_NOTIFICATION:
-            YANG_CHECK_STMTVER_RET(ctx, "notification", "augment");
+            YANG_CHECK_STMTVER2_RET(ctx, "notification", "augment");
             LY_CHECK_RET(parse_notif(ctx, data, (struct lysp_node*)aug, &aug->notifs));
             break;
         case YANG_CUSTOM:
@@ -3376,7 +3414,7 @@
             break;
 
         case YANG_ANYDATA:
-            YANG_CHECK_STMTVER_RET(ctx, "anydata", "case");
+            YANG_CHECK_STMTVER2_RET(ctx, "anydata", "case");
             /* fall through */
         case YANG_ANYXML:
             LY_CHECK_RET(parse_any(ctx, data, kw, (struct lysp_node*)cas, &cas->child));
@@ -3476,7 +3514,7 @@
             break;
 
         case YANG_ANYDATA:
-            YANG_CHECK_STMTVER_RET(ctx, "anydata", "choice");
+            YANG_CHECK_STMTVER2_RET(ctx, "anydata", "choice");
             /* fall through */
         case YANG_ANYXML:
             LY_CHECK_RET(parse_any(ctx, data, kw, (struct lysp_node*)choice, &choice->child));
@@ -3485,7 +3523,7 @@
             LY_CHECK_RET(parse_case(ctx, data, (struct lysp_node*)choice, &choice->child));
             break;
         case YANG_CHOICE:
-            YANG_CHECK_STMTVER_RET(ctx, "choice", "choice");
+            YANG_CHECK_STMTVER2_RET(ctx, "choice", "choice");
             LY_CHECK_RET(parse_choice(ctx, data, (struct lysp_node*)choice, &choice->child));
             break;
         case YANG_CONTAINER:
@@ -3581,7 +3619,7 @@
             break;
 
         case YANG_ANYDATA:
-            YANG_CHECK_STMTVER_RET(ctx, "anydata", "container");
+            YANG_CHECK_STMTVER2_RET(ctx, "anydata", "container");
             /* fall through */
         case YANG_ANYXML:
             LY_CHECK_RET(parse_any(ctx, data, kw, (struct lysp_node*)cont, &cont->child));
@@ -3612,14 +3650,14 @@
             LY_CHECK_RET(parse_restrs(ctx, data, kw, &cont->musts));
             break;
         case YANG_ACTION:
-            YANG_CHECK_STMTVER_RET(ctx, "action", "container");
+            YANG_CHECK_STMTVER2_RET(ctx, "action", "container");
             LY_CHECK_RET(parse_action(ctx, data, (struct lysp_node*)cont, &cont->actions));
             break;
         case YANG_GROUPING:
             LY_CHECK_RET(parse_grouping(ctx, data, (struct lysp_node*)cont, &cont->groupings));
             break;
         case YANG_NOTIFICATION:
-            YANG_CHECK_STMTVER_RET(ctx, "notification", "container");
+            YANG_CHECK_STMTVER2_RET(ctx, "notification", "container");
             LY_CHECK_RET(parse_notif(ctx, data, (struct lysp_node*)cont, &cont->notifs));
             break;
         case YANG_CUSTOM:
@@ -3715,7 +3753,7 @@
             break;
 
         case YANG_ANYDATA:
-            YANG_CHECK_STMTVER_RET(ctx, "anydata", "list");
+            YANG_CHECK_STMTVER2_RET(ctx, "anydata", "list");
             /* fall through */
         case YANG_ANYXML:
             LY_CHECK_RET(parse_any(ctx, data, kw, (struct lysp_node*)list, &list->child));
@@ -3746,14 +3784,14 @@
             LY_CHECK_RET(parse_restrs(ctx, data, kw, &list->musts));
             break;
         case YANG_ACTION:
-            YANG_CHECK_STMTVER_RET(ctx, "action", "list");
+            YANG_CHECK_STMTVER2_RET(ctx, "action", "list");
             LY_CHECK_RET(parse_action(ctx, data, (struct lysp_node*)list, &list->actions));
             break;
         case YANG_GROUPING:
             LY_CHECK_RET(parse_grouping(ctx, data, (struct lysp_node*)list, &list->groupings));
             break;
         case YANG_NOTIFICATION:
-            YANG_CHECK_STMTVER_RET(ctx, "notification", "list");
+            YANG_CHECK_STMTVER2_RET(ctx, "notification", "list");
             LY_CHECK_RET(parse_notif(ctx, data, (struct lysp_node*)list, &list->notifs));
             break;
         case YANG_CUSTOM:
@@ -4272,7 +4310,7 @@
             LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &ident->dsc, Y_STR_ARG, &ident->exts));
             break;
         case YANG_IF_FEATURE:
-            YANG_CHECK_STMTVER_RET(ctx, "if-feature", "identity");
+            YANG_CHECK_STMTVER2_RET(ctx, "if-feature", "identity");
             LY_CHECK_RET(parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &ident->iffeatures, Y_STR_ARG, &ident->exts));
             break;
         case YANG_REFERENCE:
@@ -4282,7 +4320,7 @@
             LY_CHECK_RET(parse_status(ctx, data, &ident->flags, &ident->exts));
             break;
         case YANG_BASE:
-            if (ident->bases && ctx->mod->version < 2) {
+            if (ident->bases && ctx->mod_version < 2) {
                 LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Identity can be derived from multiple base identities only in YANG 1.1 modules");
                 return LY_EVALID;
             }
@@ -4300,7 +4338,33 @@
 }
 
 /**
- * @brief Parse the module or submodule statement.
+ * @brief Finalize some of the (sub)module structure after parsing.
+ *
+ * Update parent pointers in the nodes inside grouping/RPC/Notification, which could be reallocated.
+ *
+ * @param[in] mod Parsed module to be updated.
+ * @return LY_ERR value (currently only LY_SUCCESS, but it can change in future).
+ */
+static LY_ERR
+parse_sub_module_finalize(struct lysp_module *mod)
+{
+    unsigned int u;
+    struct lysp_node *child;
+
+    /* finalize parent pointers to the reallocated items */
+    LY_ARRAY_FOR(mod->groupings, u) {
+        LY_LIST_FOR(mod->groupings[u].data, child) {
+            child->parent = (struct lysp_node*)&mod->groupings[u];
+        }
+    }
+
+    /* TODO the same finalization for rpcs and notifications, do also in the relevant nodes */
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse module substatements.
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] data Data to read from, always moved to currently handled character.
@@ -4309,20 +4373,18 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_sub_module(struct ly_parser_ctx *ctx, const char **data, struct lysp_module *mod)
+parse_module(struct ly_parser_ctx *ctx, const char **data, struct lysp_module *mod)
 {
     LY_ERR ret = 0;
     char *buf, *word;
     size_t word_len;
     enum yang_keyword kw, prev_kw = 0;
     enum yang_module_stmt mod_stmt = Y_MOD_MODULE_HEADER;
-    struct lysp_module *dup;
-    struct lysp_node *child;
-    unsigned int u;
+    struct lysp_submodule *dup;
 
     /* (sub)module name */
     LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
-    INSERT_WORD(ctx, buf, mod->name, word, word_len);
+    INSERT_WORD(ctx, buf, mod->mod->name, word, word_len);
 
     YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
 
@@ -4333,17 +4395,6 @@
         /* module header */
         case YANG_NAMESPACE:
         case YANG_PREFIX:
-            if (mod->submodule) {
-                LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "submodule");
-                return LY_EVALID;
-            }
-            CHECK_ORDER(Y_MOD_MODULE_HEADER);
-            break;
-        case YANG_BELONGS_TO:
-            if (!mod->submodule) {
-                LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "module");
-                return LY_EVALID;
-            }
             CHECK_ORDER(Y_MOD_MODULE_HEADER);
             break;
         case YANG_YANG_VERSION:
@@ -4397,39 +4448,36 @@
         switch (kw) {
         /* module header */
         case YANG_YANG_VERSION:
-            LY_CHECK_RET(parse_yangversion(ctx, data, mod));
+            LY_CHECK_RET(parse_yangversion(ctx, data, &mod->mod->version, &mod->exts));
+            ctx->mod_version = mod->mod->version;
             break;
         case YANG_NAMESPACE:
-            LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_NAMESPACE, 0, &mod->ns, Y_STR_ARG, &mod->exts));
+            LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_NAMESPACE, 0, &mod->mod->ns, Y_STR_ARG, &mod->exts));
             break;
         case YANG_PREFIX:
-            LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_PREFIX, 0, &mod->prefix, Y_IDENTIF_ARG, &mod->exts));
-            LY_CHECK_RET(lysp_check_prefix(ctx, mod, &mod->prefix), LY_EVALID);
-            break;
-        case YANG_BELONGS_TO:
-            LY_CHECK_RET(parse_belongsto(ctx, data, &mod->belongsto, &mod->prefix, &mod->exts));
+            LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_PREFIX, 0, &mod->mod->prefix, Y_IDENTIF_ARG, &mod->exts));
             break;
 
         /* linkage */
         case YANG_INCLUDE:
-            LY_CHECK_RET(parse_include(ctx, data, mod));
+            LY_CHECK_RET(parse_include(ctx, mod->mod->name, data, &mod->includes));
             break;
         case YANG_IMPORT:
-            LY_CHECK_RET(parse_import(ctx, data, mod));
+            LY_CHECK_RET(parse_import(ctx, mod->mod->prefix, data, &mod->imports));
             break;
 
         /* meta */
         case YANG_ORGANIZATION:
-            LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_ORGANIZATION, 0, &mod->org, Y_STR_ARG, &mod->exts));
+            LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_ORGANIZATION, 0, &mod->mod->org, Y_STR_ARG, &mod->exts));
             break;
         case YANG_CONTACT:
-            LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_CONTACT, 0, &mod->contact, Y_STR_ARG, &mod->exts));
+            LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_CONTACT, 0, &mod->mod->contact, Y_STR_ARG, &mod->exts));
             break;
         case YANG_DESCRIPTION:
-            LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &mod->dsc, Y_STR_ARG, &mod->exts));
+            LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &mod->mod->dsc, Y_STR_ARG, &mod->exts));
             break;
         case YANG_REFERENCE:
-            LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &mod->ref, Y_STR_ARG, &mod->exts));
+            LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &mod->mod->ref, Y_STR_ARG, &mod->exts));
             break;
 
         /* revision */
@@ -4439,7 +4487,7 @@
 
         /* body */
         case YANG_ANYDATA:
-            YANG_CHECK_STMTVER_RET(ctx, "anydata", mod->submodule ? "submodule" : "module");
+            YANG_CHECK_STMTVER2_RET(ctx, "anydata", "module");
             /* fall through */
         case YANG_ANYXML:
             LY_CHECK_RET(parse_any(ctx, data, kw, NULL, &mod->data));
@@ -4495,43 +4543,233 @@
             break;
 
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), mod->submodule ? "submodule" : "module");
+            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "module");
             return LY_EVALID;
         }
     }
     LY_CHECK_RET(ret);
 
-    /* finalize parent pointers to the reallocated items */
-    LY_ARRAY_FOR(mod->groupings, u) {
-        LY_LIST_FOR(mod->groupings[u].data, child) {
-            child->parent = (struct lysp_node*)&mod->groupings[u];
-        }
-    }
-    /* TODO the same finalization for rpcs and notifications, do also in the relevant nodes */
-
 checks:
+    /* finalize parent pointers to the reallocated items */
+    LY_CHECK_RET(parse_sub_module_finalize(mod));
+
     /* mandatory substatements */
-    if (mod->submodule) {
-        if (!mod->belongsto) {
-            LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "belongs-to", "submodule");
-            return LY_EVALID;
-        }
-    } else {
-        if (!mod->ns) {
-            LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "namespace", "module");
-            return LY_EVALID;
-        } else if (!mod->prefix) {
-            LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "prefix", "module");
-            return LY_EVALID;
-        }
+    if (!mod->mod->ns) {
+        LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "namespace", "module");
+        return LY_EVALID;
+    } else if (!mod->mod->prefix) {
+        LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "prefix", "module");
+        return LY_EVALID;
     }
 
     /* submodules share the namespace with the module names, so there must not be
      * a submodule of the same name in the context, no need for revision matching */
-    dup = ly_ctx_get_submodule(ctx->ctx, NULL, mod->name, NULL);
-    if (dup && (!mod->submodule || strcmp(dup->belongsto, mod->belongsto))) {
-        LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Name collision between %s of name \"%s\".",
-                    mod->submodule ? "submodules" : "module and submodule", mod->name);
+    dup = ly_ctx_get_submodule(ctx->ctx, NULL, mod->mod->name, NULL);
+    if (dup) {
+        LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Name collision between module and submodule of name \"%s\".", mod->mod->name);
+        return LY_EVALID;
+    }
+
+    return ret;
+}
+
+/**
+ * @brief Parse submodule substatements.
+ *
+ * @param[in] ctx yang parser context for logging.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[out] submod Parsed submodule structure.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+parse_submodule(struct ly_parser_ctx *ctx, const char **data, struct lysp_submodule *submod)
+{
+    LY_ERR ret = 0;
+    char *buf, *word;
+    size_t word_len;
+    enum yang_keyword kw, prev_kw = 0;
+    enum yang_module_stmt mod_stmt = Y_MOD_MODULE_HEADER;
+    struct lysp_submodule *dup;
+
+    /* submodule name */
+    LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+    INSERT_WORD(ctx, buf, submod->name, word, word_len);
+
+    YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
+
+#define CHECK_ORDER(SECTION) \
+        if (mod_stmt > SECTION) {LOGVAL_YANG(ctx, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw)); return LY_EVALID;}mod_stmt = SECTION
+
+        switch (kw) {
+        /* module header */
+        case YANG_BELONGS_TO:
+            CHECK_ORDER(Y_MOD_MODULE_HEADER);
+            break;
+        case YANG_YANG_VERSION:
+            CHECK_ORDER(Y_MOD_MODULE_HEADER);
+            break;
+        /* linkage */
+        case YANG_INCLUDE:
+        case YANG_IMPORT:
+            CHECK_ORDER(Y_MOD_LINKAGE);
+            break;
+        /* meta */
+        case YANG_ORGANIZATION:
+        case YANG_CONTACT:
+        case YANG_DESCRIPTION:
+        case YANG_REFERENCE:
+            CHECK_ORDER(Y_MOD_META);
+            break;
+
+        /* revision */
+        case YANG_REVISION:
+            CHECK_ORDER(Y_MOD_REVISION);
+            break;
+        /* body */
+        case YANG_ANYDATA:
+        case YANG_ANYXML:
+        case YANG_AUGMENT:
+        case YANG_CHOICE:
+        case YANG_CONTAINER:
+        case YANG_DEVIATION:
+        case YANG_EXTENSION:
+        case YANG_FEATURE:
+        case YANG_GROUPING:
+        case YANG_IDENTITY:
+        case YANG_LEAF:
+        case YANG_LEAF_LIST:
+        case YANG_LIST:
+        case YANG_NOTIFICATION:
+        case YANG_RPC:
+        case YANG_TYPEDEF:
+        case YANG_USES:
+        case YANG_CUSTOM:
+            mod_stmt = Y_MOD_BODY;
+            break;
+        default:
+            /* error handled in the next switch */
+            break;
+        }
+#undef CHECK_ORDER
+
+        prev_kw = kw;
+        switch (kw) {
+        /* module header */
+        case YANG_YANG_VERSION:
+            LY_CHECK_RET(parse_yangversion(ctx, data, &submod->version, &submod->exts));
+            ctx->mod_version = submod->version;
+            break;
+        case YANG_BELONGS_TO:
+            LY_CHECK_RET(parse_belongsto(ctx, data, &submod->belongsto, &submod->prefix, &submod->exts));
+            break;
+
+        /* linkage */
+        case YANG_INCLUDE:
+            LY_CHECK_RET(parse_include(ctx, submod->name, data, &submod->includes));
+            break;
+        case YANG_IMPORT:
+            LY_CHECK_RET(parse_import(ctx, submod->prefix, data, &submod->imports));
+            break;
+
+        /* meta */
+        case YANG_ORGANIZATION:
+            LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_ORGANIZATION, 0, &submod->org, Y_STR_ARG, &submod->exts));
+            break;
+        case YANG_CONTACT:
+            LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_CONTACT, 0, &submod->contact, Y_STR_ARG, &submod->exts));
+            break;
+        case YANG_DESCRIPTION:
+            LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &submod->dsc, Y_STR_ARG, &submod->exts));
+            break;
+        case YANG_REFERENCE:
+            LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &submod->ref, Y_STR_ARG, &submod->exts));
+            break;
+
+        /* revision */
+        case YANG_REVISION:
+            LY_CHECK_RET(parse_revision(ctx, data, &submod->revs));
+            break;
+
+        /* body */
+        case YANG_ANYDATA:
+            YANG_CHECK_STMTVER2_RET(ctx, "anydata", "submodule");
+            /* fall through */
+        case YANG_ANYXML:
+            LY_CHECK_RET(parse_any(ctx, data, kw, NULL, &submod->data));
+            break;
+        case YANG_CHOICE:
+            LY_CHECK_RET(parse_choice(ctx, data, NULL, &submod->data));
+            break;
+        case YANG_CONTAINER:
+            LY_CHECK_RET(parse_container(ctx, data, NULL, &submod->data));
+            break;
+        case YANG_LEAF:
+            LY_CHECK_RET(parse_leaf(ctx, data, NULL, &submod->data));
+            break;
+        case YANG_LEAF_LIST:
+            LY_CHECK_RET(parse_leaflist(ctx, data, NULL, &submod->data));
+            break;
+        case YANG_LIST:
+            LY_CHECK_RET(parse_list(ctx, data, NULL, &submod->data));
+            break;
+        case YANG_USES:
+            LY_CHECK_RET(parse_uses(ctx, data, NULL, &submod->data));
+            break;
+
+        case YANG_AUGMENT:
+            LY_CHECK_RET(parse_augment(ctx, data, NULL, &submod->augments));
+            break;
+        case YANG_DEVIATION:
+            LY_CHECK_RET(parse_deviation(ctx, data, &submod->deviations));
+            break;
+        case YANG_EXTENSION:
+            LY_CHECK_RET(parse_extension(ctx, data, &submod->extensions));
+            break;
+        case YANG_FEATURE:
+            LY_CHECK_RET(parse_feature(ctx, data, &submod->features));
+            break;
+        case YANG_GROUPING:
+            LY_CHECK_RET(parse_grouping(ctx, data, NULL, &submod->groupings));
+            break;
+        case YANG_IDENTITY:
+            LY_CHECK_RET(parse_identity(ctx, data, &submod->identities));
+            break;
+        case YANG_NOTIFICATION:
+            LY_CHECK_RET(parse_notif(ctx, data, NULL, &submod->notifs));
+            break;
+        case YANG_RPC:
+            LY_CHECK_RET(parse_action(ctx, data, NULL, &submod->rpcs));
+            break;
+        case YANG_TYPEDEF:
+            LY_CHECK_RET(parse_typedef(ctx, NULL, data, &submod->typedefs));
+            break;
+        case YANG_CUSTOM:
+            LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &submod->exts));
+            break;
+
+        default:
+            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "submodule");
+            return LY_EVALID;
+        }
+    }
+    LY_CHECK_RET(ret);
+
+checks:
+    /* finalize parent pointers to the reallocated items */
+    LY_CHECK_RET(parse_sub_module_finalize((struct lysp_module*)submod));
+
+    /* mandatory substatements */
+    if (!submod->belongsto) {
+        LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "belongs-to", "submodule");
+        return LY_EVALID;
+    }
+
+    /* submodules share the namespace with the module names, so there must not be
+     * a submodule of the same name in the context, no need for revision matching */
+    dup = ly_ctx_get_submodule(ctx->ctx, NULL, submod->name, NULL);
+    if (dup && strcmp(dup->belongsto, submod->belongsto)) {
+        LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Name collision between submodules of name \"%s\".", dup->name);
         return LY_EVALID;
     }
 
@@ -4539,35 +4777,35 @@
 }
 
 LY_ERR
-yang_parse(struct ly_parser_ctx *context, const char *data, struct lysp_module **mod_p)
+yang_parse_submodule(struct ly_parser_ctx *context, const char *data, struct lysp_submodule **submod)
 {
     LY_ERR ret = LY_SUCCESS;
     char *word, *buf;
     size_t word_len;
     enum yang_keyword kw;
-    struct lysp_module *mod = NULL;
+    struct lysp_submodule *mod_p = NULL;
 
     /* "module"/"submodule" */
     ret = get_keyword(context, &data, &kw, &word, &word_len);
     LY_CHECK_GOTO(ret, cleanup);
 
-    if ((kw != YANG_MODULE) && (kw != YANG_SUBMODULE)) {
+    if (kw == YANG_MODULE) {
+        LOGERR(context->ctx, LY_EDENIED, "Input data contains module in situation when a submodule is expected.");
+        ret = LY_EINVAL;
+        goto cleanup;
+    } else if (kw != YANG_SUBMODULE) {
         LOGVAL_YANG(context, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".",
                ly_stmt2str(kw));
+        ret = LY_EVALID;
         goto cleanup;
     }
 
-    mod = calloc(1, sizeof *mod);
-    LY_CHECK_ERR_GOTO(!mod, LOGMEM(context->ctx), cleanup);
-    if (kw == YANG_SUBMODULE) {
-        mod->submodule = 1;
-    }
-    mod->parsing = 1;
-    mod->ctx = context->ctx;
-    context->mod = mod;
+    mod_p = calloc(1, sizeof *mod_p);
+    LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(context->ctx), cleanup);
+    mod_p->parsing = 1;
 
     /* substatements */
-    ret = parse_sub_module(context, &data, mod);
+    ret = parse_submodule(context, &data, mod_p);
     LY_CHECK_GOTO(ret, cleanup);
 
     /* read some trailing spaces or new lines */
@@ -4578,16 +4816,74 @@
         LOGVAL_YANG(context, LYVE_SYNTAX, "Invalid character sequence \"%.*s\", expected end-of-file.",
                word_len, word);
         free(buf);
+        ret = LY_EVALID;
         goto cleanup;
     }
     assert(!buf);
 
-    mod->parsing = 0;
-    *mod_p = mod;
+    mod_p->parsing = 0;
+    *submod = mod_p;
 
 cleanup:
     if (ret) {
-        lysp_module_free(mod);
+        lysp_submodule_free(context->ctx, mod_p);
+    }
+
+    return ret;
+}
+
+LY_ERR
+yang_parse_module(struct ly_parser_ctx *context, const char *data, struct lys_module *mod)
+{
+    LY_ERR ret = LY_SUCCESS;
+    char *word, *buf;
+    size_t word_len;
+    enum yang_keyword kw;
+    struct lysp_module *mod_p = NULL;
+
+    /* "module"/"submodule" */
+    ret = get_keyword(context, &data, &kw, &word, &word_len);
+    LY_CHECK_GOTO(ret, cleanup);
+
+    if (kw == YANG_SUBMODULE) {
+        LOGERR(context->ctx, LY_EDENIED, "Input data contains submodule which cannot be parsed directly without its main module.");
+        ret = LY_EINVAL;
+        goto cleanup;
+    } else if (kw != YANG_MODULE) {
+        LOGVAL_YANG(context, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".",
+               ly_stmt2str(kw));
+        ret = LY_EVALID;
+        goto cleanup;
+    }
+
+    mod_p = calloc(1, sizeof *mod_p);
+    LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(context->ctx), cleanup);
+    mod_p->mod = mod;
+    mod_p->parsing = 1;
+
+    /* substatements */
+    ret = parse_module(context, &data, mod_p);
+    LY_CHECK_GOTO(ret, cleanup);
+
+    /* read some trailing spaces or new lines */
+    ret = get_argument(context, &data, Y_MAYBE_STR_ARG, &word, &buf, &word_len);
+    LY_CHECK_GOTO(ret, cleanup);
+
+    if (word) {
+        LOGVAL_YANG(context, LYVE_SYNTAX, "Invalid character sequence \"%.*s\", expected end-of-file.",
+               word_len, word);
+        free(buf);
+        ret = LY_EVALID;
+        goto cleanup;
+    }
+    assert(!buf);
+
+    mod_p->parsing = 0;
+    mod->parsed = mod_p;
+
+cleanup:
+    if (ret) {
+        lysp_module_free(mod_p);
     }
 
     return ret;
diff --git a/src/tree_schema.c b/src/tree_schema.c
index dd085de..6fba4d6 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -73,6 +73,11 @@
 
     next = last->next;
 repeat:
+    if (next && parent && parent->nodetype == LYS_CASE && next->parent != parent) {
+        /* inside case (as an explicit parent, not when diving into it from choice),
+         * limit the list of children only to the specific case */
+        next = NULL;
+    }
     if (!next) {
         /* possibly go back to parent */
         if (last->parent != parent) {
@@ -119,7 +124,7 @@
         goto repeat;
     default:
         /* we should not be here */
-        LOGINT(last->module->compiled->ctx);
+        LOGINT(last->module->ctx);
         return NULL;
     }
 
@@ -236,23 +241,29 @@
  * if-feature statements are again evaluated (disabled if a if-feature statemen
  * evaluates to false).
  *
- * @param[in] mod Compiled module where to set (search for) the feature.
+ * @param[in] mod Module where to set (search for) the feature.
  * @param[in] name Name of the feature to set. Asterisk ('*') can be used to
  * set all the features in the module.
  * @param[in] value Desired value of the feature: 1 (enable) or 0 (disable).
  * @return LY_ERR value.
  */
 static LY_ERR
-lys_feature_change(const struct lysc_module *mod, const char *name, int value)
+lys_feature_change(const struct lys_module *mod, const char *name, int value)
 {
     int all = 0;
     unsigned int u, changed_count, disabled_count;
     struct lysc_feature *f, **df;
     struct lysc_iffeature *iff;
     struct ly_set *changed;
+    struct ly_ctx *ctx = mod->ctx; /* shortcut */
 
-    if (!mod->features) {
-        LOGERR(mod->ctx, LY_EINVAL, "Unable to switch feature since the module \"%s\" has no features.", mod->name);
+    if (!mod->compiled) {
+        LOGERR(ctx, LY_EINVAL, "Module \"%s\" is not implemented so all its features are permanently disabled without a chance to change it.",
+               mod->name);
+        return LY_EINVAL;
+    }
+    if (!mod->compiled->features) {
+        LOGERR(ctx, LY_EINVAL, "Unable to switch feature since the module \"%s\" has no features.", mod->name);
         return LY_EINVAL;
     }
 
@@ -264,8 +275,8 @@
     changed_count = 0;
 
 run:
-    for (disabled_count = u = 0; u < LY_ARRAY_SIZE(mod->features); ++u) {
-        f = &mod->features[u];
+    for (disabled_count = u = 0; u < LY_ARRAY_SIZE(mod->compiled->features); ++u) {
+        f = &mod->compiled->features[u];
         if (all || !strcmp(f->name, name)) {
             if ((value && (f->flags & LYS_FENABLED)) || (!value && !(f->flags & LYS_FENABLED))) {
                 if (all) {
@@ -286,7 +297,7 @@
                             ++disabled_count;
                             goto next;
                         } else {
-                            LOGERR(mod->ctx, LY_EDENIED,
+                            LOGERR(ctx, LY_EDENIED,
                                    "Feature \"%s\" cannot be enabled since it is disabled by its if-feature condition(s).",
                                    f->name);
                             ly_set_free(changed, NULL);
@@ -314,7 +325,7 @@
     }
 
     if (!all && !changed->count) {
-        LOGERR(mod->ctx, LY_EINVAL, "Feature \"%s\" not found in module \"%s\".", name, mod->name);
+        LOGERR(ctx, LY_EINVAL, "Feature \"%s\" not found in module \"%s\".", name, mod->name);
         ly_set_free(changed, NULL);
         return LY_EINVAL;
     }
@@ -323,11 +334,11 @@
         if (changed_count == changed->count) {
             /* no change in last run -> not able to enable all ... */
             /* ... print errors */
-            for (u = 0; disabled_count && u < LY_ARRAY_SIZE(mod->features); ++u) {
-                if (!(mod->features[u].flags & LYS_FENABLED)) {
-                    LOGERR(mod->ctx, LY_EDENIED,
+            for (u = 0; disabled_count && u < LY_ARRAY_SIZE(mod->compiled->features); ++u) {
+                if (!(mod->compiled->features[u].flags & LYS_FENABLED)) {
+                    LOGERR(ctx, LY_EDENIED,
                            "Feature \"%s\" cannot be enabled since it is disabled by its if-feature condition(s).",
-                           mod->features[u].name);
+                           mod->compiled->features[u].name);
                     --disabled_count;
                 }
             }
@@ -378,17 +389,17 @@
 API LY_ERR
 lys_feature_enable(struct lys_module *module, const char *feature)
 {
-    LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, LY_EINVAL);
+    LY_CHECK_ARG_RET(NULL, module, feature, LY_EINVAL);
 
-    return lys_feature_change(module->compiled, feature, 1);
+    return lys_feature_change(module, feature, 1);
 }
 
 API LY_ERR
 lys_feature_disable(struct lys_module *module, const char *feature)
 {
-    LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, LY_EINVAL);
+    LY_CHECK_ARG_RET(NULL, module, feature, LY_EINVAL);
 
-    return lys_feature_change(module->compiled, feature, 0);
+    return lys_feature_change(module, feature, 0);
 }
 
 API int
@@ -448,25 +459,80 @@
     return NULL;
 }
 
-static void
-lys_latest_switch(struct lys_module *old, struct lysp_module *new)
+struct lysp_submodule *
+lys_parse_mem_submodule(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, struct ly_parser_ctx *main_ctx,
+                        LY_ERR (*custom_check)(struct ly_ctx*, struct lysp_module*, struct lysp_submodule*, void*), void *check_data)
 {
-    if (old->parsed) {
-        new->latest_revision = old->parsed->latest_revision;
-        old->parsed->latest_revision = 0;
+    LY_ERR ret = LY_EINVAL;
+    struct lysp_submodule *submod = NULL, *latest_sp;
+    struct ly_parser_ctx context = {0};
+
+    LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
+
+    context.ctx = ctx;
+    context.line = 1;
+
+    /* map the typedefs and groupings list from main context to the submodule's context */
+    memcpy(&context.tpdfs_nodes, &main_ctx->tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
+    memcpy(&context.grps_nodes, &main_ctx->grps_nodes, sizeof main_ctx->grps_nodes);
+
+    switch (format) {
+    case LYS_IN_YIN:
+        /* TODO not yet supported
+        mod = yin_read_module();
+        */
+        break;
+    case LYS_IN_YANG:
+        ret = yang_parse_submodule(&context, data, &submod);
+        break;
+    default:
+        LOGERR(context.ctx, LY_EINVAL, "Invalid schema input format.");
+        break;
     }
-    if (old->compiled) {
-        new->latest_revision = old->parsed->latest_revision;
-        old->compiled->latest_revision = 0;
+    LY_CHECK_RET(ret, NULL);
+
+    /* make sure that the newest revision is at position 0 */
+    lysp_sort_revisions(submod->revs);
+
+    if (custom_check) {
+        LY_CHECK_GOTO(custom_check(context.ctx, NULL, submod, check_data), error);
     }
+
+    /* decide the latest revision */
+    latest_sp = ly_ctx_get_submodule(context.ctx, submod->belongsto, submod->name, NULL);
+    if (latest_sp) {
+        if (submod->revs) {
+            if (!latest_sp->revs) {
+                /* latest has no revision, so mod is anyway newer */
+                submod->latest_revision = latest_sp->latest_revision;
+                latest_sp->latest_revision = 0;
+            } else {
+                if (strcmp(submod->revs[0].date, latest_sp->revs[0].date) > 0) {
+                    submod->latest_revision = latest_sp->latest_revision;
+                    latest_sp->latest_revision = 0;
+                }
+            }
+        }
+    } else {
+        submod->latest_revision = 1;
+    }
+
+    /* remap possibly changed and reallocated typedefs and groupings list back to the main context */
+    memcpy(&main_ctx->tpdfs_nodes, &context.tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
+    memcpy(&main_ctx->grps_nodes, &context.grps_nodes, sizeof main_ctx->grps_nodes);
+
+    return submod;
+error:
+    lysp_submodule_free(ctx, submod);
+    return NULL;
 }
 
 struct lys_module *
-lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
-               LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data)
+lys_parse_mem_module(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, int implement,
+                     LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
+                     void *check_data)
 {
     struct lys_module *mod = NULL, *latest, *mod_dup;
-    struct lysp_module *latest_p;
     struct lysp_import *imp;
     struct lysp_include *inc;
     LY_ERR ret = LY_EINVAL;
@@ -478,95 +544,67 @@
     context.ctx = ctx;
     context.line = 1;
 
-    if (main_ctx) {
-        /* map the typedefs and groupings list from main context to the submodule's context */
-        memcpy(&context.tpdfs_nodes, &main_ctx->tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
-        memcpy(&context.grps_nodes, &main_ctx->grps_nodes, sizeof main_ctx->grps_nodes);
-    }
-
     mod = calloc(1, sizeof *mod);
     LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), NULL);
+    mod->ctx = ctx;
 
     switch (format) {
     case LYS_IN_YIN:
         /* TODO not yet supported
-        mod = yin_read_module(ctx, data, revision, implement);
+        mod = yin_read_module();
         */
         break;
     case LYS_IN_YANG:
-        ret = yang_parse(&context, data, &mod->parsed);
+        ret = yang_parse_module(&context, data, mod);
         break;
     default:
         LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
         break;
     }
-    LY_CHECK_ERR_RET(ret, free(mod), NULL);
+    LY_CHECK_ERR_RET(ret, lys_module_free(mod, NULL), NULL);
 
     /* make sure that the newest revision is at position 0 */
     lysp_sort_revisions(mod->parsed->revs);
-
-    if (implement) {
-        /* mark the loaded module implemented */
-        if (ly_ctx_get_module_implemented(ctx, mod->parsed->name)) {
-            LOGERR(ctx, LY_EDENIED, "Module \"%s\" is already implemented in the context.", mod->parsed->name);
-            goto error;
-        }
-        mod->parsed->implemented = 1;
+    if (mod->parsed->revs) {
+        mod->revision = lydict_insert(ctx, mod->parsed->revs[0].date, 0);
     }
 
     if (custom_check) {
-        LY_CHECK_GOTO(custom_check(ctx, mod->parsed, check_data), error);
+        LY_CHECK_GOTO(custom_check(ctx, mod->parsed, NULL, check_data), error);
     }
 
-    if (mod->parsed->submodule) { /* submodule */
-        if (!main_ctx) {
-            LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
-                   mod->parsed->name);
+    if (implement) {
+        /* mark the loaded module implemented */
+        if (ly_ctx_get_module_implemented(ctx, mod->name)) {
+            LOGERR(ctx, LY_EDENIED, "Module \"%s\" is already implemented in the context.", mod->name);
             goto error;
         }
-        /* decide the latest revision */
-        latest_p = ly_ctx_get_submodule(ctx, mod->parsed->belongsto, mod->parsed->name, NULL);
-        if (latest_p) {
+        mod->implemented = 1;
+    }
+
+    /* check for duplicity in the context */
+    mod_dup = (struct lys_module*)ly_ctx_get_module(ctx, mod->name, mod->revision);
+    if (mod_dup) {
+        if (mod_dup->parsed) {
+            /* error */
             if (mod->parsed->revs) {
-                if (!latest_p->revs) {
-                    /* latest has no revision, so mod is anyway newer */
-                    mod->parsed->latest_revision = latest_p->latest_revision;
-                    latest_p->latest_revision = 0;
-                } else {
-                    if (strcmp(mod->parsed->revs[0].date, latest_p->revs[0].date) > 0) {
-                        mod->parsed->latest_revision = latest_p->latest_revision;
-                        latest_p->latest_revision = 0;
-                    }
-                }
-            }
-        } else {
-            mod->parsed->latest_revision = 1;
-        }
-        /* remap possibly changed and reallocated typedefs and groupings list back to the main context */
-        memcpy(&main_ctx->tpdfs_nodes, &context.tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
-        memcpy(&main_ctx->grps_nodes, &context.grps_nodes, sizeof main_ctx->grps_nodes);
-    } else { /* module */
-        /* check for duplicity in the context */
-        mod_dup = (struct lys_module*)ly_ctx_get_module(ctx, mod->parsed->name, mod->parsed->revs ? mod->parsed->revs[0].date : NULL);
-        if (mod_dup) {
-            if (mod_dup->parsed) {
-                /* error */
-                if (mod->parsed->revs) {
-                    LOGERR(ctx, LY_EEXIST, "Module \"%s\" of revision \"%s\" is already present in the context.",
-                           mod->parsed->name, mod->parsed->revs[0].date);
-                } else {
-                    LOGERR(ctx, LY_EEXIST, "Module \"%s\" with no revision is already present in the context.",
-                           mod->parsed->name);
-                }
-                goto error;
+                LOGERR(ctx, LY_EEXIST, "Module \"%s\" of revision \"%s\" is already present in the context.",
+                       mod->name, mod->parsed->revs[0].date);
             } else {
-                /* add the parsed data to the currently compiled-only module in the context */
-                mod_dup->parsed = mod->parsed;
-                free(mod);
-                mod = mod_dup;
-                goto finish_parsing;
+                LOGERR(ctx, LY_EEXIST, "Module \"%s\" with no revision is already present in the context.",
+                       mod->name);
             }
+            goto error;
+        } else {
+            /* add the parsed data to the currently compiled-only module in the context */
+            mod_dup->parsed = mod->parsed;
+            mod_dup->parsed->mod = mod_dup;
+            mod->parsed = NULL;
+            lys_module_free(mod, NULL);
+            mod = mod_dup;
+            goto finish_parsing;
         }
+    }
 
 #if 0
     /* hack for NETCONF's edit-config's operation attribute. It is not defined in the schema, but since libyang
@@ -574,7 +612,7 @@
      * internal part of libyang, we cannot add the annotation into the schema source, but we do it here to have
      * the anotation definitions available in the internal schema structure. There is another hack in schema
      * printers to do not print this internally added annotation. */
-    if (mod && ly_strequal(mod->name, "ietf-netconf", 0)) {
+    if (ly_strequal(mod->name, "ietf-netconf", 0)) {
         if (lyp_add_ietf_netconf_annotations(mod)) {
             lys_free(mod, NULL, 1, 1);
             return NULL;
@@ -582,53 +620,61 @@
     }
 #endif
 
-        /* decide the latest revision */
-        latest = (struct lys_module*)ly_ctx_get_module_latest(ctx, mod->parsed->name);
-        if (latest) {
-            if (mod->parsed->revs) {
-                if ((latest->parsed && !latest->parsed->revs) || (!latest->parsed && !latest->compiled->revision)) {
-                    /* latest has no revision, so mod is anyway newer */
-                    lys_latest_switch(latest, mod->parsed);
-                } else {
-                    if (strcmp(mod->parsed->revs[0].date, latest->parsed ? latest->parsed->revs[0].date : latest->compiled->revision) > 0) {
-                        lys_latest_switch(latest, mod->parsed);
-                    }
-                }
-            }
-        } else {
-            mod->parsed->latest_revision = 1;
-        }
+    if (!mod->implemented) {
+        /* pre-compile features of the module */
+        LY_CHECK_GOTO(lys_feature_precompile(ctx, mod->parsed->features, &mod->off_features), error);
+    }
 
-        /* add into context */
-        ly_set_add(&ctx->list, mod, LY_SET_OPT_USEASLIST);
+    /* decide the latest revision */
+    latest = (struct lys_module*)ly_ctx_get_module_latest(ctx, mod->name);
+    if (latest) {
+        if (mod->revision) {
+            if (!latest->revision) {
+                /* latest has no revision, so mod is anyway newer */
+                mod->latest_revision = latest->latest_revision;
+                latest->latest_revision = 0;
+            } else if (strcmp(mod->revision, latest->revision) > 0) {
+                mod->latest_revision = latest->latest_revision;
+                latest->latest_revision = 0;
+            }
+        }
+    } else {
+        mod->latest_revision = 1;
+    }
+
+    /* add into context */
+    ly_set_add(&ctx->list, mod, LY_SET_OPT_USEASLIST);
 
 finish_parsing:
-        /* resolve imports */
-        mod->parsed->parsing = 1;
-        LY_ARRAY_FOR(mod->parsed->imports, u) {
-            imp = &mod->parsed->imports[u];
-            if (!imp->module && lysp_load_module(ctx, imp->name, imp->rev[0] ? imp->rev : NULL, 0, 0, &imp->module)) {
-                goto error_ctx;
-            }
-            /* check for importing the same module twice */
-            for (i = 0; i < u; ++i) {
-                if (imp->module == mod->parsed->imports[i].module) {
-                    LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Single revision of the module \"%s\" referred twice.", imp->name);
-                    goto error_ctx;
-                }
-            }
+    /* resolve imports */
+    mod->parsed->parsing = 1;
+    LY_ARRAY_FOR(mod->parsed->imports, u) {
+        imp = &mod->parsed->imports[u];
+        if (!imp->module && lysp_load_module(ctx, imp->name, imp->rev[0] ? imp->rev : NULL, 0, 0, &imp->module)) {
+            goto error_ctx;
         }
-        LY_ARRAY_FOR(mod->parsed->includes, u) {
-            inc = &mod->parsed->includes[u];
-            if (!inc->submodule && lysp_load_submodule(&context, mod->parsed, inc)) {
+        /* check for importing the same module twice */
+        for (i = 0; i < u; ++i) {
+            if (imp->module == mod->parsed->imports[i].module) {
+                LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Single revision of the module \"%s\" referred twice.", imp->name);
                 goto error_ctx;
             }
         }
-        mod->parsed->parsing = 0;
-
-        /* check name collisions - typedefs and groupings */
-        LY_CHECK_GOTO(lysp_check_typedefs(&context), error_ctx);
     }
+    LY_ARRAY_FOR(mod->parsed->includes, u) {
+        inc = &mod->parsed->includes[u];
+        if (!inc->submodule && lysp_load_submodule(&context, mod->parsed, inc)) {
+            goto error_ctx;
+        }
+        if (!mod->implemented) {
+            /* pre-compile features of the module */
+            LY_CHECK_GOTO(lys_feature_precompile(ctx, inc->submodule->features, &mod->off_features), error);
+        }
+    }
+    mod->parsed->parsing = 0;
+
+    /* check name collisions - typedefs and groupings */
+    LY_CHECK_GOTO(lysp_check_typedefs(&context, mod->parsed), error_ctx);
 
     return mod;
 
@@ -643,7 +689,17 @@
 API struct lys_module *
 lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format)
 {
-    return lys_parse_mem_(ctx, data, format, 1, NULL, NULL, NULL);
+    struct lys_module *mod;
+
+    mod = lys_parse_mem_module(ctx, data, format, 1, NULL, NULL);
+    LY_CHECK_RET(!mod, NULL);
+
+    if (lys_compile(mod, 0)) {
+        ly_set_rm(&ctx->list, mod, NULL);
+        lys_module_free(mod, NULL);
+        return NULL;
+    }
+    return mod;
 }
 
 static void
@@ -667,11 +723,14 @@
 #endif
 }
 
-struct lys_module *
+void *
 lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
-              LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data)
+                    LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
+                    void *check_data)
 {
-    struct lys_module *mod;
+    void *result;
+    struct lys_module *mod = NULL;
+    struct lysp_submodule *submod = NULL;
     size_t length;
     char *addr;
 
@@ -687,25 +746,53 @@
         return NULL;
     }
 
-    mod = lys_parse_mem_(ctx, addr, format, implement, main_ctx, custom_check, check_data);
+    if (main_ctx) {
+        result = submod = lys_parse_mem_submodule(ctx, addr, format, main_ctx, custom_check, check_data);
+    } else {
+        result = mod = lys_parse_mem_module(ctx, addr, format, implement, custom_check, check_data);
+        if (mod && implement && lys_compile(mod, 0)) {
+            ly_set_rm(&ctx->list, mod, NULL);
+            lys_module_free(mod, NULL);
+            result = mod = NULL;
+        }
+    }
     ly_munmap(addr, length);
 
-    if (mod && !mod->parsed->filepath) {
-        lys_parse_set_filename(ctx, &mod->parsed->filepath, fd);
+    if (mod && !mod->filepath) {
+        lys_parse_set_filename(ctx, &mod->filepath, fd);
+    } else if (submod && !submod->filepath) {
+        lys_parse_set_filename(ctx, &submod->filepath, fd);
     }
 
-    return mod;
+    return result;
+}
+
+struct lys_module *
+lys_parse_fd_module(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement,
+                    LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
+                    void *check_data)
+{
+    return (struct lys_module*)lys_parse_fd_(ctx, fd, format, implement, NULL, custom_check, check_data);
+}
+
+struct lysp_submodule *
+lys_parse_fd_submodule(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, struct ly_parser_ctx *main_ctx,
+                       LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
+                       void *check_data)
+{
+    assert(main_ctx);
+    return (struct lysp_submodule*)lys_parse_fd_(ctx, fd, format, 0, main_ctx, custom_check, check_data);
 }
 
 API struct lys_module *
 lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format)
 {
-    return lys_parse_fd_(ctx, fd, format, 1, NULL, NULL, NULL);
+    return lys_parse_fd_module(ctx, fd, format, 1, NULL, NULL);
 }
 
 struct lys_module *
-lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
-                LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data)
+lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, int implement,
+                LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data), void *check_data)
 {
     int fd;
     struct lys_module *mod;
@@ -717,7 +804,7 @@
     fd = open(path, O_RDONLY);
     LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
 
-    mod = lys_parse_fd_(ctx, fd, format, implement, main_ctx, custom_check, check_data);
+    mod = lys_parse_fd_module(ctx, fd, format, implement, custom_check, check_data);
     close(fd);
     LY_CHECK_RET(!mod, NULL);
 
@@ -732,10 +819,10 @@
     dot = strrchr(filename, '.');
 
     /* name */
-    len = strlen(mod->parsed->name);
-    if (strncmp(filename, mod->parsed->name, len) ||
+    len = strlen(mod->name);
+    if (strncmp(filename, mod->name, len) ||
             ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
-        LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->parsed->name);
+        LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->name);
     }
     if (rev) {
         len = dot - ++rev;
@@ -745,13 +832,13 @@
         }
     }
 
-    if (!mod->parsed->filepath) {
+    if (!mod->filepath) {
         /* store URI */
         char rpath[PATH_MAX];
         if (realpath(path, rpath) != NULL) {
-            mod->parsed->filepath = lydict_insert(ctx, rpath, 0);
+            mod->filepath = lydict_insert(ctx, rpath, 0);
         } else {
-            mod->parsed->filepath = lydict_insert(ctx, path, 0);
+            mod->filepath = lydict_insert(ctx, path, 0);
         }
     }
 
@@ -761,7 +848,7 @@
 API struct lys_module *
 lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format)
 {
-    return lys_parse_path_(ctx, path, format, 1, NULL, NULL, NULL);
+    return lys_parse_path_(ctx, path, format, 1, NULL, NULL);
 }
 
 API LY_ERR
diff --git a/src/tree_schema.h b/src/tree_schema.h
index a6ed85e..bcf92d4 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -216,7 +216,7 @@
  * @brief YANG include-stmt
  */
 struct lysp_include {
-    struct lysp_module *submodule;   /**< pointer to the parsed submodule structure
+    struct lysp_submodule *submodule;/**< pointer to the parsed submodule structure
                                          (mandatory, but resolved when the referring module is completely parsed) */
     const char *name;                /**< name of the included submodule (mandatory) */
     const char *dsc;                 /**< description */
@@ -594,9 +594,7 @@
 #define LYS_STATUS_MASK  0x1C        /**< mask for status value */
 #define LYS_MAND_TRUE    0x20        /**< mandatory true; applicable only to ::lysp_node_choice/::lysc_node_choice,
                                           ::lysp_node_leaf/::lysc_node_leaf and ::lysp_node_anydata/::lysc_node_anydata */
-#define LYS_MAND_FALSE   0x40        /**< mandatory false; applicable only to
-                                          ::lysp_node_choice/::lysc_node_choice, ::lysp_node_leaf/::lysc_node_leaf
-                                          and ::lysp_node_anydata/::lysc_node_anydata */
+#define LYS_MAND_FALSE   0x40        /**< mandatory false; applicable only to ::lysp_node_choice, ::lysp_node_leaf and ::lysp_node_anydata */
 #define LYS_MAND_MASK    0x60        /**< mask for mandatory values */
 #define LYS_PRESENCE     0x80        /**< flag for presence property of a container, applicable only to ::lysc_node_container */
 #define LYS_UNIQUE       0x80        /**< flag for leafs being part of a unique set, applicable only to ::lysc_node_leaf */
@@ -624,7 +622,7 @@
 #define LYS_SET_RANGE    0x0080      /**< type's flag for present range substatement */
 #define LYS_SET_TYPE     0x0100      /**< type's flag for present type substatement */
 #define LYS_SET_REQINST  0x0200      /**< type's flag for present require-instance substatement */
-#define LYS_SET_DFLT     0x0200      /**< flag to mark leaf with own default value, not a default value taken from its type, and default
+#define LYS_SET_DFLT     0x0200      /**< flag to mark leaf with own (or refined) default value, not a default value taken from its type, and default
                                           cases of choice. This information is important for refines, since it is prohibited to make leafs
                                           with default statement mandatory. In case the default leaf value is taken from type, it is thrown
                                           away when it is refined to be mandatory node. */
@@ -868,24 +866,12 @@
  * Simple structure corresponding to the YANG format. The schema is only syntactically validated.
  */
 struct lysp_module {
-    struct ly_ctx *ctx;              /**< libyang context of the module (mandatory) */
-    const char *name;                /**< name of the module (mandatory) */
-    const char *filepath;            /**< path, if the schema was read from a file, NULL in case of reading from memory */
-    union {
-        /* module */
-        const char *ns;              /**< namespace of the module (module - mandatory) */
-        /* submodule */
-        const char *belongsto;       /**< belongs to parent module (submodule - mandatory) */
-    };
-    const char *prefix;              /**< module prefix or submodule belongsto prefix of main module (mandatory) */
+    struct lys_module *mod;          /**< covering module structure */
+
     struct lysp_revision *revs;      /**< list of the module revisions ([sized array](@ref sizedarrays)), the first revision
                                           in the list is always the last (newest) revision of the module */
     struct lysp_import *imports;     /**< list of imported modules ([sized array](@ref sizedarrays)) */
     struct lysp_include *includes;   /**< list of included submodules ([sized array](@ref sizedarrays)) */
-    const char *org;                 /**< party/company responsible for the module */
-    const char *contact;             /**< contact information for the module */
-    const char *dsc;                 /**< description of the module */
-    const char *ref;                 /**< cross-reference for the module */
     struct lysp_ext *extensions;     /**< list of extension statements ([sized array](@ref sizedarrays)) */
     struct lysp_feature *features;   /**< list of feature definitions ([sized array](@ref sizedarrays)) */
     struct lysp_ident *identities;   /**< list of identities ([sized array](@ref sizedarrays)) */
@@ -898,13 +884,41 @@
     struct lysp_deviation *deviations; /**< list of deviations ([sized array](@ref sizedarrays)) */
     struct lysp_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
 
-    uint8_t submodule:1;             /**< flag to distinguish main modules and submodules */
-    uint8_t implemented:1;           /**< flag if the module is implemented, not just imported */
+    uint8_t parsing:1;               /**< flag for circular check */
+};
+
+struct lysp_submodule {
+    const char *belongsto;           /**< belongs to parent module (submodule - mandatory) */
+
+    struct lysp_revision *revs;      /**< list of the module revisions ([sized array](@ref sizedarrays)), the first revision
+                                          in the list is always the last (newest) revision of the module */
+    struct lysp_import *imports;     /**< list of imported modules ([sized array](@ref sizedarrays)) */
+    struct lysp_include *includes;   /**< list of included submodules ([sized array](@ref sizedarrays)) */
+    struct lysp_ext *extensions;     /**< list of extension statements ([sized array](@ref sizedarrays)) */
+    struct lysp_feature *features;   /**< list of feature definitions ([sized array](@ref sizedarrays)) */
+    struct lysp_ident *identities;   /**< list of identities ([sized array](@ref sizedarrays)) */
+    struct lysp_tpdf *typedefs;      /**< list of typedefs ([sized array](@ref sizedarrays)) */
+    struct lysp_grp *groupings;      /**< list of groupings ([sized array](@ref sizedarrays)) */
+    struct lysp_node *data;          /**< list of module's top-level data nodes (linked list) */
+    struct lysp_augment *augments;   /**< list of augments ([sized array](@ref sizedarrays)) */
+    struct lysp_action *rpcs;        /**< list of RPCs ([sized array](@ref sizedarrays)) */
+    struct lysp_notif *notifs;       /**< list of notifications ([sized array](@ref sizedarrays)) */
+    struct lysp_deviation *deviations; /**< list of deviations ([sized array](@ref sizedarrays)) */
+    struct lysp_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+
+    uint8_t parsing:1;               /**< flag for circular check */
+
     uint8_t latest_revision:2;       /**< flag to mark the latest available revision:
                                           1 - the latest revision in searchdirs was not searched yet and this is the
                                           latest revision in the current context
                                           2 - searchdirs were searched and this is the latest available revision */
-    uint8_t parsing:1;               /**< flag for circular check */
+    const char *name;                /**< name of the module (mandatory) */
+    const char *filepath;            /**< path, if the schema was read from a file, NULL in case of reading from memory */
+    const char *prefix;              /**< submodule belongsto prefix of main module (mandatory) */
+    const char *org;                 /**< party/company responsible for the module */
+    const char *contact;             /**< contact information for the module */
+    const char *dsc;                 /**< description of the module */
+    const char *ref;                 /**< cross-reference for the module */
     uint8_t version;                 /**< yang-version (LYS_VERSION values) */
 };
 
@@ -959,6 +973,8 @@
  */
 struct lysc_when {
     struct lyxp_expr *cond;          /**< XPath when condition */
+    const char *dsc;                 /**< description */
+    const char *ref;                 /**< reference */
     struct lysc_node *context;       /**< context node of the expression */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
 };
@@ -968,6 +984,8 @@
  */
 struct lysc_ident {
     const char *name;                /**< identity name (mandatory), including possible prefix */
+    const char *dsc;                 /**< description */
+    const char *ref;                 /**< reference */
     struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
     struct lysc_ident **derived;     /**< list of (pointers to the) derived identities ([sized array](@ref sizedarrays)) */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
@@ -979,6 +997,8 @@
  */
 struct lysc_feature {
     const char *name;                /**< feature name (mandatory) */
+    const char *dsc;                 /**< description */
+    const char *ref;                 /**< reference */
     struct lysc_feature **depfeatures;/**< list of pointers to other features depending on this one ([sized array](@ref sizedarrays)) */
     struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
@@ -1008,11 +1028,6 @@
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
 };
 
-struct lysc_default {
-    struct lys_module *module;       /**< module where the default was defined */
-    const char *value;               /**< default value (with possible prefixes from the module where defined) */
-};
-
 struct lysc_range {
     struct lysc_range_part {
         union {                      /**< min boundary TODO decimal */
@@ -1024,6 +1039,8 @@
             uint64_t max_u64;        /**< for uint8, uint16, uint32 and uint64 */
         };
     } *parts;                        /**< compiled range expression ([sized array](@ref sizedarrays)) */
+    const char *dsc;                 /**< description */
+    const char *ref;                 /**< reference */
     const char *emsg;                /**< error-message */
     const char *eapptag;             /**< error-app-tag value */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
@@ -1032,6 +1049,8 @@
 struct lysc_pattern {
     pcre *expr;                      /**< compiled regular expression */
     pcre_extra *expr_extra;          /**< additional information to speed up matching */
+    const char *dsc;                 /**< description */
+    const char *ref;                 /**< reference */
     const char *emsg;                /**< error-message */
     const char *eapptag;             /**< error-app-tag value */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
@@ -1042,6 +1061,8 @@
 struct lysc_must {
     struct lys_module *module;       /**< module where the must was defined */
     struct lyxp_expr *cond;          /**< XPath when condition */
+    const char *dsc;                 /**< description */
+    const char *ref;                 /**< reference */
     const char *emsg;                /**< error-message */
     const char *eapptag;             /**< error-app-tag value */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
@@ -1049,12 +1070,14 @@
 
 struct lysc_type {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+    const char *dflt;                /**< type's default value if any */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
 };
 
 struct lysc_type_num {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+    const char *dflt;                /**< type's default value if any */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     struct lysc_range *range;        /**< Optional range limitation */
@@ -1062,6 +1085,7 @@
 
 struct lysc_type_dec {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+    const char *dflt;                /**< type's default value if any */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     uint8_t fraction_digits;         /**< fraction digits specification */
@@ -1070,6 +1094,7 @@
 
 struct lysc_type_str {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+    const char *dflt;                /**< type's default value if any */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     struct lysc_range *length;       /**< Optional length limitation */
@@ -1078,10 +1103,13 @@
 
 struct lysc_type_enum {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+    const char *dflt;                /**< type's default value if any */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     struct lysc_type_enum_item {
         const char *name;            /**< enumeration identifier */
+        const char *dsc;             /**< description */
+        const char *ref;             /**< reference */
         struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
         struct lysc_ext_instance *exts;    /**< list of the extension instances ([sized array](@ref sizedarrays)) */
         int32_t value;               /**< integer value associated with the enumeration */
@@ -1090,6 +1118,7 @@
 
 struct lysc_type_leafref {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+    const char *dflt;                /**< type's default value if any */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     const char* path;                /**< target path */
@@ -1100,6 +1129,7 @@
 
 struct lysc_type_identityref {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+    const char *dflt;                /**< type's default value if any */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     struct lysc_ident **bases;       /**< list of pointers to the base identities ([sized array](@ref sizedarrays)),
@@ -1108,6 +1138,7 @@
 
 struct lysc_type_instanceid {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+    const char *dflt;                /**< type's default value if any */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     uint8_t require_instance;        /**< require-instance flag */
@@ -1115,10 +1146,13 @@
 
 struct lysc_type_bits {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+    const char *dflt;                /**< type's default value if any */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     struct lysc_type_bits_item {
         const char *name;            /**< bit identifier */
+        const char *dsc;             /**< description */
+        const char *ref;             /**< reference */
         struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
         struct lysc_ext_instance *exts;    /**< list of the extension instances ([sized array](@ref sizedarrays)) */
         uint32_t position;           /**< non-negative integer value associated with the bit */
@@ -1127,6 +1161,7 @@
 
 struct lysc_type_union {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+    const char *dflt;                /**< type's default value if any */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     struct lysc_type **types;        /**< list of types in the union ([sized array](@ref sizedarrays)), mandatory (at least 1 item) */
@@ -1134,6 +1169,7 @@
 
 struct lysc_type_bin {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+    const char *dflt;                /**< type's default value if any */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     struct lysc_range *length;       /**< Optional length limitation */
@@ -1168,6 +1204,8 @@
                                           itself. In case of the first node, this pointer points to the last
                                           node in the list. */
     const char *name;                /**< node name (mandatory) */
+    const char *dsc;                 /**< description */
+    const char *ref;                 /**< reference */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     struct lysc_when *when;          /**< when statement */
     struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
@@ -1185,6 +1223,8 @@
                                           itself. In case of the first node, this pointer points to the last
                                           node in the list. */
     const char *name;                /**< node name (mandatory) */
+    const char *dsc;                 /**< description */
+    const char *ref;                 /**< reference */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     struct lysc_when *when;          /**< when statement */
     struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
@@ -1207,6 +1247,8 @@
                                           itself. In case of the first node, this pointer points to the last
                                           node in the list. */
     const char *name;                /**< name of the case, including the implicit case */
+    const char *dsc;                 /**< description */
+    const char *ref;                 /**< reference */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     struct lysc_when *when;          /**< when statement */
     struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
@@ -1229,6 +1271,8 @@
                                           itself. In case of the first node, this pointer points to the last
                                           node in the list. */
     const char *name;                /**< node name (mandatory) */
+    const char *dsc;                 /**< description */
+    const char *ref;                 /**< reference */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     struct lysc_when *when;          /**< when statement */
     struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
@@ -1251,6 +1295,8 @@
                                           itself. In case of the first node, this pointer points to the last
                                           node in the list. */
     const char *name;                /**< node name (mandatory) */
+    const char *dsc;                 /**< description */
+    const char *ref;                 /**< reference */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     struct lysc_when *when;          /**< when statement */
     struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
@@ -1274,6 +1320,8 @@
                                           itself. In case of the first node, this pointer points to the last
                                           node in the list. */
     const char *name;                /**< node name (mandatory) */
+    const char *dsc;                 /**< description */
+    const char *ref;                 /**< reference */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     struct lysc_when *when;          /**< when statement */
     struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
@@ -1300,6 +1348,8 @@
                                           itself. In case of the first node, this pointer points to the last
                                           node in the list. */
     const char *name;                /**< node name (mandatory) */
+    const char *dsc;                 /**< description */
+    const char *ref;                 /**< reference */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     struct lysc_when *when;          /**< when statement */
     struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
@@ -1327,6 +1377,8 @@
                                           itself. In case of the first node, this pointer points to the last
                                           node in the list. */
     const char *name;                /**< node name (mandatory) */
+    const char *dsc;                 /**< description */
+    const char *ref;                 /**< reference */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     struct lysc_when *when;          /**< when statement */
     struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
@@ -1341,12 +1393,7 @@
  * Contains only the necessary information for the data validation.
  */
 struct lysc_module {
-    struct ly_ctx *ctx;              /**< libyang context of the module (mandatory) */
-    const char *name;                /**< name of the module (mandatory) */
-    const char *filepath;            /**< path, if the schema was read from a file, NULL in case of reading from memory */
-    const char *ns;                  /**< namespace of the module (mandatory) */
-    const char *prefix;              /**< module prefix (mandatory) */
-    const char *revision;            /**< the revision of the module */
+    struct lys_module *mod;          /**< covering module structure */
     struct lysc_import *imports;     /**< list of imported modules ([sized array](@ref sizedarrays)) */
 
     struct lysc_feature *features;   /**< list of feature definitions ([sized array](@ref sizedarrays)) */
@@ -1355,13 +1402,6 @@
     struct lysc_action *rpcs;        /**< list of RPCs ([sized array](@ref sizedarrays)) */
     struct lysc_notif *notifs;       /**< list of notifications ([sized array](@ref sizedarrays)) */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-
-    uint8_t implemented:1;           /**< flag if the module is implemented, not just imported */
-    uint8_t latest_revision:2;       /**< flag to mark the latest available revision:
-                                          1 - the latest revision in searchdirs was not searched yet and this is the
-                                          latest revision in the current context
-                                          2 - searchdirs were searched and this is the latest available revision */
-    uint8_t version;                 /**< yang-version (LYS_VERSION values) */
 };
 
 /**
@@ -1451,8 +1491,33 @@
  * @brief Available YANG schema tree structures representing YANG module.
  */
 struct lys_module {
+    struct ly_ctx *ctx;              /**< libyang context of the module (mandatory) */
+    const char *name;                /**< name of the module (mandatory) */
+    const char *revision;            /**< revision of the module (if present) */
+    const char *ns;                  /**< namespace of the module (module - mandatory) */
+    const char *prefix;              /**< module prefix or submodule belongsto prefix of main module (mandatory) */
+    const char *filepath;            /**< path, if the schema was read from a file, NULL in case of reading from memory */
+    const char *org;                 /**< party/company responsible for the module */
+    const char *contact;             /**< contact information for the module */
+    const char *dsc;                 /**< description of the module */
+    const char *ref;                 /**< cross-reference for the module */
+
     struct lysp_module *parsed;      /**< Simply parsed (unresolved) YANG schema tree */
-    struct lysc_module *compiled;    /**< Compiled and fully validated YANG schema tree for data parsing */
+    struct lysc_module *compiled;    /**< Compiled and fully validated YANG schema tree for data parsing.
+                                          Available only for implemented modules. */
+    struct lysc_feature *off_features;/**< List of pre-compiled features of the module in non implemented modules ([sized array](@ref sizedarrays)).
+                                          These features are always disabled and cannot be enabled until the module
+                                          become implemented. The features are present in this form to allow their linkage
+                                          from if-feature statements of the compiled schemas and their proper use in case
+                                          the module became implemented in future (no matter if implicitly via augment/deviate
+                                          or explicitly via ly_ctx_module_implement()). */
+
+    uint8_t implemented:1;           /**< flag if the module is implemented, not just imported */
+    uint8_t latest_revision:2;       /**< flag to mark the latest available revision:
+                                          1 - the latest revision in searchdirs was not searched yet and this is the
+                                          latest revision in the current context
+                                          2 - searchdirs were searched and this is the latest available revision */
+    uint8_t version;                 /**< yang-version (LYS_VERSION values) */
 };
 
 /**
@@ -1549,25 +1614,6 @@
 LY_ERR lys_search_localfile(const char * const *searchpaths, int cwd, const char *name, const char *revision, char **localfile, LYS_INFORMAT *format);
 
 /**
- * @defgroup scflags Schema compile flags
- * @ingroup schematree
- *
- * @{
- */
-#define LYSC_OPT_FREE_SP 1           /**< Free the input printable schema */
-/** @} scflags */
-
-/**
- * @brief Compile printable schema into a validated schema linking all the references.
- *
- * @param[in, out] mod Schema structure holding pointers to both schema structure types. The ::lys_module#parsed
- * member is used as input and ::lys_module#compiled is used to hold the result of the compilation.
- * @param[in] options Various options to modify compiler behavior, see [compile flags](@ref scflags).
- * @return LY_ERR value.
- */
-LY_ERR lys_compile(struct lys_module *mod, int options);
-
-/**
  * @brief Get next schema tree (sibling) node element that can be instantiated in a data tree. Returned node can
  * be from an augment.
  *
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index 4761520..f94cfed 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -62,8 +62,8 @@
 
 #define COMPILE_CHECK_UNIQUENESS(CTX, ARRAY, MEMBER, EXCL, STMT, IDENT) \
     if (ARRAY) { \
-        for (unsigned int u = 0; u < LY_ARRAY_SIZE(ARRAY); ++u) { \
-            if (&(ARRAY)[u] != EXCL && (void*)((ARRAY)[u].MEMBER) == (void*)(IDENT)) { \
+        for (unsigned int u__ = 0; u__ < LY_ARRAY_SIZE(ARRAY); ++u__) { \
+            if (&(ARRAY)[u__] != EXCL && (void*)((ARRAY)[u__].MEMBER) == (void*)(IDENT)) { \
                 LOGVAL((CTX)->ctx, LY_VLOG_STR, (CTX)->path, LY_VCODE_DUPIDENT, IDENT, STMT); \
                 return LY_EVALID; \
             } \
@@ -174,16 +174,31 @@
 #define LYS_IFF_LP 0x04 /* ( */
 #define LYS_IFF_RP 0x08 /* ) */
 
+/**
+ * @brief Find a feature of the given name and referenced in the given module.
+ *
+ * If the compiled schema is available (the schema is implemented), the feature from the compiled schema is
+ * returned. Otherwise, the special array of pre-compiled features is used to search for the feature. Such
+ * features are always disabled (feature from not implemented schema cannot be enabled), but in case the schema
+ * will be made implemented in future (no matter if implicitly via augmenting/deviating it or explicitly via
+ * ly_ctx_module_implement()), the compilation of these feature structure is finished, but the pointers
+ * assigned till that time will be still valid.
+ *
+ * @param[in] mod Module where the feature was referenced (used to resolve prefix of the feature).
+ * @param[in] name Name of the feature including possible prefix.
+ * @param[in] len Length of the string representing the feature identifier in the name variable (mandatory!).
+ * @return Pointer to the feature structure if found, NULL otherwise.
+ */
 static struct lysc_feature *
-lysc_feature_find(struct lysc_module *mod, const char *name, size_t len)
+lys_feature_find(struct lys_module *mod, const char *name, size_t len)
 {
     size_t i;
-    struct lysc_feature *f;
+    struct lysc_feature *f, *flist;
 
     for (i = 0; i < len; ++i) {
         if (name[i] == ':') {
             /* we have a prefixed feature */
-            mod = lysc_module_find_prefix(mod, name, i);
+            mod = lys_module_find_prefix(mod, name, i);
             LY_CHECK_RET(!mod, NULL);
 
             name = &name[i + 1];
@@ -192,8 +207,14 @@
     }
 
     /* we have the correct module, get the feature */
-    LY_ARRAY_FOR(mod->features, i) {
-        f = &mod->features[i];
+    if (mod->implemented) {
+        /* module is implemented so there is already the compiled schema */
+        flist = mod->compiled->features;
+    } else {
+        flist = mod->off_features;
+    }
+    LY_ARRAY_FOR(flist, i) {
+        f = &flist[i];
         if (!strncmp(f->name, name, len) && f->name[len] == '\0') {
             return f;
         }
@@ -223,7 +244,7 @@
     LY_CHECK_ERR_RET(!mod->parsed->extensions,
                      LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
                             "Extension instance \"%s\" refers \"%s\" module that does not contain extension definitions.",
-                            ext_p->name, mod->parsed->name),
+                            ext_p->name, mod->name),
                      LY_EVALID);
     name = &ext_p->name[u + 1];
     /* find the extension definition there */
@@ -314,7 +335,7 @@
 
     if (checkversion || expr_size > 1) {
         /* check that we have 1.1 module */
-        if (ctx->mod_def->parsed->version != LYS_VERSION_1_1) {
+        if (ctx->mod_def->version != LYS_VERSION_1_1) {
             LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
                    "Invalid value \"%s\" of if-feature - YANG 1.1 expression in YANG 1.0 module.", *value);
             return LY_EVALID;
@@ -382,12 +403,10 @@
             iff_setop(iff->expr, LYS_IFF_F, expr_size--);
 
             /* now get the link to the feature definition */
-            f = lysc_feature_find(ctx->mod->compiled, &c[i], j - i);
-            LY_CHECK_ERR_GOTO(!f,
-                              LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
-                                     "Invalid value \"%s\" of if-feature - unable to find feature \"%.*s\".", *value, j - i, &c[i]);
-                              rc = LY_EVALID,
-                              error)
+            f = lys_feature_find(ctx->mod_def, &c[i], j - i);
+            LY_CHECK_ERR_GOTO(!f, LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
+                                         "Invalid value \"%s\" of if-feature - unable to find feature \"%.*s\".", *value, j - i, &c[i]);
+                              rc = LY_EVALID, error)
             iff->features[f_size] = f;
             LY_ARRAY_INCREMENT(iff->features);
             f_size--;
@@ -421,6 +440,8 @@
     LY_ERR ret = LY_SUCCESS;
 
     when->cond = lyxp_expr_parse(ctx->ctx, when_p->cond);
+    DUP_STRING(ctx->ctx, when_p->dsc, when->dsc);
+    DUP_STRING(ctx->ctx, when_p->ref, when->ref);
     LY_CHECK_ERR_GOTO(!when->cond, ret = ly_errcode(ctx->ctx), done);
     COMPILE_ARRAY_GOTO(ctx, when_p->exts, when->exts, options, u, lys_compile_ext, ret, done);
 
@@ -439,6 +460,8 @@
 
     DUP_STRING(ctx->ctx, must_p->eapptag, must->eapptag);
     DUP_STRING(ctx->ctx, must_p->emsg, must->emsg);
+    DUP_STRING(ctx->ctx, must_p->dsc, must->dsc);
+    DUP_STRING(ctx->ctx, must_p->ref, must->ref);
     COMPILE_ARRAY_GOTO(ctx, must_p->exts, must->exts, options, u, lys_compile_ext, ret, done);
 
 done:
@@ -450,7 +473,6 @@
 {
     unsigned int u;
     struct lys_module *mod = NULL;
-    struct lysc_module *comp;
     LY_ERR ret = LY_SUCCESS;
 
     DUP_STRING(ctx->ctx, imp_p->prefix, imp->prefix);
@@ -461,21 +483,20 @@
      * The compiled version is needed only for augments, deviates and leafrefs, so they are checked (and added,
      * if needed) when these nodes are finally being instantiated and validated at the end of schema compilation. */
     if (!imp->module->parsed) {
-        comp = imp->module->compiled;
-        /* try to get filepath from the compiled version */
-        if (comp->filepath) {
-            mod = (struct lys_module*)lys_parse_path(ctx->ctx, comp->filepath,
-                                 !strcmp(&comp->filepath[strlen(comp->filepath - 4)], ".yin") ? LYS_IN_YIN : LYS_IN_YANG);
+        /* try to use filepath if present */
+        if (imp->module->filepath) {
+            mod = (struct lys_module*)lys_parse_path(ctx->ctx, imp->module->filepath,
+                                 !strcmp(&imp->module->filepath[strlen(imp->module->filepath - 4)], ".yin") ? LYS_IN_YIN : LYS_IN_YANG);
             if (mod != imp->module) {
                 LOGERR(ctx->ctx, LY_EINT, "Filepath \"%s\" of the module \"%s\" does not match.",
-                       comp->filepath, comp->name);
+                       imp->module->filepath, imp->module->name);
                 mod = NULL;
             }
         }
         if (!mod) {
-            if (lysp_load_module(ctx->ctx, comp->name, comp->revision, 0, 1, &mod)) {
+            if (lysp_load_module(ctx->ctx, imp->module->name, imp->module->revision, 0, 1, &mod)) {
                 LOGERR(ctx->ctx, LY_ENOTFOUND, "Unable to reload \"%s\" module to import it into \"%s\", source data not found.",
-                       comp->name, ctx->mod->compiled->name);
+                       imp->module->name, ctx->mod->name);
                 return LY_ENOTFOUND;
             }
         }
@@ -493,6 +514,8 @@
 
     COMPILE_CHECK_UNIQUENESS(ctx, idents, name, ident, "identity", ident_p->name);
     DUP_STRING(ctx->ctx, ident_p->name, ident->name);
+    DUP_STRING(ctx->ctx, ident_p->ref, ident->dsc);
+    DUP_STRING(ctx->ctx, ident_p->ref, ident->dsc);
     COMPILE_ARRAY_GOTO(ctx, ident_p->iffeatures, ident->iffeatures, options, u, lys_compile_iffeature, ret, done);
     /* backlings (derived) can be added no sooner than when all the identities in the current module are present */
     COMPILE_ARRAY_GOTO(ctx, ident_p->exts, ident->exts, options, u, lys_compile_ext, ret, done);
@@ -525,7 +548,7 @@
 
     assert(ident || bases);
 
-    if (LY_ARRAY_SIZE(bases_p) > 1 && ctx->mod_def->parsed->version < 2) {
+    if (LY_ARRAY_SIZE(bases_p) > 1 && ctx->mod_def->version < 2) {
         LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
                "Multiple bases in %s are allowed only in YANG 1.1 modules.", ident ? "identity" : "identityref type");
         return LY_EVALID;
@@ -603,42 +626,81 @@
     return LY_SUCCESS;
 }
 
+LY_ERR
+lys_feature_precompile(struct ly_ctx *ctx, struct lysp_feature *features_p, struct lysc_feature **features)
+{
+    unsigned int offset = 0, u;
+    struct lysc_ctx context = {0};
+
+    assert(ctx);
+    context.ctx = ctx;
+
+    if (!features_p) {
+        return LY_SUCCESS;
+    }
+    if (*features) {
+        offset = LY_ARRAY_SIZE(*features);
+    }
+
+    LY_ARRAY_CREATE_RET(ctx, *features, LY_ARRAY_SIZE(features_p), LY_EMEM);
+    LY_ARRAY_FOR(features_p, u) {
+        LY_ARRAY_INCREMENT(*features);
+        COMPILE_CHECK_UNIQUENESS(&context, *features, name, &(*features)[offset + u], "feature", features_p[u].name);
+        DUP_STRING(ctx, features_p[u].name, (*features)[offset + u].name);
+        DUP_STRING(ctx, features_p[u].dsc, (*features)[offset + u].dsc);
+        DUP_STRING(ctx, features_p[u].ref, (*features)[offset + u].ref);
+        (*features)[offset + u].flags = features_p[u].flags;
+    }
+
+    return LY_SUCCESS;
+}
+
 /**
- * @brief Create compiled feature structure.
+ * @brief Create pre-compiled features array.
+ *
+ * See lys_feature_precompile() for more details.
+ *
  * @param[in] ctx Compile context.
  * @param[in] feature_p Parsed feature definition to compile.
  * @param[in] options Various options to modify compiler behavior, see [compile flags](@ref scflags).
- * @param[in] features List of already compiled features to check name duplicity.
- * @param[in,out] feature Compiled feature structure to fill.
+ * @param[in,out] features List of already (pre)compiled features to find the corresponding precompiled feature structure.
  * @return LY_ERR value.
  */
 static LY_ERR
-lys_compile_feature(struct lysc_ctx *ctx, struct lysp_feature *feature_p, int options, struct lysc_feature *features, struct lysc_feature *feature)
+lys_feature_precompile_finish(struct lysc_ctx *ctx, struct lysp_feature *feature_p, int options, struct lysc_feature *features)
 {
-    unsigned int u, v;
+    unsigned int u, v, x;
+    struct lysc_feature *feature, **df;
     LY_ERR ret = LY_SUCCESS;
-    struct lysc_feature **df;
 
-    COMPILE_CHECK_UNIQUENESS(ctx, features, name, feature, "feature", feature_p->name);
-    DUP_STRING(ctx->ctx, feature_p->name, feature->name);
-    feature->flags = feature_p->flags;
+    /* find the preprecompiled feature */
+    LY_ARRAY_FOR(features, x) {
+        if (strcmp(features[x].name, feature_p->name)) {
+            continue;
+        }
+        feature = &features[x];
 
-    COMPILE_ARRAY_GOTO(ctx, feature_p->exts, feature->exts, options, u, lys_compile_ext, ret, done);
-    COMPILE_ARRAY_GOTO(ctx, feature_p->iffeatures, feature->iffeatures, options, u, lys_compile_iffeature, ret, done);
-    if (feature->iffeatures) {
-        for (u = 0; u < LY_ARRAY_SIZE(feature->iffeatures); ++u) {
-            if (feature->iffeatures[u].features) {
-                for (v = 0; v < LY_ARRAY_SIZE(feature->iffeatures[u].features); ++v) {
-                    /* add itself into the dependants list */
-                    LY_ARRAY_NEW_RET(ctx->ctx, feature->iffeatures[u].features[v]->depfeatures, df, LY_EMEM);
-                    *df = feature;
+        /* finish compilation started in lys_feature_precompile() */
+        COMPILE_ARRAY_GOTO(ctx, feature_p->exts, feature->exts, options, u, lys_compile_ext, ret, done);
+        COMPILE_ARRAY_GOTO(ctx, feature_p->iffeatures, feature->iffeatures, options, u, lys_compile_iffeature, ret, done);
+        if (feature->iffeatures) {
+            for (u = 0; u < LY_ARRAY_SIZE(feature->iffeatures); ++u) {
+                if (feature->iffeatures[u].features) {
+                    for (v = 0; v < LY_ARRAY_SIZE(feature->iffeatures[u].features); ++v) {
+                        /* add itself into the dependants list */
+                        LY_ARRAY_NEW_RET(ctx->ctx, feature->iffeatures[u].features[v]->depfeatures, df, LY_EMEM);
+                        *df = feature;
+                    }
+                    /* TODO check for circular dependency */
                 }
-                /* TODO check for circular dependency */
             }
         }
+    done:
+        return ret;
     }
-done:
-    return ret;
+
+    LOGINT(ctx->ctx);
+    return LY_EINT;
 }
 
 /**
@@ -1123,6 +1185,7 @@
         LY_CHECK_ERR_RET(!(*range), LOGMEM(ctx->ctx), LY_EMEM);
     }
 
+    /* we rewrite the following values as the types chain is being processed */
     if (range_p->eapptag) {
         lydict_remove(ctx->ctx, (*range)->eapptag);
         (*range)->eapptag = lydict_insert(ctx->ctx, range_p->eapptag, 0);
@@ -1131,6 +1194,14 @@
         lydict_remove(ctx->ctx, (*range)->emsg);
         (*range)->emsg = lydict_insert(ctx->ctx, range_p->emsg, 0);
     }
+    if (range_p->dsc) {
+        lydict_remove(ctx->ctx, (*range)->dsc);
+        (*range)->dsc = lydict_insert(ctx->ctx, range_p->dsc, 0);
+    }
+    if (range_p->ref) {
+        lydict_remove(ctx->ctx, (*range)->ref);
+        (*range)->ref = lydict_insert(ctx->ctx, range_p->ref, 0);
+    }
     /* extensions are taken only from the last range by the caller */
 
     (*range)->parts = parts;
@@ -1396,6 +1467,8 @@
         }
         DUP_STRING(ctx->ctx, patterns_p[u].eapptag, (*pattern)->eapptag);
         DUP_STRING(ctx->ctx, patterns_p[u].emsg, (*pattern)->emsg);
+        DUP_STRING(ctx->ctx, patterns_p[u].dsc, (*pattern)->dsc);
+        DUP_STRING(ctx->ctx, patterns_p[u].ref, (*pattern)->ref);
         COMPILE_ARRAY_GOTO(ctx, patterns_p[u].exts, (*pattern)->exts,
                            options, v, lys_compile_ext, ret, done);
     }
@@ -1457,7 +1530,7 @@
     uint32_t position = 0;
     struct lysc_type_enum_item *e, storage;
 
-    if (base_enums && ctx->mod_def->parsed->version < 2) {
+    if (base_enums && ctx->mod_def->version < 2) {
         LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "%s type can be subtyped only in YANG 1.1 modules.",
                basetype == LY_TYPE_ENUM ? "Enumeration" : "Bits");
         return LY_EVALID;
@@ -1466,6 +1539,8 @@
     LY_ARRAY_FOR(enums_p, u) {
         LY_ARRAY_NEW_RET(ctx->ctx, *enums, e, LY_EMEM);
         DUP_STRING(ctx->ctx, enums_p[u].name, e->name);
+        DUP_STRING(ctx->ctx, enums_p[u].ref, e->dsc);
+        DUP_STRING(ctx->ctx, enums_p[u].ref, e->ref);
         if (base_enums) {
             /* check the enum/bit presence in the base type - the set of enums/bits in the derived type must be a subset */
             LY_ARRAY_FOR(base_enums, v) {
@@ -1659,7 +1734,7 @@
             if (!mod) {
                 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
                        "Invalid leafref path predicate \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
-                       *predicate - start, start, src_prefix_len, src_prefix, path_context->compiled->name);
+                       *predicate - start, start, src_prefix_len, src_prefix, path_context->name);
                 goto cleanup;
             }
         } else {
@@ -1677,7 +1752,7 @@
         if (!src_node) {
             LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
                    "Invalid leafref path predicate \"%.*s\" - predicate's key node \"%.*s\" not found.",
-                   *predicate - start, start, src_len, src, mod->compiled->name);
+                   *predicate - start, start, src_len, src, mod->name);
             goto cleanup;
         }
 
@@ -1785,7 +1860,7 @@
                 goto cleanup;
             }
         }
-        if (!(dst_node->nodetype & (dst_node->module->compiled->version < LYS_VERSION_1_1 ? LYS_LEAF : LYS_LEAF | LYS_LEAFLIST))) {
+        if (!(dst_node->nodetype & (dst_node->module->version < LYS_VERSION_1_1 ? LYS_LEAF : LYS_LEAF | LYS_LEAFLIST))) {
             LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
                    "Invalid leafref path predicate \"%.*s\" - rel-path_keyexpr \"%.*s\" refers %s instead of leaf.",
                    *predicate - start, start, path_key_expr - pke_start, pke_start, lys_nodetype2str(dst_node->nodetype));
@@ -2055,7 +2130,7 @@
 }
 
 static LY_ERR lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_node_p, uint16_t context_flags, struct lysp_module *context_mod, const char *context_name,
-                               struct lysp_type *type_p, int options, struct lysc_type **type, const char **units, const char **dflt);
+                               struct lysp_type *type_p, int options, struct lysc_type **type, const char **units);
 /**
  * @brief The core of the lys_compile_type() - compile information about the given type (from typedef or leaf/leaf-list).
  * @param[in] ctx Compile context.
@@ -2309,7 +2384,7 @@
     case LY_TYPE_LEAFREF:
         /* RFC 7950 9.9.3 - require-instance */
         if (type_p->flags & LYS_SET_REQINST) {
-            if (context_mod->version < LYS_VERSION_1_1) {
+            if (context_mod->mod->version < LYS_VERSION_1_1) {
                 if (tpdfname) {
                     LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
                            "Leafref type \"%s\" can be restricted by require-instance statement only in YANG 1.1 modules.", tpdfname);
@@ -2386,7 +2461,7 @@
             additional = 0;
             LY_ARRAY_CREATE_RET(ctx->ctx, un->types, LY_ARRAY_SIZE(type_p->types), LY_EVALID);
             for (u = 0; u < LY_ARRAY_SIZE(type_p->types); ++u) {
-                ret = lys_compile_type(ctx, context_node_p, context_flags, context_mod, context_name, &type_p->types[u], options, &un->types[u + additional], NULL, NULL);
+                ret = lys_compile_type(ctx, context_node_p, context_flags, context_mod, context_name, &type_p->types[u], options, &un->types[u + additional], NULL);
                 if (un->types[u + additional]->basetype == LY_TYPE_UNION) {
                     /* add space for additional types from the union subtype */
                     un_aux = (struct lysc_type_union *)un->types[u + additional];
@@ -2464,12 +2539,11 @@
  * @param[in] options Various options to modify compiler behavior, see [compile flags](@ref scflags).
  * @param[out] type Newly created (or reused with increased refcount) type structure with the filled information about the type.
  * @param[out] units Storage for inheriting units value from the typedefs the current type derives from.
- * @param[out] dflt Storage for inheriting default value from the typedefs the current type derives from.
  * @return LY_ERR value.
  */
 static LY_ERR
 lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_node_p, uint16_t context_flags, struct lysp_module *context_mod, const char *context_name,
-                 struct lysp_type *type_p, int options, struct lysc_type **type, const char **units, const char **dflt)
+                 struct lysp_type *type_p, int options, struct lysc_type **type, const char **units)
 {
     LY_ERR ret = LY_SUCCESS;
     unsigned int u;
@@ -2482,6 +2556,7 @@
     LY_DATA_TYPE basetype = LY_TYPE_UNKNOWN;
     struct lysc_type *base = NULL, *prev_type;
     struct ly_set tpdf_chain = {0};
+    const char *dflt = NULL;
 
     (*type) = NULL;
 
@@ -2505,11 +2580,11 @@
             /* inherit units */
             DUP_STRING(ctx->ctx, tctx->tpdf->units, *units);
         }
-        if (dflt && !*dflt) {
+        if (!dflt) {
             /* inherit default */
-            DUP_STRING(ctx->ctx, tctx->tpdf->dflt, *dflt);
+            dflt = tctx->tpdf->dflt;
         }
-        if (dummyloops && (!units || *units) && (!dflt || *dflt)) {
+        if (dummyloops && (!units || *units) && dflt) {
             basetype = ((struct type_context*)tpdf_chain.objs[tpdf_chain.count - 1])->tpdf->type.compiled->basetype;
             break;
         }
@@ -2519,7 +2594,7 @@
              * but we still may need to inherit default and units values, so start dummy loops */
             basetype = tctx->tpdf->type.compiled->basetype;
             ly_set_add(&tpdf_chain, tctx, LY_SET_OPT_USEASLIST);
-            if ((units && !*units) || (dflt && !*dflt)) {
+            if ((units && !*units) || !dflt) {
                 dummyloops = 1;
                 goto preparenext;
             } else {
@@ -2647,6 +2722,9 @@
         (*type) = base;
         ++(*type)->refcount;
     }
+    if (!(*type)->dflt) {
+        DUP_STRING(ctx->ctx, dflt, (*type)->dflt);
+    }
 
     COMPILE_ARRAY_GOTO(ctx, type_p->exts, (*type)->exts, options, u, lys_compile_ext, ret, cleanup);
 
@@ -2655,7 +2733,7 @@
     return ret;
 }
 
-static LY_ERR lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *node_p, int options, struct lysc_node *parent);
+static LY_ERR lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *node_p, int options, struct lysc_node *parent, uint16_t uses_status);
 
 /**
  * @brief Compile parsed container node information.
@@ -2676,7 +2754,7 @@
     LY_ERR ret = LY_SUCCESS;
 
     LY_LIST_FOR(cont_p->child, child_p) {
-        LY_CHECK_RET(lys_compile_node(ctx, child_p, options, node));
+        LY_CHECK_RET(lys_compile_node(ctx, child_p, options, node, 0));
     }
 
     COMPILE_ARRAY_GOTO(ctx, cont_p->musts, cont->musts, options, u, lys_compile_must, ret, done);
@@ -2712,8 +2790,11 @@
     }
 
     ret = lys_compile_type(ctx, node_p, node_p->flags, ctx->mod_def->parsed, node_p->name, &leaf_p->type, options, &leaf->type,
-                           leaf->units ? NULL : &leaf->units, leaf->dflt || (leaf->flags & LYS_MAND_TRUE) ? NULL : &leaf->dflt);
+                           leaf->units ? NULL : &leaf->units);
     LY_CHECK_GOTO(ret, done);
+    if (!leaf->dflt && !(leaf->flags & LYS_MAND_TRUE)) {
+        DUP_STRING(ctx->ctx, leaf->type->dflt, leaf->dflt);
+    }
     if (leaf->type->basetype == LY_TYPE_LEAFREF) {
         /* store to validate the path in the current context at the end of schema compiling when all the nodes are present */
         ly_set_add(&ctx->unres, leaf, 0);
@@ -2751,7 +2832,6 @@
     struct lysp_node_leaflist *llist_p = (struct lysp_node_leaflist*)node_p;
     struct lysc_node_leaflist *llist = (struct lysc_node_leaflist*)node;
     unsigned int u, v;
-    const char *dflt = NULL;
     LY_ERR ret = LY_SUCCESS;
 
     COMPILE_ARRAY_GOTO(ctx, llist_p->musts, llist->musts, options, u, lys_compile_must, ret, done);
@@ -2769,11 +2849,11 @@
     llist->max = llist_p->max ? llist_p->max : (uint32_t)-1;
 
     ret = lys_compile_type(ctx, node_p, node_p->flags, ctx->mod_def->parsed, node_p->name, &llist_p->type, options, &llist->type,
-                           llist->units ? NULL : &llist->units, (llist->dflts || llist->min) ? NULL : &dflt);
+                           llist->units ? NULL : &llist->units);
     LY_CHECK_GOTO(ret, done);
-    if (dflt) {
+    if (llist->type->dflt && !llist->dflts && !llist->min) {
         LY_ARRAY_CREATE_GOTO(ctx->ctx, llist->dflts, 1, ret, done);
-        llist->dflts[0] = dflt;
+        DUP_STRING(ctx->ctx, llist->type->dflt, llist->dflts[0]);
         LY_ARRAY_INCREMENT(llist->dflts);
     }
 
@@ -2788,7 +2868,7 @@
             }
         }
     } else if (llist->type->basetype == LY_TYPE_EMPTY) {
-        if (ctx->mod_def->parsed->version < LYS_VERSION_1_1) {
+        if (ctx->mod_def->version < LYS_VERSION_1_1) {
             LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
                    "Leaf-list of type \"empty\" is allowed only in YANG 1.1 modules.");
             return LY_EVALID;
@@ -2844,7 +2924,7 @@
     list->max = list_p->max ? list_p->max : (uint32_t)-1;
 
     LY_LIST_FOR(list_p->child, child_p) {
-        LY_CHECK_RET(lys_compile_node(ctx, child_p, options, node));
+        LY_CHECK_RET(lys_compile_node(ctx, child_p, options, node, 0));
     }
 
     COMPILE_ARRAY_GOTO(ctx, list_p->musts, list->musts, options, u, lys_compile_must, ret, done);
@@ -2889,7 +2969,7 @@
             LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Key of the configuration list must not be status leaf.");
             return LY_EVALID;
         }
-        if (ctx->mod_def->parsed->version < LYS_VERSION_1_1) {
+        if (ctx->mod_def->version < LYS_VERSION_1_1) {
             /* YANG 1.0 denies key to be of empty type */
             if ((*key)->type->basetype == LY_TYPE_EMPTY) {
                 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
@@ -3003,7 +3083,7 @@
     } else {
         name = dflt;
     }
-    if (prefix && (strncmp(prefix, node->module->compiled->prefix, prefix_len) || node->module->compiled->prefix[prefix_len] != '\0')) {
+    if (prefix && (strncmp(prefix, node->module->prefix, prefix_len) || node->module->prefix[prefix_len] != '\0')) {
         /* prefixed default case make sense only for the prefix of the schema itself */
         LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
                "Invalid default case referencing a case from different YANG module (by prefix \"%.*s\").",
@@ -3024,7 +3104,7 @@
             return LY_EVALID;
         }
     }
-    ch->flags |= LYS_SET_DFLT;
+    ch->dflt->flags |= LYS_SET_DFLT;
     return LY_SUCCESS;
 }
 
@@ -3049,10 +3129,10 @@
     LY_LIST_FOR(ch_p->child, child_p) {
         if (child_p->nodetype == LYS_CASE) {
             LY_LIST_FOR(((struct lysp_node_case*)child_p)->child, case_child_p) {
-                LY_CHECK_RET(lys_compile_node(ctx, case_child_p, options, node));
+                LY_CHECK_RET(lys_compile_node(ctx, case_child_p, options, node, 0));
             }
         } else {
-            LY_CHECK_RET(lys_compile_node(ctx, child_p, options, node));
+            LY_CHECK_RET(lys_compile_node(ctx, child_p, options, node, 0));
         }
     }
 
@@ -3110,21 +3190,24 @@
 }
 
 static LY_ERR
-lys_compile_status(struct lysc_ctx *ctx, struct lysc_node *node, struct lysc_node *parent)
+lys_compile_status(struct lysc_ctx *ctx, struct lysc_node *node, uint16_t parent_flags)
 {
-
     /* status - it is not inherited by specification, but it does not make sense to have
      * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
     if (!(node->flags & LYS_STATUS_MASK)) {
-        if (parent && (parent->flags & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT))) {
-            LOGWRN(ctx->ctx, "Missing explicit \"%s\" status that was already specified in parent, inheriting.",
-                   (parent->flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
-            node->flags |= parent->flags & LYS_STATUS_MASK;
+        if (parent_flags & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) {
+            if ((parent_flags & 0x3) != 0x3) {
+                /* do not print the warning when inheriting status from uses - the uses_status value has a special
+                 * combination of bits (0x3) which marks the uses_status value */
+                LOGWRN(ctx->ctx, "Missing explicit \"%s\" status that was already specified in parent, inheriting.",
+                       (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
+            }
+            node->flags |= parent_flags & LYS_STATUS_MASK;
         } else {
             node->flags |= LYS_STATUS_CURR;
         }
-    } else if (parent) {
-        return lys_compile_status_check(ctx, node->flags, parent->flags);
+    } else if (parent_flags & LYS_STATUS_MASK) {
+        return lys_compile_status_check(ctx, node->flags, parent_flags);
     }
     return LY_SUCCESS;
 }
@@ -3238,8 +3321,8 @@
         cs->flags = LYS_STATUS_MASK & node_p->flags;
         cs->sp = node_p;
 
-        /* check the case's status */
-        LY_CHECK_RET(lys_compile_status(ctx, (struct lysc_node*)cs, (struct lysc_node* )ch), NULL);
+        /* check the case's status (don't need to solve uses_status since case statement cannot be directly in grouping statement */
+        LY_CHECK_RET(lys_compile_status(ctx, (struct lysc_node*)cs, ch->flags), NULL);
         COMPILE_MEMBER_GOTO(ctx, node_p->when, cs->when, options, lys_compile_when, ret, error);
         COMPILE_ARRAY_GOTO(ctx, node_p->iffeatures, cs->iffeatures, options, u, lys_compile_iffeature, ret, error);
     }
@@ -3272,7 +3355,8 @@
         /* explicit refine */
         if (config == LYS_CONFIG_W && node->parent && (node->parent->flags & LYS_CONFIG_R)) {
             LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                   "Invalid refine of config in \"%s\" - configuration node cannot be child of any state data node.");
+                   "Invalid refine of config in \"%s\" - configuration node cannot be child of any state data node.",
+                   rfn->nodeid);
             return LY_EVALID;
         }
     }
@@ -3305,7 +3389,14 @@
 lys_compile_uses(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, int options, struct lysc_node *parent)
 {
     struct lysp_node *node_p;
-    struct lysc_node *node;
+    struct lysc_node *node, *child;
+    /* context_node_fake allows us to temporarily isolate the nodes inserted from the grouping instead of uses */
+    struct lysc_node_container context_node_fake =
+        {.nodetype = LYS_CONTAINER,
+         .module = ctx->mod,
+         .flags = parent ? parent->flags : 0,
+         .child = NULL, .next = NULL,
+         .prev = (struct lysc_node*)&context_node_fake};
     const struct lysp_grp *grp = NULL;
     unsigned int u, v, grp_stack_count;
     int found;
@@ -3314,6 +3405,8 @@
     struct lys_module *mod, *mod_old;
     struct lysp_refine *rfn;
     LY_ERR ret = LY_EVALID;
+    uint32_t min, max;
+    struct ly_set refined = {0};
 
     /* search for the grouping definition */
     found = 0;
@@ -3390,22 +3483,40 @@
     /* check status */
     LY_CHECK_GOTO(lysc_check_status(ctx, uses_p->flags, mod_old, uses_p->name, grp->flags, mod, grp->name), error);
 
-    /* connect the grouping's content */
     LY_LIST_FOR(grp->data, node_p) {
-        LY_CHECK_GOTO(lys_compile_node(ctx, node_p, options, parent), error);
-        /* check status between parent (uses in this case) and child - lys_compile_node() compares parent and the new node */
-        if (lys_compile_status_check(ctx, parent ? lysc_node_children(parent)->prev->flags : ctx->mod->compiled->data->prev->flags, uses_p->flags)) {
-            goto error;
+        /* 0x3 in uses_status is a special bits combination to be able to detect status flags from uses */
+        LY_CHECK_GOTO(lys_compile_node(ctx, node_p, options, parent, (uses_p->flags & LYS_STATUS_MASK) | 0x3), error);
+        child = parent ? lysc_node_children(parent)->prev : ctx->mod->compiled->data->prev;
+        if (uses_p->refines) {
+            /* some preparation for applying refines */
+            if (grp->data == node_p) {
+                /* remember the first child */
+                context_node_fake.child = child;
+            }
         }
     }
+    LY_LIST_FOR(context_node_fake.child, child) {
+        child->parent = (struct lysc_node*)&context_node_fake;
+    }
+    if (context_node_fake.child) {
+        child = context_node_fake.child->prev;
+        context_node_fake.child->prev = parent ? lysc_node_children(parent)->prev : ctx->mod->compiled->data->prev;
+    }
+
+    /* TODO: apply augment */
+
+    /* reload previous context's mod_def */
+    ctx->mod_def = mod_old;
 
     /* apply refine */
     LY_ARRAY_FOR(uses_p->refines, struct lysp_refine, rfn) {
-        LY_CHECK_GOTO(lys_resolve_descendant_schema_nodeid(ctx, rfn->nodeid, 0, parent, 0, (const struct lysc_node**)&node), error);
+        LY_CHECK_GOTO(lys_resolve_descendant_schema_nodeid(ctx, rfn->nodeid, 0, (struct lysc_node*)&context_node_fake, 0, (const struct lysc_node**)&node),
+                      error);
+        ly_set_add(&refined, node, LY_SET_OPT_USEASLIST);
 
         /* default value */
         if (rfn->dflts) {
-            if ((node->nodetype & (LYS_LEAF | LYS_CHOICE)) && LY_ARRAY_SIZE(rfn->dflts) > 1) {
+            if ((node->nodetype != LYS_LEAFLIST) && LY_ARRAY_SIZE(rfn->dflts) > 1) {
                 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
                        "Invalid refine of default in \"%s\" - %s cannot hold %d default values.",
                        rfn->nodeid, lys_nodetype2str(node->nodetype), LY_ARRAY_SIZE(rfn->dflts));
@@ -3420,12 +3531,19 @@
             if (node->nodetype == LYS_LEAF) {
                 FREE_STRING(ctx->ctx, ((struct lysc_node_leaf*)node)->dflt);
                 DUP_STRING(ctx->ctx, rfn->dflts[0], ((struct lysc_node_leaf*)node)->dflt);
+                node->flags |= LYS_SET_DFLT;
                 /* TODO check the default value according to type */
             } else if (node->nodetype == LYS_LEAFLIST) {
+                if (ctx->mod->version < 2) {
+                    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                           "Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.");
+                    goto error;
+                }
                 LY_ARRAY_FOR(((struct lysc_node_leaflist*)node)->dflts, u) {
                     lydict_remove(ctx->ctx, ((struct lysc_node_leaflist*)node)->dflts[u]);
                 }
                 LY_ARRAY_FREE(((struct lysc_node_leaflist*)node)->dflts);
+                ((struct lysc_node_leaflist*)node)->dflts = NULL;
                 LY_ARRAY_CREATE_GOTO(ctx->ctx, ((struct lysc_node_leaflist*)node)->dflts, LY_ARRAY_SIZE(rfn->dflts), ret, error);
                 LY_ARRAY_FOR(rfn->dflts, u) {
                     LY_ARRAY_INCREMENT(((struct lysc_node_leaflist*)node)->dflts);
@@ -3433,12 +3551,25 @@
                 }
                 /* TODO check the default values according to type */
             } else if (node->nodetype == LYS_CHOICE) {
+                if (((struct lysc_node_choice*)node)->dflt) {
+                    /* unset LYS_SET_DFLT from the current default case */
+                    ((struct lysc_node_choice*)node)->dflt->flags &= ~LYS_SET_DFLT;
+                }
                 LY_CHECK_GOTO(lys_compile_node_choice_dflt(ctx, rfn->dflts[0], (struct lysc_node_choice*)node), error);
             }
         }
 
-        /* description refine not applicable */
-        /* reference refine not applicable */
+        /* description */
+        if (rfn->dsc) {
+            FREE_STRING(ctx->ctx, node->dsc);
+            node->dsc = lydict_insert(ctx->ctx, rfn->dsc, 0);
+        }
+
+        /* reference */
+        if (rfn->ref) {
+            FREE_STRING(ctx->ctx, node->ref);
+            node->ref = lydict_insert(ctx->ctx, rfn->ref, 0);
+        }
 
         /* config */
         if (rfn->flags & LYS_CONFIG_MASK) {
@@ -3459,7 +3590,7 @@
                 if (node->nodetype & LYS_LEAF) {
                     if (node->flags & LYS_SET_DFLT) {
                         LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                               "Invalid refine of mandatory in \"%s\" - leafswith \"default\" statement.", rfn->nodeid);
+                               "Invalid refine of mandatory in \"%s\" - leaf already has \"default\" statement.", rfn->nodeid);
                         goto error;
                     } else {
                         /* remove the default value taken from the leaf's type */
@@ -3468,7 +3599,7 @@
                     }
                 } else if ((node->nodetype & LYS_CHOICE) && ((struct lysc_node_choice*)node)->dflt) {
                     LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                           "Invalid refine of mandatory in \"%s\" - choice with \"default\" statement.", rfn->nodeid);
+                           "Invalid refine of mandatory in \"%s\" - choice already has \"default\" statement.", rfn->nodeid);
                     goto error;
                 }
                 if (node->parent && (node->parent->flags & LYS_SET_DFLT)) {
@@ -3480,7 +3611,121 @@
 
                 node->flags |= LYS_MAND_TRUE;
             } else {
+                /* make mandatory false */
                 node->flags &= ~LYS_MAND_TRUE;
+                if ((node->nodetype & LYS_LEAF) && !((struct lysc_node_leaf*)node)->dflt) {
+                    /* get the type's default value if any */
+                    DUP_STRING(ctx->ctx, ((struct lysc_node_leaf*)node)->type->dflt, ((struct lysc_node_leaf*)node)->dflt);
+                }
+            }
+        }
+
+        /* presence */
+        if (rfn->presence) {
+            if (node->nodetype != LYS_CONTAINER) {
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                       "Invalid refine of presence statement in \"%s\" - %s cannot hold the presence statement.",
+                       rfn->nodeid, lys_nodetype2str(node->nodetype));
+                goto error;
+            }
+            node->flags |= LYS_PRESENCE;
+        }
+
+        /* must */
+        if (rfn->musts) {
+            switch (node->nodetype) {
+            case LYS_LEAF:
+                COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_leaf*)node)->musts, options, u, lys_compile_must, ret, error);
+                break;
+            case LYS_LEAFLIST:
+                COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_leaflist*)node)->musts, options, u, lys_compile_must, ret, error);
+                break;
+            case LYS_LIST:
+                COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_list*)node)->musts, options, u, lys_compile_must, ret, error);
+                break;
+            case LYS_CONTAINER:
+                COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_container*)node)->musts, options, u, lys_compile_must, ret, error);
+                break;
+            case LYS_ANYXML:
+            case LYS_ANYDATA:
+                COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_anydata*)node)->musts, options, u, lys_compile_must, ret, error);
+                break;
+            default:
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                       "Invalid refine of must statement in \"%s\" - %s cannot hold any must statement.",
+                       rfn->nodeid, lys_nodetype2str(node->nodetype));
+                goto error;
+            }
+        }
+
+        /* min/max-elements */
+        if (rfn->flags & (LYS_SET_MAX | LYS_SET_MIN)) {
+            switch (node->nodetype) {
+            case LYS_LEAFLIST:
+                if (rfn->flags & LYS_SET_MAX) {
+                    ((struct lysc_node_leaflist*)node)->max = rfn->max ? rfn->max : (uint32_t)-1;
+                }
+                if (rfn->flags & LYS_SET_MIN) {
+                    ((struct lysc_node_leaflist*)node)->min = rfn->min;
+                }
+                break;
+            case LYS_LIST:
+                if (rfn->flags & LYS_SET_MAX) {
+                    ((struct lysc_node_list*)node)->max = rfn->max ? rfn->max : (uint32_t)-1;
+                }
+                if (rfn->flags & LYS_SET_MIN) {
+                    ((struct lysc_node_list*)node)->min = rfn->min;
+                }
+                break;
+            default:
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                       "Invalid refine of %s statement in \"%s\" - %s cannot hold this statement.",
+                       (rfn->flags & LYS_SET_MAX) ? "max-elements" : "min-elements", rfn->nodeid, lys_nodetype2str(node->nodetype));
+                goto error;
+            }
+        }
+
+        /* if-feature */
+        if (rfn->iffeatures) {
+            /* any node in compiled tree can get additional if-feature, so do not check nodetype */
+            COMPILE_ARRAY_GOTO(ctx, rfn->iffeatures, node->iffeatures, options, u, lys_compile_iffeature, ret, error);
+        }
+    }
+    /* fix connection of the children nodes from fake context node back into the parent */
+    if (context_node_fake.child) {
+        context_node_fake.child->prev = child;
+    }
+    LY_LIST_FOR(context_node_fake.child, child) {
+        child->parent = parent;
+    }
+
+    /* do some additional checks of the changed nodes when all the refines are applied */
+    for (u = 0; u < refined.count; ++u) {
+        node = (struct lysc_node*)refined.objs[u];
+        rfn = &uses_p->refines[u];
+
+        /* check possible conflict with default value (default added, mandatory left true) */
+        if ((node->flags & LYS_MAND_TRUE) &&
+                (((node->nodetype & LYS_CHOICE) && ((struct lysc_node_choice*)node)->dflt) ||
+                ((node->nodetype & LYS_LEAF) && (node->flags & LYS_SET_DFLT)))) {
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                   "Invalid refine of default in \"%s\" - the node is mandatory.", rfn->nodeid);
+            goto error;
+        }
+
+        if (rfn->flags & (LYS_SET_MAX | LYS_SET_MIN)) {
+            if (node->nodetype == LYS_LIST) {
+                min = ((struct lysc_node_list*)node)->min;
+                max = ((struct lysc_node_list*)node)->max;
+            } else {
+                min = ((struct lysc_node_leaflist*)node)->min;
+                max = ((struct lysc_node_leaflist*)node)->max;
+            }
+            if (min > max) {
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                       "Invalid refine of %s statement in \"%s\" - \"min-elements\" is bigger than \"max-elements\".",
+                       (rfn->flags & LYS_SET_MAX) ? "max-elements" : "min-elements", rfn->nodeid);
+                goto error;
             }
         }
     }
@@ -3492,6 +3737,7 @@
     /* remove the grouping from the stack for circular groupings dependency check */
     ly_set_rm_index(&ctx->groupings, ctx->groupings.count - 1, NULL);
     assert(ctx->groupings.count == grp_stack_count);
+    ly_set_erase(&refined, NULL);
 
     return ret;
 }
@@ -3504,10 +3750,12 @@
  * @param[in] parent Compiled parent node where the current node is supposed to be connected. It is
  * NULL for top-level nodes, in such a case the module where the node will be connected is taken from
  * the compile context.
+ * @param[in] uses_status If the node is being placed instead of uses, here we have the uses's status value (as node's flags).
+ * Zero means no uses, non-zero value with no status bit set mean the default status.
  * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
  */
 static LY_ERR
-lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *node_p, int options, struct lysc_node *parent)
+lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *node_p, int options, struct lysc_node *parent, uint16_t uses_status)
 {
     LY_ERR ret = LY_EVALID;
     struct lysc_node *node;
@@ -3587,13 +3835,15 @@
     if (!parent || parent->nodetype != LYS_CHOICE) {
         /* in case of choice/case's children, postpone the check to the moment we know if
          * the parent is choice (parent here) or some case (so we have to get its flags to check) */
-        LY_CHECK_GOTO(lys_compile_status(ctx, node, parent), error);
+        LY_CHECK_GOTO(lys_compile_status(ctx, node, uses_status ? uses_status : (parent ? parent->flags : 0)), error);
     }
 
     if (!(options & LYSC_OPT_FREE_SP)) {
         node->sp = node_p;
     }
     DUP_STRING(ctx->ctx, node_p->name, node->name);
+    DUP_STRING(ctx->ctx, node_p->dsc, node->dsc);
+    DUP_STRING(ctx->ctx, node_p->ref, node->ref);
     COMPILE_MEMBER_GOTO(ctx, node_p->when, node->when, options, lys_compile_when, ret, error);
     COMPILE_ARRAY_GOTO(ctx, node_p->iffeatures, node->iffeatures, options, u, lys_compile_iffeature, ret, error);
     COMPILE_ARRAY_GOTO(ctx, node_p->exts, node->exts, options, u, lys_compile_ext, ret, error);
@@ -3606,9 +3856,13 @@
         if (parent->nodetype == LYS_CHOICE) {
             cs = lys_compile_node_case(ctx, node_p->parent, options, (struct lysc_node_choice*)parent, node);
             LY_CHECK_ERR_GOTO(!cs, ret = LY_EVALID, error);
+            if (uses_status) {
+
+            }
             /* the postponed status check of the node and its real parent - in case of implicit case,
-             * it directly gets the same status flags as the choice */
-            LY_CHECK_GOTO(lys_compile_status(ctx, node, (struct lysc_node*)cs), error);
+             * it directly gets the same status flags as the choice;
+             * uses_status cannot be applied here since uses cannot be child statement of choice */
+            LY_CHECK_GOTO(lys_compile_status(ctx, node, cs->flags), error);
             node->parent = (struct lysc_node*)cs;
         } else { /* other than choice */
             node->parent = parent;
@@ -3650,22 +3904,24 @@
     unsigned int u;
     LY_ERR ret = LY_SUCCESS;
     /* shortcuts */
-    struct lysp_module *submod = inc->submodule;
+    struct lysp_submodule *submod = inc->submodule;
     struct lysc_module *mainmod = ctx->mod->compiled;
 
-    COMPILE_ARRAY_UNIQUE_GOTO(ctx, submod->features, mainmod->features, options, u, lys_compile_feature, ret, error);
+    if (!mainmod->mod->off_features) {
+        /* features are compiled directly into the compiled module structure,
+         * but it must be done in two steps to allow forward references (via if-feature) between the features themselves.
+         * The features compilation is finished in the main module (lys_compile()). */
+        ret = lys_feature_precompile(ctx->ctx, submod->features,
+                                     mainmod->mod->off_features ? &mainmod->mod->off_features : &mainmod->features);
+        LY_CHECK_GOTO(ret, error);
+    }
+
     COMPILE_ARRAY_UNIQUE_GOTO(ctx, submod->identities, mainmod->identities, options, u, lys_compile_identity, ret, error);
 
 error:
     return ret;
 }
 
-/**
- * @brief Compile the given YANG module.
- * @param[in] mod Module structure where the parsed schema is expected and the compiled schema will be placed.
- * @param[in] options Various options to modify compiler behavior, see [compile flags](@ref scflags).
- * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
- */
 LY_ERR
 lys_compile(struct lys_module *mod, int options)
 {
@@ -3675,46 +3931,63 @@
     struct lysp_module *sp;
     struct lysp_node *node_p;
     unsigned int u, v;
+    int using_precompiled_features = 0;
     LY_ERR ret = LY_SUCCESS;
 
-    LY_CHECK_ARG_RET(NULL, mod, mod->parsed, mod->parsed->ctx, LY_EINVAL);
-    sp = mod->parsed;
+    LY_CHECK_ARG_RET(NULL, mod, mod->parsed, mod->ctx, LY_EINVAL);
 
-    if (sp->submodule) {
-        LOGERR(sp->ctx, LY_EINVAL, "Submodules (%s) are not supposed to be compiled, compile only the main modules.", sp->name);
-        return LY_EINVAL;
+    if (!mod->implemented) {
+        /* just imported modules are not compiled */
+        return LY_SUCCESS;
     }
 
-    ctx.ctx = sp->ctx;
+    sp = mod->parsed;
+
+    ctx.ctx = mod->ctx;
     ctx.mod = mod;
     ctx.mod_def = mod;
 
     mod->compiled = mod_c = calloc(1, sizeof *mod_c);
-    LY_CHECK_ERR_RET(!mod_c, LOGMEM(sp->ctx), LY_EMEM);
-    mod_c->ctx = sp->ctx;
-    mod_c->implemented = sp->implemented;
-    mod_c->latest_revision = sp->latest_revision;
-    mod_c->version = sp->version;
+    LY_CHECK_ERR_RET(!mod_c, LOGMEM(mod->ctx), LY_EMEM);
+    mod_c->mod = mod;
 
-    DUP_STRING(sp->ctx, sp->name, mod_c->name);
-    DUP_STRING(sp->ctx, sp->ns, mod_c->ns);
-    DUP_STRING(sp->ctx, sp->prefix, mod_c->prefix);
-    if (sp->revs) {
-        DUP_STRING(sp->ctx, sp->revs[0].date, mod_c->revision);
-    }
     COMPILE_ARRAY_GOTO(&ctx, sp->imports, mod_c->imports, options, u, lys_compile_import, ret, error);
     LY_ARRAY_FOR(sp->includes, u) {
         ret = lys_compile_submodule(&ctx, &sp->includes[u], options);
         LY_CHECK_GOTO(ret != LY_SUCCESS, error);
     }
-    COMPILE_ARRAY_UNIQUE_GOTO(&ctx, sp->features, mod_c->features, options, u, lys_compile_feature, ret, error);
+    if (mod->off_features) {
+        /* there is already precompiled array of features */
+        mod_c->features = mod->off_features;
+        mod->off_features = NULL;
+        using_precompiled_features = 1;
+    } else {
+        /* features are compiled directly into the compiled module structure,
+         * but it must be done in two steps to allow forward references (via if-feature) between the features themselves */
+        ret = lys_feature_precompile(ctx.ctx, sp->features, &mod_c->features);
+        LY_CHECK_GOTO(ret, error);
+    }
+    /* finish feature compilation, not only for the main module, but also for the submodules.
+     * Due to possible forward references, it must be done when all the features (including submodules)
+     * are present. */
+    LY_ARRAY_FOR(sp->features, u) {
+        ret = lys_feature_precompile_finish(&ctx, &sp->features[u], options, mod_c->features);
+        LY_CHECK_GOTO(ret != LY_SUCCESS, error);
+    }
+    LY_ARRAY_FOR(sp->includes, v) {
+        LY_ARRAY_FOR(sp->includes[v].submodule->features, u) {
+            ret = lys_feature_precompile_finish(&ctx, &sp->includes[v].submodule->features[u], options, mod_c->features);
+            LY_CHECK_GOTO(ret != LY_SUCCESS, error);
+        }
+    }
+
     COMPILE_ARRAY_UNIQUE_GOTO(&ctx, sp->identities, mod_c->identities, options, u, lys_compile_identity, ret, error);
     if (sp->identities) {
         LY_CHECK_RET(lys_compile_identities_derived(&ctx, sp->identities, mod_c->identities));
     }
 
     LY_LIST_FOR(sp->data, node_p) {
-        ret = lys_compile_node(&ctx, node_p, options, NULL);
+        ret = lys_compile_node(&ctx, node_p, options, NULL, 0);
         LY_CHECK_GOTO(ret, error);
     }
     //COMPILE_ARRAY_GOTO(ctx, sp->rpcs, mod_c->rpcs, options, u, lys_compile_action, ret, error);
@@ -3779,6 +4052,23 @@
     return LY_SUCCESS;
 
 error:
+    if (using_precompiled_features) {
+        /* keep the off_features list until the complete lys_module is freed */
+        mod->off_features = mod->compiled->features;
+        mod->compiled->features = NULL;
+    }
+    /* in the off_features list, remove all the parts (from finished compiling process)
+     * which may points into the data being freed here */
+    LY_ARRAY_FOR(mod->off_features, u) {
+        LY_ARRAY_FOR(mod->off_features[u].iffeatures, v) {
+            lysc_iffeature_free(ctx.ctx, &mod->off_features[u].iffeatures[v]);
+        }
+        LY_ARRAY_FREE(mod->off_features[u].iffeatures);
+        LY_ARRAY_FOR(mod->off_features[u].exts, v) {
+            lysc_ext_instance_free(ctx.ctx, &(mod->off_features[u].exts)[v]);
+        }
+        LY_ARRAY_FREE(mod->off_features[u].exts);
+    }
     ly_set_erase(&ctx.unres, NULL);
     ly_set_erase(&ctx.groupings, NULL);
     lysc_module_free(mod_c, NULL);
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index 7dbe83c..ce0dfb8 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -69,7 +69,7 @@
 lysp_include_free(struct ly_ctx *ctx, struct lysp_include *include)
 {
     if (include->submodule) {
-        lysp_module_free(include->submodule);
+        lysp_submodule_free(ctx, include->submodule);
     }
     FREE_STRING(ctx, include->name);
     FREE_STRING(ctx, include->dsc);
@@ -393,28 +393,59 @@
     free(node);
 }
 
+void
+lysp_submodule_free(struct ly_ctx *ctx, struct lysp_submodule *submod)
+{
+    struct lysp_node *node, *next;
+
+    if (!submod) {
+        return;
+    }
+
+    FREE_ARRAY(ctx, submod->imports, lysp_import_free);
+    FREE_ARRAY(ctx, submod->includes, lysp_include_free);
+
+    FREE_ARRAY(ctx, submod->revs, lysp_revision_free);
+    FREE_ARRAY(ctx, submod->extensions, lysp_ext_free);
+    FREE_ARRAY(ctx, submod->features, lysp_feature_free);
+    FREE_ARRAY(ctx, submod->identities, lysp_ident_free);
+    FREE_ARRAY(ctx, submod->typedefs, lysp_tpdf_free);
+    FREE_ARRAY(ctx, submod->groupings, lysp_grp_free);
+    LY_LIST_FOR_SAFE(submod->data, next, node) {
+        lysp_node_free(ctx, node);
+    }
+    FREE_ARRAY(ctx, submod->augments, lysp_augment_free);
+    FREE_ARRAY(ctx, submod->rpcs, lysp_action_free);
+    FREE_ARRAY(ctx, submod->notifs, lysp_notif_free);
+    FREE_ARRAY(ctx, submod->deviations, lysp_deviation_free);
+    FREE_ARRAY(ctx, submod->exts, lysp_ext_instance_free);
+
+    FREE_STRING(ctx, submod->belongsto);
+    FREE_STRING(ctx, submod->name);
+    FREE_STRING(ctx, submod->filepath);
+    FREE_STRING(ctx, submod->prefix);
+    FREE_STRING(ctx, submod->org);
+    FREE_STRING(ctx, submod->contact);
+    FREE_STRING(ctx, submod->dsc);
+    FREE_STRING(ctx, submod->ref);
+
+    free(submod);
+}
+
 API void
 lysp_module_free(struct lysp_module *module)
 {
     struct ly_ctx *ctx;
     struct lysp_node *node, *next;
 
-    LY_CHECK_ARG_RET(NULL, module,);
-    ctx = module->ctx;
-
-    FREE_STRING(ctx, module->name);
-    FREE_STRING(ctx, module->filepath);
-    FREE_STRING(ctx, module->ns);  /* or belongs-to */
-    FREE_STRING(ctx, module->prefix);
+    if (!module) {
+        return;
+    }
+    ctx = module->mod->ctx;
 
     FREE_ARRAY(ctx, module->imports, lysp_import_free);
     FREE_ARRAY(ctx, module->includes, lysp_include_free);
 
-    FREE_STRING(ctx, module->org);
-    FREE_STRING(ctx, module->contact);
-    FREE_STRING(ctx, module->dsc);
-    FREE_STRING(ctx, module->ref);
-
     FREE_ARRAY(ctx, module->revs, lysp_revision_free);
     FREE_ARRAY(ctx, module->extensions, lysp_ext_free);
     FREE_ARRAY(ctx, module->features, lysp_feature_free);
@@ -433,14 +464,14 @@
     free(module);
 }
 
-static void
+void
 lysc_ext_instance_free(struct ly_ctx *ctx, struct lysc_ext_instance *ext)
 {
     FREE_STRING(ctx, ext->argument);
     FREE_ARRAY(ctx, ext->exts, lysc_ext_instance_free);
 }
 
-static void
+void
 lysc_iffeature_free(struct ly_ctx *UNUSED(ctx), struct lysc_iffeature *iff)
 {
     LY_ARRAY_FREE(iff->features);
@@ -451,6 +482,8 @@
 lysc_when_free(struct ly_ctx *ctx, struct lysc_when *w)
 {
     lyxp_expr_free(ctx, w->cond);
+    FREE_STRING(ctx, w->dsc);
+    FREE_STRING(ctx, w->ref);
     FREE_ARRAY(ctx, w->exts, lysc_ext_instance_free);
 }
 
@@ -460,6 +493,8 @@
     lyxp_expr_free(ctx, must->cond);
     FREE_STRING(ctx, must->emsg);
     FREE_STRING(ctx, must->eapptag);
+    FREE_STRING(ctx, must->dsc);
+    FREE_STRING(ctx, must->ref);
     FREE_ARRAY(ctx, must->exts, lysc_ext_instance_free);
 }
 
@@ -475,6 +510,8 @@
 lysc_ident_free(struct ly_ctx *ctx, struct lysc_ident *ident)
 {
     FREE_STRING(ctx, ident->name);
+    FREE_STRING(ctx, ident->dsc);
+    FREE_STRING(ctx, ident->ref);
     FREE_ARRAY(ctx, ident->iffeatures, lysc_iffeature_free);
     LY_ARRAY_FREE(ident->derived);
     FREE_ARRAY(ctx, ident->exts, lysc_ext_instance_free);
@@ -484,6 +521,8 @@
 lysc_feature_free(struct ly_ctx *ctx, struct lysc_feature *feat)
 {
     FREE_STRING(ctx, feat->name);
+    FREE_STRING(ctx, feat->dsc);
+    FREE_STRING(ctx, feat->ref);
     FREE_ARRAY(ctx, feat->iffeatures, lysc_iffeature_free);
     LY_ARRAY_FREE(feat->depfeatures);
     FREE_ARRAY(ctx, feat->exts, lysc_ext_instance_free);
@@ -495,6 +534,8 @@
     LY_ARRAY_FREE(range->parts);
     FREE_STRING(ctx, range->eapptag);
     FREE_STRING(ctx, range->emsg);
+    FREE_STRING(ctx, range->dsc);
+    FREE_STRING(ctx, range->ref);
     FREE_ARRAY(ctx, range->exts, lysc_ext_instance_free);
 }
 
@@ -508,6 +549,8 @@
     pcre_free_study((*pattern)->expr_extra);
     FREE_STRING(ctx, (*pattern)->eapptag);
     FREE_STRING(ctx, (*pattern)->emsg);
+    FREE_STRING(ctx, (*pattern)->dsc);
+    FREE_STRING(ctx, (*pattern)->ref);
     FREE_ARRAY(ctx, (*pattern)->exts, lysc_ext_instance_free);
     free(*pattern);
 }
@@ -516,6 +559,8 @@
 lysc_enum_item_free(struct ly_ctx *ctx, struct lysc_type_enum_item *item)
 {
     FREE_STRING(ctx, item->name);
+    FREE_STRING(ctx, item->dsc);
+    FREE_STRING(ctx, item->ref);
     FREE_ARRAY(ctx, item->iffeatures, lysc_iffeature_free);
     FREE_ARRAY(ctx, item->exts, lysc_ext_instance_free);
 }
@@ -575,6 +620,7 @@
         break;
     }
     FREE_ARRAY(ctx, type->exts, lysc_ext_instance_free);
+    FREE_STRING(ctx, type->dflt);
 
     free(type);
 }
@@ -644,8 +690,6 @@
 {
     struct lysc_node *child, *child_next;
 
-    FREE_MEMBER(ctx, node->when, lysc_when_free);
-    FREE_ARRAY(ctx, node->iffeatures, lysc_iffeature_free);
     if (node->cases) {
         LY_LIST_FOR_SAFE(node->cases->child, child_next, child) {
             lysc_node_free(ctx, child);
@@ -667,6 +711,8 @@
 {
     /* common part */
     FREE_STRING(ctx, node->name);
+    FREE_STRING(ctx, node->dsc);
+    FREE_STRING(ctx, node->ref);
 
     /* nodetype-specific part */
     switch(node->nodetype) {
@@ -709,12 +755,7 @@
     struct lysc_node *node, *node_next;
 
     LY_CHECK_ARG_RET(NULL, module,);
-    ctx = module->ctx;
-
-    FREE_STRING(ctx, module->name);
-    FREE_STRING(ctx, module->ns);
-    FREE_STRING(ctx, module->prefix);
-    FREE_STRING(ctx, module->revision);
+    ctx = module->mod->ctx;
 
     FREE_ARRAY(ctx, module->imports, lysc_import_free);
     FREE_ARRAY(ctx, module->features, lysc_feature_free);
@@ -745,6 +786,18 @@
     }
 
     lysc_module_free(module->compiled, private_destructor);
+    FREE_ARRAY(module->ctx, module->off_features, lysc_feature_free);
     lysp_module_free(module->parsed);
+
+    FREE_STRING(module->ctx, module->name);
+    FREE_STRING(module->ctx, module->revision);
+    FREE_STRING(module->ctx, module->ns);
+    FREE_STRING(module->ctx, module->prefix);
+    FREE_STRING(module->ctx, module->filepath);
+    FREE_STRING(module->ctx, module->org);
+    FREE_STRING(module->ctx, module->contact);
+    FREE_STRING(module->ctx, module->dsc);
+    FREE_STRING(module->ctx, module->ref);
+
     free(module);
 }
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index 66fcf37..74e950d 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -107,7 +107,7 @@
             if (!mod) {
                 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
                        "Invalid descendant-schema-nodeid value \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
-                       id - nodeid, nodeid, prefix_len, prefix, context_node->module->compiled->name);
+                       id - nodeid, nodeid, prefix_len, prefix, context_node->module->name);
                 return LY_ENOTFOUND;
             }
         } else {
@@ -119,10 +119,10 @@
                    "Invalid descendant-schema-nodeid value \"%.*s\" - target node not found.", id - nodeid, nodeid);
             return LY_ENOTFOUND;
         }
-        if (nodeid_len && ((size_t)(id - nodeid) >= nodeid_len)) {
+        if (!*id || (nodeid_len && ((size_t)(id - nodeid) >= nodeid_len))) {
             break;
         }
-        if (id && *id != '/') {
+        if (*id != '/') {
             LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
                    "Invalid descendant-schema-nodeid value \"%.*s\" - missing \"/\" as node-identifier separator.",
                    id - nodeid + 1, nodeid);
@@ -142,22 +142,20 @@
 }
 
 LY_ERR
-lysp_check_prefix(struct ly_parser_ctx *ctx, struct lysp_module *module, const char **value)
+lysp_check_prefix(struct ly_parser_ctx *ctx, struct lysp_import *imports, const char *module_prefix, const char **value)
 {
     struct lysp_import *i;
 
-    if (module->prefix && &module->prefix != value && !strcmp(module->prefix, *value)) {
+    if (module_prefix && &module_prefix != value && !strcmp(module_prefix, *value)) {
         LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
                "Prefix \"%s\" already used as module prefix.", *value);
         return LY_EEXIST;
     }
-    if (module->imports) {
-        LY_ARRAY_FOR(module->imports, struct lysp_import, i) {
-            if (i->prefix && &i->prefix != value && !strcmp(i->prefix, *value)) {
-                LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
-                       "Prefix \"%s\" already used to import \"%s\" module.", *value, i->name);
-                return LY_EEXIST;
-            }
+    LY_ARRAY_FOR(imports, struct lysp_import, i) {
+        if (i->prefix && &i->prefix != value && !strcmp(i->prefix, *value)) {
+            LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Prefix \"%s\" already used to import \"%s\" module.",
+                   *value, i->name);
+            return LY_EEXIST;
         }
     }
     return LY_SUCCESS;
@@ -505,7 +503,7 @@
 }
 
 LY_ERR
-lysp_check_typedefs(struct ly_parser_ctx *ctx)
+lysp_check_typedefs(struct ly_parser_ctx *ctx, struct lysp_module *mod)
 {
     struct hash_table *ids_global;
     struct hash_table *ids_scoped;
@@ -516,14 +514,14 @@
     /* check name collisions - typedefs and groupings */
     ids_global = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
     ids_scoped = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
-    LY_ARRAY_FOR(ctx->mod->typedefs, i) {
-        if (lysp_check_typedef(ctx, NULL, &ctx->mod->typedefs[i], ids_global, ids_scoped)) {
+    LY_ARRAY_FOR(mod->typedefs, i) {
+        if (lysp_check_typedef(ctx, NULL, &mod->typedefs[i], ids_global, ids_scoped)) {
             goto cleanup;
         }
     }
-    LY_ARRAY_FOR(ctx->mod->includes, i) {
-        LY_ARRAY_FOR(ctx->mod->includes[i].submodule->typedefs, u) {
-            if (lysp_check_typedef(ctx, NULL, &ctx->mod->includes[i].submodule->typedefs[u], ids_global, ids_scoped)) {
+    LY_ARRAY_FOR(mod->includes, i) {
+        LY_ARRAY_FOR(mod->includes[i].submodule->typedefs, u) {
+            if (lysp_check_typedef(ctx, NULL, &mod->includes[i].submodule->typedefs[u], ids_global, ids_scoped)) {
                 goto cleanup;
             }
         }
@@ -545,18 +543,6 @@
     return ret;
 }
 
-void
-lys_module_implement(struct lys_module *mod)
-{
-    assert(mod);
-    if (mod->parsed) {
-        mod->parsed->implemented = 1;
-    }
-    if (mod->compiled) {
-        mod->compiled->implemented = 1;
-    }
-}
-
 struct lysp_load_module_check_data {
     const char *name;
     const char *revision;
@@ -565,44 +551,43 @@
 };
 
 static LY_ERR
-lysp_load_module_check(struct ly_ctx *ctx, struct lysp_module *mod, void *data)
+lysp_load_module_check(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data)
 {
     struct lysp_load_module_check_data *info = data;
-    const char *filename, *dot, *rev;
+    const char *filename, *dot, *rev, *name;
     size_t len;
+    struct lysp_revision *revs;
+
+    name = mod ? mod->mod->name : submod->name;
+    revs = mod ? mod->revs : submod->revs;
 
     if (info->name) {
         /* check name of the parsed model */
-        if (strcmp(info->name, mod->name)) {
-            LOGERR(ctx, LY_EINVAL, "Unexpected module \"%s\" parsed instead of \"%s\").", mod->name, info->name);
+        if (strcmp(info->name, name)) {
+            LOGERR(ctx, LY_EINVAL, "Unexpected module \"%s\" parsed instead of \"%s\").", name, info->name);
             return LY_EINVAL;
         }
     }
     if (info->revision) {
         /* check revision of the parsed model */
-        if (!mod->revs || strcmp(info->revision, mod->revs[0].date)) {
-            LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").", mod->name,
-                   mod->revs[0].date, info->revision);
+        if (!revs || strcmp(info->revision, revs[0].date)) {
+            LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").", name,
+                   revs[0].date, info->revision);
             return LY_EINVAL;
         }
     }
-    if (info->submoduleof) {
-        /* check that we have really a submodule */
-        if (!mod->submodule) {
-            /* submodule is not a submodule */
-            LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Included \"%s\" schema from \"%s\" is actually not a submodule.",
-                   mod->name, info->submoduleof);
-            return LY_EVALID;
-        }
+    if (submod) {
+        assert(info->submoduleof);
+
         /* check that the submodule belongs-to our module */
-        if (strcmp(info->submoduleof, mod->belongsto)) {
+        if (strcmp(info->submoduleof, submod->belongsto)) {
             LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Included \"%s\" submodule from \"%s\" belongs-to a different module \"%s\".",
-                   mod->name, info->submoduleof, mod->belongsto);
+                   submod->name, info->submoduleof, submod->belongsto);
             return LY_EVALID;
         }
         /* check circular dependency */
-        if (mod->parsing) {
-            LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (include) for module \"%s\".", mod->name);
+        if (submod->parsing) {
+            LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (include) for module \"%s\".", submod->name);
             return LY_EVALID;
         }
     }
@@ -615,19 +600,19 @@
             filename++;
         }
         /* name */
-        len = strlen(mod->name);
+        len = strlen(name);
         rev = strchr(filename, '@');
         dot = strrchr(info->path, '.');
-        if (strncmp(filename, mod->name, len) ||
+        if (strncmp(filename, name, len) ||
                 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
-            LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->name);
+            LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, name);
         }
         /* revision */
         if (rev) {
             len = dot - ++rev;
-            if (!mod->revs || len != 10 || strncmp(mod->revs[0].date, rev, len)) {
+            if (!revs || len != 10 || strncmp(revs[0].date, rev, len)) {
                 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
-                       mod->revs ? mod->revs[0].date : "none");
+                       revs ? revs[0].date : "none");
             }
         }
     }
@@ -636,14 +621,16 @@
 
 LY_ERR
 lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct ly_parser_ctx *main_ctx,
-                     struct lys_module **result)
+                     void **result)
 {
     int fd;
     char *filepath = NULL;
+    const char **fp;
     LYS_INFORMAT format;
-    struct lys_module *mod = NULL;
+    void *mod = NULL;
     LY_ERR ret = LY_SUCCESS;
     struct lysp_load_module_check_data check_data = {0};
+    char rpath[PATH_MAX];
 
     LY_CHECK_RET(lys_search_localfile(ly_ctx_get_searchdirs(ctx), !(ctx->flags & LY_CTX_DISABLE_SEARCHDIR_CWD), name, revision,
                                       &filepath, &format));
@@ -666,12 +653,16 @@
     close(fd);
     LY_CHECK_ERR_GOTO(!mod, ly_errcode(ctx), cleanup);
 
-    if (!mod->parsed->filepath) {
-        char rpath[PATH_MAX];
+    if (main_ctx) {
+        fp = &((struct lysp_submodule*)mod)->filepath;
+    } else {
+        fp = &((struct lys_module*)mod)->filepath;
+    }
+    if (!(*fp)) {
         if (realpath(filepath, rpath) != NULL) {
-            mod->parsed->filepath = lydict_insert(ctx, rpath, 0);
+            (*fp) = lydict_insert(ctx, rpath, 0);
         } else {
-            mod->parsed->filepath = lydict_insert(ctx, filepath, 0);
+            (*fp) = lydict_insert(ctx, filepath, 0);
         }
     }
 
@@ -690,12 +681,17 @@
     LYS_INFORMAT format = LYS_IN_UNKNOWN;
     void (*module_data_free)(void *module_data, void *user_data) = NULL;
     struct lysp_load_module_check_data check_data = {0};
+    struct lys_module *m;
 
-    /* try to get the module from the context */
-    if (revision) {
-        *mod = (struct lys_module*)ly_ctx_get_module(ctx, name, revision);
-    } else {
-        *mod = (struct lys_module*)ly_ctx_get_module_latest(ctx, name);
+    assert(mod);
+
+    if (!*mod) {
+        /* try to get the module from the context */
+        if (revision) {
+            *mod = (struct lys_module*)ly_ctx_get_module(ctx, name, revision);
+        } else {
+            *mod = (struct lys_module*)ly_ctx_get_module_latest(ctx, name);
+        }
     }
 
     if (!(*mod) || (require_parsed && !(*mod)->parsed)) {
@@ -716,11 +712,16 @@
                                       &format, &module_data, &module_data_free) == LY_SUCCESS) {
                     check_data.name = name;
                     check_data.revision = revision;
-                    *mod = lys_parse_mem_(ctx, module_data, format, implement, NULL,
-                                          lysp_load_module_check, &check_data);
+                    *mod = lys_parse_mem_module(ctx, module_data, format, implement,
+                                                lysp_load_module_check, &check_data);
                     if (module_data_free) {
                         module_data_free((void*)module_data, ctx->imp_clb_data);
                     }
+                    if (*mod && implement && lys_compile(*mod, 0)) {
+                        ly_set_rm(&ctx->list, *mod, NULL);
+                        lys_module_free(*mod, NULL);
+                        *mod = NULL;
+                    }
                 }
             }
             if (!(*mod) && !(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
@@ -730,26 +731,29 @@
 search_file:
             if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
                 /* module was not received from the callback or there is no callback set */
-                lys_module_localfile(ctx, name, revision, implement, NULL, mod);
+                lys_module_localfile(ctx, name, revision, implement, NULL, (void **)mod);
             }
             if (!(*mod) && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
                 goto search_clb;
             }
         }
 
-        if ((*mod) && !revision && ((*mod)->parsed->latest_revision == 1)) {
+        if ((*mod) && !revision && ((*mod)->latest_revision == 1)) {
             /* update the latest_revision flag - here we have selected the latest available schema,
              * consider that even the callback provides correct latest revision */
-            (*mod)->parsed->latest_revision = 2;
+            (*mod)->latest_revision = 2;
         }
     } else {
         /* we have module from the current context */
-        if (implement && (ly_ctx_get_module_implemented(ctx, name) != *mod)) {
-            /* check collision with other implemented revision */
-            LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
-                   "Module \"%s\" is already present in other implemented revision.", name);
-            *mod = NULL;
-            return LY_EDENIED;
+        if (implement) {
+            m = ly_ctx_get_module_implemented(ctx, name);
+            if (m && m != *mod) {
+                /* check collision with other implemented revision */
+                LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
+                       "Module \"%s\" is already present in other implemented revision.", name);
+                *mod = NULL;
+                return LY_EDENIED;
+            }
         }
 
         /* circular check */
@@ -766,7 +770,7 @@
 
     if (implement) {
         /* mark the module implemented, check for collision was already done */
-        lys_module_implement(*mod);
+        (*mod)->implemented = 1;
     }
 
     return LY_SUCCESS;
@@ -775,7 +779,7 @@
 LY_ERR
 lysp_load_submodule(struct ly_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
 {
-    struct lys_module *submod;
+    struct lysp_submodule *submod;
     const char *submodule_data = NULL;
     LYS_INFORMAT format = LYS_IN_UNKNOWN;
     void (*submodule_data_free)(void *module_data, void *user_data) = NULL;
@@ -785,13 +789,13 @@
     if (!(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
 search_clb:
         if (ctx->ctx->imp_clb) {
-            if (ctx->ctx->imp_clb(mod->name, NULL, inc->name, inc->rev[0] ? inc->rev : NULL, ctx->ctx->imp_clb_data,
+            if (ctx->ctx->imp_clb(mod->mod->name, NULL, inc->name, inc->rev[0] ? inc->rev : NULL, ctx->ctx->imp_clb_data,
                                   &format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
                 check_data.name = inc->name;
                 check_data.revision = inc->rev[0] ? inc->rev : NULL;
-                check_data.submoduleof = mod->name;
-                submod = lys_parse_mem_(ctx->ctx, submodule_data, format, mod->implemented, ctx,
-                                        lysp_load_module_check, &check_data);
+                check_data.submoduleof = mod->mod->name;
+                submod = lys_parse_mem_submodule(ctx->ctx, submodule_data, format, ctx,
+                                                 lysp_load_module_check, &check_data);
                 if (submodule_data_free) {
                     submodule_data_free((void*)submodule_data, ctx->ctx->imp_clb_data);
                 }
@@ -803,41 +807,41 @@
     } else {
 search_file:
         if (!(ctx->ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
-            /* module was not received from the callback or there is no callback set */
-            lys_module_localfile(ctx->ctx, inc->name, inc->rev[0] ? inc->rev : NULL, mod->implemented, ctx, &submod);
+            /* submodule was not received from the callback or there is no callback set */
+            lys_module_localfile(ctx->ctx, inc->name, inc->rev[0] ? inc->rev : NULL, 0, ctx, (void**)&submod);
         }
         if (!submod && (ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
             goto search_clb;
         }
     }
     if (submod) {
-        if (!inc->rev[0] && (submod->parsed->latest_revision == 1)) {
+        if (!inc->rev[0] && (submod->latest_revision == 1)) {
             /* update the latest_revision flag - here we have selected the latest available schema,
              * consider that even the callback provides correct latest revision */
-            submod->parsed->latest_revision = 2;
+            submod->latest_revision = 2;
         }
 
-        inc->submodule = submod->parsed;
-        free(submod);
+        inc->submodule = submod;
     }
     if (!inc->submodule) {
-        LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.", inc->name, mod->name);
+        LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.",
+               inc->name, mod->mod->name);
         return LY_EVALID;
     }
 
     return LY_SUCCESS;
 }
 
-#define FIND_MODULE(TYPE, MOD, ID) \
+#define FIND_MODULE(TYPE, MOD) \
     TYPE *imp; \
-    if (!strncmp((MOD)->prefix, prefix, len) && (MOD)->prefix[len] == '\0') { \
+    if (!strncmp((MOD)->mod->prefix, prefix, len) && (MOD)->mod->prefix[len] == '\0') { \
         /* it is the prefix of the module itself */ \
-        m = ly_ctx_get_module((MOD)->ctx, (MOD)->name, ((struct lysc_module*)(MOD))->revision); \
+        m = ly_ctx_get_module((MOD)->mod->ctx, (MOD)->mod->name, (MOD)->mod->revision); \
     } \
     /* search in imports */ \
     if (!m) { \
         LY_ARRAY_FOR((MOD)->imports, TYPE, imp) { \
-            if (!strncmp(imp->prefix, prefix, len) && (MOD)->prefix[len] == '\0') { \
+            if (!strncmp(imp->prefix, prefix, len) && imp->prefix[len] == '\0') { \
                 m = imp->module; \
                 break; \
             } \
@@ -849,7 +853,7 @@
 {
     const struct lys_module *m = NULL;
 
-    FIND_MODULE(struct lysc_import, mod, 1);
+    FIND_MODULE(struct lysc_import, mod);
     return m ? m->compiled : NULL;
 }
 
@@ -858,7 +862,7 @@
 {
     const struct lys_module *m = NULL;
 
-    FIND_MODULE(struct lysp_import, mod, 1);
+    FIND_MODULE(struct lysp_import, mod);
     return m ? m->parsed : NULL;
 }
 
@@ -868,9 +872,9 @@
     const struct lys_module *m = NULL;
 
     if (mod->compiled) {
-        FIND_MODULE(struct lysc_import, mod->compiled, 1);
+        FIND_MODULE(struct lysc_import, mod->compiled);
     } else {
-        FIND_MODULE(struct lysp_import, mod->parsed, 2);
+        FIND_MODULE(struct lysp_import, mod->parsed);
     }
     return (struct lys_module*)m;
 }
@@ -1103,6 +1107,8 @@
         } else {
             return NULL;
         }
+    case LYS_CASE:
+        return &((struct lysc_node_case*)node)->child;
     case LYS_LIST:
         return &((struct lysc_node_list*)node)->child;
 /* TODO
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 26159b1..1a3e078 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -48,11 +48,11 @@
  */
 struct ly_parser_ctx {
     struct ly_ctx *ctx;
-    struct lysp_module *mod;
     struct ly_set tpdfs_nodes;
     struct ly_set grps_nodes;
     uint64_t line;      /**< line number */
     uint64_t indent;    /**< current position on the line for YANG indentation */
+    uint8_t mod_version; /**< module's version */
 };
 
 /**
@@ -61,12 +61,12 @@
 struct lysc_ctx {
     struct ly_ctx *ctx;
     struct lys_module *mod;
-    struct lys_module *mod_def; /* context module for the definitions of the nodes being currently
-                                   processed - groupings are supposed to be evaluated in place where
-                                   defined, but its content instances are supposed to be placed into
-                                   the target module (mod) */
-    struct ly_set groupings;    /* stack for groupings circular check */
-    struct ly_set unres;        /* to validate leafref's target and xpath of when/must */
+    struct lys_module *mod_def; /**< context module for the definitions of the nodes being currently
+                                     processed - groupings are supposed to be evaluated in place where
+                                     defined, but its content instances are supposed to be placed into
+                                     the target module (mod) */
+    struct ly_set groupings;    /**< stack for groupings circular check */
+    struct ly_set unres;        /**< to validate leafref's target and xpath of when/must */
     uint16_t path_len;
 #define LYSC_CTX_BUFSIZE 4078
     char path[LYSC_CTX_BUFSIZE];
@@ -76,11 +76,12 @@
  * @brief Check the currently present prefixes in the module for collision with the new one.
  *
  * @param[in] ctx Context for logging.
- * @param[in] module Schema tree to check.
+ * @param[in] imports List of current imports of the module to check prefix collision.
+ * @param[in] module_prefix Prefix of the module to check collision.
  * @param[in] value Newly added prefix value (including its location to distinguish collision with itself).
  * @return LY_EEXIST when prefix is already used in the module, LY_SUCCESS otherwise
  */
-LY_ERR lysp_check_prefix(struct ly_parser_ctx *ctx, struct lysp_module *module, const char **value);
+LY_ERR lysp_check_prefix(struct ly_parser_ctx *ctx, struct lysp_import *imports, const char *module_prefix, const char **value);
 
 /**
  * @brief Check date string (4DIGIT "-" 2DIGIT "-" 2DIGIT)
@@ -96,10 +97,11 @@
 /**
  * @brief Check names of typedefs in the parsed module to detect collisions.
  *
- * @param[in] ctx Parser context, module where the type is being defined is taken from here.
+ * @param[in] ctx Parser context for logging and to maintain tpdfs_nodes
+ * @param[in] mod Module where the type is being defined.
  * @return LY_ERR value.
  */
-LY_ERR lysp_check_typedefs(struct ly_parser_ctx *ctx);
+LY_ERR lysp_check_typedefs(struct ly_parser_ctx *ctx, struct lysp_module *mod);
 
 /**
  * @brief Just move the newest revision into the first position, does not sort the rest
@@ -147,6 +149,25 @@
 LY_ERR lysp_load_submodule(struct ly_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc);
 
 /**
+ * @defgroup scflags Schema compile flags
+ * @ingroup schematree
+ *
+ * @{
+ */
+#define LYSC_OPT_FREE_SP 1           /**< Free the input printable schema */
+/** @} scflags */
+
+/**
+ * @brief Compile printable schema into a validated schema linking all the references.
+ *
+ * @param[in, out] mod Schema structure holding pointers to both schema structure types. The ::lys_module#parsed
+ * member is used as input and ::lys_module#compiled is used to hold the result of the compilation.
+ * @param[in] options Various options to modify compiler behavior, see [compile flags](@ref scflags).
+ * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
+ */
+LY_ERR lys_compile(struct lys_module *mod, int options);
+
+/**
  * @brief Get address of a node's actions list if any.
  *
  * Decides the node's type and in case it has an actions list, returns its address.
@@ -279,31 +300,45 @@
 const char *lys_nodetype2str(uint16_t nodetype);
 
 /**
- * @brief Parse YANG module and submodule from a string.
+ * @brief Parse YANG module from a string.
  *
- * In contrast to public lys_parse_mem(), also submodules can be parsed here. However,
- * while the modules are added into the context, submodules not. The latest_revision
- * flag is updated in both cases.
+ * The modules are added into the context and the latest_revision flag is updated.
  *
  * @param[in] ctx libyang context where to process the data model.
  * @param[in] data The string containing the dumped data model in the specified
  * format.
  * @param[in] format Format of the input data (YANG or YIN).
  * @param[in] implement Flag if the schema is supposed to be marked as implemented.
- * @param[in] main_ctx Parser context of the main module in case of parsing submodule.
  * @param[in] custom_check Callback to check the parsed schema before it is accepted.
  * @param[in] check_data Caller's data to pass to the custom_check callback.
  * @return Pointer to the data model structure or NULL on error.
  */
-struct lys_module *lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
-                                  LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data);
+struct lys_module *lys_parse_mem_module(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, int implement,
+                                        LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *check_data),
+                                        void *check_data);
 
 /**
- * @brief Parse YANG module and submodule from a file descriptor.
+ * @brief Parse YANG submodule from a string.
  *
- * In contrast to public lys_parse_mem(), also submodules can be parsed here. However,
- * while the modules are added into the context, submodules not. The latest_revision
- * flag is updated in both cases.
+ * The latest_revision flag of submodule is updated.
+ *
+ * @param[in] ctx libyang context where to process the data model.
+ * @param[in] data The string containing the dumped data model in the specified
+ * format.
+ * @param[in] format Format of the input data (YANG or YIN).
+ * @param[in] main_ctx Parser context of the main module.
+ * @param[in] custom_check Callback to check the parsed schema before it is accepted.
+ * @param[in] check_data Caller's data to pass to the custom_check callback.
+ * @return Pointer to the data model structure or NULL on error.
+ */
+struct lysp_submodule *lys_parse_mem_submodule(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, struct ly_parser_ctx *main_ctx,
+                                               LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *check_data),
+                                               void *check_data);
+
+/**
+ * @brief Parse YANG module or submodule from a file descriptor.
+ *
+ * The modules are added into the context, submodules not. The latest_revision flag is updated in both cases.
  *
  * \note Current implementation supports only reading data from standard (disk) file, not from sockets, pipes, etc.
  *
@@ -312,36 +347,74 @@
  *            in the specified format.
  * @param[in] format Format of the input data (YANG or YIN).
  * @param[in] implement Flag if the schema is supposed to be marked as implemented.
- * @param[in] main_ctx Parser context of the main module in case of parsing submodule.
+ * @param[in] main_ctx Parser context of the main module in case of parsing submodule. This flag decides if the module
+ * or submodule was expected to be parsed.
  * @param[in] custom_check Callback to check the parsed schema before it is accepted.
  * @param[in] check_data Caller's data to pass to the custom_check callback.
  * @return Pointer to the data model structure or NULL on error.
  */
-struct lys_module *lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
-                                 LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data);
+void *lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
+                    LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
+                    void *check_data);
 
 /**
- * @brief Parse YANG module and submodule from a file descriptor.
+ * @brief Parse YANG module from a file descriptor.
  *
- * In contrast to public lys_parse_mem(), also submodules can be parsed here. However,
- * while the modules are added into the context, submodules not. The latest_revision
- * flag is updated in both cases.
+ * The modules are added into the context. The latest_revision flag is updated.
  *
  * \note Current implementation supports only reading data from standard (disk) file, not from sockets, pipes, etc.
  *
- * @brief REad a schema into the specified context from a file.
+ * @param[in] ctx libyang context where to process the data model.
+ * @param[in] fd File descriptor of a regular file (e.g. sockets are not supported) containing the schema
+ *            in the specified format.
+ * @param[in] format Format of the input data (YANG or YIN).
+ * @param[in] implement Flag if the schema is supposed to be marked as implemented.
+ * @param[in] custom_check Callback to check the parsed schema before it is accepted.
+ * @param[in] check_data Caller's data to pass to the custom_check callback.
+ * @return Pointer to the data model structure or NULL on error.
+ */
+struct lys_module *lys_parse_fd_module(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement,
+                                           LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *check_data),
+                                           void *check_data);
+
+/**
+ * @brief Parse YANG submodule from a file descriptor.
+ *
+ * The latest_revision flag of submodules is updated.
+ *
+ * \note Current implementation supports only reading data from standard (disk) file, not from sockets, pipes, etc.
+ *
+ * @param[in] ctx libyang context where to process the data model.
+ * @param[in] fd File descriptor of a regular file (e.g. sockets are not supported) containing the schema
+ *            in the specified format.
+ * @param[in] format Format of the input data (YANG or YIN).
+ * @param[in] main_ctx Parser context of the main module.
+ * @param[in] custom_check Callback to check the parsed schema before it is accepted.
+ * @param[in] check_data Caller's data to pass to the custom_check callback.
+ * @return Pointer to the data model structure or NULL on error.
+ */
+struct lysp_submodule *lys_parse_fd_submodule(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, struct ly_parser_ctx *main_ctx,
+                                              LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *check_data),
+                                              void *check_data);
+
+/**
+ * @brief Parse YANG module from a filepath.
+ *
+ * The modules are added into the context. The latest_revision flag is updated.
+ *
+ * \note Current implementation supports only reading data from standard (disk) file, not from sockets, pipes, etc.
  *
  * @param[in] ctx libyang context where to process the data model.
  * @param[in] path Path to the file with the model in the specified format.
  * @param[in] format Format of the input data (YANG or YIN).
  * @param[in] implement Flag if the schema is supposed to be marked as implemented.
- * @param[in] main_ctx Parser context of the main module in case of parsing submodule.
  * @param[in] custom_check Callback to check the parsed schema before it is accepted.
  * @param[in] check_data Caller's data to pass to the custom_check callback.
  * @return Pointer to the data model structure or NULL on error.
  */
-struct lys_module *lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
-                                   LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data);
+struct lys_module *lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, int implement,
+                                   LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
+                                   void *check_data);
 
 /**
  * @brief Load the (sub)module into the context.
@@ -355,18 +428,40 @@
  * @param[in] revision Optional revision of the (sub)module to load, if NULL the newest revision is being loaded.
  * @param[in] implement Flag if the (sub)module is supposed to be marked as implemented.
  * @param[in] main_ctx Parser context of the main module in case of loading submodule.
- * @param[out] result Parsed YANG schema tree of the requested module. If it is a module, it is already in the context!
+ * @param[out] result Parsed YANG schema tree of the requested module (struct lys_module*) or submodule (struct lysp_submodule*).
+ * If it is a module, it is already in the context!
  * @return LY_ERR value, in case of LY_SUCCESS, the \arg result is always provided.
  */
 LY_ERR lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct ly_parser_ctx *main_ctx,
-                            struct lys_module **result);
+                            void **result);
 
 /**
- * @brief Make the module implemented.
- * Does not check for collision in context, it must be done before calling the function, this is a simple switch.
- * @param[in] mod Module to make implemented.
+ * @brief Create pre-compiled features array.
+ *
+ * Features are compiled in two steps to allow forward references between them via their if-feature statements.
+ * In case of not implemented schemas, the precompiled list of features is stored in lys_module structure and
+ * the compilation is not finished (if-feature and extensions are missing) and all the features are permanently
+ * disabled without a chance to change it. The list is used as target for any if-feature statement in any
+ * implemented module to get valid data to evaluate its result. The compilation is finished via
+ * lys_feature_precompile_finish() in implemented modules. In case a not implemented module becomes implemented,
+ * the precompiled list is reused to finish the compilation to preserve pointers already used in various compiled
+ * if-feature structures.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] features_p Array if the parsed features definitions to precompile.
+ * @param[in,out] features Pointer to the storage of the (pre)compiled features array where the new features are
+ * supposed to be added. The storage is supposed to be initiated to NULL when the first parsed features are going
+ * to be processed.
+ * @return LY_ERR value.
  */
-void lys_module_implement(struct lys_module *mod);
+LY_ERR lys_feature_precompile(struct ly_ctx *ctx, struct lysp_feature *features_p, struct lysc_feature **features);
+
+/**
+ * @brief Free the parsed submodule structure.
+ * @param[in] ctx libyang context where the string data resides in a dictionary.
+ * @param[in,out] submod Parsed schema submodule structure to free.
+ */
+void lysp_submodule_free(struct ly_ctx *ctx, struct lysp_submodule *submod);
 
 /**
  * @brief Free the compiled type structure.
@@ -376,6 +471,22 @@
 void lysc_type_free(struct ly_ctx *ctx, struct lysc_type *type);
 
 /**
+ * @brief Free the compiled if-feature structure.
+ * @param[in] ctx libyang context where the string data resides in a dictionary.
+ * @param[in,out] iff Compiled if-feature structure to be cleaned.
+ * Since the structure is typically part of the sized array, the structure itself is not freed.
+ */
+void lysc_iffeature_free(struct ly_ctx *ctx, struct lysc_iffeature *iff);
+
+/**
+ * @brief Free the compiled extension instance structure.
+ * @param[in] ctx libyang context where the string data resides in a dictionary.
+ * @param[in,out] ext Compiled extension instance structure to be cleaned.
+ * Since the structure is typically part of the sized array, the structure itself is not freed.
+ */
+void lysc_ext_instance_free(struct ly_ctx *ctx, struct lysc_ext_instance *ext);
+
+/**
  * @brief Free the compiled node structure.
  * @param[in] ctx libyang context where the string data resides in a dictionary.
  * @param[in,out] node Compiled node structure to be freed.
@@ -397,9 +508,23 @@
 void lys_module_free(struct lys_module *module, void (*private_destructor)(const struct lysc_node *node, void *priv));
 
 /**
- * @brief
+ * @brief Parse submodule from YANG data.
+ * @param[in] ctx Parser context.
+ * @param[in] data Input data to be parsed.
+ * @param[out] submod Pointer to the parsed submodule structure.
+ * @return LY_ERR value - LY_SUCCESS, LY_EINVAL or LY_EVALID.
  */
-LY_ERR yang_parse(struct ly_parser_ctx *ctx, const char *data, struct lysp_module **mod_p);
+LY_ERR yang_parse_submodule(struct ly_parser_ctx *ctx, const char *data, struct lysp_submodule **submod);
+
+/**
+ * @brief Parse module from YANG data.
+ * @param[in] ctx Parser context.
+ * @param[in] data Input data to be parsed.
+ * @param[in, out] mod Prepared module structure where the parsed information, including the parsed
+ * module structure, will be filled in.
+ * @return LY_ERR value - LY_SUCCESS, LY_EINVAL or LY_EVALID.
+ */
+LY_ERR yang_parse_module(struct ly_parser_ctx *ctx, const char *data, struct lys_module *mod);
 
 /**
  * @brief match yang keyword
diff --git a/src/xpath.c b/src/xpath.c
index 4a3792d..94cb734 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -35,11 +35,12 @@
  *
  * @return Length of \p ncname valid bytes.
  */
-static size_t
+static long int
 parse_ncname(const char *ncname)
 {
     unsigned int uc;
-    size_t size, len = 0;
+    size_t size;
+    long int len = 0;
 
     LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), 0);
     if (!is_xmlqnamestartchar(uc) || (uc == ':')) {
@@ -48,7 +49,10 @@
 
     do {
         len += size;
-        LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), 0);
+        if (!*ncname) {
+            break;
+        }
+        LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), -len);
     } while (is_xmlqnamechar(uc) && (uc != ':'));
 
     return len;
@@ -118,7 +122,8 @@
 lyxp_expr_parse(struct ly_ctx *ctx, const char *expr)
 {
     struct lyxp_expr *ret;
-    size_t parsed = 0, tok_len, ncname_len;
+    size_t parsed = 0, tok_len;
+    long int ncname_len;
     enum lyxp_token tok_type;
     int prev_function_check = 0;
 
@@ -305,7 +310,7 @@
                        expr[parsed], &expr[parsed], ret->tok_len[ret->used - 1], &ret->expr[ret->tok_pos[ret->used - 1]]);
                 goto error;
             } else {
-                LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, expr[parsed], &expr[parsed]);
+                LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed + 1, expr);
                 goto error;
             }
         } else if (expr[parsed] == '*') {
@@ -318,7 +323,7 @@
 
             /* NameTest (NCName ':' '*' | QName) or NodeType/FunctionName */
             ncname_len = parse_ncname(&expr[parsed]);
-            LY_CHECK_ERR_GOTO(!ncname_len, LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, expr[parsed], &expr[parsed]), error);
+            LY_CHECK_ERR_GOTO(ncname_len < 0, LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed - ncname_len + 1, expr), error);
             tok_len = ncname_len;
 
             if (expr[parsed + tok_len] == ':') {
@@ -327,7 +332,7 @@
                     ++tok_len;
                 } else {
                     ncname_len = parse_ncname(&expr[parsed + tok_len]);
-                    LY_CHECK_ERR_GOTO(!ncname_len, LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, expr[parsed], &expr[parsed]), error);
+                    LY_CHECK_ERR_GOTO(ncname_len < 0, LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed - ncname_len + 1, expr), error);
                     tok_len += ncname_len;
                 }
                 /* remove old flag to prevent ambiguities */
diff --git a/tests/src/test_context.c b/tests/src/test_context.c
index a9dae30..624cf6f 100644
--- a/tests/src/test_context.c
+++ b/tests/src/test_context.c
@@ -68,6 +68,18 @@
     return 0;
 }
 
+static int
+logger_teardown(void **state)
+{
+    (void) state; /* unused */
+#if ENABLE_LOGGER_CHECKING
+    if (*state) {
+        fprintf(stderr, "%s\n", logbuf);
+    }
+#endif
+    return 0;
+}
+
 #if ENABLE_LOGGER_CHECKING
 #   define logbuf_assert(str) assert_string_equal(logbuf, str)
 #else
@@ -77,7 +89,7 @@
 static void
 test_searchdirs(void **state)
 {
-    (void) state; /* unused */
+    *state = test_searchdirs;
 
     struct ly_ctx *ctx;
     const char * const *list;
@@ -169,13 +181,14 @@
     assert_string_equal("/home", ctx->search_paths.objs[1]);
 
     /* cleanup */
+    *state = NULL;
     ly_ctx_destroy(ctx, NULL);
 }
 
 static void
 test_options(void **state)
 {
-    (void) state; /* unused */
+    *state = test_options;
 
     struct ly_ctx *ctx;
 
@@ -249,6 +262,7 @@
     assert_int_equal(ctx->flags, ly_ctx_get_options(ctx));
 
     /* cleanup */
+    *state = NULL;
     ly_ctx_destroy(ctx, NULL);
 }
 
@@ -265,7 +279,7 @@
 static void
 test_models(void **state)
 {
-    (void) state; /* unused */
+    *state = test_models;
 
     struct ly_ctx *ctx;
     const char *str;
@@ -278,7 +292,7 @@
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
     assert_int_equal(ctx->module_set_id, ly_ctx_get_module_set_id(ctx));
 
-    assert_null(lys_parse_mem(ctx, "module x {namespace urn:x;prefix x;}", 3));
+    assert_null(lys_parse_mem_module(ctx, "module x {namespace urn:x;prefix x;}", 3, 1, NULL, NULL));
     logbuf_assert("Invalid schema input format.");
 
     /* import callback */
@@ -294,18 +308,18 @@
 
     /* name collision of module and submodule */
     ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "submodule y {belongs-to a {prefix a;} revision 2018-10-30;}");
-    assert_null(lys_parse_mem(ctx, "module y {namespace urn:y;prefix y;include y;}", LYS_IN_YANG));
+    assert_null(lys_parse_mem_module(ctx, "module y {namespace urn:y;prefix y;include y;}", LYS_IN_YANG, 1, NULL, NULL));
     assert_int_equal(LY_EVALID, ly_errcode(ctx));
     logbuf_assert("Name collision between module and submodule of name \"y\". Line number 1.");
 
-    assert_non_null(lys_parse_mem(ctx, "module a {namespace urn:a;prefix a;include y;revision 2018-10-30; }", LYS_IN_YANG));
-    assert_null(lys_parse_mem(ctx, "module y {namespace urn:y;prefix y;}", LYS_IN_YANG));
+    assert_non_null(lys_parse_mem_module(ctx, "module a {namespace urn:a;prefix a;include y;revision 2018-10-30; }", LYS_IN_YANG, 1, NULL, NULL));
+    assert_null(lys_parse_mem_module(ctx, "module y {namespace urn:y;prefix y;}", LYS_IN_YANG, 1, NULL, NULL));
     assert_int_equal(LY_EVALID, ly_errcode(ctx));
     logbuf_assert("Name collision between module and submodule of name \"y\". Line number 1.");
 
     store = 1;
     ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "submodule y {belongs-to b {prefix b;}}");
-    assert_null(lys_parse_mem(ctx, "module b {namespace urn:b;prefix b;include y;}", LYS_IN_YANG));
+    assert_null(lys_parse_mem_module(ctx, "module b {namespace urn:b;prefix b;include y;}", LYS_IN_YANG, 1, NULL, NULL));
     assert_int_equal(LY_EVALID, ly_errcode(ctx));
     logbuf_assert("Name collision between submodules of name \"y\". Line number 1.");
     store = -1;
@@ -313,17 +327,17 @@
     /* selecting correct revision of the submodules */
     ly_ctx_reset_latests(ctx);
     ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "submodule y {belongs-to a {prefix a;} revision 2018-10-31;}");
-    mod2 = lys_parse_mem_(ctx, "module a {namespace urn:a;prefix a;include y; revision 2018-10-31;}", LYS_IN_YANG, 0, NULL, NULL, NULL);
+    mod2 = lys_parse_mem_module(ctx, "module a {namespace urn:a;prefix a;include y; revision 2018-10-31;}", LYS_IN_YANG, 0, NULL, NULL);
     assert_non_null(mod2);
     assert_string_equal("2018-10-31", mod2->parsed->includes[0].submodule->revs[0].date);
 
     /* reloading module in case only the compiled module resists in the context */
-    mod1 = lys_parse_mem(ctx, "module w {namespace urn:w;prefix w;revision 2018-10-24;}", LYS_IN_YANG);
+    mod1 = lys_parse_mem_module(ctx, "module w {namespace urn:w;prefix w;revision 2018-10-24;}", LYS_IN_YANG, 1, NULL, NULL);
     assert_non_null(mod1);
     assert_int_equal(LY_SUCCESS, lys_compile(mod1, LYSC_OPT_FREE_SP));
     assert_non_null(mod1->compiled);
     assert_null(mod1->parsed);
-    mod2 = lys_parse_mem(ctx, "module z {namespace urn:z;prefix z;import w {prefix w;revision-date 2018-10-24;}}", LYS_IN_YANG);
+    mod2 = lys_parse_mem_module(ctx, "module z {namespace urn:z;prefix z;import w {prefix w;revision-date 2018-10-24;}}", LYS_IN_YANG, 1, NULL, NULL);
     assert_non_null(mod2);
     /* mod1->parsed is necessary to compile mod2 because of possible groupings, typedefs, ... */
     ly_ctx_set_module_imp_clb(ctx, NULL, NULL);
@@ -332,16 +346,17 @@
     ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "module w {namespace urn:w;prefix w;revision 2018-10-24;}");
     assert_int_equal(LY_SUCCESS, lys_compile(mod2, 0));
     assert_non_null(mod1->parsed);
-    assert_string_equal("w", mod1->parsed->name);
+    assert_string_equal("w", mod1->name);
 
     /* cleanup */
+    *state = NULL;
     ly_ctx_destroy(ctx, NULL);
 }
 
 static void
 test_get_models(void **state)
 {
-    (void) state; /* unused */
+    *state = test_get_models;
 
     struct ly_ctx *ctx;
     const struct lys_module *mod, *mod2;
@@ -367,8 +382,8 @@
     mod = ly_ctx_get_module_implemented(ctx, "yang");
     assert_non_null(mod);
     assert_non_null(mod->parsed);
-    assert_string_equal("yang", mod->parsed->name);
-    mod2 = ly_ctx_get_module_implemented_ns(ctx, mod->parsed->ns);
+    assert_string_equal("yang", mod->name);
+    mod2 = ly_ctx_get_module_implemented_ns(ctx, mod->ns);
     assert_ptr_equal(mod, mod2);
     assert_non_null(ly_ctx_get_module(ctx, "ietf-yang-metadata", "2016-08-05"));
     assert_non_null(ly_ctx_get_module(ctx, "ietf-yang-types", "2013-07-15"));
@@ -376,42 +391,43 @@
     assert_non_null(ly_ctx_get_module_ns(ctx, "urn:ietf:params:xml:ns:yang:ietf-datastores", "2017-08-17"));
 
     /* select module by revision */
-    mod = lys_parse_mem(ctx, str1, LYS_IN_YANG);
+    mod = lys_parse_mem_module(ctx, str1, LYS_IN_YANG, 1, NULL, NULL);
     /* invalid attempts - implementing module of the same name and inserting the same module */
-    assert_null(lys_parse_mem(ctx, str2, LYS_IN_YANG));
+    assert_null(lys_parse_mem_module(ctx, str2, LYS_IN_YANG, 1, NULL, NULL));
     logbuf_assert("Module \"a\" is already implemented in the context.");
-    assert_null(lys_parse_mem_(ctx, str1, LYS_IN_YANG, 0, NULL, NULL, NULL));
+    assert_null(lys_parse_mem_module(ctx, str1, LYS_IN_YANG, 0, NULL, NULL));
     logbuf_assert("Module \"a\" of revision \"2018-10-23\" is already present in the context.");
     /* insert the second module only as imported, not implemented */
-    mod2 = lys_parse_mem_(ctx, str2, LYS_IN_YANG, 0, NULL, NULL, NULL);
+    mod2 = lys_parse_mem_module(ctx, str2, LYS_IN_YANG, 0, NULL, NULL);
     assert_non_null(mod);
     assert_non_null(mod2);
     assert_ptr_not_equal(mod, mod2);
     mod = ly_ctx_get_module_latest(ctx, "a");
     assert_ptr_equal(mod, mod2);
-    mod2 = ly_ctx_get_module_latest_ns(ctx, mod->parsed->ns);
+    mod2 = ly_ctx_get_module_latest_ns(ctx, mod->ns);
     assert_ptr_equal(mod, mod2);
     /* work with module with no revision */
-    mod = lys_parse_mem_(ctx, str0, LYS_IN_YANG, 0, NULL, NULL, NULL);
+    mod = lys_parse_mem_module(ctx, str0, LYS_IN_YANG, 0, NULL, NULL);
     assert_non_null(mod);
     assert_ptr_equal(mod, ly_ctx_get_module(ctx, "a", NULL));
     assert_ptr_not_equal(mod, ly_ctx_get_module_latest(ctx, "a"));
 
     str1 = "submodule b {belongs-to a {prefix a;}}";
-    assert_null(lys_parse_mem(ctx, str1, LYS_IN_YANG));
-    logbuf_assert("Input data contains submodule \"b\" which cannot be parsed directly without its main module.");
+    assert_null(lys_parse_mem_module(ctx, str1, LYS_IN_YANG, 1, NULL, NULL));
+    logbuf_assert("Input data contains submodule which cannot be parsed directly without its main module.");
 
     /* cleanup */
+    *state = NULL;
     ly_ctx_destroy(ctx, NULL);
 }
 
 int main(void)
 {
     const struct CMUnitTest tests[] = {
-        cmocka_unit_test_setup(test_searchdirs, logger_setup),
-        cmocka_unit_test_setup(test_options, logger_setup),
-        cmocka_unit_test_setup(test_models, logger_setup),
-        cmocka_unit_test_setup(test_get_models, logger_setup),
+        cmocka_unit_test_setup_teardown(test_searchdirs, logger_setup, logger_teardown),
+        cmocka_unit_test_setup_teardown(test_options, logger_setup, logger_teardown),
+        cmocka_unit_test_setup_teardown(test_models, logger_setup, logger_teardown),
+        cmocka_unit_test_setup_teardown(test_get_models, logger_setup, logger_teardown),
     };
 
     return cmocka_run_group_tests(tests, NULL, NULL);
diff --git a/tests/src/test_parser_yang.c b/tests/src/test_parser_yang.c
index b07725a..7a034ee 100644
--- a/tests/src/test_parser_yang.c
+++ b/tests/src/test_parser_yang.c
@@ -673,7 +673,6 @@
 {
     *state = test_minmax;
 
-    struct lysp_module mod = {0};
     struct ly_parser_ctx ctx = {0};
     uint16_t flags = 0;
     uint32_t value = 0;
@@ -683,8 +682,7 @@
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
     assert_non_null(ctx.ctx);
     ctx.line = 1;
-    ctx.mod = &mod;
-    ctx.mod->version = 2; /* simulate YANG 1.1 */
+    ctx.mod_version = 2; /* simulate YANG 1.1 */
 
     str = " 1invalid; ...";
     assert_int_equal(LY_EVALID, parse_minelements(&ctx, &str, &value, &flags, &ext));
@@ -767,15 +765,38 @@
 }
 
 static struct lysp_module *
-mod_renew(struct ly_parser_ctx *ctx, struct lysp_module *mod, uint8_t submodule)
+mod_renew(struct ly_parser_ctx *ctx)
 {
-    lysp_module_free(mod);
-    mod = calloc(1, sizeof *mod);
-    mod->ctx = ctx->ctx;
-    mod->submodule = submodule;
-    assert_non_null(mod);
-    ctx->mod = mod;
-    return mod;
+    struct lysp_module *mod_p;
+    static struct lys_module mod = {0};
+
+    lysc_module_free(mod.compiled, NULL);
+    lysp_module_free(mod.parsed);
+    FREE_STRING(mod.ctx, mod.name);
+    FREE_STRING(mod.ctx, mod.ns);
+    FREE_STRING(mod.ctx, mod.prefix);
+    FREE_STRING(mod.ctx, mod.filepath);
+    FREE_STRING(mod.ctx, mod.org);
+    FREE_STRING(mod.ctx, mod.contact);
+    FREE_STRING(mod.ctx, mod.dsc);
+    FREE_STRING(mod.ctx, mod.ref);
+    memset(&mod, 0, sizeof mod);
+    mod.ctx = ctx->ctx;
+
+    mod_p = calloc(1, sizeof *mod_p);
+    mod.parsed = mod_p;
+    mod_p->mod = &mod;
+    assert_non_null(mod_p);
+    return mod_p;
+}
+
+static struct lysp_submodule *
+submod_renew(struct ly_parser_ctx *ctx, struct lysp_submodule *submod)
+{
+    lysp_submodule_free(ctx->ctx, submod);
+    submod = calloc(1, sizeof *submod);
+    assert_non_null(submod);
+    return submod;
 }
 
 static LY_ERR test_imp_clb(const char *UNUSED(mod_name), const char *UNUSED(mod_rev), const char *UNUSED(submod_name),
@@ -791,10 +812,12 @@
 static void
 test_module(void **state)
 {
-    (void) state; /* unused */
+    *state = test_module;
 
     struct ly_parser_ctx ctx;
-    struct lysp_module *mod;
+    struct lysp_module *mod = NULL;
+    struct lysp_submodule *submod = NULL;
+    struct lys_module *m;
     const char *str;
 
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
@@ -802,58 +825,58 @@
     ctx.line = 1;
     ctx.indent = 0;
 
-    mod = mod_renew(&ctx, NULL, 0);
+    mod = mod_renew(&ctx);
 
     /* missing mandatory substatements */
     str = " name {}";
-    assert_int_equal(LY_EVALID, parse_sub_module(&ctx, &str, mod));
-    assert_string_equal("name", mod->name);
+    assert_int_equal(LY_EVALID, parse_module(&ctx, &str, mod));
+    assert_string_equal("name", mod->mod->name);
     logbuf_assert("Missing mandatory keyword \"namespace\" as a child of \"module\". Line number 1.");
-    mod = mod_renew(&ctx, mod, 0);
+    mod = mod_renew(&ctx);
 
     str = " name {namespace urn:x;}";
-    assert_int_equal(LY_EVALID, parse_sub_module(&ctx, &str, mod));
-    assert_string_equal("urn:x", mod->ns);
+    assert_int_equal(LY_EVALID, parse_module(&ctx, &str, mod));
+    assert_string_equal("urn:x", mod->mod->ns);
     logbuf_assert("Missing mandatory keyword \"prefix\" as a child of \"module\". Line number 1.");
-    mod = mod_renew(&ctx, mod, 0);
+    mod = mod_renew(&ctx);
 
     str = " name {namespace urn:x;prefix \"x\";}";
-    assert_int_equal(LY_SUCCESS, parse_sub_module(&ctx, &str, mod));
-    assert_string_equal("x", mod->prefix);
-    mod = mod_renew(&ctx, mod, 0);
+    assert_int_equal(LY_SUCCESS, parse_module(&ctx, &str, mod));
+    assert_string_equal("x", mod->mod->prefix);
+    mod = mod_renew(&ctx);
 
 #define SCHEMA_BEGINNING " name {yang-version 1.1;namespace urn:x;prefix \"x\";"
 #define SCHEMA_BEGINNING2 " name {namespace urn:x;prefix \"x\";"
 #define TEST_NODE(NODETYPE, INPUT, NAME) \
         str = SCHEMA_BEGINNING INPUT; \
-        assert_int_equal(LY_SUCCESS, parse_sub_module(&ctx, &str, mod)); \
+        assert_int_equal(LY_SUCCESS, parse_module(&ctx, &str, mod)); \
         assert_non_null(mod->data); \
         assert_int_equal(NODETYPE, mod->data->nodetype); \
         assert_string_equal(NAME, mod->data->name); \
-        mod = mod_renew(&ctx, mod, 0);
+        mod = mod_renew(&ctx);
 #define TEST_GENERIC(INPUT, TARGET, TEST) \
         str = SCHEMA_BEGINNING INPUT; \
-        assert_int_equal(LY_SUCCESS, parse_sub_module(&ctx, &str, mod)); \
+        assert_int_equal(LY_SUCCESS, parse_module(&ctx, &str, mod)); \
         assert_non_null(TARGET); \
         TEST; \
-        mod = mod_renew(&ctx, mod, 0);
-#define TEST_DUP(MEMBER, VALUE1, VALUE2, LINE, SUBMODULE) \
+        mod = mod_renew(&ctx);
+#define TEST_DUP(MEMBER, VALUE1, VALUE2, LINE) \
         TEST_DUP_GENERIC(SCHEMA_BEGINNING, MEMBER, VALUE1, VALUE2, \
-                         parse_sub_module, mod, LINE, mod = mod_renew(&ctx, mod, SUBMODULE))
+                         parse_module, mod, LINE, mod = mod_renew(&ctx))
 
     /* duplicated namespace, prefix */
-    TEST_DUP("namespace", "y", "z", "1", 0);
-    TEST_DUP("prefix", "y", "z", "1", 0);
-    TEST_DUP("contact", "a", "b", "1", 0);
-    TEST_DUP("description", "a", "b", "1", 0);
-    TEST_DUP("organization", "a", "b", "1", 0);
-    TEST_DUP("reference", "a", "b", "1", 0);
+    TEST_DUP("namespace", "y", "z", "1");
+    TEST_DUP("prefix", "y", "z", "1");
+    TEST_DUP("contact", "a", "b", "1");
+    TEST_DUP("description", "a", "b", "1");
+    TEST_DUP("organization", "a", "b", "1");
+    TEST_DUP("reference", "a", "b", "1");
 
     /* not allowed in module (submodule-specific) */
     str = SCHEMA_BEGINNING "belongs-to master {prefix m;}}";
-    assert_int_equal(LY_EVALID, parse_sub_module(&ctx, &str, mod));
+    assert_int_equal(LY_EVALID, parse_module(&ctx, &str, mod));
     logbuf_assert("Invalid keyword \"belongs-to\" as a child of \"module\". Line number 1.");
-    mod = mod_renew(&ctx, mod, 0);
+    mod = mod_renew(&ctx);
 
     /* anydata */
     TEST_NODE(LYS_ANYDATA, "anydata test;}", "test");
@@ -865,13 +888,13 @@
     /* choice */
     TEST_NODE(LYS_CHOICE, "choice test;}", "test");
     /* contact 0..1 */
-    TEST_GENERIC("contact \"firstname\" + \n\t\" surname\";}", mod->contact,
-                 assert_string_equal("firstname surname", mod->contact));
+    TEST_GENERIC("contact \"firstname\" + \n\t\" surname\";}", mod->mod->contact,
+                 assert_string_equal("firstname surname", mod->mod->contact));
     /* container */
     TEST_NODE(LYS_CONTAINER, "container test;}", "test");
     /* description 0..1 */
-    TEST_GENERIC("description \'some description\';}", mod->dsc,
-                 assert_string_equal("some description", mod->dsc));
+    TEST_GENERIC("description \'some description\';}", mod->mod->dsc,
+                 assert_string_equal("some description", mod->mod->dsc));
     /* deviation */
     TEST_GENERIC("deviation /somepath {deviate not-supported;}}", mod->deviations,
                  assert_string_equal("/somepath", mod->deviations[0].nodeid));
@@ -894,13 +917,13 @@
 
     /* import - prefix collision */
     str = SCHEMA_BEGINNING "import zzz {prefix x;}}";
-    assert_int_equal(LY_EVALID, parse_sub_module(&ctx, &str, mod));
+    assert_int_equal(LY_EVALID, parse_module(&ctx, &str, mod));
     logbuf_assert("Prefix \"x\" already used as module prefix. Line number 2.");
-    mod = mod_renew(&ctx, mod, 0);
+    mod = mod_renew(&ctx);
     str = SCHEMA_BEGINNING "import zzz {prefix y;}import zzz {prefix y;}}";
-    assert_int_equal(LY_EVALID, parse_sub_module(&ctx, &str, mod));
+    assert_int_equal(LY_EVALID, parse_module(&ctx, &str, mod));
     logbuf_assert("Prefix \"y\" already used to import \"zzz\" module. Line number 2.");
-    mod = mod_renew(&ctx, mod, 0);
+    mod = mod_renew(&ctx);
     str = "module" SCHEMA_BEGINNING "import zzz {prefix y;}import zzz {prefix z;}}";
     assert_null(lys_parse_mem(ctx.ctx, str, LYS_IN_YANG));
     assert_int_equal(LY_EVALID, ly_errcode(ctx.ctx));
@@ -912,7 +935,7 @@
     str = "module" SCHEMA_BEGINNING "include xxx;}";
     assert_null(lys_parse_mem(ctx.ctx, str, LYS_IN_YANG));
     assert_int_equal(LY_EVALID, ly_errcode(ctx.ctx));
-    logbuf_assert("Included \"xxx\" schema from \"name\" is actually not a submodule.");
+    logbuf_assert("Input data contains module in situation when a submodule is expected.");
     store = -1;
 
     store = 1;
@@ -937,11 +960,11 @@
     TEST_GENERIC("notification test;}", mod->notifs,
                  assert_string_equal("test", mod->notifs[0].name));
     /* organization 0..1 */
-    TEST_GENERIC("organization \"CESNET a.l.e.\";}", mod->org,
-                 assert_string_equal("CESNET a.l.e.", mod->org));
+    TEST_GENERIC("organization \"CESNET a.l.e.\";}", mod->mod->org,
+                 assert_string_equal("CESNET a.l.e.", mod->mod->org));
     /* reference 0..1 */
-    TEST_GENERIC("reference RFC7950;}", mod->ref,
-                 assert_string_equal("RFC7950", mod->ref));
+    TEST_GENERIC("reference RFC7950;}", mod->mod->ref,
+                 assert_string_equal("RFC7950", mod->mod->ref));
     /* revision */
     TEST_GENERIC("revision 2018-10-12;}", mod->revs,
                  assert_string_equal("2018-10-12", mod->revs[0].date));
@@ -955,66 +978,96 @@
     TEST_NODE(LYS_USES, "uses test;}", "test");
     /* yang-version */
     str = SCHEMA_BEGINNING2 "\n\tyang-version 10;}";
-    assert_int_equal(LY_EVALID, parse_sub_module(&ctx, &str, mod));
+    assert_int_equal(LY_EVALID, parse_module(&ctx, &str, mod));
     logbuf_assert("Invalid value \"10\" of \"yang-version\". Line number 3.");
-    mod = mod_renew(&ctx, mod, 0);
+    mod = mod_renew(&ctx);
     str = SCHEMA_BEGINNING2 "yang-version 1.0;yang-version 1.1;}";
-    assert_int_equal(LY_EVALID, parse_sub_module(&ctx, &str, mod));
+    assert_int_equal(LY_EVALID, parse_module(&ctx, &str, mod));
     logbuf_assert("Duplicate keyword \"yang-version\". Line number 3.");
-    mod = mod_renew(&ctx, mod, 0);
+    mod = mod_renew(&ctx);
     str = SCHEMA_BEGINNING2 "yang-version 1.0;}";
-    assert_int_equal(LY_SUCCESS, parse_sub_module(&ctx, &str, mod));
-    assert_int_equal(1, mod->version);
-    mod = mod_renew(&ctx, mod, 0);
+    assert_int_equal(LY_SUCCESS, parse_module(&ctx, &str, mod));
+    assert_int_equal(1, mod->mod->version);
+    mod = mod_renew(&ctx);
     str = SCHEMA_BEGINNING2 "yang-version \"1.1\";}";
-    assert_int_equal(LY_SUCCESS, parse_sub_module(&ctx, &str, mod));
-    assert_int_equal(2, mod->version);
-    mod = mod_renew(&ctx, mod, 0);
+    assert_int_equal(LY_SUCCESS, parse_module(&ctx, &str, mod));
+    assert_int_equal(2, mod->mod->version);
+    mod = mod_renew(&ctx);
+
+    str = "module " SCHEMA_BEGINNING "} module q {namespace urn:q;prefixq;}";
+    m = mod->mod;
+    free(mod);
+    m->parsed = NULL;
+    assert_int_equal(LY_EVALID, yang_parse_module(&ctx, str, m));
+    logbuf_assert("Invalid character sequence \"module\", expected end-of-file. Line number 3.");
+    mod = mod_renew(&ctx);
+
+    str = "prefix " SCHEMA_BEGINNING "}";
+    m = mod->mod;
+    free(mod);
+    m->parsed = NULL;
+    assert_int_equal(LY_EVALID, yang_parse_module(&ctx, str, m));
+    logbuf_assert("Invalid keyword \"prefix\", expected \"module\" or \"submodule\". Line number 3.");
+    mod = mod_renew(&ctx);
 
     /* extensions */
     TEST_GENERIC("prefix:test;}", mod->exts,
                  assert_string_equal("prefix:test", mod->exts[0].name);
                  assert_int_equal(LYEXT_SUBSTMT_SELF, mod->exts[0].insubstmt));
-    mod = mod_renew(&ctx, mod, 0);
+    mod = mod_renew(&ctx);
 
     /* invalid substatement */
     str = SCHEMA_BEGINNING "must false;}";
-    assert_int_equal(LY_EVALID, parse_sub_module(&ctx, &str, mod));
+    assert_int_equal(LY_EVALID, parse_module(&ctx, &str, mod));
     logbuf_assert("Invalid keyword \"must\" as a child of \"module\". Line number 3.");
-    mod = mod_renew(&ctx, mod, 0);
+    mod = mod_renew(&ctx);
 
     /* submodule */
-    mod->submodule = 1;
+    submod = submod_renew(&ctx, submod);
 
     /* missing mandatory substatements */
     str = " subname {}";
-    lydict_remove(ctx.ctx, mod->name);
-    assert_int_equal(LY_EVALID, parse_sub_module(&ctx, &str, mod));
-    assert_string_equal("subname", mod->name);
+    lydict_remove(ctx.ctx, submod->name);
+    assert_int_equal(LY_EVALID, parse_submodule(&ctx, &str, submod));
+    assert_string_equal("subname", submod->name);
     logbuf_assert("Missing mandatory keyword \"belongs-to\" as a child of \"submodule\". Line number 3.");
-    mod = mod_renew(&ctx, mod, 1);
+    submod = submod_renew(&ctx, submod);
 
     str = " subname {belongs-to name {prefix x;}}";
-    lydict_remove(ctx.ctx, mod->name);
-    assert_int_equal(LY_SUCCESS, parse_sub_module(&ctx, &str, mod));
-    assert_string_equal("name", mod->belongsto);
-    mod = mod_renew(&ctx, mod, 1);
+    lydict_remove(ctx.ctx, submod->name);
+    assert_int_equal(LY_SUCCESS, parse_submodule(&ctx, &str, submod));
+    assert_string_equal("name", submod->belongsto);
+    submod = submod_renew(&ctx, submod);
 
 #undef SCHEMA_BEGINNING
 #define SCHEMA_BEGINNING " subname {belongs-to name {prefix x;}"
 
     /* duplicated namespace, prefix */
-    TEST_DUP("belongs-to", "module1", "module2", "3", 1);
+    str = " subname {belongs-to name {prefix x;}belongs-to module1;belongs-to module2;} ...";
+    assert_int_equal(LY_EVALID, parse_submodule(&ctx, &str, submod)); \
+    logbuf_assert("Duplicate keyword \"belongs-to\". Line number 3."); \
+    submod = submod_renew(&ctx, submod);
 
     /* not allowed in submodule (module-specific) */
     str = SCHEMA_BEGINNING "namespace \"urn:z\";}";
-    assert_int_equal(LY_EVALID, parse_sub_module(&ctx, &str, mod));
+    assert_int_equal(LY_EVALID, parse_submodule(&ctx, &str, submod));
     logbuf_assert("Invalid keyword \"namespace\" as a child of \"submodule\". Line number 3.");
-    mod = mod_renew(&ctx, mod, 1);
+    submod = submod_renew(&ctx, submod);
     str = SCHEMA_BEGINNING "prefix m;}}";
-    assert_int_equal(LY_EVALID, parse_sub_module(&ctx, &str, mod));
+    assert_int_equal(LY_EVALID, parse_submodule(&ctx, &str, submod));
     logbuf_assert("Invalid keyword \"prefix\" as a child of \"submodule\". Line number 3.");
-    mod = mod_renew(&ctx, mod, 1);
+    submod = submod_renew(&ctx, submod);
+
+    str = "submodule " SCHEMA_BEGINNING "} module q {namespace urn:q;prefixq;}";
+    lysp_submodule_free(ctx.ctx, submod);
+    submod = NULL;
+    assert_int_equal(LY_EVALID, yang_parse_submodule(&ctx, str, &submod));
+    logbuf_assert("Invalid character sequence \"module\", expected end-of-file. Line number 3.");
+
+    str = "prefix " SCHEMA_BEGINNING "}";
+    assert_int_equal(LY_EVALID, yang_parse_submodule(&ctx, str, &submod));
+    logbuf_assert("Invalid keyword \"prefix\", expected \"module\" or \"submodule\". Line number 3.");
+    submod = submod_renew(&ctx, submod);
 
 #undef TEST_GENERIC
 #undef TEST_NODE
@@ -1022,16 +1075,18 @@
 #undef SCHEMA_BEGINNING
 
     lysp_module_free(mod);
+    lysp_submodule_free(ctx.ctx, submod);
     ly_ctx_destroy(ctx.ctx, NULL);
+
+    *state = NULL;
 }
 
 static void
 test_identity(void **state)
 {
-    (void) state; /* unused */
+    *state = test_identity;
 
     struct ly_parser_ctx ctx;
-    struct lysp_module m = {0};
     struct lysp_ident *ident = NULL;
     const char *str;
 
@@ -1039,15 +1094,19 @@
     assert_non_null(ctx.ctx);
     ctx.line = 1;
     ctx.indent = 0;
-    ctx.mod = &m;
-    ctx.mod->version = 2; /* simulate YANG 1.1 */
+    ctx.mod_version = 2; /* simulate YANG 1.1 */
 
     /* invalid cardinality */
 #define TEST_DUP(MEMBER, VALUE1, VALUE2) \
     TEST_DUP_GENERIC(" test {", MEMBER, VALUE1, VALUE2, parse_identity, \
                      &ident, "1", FREE_ARRAY(ctx.ctx, ident, lysp_ident_free); ident = NULL)
 
-    TEST_DUP("description", "a", "b");
+    //TEST_DUP("description", "a", "b");
+    str = " test {description a;description b;} ...";
+    assert_int_equal(LY_EVALID, parse_identity(&ctx, &str, &ident));
+    logbuf_assert("Duplicate keyword \"description\". Line number 1.");
+    FREE_ARRAY(ctx.ctx, ident, lysp_ident_free); ident = NULL;
+
     TEST_DUP("reference", "a", "b");
     TEST_DUP("status", "current", "obsolete");
 
@@ -1068,6 +1127,7 @@
 
 #undef TEST_DUP
 
+    *state = NULL;
     ly_ctx_destroy(ctx.ctx, NULL);
 }
 
@@ -1253,7 +1313,6 @@
 {
     (void) state; /* unused */
 
-    struct lysp_module mod = {0};
     struct ly_parser_ctx ctx = {0};
     struct lysp_node_container *c = NULL;
     const char *str;
@@ -1261,8 +1320,7 @@
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
     assert_non_null(ctx.ctx);
     ctx.line = 1;
-    ctx.mod = &mod;
-    ctx.mod->version = 2; /* simulate YANG 1.1 */
+    ctx.mod_version = 2; /* simulate YANG 1.1 */
 
     /* invalid cardinality */
 #define TEST_DUP(MEMBER, VALUE1, VALUE2) \
@@ -1322,7 +1380,6 @@
 {
     *state = test_leaf;
 
-    struct lysp_module mod = {0};
     struct ly_parser_ctx ctx = {0};
     struct lysp_node_leaf *l = NULL;
     const char *str;
@@ -1330,7 +1387,6 @@
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
     assert_non_null(ctx.ctx);
     ctx.line = 1;
-    ctx.mod = &mod;
     //ctx.mod->version = 2; /* simulate YANG 1.1 */
 
     /* invalid cardinality */
@@ -1402,7 +1458,6 @@
 {
     *state = test_leaf;
 
-    struct lysp_module mod = {0};
     struct ly_parser_ctx ctx = {0};
     struct lysp_node_leaflist *ll = NULL;
     const char *str;
@@ -1410,8 +1465,7 @@
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
     assert_non_null(ctx.ctx);
     ctx.line = 1;
-    ctx.mod = &mod;
-    ctx.mod->version = 2; /* simulate YANG 1.1 */
+    ctx.mod_version = 2; /* simulate YANG 1.1 */
 
     /* invalid cardinality */
 #define TEST_DUP(MEMBER, VALUE1, VALUE2) \
@@ -1487,7 +1541,7 @@
     logbuf_assert("Invalid combination of min-elements and max-elements: min value 10 is bigger than the max value 1. Line number 1.");
     lysp_node_free(ctx.ctx, (struct lysp_node*)ll); ll = NULL;
 
-    ctx.mod->version = 1; /* simulate YANG 1.0 - default statement is not allowed */
+    ctx.mod_version = 1; /* simulate YANG 1.0 - default statement is not allowed */
     str = " ll {default xx; type string;} ...";
     assert_int_equal(LY_EVALID, parse_leaflist(&ctx, &str, NULL, (struct lysp_node**)&ll));
     logbuf_assert("Invalid keyword \"default\" as a child of \"leaf-list\" - the statement is allowed only in YANG 1.1 modules. Line number 1.");
@@ -1502,7 +1556,6 @@
 {
     *state = test_list;
 
-    struct lysp_module mod = {0};
     struct ly_parser_ctx ctx = {0};
     struct lysp_node_list *l = NULL;
     const char *str;
@@ -1510,8 +1563,7 @@
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
     assert_non_null(ctx.ctx);
     ctx.line = 1;
-    ctx.mod = &mod;
-    ctx.mod->version = 2; /* simulate YANG 1.1 */
+    ctx.mod_version = 2; /* simulate YANG 1.1 */
 
     /* invalid cardinality */
 #define TEST_DUP(MEMBER, VALUE1, VALUE2) \
@@ -1567,7 +1619,6 @@
 {
     *state = test_choice;
 
-    struct lysp_module mod = {0};
     struct ly_parser_ctx ctx = {0};
     struct lysp_node_choice *ch = NULL;
     const char *str;
@@ -1575,8 +1626,7 @@
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
     assert_non_null(ctx.ctx);
     ctx.line = 1;
-    ctx.mod = &mod;
-    ctx.mod->version = 2; /* simulate YANG 1.1 */
+    ctx.mod_version = 2; /* simulate YANG 1.1 */
 
     /* invalid cardinality */
 #define TEST_DUP(MEMBER, VALUE1, VALUE2) \
@@ -1636,7 +1686,6 @@
 {
     *state = test_case;
 
-    struct lysp_module mod = {0};
     struct ly_parser_ctx ctx = {0};
     struct lysp_node_case *cs = NULL;
     const char *str;
@@ -1644,8 +1693,7 @@
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
     assert_non_null(ctx.ctx);
     ctx.line = 1;
-    ctx.mod = &mod;
-    ctx.mod->version = 2; /* simulate YANG 1.1 */
+    ctx.mod_version = 2; /* simulate YANG 1.1 */
 
     /* invalid cardinality */
 #define TEST_DUP(MEMBER, VALUE1, VALUE2) \
@@ -1692,7 +1740,6 @@
 {
     *state = test_any;
 
-    struct lysp_module mod = {0};
     struct ly_parser_ctx ctx = {0};
     struct lysp_node_anydata *any = NULL;
     const char *str;
@@ -1700,11 +1747,10 @@
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
     assert_non_null(ctx.ctx);
     ctx.line = 1;
-    ctx.mod = &mod;
     if (kw == YANG_ANYDATA) {
-        ctx.mod->version = 2; /* simulate YANG 1.1 */
+        ctx.mod_version = 2; /* simulate YANG 1.1 */
     } else {
-        ctx.mod->version = 1; /* simulate YANG 1.0 */
+        ctx.mod_version = 1; /* simulate YANG 1.0 */
     }
 
     /* invalid cardinality */
@@ -1760,7 +1806,6 @@
 {
     *state = test_grouping;
 
-    struct lysp_module mod = {0};
     struct ly_parser_ctx ctx = {0};
     struct lysp_grp *grp = NULL;
     const char *str;
@@ -1768,8 +1813,7 @@
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
     assert_non_null(ctx.ctx);
     ctx.line = 1;
-    ctx.mod = &mod;
-    ctx.mod->version = 2; /* simulate YANG 1.1 */
+    ctx.mod_version = 2; /* simulate YANG 1.1 */
 
     /* invalid cardinality */
 #define TEST_DUP(MEMBER, VALUE1, VALUE2) \
@@ -1818,7 +1862,6 @@
 {
     *state = test_uses;
 
-    struct lysp_module mod = {0};
     struct ly_parser_ctx ctx = {0};
     struct lysp_node_uses *u = NULL;
     const char *str;
@@ -1826,8 +1869,7 @@
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
     assert_non_null(ctx.ctx);
     ctx.line = 1;
-    ctx.mod = &mod;
-    ctx.mod->version = 2; /* simulate YANG 1.1 */
+    ctx.mod_version = 2; /* simulate YANG 1.1 */
 
     /* invalid cardinality */
 #define TEST_DUP(MEMBER, VALUE1, VALUE2) \
@@ -1871,8 +1913,8 @@
         cmocka_unit_test_setup(test_arg, logger_setup),
         cmocka_unit_test_setup(test_stmts, logger_setup),
         cmocka_unit_test_setup_teardown(test_minmax, logger_setup, logger_teardown),
-        cmocka_unit_test_setup(test_module, logger_setup),
-        cmocka_unit_test_setup(test_identity, logger_setup),
+        cmocka_unit_test_setup_teardown(test_module, logger_setup, logger_teardown),
+        cmocka_unit_test_setup_teardown(test_identity, logger_setup, logger_teardown),
         cmocka_unit_test_setup(test_feature, logger_setup),
         cmocka_unit_test_setup(test_deviation, logger_setup),
         cmocka_unit_test_setup(test_deviate, logger_setup),
diff --git a/tests/src/test_tree_schema_compile.c b/tests/src/test_tree_schema_compile.c
index ea088ed..1288ee3 100644
--- a/tests/src/test_tree_schema_compile.c
+++ b/tests/src/test_tree_schema_compile.c
@@ -99,9 +99,29 @@
 }
 
 static void
+reset_mod(struct ly_ctx *ctx, struct lys_module *module)
+{
+    lysc_module_free(module->compiled, NULL);
+    lysp_module_free(module->parsed);
+
+    FREE_STRING(module->ctx, module->name);
+    FREE_STRING(module->ctx, module->ns);
+    FREE_STRING(module->ctx, module->prefix);
+    FREE_STRING(module->ctx, module->filepath);
+    FREE_STRING(module->ctx, module->org);
+    FREE_STRING(module->ctx, module->contact);
+    FREE_STRING(module->ctx, module->dsc);
+    FREE_STRING(module->ctx, module->ref);
+
+    memset(module, 0, sizeof *module);
+    module->ctx = ctx;
+    module->implemented = 1;
+}
+
+static void
 test_module(void **state)
 {
-    (void) state; /* unused */
+    *state = test_module;
 
     const char *str;
     struct ly_parser_ctx ctx = {0};
@@ -112,16 +132,22 @@
     str = "module test {namespace urn:test; prefix t;"
           "feature f1;feature f2 {if-feature f1;}}";
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
+    reset_mod(ctx.ctx, &mod);
 
     assert_int_equal(LY_EINVAL, lys_compile(NULL, 0));
     logbuf_assert("Invalid argument mod (lys_compile()).");
     assert_int_equal(LY_EINVAL, lys_compile(&mod, 0));
     logbuf_assert("Invalid argument mod->parsed (lys_compile()).");
-    assert_int_equal(LY_SUCCESS, yang_parse(&ctx, str, &mod.parsed));
+    assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, str, &mod));
+    mod.implemented = 0;
+    assert_int_equal(LY_SUCCESS, lys_compile(&mod, 0));
+    assert_null(mod.compiled);
+    mod.implemented = 1;
     assert_int_equal(LY_SUCCESS, lys_compile(&mod, 0));
     assert_non_null(mod.compiled);
-    assert_ptr_equal(mod.parsed->name, mod.compiled->name);
-    assert_ptr_equal(mod.parsed->ns, mod.compiled->ns);
+    assert_string_equal("test", mod.name);
+    assert_string_equal("urn:test", mod.ns);
+    assert_string_equal("t", mod.prefix);
     /* features */
     assert_non_null(mod.compiled->features);
     assert_int_equal(2, LY_ARRAY_SIZE(mod.compiled->features));
@@ -138,28 +164,26 @@
 
     assert_int_equal(LY_SUCCESS, lys_compile(&mod, LYSC_OPT_FREE_SP));
     assert_non_null(mod.compiled);
-    assert_string_equal("test", mod.compiled->name);
-    assert_string_equal("urn:test", mod.compiled->ns);
 
     lysc_module_free(mod.compiled, NULL);
     mod.compiled = NULL;
 
     /* submodules cannot be compiled directly */
     str = "submodule test {belongs-to xxx {prefix x;}}";
-    assert_int_equal(LY_SUCCESS, yang_parse(&ctx, str, &mod.parsed));
-    assert_int_equal(LY_EINVAL, lys_compile(&mod, 0));
-    logbuf_assert("Submodules (test) are not supposed to be compiled, compile only the main modules.");
-    assert_null(mod.compiled);
-    lysp_module_free(mod.parsed);
+    assert_int_equal(LY_EINVAL, yang_parse_module(&ctx, str, &mod));
+    logbuf_assert("Input data contains submodule which cannot be parsed directly without its main module.");
+    assert_null(mod.parsed);
+    reset_mod(ctx.ctx, &mod);
 
     /* data definition name collision in top level */
-    assert_int_equal(LY_SUCCESS, yang_parse(&ctx, "module aa {namespace urn:aa;prefix aa;"
-                                                  "leaf a {type string;} container a{presence x;}}", &mod.parsed));
+    assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module aa {namespace urn:aa;prefix aa;"
+                                                  "leaf a {type string;} container a{presence x;}}", &mod));
     assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
     logbuf_assert("Duplicate identifier \"a\" of data definition statement.");
     assert_null(mod.compiled);
-    lysp_module_free(mod.parsed);
+    reset_mod(ctx.ctx, &mod);
 
+    *state = NULL;
     ly_ctx_destroy(ctx.ctx, NULL);
 }
 
@@ -183,7 +207,9 @@
           "feature f9 {if-feature \"not not f1\";}}";
 
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
-    assert_int_equal(LY_SUCCESS, yang_parse(&ctx, str, &mod.parsed));
+    reset_mod(ctx.ctx, &mod);
+
+    assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, str, &mod));
     assert_int_equal(LY_SUCCESS, lys_compile(&mod, 0));
     assert_non_null(mod.compiled);
     assert_non_null(mod.compiled->features);
@@ -260,65 +286,77 @@
     assert_int_equal(1, lys_feature_value(&mod, "f1"));
     assert_int_equal(0, lys_feature_value(&mod, "f2"));
 
+    assert_non_null(modp = lys_parse_mem(ctx.ctx, "module b {namespace urn:b;prefix b;"
+                                         "feature f1 {if-feature f2;}feature f2;}", LYS_IN_YANG));
+    assert_non_null(modp->compiled);
+    assert_non_null(modp->compiled->features);
+    assert_int_equal(2, LY_ARRAY_SIZE(modp->compiled->features));
+    assert_non_null(modp->compiled->features[0].iffeatures);
+    assert_int_equal(1, LY_ARRAY_SIZE(modp->compiled->features[0].iffeatures));
+    assert_non_null(modp->compiled->features[0].iffeatures[0].features);
+    assert_int_equal(1, LY_ARRAY_SIZE(modp->compiled->features[0].iffeatures[0].features));
+    assert_ptr_equal(&modp->compiled->features[1], modp->compiled->features[0].iffeatures[0].features[0]);
+    assert_non_null(modp->compiled->features);
+    assert_int_equal(2, LY_ARRAY_SIZE(modp->compiled->features));
+    assert_non_null(modp->compiled->features[1].depfeatures);
+    assert_int_equal(1, LY_ARRAY_SIZE(modp->compiled->features[1].depfeatures));
+    assert_ptr_equal(&modp->compiled->features[0], modp->compiled->features[1].depfeatures[0]);
+
     /* invalid reference */
     assert_int_equal(LY_EINVAL, lys_feature_enable(&mod, "xxx"));
     logbuf_assert("Feature \"xxx\" not found in module \"a\".");
 
-    lysc_module_free(mod.compiled, NULL);
-    lysp_module_free(mod.parsed);
+    reset_mod(ctx.ctx, &mod);
 
     /* some invalid expressions */
-    assert_int_equal(LY_SUCCESS, yang_parse(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f{if-feature f1;}}", &mod.parsed));
+    assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f{if-feature f1;}}", &mod));
     assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
     logbuf_assert("Invalid value \"f1\" of if-feature - unable to find feature \"f1\".");
-    lysp_module_free(mod.parsed);
+    reset_mod(ctx.ctx, &mod);
 
-    assert_int_equal(LY_SUCCESS, yang_parse(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature 'f and';}}", &mod.parsed));
+    assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature 'f and';}}", &mod));
     assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
     logbuf_assert("Invalid value \"f and\" of if-feature - unexpected end of expression.");
-    lysp_module_free(mod.parsed);
+    reset_mod(ctx.ctx, &mod);
 
-    assert_int_equal(LY_SUCCESS, yang_parse(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f{if-feature 'or';}}", &mod.parsed));
+    assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f{if-feature 'or';}}", &mod));
     assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
     logbuf_assert("Invalid value \"or\" of if-feature - unexpected end of expression.");
-    lysp_module_free(mod.parsed);
+    reset_mod(ctx.ctx, &mod);
 
-    assert_int_equal(LY_SUCCESS, yang_parse(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature '(f1';}}", &mod.parsed));
+    assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature '(f1';}}", &mod));
     assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
     logbuf_assert("Invalid value \"(f1\" of if-feature - non-matching opening and closing parentheses.");
-    lysp_module_free(mod.parsed);
+    reset_mod(ctx.ctx, &mod);
 
-    assert_int_equal(LY_SUCCESS, yang_parse(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature 'f1)';}}", &mod.parsed));
+    assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature 'f1)';}}", &mod));
     assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
     logbuf_assert("Invalid value \"f1)\" of if-feature - non-matching opening and closing parentheses.");
-    lysp_module_free(mod.parsed);
+    reset_mod(ctx.ctx, &mod);
 
-    assert_int_equal(LY_SUCCESS, yang_parse(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature ---;}}", &mod.parsed));
+    assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature ---;}}", &mod));
     assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
     logbuf_assert("Invalid value \"---\" of if-feature - unable to find feature \"---\".");
-    lysp_module_free(mod.parsed);
+    reset_mod(ctx.ctx, &mod);
 
-    assert_int_equal(LY_SUCCESS, yang_parse(&ctx, "module b{namespace urn:b; prefix b; feature f1; feature f2{if-feature 'not f1';}}", &mod.parsed));
+    assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{namespace urn:b; prefix b; feature f1; feature f2{if-feature 'not f1';}}", &mod));
     assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
     logbuf_assert("Invalid value \"not f1\" of if-feature - YANG 1.1 expression in YANG 1.0 module.");
-    lysp_module_free(mod.parsed);
+    reset_mod(ctx.ctx, &mod);
 
-    assert_int_equal(LY_SUCCESS, yang_parse(&ctx, "module b{namespace urn:b; prefix b; feature f1; feature f1;}", &mod.parsed));
+    assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{namespace urn:b; prefix b; feature f1; feature f1;}", &mod));
     assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
     logbuf_assert("Duplicate identifier \"f1\" of feature statement.");
-    lysp_module_free(mod.parsed);
+    reset_mod(ctx.ctx, &mod);
 
-    ly_ctx_set_module_imp_clb(ctx.ctx, test_imp_clb, "submodule sb {belongs-to b {prefix b;} feature f1;}");
-    assert_non_null(modp = lys_parse_mem(ctx.ctx, "module b{namespace urn:b; prefix b; include sb;feature f1;}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(modp, 0));
+    ly_ctx_set_module_imp_clb(ctx.ctx, test_imp_clb, "submodule sz {belongs-to z {prefix z;} feature f1;}");
+    assert_null(lys_parse_mem(ctx.ctx, "module z{namespace urn:z; prefix z; include sz;feature f1;}", LYS_IN_YANG));
     logbuf_assert("Duplicate identifier \"f1\" of feature statement.");
 
     /* import reference */
     assert_non_null(modp = lys_parse_mem(ctx.ctx, str, LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(modp, 0));
     assert_int_equal(LY_SUCCESS, lys_feature_enable(modp, "f1"));
     assert_non_null(modp = lys_parse_mem(ctx.ctx, "module c{namespace urn:c; prefix c; import a {prefix a;} feature f1; feature f2{if-feature 'a:f1';}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(modp, 0));
     assert_int_equal(LY_SUCCESS, lys_feature_enable(modp, "f2"));
     assert_int_equal(0, lys_feature_value(modp, "f1"));
     assert_int_equal(1, lys_feature_value(modp, "f2"));
@@ -340,8 +378,6 @@
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
     assert_non_null(mod1 = lys_parse_mem(ctx, mod1_str, LYS_IN_YANG));
     assert_non_null(mod2 = lys_parse_mem(ctx, mod2_str, LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod1, 0));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod2, 0));
 
     assert_non_null(mod1->compiled);
     assert_non_null(mod1->compiled->identities);
@@ -362,13 +398,11 @@
     assert_int_equal(1, LY_ARRAY_SIZE(mod2->compiled->identities[2].derived));
     assert_ptr_equal(mod2->compiled->identities[2].derived[0], &mod2->compiled->identities[3]);
 
-    assert_non_null(mod1 = lys_parse_mem(ctx, "module c{namespace urn:c; prefix c; identity i1;identity i1;}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod1, 0));
+    assert_null(lys_parse_mem(ctx, "module c{namespace urn:c; prefix c; identity i1;identity i1;}", LYS_IN_YANG));
     logbuf_assert("Duplicate identifier \"i1\" of identity statement.");
 
     ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "submodule sd {belongs-to d {prefix d;} identity i1;}");
-    assert_non_null(mod1 = lys_parse_mem(ctx, "module d{namespace urn:d; prefix d; include sd;identity i1;}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod1, 0));
+    assert_null(lys_parse_mem(ctx, "module d{namespace urn:d; prefix d; include sd;identity i1;}", LYS_IN_YANG));
     logbuf_assert("Duplicate identifier \"i1\" of identity statement.");
 
     *state = NULL;
@@ -386,7 +420,6 @@
 
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
     assert_non_null(mod = lys_parse_mem(ctx, "module a {namespace urn:a;prefix a;container c;}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     assert_non_null(mod->compiled);
     assert_non_null((cont = (struct lysc_node_container*)mod->compiled->data));
     assert_int_equal(LYS_CONTAINER, cont->nodetype);
@@ -395,7 +428,6 @@
     assert_true(cont->flags & LYS_STATUS_CURR);
 
     assert_non_null(mod = lys_parse_mem(ctx, "module b {namespace urn:b;prefix b;container c {config false; status deprecated; container child;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     logbuf_assert("Missing explicit \"deprecated\" status that was already specified in parent, inheriting.");
     assert_non_null(mod->compiled);
     assert_non_null((cont = (struct lysc_node_container*)mod->compiled->data));
@@ -428,7 +460,6 @@
                                         "leaf-list ll2 {type leafref {path ../target;}}"
                                         "leaf target {type int8;}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(1, type->refcount);
@@ -448,7 +479,6 @@
     assert_int_equal(LY_TYPE_INT8, ((struct lysc_type_leafref*)type)->realtype->basetype);
 
     assert_non_null(mod = lys_parse_mem(ctx, "module b {namespace urn:b;prefix b;leaf-list ll {type string;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     assert_non_null(mod->compiled);
     assert_non_null((ll = (struct lysc_node_leaflist*)mod->compiled->data));
     assert_int_equal(0, ll->min);
@@ -457,7 +487,6 @@
     assert_non_null(mod = lys_parse_mem(ctx, "module c {yang-version 1.1;namespace urn:c;prefix c;typedef mytype {type int8;default 10;}"
                                         "leaf-list ll1 {type mytype;default 1; default 1; config false;}"
                                         "leaf-list ll2 {type mytype; ordered-by user;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     assert_non_null(mod->compiled);
     assert_non_null((ll = (struct lysc_node_leaflist*)mod->compiled->data));
     assert_non_null(ll->dflts);
@@ -477,7 +506,6 @@
      * TODO test also, RPC output parameters and notification content */
     assert_non_null(mod = lys_parse_mem(ctx, "module d {yang-version 1.1;namespace urn:d;prefix d;"
                                         "leaf-list ll {config false; type string; ordered-by user;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     /* but warning is present: */
     logbuf_assert("The ordered-by statement is ignored in lists representing state data, RPC/action output parameters or notification content ().");
     assert_non_null(mod->compiled);
@@ -485,24 +513,20 @@
     assert_int_equal(LYS_CONFIG_R | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, ll->flags);
 
     /* invalid */
-    assert_non_null(mod = lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;leaf-list ll {type empty;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;leaf-list ll {type empty;}}", LYS_IN_YANG));
     logbuf_assert("Leaf-list of type \"empty\" is allowed only in YANG 1.1 modules.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module bb {yang-version 1.1;namespace urn:bb;prefix bb;leaf-list ll {type empty; default x;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module bb {yang-version 1.1;namespace urn:bb;prefix bb;leaf-list ll {type empty; default x;}}", LYS_IN_YANG));
     logbuf_assert("Leaf-list of type \"empty\" must not have a default value (x).");
 
     assert_non_null(mod = lys_parse_mem(ctx, "module cc {yang-version 1.1;namespace urn:cc;prefix cc;"
                                         "leaf-list ll {config false;type string; default one;default two;default one;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     assert_non_null(mod->compiled);
     assert_non_null((ll = (struct lysc_node_leaflist*)mod->compiled->data));
     assert_non_null(ll->dflts);
     assert_int_equal(3, LY_ARRAY_SIZE(ll->dflts));
-    assert_non_null(mod = lys_parse_mem(ctx, "module dd {yang-version 1.1;namespace urn:dd;prefix dd;"
-                                        "leaf-list ll {type string; default one;default two;default one;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module dd {yang-version 1.1;namespace urn:dd;prefix dd;"
+                              "leaf-list ll {type string; default one;default two;default one;}}", LYS_IN_YANG));
     logbuf_assert("Configuration leaf-list has multiple defaults of the same value \"one\".");
 
     *state = NULL;
@@ -523,7 +547,6 @@
     assert_non_null(mod = lys_parse_mem(ctx, "module a {namespace urn:a;prefix a;feature f;"
                                         "list l1 {key \"x y\"; ordered-by user; leaf x {type string; when 1;}leaf y{type string;if-feature f;}}"
                                         "list l2 {config false;leaf value {type string;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     list = (struct lysc_node_list*)mod->compiled->data;
     assert_non_null(list);
     assert_non_null(list->keys);
@@ -545,7 +568,6 @@
                                         "list l {key a; unique \"a c/b:b\"; unique \"c/e d\";"
                                         "leaf a {type string; default x;} leaf d {type string;config false;}"
                                         "container c {leaf b {type string;}leaf e{type string;config false;}}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     list = (struct lysc_node_list*)mod->compiled->data;
     assert_non_null(list);
     assert_string_equal("l", list->name);
@@ -569,7 +591,6 @@
 
     assert_non_null(mod = lys_parse_mem(ctx, "module c {yang-version 1.1;namespace urn:c;prefix c;"
                                         "list l {key a;leaf a {type empty;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     list = (struct lysc_node_list*)mod->compiled->data;
     assert_non_null(list);
     assert_string_equal("l", list->name);
@@ -580,68 +601,55 @@
     assert_int_equal(LY_TYPE_EMPTY, list->keys[0]->type->basetype);
 
     /* invalid */
-    assert_non_null(mod = lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;list l;}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;list l;}", LYS_IN_YANG));
     logbuf_assert("Missing key in list representing configuration data.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module bb {yang-version 1.1; namespace urn:bb;prefix bb;"
-                                        "list l {key x; leaf x {type string; when 1;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module bb {yang-version 1.1; namespace urn:bb;prefix bb;"
+                              "list l {key x; leaf x {type string; when 1;}}}", LYS_IN_YANG));
     logbuf_assert("List's key \"x\" must not have any \"when\" statement.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module cc {yang-version 1.1;namespace urn:cc;prefix cc;feature f;"
-                                        "list l {key x; leaf x {type string; if-feature f;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module cc {yang-version 1.1;namespace urn:cc;prefix cc;feature f;"
+                              "list l {key x; leaf x {type string; if-feature f;}}}", LYS_IN_YANG));
     logbuf_assert("List's key \"x\" must not have any \"if-feature\" statement.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module dd {namespace urn:dd;prefix dd;"
-                                        "list l {key x; leaf x {type string; config false;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module dd {namespace urn:dd;prefix dd;"
+                              "list l {key x; leaf x {type string; config false;}}}", LYS_IN_YANG));
     logbuf_assert("Key of the configuration list must not be status leaf.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module ee {namespace urn:ee;prefix ee;"
-                                        "list l {config false;key x; leaf x {type string; config true;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module ee {namespace urn:ee;prefix ee;"
+                              "list l {config false;key x; leaf x {type string; config true;}}}", LYS_IN_YANG));
     logbuf_assert("Configuration node cannot be child of any state data node.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff;"
-                                        "list l {key x; leaf-list x {type string;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff;"
+                              "list l {key x; leaf-list x {type string;}}}", LYS_IN_YANG));
     logbuf_assert("The list's key \"x\" not found.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module gg {namespace urn:gg;prefix gg;"
-                                        "list l {key x; unique y;leaf x {type string;} leaf-list y {type string;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module gg {namespace urn:gg;prefix gg;"
+                              "list l {key x; unique y;leaf x {type string;} leaf-list y {type string;}}}", LYS_IN_YANG));
     logbuf_assert("Unique's descendant-schema-nodeid \"y\" refers to a leaf-list node instead of a leaf.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module hh {namespace urn:hh;prefix hh;"
-                                        "list l {key x; unique \"x y\";leaf x {type string;} leaf y {config false; type string;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module hh {namespace urn:hh;prefix hh;"
+                              "list l {key x; unique \"x y\";leaf x {type string;} leaf y {config false; type string;}}}", LYS_IN_YANG));
     logbuf_assert("Unique statement \"x y\" refers to leafs with different config type.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module ii {namespace urn:ii;prefix ii;"
-                                        "list l {key x; unique a:x;leaf x {type string;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module ii {namespace urn:ii;prefix ii;"
+                              "list l {key x; unique a:x;leaf x {type string;}}}", LYS_IN_YANG));
     logbuf_assert("Invalid descendant-schema-nodeid value \"a:x\" - prefix \"a\" not defined in module \"ii\".");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module jj {namespace urn:jj;prefix jj;"
-                                        "list l {key x; unique c/x;leaf x {type string;}container c {leaf y {type string;}}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module jj {namespace urn:jj;prefix jj;"
+                              "list l {key x; unique c/x;leaf x {type string;}container c {leaf y {type string;}}}}", LYS_IN_YANG));
     logbuf_assert("Invalid descendant-schema-nodeid value \"c/x\" - target node not found.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module kk {namespace urn:kk;prefix kk;"
-                                        "list l {key x; unique c^y;leaf x {type string;}container c {leaf y {type string;}}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null( lys_parse_mem(ctx, "module kk {namespace urn:kk;prefix kk;"
+                               "list l {key x; unique c^y;leaf x {type string;}container c {leaf y {type string;}}}}", LYS_IN_YANG));
     logbuf_assert("Invalid descendant-schema-nodeid value \"c^\" - missing \"/\" as node-identifier separator.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module ll {namespace urn:ll;prefix ll;"
-                                        "list l {key \"x y x\";leaf x {type string;}leaf y {type string;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module ll {namespace urn:ll;prefix ll;"
+                              "list l {key \"x y x\";leaf x {type string;}leaf y {type string;}}}", LYS_IN_YANG));
     logbuf_assert("Duplicated key identifier \"x\".");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module mm {namespace urn:mm;prefix mm;"
-                                        "list l {key x;leaf x {type empty;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module mm {namespace urn:mm;prefix mm;"
+                              "list l {key x;leaf x {type empty;}}}", LYS_IN_YANG));
     logbuf_assert("Key of a list can be of type \"empty\" only in YANG 1.1 modules.");
 
     *state = NULL;
@@ -663,10 +671,9 @@
     assert_non_null(mod = lys_parse_mem(ctx, "module a {namespace urn:a;prefix a;feature f;"
                                         "choice ch {default a:b; case a {leaf a1 {type string;}leaf a2 {type string;}}"
                                         "leaf b {type string;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     ch = (struct lysc_node_choice*)mod->compiled->data;
     assert_non_null(ch);
-    assert_int_equal(LYS_CONFIG_W | LYS_STATUS_CURR | LYS_SET_DFLT, ch->flags);
+    assert_int_equal(LYS_CONFIG_W | LYS_STATUS_CURR, ch->flags);
     cs = ch->cases;
     assert_non_null(cs);
     assert_string_equal("a", cs->name);
@@ -679,6 +686,7 @@
     cs = (struct lysc_node_case*)cs->next;
     assert_non_null(cs);
     assert_string_equal("b", cs->name);
+    assert_int_equal(LYS_STATUS_CURR | LYS_SET_DFLT, cs->flags);
     assert_ptr_equal(ch, cs->parent);
     assert_non_null(cs->child);
     assert_string_equal("b", cs->child->name);
@@ -688,34 +696,27 @@
     assert_ptr_equal(ch->cases->child->prev, cs->child);
     assert_ptr_equal(ch->dflt, cs);
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;"
-                                        "choice ch {case a {leaf x {type string;}}leaf x {type string;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;"
+                              "choice ch {case a {leaf x {type string;}}leaf x {type string;}}}", LYS_IN_YANG));
     logbuf_assert("Duplicate identifier \"x\" of data definition statement.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module aa2 {namespace urn:aa2;prefix aa;"
-                                        "choice ch {case a {leaf y {type string;}}case b {leaf y {type string;}}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module aa2 {namespace urn:aa2;prefix aa;"
+                              "choice ch {case a {leaf y {type string;}}case b {leaf y {type string;}}}}", LYS_IN_YANG));
     logbuf_assert("Duplicate identifier \"y\" of data definition statement.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb;"
-                                        "choice ch {case a {leaf x {type string;}}leaf a {type string;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb;"
+                              "choice ch {case a {leaf x {type string;}}leaf a {type string;}}}", LYS_IN_YANG));
     logbuf_assert("Duplicate identifier \"a\" of case statement.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module bb2 {namespace urn:bb2;prefix bb;"
-                                        "choice ch {case b {leaf x {type string;}}case b {leaf y {type string;}}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module bb2 {namespace urn:bb2;prefix bb;"
+                              "choice ch {case b {leaf x {type string;}}case b {leaf y {type string;}}}}", LYS_IN_YANG));
     logbuf_assert("Duplicate identifier \"b\" of case statement.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module ca {namespace urn:ca;prefix ca;"
-                                        "choice ch {default c;case a {leaf x {type string;}}case b {leaf y {type string;}}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module ca {namespace urn:ca;prefix ca;"
+                              "choice ch {default c;case a {leaf x {type string;}}case b {leaf y {type string;}}}}", LYS_IN_YANG));
     logbuf_assert("Default case \"c\" not found.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module cb {namespace urn:cb;prefix cb; import a {prefix a;}"
-                                        "choice ch {default a:a;case a {leaf x {type string;}}case b {leaf y {type string;}}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module cb {namespace urn:cb;prefix cb; import a {prefix a;}"
+                              "choice ch {default a:a;case a {leaf x {type string;}}case b {leaf y {type string;}}}}", LYS_IN_YANG));
     logbuf_assert("Invalid default case referencing a case from different YANG module (by prefix \"a\").");
-    assert_non_null(mod = lys_parse_mem(ctx, "module cc {namespace urn:cc;prefix cc;"
-                                        "choice ch {default a;case a {leaf x {mandatory true;type string;}}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module cc {namespace urn:cc;prefix cc;"
+                              "choice ch {default a;case a {leaf x {mandatory true;type string;}}}}", LYS_IN_YANG));
     logbuf_assert("Mandatory node \"x\" under the default case \"a\".");
     /* TODO check with mandatory nodes from augment placed into the case */
 
@@ -736,7 +737,6 @@
 
     assert_non_null(mod = lys_parse_mem(ctx, "module a {yang-version 1.1;namespace urn:a;prefix a;"
                                         "anydata any {config false;mandatory true;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     any = (struct lysc_node_anydata*)mod->compiled->data;
     assert_non_null(any);
     assert_int_equal(LYS_ANYDATA, any->nodetype);
@@ -745,7 +745,6 @@
     logbuf_clean();
     assert_non_null(mod = lys_parse_mem(ctx, "module b {namespace urn:b;prefix b;"
                                         "anyxml any;}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     any = (struct lysc_node_anydata*)mod->compiled->data;
     assert_non_null(any);
     assert_int_equal(LYS_ANYXML, any->nodetype);
@@ -753,7 +752,7 @@
     logbuf_assert("Use of anyxml to define configuration data is not recommended."); /* warning */
 
     /* invalid */
-    assert_null(mod = lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;anydata any;}", LYS_IN_YANG));
+    assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;anydata any;}", LYS_IN_YANG));
     logbuf_assert("Invalid keyword \"anydata\" as a child of \"module\" - the statement is allowed only in YANG 1.1 modules. Line number 1.");
 
     *state = NULL;
@@ -776,7 +775,6 @@
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
 
     assert_non_null(mod = lys_parse_mem(ctx, "module a {namespace urn:a;prefix a;leaf l {type int8 {range min..10|max;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_INT8, type->basetype);
@@ -789,7 +787,6 @@
     assert_int_equal(127, ((struct lysc_type_num*)type)->range->parts[1].max_64);
 
     assert_non_null(mod = lys_parse_mem(ctx, "module b {namespace urn:b;prefix b;leaf l {type int16 {range min..10|max;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_INT16, type->basetype);
@@ -802,7 +799,6 @@
     assert_int_equal(32767, ((struct lysc_type_num*)type)->range->parts[1].max_64);
 
     assert_non_null(mod = lys_parse_mem(ctx, "module c {namespace urn:c;prefix c;leaf l {type int32 {range min..10|max;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_INT32, type->basetype);
@@ -815,7 +811,6 @@
     assert_int_equal(INT64_C(2147483647), ((struct lysc_type_num*)type)->range->parts[1].max_64);
 
     assert_non_null(mod = lys_parse_mem(ctx, "module d {namespace urn:d;prefix d;leaf l {type int64 {range min..10|max;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_INT64, type->basetype);
@@ -828,7 +823,6 @@
     assert_int_equal(INT64_C(9223372036854775807), ((struct lysc_type_num*)type)->range->parts[1].max_64);
 
     assert_non_null(mod = lys_parse_mem(ctx, "module e {namespace urn:e;prefix e;leaf l {type uint8 {range min..10|max;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_UINT8, type->basetype);
@@ -841,7 +835,6 @@
     assert_int_equal(255, ((struct lysc_type_num*)type)->range->parts[1].max_u64);
 
     assert_non_null(mod = lys_parse_mem(ctx, "module f {namespace urn:f;prefix f;leaf l {type uint16 {range min..10|max;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_UINT16, type->basetype);
@@ -854,7 +847,6 @@
     assert_int_equal(65535, ((struct lysc_type_num*)type)->range->parts[1].max_u64);
 
     assert_non_null(mod = lys_parse_mem(ctx, "module g {namespace urn:g;prefix g;leaf l {type uint32 {range min..10|max;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_UINT32, type->basetype);
@@ -867,7 +859,6 @@
     assert_int_equal(UINT64_C(4294967295), ((struct lysc_type_num*)type)->range->parts[1].max_u64);
 
     assert_non_null(mod = lys_parse_mem(ctx, "module h {namespace urn:h;prefix h;leaf l {type uint64 {range min..10|max;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_UINT64, type->basetype);
@@ -881,7 +872,6 @@
 
     assert_non_null(mod = lys_parse_mem(ctx, "module i {namespace urn:i;prefix i;typedef mytype {type uint8 {range 10..100;}}"
                                              "typedef mytype2 {type mytype;} leaf l {type mytype2;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(3, type->refcount);
@@ -890,6 +880,21 @@
     assert_non_null(((struct lysc_type_num*)type)->range->parts);
     assert_int_equal(1, LY_ARRAY_SIZE(((struct lysc_type_num*)type)->range->parts));
 
+    assert_non_null(mod = lys_parse_mem(ctx, "module j {namespace urn:j;prefix j;"
+                                             "typedef mytype {type uint8 {range 1..100{description \"one to hundred\";reference A;}}}"
+                                             "leaf l {type mytype {range 1..10 {description \"one to ten\";reference B;}}}}", LYS_IN_YANG));
+    type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
+    assert_non_null(type);
+    assert_int_equal(1, type->refcount);
+    assert_int_equal(LY_TYPE_UINT8, type->basetype);
+    assert_non_null(((struct lysc_type_num*)type)->range);
+    assert_string_equal("one to ten", ((struct lysc_type_num*)type)->range->dsc);
+    assert_string_equal("B", ((struct lysc_type_num*)type)->range->ref);
+    assert_non_null(((struct lysc_type_num*)type)->range->parts);
+    assert_int_equal(1, LY_ARRAY_SIZE(((struct lysc_type_num*)type)->range->parts));
+    assert_int_equal(1, ((struct lysc_type_num*)type)->range->parts[0].min_u64);
+    assert_int_equal(10, ((struct lysc_type_num*)type)->range->parts[0].max_u64);
+
     *state = NULL;
     ly_ctx_destroy(ctx, NULL);
 }
@@ -906,7 +911,6 @@
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
 
     assert_non_null(mod = lys_parse_mem(ctx, "module a {namespace urn:a;prefix a;leaf l {type binary {length min {error-app-tag errortag;error-message error;}}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_non_null(((struct lysc_type_bin*)type)->length);
@@ -918,7 +922,6 @@
     assert_int_equal(0, ((struct lysc_type_bin*)type)->length->parts[0].max_u64);
 
     assert_non_null(mod = lys_parse_mem(ctx, "module b {namespace urn:b;prefix b;leaf l {type binary {length max;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_non_null(((struct lysc_type_bin*)type)->length);
@@ -928,7 +931,6 @@
     assert_int_equal(UINT64_C(18446744073709551615), ((struct lysc_type_bin*)type)->length->parts[0].max_u64);
 
     assert_non_null(mod = lys_parse_mem(ctx, "module c {namespace urn:c;prefix c;leaf l {type binary {length min..max;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_non_null(((struct lysc_type_bin*)type)->length);
@@ -938,7 +940,6 @@
     assert_int_equal(UINT64_C(18446744073709551615), ((struct lysc_type_bin*)type)->length->parts[0].max_u64);
 
     assert_non_null(mod = lys_parse_mem(ctx, "module d {namespace urn:d;prefix d;leaf l {type binary {length 5;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_non_null(((struct lysc_type_bin*)type)->length);
@@ -948,7 +949,6 @@
     assert_int_equal(5, ((struct lysc_type_bin*)type)->length->parts[0].max_u64);
 
     assert_non_null(mod = lys_parse_mem(ctx, "module e {namespace urn:e;prefix e;leaf l {type binary {length 1..10;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_non_null(((struct lysc_type_bin*)type)->length);
@@ -958,7 +958,6 @@
     assert_int_equal(10, ((struct lysc_type_bin*)type)->length->parts[0].max_u64);
 
     assert_non_null(mod = lys_parse_mem(ctx, "module f {namespace urn:f;prefix f;leaf l {type binary {length 1..10|20..30;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_non_null(((struct lysc_type_bin*)type)->length);
@@ -970,7 +969,6 @@
     assert_int_equal(30, ((struct lysc_type_bin*)type)->length->parts[1].max_u64);
 
     assert_non_null(mod = lys_parse_mem(ctx, "module g {namespace urn:g;prefix g;leaf l {type binary {length \"16 | 32\";}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_non_null(((struct lysc_type_bin*)type)->length);
@@ -983,7 +981,6 @@
 
     assert_non_null(mod = lys_parse_mem(ctx, "module h {namespace urn:h;prefix h;typedef mytype {type binary {length 10;}}"
                                              "leaf l {type mytype {length \"10\";}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_non_null(((struct lysc_type_bin*)type)->length);
@@ -994,7 +991,6 @@
 
     assert_non_null(mod = lys_parse_mem(ctx, "module i {namespace urn:i;prefix i;typedef mytype {type binary {length 10..100;}}"
                                              "leaf l {type mytype {length \"50\";}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_non_null(((struct lysc_type_bin*)type)->length);
@@ -1005,7 +1001,6 @@
 
     assert_non_null(mod = lys_parse_mem(ctx, "module j {namespace urn:j;prefix j;typedef mytype {type binary {length 10..100;}}"
                                              "leaf l {type mytype {length \"10..30|60..100\";}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_non_null(((struct lysc_type_bin*)type)->length);
@@ -1018,7 +1013,6 @@
 
     assert_non_null(mod = lys_parse_mem(ctx, "module k {namespace urn:k;prefix k;typedef mytype {type binary {length 10..100;}}"
                                              "leaf l {type mytype {length \"10..80\";}}leaf ll {type mytype;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(1, type->refcount);
@@ -1038,7 +1032,6 @@
 
     assert_non_null(mod = lys_parse_mem(ctx, "module l {namespace urn:l;prefix l;typedef mytype {type string {length 10..100;}}"
                                              "typedef mytype2 {type mytype {pattern '[0-9]*';}} leaf l {type mytype2 {pattern '[0-4]*';}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_STRING, type->basetype);
@@ -1051,7 +1044,6 @@
 
     assert_non_null(mod = lys_parse_mem(ctx, "module m {namespace urn:m;prefix m;typedef mytype {type string {length 10;}}"
                                              "leaf l {type mytype {length min..max;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_STRING, type->basetype);
@@ -1063,74 +1055,54 @@
     assert_int_equal(10, ((struct lysc_type_str*)type)->length->parts[0].max_u64);
 
     /* invalid values */
-    assert_non_null(mod = lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;leaf l {type binary {length -10;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;leaf l {type binary {length -10;}}}", LYS_IN_YANG));
     logbuf_assert("Invalid length restriction - value \"-10\" does not fit the type limitations.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb;leaf l {type binary {length 18446744073709551616;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb;leaf l {type binary {length 18446744073709551616;}}}", LYS_IN_YANG));
     logbuf_assert("Invalid length restriction - invalid value \"18446744073709551616\".");
-    assert_non_null(mod = lys_parse_mem(ctx, "module cc {namespace urn:cc;prefix cc;leaf l {type binary {length \"max .. 10\";}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module cc {namespace urn:cc;prefix cc;leaf l {type binary {length \"max .. 10\";}}}", LYS_IN_YANG));
     logbuf_assert("Invalid length restriction - unexpected data after max keyword (.. 10).");
-    assert_non_null(mod = lys_parse_mem(ctx, "module dd {namespace urn:dd;prefix dd;leaf l {type binary {length 50..10;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module dd {namespace urn:dd;prefix dd;leaf l {type binary {length 50..10;}}}", LYS_IN_YANG));
     logbuf_assert("Invalid length restriction - values are not in ascending order (10).");
-    assert_non_null(mod = lys_parse_mem(ctx, "module ee {namespace urn:ee;prefix ee;leaf l {type binary {length \"50 | 10\";}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module ee {namespace urn:ee;prefix ee;leaf l {type binary {length \"50 | 10\";}}}", LYS_IN_YANG));
     logbuf_assert("Invalid length restriction - values are not in ascending order (10).");
-    assert_non_null(mod = lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff;leaf l {type binary {length \"x\";}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff;leaf l {type binary {length \"x\";}}}", LYS_IN_YANG));
     logbuf_assert("Invalid length restriction - unexpected data (x).");
-    assert_non_null(mod = lys_parse_mem(ctx, "module gg {namespace urn:gg;prefix gg;leaf l {type binary {length \"50 | min\";}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module gg {namespace urn:gg;prefix gg;leaf l {type binary {length \"50 | min\";}}}", LYS_IN_YANG));
     logbuf_assert("Invalid length restriction - unexpected data before min keyword (50 | ).");
-    assert_non_null(mod = lys_parse_mem(ctx, "module hh {namespace urn:hh;prefix hh;leaf l {type binary {length \"| 50\";}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module hh {namespace urn:hh;prefix hh;leaf l {type binary {length \"| 50\";}}}", LYS_IN_YANG));
     logbuf_assert("Invalid length restriction - unexpected beginning of the expression (| 50).");
-    assert_non_null(mod = lys_parse_mem(ctx, "module ii {namespace urn:ii;prefix ii;leaf l {type binary {length \"10 ..\";}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module ii {namespace urn:ii;prefix ii;leaf l {type binary {length \"10 ..\";}}}", LYS_IN_YANG));
     logbuf_assert("Invalid length restriction - unexpected end of the expression after \"..\" (10 ..).");
-    assert_non_null(mod = lys_parse_mem(ctx, "module jj {namespace urn:jj;prefix jj;leaf l {type binary {length \".. 10\";}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module jj {namespace urn:jj;prefix jj;leaf l {type binary {length \".. 10\";}}}", LYS_IN_YANG));
     logbuf_assert("Invalid length restriction - unexpected \"..\" without a lower bound.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module kk {namespace urn:kk;prefix kk;leaf l {type binary {length \"10 |\";}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module kk {namespace urn:kk;prefix kk;leaf l {type binary {length \"10 |\";}}}", LYS_IN_YANG));
     logbuf_assert("Invalid length restriction - unexpected end of the expression (10 |).");
-    assert_non_null(mod = lys_parse_mem(ctx, "module kl {namespace urn:kl;prefix kl;leaf l {type binary {length \"10..20 | 15..30\";}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module kl {namespace urn:kl;prefix kl;leaf l {type binary {length \"10..20 | 15..30\";}}}", LYS_IN_YANG));
     logbuf_assert("Invalid length restriction - values are not in ascending order (15).");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module ll {namespace urn:ll;prefix ll;typedef mytype {type binary {length 10;}}"
-                                             "leaf l {type mytype {length 11;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module ll {namespace urn:ll;prefix ll;typedef mytype {type binary {length 10;}}"
+                                   "leaf l {type mytype {length 11;}}}", LYS_IN_YANG));
     logbuf_assert("Invalid length restriction - the derived restriction (11) is not equally or more limiting.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module mm {namespace urn:mm;prefix mm;typedef mytype {type binary {length 10..100;}}"
-                                             "leaf l {type mytype {length 1..11;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module mm {namespace urn:mm;prefix mm;typedef mytype {type binary {length 10..100;}}"
+                                   "leaf l {type mytype {length 1..11;}}}", LYS_IN_YANG));
     logbuf_assert("Invalid length restriction - the derived restriction (1..11) is not equally or more limiting.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module nn {namespace urn:nn;prefix nn;typedef mytype {type binary {length 10..100;}}"
-                                             "leaf l {type mytype {length 20..110;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module nn {namespace urn:nn;prefix nn;typedef mytype {type binary {length 10..100;}}"
+                                   "leaf l {type mytype {length 20..110;}}}", LYS_IN_YANG));
     logbuf_assert("Invalid length restriction - the derived restriction (20..110) is not equally or more limiting.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module oo {namespace urn:oo;prefix oo;typedef mytype {type binary {length 10..100;}}"
-                                             "leaf l {type mytype {length 20..30|110..120;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module oo {namespace urn:oo;prefix oo;typedef mytype {type binary {length 10..100;}}"
+                                   "leaf l {type mytype {length 20..30|110..120;}}}", LYS_IN_YANG));
     logbuf_assert("Invalid length restriction - the derived restriction (20..30|110..120) is not equally or more limiting.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module pp {namespace urn:pp;prefix pp;typedef mytype {type binary {length 10..11;}}"
+    assert_null(lys_parse_mem(ctx, "module pp {namespace urn:pp;prefix pp;typedef mytype {type binary {length 10..11;}}"
                                              "leaf l {type mytype {length 15;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid length restriction - the derived restriction (15) is not equally or more limiting.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module qq {namespace urn:qq;prefix qq;typedef mytype {type binary {length 10..20|30..40;}}"
+    assert_null(lys_parse_mem(ctx, "module qq {namespace urn:qq;prefix qq;typedef mytype {type binary {length 10..20|30..40;}}"
                                              "leaf l {type mytype {length 15..35;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid length restriction - the derived restriction (15..35) is not equally or more limiting.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module rr {namespace urn:rr;prefix rr;typedef mytype {type binary {length 10;}}"
+    assert_null(lys_parse_mem(ctx, "module rr {namespace urn:rr;prefix rr;typedef mytype {type binary {length 10;}}"
                                              "leaf l {type mytype {length 10..35;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid length restriction - the derived restriction (10..35) is not equally or more limiting.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module ss {namespace urn:rr;prefix rr;leaf l {type binary {pattern '[0-9]*';}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module ss {namespace urn:rr;prefix rr;leaf l {type binary {pattern '[0-9]*';}}}", LYS_IN_YANG));
     logbuf_assert("Invalid type restrictions for binary type.");
 
     *state = NULL;
@@ -1151,7 +1123,6 @@
     assert_non_null(mod = lys_parse_mem(ctx, "module a {yang-version 1.1; namespace urn:a;prefix a;leaf l {type string {"
                                         "pattern .* {error-app-tag errortag;error-message error;}"
                                         "pattern [0-9].*[0-9] {modifier invert-match;}}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_non_null(((struct lysc_type_str*)type)->patterns);
@@ -1165,7 +1136,6 @@
 
     assert_non_null(mod = lys_parse_mem(ctx, "module b {namespace urn:b;prefix b;typedef mytype {type string {pattern '[0-9]*';}}"
                                              "typedef mytype2 {type mytype {length 10;}} leaf l {type mytype2 {pattern '[0-4]*';}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_STRING, type->basetype);
@@ -1177,7 +1147,6 @@
 
     assert_non_null(mod = lys_parse_mem(ctx, "module c {namespace urn:c;prefix c;typedef mytype {type string {pattern '[0-9]*';}}"
                                              "leaf l {type mytype {length 10;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_STRING, type->basetype);
@@ -1189,7 +1158,6 @@
     /* test substitutions */
     assert_non_null(mod = lys_parse_mem(ctx, "module d {namespace urn:d;prefix d;leaf l {type string {"
                                         "pattern '^\\p{IsLatinExtended-A}$';}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_non_null(((struct lysc_type_str*)type)->patterns);
@@ -1214,7 +1182,6 @@
     assert_non_null(mod = lys_parse_mem(ctx, "module a {yang-version 1.1; namespace urn:a;prefix a;feature f; leaf l {type enumeration {"
                                         "enum automin; enum min {value -2147483648;}enum one {if-feature f; value 1;}"
                                         "enum two; enum seven {value 7;}enum eight;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_ENUM, type->basetype);
@@ -1238,7 +1205,6 @@
                                         "enum 11; enum min {value -2147483648;}enum x$&;"
                                         "enum two; enum seven {value 7;}enum eight;}} leaf l { type mytype {enum seven;enum eight;}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_ENUM, type->basetype);
@@ -1276,37 +1242,30 @@
                                   "enum 'inva\nlid';}}}", LYS_IN_YANG));
     logbuf_assert("Control characters in enum name should be avoided (\"inva\nlid\", character number 5).");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb; leaf l {type enumeration;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb; leaf l {type enumeration;}}", LYS_IN_YANG));
     logbuf_assert("Missing enum substatement for enumeration type.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module cc {yang-version 1.1;namespace urn:cc;prefix cc;typedef mytype {type enumeration {enum one;}}"
+    assert_null(lys_parse_mem(ctx, "module cc {yang-version 1.1;namespace urn:cc;prefix cc;typedef mytype {type enumeration {enum one;}}"
                                              "leaf l {type mytype {enum two;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid enumeration - derived type adds new item \"two\".");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module dd {yang-version 1.1;namespace urn:dd;prefix dd;typedef mytype {type enumeration {enum one;}}"
+    assert_null(lys_parse_mem(ctx, "module dd {yang-version 1.1;namespace urn:dd;prefix dd;typedef mytype {type enumeration {enum one;}}"
                                              "leaf l {type mytype {enum one {value 1;}}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid enumeration - value of the item \"one\" has changed from 0 to 1 in the derived type.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module ee {namespace urn:ee;prefix ee;leaf l {type enumeration {enum x {value 2147483647;}enum y;}}}",
+    assert_null(lys_parse_mem(ctx, "module ee {namespace urn:ee;prefix ee;leaf l {type enumeration {enum x {value 2147483647;}enum y;}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid enumeration - it is not possible to auto-assign enum value for \"y\" since the highest value is already 2147483647.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff;leaf l {type enumeration {enum x {value 1;}enum y {value 1;}}}}",
+    assert_null(lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff;leaf l {type enumeration {enum x {value 1;}enum y {value 1;}}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid enumeration - value 1 collide in items \"y\" and \"x\".");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module gg {namespace urn:gg;prefix gg;typedef mytype {type enumeration;}"
+    assert_null(lys_parse_mem(ctx, "module gg {namespace urn:gg;prefix gg;typedef mytype {type enumeration;}"
                                              "leaf l {type mytype {enum one;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Missing enum substatement for enumeration type mytype.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module hh {namespace urn:hh;prefix hh; typedef mytype {type enumeration {enum one;}}"
+    assert_null(lys_parse_mem(ctx, "module hh {namespace urn:hh;prefix hh; typedef mytype {type enumeration {enum one;}}"
                                         "leaf l {type mytype {enum one;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Enumeration type can be subtyped only in YANG 1.1 modules.");
 
     *state = NULL;
@@ -1327,7 +1286,6 @@
     assert_non_null(mod = lys_parse_mem(ctx, "module a {yang-version 1.1; namespace urn:a;prefix a;feature f; leaf l {type bits {"
                                         "bit automin; bit one {if-feature f; position 1;}"
                                         "bit two; bit seven {position 7;}bit eight;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_BITS, type->basetype);
@@ -1348,7 +1306,6 @@
     assert_non_null(mod = lys_parse_mem(ctx, "module b {yang-version 1.1;namespace urn:b;prefix b;feature f; typedef mytype {type bits {"
                                         "bit automin; bit one;bit two; bit seven {value 7;}bit eight;}} leaf l { type mytype {bit eight;bit seven;bit automin;}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_BITS, type->basetype);
@@ -1382,37 +1339,30 @@
                                    "bit 'x1$1';}}}", LYS_IN_YANG));
     logbuf_assert("Invalid identifier character '$'. Line number 1.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb; leaf l {type bits;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb; leaf l {type bits;}}", LYS_IN_YANG));
     logbuf_assert("Missing bit substatement for bits type.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module cc {yang-version 1.1;namespace urn:cc;prefix cc;typedef mytype {type bits {bit one;}}"
+    assert_null(lys_parse_mem(ctx, "module cc {yang-version 1.1;namespace urn:cc;prefix cc;typedef mytype {type bits {bit one;}}"
                                              "leaf l {type mytype {bit two;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid bits - derived type adds new item \"two\".");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module dd {yang-version 1.1;namespace urn:dd;prefix dd;typedef mytype {type bits {bit one;}}"
+    assert_null(lys_parse_mem(ctx, "module dd {yang-version 1.1;namespace urn:dd;prefix dd;typedef mytype {type bits {bit one;}}"
                                              "leaf l {type mytype {bit one {position 1;}}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid bits - position of the item \"one\" has changed from 0 to 1 in the derived type.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module ee {namespace urn:ee;prefix ee;leaf l {type bits {bit x {position 4294967295;}bit y;}}}",
+    assert_null(lys_parse_mem(ctx, "module ee {namespace urn:ee;prefix ee;leaf l {type bits {bit x {position 4294967295;}bit y;}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid bits - it is not possible to auto-assign bit position for \"y\" since the highest value is already 4294967295.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff;leaf l {type bits {bit x {value 1;}bit y {value 1;}}}}",
+    assert_null(lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff;leaf l {type bits {bit x {value 1;}bit y {value 1;}}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid bits - position 1 collide in items \"y\" and \"x\".");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module gg {namespace urn:gg;prefix gg;typedef mytype {type bits;}"
+    assert_null(lys_parse_mem(ctx, "module gg {namespace urn:gg;prefix gg;typedef mytype {type bits;}"
                                              "leaf l {type mytype {bit one;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Missing bit substatement for bits type mytype.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module hh {namespace urn:hh;prefix hh; typedef mytype {type bits {bit one;}}"
+    assert_null(lys_parse_mem(ctx, "module hh {namespace urn:hh;prefix hh; typedef mytype {type bits {bit one;}}"
                                         "leaf l {type mytype {bit one;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Bits type can be subtyped only in YANG 1.1 modules.");
 
     *state = NULL;
@@ -1432,7 +1382,6 @@
 
     assert_non_null(mod = lys_parse_mem(ctx, "module a {namespace urn:a;prefix a;leaf l {type decimal64 {"
                                         "fraction-digits 2;range min..max;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_DEC64, type->basetype);
@@ -1445,7 +1394,6 @@
 
     assert_non_null(mod = lys_parse_mem(ctx, "module b {namespace urn:b;prefix b;typedef mytype {type decimal64 {"
                                         "fraction-digits 2;range '3.14 | 5.1 | 10';}}leaf l {type mytype;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_DEC64, type->basetype);
@@ -1468,32 +1416,26 @@
     assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa; leaf l {type decimal64 {fraction-digits 19;}}}", LYS_IN_YANG));
     logbuf_assert("Value \"19\" is out of \"fraction-digits\" bounds. Line number 1.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa; leaf l {type decimal64;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa; leaf l {type decimal64;}}", LYS_IN_YANG));
     logbuf_assert("Missing fraction-digits substatement for decimal64 type.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module ab {namespace urn:ab;prefix ab; typedef mytype {type decimal64;}leaf l {type mytype;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module ab {namespace urn:ab;prefix ab; typedef mytype {type decimal64;}leaf l {type mytype;}}", LYS_IN_YANG));
     logbuf_assert("Missing fraction-digits substatement for decimal64 type mytype.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb; leaf l {type decimal64 {fraction-digits 2;"
+    assert_null(lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb; leaf l {type decimal64 {fraction-digits 2;"
                                         "range '3.142';}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Range boundary \"3.142\" of decimal64 type exceeds defined number (2) of fraction digits.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module cc {namespace urn:cc;prefix cc; leaf l {type decimal64 {fraction-digits 2;"
+    assert_null(lys_parse_mem(ctx, "module cc {namespace urn:cc;prefix cc; leaf l {type decimal64 {fraction-digits 2;"
                                         "range '4 | 3.14';}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid range restriction - values are not in ascending order (3.14).");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module dd {namespace urn:dd;prefix dd; typedef mytype {type decimal64 {fraction-digits 2;}}"
+    assert_null(lys_parse_mem(ctx, "module dd {namespace urn:dd;prefix dd; typedef mytype {type decimal64 {fraction-digits 2;}}"
                                         "leaf l {type mytype {fraction-digits 3;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid fraction-digits substatement for type not directly derived from decimal64 built-in type.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module de {namespace urn:de;prefix de; typedef mytype {type decimal64 {fraction-digits 2;}}"
+    assert_null(lys_parse_mem(ctx, "module de {namespace urn:de;prefix de; typedef mytype {type decimal64 {fraction-digits 2;}}"
                                         "typedef mytype2 {type mytype {fraction-digits 3;}}leaf l {type mytype2;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid fraction-digits substatement for type \"mytype2\" not directly derived from decimal64 built-in type.");
 
     *state = NULL;
@@ -1514,7 +1456,6 @@
     assert_non_null(mod = lys_parse_mem(ctx, "module a {namespace urn:a;prefix a;typedef mytype {type instance-identifier {require-instance false;}}"
                                         "leaf l1 {type instance-identifier {require-instance true;}}"
                                         "leaf l2 {type mytype;} leaf l3 {type instance-identifier;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_INST, type->basetype);
@@ -1534,8 +1475,7 @@
     assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa; leaf l {type instance-identifier {require-instance yes;}}}", LYS_IN_YANG));
     logbuf_assert("Invalid value \"yes\" of \"require-instance\". Line number 1.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa; leaf l {type instance-identifier {fraction-digits 1;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa; leaf l {type instance-identifier {fraction-digits 1;}}}", LYS_IN_YANG));
     logbuf_assert("Invalid type restrictions for instance-identifier type.");
 
     *state = NULL;
@@ -1556,7 +1496,6 @@
     assert_non_null(mod = lys_parse_mem(ctx, "module a {yang-version 1.1;namespace urn:a;prefix a;identity i; identity j; identity k {base i;}"
                                         "typedef mytype {type identityref {base i;}}"
                                         "leaf l1 {type mytype;} leaf l2 {type identityref {base a:k; base j;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_IDENT, type->basetype);
@@ -1574,7 +1513,6 @@
 
     assert_non_null(mod = lys_parse_mem(ctx, "module b {yang-version 1.1;namespace urn:b;prefix b;import a {prefix a;}"
                                         "leaf l {type identityref {base a:k; base a:j;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_IDENT, type->basetype);
@@ -1584,36 +1522,29 @@
     assert_string_equal("j", ((struct lysc_type_identityref*)type)->bases[1]->name);
 
     /* invalid cases */
-    assert_non_null(mod = lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa; leaf l {type identityref;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa; leaf l {type identityref;}}", LYS_IN_YANG));
     logbuf_assert("Missing base substatement for identityref type.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb; typedef mytype {type identityref;}"
+    assert_null(lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb; typedef mytype {type identityref;}"
                                         "leaf l {type mytype;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Missing base substatement for identityref type mytype.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module cc {namespace urn:cc;prefix cc; identity i; typedef mytype {type identityref {base i;}}"
+    assert_null(lys_parse_mem(ctx, "module cc {namespace urn:cc;prefix cc; identity i; typedef mytype {type identityref {base i;}}"
                                         "leaf l {type mytype {base i;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid base substatement for the type not directly derived from identityref built-in type.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module dd {namespace urn:dd;prefix dd; identity i; typedef mytype {type identityref {base i;}}"
+    assert_null(lys_parse_mem(ctx, "module dd {namespace urn:dd;prefix dd; identity i; typedef mytype {type identityref {base i;}}"
                                         "typedef mytype2 {type mytype {base i;}}leaf l {type mytype2;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid base substatement for the type \"mytype2\" not directly derived from identityref built-in type.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module ee {namespace urn:ee;prefix ee; identity i; identity j;"
+    assert_null(lys_parse_mem(ctx, "module ee {namespace urn:ee;prefix ee; identity i; identity j;"
                                         "leaf l {type identityref {base i;base j;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Multiple bases in identityref type are allowed only in YANG 1.1 modules.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff; identity i;leaf l {type identityref {base j;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff; identity i;leaf l {type identityref {base j;}}}", LYS_IN_YANG));
     logbuf_assert("Unable to find base (j) of identityref.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module gg {namespace urn:gg;prefix gg;leaf l {type identityref {base x:j;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module gg {namespace urn:gg;prefix gg;leaf l {type identityref {base x:j;}}}", LYS_IN_YANG));
     logbuf_assert("Invalid prefix used for base (x:j) of identityref.");
 
     *state = NULL;
@@ -1698,7 +1629,6 @@
     assert_non_null(mod = lys_parse_mem(ctx, "module a {yang-version 1.1;namespace urn:a;prefix a;"
                                         "leaf ref1 {type leafref {path /a:target1;}} leaf ref2 {type leafref {path /a/target2; require-instance false;}}"
                                         "leaf target1 {type string;}container a {leaf target2 {type uint8;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_LEAFREF, type->basetype);
@@ -1719,7 +1649,6 @@
     assert_non_null(mod = lys_parse_mem(ctx, "module b {namespace urn:b;prefix b; typedef mytype {type leafref {path /b:target;}}"
                                         "typedef mytype2 {type mytype;} typedef mytype3 {type leafref {path /target;}} leaf ref {type mytype2;}"
                                         "leaf target {type leafref {path ../realtarget;}} leaf realtarget {type string;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(1, type->refcount);
@@ -1734,7 +1663,6 @@
     assert_non_null(mod = lys_parse_mem(ctx, "module c {yang-version 1.1;namespace urn:c;prefix b; import b {prefix c;}"
                                         "typedef mytype3 {type c:mytype {require-instance false;}}"
                                         "leaf ref1 {type b:mytype3;}leaf ref2 {type c:mytype2;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(1, type->refcount);
@@ -1755,7 +1683,6 @@
     /* non-prefixed nodes in path are supposed to be from the module where the leafref type is instantiated */
     assert_non_null(mod = lys_parse_mem(ctx, "module d {namespace urn:d;prefix d; import b {prefix b;}"
                                         "leaf ref {type b:mytype3;}leaf target {type int8;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(1, type->refcount);
@@ -1770,7 +1697,6 @@
     assert_non_null(mod = lys_parse_mem(ctx, "module e {yang-version 1.1;namespace urn:e;prefix e;feature f1; feature f2;"
                                         "leaf ref1 {if-feature 'f1 and f2';type leafref {path /target;}}"
                                         "leaf target {if-feature f1; type boolean;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(1, type->refcount);
@@ -1785,7 +1711,6 @@
                                         "container default-address{leaf ifname{type leafref{ path \"../../interface/name\";}}"
                                           "leaf address {type leafref{ path \"../../interface[  name = current()/../ifname ]/address/ip\";}}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)(*lysc_node_children_p(mod->compiled->data->prev))->prev)->type;
     assert_non_null(type);
     assert_int_equal(1, type->refcount);
@@ -1799,7 +1724,6 @@
                                         "leaf source {type leafref {path \"/endpoint-parent[id=current()/../field]/endpoint/name\";}}"
                                         "leaf field {type int32;}list endpoint-parent {key id;leaf id {type int32;}"
                                         "list endpoint {key name;leaf name {type string;}}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(1, type->refcount);
@@ -1810,188 +1734,159 @@
     assert_int_equal(LY_TYPE_STRING, ((struct lysc_type_leafref*)type)->realtype->basetype);
 
     /* invalid paths */
-    assert_non_null(mod = lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;container a {leaf target2 {type uint8;}}"
+    assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;container a {leaf target2 {type uint8;}}"
                                         "leaf ref1 {type leafref {path ../a/invalid;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path - unable to find \"../a/invalid\".");
-    assert_non_null(mod = lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb;container a {leaf target2 {type uint8;}}"
+    assert_null(lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb;container a {leaf target2 {type uint8;}}"
                                         "leaf ref1 {type leafref {path ../../toohigh;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path \"../../toohigh\" - too many \"..\" in the path.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module cc {namespace urn:cc;prefix cc;container a {leaf target2 {type uint8;}}"
+    assert_null(lys_parse_mem(ctx, "module cc {namespace urn:cc;prefix cc;container a {leaf target2 {type uint8;}}"
                                         "leaf ref1 {type leafref {path /a:invalid;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path - unable to find module connected with the prefix of the node \"/a:invalid\".");
-    assert_non_null(mod = lys_parse_mem(ctx, "module dd {namespace urn:dd;prefix dd;leaf target1 {type string;}container a {leaf target2 {type uint8;}}"
+    assert_null(lys_parse_mem(ctx, "module dd {namespace urn:dd;prefix dd;leaf target1 {type string;}container a {leaf target2 {type uint8;}}"
                                         "leaf ref1 {type leafref {path '/a[target2 = current()/../target1]/target2';}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path - node \"/a\" is expected to be a list, but it is container.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module ee {namespace urn:ee;prefix ee;container a {leaf target2 {type uint8;}}"
+    assert_null(lys_parse_mem(ctx, "module ee {namespace urn:ee;prefix ee;container a {leaf target2 {type uint8;}}"
                                         "leaf ref1 {type leafref {path /a!invalid;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path at character 3 (/a!invalid).");
-    assert_non_null(mod = lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff;container a {leaf target2 {type uint8;}}"
+    assert_null(lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff;container a {leaf target2 {type uint8;}}"
                                         "leaf ref1 {type leafref {path /a;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path \"/a\" - target node is container instead of leaf or leaf-list.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module gg {namespace urn:gg;prefix gg;container a {leaf target2 {type uint8; status deprecated;}}"
+    assert_null(lys_parse_mem(ctx, "module gg {namespace urn:gg;prefix gg;container a {leaf target2 {type uint8; status deprecated;}}"
                                         "leaf ref1 {type leafref {path /a/target2;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("A current definition \"ref1\" is not allowed to reference deprecated definition \"target2\".");
-    assert_non_null(mod = lys_parse_mem(ctx, "module hh {namespace urn:hh;prefix hh;"
+    assert_null(lys_parse_mem(ctx, "module hh {namespace urn:hh;prefix hh;"
                                         "leaf ref1 {type leafref;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Missing path substatement for leafref type.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module ii {namespace urn:ii;prefix ii;typedef mytype {type leafref;}"
+    assert_null(lys_parse_mem(ctx, "module ii {namespace urn:ii;prefix ii;typedef mytype {type leafref;}"
                                         "leaf ref1 {type mytype;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Missing path substatement for leafref type mytype.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module jj {namespace urn:jj;prefix jj;feature f;"
+    assert_null(lys_parse_mem(ctx, "module jj {namespace urn:jj;prefix jj;feature f;"
                                         "leaf ref {type leafref {path /target;}}leaf target {if-feature f;type string;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path \"/target\" - set of features applicable to the leafref target is not a subset of features "
                   "applicable to the leafref itself.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module kk {namespace urn:kk;prefix kk;"
+    assert_null(lys_parse_mem(ctx, "module kk {namespace urn:kk;prefix kk;"
                                         "leaf ref {type leafref {path /target;}}leaf target {type string;config false;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path \"/target\" - target is supposed to represent configuration data (as the leafref does), but it does not.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module ll {namespace urn:ll;prefix ll;"
+    assert_null(lys_parse_mem(ctx, "module ll {namespace urn:ll;prefix ll;"
                                         "leaf ref {type leafref {path /target; require-instance true;}}leaf target {type string;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Leafref type can be restricted by require-instance statement only in YANG 1.1 modules.");
-    assert_non_null(mod = lys_parse_mem(ctx, "module mm {namespace urn:mm;prefix mm;typedef mytype {type leafref {path /target;require-instance false;}}"
+    assert_null(lys_parse_mem(ctx, "module mm {namespace urn:mm;prefix mm;typedef mytype {type leafref {path /target;require-instance false;}}"
                                         "leaf ref {type mytype;}leaf target {type string;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Leafref type \"mytype\" can be restricted by require-instance statement only in YANG 1.1 modules.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module nn {namespace urn:nn;prefix nn;"
+    assert_null(lys_parse_mem(ctx, "module nn {namespace urn:nn;prefix nn;"
                                         "list interface{key name;leaf name{type string;}leaf ip {type string;}}"
                                         "leaf ifname{type leafref{ path \"../interface/name\";}}"
                                         "leaf address {type leafref{ path \"/interface[name is current()/../ifname]/ip\";}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path predicate \"[name i\" - missing \"=\" after node-identifier.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module oo {namespace urn:oo;prefix oo;"
+    assert_null(lys_parse_mem(ctx, "module oo {namespace urn:oo;prefix oo;"
                                         "list interface{key name;leaf name{type string;}leaf ip {type string;}}"
                                         "leaf ifname{type leafref{ path \"../interface/name\";}}"
                                         "leaf address {type leafref{ path \"/interface[name=current()/../ifname/ip\";}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path predicate \"[name=current()/../ifname/ip\" - missing predicate termination.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module pp {namespace urn:pp;prefix pp;"
+    assert_null(lys_parse_mem(ctx, "module pp {namespace urn:pp;prefix pp;"
                                         "list interface{key name;leaf name{type string;}leaf ip {type string;}}"
                                         "leaf ifname{type leafref{ path \"../interface/name\";}}"
                                         "leaf address {type leafref{ path \"/interface[x:name=current()/../ifname]/ip\";}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path predicate \"[x:name=current()/../ifname]\" - prefix \"x\" not defined in module \"pp\".");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module qq {namespace urn:qq;prefix qq;"
+    assert_null(lys_parse_mem(ctx, "module qq {namespace urn:qq;prefix qq;"
                                         "list interface{key name;leaf name{type string;}leaf ip {type string;}}"
                                         "leaf ifname{type leafref{ path \"../interface/name\";}}"
                                         "leaf address {type leafref{ path \"/interface[id=current()/../ifname]/ip\";}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path predicate \"[id=current()/../ifname]\" - predicate's key node \"id\" not found.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module rr {namespace urn:rr;prefix rr;"
+    assert_null(lys_parse_mem(ctx, "module rr {namespace urn:rr;prefix rr;"
                                         "list interface{key name;leaf name{type string;}leaf ip {type string;}}"
                                         "leaf ifname{type leafref{ path \"../interface/name\";}}leaf test{type string;}"
                                         "leaf address {type leafref{ path \"/interface[name=current() /  .. / ifname][name=current()/../test]/ip\";}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path predicate \"[name=current()/../test]\" - multiple equality tests for the key \"name\".");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module ss {namespace urn:ss;prefix ss;"
+    assert_null(lys_parse_mem(ctx, "module ss {namespace urn:ss;prefix ss;"
                                         "list interface{key name;leaf name{type string;}leaf ip {type string;}}"
                                         "leaf ifname{type leafref{ path \"../interface/name\";}}leaf test{type string;}"
                                         "leaf address {type leafref{ path \"/interface[name = ../ifname]/ip\";}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path predicate \"[name = ../ifname]\" - missing current-function-invocation.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module tt {namespace urn:tt;prefix tt;"
+    assert_null(lys_parse_mem(ctx, "module tt {namespace urn:tt;prefix tt;"
                                         "list interface{key name;leaf name{type string;}leaf ip {type string;}}"
                                         "leaf ifname{type leafref{ path \"../interface/name\";}}leaf test{type string;}"
                                         "leaf address {type leafref{ path \"/interface[name = current()../ifname]/ip\";}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path predicate \"[name = current()../ifname]\" - missing \"/\" after current-function-invocation.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module uu {namespace urn:uu;prefix uu;"
+    assert_null(lys_parse_mem(ctx, "module uu {namespace urn:uu;prefix uu;"
                                         "list interface{key name;leaf name{type string;}leaf ip {type string;}}"
                                         "leaf ifname{type leafref{ path \"../interface/name\";}}leaf test{type string;}"
                                         "leaf address {type leafref{ path \"/interface[name = current()/..ifname]/ip\";}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path predicate \"[name = current()/..ifname]\" - missing \"/\" in \"../\" rel-path-keyexpr pattern.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module vv {namespace urn:vv;prefix vv;"
+    assert_null(lys_parse_mem(ctx, "module vv {namespace urn:vv;prefix vv;"
                                         "list interface{key name;leaf name{type string;}leaf ip {type string;}}"
                                         "leaf ifname{type leafref{ path \"../interface/name\";}}leaf test{type string;}"
                                         "leaf address {type leafref{ path \"/interface[name = current()/ifname]/ip\";}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path predicate \"[name = current()/ifname]\" - at least one \"..\" is expected in rel-path-keyexpr.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module ww {namespace urn:ww;prefix ww;"
+    assert_null(lys_parse_mem(ctx, "module ww {namespace urn:ww;prefix ww;"
                                         "list interface{key name;leaf name{type string;}leaf ip {type string;}}"
                                         "leaf ifname{type leafref{ path \"../interface/name\";}}leaf test{type string;}"
                                         "leaf address {type leafref{ path \"/interface[name = current()/../]/ip\";}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path predicate \"[name = current()/../]\" - at least one node-identifier is expected in rel-path-keyexpr.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module xx {namespace urn:xx;prefix xx;"
+    assert_null(lys_parse_mem(ctx, "module xx {namespace urn:xx;prefix xx;"
                                         "list interface{key name;leaf name{type string;}leaf ip {type string;}}"
                                         "leaf ifname{type leafref{ path \"../interface/name\";}}leaf test{type string;}"
                                         "leaf address {type leafref{ path \"/interface[name = current()/../$node]/ip\";}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid node identifier in leafref path predicate - character 22 (of [name = current()/../$node]).");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module yy {namespace urn:yy;prefix yy;"
+    assert_null(lys_parse_mem(ctx, "module yy {namespace urn:yy;prefix yy;"
                                         "list interface{key name;leaf name{type string;}leaf ip {type string;}}"
                                         "leaf ifname{type leafref{ path \"../interface/name\";}}"
                                         "leaf address {type leafref{ path \"/interface[name=current()/../x:ifname]/ip\";}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path predicate \"[name=current()/../x:ifname]\" - unable to find module of the node \"ifname\" in rel-path_keyexpr.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module zz {namespace urn:zz;prefix zz;"
+    assert_null(lys_parse_mem(ctx, "module zz {namespace urn:zz;prefix zz;"
                                         "list interface{key name;leaf name{type string;}leaf ip {type string;}}"
                                         "leaf ifname{type leafref{ path \"../interface/name\";}}"
                                         "leaf address {type leafref{ path \"/interface[name=current()/../xxx]/ip\";}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path predicate \"[name=current()/../xxx]\" - unable to find node \"current()/../xxx\" in the rel-path_keyexpr.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module zza {namespace urn:zza;prefix zza;"
+    assert_null(lys_parse_mem(ctx, "module zza {namespace urn:zza;prefix zza;"
                                         "list interface{key name;leaf name{type string;}leaf ip {type string;}}"
                                         "leaf ifname{type leafref{ path \"../interface/name\";}}container c;"
                                         "leaf address {type leafref{ path \"/interface[name=current()/../c]/ip\";}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path predicate \"[name=current()/../c]\" - rel-path_keyexpr \"current()/../c\" refers container instead of leaf.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module zzb {namespace urn:zzb;prefix zzb;"
+    assert_null(lys_parse_mem(ctx, "module zzb {namespace urn:zzb;prefix zzb;"
                                         "list interface{key name;leaf name{type string;}leaf ip {type string;}container c;}"
                                         "leaf ifname{type leafref{ path \"../interface/name\";}}"
                                         "leaf address {type leafref{ path \"/interface[c=current()/../ifname]/ip\";}}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path predicate \"[c=current()/../ifname]\" - predicate's key node \"c\" not found.");
 
     /* circular chain */
-    assert_non_null(mod = lys_parse_mem(ctx, "module aaa {namespace urn:aaa;prefix aaa;"
+    assert_null(lys_parse_mem(ctx, "module aaa {namespace urn:aaa;prefix aaa;"
                                         "leaf ref1 {type leafref {path /ref2;}}"
                                         "leaf ref2 {type leafref {path /ref3;}}"
                                         "leaf ref3 {type leafref {path /ref4;}}"
                                         "leaf ref4 {type leafref {path /ref1;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid leafref path \"/ref1\" - circular chain of leafrefs detected.");
 
     *state = NULL;
@@ -2004,19 +1899,16 @@
     *state = test_type_empty;
 
     struct ly_ctx *ctx;
-    struct lys_module *mod;
 
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
 
     /* invalid */
-    assert_non_null(mod = lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;"
+    assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;"
                                         "leaf l {type empty; default x;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Leaf of type \"empty\" must not have a default value (x).");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb;typedef mytype {type empty; default x;}"
+    assert_null(lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb;typedef mytype {type empty; default x;}"
                                         "leaf l {type mytype;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid type \"mytype\" - \"empty\" type must not have a default value (x).");
 
     *state = NULL;
@@ -2038,7 +1930,6 @@
     assert_non_null(mod = lys_parse_mem(ctx, "module a {yang-version 1.1;namespace urn:a;prefix a; typedef mybasetype {type string;}"
                                         "typedef mytype {type union {type int8; type mybasetype;}}"
                                         "leaf l {type mytype;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(2, type->refcount);
@@ -2051,7 +1942,6 @@
     assert_non_null(mod = lys_parse_mem(ctx, "module b {yang-version 1.1;namespace urn:b;prefix b; typedef mybasetype {type string;}"
                                         "typedef mytype {type union {type int8; type mybasetype;}}"
                                         "leaf l {type union {type decimal64 {fraction-digits 2;} type mytype;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(1, type->refcount);
@@ -2067,7 +1957,6 @@
                                         "leaf l {type union {type decimal64 {fraction-digits 2;} type mytype;}}"
                                         "leaf target {type leafref {path ../realtarget;}} leaf realtarget {type int8;}}",
                                         LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(1, type->refcount);
@@ -2081,23 +1970,19 @@
     assert_int_equal(LY_TYPE_INT8, ((struct lysc_type_leafref*)((struct lysc_type_union*)type)->types[1])->realtype->basetype);
 
     /* invalid unions */
-    assert_non_null(mod = lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;typedef mytype {type union;}"
+    assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;typedef mytype {type union;}"
                                         "leaf l {type mytype;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Missing type substatement for union type mytype.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb;leaf l {type union;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
-    logbuf_assert("Missing type substatement for union type.");
+    assert_null(lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb;leaf l {type union;}}", LYS_IN_YANG));
+   logbuf_assert("Missing type substatement for union type.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module cc {namespace urn:cc;prefix cc;typedef mytype {type union{type int8; type string;}}"
+    assert_null(lys_parse_mem(ctx, "module cc {namespace urn:cc;prefix cc;typedef mytype {type union{type int8; type string;}}"
                                         "leaf l {type mytype {type string;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid type substatement for the type not directly derived from union built-in type.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module dd {namespace urn:dd;prefix dd;typedef mytype {type union{type int8; type string;}}"
+    assert_null(lys_parse_mem(ctx, "module dd {namespace urn:dd;prefix dd;typedef mytype {type union{type int8; type string;}}"
                                         "typedef mytype2 {type mytype {type string;}}leaf l {type mytype2;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Invalid type substatement for the type \"mytype2\" not directly derived from union built-in type.");
 
     *state = NULL;
@@ -2118,7 +2003,6 @@
     /* default is not inherited from union's types */
     assert_non_null(mod = lys_parse_mem(ctx, "module a {namespace urn:a;prefix a; typedef mybasetype {type string;default hello;units xxx;}"
                                         "leaf l {type union {type decimal64 {fraction-digits 2;} type mybasetype;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(1, type->refcount);
@@ -2132,7 +2016,6 @@
 
     assert_non_null(mod = lys_parse_mem(ctx, "module b {namespace urn:b;prefix b; typedef mybasetype {type string;default hello;units xxx;}"
                                         "leaf l {type mybasetype;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(2, type->refcount);
@@ -2142,7 +2025,6 @@
 
     assert_non_null(mod = lys_parse_mem(ctx, "module c {namespace urn:c;prefix c; typedef mybasetype {type string;default hello;units xxx;}"
                                         "leaf l {type mybasetype; default goodbye;units yyy;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(2, type->refcount);
@@ -2153,7 +2035,6 @@
     assert_non_null(mod = lys_parse_mem(ctx, "module d {namespace urn:d;prefix d; typedef mybasetype {type string;default hello;units xxx;}"
                                         "typedef mytype {type mybasetype;}leaf l1 {type mytype; default goodbye;units yyy;}"
                                         "leaf l2 {type mytype;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(4, type->refcount);
@@ -2169,7 +2050,6 @@
 
     assert_non_null(mod = lys_parse_mem(ctx, "module e {namespace urn:e;prefix e; typedef mybasetype {type string;}"
                                         "typedef mytype {type mybasetype; default hello;units xxx;}leaf l {type mytype;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(3, type->refcount);
@@ -2180,7 +2060,6 @@
     /* mandatory leaf does not takes default value from type */
     assert_non_null(mod = lys_parse_mem(ctx, "module f {namespace urn:f;prefix f;typedef mytype {type string; default hello;units xxx;}"
                                         "leaf l {type mytype; mandatory true;}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
     assert_int_equal(LY_TYPE_STRING, type->basetype);
@@ -2197,23 +2076,19 @@
     *state = test_status;
 
     struct ly_ctx *ctx;
-    struct lys_module *mod;
 
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;"
+    assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;"
                                         "container c {status deprecated; leaf l {status current; type string;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("A \"current\" status is in conflict with the parent's \"deprecated\" status.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb;"
+    assert_null(lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb;"
                                         "container c {status obsolete; leaf l {status current; type string;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("A \"current\" status is in conflict with the parent's \"obsolete\" status.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module cc {namespace urn:cc;prefix cc;"
+    assert_null(lys_parse_mem(ctx, "module cc {namespace urn:cc;prefix cc;"
                                         "container c {status obsolete; leaf l {status deprecated; type string;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("A \"deprecated\" status is in conflict with the parent's \"obsolete\" status.");
 
     *state = NULL;
@@ -2231,15 +2106,11 @@
 
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module grp {namespace urn:grp;prefix g; typedef mytype {type string;}"
-                                        "grouping grp {leaf x {type mytype;}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
-
-
+    ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "module grp {namespace urn:grp;prefix g; typedef mytype {type string;} feature f;"
+                              "grouping grp {leaf x {type mytype;} leaf y {type string; if-feature f;}}}");
     assert_non_null(mod = lys_parse_mem(ctx, "module a {namespace urn:a;prefix a;import grp {prefix g;}"
                                         "grouping grp_a_top {leaf a1 {type int8;}}"
                                         "container a {uses grp_a; uses grp_a_top; uses g:grp; grouping grp_a {leaf a2 {type uint8;}}}}", LYS_IN_YANG));
-    assert_int_equal(LY_SUCCESS, lys_compile(mod, 0));
     assert_non_null((parent = mod->compiled->data));
     assert_int_equal(LYS_CONTAINER, parent->nodetype);
     assert_non_null((child = ((struct lysc_node_container*)parent)->child));
@@ -2251,32 +2122,209 @@
     assert_non_null((child = child->next));
     assert_string_equal("x", child->name);
     assert_ptr_equal(mod, child->module);
+    assert_non_null((child = child->next));
+    assert_string_equal("y", child->name);
+    assert_non_null(child->iffeatures);
+    assert_int_equal(1, LY_ARRAY_SIZE(child->iffeatures));
+    assert_int_equal(1, LY_ARRAY_SIZE(child->iffeatures[0].features));
+    assert_string_equal("f", child->iffeatures[0].features[0]->name);
+    assert_int_equal(LY_EINVAL, lys_feature_enable(mod->compiled->imports[0].module, "f"));
+    logbuf_assert("Module \"grp\" is not implemented so all its features are permanently disabled without a chance to change it.");
+    assert_int_equal(0, lysc_iffeature_value(&child->iffeatures[0]));
+
+    /* make the imported module implemented and enable the feature */
+    assert_non_null(mod = ly_ctx_get_module(ctx, "grp", NULL));
+    assert_int_equal(LY_SUCCESS, ly_ctx_module_implement(ctx, mod));
+    assert_int_equal(LY_SUCCESS, lys_feature_enable(mod, "f"));
+    assert_string_equal("f", child->iffeatures[0].features[0]->name);
+    assert_int_equal(1, lysc_iffeature_value(&child->iffeatures[0]));
+
+    ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "submodule bsub {belongs-to b {prefix b;} grouping grp {leaf b {type string;}}}");
+    assert_non_null(mod = lys_parse_mem(ctx, "module b {namespace urn:b;prefix b;include bsub;uses grp;}", LYS_IN_YANG));
+    assert_non_null(mod->compiled->data);
+    assert_int_equal(LYS_LEAF, mod->compiled->data->nodetype);
+    assert_string_equal("b", mod->compiled->data->name);
+
+    logbuf_clean();
+    assert_non_null(mod = lys_parse_mem(ctx, "module c {namespace urn:ii;prefix ii;"
+                                        "grouping grp {leaf l {type string;}leaf k {type string; status obsolete;}}"
+                                        "uses grp {status deprecated;}}", LYS_IN_YANG));
+    assert_int_equal(LYS_LEAF, mod->compiled->data->nodetype);
+    assert_string_equal("l", mod->compiled->data->name);
+    assert_true(LYS_STATUS_DEPRC & mod->compiled->data->flags);
+    assert_int_equal(LYS_LEAF, mod->compiled->data->next->nodetype);
+    assert_string_equal("k", mod->compiled->data->next->name);
+    assert_true(LYS_STATUS_OBSLT & mod->compiled->data->next->flags);
+    logbuf_assert(""); /* no warning about inheriting deprecated flag from uses */
 
     /* invalid */
-    assert_non_null(mod = lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;uses missinggrp;}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;uses missinggrp;}", LYS_IN_YANG));
     logbuf_assert("Grouping \"missinggrp\" referenced by a uses statement not found.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb;uses grp;"
+    assert_null(lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb;uses grp;"
                                         "grouping grp {leaf a{type string;}uses grp1;}"
                                         "grouping grp1 {leaf b {type string;}uses grp2;}"
                                         "grouping grp2 {leaf c {type string;}uses grp;}}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Grouping \"grp\" references itself through a uses statement.");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module cc {namespace urn:cc;prefix cc;uses a:missingprefix;}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
+    assert_null(lys_parse_mem(ctx, "module cc {namespace urn:cc;prefix cc;uses a:missingprefix;}", LYS_IN_YANG));
     logbuf_assert("Invalid prefix used for grouping reference (a:missingprefix).");
 
-    assert_non_null(mod = lys_parse_mem(ctx, "module dd {namespace urn:dd;prefix dd;grouping grp{leaf a{type string;}}"
+    assert_null(lys_parse_mem(ctx, "module dd {namespace urn:dd;prefix dd;grouping grp{leaf a{type string;}}"
                                         "leaf a {type string;}uses grp;}", LYS_IN_YANG));
-    assert_int_equal(LY_EVALID, lys_compile(mod, 0));
     logbuf_assert("Duplicate identifier \"a\" of data definition statement.");
 
+    assert_null(lys_parse_mem(ctx, "module ee {namespace urn:ee;prefix ee;grouping grp {leaf l {type string; status deprecated;}}"
+                                        "uses grp {status obsolete;}}", LYS_IN_YANG));
+    logbuf_assert("A \"deprecated\" status is in conflict with the parent's \"obsolete\" status.");
+
     *state = NULL;
     ly_ctx_destroy(ctx, NULL);
 }
 
+static void
+test_refine(void **state)
+{
+    *state = test_refine;
+
+    struct ly_ctx *ctx;
+    struct lys_module *mod;
+    struct lysc_node *parent, *child;
+
+    assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
+
+    assert_non_null(lys_parse_mem(ctx, "module grp {yang-version 1.1;namespace urn:grp;prefix g; feature f;typedef mytype {type string; default cheers!;}"
+                                       "grouping grp {container c {leaf l {type mytype; default goodbye;}"
+                                       "leaf-list ll {type mytype; default goodbye; max-elements 6;}"
+                                       "choice ch {default a; leaf a {type int8;}leaf b{type uint8;}}"
+                                       "leaf x {type mytype; mandatory true; must 1;}"
+                                       "anydata a {mandatory false; if-feature f; description original; reference original;}"
+                                       "container c {config false; leaf l {type string;}}}}}", LYS_IN_YANG));
+
+    assert_non_null(mod = lys_parse_mem(ctx, "module a {yang-version 1.1;namespace urn:a;prefix a;import grp {prefix g;}feature fa;"
+                                        "uses g:grp {refine c/l {default hello; config false;}"
+                                        "refine c/ll {default hello;default world; min-elements 2; max-elements 5;}"
+                                        "refine c/ch {default b;config true; if-feature fa;}"
+                                        "refine c/x {mandatory false; must ../ll;description refined; reference refined;}"
+                                        "refine c/a {mandatory true; must 1; if-feature fa;description refined; reference refined;}"
+                                        "refine c/c {config true;presence indispensable;}}}", LYS_IN_YANG));
+    assert_non_null((parent = mod->compiled->data));
+    assert_int_equal(LYS_CONTAINER, parent->nodetype);
+    assert_string_equal("c", parent->name);
+    assert_non_null((child = ((struct lysc_node_container*)parent)->child));
+    assert_int_equal(LYS_LEAF, child->nodetype);
+    assert_string_equal("l", child->name);
+    assert_string_equal("hello", ((struct lysc_node_leaf*)child)->dflt);
+    assert_int_equal(LYS_CONFIG_R, child->flags & LYS_CONFIG_MASK);
+    assert_non_null(child = child->next);
+    assert_int_equal(LYS_LEAFLIST, child->nodetype);
+    assert_string_equal("ll", child->name);
+    assert_int_equal(2, LY_ARRAY_SIZE(((struct lysc_node_leaflist*)child)->dflts));
+    assert_string_equal("hello", ((struct lysc_node_leaflist*)child)->dflts[0]);
+    assert_string_equal("world", ((struct lysc_node_leaflist*)child)->dflts[1]);
+    assert_int_equal(2, ((struct lysc_node_leaflist*)child)->min);
+    assert_int_equal(5, ((struct lysc_node_leaflist*)child)->max);
+    assert_non_null(child = child->next);
+    assert_int_equal(LYS_CHOICE, child->nodetype);
+    assert_string_equal("ch", child->name);
+    assert_string_equal("b", ((struct lysc_node_choice*)child)->dflt->name);
+    assert_true(LYS_SET_DFLT & ((struct lysc_node_choice*)child)->dflt->flags);
+    assert_false(LYS_SET_DFLT & ((struct lysc_node_choice*)child)->cases[0].flags);
+    assert_non_null(child->iffeatures);
+    assert_int_equal(1, LY_ARRAY_SIZE(child->iffeatures));
+    assert_non_null(child = child->next);
+    assert_int_equal(LYS_LEAF, child->nodetype);
+    assert_string_equal("x", child->name);
+    assert_false(LYS_MAND_TRUE & child->flags);
+    assert_string_equal("cheers!", ((struct lysc_node_leaf*)child)->dflt);
+    assert_non_null(((struct lysc_node_leaf*)child)->musts);
+    assert_int_equal(2, LY_ARRAY_SIZE(((struct lysc_node_leaf*)child)->musts));
+    assert_string_equal("refined", child->dsc);
+    assert_string_equal("refined", child->ref);
+    assert_non_null(child = child->next);
+    assert_int_equal(LYS_ANYDATA, child->nodetype);
+    assert_string_equal("a", child->name);
+    assert_true(LYS_MAND_TRUE & child->flags);
+    assert_non_null(((struct lysc_node_anydata*)child)->musts);
+    assert_int_equal(1, LY_ARRAY_SIZE(((struct lysc_node_anydata*)child)->musts));
+    assert_non_null(child->iffeatures);
+    assert_int_equal(2, LY_ARRAY_SIZE(child->iffeatures));
+    assert_string_equal("refined", child->dsc);
+    assert_string_equal("refined", child->ref);
+    assert_non_null(child = child->next);
+    assert_int_equal(LYS_CONTAINER, child->nodetype);
+    assert_string_equal("c", child->name);
+    assert_true(LYS_PRESENCE & child->flags);
+    assert_true(LYS_CONFIG_W & child->flags);
+    assert_true(LYS_CONFIG_W & ((struct lysc_node_container*)child)->child->flags);
+
+    assert_non_null(mod = lys_parse_mem(ctx, "module b {yang-version 1.1;namespace urn:b;prefix b;import grp {prefix g;}"
+                                        "uses g:grp {status deprecated; refine c/x {default hello; mandatory false;}}}", LYS_IN_YANG));
+    assert_non_null((child = ((struct lysc_node_container*)mod->compiled->data)->child->prev->prev->prev));
+    assert_int_equal(LYS_LEAF, child->nodetype);
+    assert_string_equal("x", child->name);
+    assert_false(LYS_MAND_TRUE & child->flags);
+    assert_string_equal("hello", ((struct lysc_node_leaf*)child)->dflt);
+
+    /* invalid */
+    assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;import grp {prefix g;}"
+                                        "uses g:grp {refine c {default hello;}}}", LYS_IN_YANG));
+    logbuf_assert("Invalid refine of default in \"c\" - container cannot hold default value(s).");
+
+    assert_null(lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb;import grp {prefix g;}"
+                                        "uses g:grp {refine c/l {default hello; default world;}}}", LYS_IN_YANG));
+    logbuf_assert("Invalid refine of default in \"c/l\" - leaf cannot hold 2 default values.");
+
+    assert_null(lys_parse_mem(ctx, "module cc {namespace urn:cc;prefix cc;import grp {prefix g;}"
+                                        "uses g:grp {refine c/ll {default hello; default world;}}}", LYS_IN_YANG));
+    logbuf_assert("Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.");
+
+    assert_null(lys_parse_mem(ctx, "module dd {namespace urn:dd;prefix dd;import grp {prefix g;}"
+                                        "uses g:grp {refine c/ll {mandatory true;}}}", LYS_IN_YANG));
+    logbuf_assert("Invalid refine of mandatory in \"c/ll\" - leaf-list cannot hold mandatory statement.");
+
+    assert_null(lys_parse_mem(ctx, "module ee {namespace urn:ee;prefix ee;import grp {prefix g;}"
+                                        "uses g:grp {refine c/l {mandatory true;}}}", LYS_IN_YANG));
+    logbuf_assert("Invalid refine of mandatory in \"c/l\" - leaf already has \"default\" statement.");
+    assert_null(lys_parse_mem(ctx, "module ef {namespace urn:ef;prefix ef;import grp {prefix g;}"
+                                        "uses g:grp {refine c/ch {mandatory true;}}}", LYS_IN_YANG));
+    logbuf_assert("Invalid refine of mandatory in \"c/ch\" - choice already has \"default\" statement.");
+
+    assert_null(lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff;import grp {prefix g;}"
+                                        "uses g:grp {refine c/ch/a/a {mandatory true;}}}", LYS_IN_YANG));
+    logbuf_assert("Invalid refine of mandatory in \"c/ch/a/a\" - leaf under the default case.");
+
+    assert_null(lys_parse_mem(ctx, "module gg {namespace urn:gg;prefix gg;import grp {prefix g;}"
+                                        "uses g:grp {refine c/x {default hello;}}}", LYS_IN_YANG));
+    logbuf_assert("Invalid refine of default in \"c/x\" - the node is mandatory.");
+
+    assert_null(lys_parse_mem(ctx, "module hh {namespace urn:hh;prefix hh;import grp {prefix g;}"
+                                        "uses g:grp {refine c/c/l {config true;}}}", LYS_IN_YANG));
+    logbuf_assert("Invalid refine of config in \"c/c/l\" - configuration node cannot be child of any state data node.");
+
+    assert_null(lys_parse_mem(ctx, "module ii {namespace urn:ii;prefix ii;grouping grp {leaf l {type string; status deprecated;}}"
+                                        "uses grp {status obsolete;}}", LYS_IN_YANG));
+    logbuf_assert("A \"deprecated\" status is in conflict with the parent's \"obsolete\" status.");
+
+    assert_null(lys_parse_mem(ctx, "module jj {namespace urn:jj;prefix jj;import grp {prefix g;}"
+                                        "uses g:grp {refine c/x {presence nonsence;}}}", LYS_IN_YANG));
+    logbuf_assert("Invalid refine of presence statement in \"c/x\" - leaf cannot hold the presence statement.");
+
+    assert_null(lys_parse_mem(ctx, "module kk {namespace urn:kk;prefix kk;import grp {prefix g;}"
+                                        "uses g:grp {refine c/ch {must 1;}}}", LYS_IN_YANG));
+    logbuf_assert("Invalid refine of must statement in \"c/ch\" - choice cannot hold any must statement.");
+
+    assert_null(lys_parse_mem(ctx, "module ll {namespace urn:ll;prefix ll;import grp {prefix g;}"
+                                        "uses g:grp {refine c/x {min-elements 1;}}}", LYS_IN_YANG));
+    logbuf_assert("Invalid refine of min-elements statement in \"c/x\" - leaf cannot hold this statement.");
+
+    assert_null(lys_parse_mem(ctx, "module mm {namespace urn:mm;prefix mm;import grp {prefix g;}"
+                                        "uses g:grp {refine c/ll {min-elements 10;}}}", LYS_IN_YANG));
+    logbuf_assert("Invalid refine of min-elements statement in \"c/ll\" - \"min-elements\" is bigger than \"max-elements\".");
+
+    *state = NULL;
+    ly_ctx_destroy(ctx, NULL);
+}
 
 int main(void)
 {
@@ -2303,6 +2351,7 @@
         cmocka_unit_test_setup_teardown(test_node_choice, logger_setup, logger_teardown),
         cmocka_unit_test_setup_teardown(test_node_anydata, logger_setup, logger_teardown),
         cmocka_unit_test_setup_teardown(test_uses, logger_setup, logger_teardown),
+        cmocka_unit_test_setup_teardown(test_refine, logger_setup, logger_teardown),
     };
 
     return cmocka_run_group_tests(tests, NULL, NULL);
diff --git a/tests/src/test_tree_schema_helpers.c b/tests/src/test_tree_schema_helpers.c
index 1c5ca3d..c3b3e50 100644
--- a/tests/src/test_tree_schema_helpers.c
+++ b/tests/src/test_tree_schema_helpers.c
@@ -17,6 +17,7 @@
 #include "../../src/set.c"
 #include "../../src/parser_yang.c"
 #include "../../src/tree_schema.c"
+#include "../../src/tree_schema_compile.c"
 #include "../../src/tree_schema_free.c"
 #include "../../src/tree_schema_helpers.c"
 #include "../../src/hash_table.c"