schema compile BUGFIX leafref non-prefixed node module
... should be the same as the context node, not
current module, which is only for schema paths.
Made current module in leafref redundant and some
other minor refactoring was added.
Fixes sysrepo/sysrepo#2481
diff --git a/src/parser_stmt.c b/src/parser_stmt.c
index 868a0b7..01a598e 100644
--- a/src/parser_stmt.c
+++ b/src/parser_stmt.c
@@ -931,7 +931,7 @@
break;
case LY_STMT_PATH:
LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &str_path, Y_STR_ARG, &type->exts));
- ret = ly_path_parse(PARSER_CTX(ctx), NULL, str_path, 0, LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
+ ret = ly_path_parse(PARSER_CTX(ctx), NULL, str_path, 0, 1, LY_PATH_BEGIN_EITHER,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &type->path);
lydict_remove(PARSER_CTX(ctx), str_path);
LY_CHECK_RET(ret);
@@ -2416,7 +2416,7 @@
const char *str_path = NULL;
LY_CHECK_RET(lysp_stmt_text_field(&pctx, stmt, 0, &str_path, Y_STR_ARG, exts));
- ret = ly_path_parse(ctx->ctx, NULL, str_path, 0, LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
+ ret = ly_path_parse(ctx->ctx, NULL, str_path, 0, 1, LY_PATH_BEGIN_EITHER,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, (struct lyxp_expr **)result);
lydict_remove(ctx->ctx, str_path);
break;
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 80d0efe..fc10bc4 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -2170,7 +2170,7 @@
*/
LY_CHECK_ERR_RET(ret = parse_text_field(ctx, LY_STMT_PATH, 0, &str_path, Y_STR_ARG, &type->exts),
lydict_remove(PARSER_CTX(ctx), str_path), ret);
- ret = ly_path_parse(PARSER_CTX(ctx), NULL, str_path, 0, LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
+ ret = ly_path_parse(PARSER_CTX(ctx), NULL, str_path, 0, 1, LY_PATH_BEGIN_EITHER,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &type->path);
/* Moreover, even if successful, the string is removed from the dictionary. */
lydict_remove(PARSER_CTX(ctx), str_path);
diff --git a/src/parser_yin.c b/src/parser_yin.c
index c0789db..c7a2307 100644
--- a/src/parser_yin.c
+++ b/src/parser_yin.c
@@ -622,7 +622,7 @@
const char *str_path;
LY_CHECK_RET(yin_parse_simple_element(ctx, kw, &str_path, YIN_ARG_VALUE, Y_STR_ARG, &type->exts));
- ret = ly_path_parse(ctx->xmlctx->ctx, NULL, str_path, 0, LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
+ ret = ly_path_parse(ctx->xmlctx->ctx, NULL, str_path, 0, 1, LY_PATH_BEGIN_EITHER,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &type->path);
lydict_remove(ctx->xmlctx->ctx, str_path);
LY_CHECK_RET(ret);
diff --git a/src/path.c b/src/path.c
index 1fd57d3..baa3da8 100644
--- a/src/path.c
+++ b/src/path.c
@@ -232,7 +232,7 @@
LY_ERR
ly_path_parse(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *str_path, size_t path_len,
- uint8_t begin, uint8_t lref, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
+ ly_bool lref, uint8_t begin, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
{
LY_ERR ret = LY_SUCCESS;
struct lyxp_expr *exp = NULL;
@@ -240,7 +240,6 @@
const char *cur_node, *prev_prefix = NULL, *ptr;
assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER));
- assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY) ||
(prefix == LY_PATH_PREFIX_STRICT_INHERIT));
assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
@@ -255,7 +254,7 @@
/* is the path relative? */
if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) {
/* relative path check specific to leafref */
- if (lref == LY_PATH_LREF_TRUE) {
+ if (lref) {
/* mandatory '..' */
LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_DDOT), ret = LY_EVALID, error);
@@ -385,10 +384,8 @@
* @param[in] prev_ctx_node Previous context node. Needed for ::LY_VALUE_JSON.
* @param[in] expr Parsed path.
* @param[in] tok_idx Index in @p expr.
- * @param[in] lref Lref option.
* @param[in] format Format of the path.
* @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
- * @param[in,out] unres Global unres to use.
* @param[out] mod Resolved module.
* @param[out] name Parsed node name.
* @param[out] name_len Length of @p name.
@@ -396,9 +393,8 @@
*/
static LY_ERR
ly_path_compile_prefix(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
- const struct lysc_node *prev_ctx_node, const struct lyxp_expr *expr, uint16_t tok_idx, uint8_t lref,
- LY_VALUE_FORMAT format, void *prefix_data, struct lys_glob_unres *unres, const struct lys_module **mod,
- const char **name, size_t *name_len)
+ const struct lysc_node *prev_ctx_node, const struct lyxp_expr *expr, uint16_t tok_idx, LY_VALUE_FORMAT format,
+ void *prefix_data, const struct lys_module **mod, const char **name, size_t *name_len)
{
LY_ERR ret;
const char *pref;
@@ -425,15 +421,9 @@
ret = LY_EVALID;
goto error;
} else if (!(*mod)->implemented) {
- if (lref == LY_PATH_LREF_FALSE) {
- LOGVAL(ctx, LYVE_XPATH, "Not implemented module \"%s\" in path.", (*mod)->name);
- ret = LY_EVALID;
- goto error;
- }
-
- assert(unres);
- LY_CHECK_GOTO(ret = lys_implement((struct lys_module *)*mod, NULL, unres), error);
- LY_CHECK_GOTO(ret = lys_compile((struct lys_module *)*mod, &unres->ds_unres), error);
+ LOGVAL(ctx, LYVE_XPATH, "Not implemented module \"%s\" in path.", (*mod)->name);
+ ret = LY_EVALID;
+ goto error;
}
LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
@@ -478,6 +468,97 @@
return ret;
}
+/**
+ * @brief Parse prefix from a NameTest in a leafref, if any, and node name, and return expected module of the node.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] cur_node Optional current (original context) node.
+ * @param[in] prev_ctx_node Previous context node. Needed for ::LY_VALUE_JSON.
+ * @param[in] expr Parsed path.
+ * @param[in] tok_idx Index in @p expr.
+ * @param[in] format Format of the path.
+ * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
+ * @param[in,out] unres Global unres to use.
+ * @param[out] mod Resolved module.
+ * @param[out] name Parsed node name.
+ * @param[out] name_len Length of @p name.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+ly_path_compile_prefix_leafref(const struct ly_ctx *ctx, const struct lysc_node *cur_node,
+ const struct lysc_node *prev_ctx_node, const struct lyxp_expr *expr, uint16_t tok_idx, LY_VALUE_FORMAT format,
+ void *prefix_data, struct lys_glob_unres *unres, const struct lys_module **mod, const char **name,
+ size_t *name_len)
+{
+ LY_ERR ret;
+ const char *pref;
+ size_t len;
+
+ assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
+
+ /* get prefix */
+ if ((pref = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]))) {
+ len = pref - (expr->expr + expr->tok_pos[tok_idx]);
+ pref = expr->expr + expr->tok_pos[tok_idx];
+ } else {
+ len = 0;
+ }
+
+ /* find next node module */
+ if (pref) {
+ LOG_LOCSET(cur_node, NULL, NULL, NULL);
+
+ *mod = ly_resolve_prefix(ctx, pref, len, format, prefix_data);
+ if (!*mod) {
+ LOGVAL(ctx, LYVE_XPATH, "No module connected with the prefix \"%.*s\" found (prefix format %s).",
+ (int)len, pref, ly_format2str(format));
+ ret = LY_EVALID;
+ goto error;
+ } else if (!(*mod)->implemented) {
+ assert(unres);
+ LY_CHECK_GOTO(ret = lys_implement((struct lys_module *)*mod, NULL, unres), error);
+ LY_CHECK_GOTO(ret = lys_compile((struct lys_module *)*mod, &unres->ds_unres), error);
+ }
+
+ LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
+ } else {
+ switch (format) {
+ case LY_VALUE_SCHEMA:
+ case LY_VALUE_SCHEMA_RESOLVED:
+ /* use original context node module */
+ *mod = cur_node->module;
+ break;
+ case LY_VALUE_JSON:
+ if (!prev_ctx_node) {
+ LOGINT_RET(ctx);
+ }
+ /* inherit module of the previous node */
+ *mod = prev_ctx_node->module;
+ break;
+ case LY_VALUE_CANON:
+ case LY_VALUE_XML:
+ case LY_VALUE_LYB:
+ /* not really defined or accepted */
+ LOGINT_RET(ctx);
+ }
+ }
+
+ /* set name */
+ if (pref) {
+ *name = pref + len + 1;
+ *name_len = expr->tok_len[tok_idx] - len - 1;
+ } else {
+ *name = expr->expr + expr->tok_pos[tok_idx];
+ *name_len = expr->tok_len[tok_idx];
+ }
+
+ return LY_SUCCESS;
+
+error:
+ LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
+ return ret;
+}
+
LY_ERR
ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint16_t *tok_idx, LY_VALUE_FORMAT format,
@@ -516,8 +597,8 @@
do {
/* NameTest, find the key */
- LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, LY_PATH_LREF_FALSE,
- format, prefix_data, NULL, &mod, &name, &name_len));
+ LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, format, prefix_data,
+ &mod, &name, &name_len));
key = lys_find_child(ctx_node, mod, name, name_len, 0, 0);
if (!key) {
LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
@@ -688,8 +769,8 @@
do {
/* NameTest, find the key */
- ret = ly_path_compile_prefix(ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx,
- LY_PATH_LREF_TRUE, format, prefix_data, unres, &mod, &name, &name_len);
+ ret = ly_path_compile_prefix_leafref(ctx, cur_node, ctx_node, expr, *tok_idx, format, prefix_data, unres, &mod,
+ &name, &name_len);
LY_CHECK_GOTO(ret, cleanup);
key = lys_find_child(ctx_node, mod, name, name_len, 0, 0);
if (!key) {
@@ -751,8 +832,8 @@
/* NameTest */
assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
- LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_node->module, node, expr, *tok_idx,
- LY_PATH_LREF_TRUE, format, prefix_data, unres, &mod, &name, &name_len));
+ LY_CHECK_RET(ly_path_compile_prefix_leafref(ctx, cur_node, node, expr, *tok_idx, format, prefix_data, unres,
+ &mod, &name, &name_len));
node2 = lys_find_child(node, mod, name, name_len, 0, 0);
if (!node2) {
LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
@@ -786,9 +867,30 @@
return ret;
}
-LY_ERR
-ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
- const struct lysc_ext_instance *ext, const struct lyxp_expr *expr, uint8_t lref, uint8_t oper, uint8_t target,
+/**
+ * @brief Compile path into ly_path structure. Any predicates of a leafref are only checked, not compiled.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] cur_mod Current module of the path (where it was "instantiated"), ignored of @p lref. Used for nodes
+ * without a prefix for ::LY_PREF_SCHEMA* format.
+ * @param[in] ctx_node Optional context node, mandatory of @p lref.
+ * @param[in] ext Extension instance containing the definition of the data being created. It is used to find the top-level
+ * node inside the extension instance instead of a module. Note that this is the case not only if the @p ctx_node is NULL,
+ * but also if the relative path starting in @p ctx_node reaches the document root via double dots.
+ * @param[in] expr Parsed path.
+ * @param[in] lref Whether leafref is being compiled or not.
+ * @param[in] oper Oper option (@ref path_oper_options).
+ * @param[in] target Target option (@ref path_target_options).
+ * @param[in] format Format of the path.
+ * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
+ * @param[in,out] unres Global unres structure for newly implemented modules, needed only if @p lref.
+ * @param[out] path Compiled path.
+ * @return LY_ERECOMPILE, only if @p lref.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+_ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
+ const struct lysc_ext_instance *ext, const struct lyxp_expr *expr, ly_bool lref, uint8_t oper, uint8_t target,
LY_VALUE_FORMAT format, void *prefix_data, struct lys_glob_unres *unres, struct ly_path **path)
{
LY_ERR ret = LY_SUCCESS;
@@ -801,8 +903,7 @@
size_t name_len;
assert(ctx);
- assert((lref == LY_PATH_LREF_FALSE) || ctx_node);
- assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
+ assert(!lref || ctx_node);
assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
@@ -828,7 +929,7 @@
++tok_idx;
} else {
/* relative path */
- while ((lref == LY_PATH_LREF_TRUE) && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
+ while (lref && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
if (!ctx_node) {
LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
ret = LY_EVALID;
@@ -850,8 +951,7 @@
do {
/* check last compiled inner node, whether it is uniquely identified (even key-less list) */
- if (p && (lref == LY_PATH_LREF_FALSE) && (target == LY_PATH_TARGET_SINGLE) &&
- (p->node->nodetype == LYS_LIST) && !p->predicates) {
+ if (p && !lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype == LYS_LIST) && !p->predicates) {
LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
lys_nodetype2str(p->node->nodetype), p->node->name);
ret = LY_EVALID;
@@ -862,8 +962,13 @@
LY_CHECK_ERR_GOTO(lyxp_check_token(ctx, expr, tok_idx, LYXP_TOKEN_NAMETEST), ret = LY_EVALID, cleanup);
/* get module and node name */
- LY_CHECK_GOTO(ret = ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, lref, format,
- prefix_data, unres, &mod, &name, &name_len), cleanup);
+ if (lref) {
+ LY_CHECK_GOTO(ret = ly_path_compile_prefix_leafref(ctx, cur_node, ctx_node, expr, tok_idx, format,
+ prefix_data, unres, &mod, &name, &name_len), cleanup);
+ } else {
+ LY_CHECK_GOTO(ret = ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, format,
+ prefix_data, &mod, &name, &name_len), cleanup);
+ }
++tok_idx;
/* find the next node */
@@ -884,7 +989,7 @@
p->node = ctx_node;
/* compile any predicates */
- if (lref == LY_PATH_LREF_TRUE) {
+ if (lref) {
ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data, unres);
} else {
ret = ly_path_compile_predicate(ctx, cur_node, cur_mod, ctx_node, expr, &tok_idx, format, prefix_data,
@@ -901,8 +1006,7 @@
}
/* check last compiled node */
- if ((lref == LY_PATH_LREF_FALSE) && (target == LY_PATH_TARGET_SINGLE) &&
- (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
+ if (!lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
lys_nodetype2str(p->node->nodetype), p->node->name);
ret = LY_EVALID;
@@ -919,6 +1023,22 @@
}
LY_ERR
+ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
+ const struct lysc_ext_instance *ext, const struct lyxp_expr *expr, uint8_t oper, uint8_t target,
+ LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path)
+{
+ return _ly_path_compile(ctx, cur_mod, ctx_node, ext, expr, 0, oper, target, format, prefix_data, NULL, path);
+}
+
+LY_ERR
+ly_path_compile_leafref(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const struct lysc_ext_instance *ext,
+ const struct lyxp_expr *expr, uint8_t oper, uint8_t target, LY_VALUE_FORMAT format, void *prefix_data,
+ struct lys_glob_unres *unres, struct ly_path **path)
+{
+ return _ly_path_compile(ctx, NULL, ctx_node, ext, expr, 1, oper, target, format, prefix_data, unres, path);
+}
+
+LY_ERR
ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, LY_ARRAY_COUNT_TYPE *path_idx,
struct lyd_node **match)
{
diff --git a/src/path.h b/src/path.h
index 2245298..a32a5a2 100644
--- a/src/path.h
+++ b/src/path.h
@@ -72,15 +72,6 @@
/** @} */
/**
- * @defgroup path_lref_options Path leafref options.
- * @{
- */
-#define LY_PATH_LREF_FALSE 0x04 /**< path does not represent leafref */
-#define LY_PATH_LREF_TRUE 0x08 /* '..' in path allowed, special leafref predicates expected (but are not compiled),
- implement traversed modules */
-/** @} */
-
-/**
* @defgroup path_prefix_options Path prefix options.
* @{
*/
@@ -107,15 +98,15 @@
* @param[in] ctx_node Optional context node, used for logging.
* @param[in] str_path Path to parse.
* @param[in] path_len Length of @p str_path.
+ * @param[in] lref Whether leafref is being parsed or not.
* @param[in] begin Begin option (@ref path_begin_options).
- * @param[in] lref Lref option (@ref path_lref_options).
* @param[in] prefix Prefix option (@ref path_prefix_options).
* @param[in] pred Predicate option (@ref path_pred_options).
* @param[out] expr Parsed path.
* @return LY_ERR value.
*/
LY_ERR ly_path_parse(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *str_path, size_t path_len,
- uint8_t begin, uint8_t lref, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr);
+ ly_bool lref, uint8_t begin, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr);
/**
* @brief Parse predicate into XPath token structure and perform all additional checks.
@@ -151,28 +142,47 @@
/** @} */
/**
- * @brief Compile path into ly_path structure. Any predicates of a leafref are only checked, not compiled.
+ * @brief Compile path into ly_path structure.
*
* @param[in] ctx libyang context.
- * @param[in] cur_mod Current module of the path (where it was "instantiated"). Used for nodes without a prefix
- * for ::LY_PREF_SCHEMA* format.
+ * @param[in] cur_mod Current module of the path (where it was "instantiated"). Used for nodes in schema-nodeid
+ * without a prefix for ::LY_PREF_SCHEMA* format.
* @param[in] ctx_node Optional context node.
* @param[in] ext Extension instance containing the definition of the data being created. It is used to find the top-level
* node inside the extension instance instead of a module. Note that this is the case not only if the @p ctx_node is NULL,
* but also if the relative path starting in @p ctx_node reaches the document root via double dots.
* @param[in] expr Parsed path.
- * @param[in] lref Lref option (@ref path_lref_options).
* @param[in] oper Oper option (@ref path_oper_options).
* @param[in] target Target option (@ref path_target_options).
* @param[in] format Format of the path.
* @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
- * @param[in,out] unres Global unres structure for newly implemented modules, needed only if @p lref is ::LY_PATH_LREF_TRUE.
* @param[out] path Compiled path.
- * @return LY_ERECOMPILE, only if @p lref is ::LY_PATH_LREF_TRUE.
* @return LY_ERR value.
*/
LY_ERR ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
- const struct lysc_ext_instance *ext, const struct lyxp_expr *expr, uint8_t lref, uint8_t oper, uint8_t target,
+ const struct lysc_ext_instance *ext, const struct lyxp_expr *expr, uint8_t oper, uint8_t target,
+ LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path);
+
+/**
+ * @brief Compile path into ly_path structure. Any predicates of a leafref are only checked, not compiled.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] ctx_node Context node.
+ * @param[in] ext Extension instance containing the definition of the data being created. It is used to find the top-level
+ * node inside the extension instance instead of a module. Note that this is the case not only if the @p ctx_node is NULL,
+ * but also if the relative path starting in @p ctx_node reaches the document root via double dots.
+ * @param[in] expr Parsed path.
+ * @param[in] oper Oper option (@ref path_oper_options).
+ * @param[in] target Target option (@ref path_target_options).
+ * @param[in] format Format of the path.
+ * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
+ * @param[in,out] unres Global unres structure for newly implemented modules.
+ * @param[out] path Compiled path.
+ * @return LY_ERECOMPILE if recompilation is needed before the path can be compiled.
+ * @return LY_ERR value.
+ */
+LY_ERR ly_path_compile_leafref(const struct ly_ctx *ctx, const struct lysc_node *ctx_node,
+ const struct lysc_ext_instance *ext, const struct lyxp_expr *expr, uint8_t oper, uint8_t target,
LY_VALUE_FORMAT format, void *prefix_data, struct lys_glob_unres *unres, struct ly_path **path);
/**
diff --git a/src/plugins_types.c b/src/plugins_types.c
index bd59b9a..5a256a8 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -710,8 +710,7 @@
}
/* parse the value */
- ret = ly_path_parse(ctx, ctx_node, value, value_len, LY_PATH_BEGIN_ABSOLUTE, LY_PATH_LREF_FALSE,
- prefix_opt, LY_PATH_PRED_SIMPLE, &exp);
+ ret = ly_path_parse(ctx, ctx_node, value, value_len, 0, LY_PATH_BEGIN_ABSOLUTE, prefix_opt, LY_PATH_PRED_SIMPLE, &exp);
if (ret) {
ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
"Invalid instance-identifier \"%.*s\" value - syntax error.", (int)value_len, value);
@@ -724,8 +723,8 @@
}
/* resolve it on schema tree */
- ret = ly_path_compile(ctx, NULL, ctx_node, NULL, exp, LY_PATH_LREF_FALSE, (ctx_node->flags & LYS_IS_OUTPUT) ?
- LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_SINGLE, format, prefix_data, unres, path);
+ ret = ly_path_compile(ctx, NULL, ctx_node, NULL, exp, (ctx_node->flags & LYS_IS_OUTPUT) ?
+ LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_SINGLE, format, prefix_data, path);
if (ret) {
ret = ly_err_new(err, ret, LYVE_DATA, NULL, NULL,
"Invalid instance-identifier \"%.*s\" value - semantic error.", (int)value_len, value);
@@ -787,12 +786,14 @@
uint32_t i;
int rc;
+ LY_CHECK_ARG_RET(NULL, lref, node, value, errmsg, LY_EINVAL);
+
/* find all target data instances */
- ret = lyxp_eval(lref->cur_mod->ctx, lref->path, lref->cur_mod, LY_VALUE_SCHEMA_RESOLVED, lref->prefixes, node, tree,
- &set, 0);
+ ret = lyxp_eval(LYD_CTX(node), lref->path, node->schema->module, LY_VALUE_SCHEMA_RESOLVED, lref->prefixes,
+ node, tree, &set, 0);
if (ret) {
ret = LY_ENOTFOUND;
- val_str = lref->plugin->print(lref->cur_mod->ctx, value, LY_VALUE_CANON, NULL, NULL, NULL);
+ val_str = lref->plugin->print(LYD_CTX(node), value, LY_VALUE_CANON, NULL, NULL, NULL);
if (asprintf(errmsg, "Invalid leafref value \"%s\" - XPath evaluation error.", val_str) == -1) {
*errmsg = NULL;
ret = LY_EMEM;
@@ -812,7 +813,7 @@
}
if (i == set.used) {
ret = LY_ENOTFOUND;
- val_str = lref->plugin->print(lref->cur_mod->ctx, value, LY_VALUE_CANON, NULL, NULL, NULL);
+ val_str = lref->plugin->print(LYD_CTX(node), value, LY_VALUE_CANON, NULL, NULL, NULL);
if (set.used) {
rc = asprintf(errmsg, LY_ERRMSG_NOLREF_VAL, val_str, lref->path->expr);
} else {
diff --git a/src/schema_compile.c b/src/schema_compile.c
index c2f120e..80996ad 100644
--- a/src/schema_compile.c
+++ b/src/schema_compile.c
@@ -1003,8 +1003,8 @@
assert(node->nodetype & (LYS_LEAF | LYS_LEAFLIST));
- /* try to find the target */
- LY_CHECK_RET(ly_path_compile(ctx->ctx, lref->cur_mod, node, NULL, lref->path, LY_PATH_LREF_TRUE,
+ /* try to find the target, current module is that of the context node (RFC 7950 6.4.1 second bullet) */
+ LY_CHECK_RET(ly_path_compile_leafref(ctx->ctx, node, NULL, lref->path,
(node->flags & LYS_IS_OUTPUT) ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_MANY,
LY_VALUE_SCHEMA_RESOLVED, lref->prefixes, unres, &p));
diff --git a/src/schema_compile_node.c b/src/schema_compile_node.c
index ee177da..cc3b678 100644
--- a/src/schema_compile_node.c
+++ b/src/schema_compile_node.c
@@ -1370,7 +1370,6 @@
ret = lyxp_expr_dup(ctx->ctx, ((struct lysc_type_leafref *)un_aux->types[v])->path, &lref->path);
LY_CHECK_GOTO(ret, error);
lref->refcount = 1;
- lref->cur_mod = ((struct lysc_type_leafref *)un_aux->types[v])->cur_mod;
lref->require_instance = ((struct lysc_type_leafref *)un_aux->types[v])->require_instance;
ret = lyplg_type_prefix_data_dup(ctx->ctx, LY_VALUE_SCHEMA_RESOLVED,
((struct lysc_type_leafref *)un_aux->types[v])->prefixes, (void **)&lref->prefixes);
@@ -1635,7 +1634,6 @@
LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "path", "leafref type", "");
return LY_EVALID;
}
- lref->cur_mod = type_p->pmod->mod;
break;
case LY_TYPE_INST:
/* RFC 7950 9.9.3 - require-instance */
diff --git a/src/tree_data.c b/src/tree_data.c
index cdb61b3..0c4917a 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -1778,13 +1778,13 @@
}
/* parse path */
- LY_CHECK_GOTO(ret = ly_path_parse(ctx, NULL, path, strlen(path), LY_PATH_BEGIN_EITHER, LY_PATH_LREF_FALSE,
- LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_SIMPLE, &exp), cleanup);
+ LY_CHECK_GOTO(ret = ly_path_parse(ctx, NULL, path, strlen(path), 0, LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_OPTIONAL,
+ LY_PATH_PRED_SIMPLE, &exp), cleanup);
/* compile path */
- LY_CHECK_GOTO(ret = ly_path_compile(ctx, NULL, parent ? parent->schema : NULL, ext, exp, LY_PATH_LREF_FALSE,
+ LY_CHECK_GOTO(ret = ly_path_compile(ctx, NULL, parent ? parent->schema : NULL, ext, exp,
options & LYD_NEW_PATH_OUTPUT ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_MANY, LY_VALUE_JSON,
- NULL, NULL, &p), cleanup);
+ NULL, &p), cleanup);
/* check the compiled path before searching existing nodes, it may be shortened */
orig_count = LY_ARRAY_COUNT(p);
@@ -4294,13 +4294,13 @@
LY_CHECK_ARG_RET(NULL, ctx_node, ctx_node->schema, path, LY_EINVAL);
/* parse the path */
- ret = ly_path_parse(LYD_CTX(ctx_node), ctx_node->schema, path, strlen(path), LY_PATH_BEGIN_EITHER, LY_PATH_LREF_FALSE,
+ ret = ly_path_parse(LYD_CTX(ctx_node), ctx_node->schema, path, strlen(path), 0, LY_PATH_BEGIN_EITHER,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_SIMPLE, &expr);
LY_CHECK_GOTO(ret, cleanup);
/* compile the path */
- ret = ly_path_compile(LYD_CTX(ctx_node), NULL, ctx_node->schema, NULL, expr, LY_PATH_LREF_FALSE,
- output ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_SINGLE, LY_VALUE_JSON, NULL, NULL, &lypath);
+ ret = ly_path_compile(LYD_CTX(ctx_node), NULL, ctx_node->schema, NULL, expr,
+ output ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_SINGLE, LY_VALUE_JSON, NULL, &lypath);
LY_CHECK_GOTO(ret, cleanup);
/* evaluate the path */
diff --git a/src/tree_schema.c b/src/tree_schema.c
index c9e8145..cebc59d 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -669,8 +669,7 @@
/* compile */
oper = output ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT;
- ret = ly_path_compile(ctx, NULL, ctx_node, NULL, expr, LY_PATH_LREF_FALSE, oper, LY_PATH_TARGET_MANY,
- LY_VALUE_JSON, NULL, NULL, &p);
+ ret = ly_path_compile(ctx, NULL, ctx_node, NULL, expr, oper, LY_PATH_TARGET_MANY, LY_VALUE_JSON, NULL, &p);
LY_CHECK_GOTO(ret, cleanup);
/* resolve */
@@ -703,8 +702,7 @@
/* compile */
oper = output ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT;
- ret = ly_path_compile(ctx, NULL, ctx_node, NULL, exp, LY_PATH_LREF_FALSE, oper, LY_PATH_TARGET_MANY,
- LY_VALUE_JSON, NULL, NULL, &p);
+ ret = ly_path_compile(ctx, NULL, ctx_node, NULL, exp, oper, LY_PATH_TARGET_MANY, LY_VALUE_JSON, NULL, &p);
LY_CHECK_GOTO(ret, cleanup);
/* get last node */
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 9e8dc96..0c413e0 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -1595,7 +1595,7 @@
uint32_t refcount; /**< reference counter for type sharing */
struct lyxp_expr *path; /**< parsed target path, compiled path cannot be stored because of type sharing */
struct lysc_prefix *prefixes; /**< resolved prefixes used in the path */
- const struct lys_module *cur_mod;/**< current module for the leafref (path) */
+ const struct lys_module *cur_mod;/**< unused, not needed */
struct lysc_type *realtype; /**< pointer to the real (first non-leafref in possible leafrefs chain) type. */
uint8_t require_instance; /**< require-instance flag */
};
diff --git a/src/xpath.c b/src/xpath.c
index a5651fc..8e97fc8 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -3739,7 +3739,8 @@
if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype),
sleaf->name);
- } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_LEAFREF) && !warn_is_specific_type(sleaf->type, LY_TYPE_INST)) {
+ } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_LEAFREF) &&
+ !warn_is_specific_type(sleaf->type, LY_TYPE_INST)) {
LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"leafref\" nor \"instance-identifier\".",
__func__, sleaf->name);
}
@@ -3750,8 +3751,8 @@
oper = (sleaf->flags & LYS_IS_OUTPUT) ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT;
/* it was already evaluated on schema, it must succeed */
- rc = ly_path_compile(set->ctx, lref->cur_mod, &sleaf->node, NULL, lref->path, LY_PATH_LREF_TRUE, oper,
- LY_PATH_TARGET_MANY, LY_VALUE_SCHEMA_RESOLVED, lref->prefixes, NULL, &p);
+ rc = ly_path_compile_leafref(set->ctx, &sleaf->node, NULL, lref->path, oper, LY_PATH_TARGET_MANY,
+ LY_VALUE_SCHEMA_RESOLVED, lref->prefixes, NULL, &p);
assert(!rc);
/* get the target node */
diff --git a/tests/utests/data/test_tree_data.c b/tests/utests/data/test_tree_data.c
index dc699a5..9f5e483 100644
--- a/tests/utests/data/test_tree_data.c
+++ b/tests/utests/data/test_tree_data.c
@@ -388,10 +388,10 @@
"</c></l2>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
- assert_int_equal(LY_SUCCESS, ly_path_parse(UTEST_LYCTX, NULL, path_str, strlen(path_str), LY_PATH_BEGIN_EITHER, LY_PATH_LREF_FALSE,
+ assert_int_equal(LY_SUCCESS, ly_path_parse(UTEST_LYCTX, NULL, path_str, strlen(path_str), 0, LY_PATH_BEGIN_EITHER,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_SIMPLE, &exp));
- assert_int_equal(LY_SUCCESS, ly_path_compile(UTEST_LYCTX, NULL, NULL, NULL, exp, LY_PATH_LREF_FALSE, LY_PATH_OPER_INPUT,
- LY_PATH_TARGET_SINGLE, LY_VALUE_JSON, NULL, NULL, &path));
+ assert_int_equal(LY_SUCCESS, ly_path_compile(UTEST_LYCTX, NULL, NULL, NULL, exp, LY_PATH_OPER_INPUT,
+ LY_PATH_TARGET_SINGLE, LY_VALUE_JSON, NULL, &path));
term = lyd_target(path, tree);
const int unsigned flag = LYS_CONFIG_R | LYS_SET_ENUM | LYS_ORDBY_USER;
diff --git a/tests/utests/schema/test_tree_schema_compile.c b/tests/utests/schema/test_tree_schema_compile.c
index b635fb4..75b645e 100644
--- a/tests/utests/schema/test_tree_schema_compile.c
+++ b/tests/utests/schema/test_tree_schema_compile.c
@@ -1477,28 +1477,28 @@
/* lys_path_parse() */
path = "invalid_path";
- assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
+ assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &expr));
path = "..";
- assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
+ assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &expr));
path = "..[";
- assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
+ assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &expr));
path = "../";
- assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
+ assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &expr));
path = "/";
- assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
+ assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &expr));
path = "../../pref:id/xxx[predicate]/invalid!!!";
- assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
+ assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &expr));
CHECK_LOG_CTX("Invalid character 0x21 ('!'), perhaps \"invalid\" is supposed to be a function call.", NULL);
path = "/absolute/prefix:path";
- assert_int_equal(LY_SUCCESS, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
+ assert_int_equal(LY_SUCCESS, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &expr));
assert_int_equal(4, expr->used);
assert_int_equal(LYXP_TOKEN_OPER_PATH, expr->tokens[0]);
@@ -2902,18 +2902,21 @@
assert_int_equal(LY_TYPE_IDENT, leaf->type->basetype);
ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "module y {namespace urn:y;prefix y;"
- "container cont {leaf l {type string;}}"
- "leaf bl2 {type string;}"
+ "leaf l1 {type string;}"
+ "leaf l2 {type string;}"
"}");
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module z {namespace urn:z;prefix z;"
"import y {prefix y;}"
- "deviation \"/y:cont/y:l\" {deviate replace {type leafref {path \"/al\";}}}"
- "leaf al {type string;}"
- "leaf al2 {type leafref {path \"/y:bl2\";}}"
+ "deviation \"/y:l1\" {deviate replace {type leafref {path \"/l2\";}}}"
+ "deviation \"/y:l2\" {deviate replace {type leafref {path \"/z:al2\";}}}"
+ "leaf al2 {type string;}"
"}", LYS_IN_YANG, NULL));
assert_non_null((mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "y")));
- assert_non_null(leaf = (struct lysc_node_leaf *)lysc_node_child(mod->compiled->data));
- assert_string_equal("l", leaf->name);
+ assert_non_null(leaf = (struct lysc_node_leaf *)mod->compiled->data);
+ assert_string_equal("l1", leaf->name);
+ assert_int_equal(LY_TYPE_LEAFREF, leaf->type->basetype);
+ leaf = (struct lysc_node_leaf *)leaf->next;
+ assert_string_equal("l2", leaf->name);
assert_int_equal(LY_TYPE_LEAFREF, leaf->type->basetype);
/* complex dependencies */