schema tree FEATURE pre-compile identities
That way they can be referenced even if not
in an implemented module. Added error when
instantiated identity (or a default identityref)
is found in a non-implemented module.
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index c5e56a5..14dafbc 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -440,7 +440,7 @@
/* module is implemented so there is already the compiled schema */
flist = mod->compiled->features;
} else {
- flist = mod->off_features;
+ flist = mod->dis_features;
}
LY_ARRAY_FOR(flist, u) {
f = &flist[u];
@@ -948,36 +948,52 @@
return ret;
}
-/**
- * @brief Compile information from the identity statement
- *
- * The backlinks to the identities derived from this one are supposed to be filled later via lys_compile_identity_bases().
- *
- * @param[in] ctx Compile context.
- * @param[in] ident_p The parsed identity statement structure.
- * @param[in] idents List of so far compiled identities to check the name uniqueness.
- * @param[in,out] ident Prepared (empty) compiled identity structure to fill.
- * @return LY_ERR value.
- */
-static LY_ERR
-lys_compile_identity(struct lysc_ctx *ctx, struct lysp_ident *ident_p, struct lysc_ident *idents, struct lysc_ident *ident)
+LY_ERR
+lys_identity_precompile(struct lysc_ctx *ctx_sc, struct ly_ctx *ctx, struct lys_module *module,
+ struct lysp_ident *identities_p, struct lysc_ident **identities)
{
- unsigned int u;
+ LY_ARRAY_SIZE_TYPE offset = 0, u, v;
+ struct lysc_ctx context = {0};
LY_ERR ret = LY_SUCCESS;
- lysc_update_path(ctx, NULL, ident_p->name);
+ assert(ctx_sc || ctx);
- COMPILE_CHECK_UNIQUENESS_ARRAY(ctx, idents, name, ident, "identity", ident_p->name);
- DUP_STRING(ctx->ctx, ident_p->name, ident->name);
- DUP_STRING(ctx->ctx, ident_p->dsc, ident->dsc);
- DUP_STRING(ctx->ctx, ident_p->ref, ident->ref);
- ident->module = ctx->mod;
- COMPILE_ARRAY_GOTO(ctx, ident_p->iffeatures, ident->iffeatures, u, lys_compile_iffeature, ret, done);
- /* backlings (derived) can be added no sooner than when all the identities in the current module are present */
- COMPILE_EXTS_GOTO(ctx, ident_p->exts, ident->exts, ident, LYEXT_PAR_IDENT, ret, done);
- ident->flags = ident_p->flags;
+ if (!ctx_sc) {
+ context.ctx = ctx;
+ context.mod = module;
+ context.path_len = 1;
+ context.path[0] = '/';
+ ctx_sc = &context;
+ }
- lysc_update_path(ctx, NULL, NULL);
+ if (!identities_p) {
+ return LY_SUCCESS;
+ }
+ if (*identities) {
+ offset = LY_ARRAY_SIZE(*identities);
+ }
+
+ lysc_update_path(ctx_sc, NULL, "{identity}");
+ LY_ARRAY_CREATE_RET(ctx_sc->ctx, *identities, LY_ARRAY_SIZE(identities_p), LY_EMEM);
+ LY_ARRAY_FOR(identities_p, u) {
+ lysc_update_path(ctx_sc, NULL, identities_p[u].name);
+
+ LY_ARRAY_INCREMENT(*identities);
+ COMPILE_CHECK_UNIQUENESS_ARRAY(ctx_sc, *identities, name, &(*identities)[offset + u], "identity", identities_p[u].name);
+ DUP_STRING(ctx_sc->ctx, identities_p[u].name, (*identities)[offset + u].name);
+ DUP_STRING(ctx_sc->ctx, identities_p[u].dsc, (*identities)[offset + u].dsc);
+ DUP_STRING(ctx_sc->ctx, identities_p[u].ref, (*identities)[offset + u].ref);
+ (*identities)[offset + u].module = ctx_sc->mod;
+ COMPILE_ARRAY_GOTO(ctx_sc, identities_p[u].iffeatures, (*identities)[offset + u].iffeatures, v,
+ lys_compile_iffeature, ret, done);
+ /* backlinks (derived) can be added no sooner than when all the identities in the current module are present */
+ COMPILE_EXTS_GOTO(ctx_sc, identities_p[u].exts, (*identities)[offset + u].exts, &(*identities)[offset + u],
+ LYEXT_PAR_IDENT, ret, done);
+ (*identities)[offset + u].flags = identities_p[u].flags;
+
+ lysc_update_path(ctx_sc, NULL, NULL);
+ }
+ lysc_update_path(ctx_sc, NULL, NULL);
done:
return ret;
}
@@ -1044,17 +1060,18 @@
*
* @param[in] ctx Compile context, not only for logging but also to get the current module to resolve prefixes.
* @param[in] bases_p Array of names (including prefix if necessary) of base identities.
- * @param[in] ident Referencing identity to work with.
+ * @param[in] ident Referencing identity to work with, NULL for identityref.
* @param[in] bases Array of bases of identityref to fill in.
* @return LY_ERR value.
*/
static LY_ERR
-lys_compile_identity_bases(struct lysc_ctx *ctx, struct lys_module *context_module, const char **bases_p, struct lysc_ident *ident, struct lysc_ident ***bases)
+lys_compile_identity_bases(struct lysc_ctx *ctx, struct lys_module *context_module, const char **bases_p,
+ struct lysc_ident *ident, struct lysc_ident ***bases)
{
LY_ARRAY_SIZE_TYPE u, v;
const char *s, *name;
struct lys_module *mod;
- struct lysc_ident **idref;
+ struct lysc_ident **idref, *identities;
assert(ident || bases);
@@ -1064,7 +1081,7 @@
return LY_EVALID;
}
- for (u = 0; u < LY_ARRAY_SIZE(bases_p); ++u) {
+ LY_ARRAY_FOR(bases_p, u) {
s = strchr(bases_p[u], ':');
if (s) {
/* prefixed identity */
@@ -1084,27 +1101,31 @@
}
return LY_EVALID;
}
+
idref = NULL;
- if (mod->compiled && mod->compiled->identities) {
- for (v = 0; v < LY_ARRAY_SIZE(mod->compiled->identities); ++v) {
- if (!strcmp(name, mod->compiled->identities[v].name)) {
- if (ident) {
- if (ident == &mod->compiled->identities[v]) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Identity \"%s\" is derived from itself.", ident->name);
- return LY_EVALID;
- }
- LY_CHECK_RET(lys_compile_identity_circular_check(ctx, &mod->compiled->identities[v], ident->derived));
- /* we have match! store the backlink */
- LY_ARRAY_NEW_RET(ctx->ctx, mod->compiled->identities[v].derived, idref, LY_EMEM);
- *idref = ident;
- } else {
- /* we have match! store the found identity */
- LY_ARRAY_NEW_RET(ctx->ctx, *bases, idref, LY_EMEM);
- *idref = &mod->compiled->identities[v];
+ if (mod->compiled) {
+ identities = mod->compiled->identities;
+ } else {
+ identities = mod->dis_identities;
+ }
+ LY_ARRAY_FOR(identities, v) {
+ if (!strcmp(name, identities[v].name)) {
+ if (ident) {
+ if (ident == &identities[v]) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Identity \"%s\" is derived from itself.", ident->name);
+ return LY_EVALID;
}
- break;
+ LY_CHECK_RET(lys_compile_identity_circular_check(ctx, &identities[v], ident->derived));
+ /* we have match! store the backlink */
+ LY_ARRAY_NEW_RET(ctx->ctx, identities[v].derived, idref, LY_EMEM);
+ *idref = ident;
+ } else {
+ /* we have match! store the found identity */
+ LY_ARRAY_NEW_RET(ctx->ctx, *bases, idref, LY_EMEM);
+ *idref = &identities[v];
}
+ break;
}
}
if (!idref || !(*idref)) {
@@ -1133,6 +1154,7 @@
{
LY_ARRAY_SIZE_TYPE u;
+ lysc_update_path(ctx, NULL, "{identity}");
for (u = 0; u < LY_ARRAY_SIZE(idents_p); ++u) {
if (!idents_p[u].bases) {
continue;
@@ -1141,11 +1163,13 @@
LY_CHECK_RET(lys_compile_identity_bases(ctx, idents[u].module, idents_p[u].bases, &idents[u], NULL));
lysc_update_path(ctx, NULL, NULL);
}
+ lysc_update_path(ctx, NULL, NULL);
return LY_SUCCESS;
}
LY_ERR
-lys_feature_precompile(struct lysc_ctx *ctx_sc, struct ly_ctx *ctx, struct lys_module *module, struct lysp_feature *features_p, struct lysc_feature **features)
+lys_feature_precompile(struct lysc_ctx *ctx_sc, struct ly_ctx *ctx, struct lys_module *module,
+ struct lysp_feature *features_p, struct lysc_feature **features)
{
LY_ARRAY_SIZE_TYPE offset = 0, u;
struct lysc_ctx context = {0};
@@ -1305,35 +1329,35 @@
* @brief Revert compiled list of features back to the precompiled state.
*
* Function is needed in case the compilation failed and the schema is expected to revert back to the non-compiled status.
- * The features are supposed to be stored again as off_features in ::lys_module structure.
+ * The features are supposed to be stored again as dis_features in ::lys_module structure.
*
* @param[in] ctx Compilation context.
* @param[in] mod The module structure still holding the compiled (but possibly not finished, only the list of compiled features is taken) schema
- * and supposed to hold the off_features list.
+ * and supposed to hold the dis_features list.
*/
static void
lys_feature_precompile_revert(struct lysc_ctx *ctx, struct lys_module *mod)
{
LY_ARRAY_SIZE_TYPE u, v;
- /* keep the off_features list until the complete lys_module is freed */
- mod->off_features = mod->compiled->features;
+ /* keep the dis_features list until the complete lys_module is freed */
+ mod->dis_features = mod->compiled->features;
mod->compiled->features = NULL;
- /* in the off_features list, remove all the parts (from finished compiling process)
+ /* in the dis_features list, remove all the parts (from finished compiling process)
* which may points into the data being freed here */
- LY_ARRAY_FOR(mod->off_features, u) {
- LY_ARRAY_FOR(mod->off_features[u].iffeatures, v) {
- lysc_iffeature_free(ctx->ctx, &mod->off_features[u].iffeatures[v]);
+ LY_ARRAY_FOR(mod->dis_features, u) {
+ LY_ARRAY_FOR(mod->dis_features[u].iffeatures, v) {
+ lysc_iffeature_free(ctx->ctx, &mod->dis_features[u].iffeatures[v]);
}
- LY_ARRAY_FREE(mod->off_features[u].iffeatures);
- mod->off_features[u].iffeatures = NULL;
+ LY_ARRAY_FREE(mod->dis_features[u].iffeatures);
+ mod->dis_features[u].iffeatures = NULL;
- LY_ARRAY_FOR(mod->off_features[u].exts, v) {
- lysc_ext_instance_free(ctx->ctx, &(mod->off_features[u].exts)[v]);
+ LY_ARRAY_FOR(mod->dis_features[u].exts, v) {
+ lysc_ext_instance_free(ctx->ctx, &(mod->dis_features[u].exts)[v]);
}
- LY_ARRAY_FREE(mod->off_features[u].exts);
- mod->off_features[u].exts = NULL;
+ LY_ARRAY_FREE(mod->dis_features[u].exts);
+ mod->dis_features[u].exts = NULL;
}
}
@@ -6469,7 +6493,7 @@
struct lysc_module *mainmod = ctx->mod->compiled;
struct lysp_node *node_p;
- if (!mainmod->mod->off_features) {
+ if (!mainmod->mod->dis_features) {
/* features are compiled directly into the compiled module structure,
* but it must be done in two steps to allow forward references (via if-feature) between the features themselves.
* The features compilation is finished in the main module (lys_compile()). */
@@ -6477,9 +6501,10 @@
LY_CHECK_GOTO(ret, error);
}
- lysc_update_path(ctx, NULL, "{identity}");
- COMPILE_ARRAY_UNIQUE_GOTO(ctx, submod->identities, mainmod->identities, u, lys_compile_identity, ret, error);
- lysc_update_path(ctx, NULL, NULL);
+ if (!mainmod->mod->dis_identities) {
+ ret = lys_identity_precompile(ctx, NULL, NULL, submod->identities, &mainmod->identities);
+ LY_CHECK_GOTO(ret, error);
+ }
/* data nodes */
LY_LIST_FOR(submod->data, node_p) {
@@ -7078,16 +7103,17 @@
}
/* features */
- if ((*mod)->off_features) {
+ if ((*mod)->dis_features) {
/* there is already precompiled array of features */
- mod_c->features = (*mod)->off_features;
- (*mod)->off_features = NULL;
+ mod_c->features = (*mod)->dis_features;
+ (*mod)->dis_features = NULL;
} else {
/* features are compiled directly into the compiled module structure,
* but it must be done in two steps to allow forward references (via if-feature) between the features themselves */
ret = lys_feature_precompile(&ctx, NULL, NULL, sp->features, &mod_c->features);
LY_CHECK_GOTO(ret, error);
}
+
/* finish feature compilation, not only for the main module, but also for the submodules.
* Due to possible forward references, it must be done when all the features (including submodules)
* are present. */
@@ -7106,12 +7132,26 @@
}
lysc_update_path(&ctx, NULL, NULL);
- /* identities */
- lysc_update_path(&ctx, NULL, "{identity}");
- COMPILE_ARRAY_UNIQUE_GOTO(&ctx, sp->identities, mod_c->identities, u, lys_compile_identity, ret, error);
+ /* identities, work similarly to features with the precompilation */
+ if ((*mod)->dis_identities) {
+ mod_c->identities = (*mod)->dis_identities;
+ (*mod)->dis_identities = NULL;
+ } else {
+ ret = lys_identity_precompile(&ctx, NULL, NULL, sp->identities, &mod_c->identities);
+ LY_CHECK_GOTO(ret, error);
+ }
if (sp->identities) {
LY_CHECK_GOTO(ret = lys_compile_identities_derived(&ctx, sp->identities, mod_c->identities), error);
}
+ lysc_update_path(&ctx, NULL, "{submodule}");
+ LY_ARRAY_FOR(sp->includes, v) {
+ if (sp->includes[v].submodule->identities) {
+ lysc_update_path(&ctx, NULL, sp->includes[v].name);
+ ret = lys_compile_identities_derived(&ctx, sp->includes[v].submodule->identities, mod_c->identities);
+ LY_CHECK_GOTO(ret, error);
+ lysc_update_path(&ctx, NULL, NULL);
+ }
+ }
lysc_update_path(&ctx, NULL, NULL);
/* data nodes */