schema compile REFACTOR split implementing and compiling schemas

Difference being that implementing checks that a new
module can be implemented and performs one-time compilation
tasks such as compiling identities and adding its references
to augment and eviation target modules, which are also
implemented. Compilation then actually creates the compiled
module and can be performed in each recompilation.
diff --git a/src/path.c b/src/path.c
index 293c1e5..1fd57d3 100644
--- a/src/path.c
+++ b/src/path.c
@@ -433,6 +433,7 @@
 
             assert(unres);
             LY_CHECK_GOTO(ret = lys_implement((struct lys_module *)*mod, NULL, unres), error);
+            LY_CHECK_GOTO(ret = lys_compile((struct lys_module *)*mod, &unres->ds_unres), error);
         }
 
         LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
diff --git a/src/plugins_types.c b/src/plugins_types.c
index df33bd4..24dec93 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -755,7 +755,10 @@
         return LY_SUCCESS;
     }
 
-    return lys_implement(mod, features, unres);
+    LY_CHECK_RET(lys_implement(mod, features, unres));
+    LY_CHECK_RET(lys_compile(mod, &unres->ds_unres));
+
+    return LY_SUCCESS;
 }
 
 API LY_ERR
diff --git a/src/schema_compile.c b/src/schema_compile.c
index 2b9efe7..1e18c00 100644
--- a/src/schema_compile.c
+++ b/src/schema_compile.c
@@ -838,6 +838,7 @@
             /* unimplemented module found */
             if (implement) {
                 LY_CHECK_RET(lys_implement((struct lys_module *)mod, NULL, unres));
+                LY_CHECK_RET(lys_compile((struct lys_module *)mod, &unres->ds_unres));
             } else {
                 *mod_p = mod;
                 break;
@@ -1692,13 +1693,6 @@
         return ret;
     }
 
-    /* compile identities */
-    LY_CHECK_RET(lys_compile_identities(mod));
-
-    /* mark target modules with our augments and deviations */
-    ret = lys_precompile_augments_deviations(mod, unres);
-    LY_CHECK_RET(ret && (ret != LY_ERECOMPILE), ret);
-
     /*
      * mark the module implemented, which means
      * 1) to (re)compile it only ::lys_compile() call is needed
@@ -1707,23 +1701,20 @@
      */
     mod->implemented = 1;
 
+    /* this module is compiled in this compilation */
+    mod->to_compile = 1;
+
     /* add the module into newly implemented module set */
     LY_CHECK_RET(ly_set_add(&unres->implementing, mod, 1, NULL));
 
-    if (mod->ctx->flags & LY_CTX_EXPLICIT_COMPILE) {
-        /* do not actually compile the module yet */
-        mod->to_compile = 1;
-        return LY_SUCCESS;
-    } else if (ret == LY_ERECOMPILE) {
-        /* we cannot compile the module yet */
-        return ret;
-    }
+    /* compile identities */
+    LY_CHECK_RET(lys_compile_identities(mod));
+
+    /* mark target modules with our augments and deviations */
+    LY_CHECK_RET(lys_precompile_augments_deviations(mod, unres));
 
     /* check whether this module may reference any modules compiled previously */
     LY_CHECK_RET(lys_has_compiled_import_r(mod));
 
-    /* compile the schema */
-    LY_CHECK_RET(lys_compile(mod, unres));
-
     return LY_SUCCESS;
 }
diff --git a/src/schema_compile.h b/src/schema_compile.h
index de61cc3..a0cdadf 100644
--- a/src/schema_compile.h
+++ b/src/schema_compile.h
@@ -201,6 +201,17 @@
         struct lysc_ident *ident, struct lysc_ident ***bases, ly_bool *enabled);
 
 /**
+ * @brief Compile schema into a validated schema linking all the references. Must have been implemented before.
+ *
+ * @param[in] mod Pointer to the schema structure holding pointers to both schema structure types. The ::lys_module#parsed
+ * member is used as input and ::lys_module#compiled is used to hold the result of the compilation.
+ * @param[in,out] unres Dep set unres structure to add to.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR on error.
+ */
+LY_ERR lys_compile(struct lys_module *mod, struct lys_depset_unres *unres);
+
+/**
  * @brief Check statement's status for invalid combination.
  *
  * The modX parameters are used just to determine if both flags are in the same module,
@@ -288,15 +299,12 @@
 LY_ERR lys_recompile(struct ly_ctx *ctx);
 
 /**
- * @brief Implement a single module, can be called recursively.
+ * @brief Implement a single module. Does not actually compile, only marks to_compile!
  *
  * @param[in] mod Module to implement.
  * @param[in] features Features to set, see ::lys_set_features().
- * @param[in,out] unres Global unres to add to.
- * @return LY_SUCCESS on success.
- * @return LY_ERECOMPILE on required recompilation, @p mod implemented flag is kept and
- * is left in @p unres implementing set so that it is known that the next compilation is recompilation.
- * @return LY_ERR on error.
+ * @param[in,out] unres Global unres to use.
+ * @return LY_ERR value.
  */
 LY_ERR lys_implement(struct lys_module *mod, const char **features, struct lys_glob_unres *unres);
 
diff --git a/src/schema_compile_amend.c b/src/schema_compile_amend.c
index 3a710e9..01eb98c 100644
--- a/src/schema_compile_amend.c
+++ b/src/schema_compile_amend.c
@@ -2176,14 +2176,14 @@
 LY_ERR
 lys_precompile_augments_deviations(struct lys_module *mod, struct lys_glob_unres *unres)
 {
-    LY_ERR ret = LY_SUCCESS;
+    LY_ERR ret = LY_SUCCESS, r;
     LY_ARRAY_COUNT_TYPE u, v;
     struct lysc_ctx ctx = {0};
     struct lysp_module *mod_p;
     struct lys_module *m;
     struct lysp_submodule *submod;
     struct lysp_node_augment *aug;
-    uint32_t idx;
+    uint32_t i;
     struct ly_set mod_set = {0}, set = {0};
 
     mod_p = mod->parsed;
@@ -2194,7 +2194,6 @@
     ctx.pmod = mod_p;
     ctx.path_len = 1;
     ctx.path[0] = '/';
-    ctx.unres = unres;
 
     LY_LIST_FOR(mod_p->augments, aug) {
         /* get target module */
@@ -2266,31 +2265,35 @@
         }
     }
 
-    if (mod_set.count) {
-        /* descending order to make sure the modules are implemented in the right order */
-        idx = mod_set.count;
-        do {
-            --idx;
-            m = mod_set.objs[idx];
+    for (i = 0; i < mod_set.count; ++i) {
+        m = mod_set.objs[i];
 
-            if (m == mod) {
-                /* will be applied normally later */
+        if (m == mod) {
+            /* will be applied normally later */
+            continue;
+        }
+
+        /* we do not actually need the target modules compiled with out amends, they just need to be implemented
+         * not compiled yet and marked for compilation */
+
+        if (!m->implemented) {
+            /* implement the target module */
+            r = lys_implement(m, NULL, unres);
+            if (r == LY_ERECOMPILE) {
+                /* implement all the modules right away to save possible later recompilation */
+                ret = r;
                 continue;
-            }
-
-            if (!m->implemented) {
-                /* implement (compile) the target module with our augments/deviations */
-                LY_CHECK_GOTO(ret = lys_implement(m, NULL, unres), cleanup);
-            } else if (m->compiled) {
-                /* target module was already compiled without our amends (augment/deviation), we need to recompile it */
-                ret = LY_ERECOMPILE;
+            } else if (r) {
+                /* error */
+                ret = r;
                 goto cleanup;
             }
-            /* else the module is implemented and was compiled in this compilation run or will yet be;
-             * we actually do not need the module compiled now because its compiled nodes will not be accessed,
-             * augments/deviations are applied during the target module compilation and the rest is in global unres */
-
-        } while (idx);
+        } else if (m->compiled) {
+            /* target module was already compiled without our amends (augment/deviation), we need to recompile it */
+            m->to_compile = 1;
+            ret = LY_ERECOMPILE;
+            continue;
+        }
     }
 
 cleanup:
diff --git a/src/schema_compile_amend.h b/src/schema_compile_amend.h
index 3dca22c..0ad49b4 100644
--- a/src/schema_compile_amend.h
+++ b/src/schema_compile_amend.h
@@ -156,11 +156,11 @@
 LY_ERR lys_precompile_own_deviations(struct lysc_ctx *ctx);
 
 /**
- * @brief Compile top-level augments and deviations in a module and all its submodules.
- * Adds the module reference to the target modules and if not implemented, implement them.
+ * @brief Add references to target modules of top-level augments and deviations in a module and all its submodules.
+ * Adds the module reference to the target modules and if not implemented, implement them (but not compile).
  *
  * @param[in] mod Module to process.
- * @param[in] unres Global unres to use.
+ * @param[in,out] unres Global unres to use.
  * @return LY_SUCCESS on success.
  * @return LY_ERECOMPILE on required recompilation.
  * @return LY_ERR on error.
diff --git a/tests/utests/basic/test_context.c b/tests/utests/basic/test_context.c
index a1c9e3b..ff755ad 100644
--- a/tests/utests/basic/test_context.c
+++ b/tests/utests/basic/test_context.c
@@ -241,9 +241,6 @@
 
     assert_int_equal(LY_SUCCESS, ly_in_new_memory("module a {namespace urn:a;prefix a;include y;revision 2018-10-30; }", &in));
     assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod1));
-    assert_int_equal(LY_SUCCESS, lys_implement(mod1, NULL, &unres));
-    assert_int_equal(LY_SUCCESS, lys_compile_unres_glob(UTEST_LYCTX, &unres));
-    lys_compile_unres_glob_erase(UTEST_LYCTX, &unres, 0);
     ly_in_free(in, 0);
     assert_int_equal(LY_SUCCESS, ly_in_new_memory("module y {namespace urn:y;prefix y;}", &in));
     assert_int_equal(LY_EVALID, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod1));
@@ -271,11 +268,8 @@
 
     /* reloading module in case only the compiled module resists in the context */
     assert_int_equal(LY_SUCCESS, ly_in_new_memory("module w {namespace urn:w;prefix w;revision 2018-10-24;}", &in));
-    assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod1));
+    assert_int_equal(LY_SUCCESS, lys_parse(UTEST_LYCTX, in, LYS_IN_YANG, NULL, (const struct lys_module **)&mod1));
     ly_in_free(in, 0);
-    assert_int_equal(LY_SUCCESS, lys_implement(mod1, NULL, &unres));
-    assert_int_equal(LY_SUCCESS, lys_compile_unres_glob(UTEST_LYCTX, &unres));
-    lys_compile_unres_glob_erase(UTEST_LYCTX, &unres, 0);
     assert_non_null(mod1->compiled);
     assert_non_null(mod1->parsed);
 
@@ -294,10 +288,7 @@
 
     assert_int_equal(LY_SUCCESS, ly_in_new_memory("module z {namespace urn:z;prefix z;import w {prefix w;revision-date 2018-10-24;}}", &in));
     ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "module w {namespace urn:w;prefix w;revision 2018-10-24;}");
-    assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod2));
-    assert_int_equal(LY_SUCCESS, _lys_set_implemented(mod2, NULL, &unres));
-    assert_int_equal(LY_SUCCESS, lys_compile_unres_glob(UTEST_LYCTX, &unres));
-    lys_compile_unres_glob_erase(UTEST_LYCTX, &unres, 0);
+    assert_int_equal(LY_SUCCESS, lys_parse(UTEST_LYCTX, in, LYS_IN_YANG, NULL, (const struct lys_module **)&mod2));
     ly_in_free(in, 0);
     assert_non_null(mod2);
     assert_non_null(mod1->parsed);
@@ -391,10 +382,7 @@
     assert_non_null(ly_ctx_get_module_ns(UTEST_LYCTX, "urn:ietf:params:xml:ns:yang:ietf-datastores", "2018-02-14"));
 
     /* select module by revision */
-    assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in1, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod));
-    assert_int_equal(LY_SUCCESS, lys_implement(mod, NULL, &unres));
-    assert_int_equal(LY_SUCCESS, lys_compile_unres_glob(UTEST_LYCTX, &unres));
-    lys_compile_unres_glob_erase(UTEST_LYCTX, &unres, 0);
+    assert_int_equal(LY_SUCCESS, lys_parse(UTEST_LYCTX, in1, LYS_IN_YANG, NULL, (const struct lys_module **)&mod));
     /* invalid attempts - implementing module of the same name and inserting the same module */
     assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in2, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod2));
     assert_int_equal(LY_EDENIED, lys_implement(mod2, NULL, &unres));
diff --git a/tests/utests/schema/test_tree_schema_compile.c b/tests/utests/schema/test_tree_schema_compile.c
index 227f7d2..efbff1b 100644
--- a/tests/utests/schema/test_tree_schema_compile.c
+++ b/tests/utests/schema/test_tree_schema_compile.c
@@ -81,9 +81,7 @@
     lys_compile_unres_glob_erase(UTEST_LYCTX, &unres, 0);
     ly_in_free(in, 0);
     assert_int_equal(0, mod->implemented);
-    assert_int_equal(LY_SUCCESS, lys_implement(mod, NULL, &unres));
-    assert_int_equal(LY_SUCCESS, lys_compile_unres_glob(UTEST_LYCTX, &unres));
-    lys_compile_unres_glob_erase(UTEST_LYCTX, &unres, 0);
+    assert_int_equal(LY_SUCCESS, lys_set_implemented(mod, NULL));
     assert_non_null(mod->compiled);
     assert_string_equal("test", mod->name);
     assert_string_equal("urn:test", mod->ns);
@@ -111,11 +109,9 @@
     /* data definition name collision in top level */
     str = "module aa {namespace urn:aa;prefix aa; leaf a {type string;} container a{presence x;}}";
     assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
-    assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod));
-    assert_int_equal(LY_EEXIST, lys_implement(mod, NULL, &unres));
-    CHECK_LOG_CTX("Duplicate identifier \"a\" of data definition/RPC/action/notification statement.", "/aa:a");
-    lys_compile_unres_glob_erase(UTEST_LYCTX, &unres, 0);
+    assert_int_equal(LY_EEXIST, lys_parse(UTEST_LYCTX, in, LYS_IN_YANG, NULL, (const struct lys_module **)&mod));
     ly_in_free(in, 0);
+    CHECK_LOG_CTX("Duplicate identifier \"a\" of data definition/RPC/action/notification statement.", "/aa:a");
 }
 
 static void