schema CHANGE more strict recompilation rules
The general idea now is that whenever a module
is being compiled that imports any implemented
and compiled modules, the compilation is refused
and the whole context is recompiled instead.
It is connected with the following change that
will keep disabled nodes in the compiled modules
and remove them at the whole compilation end
so they can be referenced by other modules.
diff --git a/src/context.c b/src/context.c
index 7ed97c7..5ff7380 100644
--- a/src/context.c
+++ b/src/context.c
@@ -503,7 +503,7 @@
}
/* recompile */
- LY_CHECK_RET(lys_recompile(ctx, 0));
+ LY_CHECK_RET(lys_recompile(ctx, 1));
/* everything is fine, clear the flags */
for (i = 0; i < ctx->list.count; ++i) {
diff --git a/src/log.h b/src/log.h
index 090d1aa..06d4357 100644
--- a/src/log.h
+++ b/src/log.h
@@ -249,8 +249,10 @@
LY_EINT, /**< Internal error */
LY_EVALID, /**< Validation failure */
LY_EDENIED, /**< Operation is not allowed */
- LY_EINCOMPLETE, /**< The operation did not failed, but for some reason it was not possible to finish it completely.
+ LY_EINCOMPLETE, /**< The operation did not fail, but for some reason it was not possible to finish it completely.
According to the specific use case, the caller is usually supposed to perform the operation again. */
+ LY_ERECOMPILE, /**< The operation did not fail, but requires context recompilation before it can be completed.
+ According to the specific use case, the caller should react appropriately. */
LY_ENOT, /**< Negative result */
LY_EOTHER, /**< Unknown error */
diff --git a/src/plugins_types.c b/src/plugins_types.c
index 9adb3b3..393cd66 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -737,7 +737,13 @@
API LY_ERR
lyplg_type_make_implemented(struct lys_module *mod, const char **features, struct lys_glob_unres *unres)
{
- return lys_set_implemented_r(mod, features, unres);
+ LY_CHECK_RET(lys_set_implemented_r(mod, features, unres));
+
+ if (unres->recompile) {
+ return LY_ERECOMPILE;
+ }
+
+ return LY_SUCCESS;
}
API LY_ERR
diff --git a/src/schema_compile.c b/src/schema_compile.c
index e9b7202..aa3b2af 100644
--- a/src/schema_compile.c
+++ b/src/schema_compile.c
@@ -1097,7 +1097,10 @@
options = (ctx->ctx->flags & LY_CTX_REF_IMPLEMENTED) ? LYPLG_TYPE_STORE_IMPLEMENT : 0;
ret = type->plugin->store(ctx->ctx, type, dflt, strlen(dflt), options, LY_PREF_SCHEMA, (void *)dflt_pmod,
LYD_HINT_SCHEMA, node, storage, unres, &err);
- if (ret == LY_EINCOMPLETE) {
+ if (ret == LY_ERECOMPILE) {
+ /* fine, but we need to recompile */
+ return LY_ERECOMPILE;
+ } else if (ret == LY_EINCOMPLETE) {
/* we have no data so we will not be resolving it */
ret = LY_SUCCESS;
}
@@ -1327,14 +1330,14 @@
ret = lys_compile_unres_llist_dflts(&cctx, r->llist, r->dflt, r->dflts, unres);
}
LOG_LOCBACK(1, 0, 0, 0);
- LY_CHECK_RET(ret);
+ LY_CHECK_RET(ret && (ret != LY_ERECOMPILE), ret);
lysc_unres_dflt_free(ctx, r);
ly_set_rm_index(&unres->dflts, unres->dflts.count - 1, NULL);
}
- /* some unres items may have been added */
- if (unres->leafrefs.count || unres->xpath.count || unres->dflts.count) {
+ /* some unres items may have been added or recompilation needed */
+ if (unres->leafrefs.count || unres->xpath.count || unres->dflts.count || unres->recompile) {
return lys_compile_unres_glob(ctx, unres);
}
@@ -1509,13 +1512,12 @@
LY_CHECK_RET(lys_identity_precompile(ctx, NULL, NULL, submod->identities, &ctx->cur_mod->identities));
}
}
-
if (ctx->cur_mod->parsed->identities) {
LY_CHECK_RET(lys_compile_identities_derived(ctx, ctx->cur_mod->parsed->identities, &ctx->cur_mod->identities));
}
+
lysc_update_path(ctx, NULL, "{submodule}");
LY_ARRAY_FOR(ctx->cur_mod->parsed->includes, u) {
-
submod = ctx->cur_mod->parsed->includes[u].submodule;
if (submod->identities) {
lysc_update_path(ctx, NULL, submod->name);
@@ -1537,6 +1539,9 @@
LY_ERR ret = LY_SUCCESS;
uint32_t prev_lo = 0;
+ /* we are always recompiling all the modules */
+ unres.full_compilation = 1;
+
if (!log) {
/* recompile, must succeed because the modules were already compiled; hide messages because any
* warnings were already printed, are not really relevant, and would hide the real error */
@@ -1572,6 +1577,12 @@
}
goto cleanup;
}
+
+ if (unres.recompile) {
+ /* we need to recompile again (newly compiled module caused another new implemented module) */
+ ret = lys_recompile(ctx, log);
+ goto cleanup;
+ }
}
/* resolve global unres */
@@ -1585,6 +1596,35 @@
return ret;
}
+/**
+ * @brief Check whether a module does not have any (recursive) compiled import.
+ *
+ * @param[in] mod Module to examine.
+ * @return Whether the module has a compiled imported module.
+ */
+static ly_bool
+lys_has_compiled_import_r(struct lys_module *mod)
+{
+ LY_ARRAY_COUNT_TYPE u;
+
+ LY_ARRAY_FOR(mod->parsed->imports, u) {
+ if (!mod->parsed->imports[u].module->implemented) {
+ continue;
+ }
+
+ if (mod->parsed->imports[u].module->compiled) {
+ return 1;
+ }
+
+ /* recursive */
+ if (lys_has_compiled_import_r(mod->parsed->imports[u].module)) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
LY_ERR
lys_compile(struct lys_module *mod, uint32_t options, struct lys_glob_unres *unres)
{
@@ -1599,11 +1639,24 @@
LY_CHECK_ARG_RET(NULL, mod, mod->parsed, !mod->compiled, mod->ctx, LY_EINVAL);
+ /* if some previous module was not fully compiled, it is forbidden to compile another one (even though it
+ * may be okay in some cases) */
+ assert(!unres->recompile);
+
if (!mod->implemented) {
/* just imported modules are not compiled */
return LY_SUCCESS;
}
+ if (!unres->full_compilation) {
+ /* check whether this module may reference any already-compiled modules */
+ if (lys_has_compiled_import_r(mod)) {
+ /* it may and we need even disabled nodes in those modules, recompile them */
+ unres->recompile = 1;
+ return LY_SUCCESS;
+ }
+ }
+
/* context will be changed */
++mod->ctx->change_count;
@@ -1623,36 +1676,41 @@
/* process imports */
LY_ARRAY_FOR(sp->imports, u) {
- LY_CHECK_GOTO(ret = lys_compile_import(&ctx, &sp->imports[u]), error);
+ LY_CHECK_GOTO(ret = lys_compile_import(&ctx, &sp->imports[u]), cleanup);
}
/* identities */
- LY_CHECK_GOTO(ret = lys_compile_identities(&ctx), error);
+ LY_CHECK_GOTO(ret = lys_compile_identities(&ctx), cleanup);
/* augments and deviations */
- LY_CHECK_GOTO(ret = lys_precompile_augments_deviations(&ctx), error);
+ LY_CHECK_GOTO(ret = lys_precompile_augments_deviations(&ctx), cleanup);
+
+ if (unres->recompile) {
+ /* some augments/deviations may not be possible to apply when the whole compilation may fail */
+ goto cleanup;
+ }
/* compile augments and deviations of our module from other modules so they can be applied during compilation */
- LY_CHECK_GOTO(ret = lys_precompile_own_augments(&ctx), error);
- LY_CHECK_GOTO(ret = lys_precompile_own_deviations(&ctx), error);
+ LY_CHECK_GOTO(ret = lys_precompile_own_augments(&ctx), cleanup);
+ LY_CHECK_GOTO(ret = lys_precompile_own_deviations(&ctx), cleanup);
/* data nodes */
LY_LIST_FOR(sp->data, pnode) {
- LY_CHECK_GOTO(ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL), error);
+ LY_CHECK_GOTO(ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL), cleanup);
}
/* top-level RPCs */
LY_LIST_FOR((struct lysp_node *)sp->rpcs, pnode) {
- LY_CHECK_GOTO(ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL), error);
+ LY_CHECK_GOTO(ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL), cleanup);
}
/* top-level notifications */
LY_LIST_FOR((struct lysp_node *)sp->notifs, pnode) {
- LY_CHECK_GOTO(ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL), error);
+ LY_CHECK_GOTO(ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL), cleanup);
}
/* extension instances */
- COMPILE_EXTS_GOTO(&ctx, sp->exts, mod_c->exts, mod_c, ret, error);
+ COMPILE_EXTS_GOTO(&ctx, sp->exts, mod_c->exts, mod_c, ret, cleanup);
/* the same for submodules */
LY_ARRAY_FOR(sp->includes, u) {
@@ -1661,20 +1719,20 @@
LY_LIST_FOR(submod->data, pnode) {
ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL);
- LY_CHECK_GOTO(ret, error);
+ LY_CHECK_GOTO(ret, cleanup);
}
LY_LIST_FOR((struct lysp_node *)submod->rpcs, pnode) {
ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL);
- LY_CHECK_GOTO(ret, error);
+ LY_CHECK_GOTO(ret, cleanup);
}
LY_LIST_FOR((struct lysp_node *)submod->notifs, pnode) {
ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL);
- LY_CHECK_GOTO(ret, error);
+ LY_CHECK_GOTO(ret, cleanup);
}
- COMPILE_EXTS_GOTO(&ctx, submod->exts, mod_c->exts, mod_c, ret, error);
+ COMPILE_EXTS_GOTO(&ctx, submod->exts, mod_c->exts, mod_c, ret, cleanup);
}
ctx.pmod = sp;
@@ -1683,13 +1741,13 @@
ctx.options |= LYS_COMPILE_GROUPING;
LY_LIST_FOR(sp->groupings, grp) {
if (!(grp->flags & LYS_USED_GRP)) {
- LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, NULL, grp), error);
+ LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, NULL, grp), cleanup);
}
}
LY_LIST_FOR(sp->data, pnode) {
LY_LIST_FOR((struct lysp_node_grp *)lysp_node_groupings(pnode), grp) {
if (!(grp->flags & LYS_USED_GRP)) {
- LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, grp), error);
+ LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, grp), cleanup);
}
}
}
@@ -1699,13 +1757,13 @@
LY_LIST_FOR(submod->groupings, grp) {
if (!(grp->flags & LYS_USED_GRP)) {
- LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, NULL, grp), error);
+ LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, NULL, grp), cleanup);
}
}
LY_LIST_FOR(submod->data, pnode) {
LY_LIST_FOR((struct lysp_node_grp *)lysp_node_groupings(pnode), grp) {
if (!(grp->flags & LYS_USED_GRP)) {
- LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, grp), error);
+ LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, grp), cleanup);
}
}
}
@@ -1715,17 +1773,15 @@
LOG_LOCBACK(0, 0, 1, 0);
/* finish compilation for all unresolved module items in the context */
- LY_CHECK_GOTO(ret = lys_compile_unres_mod(&ctx), error);
+ LY_CHECK_GOTO(ret = lys_compile_unres_mod(&ctx), cleanup);
- lys_compile_unres_mod_erase(&ctx, 0);
- return LY_SUCCESS;
-
-error:
+cleanup:
LOG_LOCBACK(0, 0, 1, 0);
- lys_precompile_augments_deviations_revert(ctx.ctx, mod);
- lys_compile_unres_mod_erase(&ctx, 1);
- lysc_module_free(mod_c);
- mod->compiled = NULL;
-
+ lys_compile_unres_mod_erase(&ctx, ret);
+ if (ret) {
+ lys_precompile_augments_deviations_revert(ctx.ctx, mod);
+ lysc_module_free(mod_c);
+ mod->compiled = NULL;
+ }
return ret;
}
diff --git a/src/schema_compile.h b/src/schema_compile.h
index 3252d5e..3693f55 100644
--- a/src/schema_compile.h
+++ b/src/schema_compile.h
@@ -71,7 +71,9 @@
struct ly_set xpath; /**< when/must to check */
struct ly_set leafrefs; /**< to validate leafref's targets */
struct ly_set dflts; /**< set of incomplete default values */
- ly_bool recompile; /**< flag whether all the modules need to be recompiled (because of new deviations) */
+ ly_bool full_compilation; /**< flag marking that all the currently implemented modules were compiled in this
+ compilation (meaning that all their disabled nodes are still present) */
+ ly_bool recompile; /**< flag marking that a module needs to be recompiled for this compilation to succeed */
};
/**
@@ -238,6 +240,7 @@
/**
* @brief Finish compilation of all the global unres sets.
+ * Will always finish the compilation (never return @p unres with `recompile` set).
*
* @param[in] ctx libyang context.
* @param[in] unres Global unres structure with the sets to resolve.
@@ -277,7 +280,8 @@
* @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] options Various options to modify compiler behavior, see [compile flags](@ref scflags).
- * @param[in,out] unres Global unres structure for newly implemented modules.
+ * @param[in,out] unres Global unres structure for newly implemented modules. If `recompile` was set, @p mod
+ * was actually not compiled because there is at least one compiled imported module that must be recompiled first.
* @return LY_ERR value - LY_SUCCESS or LY_EVALID.
*/
LY_ERR lys_compile(struct lys_module *mod, uint32_t options, struct lys_glob_unres *unres);
diff --git a/src/schema_compile_amend.c b/src/schema_compile_amend.c
index 2c68762..ab38edd 100644
--- a/src/schema_compile_amend.c
+++ b/src/schema_compile_amend.c
@@ -39,9 +39,20 @@
static const struct lys_module *lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest,
size_t nametest_len, const struct lysp_module *mod, const char **name, size_t *name_len);
+/**
+ * @brief Check the syntax of a node-id and collect all the referenced modules.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] nodeid Node-id to check.
+ * @param[in] abs Whether @p nodeid is absolute.
+ * @param[in,out] mod_set Set to add referenced modules into.
+ * @param[out] expr Optional node-id parsed into an expression.
+ * @param[out] target_mod Optional target module of the node-id.
+ * @return LY_ERR value.
+ */
static LY_ERR
-lys_nodeid_check(struct lysc_ctx *ctx, const char *nodeid, ly_bool abs, struct lys_module **target_mod,
- struct lyxp_expr **expr)
+lys_nodeid_mod_check(struct lysc_ctx *ctx, const char *nodeid, ly_bool abs, struct ly_set *mod_set,
+ struct lyxp_expr **expr, struct lys_module **target_mod)
{
LY_ERR ret = LY_SUCCESS;
struct lyxp_expr *e = NULL;
@@ -99,11 +110,8 @@
tmod = mod;
}
- /* all the modules must be implemented */
- if (!mod->implemented) {
- ret = lys_set_implemented_r(mod, NULL, ctx->unres);
- LY_CHECK_GOTO(ret, cleanup);
- }
+ /* store the referenced module */
+ LY_CHECK_GOTO(ret = ly_set_add(mod_set, mod, 0, NULL), cleanup);
}
}
@@ -182,13 +190,14 @@
struct lysp_refine **new_rfn;
LY_ARRAY_COUNT_TYPE u;
uint32_t i;
+ struct ly_set mod_set = {0};
LY_LIST_FOR(uses_p->augments, aug_p) {
lysc_update_path(ctx, NULL, "{augment}");
lysc_update_path(ctx, NULL, aug_p->nodeid);
/* parse the nodeid */
- LY_CHECK_GOTO(ret = lys_nodeid_check(ctx, aug_p->nodeid, 0, NULL, &exp), cleanup);
+ LY_CHECK_GOTO(ret = lys_nodeid_mod_check(ctx, aug_p->nodeid, 0, &mod_set, &exp, NULL), cleanup);
/* allocate new compiled augment and store it in the set */
aug = calloc(1, sizeof *aug);
@@ -210,7 +219,7 @@
lysc_update_path(ctx, NULL, uses_p->refines[u].nodeid);
/* parse the nodeid */
- LY_CHECK_GOTO(ret = lys_nodeid_check(ctx, uses_p->refines[u].nodeid, 0, NULL, &exp), cleanup);
+ LY_CHECK_GOTO(ret = lys_nodeid_mod_check(ctx, uses_p->refines[u].nodeid, 0, &mod_set, &exp, NULL), cleanup);
/* try to find the node in already compiled refines */
rfn = NULL;
@@ -248,6 +257,12 @@
}
cleanup:
+ if (ret) {
+ lysc_update_path(ctx, NULL, NULL);
+ lysc_update_path(ctx, NULL, NULL);
+ }
+ /* should include only this module, will fail later if not */
+ ly_set_erase(&mod_set, NULL);
lyxp_expr_free(ctx->ctx, exp);
return ret;
}
@@ -2122,76 +2137,74 @@
return LY_SUCCESS;
}
+/**
+ * @brief Check whether all modules in a set are implemented.
+ *
+ * @param[in] mod_set Module set to check.
+ * @return Whether all modules are implemented or not.
+ */
+static ly_bool
+lys_precompile_mod_set_all_implemented(const struct ly_set *mod_set)
+{
+ uint32_t i;
+ const struct lys_module *mod;
+
+ for (i = 0; i < mod_set->count; ++i) {
+ mod = mod_set->objs[i];
+ if (!mod->implemented) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
LY_ERR
lys_precompile_augments_deviations(struct lysc_ctx *ctx)
{
- LY_ERR ret;
+ LY_ERR ret = LY_SUCCESS;
LY_ARRAY_COUNT_TYPE u, v;
const struct lysp_module *mod_p;
- const struct lysc_node *target;
struct lys_module *mod;
struct lysp_submodule *submod;
struct lysp_node_augment *aug;
- ly_bool has_dev = 0;
- uint16_t flags;
- uint32_t idx, opt_prev = ctx->options;
-
- for (idx = 0; idx < ctx->unres->implementing.count; ++idx) {
- if (ctx->cur_mod == ctx->unres->implementing.objs[idx]) {
- break;
- }
- }
- if (idx == ctx->unres->implementing.count) {
- /* it was already implemented and all the augments and deviations fully applied */
- return LY_SUCCESS;
- }
+ uint32_t idx;
+ struct ly_set mod_set = {0}, set = {0};
mod_p = ctx->cur_mod->parsed;
LY_LIST_FOR(mod_p->augments, aug) {
+ /* get target module */
lysc_update_path(ctx, NULL, "{augment}");
lysc_update_path(ctx, NULL, aug->nodeid);
+ ret = lys_nodeid_mod_check(ctx, aug->nodeid, 1, &set, NULL, &mod);
+ lysc_update_path(ctx, NULL, NULL);
+ lysc_update_path(ctx, NULL, NULL);
+ LY_CHECK_GOTO(ret, cleanup);
- /* get target module */
- ret = lys_nodeid_check(ctx, aug->nodeid, 1, &mod, NULL);
- LY_CHECK_RET(ret);
-
- /* add this module into the target module augmented_by, if not there already from previous augments */
- lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->augmented_by);
-
- /* if we are compiling this module, we cannot add augments to it yet */
- if (mod != ctx->cur_mod) {
- /* apply the augment, find the target node first */
- flags = 0;
- ret = lysc_resolve_schema_nodeid(ctx, aug->nodeid, 0, NULL, ctx->cur_mod, LY_PREF_SCHEMA,
- (void *)mod_p, 0, &target, &flags);
- LY_CHECK_RET(ret);
-
- /* apply the augment */
- ctx->options |= flags;
- ret = lys_compile_augment(ctx, aug, (struct lysc_node *)target);
- ctx->options = opt_prev;
- LY_CHECK_RET(ret);
+ /* add this module into the target module augmented_by, if not there and implemented */
+ if ((lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->augmented_by) != LY_EEXIST) ||
+ !lys_precompile_mod_set_all_implemented(&set)) {
+ LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
}
-
- lysc_update_path(ctx, NULL, NULL);
- lysc_update_path(ctx, NULL, NULL);
+ ly_set_erase(&set, NULL);
}
LY_ARRAY_FOR(mod_p->deviations, u) {
/* get target module */
lysc_update_path(ctx, NULL, "{deviation}");
lysc_update_path(ctx, NULL, mod_p->deviations[u].nodeid);
- ret = lys_nodeid_check(ctx, mod_p->deviations[u].nodeid, 1, &mod, NULL);
+ ret = lys_nodeid_mod_check(ctx, mod_p->deviations[u].nodeid, 1, &set, NULL, &mod);
lysc_update_path(ctx, NULL, NULL);
lysc_update_path(ctx, NULL, NULL);
- LY_CHECK_RET(ret);
+ LY_CHECK_GOTO(ret, cleanup);
- /* add this module into the target module deviated_by, if not there already from previous deviations */
- lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->deviated_by);
-
- /* new deviation added to the target module */
- has_dev = 1;
+ /* add this module into the target module deviated_by, if not there and implemented */
+ if ((lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->deviated_by) != LY_EEXIST) ||
+ !lys_precompile_mod_set_all_implemented(&set)) {
+ LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
+ }
+ ly_set_erase(&set, NULL);
}
/* the same for augments and deviations in submodules */
@@ -2200,46 +2213,65 @@
LY_LIST_FOR(submod->augments, aug) {
lysc_update_path(ctx, NULL, "{augment}");
lysc_update_path(ctx, NULL, aug->nodeid);
+ ret = lys_nodeid_mod_check(ctx, aug->nodeid, 1, &set, NULL, &mod);
+ lysc_update_path(ctx, NULL, NULL);
+ lysc_update_path(ctx, NULL, NULL);
+ LY_CHECK_GOTO(ret, cleanup);
- ret = lys_nodeid_check(ctx, aug->nodeid, 1, &mod, NULL);
- LY_CHECK_RET(ret);
-
- lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->augmented_by);
- if (mod != ctx->cur_mod) {
- flags = 0;
- ret = lysc_resolve_schema_nodeid(ctx, aug->nodeid, 0, NULL, ctx->cur_mod, LY_PREF_SCHEMA,
- submod, 0, &target, &flags);
- LY_CHECK_RET(ret);
-
- ctx->options |= flags;
- ret = lys_compile_augment(ctx, aug, (struct lysc_node *)target);
- ctx->options = opt_prev;
- LY_CHECK_RET(ret);
+ if ((lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->augmented_by) != LY_EEXIST) ||
+ !lys_precompile_mod_set_all_implemented(&set)) {
+ LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
}
-
- lysc_update_path(ctx, NULL, NULL);
- lysc_update_path(ctx, NULL, NULL);
+ ly_set_erase(&set, NULL);
}
LY_ARRAY_FOR(submod->deviations, u) {
lysc_update_path(ctx, NULL, "{deviation}");
lysc_update_path(ctx, NULL, submod->deviations[u].nodeid);
- ret = lys_nodeid_check(ctx, submod->deviations[u].nodeid, 1, &mod, NULL);
+ ret = lys_nodeid_mod_check(ctx, submod->deviations[u].nodeid, 1, &set, NULL, &mod);
lysc_update_path(ctx, NULL, NULL);
lysc_update_path(ctx, NULL, NULL);
- LY_CHECK_RET(ret);
+ LY_CHECK_GOTO(ret, cleanup);
- lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->deviated_by);
- has_dev = 1;
+ if ((lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->deviated_by) != LY_EEXIST) ||
+ !lys_precompile_mod_set_all_implemented(&set)) {
+ LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
+ }
+ ly_set_erase(&set, NULL);
}
}
- if (has_dev) {
- /* all modules (may) need to be recompiled */
- ctx->unres->recompile = 1;
+ if (mod_set.count) {
+ /* descending order to make sure the modules are implemented in the right order */
+ idx = mod_set.count;
+ do {
+ --idx;
+ mod = mod_set.objs[idx];
+
+ if (mod == ctx->cur_mod) {
+ /* will be applied normally later */
+ continue;
+ }
+
+ if (!mod->implemented) {
+ /* implement (compile) the target module with our augments/deviations */
+ LY_CHECK_GOTO(ret = lys_set_implemented_r(mod, NULL, ctx->unres), cleanup);
+ } else {
+ /* target module was already compiled, we need to recompile it */
+ ctx->unres->recompile = 1;
+ }
+
+ if (ctx->unres->recompile) {
+ /* we need some module recompiled and cannot continue */
+ goto cleanup;
+ }
+ } while (idx);
}
- return LY_SUCCESS;
+cleanup:
+ ly_set_erase(&set, NULL);
+ ly_set_erase(&mod_set, NULL);
+ return ret;
}
void
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 89c97ad..aaeca87 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -827,7 +827,12 @@
mod->implemented = 1;
/* compile the schema */
- return lys_compile(mod, 0, unres);
+ LY_CHECK_RET(lys_compile(mod, 0, unres));
+
+ /* new module is implemented and compiled */
+ unres->full_compilation = 0;
+
+ return LY_SUCCESS;
}
API LY_ERR