Merge remote-tracking branch 'upstream/libyang2' into libyang2
diff --git a/src/common.h b/src/common.h
index 3a550b8..2be4a20 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
@@ -444,7 +444,7 @@
  *
  * @param[in] CTX libyang context for logging.
  * @param[in,out] ARRAY Pointer to the array to create.
- * @param[in] SIZE Number of items the array is supposed to hold. The size of the allocated
+ * @param[in] SIZE Number of the new items the array is supposed to hold. The size of the allocated
  * space is then counted from the type of the ARRAY, so do not provide placeholder void pointers.
  * @param[out] RET Variable to store error code.
  * @param[in] GOTO Label to go in case of error (memory allocation failure).
diff --git a/src/context.c b/src/context.c
index 66b62e5..10542c0 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,59 @@
 
     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;
                 }
             }
         }
     }
 }
 
+LY_ERR
+ly_ctx_module_implement_internal(struct ly_ctx *ctx, struct lys_module *mod, uint8_t value)
+{
+    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 = value;
+
+    /* compile the schema */
+    LY_CHECK_RET(lys_compile(mod, LYSC_OPT_INTERNAL));
+
+    return LY_SUCCESS;
+}
+
+API LY_ERR
+ly_ctx_module_implement(struct ly_ctx *ctx, struct lys_module *mod)
+{
+    return ly_ctx_module_implement_internal(ctx, mod, 1);
+}
+
 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..cb78110 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 */
@@ -517,14 +517,14 @@
  *         LYS_SET_LENGTH   | | | | | | | | | | | | | | | | | | | | | |x|
  *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  *       6 LYS_MAND_TRUE    | |x|x| | |x| | | | | | | | | | | |x| |x| | |
- *         LYS_ORDBY_SYSTEM | | | |x|x| | | | | | | | | | | | | | | | | |
  *         LYS_SET_PATH     | | | | | | | | | | | | | | | | | | | | | |x|
  *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  *       7 LYS_MAND_FALSE   | |x|x| | |x| | | | | | | | | | | |x| |x| | |
  *         LYS_ORDBY_USER   | | | |x|x| | | | | | | | | | | | | | | | | |
  *         LYS_SET_PATTERN  | | | | | | | | | | | | | | | | | | | | | |x|
  *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *       8 LYS_YINELEM_TRUE | | | | | | | | | | | | | |x| | | | | | | | |
+ *       8 LYS_ORDBY_SYSTEM | | | |x|x| | | | | | | | | | | | | | | | | |
+ *         LYS_YINELEM_TRUE | | | | | | | | | | | | | |x| | | | | | | | |
  *         LYS_SET_RANGE    | | | | | | | | | | | | | | | | | | | | | |x|
  *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  *       9 LYS_YINELEM_FALSE| | | | | | | | | | | | | |x| | | | | | | | |
@@ -564,12 +564,12 @@
  *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  *       5 LYS_STATUS_OBSLT |x|x|x|x|x|x|x|x|x| | |x|x|x|
  *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *       6 LYS_MAND_TRUE    | |x|x| | |x| | | | | | | | |
- *         LYS_ORDBY_SYSTEM | | | |x|x| | | | | | | | | |
+ *       6 LYS_MAND_TRUE    |x|x|x|x|x|x| | | | | | | | |
  *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  *       7 LYS_ORDBY_USER   | | | |x|x| | | | | | | | | |
  *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *       8 LYS_PRESENCE     |x| | | | | | | | | | | | | |
+ *       8 LYS_ORDBY_SYSTEM | | | |x|x| | | | | | | | | |
+ *         LYS_PRESENCE     |x| | | | | | | | | | | | | |
  *         LYS_UNIQUE       | | |x| | | | | | | | | | | |
  *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  *       9 LYS_KEY          | | |x| | | | | | | | | | | |
@@ -593,16 +593,17 @@
 #define LYS_STATUS_OBSLT 0x10        /**< status obsolete; */
 #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 */
+                                          ::lysp_node_leaf/::lysc_node_leaf and ::lysp_node_anydata/::lysc_node_anydata.
+                                          The ::lysc_node_leaflist and ::lysc_node_leaflist have this flag in case that min-elements > 0.
+                                          The ::lysc_node_container has this flag if it is not a presence container and it has at least one
+                                          child with LYS_MAND_TRUE. */
+#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 */
 #define LYS_KEY          0x100       /**< flag for leafs being a key of a list, applicable only to ::lysc_node_leaf */
 #define LYS_FENABLED     0x100       /**< feature enabled flag, applicable only to ::lysc_feature */
-#define LYS_ORDBY_SYSTEM 0x20        /**< ordered-by user lists, applicable only to ::lysc_node_leaflist/::lysp_node_leaflist and
+#define LYS_ORDBY_SYSTEM 0x80        /**< ordered-by user lists, applicable only to ::lysc_node_leaflist/::lysp_node_leaflist and
                                           ::lysc_node_list/::lysp_node_list */
 #define LYS_ORDBY_USER   0x40        /**< ordered-by user lists, applicable only to ::lysc_node_leaflist/::lysp_node_leaflist and
                                           ::lysc_node_list/::lysp_node_list */
@@ -624,12 +625,12 @@
 #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. */
 
-#define LYS_FLAGS_COMPILED_MASK 0x7f /**< mask for flags that maps to the compiled structures */
+#define LYS_FLAGS_COMPILED_MASK 0xff /**< mask for flags that maps to the compiled structures */
 /** @} */
 
 /**
@@ -868,24 +869,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 +887,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,8 +976,11 @@
  */
 struct lysc_when {
     struct lyxp_expr *cond;          /**< XPath when condition */
-    struct lysc_node *context;       /**< context node of the expression */
+    const char *dsc;                 /**< description */
+    const char *ref;                 /**< reference */
+    struct lysc_node *context;       /**< context node for evaluating the expression */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+    uint32_t refcount;               /**< reference counter since some of the when statements are shared among several nodes */
 };
 
 /**
@@ -968,6 +988,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 +1001,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 +1032,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 +1043,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 +1053,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 +1065,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 +1074,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 +1089,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 +1098,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 +1107,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 +1122,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 +1133,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 +1142,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 +1150,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 +1165,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 +1173,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 */
@@ -1142,6 +1182,7 @@
 struct lysc_action {
     uint16_t nodetype;               /**< LYS_ACTION */
     uint16_t flags;                  /**< [schema node flags](@ref snodeflags) */
+    struct lys_module *module;       /**< module structure */
     const char *name;                /**< action/RPC name (mandatory) */
     /* TODO */
 };
@@ -1149,6 +1190,7 @@
 struct lysc_notif {
     uint16_t nodetype;               /**< LYS_NOTIF */
     uint16_t flags;                  /**< [schema node flags](@ref snodeflags) */
+    struct lys_module *module;       /**< module structure */
     const char *name;                /**< Notification name (mandatory) */
     /* TODO */
 };
@@ -1168,8 +1210,10 @@
                                           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_when **when;         /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
     struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
 };
 
@@ -1185,8 +1229,10 @@
                                           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_when **when;         /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
     struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
 
     struct lysc_node *child;         /**< first child node (linked list) */
@@ -1207,8 +1253,10 @@
                                           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_when **when;         /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
     struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
 
     struct lysc_node *child;         /**< first child node of the case (linked list). Note that all the children of all the sibling cases are linked
@@ -1229,8 +1277,10 @@
                                           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_when **when;         /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
     struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
 
     struct lysc_node_case *cases;    /**< list of the cases (linked list). Note that all the children of all the cases are linked each other
@@ -1251,8 +1301,10 @@
                                           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_when **when;         /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
     struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
 
     struct lysc_must *musts;         /**< list of must restrictions ([sized array](@ref sizedarrays)) */
@@ -1274,8 +1326,10 @@
                                           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_when **when;         /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
     struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
 
     struct lysc_must *musts;         /**< list of must restrictions ([sized array](@ref sizedarrays)) */
@@ -1300,8 +1354,10 @@
                                           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_when **when;         /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
     struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
 
     struct lysc_node *child;         /**< first child node (linked list) */
@@ -1327,8 +1383,10 @@
                                           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_when **when;         /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
     struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
 
     struct lysc_must *musts;         /**< list of must restrictions ([sized array](@ref sizedarrays)) */
@@ -1341,12 +1399,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 +1408,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 +1497,36 @@
  * @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;             /**< flag if the module is implemented, not just imported. The module is implemented if
+                                          the flag has non-zero value. Specific values are used internally:
+                                          1 - implemented module
+                                          2 - recently implemented module by dependency, it can be reverted in rollback procedure */
+    uint8_t latest_revision;         /**< 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 +1623,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..9f8d3e7 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -60,10 +60,19 @@
         LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
     }
 
+#define COMPILE_MEMBER_ARRAY_GOTO(CTX, MEMBER_P, ARRAY_C, OPTIONS, FUNC, RET, GOTO) \
+    if (MEMBER_P) { \
+        LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, 1, RET, GOTO); \
+        size_t __array_offset = LY_ARRAY_SIZE(ARRAY_C); \
+        LY_ARRAY_INCREMENT(ARRAY_C); \
+        RET = FUNC(CTX, MEMBER_P, OPTIONS, &(ARRAY_C)[__array_offset]); \
+        LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
+    }
+
 #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; \
             } \
@@ -79,6 +88,14 @@
     return NULL;
 }
 
+/**
+ * @brief Duplicate the compiled pattern structure.
+ *
+ * Instead of duplicating memory, the reference counter in the @p orig is increased.
+ *
+ * @param[in] orig The pattern structure to duplicate.
+ * @return The duplicated structure to use.
+ */
 static struct lysc_pattern*
 lysc_pattern_dup(struct lysc_pattern *orig)
 {
@@ -86,12 +103,24 @@
     return orig;
 }
 
+/**
+ * @brief Duplicate the array of compiled patterns.
+ *
+ * The sized array itself is duplicated, but the pattern structures are just shadowed by increasing their reference counter.
+ *
+ * @param[in] ctx Libyang context for logging.
+ * @param[in] orig The patterns sized array to duplicate.
+ * @return New sized array as a copy of @p orig.
+ * @return NULL in case of memory allocation error.
+ */
 static struct lysc_pattern**
 lysc_patterns_dup(struct ly_ctx *ctx, struct lysc_pattern **orig)
 {
     struct lysc_pattern **dup = NULL;
     unsigned int u;
 
+    assert(orig);
+
     LY_ARRAY_CREATE_RET(ctx, dup, LY_ARRAY_SIZE(orig), NULL);
     LY_ARRAY_FOR(orig, u) {
         dup[u] = lysc_pattern_dup(orig[u]);
@@ -100,12 +129,22 @@
     return dup;
 }
 
+/**
+ * @brief Duplicate compiled range structure.
+ *
+ * @param[in] ctx Libyang context for logging.
+ * @param[in] orig The range structure to be duplicated.
+ * @return New compiled range structure as a copy of @p orig.
+ * @return NULL in case of memory allocation error.
+ */
 struct lysc_range*
 lysc_range_dup(struct ly_ctx *ctx, const struct lysc_range *orig)
 {
     struct lysc_range *dup;
     LY_ERR ret;
 
+    assert(orig);
+
     dup = calloc(1, sizeof *dup);
     LY_CHECK_ERR_RET(!dup, LOGMEM(ctx), NULL);
     if (orig->parts) {
@@ -124,12 +163,22 @@
     return NULL;
 }
 
+/**
+ * @brief Stack for processing if-feature expressions.
+ */
 struct iff_stack {
-    int size;
-    int index;     /* first empty item */
-    uint8_t *stack;
+    int size;      /**< number of items in the stack */
+    int index;     /**< first empty item */
+    uint8_t *stack;/**< stack - array of @ref ifftokens to create the if-feature expression in prefix format */
 };
 
+/**
+ * @brief Add @ref ifftokens into the stack.
+ * @param[in] stack The if-feature stack to use.
+ * @param[in] value One of the @ref ifftokens to store in the stack.
+ * @return LY_EMEM in case of memory allocation error
+ * @return LY_ESUCCESS if the value successfully stored.
+ */
 static LY_ERR
 iff_stack_push(struct iff_stack *stack, uint8_t value)
 {
@@ -142,13 +191,24 @@
     return LY_SUCCESS;
 }
 
+/**
+ * @brief Get (and remove) the last item form the stack.
+ * @param[in] stack The if-feature stack to use.
+ * @return The value from the top of the stack.
+ */
 static uint8_t
 iff_stack_pop(struct iff_stack *stack)
 {
+    assert(stack && stack->index);
+
     stack->index--;
     return stack->stack[stack->index];
 }
 
+/**
+ * @brief Clean up the stack.
+ * @param[in] stack The if-feature stack to use.
+ */
 static void
 iff_stack_clean(struct iff_stack *stack)
 {
@@ -156,6 +216,13 @@
     free(stack->stack);
 }
 
+/**
+ * @brief Store the @ref ifftokens (@p op) on the given position in the 2bits array
+ * (libyang format of the if-feature expression).
+ * @param[in,out] list The 2bits array to modify.
+ * @param[in] op The operand (@ref ifftokens) to store.
+ * @param[in] pos Position (0-based) where to store the given @p op.
+ */
 static void
 iff_setop(uint8_t *list, uint8_t op, int pos)
 {
@@ -171,19 +238,34 @@
     *item = (*item) | (op << 2 * (pos % 4));
 }
 
-#define LYS_IFF_LP 0x04 /* ( */
-#define LYS_IFF_RP 0x08 /* ) */
+#define LYS_IFF_LP 0x04 /**< Additional, temporary, value of @ref ifftokens: ( */
+#define LYS_IFF_RP 0x08 /**< Additional, temporary, value of @ref ifftokens: ) */
 
+/**
+ * @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 +274,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 +311,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 */
@@ -241,6 +329,14 @@
     return LY_SUCCESS;
 }
 
+/**
+ * @brief Compile information from the if-feature statement
+ * @param[in] ctx Compile context.
+ * @param[in] value The if-feature argument to process. It is pointer-to-pointer-to-char just to unify the compile functions.
+ * @param[in] options Various options to modify compiler behavior, see [compile flags](@ref scflags).
+ * @param[in,out] iff Prepared (empty) compiled if-feature structure to fill.
+ * @return LY_ERR value.
+ */
 static LY_ERR
 lys_compile_iffeature(struct lysc_ctx *ctx, const char **value, int UNUSED(options), struct lysc_iffeature *iff)
 {
@@ -314,7 +410,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 +478,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--;
@@ -414,20 +508,40 @@
     return rc;
 }
 
+/**
+ * @brief Compile information from the when statement
+ * @param[in] ctx Compile context.
+ * @param[in] when_p The parsed when statement structure.
+ * @param[in] options Various options to modify compiler behavior, see [compile flags](@ref scflags).
+ * @param[out] when Pointer where to store pointer to the created compiled when structure.
+ * @return LY_ERR value.
+ */
 static LY_ERR
-lys_compile_when(struct lysc_ctx *ctx, struct lysp_when *when_p, int options, struct lysc_when *when)
+lys_compile_when(struct lysc_ctx *ctx, struct lysp_when *when_p, int options, struct lysc_when **when)
 {
     unsigned int u;
     LY_ERR ret = LY_SUCCESS;
 
-    when->cond = lyxp_expr_parse(ctx->ctx, when_p->cond);
-    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);
+    *when = calloc(1, sizeof **when);
+    (*when)->refcount = 1;
+    (*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);
 
 done:
     return ret;
 }
 
+/**
+ * @brief Compile information from the must statement
+ * @param[in] ctx Compile context.
+ * @param[in] must_p The parsed must statement structure.
+ * @param[in] options Various options to modify compiler behavior, see [compile flags](@ref scflags).
+ * @param[in,out] must Prepared (empty) compiled must structure to fill.
+ * @return LY_ERR value.
+ */
 static LY_ERR
 lys_compile_must(struct lysc_ctx *ctx, struct lysp_restr *must_p, int options, struct lysc_must *must)
 {
@@ -439,18 +553,27 @@
 
     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:
     return ret;
 }
 
+/**
+ * @brief Compile information from the import statement
+ * @param[in] ctx Compile context.
+ * @param[in] imp_p The parsed import statement structure.
+ * @param[in] options Various options to modify compiler behavior, see [compile flags](@ref scflags).
+ * @param[in,out] imp Prepared (empty) compiled import structure to fill.
+ * @return LY_ERR value.
+ */
 static LY_ERR
 lys_compile_import(struct lysc_ctx *ctx, struct lysp_import *imp_p, int options, struct lysc_import *imp)
 {
     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 +584,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;
             }
         }
@@ -485,6 +607,18 @@
     return ret;
 }
 
+/**
+ * @brief Compile information from the identity statement
+ *
+ * The backlinks to the identities derived from this one are supposed to be filled later via lys_compile_identity_bases().
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] ident_p The parsed identity statement structure.
+ * @param[in] options Various options to modify compiler behavior, see [compile flags](@ref scflags).
+ * @param[in] idents List of so far compiled identities to check the name uniqueness.
+ * @param[in,out] ident Prepared (empty) compiled identity structure to fill.
+ * @return LY_ERR value.
+ */
 static LY_ERR
 lys_compile_identity(struct lysc_ctx *ctx, struct lysp_ident *ident_p, int options, struct lysc_ident *idents, struct lysc_ident *ident)
 {
@@ -493,6 +627,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);
@@ -503,6 +639,59 @@
 }
 
 /**
+ * @brief Check circular dependency of identities - identity MUST NOT reference itself (via their base statement).
+ *
+ * The function works in the same way as lys_compile_feature_circular_check() with different structures and error messages.
+ *
+ * @param[in] ctx Compile context for logging.
+ * @param[in] ident The base identity (its derived list is being extended by the identity being currently processed).
+ * @param[in] derived The list of derived identities of the identity being currently processed (not the one provided as @p ident)
+ * @return LY_SUCCESS if everything is ok.
+ * @return LY_EVALID if the identity is derived from itself.
+ */
+static LY_ERR
+lys_compile_identity_circular_check(struct lysc_ctx *ctx, struct lysc_ident *ident, struct lysc_ident **derived)
+{
+    LY_ERR ret = LY_EVALID;
+    unsigned int u, v;
+    struct ly_set recursion = {0};
+    struct lysc_ident *drv;
+
+    if (!derived) {
+        return LY_SUCCESS;
+    }
+
+    for (u = 0; u < LY_ARRAY_SIZE(derived); ++u) {
+        if (ident == derived[u]) {
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                   "Identity \"%s\" is indirectly derived from itself.", ident->name);
+            goto cleanup;
+        }
+        ly_set_add(&recursion, derived[u], 0);
+    }
+
+    for (v = 0; v < recursion.count; ++v) {
+        drv = recursion.objs[v];
+        if (!drv->derived) {
+            continue;
+        }
+        for (u = 0; u < LY_ARRAY_SIZE(drv->derived); ++u) {
+            if (ident == drv->derived[u]) {
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                       "Identity \"%s\" is indirectly derived from itself.", ident->name);
+                goto cleanup;
+            }
+            ly_set_add(&recursion, drv->derived[u], 0);
+        }
+    }
+    ret = LY_SUCCESS;
+
+cleanup:
+    ly_set_erase(&recursion, NULL);
+    return ret;
+}
+
+/**
  * @brief Find and process the referenced base identities from another identity or identityref
  *
  * For bases in identity se backlinks to them from the base identities. For identityref, store
@@ -525,7 +714,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;
@@ -556,6 +745,12 @@
             for (v = 0; v < LY_ARRAY_SIZE(mod->compiled->identities); ++v) {
                 if (!strcmp(name, mod->compiled->identities[v].name)) {
                     if (ident) {
+                        if (ident == &mod->compiled->identities[v]) {
+                            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                                   "Identity \"%s\" is derived from itself.", ident->name);
+                            return LY_EVALID;
+                        }
+                        LY_CHECK_RET(lys_compile_identity_circular_check(ctx, &mod->compiled->identities[v], ident->derived));
                         /* we have match! store the backlink */
                         LY_ARRAY_NEW_RET(ctx->ctx, mod->compiled->identities[v].derived, idref, LY_EMEM);
                         *idref = ident;
@@ -603,42 +798,179 @@
     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 Check circular dependency of features - feature MUST NOT reference itself (via their if-feature statement).
+ *
+ * The function works in the same way as lys_compile_identity_circular_check() with different structures and error messages.
+ *
+ * @param[in] ctx Compile context for logging.
+ * @param[in] feature The feature referenced in if-feature statement (its depfeatures list is being extended by the feature
+ *            being currently processed).
+ * @param[in] depfeatures The list of depending features of the feature being currently processed (not the one provided as @p feature)
+ * @return LY_SUCCESS if everything is ok.
+ * @return LY_EVALID if the feature references indirectly itself.
+ */
+static LY_ERR
+lys_compile_feature_circular_check(struct lysc_ctx *ctx, struct lysc_feature *feature, struct lysc_feature **depfeatures)
+{
+    LY_ERR ret = LY_EVALID;
+    unsigned int u, v;
+    struct ly_set recursion = {0};
+    struct lysc_feature *drv;
+
+    if (!depfeatures) {
+        return LY_SUCCESS;
+    }
+
+    for (u = 0; u < LY_ARRAY_SIZE(depfeatures); ++u) {
+        if (feature == depfeatures[u]) {
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                   "Feature \"%s\" is indirectly referenced from itself.", feature->name);
+            goto cleanup;
+        }
+        ly_set_add(&recursion, depfeatures[u], 0);
+    }
+
+    for (v = 0; v < recursion.count; ++v) {
+        drv = recursion.objs[v];
+        if (!drv->depfeatures) {
+            continue;
+        }
+        for (u = 0; u < LY_ARRAY_SIZE(drv->depfeatures); ++u) {
+            if (feature == drv->depfeatures[u]) {
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                       "Feature \"%s\" is indirectly referenced from itself.", feature->name);
+                goto cleanup;
+            }
+            ly_set_add(&recursion, drv->depfeatures[u], 0);
+        }
+    }
+    ret = LY_SUCCESS;
+
+cleanup:
+    ly_set_erase(&recursion, NULL);
+    return ret;
+}
+
+/**
+ * @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) {
+                        /* check for circular dependency - direct reference first,... */
+                        if (feature == feature->iffeatures[u].features[v]) {
+                            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                                   "Feature \"%s\" is referenced from itself.", feature->name);
+                            return LY_EVALID;
+                        }
+                        /* ... and indirect circular reference */
+                        LY_CHECK_RET(lys_compile_feature_circular_check(ctx, feature->iffeatures[u].features[v], feature->depfeatures));
+
+                        /* 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 */
             }
         }
+    done:
+        return ret;
     }
-done:
-    return ret;
+
+    LOGINT(ctx->ctx);
+    return LY_EINT;
+}
+
+/**
+ * @brief Revert compiled list of features back to the precompiled state.
+ *
+ * Function is needed in case the compilation failed and the schema is expected to revert back to the non-compiled status.
+ * The features are supposed to be stored again as off_features in ::lys_module structure.
+ *
+ * @param[in] ctx Compilation context.
+ * @param[in] mod The module structure still holding the compiled (but possibly not finished, only the list of compiled features is taken) schema
+ * and supposed to hold the off_features list.
+ */
+static void
+lys_feature_precompile_revert(struct lysc_ctx *ctx, struct lys_module *mod)
+{
+    unsigned int u, v;
+
+    /* 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);
+        mod->off_features[u].iffeatures = NULL;
+
+        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);
+        mod->off_features[u].exts = NULL;
+    }
 }
 
 /**
@@ -1123,6 +1455,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,13 +1464,20 @@
         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;
     parts = NULL;
     ret = LY_SUCCESS;
 cleanup:
-    /* TODO clean up */
     LY_ARRAY_FREE(parts);
 
     return ret;
@@ -1396,6 +1736,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 +1799,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 +1808,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 +2003,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 +2021,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 +2129,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 +2399,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 +2653,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 +2730,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 +2808,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 +2825,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 +2849,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 +2863,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 +2991,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 +3002,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.
@@ -2675,8 +3022,12 @@
     unsigned int u;
     LY_ERR ret = LY_SUCCESS;
 
+    if (cont_p->presence) {
+        cont->flags |= LYS_PRESENCE;
+    }
+
     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 +3063,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 +3105,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);
@@ -2766,14 +3119,17 @@
     }
 
     llist->min = llist_p->min;
+    if (llist->min) {
+        llist->flags |= LYS_MAND_TRUE;
+    }
     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 +3144,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;
@@ -2841,10 +3197,13 @@
     LY_ERR ret = LY_SUCCESS;
 
     list->min = list_p->min;
+    if (list->min) {
+        list->flags |= LYS_MAND_TRUE;
+    }
     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 +3248,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,
@@ -2945,7 +3304,7 @@
 
                 /* unique node must be present */
                 LY_ARRAY_NEW_RET(ctx->ctx, *unique, key, LY_EMEM);
-                ret = lys_resolve_descendant_schema_nodeid(ctx, keystr, len, node, LYS_LEAF, (const struct lysc_node**)key);
+                ret = lys_resolve_schema_nodeid(ctx, keystr, len, node, LYS_LEAF, 0, (const struct lysc_node**)key);
                 if (ret != LY_SUCCESS) {
                     if (ret == LY_EDENIED) {
                         LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
@@ -2987,6 +3346,17 @@
     return ret;
 }
 
+/**
+ * @brief Do some checks and set the default choice's case.
+ *
+ * Selects (and stores into ::lysc_node_choice#dflt) the default case and set LYS_SET_DFLT flag on it.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] dflt Name of the default branch. Can contain even the prefix, but it make sense only in case it is the prefix of the module itself,
+ * not the reference to the imported module.
+ * @param[in,out] ch The compiled choice node, its dflt member is filled to point to the default case node of the choice.
+ * @return LY_ERR value.
+ */
 static LY_ERR
 lys_compile_node_choice_dflt(struct lysc_ctx *ctx, const char *dflt, struct lysc_node_choice *ch)
 {
@@ -3003,7 +3373,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 +3394,7 @@
             return LY_EVALID;
         }
     }
-    ch->flags |= LYS_SET_DFLT;
+    ch->dflt->flags |= LYS_SET_DFLT;
     return LY_SUCCESS;
 }
 
@@ -3049,10 +3419,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));
         }
     }
 
@@ -3091,44 +3461,67 @@
     return ret;
 }
 
+/**
+ * @brief Compile status information of the given node.
+ *
+ * To simplify getting status of the node, the flags are set following inheritance rules, so all the nodes
+ * has the status correctly set during the compilation.
+ *
+ * @param[in] ctx Compile context
+ * @param[in,out] node Compiled node which status is supposed to be resolved. If the status was set explicitely on the node, it is already set in the
+ * flags value and we just check the compatibility with the parent's status value.
+ * @param[in] parent_flags Flags of the parent node to check/inherit the status value.
+ * @return LY_ERR value.
+ */
 static LY_ERR
-lys_compile_status_check(struct lysc_ctx *ctx, uint16_t node_flags, uint16_t parent_flags)
+lys_compile_status(struct lysc_ctx *ctx, struct lysc_node *node, uint16_t parent_flags)
 {
-    /* check status compatibility with the parent */
-    if ((parent_flags & LYS_STATUS_MASK) > (node_flags & LYS_STATUS_MASK)) {
-        if (node_flags & LYS_STATUS_CURR) {
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                   "A \"current\" status is in conflict with the parent's \"%s\" status.",
-                   (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
-        } else { /* LYS_STATUS_DEPRC */
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                   "A \"deprecated\" status is in conflict with the parent's \"obsolete\" status.");
-        }
-        return LY_EVALID;
-    }
-    return LY_SUCCESS;
-}
-
-static LY_ERR
-lys_compile_status(struct lysc_ctx *ctx, struct lysc_node *node, struct lysc_node *parent)
-{
-
     /* 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) {
+        /* check status compatibility with the parent */
+        if ((parent_flags & LYS_STATUS_MASK) > (node->flags & LYS_STATUS_MASK)) {
+            if (node->flags & LYS_STATUS_CURR) {
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                       "A \"current\" status is in conflict with the parent's \"%s\" status.",
+                       (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
+            } else { /* LYS_STATUS_DEPRC */
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                       "A \"deprecated\" status is in conflict with the parent's \"obsolete\" status.");
+            }
+            return LY_EVALID;
+        }
     }
     return LY_SUCCESS;
 }
 
+/**
+ * @brief Check uniqness of the node/action/notification name.
+ *
+ * Data nodes, actions/RPCs and Notifications are stored separately (in distinguish lists) in the schema
+ * structures, but they share the namespace so we need to check their name collisions.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] children List (linked list) of data nodes to go through.
+ * @param[in] actions List (sized array) of actions or RPCs to go through.
+ * @param[in] notifs List (sized array) of Notifications to go through.
+ * @param[in] name Name of the item to find in the given lists.
+ * @param[in] exclude Pointer to an object to exclude from the name checking - for the case that the object
+ * with the @p name being checked is already inserted into one of the list so we need to skip it when searching for duplicity.
+ * @return LY_SUCCESS in case of unique name, LY_EEXIST otherwise.
+ */
 static LY_ERR
 lys_compile_node_uniqness(struct lysc_ctx *ctx, const struct lysc_node *children,
                           const struct lysc_action *actions, const struct lysc_notif *notifs,
@@ -3138,17 +3531,17 @@
     unsigned int u;
 
     LY_LIST_FOR(children, iter) {
-        if (iter != exclude && !strcmp(name, iter->name)) {
+        if (iter != exclude && iter->module == ctx->mod && !strcmp(name, iter->name)) {
             goto error;
         }
     }
     LY_ARRAY_FOR(actions, u) {
-        if (&actions[u] != exclude && !strcmp(name, actions[u].name)) {
+        if (&actions[u] != exclude && actions[u].module == ctx->mod && !strcmp(name, actions[u].name)) {
             goto error;
         }
     }
     LY_ARRAY_FOR(notifs, u) {
-        if (&notifs[u] != exclude && !strcmp(name, notifs[u].name)) {
+        if (&notifs[u] != exclude && notifs[u].module == ctx->mod && !strcmp(name, notifs[u].name)) {
             goto error;
         }
     }
@@ -3202,35 +3595,65 @@
     return LY_SUCCESS;
 }
 
+/**
+ * @brief Get the XPath context node for the given schema node.
+ * @param[in] start The schema node where the XPath expression appears.
+ * @return The context node to evaluate XPath expression in given schema node.
+ * @return NULL in case the context node is the root node.
+ */
+static struct lysc_node *
+lysc_xpath_context(struct lysc_node *start)
+{
+    for (; start && !(start->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_ACTION | LYS_NOTIF));
+            start = start->parent);
+    return start;
+}
+
+/**
+ * @brief Prepare the case structure in choice node for the new data node.
+ *
+ * It is able to handle implicit as well as explicit cases and the situation when the case has multiple data nodes and the case was already
+ * created in the choice when the first child was processed.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] node_p Node image from the parsed tree. If the case is explicit, it is the LYS_CASE node, but in case of implicit case,
+ *                   it is the LYS_CHOICE node or LYS_AUGMENT node.
+ * @param[in] options Various options to modify compiler behavior, see [compile flags](@ref scflags).
+ * @param[in] ch The compiled choice structure where the new case structures are created (if needed).
+ * @param[in] child The new data node being part of a case (no matter if explicit or implicit).
+ * @return The case structure where the child node belongs to, NULL in case of error. Note that the child is not connected into the siblings list,
+ * it is linked from the case structure only in case it is its first child.
+ */
 static struct lysc_node_case*
 lys_compile_node_case(struct lysc_ctx *ctx, struct lysp_node *node_p, int options, struct lysc_node_choice *ch, struct lysc_node *child)
 {
     struct lysc_node *iter;
     struct lysc_node_case *cs;
+    struct lysc_when **when;
     unsigned int u;
     LY_ERR ret;
 
-#define UNIQUE_CHECK(NAME) \
+#define UNIQUE_CHECK(NAME, MOD) \
     LY_LIST_FOR((struct lysc_node*)ch->cases, iter) { \
-        if (!strcmp(iter->name, NAME)) { \
+        if (iter->module == MOD && !strcmp(iter->name, NAME)) { \
             LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPIDENT, NAME, "case"); \
             return NULL; \
         } \
     }
 
-    if (node_p->nodetype == LYS_CHOICE) {
-        UNIQUE_CHECK(child->name);
+    if (node_p->nodetype == LYS_CHOICE || node_p->nodetype == LYS_AUGMENT) {
+        UNIQUE_CHECK(child->name, ctx->mod);
 
         /* we have to add an implicit case node into the parent choice */
         cs = calloc(1, sizeof(struct lysc_node_case));
         DUP_STRING(ctx->ctx, child->name, cs->name);
         cs->flags = ch->flags & LYS_STATUS_MASK;
-    } else { /* node_p->nodetype == LYS_CASE */
+    } else if (node_p->nodetype == LYS_CASE) {
         if (ch->cases && (node_p == ch->cases->prev->sp)) {
             /* the case is already present since the child is not its first children */
             return (struct lysc_node_case*)ch->cases->prev;
         }
-        UNIQUE_CHECK(node_p->name);
+        UNIQUE_CHECK(node_p->name, ctx->mod);
 
         /* explicit parent case is not present (this is its first child) */
         cs = calloc(1, sizeof(struct lysc_node_case));
@@ -3238,10 +3661,19 @@
         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);
-        COMPILE_MEMBER_GOTO(ctx, node_p->when, cs->when, options, lys_compile_when, ret, error);
+        /* 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);
+
+        if (node_p->when) {
+            LY_ARRAY_NEW_GOTO(ctx->ctx, cs->when, when, ret, error);
+            ret = lys_compile_when(ctx, node_p->when, options, when);
+            LY_CHECK_GOTO(ret, error);
+            (*when)->context = lysc_xpath_context(ch->parent);
+        }
         COMPILE_ARRAY_GOTO(ctx, node_p->iffeatures, cs->iffeatures, options, u, lys_compile_iffeature, ret, error);
+    } else {
+        LOGINT(ctx->ctx);
+        goto error;
     }
     cs->module = ctx->mod;
     cs->prev = (struct lysc_node*)cs;
@@ -3257,6 +3689,17 @@
 #undef UNIQUE_CHECK
 }
 
+/**
+ * @brief Apply refined config to the refine's target node.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] node Refine's target node.
+ * @param[in] rfn Parsed refine information.
+ * @param[in] inheriting Flag (inverted) to check the refined config compatibility with the node's parent. This is
+ * done only on the node for which the refine was created. The function applies also recursively to apply the config change
+ * to the complete subtree and the test is not needed for the subnodes.
+ * @return LY_ERR value.
+ */
 static LY_ERR
 lys_compile_refine_config(struct lysc_ctx *ctx, struct lysc_node *node, struct lysp_refine *rfn, int inheriting)
 {
@@ -3272,7 +3715,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;
         }
     }
@@ -3290,6 +3734,229 @@
 }
 
 /**
+ * @brief Set LYS_MAND_TRUE flag for the non-presence container parents.
+ *
+ * A non-presence container is mandatory in case it has at least one mandatory children. This function propagate
+ * the flag to such parents from a mandatory children.
+ *
+ * @param[in] parent A schema node to be examined if the mandatory child make it also mandatory.
+ * @param[in] add Flag to distinguish adding the mandatory flag (new mandatory children appeared) or removing the flag
+ * (mandatory children was removed).
+ */
+void
+lys_compile_mandatory_parents(struct lysc_node *parent, int add)
+{
+    struct lysc_node *iter;
+
+    if (add) { /* set flag */
+        for (; parent &&  parent->nodetype == LYS_CONTAINER && !(parent->flags & LYS_MAND_TRUE) && !(parent->flags & LYS_PRESENCE);
+                parent = parent->parent) {
+            parent->flags |= LYS_MAND_TRUE;
+        }
+    } else { /* unset flag */
+        for (; parent && parent->nodetype == LYS_CONTAINER && (parent->flags & LYS_MAND_TRUE); parent = parent->parent) {
+            for (iter = (struct lysc_node*)lysc_node_children(parent); iter; iter = iter->next) {
+                if (iter->flags && LYS_MAND_TRUE) {
+                    /* there is another mandatory node */
+                    return;
+                }
+            }
+            /* unset mandatory flag - there is no mandatory children in the non-presence container */
+            parent->flags &= ~LYS_MAND_TRUE;
+        }
+    }
+}
+
+/**
+ * @brief Internal sorting process for the lys_compile_augment_sort().
+ * @param[in] aug_p The parsed augment structure to insert into the sorter sized array @p result.
+ * @param[in,out] result Sized array to store the sorted list of augments. The array is expected
+ * to be allocated to hold the complete list, its size is just incremented by adding another item.
+ */
+static void
+lys_compile_augment_sort_(struct lysp_augment *aug_p, struct lysp_augment **result)
+{
+    unsigned int v;
+    size_t len;
+
+    len = strlen(aug_p->nodeid);
+    LY_ARRAY_FOR(result, v) {
+        if (strlen(result[v]->nodeid) <= len) {
+            continue;
+        }
+        if (v < LY_ARRAY_SIZE(result)) {
+            /* move the rest of array */
+            memmove(&result[v + 1], &result[v], (LY_ARRAY_SIZE(result) - v) * sizeof *result);
+            break;
+        }
+    }
+    result[v] = aug_p;
+    LY_ARRAY_INCREMENT(result);
+}
+
+/**
+ * @brief Sort augments to apply /a/b before /a/b/c (where the /a/b/c was added by the first augment).
+ *
+ * The sorting is based only on the length of the augment's path since it guarantee the correct order
+ * (it doesn't matter the /a/x is done before /a/b/c from the example above).
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] mod_p Parsed module with the global augments (also augments from the submodules are taken).
+ * @param[in] aug_p Parsed sized array of augments to sort (no matter if global or uses's)
+ * @param[in] inc_p In case of global augments, sized array of module includes (submodules) to get global augments from submodules.
+ * @param[out] augments Resulting sorted sized array of pointers to the augments.
+ * @return LY_ERR value.
+ */
+LY_ERR
+lys_compile_augment_sort(struct lysc_ctx *ctx, struct lysp_augment *aug_p, struct lysp_include *inc_p, struct lysp_augment ***augments)
+{
+    struct lysp_augment **result = NULL;
+    unsigned int u, v;
+    size_t count = 0;
+
+    assert(augments);
+
+    /* get count of the augments in module and all its submodules */
+    if (aug_p) {
+        count += LY_ARRAY_SIZE(aug_p);
+    }
+    LY_ARRAY_FOR(inc_p, u) {
+        if (inc_p[u].submodule->augments) {
+            count += LY_ARRAY_SIZE(inc_p[u].submodule->augments);
+        }
+    }
+
+    if (!count) {
+        *augments = NULL;
+        return LY_SUCCESS;
+    }
+    LY_ARRAY_CREATE_RET(ctx->ctx, result, count, LY_EMEM);
+
+    /* sort by the length of schema-nodeid - we need to solve /x before /x/xy. It is not necessary to group them
+     * together, so there can be even /z/y betwwen them. */
+    LY_ARRAY_FOR(aug_p, u) {
+        lys_compile_augment_sort_(&aug_p[u], result);
+    }
+    LY_ARRAY_FOR(inc_p, u) {
+        LY_ARRAY_FOR(inc_p[u].submodule->augments, v) {
+            lys_compile_augment_sort_(&inc_p[u].submodule->augments[v], result);
+        }
+    }
+
+    *augments = result;
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Compile the parsed augment connecting it into its target.
+ *
+ * It is expected that all the data referenced in path are present - augments are ordered so that augment B
+ * targeting data from augment A is being compiled after augment A. Also the modules referenced in the path
+ * are already implemented and compiled.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] aug_p Parsed augment to compile.
+ * @param[in] options Various options to modify compiler behavior, see [compile flags](@ref scflags).
+ * @param[in] parent Parent node to provide the augment's context. It is NULL for the top level augments and a node holding uses's
+ * children in case of the augmenting uses data.
+ * @return LY_SUCCESS on success.
+ * @return LY_EVALID on failure.
+ */
+LY_ERR
+lys_compile_augment(struct lysc_ctx *ctx, struct lysp_augment *aug_p, int options, const struct lysc_node *parent)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct lysp_node *node_p, *case_node_p;
+    struct lysc_node *target; /* target target of the augment */
+    struct lysc_node *node;
+    struct lysc_node_case *next_case;
+    struct lysc_when **when, *when_shared;
+    int allow_mandatory = 0;
+
+    ret = lys_resolve_schema_nodeid(ctx, aug_p->nodeid, 0, parent,
+                                               LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INOUT | LYS_NOTIF,
+                                               1, (const struct lysc_node**)&target);
+    if (ret != LY_SUCCESS) {
+        if (ret == LY_EDENIED) {
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                   "Augment's %s-schema-nodeid \"%s\" refers to a %s node which is not an allowed augment's target.",
+                   parent ? "descendant" : "absolute", aug_p->nodeid, lys_nodetype2str(target->nodetype));
+        }
+        return LY_EVALID;
+    }
+
+    /* check for mandatory nodes
+     * - new cases augmenting some choice can have mandatory nodes
+     * - mandatory nodes are allowed only in case the augmentation is made conditional with a when statement
+     */
+    if (aug_p->when || target->nodetype == LYS_CHOICE) {
+        allow_mandatory = 1;
+    }
+
+    when_shared = NULL;
+    LY_LIST_FOR(aug_p->child, node_p) {
+        /* check if the subnode can be connected to the found target (e.g. case cannot be inserted into container) */
+        if (!(target->nodetype == LYS_CHOICE && node_p->nodetype == LYS_CASE)
+                && !((target->nodetype & (LYS_CONTAINER | LYS_LIST)) && (node_p->nodetype & (LYS_ACTION | LYS_NOTIF)))
+                && !(node_p->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_CHOICE | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES))) {
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                   "Invalid augment (%s) of %s node which is not allowed to contain %s node \"%s\".",
+                   aug_p->nodeid, lys_nodetype2str(target->nodetype), lys_nodetype2str(node_p->nodetype), node_p->name);
+            return LY_EVALID;
+        }
+
+        /* compile the children */
+        if (node_p->nodetype != LYS_CASE) {
+            LY_CHECK_RET(lys_compile_node(ctx, node_p, options, target, 0));
+        } else {
+            LY_LIST_FOR(((struct lysp_node_case *)node_p)->child, case_node_p) {
+                LY_CHECK_RET(lys_compile_node(ctx, case_node_p, options, target, 0));
+            }
+        }
+
+        /* since the augment node is not present in the compiled tree, we need to pass some of its statements to all its children */
+        if (target->nodetype == LYS_CASE) {
+            /* the compiled node is the last child of the target (but it is a case, so we have to be careful) */
+            next_case = target->next ? (struct lysc_node_case*)target->next : ((struct lysc_node_choice*)target->parent)->cases;
+            for (node = (struct lysc_node*)lysc_node_children(target); node->next && node->next != next_case->child; node = node->next);
+        } else if (target->nodetype == LYS_CHOICE) {
+            /* to pass when statement, we need the last case no matter if it is explicit or implicit case */
+            node = ((struct lysc_node_choice*)target)->cases->prev;
+        } else {
+            /* the compiled node is the last child of the target */
+            node = lysc_node_children(target)->prev;
+        }
+
+        if (!allow_mandatory && (node->flags & LYS_MAND_TRUE)) {
+            node->flags &= ~LYS_MAND_TRUE;
+            lys_compile_mandatory_parents(target, 0);
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                   "Invalid augment (%s) adding mandatory node \"%s\" without making it conditional via when statement.",
+                   aug_p->nodeid, node->name);
+            return LY_EVALID;
+        }
+
+        /* pass augment's when to all the children */
+        if (aug_p->when) {
+            LY_ARRAY_NEW_GOTO(ctx->ctx, node->when, when, ret, error);
+            if (!when_shared) {
+                ret = lys_compile_when(ctx, aug_p->when, options, when);
+                LY_CHECK_GOTO(ret, error);
+                (*when)->context = lysc_xpath_context(target);
+                when_shared = *when;
+            } else {
+                ++when_shared->refcount;
+                (*when) = when_shared;
+            }
+        }
+    }
+    /* TODO actions, notifications */
+
+error:
+    return ret;
+}
+
+/**
  * @brief Compile parsed uses statement - resolve target grouping and connect its content into parent.
  * If present, also apply uses's modificators.
  *
@@ -3305,7 +3972,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 +3988,10 @@
     struct lys_module *mod, *mod_old;
     struct lysp_refine *rfn;
     LY_ERR ret = LY_EVALID;
+    uint32_t min, max;
+    struct ly_set refined = {0};
+    struct lysc_when **when, *when_shared;
+    struct lysp_augment **augments = NULL;
 
     /* search for the grouping definition */
     found = 0;
@@ -3390,22 +4068,57 @@
     /* 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;
+
+        /* some preparation for applying refines */
+        if (grp->data == node_p) {
+            /* remember the first child */
+            context_node_fake.child = child;
         }
     }
+    when_shared = NULL;
+    LY_LIST_FOR(context_node_fake.child, child) {
+        child->parent = (struct lysc_node*)&context_node_fake;
+
+        /* pass uses's when to all the children */
+        if (uses_p->when) {
+            LY_ARRAY_NEW_GOTO(ctx->ctx, child->when, when, ret, error);
+            if (!when_shared) {
+                LY_CHECK_GOTO(lys_compile_when(ctx, uses_p->when, options, when), error);
+                (*when)->context = lysc_xpath_context(parent);
+                when_shared = *when;
+            } else {
+                ++when_shared->refcount;
+                (*when) = when_shared;
+            }
+        }
+    }
+    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;
+    }
+
+    /* sort and apply augments */
+    LY_CHECK_GOTO(lys_compile_augment_sort(ctx, uses_p->augments, NULL, &augments), error);
+    LY_ARRAY_FOR(augments, u) {
+        LY_CHECK_GOTO(lys_compile_augment(ctx, augments[u], options, (struct lysc_node*)&context_node_fake), error);
+    }
+
+    /* 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_schema_nodeid(ctx, rfn->nodeid, 0, (struct lysc_node*)&context_node_fake, 0, 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 +4133,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 +4153,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 +4192,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 +4201,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)) {
@@ -3479,8 +4212,138 @@
                 }
 
                 node->flags |= LYS_MAND_TRUE;
+                lys_compile_mandatory_parents(node->parent, 1);
             } else {
+                /* make mandatory false */
                 node->flags &= ~LYS_MAND_TRUE;
+                lys_compile_mandatory_parents(node->parent, 0);
+                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;
+                    if (rfn->min) {
+                        node->flags |= LYS_MAND_TRUE;
+                        lys_compile_mandatory_parents(node->parent, 1);
+                    } else {
+                        node->flags &= ~LYS_MAND_TRUE;
+                        lys_compile_mandatory_parents(node->parent, 0);
+                    }
+                }
+                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;
+                    if (rfn->min) {
+                        node->flags |= LYS_MAND_TRUE;
+                        lys_compile_mandatory_parents(node->parent, 1);
+                    } else {
+                        node->flags &= ~LYS_MAND_TRUE;
+                        lys_compile_mandatory_parents(node->parent, 0);
+                    }
+                }
+                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,10 +4355,13 @@
     /* 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);
+    LY_ARRAY_FREE(augments);
 
     return ret;
 }
 
+
 /**
  * @brief Compile parsed schema node information.
  * @param[in] ctx Compile context
@@ -3504,14 +4370,17 @@
  * @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;
     struct lysc_node_case *cs;
+    struct lysc_when **when;
     unsigned int u;
     LY_ERR (*node_compile_spec)(struct lysc_ctx*, struct lysp_node*, int, struct lysc_node*);
 
@@ -3587,33 +4456,49 @@
     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);
-    COMPILE_MEMBER_GOTO(ctx, node_p->when, node->when, options, lys_compile_when, ret, error);
+    DUP_STRING(ctx->ctx, node_p->dsc, node->dsc);
+    DUP_STRING(ctx->ctx, node_p->ref, node->ref);
+    if (node_p->when) {
+        LY_ARRAY_NEW_GOTO(ctx->ctx, node->when, when, ret, error);
+        ret = lys_compile_when(ctx, node_p->when, options, when);
+        LY_CHECK_GOTO(ret, error);
+        (*when)->context = lysc_xpath_context(node);
+    }
     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);
 
     /* nodetype-specific part */
     LY_CHECK_GOTO(node_compile_spec(ctx, node_p, options, node), error);
 
+    /* inherit LYS_MAND_TRUE in parent containers */
+    if (node->flags & LYS_MAND_TRUE) {
+        lys_compile_mandatory_parents(parent, 1);
+    }
+
     /* insert into parent's children */
     if (parent) {
         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;
         }
-        LY_CHECK_RET(lys_compile_node_connect(ctx, parent, node), LY_EVALID);
+        LY_CHECK_RET(lys_compile_node_connect(ctx, parent->nodetype == LYS_CASE ? parent->parent : parent, node), LY_EVALID);
     } else {
         /* top-level element */
         if (!ctx->mod->compiled->data) {
@@ -3650,22 +4535,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)
 {
@@ -3674,47 +4561,73 @@
     struct lysc_type *type, *typeiter;
     struct lysp_module *sp;
     struct lysp_node *node_p;
+    struct lysp_augment **augments = NULL;
+    struct lys_module *m;
     unsigned int u, v;
     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;
+    } 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));
     }
 
+    /* data nodes */
     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);
+    }
+
+    /* augments - sort first to cover augments augmenting other augments */
+    ret = lys_compile_augment_sort(&ctx, sp->augments, sp->includes, &augments);
+    LY_CHECK_GOTO(ret, error);
+    LY_ARRAY_FOR(augments, u) {
+        ret = lys_compile_augment(&ctx, augments[u], options, NULL);
         LY_CHECK_GOTO(ret, error);
     }
     //COMPILE_ARRAY_GOTO(ctx, sp->rpcs, mod_c->rpcs, options, u, lys_compile_action, ret, error);
@@ -3769,19 +4682,47 @@
     }
     ly_set_erase(&ctx.unres, NULL);
     ly_set_erase(&ctx.groupings, NULL);
+    LY_ARRAY_FREE(augments);
 
     if (options & LYSC_OPT_FREE_SP) {
         lysp_module_free(mod->parsed);
         ((struct lys_module*)mod)->parsed = NULL;
     }
 
+    if (!(options & LYSC_OPT_INTERNAL)) {
+        /* remove flag of the modules implemented by dependency */
+        for (u = 0; u < ctx.ctx->list.count; ++u) {
+            m = ctx.ctx->list.objs[u];
+            if (m->implemented == 2) {
+                m->implemented = 1;
+            }
+        }
+    }
+
     ((struct lys_module*)mod)->compiled = mod_c;
     return LY_SUCCESS;
 
 error:
+    lys_feature_precompile_revert(&ctx, mod);
     ly_set_erase(&ctx.unres, NULL);
     ly_set_erase(&ctx.groupings, NULL);
+    LY_ARRAY_FREE(augments);
     lysc_module_free(mod_c, NULL);
-    ((struct lys_module*)mod)->compiled = NULL;
+    mod->compiled = NULL;
+
+    /* revert compilation of modules implemented by dependency */
+    for (u = 0; u < ctx.ctx->list.count; ++u) {
+        m = ctx.ctx->list.objs[u];
+        if (m->implemented == 2) {
+            /* revert features list to the precompiled state */
+            lys_feature_precompile_revert(&ctx, m);
+            /* mark module as imported-only / not-implemented */
+            m->implemented = 0;
+            /* free the compiled version of the module */
+            lysc_module_free(m->compiled, NULL);
+            m->compiled = NULL;
+        }
+    }
+
     return ret;
 }
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index 7dbe83c..aa026f7 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);
@@ -448,10 +479,16 @@
 }
 
 static void
-lysc_when_free(struct ly_ctx *ctx, struct lysc_when *w)
+lysc_when_free(struct ly_ctx *ctx, struct lysc_when **w)
 {
-    lyxp_expr_free(ctx, w->cond);
-    FREE_ARRAY(ctx, w->exts, lysc_ext_instance_free);
+    if (--(*w)->refcount) {
+        return;
+    }
+    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);
+    free(*w);
 }
 
 static void
@@ -460,6 +497,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 +514,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 +525,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 +538,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 +553,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 +563,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 +624,7 @@
         break;
     }
     FREE_ARRAY(ctx, type->exts, lysc_ext_instance_free);
+    FREE_STRING(ctx, type->dflt);
 
     free(type);
 }
@@ -644,8 +694,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 +715,8 @@
 {
     /* common part */
     FREE_STRING(ctx, node->name);
+    FREE_STRING(ctx, node->dsc);
+    FREE_STRING(ctx, node->ref);
 
     /* nodetype-specific part */
     switch(node->nodetype) {
@@ -696,7 +746,7 @@
         LOGINT(ctx);
     }
 
-    FREE_MEMBER(ctx, node->when, lysc_when_free);
+    FREE_ARRAY(ctx, node->when, lysc_when_free);
     FREE_ARRAY(ctx, node->iffeatures, lysc_iffeature_free);
     FREE_ARRAY(ctx, node->exts, lysc_ext_instance_free);
     free(node);
@@ -709,12 +759,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);
@@ -732,6 +777,9 @@
 void
 lysc_module_free(struct lysc_module *module, void (*private_destructor)(const struct lysc_node *node, void *priv))
 {
+    /* TODO use the destructor, this just suppress warning about unused parameter */
+    (void) private_destructor;
+
     if (module) {
         lysc_module_free_(module);
     }
@@ -745,6 +793,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..396b9f7 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -85,47 +85,77 @@
 }
 
 LY_ERR
-lys_resolve_descendant_schema_nodeid(struct lysc_ctx *ctx, const char *nodeid, size_t nodeid_len, const struct lysc_node *context_node,
-                                     int nodetype, const struct lysc_node **target)
+lys_resolve_schema_nodeid(struct lysc_ctx *ctx, const char *nodeid, size_t nodeid_len, const struct lysc_node *context_node,
+                          int nodetype, int implement, const struct lysc_node **target)
 {
     LY_ERR ret = LY_EVALID;
     const char *name, *prefix, *id;
     const struct lysc_node *context;
     size_t name_len, prefix_len;
-    const struct lys_module *mod;
+    const struct lys_module *mod, *context_module;
+    const char *nodeid_type;
 
     assert(nodeid);
-    assert(context_node);
     assert(target);
     *target = NULL;
 
     id = nodeid;
     context = context_node;
+
+    if (context_node) {
+        /* descendant-schema-nodeid */
+        nodeid_type = "descendant";
+        context_module = context_node->module;
+
+        if (*id == '/') {
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                   "Invalid descendant-schema-nodeid value \"%.*s\" - absolute-schema-nodeid used.",
+                   nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
+            return LY_EVALID;
+        }
+    } else {
+        /* absolute-schema-nodeid */
+        nodeid_type = "absolute";
+        context_module = ctx->mod_def;
+
+        if (*id != '/') {
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                   "Invalid absolute-schema-nodeid value \"%.*s\" - missing starting \"/\".",
+                   nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
+            return LY_EVALID;
+        }
+        ++id;
+    }
+
     while (*id && (ret = lys_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len)) == LY_SUCCESS) {
         if (prefix) {
-            mod = lys_module_find_prefix(context_node->module, prefix, prefix_len);
+            mod = lys_module_find_prefix(context_module, prefix, prefix_len);
             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);
+                       "Invalid %s-schema-nodeid value \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
+                       nodeid_type, id - nodeid, nodeid, prefix_len, prefix, context_module->name);
                 return LY_ENOTFOUND;
             }
         } else {
-            mod = context_node->module;
+            mod = context_module;
+        }
+        if (implement && !mod->implemented) {
+            /* make the module implemented */
+            ly_ctx_module_implement_internal(ctx->ctx, (struct lys_module*)mod, 2);
         }
         context = lys_child(context, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
         if (!context) {
             LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                   "Invalid descendant-schema-nodeid value \"%.*s\" - target node not found.", id - nodeid, nodeid);
+                   "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.", nodeid_type, 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);
+                   "Invalid %s-schema-nodeid value \"%.*s\" - missing \"/\" as node-identifier separator.",
+                   nodeid_type, id - nodeid + 1, nodeid);
             return LY_EVALID;
         }
         ++id;
@@ -136,28 +166,30 @@
         if (nodetype && !(context->nodetype & nodetype)) {
             return LY_EDENIED;
         }
+    } else {
+        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+               "Invalid %s-schema-nodeid value \"%.*s\" - unexpected end of expression.",
+               nodeid_type, nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
     }
 
     return ret;
 }
 
 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 +537,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 +548,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 +577,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 +585,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 +634,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 +655,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 +687,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 +715,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 +746,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 +765,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 +804,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 +813,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 +823,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 +841,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 +887,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 +896,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 +906,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;
 }
@@ -893,6 +931,8 @@
         return "anyxml";
     case LYS_ANYDATA:
         return "anydata";
+    case LYS_CASE:
+        return "case";
     default:
         return "unknown";
     }
@@ -1099,10 +1139,12 @@
         return &((struct lysc_node_container*)node)->child;
     case LYS_CHOICE:
         if (((struct lysc_node_choice*)node)->cases) {
-            return &((struct lysc_node_choice*)node)->cases[0].child;
+            return &((struct lysc_node_choice*)node)->cases->child;
         } 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..1d9ff5d 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,26 @@
 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 */
+#define LYSC_OPT_INTERNAL 2          /**< Internal compilation caused by dependency */
+/** @} 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.
@@ -245,21 +267,24 @@
 LY_ERR lys_parse_nodeid(const char **id, const char **prefix, size_t *prefix_len, const char **name, size_t *name_len);
 
 /**
- * @brief Find the node according to the given descendant schema node id.
- * Used in unique, refine and uses's augment statements
+ * @brief Find the node according to the given descendant/absolute schema nodeid.
+ * Used in unique, refine and augment statements.
  *
  * @param[in] ctx Compile context
  * @param[in] nodeid Descendant-schema-nodeid (according to the YANG grammar)
  * @param[in] nodeid_len Length of the given nodeid, if it is not NULL-terminated string.
  * @param[in] context_node Node where the nodeid is specified to correctly resolve prefixes and to start searching.
+ * If no context node is provided, the nodeid is actually expected to be the absolute schema node id and the module
+ * to resolve prefixes and to start searching is taken from ctx's mod_def.
  * @param[in] nodetype Optional (can be 0) restriction for target's nodetype. If target exists, but does not match
- * the given nodetype, LY_EDENIED is returned, but no error message is printed. The value can be even an ORed value to allow
- * multiple nodetypes.
+ * the given nodetype, LY_EDENIED is returned (and target is provided), but no error message is printed.
+ * The value can be even an ORed value to allow multiple nodetypes.
+ * @param[in] implement Flag if the modules mentioned in the nodeid are supposed to be made implemented.
  * @param[out] target Found target node if any.
  * @return LY_ERR values - LY_ENOTFOUND, LY_EVALID, LY_EDENIED or LY_SUCCESS.
  */
-LY_ERR lys_resolve_descendant_schema_nodeid(struct lysc_ctx *ctx, const char *nodeid, size_t nodeid_len, const struct lysc_node *context_node,
-                                            int nodetype, const struct lysc_node **target);
+LY_ERR lys_resolve_schema_nodeid(struct lysc_ctx *ctx, const char *nodeid, size_t nodeid_len, const struct lysc_node *context_node,
+                                 int nodetype, int implement, const struct lysc_node **target);
 
 /**
  * @brief Find the module referenced by prefix in the provided mod.
@@ -279,31 +304,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 +351,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 +432,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 +475,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 +512,35 @@
 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 Make the specific module implemented, use the provided value as flag.
+ *
+ * @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.
+ * @param[in] implemented Flag value for the ::lys_module#implemented item.
+ * @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_internal(struct ly_ctx *ctx, struct lys_module *mod, uint8_t implemented);
 
 /**
  * @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..d0935ad 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,8 +1094,7 @@
     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) \
@@ -1068,6 +1122,7 @@
 
 #undef TEST_DUP
 
+    *state = NULL;
     ly_ctx_destroy(ctx.ctx, NULL);
 }
 
@@ -1253,7 +1308,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 +1315,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 +1375,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 +1382,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 +1453,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 +1460,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 +1536,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 +1551,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 +1558,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 +1614,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 +1621,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 +1681,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 +1688,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 +1735,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 +1742,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 +1801,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 +1808,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 +1857,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 +1864,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) \
@@ -1863,6 +1900,55 @@
     *state = NULL;
     ly_ctx_destroy(ctx.ctx, NULL);
 }
+
+
+static void
+test_augment(void **state)
+{
+    *state = test_augment;
+
+    struct ly_parser_ctx ctx = {0};
+    struct lysp_augment *a = NULL;
+    const char *str;
+
+    assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
+    assert_non_null(ctx.ctx);
+    ctx.line = 1;
+    //ctx.mod_version = 2; /* simulate YANG 1.1 */
+
+    /* invalid cardinality */
+#define TEST_DUP(MEMBER, VALUE1, VALUE2) \
+    str = "l {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
+    assert_int_equal(LY_EVALID, parse_augment(&ctx, &str, NULL, &a)); \
+    logbuf_assert("Duplicate keyword \""MEMBER"\". Line number 1."); \
+    lysp_augment_free(ctx.ctx, a); a = NULL;
+
+    TEST_DUP("description", "text1", "text2");
+    TEST_DUP("reference", "1", "2");
+    TEST_DUP("status", "current", "obsolete");
+    TEST_DUP("when", "true", "false");
+#undef TEST_DUP
+
+    /* full content */
+    str = "/target/nodeid {action x; anydata any;anyxml anyxml; case cs; choice ch;container c;description test;if-feature f;leaf l {type string;}"
+          "leaf-list ll {type string;} list li;notification not;reference test;status current;uses g;when true;m:ext;} ...";
+    assert_int_equal(LY_SUCCESS, parse_augment(&ctx, &str, NULL, &a));
+    assert_non_null(a);
+    assert_int_equal(LYS_AUGMENT, a->nodetype);
+    assert_string_equal("/target/nodeid", a->nodeid);
+    assert_string_equal("test", a->dsc);
+    assert_non_null(a->exts);
+    assert_non_null(a->iffeatures);
+    assert_string_equal("test", a->ref);
+    assert_non_null(a->when);
+    assert_null(a->parent);
+    assert_int_equal(LYS_STATUS_CURR, a->flags);
+    lysp_augment_free(ctx.ctx, a); a = NULL;
+
+    *state = NULL;
+    ly_ctx_destroy(ctx.ctx, NULL);
+}
+
 int main(void)
 {
     const struct CMUnitTest tests[] = {
@@ -1871,8 +1957,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..cfdc33a 100644
--- a/tests/src/test_tree_schema_compile.c
+++ b/tests/src/test_tree_schema_compile.c
@@ -99,9 +99,30 @@
 }
 
 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);
+    FREE_ARRAY(module->ctx, module->off_features, lysc_feature_free);
+
+    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 +133,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 +165,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 +208,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 +287,82 @@
     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.");
 
+    assert_null(lys_parse_mem(ctx.ctx, "module aa{namespace urn:aa; prefix aa; feature f1 {if-feature f2;} feature f2 {if-feature f1;}}", LYS_IN_YANG));
+    logbuf_assert("Feature \"f1\" is indirectly referenced from itself.");
+    assert_null(lys_parse_mem(ctx.ctx, "module ab{namespace urn:ab; prefix ab; feature f1 {if-feature f1;}}", LYS_IN_YANG));
+    logbuf_assert("Feature \"f1\" is referenced from itself.");
+
     /* 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"));
@@ -334,14 +378,12 @@
 
     struct ly_ctx *ctx;
     struct lys_module *mod1, *mod2;
-    const char *mod1_str = "module a {namespace urn:a;prefix a; identity a1;}";
-    const char *mod2_str = "module b {yang-version 1.1;namespace urn:b;prefix b; import a {prefix a;}identity b1; identity b2; identity b3 {base b1; base b:b2; base a:a1;} identity b4 {base b:b1; base b3;}}";
 
     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 = lys_parse_mem(ctx, "module a {namespace urn:a;prefix a; identity a1;}", LYS_IN_YANG));
+    assert_non_null(mod2 = lys_parse_mem(ctx, "module b {yang-version 1.1;namespace urn:b;prefix b; import a {prefix a;}"
+                                         "identity b1; identity b2; identity b3 {base b1; base b:b2; base a:a1;}"
+                                         "identity b4 {base b:b1; base b3;}}", LYS_IN_YANG));
 
     assert_non_null(mod1->compiled);
     assert_non_null(mod1->compiled->identities);
@@ -362,15 +404,26 @@
     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_non_null(mod2 = lys_parse_mem(ctx, "module c {yang-version 1.1;namespace urn:c;prefix c;"
+                                             "identity c2 {base c1;} identity c1;}", LYS_IN_YANG));
+    assert_int_equal(1, LY_ARRAY_SIZE(mod2->compiled->identities[1].derived));
+    assert_ptr_equal(mod2->compiled->identities[1].derived[0], &mod2->compiled->identities[0]);
+
+    assert_null(lys_parse_mem(ctx, "module aa{namespace urn:aa; prefix aa; 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));
+    ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "submodule sbb {belongs-to bb {prefix bb;} identity i1;}");
+    assert_null(lys_parse_mem(ctx, "module bb{namespace urn:bb; prefix bb; include sbb;identity i1;}", LYS_IN_YANG));
     logbuf_assert("Duplicate identifier \"i1\" of identity statement.");
 
+    assert_null(lys_parse_mem(ctx, "module cc{namespace urn:cc; prefix cc; identity i1 {base i2;}}", LYS_IN_YANG));
+    logbuf_assert("Unable to find base (i2) of identity \"i1\".");
+
+    assert_null(lys_parse_mem(ctx, "module dd{namespace urn:dd; prefix dd; identity i1 {base i1;}}", LYS_IN_YANG));
+    logbuf_assert("Identity \"i1\" is derived from itself.");
+    assert_null(lys_parse_mem(ctx, "module de{namespace urn:de; prefix de; identity i1 {base i2;}identity i2 {base i3;}identity i3 {base i1;}}", LYS_IN_YANG));
+    logbuf_assert("Identity \"i1\" is indirectly derived from itself.");
+
     *state = NULL;
     ly_ctx_destroy(ctx, NULL);
 }
@@ -386,7 +439,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 +447,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 +479,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 +498,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 +506,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 +525,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 +532,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 +566,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 +587,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 +610,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 +620,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 +690,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 +705,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 +715,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 +756,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 +764,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 +771,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 +794,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 +806,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 +818,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 +830,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 +842,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 +854,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 +866,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 +878,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 +891,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 +899,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 +930,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 +941,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 +950,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 +959,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 +968,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 +977,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 +988,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 +1000,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 +1010,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 +1020,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 +1032,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 +1051,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 +1063,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 +1074,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 +1142,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 +1155,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 +1166,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 +1177,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 +1201,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 +1224,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 +1261,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 +1305,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 +1325,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 +1358,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 +1401,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 +1413,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 +1435,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 +1475,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 +1494,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 +1515,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 +1532,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 +1541,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 +1648,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 +1668,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 +1682,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 +1702,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 +1716,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 +1730,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 +1743,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 +1753,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 +1918,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 +1949,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 +1961,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 +1976,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 +1989,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 +2022,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 +2035,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 +2044,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 +2054,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 +2069,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 +2079,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 +2095,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;
@@ -2227,19 +2121,15 @@
 
     struct ly_ctx *ctx;
     struct lys_module *mod;
-    struct lysc_node *parent, *child;
+    const struct lysc_node *parent, *child;
 
     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 +2141,349 @@
     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 {when 1; type string;}}}");
+    assert_non_null(mod = lys_parse_mem(ctx, "module b {namespace urn:b;prefix b;include bsub;uses grp {when 2;}}", 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);
+    assert_int_equal(2, LY_ARRAY_SIZE(mod->compiled->data->when));
+
+    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 */
+
+    assert_non_null(mod = lys_parse_mem(ctx, "module d {namespace urn:d;prefix d; grouping grp {container g;}"
+                                        "container top {uses grp {augment g {leaf x {type int8;}}}}}", LYS_IN_YANG));
+    assert_non_null(mod->compiled->data);
+    assert_non_null(child = lysc_node_children(mod->compiled->data));
+    assert_string_equal("g", child->name);
+    assert_non_null(child = lysc_node_children(child));
+    assert_string_equal("x", child->name);
 
     /* 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.");
+
+    assert_null(lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff;grouping grp {leaf l {type string;}}"
+                                        "leaf l {type int8;}uses grp;}", LYS_IN_YANG));
+    logbuf_assert("Duplicate identifier \"l\" of data definition statement.");
+    assert_null(lys_parse_mem(ctx, "module fg {namespace urn:fg;prefix fg;grouping grp {leaf m {type string;}}"
+                                        "uses grp;leaf m {type int8;}}", LYS_IN_YANG));
+    logbuf_assert("Duplicate identifier \"m\" of data definition statement.");
+
+
+    assert_null(lys_parse_mem(ctx, "module gg {namespace urn:gg;prefix gg; grouping grp {container g;}"
+                              "leaf g {type string;}"
+                              "container top {uses grp {augment /g {leaf x {type int8;}}}}}", LYS_IN_YANG));
+    logbuf_assert("Invalid descendant-schema-nodeid value \"/g\" - absolute-schema-nodeid used.");
+
+
     *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);
+}
+
+static void
+test_augment(void **state)
+{
+    *state = test_augment;
+
+    struct ly_ctx *ctx;
+    struct lys_module *mod;
+    const struct lysc_node *node;
+    const struct lysc_node_choice *ch;
+    const struct lysc_node_case *c;
+
+    assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
+
+    ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "module a {namespace urn:a;prefix a; typedef atype {type string;}"
+                              "container top {leaf a {type string;}}}");
+    assert_non_null(lys_parse_mem(ctx, "module b {namespace urn:b;prefix b;import a {prefix a;}"
+                                  "leaf b {type a:atype;}}", LYS_IN_YANG));
+    ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "module c {namespace urn:c;prefix c; import a {prefix a;}"
+                              "augment /a:top/ { container c {leaf c {type a:atype;}}}}");
+    assert_non_null(lys_parse_mem(ctx, "module d {namespace urn:d;prefix d;import a {prefix a;} import c {prefix c;}"
+                                  "augment /a:top/c:c/ { leaf d {type a:atype;} leaf c {type string;}}}", LYS_IN_YANG));
+    assert_non_null((mod = ly_ctx_get_module_implemented(ctx, "a")));
+    assert_non_null(ly_ctx_get_module_implemented(ctx, "b"));
+    assert_non_null(ly_ctx_get_module_implemented(ctx, "c"));
+    assert_non_null(ly_ctx_get_module_implemented(ctx, "d"));
+    assert_non_null(node = mod->compiled->data);
+    assert_string_equal(node->name, "top");
+    assert_non_null(node = lysc_node_children(node));
+    assert_string_equal(node->name, "a");
+    assert_non_null(node = node->next);
+    assert_string_equal(node->name, "c");
+    assert_non_null(node = lysc_node_children(node));
+    assert_string_equal(node->name, "c");
+    assert_non_null(node = node->next);
+    assert_string_equal(node->name, "d");
+    assert_non_null(node = node->next);
+    assert_string_equal(node->name, "c");
+
+    assert_non_null((mod = lys_parse_mem(ctx, "module e {namespace urn:e;prefix e;choice ch {leaf a {type string;}}"
+                                         "augment /ch/c {when 1; leaf lc2 {type uint16;}}"
+                                         "augment /ch { when 1; leaf b {type int8;} case c {leaf lc1 {type uint8;}}}}", LYS_IN_YANG)));
+    assert_non_null((ch = (const struct lysc_node_choice*)mod->compiled->data));
+    assert_null(mod->compiled->data->next);
+    assert_string_equal("ch", ch->name);
+    assert_non_null(c = ch->cases);
+    assert_string_equal("a", c->name);
+    assert_null(c->when);
+    assert_string_equal("a", c->child->name);
+    assert_non_null(c = (const struct lysc_node_case*)c->next);
+    assert_string_equal("b", c->name);
+    assert_non_null(c->when);
+    assert_string_equal("b", c->child->name);
+    assert_non_null(c = (const struct lysc_node_case*)c->next);
+    assert_string_equal("c", c->name);
+    assert_non_null(c->when);
+    assert_string_equal("lc1", ((const struct lysc_node_case*)c)->child->name);
+    assert_null(((const struct lysc_node_case*)c)->child->when);
+    assert_string_equal("lc2", ((const struct lysc_node_case*)c)->child->next->name);
+    assert_non_null(((const struct lysc_node_case*)c)->child->next->when);
+    assert_ptr_equal(ch->cases->child->prev, ((const struct lysc_node_case*)c)->child->next);
+    assert_null(c->next);
+
+    assert_non_null((mod = lys_parse_mem(ctx, "module f {namespace urn:f;prefix f;grouping g {leaf a {type string;}}"
+                                         "container c;"
+                                         "augment /c {uses g;}}", LYS_IN_YANG)));
+    assert_non_null(node = lysc_node_children(mod->compiled->data));
+    assert_string_equal(node->name, "a");
+
+    ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "submodule gsub {belongs-to g {prefix g;}"
+                                  "augment /c {container sub;}}");
+    assert_non_null(mod = lys_parse_mem(ctx, "module g {namespace urn:g;prefix g;include gsub; container c;"
+                                        "augment /c/sub {leaf main {type string;}}}", LYS_IN_YANG));
+    assert_non_null(mod->compiled->data);
+    assert_string_equal("c", mod->compiled->data->name);
+    assert_non_null(node = ((struct lysc_node_container*)mod->compiled->data)->child);
+    assert_string_equal("sub", node->name);
+    assert_non_null(node = ((struct lysc_node_container*)node)->child);
+    assert_string_equal("main", node->name);
+
+    assert_non_null(mod = lys_parse_mem(ctx, "module h {namespace urn:h;prefix h;container top;"
+                                        "augment /top {container p {presence XXX; leaf x {mandatory true;type string;}}}"
+                                        "augment /top {list l {key x;leaf x {type string;}leaf y {mandatory true; type string;}}}}", LYS_IN_YANG));
+    assert_non_null(node = mod->compiled->data);
+    assert_non_null(node = ((struct lysc_node_container*)node)->child);
+    assert_string_equal("p", node->name);
+    assert_non_null(node->next);
+    assert_string_equal("l", node->next->name);
+
+    assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa; container c {leaf a {type string;}}"
+                                        "augment /x {leaf a {type int8;}}}", LYS_IN_YANG));
+    logbuf_assert("Invalid absolute-schema-nodeid value \"/x\" - target node not found.");
+
+    assert_null(lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb; container c {leaf a {type string;}}"
+                                        "augment /c {leaf a {type int8;}}}", LYS_IN_YANG));
+    logbuf_assert("Duplicate identifier \"a\" of data definition statement.");
+
+
+    assert_null(lys_parse_mem(ctx, "module cc {namespace urn:cc;prefix cc; container c {leaf a {type string;}}"
+                                        "augment /c/a {leaf a {type int8;}}}", LYS_IN_YANG));
+    logbuf_assert("Augment's absolute-schema-nodeid \"/c/a\" refers to a leaf node which is not an allowed augment's target.");
+
+    assert_null(lys_parse_mem(ctx, "module dd {namespace urn:dd;prefix dd; container c {leaf a {type string;}}"
+                                        "augment /c {case b {leaf d {type int8;}}}}", LYS_IN_YANG));
+    logbuf_assert("Invalid augment (/c) of container node which is not allowed to contain case node \"b\".");
+
+    assert_null(lys_parse_mem(ctx, "module ee {namespace urn:ee;prefix ee; container top;"
+                                        "augment /top {container c {leaf d {mandatory true; type int8;}}}}", LYS_IN_YANG));
+    logbuf_assert("Invalid augment (/top) adding mandatory node \"c\" without making it conditional via when statement.");
+
+    assert_null(lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff; container top;"
+                                        "augment ../top {leaf x {type int8;}}}", LYS_IN_YANG));
+    logbuf_assert("Invalid absolute-schema-nodeid value \"../top\" - missing starting \"/\".");
+
+    *state = NULL;
+    ly_ctx_destroy(ctx, NULL);
+}
 
 int main(void)
 {
@@ -2303,6 +2510,8 @@
         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),
+        cmocka_unit_test_setup_teardown(test_augment, 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"