data tree NEW support for with-defaults attribute
Tests included.
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index 064e6cd..61f4a19 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -68,7 +68,7 @@
LY_ARRAY_CREATE_GOTO((CTX)->ctx, EXT_C, LY_ARRAY_SIZE(EXTS_P), RET, GOTO); \
for (uint32_t __exts_iter = 0, __array_offset = LY_ARRAY_SIZE(EXT_C); __exts_iter < LY_ARRAY_SIZE(EXTS_P); ++__exts_iter) { \
LY_ARRAY_INCREMENT(EXT_C); \
- RET = lys_compile_ext(CTX, &(EXTS_P)[__exts_iter], &(EXT_C)[__exts_iter + __array_offset], PARENT, PARENT_TYPE); \
+ RET = lys_compile_ext(CTX, &(EXTS_P)[__exts_iter], &(EXT_C)[__exts_iter + __array_offset], PARENT, PARENT_TYPE, NULL); \
LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
} \
}
@@ -441,13 +441,23 @@
return NULL;
}
+/**
+ * @brief Fill in the prepared compiled extension instance structure according to the parsed extension instance.
+ *
+ * @param[in] ctx Compilation context.
+ * @param[in] ext_p Parsed extension instance.
+ * @param[in,out] ext Prepared compiled extension instance.
+ * @param[in] parent Extension instance parent.
+ * @param[in] parent_type Extension instance parent type.
+ * @param[in] ext_mod Optional module with the extension instance extension definition, set only for internal annotations.
+ */
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)
+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)
{
LY_ERR ret = LY_EVALID;
const char *name;
unsigned int u;
- const struct lys_module *mod;
struct lysc_ext **elist = NULL;
const char *prefixed_name = NULL;
@@ -491,24 +501,26 @@
}
lysc_update_path(ctx, NULL, prefixed_name);
- mod = lys_module_find_prefix(ctx->mod_def, prefixed_name, u - 1);
- if (!mod) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Invalid prefix \"%.*s\" used for extension instance identifier.", u, prefixed_name);
- goto cleanup;
- } else if (!mod->parsed->extensions) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Extension instance \"%s\" refers \"%s\" module that does not contain extension definitions.",
- prefixed_name, mod->name);
- goto cleanup;
+ if (!ext_mod) {
+ ext_mod = lys_module_find_prefix(ctx->mod_def, prefixed_name, u - 1);
+ if (!ext_mod) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid prefix \"%.*s\" used for extension instance identifier.", u, prefixed_name);
+ goto cleanup;
+ } else if (!ext_mod->parsed->extensions) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Extension instance \"%s\" refers \"%s\" module that does not contain extension definitions.",
+ prefixed_name, ext_mod->name);
+ goto cleanup;
+ }
}
name = &prefixed_name[u];
/* find the extension definition there */
- if (mod->off_extensions) {
- elist = mod->off_extensions;
+ if (ext_mod->off_extensions) {
+ elist = ext_mod->off_extensions;
} else {
- elist = mod->compiled->extensions;
+ elist = ext_mod->compiled->extensions;
}
LY_ARRAY_FOR(elist, u) {
if (!strcmp(name, elist[u]->name)) {
@@ -7209,6 +7221,44 @@
return ret;
}
+static LY_ERR
+lys_compile_ietf_netconf_wd_annotation(struct lysc_ctx *ctx, struct lys_module *mod)
+{
+ struct lysc_ext_instance *ext;
+ struct lysp_ext_instance *ext_p = NULL;
+ struct lysp_stmt *stmt;
+ const struct lys_module *ext_mod;
+ LY_ERR ret = LY_SUCCESS;
+
+ /* create the parsed extension instance manually */
+ ext_p = calloc(1, sizeof *ext_p);
+ LY_CHECK_ERR_GOTO(!ext_p, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
+ ext_p->name = lydict_insert(ctx->ctx, "md:annotation", 0);
+ ext_p->argument = lydict_insert(ctx->ctx, "default", 0);
+ ext_p->insubstmt = LYEXT_SUBSTMT_SELF;
+ ext_p->insubstmt_index = 0;
+
+ stmt = calloc(1, sizeof *ext_p->child);
+ stmt->stmt = lydict_insert(ctx->ctx, "type", 0);
+ stmt->arg = lydict_insert(ctx->ctx, "boolean", 0);
+ stmt->kw = LY_STMT_TYPE;
+ ext_p->child = stmt;
+
+ /* allocate new extension instance */
+ LY_ARRAY_NEW_GOTO(mod->ctx, mod->compiled->exts, ext, ret, cleanup);
+
+ /* manually get extension definition module */
+ ext_mod = ly_ctx_get_module_latest(ctx->ctx, "ietf-yang-metadata");
+
+ /* compile the extension instance */
+ LY_CHECK_GOTO(ret = lys_compile_ext(ctx, ext_p, ext, mod->compiled, LYEXT_PAR_MODULE, ext_mod), cleanup);
+
+cleanup:
+ lysp_ext_instance_free(ctx->ctx, ext_p);
+ free(ext_p);
+ return ret;
+}
+
LY_ERR
lys_compile(struct lys_module *mod, int options)
{
@@ -7408,6 +7458,24 @@
leafref paths, default values and must/when expressions in all schemas of the context to check that they are still valid */
}
+#if 0
+ /* hack for NETCONF's edit-config's operation attribute. It is not defined in the schema, but since libyang
+ * implements YANG metadata (annotations), we need its definition. Because the ietf-netconf schema is not the
+ * internal part of libyang, we cannot add the annotation into the schema source, but we do it here to have
+ * the anotation definitions available in the internal schema structure. */
+ if (ly_strequal(mod->name, "ietf-netconf", 0)) {
+ if (lyp_add_ietf_netconf_annotations(mod)) {
+ lys_free(mod, NULL, 1, 1);
+ return NULL;
+ }
+ }
+#endif
+
+ /* add ietf-netconf-with-defaults "default" metadata to the compiled module */
+ if (!strcmp(mod->name, "ietf-netconf-with-defaults")) {
+ LY_CHECK_GOTO(ret = lys_compile_ietf_netconf_wd_annotation(&ctx, mod), error);
+ }
+
ly_set_erase(&ctx.dflts, free);
ly_set_erase(&ctx.unres, NULL);
ly_set_erase(&ctx.groupings, NULL);