Merge branch 'libyang2' of https://github.com/Dajvid/libyang into libyang2
diff --git a/src/common.h b/src/common.h
index 6fc0ae7..2be4a20 100644
--- a/src/common.h
+++ b/src/common.h
@@ -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 ad3abb2..10542c0 100644
--- a/src/context.c
+++ b/src/context.c
@@ -484,8 +484,8 @@
     }
 }
 
-API LY_ERR
-ly_ctx_module_implement(struct ly_ctx *ctx, struct lys_module *mod)
+LY_ERR
+ly_ctx_module_implement_internal(struct ly_ctx *ctx, struct lys_module *mod, uint8_t value)
 {
     struct lys_module *m;
 
@@ -510,14 +510,20 @@
     }
 
     /* mark the module implemented, check for collision was already done */
-    mod->implemented = 1;
+    mod->implemented = value;
 
     /* compile the schema */
-    LY_CHECK_RET(lys_compile(mod, 0));
+    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/parser_yin.c b/src/parser_yin.c
index e8b0333..aa67056 100644
--- a/src/parser_yin.c
+++ b/src/parser_yin.c
@@ -35,55 +35,87 @@
     YIN_ARG_TAG,
 };
 
+LY_ERR
+parse_text_element(struct lyxml_context *xml_ctx, const char **data, const char **value)
+{
+    LY_ERR ret = LY_SUCCESS;
+    char *buf = NULL, *out = NULL;
+    size_t buf_len = 0, out_len = 0;
+    int dynamic;
+
+    const char *prefix, *name;
+    size_t prefix_len, name_len;
+
+
+    if (xml_ctx->status == LYXML_ELEM_CONTENT) {
+        ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
+        LY_CHECK_RET(ret);
+        *value = lydict_insert(xml_ctx->ctx, out, out_len);
+        LY_CHECK_ERR_RET(!(*value), LOGMEM(xml_ctx->ctx), LY_EMEM);
+    }
+
+    LY_CHECK_ERR_RET(xml_ctx->status != LYXML_ELEMENT, "erere", LY_EINT);
+    lyxml_get_element(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
+
+    return 0;
+}
+
+/**
+ * @brief Match argument name.
+ *
+ * @param[in] name String representing name.
+ * @param[in] len Lenght of the name.
+ *
+ * @reurn YIN_ARGUMENT value.
+ */
 enum YIN_ARGUMENT
 match_argument_name(const char *name, size_t len)
 {
     enum YIN_ARGUMENT arg = YIN_ARG_NONE;
     size_t already_read = 0;
 
-#define MOVE_DATA(DATA, COUNT) already_read+=COUNT;
-#define IF_ARG(STR, LEN, STMT) if (!strncmp((name) + already_read, STR, LEN)) {MOVE_DATA(name, LEN);arg=STMT;}
-#define IF_ARG_PREFIX(STR, LEN) if (!strncmp((name) + already_read, STR, LEN)) {MOVE_DATA(name, LEN);
+#define IF_ARG(STR, LEN, STMT) if (!strncmp((name) + already_read, STR, LEN)) {already_read+=LEN;arg=STMT;}
+#define IF_ARG_PREFIX(STR, LEN) if (!strncmp((name) + already_read, STR, LEN)) {already_read+=LEN;
 #define IF_ARG_PREFIX_END }
 
-    switch(*name) {
-        case 'c':
-            MOVE_DATA(name, 1);
-            IF_ARG("ondition", 8, YIN_ARG_CONDITION);
+    switch (*name) {
+    case 'c':
+        already_read += 1;
+        IF_ARG("ondition", 8, YIN_ARG_CONDITION);
         break;
 
-        case 'd':
-            MOVE_DATA(name, 1);
-            IF_ARG("ate", 3, YIN_ARG_DATE);
+    case 'd':
+        already_read += 1;
+        IF_ARG("ate", 3, YIN_ARG_DATE);
         break;
 
-        case 'm':
-            MOVE_DATA(name, 1);
-            IF_ARG("odule", 5, YIN_ARG_MODULE);
+    case 'm':
+        already_read += 1;
+        IF_ARG("odule", 5, YIN_ARG_MODULE);
         break;
 
-        case 'n':
-            MOVE_DATA(name, 1);
-            IF_ARG("ame", 3, YIN_ARG_NAME);
+    case 'n':
+        already_read += 1;
+        IF_ARG("ame", 3, YIN_ARG_NAME);
         break;
 
-        case 't':
-            MOVE_DATA(name, 1);
-            IF_ARG_PREFIX("a", 1)
-                IF_ARG("g", 1, YIN_ARG_TAG)
-                else IF_ARG("rget-node", 9, YIN_ARG_TARGET_NODE)
-            IF_ARG_PREFIX_END
-            else IF_ARG("ext", 3, YIN_ARG_TEXT)
+    case 't':
+        already_read += 1;
+        IF_ARG_PREFIX("a", 1)
+            IF_ARG("g", 1, YIN_ARG_TAG)
+            else IF_ARG("rget-node", 9, YIN_ARG_TARGET_NODE)
+        IF_ARG_PREFIX_END
+        else IF_ARG("ext", 3, YIN_ARG_TEXT)
         break;
 
-        case 'u':
-            MOVE_DATA(name, 1);
-            IF_ARG("ri", 2, YIN_ARG_URI)
+    case 'u':
+        already_read += 1;
+        IF_ARG("ri", 2, YIN_ARG_URI)
         break;
 
-        case 'v':
-            MOVE_DATA(name, 1);
-            IF_ARG("alue", 4, YIN_ARG_VALUE);
+    case 'v':
+        already_read += 1;
+        IF_ARG("alue", 4, YIN_ARG_VALUE);
         break;
     }
 
@@ -95,60 +127,69 @@
     return arg;
 }
 
-LY_ERR
-parser_belongs_to(struct lyxml_context *xml_ctx, const char **data, const char **belongsto, const char **prefix, struct lysp_ext **extensions)
-{
-    enum yang_keyword kw = YANG_NONE;
-    LY_ERR ret = LY_SUCCESS;
-    const char *prefix_out, *name;
-    size_t prefix_len, name_len;
+// LY_ERR
+// parser_belongs_to(struct lyxml_context *xml_ctx, const char **data, const char **belongsto, const char **prefix, struct lysp_ext **extensions)
+// {
+//     enum yang_keyword kw = YANG_NONE;
+//     LY_ERR ret = LY_SUCCESS;
+//     const char *prefix_out, *name;
+//     size_t prefix_len, name_len;
 
-    char *buf = NULL, *out = NULL;
-    size_t buf_len = 0, out_len = 0;
-    int dynamic;
+//     char *buf = NULL, *out = NULL;
+//     size_t buf_len = 0, out_len = 0;
+//     int dynamic;
 
-    /* check if belongs-to has argument module */
-    ret = lyxml_get_attribute(xml_ctx, data, &prefix_out, &prefix_len, &name, &name_len);
-    LY_CHECK_RET1(ret);
-    if (match_argument_name(name, name_len) != YIN_ARG_MODULE) {
-        LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Invalid argument name \"%s\", expected \"module\".", name);
-        return LY_EINVAL;
-    }
+//     /* check if belongs-to has argument module */
+//     ret = lyxml_get_attribute(xml_ctx, data, &prefix_out, &prefix_len, &name, &name_len);
+//     LY_CHECK_RET1(ret);
+//     if (match_argument_name(name, name_len) != YIN_ARG_MODULE) {
+//         LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Invalid argument name \"%s\", expected \"module\".", name);
+//         return LY_EINVAL;
+//     }
 
-    /* read content of argument */
-    ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
-    LY_CHECK_RET1(ret);
-    *belongsto = lydict_insert(xml_ctx->ctx, out, out_len);
-    LY_CHECK_ERR_RET(!belongsto, LOGMEM(xml_ctx->ctx), LY_EMEM);
+//     /* read content of argument */
+//     ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
+//     LY_CHECK_RET1(ret);
+//     *belongsto = lydict_insert(xml_ctx->ctx, out, out_len);
+//     LY_CHECK_ERR_RET(!belongsto, LOGMEM(xml_ctx->ctx), LY_EMEM);
 
-    /* read substatements */
-    while (xml_ctx->status == LYXML_ATTRIBUTE) {
-        ret = lyxml_get_attribute(xml_ctx, data, &prefix_out, &prefix_len, &name, &name_len);
-        LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), ret);
-        kw = match_keyword(name);
+//     /* read substatements */
+//     while (xml_ctx->status == LYXML_ATTRIBUTE) {
+//         ret = lyxml_get_attribute(xml_ctx, data, &prefix_out, &prefix_len, &name, &name_len);
+//         LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), ret);
+//         kw = match_keyword(name);
 
-        switch (kw) {
-        case YANG_PREFIX:
-            ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
-            *prefix = lydict_insert(xml_ctx->ctx, out, out_len);
-            break;
-        case YANG_CUSTOM:
-            /* TODO parse extension */
-            break;
-        default:
-            LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Unexpected attribute");
-            return LY_EVALID;
-        }
-    }
+//         switch (kw) {
+//         case YANG_PREFIX:
+//             ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
+//             *prefix = lydict_insert(xml_ctx->ctx, out, out_len);
+//             break;
+//         case YANG_CUSTOM:
+//             /* TODO parse extension */
+//             break;
+//         default:
+//             LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Unexpected attribute");
+//             return LY_EVALID;
+//         }
+//     }
 
-    if (!prefix) {
-        LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Missing prefix");
-        return LY_EVALID;
-    }
+//     if (!prefix) {
+//         LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Missing prefix");
+//         return LY_EVALID;
+//     }
 
-    return LY_SUCCESS;
-}
+//     return LY_SUCCESS;
+// }
 
+/**
+ * @brief Parse namespace statement.
+ *
+ * @param[in] xml_ctx xml context.
+ * @param[in, out] data Data to read from.
+ * @param[in, out] mod_p Module to write to.
+ *
+ * @return LY_ERR values.
+ */
 LY_ERR
 parse_namespace(struct lyxml_context *xml_ctx, const char **data, struct lysp_module **mod_p)
 {
@@ -162,20 +203,20 @@
 
     /* check if namespace has argument uri */
     ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
-    LY_CHECK_RET1(ret);
+    LY_CHECK_RET(ret);
     if (match_argument_name(name, name_len) != YIN_ARG_URI) {
         LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Invalid argument name \"%s\", expected \"uri\".", name);
         return LY_EVALID;
     }
 
     ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
-    LY_CHECK_RET1(ret);
-    (*mod_p)->ns = lydict_insert(xml_ctx->ctx, out, out_len);
-    LY_CHECK_ERR_RET(!(*mod_p)->ns, LOGMEM(xml_ctx->ctx), LY_EMEM);
+    LY_CHECK_RET(ret);
+    (*mod_p)->mod->ns = lydict_insert(xml_ctx->ctx, out, out_len);
+    LY_CHECK_ERR_RET(!(*mod_p)->mod->ns, LOGMEM(xml_ctx->ctx), LY_EMEM);
 
-    /* namespace can only have one argument */
+    /* namespace can have only one argument */
     ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
-    LY_CHECK_RET1(ret);
+    LY_CHECK_RET(ret);
     if (name) {
         LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Unexpected argument \"%s\".", name);
         return LY_EVALID;
@@ -184,6 +225,15 @@
     return LY_SUCCESS;
 }
 
+/**
+ * @brief Parse prefix statement.
+ *
+ * @param[in] xml_ctx Xml context.
+ * @param[in, out] data Data to reda from.
+ * @param[out] mod_p Module to write to.
+ *
+ * @return LY_ERR values.
+ */
 LY_ERR
 parse_prefix(struct lyxml_context *xml_ctx, const char **data, struct lysp_module **mod_p)
 {
@@ -197,20 +247,20 @@
 
     /* check if prefix has argument value */
     ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
-    LY_CHECK_RET1(ret);
+    LY_CHECK_RET(ret);
     if (match_argument_name(name, name_len) != YIN_ARG_VALUE) {
         LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Invalid argument name \"%s\", expected \"value\".", name);
         return LY_EVALID;
     }
 
     ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
-    LY_CHECK_RET1(ret);
-    (*mod_p)->prefix = lydict_insert(xml_ctx->ctx, out, out_len);
-    LY_CHECK_ERR_RET(!(*mod_p)->prefix, LOGMEM(xml_ctx->ctx), LY_EMEM);
+    LY_CHECK_RET(ret);
+    (*mod_p)->mod->prefix = lydict_insert(xml_ctx->ctx, out, out_len);
+    LY_CHECK_ERR_RET(!(*mod_p)->mod->prefix, LOGMEM(xml_ctx->ctx), LY_EMEM);
 
-    /* prefix element can only have one argument */
+    /* prefix element can have only one argument */
     ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
-    LY_CHECK_RET1(ret);
+    LY_CHECK_RET(ret);
     if (name) {
         LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Unexpected argument \"%s\".", name);
         return LY_EVALID;
@@ -218,11 +268,12 @@
     return LY_SUCCESS;
 }
 
-LY_ERR
-parse_submodule(struct lyxml_context *xml_ctx, const char **data, struct lysp_module **mod_p)
+static LY_ERR
+yin_parse_import(struct lyxml_context *xml_ctx, const char *module_prefix, const char **data, struct lysp_import **imports)
 {
     LY_ERR ret = LY_SUCCESS;
-    enum yang_keyword kw = YANG_NONE;
+    enum yang_keyword kw;
+    struct lysp_import *imp;
     const char *prefix, *name;
     size_t prefix_len, name_len;
 
@@ -230,7 +281,69 @@
     size_t buf_len = 0, out_len = 0;
     int dynamic;
 
-    /* check if module/submodule has argument "name" */
+    /* allocate sized array for imports */
+    LY_ARRAY_NEW_RET(xml_ctx->ctx, *imports, imp, LY_EVALID);
+
+    /* get value */
+    ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
+    LY_CHECK_RET(ret);
+    if (match_argument_name(name, name_len) != YIN_ARG_MODULE) {
+        LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Invalid argument name \"%s\", expected \"module\".", name);
+        return LY_EVALID;
+    }
+    ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
+    LY_CHECK_RET(ret);
+    imp->name = lydict_insert(xml_ctx->ctx, out, out_len);
+    LY_CHECK_ERR_RET(!imp->name, LOGMEM(xml_ctx->ctx), LY_EMEM);
+
+
+    while ((ret = lyxml_get_element(xml_ctx, data, &prefix, &prefix_len, &name, &name_len) == LY_SUCCESS && name != NULL)) {
+        kw = match_keyword(name, name_len);
+        switch (kw) {
+        case YANG_PREFIX:
+            /* TODO parse prefix */
+        case YANG_DESCRIPTION:
+            /* TODO parse description */
+        case YANG_REFERENCE:
+            /* TODO parse reference */
+        case YANG_REVISION_DATE:
+            /* TODO parse revision date */
+        case YANG_CUSTOM:
+            /* TODO parse extension */
+        default:
+            /* TODO log error */
+            return LY_EVALID;
+        }
+    }
+
+    /* TODO add log macro and log error */
+    LY_CHECK_RET(!imp->prefix);
+    return ret;
+}
+
+/**
+ * @brief Parse module substatements.
+ *
+ * @param[in] xml_ctx xml context.
+ * @param[in, out] data Data to read from.
+ * @param[out] mod Parsed module structure
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR
+parse_mod(struct lyxml_context *xml_ctx, const char **data, struct lysp_module **mod)
+{
+    LY_ERR ret = LY_SUCCESS;
+    enum yang_keyword kw = YANG_NONE;
+    const char *prefix, *name;
+    size_t prefix_len, name_len;
+    enum yang_module_stmt mod_stmt = Y_MOD_MODULE_HEADER;
+
+    char *buf = NULL, *out = NULL;
+    size_t buf_len = 0, out_len = 0;
+    int dynamic;
+
+    /* check if module has argument "name" */
     ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
     LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), LY_EMEM);
     if (match_argument_name(name, name_len) != YIN_ARG_NAME) {
@@ -243,8 +356,8 @@
     }
     ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
     LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), LY_EMEM);
-    (*mod_p)->name = lydict_insert(xml_ctx->ctx, out, out_len);
-    LY_CHECK_ERR_RET(!(*mod_p)->name, LOGMEM(xml_ctx->ctx), LY_EMEM);
+    (*mod)->mod->name = lydict_insert(xml_ctx->ctx, out, out_len);
+    LY_CHECK_ERR_RET(!(*mod)->mod->name, LOGMEM(xml_ctx->ctx), LY_EMEM);
 
     /* read all attributes and their content only for testing */
     while (xml_ctx->status == LYXML_ATTRIBUTE) {
@@ -254,27 +367,103 @@
         }
     }
 
-
+    /* loop over all elements and parse them */
     while (xml_ctx->status == LYXML_ELEMENT || xml_ctx->status == LYXML_ELEM_CONTENT) {
-        ret = lyxml_get_element(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
-        LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), LY_EMEM);
-        kw = match_keyword(name);
+
+/* TODO ADD error log to macro */
+#define CHECK_ORDER(SECTION) \
+        if (mod_stmt > SECTION) {return LY_EVALID;}mod_stmt = SECTION
 
         switch (kw) {
-            case YANG_NAMESPACE:
-                ret = parse_namespace(xml_ctx, data, mod_p);
+        /* module header */
+        case YANG_NAMESPACE:
+        case YANG_PREFIX:
+            CHECK_ORDER(Y_MOD_MODULE_HEADER);
             break;
-            case YANG_PREFIX:
-                ret = parse_prefix(xml_ctx, data, mod_p);
-                /* TODO change lysp_check_prefix function to work with ctx and not parser_ctx */
-                //LY_CHECK_RET(lysp_check_prefix(&xml_ctx->ctx, *mod_p, &((*mod_p)->prefix)), LY_EVALID);
+        case YANG_YANG_VERSION:
+            CHECK_ORDER(Y_MOD_MODULE_HEADER);
             break;
-            case YANG_BELONGS_TO:
-                ret = parser_belongs_to(xml_ctx, data, &(*mod_p)->belongsto, &(*mod_p)->prefix, &(*mod_p)->extensions);
+        /* 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;
 
-            default:
-                /* error */
+        /* 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 will be handled in the next switch */
+            break;
+        }
+#undef CHECK_ORDER
+
+        ret = lyxml_get_element(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
+        LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), LY_EMEM);
+        kw = match_keyword(name, name_len);
+
+        switch (kw) {
+
+        /* module header */
+        case YANG_NAMESPACE:
+            LY_CHECK_RET(parse_namespace(xml_ctx, data, mod));
+            break;
+        case YANG_PREFIX:
+            LY_CHECK_RET(parse_prefix(xml_ctx, data, mod));
+            /* TODO change lysp_check_prefix function to work with ctx and not parser_ctx */
+            //LY_CHECK_RET(lysp_check_prefix(&xml_ctx->ctx, *mod_p, &((*mod_p)->prefix)), LY_EVALID);
+            break;
+
+        /* linkage */
+        case YANG_IMPORT:
+            yin_parse_import(xml_ctx, (*mod)->mod->prefix, data, &(*mod)->imports);
+            break;
+
+        /* meta */
+        case YANG_ORGANIZATION:
+            LY_CHECK_RET(parse_text_element(xml_ctx, data, &(*mod)->mod->org));
+            break;
+        case YANG_CONTACT:
+            LY_CHECK_RET(parse_text_element(xml_ctx, data, &(*mod)->mod->contact));
+            break;
+        case YANG_DESCRIPTION:
+            LY_CHECK_RET(parse_text_element(xml_ctx, data, &(*mod)->mod->dsc));
+            break;
+        case YANG_REFERENCE:
+            LY_CHECK_RET(parse_text_element(xml_ctx, data, &(*mod)->mod->ref));
+            break;
+
+        default:
+            /* error */
             break;
         }
     }
@@ -282,38 +471,121 @@
     return ret;
 }
 
+/**
+ * @brief Parse yin submodule.
+ *
+ * @param[in] ctx Context of YANG schemas.
+ * @param[in] data Data to read from.
+ * @param[out] submod Module to write to.
+ *
+ * @return LY_ERR values.
+ */
 LY_ERR
-yin_parse(struct ly_ctx *ctx, const char *data, struct lysp_module **mod_p)
+yin_parse_submodule(struct ly_ctx *ctx, const char *data, struct lysp_submodule **submod)
 {
     LY_ERR ret = LY_SUCCESS;
     enum yang_keyword kw = YANG_NONE;
     struct lyxml_context xml_ctx;
+    struct lysp_submodule *mod_p = NULL;
+    const char *prefix, *name;
+    size_t prefix_len, name_len;
 
+    /* initialize xml context */
     memset(&xml_ctx, 0, sizeof xml_ctx);
     xml_ctx.ctx = ctx;
     xml_ctx.line = 1;
 
-    const char *prefix, *name;
-    size_t prefix_len, name_len;
-
-    /* check if root element is module or submodule */
+    /* check submodule */
     ret = lyxml_get_element(&xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
-    LY_CHECK_GOTO(ret != LY_SUCCESS, error);
-    kw = match_keyword(name);
-    if (kw != YANG_MODULE && kw != YANG_SUBMODULE) {
-        LOGVAL(xml_ctx.ctx, LY_VLOG_LINE, &xml_ctx.line, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".", name);
+    LY_CHECK_GOTO(ret != LY_SUCCESS, cleanup);
+    kw = match_keyword(name, name_len);
+    if (kw == YANG_MODULE) {
+        LOGERR(ctx, LY_EDENIED, "Input data contains module in situation when a submodule is expected.");
+        ret = LY_EINVAL;
+        goto cleanup;
+    } else if (kw != YANG_SUBMODULE) {
+        /* TODO log error using LOGVAL_YIN macro */
+        ret = LY_EVALID;
+        goto cleanup;
     }
 
-    if (kw == YANG_SUBMODULE) {
-        (*mod_p)->submodule = 1;
-    }
+    /* allocate module */
+    mod_p = calloc(1, sizeof *mod_p);
+    LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(ctx), cleanup);
+    mod_p->parsing = 1;
 
-    ret = parse_submodule(&xml_ctx, &data, mod_p);
+    /* parser submodule substatements */
+    //ret = parse_submod(&xml_ctx, &data, mod_p);
+    LY_CHECK_GOTO(ret, cleanup);
+
+    mod_p->parsing = 0;
+    *submod = mod_p;
+
+cleanup:
+    if (ret) {
+        lysp_submodule_free(ctx, mod_p);
+    }
 
     lyxml_context_clear(&xml_ctx);
     return ret;
+}
 
-error:
+/**
+ * @brief Parse yin module.
+ *
+ * @param[in] ctx Context of YANG schemas.
+ * @param[in] data Data to read from.
+ * @param[out] mod Module to write to.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR
+yin_parse_module(struct ly_ctx *ctx, const char *data, struct lys_module *mod)
+{
+    LY_ERR ret = LY_SUCCESS;
+    enum yang_keyword kw = YANG_NONE;
+    struct lyxml_context xml_ctx;
+    struct lysp_module *mod_p = NULL;
+    const char *prefix, *name;
+    size_t prefix_len, name_len;
+
+    /* initialize xml context */
+    memset(&xml_ctx, 0, sizeof xml_ctx);
+    xml_ctx.ctx = ctx;
+    xml_ctx.line = 1;
+
+    /* check submodule */
+    ret = lyxml_get_element(&xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+    LY_CHECK_GOTO(ret != LY_SUCCESS, cleanup);
+    kw = match_keyword(name, name_len);
+    if (kw == YANG_SUBMODULE) {
+        LOGERR(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) {
+        /* TODO log error using LOGVAL_YIN macro */
+        ret = LY_EVALID;
+        goto cleanup;
+    }
+
+    /* allocate module */
+    mod_p = calloc(1, sizeof *mod_p);
+    LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(ctx), cleanup);
+    mod_p->mod = mod;
+    mod_p->parsing = 1;
+
+    /* parser module substatements */
+    ret = parse_mod(&xml_ctx, &data, &mod_p);
+    LY_CHECK_GOTO(ret, cleanup);
+
+    mod_p->parsing = 0;
+    mod->parsed = mod_p;
+
+cleanup:
+    if (ret) {
+        lysp_module_free(mod_p);
+    }
+
     lyxml_context_clear(&xml_ctx);
     return ret;
 }
diff --git a/src/tree_schema.h b/src/tree_schema.h
index bcf92d4..cb78110 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -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,14 +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 */
+                                          ::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 */
@@ -627,7 +630,7 @@
                                           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 */
 /** @} */
 
 /**
@@ -975,8 +978,9 @@
     struct lyxp_expr *cond;          /**< XPath when condition */
     const char *dsc;                 /**< description */
     const char *ref;                 /**< reference */
-    struct lysc_node *context;       /**< context node of the expression */
+    struct lysc_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 */
 };
 
 /**
@@ -1178,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 */
 };
@@ -1185,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 */
 };
@@ -1207,7 +1213,7 @@
     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)) */
 };
 
@@ -1226,7 +1232,7 @@
     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) */
@@ -1250,7 +1256,7 @@
     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
@@ -1274,7 +1280,7 @@
     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
@@ -1298,7 +1304,7 @@
     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)) */
@@ -1323,7 +1329,7 @@
     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)) */
@@ -1351,7 +1357,7 @@
     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) */
@@ -1380,7 +1386,7 @@
     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)) */
@@ -1512,8 +1518,11 @@
                                           the module became implemented in future (no matter if implicitly via augment/deviate
                                           or explicitly via ly_ctx_module_implement()). */
 
-    uint8_t implemented:1;           /**< flag if the module is implemented, not just imported */
-    uint8_t latest_revision:2;       /**< flag to mark the latest available revision:
+    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 */
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index f94cfed..9f8d3e7 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -60,6 +60,15 @@
         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__) { \
@@ -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,8 +238,8 @@
     *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.
@@ -262,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)
 {
@@ -433,22 +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);
-    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);
+    *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)
 {
@@ -468,6 +561,14 @@
     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)
 {
@@ -506,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)
 {
@@ -526,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
@@ -579,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;
@@ -656,6 +828,60 @@
 }
 
 /**
+ * @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.
@@ -687,11 +913,19 @@
             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 */
                 }
             }
         }
@@ -704,6 +938,42 @@
 }
 
 /**
+ * @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;
+    }
+}
+
+/**
  * @brief Validate and normalize numeric value from a range definition.
  * @param[in] ctx Compile context.
  * @param[in] basetype Base YANG built-in type of the node connected with the range restriction. Actually only LY_TYPE_DEC64 is important to
@@ -1208,7 +1478,6 @@
     parts = NULL;
     ret = LY_SUCCESS;
 cleanup:
-    /* TODO clean up */
     LY_ARRAY_FREE(parts);
 
     return ret;
@@ -2753,6 +3022,10 @@
     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, 0));
     }
@@ -2846,6 +3119,9 @@
     }
 
     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,
@@ -2921,6 +3197,9 @@
     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) {
@@ -3025,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,
@@ -3067,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)
 {
@@ -3171,24 +3461,18 @@
     return ret;
 }
 
-static LY_ERR
-lys_compile_status_check(struct lysc_ctx *ctx, uint16_t node_flags, 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;
-}
-
+/**
+ * @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(struct lysc_ctx *ctx, struct lysc_node *node, uint16_t parent_flags)
 {
@@ -3207,11 +3491,37 @@
             node->flags |= LYS_STATUS_CURR;
         }
     } else if (parent_flags & LYS_STATUS_MASK) {
-        return lys_compile_status_check(ctx, node->flags, 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;
 }
 
+/**
+ * @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,
@@ -3221,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;
         }
     }
@@ -3285,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));
@@ -3323,8 +3663,17 @@
 
         /* check the case's status (don't need to solve uses_status since case statement cannot be directly in grouping statement */
         LY_CHECK_RET(lys_compile_status(ctx, (struct lysc_node*)cs, ch->flags), NULL);
-        COMPILE_MEMBER_GOTO(ctx, node_p->when, cs->when, options, lys_compile_when, ret, error);
+
+        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;
@@ -3340,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)
 {
@@ -3374,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.
  *
@@ -3407,6 +3990,8 @@
     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;
@@ -3487,30 +4072,47 @@
         /* 0x3 in uses_status is a special bits combination to be able to detect status flags from uses */
         LY_CHECK_GOTO(lys_compile_node(ctx, node_p, options, parent, (uses_p->flags & LYS_STATUS_MASK) | 0x3), error);
         child = parent ? lysc_node_children(parent)->prev : ctx->mod->compiled->data->prev;
-        if (uses_p->refines) {
-            /* some preparation for applying refines */
-            if (grp->data == node_p) {
-                /* remember the first child */
-                context_node_fake.child = child;
-            }
+
+        /* 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;
     }
 
-    /* TODO: apply augment */
+    /* 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, (struct lysc_node*)&context_node_fake, 0, (const struct lysc_node**)&node),
+        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);
 
@@ -3610,9 +4212,11 @@
                 }
 
                 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);
@@ -3667,6 +4271,13 @@
                 }
                 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:
@@ -3675,6 +4286,13 @@
                 }
                 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:
@@ -3738,10 +4356,12 @@
     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
@@ -3760,6 +4380,7 @@
     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*);
 
@@ -3844,13 +4465,23 @@
     DUP_STRING(ctx->ctx, node_p->name, node->name);
     DUP_STRING(ctx->ctx, node_p->dsc, node->dsc);
     DUP_STRING(ctx->ctx, node_p->ref, node->ref);
-    COMPILE_MEMBER_GOTO(ctx, node_p->when, node->when, options, lys_compile_when, ret, error);
+    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) {
@@ -3867,7 +4498,7 @@
         } 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) {
@@ -3930,8 +4561,9 @@
     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;
-    int using_precompiled_features = 0;
     LY_ERR ret = LY_SUCCESS;
 
     LY_CHECK_ARG_RET(NULL, mod, mod->parsed, mod->ctx, LY_EINVAL);
@@ -3960,7 +4592,6 @@
         /* there is already precompiled array of features */
         mod_c->features = mod->off_features;
         mod->off_features = NULL;
-        using_precompiled_features = 1;
     } else {
         /* features are compiled directly into the compiled module structure,
          * but it must be done in two steps to allow forward references (via if-feature) between the features themselves */
@@ -3986,10 +4617,19 @@
         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, 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);
     //COMPILE_ARRAY_GOTO(ctx, sp->notifs, mod_c->notifs, options, u, lys_compile_notif, ret, error);
 
@@ -4042,36 +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:
-    if (using_precompiled_features) {
-        /* keep the off_features list until the complete lys_module is freed */
-        mod->off_features = mod->compiled->features;
-        mod->compiled->features = NULL;
-    }
-    /* in the off_features list, remove all the parts (from finished compiling process)
-     * which may points into the data being freed here */
-    LY_ARRAY_FOR(mod->off_features, u) {
-        LY_ARRAY_FOR(mod->off_features[u].iffeatures, v) {
-            lysc_iffeature_free(ctx.ctx, &mod->off_features[u].iffeatures[v]);
-        }
-        LY_ARRAY_FREE(mod->off_features[u].iffeatures);
-        LY_ARRAY_FOR(mod->off_features[u].exts, v) {
-            lysc_ext_instance_free(ctx.ctx, &(mod->off_features[u].exts)[v]);
-        }
-        LY_ARRAY_FREE(mod->off_features[u].exts);
-    }
+    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 ce0dfb8..aa026f7 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -479,12 +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_STRING(ctx, w->dsc);
-    FREE_STRING(ctx, w->ref);
-    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
@@ -742,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);
@@ -773,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);
     }
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index 74e950d..cd056d9 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -85,38 +85,68 @@
 }
 
 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->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 (!*id || (nodeid_len && ((size_t)(id - nodeid) >= nodeid_len))) {
@@ -124,8 +154,8 @@
         }
         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,6 +166,10 @@
         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;
@@ -897,6 +931,8 @@
         return "anyxml";
     case LYS_ANYDATA:
         return "anydata";
+    case LYS_CASE:
+        return "case";
     default:
         return "unknown";
     }
@@ -1103,7 +1139,7 @@
         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;
         }
@@ -1148,7 +1184,7 @@
 }
 
 enum yang_keyword
-match_keyword(const char *data)
+match_keyword(const char *data, size_t len)
 {
 /* TODO make this function usable in get_keyword function */
 #define MOVE_IN(DATA, COUNT) (data)+=COUNT;
@@ -1156,6 +1192,7 @@
 #define IF_KEYWORD_PREFIX(STR, LEN) if (!strncmp((data), STR, LEN)) {MOVE_IN(data, LEN);
 #define IF_KEYWORD_PREFIX_END }
 
+    const char *start = data;
     enum yang_keyword kw = YANG_NONE;
     /* read the keyword itself */
     switch (*data) {
@@ -1339,6 +1376,10 @@
         break;
     }
 
-    /* TODO important fix whole keyword must be matched */
-    return kw;
+    if (data - start == (long int)len) {
+        return kw;
+    } else {
+        return YANG_NONE;
+    }
+
 }
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 1a3e078..563ec0f 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -155,6 +155,7 @@
  * @{
  */
 #define LYSC_OPT_FREE_SP 1           /**< Free the input printable schema */
+#define LYSC_OPT_INTERNAL 2          /**< Internal compilation caused by dependency */
 /** @} scflags */
 
 /**
@@ -266,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.
@@ -527,7 +531,19 @@
 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
  */
-enum yang_keyword match_keyword(const char *data);
+enum yang_keyword match_keyword(const char *data, size_t len);
 #endif /* LY_TREE_SCHEMA_INTERNAL_H_ */
diff --git a/tests/src/test_parser_yang.c b/tests/src/test_parser_yang.c
index 7a034ee..d0935ad 100644
--- a/tests/src/test_parser_yang.c
+++ b/tests/src/test_parser_yang.c
@@ -1101,12 +1101,7 @@
     TEST_DUP_GENERIC(" test {", MEMBER, VALUE1, VALUE2, parse_identity, \
                      &ident, "1", FREE_ARRAY(ctx.ctx, ident, lysp_ident_free); ident = NULL)
 
-    //TEST_DUP("description", "a", "b");
-    str = " test {description a;description b;} ...";
-    assert_int_equal(LY_EVALID, parse_identity(&ctx, &str, &ident));
-    logbuf_assert("Duplicate keyword \"description\". Line number 1.");
-    FREE_ARRAY(ctx.ctx, ident, lysp_ident_free); ident = NULL;
-
+    TEST_DUP("description", "a", "b");
     TEST_DUP("reference", "a", "b");
     TEST_DUP("status", "current", "obsolete");
 
@@ -1905,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[] = {
diff --git a/tests/src/test_parser_yin.c b/tests/src/test_parser_yin.c
index 870e5b4..f1dc88c 100644
--- a/tests/src/test_parser_yin.c
+++ b/tests/src/test_parser_yin.c
@@ -28,13 +28,14 @@
     (void)state; /* unused */
 
     struct ly_ctx *ctx;
-    struct lysp_module *mod;
+    struct lys_module *mod;
+    LY_ERR ret = LY_SUCCESS;
 
     ly_ctx_new(NULL, 0, &ctx);
     mod = calloc(1, sizeof(*mod));
     mod->ctx = ctx;
 
-    yin_parse(ctx, "<module name=\"example-foo\"\
+    ret = yin_parse_module(ctx, "<module name=\"example-foo\"\
                     xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"\
                     xmlns:foo=\"urn:example:foo\"\
                     xmlns:myext=\"urn:example:extensions\">\
@@ -59,12 +60,14 @@
                         </leaf>\
                     </list>\
                     </module>",
-                &mod);
+                mod);
 
-    assert_string_equal(mod->name, "example-foo");
-    assert_string_equal(mod->prefix, "foo");
+    assert_int_equal(ret, LY_SUCCESS);
+    assert_string_equal(mod->parsed->mod->name, "example-foo");
+    assert_string_equal(mod->parsed->mod->prefix, "foo");
+    assert_string_equal(mod->parsed->imports->name, "example-extensions");
 
-    lysp_module_free(mod);
+    lys_module_free(mod, NULL);
     ly_ctx_destroy(ctx, NULL);
 }
 
@@ -79,76 +82,76 @@
 {
     (void)state; /* unused */
 
-    assert_int_equal(match_keyword("anydata"), YANG_ANYDATA);
-    assert_int_equal(match_keyword("asdasd"), YANG_NONE);
-    assert_int_equal(match_keyword(""), YANG_NONE);
-    assert_int_equal(match_keyword("anydata"), YANG_ANYDATA);
-    assert_int_equal(match_keyword("anyxml"), YANG_ANYXML);
-    assert_int_equal(match_keyword("argument"), YANG_ARGUMENT);
-    assert_int_equal(match_keyword("augment"), YANG_AUGMENT);
-    assert_int_equal(match_keyword("base"), YANG_BASE);
-    assert_int_equal(match_keyword("belongs-to"), YANG_BELONGS_TO);
-    assert_int_equal(match_keyword("bit"), YANG_BIT);
-    assert_int_equal(match_keyword("case"), YANG_CASE);
-    assert_int_equal(match_keyword("choice"), YANG_CHOICE);
-    assert_int_equal(match_keyword("config"), YANG_CONFIG);
-    assert_int_equal(match_keyword("contact"), YANG_CONTACT);
-    assert_int_equal(match_keyword("container"), YANG_CONTAINER);
-    assert_int_equal(match_keyword("default"), YANG_DEFAULT);
-    assert_int_equal(match_keyword("description"), YANG_DESCRIPTION);
-    assert_int_equal(match_keyword("deviate"), YANG_DEVIATE);
-    assert_int_equal(match_keyword("deviation"), YANG_DEVIATION);
-    assert_int_equal(match_keyword("enum"), YANG_ENUM);
-    assert_int_equal(match_keyword("error-app-tag"), YANG_ERROR_APP_TAG);
-    assert_int_equal(match_keyword("error-message"), YANG_ERROR_MESSAGE);
-    assert_int_equal(match_keyword("extension"), YANG_EXTENSION);
-    assert_int_equal(match_keyword("feature"), YANG_FEATURE);
-    assert_int_equal(match_keyword("fraction-digits"), YANG_FRACTION_DIGITS);
-    assert_int_equal(match_keyword("grouping"), YANG_GROUPING);
-    assert_int_equal(match_keyword("identity"), YANG_IDENTITY);
-    assert_int_equal(match_keyword("if-feature"), YANG_IF_FEATURE);
-    assert_int_equal(match_keyword("import"), YANG_IMPORT);
-    assert_int_equal(match_keyword("include"), YANG_INCLUDE);
-    assert_int_equal(match_keyword("input"), YANG_INPUT);
-    assert_int_equal(match_keyword("key"), YANG_KEY);
-    assert_int_equal(match_keyword("leaf"), YANG_LEAF);
-    assert_int_equal(match_keyword("leaf-list"), YANG_LEAF_LIST);
-    assert_int_equal(match_keyword("length"), YANG_LENGTH);
-    assert_int_equal(match_keyword("list"), YANG_LIST);
-    assert_int_equal(match_keyword("mandatory"), YANG_MANDATORY);
-    assert_int_equal(match_keyword("max-elements"), YANG_MAX_ELEMENTS);
-    assert_int_equal(match_keyword("min-elements"), YANG_MIN_ELEMENTS);
-    assert_int_equal(match_keyword("modifier"), YANG_MODIFIER);
-    assert_int_equal(match_keyword("module"), YANG_MODULE);
-    assert_int_equal(match_keyword("must"), YANG_MUST);
-    assert_int_equal(match_keyword("namespace"), YANG_NAMESPACE);
-    assert_int_equal(match_keyword("notification"), YANG_NOTIFICATION);
-    assert_int_equal(match_keyword("ordered-by"), YANG_ORDERED_BY);
-    assert_int_equal(match_keyword("organization"), YANG_ORGANIZATION);
-    assert_int_equal(match_keyword("output"), YANG_OUTPUT);
-    assert_int_equal(match_keyword("path"), YANG_PATH);
-    assert_int_equal(match_keyword("pattern"), YANG_PATTERN);
-    assert_int_equal(match_keyword("position"), YANG_POSITION);
-    assert_int_equal(match_keyword("prefix"), YANG_PREFIX);
-    assert_int_equal(match_keyword("presence"), YANG_PRESENCE);
-    assert_int_equal(match_keyword("range"), YANG_RANGE);
-    assert_int_equal(match_keyword("reference"), YANG_REFERENCE);
-    assert_int_equal(match_keyword("refine"), YANG_REFINE);
-    assert_int_equal(match_keyword("require-instance"), YANG_REQUIRE_INSTANCE);
-    assert_int_equal(match_keyword("revision"), YANG_REVISION);
-    assert_int_equal(match_keyword("revision-date"), YANG_REVISION_DATE);
-    assert_int_equal(match_keyword("rpc"), YANG_RPC);
-    assert_int_equal(match_keyword("status"), YANG_STATUS);
-    assert_int_equal(match_keyword("submodule"), YANG_SUBMODULE);
-    assert_int_equal(match_keyword("type"), YANG_TYPE);
-    assert_int_equal(match_keyword("typedef"), YANG_TYPEDEF);
-    assert_int_equal(match_keyword("unique"), YANG_UNIQUE);
-    assert_int_equal(match_keyword("units"), YANG_UNITS);
-    assert_int_equal(match_keyword("uses"), YANG_USES);
-    assert_int_equal(match_keyword("value"), YANG_VALUE);
-    assert_int_equal(match_keyword("when"), YANG_WHEN);
-    assert_int_equal(match_keyword("yang-version"), YANG_YANG_VERSION);
-    assert_int_equal(match_keyword("yin-element"), YANG_YIN_ELEMENT);
+    assert_int_equal(match_keyword("anydatax", strlen("anydatax")), YANG_NONE);
+    assert_int_equal(match_keyword("asdasd", strlen("asdasd")), YANG_NONE);
+    assert_int_equal(match_keyword("", 0), YANG_NONE);
+    assert_int_equal(match_keyword("anydata", strlen("anydata")), YANG_ANYDATA);
+    assert_int_equal(match_keyword("anyxml", strlen("anyxml")), YANG_ANYXML);
+    assert_int_equal(match_keyword("argument", strlen("argument")), YANG_ARGUMENT);
+    assert_int_equal(match_keyword("augment", strlen("augment")), YANG_AUGMENT);
+    assert_int_equal(match_keyword("base", strlen("base")), YANG_BASE);
+    assert_int_equal(match_keyword("belongs-to", strlen("belongs-to")), YANG_BELONGS_TO);
+    assert_int_equal(match_keyword("bit", strlen("bit")), YANG_BIT);
+    assert_int_equal(match_keyword("case", strlen("case")), YANG_CASE);
+    assert_int_equal(match_keyword("choice", strlen("choice")), YANG_CHOICE);
+    assert_int_equal(match_keyword("config", strlen("config")), YANG_CONFIG);
+    assert_int_equal(match_keyword("contact", strlen("contact")), YANG_CONTACT);
+    assert_int_equal(match_keyword("container", strlen("container")), YANG_CONTAINER);
+    assert_int_equal(match_keyword("default", strlen("default")), YANG_DEFAULT);
+    assert_int_equal(match_keyword("description", strlen("description")), YANG_DESCRIPTION);
+    assert_int_equal(match_keyword("deviate", strlen("deviate")), YANG_DEVIATE);
+    assert_int_equal(match_keyword("deviation", strlen("deviation")), YANG_DEVIATION);
+    assert_int_equal(match_keyword("enum", strlen("enum")), YANG_ENUM);
+    assert_int_equal(match_keyword("error-app-tag", strlen("error-app-tag")), YANG_ERROR_APP_TAG);
+    assert_int_equal(match_keyword("error-message", strlen("error-message")), YANG_ERROR_MESSAGE);
+    assert_int_equal(match_keyword("extension", strlen("extension")), YANG_EXTENSION);
+    assert_int_equal(match_keyword("feature", strlen("feature")), YANG_FEATURE);
+    assert_int_equal(match_keyword("fraction-digits", strlen("fraction-digits")), YANG_FRACTION_DIGITS);
+    assert_int_equal(match_keyword("grouping", strlen("grouping")), YANG_GROUPING);
+    assert_int_equal(match_keyword("identity", strlen("identity")), YANG_IDENTITY);
+    assert_int_equal(match_keyword("if-feature", strlen("if-feature")), YANG_IF_FEATURE);
+    assert_int_equal(match_keyword("import", strlen("import")), YANG_IMPORT);
+    assert_int_equal(match_keyword("include", strlen("include")), YANG_INCLUDE);
+    assert_int_equal(match_keyword("input", strlen("input")), YANG_INPUT);
+    assert_int_equal(match_keyword("key", strlen("key")), YANG_KEY);
+    assert_int_equal(match_keyword("leaf", strlen("leaf")), YANG_LEAF);
+    assert_int_equal(match_keyword("leaf-list", strlen("leaf-list")), YANG_LEAF_LIST);
+    assert_int_equal(match_keyword("length", strlen("length")), YANG_LENGTH);
+    assert_int_equal(match_keyword("list", strlen("list")), YANG_LIST);
+    assert_int_equal(match_keyword("mandatory", strlen("mandatory")), YANG_MANDATORY);
+    assert_int_equal(match_keyword("max-elements", strlen("max-elements")), YANG_MAX_ELEMENTS);
+    assert_int_equal(match_keyword("min-elements", strlen("min-elements")), YANG_MIN_ELEMENTS);
+    assert_int_equal(match_keyword("modifier", strlen("modifier")), YANG_MODIFIER);
+    assert_int_equal(match_keyword("module", strlen("module")), YANG_MODULE);
+    assert_int_equal(match_keyword("must", strlen("must")), YANG_MUST);
+    assert_int_equal(match_keyword("namespace", strlen("namespace")), YANG_NAMESPACE);
+    assert_int_equal(match_keyword("notification", strlen("notification")), YANG_NOTIFICATION);
+    assert_int_equal(match_keyword("ordered-by", strlen("ordered-by")), YANG_ORDERED_BY);
+    assert_int_equal(match_keyword("organization", strlen("organization")), YANG_ORGANIZATION);
+    assert_int_equal(match_keyword("output", strlen("output")), YANG_OUTPUT);
+    assert_int_equal(match_keyword("path", strlen("path")), YANG_PATH);
+    assert_int_equal(match_keyword("pattern", strlen("pattern")), YANG_PATTERN);
+    assert_int_equal(match_keyword("position", strlen("position")), YANG_POSITION);
+    assert_int_equal(match_keyword("prefix", strlen("prefix")), YANG_PREFIX);
+    assert_int_equal(match_keyword("presence", strlen("presence")), YANG_PRESENCE);
+    assert_int_equal(match_keyword("range", strlen("range")), YANG_RANGE);
+    assert_int_equal(match_keyword("reference", strlen("reference")), YANG_REFERENCE);
+    assert_int_equal(match_keyword("refine", strlen("refine")), YANG_REFINE);
+    assert_int_equal(match_keyword("require-instance", strlen("require-instance")), YANG_REQUIRE_INSTANCE);
+    assert_int_equal(match_keyword("revision", strlen("revision")), YANG_REVISION);
+    assert_int_equal(match_keyword("revision-date", strlen("revision-date")), YANG_REVISION_DATE);
+    assert_int_equal(match_keyword("rpc", strlen("rpc")), YANG_RPC);
+    assert_int_equal(match_keyword("status", strlen("status")), YANG_STATUS);
+    assert_int_equal(match_keyword("submodule", strlen("submodule")), YANG_SUBMODULE);
+    assert_int_equal(match_keyword("type", strlen("type")), YANG_TYPE);
+    assert_int_equal(match_keyword("typedef", strlen("typedef")), YANG_TYPEDEF);
+    assert_int_equal(match_keyword("unique", strlen("unique")), YANG_UNIQUE);
+    assert_int_equal(match_keyword("units", strlen("units")), YANG_UNITS);
+    assert_int_equal(match_keyword("uses", strlen("uses")), YANG_USES);
+    assert_int_equal(match_keyword("value", strlen("value")), YANG_VALUE);
+    assert_int_equal(match_keyword("when", strlen("when")), YANG_WHEN);
+    assert_int_equal(match_keyword("yang-version", strlen("yang-version")), YANG_YANG_VERSION);
+    assert_int_equal(match_keyword("yin-element", strlen("yin-element")), YANG_YIN_ELEMENT);
 }
 
 static void
diff --git a/tests/src/test_tree_schema_compile.c b/tests/src/test_tree_schema_compile.c
index 1288ee3..cfdc33a 100644
--- a/tests/src/test_tree_schema_compile.c
+++ b/tests/src/test_tree_schema_compile.c
@@ -112,6 +112,7 @@
     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;
@@ -353,6 +354,11 @@
     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_feature_enable(modp, "f1"));
@@ -372,12 +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_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);
@@ -398,13 +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_null(lys_parse_mem(ctx, "module c{namespace urn:c; prefix c; identity i1;identity i1;}", LYS_IN_YANG));
+    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_null(lys_parse_mem(ctx, "module d{namespace urn:d; prefix d; include sd;identity i1;}", LYS_IN_YANG));
+    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);
 }
@@ -2102,7 +2121,7 @@
 
     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));
 
@@ -2139,11 +2158,12 @@
     assert_string_equal("f", child->iffeatures[0].features[0]->name);
     assert_int_equal(1, lysc_iffeature_value(&child->iffeatures[0]));
 
-    ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "submodule bsub {belongs-to b {prefix b;} grouping grp {leaf b {type string;}}}");
-    assert_non_null(mod = lys_parse_mem(ctx, "module b {namespace urn:b;prefix b;include bsub;uses grp;}", LYS_IN_YANG));
+    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;"
@@ -2157,6 +2177,14 @@
     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_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.");
@@ -2178,6 +2206,20 @@
                                         "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);
 }
@@ -2326,6 +2368,123 @@
     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)
 {
     const struct CMUnitTest tests[] = {
@@ -2352,6 +2511,7 @@
         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);