libyang REFACTOR applying deviations, augments, and refines (#1217)
They are no longer applied as part of their
definition module compilation but instead their
target module compilation.
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index d7f0872..c98c1d6 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -44,6 +44,8 @@
static LY_ERR lys_compile_ext(struct lysc_ctx *ctx, struct lysp_ext_instance *ext_p, struct lysc_ext_instance *ext,
void *parent, LYEXT_PARENT parent_type, const struct lys_module *ext_mod);
+static LY_ERR lysp_qname_dup(const struct ly_ctx *ctx, struct lysp_qname *qname, const struct lysp_qname *orig_qname);
+
/**
* @brief Duplicate string into dictionary
* @param[in] CTX libyang context of the dictionary.
@@ -54,6 +56,16 @@
#define DUP_STRING_GOTO(CTX, ORIG, DUP, RET, GOTO) if (ORIG) {LY_CHECK_GOTO(RET = lydict_insert(CTX, ORIG, 0, &DUP), GOTO);}
+#define DUP_ARRAY(CTX, ORIG_ARRAY, NEW_ARRAY, DUP_FUNC) \
+ if (ORIG_ARRAY) { \
+ LY_ARRAY_COUNT_TYPE u; \
+ LY_ARRAY_CREATE_RET(CTX, NEW_ARRAY, LY_ARRAY_COUNT(ORIG_ARRAY), LY_EMEM); \
+ LY_ARRAY_FOR(ORIG_ARRAY, u) { \
+ LY_ARRAY_INCREMENT(NEW_ARRAY); \
+ LY_CHECK_RET(DUP_FUNC(CTX, &(NEW_ARRAY)[u], &(ORIG_ARRAY)[u])); \
+ } \
+ }
+
#define COMPILE_ARRAY_GOTO(CTX, ARRAY_P, ARRAY_C, ITER, FUNC, RET, GOTO) \
if (ARRAY_P) { \
LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, LY_ARRAY_COUNT(ARRAY_P), RET, GOTO); \
@@ -65,14 +77,18 @@
} \
}
-#define COMPILE_ARRAY1_GOTO(CTX, ARRAY_P, ARRAY_C, PARENT, ITER, FUNC, USES_STATUS, RET, GOTO) \
+#define COMPILE_OP_ARRAY_GOTO(CTX, ARRAY_P, ARRAY_C, PARENT, ITER, FUNC, USES_STATUS, RET, GOTO) \
if (ARRAY_P) { \
LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, LY_ARRAY_COUNT(ARRAY_P), RET, GOTO); \
LY_ARRAY_COUNT_TYPE __array_offset = LY_ARRAY_COUNT(ARRAY_C); \
for (ITER = 0; ITER < LY_ARRAY_COUNT(ARRAY_P); ++ITER) { \
LY_ARRAY_INCREMENT(ARRAY_C); \
RET = FUNC(CTX, &(ARRAY_P)[ITER], PARENT, &(ARRAY_C)[ITER + __array_offset], USES_STATUS); \
- LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
+ if (RET == LY_EDENIED) { \
+ LY_ARRAY_DECREMENT(ARRAY_C); \
+ } else if (RET != LY_SUCCESS) { \
+ goto GOTO; \
+ } \
} \
}
@@ -150,90 +166,95 @@
return NULL;
}
+/**
+ * @brief Add/replace a leaf default value in unres.
+ * Can also be used for a single leaf-list default value.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] leaf Leaf with the default value.
+ * @param[in] dflt Default value to use.
+ * @return LY_ERR value.
+ */
static LY_ERR
-lysc_incomplete_leaf_dflt_add(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, const char *dflt,
- struct lys_module *dflt_mod)
+lysc_unres_leaf_dflt_add(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, struct lysp_qname *dflt)
{
- struct lysc_incomplete_dflt *r;
+ struct lysc_unres_dflt *r = NULL;
uint32_t i;
for (i = 0; i < ctx->dflts.count; ++i) {
- r = (struct lysc_incomplete_dflt *)ctx->dflts.objs[i];
- if (r->leaf == leaf) {
+ if (((struct lysc_unres_dflt *)ctx->dflts.objs[i])->leaf == leaf) {
/* just replace the default */
- r->dflt = dflt;
- return LY_SUCCESS;
+ r = ctx->dflts.objs[i];
+ lysp_qname_free(ctx->ctx, r->dflt);
+ free(r->dflt);
+ break;
}
}
+ if (!r) {
+ /* add new unres item */
+ r = calloc(1, sizeof *r);
+ LY_CHECK_ERR_RET(!r, LOGMEM(ctx->ctx), LY_EMEM);
+ r->leaf = leaf;
- r = malloc(sizeof *r);
- LY_CHECK_ERR_RET(!r, LOGMEM(ctx->ctx), LY_EMEM);
- r->leaf = leaf;
- r->dflt = dflt;
- r->dflts = NULL;
- r->dflt_mod = dflt_mod;
- LY_CHECK_RET(ly_set_add(&ctx->dflts, r, LY_SET_OPT_USEASLIST, NULL));
+ LY_CHECK_RET(ly_set_add(&ctx->dflts, r, LY_SET_OPT_USEASLIST, NULL));
+ }
+
+ r->dflt = malloc(sizeof *r->dflt);
+ lysp_qname_dup(ctx->ctx, r->dflt, dflt);
return LY_SUCCESS;
}
/**
- * @brief Add record into the compile context's list of incomplete default values.
- * @param[in] ctx Compile context with the incomplete default values list.
- * @param[in] term Term context node with the default value.
- * @param[in] value String default value.
- * @param[in] val_len Length of @p value.
- * @param[in] dflt_mod Module of the default value definition to store in the record.
- * @return LY_EMEM in case of memory allocation failure.
- * @return LY_SUCCESS
+ * @brief Add/replace a leaf-list default value(s) in unres.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] llist Leaf-list with the default value.
+ * @param[in] dflts Sized array of the default values.
+ * @return LY_ERR value.
*/
static LY_ERR
-lysc_incomplete_llist_dflts_add(struct lysc_ctx *ctx, struct lysc_node_leaflist *llist, const char **dflts,
- struct lys_module *dflt_mod)
+lysc_unres_llist_dflts_add(struct lysc_ctx *ctx, struct lysc_node_leaflist *llist, struct lysp_qname *dflts)
{
- struct lysc_incomplete_dflt *r;
+ struct lysc_unres_dflt *r = NULL;
uint32_t i;
for (i = 0; i < ctx->dflts.count; ++i) {
- r = (struct lysc_incomplete_dflt *)ctx->dflts.objs[i];
- if (r->llist == llist) {
+ if (((struct lysc_unres_dflt *)ctx->dflts.objs[i])->llist == llist) {
/* just replace the defaults */
- r->dflts = dflts;
- return LY_SUCCESS;
+ r = ctx->dflts.objs[i];
+ lysp_qname_free(ctx->ctx, r->dflt);
+ free(r->dflt);
+ r->dflt = NULL;
+ FREE_ARRAY(ctx->ctx, r->dflts, lysp_qname_free);
+ r->dflts = NULL;
+ break;
}
}
+ if (!r) {
+ r = calloc(1, sizeof *r);
+ LY_CHECK_ERR_RET(!r, LOGMEM(ctx->ctx), LY_EMEM);
+ r->llist = llist;
- r = malloc(sizeof *r);
- LY_CHECK_ERR_RET(!r, LOGMEM(ctx->ctx), LY_EMEM);
- r->llist = llist;
- r->dflt = NULL;
- r->dflts = dflts;
- r->dflt_mod = dflt_mod;
- LY_CHECK_RET(ly_set_add(&ctx->dflts, r, LY_SET_OPT_USEASLIST, NULL));
+ LY_CHECK_RET(ly_set_add(&ctx->dflts, r, LY_SET_OPT_USEASLIST, NULL));
+ }
+
+ DUP_ARRAY(ctx->ctx, dflts, r->dflts, lysp_qname_dup);
return LY_SUCCESS;
}
-/**
- * @brief Remove record of the given default value from the compile context's list of incomplete default values.
- * @param[in] ctx Compile context with the incomplete default values list.
- * @param[in] dflt Incomplete default values identifying the record to remove.
- */
static void
-lysc_incomplete_dflt_remove(struct lysc_ctx *ctx, struct lysc_node *term)
+lysc_unres_dflt_free(const struct ly_ctx *ctx, struct lysc_unres_dflt *r)
{
- uint32_t u;
- struct lysc_incomplete_dflt *r;
-
- for (u = 0; u < ctx->dflts.count; ++u) {
- r = ctx->dflts.objs[u];
- if (r->leaf == (struct lysc_node_leaf *)term) {
- free(ctx->dflts.objs[u]);
- memmove(&ctx->dflts.objs[u], &ctx->dflts.objs[u + 1], (ctx->dflts.count - (u + 1)) * sizeof *ctx->dflts.objs);
- --ctx->dflts.count;
- return;
- }
+ assert(!r->dflt || !r->dflts);
+ if (r->dflt) {
+ lysp_qname_free((struct ly_ctx *)ctx, r->dflt);
+ free(r->dflt);
+ } else {
+ FREE_ARRAY((struct ly_ctx *)ctx, r->dflts, lysp_qname_free);
}
+ free(r);
}
void
@@ -461,7 +482,7 @@
* @return Pointer to the feature structure if found, NULL otherwise.
*/
static struct lysc_feature *
-lys_feature_find(struct lys_module *mod, const char *name, size_t len)
+lys_feature_find(const struct lys_module *mod, const char *name, size_t len)
{
size_t i;
LY_ARRAY_COUNT_TYPE u;
@@ -689,15 +710,15 @@
/**
* @brief Compile information from the if-feature statement
* @param[in] ctx Compile context.
- * @param[in] value The if-feature argument to process. It is pointer-to-pointer-to-char just to unify the compile functions.
+ * @param[in] qname The if-feature argument to process. It is pointer-to-qname just to unify the compile functions.
* @param[in,out] iff Prepared (empty) compiled if-feature structure to fill.
* @return LY_ERR value.
*/
static LY_ERR
-lys_compile_iffeature(struct lysc_ctx *ctx, const char **value, struct lysc_iffeature *iff)
+lys_compile_iffeature(struct lysc_ctx *ctx, struct lysp_qname *qname, struct lysc_iffeature *iff)
{
LY_ERR rc = LY_SUCCESS;
- const char *c = *value;
+ const char *c = qname->str;
int64_t i, j;
int8_t op_len, last_not = 0, checkversion = 0;
LY_ARRAY_COUNT_TYPE f_size = 0, expr_size = 0, f_exp = 1;
@@ -726,7 +747,7 @@
for (spaces = 0; c[i + op_len + spaces] && isspace(c[i + op_len + spaces]); spaces++);
if (c[i + op_len + spaces] == '\0') {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
- "Invalid value \"%s\" of if-feature - unexpected end of expression.", *value);
+ "Invalid value \"%s\" of if-feature - unexpected end of expression.", qname->str);
return LY_EVALID;
} else if (!isspace(c[i + op_len])) {
/* feature name starting with the not/and/or */
@@ -743,7 +764,8 @@
} else { /* and, or */
if (f_exp != f_size) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
- "Invalid value \"%s\" of if-feature - missing feature/expression before \"%.*s\" operation.", *value, op_len, &c[i]);
+ "Invalid value \"%s\" of if-feature - missing feature/expression before \"%.*s\" operation.",
+ qname->str, op_len, &c[i]);
return LY_EVALID;
}
f_exp++;
@@ -769,22 +791,22 @@
if (j) {
/* not matching count of ( and ) */
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
- "Invalid value \"%s\" of if-feature - non-matching opening and closing parentheses.", *value);
+ "Invalid value \"%s\" of if-feature - non-matching opening and closing parentheses.", qname->str);
return LY_EVALID;
}
if (f_exp != f_size) {
/* features do not match the needed arguments for the logical operations */
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
"Invalid value \"%s\" of if-feature - number of features in expression does not match "
- "the required number of operands for the operations.", *value);
+ "the required number of operands for the operations.", qname->str);
return LY_EVALID;
}
if (checkversion || expr_size > 1) {
/* check that we have 1.1 module */
- if (ctx->mod_def->version != LYS_VERSION_1_1) {
+ if (qname->mod->version != LYS_VERSION_1_1) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
- "Invalid value \"%s\" of if-feature - YANG 1.1 expression in YANG 1.0 module.", *value);
+ "Invalid value \"%s\" of if-feature - YANG 1.1 expression in YANG 1.0 module.", qname->str);
return LY_EVALID;
}
}
@@ -850,10 +872,10 @@
iff_setop(iff->expr, LYS_IFF_F, expr_size--);
/* now get the link to the feature definition */
- f = lys_feature_find(ctx->mod_def, &c[i], j - i);
+ f = lys_feature_find(qname->mod, &c[i], j - i);
LY_CHECK_ERR_GOTO(!f, LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
- "Invalid value \"%s\" of if-feature - unable to find feature \"%.*s\".", *value, j - i, &c[i]);
- rc = LY_EVALID, error)
+ "Invalid value \"%s\" of if-feature - unable to find feature \"%.*s\".", qname->str, j - i, &c[i]);
+ rc = LY_EVALID, error)
iff->features[f_size] = f;
LY_ARRAY_INCREMENT(iff->features);
f_size--;
@@ -867,7 +889,7 @@
if (++expr_size || ++f_size) {
/* not all expected operators and operands found */
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
- "Invalid value \"%s\" of if-feature - processing error.", *value);
+ "Invalid value \"%s\" of if-feature - processing error.", qname->str);
rc = LY_EINT;
} else {
rc = LY_SUCCESS;
@@ -935,8 +957,8 @@
{
LY_ERR ret = LY_SUCCESS;
- LY_CHECK_RET(lyxp_expr_parse(ctx->ctx, must_p->arg, 0, 1, &must->cond));
- must->module = ctx->mod_def;
+ LY_CHECK_RET(lyxp_expr_parse(ctx->ctx, must_p->arg.str, 0, 1, &must->cond));
+ must->module = (struct lys_module *)must_p->arg.mod;
DUP_STRING_GOTO(ctx->ctx, must_p->eapptag, must->eapptag, ret, done);
DUP_STRING_GOTO(ctx->ctx, must_p->emsg, must->emsg, ret, done);
DUP_STRING_GOTO(ctx->ctx, must_p->dsc, must->dsc, ret, done);
@@ -1375,11 +1397,9 @@
* @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 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 dis_features list.
+ * @param[in] mod The module structure with the features to decompile.
*/
static void
lys_feature_precompile_revert(struct lysc_ctx *ctx, struct lys_module *mod)
@@ -1698,7 +1718,7 @@
assert(range);
assert(range_p);
- expr = range_p->arg;
+ expr = range_p->arg.str;
while (1) {
if (isspace(*expr)) {
++expr;
@@ -1721,7 +1741,7 @@
/* min cannot be used elsewhere than in the first part */
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
"Invalid %s restriction - unexpected data before min keyword (%.*s).", length_restr ? "length" : "range",
- expr - range_p->arg, range_p->arg);
+ expr - range_p->arg.str, range_p->arg.str);
goto cleanup;
}
expr += 3;
@@ -2175,13 +2195,13 @@
*pattern = calloc(1, sizeof **pattern);
++(*pattern)->refcount;
- ret = lys_compile_type_pattern_check(ctx->ctx, ctx->path, &patterns_p[u].arg[1], &(*pattern)->code);
+ ret = lys_compile_type_pattern_check(ctx->ctx, ctx->path, &patterns_p[u].arg.str[1], &(*pattern)->code);
LY_CHECK_RET(ret);
- if (patterns_p[u].arg[0] == 0x15) {
+ if (patterns_p[u].arg.str[0] == 0x15) {
(*pattern)->inverted = 1;
}
- DUP_STRING_GOTO(ctx->ctx, &patterns_p[u].arg[1], (*pattern)->expr, ret, done);
+ DUP_STRING_GOTO(ctx->ctx, &patterns_p[u].arg.str[1], (*pattern)->expr, ret, done);
DUP_STRING_GOTO(ctx->ctx, patterns_p[u].eapptag, (*pattern)->eapptag, ret, done);
DUP_STRING_GOTO(ctx->ctx, patterns_p[u].emsg, (*pattern)->emsg, ret, done);
DUP_STRING_GOTO(ctx->ctx, patterns_p[u].dsc, (*pattern)->dsc, ret, done);
@@ -2500,14 +2520,14 @@
return ret;
}
-static LY_ERR lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_node_p, uint16_t context_flags,
+static LY_ERR lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags,
struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p,
- struct lysc_type **type, const char **units, const char **dflt, struct lys_module **dflt_mod);
+ struct lysc_type **type, const char **units, struct lysp_qname **dflt);
/**
* @brief The core of the lys_compile_type() - compile information about the given type (from typedef or leaf/leaf-list).
* @param[in] ctx Compile context.
- * @param[in] context_node_p Schema node where the type/typedef is placed to correctly find the base types.
+ * @param[in] context_pnode Schema node where the type/typedef is placed to correctly find the base types.
* @param[in] context_flags Flags of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
* @param[in] context_mod Module of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
* @param[in] context_name Name of the context node or referencing typedef for logging.
@@ -2520,7 +2540,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lys_compile_type_(struct lysc_ctx *ctx, struct lysp_node *context_node_p, uint16_t context_flags,
+lys_compile_type_(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags,
struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p, struct lys_module *module,
LY_DATA_TYPE basetype, const char *tpdfname, struct lysc_type *base, struct lysc_type **type)
{
@@ -2762,8 +2782,8 @@
/* compile the type */
LY_ARRAY_CREATE_RET(ctx->ctx, un->types, LY_ARRAY_COUNT(type_p->types), LY_EVALID);
for (LY_ARRAY_COUNT_TYPE u = 0, additional = 0; u < LY_ARRAY_COUNT(type_p->types); ++u) {
- LY_CHECK_RET(lys_compile_type(ctx, context_node_p, context_flags, context_mod, context_name,
- &type_p->types[u], &un->types[u + additional], NULL, NULL, NULL));
+ LY_CHECK_RET(lys_compile_type(ctx, context_pnode, context_flags, context_mod, context_name,
+ &type_p->types[u], &un->types[u + additional], NULL, NULL));
if (un->types[u + additional]->basetype == LY_TYPE_UNION) {
/* add space for additional types from the union subtype */
un_aux = (struct lysc_type_union *)un->types[u + additional];
@@ -2883,7 +2903,7 @@
/**
* @brief Compile information about the leaf/leaf-list's type.
* @param[in] ctx Compile context.
- * @param[in] context_node_p Schema node where the type/typedef is placed to correctly find the base types.
+ * @param[in] context_pnode Schema node where the type/typedef is placed to correctly find the base types.
* @param[in] context_flags Flags of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
* @param[in] context_mod Module of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
* @param[in] context_name Name of the context node or referencing typedef for logging.
@@ -2891,13 +2911,12 @@
* @param[out] type Newly created (or reused with increased refcount) type structure with the filled information about the type.
* @param[out] units Storage for inheriting units value from the typedefs the current type derives from.
* @param[out] dflt Default value for the type.
- * @param[out] dflt_mod Local module for the default value.
* @return LY_ERR value.
*/
static LY_ERR
-lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_node_p, uint16_t context_flags,
+lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags,
struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p,
- struct lysc_type **type, const char **units, const char **dflt, struct lys_module **dflt_mod)
+ struct lysc_type **type, const char **units, struct lysp_qname **dflt)
{
LY_ERR ret = LY_SUCCESS;
ly_bool dummyloops = 0;
@@ -2910,17 +2929,14 @@
struct lysc_type *base = NULL, *prev_type;
struct ly_set tpdf_chain = {0};
- assert((dflt && dflt_mod) || (!dflt && !dflt_mod));
-
(*type) = NULL;
if (dflt) {
*dflt = NULL;
- *dflt_mod = NULL;
}
tctx = calloc(1, sizeof *tctx);
LY_CHECK_ERR_RET(!tctx, LOGMEM(ctx->ctx), LY_EMEM);
- for (ret = lysp_type_find(type_p->name, context_node_p, ctx->mod_def->parsed,
+ for (ret = lysp_type_find(type_p->name, context_pnode, ctx->mod_def->parsed,
&basetype, &tctx->tpdf, &tctx->node, &tctx->mod);
ret == LY_SUCCESS;
ret = lysp_type_find(tctx_prev->tpdf->type.name, tctx_prev->node, tctx_prev->mod,
@@ -2939,10 +2955,9 @@
DUP_STRING(ctx->ctx, tctx->tpdf->units, *units, ret);
LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
}
- if (dflt && !*dflt) {
+ if (dflt && !*dflt && tctx->tpdf->dflt.str) {
/* inherit default */
- *dflt = tctx->tpdf->dflt;
- *dflt_mod = tctx->mod->mod;
+ *dflt = (struct lysp_qname *)&tctx->tpdf->dflt;
}
if (dummyloops && (!units || *units) && dflt && *dflt) {
basetype = ((struct type_context *)tpdf_chain.objs[tpdf_chain.count - 1])->tpdf->type.compiled->basetype;
@@ -3084,10 +3099,10 @@
tctx->tpdf->name, ly_data_type2str[basetype]);
ret = LY_EVALID;
goto cleanup;
- } else if (basetype == LY_TYPE_EMPTY && tctx->tpdf->dflt) {
+ } else if (basetype == LY_TYPE_EMPTY && tctx->tpdf->dflt.str) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
"Invalid type \"%s\" - \"empty\" type must not have a default value (%s).",
- tctx->tpdf->name, tctx->tpdf->dflt);
+ tctx->tpdf->name, tctx->tpdf->dflt.str);
ret = LY_EVALID;
goto cleanup;
}
@@ -3112,7 +3127,7 @@
/* TODO user type plugins */
(*type)->plugin = &ly_builtin_type_plugins[basetype];
++(*type)->refcount;
- ret = lys_compile_type_(ctx, context_node_p, context_flags, context_mod, context_name, type_p, ctx->mod_def, basetype, NULL, base, type);
+ ret = lys_compile_type_(ctx, context_pnode, context_flags, context_mod, context_name, type_p, ctx->mod_def, basetype, NULL, base, type);
LY_CHECK_GOTO(ret, cleanup);
} else if (basetype != LY_TYPE_BOOL && basetype != LY_TYPE_EMPTY) {
/* no specific restriction in leaf's type definition, copy from the base */
@@ -3264,7 +3279,15 @@
#undef CHECK_NODE
}
-static LY_ERR lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *node_p, struct lysc_node *parent, uint16_t uses_status);
+static LY_ERR lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *parent,
+ uint16_t uses_status, struct ly_set *child_set);
+
+static LY_ERR lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode,
+ const struct lysc_node *parent, struct lysp_node **dev_pnode, ly_bool *not_supported);
+
+static LY_ERR lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node);
+
+static void lysp_dev_node_free(const struct ly_ctx *ctx, struct lysp_node *dev_pnode);
/**
* @brief Compile parsed RPC/action schema node information.
@@ -3274,19 +3297,33 @@
* @param[in,out] action Prepared (empty) compiled action structure to fill.
* @param[in] uses_status If the RPC/action is being placed instead of uses, here we have the uses's status value (as node's flags).
* Zero means no uses, non-zero value with no status bit set mean the default status.
- * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
+ * @return LY_SUCCESS on success,
+ * @return LY_EVALID on validation error,
+ * @return LY_EDENIED on not-supported deviation.
*/
static LY_ERR
lys_compile_action(struct lysc_ctx *ctx, struct lysp_action *action_p,
struct lysc_node *parent, struct lysc_action *action, uint16_t uses_status)
{
LY_ERR ret = LY_SUCCESS;
- struct lysp_node *child_p;
+ struct lysp_node *child_p, *dev_pnode = NULL, *dev_input_p = NULL, *dev_output_p = NULL;
+ struct lysp_action *orig_action_p = action_p;
+ struct lysp_action_inout *inout_p;
LY_ARRAY_COUNT_TYPE u;
+ ly_bool not_supported;
uint32_t opt_prev = ctx->options;
lysc_update_path(ctx, parent, action_p->name);
+ /* apply deviation on the action/RPC */
+ LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)action_p, parent, &dev_pnode, ¬_supported));
+ if (not_supported) {
+ lysc_update_path(ctx, NULL, NULL);
+ return LY_EDENIED;
+ } else if (dev_pnode) {
+ action_p = (struct lysp_action *)dev_pnode;
+ }
+
/* member needed for uniqueness check lys_getnext() */
action->nodetype = parent ? LYS_ACTION : LYS_RPC;
action->module = ctx->mod;
@@ -3302,7 +3339,7 @@
}
if (!(ctx->options & LYSC_OPT_FREE_SP)) {
- action->sp = action_p;
+ action->sp = orig_action_p;
}
action->flags = action_p->flags & LYS_FLAGS_COMPILED_MASK;
@@ -3316,35 +3353,83 @@
COMPILE_ARRAY_GOTO(ctx, action_p->iffeatures, action->iffeatures, u, lys_compile_iffeature, ret, cleanup);
COMPILE_EXTS_GOTO(ctx, action_p->exts, action->exts, action, LYEXT_PAR_NODE, ret, cleanup);
+ /* connect any action augments */
+ LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)action));
+
/* input */
lysc_update_path(ctx, (struct lysc_node *)action, "input");
- COMPILE_ARRAY_GOTO(ctx, action_p->input.musts, action->input.musts, u, lys_compile_must, ret, cleanup);
- COMPILE_EXTS_GOTO(ctx, action_p->input.exts, action->input_exts, &action->input, LYEXT_PAR_INPUT, ret, cleanup);
- ctx->options |= LYSC_OPT_RPC_INPUT;
- LY_LIST_FOR(action_p->input.data, child_p) {
- LY_CHECK_RET(lys_compile_node(ctx, child_p, (struct lysc_node *)action, uses_status));
+
+ /* apply deviations on input */
+ LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)&action_p->input, (struct lysc_node *)action,
+ &dev_input_p, ¬_supported));
+ if (not_supported) {
+ inout_p = NULL;
+ } else if (dev_input_p) {
+ inout_p = (struct lysp_action_inout *)dev_input_p;
+ } else {
+ inout_p = &action_p->input;
}
+
+ if (inout_p) {
+ action->input.nodetype = LYS_INPUT;
+ COMPILE_ARRAY_GOTO(ctx, inout_p->musts, action->input.musts, u, lys_compile_must, ret, cleanup);
+ COMPILE_EXTS_GOTO(ctx, inout_p->exts, action->input_exts, &action->input, LYEXT_PAR_INPUT, ret, cleanup);
+ ctx->options |= LYSC_OPT_RPC_INPUT;
+
+ /* connect any input augments */
+ LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)&action->input));
+
+ LY_LIST_FOR(inout_p->data, child_p) {
+ LY_CHECK_RET(lys_compile_node(ctx, child_p, (struct lysc_node *)action, uses_status, NULL));
+ }
+ ctx->options = opt_prev;
+ }
+
lysc_update_path(ctx, NULL, NULL);
- ctx->options = opt_prev;
/* output */
lysc_update_path(ctx, (struct lysc_node *)action, "output");
- COMPILE_ARRAY_GOTO(ctx, action_p->output.musts, action->output.musts, u, lys_compile_must, ret, cleanup);
- COMPILE_EXTS_GOTO(ctx, action_p->output.exts, action->output_exts, &action->output, LYEXT_PAR_OUTPUT, ret, cleanup);
- ctx->options |= LYSC_OPT_RPC_OUTPUT;
- LY_LIST_FOR(action_p->output.data, child_p) {
- LY_CHECK_RET(lys_compile_node(ctx, child_p, (struct lysc_node *)action, uses_status));
+
+ /* apply deviations on output */
+ LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)&action_p->output, (struct lysc_node *)action,
+ &dev_output_p, ¬_supported));
+ if (not_supported) {
+ inout_p = NULL;
+ } else if (dev_output_p) {
+ inout_p = (struct lysp_action_inout *)dev_output_p;
+ } else {
+ inout_p = &action_p->output;
}
- lysc_update_path(ctx, NULL, NULL);
+
+ if (inout_p) {
+ action->output.nodetype = LYS_OUTPUT;
+ COMPILE_ARRAY_GOTO(ctx, inout_p->musts, action->output.musts, u, lys_compile_must, ret, cleanup);
+ COMPILE_EXTS_GOTO(ctx, inout_p->exts, action->output_exts, &action->output, LYEXT_PAR_OUTPUT, ret, cleanup);
+ ctx->options |= LYSC_OPT_RPC_OUTPUT;
+
+ /* connect any output augments */
+ LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)&action->output));
+
+ LY_LIST_FOR(inout_p->data, child_p) {
+ LY_CHECK_RET(lys_compile_node(ctx, child_p, (struct lysc_node *)action, uses_status, NULL));
+ }
+ ctx->options = opt_prev;
+ }
+
lysc_update_path(ctx, NULL, NULL);
- if ((action_p->input.musts || action_p->output.musts) && !(ctx->options & LYSC_OPT_GROUPING)) {
+ if ((action->input.musts || action->output.musts) && !(ctx->options & LYSC_OPT_GROUPING)) {
/* do not check "must" semantics in a grouping */
ret = ly_set_add(&ctx->xpath, action, 0, NULL);
LY_CHECK_GOTO(ret, cleanup);
}
+ lysc_update_path(ctx, NULL, NULL);
+
cleanup:
+ lysp_dev_node_free(ctx->ctx, dev_pnode);
+ lysp_dev_node_free(ctx->ctx, dev_input_p);
+ lysp_dev_node_free(ctx->ctx, dev_output_p);
ctx->options = opt_prev;
return ret;
}
@@ -3357,19 +3442,31 @@
* @param[in,out] notif Prepared (empty) compiled notification structure to fill.
* @param[in] uses_status If the Notification is being placed instead of uses, here we have the uses's status value (as node's flags).
* Zero means no uses, non-zero value with no status bit set mean the default status.
- * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
+ * @return LY_SUCCESS on success,
+ * @return LY_EVALID on validation error,
+ * @return LY_EDENIED on not-supported deviation.
*/
static LY_ERR
lys_compile_notif(struct lysc_ctx *ctx, struct lysp_notif *notif_p,
struct lysc_node *parent, struct lysc_notif *notif, uint16_t uses_status)
{
LY_ERR ret = LY_SUCCESS;
- struct lysp_node *child_p;
+ struct lysp_node *child_p, *dev_pnode = NULL;
+ struct lysp_notif *orig_notif_p = notif_p;
LY_ARRAY_COUNT_TYPE u;
+ ly_bool not_supported;
uint32_t opt_prev = ctx->options;
lysc_update_path(ctx, parent, notif_p->name);
+ LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)notif_p, parent, &dev_pnode, ¬_supported));
+ if (not_supported) {
+ lysc_update_path(ctx, NULL, NULL);
+ return LY_EDENIED;
+ } else if (dev_pnode) {
+ notif_p = (struct lysp_notif *)dev_pnode;
+ }
+
/* member needed for uniqueness check lys_getnext() */
notif->nodetype = LYS_NOTIF;
notif->module = ctx->mod;
@@ -3385,7 +3482,7 @@
}
if (!(ctx->options & LYSC_OPT_FREE_SP)) {
- notif->sp = notif_p;
+ notif->sp = orig_notif_p;
}
notif->flags = notif_p->flags & LYS_FLAGS_COMPILED_MASK;
@@ -3407,13 +3504,19 @@
COMPILE_EXTS_GOTO(ctx, notif_p->exts, notif->exts, notif, LYEXT_PAR_NODE, ret, cleanup);
ctx->options |= LYSC_OPT_NOTIFICATION;
+
+ /* connect any notification augments */
+ LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)notif));
+
LY_LIST_FOR(notif_p->data, child_p) {
- ret = lys_compile_node(ctx, child_p, (struct lysc_node *)notif, uses_status);
+ ret = lys_compile_node(ctx, child_p, (struct lysc_node *)notif, uses_status, NULL);
LY_CHECK_GOTO(ret, cleanup);
}
lysc_update_path(ctx, NULL, NULL);
+
cleanup:
+ lysp_dev_node_free(ctx->ctx, dev_pnode);
ctx->options = opt_prev;
return ret;
}
@@ -3421,15 +3524,15 @@
/**
* @brief Compile parsed container node information.
* @param[in] ctx Compile context
- * @param[in] node_p Parsed container node.
+ * @param[in] pnode Parsed container node.
* @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
* is enriched with the container-specific information.
* @return LY_ERR value - LY_SUCCESS or LY_EVALID.
*/
static LY_ERR
-lys_compile_node_container(struct lysc_ctx *ctx, struct lysp_node *node_p, struct lysc_node *node)
+lys_compile_node_container(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
{
- struct lysp_node_container *cont_p = (struct lysp_node_container *)node_p;
+ struct lysp_node_container *cont_p = (struct lysp_node_container *)pnode;
struct lysc_node_container *cont = (struct lysc_node_container *)node;
struct lysp_node *child_p;
LY_ARRAY_COUNT_TYPE u;
@@ -3453,7 +3556,7 @@
cont_p->name, cont_p->parent->name);
cont->flags |= LYS_PRESENCE;
} else if ((cont_p->parent->nodetype == LYS_CASE)
- && (((struct lysp_node_case *)cont_p->parent)->child == node_p) && !cont_p->next) {
+ && (((struct lysp_node_case *)cont_p->parent)->child == pnode) && !cont_p->next) {
/* container is the only node in a case, so its existence decides the existence of the whole case */
LOGWRN(ctx->ctx, "Container \"%s\" changed to presence because it has a meaning as a case of choice \"%s\".",
cont_p->name, cont_p->parent->name);
@@ -3467,7 +3570,7 @@
*/
LY_LIST_FOR(cont_p->child, child_p) {
- ret = lys_compile_node(ctx, child_p, node, 0);
+ ret = lys_compile_node(ctx, child_p, node, 0, NULL);
LY_CHECK_GOTO(ret, done);
}
@@ -3477,8 +3580,8 @@
ret = ly_set_add(&ctx->xpath, cont, 0, NULL);
LY_CHECK_GOTO(ret, done);
}
- COMPILE_ARRAY1_GOTO(ctx, cont_p->actions, cont->actions, node, u, lys_compile_action, 0, ret, done);
- COMPILE_ARRAY1_GOTO(ctx, cont_p->notifs, cont->notifs, node, u, lys_compile_notif, 0, ret, done);
+ COMPILE_OP_ARRAY_GOTO(ctx, cont_p->actions, cont->actions, node, u, lys_compile_action, 0, ret, done);
+ COMPILE_OP_ARRAY_GOTO(ctx, cont_p->notifs, cont->notifs, node, u, lys_compile_notif, 0, ret, done);
done:
return ret;
@@ -3496,15 +3599,14 @@
lys_compile_node_type(struct lysc_ctx *ctx, struct lysp_node *context_node, struct lysp_type *type_p,
struct lysc_node_leaf *leaf)
{
- const char *dflt;
- struct lys_module *dflt_mod;
+ struct lysp_qname *dflt;
LY_CHECK_RET(lys_compile_type(ctx, context_node, leaf->flags, ctx->mod_def->parsed, leaf->name, type_p, &leaf->type,
- leaf->units ? NULL : &leaf->units, &dflt, &dflt_mod));
+ leaf->units ? NULL : &leaf->units, &dflt));
/* store default value, if any */
if (dflt && !(leaf->flags & LYS_SET_DFLT)) {
- LY_CHECK_RET(lysc_incomplete_leaf_dflt_add(ctx, leaf, dflt, dflt_mod));
+ LY_CHECK_RET(lysc_unres_leaf_dflt_add(ctx, leaf, dflt));
}
if (leaf->type->basetype == LY_TYPE_LEAFREF) {
@@ -3532,15 +3634,15 @@
/**
* @brief Compile parsed leaf node information.
* @param[in] ctx Compile context
- * @param[in] node_p Parsed leaf node.
+ * @param[in] pnode Parsed leaf node.
* @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
* is enriched with the leaf-specific information.
* @return LY_ERR value - LY_SUCCESS or LY_EVALID.
*/
static LY_ERR
-lys_compile_node_leaf(struct lysc_ctx *ctx, struct lysp_node *node_p, struct lysc_node *node)
+lys_compile_node_leaf(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
{
- struct lysp_node_leaf *leaf_p = (struct lysp_node_leaf *)node_p;
+ struct lysp_node_leaf *leaf_p = (struct lysp_node_leaf *)pnode;
struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)node;
LY_ARRAY_COUNT_TYPE u;
LY_ERR ret = LY_SUCCESS;
@@ -3557,15 +3659,22 @@
}
/* compile type */
- ret = lys_compile_node_type(ctx, node_p, &leaf_p->type, leaf);
+ ret = lys_compile_node_type(ctx, pnode, &leaf_p->type, leaf);
LY_CHECK_GOTO(ret, done);
/* store/update default value */
- if (leaf_p->dflt) {
- LY_CHECK_RET(lysc_incomplete_leaf_dflt_add(ctx, leaf, leaf_p->dflt, ctx->mod_def));
+ if (leaf_p->dflt.str) {
+ LY_CHECK_RET(lysc_unres_leaf_dflt_add(ctx, leaf, &leaf_p->dflt));
leaf->flags |= LYS_SET_DFLT;
}
+ /* checks */
+ if ((leaf->flags & LYS_SET_DFLT) && (leaf->flags & LYS_MAND_TRUE)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid mandatory leaf with a default value.");
+ return LY_EVALID;
+ }
+
done:
return ret;
}
@@ -3573,15 +3682,15 @@
/**
* @brief Compile parsed leaf-list node information.
* @param[in] ctx Compile context
- * @param[in] node_p Parsed leaf-list node.
+ * @param[in] pnode Parsed leaf-list node.
* @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
* is enriched with the leaf-list-specific information.
* @return LY_ERR value - LY_SUCCESS or LY_EVALID.
*/
static LY_ERR
-lys_compile_node_leaflist(struct lysc_ctx *ctx, struct lysp_node *node_p, struct lysc_node *node)
+lys_compile_node_leaflist(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
{
- struct lysp_node_leaflist *llist_p = (struct lysp_node_leaflist *)node_p;
+ struct lysp_node_leaflist *llist_p = (struct lysp_node_leaflist *)pnode;
struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)node;
LY_ARRAY_COUNT_TYPE u;
LY_ERR ret = LY_SUCCESS;
@@ -3598,12 +3707,18 @@
}
/* compile type */
- ret = lys_compile_node_type(ctx, node_p, &llist_p->type, (struct lysc_node_leaf *)llist);
+ ret = lys_compile_node_type(ctx, pnode, &llist_p->type, (struct lysc_node_leaf *)llist);
LY_CHECK_GOTO(ret, done);
/* store/update default values */
if (llist_p->dflts) {
- LY_CHECK_GOTO(lysc_incomplete_llist_dflts_add(ctx, llist, llist_p->dflts, ctx->mod_def), done);
+ if (ctx->mod_def->version < LYS_VERSION_1_1) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Leaf-list default values are allowed only in YANG 1.1 modules.");
+ return LY_EVALID;
+ }
+
+ LY_CHECK_GOTO(lysc_unres_llist_dflts_add(ctx, llist, llist_p->dflts), done);
llist->flags |= LYS_SET_DFLT;
}
@@ -3613,6 +3728,19 @@
}
llist->max = llist_p->max ? llist_p->max : (uint32_t)-1;
+ /* checks */
+ if ((llist->flags & LYS_SET_DFLT) && (llist->flags & LYS_MAND_TRUE)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid mandatory leaf-list with default value(s).");
+ return LY_EVALID;
+ }
+
+ if (llist->min > llist->max) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Leaf-list min-elements %u is bigger than max-elements %u.",
+ llist->min, llist->max);
+ return LY_EVALID;
+ }
+
done:
return ret;
}
@@ -3620,13 +3748,12 @@
/**
* @brief Compile information about list's uniques.
* @param[in] ctx Compile context.
- * @param[in] context_module Module where the prefixes are going to be resolved.
* @param[in] uniques Sized array list of unique statements.
* @param[in] list Compiled list where the uniques are supposed to be resolved and stored.
* @return LY_ERR value.
*/
static LY_ERR
-lys_compile_node_list_unique(struct lysc_ctx *ctx, struct lys_module *context_module, const char **uniques, struct lysc_node_list *list)
+lys_compile_node_list_unique(struct lysc_ctx *ctx, struct lysp_qname *uniques, struct lysc_node_list *list)
{
LY_ERR ret = LY_SUCCESS;
struct lysc_node_leaf **key, ***unique;
@@ -3637,10 +3764,10 @@
int8_t config; /* -1 - not yet seen; 0 - LYS_CONFIG_R; 1 - LYS_CONFIG_W */
uint16_t flags;
- for (v = 0; v < LY_ARRAY_COUNT(uniques); ++v) {
+ LY_ARRAY_FOR(uniques, v) {
config = -1;
LY_ARRAY_NEW_RET(ctx->ctx, list->uniques, unique, LY_EMEM);
- keystr = uniques[v];
+ keystr = uniques[v].str;
while (keystr) {
delim = strpbrk(keystr, " \t\n");
if (delim) {
@@ -3654,7 +3781,7 @@
/* unique node must be present */
LY_ARRAY_NEW_RET(ctx->ctx, *unique, key, LY_EMEM);
- ret = lysc_resolve_schema_nodeid(ctx, keystr, len, (struct lysc_node *)list, context_module, LYS_LEAF, 0,
+ ret = lysc_resolve_schema_nodeid(ctx, keystr, len, (struct lysc_node *)list, uniques[v].mod, LYS_LEAF,
(const struct lysc_node **)key, &flags);
if (ret != LY_SUCCESS) {
if (ret == LY_EDENIED) {
@@ -3673,7 +3800,7 @@
/* all referenced leafs must be of the same config type */
if (config != -1 && ((((*key)->flags & LYS_CONFIG_W) && config == 0) || (((*key)->flags & LYS_CONFIG_R) && config == 1))) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Unique statement \"%s\" refers to leaves with different config type.", uniques[v]);
+ "Unique statement \"%s\" refers to leaves with different config type.", uniques[v].str);
return LY_EVALID;
} else if ((*key)->flags & LYS_CONFIG_W) {
config = 1;
@@ -3685,7 +3812,7 @@
for (parent = (*key)->parent; parent != (struct lysc_node *)list; parent = parent->parent) {
if (parent->nodetype == LYS_LIST) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Unique statement \"%s\" refers to a leaf in nested list \"%s\".", uniques[v], parent->name);
+ "Unique statement \"%s\" refers to a leaf in nested list \"%s\".", uniques[v].str, parent->name);
return LY_EVALID;
}
}
@@ -3709,15 +3836,15 @@
/**
* @brief Compile parsed list node information.
* @param[in] ctx Compile context
- * @param[in] node_p Parsed list node.
+ * @param[in] pnode Parsed list node.
* @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
* is enriched with the list-specific information.
* @return LY_ERR value - LY_SUCCESS or LY_EVALID.
*/
static LY_ERR
-lys_compile_node_list(struct lysc_ctx *ctx, struct lysp_node *node_p, struct lysc_node *node)
+lys_compile_node_list(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
{
- struct lysp_node_list *list_p = (struct lysp_node_list *)node_p;
+ struct lysp_node_list *list_p = (struct lysp_node_list *)pnode;
struct lysc_node_list *list = (struct lysc_node_list *)node;
struct lysp_node *child_p;
struct lysc_node_leaf *key, *prev_key = NULL;
@@ -3733,7 +3860,7 @@
list->max = list_p->max ? list_p->max : (uint32_t)-1;
LY_LIST_FOR(list_p->child, child_p) {
- LY_CHECK_RET(lys_compile_node(ctx, child_p, node, 0));
+ LY_CHECK_RET(lys_compile_node(ctx, child_p, node, 0, NULL));
}
COMPILE_ARRAY_GOTO(ctx, list_p->musts, list->musts, u, lys_compile_must, ret, done);
@@ -3866,11 +3993,18 @@
/* uniques */
if (list_p->uniques) {
- LY_CHECK_RET(lys_compile_node_list_unique(ctx, list->module, list_p->uniques, list));
+ LY_CHECK_RET(lys_compile_node_list_unique(ctx, list_p->uniques, list));
}
- COMPILE_ARRAY1_GOTO(ctx, list_p->actions, list->actions, node, u, lys_compile_action, 0, ret, done);
- COMPILE_ARRAY1_GOTO(ctx, list_p->notifs, list->notifs, node, u, lys_compile_notif, 0, ret, done);
+ COMPILE_OP_ARRAY_GOTO(ctx, list_p->actions, list->actions, node, u, lys_compile_action, 0, ret, done);
+ COMPILE_OP_ARRAY_GOTO(ctx, list_p->notifs, list->notifs, node, u, lys_compile_notif, 0, ret, done);
+
+ /* checks */
+ if (list->min > list->max) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "List min-elements %u is bigger than max-elements %u.",
+ list->min, list->max);
+ return LY_EVALID;
+ }
done:
return ret;
@@ -3882,40 +4016,45 @@
* Selects (and stores into ::lysc_node_choice#dflt) the default case and set LYS_SET_DFLT flag on it.
*
* @param[in] ctx Compile context.
- * @param[in] dflt Name of the default branch. Can contain even the prefix, but it make sense only in case it is the prefix of the module itself,
- * not the reference to the imported module.
+ * @param[in] dflt Name of the default branch. Can even contain a prefix.
* @param[in,out] ch The compiled choice node, its dflt member is filled to point to the default case node of the choice.
* @return LY_ERR value.
*/
static LY_ERR
-lys_compile_node_choice_dflt(struct lysc_ctx *ctx, const char *dflt, struct lysc_node_choice *ch)
+lys_compile_node_choice_dflt(struct lysc_ctx *ctx, struct lysp_qname *dflt, struct lysc_node_choice *ch)
{
struct lysc_node *iter, *node = (struct lysc_node *)ch;
+ const struct lys_module *mod;
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, ':');
+ name = strchr(dflt->str, ':');
if (name) {
- prefix = dflt;
+ prefix = dflt->str;
prefix_len = name - prefix;
++name;
} else {
- name = dflt;
+ name = dflt->str;
}
- if (prefix && ly_strncmp(node->module->prefix, prefix, prefix_len)) {
- /* 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;
+ if (prefix) {
+ mod = ly_resolve_prefix(ctx->ctx, prefix, prefix_len, LY_PREF_SCHEMA, (void *)dflt->mod);
+ if (!mod) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Default case prefix \"%.*s\" not found in imports of \"%s\".", prefix_len, prefix, dflt->mod->name);
+ return LY_EVALID;
+ }
+ } else {
+ mod = node->module;
}
- ch->dflt = (struct lysc_node_case *)lys_find_child(node, node->module, name, 0, LYS_CASE, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCASE);
+
+ ch->dflt = (struct lysc_node_case *)lys_find_child(node, mod, 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);
+ "Default case \"%s\" not found.", dflt->str);
return LY_EVALID;
}
+
/* no mandatory nodes directly under the default case */
LY_LIST_FOR(ch->dflt->child, iter) {
if (iter->parent != (struct lysc_node *)ch->dflt) {
@@ -3923,68 +4062,17 @@
}
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);
+ "Mandatory node \"%s\" under the default case \"%s\".", iter->name, dflt->str);
return LY_EVALID;
}
}
- ch->dflt->flags |= LYS_SET_DFLT;
- return LY_SUCCESS;
-}
-static LY_ERR
-lys_compile_deviation_set_choice_dflt(struct lysc_ctx *ctx, const char *dflt, struct lysc_node_choice *ch)
-{
- struct lys_module *mod;
- const char *prefix = NULL, *name;
- size_t prefix_len = 0;
- struct lysc_node_case *cs;
- struct lysc_node *node;
-
- /* 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;
- }
- /* this code is for deviation, so we allow as the default case even the cases from other modules than the choice (augments) */
- if (prefix) {
- if (!(mod = lys_module_find_prefix(ctx->mod, prefix, prefix_len))) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Invalid deviation adding \"default\" property \"%s\" of choice. "
- "The prefix does not match any imported module of the deviation module.", dflt);
- return LY_EVALID;
- }
- } else {
- mod = ctx->mod;
- }
- /* get the default case */
- cs = (struct lysc_node_case *)lys_find_child((struct lysc_node *)ch, mod, name, 0, LYS_CASE, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCASE);
- if (!cs) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Invalid deviation adding \"default\" property \"%s\" of choice - the specified case does not exists.", dflt);
+ if (ch->flags & LYS_MAND_TRUE) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid mandatory choice with a default case.");
return LY_EVALID;
}
- /* check that there is no mandatory node */
- LY_LIST_FOR(cs->child, node) {
- if (node->parent != (struct lysc_node *)cs) {
- break;
- }
- if (node->flags & LYS_MAND_TRUE) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid deviation adding \"default\" property \"%s\" of choice - "
- "mandatory node \"%s\" under the default case.", dflt, node->name);
- return LY_EVALID;
- }
- }
-
- /* set the default case in choice */
- ch->dflt = cs;
- cs->flags |= LYS_SET_DFLT;
-
+ ch->dflt->flags |= LYS_SET_DFLT;
return LY_SUCCESS;
}
@@ -3997,7 +4085,8 @@
* @return LY_ERR value - LY_SUCCESS or LY_EVALID.
*/
static LY_ERR
-lys_compile_node_choice_child(struct lysc_ctx *ctx, struct lysp_node *child_p, struct lysc_node *node)
+lys_compile_node_choice_child(struct lysc_ctx *ctx, struct lysp_node *child_p, struct lysc_node *node,
+ struct ly_set *child_set)
{
LY_ERR ret = LY_SUCCESS;
struct lysp_node *child_p_next = child_p->next;
@@ -4005,7 +4094,7 @@
if (child_p->nodetype == LYS_CASE) {
/* standard case under choice */
- ret = lys_compile_node(ctx, child_p, node, 0);
+ ret = lys_compile_node(ctx, child_p, node, 0, child_set);
} else {
/* we need the implicit case first, so create a fake parsed case */
cs_p = calloc(1, sizeof *cs_p);
@@ -4017,7 +4106,7 @@
child_p->next = NULL;
/* compile it normally */
- ret = lys_compile_node(ctx, (struct lysp_node *)cs_p, node, 0);
+ ret = lys_compile_node(ctx, (struct lysp_node *)cs_p, node, 0, child_set);
free_fake_node:
/* free the fake parsed node and correct pointers back */
@@ -4033,15 +4122,15 @@
* @brief Compile parsed choice node information.
*
* @param[in] ctx Compile context
- * @param[in] node_p Parsed choice node.
+ * @param[in] pnode Parsed choice node.
* @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
* is enriched with the choice-specific information.
* @return LY_ERR value - LY_SUCCESS or LY_EVALID.
*/
static LY_ERR
-lys_compile_node_choice(struct lysc_ctx *ctx, struct lysp_node *node_p, struct lysc_node *node)
+lys_compile_node_choice(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
{
- struct lysp_node_choice *ch_p = (struct lysp_node_choice *)node_p;
+ struct lysp_node_choice *ch_p = (struct lysp_node_choice *)pnode;
struct lysc_node_choice *ch = (struct lysc_node_choice *)node;
struct lysp_node *child_p;
LY_ERR ret = LY_SUCCESS;
@@ -4049,12 +4138,12 @@
assert(node->nodetype == LYS_CHOICE);
LY_LIST_FOR(ch_p->child, child_p) {
- LY_CHECK_RET(lys_compile_node_choice_child(ctx, child_p, node));
+ LY_CHECK_RET(lys_compile_node_choice_child(ctx, child_p, node, NULL));
}
/* default branch */
- if (ch_p->dflt) {
- LY_CHECK_RET(lys_compile_node_choice_dflt(ctx, ch_p->dflt, ch));
+ if (ch_p->dflt.str) {
+ LY_CHECK_RET(lys_compile_node_choice_dflt(ctx, &ch_p->dflt, ch));
}
return ret;
@@ -4063,15 +4152,15 @@
/**
* @brief Compile parsed anydata or anyxml node information.
* @param[in] ctx Compile context
- * @param[in] node_p Parsed anydata or anyxml node.
+ * @param[in] pnode Parsed anydata or anyxml node.
* @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
* is enriched with the any-specific information.
* @return LY_ERR value - LY_SUCCESS or LY_EVALID.
*/
static LY_ERR
-lys_compile_node_any(struct lysc_ctx *ctx, struct lysp_node *node_p, struct lysc_node *node)
+lys_compile_node_any(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
{
- struct lysp_node_anydata *any_p = (struct lysp_node_anydata *)node_p;
+ struct lysp_node_anydata *any_p = (struct lysp_node_anydata *)pnode;
struct lysc_node_anydata *any = (struct lysc_node_anydata *)node;
LY_ARRAY_COUNT_TYPE u;
LY_ERR ret = LY_SUCCESS;
@@ -4105,8 +4194,8 @@
static LY_ERR
lys_compile_node_connect(struct lysc_ctx *ctx, struct lysc_node *parent, struct lysc_node *node)
{
- struct lysc_node **children, *start, *end;
- const struct lys_module *mod;
+ struct lysc_node **children, *anchor = NULL;
+ int insert_after = 0;
node->parent = parent;
@@ -4122,36 +4211,69 @@
if (!(*children)) {
/* first child */
*children = node;
- } else if (*children != node) {
- /* by the condition in previous branch we cover the choice/case children
- * - the children list is shared by the choice and the the first case, in addition
- * the first child of each case must be referenced from the case node. So the node is
- * actually always already inserted in case it is the first children - so here such
- * a situation actually corresponds to the first branch */
- if (((*children)->prev->module != (*children)->module) && (node->module != (*children)->module)
- && (strcmp((*children)->prev->module->name, node->module->name) > 0)) {
- /* some augments are already connected and we are connecting new ones,
- * keep module name order and insert the node into the children list */
- end = (*children);
- do {
- end = end->prev;
- mod = end->module;
- while (end->prev->module == mod) {
- end = end->prev;
- }
- } while ((end->prev->module != (*children)->module) && (end->prev->module != node->module) && (strcmp(mod->name, node->module->name) > 0));
+ } else if (node->flags & LYS_KEY) {
+ /* special handling of adding keys */
+ assert(node->module == parent->module);
+ anchor = *children;
+ if (anchor->flags & LYS_KEY) {
+ while ((anchor->flags & LYS_KEY) && anchor->next) {
+ anchor = anchor->next;
+ }
+ /* insert after the last key */
+ insert_after = 1;
+ } /* else insert before anchor (at the beginning) */
+ } else if ((*children)->prev->module == node->module) {
+ /* last child is from the same module, keep the order and insert at the end */
+ anchor = (*children)->prev;
+ insert_after = 1;
+ } else if (parent->module == node->module) {
+ /* adding module child after some augments were connected */
+ for (anchor = *children; anchor->module == node->module; anchor = anchor->next) {}
+ } else {
+ /* some augments are already connected and we are connecting new ones,
+ * keep module name order and insert the node into the children list */
+ anchor = *children;
+ do {
+ anchor = anchor->prev;
- /* we have the last existing node after our node, easily get the first before and connect it */
- start = end->prev;
- start->next = node;
- node->next = end;
- end->prev = node;
- node->prev = start;
+ /* check that we have not found the last augment node from our module or
+ * the first augment node from a "smaller" module or
+ * the first node from a local module */
+ if ((anchor->module == node->module) || (strcmp(anchor->module->name, node->module->name) < 0)
+ || (anchor->module == parent->module)) {
+ /* insert after */
+ insert_after = 1;
+ break;
+ }
+
+ /* we have traversed all the nodes, insert before anchor (as the first node) */
+ } while (anchor->prev->next);
+ }
+
+ /* insert */
+ if (anchor) {
+ if (insert_after) {
+ node->next = anchor->next;
+ node->prev = anchor;
+ anchor->next = node;
+ if (node->next) {
+ /* middle node */
+ node->next->prev = node;
+ } else {
+ /* last node */
+ (*children)->prev = node;
+ }
} else {
- /* insert at the end of the parent's children list */
- (*children)->prev->next = node;
- node->prev = (*children)->prev;
- (*children)->prev = node;
+ node->next = anchor;
+ node->prev = anchor->prev;
+ anchor->prev = node;
+ if (anchor == *children) {
+ /* first node */
+ *children = node;
+ } else {
+ /* middle node */
+ node->prev->next = node;
+ }
}
}
@@ -4186,7 +4308,7 @@
* created in the choice when the first child was processed.
*
* @param[in] ctx Compile context.
- * @param[in] node_p Node image from the parsed tree. If the case is explicit, it is the LYS_CASE node, but in case of implicit case,
+ * @param[in] pnode Node image from the parsed tree. If the case is explicit, it is the LYS_CASE node, but in case of implicit case,
* it is the LYS_CHOICE, LYS_AUGMENT or LYS_GROUPING node.
* @param[in] ch The compiled choice structure where the new case structures are created (if needed).
* @param[in] child The new data node being part of a case (no matter if explicit or implicit).
@@ -4194,17 +4316,17 @@
* it is linked from the case structure only in case it is its first child.
*/
static LY_ERR
-lys_compile_node_case(struct lysc_ctx *ctx, struct lysp_node *node_p, struct lysc_node *node)
+lys_compile_node_case(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
{
struct lysp_node *child_p;
- struct lysp_node_case *cs_p = (struct lysp_node_case *)node_p;
+ struct lysp_node_case *cs_p = (struct lysp_node_case *)pnode;
- if (node_p->nodetype & (LYS_CHOICE | LYS_AUGMENT | LYS_GROUPING)) {
+ if (pnode->nodetype & (LYS_CHOICE | LYS_AUGMENT | LYS_GROUPING)) {
/* we have to add an implicit case node into the parent choice */
- } else if (node_p->nodetype == LYS_CASE) {
+ } else if (pnode->nodetype == LYS_CASE) {
/* explicit parent case */
LY_LIST_FOR(cs_p->child, child_p) {
- LY_CHECK_RET(lys_compile_node(ctx, child_p, node, 0));
+ LY_CHECK_RET(lys_compile_node(ctx, child_p, node, 0, NULL));
}
} else {
LOGINT_RET(ctx->ctx);
@@ -4214,64 +4336,6 @@
}
/**
- * @brief Apply refined or deviated config to the target node.
- *
- * @param[in] ctx Compile context.
- * @param[in] node Target node where the config is supposed to be changed.
- * @param[in] config_flag Node's config flag to be applied to the @p node.
- * @param[in] inheriting Flag (inverted) to check the refined config compatibility with the node's parent. This is
- * done only on the node for which the refine was created. The function applies also recursively to apply the config change
- * to the complete subtree (except the subnodes with explicit config set) and the test is not needed for the subnodes.
- * @param[in] refine_flag Flag to distinguish if the change is caused by refine (flag set) or deviation (for logging).
- * @return LY_ERR value.
- */
-static LY_ERR
-lys_compile_change_config(struct lysc_ctx *ctx, struct lysc_node *node, uint16_t config_flag,
- ly_bool inheriting, ly_bool refine_flag)
-{
- struct lysc_node *child;
- uint16_t config = config_flag & LYS_CONFIG_MASK;
-
- if (config == (node->flags & LYS_CONFIG_MASK)) {
- /* nothing to do */
- return LY_SUCCESS;
- }
-
- if (!inheriting) {
- /* explicit change */
- if (config == LYS_CONFIG_W && node->parent && (node->parent->flags & LYS_CONFIG_R)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid %s of config - configuration node cannot be child of any state data node.",
- refine_flag ? "refine" : "deviation");
- return LY_EVALID;
- }
- node->flags |= LYS_SET_CONFIG;
- } else {
- if (node->flags & LYS_SET_CONFIG) {
- if ((node->flags & LYS_CONFIG_W) && (config == LYS_CONFIG_R)) {
- /* setting config flags, but have node with explicit config true */
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid %s of config - configuration node cannot be child of any state data node.",
- refine_flag ? "refine" : "deviation");
- return LY_EVALID;
- }
- /* do not change config on nodes where the config is explicitely set, this does not apply to
- * nodes, which are being changed explicitly (targets of refine or deviation) */
- return LY_SUCCESS;
- }
- }
- node->flags &= ~LYS_CONFIG_MASK;
- node->flags |= config;
-
- /* inherit the change into the children */
- LY_LIST_FOR((struct lysc_node *)lysc_node_children(node, 0), child) {
- LY_CHECK_RET(lys_compile_change_config(ctx, child, config_flag, 1, refine_flag));
- }
-
- return LY_SUCCESS;
-}
-
-/**
* @brief Set LYS_MAND_TRUE flag for the non-presence container parents.
*
* A non-presence container is mandatory in case it has at least one mandatory children. This function propagate
@@ -4306,85 +4370,6 @@
}
/**
- * @brief Internal sorting process for the lys_compile_augment_sort().
- * @param[in] aug_p The parsed augment structure to insert into the sorter sized array @p result.
- * @param[in,out] result Sized array to store the sorted list of augments. The array is expected
- * to be allocated to hold the complete list, its size is just incremented by adding another item.
- */
-static void
-lys_compile_augment_sort_(struct lysp_augment *aug_p, struct lysp_augment **result)
-{
- LY_ARRAY_COUNT_TYPE v;
- size_t len;
-
- len = strlen(aug_p->nodeid);
- LY_ARRAY_FOR(result, v) {
- if (strlen(result[v]->nodeid) <= len) {
- continue;
- }
- if (v < LY_ARRAY_COUNT(result)) {
- /* move the rest of array */
- memmove(&result[v + 1], &result[v], (LY_ARRAY_COUNT(result) - v) * sizeof *result);
- break;
- }
- }
- result[v] = aug_p;
- LY_ARRAY_INCREMENT(result);
-}
-
-/**
- * @brief Sort augments to apply /a/b before /a/b/c (where the /a/b/c was added by the first augment).
- *
- * The sorting is based only on the length of the augment's path since it guarantee the correct order
- * (it doesn't matter the /a/x is done before /a/b/c from the example above).
- *
- * @param[in] ctx Compile context.
- * @param[in] mod_p Parsed module with the global augments (also augments from the submodules are taken).
- * @param[in] aug_p Parsed sized array of augments to sort (no matter if global or uses's)
- * @param[in] inc_p In case of global augments, sized array of module includes (submodules) to get global augments from submodules.
- * @param[out] augments Resulting sorted sized array of pointers to the augments.
- * @return LY_ERR value.
- */
-LY_ERR
-lys_compile_augment_sort(struct lysc_ctx *ctx, struct lysp_augment *aug_p, struct lysp_include *inc_p, struct lysp_augment ***augments)
-{
- struct lysp_augment **result = NULL;
- LY_ARRAY_COUNT_TYPE u, v, count = 0;
-
- assert(augments);
-
- /* get count of the augments in module and all its submodules */
- if (aug_p) {
- count += LY_ARRAY_COUNT(aug_p);
- }
- LY_ARRAY_FOR(inc_p, u) {
- if (inc_p[u].submodule->augments) {
- count += LY_ARRAY_COUNT(inc_p[u].submodule->augments);
- }
- }
-
- if (!count) {
- *augments = NULL;
- return LY_SUCCESS;
- }
- LY_ARRAY_CREATE_RET(ctx->ctx, result, count, LY_EMEM);
-
- /* sort by the length of schema-nodeid - we need to solve /x before /x/xy. It is not necessary to group them
- * together, so there can be even /z/y betwwen them. */
- LY_ARRAY_FOR(aug_p, u) {
- lys_compile_augment_sort_(&aug_p[u], result);
- }
- LY_ARRAY_FOR(inc_p, u) {
- LY_ARRAY_FOR(inc_p[u].submodule->augments, v) {
- lys_compile_augment_sort_(&inc_p[u].submodule->augments[v], result);
- }
- }
-
- *augments = result;
- return LY_SUCCESS;
-}
-
-/**
* @brief Compile the parsed augment connecting it into its target.
*
* It is expected that all the data referenced in path are present - augments are ordered so that augment B
@@ -4393,38 +4378,28 @@
*
* @param[in] ctx Compile context.
* @param[in] aug_p Parsed augment to compile.
- * @param[in] parent Parent node to provide the augment's context. It is NULL for the top level augments and a node holding uses's
- * children in case of the augmenting uses data.
+ * @param[in] target Target node of the augment.
* @return LY_SUCCESS on success.
* @return LY_EVALID on failure.
*/
-LY_ERR
-lys_compile_augment(struct lysc_ctx *ctx, struct lysp_augment *aug_p, const struct lysc_node *parent)
+static LY_ERR
+lys_compile_augment(struct lysc_ctx *ctx, struct lysp_augment *aug_p, struct lysc_node *target)
{
- LY_ERR ret = LY_SUCCESS, rc;
- struct lysp_node *node_p;
- struct lysc_node *target; /* target target of the augment */
+ LY_ERR ret = LY_SUCCESS;
+ struct lysp_node *pnode;
struct lysc_node *node;
struct lysc_when **when, *when_shared;
- struct lys_module **aug_mod;
ly_bool allow_mandatory = 0;
- uint16_t flags = 0;
- LY_ARRAY_COUNT_TYPE u, v;
- uint32_t opt_prev = ctx->options;
+ LY_ARRAY_COUNT_TYPE u;
+ struct ly_set child_set = {0};
+ uint32_t i;
- lysc_update_path(ctx, NULL, "{augment}");
- lysc_update_path(ctx, NULL, aug_p->nodeid);
-
- ret = lysc_resolve_schema_nodeid(ctx, aug_p->nodeid, 0, parent, parent ? parent->module : ctx->mod_def,
- LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INOUT | LYS_NOTIF,
- 1, (const struct lysc_node **)&target, &flags);
- if (ret != LY_SUCCESS) {
- if (ret == LY_EDENIED) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Augment's %s-schema-nodeid \"%s\" refers to a %s node which is not an allowed augment's target.",
- parent ? "descendant" : "absolute", aug_p->nodeid, lys_nodetype2str(target->nodetype));
- }
- return LY_EVALID;
+ if (!(target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF))) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Augment's %s-schema-nodeid \"%s\" refers to a %s node which is not an allowed augment's target.",
+ aug_p->nodeid[0] == '/' ? "absolute" : "descendant", aug_p->nodeid, lys_nodetype2str(target->nodetype));
+ ret = LY_EVALID;
+ goto cleanup;
}
/* check for mandatory nodes
@@ -4436,188 +4411,100 @@
}
when_shared = NULL;
- LY_LIST_FOR(aug_p->child, node_p) {
+ LY_LIST_FOR(aug_p->child, pnode) {
/* check if the subnode can be connected to the found target (e.g. case cannot be inserted into container) */
- if (!(target->nodetype == LYS_CHOICE && node_p->nodetype == LYS_CASE)
- && !((target->nodetype & (LYS_CONTAINER | LYS_LIST)) && (node_p->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)))
- && !(target->nodetype != LYS_CHOICE && node_p->nodetype == LYS_USES)
- && !(node_p->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_CHOICE | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
+ if ((pnode->nodetype == LYS_CASE && target->nodetype != LYS_CHOICE)
+ || ((pnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && !(target->nodetype & (LYS_CONTAINER | LYS_LIST)))
+ || (pnode->nodetype == LYS_USES && target->nodetype == LYS_CHOICE)) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
"Invalid augment of %s node which is not allowed to contain %s node \"%s\".",
- lys_nodetype2str(target->nodetype), lys_nodetype2str(node_p->nodetype), node_p->name);
- return LY_EVALID;
+ lys_nodetype2str(target->nodetype), lys_nodetype2str(pnode->nodetype), pnode->name);
+ ret = LY_EVALID;
+ goto cleanup;
}
/* compile the children */
- ctx->options |= flags;
if (target->nodetype == LYS_CHOICE) {
- LY_CHECK_RET(lys_compile_node_choice_child(ctx, node_p, target));
+ LY_CHECK_GOTO(ret = lys_compile_node_choice_child(ctx, pnode, target, &child_set), cleanup);
} else {
- LY_CHECK_RET(lys_compile_node(ctx, node_p, target, 0));
+ LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
}
- ctx->options = opt_prev;
- /* since the augment node is not present in the compiled tree, we need to pass some of its statements to all its children,
- * here we gets the last created node as last children of our parent */
- if (target->nodetype == LYS_CASE) {
- /* the compiled node is the last child of the target (but it is a case, so we have to be careful and stop) */
- for (node = (struct lysc_node *)lysc_node_children(target, flags); node->next && node->next->parent == node->parent; node = node->next) {}
- } else if (target->nodetype == LYS_CHOICE) {
- /* to pass when statement, we need the last case no matter if it is explicit or implicit case */
- node = ((struct lysc_node_choice *)target)->cases->prev;
- } else {
- /* the compiled node is the last child of the target */
- node = (struct lysc_node *)lysc_node_children(target, flags);
- if (!node) {
- /* there is no data children (compiled nodes is e.g. notification or action or nothing) */
- break;
+ /* since the augment node is not present in the compiled tree, we need to pass some of its
+ * statements to all its children */
+ for (i = 0; i < child_set.count; ++i) {
+ node = child_set.snodes[i];
+ if (!allow_mandatory && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
+ node->flags &= ~LYS_MAND_TRUE;
+ lys_compile_mandatory_parents(target, 0);
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.", node->name);
+ ret = LY_EVALID;
+ goto cleanup;
}
- node = node->prev;
- }
- if (!allow_mandatory && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
- node->flags &= ~LYS_MAND_TRUE;
- lys_compile_mandatory_parents(target, 0);
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.", node->name);
- return LY_EVALID;
- }
+ /* pass augment's when to all the children TODO this way even action and notif should have "when" (code below) */
+ if (aug_p->when) {
+ LY_ARRAY_NEW_GOTO(ctx->ctx, node->when, when, ret, cleanup);
+ if (!when_shared) {
+ LY_CHECK_GOTO(ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, target, when), cleanup);
- /* pass augment's when to all the children */
- if (aug_p->when) {
- LY_ARRAY_NEW_GOTO(ctx->ctx, node->when, when, ret, error);
- if (!when_shared) {
- ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, target, when);
- LY_CHECK_GOTO(ret, error);
+ if (!(ctx->options & LYSC_OPT_GROUPING)) {
+ /* do not check "when" semantics in a grouping */
+ LY_CHECK_GOTO(ret = ly_set_add(&ctx->xpath, node, 0, NULL), cleanup);
+ }
- if (!(ctx->options & LYSC_OPT_GROUPING)) {
- /* do not check "when" semantics in a grouping */
- ret = ly_set_add(&ctx->xpath, node, 0, NULL);
- LY_CHECK_GOTO(ret, error);
- }
+ when_shared = *when;
+ } else {
+ ++when_shared->refcount;
+ (*when) = when_shared;
- when_shared = *when;
- } else {
- ++when_shared->refcount;
- (*when) = when_shared;
-
- if (!(ctx->options & LYSC_OPT_GROUPING)) {
- /* in this case check "when" again for all children because of dummy node check */
- ret = ly_set_add(&ctx->xpath, node, 0, NULL);
- LY_CHECK_GOTO(ret, error);
+ if (!(ctx->options & LYSC_OPT_GROUPING)) {
+ /* in this case check "when" again for all children because of dummy node check */
+ LY_CHECK_GOTO(ret = ly_set_add(&ctx->xpath, node, 0, NULL), cleanup);
+ }
}
}
}
+ ly_set_erase(&child_set, NULL);
}
- ctx->options |= flags;
switch (target->nodetype) {
case LYS_CONTAINER:
- COMPILE_ARRAY1_GOTO(ctx, aug_p->actions, ((struct lysc_node_container *)target)->actions, target,
- u, lys_compile_action, 0, ret, error);
- COMPILE_ARRAY1_GOTO(ctx, aug_p->notifs, ((struct lysc_node_container *)target)->notifs, target,
- u, lys_compile_notif, 0, ret, error);
+ COMPILE_OP_ARRAY_GOTO(ctx, aug_p->actions, ((struct lysc_node_container *)target)->actions, target,
+ u, lys_compile_action, 0, ret, cleanup);
+ COMPILE_OP_ARRAY_GOTO(ctx, aug_p->notifs, ((struct lysc_node_container *)target)->notifs, target,
+ u, lys_compile_notif, 0, ret, cleanup);
break;
case LYS_LIST:
- COMPILE_ARRAY1_GOTO(ctx, aug_p->actions, ((struct lysc_node_list *)target)->actions, target,
- u, lys_compile_action, 0, ret, error);
- COMPILE_ARRAY1_GOTO(ctx, aug_p->notifs, ((struct lysc_node_list *)target)->notifs, target,
- u, lys_compile_notif, 0, ret, error);
+ COMPILE_OP_ARRAY_GOTO(ctx, aug_p->actions, ((struct lysc_node_list *)target)->actions, target,
+ u, lys_compile_action, 0, ret, cleanup);
+ COMPILE_OP_ARRAY_GOTO(ctx, aug_p->notifs, ((struct lysc_node_list *)target)->notifs, target,
+ u, lys_compile_notif, 0, ret, cleanup);
break;
default:
- ctx->options = opt_prev;
if (aug_p->actions) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
"Invalid augment of %s node which is not allowed to contain RPC/action node \"%s\".",
lys_nodetype2str(target->nodetype), aug_p->actions[0].name);
- return LY_EVALID;
+ ret = LY_EVALID;
+ goto cleanup;
}
if (aug_p->notifs) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
"Invalid augment of %s node which is not allowed to contain notification node \"%s\".",
lys_nodetype2str(target->nodetype), aug_p->notifs[0].name);
- return LY_EVALID;
+ ret = LY_EVALID;
+ goto cleanup;
}
}
- /* add this module into the target module augmented_by, if not there already */
- rc = LY_SUCCESS;
- LY_ARRAY_FOR(target->module->compiled->augmented_by, v) {
- if (target->module->compiled->augmented_by[v] == ctx->mod) {
- rc = LY_EEXIST;
- break;
- }
- }
- if (!rc) {
- LY_ARRAY_NEW_GOTO(ctx->ctx, target->module->compiled->augmented_by, aug_mod, ret, error);
- *aug_mod = ctx->mod;
- }
-
- lysc_update_path(ctx, NULL, NULL);
- lysc_update_path(ctx, NULL, NULL);
-
-error:
- ctx->options = opt_prev;
+cleanup:
+ ly_set_erase(&child_set, NULL);
return ret;
}
/**
- * @brief Apply refined or deviated mandatory flag to the target node.
- *
- * @param[in] ctx Compile context.
- * @param[in] node Target node where the mandatory property is supposed to be changed.
- * @param[in] mandatory_flag Node's mandatory flag to be applied to the @p node.
- * @param[in] refine_flag Flag to distinguish if the change is caused by refine (flag set) or deviation (for logging).
- * @param[in] It is also used as a flag for testing for compatibility with default statement. In case of deviations,
- * there can be some other deviations of the default properties that we are testing here. To avoid false positive failure,
- * the tests are skipped here, but they are supposed to be performed after all the deviations are applied.
- * @return LY_ERR value.
- */
-static LY_ERR
-lys_compile_change_mandatory(struct lysc_ctx *ctx, struct lysc_node *node, uint16_t mandatory_flag, ly_bool refine_flag)
-{
- if (!(node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_ANYXML | LYS_CHOICE))) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid %s of mandatory - %s cannot hold mandatory statement.",
- refine_flag ? "refine" : "deviation", lys_nodetype2str(node->nodetype));
- return LY_EVALID;
- }
-
- if (mandatory_flag & LYS_MAND_TRUE) {
- /* check if node has default value */
- if (node->nodetype & LYS_LEAF) {
- if (node->flags & LYS_SET_DFLT) {
- if (refine_flag) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid refine of mandatory - leaf already has \"default\" statement.");
- return LY_EVALID;
- }
- }
- } else if ((node->nodetype & LYS_CHOICE) && ((struct lysc_node_choice *)node)->dflt) {
- if (refine_flag) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid refine of mandatory - choice already has \"default\" statement.");
- return LY_EVALID;
- }
- }
- if (refine_flag && node->parent && (node->parent->flags & LYS_SET_DFLT)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid refine of mandatory under the default case.");
- return LY_EVALID;
- }
-
- node->flags &= ~LYS_MAND_FALSE;
- node->flags |= LYS_MAND_TRUE;
- lys_compile_mandatory_parents(node->parent, 1);
- } else {
- /* make mandatory false */
- node->flags &= ~LYS_MAND_TRUE;
- node->flags |= LYS_MAND_FALSE;
- lys_compile_mandatory_parents(node->parent, 0);
- }
- return LY_SUCCESS;
-}
-
-/**
* @brief Find grouping for a uses.
*
* @param[in] ctx Compile context.
@@ -4630,7 +4517,7 @@
lys_compile_uses_find_grouping(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, struct lysp_grp **grp_p,
struct lys_module **grp_mod)
{
- struct lysp_node *node_p;
+ struct lysp_node *pnode;
struct lysp_grp *grp;
LY_ARRAY_COUNT_TYPE u, v;
ly_bool found = 0;
@@ -4655,8 +4542,8 @@
mod = ctx->mod_def;
}
if (mod == ctx->mod_def) {
- for (node_p = uses_p->parent; !found && node_p; node_p = node_p->parent) {
- grp = (struct lysp_grp *)lysp_node_groupings(node_p);
+ for (pnode = uses_p->parent; !found && pnode; pnode = pnode->parent) {
+ grp = (struct lysp_grp *)lysp_node_groupings(pnode);
LY_ARRAY_FOR(grp, u) {
if (!strcmp(grp[u].name, name)) {
grp = &grp[u];
@@ -4709,235 +4596,223 @@
return LY_SUCCESS;
}
+static const struct lys_module *lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest,
+ size_t nametest_len, const struct lys_module *local_mod, const char **name, size_t *name_len);
+
static LY_ERR
-lys_compile_refines(struct lysc_ctx *ctx, struct lysp_refine *refines, const struct lysc_node *context_node)
+lys_nodeid_check(struct lysc_ctx *ctx, const char *nodeid, ly_bool abs, struct lys_module **target_mod,
+ struct lyxp_expr **expr)
{
- struct lysc_node *node;
- LY_ARRAY_COUNT_TYPE u;
- struct lysp_refine *rfn;
LY_ERR ret = LY_SUCCESS;
- uint32_t min, max;
- uint16_t flags;
- struct ly_set refined = {0};
+ struct lyxp_expr *e = NULL;
+ struct lys_module *tmod = NULL, *mod;
+ const char *nodeid_type = abs ? "absolute-schema-nodeid" : "descendant-schema-nodeid";
+ uint32_t i;
- lysc_update_path(ctx, NULL, "{refine}");
-
- /* apply refine */
- LY_ARRAY_FOR(refines, struct lysp_refine, rfn) {
- lysc_update_path(ctx, NULL, rfn->nodeid);
-
- ret = lysc_resolve_schema_nodeid(ctx, rfn->nodeid, 0, context_node, ctx->mod,
- 0, 0, (const struct lysc_node **)&node, &flags);
- LY_CHECK_GOTO(ret, cleanup);
- ret = ly_set_add(&refined, node, LY_SET_OPT_USEASLIST, NULL);
- LY_CHECK_GOTO(ret, cleanup);
-
- /* default value */
- if (rfn->dflts) {
- if ((node->nodetype != LYS_LEAFLIST) && LY_ARRAY_COUNT(rfn->dflts) > 1) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid refine of default - %s cannot hold %"LY_PRI_ARRAY_COUNT_TYPE " default values.",
- lys_nodetype2str(node->nodetype), LY_ARRAY_COUNT(rfn->dflts));
- ret = LY_EVALID;
- goto cleanup;
- }
- if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_CHOICE))) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid refine of default - %s cannot hold default value(s).",
- lys_nodetype2str(node->nodetype));
- ret = LY_EVALID;
- goto cleanup;
- }
- if (node->nodetype == LYS_LEAF) {
- /* postpone default compilation when the tree is complete */
- ret = lysc_incomplete_leaf_dflt_add(ctx, (struct lysc_node_leaf *)node, rfn->dflts[0], ctx->mod_def);
- LY_CHECK_GOTO(ret, cleanup);
-
- node->flags |= LYS_SET_DFLT;
- } else if (node->nodetype == LYS_LEAFLIST) {
- if (ctx->mod->version < 2) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.");
- ret = LY_EVALID;
- goto cleanup;
- }
-
- /* postpone default compilation when the tree is complete */
- ret = lysc_incomplete_llist_dflts_add(ctx, (struct lysc_node_leaflist *)node, rfn->dflts, ctx->mod_def);
- LY_CHECK_GOTO(ret, cleanup);
-
- node->flags |= LYS_SET_DFLT;
- } else if (node->nodetype == LYS_CHOICE) {
- if (((struct lysc_node_choice *)node)->dflt) {
- /* unset LYS_SET_DFLT from the current default case */
- ((struct lysc_node_choice *)node)->dflt->flags &= ~LYS_SET_DFLT;
- }
- ret = lys_compile_node_choice_dflt(ctx, rfn->dflts[0], (struct lysc_node_choice *)node);
- LY_CHECK_GOTO(ret, cleanup);
- }
- }
-
- /* description */
- if (rfn->dsc) {
- FREE_STRING(ctx->ctx, node->dsc);
- LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, rfn->dsc, 0, &node->dsc), cleanup);
- }
-
- /* reference */
- if (rfn->ref) {
- FREE_STRING(ctx->ctx, node->ref);
- LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, rfn->ref, 0, &node->ref), cleanup);
- }
-
- /* config */
- if (rfn->flags & LYS_CONFIG_MASK) {
- if (!flags) {
- ret = lys_compile_change_config(ctx, node, rfn->flags, 0, 1);
- LY_CHECK_GOTO(ret, cleanup);
- } else {
- LOGWRN(ctx->ctx, "Refining config inside %s has no effect (%s).",
- flags & LYSC_OPT_NOTIFICATION ? "notification" : "RPC/action", ctx->path);
- }
- }
-
- /* mandatory */
- if (rfn->flags & LYS_MAND_MASK) {
- ret = lys_compile_change_mandatory(ctx, node, rfn->flags, 1);
- LY_CHECK_GOTO(ret, cleanup);
- }
-
- /* presence */
- if (rfn->presence) {
- if (node->nodetype != LYS_CONTAINER) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid refine of presence statement - %s cannot hold the presence statement.",
- lys_nodetype2str(node->nodetype));
- ret = LY_EVALID;
- goto cleanup;
- }
- node->flags |= LYS_PRESENCE;
- }
-
- /* must */
- if (rfn->musts) {
- switch (node->nodetype) {
- case LYS_LEAF:
- COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_leaf *)node)->musts, u, lys_compile_must, ret, cleanup);
- break;
- case LYS_LEAFLIST:
- COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_leaflist *)node)->musts, u, lys_compile_must, ret, cleanup);
- break;
- case LYS_LIST:
- COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_list *)node)->musts, u, lys_compile_must, ret, cleanup);
- break;
- case LYS_CONTAINER:
- COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_container *)node)->musts, u, lys_compile_must, ret, cleanup);
- break;
- case LYS_ANYXML:
- case LYS_ANYDATA:
- COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_anydata *)node)->musts, u, lys_compile_must, ret, cleanup);
- break;
- default:
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid refine of must statement - %s cannot hold any must statement.",
- lys_nodetype2str(node->nodetype));
- ret = LY_EVALID;
- goto cleanup;
- }
- ret = ly_set_add(&ctx->xpath, node, 0, NULL);
- LY_CHECK_GOTO(ret, cleanup);
- }
-
- /* min/max-elements */
- if (rfn->flags & (LYS_SET_MAX | LYS_SET_MIN)) {
- switch (node->nodetype) {
- case LYS_LEAFLIST:
- if (rfn->flags & LYS_SET_MAX) {
- ((struct lysc_node_leaflist *)node)->max = rfn->max ? rfn->max : (uint32_t)-1;
- }
- if (rfn->flags & LYS_SET_MIN) {
- ((struct lysc_node_leaflist *)node)->min = rfn->min;
- if (rfn->min) {
- node->flags |= LYS_MAND_TRUE;
- lys_compile_mandatory_parents(node->parent, 1);
- } else {
- node->flags &= ~LYS_MAND_TRUE;
- lys_compile_mandatory_parents(node->parent, 0);
- }
- }
- break;
- case LYS_LIST:
- if (rfn->flags & LYS_SET_MAX) {
- ((struct lysc_node_list *)node)->max = rfn->max ? rfn->max : (uint32_t)-1;
- }
- if (rfn->flags & LYS_SET_MIN) {
- ((struct lysc_node_list *)node)->min = rfn->min;
- if (rfn->min) {
- node->flags |= LYS_MAND_TRUE;
- lys_compile_mandatory_parents(node->parent, 1);
- } else {
- node->flags &= ~LYS_MAND_TRUE;
- lys_compile_mandatory_parents(node->parent, 0);
- }
- }
- break;
- default:
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid refine of %s statement - %s cannot hold this statement.",
- (rfn->flags & LYS_SET_MAX) ? "max-elements" : "min-elements", lys_nodetype2str(node->nodetype));
- ret = LY_EVALID;
- goto cleanup;
- }
- }
-
- /* if-feature */
- if (rfn->iffeatures) {
- /* any node in compiled tree can get additional if-feature, so do not check nodetype */
- COMPILE_ARRAY_GOTO(ctx, rfn->iffeatures, node->iffeatures, u, lys_compile_iffeature, ret, cleanup);
- }
-
- lysc_update_path(ctx, NULL, NULL);
+ /* parse */
+ ret = lyxp_expr_parse(ctx->ctx, nodeid, strlen(nodeid), 0, &e);
+ if (ret) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid %s value \"%s\" - invalid syntax.",
+ nodeid_type, nodeid);
+ ret = LY_EVALID;
+ goto cleanup;
}
- /* do some additional checks of the changed nodes when all the refines are applied */
- for (uint32_t i = 0; i < refined.count; ++i) {
- node = (struct lysc_node *)refined.objs[i];
- rfn = &refines[i];
- lysc_update_path(ctx, NULL, rfn->nodeid);
-
- /* check possible conflict with default value (default added, mandatory left true) */
- if ((node->flags & LYS_MAND_TRUE) &&
- (((node->nodetype & LYS_CHOICE) && ((struct lysc_node_choice *)node)->dflt) ||
- ((node->nodetype & LYS_LEAF) && (node->flags & LYS_SET_DFLT)))) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid refine of default - the node is mandatory.");
+ if (abs) {
+ /* absolute schema nodeid */
+ i = 0;
+ } else {
+ /* descendant schema nodeid */
+ if (e->tokens[0] != LYXP_TOKEN_NAMETEST) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
+ nodeid_type, nodeid, e->tok_len[0], e->expr + e->tok_pos[0]);
ret = LY_EVALID;
goto cleanup;
}
+ i = 1;
+ }
- if (rfn->flags & (LYS_SET_MAX | LYS_SET_MIN)) {
- if (node->nodetype == LYS_LIST) {
- min = ((struct lysc_node_list *)node)->min;
- max = ((struct lysc_node_list *)node)->max;
- } else {
- min = ((struct lysc_node_leaflist *)node)->min;
- max = ((struct lysc_node_leaflist *)node)->max;
+ /* check all the tokens */
+ for ( ; i < e->used; i += 2) {
+ if (e->tokens[i] != LYXP_TOKEN_OPER_PATH) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s value \"%s\" - \"/\" expected instead of \"%.*s\".",
+ nodeid_type, nodeid, e->tok_len[i], e->expr + e->tok_pos[i]);
+ ret = LY_EVALID;
+ goto cleanup;
+ } else if (e->used == i + 1) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid %s value \"%s\" - unexpected end of expression.", nodeid_type, e->expr);
+ ret = LY_EVALID;
+ goto cleanup;
+ } else if (e->tokens[i + 1] != LYXP_TOKEN_NAMETEST) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
+ nodeid_type, nodeid, e->tok_len[i + 1], e->expr + e->tok_pos[i + 1]);
+ ret = LY_EVALID;
+ goto cleanup;
+ } else if (abs) {
+ mod = (struct lys_module *)lys_schema_node_get_module(ctx->ctx, e->expr + e->tok_pos[i + 1],
+ e->tok_len[i + 1], ctx->mod_def, NULL, NULL);
+ LY_CHECK_ERR_GOTO(!mod, ret = LY_EVALID, cleanup);
+
+ /* only keep the first module */
+ if (!tmod) {
+ tmod = mod;
}
- if (min > max) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid refine of %s statement - \"min-elements\" is bigger than \"max-elements\".",
- (rfn->flags & LYS_SET_MAX) ? "max-elements" : "min-elements");
- ret = LY_EVALID;
- goto cleanup;
+
+ /* all the modules must be implemented */
+ if (!mod->implemented) {
+ ret = lys_set_implemented_internal(mod, ctx->ctx->module_set_id);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+ }
+ }
+
+cleanup:
+ if (ret || !expr) {
+ lyxp_expr_free(ctx->ctx, e);
+ e = NULL;
+ }
+ if (expr) {
+ *expr = ret ? NULL : e;
+ }
+ if (target_mod) {
+ *target_mod = ret ? NULL : tmod;
+ }
+ return ret;
+}
+
+/**
+ * @brief Check whether 2 schema nodeids match.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] exp1 First schema nodeid.
+ * @param[in] exp1_mod Module of @p exp1 nodes without any prefix.
+ * @param[in] exp2 Second schema nodeid.
+ * @param[in] exp2_mod Module of @p exp2 nodes without any prefix.
+ * @return Whether the schema nodeids match or not.
+ */
+static ly_bool
+lys_abs_schema_nodeid_match(const struct ly_ctx *ctx, const struct lyxp_expr *exp1, const struct lys_module *exp1_mod,
+ const struct lyxp_expr *exp2, const struct lys_module *exp2_mod)
+{
+ uint32_t i;
+ const struct lys_module *mod1, *mod2;
+ const char *name1, *name2;
+ size_t name1_len, name2_len;
+
+ if (exp1->used != exp2->used) {
+ return 0;
+ }
+
+ for (i = 0; i < exp1->used; ++i) {
+ assert(exp1->tokens[i] == exp2->tokens[i]);
+
+ if (exp1->tokens[i] == LYXP_TOKEN_NAMETEST) {
+ /* check modules of all the nodes in the node ID */
+ mod1 = lys_schema_node_get_module(ctx, exp1->expr + exp1->tok_pos[i], exp1->tok_len[i], exp1_mod,
+ &name1, &name1_len);
+ assert(mod1);
+ mod2 = lys_schema_node_get_module(ctx, exp2->expr + exp2->tok_pos[i], exp2->tok_len[i], exp2_mod,
+ &name2, &name2_len);
+ assert(mod2);
+
+ /* compare modules */
+ if (mod1 != mod2) {
+ return 0;
+ }
+
+ /* compare names */
+ if ((name1_len != name2_len) || strncmp(name1, name2, name1_len)) {
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+/**
+ * @brief Prepare any uses augments and refines in the context to be applied during uses descendant node compilation.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] uses_p Parsed uses structure with augments and refines.
+ * @param[in] ctx_node Context node of @p uses_p meaning its first data definiition parent.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_precompile_uses_augments_refines(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, const struct lysc_node *ctx_node)
+{
+ LY_ERR ret = LY_SUCCESS;
+ LY_ARRAY_COUNT_TYPE u;
+ struct lyxp_expr *exp = NULL;
+ struct lysc_augment *aug;
+ struct lysc_refine *rfn;
+ struct lysp_refine **new_rfn;
+ uint32_t i;
+
+ LY_ARRAY_FOR(uses_p->augments, u) {
+ lysc_update_path(ctx, NULL, "{augment}");
+ lysc_update_path(ctx, NULL, uses_p->augments[u].nodeid);
+
+ /* parse the nodeid */
+ LY_CHECK_GOTO(ret = lys_nodeid_check(ctx, uses_p->augments[u].nodeid, 0, NULL, &exp), cleanup);
+
+ /* allocate new compiled augment and store it in the set */
+ aug = calloc(1, sizeof *aug);
+ LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
+ LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_augs, aug, LY_SET_OPT_USEASLIST, NULL), cleanup);
+
+ aug->nodeid = exp;
+ exp = NULL;
+ aug->nodeid_ctx_node = ctx_node;
+ aug->aug_p = &uses_p->augments[u];
+
+ lysc_update_path(ctx, NULL, NULL);
+ lysc_update_path(ctx, NULL, NULL);
+ }
+
+ LY_ARRAY_FOR(uses_p->refines, u) {
+ lysc_update_path(ctx, NULL, "{refine}");
+ 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);
+
+ /* try to find the node in already compiled refines */
+ rfn = NULL;
+ for (i = 0; i < ctx->uses_rfns.count; ++i) {
+ if (lys_abs_schema_nodeid_match(ctx->ctx, exp, ctx->mod_def, ((struct lysc_refine *)ctx->uses_rfns.objs[i])->nodeid,
+ ctx->mod_def)) {
+ rfn = ctx->uses_rfns.objs[i];
+ break;
}
}
+ if (!rfn) {
+ /* allocate new compiled refine */
+ rfn = calloc(1, sizeof *rfn);
+ LY_CHECK_ERR_GOTO(!rfn, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
+ LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_rfns, rfn, LY_SET_OPT_USEASLIST, NULL), cleanup);
+
+ rfn->nodeid = exp;
+ exp = NULL;
+ rfn->nodeid_ctx_node = ctx_node;
+ } else {
+ /* just free exp */
+ lyxp_expr_free(ctx->ctx, exp);
+ exp = NULL;
+ }
+
+ /* add new parsed refine structure */
+ LY_ARRAY_NEW_GOTO(ctx->ctx, rfn->rfns, new_rfn, ret, cleanup);
+ *new_rfn = &uses_p->refines[u];
+
+ lysc_update_path(ctx, NULL, NULL);
lysc_update_path(ctx, NULL, NULL);
}
cleanup:
- ly_set_erase(&refined, NULL);
- lysc_update_path(ctx, NULL, NULL);
+ lyxp_expr_free(ctx->ctx, exp);
return ret;
}
@@ -4953,28 +4828,19 @@
* @return LY_ERR value - LY_SUCCESS or LY_EVALID.
*/
static LY_ERR
-lys_compile_uses(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, struct lysc_node *parent, struct lysc_node **first_p)
+lys_compile_uses(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, struct lysc_node *parent, struct ly_set *child_set)
{
- struct lysp_node *node_p;
- struct lysc_node *child = NULL, *iter;
- /* context_node_fake allows us to temporarily isolate the nodes inserted from the grouping instead of uses */
- struct lysc_node_container context_node_fake =
- {.nodetype = LYS_CONTAINER,
- .module = ctx->mod,
- .flags = parent ? parent->flags : 0,
- .child = NULL, .next = NULL,
- .prev = (struct lysc_node *)&context_node_fake,
- .actions = NULL, .notifs = NULL};
+ struct lysp_node *pnode;
+ struct lysc_node *child;
struct lysp_grp *grp = NULL;
- LY_ARRAY_COUNT_TYPE u;
- uint32_t grp_stack_count;
+ uint32_t i, grp_stack_count;
struct lys_module *grp_mod, *mod_old;
LY_ERR ret = LY_SUCCESS;
struct lysc_when **when, *when_shared;
- struct lysp_augment **augments = NULL;
- LY_ARRAY_COUNT_TYPE actions_index = 0, notifs_index = 0;
+ LY_ARRAY_COUNT_TYPE u;
struct lysc_notif **notifs = NULL;
struct lysc_action **actions = NULL;
+ struct ly_set uses_child_set = {0};
/* find the referenced grouping */
LY_CHECK_RET(lys_compile_uses_find_grouping(ctx, uses_p, &grp, &grp_mod));
@@ -4989,63 +4855,44 @@
return LY_EVALID;
}
+ /* check status */
+ ret = lysc_check_status(ctx, uses_p->flags, ctx->mod_def, uses_p->name, grp->flags, grp_mod, grp->name);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* compile any augments and refines so they can be applied during the grouping nodes compilation */
+ ret = lys_precompile_uses_augments_refines(ctx, uses_p, parent);
+ LY_CHECK_GOTO(ret, cleanup);
+
/* switch context's mod_def */
mod_old = ctx->mod_def;
ctx->mod_def = grp_mod;
- /* check status */
- ret = lysc_check_status(ctx, uses_p->flags, mod_old, uses_p->name, grp->flags, grp_mod, grp->name);
- LY_CHECK_GOTO(ret, cleanup);
-
- /* remember the currently last child before processing the uses - it is needed to split the siblings to corretly
- * applu refine and augment only to the nodes from the uses */
- if (parent) {
- child = (struct lysc_node *)lysc_node_children(parent, ctx->options & LYSC_OPT_RPC_MASK);
- } else if (ctx->mod->compiled->data) {
- child = ctx->mod->compiled->data;
- } else {
- child = NULL;
- }
- /* remember the last child */
- if (child) {
- child = child->prev;
- }
-
/* compile data nodes */
- LY_LIST_FOR(grp->data, node_p) {
+ LY_LIST_FOR(grp->data, pnode) {
/* 0x3 in uses_status is a special bits combination to be able to detect status flags from uses */
- ret = lys_compile_node(ctx, node_p, parent, (uses_p->flags & LYS_STATUS_MASK) | 0x3);
+ ret = lys_compile_node(ctx, pnode, parent, (uses_p->flags & LYS_STATUS_MASK) | 0x3, &uses_child_set);
LY_CHECK_GOTO(ret, cleanup);
}
- /* split the children and add the uses's data into the fake context node */
- if (child) {
- context_node_fake.child = child->next;
- } else if (parent) {
- context_node_fake.child = (struct lysc_node *)lysc_node_children(parent, ctx->options & LYSC_OPT_RPC_MASK);
- } else if (ctx->mod->compiled->data) {
- context_node_fake.child = ctx->mod->compiled->data;
- }
- if (context_node_fake.child) {
- /* remember child as the last data node added by grouping to fix the list later */
- child = context_node_fake.child->prev;
- context_node_fake.child->prev = NULL;
+ if (child_set) {
+ /* add these children to our compiled child_set as well since uses is a schema-only node */
+ LY_CHECK_GOTO(ret = ly_set_merge(child_set, &uses_child_set, LY_SET_OPT_USEASLIST, NULL), cleanup);
}
- when_shared = NULL;
- LY_LIST_FOR(context_node_fake.child, iter) {
- iter->parent = (struct lysc_node *)&context_node_fake;
-
+ if (uses_p->when) {
/* pass uses's when to all the data children, actions and notifications are ignored */
- if (uses_p->when) {
- LY_ARRAY_NEW_GOTO(ctx->ctx, iter->when, when, ret, cleanup);
+ when_shared = NULL;
+ for (i = 0; i < uses_child_set.count; ++i) {
+ child = uses_child_set.snodes[i];
+
+ LY_ARRAY_NEW_GOTO(ctx->ctx, child->when, when, ret, cleanup);
if (!when_shared) {
ret = lys_compile_when(ctx, uses_p->when, uses_p->flags, parent, when);
LY_CHECK_GOTO(ret, cleanup);
if (!(ctx->options & LYSC_OPT_GROUPING)) {
/* do not check "when" semantics in a grouping */
- ret = ly_set_add(&ctx->xpath, iter, 0, NULL);
+ ret = ly_set_add(&ctx->xpath, child, 0, NULL);
LY_CHECK_GOTO(ret, cleanup);
}
@@ -5056,7 +4903,7 @@
if (!(ctx->options & LYSC_OPT_GROUPING)) {
/* in this case check "when" again for all children because of dummy node check */
- ret = ly_set_add(&ctx->xpath, iter, 0, NULL);
+ ret = ly_set_add(&ctx->xpath, child, 0, NULL);
LY_CHECK_GOTO(ret, cleanup);
}
}
@@ -5064,78 +4911,58 @@
}
/* compile actions */
- actions = parent ? lysc_node_actions_p(parent) : &ctx->mod->compiled->rpcs;
- if (actions) {
- actions_index = *actions ? LY_ARRAY_COUNT(*actions) : 0;
- COMPILE_ARRAY1_GOTO(ctx, grp->actions, *actions, parent, u, lys_compile_action, 0, ret, cleanup);
- if (*actions && (uses_p->augments || uses_p->refines)) {
- /* but for augment and refine, we need to separate the compiled grouping's actions to avoid modification of others */
- LY_ARRAY_CREATE_GOTO(ctx->ctx, context_node_fake.actions, LY_ARRAY_COUNT(*actions) - actions_index, ret, cleanup);
- LY_ARRAY_COUNT(context_node_fake.actions) = LY_ARRAY_COUNT(*actions) - actions_index;
- memcpy(context_node_fake.actions, &(*actions)[actions_index], LY_ARRAY_COUNT(context_node_fake.actions) * sizeof **actions);
+ if (grp->actions) {
+ actions = parent ? lysc_node_actions_p(parent) : &ctx->mod->compiled->rpcs;
+ if (!actions) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid child %s \"%s\" of uses parent %s \"%s\" node.",
+ grp->actions[0].name, lys_nodetype2str(grp->actions[0].nodetype), parent->name,
+ lys_nodetype2str(parent->nodetype));
+ ret = LY_EVALID;
+ goto cleanup;
}
+ COMPILE_OP_ARRAY_GOTO(ctx, grp->actions, *actions, parent, u, lys_compile_action, 0, ret, cleanup);
}
/* compile notifications */
- notifs = parent ? lysc_node_notifs_p(parent) : &ctx->mod->compiled->notifs;
- if (notifs) {
- notifs_index = *notifs ? LY_ARRAY_COUNT(*notifs) : 0;
- COMPILE_ARRAY1_GOTO(ctx, grp->notifs, *notifs, parent, u, lys_compile_notif, 0, ret, cleanup);
- if (*notifs && (uses_p->augments || uses_p->refines)) {
- /* but for augment and refine, we need to separate the compiled grouping's notification to avoid modification of others */
- LY_ARRAY_CREATE_GOTO(ctx->ctx, context_node_fake.notifs, LY_ARRAY_COUNT(*notifs) - notifs_index, ret, cleanup);
- LY_ARRAY_COUNT(context_node_fake.notifs) = LY_ARRAY_COUNT(*notifs) - notifs_index;
- memcpy(context_node_fake.notifs, &(*notifs)[notifs_index], LY_ARRAY_COUNT(context_node_fake.notifs) * sizeof **notifs);
+ if (grp->notifs) {
+ notifs = parent ? lysc_node_notifs_p(parent) : &ctx->mod->compiled->notifs;
+ if (!notifs) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid child %s \"%s\" of uses parent %s \"%s\" node.",
+ grp->notifs[0].name, lys_nodetype2str(grp->notifs[0].nodetype), parent->name,
+ lys_nodetype2str(parent->nodetype));
+ ret = LY_EVALID;
+ goto cleanup;
}
+ COMPILE_OP_ARRAY_GOTO(ctx, grp->notifs, *notifs, parent, u, lys_compile_notif, 0, ret, cleanup);
}
- /* sort and apply augments */
- ret = lys_compile_augment_sort(ctx, uses_p->augments, NULL, &augments);
- LY_CHECK_GOTO(ret, cleanup);
- LY_ARRAY_FOR(augments, u) {
- ret = lys_compile_augment(ctx, augments[u], (struct lysc_node *)&context_node_fake);
- LY_CHECK_GOTO(ret, cleanup);
+ /* check that all augments were applied */
+ for (i = 0; i < ctx->uses_augs.count; ++i) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Augment target node \"%s\" in grouping \"%s\" was not found.",
+ ((struct lysc_augment *)ctx->uses_augs.objs[i])->nodeid->expr, grp->name);
+ ret = LY_ENOTFOUND;
}
-
- /* reload previous context's mod_def */
- ctx->mod_def = mod_old;
-
- /* apply all refines */
- ret = lys_compile_refines(ctx, uses_p->refines, (struct lysc_node *)&context_node_fake);
LY_CHECK_GOTO(ret, cleanup);
- if (first_p) {
- *first_p = context_node_fake.child;
+ /* check that all refines were applied */
+ for (i = 0; i < ctx->uses_rfns.count; ++i) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Refine(s) target node \"%s\" in grouping \"%s\" was not found.",
+ ((struct lysc_refine *)ctx->uses_rfns.objs[i])->nodeid->expr, grp->name);
+ ret = LY_ENOTFOUND;
}
+ LY_CHECK_GOTO(ret, cleanup);
cleanup:
- /* fix connection of the children nodes from fake context node back into the parent */
- if (context_node_fake.child) {
- context_node_fake.child->prev = child;
- }
- LY_LIST_FOR(context_node_fake.child, child) {
- child->parent = parent;
- }
-
- if (uses_p->augments || uses_p->refines) {
- /* return back actions and notifications in case they were separated for augment/refine processing */
- if (context_node_fake.actions) {
- memcpy(&(*actions)[actions_index], context_node_fake.actions, LY_ARRAY_COUNT(context_node_fake.actions) * sizeof **actions);
- LY_ARRAY_FREE(context_node_fake.actions);
- }
- if (context_node_fake.notifs) {
- memcpy(&(*notifs)[notifs_index], context_node_fake.notifs, LY_ARRAY_COUNT(context_node_fake.notifs) * sizeof **notifs);
- LY_ARRAY_FREE(context_node_fake.notifs);
- }
- }
-
/* reload previous context's mod_def */
ctx->mod_def = mod_old;
+
/* remove the grouping from the stack for circular groupings dependency check */
ly_set_rm_index(&ctx->groupings, ctx->groupings.count - 1, NULL);
assert(ctx->groupings.count == grp_stack_count);
- LY_ARRAY_FREE(augments);
+ ly_set_erase(&uses_child_set, NULL);
return ret;
}
@@ -5193,14 +5020,14 @@
* but to have the complete result of the schema validity, even such groupings are supposed to be checked.
*/
static LY_ERR
-lys_compile_grouping(struct lysc_ctx *ctx, struct lysp_node *node_p, struct lysp_grp *grp)
+lys_compile_grouping(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysp_grp *grp)
{
LY_ERR ret;
char *path;
int len;
struct lysp_node_uses fake_uses = {
- .parent = node_p,
+ .parent = pnode,
.nodetype = LYS_USES,
.flags = 0, .next = NULL,
.name = grp->name,
@@ -5209,7 +5036,7 @@
};
struct lysc_node_container fake_container = {
.nodetype = LYS_CONTAINER,
- .flags = node_p ? (node_p->flags & LYS_FLAGS_COMPILED_MASK) : 0,
+ .flags = pnode ? (pnode->flags & LYS_FLAGS_COMPILED_MASK) : 0,
.module = ctx->mod,
.sp = NULL, .parent = NULL, .next = NULL,
.prev = (struct lysc_node *)&fake_container,
@@ -5299,10 +5126,1825 @@
return LY_SUCCESS;
}
+static LY_ERR
+lysp_ext_dup(const struct ly_ctx *ctx, struct lysp_ext_instance *ext, const struct lysp_ext_instance *orig_ext)
+{
+ LY_ERR ret = LY_SUCCESS;
+
+ *ext = *orig_ext;
+ DUP_STRING(ctx, orig_ext->name, ext->name, ret);
+ DUP_STRING(ctx, orig_ext->argument, ext->argument, ret);
+
+ return ret;
+}
+
+static LY_ERR
+lysp_restr_dup(const struct ly_ctx *ctx, struct lysp_restr *restr, const struct lysp_restr *orig_restr)
+{
+ LY_ERR ret = LY_SUCCESS;
+
+ if (orig_restr) {
+ DUP_STRING(ctx, orig_restr->arg.str, restr->arg.str, ret);
+ restr->arg.mod = orig_restr->arg.mod;
+ DUP_STRING(ctx, orig_restr->emsg, restr->emsg, ret);
+ DUP_STRING(ctx, orig_restr->eapptag, restr->eapptag, ret);
+ DUP_STRING(ctx, orig_restr->dsc, restr->dsc, ret);
+ DUP_STRING(ctx, orig_restr->ref, restr->ref, ret);
+ DUP_ARRAY(ctx, orig_restr->exts, restr->exts, lysp_ext_dup);
+ }
+
+ return ret;
+}
+
+static LY_ERR
+lysp_string_dup(const struct ly_ctx *ctx, const char **str, const char **orig_str)
+{
+ LY_ERR ret = LY_SUCCESS;
+
+ DUP_STRING(ctx, *orig_str, *str, ret);
+
+ return ret;
+}
+
+static LY_ERR
+lysp_qname_dup(const struct ly_ctx *ctx, struct lysp_qname *qname, const struct lysp_qname *orig_qname)
+{
+ LY_ERR ret = LY_SUCCESS;
+
+ DUP_STRING(ctx, orig_qname->str, qname->str, ret);
+ qname->mod = orig_qname->mod;
+
+ return ret;
+}
+
+static LY_ERR
+lysp_type_enum_dup(const struct ly_ctx *ctx, struct lysp_type_enum *enm, const struct lysp_type_enum *orig_enm)
+{
+ LY_ERR ret = LY_SUCCESS;
+
+ DUP_STRING(ctx, orig_enm->name, enm->name, ret);
+ DUP_STRING(ctx, orig_enm->dsc, enm->dsc, ret);
+ DUP_STRING(ctx, orig_enm->ref, enm->ref, ret);
+ enm->value = orig_enm->value;
+ DUP_ARRAY(ctx, orig_enm->iffeatures, enm->iffeatures, lysp_qname_dup);
+ DUP_ARRAY(ctx, orig_enm->exts, enm->exts, lysp_ext_dup);
+ enm->flags = orig_enm->flags;
+
+ return ret;
+}
+
+static LY_ERR
+lysp_type_dup(const struct ly_ctx *ctx, struct lysp_type *type, const struct lysp_type *orig_type)
+{
+ LY_ERR ret = LY_SUCCESS;
+
+ DUP_STRING_GOTO(ctx, orig_type->name, type->name, ret, done);
+
+ if (orig_type->range) {
+ type->range = calloc(1, sizeof *type->range);
+ LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx), LY_EMEM);
+ LY_CHECK_RET(lysp_restr_dup(ctx, type->range, orig_type->range));
+ }
+
+ if (orig_type->length) {
+ type->length = calloc(1, sizeof *type->length);
+ LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx), LY_EMEM);
+ LY_CHECK_RET(lysp_restr_dup(ctx, type->length, orig_type->length));
+ }
+
+ DUP_ARRAY(ctx, orig_type->patterns, type->patterns, lysp_restr_dup);
+ DUP_ARRAY(ctx, orig_type->enums, type->enums, lysp_type_enum_dup);
+ DUP_ARRAY(ctx, orig_type->bits, type->bits, lysp_type_enum_dup);
+ LY_CHECK_GOTO(ret = lyxp_expr_dup(ctx, orig_type->path, &type->path), done);
+ DUP_ARRAY(ctx, orig_type->bases, type->bases, lysp_string_dup);
+ DUP_ARRAY(ctx, orig_type->types, type->types, lysp_type_dup);
+ DUP_ARRAY(ctx, orig_type->exts, type->exts, lysp_ext_dup);
+
+ type->compiled = orig_type->compiled;
+
+ type->fraction_digits = orig_type->fraction_digits;
+ type->require_instance = orig_type->require_instance;
+ type->flags = orig_type->flags;
+
+done:
+ return ret;
+}
+
+static LY_ERR
+lysp_when_dup(const struct ly_ctx *ctx, struct lysp_when *when, const struct lysp_when *orig_when)
+{
+ LY_ERR ret = LY_SUCCESS;
+
+ DUP_STRING(ctx, orig_when->cond, when->cond, ret);
+ DUP_STRING(ctx, orig_when->dsc, when->dsc, ret);
+ DUP_STRING(ctx, orig_when->ref, when->ref, ret);
+ DUP_ARRAY(ctx, orig_when->exts, when->exts, lysp_ext_dup);
+
+ return ret;
+}
+
+static LY_ERR
+lysp_node_common_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
+{
+ LY_ERR ret = LY_SUCCESS;
+
+ node->parent = NULL;
+ node->nodetype = orig->nodetype;
+ node->flags = orig->flags;
+ node->next = NULL;
+ DUP_STRING(ctx, orig->name, node->name, ret);
+ DUP_STRING(ctx, orig->dsc, node->dsc, ret);
+ DUP_STRING(ctx, orig->ref, node->ref, ret);
+
+ if (orig->when) {
+ node->when = calloc(1, sizeof *node->when);
+ LY_CHECK_ERR_RET(!node->when, LOGMEM(ctx), LY_EMEM);
+ LY_CHECK_RET(lysp_when_dup(ctx, node->when, orig->when));
+ }
+
+ DUP_ARRAY(ctx, orig->iffeatures, node->iffeatures, lysp_qname_dup);
+ DUP_ARRAY(ctx, orig->exts, node->exts, lysp_ext_dup);
+
+ return ret;
+}
+
+static LY_ERR
+lysp_node_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lysp_node_container *cont;
+ const struct lysp_node_container *orig_cont;
+ struct lysp_node_leaf *leaf;
+ const struct lysp_node_leaf *orig_leaf;
+ struct lysp_node_leaflist *llist;
+ const struct lysp_node_leaflist *orig_llist;
+ struct lysp_node_list *list;
+ const struct lysp_node_list *orig_list;
+ struct lysp_node_choice *choice;
+ const struct lysp_node_choice *orig_choice;
+ struct lysp_node_case *cas;
+ const struct lysp_node_case *orig_cas;
+ struct lysp_node_anydata *any;
+ const struct lysp_node_anydata *orig_any;
+
+ assert(orig->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_ANYDATA));
+
+ /* common part */
+ LY_CHECK_RET(lysp_node_common_dup(ctx, node, orig));
+
+ /* specific part */
+ switch (node->nodetype) {
+ case LYS_CONTAINER:
+ cont = (struct lysp_node_container *)node;
+ orig_cont = (const struct lysp_node_container *)orig;
+
+ DUP_ARRAY(ctx, orig_cont->musts, cont->musts, lysp_restr_dup);
+ DUP_STRING(ctx, orig_cont->presence, cont->presence, ret);
+ /* we do not need the rest */
+ break;
+ case LYS_LEAF:
+ leaf = (struct lysp_node_leaf *)node;
+ orig_leaf = (const struct lysp_node_leaf *)orig;
+
+ DUP_ARRAY(ctx, orig_leaf->musts, leaf->musts, lysp_restr_dup);
+ LY_CHECK_RET(lysp_type_dup(ctx, &leaf->type, &orig_leaf->type));
+ DUP_STRING(ctx, orig_leaf->units, leaf->units, ret);
+ DUP_STRING(ctx, orig_leaf->dflt.str, leaf->dflt.str, ret);
+ break;
+ case LYS_LEAFLIST:
+ llist = (struct lysp_node_leaflist *)node;
+ orig_llist = (const struct lysp_node_leaflist *)orig;
+
+ DUP_ARRAY(ctx, orig_llist->musts, llist->musts, lysp_restr_dup);
+ LY_CHECK_RET(lysp_type_dup(ctx, &llist->type, &orig_llist->type));
+ DUP_STRING(ctx, orig_llist->units, llist->units, ret);
+ DUP_ARRAY(ctx, orig_llist->dflts, llist->dflts, lysp_qname_dup);
+ llist->min = orig_llist->min;
+ llist->max = orig_llist->max;
+ break;
+ case LYS_LIST:
+ list = (struct lysp_node_list *)node;
+ orig_list = (const struct lysp_node_list *)orig;
+
+ DUP_ARRAY(ctx, orig_list->musts, list->musts, lysp_restr_dup);
+ DUP_STRING(ctx, orig_list->key, list->key, ret);
+ /* we do not need these arrays */
+ DUP_ARRAY(ctx, orig_list->uniques, list->uniques, lysp_qname_dup);
+ list->min = orig_list->min;
+ list->max = orig_list->max;
+ break;
+ case LYS_CHOICE:
+ choice = (struct lysp_node_choice *)node;
+ orig_choice = (const struct lysp_node_choice *)orig;
+
+ /* we do not need children */
+ LY_CHECK_RET(lysp_qname_dup(ctx, &choice->dflt, &orig_choice->dflt));
+ break;
+ case LYS_CASE:
+ cas = (struct lysp_node_case *)node;
+ orig_cas = (const struct lysp_node_case *)orig;
+
+ /* we do not need children */
+ (void)cas;
+ (void)orig_cas;
+ break;
+ case LYS_ANYDATA:
+ case LYS_ANYXML:
+ any = (struct lysp_node_anydata *)node;
+ orig_any = (const struct lysp_node_anydata *)orig;
+
+ DUP_ARRAY(ctx, orig_any->musts, any->musts, lysp_restr_dup);
+ break;
+ default:
+ LOGINT_RET(ctx);
+ }
+
+ return ret;
+}
+
+static LY_ERR
+lysp_action_inout_dup(const struct ly_ctx *ctx, struct lysp_action_inout *inout, const struct lysp_action_inout *orig)
+{
+ inout->parent = NULL;
+ inout->nodetype = orig->nodetype;
+ DUP_ARRAY(ctx, orig->musts, inout->musts, lysp_restr_dup);
+ /* we dot need these arrays */
+ DUP_ARRAY(ctx, orig->exts, inout->exts, lysp_ext_dup);
+
+ return LY_SUCCESS;
+}
+
+static LY_ERR
+lysp_action_dup(const struct ly_ctx *ctx, struct lysp_action *act, const struct lysp_action *orig)
+{
+ LY_ERR ret = LY_SUCCESS;
+
+ act->parent = NULL;
+ act->nodetype = orig->nodetype;
+ act->flags = orig->flags;
+ DUP_STRING(ctx, orig->name, act->name, ret);
+ DUP_STRING(ctx, orig->dsc, act->dsc, ret);
+ DUP_STRING(ctx, orig->ref, act->ref, ret);
+ DUP_ARRAY(ctx, orig->iffeatures, act->iffeatures, lysp_qname_dup);
+
+ act->input.nodetype = orig->input.nodetype;
+ act->output.nodetype = orig->output.nodetype;
+ /* we do not need choldren of in/out */
+ DUP_ARRAY(ctx, orig->exts, act->exts, lysp_ext_dup);
+
+ return ret;
+}
+
+static LY_ERR
+lysp_notif_dup(const struct ly_ctx *ctx, struct lysp_notif *notif, const struct lysp_notif *orig)
+{
+ LY_ERR ret = LY_SUCCESS;
+
+ notif->parent = NULL;
+ notif->nodetype = orig->nodetype;
+ notif->flags = orig->flags;
+ DUP_STRING(ctx, orig->name, notif->name, ret);
+ DUP_STRING(ctx, orig->dsc, notif->dsc, ret);
+ DUP_STRING(ctx, orig->ref, notif->ref, ret);
+ DUP_ARRAY(ctx, orig->iffeatures, notif->iffeatures, lysp_qname_dup);
+ DUP_ARRAY(ctx, orig->musts, notif->musts, lysp_restr_dup);
+ /* we do not need these arrays */
+ DUP_ARRAY(ctx, orig->exts, notif->exts, lysp_ext_dup);
+
+ return ret;
+}
+
+/**
+ * @brief Duplicate a single parsed node. Only attributes that are used in compilation are copied.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] pnode Node to duplicate.
+ * @param[in] with_links Whether to also copy any links (child, parent pointers).
+ * @param[out] dup_p Duplicated parsed node.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lysp_dup_single(const struct ly_ctx *ctx, const struct lysp_node *pnode, ly_bool with_links, struct lysp_node **dup_p)
+{
+ void *mem;
+
+ if (!pnode) {
+ *dup_p = NULL;
+ return LY_SUCCESS;
+ }
+
+ switch (pnode->nodetype) {
+ case LYS_CONTAINER:
+ mem = calloc(1, sizeof(struct lysp_node_container));
+ LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
+ LY_CHECK_RET(lysp_node_dup(ctx, mem, pnode));
+ break;
+ case LYS_LEAF:
+ mem = calloc(1, sizeof(struct lysp_node_leaf));
+ LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
+ LY_CHECK_RET(lysp_node_dup(ctx, mem, pnode));
+ break;
+ case LYS_LEAFLIST:
+ mem = calloc(1, sizeof(struct lysp_node_leaflist));
+ LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
+ LY_CHECK_RET(lysp_node_dup(ctx, mem, pnode));
+ break;
+ case LYS_LIST:
+ mem = calloc(1, sizeof(struct lysp_node_list));
+ LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
+ LY_CHECK_RET(lysp_node_dup(ctx, mem, pnode));
+ break;
+ case LYS_CHOICE:
+ mem = calloc(1, sizeof(struct lysp_node_choice));
+ LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
+ LY_CHECK_RET(lysp_node_dup(ctx, mem, pnode));
+ break;
+ case LYS_CASE:
+ mem = calloc(1, sizeof(struct lysp_node_case));
+ LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
+ LY_CHECK_RET(lysp_node_dup(ctx, mem, pnode));
+ break;
+ case LYS_ANYDATA:
+ case LYS_ANYXML:
+ mem = calloc(1, sizeof(struct lysp_node_anydata));
+ LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
+ LY_CHECK_RET(lysp_node_dup(ctx, mem, pnode));
+ break;
+ case LYS_INPUT:
+ case LYS_OUTPUT:
+ mem = calloc(1, sizeof(struct lysp_action_inout));
+ LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
+ LY_CHECK_RET(lysp_action_inout_dup(ctx, mem, (struct lysp_action_inout *)pnode));
+ break;
+ case LYS_ACTION:
+ case LYS_RPC:
+ mem = calloc(1, sizeof(struct lysp_action));
+ LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
+ LY_CHECK_RET(lysp_action_dup(ctx, mem, (struct lysp_action *)pnode));
+ break;
+ case LYS_NOTIF:
+ mem = calloc(1, sizeof(struct lysp_notif));
+ LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
+ LY_CHECK_RET(lysp_notif_dup(ctx, mem, (struct lysp_notif *)pnode));
+ break;
+ default:
+ LOGINT_RET(ctx);
+ }
+
+ if (with_links) {
+ /* copy also parent and child pointers */
+ ((struct lysp_node *)mem)->parent = pnode->parent;
+ switch (pnode->nodetype) {
+ case LYS_CONTAINER:
+ ((struct lysp_node_container *)mem)->child = ((struct lysp_node_container *)pnode)->child;
+ break;
+ case LYS_LIST:
+ ((struct lysp_node_list *)mem)->child = ((struct lysp_node_list *)pnode)->child;
+ break;
+ case LYS_CHOICE:
+ ((struct lysp_node_choice *)mem)->child = ((struct lysp_node_choice *)pnode)->child;
+ break;
+ case LYS_CASE:
+ ((struct lysp_node_case *)mem)->child = ((struct lysp_node_case *)pnode)->child;
+ break;
+ default:
+ break;
+ }
+ }
+
+ *dup_p = mem;
+ return LY_SUCCESS;
+}
+
+#define AMEND_WRONG_NODETYPE(AMEND_STR, OP_STR, PROPERTY) \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s of %s node - it is not possible to %s \"%s\" property.", \
+ AMEND_STR, lys_nodetype2str(target->nodetype), OP_STR, PROPERTY);\
+ ret = LY_EVALID; \
+ goto cleanup;
+
+#define AMEND_CHECK_CARDINALITY(ARRAY, MAX, AMEND_STR, PROPERTY) \
+ if (LY_ARRAY_COUNT(ARRAY) > MAX) { \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid %s of %s with too many (%"LY_PRI_ARRAY_COUNT_TYPE") %s properties.", \
+ AMEND_STR, lys_nodetype2str(target->nodetype), LY_ARRAY_COUNT(ARRAY), PROPERTY); \
+ ret = LY_EVALID; \
+ goto cleanup; \
+ }
+
+/**
+ * @brief Apply refine.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] rfn Refine to apply.
+ * @param[in,out] target Refine target.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_apply_refine(struct lysc_ctx *ctx, struct lysp_refine *rfn, struct lysp_node *target)
+{
+ LY_ERR ret = LY_SUCCESS;
+ LY_ARRAY_COUNT_TYPE u;
+ struct lysp_qname *qname;
+ struct lysp_restr **musts, *must;
+ uint32_t *num;
+
+ /* default value */
+ if (rfn->dflts) {
+ switch (target->nodetype) {
+ case LYS_LEAF:
+ AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
+
+ FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
+ DUP_STRING_GOTO(ctx->ctx, rfn->dflts[0], ((struct lysp_node_leaf *)target)->dflt.str, ret, cleanup);
+ ((struct lysp_node_leaf *)target)->dflt.mod = ctx->mod;
+ break;
+ case LYS_LEAFLIST:
+ if (ctx->mod->version < LYS_VERSION_1_1) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.");
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ FREE_ARRAY(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, lysp_qname_free);
+ ((struct lysp_node_leaflist *)target)->dflts = NULL;
+ LY_ARRAY_FOR(rfn->dflts, u) {
+ LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
+ DUP_STRING_GOTO(ctx->ctx, rfn->dflts[u], qname->str, ret, cleanup);
+ qname->mod = ctx->mod;
+ }
+ break;
+ case LYS_CHOICE:
+ AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
+
+ FREE_STRING(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
+ DUP_STRING_GOTO(ctx->ctx, rfn->dflts[0], ((struct lysp_node_choice *)target)->dflt.str, ret, cleanup);
+ ((struct lysp_node_choice *)target)->dflt.mod = ctx->mod;
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("refine", "replace", "default");
+ }
+ }
+
+ /* description */
+ if (rfn->dsc) {
+ FREE_STRING(ctx->ctx, target->dsc);
+ DUP_STRING_GOTO(ctx->ctx, rfn->dsc, target->dsc, ret, cleanup);
+ }
+
+ /* reference */
+ if (rfn->ref) {
+ FREE_STRING(ctx->ctx, target->ref);
+ DUP_STRING_GOTO(ctx->ctx, rfn->ref, target->ref, ret, cleanup);
+ }
+
+ /* config */
+ if (rfn->flags & LYS_CONFIG_MASK) {
+ if (ctx->options & (LYSC_OPT_NOTIFICATION | LYSC_OPT_RPC_INPUT | LYSC_OPT_RPC_OUTPUT)) {
+ LOGWRN(ctx->ctx, "Refining config inside %s has no effect (%s).",
+ ctx->options & LYSC_OPT_NOTIFICATION ? "notification" : "RPC/action", ctx->path);
+ } else {
+ target->flags &= ~LYS_CONFIG_MASK;
+ target->flags |= rfn->flags & LYS_CONFIG_MASK;
+ }
+ }
+
+ /* mandatory */
+ if (rfn->flags & LYS_MAND_MASK) {
+ switch (target->nodetype) {
+ case LYS_LEAF:
+ case LYS_CHOICE:
+ case LYS_ANYDATA:
+ case LYS_ANYXML:
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("refine", "replace", "mandatory");
+ }
+
+ target->flags &= ~LYS_MAND_MASK;
+ target->flags |= rfn->flags & LYS_MAND_MASK;
+ }
+
+ /* presence */
+ if (rfn->presence) {
+ switch (target->nodetype) {
+ case LYS_CONTAINER:
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("refine", "replace", "presence");
+ }
+
+ FREE_STRING(ctx->ctx, ((struct lysp_node_container *)target)->presence);
+ DUP_STRING_GOTO(ctx->ctx, rfn->presence, ((struct lysp_node_container *)target)->presence, ret, cleanup);
+ }
+
+ /* must */
+ if (rfn->musts) {
+ switch (target->nodetype) {
+ case LYS_CONTAINER:
+ case LYS_LIST:
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ case LYS_ANYDATA:
+ case LYS_ANYXML:
+ musts = &((struct lysp_node_container *)target)->musts;
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("refine", "add", "must");
+ }
+
+ LY_ARRAY_FOR(rfn->musts, u) {
+ LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
+ LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &rfn->musts[u]), cleanup);
+ }
+ }
+
+ /* min-elements */
+ if (rfn->flags & LYS_SET_MIN) {
+ switch (target->nodetype) {
+ case LYS_LEAFLIST:
+ num = &((struct lysp_node_leaflist *)target)->min;
+ break;
+ case LYS_LIST:
+ num = &((struct lysp_node_list *)target)->min;
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("refine", "replace", "min-elements");
+ }
+
+ *num = rfn->min;
+ }
+
+ /* max-elements */
+ if (rfn->flags & LYS_SET_MAX) {
+ switch (target->nodetype) {
+ case LYS_LEAFLIST:
+ num = &((struct lysp_node_leaflist *)target)->max;
+ break;
+ case LYS_LIST:
+ num = &((struct lysp_node_list *)target)->max;
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("refine", "replace", "max-elements");
+ }
+
+ *num = rfn->max;
+ }
+
+ /* if-feature */
+ if (rfn->iffeatures) {
+ switch (target->nodetype) {
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ case LYS_LIST:
+ case LYS_CONTAINER:
+ case LYS_CHOICE:
+ case LYS_CASE:
+ case LYS_ANYDATA:
+ case LYS_ANYXML:
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("refine", "add", "if-feature");
+ }
+
+ LY_ARRAY_FOR(rfn->iffeatures, u) {
+ LY_ARRAY_NEW_GOTO(ctx->ctx, target->iffeatures, qname, ret, cleanup);
+ DUP_STRING_GOTO(ctx->ctx, rfn->iffeatures[u].str, qname->str, ret, cleanup);
+ qname->mod = ctx->mod;
+ }
+ }
+
+ /* extension */
+ /* TODO refine extensions */
+
+cleanup:
+ return ret;
+}
+
+/**
+ * @brief Apply deviate add.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] d Deviate add to apply.
+ * @param[in,out] target Deviation target.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysp_deviate_add *d, struct lysp_node *target)
+{
+ LY_ERR ret = LY_SUCCESS;
+ LY_ARRAY_COUNT_TYPE u;
+ struct lysp_qname *qname;
+ uint32_t *num;
+ struct lysp_restr **musts, *must;
+
+#define DEV_CHECK_NONPRESENCE(TYPE, MEMBER, PROPERTY, VALUEMEMBER) \
+ if (((TYPE)target)->MEMBER) { \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
+ "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", \
+ PROPERTY, ((TYPE)target)->VALUEMEMBER); \
+ ret = LY_EVALID; \
+ goto cleanup; \
+ }
+
+ /* [units-stmt] */
+ if (d->units) {
+ switch (target->nodetype) {
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("deviation", "add", "units");
+ }
+
+ DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, units, "units", units);
+ DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
+ }
+
+ /* *must-stmt */
+ if (d->musts) {
+ switch (target->nodetype) {
+ case LYS_CONTAINER:
+ case LYS_LIST:
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ case LYS_ANYDATA:
+ case LYS_ANYXML:
+ musts = &((struct lysp_node_container *)target)->musts;
+ break;
+ case LYS_NOTIF:
+ musts = &((struct lysp_notif *)target)->musts;
+ break;
+ case LYS_INPUT:
+ case LYS_OUTPUT:
+ musts = &((struct lysp_action_inout *)target)->musts;
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("deviation", "add", "must");
+ }
+
+ LY_ARRAY_FOR(d->musts, u) {
+ LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
+ LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &d->musts[u]), cleanup);
+ }
+ }
+
+ /* *unique-stmt */
+ if (d->uniques) {
+ switch (target->nodetype) {
+ case LYS_LIST:
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("deviation", "add", "unique");
+ }
+
+ LY_ARRAY_FOR(d->uniques, u) {
+ LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_list *)target)->uniques, qname, ret, cleanup);
+ DUP_STRING_GOTO(ctx->ctx, d->uniques[u], qname->str, ret, cleanup);
+ qname->mod = ctx->mod;
+ }
+ }
+
+ /* *default-stmt */
+ if (d->dflts) {
+ switch (target->nodetype) {
+ case LYS_LEAF:
+ AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
+ DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, dflt.str, "default", dflt.str);
+
+ DUP_STRING_GOTO(ctx->ctx, d->dflts[0], ((struct lysp_node_leaf *)target)->dflt.str, ret, cleanup);
+ ((struct lysp_node_leaf *)target)->dflt.mod = ctx->mod;
+ break;
+ case LYS_LEAFLIST:
+ LY_ARRAY_FOR(d->dflts, u) {
+ LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
+ DUP_STRING_GOTO(ctx->ctx, d->dflts[u], qname->str, ret, cleanup);
+ qname->mod = ctx->mod;
+ }
+ break;
+ case LYS_CHOICE:
+ AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
+ DEV_CHECK_NONPRESENCE(struct lysp_node_choice *, dflt.str, "default", dflt.str);
+
+ DUP_STRING_GOTO(ctx->ctx, d->dflts[0], ((struct lysp_node_choice *)target)->dflt.str, ret, cleanup);
+ ((struct lysp_node_choice *)target)->dflt.mod = ctx->mod;
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("deviation", "add", "default");
+ }
+ }
+
+ /* [config-stmt] */
+ if (d->flags & LYS_CONFIG_MASK) {
+ switch (target->nodetype) {
+ case LYS_CONTAINER:
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ case LYS_LIST:
+ case LYS_CHOICE:
+ case LYS_ANYDATA:
+ case LYS_ANYXML:
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("deviation", "add", "config");
+ }
+
+ if (target->flags & LYS_CONFIG_MASK) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid deviation adding \"config\" property which already exists (with value \"config %s\").",
+ target->flags & LYS_CONFIG_W ? "true" : "false");
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ target->flags |= d->flags & LYS_CONFIG_MASK;
+ }
+
+ /* [mandatory-stmt] */
+ if (d->flags & LYS_MAND_MASK) {
+ switch (target->nodetype) {
+ case LYS_LEAF:
+ case LYS_CHOICE:
+ case LYS_ANYDATA:
+ case LYS_ANYXML:
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("deviation", "add", "mandatory");
+ }
+
+ if (target->flags & LYS_MAND_MASK) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory %s\").",
+ target->flags & LYS_MAND_TRUE ? "true" : "false");
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ target->flags |= d->flags & LYS_MAND_MASK;
+ }
+
+ /* [min-elements-stmt] */
+ if (d->flags & LYS_SET_MIN) {
+ switch (target->nodetype) {
+ case LYS_LEAFLIST:
+ num = &((struct lysp_node_leaflist *)target)->min;
+ break;
+ case LYS_LIST:
+ num = &((struct lysp_node_list *)target)->min;
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("deviation", "add", "min-elements");
+ }
+
+ if (target->flags & LYS_SET_MIN) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid deviation adding \"min-elements\" property which already exists (with value \"%u\").", *num);
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ *num = d->min;
+ }
+
+ /* [max-elements-stmt] */
+ if (d->flags & LYS_SET_MAX) {
+ switch (target->nodetype) {
+ case LYS_LEAFLIST:
+ num = &((struct lysp_node_leaflist *)target)->max;
+ break;
+ case LYS_LIST:
+ num = &((struct lysp_node_list *)target)->max;
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("deviation", "add", "max-elements");
+ }
+
+ if (target->flags & LYS_SET_MAX) {
+ if (*num) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid deviation adding \"max-elements\" property which already exists (with value \"%u\").",
+ *num);
+ } else {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid deviation adding \"max-elements\" property which already exists (with value \"unbounded\").");
+ }
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ *num = d->max;
+ }
+
+cleanup:
+ return ret;
+}
+
+/**
+ * @brief Apply deviate delete.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] d Deviate delete to apply.
+ * @param[in,out] target Deviation target.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysp_deviate_del *d, struct lysp_node *target)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lysp_restr **musts;
+ LY_ARRAY_COUNT_TYPE u, v;
+ struct lysp_qname **uniques, **dflts;
+
+#define DEV_DEL_ARRAY(DEV_ARRAY, ORIG_ARRAY, DEV_MEMBER, ORIG_MEMBER, FREE_FUNC, PROPERTY) \
+ LY_ARRAY_FOR(d->DEV_ARRAY, u) { \
+ int found = 0; \
+ LY_ARRAY_FOR(ORIG_ARRAY, v) { \
+ if (!strcmp(d->DEV_ARRAY[u]DEV_MEMBER, (ORIG_ARRAY)[v]ORIG_MEMBER)) { \
+ found = 1; \
+ break; \
+ } \
+ } \
+ if (!found) { \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
+ "Invalid deviation deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
+ PROPERTY, d->DEV_ARRAY[u]DEV_MEMBER); \
+ ret = LY_EVALID; \
+ goto cleanup; \
+ } \
+ LY_ARRAY_DECREMENT(ORIG_ARRAY); \
+ FREE_FUNC(ctx->ctx, &(ORIG_ARRAY)[v]); \
+ memmove(&(ORIG_ARRAY)[v], &(ORIG_ARRAY)[v + 1], (LY_ARRAY_COUNT(ORIG_ARRAY) - v) * sizeof *(ORIG_ARRAY)); \
+ } \
+ if (!LY_ARRAY_COUNT(ORIG_ARRAY)) { \
+ LY_ARRAY_FREE(ORIG_ARRAY); \
+ ORIG_ARRAY = NULL; \
+ }
+
+#define DEV_CHECK_PRESENCE_VALUE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
+ if (!((TYPE)target)->MEMBER) { \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
+ ret = LY_EVALID; \
+ goto cleanup; \
+ } else if (strcmp(((TYPE)target)->MEMBER, VALUE)) { \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
+ "Invalid deviation deleting \"%s\" property \"%s\" which does not match the target's property value \"%s\".", \
+ PROPERTY, VALUE, ((TYPE)target)->MEMBER); \
+ ret = LY_EVALID; \
+ goto cleanup; \
+ }
+
+ /* [units-stmt] */
+ if (d->units) {
+ switch (target->nodetype) {
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("deviation", "delete", "units");
+ }
+
+ DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, units, "deleting", "units", d->units);
+ FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
+ ((struct lysp_node_leaf *)target)->units = NULL;
+ }
+
+ /* *must-stmt */
+ if (d->musts) {
+ switch (target->nodetype) {
+ case LYS_CONTAINER:
+ case LYS_LIST:
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ case LYS_ANYDATA:
+ case LYS_ANYXML:
+ musts = &((struct lysp_node_container *)target)->musts;
+ break;
+ case LYS_NOTIF:
+ musts = &((struct lysp_notif *)target)->musts;
+ break;
+ case LYS_INPUT:
+ case LYS_OUTPUT:
+ musts = &((struct lysp_action_inout *)target)->musts;
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("deviation", "delete", "must");
+ }
+
+ DEV_DEL_ARRAY(musts, *musts, .arg.str, .arg.str, lysp_restr_free, "must");
+ }
+
+ /* *unique-stmt */
+ if (d->uniques) {
+ switch (target->nodetype) {
+ case LYS_LIST:
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("deviation", "delete", "unique");
+ }
+
+ uniques = &((struct lysp_node_list *)target)->uniques;
+ DEV_DEL_ARRAY(uniques, *uniques, , .str, lysp_qname_free, "unique");
+ }
+
+ /* *default-stmt */
+ if (d->dflts) {
+ switch (target->nodetype) {
+ case LYS_LEAF:
+ AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
+ DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, dflt.str, "deleting", "default", d->dflts[0]);
+
+ FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
+ ((struct lysp_node_leaf *)target)->dflt.str = NULL;
+ break;
+ case LYS_LEAFLIST:
+ dflts = &((struct lysp_node_leaflist *)target)->dflts;
+ DEV_DEL_ARRAY(dflts, *dflts, , .str, lysp_qname_free, "default");
+ break;
+ case LYS_CHOICE:
+ AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
+ DEV_CHECK_PRESENCE_VALUE(struct lysp_node_choice *, dflt.str, "deleting", "default", d->dflts[0]);
+
+ FREE_STRING(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
+ ((struct lysp_node_choice *)target)->dflt.str = NULL;
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("deviation", "delete", "default");
+ }
+ }
+
+cleanup:
+ return ret;
+}
+
+/**
+ * @brief Apply deviate replace.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] d Deviate replace to apply.
+ * @param[in,out] target Deviation target.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysp_deviate_rpl *d, struct lysp_node *target)
+{
+ LY_ERR ret = LY_SUCCESS;
+ uint32_t *num;
+
+#define DEV_CHECK_PRESENCE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
+ if (!((TYPE)target)->MEMBER) { \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
+ ret = LY_EVALID; \
+ goto cleanup; \
+ }
+
+ /* [type-stmt] */
+ if (d->type) {
+ switch (target->nodetype) {
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("deviation", "replace", "type");
+ }
+
+ lysp_type_free(ctx->ctx, &((struct lysp_node_leaf *)target)->type);
+ lysp_type_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->type, d->type);
+ }
+
+ /* [units-stmt] */
+ if (d->units) {
+ switch (target->nodetype) {
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("deviation", "replace", "units");
+ }
+
+ DEV_CHECK_PRESENCE(struct lysp_node_leaf *, units, "replacing", "units", d->units);
+ FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
+ DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
+ }
+
+ /* [default-stmt] */
+ if (d->dflt) {
+ switch (target->nodetype) {
+ case LYS_LEAF:
+ DEV_CHECK_PRESENCE(struct lysp_node_leaf *, dflt.str, "replacing", "default", d->dflt);
+
+ FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
+ DUP_STRING_GOTO(ctx->ctx, d->dflt, ((struct lysp_node_leaf *)target)->dflt.str, ret, cleanup);
+ ((struct lysp_node_leaf *)target)->dflt.mod = ctx->mod;
+ break;
+ case LYS_CHOICE:
+ DEV_CHECK_PRESENCE(struct lysp_node_choice *, dflt.str, "replacing", "default", d->dflt);
+
+ FREE_STRING(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
+ DUP_STRING_GOTO(ctx->ctx, d->dflt, ((struct lysp_node_choice *)target)->dflt.str, ret, cleanup);
+ ((struct lysp_node_choice *)target)->dflt.mod = ctx->mod;
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("deviation", "replace", "default");
+ }
+ }
+
+ /* [config-stmt] */
+ if (d->flags & LYS_CONFIG_MASK) {
+ switch (target->nodetype) {
+ case LYS_CONTAINER:
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ case LYS_LIST:
+ case LYS_CHOICE:
+ case LYS_ANYDATA:
+ case LYS_ANYXML:
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("deviation", "replace", "config");
+ }
+
+ if (!(target->flags & LYS_CONFIG_MASK)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT,
+ "replacing", "config", d->flags & LYS_CONFIG_W ? "config true" : "config false");
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ target->flags &= ~LYS_CONFIG_MASK;
+ target->flags |= d->flags & LYS_CONFIG_MASK;
+ }
+
+ /* [mandatory-stmt] */
+ if (d->flags & LYS_MAND_MASK) {
+ switch (target->nodetype) {
+ case LYS_LEAF:
+ case LYS_CHOICE:
+ case LYS_ANYDATA:
+ case LYS_ANYXML:
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("deviation", "replace", "mandatory");
+ }
+
+ if (!(target->flags & LYS_MAND_MASK)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT,
+ "replacing", "mandatory", d->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ target->flags &= ~LYS_MAND_MASK;
+ target->flags |= d->flags & LYS_MAND_MASK;
+ }
+
+ /* [min-elements-stmt] */
+ if (d->flags & LYS_SET_MIN) {
+ switch (target->nodetype) {
+ case LYS_LEAFLIST:
+ num = &((struct lysp_node_leaflist *)target)->min;
+ break;
+ case LYS_LIST:
+ num = &((struct lysp_node_list *)target)->min;
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("deviation", "replace", "min-elements");
+ }
+
+ if (!(target->flags & LYS_SET_MIN)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid deviation replacing \"min-elements\" property which is not present.");
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ *num = d->min;
+ }
+
+ /* [max-elements-stmt] */
+ if (d->flags & LYS_SET_MAX) {
+ switch (target->nodetype) {
+ case LYS_LEAFLIST:
+ num = &((struct lysp_node_leaflist *)target)->max;
+ break;
+ case LYS_LIST:
+ num = &((struct lysp_node_list *)target)->max;
+ break;
+ default:
+ AMEND_WRONG_NODETYPE("deviation", "replace", "max-elements");
+ }
+
+ if (!(target->flags & LYS_SET_MAX)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid deviation replacing \"max-elements\" property which is not present.");
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ *num = d->max;
+ }
+
+cleanup:
+ return ret;
+}
+
+/**
+ * @brief Get module of a single nodeid node name test.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] nametest Nametest with an optional prefix.
+ * @param[in] nametest_len Length of @p nametest.
+ * @param[in] local_mod Module to return in case of no prefix.
+ * @param[out] name Optional pointer to the name test without the prefix.
+ * @param[out] name_len Length of @p name.
+ * @return Resolved module.
+ */
+static const struct lys_module *
+lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest, size_t nametest_len,
+ const struct lys_module *local_mod, const char **name, size_t *name_len)
+{
+ const struct lys_module *target_mod;
+ const char *ptr;
+
+ ptr = ly_strnchr(nametest, ':', nametest_len);
+ if (ptr) {
+ target_mod = ly_resolve_prefix(ctx, nametest, ptr - nametest, LY_PREF_SCHEMA, (void *)local_mod);
+ if (!target_mod) {
+ LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
+ "Invalid absolute-schema-nodeid nametest \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
+ nametest_len, nametest, ptr - nametest, nametest, local_mod->name);
+ return NULL;
+ }
+
+ if (name) {
+ *name = ptr + 1;
+ *name_len = nametest_len - ((ptr - nametest) + 1);
+ }
+ } else {
+ target_mod = local_mod;
+ if (name) {
+ *name = nametest;
+ *name_len = nametest_len;
+ }
+ }
+
+ return target_mod;
+}
+
+/**
+ * @brief Check whether a parsed node matches a single schema nodeid name test.
+ *
+ * @param[in] pnode Parsed node to consider.
+ * @param[in] pnode_mod Compiled @p pnode to-be module.
+ * @param[in] mod Expected module.
+ * @param[in] name Expected name.
+ * @param[in] name_len Length of @p name.
+ * @return Whether it is a match or not.
+ */
+static ly_bool
+lysp_schema_nodeid_match_pnode(const struct lysp_node *pnode, const struct lys_module *pnode_mod,
+ const struct lys_module *mod, const char *name, size_t name_len)
+{
+ const char *pname;
+
+ /* compare with the module of the node */
+ if (pnode_mod != mod) {
+ return 0;
+ }
+
+ /* compare names */
+ if (pnode->nodetype & (LYS_ACTION | LYS_RPC)) {
+ pname = ((struct lysp_action *)pnode)->name;
+ } else if (pnode->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
+ pname = (pnode->nodetype & LYS_INPUT) ? "input" : "output";
+ } else {
+ pname = pnode->name;
+ }
+ if (ly_strncmp(pname, name, name_len)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * @brief Check whether a compiled node matches a single schema nodeid name test.
+ *
+ * @param[in,out] node Compiled node to consider. On a match it is moved to its parent.
+ * @param[in] mod Expected module.
+ * @param[in] name Expected name.
+ * @param[in] name_len Length of @p name.
+ * @return Whether it is a match or not.
+ */
+static ly_bool
+lysp_schema_nodeid_match_node(const struct lysc_node **node, const struct lys_module *mod, const char *name,
+ size_t name_len)
+{
+ const struct lys_module *node_mod;
+ const char *node_name;
+
+ /* compare with the module of the node */
+ if ((*node)->nodetype == LYS_INPUT) {
+ node_mod = ((struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, input)))->module;
+ } else if ((*node)->nodetype == LYS_OUTPUT) {
+ node_mod = ((struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, output)))->module;
+ } else {
+ node_mod = (*node)->module;
+ }
+ if (node_mod != mod) {
+ return 0;
+ }
+
+ /* compare names */
+ if ((*node)->nodetype == LYS_INPUT) {
+ node_name = "input";
+ } else if ((*node)->nodetype == LYS_OUTPUT) {
+ node_name = "output";
+ } else {
+ node_name = (*node)->name;
+ }
+ if (ly_strncmp(node_name, name, name_len)) {
+ return 0;
+ }
+
+ if ((*node)->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
+ /* move up from input/output */
+ if ((*node)->nodetype == LYS_INPUT) {
+ (*node) = (struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, input));
+ } else {
+ (*node) = (struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, output));
+ }
+ } else if ((*node)->parent && ((*node)->parent->nodetype & (LYS_RPC | LYS_ACTION))) {
+ /* move to the input/output */
+ if ((*node)->flags & LYS_CONFIG_W) {
+ *node = (struct lysc_node *)&((struct lysc_action *)(*node)->parent)->input;
+ } else {
+ *node = (struct lysc_node *)&((struct lysc_action *)(*node)->parent)->output;
+ }
+ } else {
+ /* move to next parent */
+ *node = (*node)->parent;
+ }
+
+ return 1;
+}
+
+/**
+ * @brief Check whether a node matches specific schema nodeid.
+ *
+ * @param[in] exp Parsed nodeid to match.
+ * @param[in] exp_mod Module to use for nodes in @p exp without a prefix.
+ * @param[in] ctx_node Initial context node that should match, only for descendant paths.
+ * @param[in] parent First compiled parent to consider. If @p pnode is NULL, it is condered the node to be matched.
+ * @param[in] pnode Parsed node to be matched. May be NULL if the target node was already compiled.
+ * @param[in] pnode_mod Compiled @p pnode to-be module.
+ * @return Whether it is a match or not.
+ */
+static ly_bool
+lysp_schema_nodeid_match(const struct lyxp_expr *exp, const struct lys_module *exp_mod, const struct lysc_node *ctx_node,
+ const struct lysc_node *parent, const struct lysp_node *pnode, const struct lys_module *pnode_mod)
+{
+ uint32_t i;
+ const struct lys_module *mod;
+ const char *name;
+ size_t name_len;
+
+ /* compare last node in the node ID */
+ i = exp->used - 1;
+
+ /* get exp node ID module */
+ mod = lys_schema_node_get_module(exp_mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_mod, &name, &name_len);
+ assert(mod);
+
+ if (pnode) {
+ /* compare on the last parsed-only node */
+ if (!lysp_schema_nodeid_match_pnode(pnode, pnode_mod, mod, name, name_len)) {
+ return 0;
+ }
+ } else {
+ /* using parent directly */
+ if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
+ return 0;
+ }
+ }
+
+ /* now compare all the compiled parents */
+ while (i > 1) {
+ i -= 2;
+ assert(exp->tokens[i] == LYXP_TOKEN_NAMETEST);
+
+ if (!parent) {
+ /* no more parents but path continues */
+ return 0;
+ }
+
+ /* get exp node ID module */
+ mod = lys_schema_node_get_module(exp_mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_mod, &name,
+ &name_len);
+ assert(mod);
+
+ /* compare with the parent */
+ if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
+ return 0;
+ }
+ }
+
+ if (ctx_node && (ctx_node != parent)) {
+ /* descendant path has not finished in the context node */
+ return 0;
+ } else if (!ctx_node && parent) {
+ /* some parent was not matched */
+ return 0;
+ }
+
+ return 1;
+}
+
+static void
+lysc_augment_free(const struct ly_ctx *ctx, struct lysc_augment *aug)
+{
+ if (aug) {
+ lyxp_expr_free(ctx, aug->nodeid);
+
+ free(aug);
+ }
+}
+
+static void
+lysc_deviation_free(const struct ly_ctx *ctx, struct lysc_deviation *dev)
+{
+ if (dev) {
+ lyxp_expr_free(ctx, dev->nodeid);
+ LY_ARRAY_FREE(dev->devs);
+ LY_ARRAY_FREE(dev->dev_mods);
+
+ free(dev);
+ }
+}
+
+static void
+lysc_refine_free(const struct ly_ctx *ctx, struct lysc_refine *rfn)
+{
+ if (rfn) {
+ lyxp_expr_free(ctx, rfn->nodeid);
+ LY_ARRAY_FREE(rfn->rfns);
+
+ free(rfn);
+ }
+}
+
+static void
+lysp_dev_node_free(const struct ly_ctx *ctx, struct lysp_node *dev_pnode)
+{
+ if (!dev_pnode) {
+ return;
+ }
+
+ switch (dev_pnode->nodetype) {
+ case LYS_CONTAINER:
+ ((struct lysp_node_container *)dev_pnode)->child = NULL;
+ break;
+ case LYS_LIST:
+ ((struct lysp_node_list *)dev_pnode)->child = NULL;
+ break;
+ case LYS_CHOICE:
+ ((struct lysp_node_choice *)dev_pnode)->child = NULL;
+ break;
+ case LYS_CASE:
+ ((struct lysp_node_case *)dev_pnode)->child = NULL;
+ break;
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ case LYS_ANYXML:
+ case LYS_ANYDATA:
+ /* no children */
+ break;
+ case LYS_NOTIF:
+ ((struct lysp_notif *)dev_pnode)->data = NULL;
+ lysp_notif_free((struct ly_ctx *)ctx, (struct lysp_notif *)dev_pnode);
+ free(dev_pnode);
+ return;
+ case LYS_RPC:
+ case LYS_ACTION:
+ ((struct lysp_action *)dev_pnode)->input.data = NULL;
+ ((struct lysp_action *)dev_pnode)->output.data = NULL;
+ lysp_action_free((struct ly_ctx *)ctx, (struct lysp_action *)dev_pnode);
+ free(dev_pnode);
+ return;
+ case LYS_INPUT:
+ case LYS_OUTPUT:
+ ((struct lysp_action_inout *)dev_pnode)->data = NULL;
+ lysp_action_inout_free((struct ly_ctx *)ctx, (struct lysp_action_inout *)dev_pnode);
+ free(dev_pnode);
+ return;
+ default:
+ LOGINT(ctx);
+ return;
+ }
+
+ lysp_node_free((struct ly_ctx *)ctx, dev_pnode);
+}
+
+/**
+ * @brief Compile and apply any precompiled deviations and refines targetting a node.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] pnode Parsed node to consider.
+ * @param[in] parent First compiled parent of @p pnode.
+ * @param[out] dev_pnode Copy of parsed node @p pnode with deviations and refines, if any. NULL if there are none.
+ * @param[out] no_supported Whether a not-supported deviation is defined for the node.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode, const struct lysc_node *parent,
+ struct lysp_node **dev_pnode, ly_bool *not_supported)
+{
+ LY_ERR ret = LY_SUCCESS;
+ uint32_t i;
+ LY_ARRAY_COUNT_TYPE u;
+ struct lys_module *orig_mod = ctx->mod, *orig_mod_def = ctx->mod_def;
+ char orig_path[LYSC_CTX_BUFSIZE];
+ struct lysc_refine *rfn;
+ struct lysc_deviation *dev;
+ struct lysp_deviation *dev_p;
+ struct lysp_deviate *d;
+
+ *dev_pnode = NULL;
+ *not_supported = 0;
+
+ for (i = 0; i < ctx->uses_rfns.count; ++i) {
+ rfn = ctx->uses_rfns.objs[i];
+
+ if (!lysp_schema_nodeid_match(rfn->nodeid, ctx->mod, rfn->nodeid_ctx_node, parent, pnode, ctx->mod)) {
+ /* not our target node */
+ continue;
+ }
+
+ if (!*dev_pnode) {
+ /* first refine on this node, create a copy first */
+ LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
+ }
+
+ /* apply all the refines by changing (the copy of) the parsed node */
+ LY_ARRAY_FOR(rfn->rfns, u) {
+ /* apply refine, keep the current path and add to it */
+ lysc_update_path(ctx, NULL, "{refine}");
+ lysc_update_path(ctx, NULL, rfn->rfns[u]->nodeid);
+ ret = lys_apply_refine(ctx, rfn->rfns[u], *dev_pnode);
+ lysc_update_path(ctx, NULL, NULL);
+ lysc_update_path(ctx, NULL, NULL);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+
+ /* refine was applied, remove it */
+ lysc_refine_free(ctx->ctx, rfn);
+ ly_set_rm_index(&ctx->uses_rfns, i, NULL);
+
+ /* all the refines for one target node are in one structure, we are done */
+ break;
+ }
+
+ for (i = 0; i < ctx->devs.count; ++i) {
+ dev = ctx->devs.objs[i];
+
+ if (!lysp_schema_nodeid_match(dev->nodeid, dev->nodeid_mod, NULL, parent, pnode, ctx->mod_def)) {
+ /* not our target node */
+ continue;
+ }
+
+ if (dev->not_supported) {
+ /* it is not supported, no more deviations */
+ *not_supported = 1;
+ goto dev_applied;
+ }
+
+ if (!*dev_pnode) {
+ /* first deviation on this node, create a copy first */
+ LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
+ }
+
+ /* apply all the deviates by changing (the copy of) the parsed node */
+ LY_ARRAY_FOR(dev->devs, u) {
+ dev_p = dev->devs[u];
+ LY_LIST_FOR(dev_p->deviates, d) {
+ /* generate correct path */
+ strcpy(orig_path, ctx->path);
+ ctx->path_len = 1;
+ ctx->mod = (struct lys_module *)dev->dev_mods[u];
+ ctx->mod_def = (struct lys_module *)dev->dev_mods[u];
+ lysc_update_path(ctx, NULL, "{deviation}");
+ lysc_update_path(ctx, NULL, dev_p->nodeid);
+
+ switch (d->mod) {
+ case LYS_DEV_ADD:
+ ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, *dev_pnode);
+ break;
+ case LYS_DEV_DELETE:
+ ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, *dev_pnode);
+ break;
+ case LYS_DEV_REPLACE:
+ ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, *dev_pnode);
+ break;
+ default:
+ LOGINT(ctx->ctx);
+ ret = LY_EINT;
+ }
+
+ /* restore previous path */
+ strcpy(ctx->path, orig_path);
+ ctx->path_len = strlen(ctx->path);
+ ctx->mod = orig_mod;
+ ctx->mod_def = orig_mod_def;
+
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+ }
+
+dev_applied:
+ /* deviation was applied, remove it */
+ lysc_deviation_free(ctx->ctx, dev);
+ ly_set_rm_index(&ctx->devs, i, NULL);
+
+ /* all the deviations for one target node are in one structure, we are done */
+ break;
+ }
+
+cleanup:
+ if (ret) {
+ lysp_dev_node_free(ctx->ctx, *dev_pnode);
+ *dev_pnode = NULL;
+ *not_supported = 0;
+ }
+ return ret;
+}
+
+/**
+ * @brief Compile and apply any precompiled top-level or uses augments targetting a node.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] node Compiled node to consider.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lys_module *orig_mod = ctx->mod, *orig_mod_def = ctx->mod_def;
+ uint32_t i;
+ char orig_path[LYSC_CTX_BUFSIZE];
+ struct lysc_augment *aug;
+
+ /* uses augments */
+ for (i = 0; i < ctx->uses_augs.count; ) {
+ aug = ctx->uses_augs.objs[i];
+
+ if (!lysp_schema_nodeid_match(aug->nodeid, ctx->mod, aug->nodeid_ctx_node, node, NULL, NULL)) {
+ /* not our target node */
+ ++i;
+ continue;
+ }
+
+ /* apply augment, keep the current path and add to it */
+ lysc_update_path(ctx, NULL, "{augment}");
+ lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
+ ret = lys_compile_augment(ctx, aug->aug_p, node);
+ lysc_update_path(ctx, NULL, NULL);
+ lysc_update_path(ctx, NULL, NULL);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* augment was applied, remove it (index may have changed because other augments could have been applied) */
+ lysc_augment_free(ctx->ctx, aug);
+ ly_set_rm(&ctx->uses_augs, aug, NULL);
+ }
+
+ /* top-level augments */
+ for (i = 0; i < ctx->augs.count; ) {
+ aug = ctx->augs.objs[i];
+
+ if (!lysp_schema_nodeid_match(aug->nodeid, aug->nodeid_mod, NULL, node, NULL, NULL)) {
+ /* not our target node */
+ ++i;
+ continue;
+ }
+
+ /* apply augment, use the path and modules from the augment */
+ strcpy(orig_path, ctx->path);
+ ctx->path_len = 1;
+ lysc_update_path(ctx, NULL, "{augment}");
+ lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
+ ctx->mod = (struct lys_module *)aug->nodeid_mod;
+ ctx->mod_def = (struct lys_module *)aug->nodeid_mod;
+ ret = lys_compile_augment(ctx, aug->aug_p, node);
+ strcpy(ctx->path, orig_path);
+ ctx->path_len = strlen(ctx->path);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* augment was applied, remove it */
+ lysc_augment_free(ctx->ctx, aug);
+ ly_set_rm(&ctx->augs, aug, NULL);
+ }
+
+cleanup:
+ ctx->mod = orig_mod;
+ ctx->mod_def = orig_mod_def;
+ return ret;
+}
+
+/**
+ * @brief Prepare a top-level augment to be applied during data nodes compilation.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] aug_p Parsed augment to be applied.
+ * @param[in] mod_def Local module for @p aug_p.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_precompile_own_augment(struct lysc_ctx *ctx, struct lysp_augment *aug_p, const struct lys_module *mod_def)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lyxp_expr *exp = NULL;
+ struct lysc_augment *aug;
+ const struct lys_module *mod;
+
+ /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
+ ret = lyxp_expr_parse(ctx->ctx, aug_p->nodeid, strlen(aug_p->nodeid), 0, &exp);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], mod_def, NULL, NULL);
+ LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
+ if (mod != ctx->mod) {
+ /* augment for another module, ignore */
+ goto cleanup;
+ }
+
+ /* allocate new compiled augment and store it in the set */
+ aug = calloc(1, sizeof *aug);
+ LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
+ LY_CHECK_GOTO(ret = ly_set_add(&ctx->augs, aug, LY_SET_OPT_USEASLIST, NULL), cleanup);
+
+ aug->nodeid = exp;
+ exp = NULL;
+ aug->nodeid_mod = mod_def;
+ aug->aug_p = aug_p;
+
+cleanup:
+ lyxp_expr_free(ctx->ctx, exp);
+ return ret;
+}
+
+/**
+ * @brief Prepare all top-level augments for the current module to be applied during data nodes compilation.
+ *
+ * @param[in] ctx Compile context.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_precompile_own_augments(struct lysc_ctx *ctx)
+{
+ LY_ARRAY_COUNT_TYPE u, v, w;
+ const struct lys_module *aug_mod;
+
+ LY_ARRAY_FOR(ctx->mod->augmented_by, u) {
+ aug_mod = ctx->mod->augmented_by[u];
+
+ /* collect all module augments */
+ LY_ARRAY_FOR(aug_mod->parsed->augments, v) {
+ LY_CHECK_RET(lys_precompile_own_augment(ctx, &aug_mod->parsed->augments[v], aug_mod));
+ }
+
+ /* collect all submodules augments */
+ LY_ARRAY_FOR(aug_mod->parsed->includes, v) {
+ LY_ARRAY_FOR(aug_mod->parsed->includes[v].submodule->augments, w) {
+ LY_CHECK_RET(lys_precompile_own_augment(ctx, &aug_mod->parsed->includes[v].submodule->augments[w], aug_mod));
+ }
+ }
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Prepare a deviation to be applied during data nodes compilation.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] dev_p Parsed deviation to be applied.
+ * @param[in] mod_def Local module for @p dev_p.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_precompile_own_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev_p, const struct lys_module *mod_def)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lysc_deviation *dev = NULL;
+ struct lyxp_expr *exp = NULL;
+ struct lysp_deviation **new_dev;
+ const struct lys_module *mod, **new_dev_mod;
+ uint32_t i;
+
+ /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
+ ret = lyxp_expr_parse(ctx->ctx, dev_p->nodeid, strlen(dev_p->nodeid), 0, &exp);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], mod_def, NULL, NULL);
+ LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
+ if (mod != ctx->mod) {
+ /* deviation for another module, ignore */
+ goto cleanup;
+ }
+
+ /* try to find the node in already compiled deviations */
+ for (i = 0; i < ctx->devs.count; ++i) {
+ if (lys_abs_schema_nodeid_match(ctx->ctx, exp, mod_def, ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid,
+ ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid_mod)) {
+ dev = ctx->devs.objs[i];
+ break;
+ }
+ }
+
+ if (!dev) {
+ /* allocate new compiled deviation */
+ dev = calloc(1, sizeof *dev);
+ LY_CHECK_ERR_GOTO(!dev, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
+ LY_CHECK_GOTO(ret = ly_set_add(&ctx->devs, dev, LY_SET_OPT_USEASLIST, NULL), cleanup);
+
+ dev->nodeid = exp;
+ exp = NULL;
+ dev->nodeid_mod = mod_def;
+ }
+
+ /* add new parsed deviation structure */
+ LY_ARRAY_NEW_GOTO(ctx->ctx, dev->devs, new_dev, ret, cleanup);
+ *new_dev = dev_p;
+ LY_ARRAY_NEW_GOTO(ctx->ctx, dev->dev_mods, new_dev_mod, ret, cleanup);
+ *new_dev_mod = mod_def;
+
+cleanup:
+ lyxp_expr_free(ctx->ctx, exp);
+ return ret;
+}
+
+/**
+ * @brief Prepare all deviations for the current module to be applied during data nodes compilation.
+ *
+ * @param[in] ctx Compile context.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_precompile_own_deviations(struct lysc_ctx *ctx)
+{
+ LY_ARRAY_COUNT_TYPE u, v, w;
+ const struct lys_module *dev_mod;
+ struct lysc_deviation *dev;
+ struct lysp_deviate *d;
+ int not_supported;
+ uint32_t i;
+
+ LY_ARRAY_FOR(ctx->mod->deviated_by, u) {
+ dev_mod = ctx->mod->deviated_by[u];
+
+ /* compile all module deviations */
+ LY_ARRAY_FOR(dev_mod->parsed->deviations, v) {
+ LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->deviations[v], dev_mod));
+ }
+
+ /* compile all submodules deviations */
+ LY_ARRAY_FOR(dev_mod->parsed->includes, v) {
+ LY_ARRAY_FOR(dev_mod->parsed->includes[v].submodule->deviations, w) {
+ LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->includes[v].submodule->deviations[w], dev_mod));
+ }
+ }
+ }
+
+ /* set not-supported flags for all the deviations */
+ for (i = 0; i < ctx->devs.count; ++i) {
+ dev = ctx->devs.objs[i];
+ not_supported = 0;
+
+ LY_ARRAY_FOR(dev->devs, u) {
+ LY_LIST_FOR(dev->devs[u]->deviates, d) {
+ if (d->mod == LYS_DEV_NOT_SUPPORTED) {
+ not_supported = 1;
+ break;
+ }
+ }
+ if (not_supported) {
+ break;
+ }
+ }
+ if (not_supported && (LY_ARRAY_COUNT(dev->devs) > 1)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Multiple deviations of \"%s\" with one of them being \"not-supported\".", dev->nodeid->expr);
+ return LY_EVALID;
+ }
+
+ dev->not_supported = not_supported;
+ }
+
+ return LY_SUCCESS;
+}
+
/**
* @brief Compile parsed schema node information.
* @param[in] ctx Compile context
- * @param[in] node_p Parsed schema node.
+ * @param[in] pnode Parsed schema node.
* @param[in] parent Compiled parent node where the current node is supposed to be connected. It is
* NULL for top-level nodes, in such a case the module where the node will be connected is taken from
* the compile context.
@@ -5311,22 +6953,25 @@
* @return LY_ERR value - LY_SUCCESS or LY_EVALID.
*/
static LY_ERR
-lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *node_p, struct lysc_node *parent, uint16_t uses_status)
+lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *parent, uint16_t uses_status,
+ struct ly_set *child_set)
{
LY_ERR ret = LY_SUCCESS;
struct lysc_node *node = NULL;
struct lysc_when **when;
+ struct lysp_node *dev_pnode = NULL, *orig_pnode = pnode;
LY_ARRAY_COUNT_TYPE u;
+ ly_bool not_supported;
LY_ERR (*node_compile_spec)(struct lysc_ctx *, struct lysp_node *, struct lysc_node *);
- if (node_p->nodetype != LYS_USES) {
- lysc_update_path(ctx, parent, node_p->name);
+ if (pnode->nodetype != LYS_USES) {
+ lysc_update_path(ctx, parent, pnode->name);
} else {
lysc_update_path(ctx, NULL, "{uses}");
- lysc_update_path(ctx, NULL, node_p->name);
+ lysc_update_path(ctx, NULL, pnode->name);
}
- switch (node_p->nodetype) {
+ switch (pnode->nodetype) {
case LYS_CONTAINER:
node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_container));
node_compile_spec = lys_compile_node_container;
@@ -5347,7 +6992,7 @@
node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_choice));
node_compile_spec = lys_compile_node_choice;
break;
- case LYS_CASE:
+ case LYS_CASE:
node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_case));
node_compile_spec = lys_compile_node_case;
break;
@@ -5357,7 +7002,7 @@
node_compile_spec = lys_compile_node_any;
break;
case LYS_USES:
- ret = lys_compile_uses(ctx, (struct lysp_node_uses *)node_p, parent, &node);
+ ret = lys_compile_uses(ctx, (struct lysp_node_uses *)pnode, parent, child_set);
lysc_update_path(ctx, NULL, NULL);
lysc_update_path(ctx, NULL, NULL);
return ret;
@@ -5366,10 +7011,22 @@
return LY_EINT;
}
LY_CHECK_ERR_RET(!node, LOGMEM(ctx->ctx), LY_EMEM);
- node->nodetype = node_p->nodetype;
+
+ /* compile any deviations for this node */
+ LY_CHECK_ERR_RET(ret = lys_compile_node_deviations_refines(ctx, pnode, parent, &dev_pnode, ¬_supported),
+ free(node), ret);
+ if (not_supported) {
+ free(node);
+ lysc_update_path(ctx, NULL, NULL);
+ return LY_SUCCESS;
+ } else if (dev_pnode) {
+ pnode = dev_pnode;
+ }
+
+ node->nodetype = pnode->nodetype;
node->module = ctx->mod;
node->prev = node;
- node->flags = node_p->flags & LYS_FLAGS_COMPILED_MASK;
+ node->flags = pnode->flags & LYS_FLAGS_COMPILED_MASK;
/* config */
ret = lys_compile_config(ctx, node, parent);
@@ -5394,1227 +7051,237 @@
LY_CHECK_GOTO(ret = lys_compile_status(ctx, &node->flags, uses_status ? uses_status : (parent ? parent->flags : 0)), error);
if (!(ctx->options & LYSC_OPT_FREE_SP)) {
- node->sp = node_p;
+ node->sp = orig_pnode;
}
- DUP_STRING_GOTO(ctx->ctx, node_p->name, node->name, ret, error);
- DUP_STRING_GOTO(ctx->ctx, node_p->dsc, node->dsc, ret, error);
- DUP_STRING_GOTO(ctx->ctx, node_p->ref, node->ref, ret, error);
- if (node_p->when) {
+ DUP_STRING_GOTO(ctx->ctx, pnode->name, node->name, ret, error);
+ DUP_STRING_GOTO(ctx->ctx, pnode->dsc, node->dsc, ret, error);
+ DUP_STRING_GOTO(ctx->ctx, pnode->ref, node->ref, ret, error);
+ if (pnode->when) {
LY_ARRAY_NEW_GOTO(ctx->ctx, node->when, when, ret, error);
- LY_CHECK_GOTO(ret = lys_compile_when(ctx, node_p->when, node_p->flags, node, when), error);
+ LY_CHECK_GOTO(ret = lys_compile_when(ctx, pnode->when, pnode->flags, node, when), error);
if (!(ctx->options & LYSC_OPT_GROUPING)) {
/* do not check "when" semantics in a grouping */
- ret = ly_set_add(&ctx->xpath, node, 0, NULL);
- LY_CHECK_GOTO(ret, error);
+ LY_CHECK_GOTO(ret = ly_set_add(&ctx->xpath, node, 0, NULL), error);
}
}
- COMPILE_ARRAY_GOTO(ctx, node_p->iffeatures, node->iffeatures, u, lys_compile_iffeature, ret, error);
+ COMPILE_ARRAY_GOTO(ctx, pnode->iffeatures, node->iffeatures, u, lys_compile_iffeature, ret, error);
/* insert into parent's children/compiled module (we can no longer free the node separately on error) */
- LY_CHECK_RET(lys_compile_node_connect(ctx, parent, node));
+ LY_CHECK_GOTO(ret = lys_compile_node_connect(ctx, parent, node), cleanup);
+
+ /* connect any augments */
+ LY_CHECK_GOTO(ret = lys_compile_node_augments(ctx, node), cleanup);
/* nodetype-specific part */
- LY_CHECK_RET(node_compile_spec(ctx, node_p, node));
+ LY_CHECK_GOTO(ret = node_compile_spec(ctx, pnode, node), cleanup);
/* final compilation tasks that require the node to be connected */
- COMPILE_EXTS_GOTO(ctx, node_p->exts, node->exts, node, LYEXT_PAR_NODE, ret, done);
+ COMPILE_EXTS_GOTO(ctx, pnode->exts, node->exts, node, LYEXT_PAR_NODE, ret, cleanup);
if (node->flags & LYS_MAND_TRUE) {
/* inherit LYS_MAND_TRUE in parent containers */
lys_compile_mandatory_parents(parent, 1);
}
+ if (child_set) {
+ /* add the new node into set */
+ LY_CHECK_GOTO(ret = ly_set_add(child_set, node, LY_SET_OPT_USEASLIST, NULL), cleanup);
+ }
+
lysc_update_path(ctx, NULL, NULL);
+ lysp_dev_node_free(ctx->ctx, dev_pnode);
return LY_SUCCESS;
error:
lysc_node_free(ctx->ctx, node);
-done:
+cleanup:
+ if (dev_pnode) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_OTHER, "Compilation of a deviated and/or refined node failed.");
+ lysp_dev_node_free(ctx->ctx, dev_pnode);
+ }
return ret;
}
-static void
-lysc_node_unlink(struct lysc_node *node)
-{
- struct lysc_node *parent, *child;
- struct lysc_module *modc = node->module->compiled;
-
- parent = node->parent;
-
- /* parent's first child */
- if (parent && lysc_node_children(parent, node->flags) == node) {
- *lysc_node_children_p(parent, node->flags) = node->next;
- } else if (modc->data == node) {
- modc->data = node->next;
- }
-
- /* special choice case unlinking */
- if (parent && parent->nodetype == LYS_CHOICE) {
- if (((struct lysc_node_choice *)parent)->dflt == (struct lysc_node_case *)node) {
- /* default case removed */
- ((struct lysc_node_choice *)parent)->dflt = NULL;
- }
- }
-
- /* siblings */
- if (node->prev->next) {
- node->prev->next = node->next;
- }
- if (node->next) {
- node->next->prev = node->prev;
- } else {
- /* last child */
- if (parent) {
- child = (struct lysc_node *)lysc_node_children(parent, node->flags);
- } else {
- child = modc->data;
- }
- if (child) {
- child->prev = node->prev;
- }
- }
-}
-
-struct lysc_deviation {
- const char *nodeid;
- struct lysc_node *target; /* target node of the deviation */
- struct lysp_deviate **deviates;/* sized array of pointers to parsed deviate statements to apply on target */
- uint16_t flags; /* target's flags from lysc_resolve_schema_nodeid() */
- ly_bool not_supported; /* flag if deviates contains not-supported deviate */
-};
-
-/* MACROS for deviates checking */
-#define DEV_CHECK_NODETYPE(NODETYPES, DEVTYPE, PROPERTY) \
- if (!(target->nodetype & (NODETYPES))) { \
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE, lys_nodetype2str(target->nodetype), DEVTYPE, PROPERTY);\
- goto cleanup; \
- }
-
-#define DEV_CHECK_CARDINALITY(ARRAY, MAX, PROPERTY) \
- if (LY_ARRAY_COUNT(ARRAY) > MAX) { \
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid deviation of %s with too many (%"LY_PRI_ARRAY_COUNT_TYPE") %s properties.", \
- lys_nodetype2str(target->nodetype), LY_ARRAY_COUNT(ARRAY), PROPERTY); \
- goto cleanup; \
- }
-
-#define DEV_CHECK_PRESENCE(TYPE, COND, MEMBER, DEVTYPE, PROPERTY, VALUE) \
- if (!((TYPE)target)->MEMBER || COND) { \
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
- goto cleanup; \
- }
-
/**
- * @brief Apply deviate add.
+ * @brief Add a module reference into an array, checks for duplicities.
*
* @param[in] ctx Compile context.
- * @param[in] target Deviation target.
- * @param[in] dev_flags Internal deviation flags.
- * @param[in] d Deviate add to apply.
+ * @param[in] mod Module reference to add.
+ * @param[in,out] mod_array Module sized array to add to.
* @return LY_ERR value.
*/
static LY_ERR
-lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysc_node *target, uint32_t dev_flags, struct lysp_deviate_add *d)
+lys_array_add_mod_ref(struct lysc_ctx *ctx, struct lys_module *mod, struct lys_module ***mod_array)
{
- LY_ERR ret = LY_EVALID, rc = LY_SUCCESS;
- struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)target;
- struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)target;
- LY_ARRAY_COUNT_TYPE x;
+ LY_ARRAY_COUNT_TYPE u;
+ struct lys_module **new_mod;
-#define DEV_CHECK_NONPRESENCE_UINT(TYPE, COND, MEMBER, PROPERTY) \
- if (((TYPE)target)->MEMBER COND) { \
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
- "Invalid deviation adding \"%s\" property which already exists (with value \"%u\").", \
- PROPERTY, ((TYPE)target)->MEMBER); \
- goto cleanup; \
- }
-
-#define DEV_CHECK_NONPRESENCE_VALUE(TYPE, COND, MEMBER, PROPERTY, VALUEMEMBER) \
- if (((TYPE)target)->MEMBER && (COND)) { \
- ly_bool dynamic_ = 0; const char *val_; \
- val_ = ((TYPE)target)->VALUEMEMBER->realtype->plugin->print(((TYPE)target)->VALUEMEMBER, LY_PREF_SCHEMA, \
- ctx->mod_def, &dynamic_); \
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
- "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", PROPERTY, val_); \
- if (dynamic_) {free((void*)val_);} \
- goto cleanup; \
- }
-
-#define DEV_CHECK_NONPRESENCE(TYPE, COND, MEMBER, PROPERTY, VALUEMEMBER) \
- if (((TYPE)target)->MEMBER && (COND)) { \
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
- "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", \
- PROPERTY, ((TYPE)target)->VALUEMEMBER); \
- goto cleanup; \
- }
-
- /* [units-stmt] */
- if (d->units) {
- DEV_CHECK_NODETYPE(LYS_LEAF | LYS_LEAFLIST, "add", "units");
- DEV_CHECK_NONPRESENCE(struct lysc_node_leaf *, (target->flags & LYS_SET_UNITS), units, "units", units);
-
- FREE_STRING(ctx->ctx, ((struct lysc_node_leaf *)target)->units);
- DUP_STRING(ctx->ctx, d->units, ((struct lysc_node_leaf *)target)->units, rc);
- LY_CHECK_ERR_GOTO(rc, ret = rc, cleanup);
- }
-
- /* *must-stmt */
- if (d->musts) {
- switch (target->nodetype) {
- case LYS_CONTAINER:
- case LYS_LIST:
- COMPILE_ARRAY_GOTO(ctx, d->musts, ((struct lysc_node_container *)target)->musts,
- x, lys_compile_must, ret, cleanup);
- break;
- case LYS_LEAF:
- case LYS_LEAFLIST:
- case LYS_ANYDATA:
- COMPILE_ARRAY_GOTO(ctx, d->musts, ((struct lysc_node_leaf *)target)->musts,
- x, lys_compile_must, ret, cleanup);
- break;
- case LYS_NOTIF:
- COMPILE_ARRAY_GOTO(ctx, d->musts, ((struct lysc_notif *)target)->musts,
- x, lys_compile_must, ret, cleanup);
- break;
- case LYS_RPC:
- case LYS_ACTION:
- if (dev_flags & LYSC_OPT_RPC_INPUT) {
- COMPILE_ARRAY_GOTO(ctx, d->musts, ((struct lysc_action *)target)->input.musts,
- x, lys_compile_must, ret, cleanup);
- break;
- } else if (dev_flags & LYSC_OPT_RPC_OUTPUT) {
- COMPILE_ARRAY_GOTO(ctx, d->musts, ((struct lysc_action *)target)->output.musts,
- x, lys_compile_must, ret, cleanup);
- break;
- }
- /* fall through */
- default:
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
- lys_nodetype2str(target->nodetype), "add", "must");
- goto cleanup;
- }
- ret = ly_set_add(&ctx->xpath, target, 0, NULL);
- LY_CHECK_GOTO(ret, cleanup);
- }
-
- /* *unique-stmt */
- if (d->uniques) {
- DEV_CHECK_NODETYPE(LYS_LIST, "add", "unique");
- LY_CHECK_GOTO(lys_compile_node_list_unique(ctx, ctx->mod, d->uniques, (struct lysc_node_list *)target), cleanup);
- }
-
- /* *default-stmt */
- if (d->dflts) {
- switch (target->nodetype) {
- case LYS_LEAF:
- DEV_CHECK_CARDINALITY(d->dflts, 1, "default");
- DEV_CHECK_NONPRESENCE_VALUE(struct lysc_node_leaf *, (target->flags & LYS_SET_DFLT), dflt, "default", dflt);
- if (leaf->dflt) {
- /* first, remove the default value taken from the type */
- leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
- lysc_type_free(ctx->ctx, leaf->dflt->realtype);
- free(leaf->dflt);
- leaf->dflt = NULL;
- }
-
- /* store the default value in unres */
- LY_CHECK_GOTO(lysc_incomplete_leaf_dflt_add(ctx, leaf, d->dflts[0], ctx->mod_def), cleanup);
- target->flags |= LYS_SET_DFLT;
- break;
- case LYS_LEAFLIST:
- if (llist->dflts && !(target->flags & LYS_SET_DFLT)) {
- /* first, remove the default value taken from the type */
- LY_ARRAY_FOR(llist->dflts, x) {
- llist->dflts[x]->realtype->plugin->free(ctx->ctx, llist->dflts[x]);
- lysc_type_free(ctx->ctx, llist->dflts[x]->realtype);
- free(llist->dflts[x]);
- }
- LY_ARRAY_FREE(llist->dflts);
- llist->dflts = NULL;
- }
-
- /* store the default values in unres */
- LY_CHECK_GOTO(lysc_incomplete_llist_dflts_add(ctx, llist, d->dflts, ctx->mod_def), cleanup);
- target->flags |= LYS_SET_DFLT;
- break;
- case LYS_CHOICE:
- DEV_CHECK_CARDINALITY(d->dflts, 1, "default");
- DEV_CHECK_NONPRESENCE(struct lysc_node_choice *, 1, dflt, "default", dflt->name);
- /* in contrast to delete, here we strictly resolve the prefix in the module of the deviation
- * to allow making the default case even the augmented case from the deviating module */
- if (lys_compile_deviation_set_choice_dflt(ctx, d->dflts[0], (struct lysc_node_choice *)target)) {
- goto cleanup;
- }
- break;
- default:
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
- lys_nodetype2str(target->nodetype), "add", "default");
- goto cleanup;
+ LY_ARRAY_FOR(*mod_array, u) {
+ if ((*mod_array)[u] == mod) {
+ /* already there */
+ return LY_EEXIST;
}
}
- /* [config-stmt] */
- if (d->flags & LYS_CONFIG_MASK) {
- if (target->nodetype & (LYS_CASE | LYS_INOUT | LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
- lys_nodetype2str(target->nodetype), "add", "config");
- goto cleanup;
- }
- if (dev_flags) {
- LOGWRN(ctx->ctx, "Deviating config inside %s has no effect.",
- dev_flags & LYSC_OPT_NOTIFICATION ? "notification" : "RPC/action");
- }
- if (target->flags & LYS_SET_CONFIG) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Invalid deviation adding \"config\" property which already exists (with value \"config %s\").",
- target->flags & LYS_CONFIG_W ? "true" : "false");
- goto cleanup;
- }
- LY_CHECK_GOTO(lys_compile_change_config(ctx, target, d->flags, 0, 0), cleanup);
- }
-
- /* [mandatory-stmt] */
- if (d->flags & LYS_MAND_MASK) {
- if (target->flags & LYS_MAND_MASK) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory %s\").",
- target->flags & LYS_MAND_TRUE ? "true" : "false");
- goto cleanup;
- }
- LY_CHECK_GOTO(lys_compile_change_mandatory(ctx, target, d->flags, 0), cleanup);
- }
-
- /* [min-elements-stmt] */
- if (d->flags & LYS_SET_MIN) {
- if (target->nodetype == LYS_LEAFLIST) {
- DEV_CHECK_NONPRESENCE_UINT(struct lysc_node_leaflist *, > 0, min, "min-elements");
- /* change value */
- ((struct lysc_node_leaflist *)target)->min = d->min;
- } else if (target->nodetype == LYS_LIST) {
- DEV_CHECK_NONPRESENCE_UINT(struct lysc_node_list *, > 0, min, "min-elements");
- /* change value */
- ((struct lysc_node_list *)target)->min = d->min;
- } else {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
- lys_nodetype2str(target->nodetype), "add", "min-elements");
- goto cleanup;
- }
- if (d->min) {
- target->flags |= LYS_MAND_TRUE;
- }
- }
-
- /* [max-elements-stmt] */
- if (d->flags & LYS_SET_MAX) {
- if (target->nodetype == LYS_LEAFLIST) {
- DEV_CHECK_NONPRESENCE_UINT(struct lysc_node_leaflist *, < (uint32_t)-1, max, "max-elements");
- /* change value */
- ((struct lysc_node_leaflist *)target)->max = d->max ? d->max : (uint32_t)-1;
- } else if (target->nodetype == LYS_LIST) {
- DEV_CHECK_NONPRESENCE_UINT(struct lysc_node_list *, < (uint32_t)-1, max, "max-elements");
- /* change value */
- ((struct lysc_node_list *)target)->max = d->max ? d->max : (uint32_t)-1;
- } else {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
- lys_nodetype2str(target->nodetype), "add", "max-elements");
- goto cleanup;
- }
- }
-
- ret = LY_SUCCESS;
-
-cleanup:
- return ret;
-}
-
-static LY_ERR
-lys_apply_deviate_delete_leaf_dflt(struct lysc_ctx *ctx, struct lysc_node *target, const char *dflt)
-{
- struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)target;
- ly_bool dyn = 0;
- const char *orig_dflt;
- uint32_t i;
-
- if (target->module != ctx->mod) {
- /* foreign deviation */
- DEV_CHECK_PRESENCE(struct lysc_node_leaf *, !(target->flags & LYS_SET_DFLT), dflt, "deleting", "default", dflt);
-
- /* check that the value matches */
- orig_dflt = leaf->dflt->realtype->plugin->print(leaf->dflt, LY_PREF_SCHEMA, ctx->mod_def, &dyn);
- if (strcmp(orig_dflt, dflt)) {
- goto error;
- }
- if (dyn) {
- free((char *)orig_dflt);
- }
-
- /* remove the default specification */
- leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
- lysc_type_free(ctx->ctx, leaf->dflt->realtype);
- free(leaf->dflt);
- leaf->dflt = NULL;
- } else {
- /* local deviation */
- DEV_CHECK_PRESENCE(struct lysc_node_leaf *, !(target->flags & LYS_SET_DFLT), name, "deleting", "default", dflt);
-
- /* find the incomplete default */
- orig_dflt = NULL;
- for (i = 0; i < ctx->dflts.count; ++i) {
- if (((struct lysc_incomplete_dflt *)ctx->dflts.objs[i])->leaf == leaf) {
- orig_dflt = ((struct lysc_incomplete_dflt *)ctx->dflts.objs[i])->dflt;
- break;
- }
- }
- LY_CHECK_ERR_RET(!orig_dflt, LOGINT(ctx->ctx), LY_EINT);
-
- /* check that the value matches */
- if (strcmp(orig_dflt, dflt)) {
- goto error;
- }
-
- /* update the list of incomplete default values */
- lysc_incomplete_dflt_remove(ctx, target);
- }
-
- target->flags &= ~LYS_SET_DFLT;
- return LY_SUCCESS;
-
-error:
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Invalid deviation deleting \"default\" property \"%s\" which does not match the target's property value \"%s\".",
- dflt, orig_dflt);
- if (dyn) {
- free((char *)orig_dflt);
- }
-cleanup:
- return LY_EVALID;
-}
-
-static LY_ERR
-lys_apply_deviate_delete_llist_dflts(struct lysc_ctx *ctx, struct lysc_node *target, const char **dflts)
-{
- struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)target;
- ly_bool dyn = 0, found;
- const char *orig_dflt, **orig_dflts;
- uint32_t i;
- LY_ARRAY_COUNT_TYPE x, y;
-
- if (target->module != ctx->mod) {
- /* foreign deviation */
- DEV_CHECK_PRESENCE(struct lysc_node_leaflist *, 0, dflts, "deleting", "default", dflts[0]);
- LY_ARRAY_FOR(dflts, x) {
- found = 0;
- LY_ARRAY_FOR(llist->dflts, y) {
- orig_dflt = llist->type->plugin->print(llist->dflts[y], LY_PREF_SCHEMA, ctx->mod_def, &dyn);
- if (!strcmp(orig_dflt, dflts[x])) {
- if (dyn) {
- free((char *)orig_dflt);
- }
- found = 1;
- break;
- }
- if (dyn) {
- free((char *)orig_dflt);
- }
- }
- if (!found) {
- goto error;
- }
-
- /* update compiled default values */
- LY_ARRAY_DECREMENT(llist->dflts);
- llist->dflts[y]->realtype->plugin->free(ctx->ctx, llist->dflts[y]);
- lysc_type_free(ctx->ctx, llist->dflts[y]->realtype);
- free(llist->dflts[y]);
- memmove(&llist->dflts[y], &llist->dflts[y + 1], (LY_ARRAY_COUNT(llist->dflts) - y) * (sizeof *llist->dflts));
- }
- if (!LY_ARRAY_COUNT(llist->dflts)) {
- LY_ARRAY_FREE(llist->dflts);
- llist->dflts = NULL;
- llist->flags &= ~LYS_SET_DFLT;
- }
- } else {
- /* local deviation */
- orig_dflt = NULL;
- orig_dflts = NULL;
- for (i = 0; i < ctx->dflts.count; ++i) {
- if (((struct lysc_incomplete_dflt *)ctx->dflts.objs[i])->llist == llist) {
- orig_dflt = ((struct lysc_incomplete_dflt *)ctx->dflts.objs[i])->dflt;
- orig_dflts = ((struct lysc_incomplete_dflt *)ctx->dflts.objs[i])->dflts;
- break;
- }
- }
- LY_CHECK_ERR_RET(!orig_dflt && !orig_dflts, LOGINT(ctx->ctx), LY_EINT);
-
- if (orig_dflts && (LY_ARRAY_COUNT(orig_dflts) > 1)) {
- /* TODO it is not currently possible to remove just one default value from incomplete defaults array */
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Local deviation deleting leaf-list defaults is not supported.");
- return LY_EVALID;
- }
-
- LY_ARRAY_FOR(dflts, x) {
- found = 0;
- if (orig_dflts) {
- LY_ARRAY_FOR(orig_dflts, y) {
- if (!strcmp(orig_dflts[y], dflts[x])) {
- found = 1;
- break;
- }
- }
- } else if (!strcmp(orig_dflt, dflts[x])) {
- found = 1;
- }
- if (!found) {
- goto error;
- }
-
- /* update the list of incomplete default values */
- lysc_incomplete_dflt_remove(ctx, target);
- }
-
- llist->flags &= ~LYS_SET_DFLT;
- }
+ /* add the new module ref */
+ LY_ARRAY_NEW_RET(ctx->ctx, *mod_array, new_mod, LY_EMEM);
+ *new_mod = mod;
return LY_SUCCESS;
-
-error:
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid deviation deleting \"default\" property \"%s\" "
- "which does not match any of the target's property values.", dflts[x]);
-cleanup:
- return LY_EVALID;
}
/**
- * @brief Apply deviate delete.
+ * @brief Compile top-level augments and deviations defined in the current module.
+ * Generally, just add the module refence to the target modules.
*
* @param[in] ctx Compile context.
- * @param[in] target Deviation target.
- * @param[in] dev_flags Internal deviation flags.
- * @param[in] d Deviate delete to apply.
* @return LY_ERR value.
*/
static LY_ERR
-lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysc_node *target, uint32_t dev_flags, struct lysp_deviate_del *d)
+lys_precompile_augments_deviations(struct lysc_ctx *ctx)
{
- LY_ERR ret = LY_EVALID;
- struct lysc_node_list *list = (struct lysc_node_list *)target;
- LY_ARRAY_COUNT_TYPE x, y, z;
- size_t prefix_len, name_len;
- const char *prefix, *name, *nodeid;
+ 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;
+ ly_bool has_dev = 0;
+ uint16_t flags;
+ uint32_t idx, opt_prev = ctx->options;
-#define DEV_DEL_ARRAY(TYPE, ARRAY_TRG, ARRAY_DEV, VALMEMBER, VALMEMBER_CMP, DELFUNC_DEREF, DELFUNC, PROPERTY) \
- DEV_CHECK_PRESENCE(TYPE, 0, ARRAY_TRG, "deleting", PROPERTY, d->ARRAY_DEV[0]VALMEMBER); \
- LY_ARRAY_FOR(d->ARRAY_DEV, x) { \
- LY_ARRAY_FOR(((TYPE)target)->ARRAY_TRG, y) { \
- if (!strcmp(((TYPE)target)->ARRAY_TRG[y]VALMEMBER_CMP, d->ARRAY_DEV[x]VALMEMBER)) { break; } \
- } \
- if (y == LY_ARRAY_COUNT(((TYPE)target)->ARRAY_TRG)) { \
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
- "Invalid deviation deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
- PROPERTY, d->ARRAY_DEV[x]VALMEMBER); \
- goto cleanup; \
- } \
- LY_ARRAY_DECREMENT(((TYPE)target)->ARRAY_TRG); \
- DELFUNC(ctx->ctx, DELFUNC_DEREF((TYPE)target)->ARRAY_TRG[y]); \
- memmove(&((TYPE)target)->ARRAY_TRG[y], \
- &((TYPE)target)->ARRAY_TRG[y + 1], \
- (LY_ARRAY_COUNT(((TYPE)target)->ARRAY_TRG) - y) * (sizeof *((TYPE)target)->ARRAY_TRG)); \
- } \
- if (!LY_ARRAY_COUNT(((TYPE)target)->ARRAY_TRG)) { \
- LY_ARRAY_FREE(((TYPE)target)->ARRAY_TRG); \
- ((TYPE)target)->ARRAY_TRG = NULL; \
+ mod_p = ctx->mod->parsed;
+
+ if (mod_p->mod->implemented == 1) {
+ /* it was already implemented and all the augments and deviations fully applied */
+ return LY_SUCCESS;
}
- /* [units-stmt] */
- if (d->units) {
- DEV_CHECK_NODETYPE(LYS_LEAF | LYS_LEAFLIST, "delete", "units");
- DEV_CHECK_PRESENCE(struct lysc_node_leaf *, 0, units, "deleting", "units", d->units);
- if (strcmp(((struct lysc_node_leaf *)target)->units, d->units)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Invalid deviation deleting \"units\" property \"%s\" which does not match the target's property value \"%s\".",
- d->units, ((struct lysc_node_leaf *)target)->units);
- goto cleanup;
- }
- lydict_remove(ctx->ctx, ((struct lysc_node_leaf *)target)->units);
- ((struct lysc_node_leaf *)target)->units = NULL;
- }
+ LY_ARRAY_FOR(mod_p->augments, u) {
+ lysc_update_path(ctx, NULL, "{augment}");
+ lysc_update_path(ctx, NULL, mod_p->augments[u].nodeid);
- /* *must-stmt */
- if (d->musts) {
- switch (target->nodetype) {
- case LYS_CONTAINER:
- case LYS_LIST:
- DEV_DEL_ARRAY(struct lysc_node_container *, musts, musts, .arg, .cond->expr, &, lysc_must_free, "must");
- break;
- case LYS_LEAF:
- case LYS_LEAFLIST:
- case LYS_ANYDATA:
- DEV_DEL_ARRAY(struct lysc_node_leaf *, musts, musts, .arg, .cond->expr, &, lysc_must_free, "must");
- break;
- case LYS_NOTIF:
- DEV_DEL_ARRAY(struct lysc_notif *, musts, musts, .arg, .cond->expr, &, lysc_must_free, "must");
- break;
- case LYS_RPC:
- case LYS_ACTION:
- if (dev_flags & LYSC_OPT_RPC_INPUT) {
- DEV_DEL_ARRAY(struct lysc_action *, input.musts, musts, .arg, .cond->expr, &, lysc_must_free, "must");
- break;
- } else if (dev_flags & LYSC_OPT_RPC_OUTPUT) {
- DEV_DEL_ARRAY(struct lysc_action *, output.musts, musts, .arg, .cond->expr, &, lysc_must_free, "must");
- break;
- }
- /* fall through */
- default:
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
- lys_nodetype2str(target->nodetype), "delete", "must");
- goto cleanup;
- }
- }
+ /* get target module */
+ ret = lys_nodeid_check(ctx, mod_p->augments[u].nodeid, 1, &mod, NULL);
+ LY_CHECK_RET(ret);
- /* *unique-stmt */
- if (d->uniques) {
- DEV_CHECK_NODETYPE(LYS_LIST, "delete", "unique");
- LY_ARRAY_FOR(d->uniques, x) {
- LY_ARRAY_FOR(list->uniques, z) {
- for (name = d->uniques[x], y = 0; name; name = nodeid, ++y) {
- nodeid = strpbrk(name, " \t\n");
- if (nodeid) {
- if (ly_strncmp(list->uniques[z][y]->name, name, nodeid - name)) {
- break;
- }
- while (isspace(*nodeid)) {
- ++nodeid;
- }
- } else {
- if (strcmp(name, list->uniques[z][y]->name)) {
- break;
- }
- }
- }
- if (!name) {
- /* complete match - remove the unique */
- LY_ARRAY_DECREMENT(list->uniques);
- LY_ARRAY_FREE(list->uniques[z]);
- memmove(&list->uniques[z], &list->uniques[z + 1], (LY_ARRAY_COUNT(list->uniques) - z) * (sizeof *list->uniques));
- --z;
- break;
- }
- }
- if (!list->uniques || z == LY_ARRAY_COUNT(list->uniques)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Invalid deviation deleting \"unique\" property \"%s\" which does not match any of the target's property values.",
- d->uniques[x]);
- goto cleanup;
- }
- }
- if (!LY_ARRAY_COUNT(list->uniques)) {
- LY_ARRAY_FREE(list->uniques);
- list->uniques = NULL;
- }
- }
+ /* add this module into the target module augmented_by, if not there already from previous augments */
+ lys_array_add_mod_ref(ctx, ctx->mod, &mod->augmented_by);
- /* *default-stmt */
- if (d->dflts) {
- switch (target->nodetype) {
- case LYS_LEAF:
- DEV_CHECK_CARDINALITY(d->dflts, 1, "default");
- LY_CHECK_GOTO(lys_apply_deviate_delete_leaf_dflt(ctx, target, d->dflts[0]), cleanup);
- break;
- case LYS_LEAFLIST:
- LY_CHECK_GOTO(lys_apply_deviate_delete_llist_dflts(ctx, target, d->dflts), cleanup);
- break;
- case LYS_CHOICE:
- DEV_CHECK_CARDINALITY(d->dflts, 1, "default");
- DEV_CHECK_PRESENCE(struct lysc_node_choice *, 0, dflt, "deleting", "default", d->dflts[0]);
- nodeid = d->dflts[0];
- LY_CHECK_GOTO(ly_parse_nodeid(&nodeid, &prefix, &prefix_len, &name, &name_len), cleanup);
- if (prefix) {
- /* use module prefixes from the deviation module to match the module of the default case */
- if (!(mod = lys_module_find_prefix(ctx->mod, prefix, prefix_len))) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Invalid deviation deleting \"default\" property \"%s\" of choice. "
- "The prefix does not match any imported module of the deviation module.", d->dflts[0]);
- goto cleanup;
- }
- if (mod != ((struct lysc_node_choice *)target)->dflt->module) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Invalid deviation deleting \"default\" property \"%s\" of choice. "
- "The prefix does not match the default case's module.", d->dflts[0]);
- goto cleanup;
- }
- }
- /* else {
- * strictly, the default prefix would point to the deviation module, but the value should actually
- * match the default string in the original module (usually unprefixed), so in this case we do not check
- * the module of the default case, just matching its name */
- if (strcmp(name, ((struct lysc_node_choice *)target)->dflt->name)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Invalid deviation deleting \"default\" property \"%s\" of choice does not match the default case name \"%s\".",
- d->dflts[0], ((struct lysc_node_choice *)target)->dflt->name);
- goto cleanup;
- }
- ((struct lysc_node_choice *)target)->dflt->flags &= ~LYS_SET_DFLT;
- ((struct lysc_node_choice *)target)->dflt = NULL;
- break;
- default:
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
- lys_nodetype2str(target->nodetype), "delete", "default");
- goto cleanup;
- }
- }
-
- ret = LY_SUCCESS;
-
-cleanup:
- return ret;
-}
-
-static LY_ERR
-lys_apply_deviate_replace_dflt_recompile(struct lysc_ctx *ctx, struct lysc_node *target)
-{
- LY_ERR ret;
- struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)target;
- struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)target;
- struct ly_err_item *err = NULL;
- LY_ARRAY_COUNT_TYPE x;
- const char *dflt;
- ly_bool dyn;
-
- if (target->module != ctx->mod) {
- /* foreign deviation */
- if (target->nodetype == LYS_LEAF) {
- dflt = leaf->dflt->realtype->plugin->print(leaf->dflt, LY_PREF_JSON, NULL, &dyn);
- leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
- lysc_type_free(ctx->ctx, leaf->dflt->realtype);
-
- ret = leaf->type->plugin->store(ctx->ctx, leaf->type, dflt, strlen(dflt), LY_TYPE_OPTS_SCHEMA,
- LY_PREF_JSON, NULL, target, NULL, leaf->dflt, &err);
- if (dyn) {
- free((char *)dflt);
- }
- if (err) {
- ly_err_print(err);
- ctx->path[0] = '\0';
- lysc_path(target, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid default - value does not fit the type (%s).", err->msg);
- ly_err_free(err);
- }
+ /* if we are compiling this module, we cannot add augments to it yet */
+ if (mod != ctx->mod) {
+ /* apply the augment, find the target node first */
+ flags = 0;
+ ret = lysc_resolve_schema_nodeid(ctx, mod_p->augments[u].nodeid, 0, NULL, ctx->mod_def, 0, &target, &flags);
LY_CHECK_RET(ret);
- ++leaf->dflt->realtype->refcount;
- } else { /* LY_LEAFLIST */
- LY_ARRAY_FOR(llist->dflts, x) {
- dflt = llist->dflts[x]->realtype->plugin->print(llist->dflts[x], LY_PREF_JSON, NULL, &dyn);
- llist->dflts[x]->realtype->plugin->free(ctx->ctx, llist->dflts[x]);
- lysc_type_free(ctx->ctx, llist->dflts[x]->realtype);
-
- ret = llist->type->plugin->store(ctx->ctx, llist->type, dflt, strlen(dflt), LY_TYPE_OPTS_SCHEMA,
- LY_PREF_JSON, NULL, target, NULL, llist->dflts[x], &err);
- if (dyn) {
- free((char *)dflt);
- }
- if (err) {
- ly_err_print(err);
- ctx->path[0] = '\0';
- lysc_path(target, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid default - value does not fit the type (%s).", err->msg);
- ly_err_free(err);
- }
- LY_CHECK_RET(ret);
-
- ++llist->dflts[x]->realtype->refcount;
- }
- }
- } else {
- /* local deviation */
-
- /* these default were not compiled yet, so they will use the new type automatically */
- }
-
- return LY_SUCCESS;
-}
-
-/**
- * @brief Apply deviate replace.
- *
- * @param[in] ctx Compile context.
- * @param[in] target Deviation target.
- * @param[in] d Deviate replace to apply.
- * @return LY_ERR value.
- */
-static LY_ERR
-lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysc_node *target, struct lysp_deviate_rpl *d)
-{
- LY_ERR ret = LY_EVALID, rc = LY_SUCCESS;
- struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)target;
- struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)target;
- LY_ARRAY_COUNT_TYPE x;
-
-#define DEV_CHECK_PRESENCE_UINT(TYPE, COND, MEMBER, PROPERTY) \
- if (!(((TYPE)target)->MEMBER COND)) { \
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
- "Invalid deviation replacing with \"%s\" property \"%u\" which is not present.", PROPERTY, d->MEMBER); \
- goto cleanup; \
- }
-
- /* [type-stmt] */
- if (d->type) {
- DEV_CHECK_NODETYPE(LYS_LEAF | LYS_LEAFLIST, "replace", "type");
- /* type is mandatory, so checking for its presence is not necessary */
- lysc_type_free(ctx->ctx, ((struct lysc_node_leaf *)target)->type);
-
- /* remove only default value inherited from the type */
- if (!(target->flags & LYS_SET_DFLT)) {
- if (target->module != ctx->mod) {
- /* foreign deviation - the target has default from the previous type, remove it */
- if (target->nodetype == LYS_LEAF) {
- leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
- lysc_type_free(ctx->ctx, leaf->dflt->realtype);
- free(leaf->dflt);
- leaf->dflt = NULL;
- } else { /* LYS_LEAFLIST */
- LY_ARRAY_FOR(llist->dflts, x) {
- llist->dflts[x]->realtype->plugin->free(ctx->ctx, llist->dflts[x]);
- lysc_type_free(ctx->ctx, llist->dflts[x]->realtype);
- free(llist->dflts[x]);
- }
- LY_ARRAY_FREE(llist->dflts);
- llist->dflts = NULL;
- }
- } else {
- /* local deviation */
- lysc_incomplete_dflt_remove(ctx, target);
- }
- }
-
- LY_CHECK_RET(lys_compile_node_type(ctx, NULL, d->type, leaf));
-
- if (target->flags & LYS_SET_DFLT) {
- /* the term default value(s) needs to be recompiled */
- LY_CHECK_RET(lys_apply_deviate_replace_dflt_recompile(ctx, target));
- }
- }
-
- /* [units-stmt] */
- if (d->units) {
- DEV_CHECK_NODETYPE(LYS_LEAF | LYS_LEAFLIST, "replace", "units");
- DEV_CHECK_PRESENCE(struct lysc_node_leaf *, !(target->flags & LYS_SET_UNITS),
- units, "replacing", "units", d->units);
-
- lydict_remove(ctx->ctx, leaf->units);
- DUP_STRING(ctx->ctx, d->units, leaf->units, rc);
- LY_CHECK_ERR_GOTO(rc, ret = rc, cleanup);
- }
-
- /* [default-stmt] */
- if (d->dflt) {
- switch (target->nodetype) {
- case LYS_LEAF:
- if (target->module != ctx->mod) {
- /* foreign deviation */
- DEV_CHECK_PRESENCE(struct lysc_node_leaf *, !(target->flags & LYS_SET_DFLT), dflt, "replacing",
- "default", d->dflt);
-
- /* remove the default specification */
- leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
- lysc_type_free(ctx->ctx, leaf->dflt->realtype);
- free(leaf->dflt);
- leaf->dflt = NULL;
- } else {
- /* local deviation */
- DEV_CHECK_PRESENCE(struct lysc_node_leaf *, !(target->flags & LYS_SET_DFLT), name, "replacing",
- "default", d->dflt);
- assert(!leaf->dflt);
- }
-
- /* store the new default value */
- LY_CHECK_RET(lysc_incomplete_leaf_dflt_add(ctx, leaf, d->dflt, ctx->mod_def));
- break;
- case LYS_CHOICE:
- DEV_CHECK_PRESENCE(struct lysc_node_choice *, 0, dflt, "replacing", "default", d->dflt);
- if (lys_compile_deviation_set_choice_dflt(ctx, d->dflt, (struct lysc_node_choice *)target)) {
- goto cleanup;
- }
- break;
- default:
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
- lys_nodetype2str(target->nodetype), "replace", "default");
- goto cleanup;
- }
- }
-
- /* [config-stmt] */
- if (d->flags & LYS_CONFIG_MASK) {
- if (target->nodetype & (LYS_CASE | LYS_INOUT | LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
- lys_nodetype2str(target->nodetype), "replace", "config");
- goto cleanup;
- }
- if (!(target->flags & LYS_SET_CONFIG)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT,
- "replacing", "config", d->flags & LYS_CONFIG_W ? "config true" : "config false");
- goto cleanup;
- }
- LY_CHECK_GOTO(lys_compile_change_config(ctx, target, d->flags, 0, 0), cleanup);
- }
-
- /* [mandatory-stmt] */
- if (d->flags & LYS_MAND_MASK) {
- if (!(target->flags & LYS_MAND_MASK)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT,
- "replacing", "mandatory", d->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
- goto cleanup;
- }
- LY_CHECK_GOTO(lys_compile_change_mandatory(ctx, target, d->flags, 0), cleanup);
- }
-
- /* [min-elements-stmt] */
- if (d->flags & LYS_SET_MIN) {
- if (target->nodetype == LYS_LEAFLIST) {
- DEV_CHECK_PRESENCE_UINT(struct lysc_node_leaflist *, > 0, min, "min-elements");
- /* change value */
- ((struct lysc_node_leaflist *)target)->min = d->min;
- } else if (target->nodetype == LYS_LIST) {
- DEV_CHECK_PRESENCE_UINT(struct lysc_node_list *, > 0, min, "min-elements");
- /* change value */
- ((struct lysc_node_list *)target)->min = d->min;
- } else {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
- lys_nodetype2str(target->nodetype), "replace", "min-elements");
- goto cleanup;
- }
- if (d->min) {
- target->flags |= LYS_MAND_TRUE;
- }
- }
-
- /* [max-elements-stmt] */
- if (d->flags & LYS_SET_MAX) {
- if (target->nodetype == LYS_LEAFLIST) {
- DEV_CHECK_PRESENCE_UINT(struct lysc_node_leaflist *, < (uint32_t)-1, max, "max-elements");
- /* change value */
- ((struct lysc_node_leaflist *)target)->max = d->max ? d->max : (uint32_t)-1;
- } else if (target->nodetype == LYS_LIST) {
- DEV_CHECK_PRESENCE_UINT(struct lysc_node_list *, < (uint32_t)-1, max, "max-elements");
- /* change value */
- ((struct lysc_node_list *)target)->max = d->max ? d->max : (uint32_t)-1;
- } else {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
- lys_nodetype2str(target->nodetype), "replace", "max-elements");
- goto cleanup;
- }
- }
-
- ret = LY_SUCCESS;
-
-cleanup:
- return ret;
-}
-
-/**
- * @brief Apply all deviations of one target node.
- *
- * @param[in] ctx Compile context.
- * @param[in] dev Deviation structure to apply.
- * @return LY_ERR value.
- */
-static LY_ERR
-lys_apply_deviation(struct lysc_ctx *ctx, struct lysc_deviation *dev)
-{
- LY_ERR ret = LY_EVALID;
- struct lysc_node *target = dev->target;
- struct lysc_action *rpcs;
- struct lysc_notif *notifs;
- struct lysp_deviate *d;
- LY_ARRAY_COUNT_TYPE v, x;
- uint32_t min, max;
-
- lysc_update_path(ctx, NULL, dev->nodeid);
-
- /* not-supported */
- if (dev->not_supported) {
- if (LY_ARRAY_COUNT(dev->deviates) > 1) {
- LOGWRN(ctx->ctx, "Useless multiple (%"LY_PRI_ARRAY_COUNT_TYPE ") deviates on node \"%s\" since the node is not-supported.",
- LY_ARRAY_COUNT(dev->deviates), dev->nodeid);
- }
-
-#define REMOVE_NONDATA(ARRAY, TYPE, GETFUNC, FREEFUNC) \
- if (target->parent) { \
- ARRAY = (TYPE*)GETFUNC(target->parent); \
- } else { \
- ARRAY = target->module->compiled->ARRAY; \
- } \
- LY_ARRAY_FOR(ARRAY, x) { \
- if (&ARRAY[x] == (TYPE*)target) { break; } \
- } \
- if (x < LY_ARRAY_COUNT(ARRAY)) { \
- FREEFUNC(ctx->ctx, &ARRAY[x]); \
- memmove(&ARRAY[x], &ARRAY[x + 1], (LY_ARRAY_COUNT(ARRAY) - (x + 1)) * sizeof *ARRAY); \
- LY_ARRAY_DECREMENT(ARRAY); \
- }
-
- if (target->nodetype & (LYS_RPC | LYS_ACTION)) {
- if (dev->flags & LYSC_OPT_RPC_INPUT) {
- /* remove RPC's/action's input */
- lysc_action_inout_free(ctx->ctx, &((struct lysc_action *)target)->input);
- memset(&((struct lysc_action *)target)->input, 0, sizeof ((struct lysc_action *)target)->input);
- FREE_ARRAY(ctx->ctx, ((struct lysc_action *)target)->input_exts, lysc_ext_instance_free);
- ((struct lysc_action *)target)->input_exts = NULL;
- } else if (dev->flags & LYSC_OPT_RPC_OUTPUT) {
- /* remove RPC's/action's output */
- lysc_action_inout_free(ctx->ctx, &((struct lysc_action *)target)->output);
- memset(&((struct lysc_action *)target)->output, 0, sizeof ((struct lysc_action *)target)->output);
- FREE_ARRAY(ctx->ctx, ((struct lysc_action *)target)->output_exts, lysc_ext_instance_free);
- ((struct lysc_action *)target)->output_exts = NULL;
- } else {
- /* remove RPC/action */
- REMOVE_NONDATA(rpcs, struct lysc_action, lysc_node_actions, lysc_action_free);
- }
- } else if (target->nodetype == LYS_NOTIF) {
- /* remove Notification */
- REMOVE_NONDATA(notifs, struct lysc_notif, lysc_node_notifs, lysc_notif_free);
- } else {
- if (target->parent && (target->parent->nodetype == LYS_CASE) && (target->prev == target)) {
- /* remove the target node with its parent case node because it is the only node of the case */
- lysc_node_unlink(target->parent);
- lysc_node_free(ctx->ctx, target->parent);
- } else {
- /* remove the target node */
- lysc_node_unlink(target);
- lysc_node_free(ctx->ctx, target);
- }
- }
-
- /* mark the context for later re-compilation of objects that could reference the curently removed node */
- ctx->ctx->flags |= LY_CTX_CHANGED_TREE;
- return LY_SUCCESS;
- }
-
- /* list of deviates (not-supported is not present in the list) */
- LY_ARRAY_FOR(dev->deviates, v) {
- d = dev->deviates[v];
- switch (d->mod) {
- case LYS_DEV_ADD:
- LY_CHECK_GOTO(lys_apply_deviate_add(ctx, target, dev->flags, (struct lysp_deviate_add *)d), cleanup);
- break;
- case LYS_DEV_DELETE:
- LY_CHECK_GOTO(lys_apply_deviate_delete(ctx, target, dev->flags, (struct lysp_deviate_del *)d), cleanup);
- break;
- case LYS_DEV_REPLACE:
- LY_CHECK_GOTO(lys_apply_deviate_replace(ctx, target, (struct lysp_deviate_rpl *)d), cleanup);
- break;
- default:
- LOGINT(ctx->ctx);
- goto cleanup;
- }
- }
-
- /* final check when all deviations of a single target node are applied */
-
- /* check min-max compatibility */
- if (target->nodetype == LYS_LEAFLIST) {
- min = ((struct lysc_node_leaflist *)target)->min;
- max = ((struct lysc_node_leaflist *)target)->max;
- } else if (target->nodetype == LYS_LIST) {
- min = ((struct lysc_node_list *)target)->min;
- max = ((struct lysc_node_list *)target)->max;
- } else {
- min = max = 0;
- }
- if (min > max) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid combination of min-elements and max-elements "
- "after deviation: min value %u is bigger than max value %u.", min, max);
- goto cleanup;
- }
-
- /* check mandatory - default compatibility */
- if ((target->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (target->flags & LYS_SET_DFLT)
- && (target->flags & LYS_MAND_TRUE)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid deviation combining default value and mandatory %s.", lys_nodetype2str(target->nodetype));
- goto cleanup;
- } else if ((target->nodetype & LYS_CHOICE) && ((struct lysc_node_choice *)target)->dflt
- && (target->flags & LYS_MAND_TRUE)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid deviation combining default case and mandatory choice.");
- goto cleanup;
- }
- if (target->parent && (target->parent->flags & LYS_SET_DFLT) && (target->flags & LYS_MAND_TRUE)) {
- /* mandatory node under a default case */
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid deviation combining mandatory %s \"%s\" in a default choice's case \"%s\".",
- lys_nodetype2str(target->nodetype), target->name, target->parent->name);
- goto cleanup;
- }
-
- /* success */
- ret = LY_SUCCESS;
-
-cleanup:
- lysc_update_path(ctx, NULL, NULL);
- return ret;
-}
-
-LY_ERR
-lys_compile_deviations(struct lysc_ctx *ctx, struct lysp_module *mod_p)
-{
- LY_ERR ret = LY_EVALID;
- struct ly_set devs_p = {0};
- struct ly_set targets = {0};
- struct lysc_node *target; /* target target of the deviation */
- struct lysp_deviation *dev;
- struct lysp_deviate *d, **dp_new;
- LY_ARRAY_COUNT_TYPE u, v;
- struct lysc_deviation **devs = NULL;
- struct lys_module *target_mod, **dev_mod;
- uint16_t flags;
-
- /* get all deviations from the module and all its submodules ... */
- LY_ARRAY_FOR(mod_p->deviations, u) {
- LY_CHECK_RET(ly_set_add(&devs_p, &mod_p->deviations[u], LY_SET_OPT_USEASLIST, NULL));
- }
- LY_ARRAY_FOR(mod_p->includes, v) {
- LY_ARRAY_FOR(mod_p->includes[v].submodule->deviations, u) {
- LY_CHECK_RET(ly_set_add(&devs_p, &mod_p->includes[v].submodule->deviations[u], LY_SET_OPT_USEASLIST, NULL));
- }
- }
- if (!devs_p.count) {
- /* nothing to do */
- return LY_SUCCESS;
- }
-
- lysc_update_path(ctx, NULL, "{deviation}");
-
- /* ... and group them by the target node */
- devs = calloc(devs_p.count, sizeof *devs);
- for (u = 0; u < devs_p.count; ++u) {
- uint32_t index;
-
- dev = devs_p.objs[u];
- lysc_update_path(ctx, NULL, dev->nodeid);
-
- /* resolve the target */
- LY_CHECK_GOTO(lysc_resolve_schema_nodeid(ctx, dev->nodeid, 0, NULL, ctx->mod, 0, 1,
- (const struct lysc_node **)&target, &flags), cleanup);
- if (target->nodetype & (LYS_RPC | LYS_ACTION)) {
- /* move the target pointer to input/output to make them different from the action and
- * between them. Before the devs[] item is being processed, the target pointer must be fixed
- * back to the RPC/action node due to a better compatibility and decision code in this function.
- * The LYSC_OPT_INTERNAL is used as a flag to this change. */
- if (flags & LYSC_OPT_RPC_INPUT) {
- target = (struct lysc_node *)&((struct lysc_action *)target)->input;
- flags |= LYSC_OPT_INTERNAL;
- } else if (flags & LYSC_OPT_RPC_OUTPUT) {
- target = (struct lysc_node *)&((struct lysc_action *)target)->output;
- flags |= LYSC_OPT_INTERNAL;
- }
- }
- /* insert into the set of targets with duplicity detection */
- ret = ly_set_add(&targets, target, 0, &index);
- LY_CHECK_GOTO(ret, cleanup);
- if (!devs[index]) {
- /* new record */
- devs[index] = calloc(1, sizeof **devs);
- devs[index]->target = target;
- devs[index]->nodeid = dev->nodeid;
- devs[index]->flags = flags;
- }
- /* add deviates into the deviation's list of deviates */
- LY_LIST_FOR(dev->deviates, d) {
- LY_ARRAY_NEW_GOTO(ctx->ctx, devs[index]->deviates, dp_new, ret, cleanup);
- *dp_new = d;
- if (d->mod == LYS_DEV_NOT_SUPPORTED) {
- devs[index]->not_supported = 1;
- }
+ /* apply the augment */
+ ctx->options |= flags;
+ ret = lys_compile_augment(ctx, &mod_p->augments[u], (struct lysc_node *)target);
+ ctx->options = opt_prev;
+ LY_CHECK_RET(ret);
}
lysc_update_path(ctx, NULL, NULL);
+ lysc_update_path(ctx, NULL, NULL);
}
- /* apply deviations */
- for (u = 0; u < devs_p.count && devs[u]; ++u) {
- ly_bool match = 0;
+ 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);
+ lysc_update_path(ctx, NULL, NULL);
+ lysc_update_path(ctx, NULL, NULL);
+ LY_CHECK_RET(ret);
- if (devs[u]->flags & LYSC_OPT_INTERNAL) {
- /* fix the target pointer in case of RPC's/action's input/output */
- if (devs[u]->flags & LYSC_OPT_RPC_INPUT) {
- devs[u]->target = (struct lysc_node *)((char *)devs[u]->target - offsetof(struct lysc_action, input));
- } else if (devs[u]->flags & LYSC_OPT_RPC_OUTPUT) {
- devs[u]->target = (struct lysc_node *)((char *)devs[u]->target - offsetof(struct lysc_action, output));
+ /* add this module into the target module deviated_by, if not there already from previous deviations */
+ lys_array_add_mod_ref(ctx, ctx->mod, &mod->deviated_by);
+
+ /* new deviation added to the target module */
+ has_dev = 1;
+ }
+
+ /* the same for augments and deviations in submodules */
+ LY_ARRAY_FOR(mod_p->includes, v) {
+ submod = mod_p->includes[v].submodule;
+ LY_ARRAY_FOR(submod->augments, u) {
+ lysc_update_path(ctx, NULL, "{augment}");
+ lysc_update_path(ctx, NULL, submod->augments[u].nodeid);
+
+ ret = lys_nodeid_check(ctx, submod->augments[u].nodeid, 1, &mod, NULL);
+ LY_CHECK_RET(ret);
+
+ lys_array_add_mod_ref(ctx, ctx->mod, &mod->augmented_by);
+ if (mod != ctx->mod) {
+ flags = 0;
+ ret = lysc_resolve_schema_nodeid(ctx, mod_p->augments[u].nodeid, 0, NULL, ctx->mod_def, 0, &target, &flags);
+ LY_CHECK_RET(ret);
+
+ ctx->options |= flags;
+ ret = lys_compile_augment(ctx, &submod->augments[u], (struct lysc_node *)target);
+ ctx->options = opt_prev;
+ LY_CHECK_RET(ret);
}
+
+ lysc_update_path(ctx, NULL, NULL);
+ lysc_update_path(ctx, NULL, NULL);
}
- /* remember target module (the target node may be removed) */
- target_mod = devs[u]->target->module;
+ 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);
+ lysc_update_path(ctx, NULL, NULL);
+ lysc_update_path(ctx, NULL, NULL);
+ LY_CHECK_RET(ret);
- /* apply the deviation */
- LY_CHECK_GOTO(ret = lys_apply_deviation(ctx, devs[u]), cleanup);
-
- /* add this module into the target module deviated_by, if not there already */
- LY_ARRAY_FOR(target_mod->compiled->deviated_by, v) {
- if (target_mod->compiled->deviated_by[v] == mod_p->mod) {
- match = 1;
- break;
- }
- }
- if (!match) {
- LY_ARRAY_NEW_GOTO(ctx->ctx, target_mod->compiled->deviated_by, dev_mod, ret, cleanup);
- *dev_mod = mod_p->mod;
+ lys_array_add_mod_ref(ctx, ctx->mod, &mod->deviated_by);
+ has_dev = 1;
}
}
- lysc_update_path(ctx, NULL, NULL);
- ret = LY_SUCCESS;
+ if (!has_dev) {
+ /* no need to recompile any modules */
+ return LY_SUCCESS;
+ }
+
+ /* free all the modules in descending order */
+ idx = ctx->ctx->list.count;
+ do {
+ --idx;
+ mod = ctx->ctx->list.objs[idx];
+ /* skip this module */
+ if (mod == mod_p->mod) {
+ continue;
+ }
+
+ if (mod->implemented && mod->compiled) {
+ /* keep information about features state in the module */
+ lys_feature_precompile_revert(ctx, mod);
+
+ /* free the module */
+ lysc_module_free(mod->compiled, NULL);
+ mod->compiled = NULL;
+ }
+ } while (idx);
+
+ /* recompile all the modules in ascending order */
+ for (idx = 0; idx < ctx->ctx->list.count; ++idx) {
+ mod = ctx->ctx->list.objs[idx];
+
+ /* skip this module */
+ if (mod == mod_p->mod) {
+ continue;
+ }
+
+ if (mod->implemented) {
+ /* compile */
+ LY_CHECK_GOTO(ret = lys_compile(mod, LYSC_OPT_INTERNAL), cleanup);
+ }
+ }
cleanup:
- for (u = 0; u < devs_p.count && devs[u]; ++u) {
- LY_ARRAY_FREE(devs[u]->deviates);
- free(devs[u]);
- }
- free(devs);
- ly_set_erase(&targets, NULL);
- ly_set_erase(&devs_p, NULL);
-
- return ret;
-}
-
-/**
- * @brief Compile the given YANG submodule into the main module.
- * @param[in] ctx Compile context
- * @param[in] inc Include structure from the main module defining the submodule.
- * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
- */
-LY_ERR
-lys_compile_submodule(struct lysc_ctx *ctx, struct lysp_include *inc)
-{
- LY_ARRAY_COUNT_TYPE u;
- LY_ERR ret = LY_SUCCESS;
- /* shortcuts */
- struct lysp_submodule *submod = inc->submodule;
- struct lysc_module *mainmod = ctx->mod->compiled;
- struct lysp_node *node_p;
-
- /* 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()). */
- ret = lys_feature_precompile(ctx, NULL, NULL, submod->features, &mainmod->mod->features);
- LY_CHECK_GOTO(ret, error);
-
- ret = lys_identity_precompile(ctx, NULL, NULL, submod->identities, &mainmod->mod->identities);
- LY_CHECK_GOTO(ret, error);
-
- /* data nodes */
- LY_LIST_FOR(submod->data, node_p) {
- ret = lys_compile_node(ctx, node_p, NULL, 0);
- LY_CHECK_GOTO(ret, error);
- }
-
- COMPILE_ARRAY1_GOTO(ctx, submod->rpcs, mainmod->rpcs, NULL, u, lys_compile_action, 0, ret, error);
- COMPILE_ARRAY1_GOTO(ctx, submod->notifs, mainmod->notifs, NULL, u, lys_compile_notif, 0, ret, error);
-
-error:
return ret;
}
@@ -6635,6 +7302,7 @@
LY_ERR ret = LY_EVALID, r;
LY_ARRAY_COUNT_TYPE u;
struct lysp_stmt *stmt;
+ struct lysp_qname qname;
void *parsed = NULL, **compiled = NULL;
/* check for invalid substatements */
@@ -6713,7 +7381,7 @@
LY_CHECK_ERR_GOTO(r = lysp_stmt_parse(ctx, stmt, stmt->kw, &parsed, NULL), ret = r, cleanup);
LY_CHECK_ERR_GOTO(r = lys_compile_type(ctx, ext->parent_type == LYEXT_PAR_NODE ? ((struct lysc_node *)ext->parent)->sp : NULL,
flags ? *flags : 0, ctx->mod_def->parsed, ext->name, parsed, (struct lysc_type **)compiled,
- units && !*units ? units : NULL, NULL, NULL), lysp_type_free(ctx->ctx, parsed); free(parsed); ret = r, cleanup);
+ units && !*units ? units : NULL, NULL), lysp_type_free(ctx->ctx, parsed); free(parsed); ret = r, cleanup);
lysp_type_free(ctx->ctx, parsed);
free(parsed);
break;
@@ -6733,7 +7401,9 @@
struct lysc_iffeature **iffs = (struct lysc_iffeature **)substmts[u].storage;
LY_ARRAY_NEW_GOTO(ctx->ctx, *iffs, iff, ret, cleanup);
}
- LY_CHECK_ERR_GOTO(r = lys_compile_iffeature(ctx, &stmt->arg, iff), ret = r, cleanup);
+ qname.str = stmt->arg;
+ qname.mod = ctx->mod_def;
+ LY_CHECK_ERR_GOTO(r = lys_compile_iffeature(ctx, &qname, iff), ret = r, cleanup);
break;
}
/* TODO support other substatements (parse stmt to lysp and then compile lysp to lysc),
@@ -6761,6 +7431,7 @@
/**
* @brief Check when for cyclic dependencies.
+ *
* @param[in] set Set with all the referenced nodes.
* @param[in] node Node whose "when" referenced nodes are in @p set.
* @return LY_ERR value
@@ -6849,7 +7520,8 @@
}
/**
- * @brief Check when/must expressions of a node on a compiled schema tree.
+ * @brief Check when/must expressions of a node on a complete compiled schema tree.
+ *
* @param[in] ctx Compile context.
* @param[in] node Node to check.
* @return LY_ERR value
@@ -6992,6 +7664,14 @@
return ret;
}
+/**
+ * @brief Check leafref for its target existence on a complete compiled schema tree.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] node Context node for the leafref.
+ * @param[in] lref Leafref to resolve.
+ * @return LY_ERR value.
+ */
static LY_ERR
lys_compile_unres_leafref(struct lysc_ctx *ctx, const struct lysc_node *node, struct lysc_type_leafref *lref)
{
@@ -7097,6 +7777,17 @@
return ret;
}
+/**
+ * @brief Compile default value(s) for leaf or leaf-list expecting a complete compiled schema tree.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] node Leaf or leaf-list to compile the default value(s) for.
+ * @param[in] type Type of the default value.
+ * @param[in] dflt Default value.
+ * @param[in] dflt_mod Local module for @p dflt.
+ * @param[in,out] storage Storage for the compiled default value.
+ * @return LY_ERR value.
+ */
static LY_ERR
lys_compile_unres_dflt(struct lysc_ctx *ctx, struct lysc_node *node, struct lysc_type *type, const char *dflt,
const struct lys_module *dflt_mod, struct lyd_value *storage)
@@ -7121,9 +7812,16 @@
return ret;
}
+/**
+ * @brief Compile default value of a leaf expecting a complete compiled schema tree.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] leaf Leaf that the default value is for.
+ * @param[in] dflt Default value to compile.
+ * @return LY_ERR value.
+ */
static LY_ERR
-lys_compile_unres_leaf_dlft(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, const char *dflt,
- const struct lys_module *dflt_mod)
+lys_compile_unres_leaf_dlft(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, struct lysp_qname *dflt)
{
LY_ERR ret;
@@ -7139,7 +7837,7 @@
LY_CHECK_ERR_RET(!leaf->dflt, LOGMEM(ctx->ctx), LY_EMEM);
/* store the default value */
- ret = lys_compile_unres_dflt(ctx, (struct lysc_node *)leaf, leaf->type, dflt, dflt_mod, leaf->dflt);
+ ret = lys_compile_unres_dflt(ctx, (struct lysc_node *)leaf, leaf->type, dflt->str, dflt->mod, leaf->dflt);
if (ret) {
free(leaf->dflt);
leaf->dflt = NULL;
@@ -7148,9 +7846,18 @@
return ret;
}
+/**
+ * @brief Compile default values of a leaf-list expecting a complete compiled schema tree.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] llist Leaf-list that the default value(s) are for.
+ * @param[in] dflt Default value to compile, in case of a single value.
+ * @param[in] dflts Sized array of default values, in case of more values.
+ * @return LY_ERR value.
+ */
static LY_ERR
-lys_compile_unres_llist_dflts(struct lysc_ctx *ctx, struct lysc_node_leaflist *llist, const char *dflt, const char **dflts,
- const struct lys_module *dflt_mod)
+lys_compile_unres_llist_dflts(struct lysc_ctx *ctx, struct lysc_node_leaflist *llist, struct lysp_qname *dflt,
+ struct lysp_qname *dflts)
{
LY_ERR ret;
LY_ARRAY_COUNT_TYPE orig_count, u, v;
@@ -7176,14 +7883,15 @@
if (dflts) {
LY_ARRAY_FOR(dflts, u) {
llist->dflts[orig_count + u] = calloc(1, sizeof **llist->dflts);
- ret = lys_compile_unres_dflt(ctx, (struct lysc_node *)llist, llist->type, dflts[u], dflt_mod,
- llist->dflts[orig_count + u]);
+ ret = lys_compile_unres_dflt(ctx, (struct lysc_node *)llist, llist->type, dflts[u].str, dflts[u].mod,
+ llist->dflts[orig_count + u]);
LY_CHECK_ERR_RET(ret, free(llist->dflts[orig_count + u]), ret);
LY_ARRAY_INCREMENT(llist->dflts);
}
} else {
llist->dflts[orig_count] = calloc(1, sizeof **llist->dflts);
- ret = lys_compile_unres_dflt(ctx, (struct lysc_node *)llist, llist->type, dflt, dflt_mod, llist->dflts[orig_count]);
+ ret = lys_compile_unres_dflt(ctx, (struct lysc_node *)llist, llist->type, dflt->str, dflt->mod,
+ llist->dflts[orig_count]);
LY_CHECK_ERR_RET(ret, free(llist->dflts[orig_count]), ret);
LY_ARRAY_INCREMENT(llist->dflts);
}
@@ -7194,16 +7902,11 @@
for (u = orig_count; u < LY_ARRAY_COUNT(llist->dflts); ++u) {
for (v = 0; v < u; ++v) {
if (!llist->dflts[u]->realtype->plugin->compare(llist->dflts[u], llist->dflts[v])) {
- ly_bool dynamic = 0;
- const char *val = llist->type->plugin->print(llist->dflts[u], LY_PREF_SCHEMA, (void *)dflt_mod, &dynamic);
-
lysc_update_path(ctx, llist->parent, llist->name);
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Configuration leaf-list has multiple defaults of the same value \"%s\".", val);
+ "Configuration leaf-list has multiple defaults of the same value \"%s\".",
+ llist->dflts[u]->canonical);
lysc_update_path(ctx, NULL, NULL);
- if (dynamic) {
- free((char *)val);
- }
return LY_EVALID;
}
}
@@ -7213,12 +7916,20 @@
return LY_SUCCESS;
}
+/**
+ * @brief Finish compilation of all the unres sets of a compile context.
+ *
+ * @param[in] ctx Compile context with unres sets.
+ * @return LY_ERR value.
+ */
static LY_ERR
lys_compile_unres(struct lysc_ctx *ctx)
{
struct lysc_node *node;
struct lysc_type *type, *typeiter;
struct lysc_type_leafref *lref;
+ struct lysc_augment *aug;
+ struct lysc_deviation *dev;
LY_ARRAY_COUNT_TYPE v;
uint32_t i;
@@ -7267,14 +7978,173 @@
/* finish incomplete default values compilation */
for (i = 0; i < ctx->dflts.count; ++i) {
- struct lysc_incomplete_dflt *r = ctx->dflts.objs[i];
+ struct lysc_unres_dflt *r = ctx->dflts.objs[i];
if (r->leaf->nodetype == LYS_LEAF) {
- LY_CHECK_RET(lys_compile_unres_leaf_dlft(ctx, r->leaf, r->dflt, r->dflt_mod));
+ LY_CHECK_RET(lys_compile_unres_leaf_dlft(ctx, r->leaf, r->dflt));
} else {
- LY_CHECK_RET(lys_compile_unres_llist_dflts(ctx, r->llist, r->dflt, r->dflts, r->dflt_mod));
+ LY_CHECK_RET(lys_compile_unres_llist_dflts(ctx, r->llist, r->dflt, r->dflts));
}
}
+ /* check that all augments were applied */
+ for (i = 0; i < ctx->augs.count; ++i) {
+ aug = ctx->augs.objs[i];
+ LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
+ "Augment target node \"%s\" from module \"%s\" was not found.", aug->nodeid->expr,
+ aug->nodeid_mod->name);
+ }
+ if (ctx->augs.count) {
+ return LY_ENOTFOUND;
+ }
+
+ /* check that all deviations were applied */
+ for (i = 0; i < ctx->devs.count; ++i) {
+ dev = ctx->devs.objs[i];
+ LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
+ "Deviation(s) target node \"%s\" from module \"%s\" was not found.", dev->nodeid->expr,
+ dev->nodeid_mod->name);
+ }
+ if (ctx->devs.count) {
+ return LY_ENOTFOUND;
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Revert precompilation of module augments and deviations. Meaning remove its reference from
+ * all the target modules.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] mod Mod whose precompilation to revert.
+ */
+static void
+lys_precompile_augments_deviations_revert(struct lysc_ctx *ctx, const struct lys_module *mod)
+{
+ uint32_t i;
+ LY_ARRAY_COUNT_TYPE u, count;
+ struct lys_module *m;
+
+ for (i = 0; i < ctx->ctx->list.count; ++i) {
+ m = ctx->ctx->list.objs[i];
+
+ if (m->augmented_by) {
+ count = LY_ARRAY_COUNT(m->augmented_by);
+ for (u = 0; u < count; ++u) {
+ if (m->augmented_by[u] == mod) {
+ /* keep the order */
+ if (u < count - 1) {
+ memmove(m->augmented_by + u, m->augmented_by + u + 1, (count - u) * sizeof *m->augmented_by);
+ }
+ LY_ARRAY_DECREMENT(m->augmented_by);
+ break;
+ }
+ }
+ if (!LY_ARRAY_COUNT(m->augmented_by)) {
+ LY_ARRAY_FREE(m->augmented_by);
+ m->augmented_by = NULL;
+ }
+ }
+
+ if (m->deviated_by) {
+ count = LY_ARRAY_COUNT(m->deviated_by);
+ for (u = 0; u < count; ++u) {
+ if (m->deviated_by[u] == mod) {
+ /* keep the order */
+ if (u < count - 1) {
+ memmove(m->deviated_by + u, m->deviated_by + u + 1, (count - u) * sizeof *m->deviated_by);
+ }
+ LY_ARRAY_DECREMENT(m->deviated_by);
+ break;
+ }
+ }
+ if (!LY_ARRAY_COUNT(m->deviated_by)) {
+ LY_ARRAY_FREE(m->deviated_by);
+ m->deviated_by = NULL;
+ }
+ }
+ }
+}
+
+/**
+ * @brief Compile features in the current module and all its submodules.
+ *
+ * @param[in] ctx Compile context.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_compile_features(struct lysc_ctx *ctx)
+{
+ struct lysp_submodule *submod;
+ LY_ARRAY_COUNT_TYPE u, v;
+
+ if (!ctx->mod->features) {
+ /* features are compiled directly into the module structure,
+ * but it must be done in two steps to allow forward references (via if-feature) between the features themselves */
+ LY_CHECK_RET(lys_feature_precompile(ctx, NULL, NULL, ctx->mod->parsed->features, &ctx->mod->features));
+ LY_ARRAY_FOR(ctx->mod->parsed->includes, v) {
+ submod = ctx->mod->parsed->includes[v].submodule;
+ LY_CHECK_RET(lys_feature_precompile(ctx, NULL, NULL, submod->features, &ctx->mod->features));
+ }
+ }
+
+ /* 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. */
+ LY_ARRAY_FOR(ctx->mod->parsed->features, u) {
+ LY_CHECK_RET(lys_feature_precompile_finish(ctx, &ctx->mod->parsed->features[u], ctx->mod->features));
+ }
+
+ lysc_update_path(ctx, NULL, "{submodule}");
+ LY_ARRAY_FOR(ctx->mod->parsed->includes, v) {
+ submod = ctx->mod->parsed->includes[v].submodule;
+
+ lysc_update_path(ctx, NULL, submod->name);
+ LY_ARRAY_FOR(submod->features, u) {
+ LY_CHECK_RET(lys_feature_precompile_finish(ctx, &submod->features[u], ctx->mod->features));
+ }
+ lysc_update_path(ctx, NULL, NULL);
+ }
+ lysc_update_path(ctx, NULL, NULL);
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Compile identites in the current module and all its submodules.
+ *
+ * @param[in] ctx Compile context.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_compile_identities(struct lysc_ctx *ctx)
+{
+ struct lysp_submodule *submod;
+ LY_ARRAY_COUNT_TYPE u;
+
+ if (!ctx->mod->identities) {
+ LY_CHECK_RET(lys_identity_precompile(ctx, NULL, NULL, ctx->mod->parsed->identities, &ctx->mod->identities));
+ LY_ARRAY_FOR(ctx->mod->parsed->includes, u) {
+ submod = ctx->mod->parsed->includes[u].submodule;
+ LY_CHECK_RET(lys_identity_precompile(ctx, NULL, NULL, submod->identities, &ctx->mod->identities));
+ }
+ }
+
+ if (ctx->mod->parsed->identities) {
+ LY_CHECK_RET(lys_compile_identities_derived(ctx, ctx->mod->parsed->identities, ctx->mod->identities));
+ }
+ lysc_update_path(ctx, NULL, "{submodule}");
+ LY_ARRAY_FOR(ctx->mod->parsed->includes, u) {
+
+ submod = ctx->mod->parsed->includes[u].submodule;
+ if (submod->identities) {
+ lysc_update_path(ctx, NULL, submod->name);
+ LY_CHECK_RET(lys_compile_identities_derived(ctx, submod->identities, ctx->mod->identities));
+ lysc_update_path(ctx, NULL, NULL);
+ }
+ }
+ lysc_update_path(ctx, NULL, NULL);
+
return LY_SUCCESS;
}
@@ -7284,13 +8154,12 @@
struct lysc_ctx ctx = {0};
struct lysc_module *mod_c;
struct lysp_module *sp;
- struct lysp_node *node_p;
- struct lysp_augment **augments = NULL;
+ struct lysp_submodule *submod;
+ struct lysp_node *pnode;
struct lysp_grp *grps;
struct lys_module *m;
LY_ARRAY_COUNT_TYPE u, v;
uint32_t i;
- uint16_t compile_id;
LY_ERR ret = LY_SUCCESS;
LY_CHECK_ARG_RET(NULL, mod, mod->parsed, !mod->compiled, mod->ctx, LY_EINVAL);
@@ -7300,7 +8169,9 @@
return LY_SUCCESS;
}
- compile_id = ++mod->ctx->module_set_id;
+ /* context will be changed */
+ ++mod->ctx->module_set_id;
+
sp = mod->parsed;
ctx.ctx = mod->ctx;
@@ -7314,84 +8185,50 @@
LY_CHECK_ERR_RET(!mod_c, LOGMEM(mod->ctx), LY_EMEM);
mod_c->mod = mod;
+ /* process imports */
LY_ARRAY_FOR(sp->imports, u) {
LY_CHECK_GOTO(ret = lys_compile_import(&ctx, &sp->imports[u]), error);
}
- /* features precompilation */
- if (!mod->features && sp->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 */
- ret = lys_feature_precompile(&ctx, NULL, NULL, sp->features, &mod->features);
- LY_CHECK_GOTO(ret, error);
- } /* else the features are already precompiled */
-
- /* similarly, identities precompilation */
- if (!mod->identities && sp->identities) {
- ret = lys_identity_precompile(&ctx, NULL, NULL, sp->identities, &mod->identities);
- LY_CHECK_GOTO(ret, error);
- }
-
- /* compile submodules
- * - must be between features/identities precompilation and finishing their compilation to cover features/identities from
- * submodules */
- LY_ARRAY_FOR(sp->includes, u) {
- LY_CHECK_GOTO(ret = lys_compile_submodule(&ctx, &sp->includes[u]), 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. */
- LY_ARRAY_FOR(sp->features, u) {
- ret = lys_feature_precompile_finish(&ctx, &sp->features[u], mod->features);
- LY_CHECK_GOTO(ret != LY_SUCCESS, error);
- }
- lysc_update_path(&ctx, NULL, "{submodule}");
- LY_ARRAY_FOR(sp->includes, v) {
- lysc_update_path(&ctx, NULL, sp->includes[v].name);
- LY_ARRAY_FOR(sp->includes[v].submodule->features, u) {
- ret = lys_feature_precompile_finish(&ctx, &sp->includes[v].submodule->features[u], mod->features);
- LY_CHECK_GOTO(ret != LY_SUCCESS, error);
- }
- lysc_update_path(&ctx, NULL, NULL);
- }
- lysc_update_path(&ctx, NULL, NULL);
+ /* features */
+ LY_CHECK_GOTO(ret = lys_compile_features(&ctx), error);
/* identities, work similarly to features with the precompilation */
- if (sp->identities) {
- LY_CHECK_GOTO(ret = lys_compile_identities_derived(&ctx, sp->identities, mod->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->identities);
- LY_CHECK_GOTO(ret, error);
- lysc_update_path(&ctx, NULL, NULL);
- }
- }
- lysc_update_path(&ctx, NULL, NULL);
+ LY_CHECK_GOTO(ret = lys_compile_identities(&ctx), error);
+
+ /* augments and deviations */
+ LY_CHECK_GOTO(ret = lys_precompile_augments_deviations(&ctx), error);
+
+ /* 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);
/* data nodes */
- LY_LIST_FOR(sp->data, node_p) {
- LY_CHECK_GOTO(ret = lys_compile_node(&ctx, node_p, NULL, 0), error);
+ LY_LIST_FOR(sp->data, pnode) {
+ LY_CHECK_GOTO(ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL), error);
}
- COMPILE_ARRAY1_GOTO(&ctx, sp->rpcs, mod_c->rpcs, NULL, u, lys_compile_action, 0, ret, error);
- COMPILE_ARRAY1_GOTO(&ctx, sp->notifs, mod_c->notifs, NULL, u, lys_compile_notif, 0, ret, error);
+ /* top-level RPCs and notifications */
+ COMPILE_OP_ARRAY_GOTO(&ctx, sp->rpcs, mod_c->rpcs, NULL, u, lys_compile_action, 0, ret, error);
+ COMPILE_OP_ARRAY_GOTO(&ctx, sp->notifs, mod_c->notifs, NULL, u, lys_compile_notif, 0, ret, error);
- /* augments - sort first to cover augments augmenting other augments */
- LY_CHECK_GOTO(ret = lys_compile_augment_sort(&ctx, sp->augments, sp->includes, &augments), error);
- LY_ARRAY_FOR(augments, u) {
- LY_CHECK_GOTO(ret = lys_compile_augment(&ctx, augments[u], NULL), error);
- }
-
- /* deviations TODO cover deviations from submodules */
- LY_CHECK_GOTO(ret = lys_compile_deviations(&ctx, sp), error);
-
- /* extension instances TODO cover extension instances from submodules */
+ /* extension instances */
COMPILE_EXTS_GOTO(&ctx, sp->exts, mod_c->exts, mod_c, LYEXT_PAR_MODULE, ret, error);
+ /* the same for submodules */
+ LY_ARRAY_FOR(sp->includes, u) {
+ submod = sp->includes[u].submodule;
+ LY_LIST_FOR(submod->data, pnode) {
+ ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL);
+ LY_CHECK_GOTO(ret, error);
+ }
+
+ COMPILE_OP_ARRAY_GOTO(&ctx, submod->rpcs, mod_c->rpcs, NULL, v, lys_compile_action, 0, ret, error);
+ COMPILE_OP_ARRAY_GOTO(&ctx, submod->notifs, mod_c->notifs, NULL, v, lys_compile_notif, 0, ret, error);
+
+ COMPILE_EXTS_GOTO(&ctx, submod->exts, mod_c->exts, mod_c, LYEXT_PAR_MODULE, ret, error);
+ }
+
/* finish compilation for all unresolved items in the context */
LY_CHECK_GOTO(ret = lys_compile_unres(&ctx), error);
@@ -7400,21 +8237,32 @@
ctx.options |= LYSC_OPT_GROUPING;
LY_ARRAY_FOR(sp->groupings, u) {
if (!(sp->groupings[u].flags & LYS_USED_GRP)) {
- LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, node_p, &sp->groupings[u]), error);
+ LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &sp->groupings[u]), error);
}
}
- LY_LIST_FOR(sp->data, node_p) {
- grps = (struct lysp_grp *)lysp_node_groupings(node_p);
+ LY_LIST_FOR(sp->data, pnode) {
+ grps = (struct lysp_grp *)lysp_node_groupings(pnode);
LY_ARRAY_FOR(grps, u) {
if (!(grps[u].flags & LYS_USED_GRP)) {
- LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, node_p, &grps[u]), error);
+ LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &grps[u]), error);
}
}
}
-
- if (ctx.ctx->flags & LY_CTX_CHANGED_TREE) {
- /* TODO Deviation has changed tree of a module(s) in the context (by deviate-not-supported), it is necessary to recompile
- leafref paths, default values and must/when expressions in all schemas of the context to check that they are still valid */
+ LY_ARRAY_FOR(sp->includes, u) {
+ submod = sp->includes[u].submodule;
+ LY_ARRAY_FOR(submod->groupings, u) {
+ if (!(submod->groupings[u].flags & LYS_USED_GRP)) {
+ LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &submod->groupings[u]), error);
+ }
+ }
+ LY_LIST_FOR(submod->data, pnode) {
+ grps = (struct lysp_grp *)lysp_node_groupings(pnode);
+ LY_ARRAY_FOR(grps, u) {
+ if (!(grps[u].flags & LYS_USED_GRP)) {
+ LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &grps[u]), error);
+ }
+ }
+ }
}
#if 0
@@ -7435,12 +8283,21 @@
LY_CHECK_GOTO(ret = lys_compile_ietf_netconf_wd_annotation(&ctx, mod), error);
}
- ly_set_erase(&ctx.dflts, free);
+ /* there can be no leftover deviations */
+ LY_CHECK_ERR_GOTO(ctx.devs.count, LOGINT(ctx.ctx); ret = LY_EINT, error);
+
+ for (i = 0; i < ctx.dflts.count; ++i) {
+ lysc_unres_dflt_free(ctx.ctx, ctx.dflts.objs[i]);
+ }
+ ly_set_erase(&ctx.dflts, NULL);
ly_set_erase(&ctx.xpath, NULL);
ly_set_erase(&ctx.leafrefs, NULL);
ly_set_erase(&ctx.groupings, NULL);
ly_set_erase(&ctx.tpdf_chain, NULL);
- LY_ARRAY_FREE(augments);
+ ly_set_erase(&ctx.augs, NULL);
+ ly_set_erase(&ctx.devs, NULL);
+ ly_set_erase(&ctx.uses_augs, NULL);
+ ly_set_erase(&ctx.uses_rfns, NULL);
if (ctx.options & LYSC_OPT_FREE_SP) {
lysp_module_free(mod->parsed);
@@ -7460,29 +8317,58 @@
return LY_SUCCESS;
error:
+ lys_precompile_augments_deviations_revert(&ctx, mod);
lys_feature_precompile_revert(&ctx, mod);
- ly_set_erase(&ctx.dflts, free);
+ for (i = 0; i < ctx.dflts.count; ++i) {
+ lysc_unres_dflt_free(ctx.ctx, ctx.dflts.objs[i]);
+ }
+ ly_set_erase(&ctx.dflts, NULL);
ly_set_erase(&ctx.xpath, NULL);
ly_set_erase(&ctx.leafrefs, NULL);
ly_set_erase(&ctx.groupings, NULL);
ly_set_erase(&ctx.tpdf_chain, NULL);
- LY_ARRAY_FREE(augments);
+ for (i = 0; i < ctx.augs.count; ++i) {
+ lysc_augment_free(ctx.ctx, ctx.augs.objs[i]);
+ }
+ ly_set_erase(&ctx.augs, NULL);
+ for (i = 0; i < ctx.devs.count; ++i) {
+ lysc_deviation_free(ctx.ctx, ctx.devs.objs[i]);
+ }
+ ly_set_erase(&ctx.devs, NULL);
+ for (i = 0; i < ctx.uses_augs.count; ++i) {
+ lysc_augment_free(ctx.ctx, ctx.uses_augs.objs[i]);
+ }
+ ly_set_erase(&ctx.uses_augs, NULL);
+ for (i = 0; i < ctx.uses_rfns.count; ++i) {
+ lysc_refine_free(ctx.ctx, ctx.uses_rfns.objs[i]);
+ }
+ ly_set_erase(&ctx.uses_rfns, NULL);
lysc_module_free(mod_c, NULL);
mod->compiled = NULL;
- /* revert compilation of modules implemented by dependency, but only by (directly or indirectly) by dependency
- * of this module, since this module can be also compiled from dependency, there can be some other modules being
- * processed and we are going to get back to them via stack, so freeing them is not a good idea. */
- for (i = 0; i < ctx.ctx->list.count; ++i) {
- m = ctx.ctx->list.objs[i];
- if ((m->implemented >= compile_id) && m->compiled) {
- /* revert features list to the precompiled state */
- lys_feature_precompile_revert(&ctx, m);
- /* mark module as imported-only / not-implemented */
- m->implemented = 0;
- /* free the compiled version of the module */
+ /* revert compilation of modules implemented by dependency */
+ if (!(ctx.options & LYSC_OPT_INTERNAL)) {
+ for (i = 0; i < ctx.ctx->list.count; ++i) {
+ m = ctx.ctx->list.objs[i];
+ if (m->implemented > 1) {
+ /* make the module non-implemented */
+ m->implemented = 0;
+ }
+
+ /* free the compiled version of the module, if any */
lysc_module_free(m->compiled, NULL);
m->compiled = NULL;
+
+ if (m->implemented) {
+ /* recompile, must succeed because it was already compiled; hide messages because any
+ * warnings were already printed, are not really relevant, and would hide the real error */
+ uint32_t prev_lo = ly_log_options(0);
+ LY_ERR r = lys_compile(m, LYSC_OPT_INTERNAL);
+ ly_log_options(prev_lo);
+ if (r) {
+ LOGERR(ctx.ctx, r, "Recompilation of module \"%s\" failed.", m->name);
+ }
+ }
}
}