schema compile CHANGE better handling of features

- allow forward reference in feature's if-feature statements
- handling features of not implemented modules - all such features
are permanently disabled, but the structures must be available for
the implemented (compiled) modules which import their module.
diff --git a/src/tree_schema.c b/src/tree_schema.c
index c3a4d2d..6fba4d6 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -241,24 +241,29 @@
  * if-feature statements are again evaluated (disabled if a if-feature statemen
  * evaluates to false).
  *
- * @param[in] mod Compiled module where to set (search for) the feature.
+ * @param[in] mod Module where to set (search for) the feature.
  * @param[in] name Name of the feature to set. Asterisk ('*') can be used to
  * set all the features in the module.
  * @param[in] value Desired value of the feature: 1 (enable) or 0 (disable).
  * @return LY_ERR value.
  */
 static LY_ERR
-lys_feature_change(const struct lysc_module *mod, const char *name, int value)
+lys_feature_change(const struct lys_module *mod, const char *name, int value)
 {
     int all = 0;
     unsigned int u, changed_count, disabled_count;
     struct lysc_feature *f, **df;
     struct lysc_iffeature *iff;
     struct ly_set *changed;
-    struct ly_ctx *ctx = mod->mod->ctx; /* shortcut */
+    struct ly_ctx *ctx = mod->ctx; /* shortcut */
 
-    if (!mod->features) {
-        LOGERR(ctx, LY_EINVAL, "Unable to switch feature since the module \"%s\" has no features.", mod->mod->name);
+    if (!mod->compiled) {
+        LOGERR(ctx, LY_EINVAL, "Module \"%s\" is not implemented so all its features are permanently disabled without a chance to change it.",
+               mod->name);
+        return LY_EINVAL;
+    }
+    if (!mod->compiled->features) {
+        LOGERR(ctx, LY_EINVAL, "Unable to switch feature since the module \"%s\" has no features.", mod->name);
         return LY_EINVAL;
     }
 
@@ -270,8 +275,8 @@
     changed_count = 0;
 
 run:
-    for (disabled_count = u = 0; u < LY_ARRAY_SIZE(mod->features); ++u) {
-        f = &mod->features[u];
+    for (disabled_count = u = 0; u < LY_ARRAY_SIZE(mod->compiled->features); ++u) {
+        f = &mod->compiled->features[u];
         if (all || !strcmp(f->name, name)) {
             if ((value && (f->flags & LYS_FENABLED)) || (!value && !(f->flags & LYS_FENABLED))) {
                 if (all) {
@@ -320,7 +325,7 @@
     }
 
     if (!all && !changed->count) {
-        LOGERR(ctx, LY_EINVAL, "Feature \"%s\" not found in module \"%s\".", name, mod->mod->name);
+        LOGERR(ctx, LY_EINVAL, "Feature \"%s\" not found in module \"%s\".", name, mod->name);
         ly_set_free(changed, NULL);
         return LY_EINVAL;
     }
@@ -329,11 +334,11 @@
         if (changed_count == changed->count) {
             /* no change in last run -> not able to enable all ... */
             /* ... print errors */
-            for (u = 0; disabled_count && u < LY_ARRAY_SIZE(mod->features); ++u) {
-                if (!(mod->features[u].flags & LYS_FENABLED)) {
+            for (u = 0; disabled_count && u < LY_ARRAY_SIZE(mod->compiled->features); ++u) {
+                if (!(mod->compiled->features[u].flags & LYS_FENABLED)) {
                     LOGERR(ctx, LY_EDENIED,
                            "Feature \"%s\" cannot be enabled since it is disabled by its if-feature condition(s).",
-                           mod->features[u].name);
+                           mod->compiled->features[u].name);
                     --disabled_count;
                 }
             }
@@ -384,17 +389,17 @@
 API LY_ERR
 lys_feature_enable(struct lys_module *module, const char *feature)
 {
-    LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, LY_EINVAL);
+    LY_CHECK_ARG_RET(NULL, module, feature, LY_EINVAL);
 
-    return lys_feature_change(module->compiled, feature, 1);
+    return lys_feature_change(module, feature, 1);
 }
 
 API LY_ERR
 lys_feature_disable(struct lys_module *module, const char *feature)
 {
-    LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, LY_EINVAL);
+    LY_CHECK_ARG_RET(NULL, module, feature, LY_EINVAL);
 
-    return lys_feature_change(module->compiled, feature, 0);
+    return lys_feature_change(module, feature, 0);
 }
 
 API int
@@ -560,6 +565,9 @@
 
     /* make sure that the newest revision is at position 0 */
     lysp_sort_revisions(mod->parsed->revs);
+    if (mod->parsed->revs) {
+        mod->revision = lydict_insert(ctx, mod->parsed->revs[0].date, 0);
+    }
 
     if (custom_check) {
         LY_CHECK_GOTO(custom_check(ctx, mod->parsed, NULL, check_data), error);
@@ -575,7 +583,7 @@
     }
 
     /* check for duplicity in the context */
-    mod_dup = (struct lys_module*)ly_ctx_get_module(ctx, mod->name, mod->parsed->revs ? mod->parsed->revs[0].date : NULL);
+    mod_dup = (struct lys_module*)ly_ctx_get_module(ctx, mod->name, mod->revision);
     if (mod_dup) {
         if (mod_dup->parsed) {
             /* error */
@@ -612,15 +620,20 @@
     }
 #endif
 
+    if (!mod->implemented) {
+        /* pre-compile features of the module */
+        LY_CHECK_GOTO(lys_feature_precompile(ctx, mod->parsed->features, &mod->off_features), error);
+    }
+
     /* decide the latest revision */
     latest = (struct lys_module*)ly_ctx_get_module_latest(ctx, mod->name);
     if (latest) {
-        if (mod->parsed->revs) {
-            if ((latest->parsed && !latest->parsed->revs) || (!latest->parsed && !latest->compiled->revision)) {
+        if (mod->revision) {
+            if (!latest->revision) {
                 /* latest has no revision, so mod is anyway newer */
                 mod->latest_revision = latest->latest_revision;
                 latest->latest_revision = 0;
-            } else if (strcmp(mod->parsed->revs[0].date, latest->parsed ? latest->parsed->revs[0].date : latest->compiled->revision) > 0) {
+            } else if (strcmp(mod->revision, latest->revision) > 0) {
                 mod->latest_revision = latest->latest_revision;
                 latest->latest_revision = 0;
             }
@@ -653,6 +666,10 @@
         if (!inc->submodule && lysp_load_submodule(&context, mod->parsed, inc)) {
             goto error_ctx;
         }
+        if (!mod->implemented) {
+            /* pre-compile features of the module */
+            LY_CHECK_GOTO(lys_feature_precompile(ctx, inc->submodule->features, &mod->off_features), error);
+        }
     }
     mod->parsed->parsing = 0;