blob: 5db58e013ff89c7c6d091145217469b3e02e706c [file] [log] [blame]
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001/**
2 * @file schema_compile.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Schema compilation.
5 *
6 * Copyright (c) 2015 - 2020 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15#define _GNU_SOURCE
16
17#include "schema_compile.h"
18
19#include <assert.h>
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020020#include <stddef.h>
21#include <stdint.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include "common.h"
27#include "compat.h"
28#include "context.h"
29#include "dict.h"
Michal Vaskoafac7822020-10-20 14:22:26 +020030#include "in.h"
Radek Krejci47fab892020-11-05 17:02:41 +010031#include "log.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020032#include "parser_schema.h"
33#include "path.h"
34#include "plugins_exts.h"
35#include "plugins_exts_internal.h"
36#include "plugins_types.h"
37#include "schema_compile_amend.h"
38#include "schema_compile_node.h"
Michal Vasko7b1ad1a2020-11-02 15:41:27 +010039#include "schema_features.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020040#include "set.h"
41#include "tree.h"
42#include "tree_data.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020043#include "tree_schema.h"
44#include "tree_schema_internal.h"
45#include "xpath.h"
46
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020047/**
48 * @brief Fill in the prepared compiled extensions definition structure according to the parsed extension definition.
49 */
50static LY_ERR
51lys_compile_extension(struct lysc_ctx *ctx, const struct lys_module *ext_mod, struct lysp_ext *ext_p, struct lysc_ext **ext)
52{
53 LY_ERR ret = LY_SUCCESS;
54
Radek Krejci720d2612021-03-03 19:44:22 +010055 if (ext_p->compiled && (ext_p->compiled->refcount == 1)) {
56 /* context recompilation - all the extension instances were previously freed (the last link to the compiled extension
57 * remains from the parsed extension definition) and now we are recompiling them again, to have the up-to-date
58 * extension definition, we have to recompile it as well now */
59 lysc_extension_free(ctx->ctx, &ext_p->compiled);
60 }
61
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020062 if (!ext_p->compiled) {
63 lysc_update_path(ctx, NULL, "{extension}");
64 lysc_update_path(ctx, NULL, ext_p->name);
65
66 /* compile the extension definition */
67 ext_p->compiled = calloc(1, sizeof **ext);
68 ext_p->compiled->refcount = 1;
69 DUP_STRING_GOTO(ctx->ctx, ext_p->name, ext_p->compiled->name, ret, done);
70 DUP_STRING_GOTO(ctx->ctx, ext_p->argument, ext_p->compiled->argument, ret, done);
71 ext_p->compiled->module = (struct lys_module *)ext_mod;
Radek Krejciab430862021-03-02 20:13:40 +010072 COMPILE_EXTS_GOTO(ctx, ext_p->exts, ext_p->compiled->exts, *ext, ret, done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020073
74 lysc_update_path(ctx, NULL, NULL);
75 lysc_update_path(ctx, NULL, NULL);
76
77 /* find extension definition plugin */
78 ext_p->compiled->plugin = lyext_get_plugin(ext_p->compiled);
79 }
80
81 *ext = lysc_ext_dup(ext_p->compiled);
82
83done:
Radek Krejci2efc45b2020-12-22 16:25:44 +010084 if (ret) {
85 lysc_update_path(ctx, NULL, NULL);
86 lysc_update_path(ctx, NULL, NULL);
87 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020088 return ret;
89}
90
91LY_ERR
92lys_compile_ext(struct lysc_ctx *ctx, struct lysp_ext_instance *ext_p, struct lysc_ext_instance *ext, void *parent,
Radek Krejciab430862021-03-02 20:13:40 +010093 const struct lys_module *ext_mod)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020094{
Michal Vaskofc2cd072021-02-24 13:17:17 +010095 LY_ERR r, ret = LY_SUCCESS;
96 const char *tmp, *name, *prefix;
97 size_t pref_len, name_len;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020098 LY_ARRAY_COUNT_TYPE v;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020099
100 DUP_STRING(ctx->ctx, ext_p->argument, ext->argument, ret);
101 LY_CHECK_RET(ret);
102
Radek Krejciab430862021-03-02 20:13:40 +0100103 ext->parent_stmt = ext_p->parent_stmt;
104 ext->parent_stmt_index = ext_p->parent_stmt_index;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200105 ext->module = ctx->cur_mod;
106 ext->parent = parent;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200107
Radek Krejciab430862021-03-02 20:13:40 +0100108 lysc_update_path(ctx, LY_STMT_IS_NODE(ext->parent_stmt) ? ((struct lysc_node *)ext->parent)->module : NULL, "{extension}");
Michal Vaskofc2cd072021-02-24 13:17:17 +0100109 lysc_update_path(ctx, NULL, ext_p->name);
110
111 /* parse the prefix */
112 tmp = ext_p->name;
113 r = ly_parse_nodeid(&tmp, &prefix, &pref_len, &name, &name_len);
114 /* it was parsed already */
115 assert(!r && !tmp[0]);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200116
117 /* get module where the extension definition should be placed */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200118 if (!ext_mod) {
Michal Vaskofc2cd072021-02-24 13:17:17 +0100119 ext_mod = ly_resolve_prefix(ctx->ctx, prefix, pref_len, ext_p->format, ext_p->prefix_data);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200120 if (!ext_mod) {
Michal Vaskofc2cd072021-02-24 13:17:17 +0100121 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid prefix \"%.*s\" used for extension instance identifier.",
122 pref_len, prefix);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200123 ret = LY_EVALID;
124 goto cleanup;
125 } else if (!ext_mod->parsed->extensions) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100126 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200127 "Extension instance \"%s\" refers \"%s\" module that does not contain extension definitions.",
Michal Vaskofc2cd072021-02-24 13:17:17 +0100128 ext_p->name, ext_mod->name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200129 ret = LY_EVALID;
130 goto cleanup;
131 }
132 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200133
134 /* find the parsed extension definition there */
135 LY_ARRAY_FOR(ext_mod->parsed->extensions, v) {
136 if (!strcmp(name, ext_mod->parsed->extensions[v].name)) {
137 /* compile extension definition and assign it */
138 LY_CHECK_GOTO(ret = lys_compile_extension(ctx, ext_mod, &ext_mod->parsed->extensions[v], &ext->def), cleanup);
139 break;
140 }
141 }
142 if (!ext->def) {
Michal Vaskofc2cd072021-02-24 13:17:17 +0100143 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Extension definition of extension instance \"%s\" not found.", ext_p->name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200144 ret = LY_EVALID;
145 goto cleanup;
146 }
147
148 /* unify the parsed extension from YIN and YANG sources. Without extension definition, it is not possible
149 * to get extension's argument from YIN source, so it is stored as one of the substatements. Here we have
150 * to find it, mark it with LYS_YIN_ARGUMENT and store it in the compiled structure. */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100151 if ((ext_p->format == LY_PREF_XML) && ext->def->argument && !ext->argument) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200152 /* Schema was parsed from YIN and an argument is expected, ... */
153 struct lysp_stmt *stmt = NULL;
154
155 if (ext->def->flags & LYS_YINELEM_TRUE) {
156 /* ... argument was the first XML child element */
157 if (ext_p->child && !(ext_p->child->flags & LYS_YIN_ATTR)) {
158 /* TODO check namespace of the statement */
159 if (!strcmp(ext_p->child->stmt, ext->def->argument)) {
160 stmt = ext_p->child;
161 }
162 }
163 } else {
164 /* ... argument was one of the XML attributes which are represented as child stmt
165 * with LYS_YIN_ATTR flag */
166 for (stmt = ext_p->child; stmt && (stmt->flags & LYS_YIN_ATTR); stmt = stmt->next) {
167 if (!strcmp(stmt->stmt, ext->def->argument)) {
168 /* this is the extension's argument */
169 break;
170 }
171 }
172 }
173 if (!stmt) {
174 /* missing extension's argument */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100175 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Extension instance \"%s\" misses argument \"%s\".",
176 ext_p->name, ext->def->argument);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200177 ret = LY_EVALID;
178 goto cleanup;
179
180 }
181 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, stmt->arg, 0, &ext->argument), cleanup);
182 stmt->flags |= LYS_YIN_ARGUMENT;
183 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200184
185 if (ext->def->plugin && ext->def->plugin->compile) {
186 if (ext->argument) {
Radek Krejcia6016992021-03-03 10:13:41 +0100187 lysc_update_path(ctx, ext->module, ext->argument);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200188 }
Michal Vaskofc2cd072021-02-24 13:17:17 +0100189 ret = ext->def->plugin->compile(ctx, ext_p, ext);
Radek Krejcicc21a4f2021-02-09 15:23:31 +0100190 if (ret == LY_ENOT) {
191 lysc_ext_instance_free(ctx->ctx, ext);
192 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200193 if (ext->argument) {
194 lysc_update_path(ctx, NULL, NULL);
195 }
Michal Vaskofc2cd072021-02-24 13:17:17 +0100196 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200197 }
198 ext_p->compiled = ext;
199
200cleanup:
Radek Krejci2efc45b2020-12-22 16:25:44 +0100201 lysc_update_path(ctx, NULL, NULL);
Michal Vaskofc2cd072021-02-24 13:17:17 +0100202 lysc_update_path(ctx, NULL, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200203
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200204 return ret;
205}
206
207struct lysc_ext *
208lysc_ext_dup(struct lysc_ext *orig)
209{
210 ++orig->refcount;
211 return orig;
212}
213
Radek Krejci1b2eef82021-02-17 11:17:27 +0100214LY_ERR
215lysc_ext_substmt(const struct lysc_ext_instance *ext, enum ly_stmt substmt, void **instance_p, enum ly_stmt_cardinality *cardinality_p)
216{
217 LY_ARRAY_COUNT_TYPE u;
218
219 LY_ARRAY_FOR(ext->substmts, u) {
Radek Krejci61837f72021-03-02 19:53:59 +0100220 if (LY_STMT_IS_DATA_NODE(substmt)) {
221 if (!LY_STMT_IS_DATA_NODE(ext->substmts[u].stmt)) {
Radek Krejci1b2eef82021-02-17 11:17:27 +0100222 continue;
223 }
224 } else if (LY_STMT_IS_OP(substmt)) {
225 if (!LY_STMT_IS_OP(ext->substmts[u].stmt)) {
226 continue;
227 }
228 } else if (ext->substmts[u].stmt != substmt) {
229 continue;
230 }
231
232 /* match */
233 if (cardinality_p) {
234 *cardinality_p = ext->substmts[u].cardinality;
235 }
236 if (instance_p) {
237 *instance_p = ext->substmts[u].storage;
238 }
239 return LY_SUCCESS;
240 }
241
242 return LY_ENOT;
243}
244
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200245static void
246lysc_unres_dflt_free(const struct ly_ctx *ctx, struct lysc_unres_dflt *r)
247{
248 assert(!r->dflt || !r->dflts);
249 if (r->dflt) {
250 lysp_qname_free((struct ly_ctx *)ctx, r->dflt);
251 free(r->dflt);
252 } else {
253 FREE_ARRAY((struct ly_ctx *)ctx, r->dflts, lysp_qname_free);
254 }
255 free(r);
256}
257
258void
Radek Krejcia6016992021-03-03 10:13:41 +0100259lysc_update_path(struct lysc_ctx *ctx, struct lys_module *parent_module, const char *name)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200260{
261 int len;
262 uint8_t nextlevel = 0; /* 0 - no starttag, 1 - '/' starttag, 2 - '=' starttag + '}' endtag */
263
264 if (!name) {
265 /* removing last path segment */
266 if (ctx->path[ctx->path_len - 1] == '}') {
267 for ( ; ctx->path[ctx->path_len] != '=' && ctx->path[ctx->path_len] != '{'; --ctx->path_len) {}
268 if (ctx->path[ctx->path_len] == '=') {
269 ctx->path[ctx->path_len++] = '}';
270 } else {
271 /* not a top-level special tag, remove also preceiding '/' */
272 goto remove_nodelevel;
273 }
274 } else {
275remove_nodelevel:
276 for ( ; ctx->path[ctx->path_len] != '/'; --ctx->path_len) {}
277 if (ctx->path_len == 0) {
278 /* top-level (last segment) */
279 ctx->path_len = 1;
280 }
281 }
282 /* set new terminating NULL-byte */
283 ctx->path[ctx->path_len] = '\0';
284 } else {
285 if (ctx->path_len > 1) {
Radek Krejcia6016992021-03-03 10:13:41 +0100286 if (!parent_module && (ctx->path[ctx->path_len - 1] == '}') && (ctx->path[ctx->path_len - 2] != '\'')) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200287 /* extension of the special tag */
288 nextlevel = 2;
289 --ctx->path_len;
290 } else {
291 /* there is already some path, so add next level */
292 nextlevel = 1;
293 }
294 } /* else the path is just initiated with '/', so do not add additional slash in case of top-level nodes */
295
296 if (nextlevel != 2) {
Radek Krejcia6016992021-03-03 10:13:41 +0100297 if ((parent_module && (parent_module == ctx->cur_mod)) || (!parent_module && (ctx->path_len > 1) && (name[0] == '{'))) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200298 /* module not changed, print the name unprefixed */
299 len = snprintf(&ctx->path[ctx->path_len], LYSC_CTX_BUFSIZE - ctx->path_len, "%s%s", nextlevel ? "/" : "", name);
300 } else {
301 len = snprintf(&ctx->path[ctx->path_len], LYSC_CTX_BUFSIZE - ctx->path_len, "%s%s:%s", nextlevel ? "/" : "", ctx->cur_mod->name, name);
302 }
303 } else {
304 len = snprintf(&ctx->path[ctx->path_len], LYSC_CTX_BUFSIZE - ctx->path_len, "='%s'}", name);
305 }
306 if (len >= LYSC_CTX_BUFSIZE - (int)ctx->path_len) {
307 /* output truncated */
308 ctx->path_len = LYSC_CTX_BUFSIZE - 1;
309 } else {
310 ctx->path_len += len;
311 }
312 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100313
Radek Krejciddace2c2021-01-08 11:30:56 +0100314 LOG_LOCBACK(0, 0, 1, 0);
315 LOG_LOCSET(NULL, NULL, ctx->path, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200316}
317
318/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200319 * @brief Compile information in the import statement - make sure there is the target module
320 * @param[in] ctx Compile context.
321 * @param[in] imp_p The parsed import statement structure to fill the module to.
322 * @return LY_ERR value.
323 */
324static LY_ERR
325lys_compile_import(struct lysc_ctx *ctx, struct lysp_import *imp_p)
326{
327 const struct lys_module *mod = NULL;
328 LY_ERR ret = LY_SUCCESS;
329
330 /* make sure that we have the parsed version (lysp_) of the imported module to import groupings or typedefs.
331 * The compiled version is needed only for augments, deviates and leafrefs, so they are checked (and added,
332 * if needed) when these nodes are finally being instantiated and validated at the end of schema compilation. */
333 if (!imp_p->module->parsed) {
334 /* try to use filepath if present */
335 if (imp_p->module->filepath) {
336 struct ly_in *in;
337 if (ly_in_new_filepath(imp_p->module->filepath, 0, &in)) {
338 LOGINT(ctx->ctx);
339 } else {
340 LY_CHECK_RET(lys_parse(ctx->ctx, in, !strcmp(&imp_p->module->filepath[strlen(imp_p->module->filepath - 4)],
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100341 ".yin") ? LYS_IN_YIN : LYS_IN_YANG, NULL, &mod));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200342 if (mod != imp_p->module) {
343 LOGERR(ctx->ctx, LY_EINT, "Filepath \"%s\" of the module \"%s\" does not match.",
344 imp_p->module->filepath, imp_p->module->name);
345 mod = NULL;
346 }
347 }
348 ly_in_free(in, 1);
349 }
350 if (!mod) {
Michal Vasko405cc9e2020-12-01 12:01:27 +0100351 if (lysp_load_module(ctx->ctx, imp_p->module->name, imp_p->module->revision, 0, NULL, ctx->unres,
352 (struct lys_module **)&mod)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200353 LOGERR(ctx->ctx, LY_ENOTFOUND, "Unable to reload \"%s\" module to import it into \"%s\", source data not found.",
354 imp_p->module->name, ctx->cur_mod->name);
355 return LY_ENOTFOUND;
356 }
357 }
358 }
359
360 return ret;
361}
362
363LY_ERR
364lys_identity_precompile(struct lysc_ctx *ctx_sc, struct ly_ctx *ctx, struct lysp_module *parsed_mod,
365 struct lysp_ident *identities_p, struct lysc_ident **identities)
366{
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100367 LY_ARRAY_COUNT_TYPE u;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200368 struct lysc_ctx context = {0};
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100369 struct lysc_ident *ident;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200370 LY_ERR ret = LY_SUCCESS;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100371 ly_bool enabled;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200372
373 assert(ctx_sc || ctx);
374
375 if (!ctx_sc) {
376 context.ctx = ctx;
Radek Krejci3aac9a72020-12-01 12:24:26 +0100377 context.cur_mod = parsed_mod ? parsed_mod->mod : NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200378 context.pmod = parsed_mod;
379 context.path_len = 1;
380 context.path[0] = '/';
381 ctx_sc = &context;
382 }
383
384 if (!identities_p) {
385 return LY_SUCCESS;
386 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200387
388 lysc_update_path(ctx_sc, NULL, "{identity}");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200389 LY_ARRAY_FOR(identities_p, u) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100390 /* evaluate if-features */
391 LY_CHECK_RET(lys_eval_iffeatures(ctx, identities_p[u].iffeatures, &enabled));
392 if (!enabled) {
393 continue;
394 }
395
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200396 lysc_update_path(ctx_sc, NULL, identities_p[u].name);
397
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100398 /* add new compiled identity */
399 LY_ARRAY_NEW_RET(ctx_sc->ctx, *identities, ident, LY_EMEM);
400
401 DUP_STRING_GOTO(ctx_sc->ctx, identities_p[u].name, ident->name, ret, done);
402 DUP_STRING_GOTO(ctx_sc->ctx, identities_p[u].dsc, ident->dsc, ret, done);
403 DUP_STRING_GOTO(ctx_sc->ctx, identities_p[u].ref, ident->ref, ret, done);
404 ident->module = ctx_sc->cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200405 /* backlinks (derived) can be added no sooner than when all the identities in the current module are present */
Radek Krejciab430862021-03-02 20:13:40 +0100406 COMPILE_EXTS_GOTO(ctx_sc, identities_p[u].exts, ident->exts, ident, ret, done);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100407 ident->flags = identities_p[u].flags;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200408
409 lysc_update_path(ctx_sc, NULL, NULL);
410 }
411 lysc_update_path(ctx_sc, NULL, NULL);
412done:
413 return ret;
414}
415
416/**
417 * @brief Check circular dependency of identities - identity MUST NOT reference itself (via their base statement).
418 *
419 * The function works in the same way as lys_compile_feature_circular_check() with different structures and error messages.
420 *
421 * @param[in] ctx Compile context for logging.
422 * @param[in] ident The base identity (its derived list is being extended by the identity being currently processed).
423 * @param[in] derived The list of derived identities of the identity being currently processed (not the one provided as @p ident)
424 * @return LY_SUCCESS if everything is ok.
425 * @return LY_EVALID if the identity is derived from itself.
426 */
427static LY_ERR
428lys_compile_identity_circular_check(struct lysc_ctx *ctx, struct lysc_ident *ident, struct lysc_ident **derived)
429{
430 LY_ERR ret = LY_SUCCESS;
431 LY_ARRAY_COUNT_TYPE u, v;
432 struct ly_set recursion = {0};
433 struct lysc_ident *drv;
434
435 if (!derived) {
436 return LY_SUCCESS;
437 }
438
439 for (u = 0; u < LY_ARRAY_COUNT(derived); ++u) {
440 if (ident == derived[u]) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100441 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200442 "Identity \"%s\" is indirectly derived from itself.", ident->name);
443 ret = LY_EVALID;
444 goto cleanup;
445 }
446 ret = ly_set_add(&recursion, derived[u], 0, NULL);
447 LY_CHECK_GOTO(ret, cleanup);
448 }
449
450 for (v = 0; v < recursion.count; ++v) {
451 drv = recursion.objs[v];
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200452 for (u = 0; u < LY_ARRAY_COUNT(drv->derived); ++u) {
453 if (ident == drv->derived[u]) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100454 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200455 "Identity \"%s\" is indirectly derived from itself.", ident->name);
456 ret = LY_EVALID;
457 goto cleanup;
458 }
459 ret = ly_set_add(&recursion, drv->derived[u], 0, NULL);
460 LY_CHECK_GOTO(ret, cleanup);
461 }
462 }
463
464cleanup:
465 ly_set_erase(&recursion, NULL);
466 return ret;
467}
468
469LY_ERR
470lys_compile_identity_bases(struct lysc_ctx *ctx, const struct lysp_module *base_pmod, const char **bases_p,
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100471 struct lysc_ident *ident, struct lysc_ident ***bases, ly_bool *enabled)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200472{
473 LY_ARRAY_COUNT_TYPE u, v;
474 const char *s, *name;
475 const struct lys_module *mod;
476 struct lysc_ident **idref;
477
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100478 assert((ident && enabled) || bases);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200479
480 if ((LY_ARRAY_COUNT(bases_p) > 1) && (ctx->pmod->version < LYS_VERSION_1_1)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100481 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200482 "Multiple bases in %s are allowed only in YANG 1.1 modules.", ident ? "identity" : "identityref type");
483 return LY_EVALID;
484 }
485
486 LY_ARRAY_FOR(bases_p, u) {
487 s = strchr(bases_p[u], ':');
488 if (s) {
489 /* prefixed identity */
490 name = &s[1];
Michal Vaskob2d55bf2020-11-02 15:42:43 +0100491 mod = ly_resolve_prefix(ctx->ctx, bases_p[u], s - bases_p[u], LY_PREF_SCHEMA, (void *)base_pmod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200492 } else {
493 name = bases_p[u];
494 mod = base_pmod->mod;
495 }
496 if (!mod) {
497 if (ident) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100498 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200499 "Invalid prefix used for base (%s) of identity \"%s\".", bases_p[u], ident->name);
500 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100501 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200502 "Invalid prefix used for base (%s) of identityref.", bases_p[u]);
503 }
504 return LY_EVALID;
505 }
506
507 idref = NULL;
508 LY_ARRAY_FOR(mod->identities, v) {
509 if (!strcmp(name, mod->identities[v].name)) {
510 if (ident) {
511 if (ident == &mod->identities[v]) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100512 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200513 "Identity \"%s\" is derived from itself.", ident->name);
514 return LY_EVALID;
515 }
516 LY_CHECK_RET(lys_compile_identity_circular_check(ctx, &mod->identities[v], ident->derived));
517 /* we have match! store the backlink */
518 LY_ARRAY_NEW_RET(ctx->ctx, mod->identities[v].derived, idref, LY_EMEM);
519 *idref = ident;
520 } else {
521 /* we have match! store the found identity */
522 LY_ARRAY_NEW_RET(ctx->ctx, *bases, idref, LY_EMEM);
523 *idref = &mod->identities[v];
524 }
525 break;
526 }
527 }
528 if (!idref || !(*idref)) {
529 if (ident) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100530 /* look into the parsed module to check whether the identity is not merely disabled */
531 LY_ARRAY_FOR(mod->parsed->identities, v) {
532 if (!strcmp(mod->parsed->identities[v].name, name)) {
533 *enabled = 0;
534 return LY_SUCCESS;
535 }
536 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100537 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200538 "Unable to find base (%s) of identity \"%s\".", bases_p[u], ident->name);
539 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100540 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200541 "Unable to find base (%s) of identityref.", bases_p[u]);
542 }
543 return LY_EVALID;
544 }
545 }
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100546
547 if (ident) {
548 *enabled = 1;
549 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200550 return LY_SUCCESS;
551}
552
553/**
554 * @brief For the given array of identities, set the backlinks from all their base identities.
555 * @param[in] ctx Compile context, not only for logging but also to get the current module to resolve prefixes.
556 * @param[in] idents_p Array of identities definitions from the parsed schema structure.
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100557 * @param[in,out] idents Array of referencing identities to which the backlinks are supposed to be set. Any
558 * identities with disabled bases are removed.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200559 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
560 */
561static LY_ERR
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100562lys_compile_identities_derived(struct lysc_ctx *ctx, struct lysp_ident *idents_p, struct lysc_ident **idents)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200563{
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100564 LY_ARRAY_COUNT_TYPE u, v;
565 ly_bool enabled;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200566
567 lysc_update_path(ctx, NULL, "{identity}");
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100568
569restart:
Radek Krejcic7d13e32020-12-09 12:32:24 +0100570 for (u = 0, v = 0; u < LY_ARRAY_COUNT(*idents); ++u) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100571 /* find matching parsed identity, the disabled ones are missing in the compiled array */
572 while (v < LY_ARRAY_COUNT(idents_p)) {
573 if (idents_p[v].name == (*idents)[u].name) {
574 break;
575 }
576 ++v;
577 }
578 assert(v < LY_ARRAY_COUNT(idents_p));
579
580 if (!idents_p[v].bases) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200581 continue;
582 }
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100583 lysc_update_path(ctx, NULL, (*idents)[u].name);
584 LY_CHECK_RET(lys_compile_identity_bases(ctx, (*idents)[u].module->parsed, idents_p[v].bases, &(*idents)[u], NULL,
585 &enabled));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200586 lysc_update_path(ctx, NULL, NULL);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100587
588 if (!enabled) {
589 /* remove the identity */
590 lysc_ident_free(ctx->ctx, &(*idents)[u]);
591 LY_ARRAY_DECREMENT(*idents);
592 if (u < LY_ARRAY_COUNT(*idents)) {
593 memmove(&(*idents)[u], &(*idents)[u + 1], (LY_ARRAY_COUNT(*idents) - u) * sizeof **idents);
594 }
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100595
596 /* revert compilation of all the previous identities */
597 for (v = 0; v < u; ++v) {
598 LY_ARRAY_FREE((*idents)[v].derived);
599 }
600
Michal Vasko74c82ae2020-11-03 17:36:53 +0100601 /* free the whole array if there are no identites left */
602 if (!LY_ARRAY_COUNT(*idents)) {
603 LY_ARRAY_FREE(*idents);
604 *idents = NULL;
605 }
606
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100607 /* restart the whole process without this identity */
608 goto restart;
609 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200610 }
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100611
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200612 lysc_update_path(ctx, NULL, NULL);
613 return LY_SUCCESS;
614}
615
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200616static void *
617lys_compile_extension_instance_storage(enum ly_stmt stmt, struct lysc_ext_substmt *substmts)
618{
619 for (LY_ARRAY_COUNT_TYPE u = 0; substmts[u].stmt; ++u) {
620 if (substmts[u].stmt == stmt) {
621 return substmts[u].storage;
622 }
623 }
624 return NULL;
625}
626
627LY_ERR
Radek Krejci6b88a462021-02-17 12:39:34 +0100628lys_compile_extension_instance(struct lysc_ctx *ctx, const struct lysp_ext_instance *ext_p, struct lysc_ext_instance *ext)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200629{
630 LY_ERR ret = LY_EVALID, r;
631 LY_ARRAY_COUNT_TYPE u;
632 struct lysp_stmt *stmt;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200633 void *parsed = NULL, **compiled = NULL;
634
635 /* check for invalid substatements */
Radek Krejci6b88a462021-02-17 12:39:34 +0100636 for (stmt = ext_p->child; stmt; stmt = stmt->next) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200637 if (stmt->flags & (LYS_YIN_ATTR | LYS_YIN_ARGUMENT)) {
638 continue;
639 }
Radek Krejci6b88a462021-02-17 12:39:34 +0100640 LY_ARRAY_FOR(ext->substmts, u) {
641 if (ext->substmts[u].stmt == stmt->kw) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200642 break;
643 }
644 }
Radek Krejci6b88a462021-02-17 12:39:34 +0100645 if (u == LY_ARRAY_COUNT(ext->substmts)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100646 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s%s%s\" extension instance.",
Radek Krejci6b88a462021-02-17 12:39:34 +0100647 stmt->stmt, ext_p->name, ext_p->argument ? " " : "", ext_p->argument ? ext_p->argument : "");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200648 goto cleanup;
649 }
650 }
651
652 /* TODO store inherited data, e.g. status first, but mark them somehow to allow to overwrite them and not detect duplicity */
653
Radek Krejci6b88a462021-02-17 12:39:34 +0100654 /* note into the compile context that we are processing extension now */
655 ctx->ext = ext;
656
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200657 /* keep order of the processing the same as the order in the defined substmts,
658 * the order is important for some of the statements depending on others (e.g. type needs status and units) */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200659
Radek Krejci6b88a462021-02-17 12:39:34 +0100660 LY_ARRAY_FOR(ext->substmts, u) {
661 uint64_t stmt_counter = 0;
662
663 for (stmt = ext_p->child; stmt; stmt = stmt->next) {
664 if (ext->substmts[u].stmt != stmt->kw) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200665 continue;
666 }
667
Radek Krejci6b88a462021-02-17 12:39:34 +0100668 parsed = NULL;
669 stmt_counter++;
670 if (ext->substmts[u].storage) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200671 switch (stmt->kw) {
Radek Krejci6b88a462021-02-17 12:39:34 +0100672 case LY_STMT_ACTION:
673 case LY_STMT_ANYDATA:
674 case LY_STMT_ANYXML:
675 case LY_STMT_CONTAINER:
676 case LY_STMT_CHOICE:
677 case LY_STMT_LEAF:
678 case LY_STMT_LEAF_LIST:
679 case LY_STMT_LIST:
680 case LY_STMT_NOTIFICATION:
681 case LY_STMT_RPC:
682 case LY_STMT_USES:
683 r = lysp_stmt_parse(ctx, stmt, &parsed, NULL);
684 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
685
686 /* set storage as an alternative document root in the compile context */
687 r = lys_compile_node(ctx, parsed, NULL, 0, NULL);
688 lysp_node_free(ctx->ctx, parsed);
689 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200690 break;
Radek Krejci1b2eef82021-02-17 11:17:27 +0100691 case LY_STMT_DESCRIPTION:
692 case LY_STMT_REFERENCE:
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200693 case LY_STMT_UNITS: {
Radek Krejci6b88a462021-02-17 12:39:34 +0100694 const char **str_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200695
Radek Krejci6b88a462021-02-17 12:39:34 +0100696 if (ext->substmts[u].cardinality < LY_STMT_CARD_SOME) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200697 /* single item */
Radek Krejci6b88a462021-02-17 12:39:34 +0100698 if (*((const char **)ext->substmts[u].storage)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100699 LOGVAL(ctx->ctx, LY_VCODE_DUPSTMT, stmt->stmt);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200700 goto cleanup;
701 }
Radek Krejci6b88a462021-02-17 12:39:34 +0100702 str_p = (const char **)ext->substmts[u].storage;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200703 } else {
704 /* sized array */
Radek Krejci6b88a462021-02-17 12:39:34 +0100705 const char ***strings_array = (const char ***)ext->substmts[u].storage;
706 LY_ARRAY_NEW_GOTO(ctx->ctx, *strings_array, str_p, ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200707 }
Radek Krejci6b88a462021-02-17 12:39:34 +0100708 r = lydict_insert(ctx->ctx, stmt->arg, 0, str_p);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200709 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
710 break;
711 }
Radek Krejci6b88a462021-02-17 12:39:34 +0100712 case LY_STMT_IF_FEATURE: {
713 ly_bool enabled;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200714
Radek Krejci76c8c4e2021-02-17 10:16:48 +0100715 r = lysp_stmt_parse(ctx, stmt, &parsed, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200716 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
Radek Krejci6b88a462021-02-17 12:39:34 +0100717
718 r = lys_eval_iffeatures(ctx->ctx, parsed, &enabled);
719 FREE_ARRAY(ctx->ctx, (struct lysp_qname *)parsed, lysp_qname_free);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100720 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
721 if (!enabled) {
722 /* it is disabled, remove the whole extension instance */
723 return LY_ENOT;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200724 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200725 break;
Radek Krejci6b88a462021-02-17 12:39:34 +0100726 }
727 case LY_STMT_STATUS:
728 assert(ext->substmts[u].cardinality < LY_STMT_CARD_SOME);
729 LY_CHECK_ERR_GOTO(r = lysp_stmt_parse(ctx, stmt, &ext->substmts[u].storage, /* TODO */ NULL), ret = r, cleanup);
730 break;
731 case LY_STMT_TYPE: {
732 uint16_t *flags = lys_compile_extension_instance_storage(LY_STMT_STATUS, ext->substmts);
733 const char **units = lys_compile_extension_instance_storage(LY_STMT_UNITS, ext->substmts);
734
735 if (ext->substmts[u].cardinality < LY_STMT_CARD_SOME) {
736 /* single item */
737 if (*(struct lysc_type **)ext->substmts[u].storage) {
738 LOGVAL(ctx->ctx, LY_VCODE_DUPSTMT, stmt->stmt);
739 goto cleanup;
740 }
741 compiled = ext->substmts[u].storage;
742 } else {
743 /* sized array */
744 struct lysc_type ***types = (struct lysc_type ***)ext->substmts[u].storage, **type = NULL;
745 LY_ARRAY_NEW_GOTO(ctx->ctx, *types, type, ret, cleanup);
746 compiled = (void *)type;
747 }
748
749 r = lysp_stmt_parse(ctx, stmt, &parsed, NULL);
750 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
751 r = lys_compile_type(ctx, NULL, flags ? *flags : 0, ext_p->name, parsed, (struct lysc_type **)compiled,
752 units && !*units ? units : NULL, NULL);
753 lysp_type_free(ctx->ctx, parsed);
754 free(parsed);
755 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
756 break;
757 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200758 /* TODO support other substatements (parse stmt to lysp and then compile lysp to lysc),
759 * also note that in many statements their extensions are not taken into account */
760 default:
Radek Krejci2efc45b2020-12-22 16:25:44 +0100761 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Statement \"%s\" is not supported as an extension (found in \"%s%s%s\") substatement.",
Radek Krejci6b88a462021-02-17 12:39:34 +0100762 stmt->stmt, ext_p->name, ext_p->argument ? " " : "", ext_p->argument ? ext_p->argument : "");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200763 goto cleanup;
764 }
765 }
766 }
767
Radek Krejci6b88a462021-02-17 12:39:34 +0100768 if (((ext->substmts[u].cardinality == LY_STMT_CARD_MAND) || (ext->substmts[u].cardinality == LY_STMT_CARD_SOME)) && !stmt_counter) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100769 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Missing mandatory keyword \"%s\" as a child of \"%s%s%s\".",
Radek Krejci6b88a462021-02-17 12:39:34 +0100770 ly_stmt2str(ext->substmts[u].stmt), ext_p->name, ext_p->argument ? " " : "", ext_p->argument ? ext_p->argument : "");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200771 goto cleanup;
772 }
773 }
774
775 ret = LY_SUCCESS;
776
777cleanup:
Radek Krejci6b88a462021-02-17 12:39:34 +0100778 ctx->ext = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200779 return ret;
780}
781
782/**
783 * @brief Check when for cyclic dependencies.
784 *
785 * @param[in] set Set with all the referenced nodes.
786 * @param[in] node Node whose "when" referenced nodes are in @p set.
787 * @return LY_ERR value
788 */
789static LY_ERR
790lys_compile_unres_when_cyclic(struct lyxp_set *set, const struct lysc_node *node)
791{
792 struct lyxp_set tmp_set;
793 struct lyxp_set_scnode *xp_scnode;
794 uint32_t i, j;
795 LY_ARRAY_COUNT_TYPE u;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200796 LY_ERR ret = LY_SUCCESS;
797
798 memset(&tmp_set, 0, sizeof tmp_set);
799
800 /* prepare in_ctx of the set */
801 for (i = 0; i < set->used; ++i) {
802 xp_scnode = &set->val.scnodes[i];
803
Radek Krejcif13b87b2020-12-01 22:02:17 +0100804 if (xp_scnode->in_ctx != LYXP_SET_SCNODE_START_USED) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200805 /* check node when, skip the context node (it was just checked) */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100806 xp_scnode->in_ctx = LYXP_SET_SCNODE_ATOM_CTX;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200807 }
808 }
809
810 for (i = 0; i < set->used; ++i) {
811 xp_scnode = &set->val.scnodes[i];
Radek Krejcif13b87b2020-12-01 22:02:17 +0100812 if (xp_scnode->in_ctx != LYXP_SET_SCNODE_ATOM_CTX) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200813 /* already checked */
814 continue;
815 }
816
817 if ((xp_scnode->type != LYXP_NODE_ELEM) || (xp_scnode->scnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) ||
Radek Krejci9a3823e2021-01-27 20:26:46 +0100818 !lysc_node_when(xp_scnode->scnode)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200819 /* no when to check */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100820 xp_scnode->in_ctx = LYXP_SET_SCNODE_ATOM;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200821 continue;
822 }
823
824 node = xp_scnode->scnode;
825 do {
Radek Krejci9a3823e2021-01-27 20:26:46 +0100826 struct lysc_when **when_list, *when;
827
Radek Krejciddace2c2021-01-08 11:30:56 +0100828 LOG_LOCSET(node, NULL, NULL, NULL);
Radek Krejci9a3823e2021-01-27 20:26:46 +0100829 when_list = lysc_node_when(node);
830 LY_ARRAY_FOR(when_list, u) {
831 when = when_list[u];
Michal Vasko400e9672021-01-11 13:39:17 +0100832 ret = lyxp_atomize(set->ctx, when->cond, node->module, LY_PREF_SCHEMA_RESOLVED, when->prefixes,
833 when->context, &tmp_set, LYXP_SCNODE_SCHEMA);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200834 if (ret != LY_SUCCESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100835 LOGVAL(set->ctx, LYVE_SEMANTICS, "Invalid when condition \"%s\".", when->cond->expr);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200836 goto cleanup;
837 }
838
839 for (j = 0; j < tmp_set.used; ++j) {
840 /* skip roots'n'stuff */
841 if (tmp_set.val.scnodes[j].type == LYXP_NODE_ELEM) {
842 /* try to find this node in our set */
843 uint32_t idx;
Radek Krejcif13b87b2020-12-01 22:02:17 +0100844 if (lyxp_set_scnode_contains(set, tmp_set.val.scnodes[j].scnode, LYXP_NODE_ELEM, -1, &idx) &&
845 (set->val.scnodes[idx].in_ctx == LYXP_SET_SCNODE_START_USED)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100846 LOGVAL(set->ctx, LYVE_SEMANTICS, "When condition includes a self-reference.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200847 ret = LY_EVALID;
848 goto cleanup;
849 }
850
851 /* needs to be checked, if in both sets, will be ignored */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100852 tmp_set.val.scnodes[j].in_ctx = LYXP_SET_SCNODE_ATOM_CTX;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200853 } else {
854 /* no when, nothing to check */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100855 tmp_set.val.scnodes[j].in_ctx = LYXP_SET_SCNODE_ATOM;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200856 }
857 }
858
859 /* merge this set into the global when set */
860 lyxp_set_scnode_merge(set, &tmp_set);
861 }
862
863 /* check when of non-data parents as well */
864 node = node->parent;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100865
Radek Krejciddace2c2021-01-08 11:30:56 +0100866 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200867 } while (node && (node->nodetype & (LYS_CASE | LYS_CHOICE)));
868
869 /* this node when was checked (xp_scnode could have been reallocd) */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100870 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_START_USED;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200871 }
872
873cleanup:
874 lyxp_set_free_content(&tmp_set);
875 return ret;
876}
877
878LY_ERR
879lysc_check_status(struct lysc_ctx *ctx, uint16_t flags1, void *mod1, const char *name1, uint16_t flags2, void *mod2,
880 const char *name2)
881{
882 uint16_t flg1, flg2;
883
884 flg1 = (flags1 & LYS_STATUS_MASK) ? (flags1 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
885 flg2 = (flags2 & LYS_STATUS_MASK) ? (flags2 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
886
887 if ((flg1 < flg2) && (mod1 == mod2)) {
888 if (ctx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100889 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200890 "A %s definition \"%s\" is not allowed to reference %s definition \"%s\".",
891 flg1 == LYS_STATUS_CURR ? "current" : "deprecated", name1,
892 flg2 == LYS_STATUS_OBSLT ? "obsolete" : "deprecated", name2);
893 }
894 return LY_EVALID;
895 }
896
897 return LY_SUCCESS;
898}
899
Michal Vasko25d6ad02020-10-22 12:20:22 +0200900LY_ERR
901lys_compile_expr_implement(const struct ly_ctx *ctx, const struct lyxp_expr *expr, LY_PREFIX_FORMAT format,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100902 void *prefix_data, ly_bool implement, struct lys_glob_unres *unres, const struct lys_module **mod_p)
Michal Vaskocfaff232020-10-20 09:35:14 +0200903{
904 uint32_t i;
905 const char *ptr, *start;
906 const struct lys_module *mod;
907
Michal Vasko25d6ad02020-10-22 12:20:22 +0200908 assert(implement || mod_p);
909
Michal Vaskocfaff232020-10-20 09:35:14 +0200910 for (i = 0; i < expr->used; ++i) {
911 if ((expr->tokens[i] != LYXP_TOKEN_NAMETEST) && (expr->tokens[i] != LYXP_TOKEN_LITERAL)) {
912 /* token cannot have a prefix */
913 continue;
914 }
915
916 start = expr->expr + expr->tok_pos[i];
917 if (!(ptr = ly_strnchr(start, ':', expr->tok_len[i]))) {
918 /* token without a prefix */
919 continue;
920 }
921
922 if (!(mod = ly_resolve_prefix(ctx, start, ptr - start, format, prefix_data))) {
923 /* unknown prefix, do not care right now */
924 continue;
925 }
926
927 if (!mod->implemented) {
928 /* unimplemented module found */
Michal Vasko25d6ad02020-10-22 12:20:22 +0200929 if (implement) {
Michal Vasko405cc9e2020-12-01 12:01:27 +0100930 LY_CHECK_RET(lys_set_implemented_r((struct lys_module *)mod, NULL, unres));
Michal Vasko25d6ad02020-10-22 12:20:22 +0200931 } else {
Michal Vaskocfaff232020-10-20 09:35:14 +0200932 *mod_p = mod;
Michal Vasko25d6ad02020-10-22 12:20:22 +0200933 break;
Michal Vaskocfaff232020-10-20 09:35:14 +0200934 }
Michal Vaskocfaff232020-10-20 09:35:14 +0200935 }
936 }
937
Michal Vasko25d6ad02020-10-22 12:20:22 +0200938 return LY_SUCCESS;
Michal Vaskocfaff232020-10-20 09:35:14 +0200939}
940
941/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200942 * @brief Check when/must expressions of a node on a complete compiled schema tree.
943 *
944 * @param[in] ctx Compile context.
945 * @param[in] node Node to check.
Michal Vasko405cc9e2020-12-01 12:01:27 +0100946 * @param[in,out] unres Global unres structure.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200947 * @return LY_ERR value
948 */
949static LY_ERR
Michal Vasko405cc9e2020-12-01 12:01:27 +0100950lys_compile_unres_xpath(struct lysc_ctx *ctx, const struct lysc_node *node, struct lys_glob_unres *unres)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200951{
952 struct lyxp_set tmp_set;
953 uint32_t i, opts;
954 LY_ARRAY_COUNT_TYPE u;
955 ly_bool input_done = 0;
Radek Krejci9a3823e2021-01-27 20:26:46 +0100956 struct lysc_when **whens = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200957 struct lysc_must *musts = NULL;
958 LY_ERR ret = LY_SUCCESS;
Michal Vaskocfaff232020-10-20 09:35:14 +0200959 const struct lys_module *mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200960
Radek Krejciddace2c2021-01-08 11:30:56 +0100961 LOG_LOCSET(node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100962
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200963 memset(&tmp_set, 0, sizeof tmp_set);
Michal Vaskod1e53b92021-01-28 13:11:06 +0100964 opts = LYXP_SCNODE_SCHEMA | ((node->flags & LYS_IS_OUTPUT) ? LYXP_SCNODE_OUTPUT : 0);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200965
Radek Krejci9a3823e2021-01-27 20:26:46 +0100966 whens = lysc_node_when(node);
967 musts = lysc_node_musts(node);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200968
Radek Krejci9a3823e2021-01-27 20:26:46 +0100969 LY_ARRAY_FOR(whens, u) {
Michal Vaskocfaff232020-10-20 09:35:14 +0200970 /* first check whether all the referenced modules are implemented */
Michal Vasko25d6ad02020-10-22 12:20:22 +0200971 mod = NULL;
Radek Krejci9a3823e2021-01-27 20:26:46 +0100972 ret = lys_compile_expr_implement(ctx->ctx, whens[u]->cond, LY_PREF_SCHEMA_RESOLVED, whens[u]->prefixes,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100973 ctx->ctx->flags & LY_CTX_REF_IMPLEMENTED, unres, &mod);
Michal Vasko25d6ad02020-10-22 12:20:22 +0200974 if (ret) {
975 goto cleanup;
976 } else if (mod) {
Michal Vaskocfaff232020-10-20 09:35:14 +0200977 LOGWRN(ctx->ctx, "When condition \"%s\" check skipped because referenced module \"%s\" is not implemented.",
Radek Krejci9a3823e2021-01-27 20:26:46 +0100978 whens[u]->cond->expr, mod->name);
Michal Vaskocfaff232020-10-20 09:35:14 +0200979 continue;
980 }
981
982 /* check "when" */
Radek Krejci9a3823e2021-01-27 20:26:46 +0100983 ret = lyxp_atomize(ctx->ctx, whens[u]->cond, node->module, LY_PREF_SCHEMA_RESOLVED, whens[u]->prefixes,
984 whens[u]->context, &tmp_set, opts);
Michal Vasko25d6ad02020-10-22 12:20:22 +0200985 if (ret) {
Radek Krejci9a3823e2021-01-27 20:26:46 +0100986 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Invalid when condition \"%s\".", whens[u]->cond->expr);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200987 goto cleanup;
988 }
989
990 ctx->path[0] = '\0';
Michal Vasko14ed9cd2021-01-28 14:16:25 +0100991 lysc_path(node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200992 for (i = 0; i < tmp_set.used; ++i) {
993 /* skip roots'n'stuff */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100994 if ((tmp_set.val.scnodes[i].type == LYXP_NODE_ELEM) && (tmp_set.val.scnodes[i].in_ctx != LYXP_SET_SCNODE_START_USED)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200995 struct lysc_node *schema = tmp_set.val.scnodes[i].scnode;
996
997 /* XPath expression cannot reference "lower" status than the node that has the definition */
Radek Krejci9a3823e2021-01-27 20:26:46 +0100998 ret = lysc_check_status(ctx, whens[u]->flags, node->module, node->name, schema->flags, schema->module,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200999 schema->name);
1000 LY_CHECK_GOTO(ret, cleanup);
1001
1002 /* check dummy node accessing */
1003 if (schema == node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001004 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "When condition is accessing its own conditional node.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001005 ret = LY_EVALID;
1006 goto cleanup;
1007 }
1008 }
1009 }
1010
1011 /* check cyclic dependencies */
1012 ret = lys_compile_unres_when_cyclic(&tmp_set, node);
1013 LY_CHECK_GOTO(ret, cleanup);
1014
1015 lyxp_set_free_content(&tmp_set);
1016 }
1017
1018check_musts:
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001019 LY_ARRAY_FOR(musts, u) {
Michal Vaskocfaff232020-10-20 09:35:14 +02001020 /* first check whether all the referenced modules are implemented */
Michal Vasko25d6ad02020-10-22 12:20:22 +02001021 mod = NULL;
1022 ret = lys_compile_expr_implement(ctx->ctx, musts[u].cond, LY_PREF_SCHEMA_RESOLVED, musts[u].prefixes,
Michal Vasko405cc9e2020-12-01 12:01:27 +01001023 ctx->ctx->flags & LY_CTX_REF_IMPLEMENTED, unres, &mod);
Michal Vasko25d6ad02020-10-22 12:20:22 +02001024 if (ret) {
1025 goto cleanup;
1026 } else if (mod) {
Michal Vaskocfaff232020-10-20 09:35:14 +02001027 LOGWRN(ctx->ctx, "Must condition \"%s\" check skipped because referenced module \"%s\" is not implemented.",
1028 musts[u].cond->expr, mod->name);
1029 continue;
1030 }
1031
1032 /* check "must" */
Michal Vasko400e9672021-01-11 13:39:17 +01001033 ret = lyxp_atomize(ctx->ctx, musts[u].cond, node->module, LY_PREF_SCHEMA_RESOLVED, musts[u].prefixes, node,
1034 &tmp_set, opts);
Michal Vasko25d6ad02020-10-22 12:20:22 +02001035 if (ret) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001036 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Invalid must restriction \"%s\".", musts[u].cond->expr);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001037 goto cleanup;
1038 }
1039
1040 ctx->path[0] = '\0';
Michal Vasko14ed9cd2021-01-28 14:16:25 +01001041 lysc_path(node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001042 for (i = 0; i < tmp_set.used; ++i) {
1043 /* skip roots'n'stuff */
1044 if (tmp_set.val.scnodes[i].type == LYXP_NODE_ELEM) {
1045 /* XPath expression cannot reference "lower" status than the node that has the definition */
1046 ret = lysc_check_status(ctx, node->flags, node->module, node->name, tmp_set.val.scnodes[i].scnode->flags,
1047 tmp_set.val.scnodes[i].scnode->module, tmp_set.val.scnodes[i].scnode->name);
1048 LY_CHECK_GOTO(ret, cleanup);
1049 }
1050 }
1051
1052 lyxp_set_free_content(&tmp_set);
1053 }
1054
1055 if ((node->nodetype & (LYS_RPC | LYS_ACTION)) && !input_done) {
1056 /* now check output musts */
1057 input_done = 1;
Radek Krejci9a3823e2021-01-27 20:26:46 +01001058 whens = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001059 musts = ((struct lysc_node_action *)node)->output.musts;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001060 opts = LYXP_SCNODE_OUTPUT;
1061 goto check_musts;
1062 }
1063
1064cleanup:
1065 lyxp_set_free_content(&tmp_set);
Radek Krejciddace2c2021-01-08 11:30:56 +01001066 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001067 return ret;
1068}
1069
1070/**
1071 * @brief Check leafref for its target existence on a complete compiled schema tree.
1072 *
1073 * @param[in] ctx Compile context.
1074 * @param[in] node Context node for the leafref.
1075 * @param[in] lref Leafref to check/resolve.
Michal Vasko405cc9e2020-12-01 12:01:27 +01001076 * @param[in,out] unres Global unres structure.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001077 * @return LY_ERR value.
1078 */
1079static LY_ERR
Michal Vasko405cc9e2020-12-01 12:01:27 +01001080lys_compile_unres_leafref(struct lysc_ctx *ctx, const struct lysc_node *node, struct lysc_type_leafref *lref,
1081 struct lys_glob_unres *unres)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001082{
Michal Vaskod1e53b92021-01-28 13:11:06 +01001083 const struct lysc_node *target = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001084 struct ly_path *p;
1085 struct lysc_type *type;
1086
1087 assert(node->nodetype & (LYS_LEAF | LYS_LEAFLIST));
1088
1089 /* try to find the target */
Michal Vaskod1e53b92021-01-28 13:11:06 +01001090 LY_CHECK_RET(ly_path_compile(ctx->ctx, lref->cur_mod, node, lref->path, LY_PATH_LREF_TRUE,
1091 (node->flags & LYS_IS_OUTPUT) ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_MANY,
1092 LY_PREF_SCHEMA_RESOLVED, lref->prefixes, unres, &p));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001093
1094 /* get the target node */
1095 target = p[LY_ARRAY_COUNT(p) - 1].node;
1096 ly_path_free(node->module->ctx, p);
1097
1098 if (!(target->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001099 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid leafref path \"%s\" - target node is %s instead of leaf or leaf-list.",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001100 lref->path->expr, lys_nodetype2str(target->nodetype));
1101 return LY_EVALID;
1102 }
1103
1104 /* check status */
1105 ctx->path[0] = '\0';
1106 lysc_path(node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
1107 ctx->path_len = strlen(ctx->path);
1108 if (lysc_check_status(ctx, node->flags, node->module, node->name, target->flags, target->module, target->name)) {
1109 return LY_EVALID;
1110 }
1111 ctx->path_len = 1;
1112 ctx->path[1] = '\0';
1113
1114 /* check config */
1115 if (lref->require_instance) {
Michal Vaskod1e53b92021-01-28 13:11:06 +01001116 if ((node->flags & LYS_CONFIG_W) && (target->flags & LYS_CONFIG_R)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001117 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid leafref path \"%s\" - target is supposed"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001118 " to represent configuration data (as the leafref does), but it does not.", lref->path->expr);
1119 return LY_EVALID;
1120 }
1121 }
1122
1123 /* store the target's type and check for circular chain of leafrefs */
1124 lref->realtype = ((struct lysc_node_leaf *)target)->type;
1125 for (type = lref->realtype; type && type->basetype == LY_TYPE_LEAFREF; type = ((struct lysc_type_leafref *)type)->realtype) {
1126 if (type == (struct lysc_type *)lref) {
1127 /* circular chain detected */
Radek Krejci2efc45b2020-12-22 16:25:44 +01001128 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid leafref path \"%s\" - circular chain of leafrefs detected.",
1129 lref->path->expr);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001130 return LY_EVALID;
1131 }
1132 }
1133
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001134 /* TODO check if leafref and its target are under common if-features */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001135
1136 return LY_SUCCESS;
1137}
1138
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001139/**
1140 * @brief Compile default value(s) for leaf or leaf-list expecting a complete compiled schema tree.
1141 *
1142 * @param[in] ctx Compile context.
1143 * @param[in] node Leaf or leaf-list to compile the default value(s) for.
1144 * @param[in] type Type of the default value.
1145 * @param[in] dflt Default value.
1146 * @param[in] dflt_pmod Parsed module of the @p dflt to resolve possible prefixes.
1147 * @param[in,out] storage Storage for the compiled default value.
Michal Vasko405cc9e2020-12-01 12:01:27 +01001148 * @param[in,out] unres Global unres structure for newly implemented modules.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001149 * @return LY_ERR value.
1150 */
1151static LY_ERR
1152lys_compile_unres_dflt(struct lysc_ctx *ctx, struct lysc_node *node, struct lysc_type *type, const char *dflt,
Michal Vasko405cc9e2020-12-01 12:01:27 +01001153 const struct lysp_module *dflt_pmod, struct lyd_value *storage, struct lys_glob_unres *unres)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001154{
1155 LY_ERR ret;
Michal Vasko25d6ad02020-10-22 12:20:22 +02001156 uint32_t options;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001157 struct ly_err_item *err = NULL;
1158
Michal Vasko25d6ad02020-10-22 12:20:22 +02001159 options = (ctx->ctx->flags & LY_CTX_REF_IMPLEMENTED) ? LY_TYPE_STORE_IMPLEMENT : 0;
1160 ret = type->plugin->store(ctx->ctx, type, dflt, strlen(dflt), options, LY_PREF_SCHEMA, (void *)dflt_pmod,
Michal Vasko405cc9e2020-12-01 12:01:27 +01001161 LYD_HINT_SCHEMA, node, storage, unres, &err);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001162 if (ret == LY_EINCOMPLETE) {
1163 /* we have no data so we will not be resolving it */
1164 ret = LY_SUCCESS;
1165 }
1166
1167 if (ret) {
Radek Krejciddace2c2021-01-08 11:30:56 +01001168 LOG_LOCSET(node, NULL, NULL, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001169 if (err) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001170 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Invalid default - value does not fit the type (%s).", err->msg);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001171 ly_err_free(err);
1172 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001173 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Invalid default - value does not fit the type.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001174 }
Radek Krejciddace2c2021-01-08 11:30:56 +01001175 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001176 return ret;
1177 }
1178
1179 ++((struct lysc_type *)storage->realtype)->refcount;
1180 return LY_SUCCESS;
1181}
1182
1183/**
1184 * @brief Compile default value of a leaf expecting a complete compiled schema tree.
1185 *
1186 * @param[in] ctx Compile context.
1187 * @param[in] leaf Leaf that the default value is for.
1188 * @param[in] dflt Default value to compile.
Michal Vasko405cc9e2020-12-01 12:01:27 +01001189 * @param[in,out] unres Global unres structure for newly implemented modules.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001190 * @return LY_ERR value.
1191 */
1192static LY_ERR
Michal Vasko405cc9e2020-12-01 12:01:27 +01001193lys_compile_unres_leaf_dlft(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, struct lysp_qname *dflt,
1194 struct lys_glob_unres *unres)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001195{
1196 LY_ERR ret;
1197
1198 assert(!leaf->dflt);
1199
1200 if (leaf->flags & (LYS_MAND_TRUE | LYS_KEY)) {
1201 /* ignore default values for keys and mandatory leaves */
1202 return LY_SUCCESS;
1203 }
1204
1205 /* allocate the default value */
1206 leaf->dflt = calloc(1, sizeof *leaf->dflt);
1207 LY_CHECK_ERR_RET(!leaf->dflt, LOGMEM(ctx->ctx), LY_EMEM);
1208
1209 /* store the default value */
Michal Vasko14ed9cd2021-01-28 14:16:25 +01001210 ret = lys_compile_unres_dflt(ctx, &leaf->node, leaf->type, dflt->str, dflt->mod, leaf->dflt, unres);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001211 if (ret) {
1212 free(leaf->dflt);
1213 leaf->dflt = NULL;
1214 }
1215
1216 return ret;
1217}
1218
1219/**
1220 * @brief Compile default values of a leaf-list expecting a complete compiled schema tree.
1221 *
1222 * @param[in] ctx Compile context.
1223 * @param[in] llist Leaf-list that the default value(s) are for.
1224 * @param[in] dflt Default value to compile, in case of a single value.
1225 * @param[in] dflts Sized array of default values, in case of more values.
Michal Vasko405cc9e2020-12-01 12:01:27 +01001226 * @param[in,out] unres Global unres structure for newly implemented modules.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001227 * @return LY_ERR value.
1228 */
1229static LY_ERR
1230lys_compile_unres_llist_dflts(struct lysc_ctx *ctx, struct lysc_node_leaflist *llist, struct lysp_qname *dflt,
Michal Vasko405cc9e2020-12-01 12:01:27 +01001231 struct lysp_qname *dflts, struct lys_glob_unres *unres)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001232{
1233 LY_ERR ret;
1234 LY_ARRAY_COUNT_TYPE orig_count, u, v;
1235
1236 assert(dflt || dflts);
1237
Radek Krejcic7d13e32020-12-09 12:32:24 +01001238 /* in case there were already some defaults and we are adding new by deviations */
1239 orig_count = LY_ARRAY_COUNT(llist->dflts);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001240
1241 /* allocate new items */
Radek Krejcic7d13e32020-12-09 12:32:24 +01001242 LY_ARRAY_CREATE_RET(ctx->ctx, llist->dflts, orig_count + (dflts ? LY_ARRAY_COUNT(dflts) : 1), LY_EMEM);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001243
1244 /* fill each new default value */
1245 if (dflts) {
1246 LY_ARRAY_FOR(dflts, u) {
1247 llist->dflts[orig_count + u] = calloc(1, sizeof **llist->dflts);
Michal Vasko14ed9cd2021-01-28 14:16:25 +01001248 ret = lys_compile_unres_dflt(ctx, &llist->node, llist->type, dflts[u].str, dflts[u].mod,
Michal Vasko405cc9e2020-12-01 12:01:27 +01001249 llist->dflts[orig_count + u], unres);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001250 LY_CHECK_ERR_RET(ret, free(llist->dflts[orig_count + u]), ret);
1251 LY_ARRAY_INCREMENT(llist->dflts);
1252 }
1253 } else {
1254 llist->dflts[orig_count] = calloc(1, sizeof **llist->dflts);
Michal Vasko14ed9cd2021-01-28 14:16:25 +01001255 ret = lys_compile_unres_dflt(ctx, &llist->node, llist->type, dflt->str, dflt->mod,
Michal Vasko405cc9e2020-12-01 12:01:27 +01001256 llist->dflts[orig_count], unres);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001257 LY_CHECK_ERR_RET(ret, free(llist->dflts[orig_count]), ret);
1258 LY_ARRAY_INCREMENT(llist->dflts);
1259 }
1260
1261 /* check default value uniqueness */
1262 if (llist->flags & LYS_CONFIG_W) {
1263 /* configuration data values must be unique - so check the default values */
1264 for (u = orig_count; u < LY_ARRAY_COUNT(llist->dflts); ++u) {
1265 for (v = 0; v < u; ++v) {
1266 if (!llist->dflts[u]->realtype->plugin->compare(llist->dflts[u], llist->dflts[v])) {
Radek Krejcia6016992021-03-03 10:13:41 +01001267 lysc_update_path(ctx, llist->parent ? llist->parent->module : NULL, llist->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001268 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Configuration leaf-list has multiple defaults of the same value \"%s\".",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001269 llist->dflts[u]->canonical);
1270 lysc_update_path(ctx, NULL, NULL);
1271 return LY_EVALID;
1272 }
1273 }
1274 }
1275 }
1276
1277 return LY_SUCCESS;
1278}
1279
Michal Vasko405cc9e2020-12-01 12:01:27 +01001280LY_ERR
1281lys_compile_unres_glob(struct ly_ctx *ctx, struct lys_glob_unres *unres)
1282{
Radek Krejci2efc45b2020-12-22 16:25:44 +01001283 LY_ERR ret;
Michal Vasko405cc9e2020-12-01 12:01:27 +01001284 struct lysc_node *node;
1285 struct lysc_type *type, *typeiter;
1286 struct lysc_type_leafref *lref;
1287 struct lysc_ctx cctx = {0};
1288 LY_ARRAY_COUNT_TYPE v;
1289 uint32_t i;
1290
1291 if (unres->recompile) {
1292 /* recompile all the modules and resolve the new unres instead (during recompilation) */
1293 unres->recompile = 0;
1294 return lys_recompile(ctx, 1);
1295 }
1296
1297 /* fake compile context */
1298 cctx.ctx = ctx;
1299 cctx.path_len = 1;
1300 cctx.path[0] = '/';
1301
1302 /* for leafref, we need 2 rounds - first detects circular chain by storing the first referred type (which
1303 * can be also leafref, in case it is already resolved, go through the chain and check that it does not
1304 * point to the starting leafref type). The second round stores the first non-leafref type for later data validation. */
1305 for (i = 0; i < unres->leafrefs.count; ++i) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001306 LY_ERR ret = LY_SUCCESS;
Michal Vasko405cc9e2020-12-01 12:01:27 +01001307 node = unres->leafrefs.objs[i];
1308 cctx.cur_mod = node->module;
1309 cctx.pmod = node->module->parsed;
1310
Radek Krejciddace2c2021-01-08 11:30:56 +01001311 LOG_LOCSET(node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001312
Michal Vasko405cc9e2020-12-01 12:01:27 +01001313 assert(node->nodetype & (LYS_LEAF | LYS_LEAFLIST));
1314 type = ((struct lysc_node_leaf *)node)->type;
1315 if (type->basetype == LY_TYPE_LEAFREF) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001316 ret = lys_compile_unres_leafref(&cctx, node, (struct lysc_type_leafref *)type, unres);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001317 } else if (type->basetype == LY_TYPE_UNION) {
1318 LY_ARRAY_FOR(((struct lysc_type_union *)type)->types, v) {
1319 if (((struct lysc_type_union *)type)->types[v]->basetype == LY_TYPE_LEAFREF) {
1320 lref = (struct lysc_type_leafref *)((struct lysc_type_union *)type)->types[v];
Radek Krejci2efc45b2020-12-22 16:25:44 +01001321 ret = lys_compile_unres_leafref(&cctx, node, lref, unres);
1322 if (ret) {
1323 break;
1324 }
Michal Vasko405cc9e2020-12-01 12:01:27 +01001325 }
1326 }
1327 }
Radek Krejci2efc45b2020-12-22 16:25:44 +01001328
Radek Krejciddace2c2021-01-08 11:30:56 +01001329 LOG_LOCBACK(1, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001330 if (ret) {
1331 return ret;
1332 }
Michal Vasko405cc9e2020-12-01 12:01:27 +01001333 }
1334 while (unres->leafrefs.count) {
1335 node = unres->leafrefs.objs[unres->leafrefs.count - 1];
1336 cctx.cur_mod = node->module;
1337 cctx.pmod = node->module->parsed;
1338
Radek Krejciddace2c2021-01-08 11:30:56 +01001339 LOG_LOCSET(node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001340
Michal Vasko405cc9e2020-12-01 12:01:27 +01001341 /* store pointer to the real type */
1342 type = ((struct lysc_node_leaf *)node)->type;
1343 if (type->basetype == LY_TYPE_LEAFREF) {
1344 for (typeiter = ((struct lysc_type_leafref *)type)->realtype;
1345 typeiter->basetype == LY_TYPE_LEAFREF;
1346 typeiter = ((struct lysc_type_leafref *)typeiter)->realtype) {}
1347 ((struct lysc_type_leafref *)type)->realtype = typeiter;
1348 } else if (type->basetype == LY_TYPE_UNION) {
1349 LY_ARRAY_FOR(((struct lysc_type_union *)type)->types, v) {
1350 if (((struct lysc_type_union *)type)->types[v]->basetype == LY_TYPE_LEAFREF) {
1351 for (typeiter = ((struct lysc_type_leafref *)((struct lysc_type_union *)type)->types[v])->realtype;
1352 typeiter->basetype == LY_TYPE_LEAFREF;
1353 typeiter = ((struct lysc_type_leafref *)typeiter)->realtype) {}
1354 ((struct lysc_type_leafref *)((struct lysc_type_union *)type)->types[v])->realtype = typeiter;
1355 }
1356 }
1357 }
Radek Krejciddace2c2021-01-08 11:30:56 +01001358 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001359
1360 ly_set_rm_index(&unres->leafrefs, unres->leafrefs.count - 1, NULL);
1361 }
1362
1363 /* check xpath */
1364 while (unres->xpath.count) {
1365 node = unres->xpath.objs[unres->xpath.count - 1];
1366 cctx.cur_mod = node->module;
1367 cctx.pmod = node->module->parsed;
1368
Radek Krejciddace2c2021-01-08 11:30:56 +01001369 LOG_LOCSET(node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001370
1371 ret = lys_compile_unres_xpath(&cctx, node, unres);
Radek Krejciddace2c2021-01-08 11:30:56 +01001372 LOG_LOCBACK(1, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001373 LY_CHECK_RET(ret);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001374
1375 ly_set_rm_index(&unres->xpath, unres->xpath.count - 1, NULL);
1376 }
1377
1378 /* finish incomplete default values compilation */
1379 while (unres->dflts.count) {
1380 struct lysc_unres_dflt *r = unres->dflts.objs[unres->dflts.count - 1];
1381 cctx.cur_mod = r->leaf->module;
1382 cctx.pmod = r->leaf->module->parsed;
1383
Michal Vasko14ed9cd2021-01-28 14:16:25 +01001384 LOG_LOCSET(&r->leaf->node, NULL, NULL, NULL);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001385
Radek Krejci2efc45b2020-12-22 16:25:44 +01001386 if (r->leaf->nodetype == LYS_LEAF) {
1387 ret = lys_compile_unres_leaf_dlft(&cctx, r->leaf, r->dflt, unres);
1388 } else {
1389 ret = lys_compile_unres_llist_dflts(&cctx, r->llist, r->dflt, r->dflts, unres);
1390 }
Radek Krejciddace2c2021-01-08 11:30:56 +01001391 LOG_LOCBACK(1, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001392 LY_CHECK_RET(ret);
1393
1394 lysc_unres_dflt_free(ctx, r);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001395 ly_set_rm_index(&unres->dflts, unres->dflts.count - 1, NULL);
1396 }
1397
1398 /* some unres items may have been added */
1399 if (unres->leafrefs.count || unres->xpath.count || unres->dflts.count) {
1400 return lys_compile_unres_glob(ctx, unres);
1401 }
1402
1403 return LY_SUCCESS;
1404}
1405
1406void
1407lys_compile_unres_glob_revert(struct ly_ctx *ctx, struct lys_glob_unres *unres)
1408{
1409 uint32_t i;
1410 struct lys_module *m;
1411
1412 for (i = 0; i < unres->implementing.count; ++i) {
1413 m = unres->implementing.objs[i];
1414 assert(m->implemented);
1415
1416 /* make the module correctly non-implemented again */
1417 m->implemented = 0;
1418 lys_precompile_augments_deviations_revert(ctx, m);
1419 }
1420
1421 for (i = 0; i < unres->creating.count; ++i) {
1422 m = unres->creating.objs[i];
1423
1424 /* remove the module from the context and free it */
1425 ly_set_rm(&ctx->list, m, NULL);
1426 lys_module_free(m, NULL);
1427 }
1428
1429 if (unres->implementing.count) {
1430 /* recompile because some implemented modules are no longer implemented */
1431 lys_recompile(ctx, 0);
1432 }
1433}
1434
1435void
1436lys_compile_unres_glob_erase(const struct ly_ctx *ctx, struct lys_glob_unres *unres)
1437{
1438 uint32_t i;
1439
1440 ly_set_erase(&unres->implementing, NULL);
1441 ly_set_erase(&unres->creating, NULL);
1442 for (i = 0; i < unres->dflts.count; ++i) {
1443 lysc_unres_dflt_free(ctx, unres->dflts.objs[i]);
1444 }
1445 ly_set_erase(&unres->dflts, NULL);
1446 ly_set_erase(&unres->xpath, NULL);
1447 ly_set_erase(&unres->leafrefs, NULL);
1448}
1449
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001450/**
Michal Vasko405cc9e2020-12-01 12:01:27 +01001451 * @brief Finish compilation of all the module unres sets in a compile context.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001452 *
1453 * @param[in] ctx Compile context with unres sets.
1454 * @return LY_ERR value.
1455 */
1456static LY_ERR
Michal Vasko405cc9e2020-12-01 12:01:27 +01001457lys_compile_unres_mod(struct lysc_ctx *ctx)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001458{
1459 struct lysc_node *node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001460 struct lysc_augment *aug;
1461 struct lysc_deviation *dev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001462 uint32_t i;
1463
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001464 /* remove all disabled nodes */
1465 for (i = 0; i < ctx->disabled.count; ++i) {
1466 node = ctx->disabled.snodes[i];
1467 if (node->flags & LYS_KEY) {
Radek Krejciddace2c2021-01-08 11:30:56 +01001468 LOG_LOCSET(node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001469 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Key \"%s\" is disabled by its if-features.", node->name);
Radek Krejciddace2c2021-01-08 11:30:56 +01001470 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001471 return LY_EVALID;
1472 }
1473
Radek Krejci2a9fc652021-01-22 17:44:34 +01001474 lysc_node_free(ctx->ctx, node, 1);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001475 }
1476
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001477 /* check that all augments were applied */
1478 for (i = 0; i < ctx->augs.count; ++i) {
1479 aug = ctx->augs.objs[i];
Radek Krejci2efc45b2020-12-22 16:25:44 +01001480 lysc_update_path(ctx, NULL, "{augment}");
1481 lysc_update_path(ctx, NULL, aug->nodeid->expr);
1482 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Augment target node \"%s\" from module \"%s\" was not found.",
Michal Vasko28fe5f62021-03-03 16:37:39 +01001483 aug->nodeid->expr, LYSP_MODULE_NAME(aug->aug_pmod));
Radek Krejci2efc45b2020-12-22 16:25:44 +01001484 lysc_update_path(ctx, NULL, NULL);
1485 lysc_update_path(ctx, NULL, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001486 }
1487 if (ctx->augs.count) {
1488 return LY_ENOTFOUND;
1489 }
1490
1491 /* check that all deviations were applied */
1492 for (i = 0; i < ctx->devs.count; ++i) {
1493 dev = ctx->devs.objs[i];
Radek Krejci2efc45b2020-12-22 16:25:44 +01001494 lysc_update_path(ctx, NULL, "{deviation}");
1495 lysc_update_path(ctx, NULL, dev->nodeid->expr);
1496 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Deviation(s) target node \"%s\" from module \"%s\" was not found.",
1497 dev->nodeid->expr, LYSP_MODULE_NAME(dev->dev_pmods[0]));
1498 lysc_update_path(ctx, NULL, NULL);
1499 lysc_update_path(ctx, NULL, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001500 }
1501 if (ctx->devs.count) {
1502 return LY_ENOTFOUND;
1503 }
1504
1505 return LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001506}
1507
1508/**
Michal Vasko405cc9e2020-12-01 12:01:27 +01001509 * @brief Erase all the module unres sets in a compile context.
1510 *
1511 * @param[in] ctx Compile context with unres sets.
1512 * @param[in] error Whether the compilation finished with an error or not.
1513 */
1514static void
1515lys_compile_unres_mod_erase(struct lysc_ctx *ctx, ly_bool error)
1516{
1517 uint32_t i;
1518
1519 ly_set_erase(&ctx->groupings, NULL);
1520 ly_set_erase(&ctx->tpdf_chain, NULL);
1521 ly_set_erase(&ctx->disabled, NULL);
1522
1523 if (!error) {
1524 /* there can be no leftover deviations or augments */
1525 LY_CHECK_ERR_RET(ctx->augs.count, LOGINT(ctx->ctx), );
1526 LY_CHECK_ERR_RET(ctx->devs.count, LOGINT(ctx->ctx), );
1527
1528 ly_set_erase(&ctx->augs, NULL);
1529 ly_set_erase(&ctx->devs, NULL);
1530 ly_set_erase(&ctx->uses_augs, NULL);
1531 ly_set_erase(&ctx->uses_rfns, NULL);
1532 } else {
1533 for (i = 0; i < ctx->augs.count; ++i) {
1534 lysc_augment_free(ctx->ctx, ctx->augs.objs[i]);
1535 }
1536 ly_set_erase(&ctx->augs, NULL);
1537 for (i = 0; i < ctx->devs.count; ++i) {
1538 lysc_deviation_free(ctx->ctx, ctx->devs.objs[i]);
1539 }
1540 ly_set_erase(&ctx->devs, NULL);
1541 for (i = 0; i < ctx->uses_augs.count; ++i) {
1542 lysc_augment_free(ctx->ctx, ctx->uses_augs.objs[i]);
1543 }
1544 ly_set_erase(&ctx->uses_augs, NULL);
1545 for (i = 0; i < ctx->uses_rfns.count; ++i) {
1546 lysc_refine_free(ctx->ctx, ctx->uses_rfns.objs[i]);
1547 }
1548 ly_set_erase(&ctx->uses_rfns, NULL);
1549 }
1550}
1551
1552/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001553 * @brief Compile identites in the current module and all its submodules.
1554 *
1555 * @param[in] ctx Compile context.
1556 * @return LY_ERR value.
1557 */
1558static LY_ERR
1559lys_compile_identities(struct lysc_ctx *ctx)
1560{
1561 struct lysp_submodule *submod;
1562 LY_ARRAY_COUNT_TYPE u;
1563
1564 if (!ctx->cur_mod->identities) {
1565 LY_CHECK_RET(lys_identity_precompile(ctx, NULL, NULL, ctx->cur_mod->parsed->identities, &ctx->cur_mod->identities));
1566 LY_ARRAY_FOR(ctx->cur_mod->parsed->includes, u) {
1567 submod = ctx->cur_mod->parsed->includes[u].submodule;
1568 LY_CHECK_RET(lys_identity_precompile(ctx, NULL, NULL, submod->identities, &ctx->cur_mod->identities));
1569 }
1570 }
1571
1572 if (ctx->cur_mod->parsed->identities) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001573 LY_CHECK_RET(lys_compile_identities_derived(ctx, ctx->cur_mod->parsed->identities, &ctx->cur_mod->identities));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001574 }
1575 lysc_update_path(ctx, NULL, "{submodule}");
1576 LY_ARRAY_FOR(ctx->cur_mod->parsed->includes, u) {
1577
1578 submod = ctx->cur_mod->parsed->includes[u].submodule;
1579 if (submod->identities) {
1580 lysc_update_path(ctx, NULL, submod->name);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001581 LY_CHECK_RET(lys_compile_identities_derived(ctx, submod->identities, &ctx->cur_mod->identities));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001582 lysc_update_path(ctx, NULL, NULL);
1583 }
1584 }
1585 lysc_update_path(ctx, NULL, NULL);
1586
1587 return LY_SUCCESS;
1588}
1589
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001590LY_ERR
Michal Vasko405cc9e2020-12-01 12:01:27 +01001591lys_recompile(struct ly_ctx *ctx, ly_bool log)
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001592{
1593 uint32_t idx;
1594 struct lys_module *mod;
Michal Vasko405cc9e2020-12-01 12:01:27 +01001595 struct lys_glob_unres unres = {0};
1596 LY_ERR ret = LY_SUCCESS;
Radek Krejci430a5582020-12-01 13:35:18 +01001597 uint32_t prev_lo = 0;
Michal Vasko405cc9e2020-12-01 12:01:27 +01001598
1599 if (!log) {
1600 /* recompile, must succeed because the modules were already compiled; hide messages because any
1601 * warnings were already printed, are not really relevant, and would hide the real error */
1602 prev_lo = ly_log_options(0);
1603 }
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001604
1605 /* free all the modules */
1606 for (idx = 0; idx < ctx->list.count; ++idx) {
1607 mod = ctx->list.objs[idx];
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001608 if (mod->compiled) {
1609 /* free the module */
1610 lysc_module_free(mod->compiled, NULL);
1611 mod->compiled = NULL;
1612 }
1613
1614 /* free precompiled iffeatures */
1615 lys_free_feature_iffeatures(mod->parsed);
1616 }
1617
1618 /* recompile all the modules */
1619 for (idx = 0; idx < ctx->list.count; ++idx) {
1620 mod = ctx->list.objs[idx];
Michal Vasko405cc9e2020-12-01 12:01:27 +01001621 if (!mod->implemented || mod->compiled) {
1622 /* nothing to do */
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001623 continue;
1624 }
1625
Michal Vasko405cc9e2020-12-01 12:01:27 +01001626 /* recompile */
1627 ret = lys_compile(mod, 0, &unres);
1628 if (ret) {
1629 if (!log) {
1630 LOGERR(mod->ctx, ret, "Recompilation of module \"%s\" failed.", mod->name);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001631 }
Michal Vasko405cc9e2020-12-01 12:01:27 +01001632 goto cleanup;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001633 }
1634 }
1635
Michal Vasko405cc9e2020-12-01 12:01:27 +01001636 /* resolve global unres */
1637 LY_CHECK_GOTO(ret = lys_compile_unres_glob(ctx, &unres), cleanup);
1638
1639cleanup:
1640 if (!log) {
1641 ly_log_options(prev_lo);
1642 }
1643 lys_compile_unres_glob_erase(ctx, &unres);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001644 return ret;
1645}
1646
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001647LY_ERR
Michal Vasko405cc9e2020-12-01 12:01:27 +01001648lys_compile(struct lys_module *mod, uint32_t options, struct lys_glob_unres *unres)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001649{
1650 struct lysc_ctx ctx = {0};
1651 struct lysc_module *mod_c;
1652 struct lysp_module *sp;
1653 struct lysp_submodule *submod;
1654 struct lysp_node *pnode;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001655 struct lysp_node_grp *grp;
1656 LY_ARRAY_COUNT_TYPE u;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001657 LY_ERR ret = LY_SUCCESS;
1658
1659 LY_CHECK_ARG_RET(NULL, mod, mod->parsed, !mod->compiled, mod->ctx, LY_EINVAL);
1660
1661 if (!mod->implemented) {
1662 /* just imported modules are not compiled */
1663 return LY_SUCCESS;
1664 }
1665
1666 /* context will be changed */
1667 ++mod->ctx->module_set_id;
1668
1669 sp = mod->parsed;
1670
1671 ctx.ctx = mod->ctx;
1672 ctx.cur_mod = mod;
1673 ctx.pmod = sp;
1674 ctx.options = options;
1675 ctx.path_len = 1;
1676 ctx.path[0] = '/';
Michal Vasko405cc9e2020-12-01 12:01:27 +01001677 ctx.unres = unres;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001678
1679 mod->compiled = mod_c = calloc(1, sizeof *mod_c);
1680 LY_CHECK_ERR_RET(!mod_c, LOGMEM(mod->ctx), LY_EMEM);
1681 mod_c->mod = mod;
1682
1683 /* process imports */
1684 LY_ARRAY_FOR(sp->imports, u) {
1685 LY_CHECK_GOTO(ret = lys_compile_import(&ctx, &sp->imports[u]), error);
1686 }
1687
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001688 /* identities */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001689 LY_CHECK_GOTO(ret = lys_compile_identities(&ctx), error);
1690
1691 /* augments and deviations */
1692 LY_CHECK_GOTO(ret = lys_precompile_augments_deviations(&ctx), error);
1693
1694 /* compile augments and deviations of our module from other modules so they can be applied during compilation */
1695 LY_CHECK_GOTO(ret = lys_precompile_own_augments(&ctx), error);
1696 LY_CHECK_GOTO(ret = lys_precompile_own_deviations(&ctx), error);
1697
1698 /* data nodes */
1699 LY_LIST_FOR(sp->data, pnode) {
1700 LY_CHECK_GOTO(ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL), error);
1701 }
1702
Radek Krejci2a9fc652021-01-22 17:44:34 +01001703 /* top-level RPCs */
1704 LY_LIST_FOR((struct lysp_node *)sp->rpcs, pnode) {
1705 LY_CHECK_GOTO(ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL), error);
1706 }
1707
1708 /* top-level notifications */
1709 LY_LIST_FOR((struct lysp_node *)sp->notifs, pnode) {
1710 LY_CHECK_GOTO(ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL), error);
1711 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001712
1713 /* extension instances */
Radek Krejciab430862021-03-02 20:13:40 +01001714 COMPILE_EXTS_GOTO(&ctx, sp->exts, mod_c->exts, mod_c, ret, error);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001715
1716 /* the same for submodules */
1717 LY_ARRAY_FOR(sp->includes, u) {
1718 submod = sp->includes[u].submodule;
1719 ctx.pmod = (struct lysp_module *)submod;
1720
1721 LY_LIST_FOR(submod->data, pnode) {
1722 ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL);
1723 LY_CHECK_GOTO(ret, error);
1724 }
1725
Radek Krejci2a9fc652021-01-22 17:44:34 +01001726 LY_LIST_FOR((struct lysp_node *)submod->rpcs, pnode) {
1727 ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL);
1728 LY_CHECK_GOTO(ret, error);
1729 }
1730
1731 LY_LIST_FOR((struct lysp_node *)submod->notifs, pnode) {
1732 ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL);
1733 LY_CHECK_GOTO(ret, error);
1734 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001735
Radek Krejciab430862021-03-02 20:13:40 +01001736 COMPILE_EXTS_GOTO(&ctx, submod->exts, mod_c->exts, mod_c, ret, error);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001737 }
Michal Vasko12606ee2020-11-25 17:05:11 +01001738 ctx.pmod = sp;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001739
1740 /* validate non-instantiated groupings from the parsed schema,
1741 * without it we would accept even the schemas with invalid grouping specification */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001742 ctx.options |= LYS_COMPILE_GROUPING;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001743 LY_LIST_FOR(sp->groupings, grp) {
1744 if (!(grp->flags & LYS_USED_GRP)) {
1745 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, NULL, grp), error);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001746 }
1747 }
1748 LY_LIST_FOR(sp->data, pnode) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01001749 LY_LIST_FOR((struct lysp_node_grp *)lysp_node_groupings(pnode), grp) {
1750 if (!(grp->flags & LYS_USED_GRP)) {
1751 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, grp), error);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001752 }
1753 }
1754 }
1755 LY_ARRAY_FOR(sp->includes, u) {
1756 submod = sp->includes[u].submodule;
1757 ctx.pmod = (struct lysp_module *)submod;
1758
Radek Krejci2a9fc652021-01-22 17:44:34 +01001759 LY_LIST_FOR(submod->groupings, grp) {
1760 if (!(grp->flags & LYS_USED_GRP)) {
1761 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, NULL, grp), error);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001762 }
1763 }
1764 LY_LIST_FOR(submod->data, pnode) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01001765 LY_LIST_FOR((struct lysp_node_grp *)lysp_node_groupings(pnode), grp) {
1766 if (!(grp->flags & LYS_USED_GRP)) {
1767 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, grp), error);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001768 }
1769 }
1770 }
1771 }
1772 ctx.pmod = sp;
1773
Radek Krejciddace2c2021-01-08 11:30:56 +01001774 LOG_LOCBACK(0, 0, 1, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001775
Michal Vasko405cc9e2020-12-01 12:01:27 +01001776 /* finish compilation for all unresolved module items in the context */
1777 LY_CHECK_GOTO(ret = lys_compile_unres_mod(&ctx), error);
Michal Vasko12606ee2020-11-25 17:05:11 +01001778
Michal Vasko405cc9e2020-12-01 12:01:27 +01001779 lys_compile_unres_mod_erase(&ctx, 0);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001780 return LY_SUCCESS;
1781
1782error:
Radek Krejciddace2c2021-01-08 11:30:56 +01001783 LOG_LOCBACK(0, 0, 1, 0);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001784 lys_precompile_augments_deviations_revert(ctx.ctx, mod);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001785 lys_compile_unres_mod_erase(&ctx, 1);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001786 lysc_module_free(mod_c, NULL);
1787 mod->compiled = NULL;
1788
1789 return ret;
1790}