tree schema CHANGE compile import module information
diff --git a/src/common.h b/src/common.h
index fe00f7b..c075979 100644
--- a/src/common.h
+++ b/src/common.h
@@ -353,6 +353,24 @@
         LY_CHECK_ERR_RET(!(ARRAY), LOGMEM(CTX), RETVAL); \
         ARRAY = (void*)((uint32_t*)(ARRAY) + 1)
 
+/**
+ * @brief Allocate a ([sized array](@ref sizedarrays)) for the specified number of items.
+ *
+ * Does not set the size information, it is supposed to be incremented via ::LY_ARRAY_INCREMENT
+ * when the items are filled.
+ *
+ * @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
+ * 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).
+ */
+#define LY_ARRAY_CREATE_GOTO(CTX, ARRAY, SIZE, RET, GOTO) \
+        ARRAY = calloc(1, sizeof(uint32_t) + SIZE * sizeof *(ARRAY)); \
+        LY_CHECK_ERR_GOTO(!(ARRAY), LOGMEM(CTX); RET = LY_EMEM, GOTO); \
+        ARRAY = (void*)((uint32_t*)(ARRAY) + 1)
+
 #define LY_ARRAY_INCREMENT(ARRAY) \
         ++(*((uint32_t*)(ARRAY) - 1))
 /**
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 257a259..8c117f1 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -34,6 +34,16 @@
 #define FREE_STRING(CTX, STRING, DICT) if (DICT && STRING) {lydict_remove(CTX, STRING);}
 #define FREE_STRINGS(CTX, ARRAY, DICT) {uint64_t c__; LY_ARRAY_FOR(ARRAY, c__){FREE_STRING(CTX, ARRAY[c__], DICT);}LY_ARRAY_FREE(ARRAY);}
 
+#define COMPILE_ARRAY_GOTO(CTX, ARRAY_P, ARRAY_C, OPTIONS, ITER, FUNC, RET, GOTO) \
+    if (ARRAY_P) { \
+        LY_ARRAY_CREATE_GOTO((CTX).mod->ctx, ARRAY_C, LY_ARRAY_SIZE(ARRAY_P), RET, GOTO); \
+        for (ITER = 0; ITER < LY_ARRAY_SIZE(ARRAY_P); ++ITER) { \
+            RET = FUNC(&(CTX), &(ARRAY_P)[ITER], OPTIONS, &(ARRAY_C)[ITER]); \
+            LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
+            LY_ARRAY_INCREMENT(ARRAY_C); \
+        } \
+    }
+
 static void lysp_grp_free(struct ly_ctx *ctx, struct lysp_grp *grp, int dict);
 static void lysp_node_free(struct ly_ctx *ctx, struct lysp_node *node, int dict);
 
@@ -993,6 +1003,49 @@
 }
 
 static LY_ERR
+lys_compile_import(struct lysc_ctx *ctx, struct lysp_import *imp_p, int options, struct lysc_import *imp)
+{
+    struct lys_module *mod;
+    struct lysc_module *comp;
+
+    if (options & LYSC_OPT_FREE_SP) {
+        /* just switch the pointers */
+        imp->prefix = imp_p->prefix;
+    } else {
+        /* keep refcounts correct for lysp_module_free() */
+        imp->prefix = lydict_insert(ctx->mod->ctx, imp_p->prefix, 0);
+    }
+    imp->module = imp_p->module;
+
+    /* make sure that we have both versions (lysp_ and lysc_) of the imported module. To import groupings or
+     * typedefs, the lysp_ is needed. To augment or deviate imported module, we need the lysc_ structure */
+    if (!imp->module->parsed) {
+        comp = imp->module->compiled;
+        /* try to get filepath from the compiled version */
+        if (comp->filepath) {
+            mod = (struct lys_module*)lys_parse_path(ctx->mod->ctx, comp->filepath,
+                                 !strcmp(&comp->filepath[strlen(comp->filepath - 4)], ".yin") ? LYS_IN_YIN : LYS_IN_YANG);
+            if (mod != imp->module) {
+                LOGERR(ctx->mod->ctx, LY_EINT, "Filepath \"%s\" of the module \"%s\" does not match.",
+                       comp->filepath, comp->name);
+                mod = NULL;
+            }
+        }
+        if (!mod) {
+            if (lysp_load_module(ctx->mod->ctx, comp->name, comp->revs ? comp->revs[0].date : NULL, 0, 1, &mod)) {
+                LOGERR(ctx->mod->ctx, LY_ENOTFOUND, "Unable to reload \"%s\" module to import it into \"%s\", source data not found.",
+                       comp->name, ctx->mod->name);
+                return LY_ENOTFOUND;
+            }
+        }
+    } else if (!imp->module->compiled) {
+        return lys_compile(imp->module->parsed, options, &imp->module->compiled);
+    }
+
+    return LY_SUCCESS;
+}
+
+static LY_ERR
 lys_compile_feature(struct lysc_ctx *ctx, struct lysp_feature *feature_p, int options, struct lysc_feature *feature)
 {
     unsigned int u;
@@ -1053,16 +1106,8 @@
         mod_c->prefix = lydict_insert(sp->ctx, sp->prefix, 0);
     }
 
-    if (sp->features) {
-        /* allocate everything now */
-        LY_ARRAY_CREATE_RET(ctx.mod->ctx, mod_c->features, LY_ARRAY_SIZE(sp->features), LY_EMEM);
-
-        for (u = 0; u < LY_ARRAY_SIZE(sp->features); ++u) {
-            ret = lys_compile_feature(&ctx, &sp->features[u], options, &mod_c->features[u]);
-            LY_CHECK_GOTO(ret != LY_SUCCESS, error);
-            LY_ARRAY_INCREMENT(mod_c->features);
-        }
-    }
+    COMPILE_ARRAY_GOTO(ctx, sp->imports, mod_c->imports, options, u, lys_compile_import, ret, error);
+    COMPILE_ARRAY_GOTO(ctx, sp->features, mod_c->features, options, u, lys_compile_feature, ret, error);
 
     if (options & LYSC_OPT_FREE_SP) {
         lysp_module_free_(sp, 0);
@@ -1072,12 +1117,8 @@
     return LY_SUCCESS;
 
 error:
+    lysc_module_free_(mod_c, (options & LYSC_OPT_FREE_SP) ? 0 : 1);
 
-    if (options & LYSC_OPT_FREE_SP) {
-        lysc_module_free_(mod_c, 0);
-    } else {
-        lysc_module_free_(mod_c, 1);
-    }
     return ret;
 }
 
@@ -1097,7 +1138,7 @@
 struct lys_module *
 lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, const char *revision, int implement)
 {
-    struct lys_module *mod = NULL, *latest;
+    struct lys_module *mod = NULL, *latest, *mod_dup;
     struct lysp_module *latest_p;
     struct lysp_import *imp;
     struct lysp_include *inc;
@@ -1168,16 +1209,26 @@
         }
     } else { /* module */
         /* check for duplicity in the context */
-        if (ly_ctx_get_module(ctx, mod->parsed->name, mod->parsed->revs ? mod->parsed->revs[0].date : NULL)) {
-            if (mod->parsed->revs) {
-                LOGERR(ctx, LY_EEXIST, "Module \"%s\" of revision \"%s\" is already present in the context.",
-                       mod->parsed->name, mod->parsed->revs[0].date);
+        mod_dup = (struct lys_module*)ly_ctx_get_module(ctx, mod->parsed->name, mod->parsed->revs ? mod->parsed->revs[0].date : NULL);
+        if (mod_dup) {
+            if (mod_dup->parsed) {
+                /* error */
+                if (mod->parsed->revs) {
+                    LOGERR(ctx, LY_EEXIST, "Module \"%s\" of revision \"%s\" is already present in the context.",
+                           mod->parsed->name, mod->parsed->revs[0].date);
+                } else {
+                    LOGERR(ctx, LY_EEXIST, "Module \"%s\" with no revision is already present in the context.",
+                           mod->parsed->name);
+                }
+                lys_module_free(mod, NULL);
+                return NULL;
             } else {
-                LOGERR(ctx, LY_EEXIST, "Module \"%s\" with no revision is already present in the context.",
-                       mod->parsed->name);
+                /* add the parsed data to the currently compiled-only module in the context */
+                mod_dup->parsed = mod->parsed;
+                free(mod);
+                mod = mod_dup;
+                goto finish_parsing;
             }
-            lys_module_free(mod, NULL);
-            return NULL;
         }
 
 #if 0
@@ -1214,11 +1265,12 @@
         /* add into context */
         ly_set_add(&ctx->list, mod, LY_SET_OPT_USEASLIST);
 
+finish_parsing:
         /* resolve imports and includes */
         mod->parsed->parsing = 1;
         LY_ARRAY_FOR(mod->parsed->imports, u) {
             imp = &mod->parsed->imports[u];
-            if (!imp->module && lysp_load_module(ctx, imp->name, imp->rev[0] ? imp->rev : NULL, 0, &imp->module)) {
+            if (!imp->module && lysp_load_module(ctx, imp->name, imp->rev[0] ? imp->rev : NULL, 0, 0, &imp->module)) {
                 ly_set_rm(&ctx->list, mod, NULL);
                 lys_module_free(mod, NULL);
                 return NULL;
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 048e87e..ff1d929 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -743,6 +743,7 @@
 struct lysp_module {
     struct ly_ctx *ctx;              /**< libyang context of the module (mandatory) */
     const char *name;                /**< name of the module (mandatory) */
+    const char *filepath;            /**< path, if the schema was read from a file, NULL in case of reading from memory */
     union {
         /* module */
         const char *ns;              /**< namespace of the module (module - mandatory) */
@@ -754,7 +755,6 @@
                                           in the list is always the last (newest) revision of the module */
     struct lysp_import *imports;     /**< list of imported modules ([sized array](@ref sizedarrays)) */
     struct lysp_include *includes;   /**< list of included submodules ([sized array](@ref sizedarrays)) */
-    const char *filepath;            /**< path, if the schema was read from a file, NULL in case of reading from memory */
     const char *org;                 /**< party/company responsible for the module */
     const char *contact;             /**< contact information for the module */
     const char *dsc;                 /**< description of the module */
@@ -793,7 +793,7 @@
  * @brief YANG import-stmt
  */
 struct lysc_import {
-    struct lysc_module *module;      /**< link to the imported module */
+    struct lys_module *module;       /**< link to the imported module */
     const char *prefix;              /**< prefix for the data from the imported schema (mandatory) */
     struct lysp_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
 };
@@ -871,6 +871,7 @@
 struct lysc_module {
     struct ly_ctx *ctx;              /**< libyang context of the module (mandatory) */
     const char *name;                /**< name of the module (mandatory) */
+    const char *filepath;            /**< path, if the schema was read from a file, NULL in case of reading from memory */
     const char *ns;                  /**< namespace of the module (mandatory) */
     const char *prefix;              /**< module prefix (mandatory) */
     struct lysc_revision *revs;      /**< list of the module revisions ([sized array](@ref sizedarrays)), the first revision
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index a9bd79f..e4d26b9 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -120,7 +120,7 @@
 }
 
 LY_ERR
-lysp_load_module(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct lys_module **mod)
+lysp_load_module(struct ly_ctx *ctx, const char *name, const char *revision, int implement, int require_parsed, struct lys_module **mod)
 {
     const char *submodule_data = NULL;
     LYS_INFORMAT format = LYS_IN_UNKNOWN;
@@ -133,7 +133,9 @@
         *mod = (struct lys_module*)ly_ctx_get_module_latest(ctx, name);
     }
 
-    if (!(*mod)) {
+    if (!(*mod) || (require_parsed && !(*mod)->parsed)) {
+        (*mod) = NULL;
+
         /* check collision with other implemented revision */
         if (implement && ly_ctx_get_module_implemented(ctx, name)) {
             LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
@@ -293,7 +295,13 @@
     /* search in imports */
     LY_ARRAY_FOR(mod->imports, struct lysc_import, imp) {
         if (!strncmp(imp->prefix, prefix, len) && mod->prefix[len] == '\0') {
-            return imp->module;
+            if (!imp->module->compiled) {
+                /* shouldn't be needed, the function is internally used when
+                 * the imported modules should be also compiled. But for sure
+                 * and possible future optimizations, check it here */
+                lys_compile(imp->module->parsed, 0, &imp->module->compiled);
+            }
+            return imp->module->compiled;
         }
     }
 
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 58be352..f99d6f6 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -80,10 +80,13 @@
  * @param[in] ctx libyang context.
  * @param[in] name Name of the module to load.
  * @param[in] revison Optional revision of the module to load. If NULL, the newest revision is loaded.
+ * @param[in] implement Flag if the loaded module is supposed to be marked as implemented.
+ * @param[in] require_parsed Flag to require parsed module structure in case the module is already in the context,
+ * but only the compiled structure is available.
  * @param[out] mod Parsed module structure.
  * @return LY_ERR value.
  */
-LY_ERR lysp_load_module(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct lys_module **mod);
+LY_ERR lysp_load_module(struct ly_ctx *ctx, const char *name, const char *revision, int implement, int require_parsed, struct lys_module **mod);
 
 /**
  * @brief Parse included submodule into the simply parsed YANG module.