schema compile WIP partial support for uses's refine
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index bbae473..4761520 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -2707,6 +2707,9 @@
COMPILE_ARRAY_GOTO(ctx, leaf_p->musts, leaf->musts, options, u, lys_compile_must, ret, done);
DUP_STRING(ctx->ctx, leaf_p->units, leaf->units);
DUP_STRING(ctx->ctx, leaf_p->dflt, leaf->dflt);
+ if (leaf->dflt) {
+ leaf->flags |= LYS_SET_DFLT;
+ }
ret = lys_compile_type(ctx, node_p, node_p->flags, ctx->mod_def->parsed, node_p->name, &leaf_p->type, options, &leaf->type,
leaf->units ? NULL : &leaf->units, leaf->dflt || (leaf->flags & LYS_MAND_TRUE) ? NULL : &leaf->dflt);
@@ -2906,6 +2909,11 @@
return LY_EVALID;
}
}
+
+ /* check status */
+ LY_CHECK_RET(lysc_check_status(ctx, list->flags, list->module, list->name,
+ (*key)->flags, (*key)->module, (*key)->name));
+
/* ignore default values of the key */
if ((*key)->dflt) {
lydict_remove(ctx->ctx, (*key)->dflt);
@@ -2958,6 +2966,10 @@
config = 0;
}
+ /* check status */
+ LY_CHECK_RET(lysc_check_status(ctx, list->flags, list->module, list->name,
+ (*key)->flags, (*key)->module, (*key)->name));
+
/* mark leaf as unique */
(*key)->flags |= LYS_UNIQUE;
@@ -2975,13 +2987,54 @@
return ret;
}
+static LY_ERR
+lys_compile_node_choice_dflt(struct lysc_ctx *ctx, const char *dflt, struct lysc_node_choice *ch)
+{
+ struct lysc_node *iter, *node = (struct lysc_node*)ch;
+ const char *prefix = NULL, *name;
+ size_t prefix_len = 0;
+
+ /* could use lys_parse_nodeid(), but it checks syntax which is already done in this case by the parsers */
+ name = strchr(dflt, ':');
+ if (name) {
+ prefix = dflt;
+ prefix_len = name - prefix;
+ ++name;
+ } else {
+ name = dflt;
+ }
+ if (prefix && (strncmp(prefix, node->module->compiled->prefix, prefix_len) || node->module->compiled->prefix[prefix_len] != '\0')) {
+ /* prefixed default case make sense only for the prefix of the schema itself */
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid default case referencing a case from different YANG module (by prefix \"%.*s\").",
+ prefix_len, prefix);
+ return LY_EVALID;
+ }
+ ch->dflt = (struct lysc_node_case*)lys_child(node, node->module, name, 0, LYS_CASE, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCASE);
+ if (!ch->dflt) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Default case \"%s\" not found.", dflt);
+ return LY_EVALID;
+ }
+ /* no mandatory nodes directly under the default case */
+ LY_LIST_FOR(ch->dflt->child, iter) {
+ if (iter->flags & LYS_MAND_TRUE) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Mandatory node \"%s\" under the default case \"%s\".", iter->name, dflt);
+ return LY_EVALID;
+ }
+ }
+ ch->flags |= LYS_SET_DFLT;
+ return LY_SUCCESS;
+}
+
/**
* @brief Compile parsed choice node information.
* @param[in] ctx Compile context
* @param[in] node_p Parsed choice node.
* @param[in] options Various options to modify compiler behavior, see [compile flags](@ref scflags).
* @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
- * is enriched with the container-specific information.
+ * is enriched with the choice-specific information.
* @return LY_ERR value - LY_SUCCESS or LY_EVALID.
*/
static LY_ERR
@@ -2990,9 +3043,6 @@
struct lysp_node_choice *ch_p = (struct lysp_node_choice*)node_p;
struct lysc_node_choice *ch = (struct lysc_node_choice*)node;
struct lysp_node *child_p, *case_child_p;
- struct lysc_node *iter;
- const char *prefix = NULL, *name;
- size_t prefix_len = 0;
struct lys_module;
LY_ERR ret = LY_SUCCESS;
@@ -3008,36 +3058,7 @@
/* default branch */
if (ch_p->dflt) {
- /* could use lys_parse_nodeid(), but it checks syntax which is already done in this case by the parsers */
- name = strchr(ch_p->dflt, ':');
- if (name) {
- prefix = ch_p->dflt;
- prefix_len = name - prefix;
- ++name;
- } else {
- name = ch_p->dflt;
- }
- if (prefix && (strncmp(prefix, node->module->compiled->prefix, prefix_len) || node->module->compiled->prefix[prefix_len] != '\0')) {
- /* prefixed default case make sense only for the prefix of the schema itself */
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Invalid default case referencing a case from different YANG module (by prefix \"%.*s\").",
- prefix_len, prefix);
- return LY_EVALID;
- }
- ch->dflt = (struct lysc_node_case*)lys_child(node, node->module, name, 0, LYS_CASE, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCASE);
- if (!ch->dflt) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Default case \"%s\" not found.", ch_p->dflt);
- return LY_EVALID;
- }
- /* no mandatory nodes directly under the default case */
- LY_LIST_FOR(ch->dflt->child, iter) {
- if (iter->flags & LYS_MAND_TRUE) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Mandatory node \"%s\" under the default case \"%s\".", iter->name, ch_p->dflt);
- return LY_EVALID;
- }
- }
+ LY_CHECK_RET(lys_compile_node_choice_dflt(ctx, ch_p->dflt, ch));
}
return ret;
@@ -3071,7 +3092,25 @@
}
static LY_ERR
-lys_compile_status(struct lysc_ctx *ctx, struct lysc_node *node, struct lysc_node *parent)
+lys_compile_status_check(struct lysc_ctx *ctx, uint16_t node_flags, uint16_t parent_flags)
+{
+ /* check status compatibility with the parent */
+ if ((parent_flags & LYS_STATUS_MASK) > (node_flags & LYS_STATUS_MASK)) {
+ if (node_flags & LYS_STATUS_CURR) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "A \"current\" status is in conflict with the parent's \"%s\" status.",
+ (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
+ } else { /* LYS_STATUS_DEPRC */
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "A \"deprecated\" status is in conflict with the parent's \"obsolete\" status.");
+ }
+ return LY_EVALID;
+ }
+ return LY_SUCCESS;
+}
+
+static LY_ERR
+lys_compile_status(struct lysc_ctx *ctx, struct lysc_node *node, struct lysc_node *parent)
{
/* status - it is not inherited by specification, but it does not make sense to have
@@ -3085,18 +3124,7 @@
node->flags |= LYS_STATUS_CURR;
}
} else if (parent) {
- /* check status compatibility with the parent */
- if ((parent->flags & LYS_STATUS_MASK) > (node->flags & LYS_STATUS_MASK)) {
- if (node->flags & LYS_STATUS_CURR) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "A \"current\" status is in conflict with the parent's \"%s\" status.",
- (parent->flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
- } else { /* LYS_STATUS_DEPRC */
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "A \"deprecated\" status is in conflict with the parent's \"obsolete\" status.");
- }
- return LY_EVALID;
- }
+ return lys_compile_status_check(ctx, node->flags, parent->flags);
}
return LY_SUCCESS;
}
@@ -3229,6 +3257,38 @@
#undef UNIQUE_CHECK
}
+static LY_ERR
+lys_compile_refine_config(struct lysc_ctx *ctx, struct lysc_node *node, struct lysp_refine *rfn, int inheriting)
+{
+ struct lysc_node *child;
+ uint16_t config = rfn->flags & LYS_CONFIG_MASK;
+
+ if (config == (node->flags & LYS_CONFIG_MASK)) {
+ /* nothing to do */
+ return LY_SUCCESS;
+ }
+
+ if (!inheriting) {
+ /* explicit refine */
+ if (config == LYS_CONFIG_W && node->parent && (node->parent->flags & LYS_CONFIG_R)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid refine of config in \"%s\" - configuration node cannot be child of any state data node.");
+ return LY_EVALID;
+ }
+ }
+ node->flags &= ~LYS_CONFIG_MASK;
+ node->flags |= config;
+
+ /* inherit the change into the children */
+ LY_LIST_FOR((struct lysc_node*)lysc_node_children(node), child) {
+ LY_CHECK_RET(lys_compile_refine_config(ctx, child, rfn, 1));
+ }
+
+ /* TODO actions and notifications */
+
+ return LY_SUCCESS;
+}
+
/**
* @brief Compile parsed uses statement - resolve target grouping and connect its content into parent.
* If present, also apply uses's modificators.
@@ -3245,13 +3305,14 @@
lys_compile_uses(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, int options, struct lysc_node *parent)
{
struct lysp_node *node_p;
- struct lysc_node *last;
+ struct lysc_node *node;
const struct lysp_grp *grp = NULL;
- unsigned int u, grp_stack_count;
+ unsigned int u, v, grp_stack_count;
int found;
const char *id, *name, *prefix;
size_t prefix_len, name_len;
struct lys_module *mod, *mod_old;
+ struct lysp_refine *rfn;
LY_ERR ret = LY_EVALID;
/* search for the grouping definition */
@@ -3281,13 +3342,28 @@
}
}
if (!found) {
- /* search in top-level groupings */
+ /* search in top-level groupings of the main module ... */
grp = mod->parsed->groupings;
- LY_ARRAY_FOR(grp, u) {
- if (!strcmp(grp[u].name, name)) {
- grp = &grp[u];
- found = 1;
- break;
+ if (grp) {
+ for (u = 0; !found && u < LY_ARRAY_SIZE(grp); ++u) {
+ if (!strcmp(grp[u].name, name)) {
+ grp = &grp[u];
+ found = 1;
+ }
+ }
+ }
+ if (!found && mod->parsed->includes) {
+ /* ... and all the submodules */
+ for (u = 0; !found && u < LY_ARRAY_SIZE(mod->parsed->includes); ++u) {
+ grp = mod->parsed->includes[u].submodule->groupings;
+ if (grp) {
+ for (v = 0; !found && v < LY_ARRAY_SIZE(grp); ++v) {
+ if (!strcmp(grp[v].name, name)) {
+ grp = &grp[v];
+ found = 1;
+ }
+ }
+ }
}
}
}
@@ -3314,20 +3390,99 @@
/* check status */
LY_CHECK_GOTO(lysc_check_status(ctx, uses_p->flags, mod_old, uses_p->name, grp->flags, mod, grp->name), error);
- /* remember the last parent's child present before connecting the grouping content, it will be used later
- * to know where start when applying uses's modificators */
- if (parent) {
- last = (struct lysc_node*)lysc_node_children(parent);
- } else {
- last = ctx->mod->compiled->data;
- }
- if (last) {
- last = last->prev; /* get the last one */
- }
-
/* connect the grouping's content */
LY_LIST_FOR(grp->data, node_p) {
LY_CHECK_GOTO(lys_compile_node(ctx, node_p, options, parent), error);
+ /* check status between parent (uses in this case) and child - lys_compile_node() compares parent and the new node */
+ if (lys_compile_status_check(ctx, parent ? lysc_node_children(parent)->prev->flags : ctx->mod->compiled->data->prev->flags, uses_p->flags)) {
+ goto error;
+ }
+ }
+
+ /* apply refine */
+ LY_ARRAY_FOR(uses_p->refines, struct lysp_refine, rfn) {
+ LY_CHECK_GOTO(lys_resolve_descendant_schema_nodeid(ctx, rfn->nodeid, 0, parent, 0, (const struct lysc_node**)&node), error);
+
+ /* default value */
+ if (rfn->dflts) {
+ if ((node->nodetype & (LYS_LEAF | LYS_CHOICE)) && LY_ARRAY_SIZE(rfn->dflts) > 1) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid refine of default in \"%s\" - %s cannot hold %d default values.",
+ rfn->nodeid, lys_nodetype2str(node->nodetype), LY_ARRAY_SIZE(rfn->dflts));
+ goto error;
+ }
+ if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_CHOICE))) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid refine of default in \"%s\" - %s cannot hold default value(s).",
+ rfn->nodeid, lys_nodetype2str(node->nodetype));
+ goto error;
+ }
+ if (node->nodetype == LYS_LEAF) {
+ FREE_STRING(ctx->ctx, ((struct lysc_node_leaf*)node)->dflt);
+ DUP_STRING(ctx->ctx, rfn->dflts[0], ((struct lysc_node_leaf*)node)->dflt);
+ /* TODO check the default value according to type */
+ } else if (node->nodetype == LYS_LEAFLIST) {
+ LY_ARRAY_FOR(((struct lysc_node_leaflist*)node)->dflts, u) {
+ lydict_remove(ctx->ctx, ((struct lysc_node_leaflist*)node)->dflts[u]);
+ }
+ LY_ARRAY_FREE(((struct lysc_node_leaflist*)node)->dflts);
+ LY_ARRAY_CREATE_GOTO(ctx->ctx, ((struct lysc_node_leaflist*)node)->dflts, LY_ARRAY_SIZE(rfn->dflts), ret, error);
+ LY_ARRAY_FOR(rfn->dflts, u) {
+ LY_ARRAY_INCREMENT(((struct lysc_node_leaflist*)node)->dflts);
+ DUP_STRING(ctx->ctx, rfn->dflts[u], ((struct lysc_node_leaflist*)node)->dflts[u]);
+ }
+ /* TODO check the default values according to type */
+ } else if (node->nodetype == LYS_CHOICE) {
+ LY_CHECK_GOTO(lys_compile_node_choice_dflt(ctx, rfn->dflts[0], (struct lysc_node_choice*)node), error);
+ }
+ }
+
+ /* description refine not applicable */
+ /* reference refine not applicable */
+
+ /* config */
+ if (rfn->flags & LYS_CONFIG_MASK) {
+ LY_CHECK_GOTO(lys_compile_refine_config(ctx, node, rfn, 0), error);
+ }
+
+ /* mandatory */
+ if (rfn->flags & LYS_MAND_MASK) {
+ if (!(node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_ANYXML | LYS_CHOICE))) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid refine of mandatory in \"%s\" - %s cannot hold mandatory statement.",
+ rfn->nodeid, lys_nodetype2str(node->nodetype));
+ goto error;
+ }
+ /* in compiled flags, only the LYS_MAND_TRUE is present */
+ if (rfn->flags & LYS_MAND_TRUE) {
+ /* check if node has default value */
+ if (node->nodetype & LYS_LEAF) {
+ if (node->flags & LYS_SET_DFLT) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid refine of mandatory in \"%s\" - leafswith \"default\" statement.", rfn->nodeid);
+ goto error;
+ } else {
+ /* remove the default value taken from the leaf's type */
+ FREE_STRING(ctx->ctx, ((struct lysc_node_leaf*)node)->dflt);
+ ((struct lysc_node_leaf*)node)->dflt = NULL;
+ }
+ } else if ((node->nodetype & LYS_CHOICE) && ((struct lysc_node_choice*)node)->dflt) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid refine of mandatory in \"%s\" - choice with \"default\" statement.", rfn->nodeid);
+ goto error;
+ }
+ if (node->parent && (node->parent->flags & LYS_SET_DFLT)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid refine of mandatory in \"%s\" - %s under the default case.",
+ rfn->nodeid, lys_nodetype2str(node->nodetype));
+ goto error;
+ }
+
+ node->flags |= LYS_MAND_TRUE;
+ } else {
+ node->flags &= ~LYS_MAND_TRUE;
+ }
+ }
}
ret = LY_SUCCESS;
@@ -3469,6 +3624,10 @@
node->prev = ctx->mod->compiled->data->prev;
ctx->mod->compiled->data->prev = node;
}
+ if (lys_compile_node_uniqness(ctx, ctx->mod->compiled->data, ctx->mod->compiled->rpcs,
+ ctx->mod->compiled->notifs, node->name, node)) {
+ return LY_EVALID;
+ }
}
return LY_SUCCESS;