schema parsers FEATURE processing imports and includes

So far only in parsed structures, not the compiled.
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index 746b7cb..a9bd79f 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -107,8 +107,102 @@
     }
 }
 
+void
+lys_module_implement(struct lys_module *mod)
+{
+    assert(mod);
+    if (mod->parsed) {
+        mod->parsed->implemented = 1;
+    }
+    if (mod->compiled) {
+        mod->compiled->implemented = 1;
+    }
+}
+
 LY_ERR
-lysp_parse_include(struct ly_parser_ctx *ctx, struct lysp_module *mod, const char *name, struct lysp_include *inc)
+lysp_load_module(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct lys_module **mod)
+{
+    const char *submodule_data = NULL;
+    LYS_INFORMAT format = LYS_IN_UNKNOWN;
+    void (*submodule_data_free)(void *module_data, void *user_data) = NULL;
+
+    /* try to get the module from the context */
+    if (revision) {
+        *mod = (struct lys_module*)ly_ctx_get_module(ctx, name, revision);
+    } else {
+        *mod = (struct lys_module*)ly_ctx_get_module_latest(ctx, name);
+    }
+
+    if (!(*mod)) {
+        /* check collision with other implemented revision */
+        if (implement && ly_ctx_get_module_implemented(ctx, name)) {
+            LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
+                   "Module \"%s\" is already present in other implemented revision.", name);
+            return LY_EDENIED;
+        }
+
+        /* submodule not present in the context, get the input data and parse it */
+        if (!(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+search_clb:
+            if (ctx->imp_clb) {
+                if (ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data,
+                                      &format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
+                    *mod = lys_parse_mem_(ctx, submodule_data, format, revision, implement);
+                }
+            }
+            if (!(*mod) && !(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+                goto search_file;
+            }
+        } else {
+search_file:
+            if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
+                /* module was not received from the callback or there is no callback set */
+                lys_module_localfile(ctx, name, revision, implement, mod);
+            }
+            if (!(*mod) && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+                goto search_clb;
+            }
+        }
+    } else {
+        /* we have module from the current context */
+        if (implement && (ly_ctx_get_module_implemented(ctx, name) != *mod)) {
+            /* check collision with other implemented revision */
+            LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
+                   "Module \"%s\" is already present in other implemented revision.", name);
+            *mod = NULL;
+            return LY_EDENIED;
+        }
+
+        /* circular check */
+        if ((*mod)->parsed->parsing) {
+            LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (import) for module \"%s\".", name);
+            *mod = NULL;
+            return LY_EVALID;
+        }
+    }
+    if (!(*mod)) {
+        if (ly_errcode(ctx) != LY_EVALID) {
+            LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, strlen(name), name, "import");
+        } else {
+            LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Loading \"%s\" module failed.", name);
+        }
+        return LY_EVALID;
+    }
+
+    if (implement) {
+        /* mark the module implemented, check for collision was already done */
+        lys_module_implement(*mod);
+    }
+    if (!revision && ((*mod)->parsed->latest_revision == 1)) {
+        /* update the latest_revision flag - here we have selected the latest available schema */
+        (*mod)->parsed->latest_revision = 2;
+    }
+
+    return LY_SUCCESS;
+}
+
+LY_ERR
+lysp_load_submodule(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
 {
     struct lys_module *submod;
     const char *submodule_data = NULL;
@@ -116,30 +210,27 @@
     void (*submodule_data_free)(void *module_data, void *user_data) = NULL;
 
     /* Try to get submodule from the context, if already present */
-    inc->submodule = ly_ctx_get_submodule(ctx->ctx, mod->name, name, inc->rev[0] ? inc->rev : NULL);
+    inc->submodule = ly_ctx_get_submodule(ctx, mod->name, inc->name, inc->rev[0] ? inc->rev : NULL);
     if (!inc->submodule) {
         /* submodule not present in the context, get the input data and parse it */
-        if (!(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+        if (!(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
 search_clb:
-            if (ctx->ctx->imp_clb) {
-                if (ctx->ctx->imp_clb(mod->name, NULL, name, inc->rev[0] ? inc->rev : NULL, ctx->ctx->imp_clb_data,
+            if (ctx->imp_clb) {
+                if (ctx->imp_clb(mod->name, NULL, inc->name, inc->rev[0] ? inc->rev : NULL, ctx->imp_clb_data,
                                       &format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
-                    submod = lys_parse_mem_(ctx->ctx, submodule_data, format, inc->rev[0] ? inc->rev : NULL, mod->implemented);
+                    submod = lys_parse_mem_(ctx, submodule_data, format, inc->rev[0] ? inc->rev : NULL, mod->implemented);
                 }
             }
-            if (!submod && !(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+            if (!submod && !(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
                 goto search_file;
             }
         } else {
 search_file:
-            if (!(ctx->ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
+            if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
                 /* module was not received from the callback or there is no callback set */
-                lys_module_localfile(ctx->ctx, name, inc->rev[0] ? inc->rev : NULL, mod->implemented, &submod);
-                if (inc->submodule) {
-                    ++inc->submodule->refcount;
-                }
+                lys_module_localfile(ctx, inc->name, inc->rev[0] ? inc->rev : NULL, mod->implemented, &submod);
             }
-            if (!submod && (ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+            if (!submod && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
                 goto search_clb;
             }
         }
@@ -147,16 +238,24 @@
             /* check that we have really a submodule */
             if (!submod->parsed->submodule) {
                 /* submodule is not a submodule */
-                LOGVAL_YANG(ctx, LYVE_REFERENCE, "Included \"%s\" schema from \"%s\" is actually not a submodule.", name, mod->name);
+                LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Included \"%s\" schema from \"%s\" is actually not a submodule.",
+                       inc->name, mod->name);
                 lys_module_free(submod, NULL);
                 /* fix list of modules in context, since it was already changed */
-                --ctx->ctx->list.count;
+                --ctx->list.count;
                 return LY_EVALID;
             }
             /* check that the submodule belongs-to our module */
             if (strcmp(mod->name, submod->parsed->belongsto)) {
-                LOGVAL_YANG(ctx, LYVE_REFERENCE, "Included \"%s\" submodule from \"%s\" belongs-to a different module \"%s\".",
-                            name, mod->name, submod->parsed->belongsto);
+                LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Included \"%s\" submodule from \"%s\" belongs-to a different module \"%s\".",
+                       inc->name, mod->name, submod->parsed->belongsto);
+                lys_module_free(submod, NULL);
+                return LY_EVALID;
+            }
+            /* check circular dependency */
+            if (submod->parsed->parsing) {
+                LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (include) for module \"%s\".",
+                       submod->parsed->name);
                 lys_module_free(submod, NULL);
                 return LY_EVALID;
             }
@@ -168,10 +267,10 @@
         ++inc->submodule->refcount;
     }
     if (!inc->submodule) {
-        if (ly_errcode(ctx->ctx) != LY_EVALID) {
-            LOGVAL_YANG(ctx, LY_VCODE_INVAL, strlen(name), name, "include");
+        if (ly_errcode(ctx) != LY_EVALID) {
+            LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Invalid value \"%s\" of include statement.", inc->name);
         } else {
-            LOGVAL_YANG(ctx, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.", name, mod->name);
+            LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.", inc->name, mod->name);
         }
         return LY_EVALID;
     }