blob: d949b49d85b1071e5469b68e235539c8641a1c23 [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);
Radek Krejci9f87b0c2021-03-05 14:45:26 +010070 DUP_STRING_GOTO(ctx->ctx, ext_p->argname, ext_p->compiled->argname, ret, done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020071 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{
Radek Krejci85ac8312021-03-03 20:21:33 +010095 LY_ERR ret = LY_SUCCESS;
96 struct lysp_ext *ext_def;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020097
Radek Krejciab430862021-03-02 20:13:40 +010098 ext->parent_stmt = ext_p->parent_stmt;
99 ext->parent_stmt_index = ext_p->parent_stmt_index;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200100 ext->module = ctx->cur_mod;
101 ext->parent = parent;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200102
Radek Krejciab430862021-03-02 20:13:40 +0100103 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 +0100104 lysc_update_path(ctx, NULL, ext_p->name);
105
Radek Krejci85ac8312021-03-03 20:21:33 +0100106 LY_CHECK_GOTO(ret = lysp_ext_find_definition(ctx->ctx, ext_p, &ext_mod, &ext_def), cleanup);
107 LY_CHECK_GOTO(ret = lys_compile_extension(ctx, ext_mod, ext_def, &ext->def), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200108
Radek Krejci9f87b0c2021-03-05 14:45:26 +0100109 if (ext_def->argname) {
Radek Krejci85ac8312021-03-03 20:21:33 +0100110 LY_CHECK_GOTO(ret = lysp_ext_instance_resolve_argument(ctx->ctx, ext_p, ext_def), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200111 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200112
Radek Krejci85ac8312021-03-03 20:21:33 +0100113 DUP_STRING(ctx->ctx, ext_p->argument, ext->argument, ret);
114 LY_CHECK_RET(ret);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200115
116 if (ext->def->plugin && ext->def->plugin->compile) {
117 if (ext->argument) {
Radek Krejcia6016992021-03-03 10:13:41 +0100118 lysc_update_path(ctx, ext->module, ext->argument);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200119 }
Michal Vaskofc2cd072021-02-24 13:17:17 +0100120 ret = ext->def->plugin->compile(ctx, ext_p, ext);
Radek Krejcicc21a4f2021-02-09 15:23:31 +0100121 if (ret == LY_ENOT) {
122 lysc_ext_instance_free(ctx->ctx, ext);
123 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200124 if (ext->argument) {
125 lysc_update_path(ctx, NULL, NULL);
126 }
Michal Vaskofc2cd072021-02-24 13:17:17 +0100127 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200128 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200129
130cleanup:
Radek Krejci2efc45b2020-12-22 16:25:44 +0100131 lysc_update_path(ctx, NULL, NULL);
Michal Vaskofc2cd072021-02-24 13:17:17 +0100132 lysc_update_path(ctx, NULL, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200133
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200134 return ret;
135}
136
137struct lysc_ext *
138lysc_ext_dup(struct lysc_ext *orig)
139{
140 ++orig->refcount;
141 return orig;
142}
143
Radek Krejci1b2eef82021-02-17 11:17:27 +0100144LY_ERR
145lysc_ext_substmt(const struct lysc_ext_instance *ext, enum ly_stmt substmt, void **instance_p, enum ly_stmt_cardinality *cardinality_p)
146{
147 LY_ARRAY_COUNT_TYPE u;
148
149 LY_ARRAY_FOR(ext->substmts, u) {
Radek Krejci61837f72021-03-02 19:53:59 +0100150 if (LY_STMT_IS_DATA_NODE(substmt)) {
151 if (!LY_STMT_IS_DATA_NODE(ext->substmts[u].stmt)) {
Radek Krejci1b2eef82021-02-17 11:17:27 +0100152 continue;
153 }
154 } else if (LY_STMT_IS_OP(substmt)) {
155 if (!LY_STMT_IS_OP(ext->substmts[u].stmt)) {
156 continue;
157 }
158 } else if (ext->substmts[u].stmt != substmt) {
159 continue;
160 }
161
162 /* match */
163 if (cardinality_p) {
164 *cardinality_p = ext->substmts[u].cardinality;
165 }
166 if (instance_p) {
167 *instance_p = ext->substmts[u].storage;
168 }
169 return LY_SUCCESS;
170 }
171
172 return LY_ENOT;
173}
174
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200175static void
176lysc_unres_dflt_free(const struct ly_ctx *ctx, struct lysc_unres_dflt *r)
177{
178 assert(!r->dflt || !r->dflts);
179 if (r->dflt) {
180 lysp_qname_free((struct ly_ctx *)ctx, r->dflt);
181 free(r->dflt);
182 } else {
183 FREE_ARRAY((struct ly_ctx *)ctx, r->dflts, lysp_qname_free);
184 }
185 free(r);
186}
187
188void
Radek Krejcia6016992021-03-03 10:13:41 +0100189lysc_update_path(struct lysc_ctx *ctx, struct lys_module *parent_module, const char *name)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200190{
191 int len;
192 uint8_t nextlevel = 0; /* 0 - no starttag, 1 - '/' starttag, 2 - '=' starttag + '}' endtag */
193
194 if (!name) {
195 /* removing last path segment */
196 if (ctx->path[ctx->path_len - 1] == '}') {
197 for ( ; ctx->path[ctx->path_len] != '=' && ctx->path[ctx->path_len] != '{'; --ctx->path_len) {}
198 if (ctx->path[ctx->path_len] == '=') {
199 ctx->path[ctx->path_len++] = '}';
200 } else {
201 /* not a top-level special tag, remove also preceiding '/' */
202 goto remove_nodelevel;
203 }
204 } else {
205remove_nodelevel:
206 for ( ; ctx->path[ctx->path_len] != '/'; --ctx->path_len) {}
207 if (ctx->path_len == 0) {
208 /* top-level (last segment) */
209 ctx->path_len = 1;
210 }
211 }
212 /* set new terminating NULL-byte */
213 ctx->path[ctx->path_len] = '\0';
214 } else {
215 if (ctx->path_len > 1) {
Radek Krejcia6016992021-03-03 10:13:41 +0100216 if (!parent_module && (ctx->path[ctx->path_len - 1] == '}') && (ctx->path[ctx->path_len - 2] != '\'')) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200217 /* extension of the special tag */
218 nextlevel = 2;
219 --ctx->path_len;
220 } else {
221 /* there is already some path, so add next level */
222 nextlevel = 1;
223 }
224 } /* else the path is just initiated with '/', so do not add additional slash in case of top-level nodes */
225
226 if (nextlevel != 2) {
Radek Krejcia6016992021-03-03 10:13:41 +0100227 if ((parent_module && (parent_module == ctx->cur_mod)) || (!parent_module && (ctx->path_len > 1) && (name[0] == '{'))) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200228 /* module not changed, print the name unprefixed */
229 len = snprintf(&ctx->path[ctx->path_len], LYSC_CTX_BUFSIZE - ctx->path_len, "%s%s", nextlevel ? "/" : "", name);
230 } else {
231 len = snprintf(&ctx->path[ctx->path_len], LYSC_CTX_BUFSIZE - ctx->path_len, "%s%s:%s", nextlevel ? "/" : "", ctx->cur_mod->name, name);
232 }
233 } else {
234 len = snprintf(&ctx->path[ctx->path_len], LYSC_CTX_BUFSIZE - ctx->path_len, "='%s'}", name);
235 }
236 if (len >= LYSC_CTX_BUFSIZE - (int)ctx->path_len) {
237 /* output truncated */
238 ctx->path_len = LYSC_CTX_BUFSIZE - 1;
239 } else {
240 ctx->path_len += len;
241 }
242 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100243
Radek Krejciddace2c2021-01-08 11:30:56 +0100244 LOG_LOCBACK(0, 0, 1, 0);
245 LOG_LOCSET(NULL, NULL, ctx->path, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200246}
247
248/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200249 * @brief Compile information in the import statement - make sure there is the target module
250 * @param[in] ctx Compile context.
251 * @param[in] imp_p The parsed import statement structure to fill the module to.
252 * @return LY_ERR value.
253 */
254static LY_ERR
255lys_compile_import(struct lysc_ctx *ctx, struct lysp_import *imp_p)
256{
257 const struct lys_module *mod = NULL;
258 LY_ERR ret = LY_SUCCESS;
259
260 /* make sure that we have the parsed version (lysp_) of the imported module to import groupings or typedefs.
261 * The compiled version is needed only for augments, deviates and leafrefs, so they are checked (and added,
262 * if needed) when these nodes are finally being instantiated and validated at the end of schema compilation. */
263 if (!imp_p->module->parsed) {
264 /* try to use filepath if present */
265 if (imp_p->module->filepath) {
266 struct ly_in *in;
267 if (ly_in_new_filepath(imp_p->module->filepath, 0, &in)) {
268 LOGINT(ctx->ctx);
269 } else {
270 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 +0100271 ".yin") ? LYS_IN_YIN : LYS_IN_YANG, NULL, &mod));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200272 if (mod != imp_p->module) {
273 LOGERR(ctx->ctx, LY_EINT, "Filepath \"%s\" of the module \"%s\" does not match.",
274 imp_p->module->filepath, imp_p->module->name);
275 mod = NULL;
276 }
277 }
278 ly_in_free(in, 1);
279 }
280 if (!mod) {
Michal Vasko405cc9e2020-12-01 12:01:27 +0100281 if (lysp_load_module(ctx->ctx, imp_p->module->name, imp_p->module->revision, 0, NULL, ctx->unres,
282 (struct lys_module **)&mod)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200283 LOGERR(ctx->ctx, LY_ENOTFOUND, "Unable to reload \"%s\" module to import it into \"%s\", source data not found.",
284 imp_p->module->name, ctx->cur_mod->name);
285 return LY_ENOTFOUND;
286 }
287 }
288 }
289
290 return ret;
291}
292
293LY_ERR
294lys_identity_precompile(struct lysc_ctx *ctx_sc, struct ly_ctx *ctx, struct lysp_module *parsed_mod,
295 struct lysp_ident *identities_p, struct lysc_ident **identities)
296{
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100297 LY_ARRAY_COUNT_TYPE u;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200298 struct lysc_ctx context = {0};
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100299 struct lysc_ident *ident;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200300 LY_ERR ret = LY_SUCCESS;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100301 ly_bool enabled;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200302
303 assert(ctx_sc || ctx);
304
305 if (!ctx_sc) {
306 context.ctx = ctx;
Radek Krejci3aac9a72020-12-01 12:24:26 +0100307 context.cur_mod = parsed_mod ? parsed_mod->mod : NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200308 context.pmod = parsed_mod;
309 context.path_len = 1;
310 context.path[0] = '/';
311 ctx_sc = &context;
312 }
313
314 if (!identities_p) {
315 return LY_SUCCESS;
316 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200317
318 lysc_update_path(ctx_sc, NULL, "{identity}");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200319 LY_ARRAY_FOR(identities_p, u) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100320 /* evaluate if-features */
321 LY_CHECK_RET(lys_eval_iffeatures(ctx, identities_p[u].iffeatures, &enabled));
322 if (!enabled) {
323 continue;
324 }
325
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200326 lysc_update_path(ctx_sc, NULL, identities_p[u].name);
327
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100328 /* add new compiled identity */
329 LY_ARRAY_NEW_RET(ctx_sc->ctx, *identities, ident, LY_EMEM);
330
331 DUP_STRING_GOTO(ctx_sc->ctx, identities_p[u].name, ident->name, ret, done);
332 DUP_STRING_GOTO(ctx_sc->ctx, identities_p[u].dsc, ident->dsc, ret, done);
333 DUP_STRING_GOTO(ctx_sc->ctx, identities_p[u].ref, ident->ref, ret, done);
334 ident->module = ctx_sc->cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200335 /* 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 +0100336 COMPILE_EXTS_GOTO(ctx_sc, identities_p[u].exts, ident->exts, ident, ret, done);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100337 ident->flags = identities_p[u].flags;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200338
339 lysc_update_path(ctx_sc, NULL, NULL);
340 }
341 lysc_update_path(ctx_sc, NULL, NULL);
342done:
343 return ret;
344}
345
346/**
347 * @brief Check circular dependency of identities - identity MUST NOT reference itself (via their base statement).
348 *
349 * The function works in the same way as lys_compile_feature_circular_check() with different structures and error messages.
350 *
351 * @param[in] ctx Compile context for logging.
352 * @param[in] ident The base identity (its derived list is being extended by the identity being currently processed).
353 * @param[in] derived The list of derived identities of the identity being currently processed (not the one provided as @p ident)
354 * @return LY_SUCCESS if everything is ok.
355 * @return LY_EVALID if the identity is derived from itself.
356 */
357static LY_ERR
358lys_compile_identity_circular_check(struct lysc_ctx *ctx, struct lysc_ident *ident, struct lysc_ident **derived)
359{
360 LY_ERR ret = LY_SUCCESS;
361 LY_ARRAY_COUNT_TYPE u, v;
362 struct ly_set recursion = {0};
363 struct lysc_ident *drv;
364
365 if (!derived) {
366 return LY_SUCCESS;
367 }
368
369 for (u = 0; u < LY_ARRAY_COUNT(derived); ++u) {
370 if (ident == derived[u]) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100371 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200372 "Identity \"%s\" is indirectly derived from itself.", ident->name);
373 ret = LY_EVALID;
374 goto cleanup;
375 }
376 ret = ly_set_add(&recursion, derived[u], 0, NULL);
377 LY_CHECK_GOTO(ret, cleanup);
378 }
379
380 for (v = 0; v < recursion.count; ++v) {
381 drv = recursion.objs[v];
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200382 for (u = 0; u < LY_ARRAY_COUNT(drv->derived); ++u) {
383 if (ident == drv->derived[u]) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100384 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200385 "Identity \"%s\" is indirectly derived from itself.", ident->name);
386 ret = LY_EVALID;
387 goto cleanup;
388 }
389 ret = ly_set_add(&recursion, drv->derived[u], 0, NULL);
390 LY_CHECK_GOTO(ret, cleanup);
391 }
392 }
393
394cleanup:
395 ly_set_erase(&recursion, NULL);
396 return ret;
397}
398
399LY_ERR
400lys_compile_identity_bases(struct lysc_ctx *ctx, const struct lysp_module *base_pmod, const char **bases_p,
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100401 struct lysc_ident *ident, struct lysc_ident ***bases, ly_bool *enabled)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200402{
403 LY_ARRAY_COUNT_TYPE u, v;
404 const char *s, *name;
405 const struct lys_module *mod;
406 struct lysc_ident **idref;
407
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100408 assert((ident && enabled) || bases);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200409
410 if ((LY_ARRAY_COUNT(bases_p) > 1) && (ctx->pmod->version < LYS_VERSION_1_1)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100411 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200412 "Multiple bases in %s are allowed only in YANG 1.1 modules.", ident ? "identity" : "identityref type");
413 return LY_EVALID;
414 }
415
416 LY_ARRAY_FOR(bases_p, u) {
417 s = strchr(bases_p[u], ':');
418 if (s) {
419 /* prefixed identity */
420 name = &s[1];
Michal Vaskob2d55bf2020-11-02 15:42:43 +0100421 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 +0200422 } else {
423 name = bases_p[u];
424 mod = base_pmod->mod;
425 }
426 if (!mod) {
427 if (ident) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100428 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200429 "Invalid prefix used for base (%s) of identity \"%s\".", bases_p[u], ident->name);
430 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100431 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200432 "Invalid prefix used for base (%s) of identityref.", bases_p[u]);
433 }
434 return LY_EVALID;
435 }
436
437 idref = NULL;
438 LY_ARRAY_FOR(mod->identities, v) {
439 if (!strcmp(name, mod->identities[v].name)) {
440 if (ident) {
441 if (ident == &mod->identities[v]) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100442 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200443 "Identity \"%s\" is derived from itself.", ident->name);
444 return LY_EVALID;
445 }
446 LY_CHECK_RET(lys_compile_identity_circular_check(ctx, &mod->identities[v], ident->derived));
447 /* we have match! store the backlink */
448 LY_ARRAY_NEW_RET(ctx->ctx, mod->identities[v].derived, idref, LY_EMEM);
449 *idref = ident;
450 } else {
451 /* we have match! store the found identity */
452 LY_ARRAY_NEW_RET(ctx->ctx, *bases, idref, LY_EMEM);
453 *idref = &mod->identities[v];
454 }
455 break;
456 }
457 }
458 if (!idref || !(*idref)) {
459 if (ident) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100460 /* look into the parsed module to check whether the identity is not merely disabled */
461 LY_ARRAY_FOR(mod->parsed->identities, v) {
462 if (!strcmp(mod->parsed->identities[v].name, name)) {
463 *enabled = 0;
464 return LY_SUCCESS;
465 }
466 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100467 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200468 "Unable to find base (%s) of identity \"%s\".", bases_p[u], ident->name);
469 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100470 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200471 "Unable to find base (%s) of identityref.", bases_p[u]);
472 }
473 return LY_EVALID;
474 }
475 }
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100476
477 if (ident) {
478 *enabled = 1;
479 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200480 return LY_SUCCESS;
481}
482
483/**
484 * @brief For the given array of identities, set the backlinks from all their base identities.
485 * @param[in] ctx Compile context, not only for logging but also to get the current module to resolve prefixes.
486 * @param[in] idents_p Array of identities definitions from the parsed schema structure.
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100487 * @param[in,out] idents Array of referencing identities to which the backlinks are supposed to be set. Any
488 * identities with disabled bases are removed.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200489 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
490 */
491static LY_ERR
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100492lys_compile_identities_derived(struct lysc_ctx *ctx, struct lysp_ident *idents_p, struct lysc_ident **idents)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200493{
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100494 LY_ARRAY_COUNT_TYPE u, v;
495 ly_bool enabled;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200496
497 lysc_update_path(ctx, NULL, "{identity}");
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100498
499restart:
Radek Krejcic7d13e32020-12-09 12:32:24 +0100500 for (u = 0, v = 0; u < LY_ARRAY_COUNT(*idents); ++u) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100501 /* find matching parsed identity, the disabled ones are missing in the compiled array */
502 while (v < LY_ARRAY_COUNT(idents_p)) {
503 if (idents_p[v].name == (*idents)[u].name) {
504 break;
505 }
506 ++v;
507 }
508 assert(v < LY_ARRAY_COUNT(idents_p));
509
510 if (!idents_p[v].bases) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200511 continue;
512 }
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100513 lysc_update_path(ctx, NULL, (*idents)[u].name);
514 LY_CHECK_RET(lys_compile_identity_bases(ctx, (*idents)[u].module->parsed, idents_p[v].bases, &(*idents)[u], NULL,
515 &enabled));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200516 lysc_update_path(ctx, NULL, NULL);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100517
518 if (!enabled) {
519 /* remove the identity */
520 lysc_ident_free(ctx->ctx, &(*idents)[u]);
521 LY_ARRAY_DECREMENT(*idents);
522 if (u < LY_ARRAY_COUNT(*idents)) {
523 memmove(&(*idents)[u], &(*idents)[u + 1], (LY_ARRAY_COUNT(*idents) - u) * sizeof **idents);
524 }
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100525
526 /* revert compilation of all the previous identities */
527 for (v = 0; v < u; ++v) {
528 LY_ARRAY_FREE((*idents)[v].derived);
529 }
530
Michal Vasko74c82ae2020-11-03 17:36:53 +0100531 /* free the whole array if there are no identites left */
532 if (!LY_ARRAY_COUNT(*idents)) {
533 LY_ARRAY_FREE(*idents);
534 *idents = NULL;
535 }
536
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100537 /* restart the whole process without this identity */
538 goto restart;
539 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200540 }
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100541
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200542 lysc_update_path(ctx, NULL, NULL);
543 return LY_SUCCESS;
544}
545
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200546static void *
547lys_compile_extension_instance_storage(enum ly_stmt stmt, struct lysc_ext_substmt *substmts)
548{
549 for (LY_ARRAY_COUNT_TYPE u = 0; substmts[u].stmt; ++u) {
550 if (substmts[u].stmt == stmt) {
551 return substmts[u].storage;
552 }
553 }
554 return NULL;
555}
556
557LY_ERR
Radek Krejci6b88a462021-02-17 12:39:34 +0100558lys_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 +0200559{
560 LY_ERR ret = LY_EVALID, r;
561 LY_ARRAY_COUNT_TYPE u;
562 struct lysp_stmt *stmt;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200563 void *parsed = NULL, **compiled = NULL;
564
565 /* check for invalid substatements */
Radek Krejci6b88a462021-02-17 12:39:34 +0100566 for (stmt = ext_p->child; stmt; stmt = stmt->next) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200567 if (stmt->flags & (LYS_YIN_ATTR | LYS_YIN_ARGUMENT)) {
568 continue;
569 }
Radek Krejci6b88a462021-02-17 12:39:34 +0100570 LY_ARRAY_FOR(ext->substmts, u) {
571 if (ext->substmts[u].stmt == stmt->kw) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200572 break;
573 }
574 }
Radek Krejci6b88a462021-02-17 12:39:34 +0100575 if (u == LY_ARRAY_COUNT(ext->substmts)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100576 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 +0100577 stmt->stmt, ext_p->name, ext_p->argument ? " " : "", ext_p->argument ? ext_p->argument : "");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200578 goto cleanup;
579 }
580 }
581
582 /* TODO store inherited data, e.g. status first, but mark them somehow to allow to overwrite them and not detect duplicity */
583
Radek Krejci6b88a462021-02-17 12:39:34 +0100584 /* note into the compile context that we are processing extension now */
585 ctx->ext = ext;
586
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200587 /* keep order of the processing the same as the order in the defined substmts,
588 * 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 +0200589
Radek Krejci6b88a462021-02-17 12:39:34 +0100590 LY_ARRAY_FOR(ext->substmts, u) {
591 uint64_t stmt_counter = 0;
592
593 for (stmt = ext_p->child; stmt; stmt = stmt->next) {
594 if (ext->substmts[u].stmt != stmt->kw) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200595 continue;
596 }
597
Radek Krejci6b88a462021-02-17 12:39:34 +0100598 parsed = NULL;
599 stmt_counter++;
600 if (ext->substmts[u].storage) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200601 switch (stmt->kw) {
Radek Krejci6b88a462021-02-17 12:39:34 +0100602 case LY_STMT_ACTION:
603 case LY_STMT_ANYDATA:
604 case LY_STMT_ANYXML:
605 case LY_STMT_CONTAINER:
606 case LY_STMT_CHOICE:
607 case LY_STMT_LEAF:
608 case LY_STMT_LEAF_LIST:
609 case LY_STMT_LIST:
610 case LY_STMT_NOTIFICATION:
611 case LY_STMT_RPC:
612 case LY_STMT_USES:
613 r = lysp_stmt_parse(ctx, stmt, &parsed, NULL);
614 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
615
616 /* set storage as an alternative document root in the compile context */
617 r = lys_compile_node(ctx, parsed, NULL, 0, NULL);
618 lysp_node_free(ctx->ctx, parsed);
619 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200620 break;
Radek Krejci1b2eef82021-02-17 11:17:27 +0100621 case LY_STMT_DESCRIPTION:
622 case LY_STMT_REFERENCE:
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200623 case LY_STMT_UNITS: {
Radek Krejci6b88a462021-02-17 12:39:34 +0100624 const char **str_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200625
Radek Krejci6b88a462021-02-17 12:39:34 +0100626 if (ext->substmts[u].cardinality < LY_STMT_CARD_SOME) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200627 /* single item */
Radek Krejci6b88a462021-02-17 12:39:34 +0100628 if (*((const char **)ext->substmts[u].storage)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100629 LOGVAL(ctx->ctx, LY_VCODE_DUPSTMT, stmt->stmt);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200630 goto cleanup;
631 }
Radek Krejci6b88a462021-02-17 12:39:34 +0100632 str_p = (const char **)ext->substmts[u].storage;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200633 } else {
634 /* sized array */
Radek Krejci6b88a462021-02-17 12:39:34 +0100635 const char ***strings_array = (const char ***)ext->substmts[u].storage;
636 LY_ARRAY_NEW_GOTO(ctx->ctx, *strings_array, str_p, ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200637 }
Radek Krejci6b88a462021-02-17 12:39:34 +0100638 r = lydict_insert(ctx->ctx, stmt->arg, 0, str_p);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200639 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
640 break;
641 }
Radek Krejci6b88a462021-02-17 12:39:34 +0100642 case LY_STMT_IF_FEATURE: {
643 ly_bool enabled;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200644
Radek Krejci76c8c4e2021-02-17 10:16:48 +0100645 r = lysp_stmt_parse(ctx, stmt, &parsed, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200646 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
Radek Krejci6b88a462021-02-17 12:39:34 +0100647
648 r = lys_eval_iffeatures(ctx->ctx, parsed, &enabled);
649 FREE_ARRAY(ctx->ctx, (struct lysp_qname *)parsed, lysp_qname_free);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100650 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
651 if (!enabled) {
652 /* it is disabled, remove the whole extension instance */
653 return LY_ENOT;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200654 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200655 break;
Radek Krejci6b88a462021-02-17 12:39:34 +0100656 }
657 case LY_STMT_STATUS:
658 assert(ext->substmts[u].cardinality < LY_STMT_CARD_SOME);
659 LY_CHECK_ERR_GOTO(r = lysp_stmt_parse(ctx, stmt, &ext->substmts[u].storage, /* TODO */ NULL), ret = r, cleanup);
660 break;
661 case LY_STMT_TYPE: {
662 uint16_t *flags = lys_compile_extension_instance_storage(LY_STMT_STATUS, ext->substmts);
663 const char **units = lys_compile_extension_instance_storage(LY_STMT_UNITS, ext->substmts);
664
665 if (ext->substmts[u].cardinality < LY_STMT_CARD_SOME) {
666 /* single item */
667 if (*(struct lysc_type **)ext->substmts[u].storage) {
668 LOGVAL(ctx->ctx, LY_VCODE_DUPSTMT, stmt->stmt);
669 goto cleanup;
670 }
671 compiled = ext->substmts[u].storage;
672 } else {
673 /* sized array */
674 struct lysc_type ***types = (struct lysc_type ***)ext->substmts[u].storage, **type = NULL;
675 LY_ARRAY_NEW_GOTO(ctx->ctx, *types, type, ret, cleanup);
676 compiled = (void *)type;
677 }
678
679 r = lysp_stmt_parse(ctx, stmt, &parsed, NULL);
680 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
681 r = lys_compile_type(ctx, NULL, flags ? *flags : 0, ext_p->name, parsed, (struct lysc_type **)compiled,
682 units && !*units ? units : NULL, NULL);
683 lysp_type_free(ctx->ctx, parsed);
684 free(parsed);
685 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
686 break;
687 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200688 /* TODO support other substatements (parse stmt to lysp and then compile lysp to lysc),
689 * also note that in many statements their extensions are not taken into account */
690 default:
Radek Krejci2efc45b2020-12-22 16:25:44 +0100691 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 +0100692 stmt->stmt, ext_p->name, ext_p->argument ? " " : "", ext_p->argument ? ext_p->argument : "");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200693 goto cleanup;
694 }
695 }
696 }
697
Radek Krejci6b88a462021-02-17 12:39:34 +0100698 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 +0100699 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Missing mandatory keyword \"%s\" as a child of \"%s%s%s\".",
Radek Krejci6b88a462021-02-17 12:39:34 +0100700 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 +0200701 goto cleanup;
702 }
703 }
704
705 ret = LY_SUCCESS;
706
707cleanup:
Radek Krejci6b88a462021-02-17 12:39:34 +0100708 ctx->ext = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200709 return ret;
710}
711
712/**
713 * @brief Check when for cyclic dependencies.
714 *
715 * @param[in] set Set with all the referenced nodes.
716 * @param[in] node Node whose "when" referenced nodes are in @p set.
717 * @return LY_ERR value
718 */
719static LY_ERR
720lys_compile_unres_when_cyclic(struct lyxp_set *set, const struct lysc_node *node)
721{
722 struct lyxp_set tmp_set;
723 struct lyxp_set_scnode *xp_scnode;
724 uint32_t i, j;
725 LY_ARRAY_COUNT_TYPE u;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200726 LY_ERR ret = LY_SUCCESS;
727
728 memset(&tmp_set, 0, sizeof tmp_set);
729
730 /* prepare in_ctx of the set */
731 for (i = 0; i < set->used; ++i) {
732 xp_scnode = &set->val.scnodes[i];
733
Radek Krejcif13b87b2020-12-01 22:02:17 +0100734 if (xp_scnode->in_ctx != LYXP_SET_SCNODE_START_USED) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200735 /* check node when, skip the context node (it was just checked) */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100736 xp_scnode->in_ctx = LYXP_SET_SCNODE_ATOM_CTX;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200737 }
738 }
739
740 for (i = 0; i < set->used; ++i) {
741 xp_scnode = &set->val.scnodes[i];
Radek Krejcif13b87b2020-12-01 22:02:17 +0100742 if (xp_scnode->in_ctx != LYXP_SET_SCNODE_ATOM_CTX) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200743 /* already checked */
744 continue;
745 }
746
747 if ((xp_scnode->type != LYXP_NODE_ELEM) || (xp_scnode->scnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) ||
Radek Krejci9a3823e2021-01-27 20:26:46 +0100748 !lysc_node_when(xp_scnode->scnode)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200749 /* no when to check */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100750 xp_scnode->in_ctx = LYXP_SET_SCNODE_ATOM;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200751 continue;
752 }
753
754 node = xp_scnode->scnode;
755 do {
Radek Krejci9a3823e2021-01-27 20:26:46 +0100756 struct lysc_when **when_list, *when;
757
Radek Krejciddace2c2021-01-08 11:30:56 +0100758 LOG_LOCSET(node, NULL, NULL, NULL);
Radek Krejci9a3823e2021-01-27 20:26:46 +0100759 when_list = lysc_node_when(node);
760 LY_ARRAY_FOR(when_list, u) {
761 when = when_list[u];
Michal Vasko400e9672021-01-11 13:39:17 +0100762 ret = lyxp_atomize(set->ctx, when->cond, node->module, LY_PREF_SCHEMA_RESOLVED, when->prefixes,
763 when->context, &tmp_set, LYXP_SCNODE_SCHEMA);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200764 if (ret != LY_SUCCESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100765 LOGVAL(set->ctx, LYVE_SEMANTICS, "Invalid when condition \"%s\".", when->cond->expr);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200766 goto cleanup;
767 }
768
769 for (j = 0; j < tmp_set.used; ++j) {
770 /* skip roots'n'stuff */
771 if (tmp_set.val.scnodes[j].type == LYXP_NODE_ELEM) {
772 /* try to find this node in our set */
773 uint32_t idx;
Radek Krejcif13b87b2020-12-01 22:02:17 +0100774 if (lyxp_set_scnode_contains(set, tmp_set.val.scnodes[j].scnode, LYXP_NODE_ELEM, -1, &idx) &&
775 (set->val.scnodes[idx].in_ctx == LYXP_SET_SCNODE_START_USED)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100776 LOGVAL(set->ctx, LYVE_SEMANTICS, "When condition includes a self-reference.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200777 ret = LY_EVALID;
778 goto cleanup;
779 }
780
781 /* needs to be checked, if in both sets, will be ignored */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100782 tmp_set.val.scnodes[j].in_ctx = LYXP_SET_SCNODE_ATOM_CTX;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200783 } else {
784 /* no when, nothing to check */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100785 tmp_set.val.scnodes[j].in_ctx = LYXP_SET_SCNODE_ATOM;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200786 }
787 }
788
789 /* merge this set into the global when set */
790 lyxp_set_scnode_merge(set, &tmp_set);
791 }
792
793 /* check when of non-data parents as well */
794 node = node->parent;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100795
Radek Krejciddace2c2021-01-08 11:30:56 +0100796 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200797 } while (node && (node->nodetype & (LYS_CASE | LYS_CHOICE)));
798
799 /* this node when was checked (xp_scnode could have been reallocd) */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100800 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_START_USED;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200801 }
802
803cleanup:
804 lyxp_set_free_content(&tmp_set);
805 return ret;
806}
807
808LY_ERR
809lysc_check_status(struct lysc_ctx *ctx, uint16_t flags1, void *mod1, const char *name1, uint16_t flags2, void *mod2,
810 const char *name2)
811{
812 uint16_t flg1, flg2;
813
814 flg1 = (flags1 & LYS_STATUS_MASK) ? (flags1 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
815 flg2 = (flags2 & LYS_STATUS_MASK) ? (flags2 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
816
817 if ((flg1 < flg2) && (mod1 == mod2)) {
818 if (ctx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100819 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200820 "A %s definition \"%s\" is not allowed to reference %s definition \"%s\".",
821 flg1 == LYS_STATUS_CURR ? "current" : "deprecated", name1,
822 flg2 == LYS_STATUS_OBSLT ? "obsolete" : "deprecated", name2);
823 }
824 return LY_EVALID;
825 }
826
827 return LY_SUCCESS;
828}
829
Michal Vasko25d6ad02020-10-22 12:20:22 +0200830LY_ERR
831lys_compile_expr_implement(const struct ly_ctx *ctx, const struct lyxp_expr *expr, LY_PREFIX_FORMAT format,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100832 void *prefix_data, ly_bool implement, struct lys_glob_unres *unres, const struct lys_module **mod_p)
Michal Vaskocfaff232020-10-20 09:35:14 +0200833{
834 uint32_t i;
835 const char *ptr, *start;
836 const struct lys_module *mod;
837
Michal Vasko25d6ad02020-10-22 12:20:22 +0200838 assert(implement || mod_p);
839
Michal Vaskocfaff232020-10-20 09:35:14 +0200840 for (i = 0; i < expr->used; ++i) {
841 if ((expr->tokens[i] != LYXP_TOKEN_NAMETEST) && (expr->tokens[i] != LYXP_TOKEN_LITERAL)) {
842 /* token cannot have a prefix */
843 continue;
844 }
845
846 start = expr->expr + expr->tok_pos[i];
847 if (!(ptr = ly_strnchr(start, ':', expr->tok_len[i]))) {
848 /* token without a prefix */
849 continue;
850 }
851
852 if (!(mod = ly_resolve_prefix(ctx, start, ptr - start, format, prefix_data))) {
853 /* unknown prefix, do not care right now */
854 continue;
855 }
856
857 if (!mod->implemented) {
858 /* unimplemented module found */
Michal Vasko25d6ad02020-10-22 12:20:22 +0200859 if (implement) {
Michal Vasko405cc9e2020-12-01 12:01:27 +0100860 LY_CHECK_RET(lys_set_implemented_r((struct lys_module *)mod, NULL, unres));
Michal Vasko25d6ad02020-10-22 12:20:22 +0200861 } else {
Michal Vaskocfaff232020-10-20 09:35:14 +0200862 *mod_p = mod;
Michal Vasko25d6ad02020-10-22 12:20:22 +0200863 break;
Michal Vaskocfaff232020-10-20 09:35:14 +0200864 }
Michal Vaskocfaff232020-10-20 09:35:14 +0200865 }
866 }
867
Michal Vasko25d6ad02020-10-22 12:20:22 +0200868 return LY_SUCCESS;
Michal Vaskocfaff232020-10-20 09:35:14 +0200869}
870
871/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200872 * @brief Check when/must expressions of a node on a complete compiled schema tree.
873 *
874 * @param[in] ctx Compile context.
875 * @param[in] node Node to check.
Michal Vasko405cc9e2020-12-01 12:01:27 +0100876 * @param[in,out] unres Global unres structure.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200877 * @return LY_ERR value
878 */
879static LY_ERR
Michal Vasko405cc9e2020-12-01 12:01:27 +0100880lys_compile_unres_xpath(struct lysc_ctx *ctx, const struct lysc_node *node, struct lys_glob_unres *unres)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200881{
882 struct lyxp_set tmp_set;
883 uint32_t i, opts;
884 LY_ARRAY_COUNT_TYPE u;
885 ly_bool input_done = 0;
Radek Krejci9a3823e2021-01-27 20:26:46 +0100886 struct lysc_when **whens = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200887 struct lysc_must *musts = NULL;
888 LY_ERR ret = LY_SUCCESS;
Michal Vaskocfaff232020-10-20 09:35:14 +0200889 const struct lys_module *mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200890
Radek Krejciddace2c2021-01-08 11:30:56 +0100891 LOG_LOCSET(node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100892
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200893 memset(&tmp_set, 0, sizeof tmp_set);
Michal Vaskod1e53b92021-01-28 13:11:06 +0100894 opts = LYXP_SCNODE_SCHEMA | ((node->flags & LYS_IS_OUTPUT) ? LYXP_SCNODE_OUTPUT : 0);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200895
Radek Krejci9a3823e2021-01-27 20:26:46 +0100896 whens = lysc_node_when(node);
897 musts = lysc_node_musts(node);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200898
Radek Krejci9a3823e2021-01-27 20:26:46 +0100899 LY_ARRAY_FOR(whens, u) {
Michal Vaskocfaff232020-10-20 09:35:14 +0200900 /* first check whether all the referenced modules are implemented */
Michal Vasko25d6ad02020-10-22 12:20:22 +0200901 mod = NULL;
Radek Krejci9a3823e2021-01-27 20:26:46 +0100902 ret = lys_compile_expr_implement(ctx->ctx, whens[u]->cond, LY_PREF_SCHEMA_RESOLVED, whens[u]->prefixes,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100903 ctx->ctx->flags & LY_CTX_REF_IMPLEMENTED, unres, &mod);
Michal Vasko25d6ad02020-10-22 12:20:22 +0200904 if (ret) {
905 goto cleanup;
906 } else if (mod) {
Michal Vaskocfaff232020-10-20 09:35:14 +0200907 LOGWRN(ctx->ctx, "When condition \"%s\" check skipped because referenced module \"%s\" is not implemented.",
Radek Krejci9a3823e2021-01-27 20:26:46 +0100908 whens[u]->cond->expr, mod->name);
Michal Vaskocfaff232020-10-20 09:35:14 +0200909 continue;
910 }
911
912 /* check "when" */
Radek Krejci9a3823e2021-01-27 20:26:46 +0100913 ret = lyxp_atomize(ctx->ctx, whens[u]->cond, node->module, LY_PREF_SCHEMA_RESOLVED, whens[u]->prefixes,
914 whens[u]->context, &tmp_set, opts);
Michal Vasko25d6ad02020-10-22 12:20:22 +0200915 if (ret) {
Radek Krejci9a3823e2021-01-27 20:26:46 +0100916 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Invalid when condition \"%s\".", whens[u]->cond->expr);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200917 goto cleanup;
918 }
919
920 ctx->path[0] = '\0';
Michal Vasko14ed9cd2021-01-28 14:16:25 +0100921 lysc_path(node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200922 for (i = 0; i < tmp_set.used; ++i) {
923 /* skip roots'n'stuff */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100924 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 +0200925 struct lysc_node *schema = tmp_set.val.scnodes[i].scnode;
926
927 /* XPath expression cannot reference "lower" status than the node that has the definition */
Radek Krejci9a3823e2021-01-27 20:26:46 +0100928 ret = lysc_check_status(ctx, whens[u]->flags, node->module, node->name, schema->flags, schema->module,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200929 schema->name);
930 LY_CHECK_GOTO(ret, cleanup);
931
932 /* check dummy node accessing */
933 if (schema == node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100934 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "When condition is accessing its own conditional node.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200935 ret = LY_EVALID;
936 goto cleanup;
937 }
938 }
939 }
940
941 /* check cyclic dependencies */
942 ret = lys_compile_unres_when_cyclic(&tmp_set, node);
943 LY_CHECK_GOTO(ret, cleanup);
944
945 lyxp_set_free_content(&tmp_set);
946 }
947
948check_musts:
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200949 LY_ARRAY_FOR(musts, u) {
Michal Vaskocfaff232020-10-20 09:35:14 +0200950 /* first check whether all the referenced modules are implemented */
Michal Vasko25d6ad02020-10-22 12:20:22 +0200951 mod = NULL;
952 ret = lys_compile_expr_implement(ctx->ctx, musts[u].cond, LY_PREF_SCHEMA_RESOLVED, musts[u].prefixes,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100953 ctx->ctx->flags & LY_CTX_REF_IMPLEMENTED, unres, &mod);
Michal Vasko25d6ad02020-10-22 12:20:22 +0200954 if (ret) {
955 goto cleanup;
956 } else if (mod) {
Michal Vaskocfaff232020-10-20 09:35:14 +0200957 LOGWRN(ctx->ctx, "Must condition \"%s\" check skipped because referenced module \"%s\" is not implemented.",
958 musts[u].cond->expr, mod->name);
959 continue;
960 }
961
962 /* check "must" */
Michal Vasko400e9672021-01-11 13:39:17 +0100963 ret = lyxp_atomize(ctx->ctx, musts[u].cond, node->module, LY_PREF_SCHEMA_RESOLVED, musts[u].prefixes, node,
964 &tmp_set, opts);
Michal Vasko25d6ad02020-10-22 12:20:22 +0200965 if (ret) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100966 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Invalid must restriction \"%s\".", musts[u].cond->expr);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200967 goto cleanup;
968 }
969
970 ctx->path[0] = '\0';
Michal Vasko14ed9cd2021-01-28 14:16:25 +0100971 lysc_path(node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200972 for (i = 0; i < tmp_set.used; ++i) {
973 /* skip roots'n'stuff */
974 if (tmp_set.val.scnodes[i].type == LYXP_NODE_ELEM) {
975 /* XPath expression cannot reference "lower" status than the node that has the definition */
976 ret = lysc_check_status(ctx, node->flags, node->module, node->name, tmp_set.val.scnodes[i].scnode->flags,
977 tmp_set.val.scnodes[i].scnode->module, tmp_set.val.scnodes[i].scnode->name);
978 LY_CHECK_GOTO(ret, cleanup);
979 }
980 }
981
982 lyxp_set_free_content(&tmp_set);
983 }
984
985 if ((node->nodetype & (LYS_RPC | LYS_ACTION)) && !input_done) {
986 /* now check output musts */
987 input_done = 1;
Radek Krejci9a3823e2021-01-27 20:26:46 +0100988 whens = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100989 musts = ((struct lysc_node_action *)node)->output.musts;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200990 opts = LYXP_SCNODE_OUTPUT;
991 goto check_musts;
992 }
993
994cleanup:
995 lyxp_set_free_content(&tmp_set);
Radek Krejciddace2c2021-01-08 11:30:56 +0100996 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200997 return ret;
998}
999
1000/**
1001 * @brief Check leafref for its target existence on a complete compiled schema tree.
1002 *
1003 * @param[in] ctx Compile context.
1004 * @param[in] node Context node for the leafref.
1005 * @param[in] lref Leafref to check/resolve.
Michal Vasko405cc9e2020-12-01 12:01:27 +01001006 * @param[in,out] unres Global unres structure.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001007 * @return LY_ERR value.
1008 */
1009static LY_ERR
Michal Vasko405cc9e2020-12-01 12:01:27 +01001010lys_compile_unres_leafref(struct lysc_ctx *ctx, const struct lysc_node *node, struct lysc_type_leafref *lref,
1011 struct lys_glob_unres *unres)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001012{
Michal Vaskod1e53b92021-01-28 13:11:06 +01001013 const struct lysc_node *target = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001014 struct ly_path *p;
1015 struct lysc_type *type;
1016
1017 assert(node->nodetype & (LYS_LEAF | LYS_LEAFLIST));
1018
1019 /* try to find the target */
Michal Vaskod1e53b92021-01-28 13:11:06 +01001020 LY_CHECK_RET(ly_path_compile(ctx->ctx, lref->cur_mod, node, lref->path, LY_PATH_LREF_TRUE,
1021 (node->flags & LYS_IS_OUTPUT) ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_MANY,
1022 LY_PREF_SCHEMA_RESOLVED, lref->prefixes, unres, &p));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001023
1024 /* get the target node */
1025 target = p[LY_ARRAY_COUNT(p) - 1].node;
1026 ly_path_free(node->module->ctx, p);
1027
1028 if (!(target->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001029 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 +02001030 lref->path->expr, lys_nodetype2str(target->nodetype));
1031 return LY_EVALID;
1032 }
1033
1034 /* check status */
1035 ctx->path[0] = '\0';
1036 lysc_path(node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
1037 ctx->path_len = strlen(ctx->path);
1038 if (lysc_check_status(ctx, node->flags, node->module, node->name, target->flags, target->module, target->name)) {
1039 return LY_EVALID;
1040 }
1041 ctx->path_len = 1;
1042 ctx->path[1] = '\0';
1043
1044 /* check config */
1045 if (lref->require_instance) {
Michal Vaskod1e53b92021-01-28 13:11:06 +01001046 if ((node->flags & LYS_CONFIG_W) && (target->flags & LYS_CONFIG_R)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001047 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid leafref path \"%s\" - target is supposed"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001048 " to represent configuration data (as the leafref does), but it does not.", lref->path->expr);
1049 return LY_EVALID;
1050 }
1051 }
1052
1053 /* store the target's type and check for circular chain of leafrefs */
1054 lref->realtype = ((struct lysc_node_leaf *)target)->type;
1055 for (type = lref->realtype; type && type->basetype == LY_TYPE_LEAFREF; type = ((struct lysc_type_leafref *)type)->realtype) {
1056 if (type == (struct lysc_type *)lref) {
1057 /* circular chain detected */
Radek Krejci2efc45b2020-12-22 16:25:44 +01001058 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid leafref path \"%s\" - circular chain of leafrefs detected.",
1059 lref->path->expr);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001060 return LY_EVALID;
1061 }
1062 }
1063
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001064 /* TODO check if leafref and its target are under common if-features */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001065
1066 return LY_SUCCESS;
1067}
1068
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001069/**
1070 * @brief Compile default value(s) for leaf or leaf-list expecting a complete compiled schema tree.
1071 *
1072 * @param[in] ctx Compile context.
1073 * @param[in] node Leaf or leaf-list to compile the default value(s) for.
1074 * @param[in] type Type of the default value.
1075 * @param[in] dflt Default value.
1076 * @param[in] dflt_pmod Parsed module of the @p dflt to resolve possible prefixes.
1077 * @param[in,out] storage Storage for the compiled default value.
Michal Vasko405cc9e2020-12-01 12:01:27 +01001078 * @param[in,out] unres Global unres structure for newly implemented modules.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001079 * @return LY_ERR value.
1080 */
1081static LY_ERR
1082lys_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 +01001083 const struct lysp_module *dflt_pmod, struct lyd_value *storage, struct lys_glob_unres *unres)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001084{
1085 LY_ERR ret;
Michal Vasko25d6ad02020-10-22 12:20:22 +02001086 uint32_t options;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001087 struct ly_err_item *err = NULL;
1088
Michal Vasko25d6ad02020-10-22 12:20:22 +02001089 options = (ctx->ctx->flags & LY_CTX_REF_IMPLEMENTED) ? LY_TYPE_STORE_IMPLEMENT : 0;
1090 ret = type->plugin->store(ctx->ctx, type, dflt, strlen(dflt), options, LY_PREF_SCHEMA, (void *)dflt_pmod,
Michal Vasko405cc9e2020-12-01 12:01:27 +01001091 LYD_HINT_SCHEMA, node, storage, unres, &err);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001092 if (ret == LY_EINCOMPLETE) {
1093 /* we have no data so we will not be resolving it */
1094 ret = LY_SUCCESS;
1095 }
1096
1097 if (ret) {
Radek Krejciddace2c2021-01-08 11:30:56 +01001098 LOG_LOCSET(node, NULL, NULL, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001099 if (err) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001100 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Invalid default - value does not fit the type (%s).", err->msg);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001101 ly_err_free(err);
1102 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001103 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Invalid default - value does not fit the type.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001104 }
Radek Krejciddace2c2021-01-08 11:30:56 +01001105 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001106 return ret;
1107 }
1108
1109 ++((struct lysc_type *)storage->realtype)->refcount;
1110 return LY_SUCCESS;
1111}
1112
1113/**
1114 * @brief Compile default value of a leaf expecting a complete compiled schema tree.
1115 *
1116 * @param[in] ctx Compile context.
1117 * @param[in] leaf Leaf that the default value is for.
1118 * @param[in] dflt Default value to compile.
Michal Vasko405cc9e2020-12-01 12:01:27 +01001119 * @param[in,out] unres Global unres structure for newly implemented modules.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001120 * @return LY_ERR value.
1121 */
1122static LY_ERR
Michal Vasko405cc9e2020-12-01 12:01:27 +01001123lys_compile_unres_leaf_dlft(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, struct lysp_qname *dflt,
1124 struct lys_glob_unres *unres)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001125{
1126 LY_ERR ret;
1127
1128 assert(!leaf->dflt);
1129
1130 if (leaf->flags & (LYS_MAND_TRUE | LYS_KEY)) {
1131 /* ignore default values for keys and mandatory leaves */
1132 return LY_SUCCESS;
1133 }
1134
1135 /* allocate the default value */
1136 leaf->dflt = calloc(1, sizeof *leaf->dflt);
1137 LY_CHECK_ERR_RET(!leaf->dflt, LOGMEM(ctx->ctx), LY_EMEM);
1138
1139 /* store the default value */
Michal Vasko14ed9cd2021-01-28 14:16:25 +01001140 ret = lys_compile_unres_dflt(ctx, &leaf->node, leaf->type, dflt->str, dflt->mod, leaf->dflt, unres);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001141 if (ret) {
1142 free(leaf->dflt);
1143 leaf->dflt = NULL;
1144 }
1145
1146 return ret;
1147}
1148
1149/**
1150 * @brief Compile default values of a leaf-list expecting a complete compiled schema tree.
1151 *
1152 * @param[in] ctx Compile context.
1153 * @param[in] llist Leaf-list that the default value(s) are for.
1154 * @param[in] dflt Default value to compile, in case of a single value.
1155 * @param[in] dflts Sized array of default values, in case of more values.
Michal Vasko405cc9e2020-12-01 12:01:27 +01001156 * @param[in,out] unres Global unres structure for newly implemented modules.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001157 * @return LY_ERR value.
1158 */
1159static LY_ERR
1160lys_compile_unres_llist_dflts(struct lysc_ctx *ctx, struct lysc_node_leaflist *llist, struct lysp_qname *dflt,
Michal Vasko405cc9e2020-12-01 12:01:27 +01001161 struct lysp_qname *dflts, struct lys_glob_unres *unres)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001162{
1163 LY_ERR ret;
1164 LY_ARRAY_COUNT_TYPE orig_count, u, v;
1165
1166 assert(dflt || dflts);
1167
Radek Krejcic7d13e32020-12-09 12:32:24 +01001168 /* in case there were already some defaults and we are adding new by deviations */
1169 orig_count = LY_ARRAY_COUNT(llist->dflts);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001170
1171 /* allocate new items */
Radek Krejcic7d13e32020-12-09 12:32:24 +01001172 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 +02001173
1174 /* fill each new default value */
1175 if (dflts) {
1176 LY_ARRAY_FOR(dflts, u) {
1177 llist->dflts[orig_count + u] = calloc(1, sizeof **llist->dflts);
Michal Vasko14ed9cd2021-01-28 14:16:25 +01001178 ret = lys_compile_unres_dflt(ctx, &llist->node, llist->type, dflts[u].str, dflts[u].mod,
Michal Vasko405cc9e2020-12-01 12:01:27 +01001179 llist->dflts[orig_count + u], unres);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001180 LY_CHECK_ERR_RET(ret, free(llist->dflts[orig_count + u]), ret);
1181 LY_ARRAY_INCREMENT(llist->dflts);
1182 }
1183 } else {
1184 llist->dflts[orig_count] = calloc(1, sizeof **llist->dflts);
Michal Vasko14ed9cd2021-01-28 14:16:25 +01001185 ret = lys_compile_unres_dflt(ctx, &llist->node, llist->type, dflt->str, dflt->mod,
Michal Vasko405cc9e2020-12-01 12:01:27 +01001186 llist->dflts[orig_count], unres);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001187 LY_CHECK_ERR_RET(ret, free(llist->dflts[orig_count]), ret);
1188 LY_ARRAY_INCREMENT(llist->dflts);
1189 }
1190
1191 /* check default value uniqueness */
1192 if (llist->flags & LYS_CONFIG_W) {
1193 /* configuration data values must be unique - so check the default values */
1194 for (u = orig_count; u < LY_ARRAY_COUNT(llist->dflts); ++u) {
1195 for (v = 0; v < u; ++v) {
1196 if (!llist->dflts[u]->realtype->plugin->compare(llist->dflts[u], llist->dflts[v])) {
Radek Krejcia6016992021-03-03 10:13:41 +01001197 lysc_update_path(ctx, llist->parent ? llist->parent->module : NULL, llist->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001198 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Configuration leaf-list has multiple defaults of the same value \"%s\".",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001199 llist->dflts[u]->canonical);
1200 lysc_update_path(ctx, NULL, NULL);
1201 return LY_EVALID;
1202 }
1203 }
1204 }
1205 }
1206
1207 return LY_SUCCESS;
1208}
1209
Michal Vasko405cc9e2020-12-01 12:01:27 +01001210LY_ERR
1211lys_compile_unres_glob(struct ly_ctx *ctx, struct lys_glob_unres *unres)
1212{
Radek Krejci2efc45b2020-12-22 16:25:44 +01001213 LY_ERR ret;
Michal Vasko405cc9e2020-12-01 12:01:27 +01001214 struct lysc_node *node;
1215 struct lysc_type *type, *typeiter;
1216 struct lysc_type_leafref *lref;
1217 struct lysc_ctx cctx = {0};
1218 LY_ARRAY_COUNT_TYPE v;
1219 uint32_t i;
1220
1221 if (unres->recompile) {
1222 /* recompile all the modules and resolve the new unres instead (during recompilation) */
1223 unres->recompile = 0;
1224 return lys_recompile(ctx, 1);
1225 }
1226
1227 /* fake compile context */
1228 cctx.ctx = ctx;
1229 cctx.path_len = 1;
1230 cctx.path[0] = '/';
1231
1232 /* for leafref, we need 2 rounds - first detects circular chain by storing the first referred type (which
1233 * can be also leafref, in case it is already resolved, go through the chain and check that it does not
1234 * point to the starting leafref type). The second round stores the first non-leafref type for later data validation. */
1235 for (i = 0; i < unres->leafrefs.count; ++i) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001236 LY_ERR ret = LY_SUCCESS;
Michal Vasko405cc9e2020-12-01 12:01:27 +01001237 node = unres->leafrefs.objs[i];
1238 cctx.cur_mod = node->module;
1239 cctx.pmod = node->module->parsed;
1240
Radek Krejciddace2c2021-01-08 11:30:56 +01001241 LOG_LOCSET(node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001242
Michal Vasko405cc9e2020-12-01 12:01:27 +01001243 assert(node->nodetype & (LYS_LEAF | LYS_LEAFLIST));
1244 type = ((struct lysc_node_leaf *)node)->type;
1245 if (type->basetype == LY_TYPE_LEAFREF) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001246 ret = lys_compile_unres_leafref(&cctx, node, (struct lysc_type_leafref *)type, unres);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001247 } else if (type->basetype == LY_TYPE_UNION) {
1248 LY_ARRAY_FOR(((struct lysc_type_union *)type)->types, v) {
1249 if (((struct lysc_type_union *)type)->types[v]->basetype == LY_TYPE_LEAFREF) {
1250 lref = (struct lysc_type_leafref *)((struct lysc_type_union *)type)->types[v];
Radek Krejci2efc45b2020-12-22 16:25:44 +01001251 ret = lys_compile_unres_leafref(&cctx, node, lref, unres);
1252 if (ret) {
1253 break;
1254 }
Michal Vasko405cc9e2020-12-01 12:01:27 +01001255 }
1256 }
1257 }
Radek Krejci2efc45b2020-12-22 16:25:44 +01001258
Radek Krejciddace2c2021-01-08 11:30:56 +01001259 LOG_LOCBACK(1, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001260 if (ret) {
1261 return ret;
1262 }
Michal Vasko405cc9e2020-12-01 12:01:27 +01001263 }
1264 while (unres->leafrefs.count) {
1265 node = unres->leafrefs.objs[unres->leafrefs.count - 1];
1266 cctx.cur_mod = node->module;
1267 cctx.pmod = node->module->parsed;
1268
Radek Krejciddace2c2021-01-08 11:30:56 +01001269 LOG_LOCSET(node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001270
Michal Vasko405cc9e2020-12-01 12:01:27 +01001271 /* store pointer to the real type */
1272 type = ((struct lysc_node_leaf *)node)->type;
1273 if (type->basetype == LY_TYPE_LEAFREF) {
1274 for (typeiter = ((struct lysc_type_leafref *)type)->realtype;
1275 typeiter->basetype == LY_TYPE_LEAFREF;
1276 typeiter = ((struct lysc_type_leafref *)typeiter)->realtype) {}
1277 ((struct lysc_type_leafref *)type)->realtype = typeiter;
1278 } else if (type->basetype == LY_TYPE_UNION) {
1279 LY_ARRAY_FOR(((struct lysc_type_union *)type)->types, v) {
1280 if (((struct lysc_type_union *)type)->types[v]->basetype == LY_TYPE_LEAFREF) {
1281 for (typeiter = ((struct lysc_type_leafref *)((struct lysc_type_union *)type)->types[v])->realtype;
1282 typeiter->basetype == LY_TYPE_LEAFREF;
1283 typeiter = ((struct lysc_type_leafref *)typeiter)->realtype) {}
1284 ((struct lysc_type_leafref *)((struct lysc_type_union *)type)->types[v])->realtype = typeiter;
1285 }
1286 }
1287 }
Radek Krejciddace2c2021-01-08 11:30:56 +01001288 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001289
1290 ly_set_rm_index(&unres->leafrefs, unres->leafrefs.count - 1, NULL);
1291 }
1292
1293 /* check xpath */
1294 while (unres->xpath.count) {
1295 node = unres->xpath.objs[unres->xpath.count - 1];
1296 cctx.cur_mod = node->module;
1297 cctx.pmod = node->module->parsed;
1298
Radek Krejciddace2c2021-01-08 11:30:56 +01001299 LOG_LOCSET(node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001300
1301 ret = lys_compile_unres_xpath(&cctx, node, unres);
Radek Krejciddace2c2021-01-08 11:30:56 +01001302 LOG_LOCBACK(1, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001303 LY_CHECK_RET(ret);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001304
1305 ly_set_rm_index(&unres->xpath, unres->xpath.count - 1, NULL);
1306 }
1307
1308 /* finish incomplete default values compilation */
1309 while (unres->dflts.count) {
1310 struct lysc_unres_dflt *r = unres->dflts.objs[unres->dflts.count - 1];
1311 cctx.cur_mod = r->leaf->module;
1312 cctx.pmod = r->leaf->module->parsed;
1313
Michal Vasko14ed9cd2021-01-28 14:16:25 +01001314 LOG_LOCSET(&r->leaf->node, NULL, NULL, NULL);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001315
Radek Krejci2efc45b2020-12-22 16:25:44 +01001316 if (r->leaf->nodetype == LYS_LEAF) {
1317 ret = lys_compile_unres_leaf_dlft(&cctx, r->leaf, r->dflt, unres);
1318 } else {
1319 ret = lys_compile_unres_llist_dflts(&cctx, r->llist, r->dflt, r->dflts, unres);
1320 }
Radek Krejciddace2c2021-01-08 11:30:56 +01001321 LOG_LOCBACK(1, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001322 LY_CHECK_RET(ret);
1323
1324 lysc_unres_dflt_free(ctx, r);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001325 ly_set_rm_index(&unres->dflts, unres->dflts.count - 1, NULL);
1326 }
1327
1328 /* some unres items may have been added */
1329 if (unres->leafrefs.count || unres->xpath.count || unres->dflts.count) {
1330 return lys_compile_unres_glob(ctx, unres);
1331 }
1332
1333 return LY_SUCCESS;
1334}
1335
1336void
1337lys_compile_unres_glob_revert(struct ly_ctx *ctx, struct lys_glob_unres *unres)
1338{
1339 uint32_t i;
1340 struct lys_module *m;
1341
1342 for (i = 0; i < unres->implementing.count; ++i) {
1343 m = unres->implementing.objs[i];
1344 assert(m->implemented);
1345
1346 /* make the module correctly non-implemented again */
1347 m->implemented = 0;
1348 lys_precompile_augments_deviations_revert(ctx, m);
1349 }
1350
1351 for (i = 0; i < unres->creating.count; ++i) {
1352 m = unres->creating.objs[i];
1353
1354 /* remove the module from the context and free it */
1355 ly_set_rm(&ctx->list, m, NULL);
1356 lys_module_free(m, NULL);
1357 }
1358
1359 if (unres->implementing.count) {
1360 /* recompile because some implemented modules are no longer implemented */
1361 lys_recompile(ctx, 0);
1362 }
1363}
1364
1365void
1366lys_compile_unres_glob_erase(const struct ly_ctx *ctx, struct lys_glob_unres *unres)
1367{
1368 uint32_t i;
1369
1370 ly_set_erase(&unres->implementing, NULL);
1371 ly_set_erase(&unres->creating, NULL);
1372 for (i = 0; i < unres->dflts.count; ++i) {
1373 lysc_unres_dflt_free(ctx, unres->dflts.objs[i]);
1374 }
1375 ly_set_erase(&unres->dflts, NULL);
1376 ly_set_erase(&unres->xpath, NULL);
1377 ly_set_erase(&unres->leafrefs, NULL);
1378}
1379
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001380/**
Michal Vasko405cc9e2020-12-01 12:01:27 +01001381 * @brief Finish compilation of all the module unres sets in a compile context.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001382 *
1383 * @param[in] ctx Compile context with unres sets.
1384 * @return LY_ERR value.
1385 */
1386static LY_ERR
Michal Vasko405cc9e2020-12-01 12:01:27 +01001387lys_compile_unres_mod(struct lysc_ctx *ctx)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001388{
1389 struct lysc_node *node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001390 struct lysc_augment *aug;
1391 struct lysc_deviation *dev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001392 uint32_t i;
1393
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001394 /* remove all disabled nodes */
1395 for (i = 0; i < ctx->disabled.count; ++i) {
1396 node = ctx->disabled.snodes[i];
1397 if (node->flags & LYS_KEY) {
Radek Krejciddace2c2021-01-08 11:30:56 +01001398 LOG_LOCSET(node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001399 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Key \"%s\" is disabled by its if-features.", node->name);
Radek Krejciddace2c2021-01-08 11:30:56 +01001400 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001401 return LY_EVALID;
1402 }
1403
Radek Krejci2a9fc652021-01-22 17:44:34 +01001404 lysc_node_free(ctx->ctx, node, 1);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001405 }
1406
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001407 /* check that all augments were applied */
1408 for (i = 0; i < ctx->augs.count; ++i) {
1409 aug = ctx->augs.objs[i];
Radek Krejci2efc45b2020-12-22 16:25:44 +01001410 lysc_update_path(ctx, NULL, "{augment}");
1411 lysc_update_path(ctx, NULL, aug->nodeid->expr);
1412 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Augment target node \"%s\" from module \"%s\" was not found.",
Michal Vasko28fe5f62021-03-03 16:37:39 +01001413 aug->nodeid->expr, LYSP_MODULE_NAME(aug->aug_pmod));
Radek Krejci2efc45b2020-12-22 16:25:44 +01001414 lysc_update_path(ctx, NULL, NULL);
1415 lysc_update_path(ctx, NULL, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001416 }
1417 if (ctx->augs.count) {
1418 return LY_ENOTFOUND;
1419 }
1420
1421 /* check that all deviations were applied */
1422 for (i = 0; i < ctx->devs.count; ++i) {
1423 dev = ctx->devs.objs[i];
Radek Krejci2efc45b2020-12-22 16:25:44 +01001424 lysc_update_path(ctx, NULL, "{deviation}");
1425 lysc_update_path(ctx, NULL, dev->nodeid->expr);
1426 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Deviation(s) target node \"%s\" from module \"%s\" was not found.",
1427 dev->nodeid->expr, LYSP_MODULE_NAME(dev->dev_pmods[0]));
1428 lysc_update_path(ctx, NULL, NULL);
1429 lysc_update_path(ctx, NULL, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001430 }
1431 if (ctx->devs.count) {
1432 return LY_ENOTFOUND;
1433 }
1434
1435 return LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001436}
1437
1438/**
Michal Vasko405cc9e2020-12-01 12:01:27 +01001439 * @brief Erase all the module unres sets in a compile context.
1440 *
1441 * @param[in] ctx Compile context with unres sets.
1442 * @param[in] error Whether the compilation finished with an error or not.
1443 */
1444static void
1445lys_compile_unres_mod_erase(struct lysc_ctx *ctx, ly_bool error)
1446{
1447 uint32_t i;
1448
1449 ly_set_erase(&ctx->groupings, NULL);
1450 ly_set_erase(&ctx->tpdf_chain, NULL);
1451 ly_set_erase(&ctx->disabled, NULL);
1452
1453 if (!error) {
1454 /* there can be no leftover deviations or augments */
1455 LY_CHECK_ERR_RET(ctx->augs.count, LOGINT(ctx->ctx), );
1456 LY_CHECK_ERR_RET(ctx->devs.count, LOGINT(ctx->ctx), );
1457
1458 ly_set_erase(&ctx->augs, NULL);
1459 ly_set_erase(&ctx->devs, NULL);
1460 ly_set_erase(&ctx->uses_augs, NULL);
1461 ly_set_erase(&ctx->uses_rfns, NULL);
1462 } else {
1463 for (i = 0; i < ctx->augs.count; ++i) {
1464 lysc_augment_free(ctx->ctx, ctx->augs.objs[i]);
1465 }
1466 ly_set_erase(&ctx->augs, NULL);
1467 for (i = 0; i < ctx->devs.count; ++i) {
1468 lysc_deviation_free(ctx->ctx, ctx->devs.objs[i]);
1469 }
1470 ly_set_erase(&ctx->devs, NULL);
1471 for (i = 0; i < ctx->uses_augs.count; ++i) {
1472 lysc_augment_free(ctx->ctx, ctx->uses_augs.objs[i]);
1473 }
1474 ly_set_erase(&ctx->uses_augs, NULL);
1475 for (i = 0; i < ctx->uses_rfns.count; ++i) {
1476 lysc_refine_free(ctx->ctx, ctx->uses_rfns.objs[i]);
1477 }
1478 ly_set_erase(&ctx->uses_rfns, NULL);
1479 }
1480}
1481
1482/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001483 * @brief Compile identites in the current module and all its submodules.
1484 *
1485 * @param[in] ctx Compile context.
1486 * @return LY_ERR value.
1487 */
1488static LY_ERR
1489lys_compile_identities(struct lysc_ctx *ctx)
1490{
1491 struct lysp_submodule *submod;
1492 LY_ARRAY_COUNT_TYPE u;
1493
1494 if (!ctx->cur_mod->identities) {
1495 LY_CHECK_RET(lys_identity_precompile(ctx, NULL, NULL, ctx->cur_mod->parsed->identities, &ctx->cur_mod->identities));
1496 LY_ARRAY_FOR(ctx->cur_mod->parsed->includes, u) {
1497 submod = ctx->cur_mod->parsed->includes[u].submodule;
1498 LY_CHECK_RET(lys_identity_precompile(ctx, NULL, NULL, submod->identities, &ctx->cur_mod->identities));
1499 }
1500 }
1501
1502 if (ctx->cur_mod->parsed->identities) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001503 LY_CHECK_RET(lys_compile_identities_derived(ctx, ctx->cur_mod->parsed->identities, &ctx->cur_mod->identities));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001504 }
1505 lysc_update_path(ctx, NULL, "{submodule}");
1506 LY_ARRAY_FOR(ctx->cur_mod->parsed->includes, u) {
1507
1508 submod = ctx->cur_mod->parsed->includes[u].submodule;
1509 if (submod->identities) {
1510 lysc_update_path(ctx, NULL, submod->name);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001511 LY_CHECK_RET(lys_compile_identities_derived(ctx, submod->identities, &ctx->cur_mod->identities));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001512 lysc_update_path(ctx, NULL, NULL);
1513 }
1514 }
1515 lysc_update_path(ctx, NULL, NULL);
1516
1517 return LY_SUCCESS;
1518}
1519
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001520LY_ERR
Michal Vasko405cc9e2020-12-01 12:01:27 +01001521lys_recompile(struct ly_ctx *ctx, ly_bool log)
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001522{
1523 uint32_t idx;
1524 struct lys_module *mod;
Michal Vasko405cc9e2020-12-01 12:01:27 +01001525 struct lys_glob_unres unres = {0};
1526 LY_ERR ret = LY_SUCCESS;
Radek Krejci430a5582020-12-01 13:35:18 +01001527 uint32_t prev_lo = 0;
Michal Vasko405cc9e2020-12-01 12:01:27 +01001528
1529 if (!log) {
1530 /* recompile, must succeed because the modules were already compiled; hide messages because any
1531 * warnings were already printed, are not really relevant, and would hide the real error */
1532 prev_lo = ly_log_options(0);
1533 }
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001534
1535 /* free all the modules */
1536 for (idx = 0; idx < ctx->list.count; ++idx) {
1537 mod = ctx->list.objs[idx];
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001538 if (mod->compiled) {
1539 /* free the module */
1540 lysc_module_free(mod->compiled, NULL);
1541 mod->compiled = NULL;
1542 }
1543
1544 /* free precompiled iffeatures */
1545 lys_free_feature_iffeatures(mod->parsed);
1546 }
1547
1548 /* recompile all the modules */
1549 for (idx = 0; idx < ctx->list.count; ++idx) {
1550 mod = ctx->list.objs[idx];
Michal Vasko405cc9e2020-12-01 12:01:27 +01001551 if (!mod->implemented || mod->compiled) {
1552 /* nothing to do */
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001553 continue;
1554 }
1555
Michal Vasko405cc9e2020-12-01 12:01:27 +01001556 /* recompile */
1557 ret = lys_compile(mod, 0, &unres);
1558 if (ret) {
1559 if (!log) {
1560 LOGERR(mod->ctx, ret, "Recompilation of module \"%s\" failed.", mod->name);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001561 }
Michal Vasko405cc9e2020-12-01 12:01:27 +01001562 goto cleanup;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001563 }
1564 }
1565
Michal Vasko405cc9e2020-12-01 12:01:27 +01001566 /* resolve global unres */
1567 LY_CHECK_GOTO(ret = lys_compile_unres_glob(ctx, &unres), cleanup);
1568
1569cleanup:
1570 if (!log) {
1571 ly_log_options(prev_lo);
1572 }
1573 lys_compile_unres_glob_erase(ctx, &unres);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001574 return ret;
1575}
1576
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001577LY_ERR
Michal Vasko405cc9e2020-12-01 12:01:27 +01001578lys_compile(struct lys_module *mod, uint32_t options, struct lys_glob_unres *unres)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001579{
1580 struct lysc_ctx ctx = {0};
1581 struct lysc_module *mod_c;
1582 struct lysp_module *sp;
1583 struct lysp_submodule *submod;
1584 struct lysp_node *pnode;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001585 struct lysp_node_grp *grp;
1586 LY_ARRAY_COUNT_TYPE u;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001587 LY_ERR ret = LY_SUCCESS;
1588
1589 LY_CHECK_ARG_RET(NULL, mod, mod->parsed, !mod->compiled, mod->ctx, LY_EINVAL);
1590
1591 if (!mod->implemented) {
1592 /* just imported modules are not compiled */
1593 return LY_SUCCESS;
1594 }
1595
1596 /* context will be changed */
1597 ++mod->ctx->module_set_id;
1598
1599 sp = mod->parsed;
1600
1601 ctx.ctx = mod->ctx;
1602 ctx.cur_mod = mod;
1603 ctx.pmod = sp;
1604 ctx.options = options;
1605 ctx.path_len = 1;
1606 ctx.path[0] = '/';
Michal Vasko405cc9e2020-12-01 12:01:27 +01001607 ctx.unres = unres;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001608
1609 mod->compiled = mod_c = calloc(1, sizeof *mod_c);
1610 LY_CHECK_ERR_RET(!mod_c, LOGMEM(mod->ctx), LY_EMEM);
1611 mod_c->mod = mod;
1612
1613 /* process imports */
1614 LY_ARRAY_FOR(sp->imports, u) {
1615 LY_CHECK_GOTO(ret = lys_compile_import(&ctx, &sp->imports[u]), error);
1616 }
1617
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001618 /* identities */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001619 LY_CHECK_GOTO(ret = lys_compile_identities(&ctx), error);
1620
1621 /* augments and deviations */
1622 LY_CHECK_GOTO(ret = lys_precompile_augments_deviations(&ctx), error);
1623
1624 /* compile augments and deviations of our module from other modules so they can be applied during compilation */
1625 LY_CHECK_GOTO(ret = lys_precompile_own_augments(&ctx), error);
1626 LY_CHECK_GOTO(ret = lys_precompile_own_deviations(&ctx), error);
1627
1628 /* data nodes */
1629 LY_LIST_FOR(sp->data, pnode) {
1630 LY_CHECK_GOTO(ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL), error);
1631 }
1632
Radek Krejci2a9fc652021-01-22 17:44:34 +01001633 /* top-level RPCs */
1634 LY_LIST_FOR((struct lysp_node *)sp->rpcs, pnode) {
1635 LY_CHECK_GOTO(ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL), error);
1636 }
1637
1638 /* top-level notifications */
1639 LY_LIST_FOR((struct lysp_node *)sp->notifs, pnode) {
1640 LY_CHECK_GOTO(ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL), error);
1641 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001642
1643 /* extension instances */
Radek Krejciab430862021-03-02 20:13:40 +01001644 COMPILE_EXTS_GOTO(&ctx, sp->exts, mod_c->exts, mod_c, ret, error);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001645
1646 /* the same for submodules */
1647 LY_ARRAY_FOR(sp->includes, u) {
1648 submod = sp->includes[u].submodule;
1649 ctx.pmod = (struct lysp_module *)submod;
1650
1651 LY_LIST_FOR(submod->data, pnode) {
1652 ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL);
1653 LY_CHECK_GOTO(ret, error);
1654 }
1655
Radek Krejci2a9fc652021-01-22 17:44:34 +01001656 LY_LIST_FOR((struct lysp_node *)submod->rpcs, pnode) {
1657 ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL);
1658 LY_CHECK_GOTO(ret, error);
1659 }
1660
1661 LY_LIST_FOR((struct lysp_node *)submod->notifs, pnode) {
1662 ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL);
1663 LY_CHECK_GOTO(ret, error);
1664 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001665
Radek Krejciab430862021-03-02 20:13:40 +01001666 COMPILE_EXTS_GOTO(&ctx, submod->exts, mod_c->exts, mod_c, ret, error);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001667 }
Michal Vasko12606ee2020-11-25 17:05:11 +01001668 ctx.pmod = sp;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001669
1670 /* validate non-instantiated groupings from the parsed schema,
1671 * without it we would accept even the schemas with invalid grouping specification */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001672 ctx.options |= LYS_COMPILE_GROUPING;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001673 LY_LIST_FOR(sp->groupings, grp) {
1674 if (!(grp->flags & LYS_USED_GRP)) {
1675 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, NULL, grp), error);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001676 }
1677 }
1678 LY_LIST_FOR(sp->data, pnode) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01001679 LY_LIST_FOR((struct lysp_node_grp *)lysp_node_groupings(pnode), grp) {
1680 if (!(grp->flags & LYS_USED_GRP)) {
1681 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, grp), error);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001682 }
1683 }
1684 }
1685 LY_ARRAY_FOR(sp->includes, u) {
1686 submod = sp->includes[u].submodule;
1687 ctx.pmod = (struct lysp_module *)submod;
1688
Radek Krejci2a9fc652021-01-22 17:44:34 +01001689 LY_LIST_FOR(submod->groupings, grp) {
1690 if (!(grp->flags & LYS_USED_GRP)) {
1691 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, NULL, grp), error);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001692 }
1693 }
1694 LY_LIST_FOR(submod->data, pnode) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01001695 LY_LIST_FOR((struct lysp_node_grp *)lysp_node_groupings(pnode), grp) {
1696 if (!(grp->flags & LYS_USED_GRP)) {
1697 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, grp), error);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001698 }
1699 }
1700 }
1701 }
1702 ctx.pmod = sp;
1703
Radek Krejciddace2c2021-01-08 11:30:56 +01001704 LOG_LOCBACK(0, 0, 1, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001705
Michal Vasko405cc9e2020-12-01 12:01:27 +01001706 /* finish compilation for all unresolved module items in the context */
1707 LY_CHECK_GOTO(ret = lys_compile_unres_mod(&ctx), error);
Michal Vasko12606ee2020-11-25 17:05:11 +01001708
Michal Vasko405cc9e2020-12-01 12:01:27 +01001709 lys_compile_unres_mod_erase(&ctx, 0);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001710 return LY_SUCCESS;
1711
1712error:
Radek Krejciddace2c2021-01-08 11:30:56 +01001713 LOG_LOCBACK(0, 0, 1, 0);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001714 lys_precompile_augments_deviations_revert(ctx.ctx, mod);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001715 lys_compile_unres_mod_erase(&ctx, 1);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001716 lysc_module_free(mod_c, NULL);
1717 mod->compiled = NULL;
1718
1719 return ret;
1720}