blob: 0d2fe6dcb5e6e1e667174494cbc2571acc7bbfe8 [file] [log] [blame]
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001/**
2 * @file schema_compile_node.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
Michal Vasko0b50f6b2022-10-05 15:07:55 +02004 * @author Michal Vasko <mvasko@cesnet.cz>
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02005 * @brief Schema compilation of common nodes.
6 *
Michal Vasko0b50f6b2022-10-05 15:07:55 +02007 * Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02008 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
15
Christian Hopps32874e12021-05-01 09:43:54 -040016#define _GNU_SOURCE /* asprintf, strdup */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020017
18#include "schema_compile_node.h"
19
20#include <assert.h>
21#include <ctype.h>
22#include <stddef.h>
23#include <stdint.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include "common.h"
29#include "compat.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020030#include "dict.h"
31#include "log.h"
Radek Krejci0aa1f702021-04-01 16:16:19 +020032#include "plugins.h"
Radek Krejci77114102021-03-10 15:21:57 +010033#include "plugins_exts_compile.h"
Radek Krejci04699f02021-03-22 21:50:29 +010034#include "plugins_internal.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020035#include "plugins_types.h"
36#include "schema_compile.h"
37#include "schema_compile_amend.h"
Michal Vasko7b1ad1a2020-11-02 15:41:27 +010038#include "schema_features.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020039#include "set.h"
40#include "tree.h"
41#include "tree_data.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010042#include "tree_edit.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020043#include "tree_schema.h"
44#include "tree_schema_internal.h"
45#include "xpath.h"
46
47static struct lysc_ext_instance *
48lysc_ext_instance_dup(struct ly_ctx *ctx, struct lysc_ext_instance *orig)
49{
50 /* TODO - extensions, increase refcount */
51 (void) ctx;
52 (void) orig;
53 return NULL;
54}
55
56/**
Michal Vaskoc130e162021-10-19 11:30:00 +020057 * @brief Add a node with must(s) to unres.
58 *
59 * @param[in] ctx Compile context.
60 * @param[in] node Compiled node with must(s).
61 * @param[in] pnode Parsed ndoe with must(s).
62 * @return LY_ERR value.
63 */
64static LY_ERR
65lysc_unres_must_add(struct lysc_ctx *ctx, struct lysc_node *node, struct lysp_node *pnode)
66{
67 struct lysc_unres_must *m = NULL;
68 LY_ARRAY_COUNT_TYPE u;
69 struct lysc_must *musts;
70 struct lysp_restr *pmusts;
71 LY_ERR ret;
72
73 /* do not check must(s) in a grouping */
74 if (ctx->compile_opts & LYS_COMPILE_GROUPING) {
75 return LY_SUCCESS;
76 }
77
78 musts = lysc_node_musts(node);
79 pmusts = lysp_node_musts(pnode);
80 assert(LY_ARRAY_COUNT(musts) == LY_ARRAY_COUNT(pmusts));
81
82 if (!musts) {
83 /* no must */
84 return LY_SUCCESS;
85 }
86
87 /* add new unres must */
88 m = calloc(1, sizeof *m);
89 LY_CHECK_ERR_GOTO(!m, ret = LY_EMEM, error);
90 m->node = node;
91
92 /* add must local modules */
93 LY_ARRAY_CREATE_GOTO(ctx->ctx, m->local_mods, LY_ARRAY_COUNT(pmusts), ret, error);
94 LY_ARRAY_FOR(pmusts, u) {
95 m->local_mods[u] = pmusts[u].arg.mod;
96 LY_ARRAY_INCREMENT(m->local_mods);
97 }
98
Michal Vaskoedb0fa52022-10-04 10:36:00 +020099 /* store ext */
100 m->ext = ctx->ext;
101
Michal Vaskoc130e162021-10-19 11:30:00 +0200102 LY_CHECK_ERR_GOTO(ly_set_add(&ctx->unres->musts, m, 1, NULL), ret = LY_EMEM, error);
103
104 return LY_SUCCESS;
105
106error:
107 if (m) {
108 LY_ARRAY_FREE(m->local_mods);
109 free(m);
110 }
111 LOGMEM(ctx->ctx);
112 return ret;
113}
114
115static LY_ERR
116lysc_unres_leafref_add(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, const struct lysp_module *local_mod)
117{
118 struct lysc_unres_leafref *l = NULL;
119 struct ly_set *leafrefs_set;
120 LY_ARRAY_COUNT_TYPE u;
121 int is_lref = 0;
122
123 if (ctx->compile_opts & LYS_COMPILE_GROUPING) {
124 /* do not check leafrefs in groupings */
125 return LY_SUCCESS;
126 }
127
128 /* use special set for disabled leafrefs */
129 leafrefs_set = ctx->compile_opts & LYS_COMPILE_DISABLED ? &ctx->unres->disabled_leafrefs : &ctx->unres->leafrefs;
130
131 if (leaf->type->basetype == LY_TYPE_LEAFREF) {
132 /* leafref */
133 is_lref = 1;
134 } else if (leaf->type->basetype == LY_TYPE_UNION) {
135 /* union with leafrefs */
136 LY_ARRAY_FOR(((struct lysc_type_union *)leaf->type)->types, u) {
137 if (((struct lysc_type_union *)leaf->type)->types[u]->basetype == LY_TYPE_LEAFREF) {
138 is_lref = 1;
139 break;
140 }
141 }
142 }
143
144 if (is_lref) {
145 /* add new unresolved leafref node */
146 l = calloc(1, sizeof *l);
147 LY_CHECK_ERR_RET(!l, LOGMEM(ctx->ctx), LY_EMEM);
148
149 l->node = &leaf->node;
150 l->local_mod = local_mod;
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200151 l->ext = ctx->ext;
Michal Vaskoc130e162021-10-19 11:30:00 +0200152
153 LY_CHECK_ERR_RET(ly_set_add(leafrefs_set, l, 1, NULL), free(l); LOGMEM(ctx->ctx), LY_EMEM);
154 }
155
156 return LY_SUCCESS;
157}
158
159/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200160 * @brief Add/replace a leaf default value in unres.
161 * Can also be used for a single leaf-list default value.
162 *
163 * @param[in] ctx Compile context.
164 * @param[in] leaf Leaf with the default value.
165 * @param[in] dflt Default value to use.
166 * @return LY_ERR value.
167 */
168static LY_ERR
169lysc_unres_leaf_dflt_add(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, struct lysp_qname *dflt)
170{
171 struct lysc_unres_dflt *r = NULL;
172 uint32_t i;
173
Michal Vasko7c565922021-06-10 14:58:27 +0200174 if (ctx->compile_opts & (LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING)) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100175 return LY_SUCCESS;
176 }
177
Michal Vasko405cc9e2020-12-01 12:01:27 +0100178 for (i = 0; i < ctx->unres->dflts.count; ++i) {
179 if (((struct lysc_unres_dflt *)ctx->unres->dflts.objs[i])->leaf == leaf) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200180 /* just replace the default */
Michal Vasko405cc9e2020-12-01 12:01:27 +0100181 r = ctx->unres->dflts.objs[i];
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200182 lysp_qname_free(ctx->ctx, r->dflt);
183 free(r->dflt);
184 break;
185 }
186 }
187 if (!r) {
188 /* add new unres item */
189 r = calloc(1, sizeof *r);
190 LY_CHECK_ERR_RET(!r, LOGMEM(ctx->ctx), LY_EMEM);
191 r->leaf = leaf;
192
Michal Vasko405cc9e2020-12-01 12:01:27 +0100193 LY_CHECK_RET(ly_set_add(&ctx->unres->dflts, r, 1, NULL));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200194 }
195
196 r->dflt = malloc(sizeof *r->dflt);
197 LY_CHECK_GOTO(!r->dflt, error);
198 LY_CHECK_GOTO(lysp_qname_dup(ctx->ctx, r->dflt, dflt), error);
199
200 return LY_SUCCESS;
201
202error:
203 free(r->dflt);
204 LOGMEM(ctx->ctx);
205 return LY_EMEM;
206}
207
208/**
209 * @brief Add/replace a leaf-list default value(s) in unres.
210 *
211 * @param[in] ctx Compile context.
212 * @param[in] llist Leaf-list with the default value.
213 * @param[in] dflts Sized array of the default values.
214 * @return LY_ERR value.
215 */
216static LY_ERR
217lysc_unres_llist_dflts_add(struct lysc_ctx *ctx, struct lysc_node_leaflist *llist, struct lysp_qname *dflts)
218{
219 struct lysc_unres_dflt *r = NULL;
220 uint32_t i;
221
Michal Vasko7c565922021-06-10 14:58:27 +0200222 if (ctx->compile_opts & (LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING)) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100223 return LY_SUCCESS;
224 }
225
Michal Vasko405cc9e2020-12-01 12:01:27 +0100226 for (i = 0; i < ctx->unres->dflts.count; ++i) {
227 if (((struct lysc_unres_dflt *)ctx->unres->dflts.objs[i])->llist == llist) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200228 /* just replace the defaults */
Michal Vasko405cc9e2020-12-01 12:01:27 +0100229 r = ctx->unres->dflts.objs[i];
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200230 lysp_qname_free(ctx->ctx, r->dflt);
231 free(r->dflt);
232 r->dflt = NULL;
233 FREE_ARRAY(ctx->ctx, r->dflts, lysp_qname_free);
234 r->dflts = NULL;
235 break;
236 }
237 }
238 if (!r) {
239 r = calloc(1, sizeof *r);
240 LY_CHECK_ERR_RET(!r, LOGMEM(ctx->ctx), LY_EMEM);
241 r->llist = llist;
242
Michal Vasko405cc9e2020-12-01 12:01:27 +0100243 LY_CHECK_RET(ly_set_add(&ctx->unres->dflts, r, 1, NULL));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200244 }
245
246 DUP_ARRAY(ctx->ctx, dflts, r->dflts, lysp_qname_dup);
247
248 return LY_SUCCESS;
249}
250
251/**
Michal Vaskof4fa90d2021-11-11 15:05:19 +0100252 * @brief Add a bits/enumeration type to unres.
253 *
254 * @param[in] ctx Compile context.
255 * @param[in] leaf Leaf of type bits/enumeration whose disabled items to free.
256 * @return LY_ERR value.
257 */
258static LY_ERR
259lysc_unres_bitenum_add(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf)
260{
261 if (ctx->compile_opts & (LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING)) {
262 /* skip groupings and redundant for disabled nodes */
263 return LY_SUCCESS;
264 }
265
266 LY_CHECK_RET(ly_set_add(&ctx->unres->disabled_bitenums, leaf, 1, NULL));
267
268 return LY_SUCCESS;
269}
270
271/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200272 * @brief Duplicate the compiled pattern structure.
273 *
274 * Instead of duplicating memory, the reference counter in the @p orig is increased.
275 *
276 * @param[in] orig The pattern structure to duplicate.
277 * @return The duplicated structure to use.
278 */
279static struct lysc_pattern *
280lysc_pattern_dup(struct lysc_pattern *orig)
281{
282 ++orig->refcount;
283 return orig;
284}
285
286/**
287 * @brief Duplicate the array of compiled patterns.
288 *
289 * The sized array itself is duplicated, but the pattern structures are just shadowed by increasing their reference counter.
290 *
291 * @param[in] ctx Libyang context for logging.
292 * @param[in] orig The patterns sized array to duplicate.
293 * @return New sized array as a copy of @p orig.
294 * @return NULL in case of memory allocation error.
295 */
296static struct lysc_pattern **
297lysc_patterns_dup(struct ly_ctx *ctx, struct lysc_pattern **orig)
298{
299 struct lysc_pattern **dup = NULL;
300 LY_ARRAY_COUNT_TYPE u;
301
302 assert(orig);
303
304 LY_ARRAY_CREATE_RET(ctx, dup, LY_ARRAY_COUNT(orig), NULL);
305 LY_ARRAY_FOR(orig, u) {
306 dup[u] = lysc_pattern_dup(orig[u]);
307 LY_ARRAY_INCREMENT(dup);
308 }
309 return dup;
310}
311
312/**
313 * @brief Duplicate compiled range structure.
314 *
315 * @param[in] ctx Libyang context for logging.
316 * @param[in] orig The range structure to be duplicated.
317 * @return New compiled range structure as a copy of @p orig.
318 * @return NULL in case of memory allocation error.
319 */
320static struct lysc_range *
321lysc_range_dup(struct ly_ctx *ctx, const struct lysc_range *orig)
322{
323 struct lysc_range *dup;
324 LY_ERR ret;
325
326 assert(orig);
327
328 dup = calloc(1, sizeof *dup);
329 LY_CHECK_ERR_RET(!dup, LOGMEM(ctx), NULL);
330 if (orig->parts) {
331 LY_ARRAY_CREATE_GOTO(ctx, dup->parts, LY_ARRAY_COUNT(orig->parts), ret, cleanup);
Michal Vasko79135ae2020-12-16 10:08:35 +0100332 (*((LY_ARRAY_COUNT_TYPE *)(dup->parts) - 1)) = LY_ARRAY_COUNT(orig->parts);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200333 memcpy(dup->parts, orig->parts, LY_ARRAY_COUNT(dup->parts) * sizeof *dup->parts);
334 }
335 DUP_STRING_GOTO(ctx, orig->eapptag, dup->eapptag, ret, cleanup);
336 DUP_STRING_GOTO(ctx, orig->emsg, dup->emsg, ret, cleanup);
337 dup->exts = lysc_ext_instance_dup(ctx, orig->exts);
338
339 return dup;
340cleanup:
341 free(dup);
342 (void) ret; /* set but not used due to the return type */
343 return NULL;
344}
345
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200346/**
Michal Vaskodfd254d2021-06-24 09:24:59 +0200347 * @brief Compile status information of the given statement.
348 *
349 * To simplify getting status of the node, the flags are set following inheritance rules, so all the nodes
350 * has the status correctly set during the compilation.
351 *
352 * @param[in] ctx Compile context
353 * @param[in,out] stmt_flags Compiled flags to update. If the status was set explicitly, it is already set
354 * in the flags value and we just check the compatibility with the parent's status value.
355 * @param[in] stmt_name Statement name, for logging.
356 * @param[in] parent_flags Flags of the parent node to check/inherit the status value.
357 * @param[in] parent_name Name of the parent node, for logging.
358 * @param[in] inherit_log Whether to print inherit message.
359 * @return LY_ERR value.
360 */
361static LY_ERR
362lys_compile_status(struct lysc_ctx *ctx, uint16_t *stmt_flags, const char *stmt_name, uint16_t parent_flags,
363 const char *parent_name, ly_bool inherit_log)
364{
365 /* status - it is not inherited by specification, but it does not make sense to have
366 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
367 if (!(*stmt_flags & LYS_STATUS_MASK)) {
368 if (parent_flags & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) {
369 if (inherit_log) {
370 LOGVRB("Missing explicit \"%s\" status specified in parent \"%s\", inheriting for \"%s\".",
371 (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete", parent_name, stmt_name);
372 }
373 *stmt_flags |= parent_flags & LYS_STATUS_MASK;
374 } else {
375 *stmt_flags |= LYS_STATUS_CURR;
376 }
377 } else if (parent_flags & LYS_STATUS_MASK) {
378 /* check status compatibility with the parent */
379 if ((parent_flags & LYS_STATUS_MASK) > (*stmt_flags & LYS_STATUS_MASK)) {
380 if (*stmt_flags & LYS_STATUS_CURR) {
381 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
382 "Status \"current\" of \"%s\" is in conflict with the \"%s\" status of parent \"%s\".",
383 stmt_name, (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete", parent_name);
384 } else { /* LYS_STATUS_DEPRC */
385 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
386 "Status \"deprecated\" of \"%s\" is in conflict with the \"obsolete\" status of parent \"%s\".",
387 stmt_name, parent_name);
388 }
389 return LY_EVALID;
390 }
391 }
392 return LY_SUCCESS;
393}
394
395/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200396 * @brief Compile information from the when statement
397 *
398 * @param[in] ctx Compile context.
399 * @param[in] when_p Parsed when structure.
Michal Vaskodfd254d2021-06-24 09:24:59 +0200400 * @param[in] parent_flags Flags of the parsed node with the when statement.
401 * @param[in] compiled_parent Closest compiled parent of the when statement.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200402 * @param[in] ctx_node Context node for the when statement.
403 * @param[out] when Pointer where to store pointer to the created compiled when structure.
404 * @return LY_ERR value.
405 */
406static LY_ERR
Michal Vaskodfd254d2021-06-24 09:24:59 +0200407lys_compile_when_(struct lysc_ctx *ctx, struct lysp_when *when_p, uint16_t parent_flags,
408 const struct lysc_node *compiled_parent, const struct lysc_node *ctx_node, struct lysc_when **when)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200409{
410 LY_ERR ret = LY_SUCCESS;
Radek Krejci8df109d2021-04-23 12:19:08 +0200411 LY_VALUE_FORMAT format;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200412
413 *when = calloc(1, sizeof **when);
414 LY_CHECK_ERR_RET(!(*when), LOGMEM(ctx->ctx), LY_EMEM);
415 (*when)->refcount = 1;
416 LY_CHECK_RET(lyxp_expr_parse(ctx->ctx, when_p->cond, 0, 1, &(*when)->cond));
Radek Krejci0b013302021-03-29 15:22:32 +0200417 LY_CHECK_RET(lyplg_type_prefix_data_new(ctx->ctx, when_p->cond, strlen(when_p->cond),
Radek Krejci8df109d2021-04-23 12:19:08 +0200418 LY_VALUE_SCHEMA, ctx->pmod, &format, (void **)&(*when)->prefixes));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200419 (*when)->context = (struct lysc_node *)ctx_node;
420 DUP_STRING_GOTO(ctx->ctx, when_p->dsc, (*when)->dsc, ret, done);
421 DUP_STRING_GOTO(ctx->ctx, when_p->ref, (*when)->ref, ret, done);
Radek Krejciab430862021-03-02 20:13:40 +0100422 COMPILE_EXTS_GOTO(ctx, when_p->exts, (*when)->exts, (*when), ret, done);
Michal Vaskodfd254d2021-06-24 09:24:59 +0200423 (*when)->flags = (parent_flags & LYS_STATUS_MASK);
424 if (compiled_parent) {
425 LY_CHECK_RET(lys_compile_status(ctx, &(*when)->flags, "when", compiled_parent->flags, compiled_parent->name, 0));
426 } else {
427 LY_CHECK_RET(lys_compile_status(ctx, &(*when)->flags, "when", 0, NULL, 0));
428 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200429
430done:
431 return ret;
432}
433
434LY_ERR
Michal Vaskodfd254d2021-06-24 09:24:59 +0200435lys_compile_when(struct lysc_ctx *ctx, struct lysp_when *when_p, uint16_t parent_flags, const struct lysc_node *compiled_parent,
436 const struct lysc_node *ctx_node, struct lysc_node *node, struct lysc_when **when_c)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200437{
438 struct lysc_when **new_when, ***node_when;
439
440 assert(when_p);
441
442 /* get the when array */
Radek Krejci9a3823e2021-01-27 20:26:46 +0100443 node_when = lysc_node_when_p(node);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200444
445 /* create new when pointer */
446 LY_ARRAY_NEW_RET(ctx->ctx, *node_when, new_when, LY_EMEM);
447 if (!when_c || !(*when_c)) {
448 /* compile when */
Michal Vaskodfd254d2021-06-24 09:24:59 +0200449 LY_CHECK_RET(lys_compile_when_(ctx, when_p, parent_flags, compiled_parent, ctx_node, new_when));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200450
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200451 /* remember the compiled when for sharing */
452 if (when_c) {
453 *when_c = *new_when;
454 }
455 } else {
456 /* use the previously compiled when */
457 ++(*when_c)->refcount;
458 *new_when = *when_c;
Michal Vaskof01fd0b2020-11-23 16:53:07 +0100459 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200460
Michal Vasko6f08e962021-07-23 08:30:47 +0200461 if (!(ctx->compile_opts & LYS_COMPILE_GROUPING)) {
Michal Vaskof01fd0b2020-11-23 16:53:07 +0100462 /* do not check "when" semantics in a grouping, but repeat the check for different node because
463 * of dummy node check */
Michal Vaskoc130e162021-10-19 11:30:00 +0200464 LY_CHECK_RET(ly_set_add(&ctx->unres->whens, node, 0, NULL));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200465 }
466
467 return LY_SUCCESS;
468}
469
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200470LY_ERR
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200471lys_compile_must(struct lysc_ctx *ctx, struct lysp_restr *must_p, struct lysc_must *must)
472{
473 LY_ERR ret = LY_SUCCESS;
Radek Krejci8df109d2021-04-23 12:19:08 +0200474 LY_VALUE_FORMAT format;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200475
476 LY_CHECK_RET(lyxp_expr_parse(ctx->ctx, must_p->arg.str, 0, 1, &must->cond));
Radek Krejci0b013302021-03-29 15:22:32 +0200477 LY_CHECK_RET(lyplg_type_prefix_data_new(ctx->ctx, must_p->arg.str, strlen(must_p->arg.str),
Radek Krejci8df109d2021-04-23 12:19:08 +0200478 LY_VALUE_SCHEMA, must_p->arg.mod, &format, (void **)&must->prefixes));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200479 DUP_STRING_GOTO(ctx->ctx, must_p->eapptag, must->eapptag, ret, done);
480 DUP_STRING_GOTO(ctx->ctx, must_p->emsg, must->emsg, ret, done);
481 DUP_STRING_GOTO(ctx->ctx, must_p->dsc, must->dsc, ret, done);
482 DUP_STRING_GOTO(ctx->ctx, must_p->ref, must->ref, ret, done);
Radek Krejciab430862021-03-02 20:13:40 +0100483 COMPILE_EXTS_GOTO(ctx, must_p->exts, must->exts, must, ret, done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200484
485done:
486 return ret;
487}
488
489/**
490 * @brief Validate and normalize numeric value from a range definition.
491 * @param[in] ctx Compile context.
492 * @param[in] basetype Base YANG built-in type of the node connected with the range restriction. Actually only LY_TYPE_DEC64 is important to
493 * allow processing of the fractions. The fraction point is extracted from the value which is then normalize according to given frdigits into
494 * valcopy to allow easy parsing and storing of the value. libyang stores decimal number without the decimal point which is always recovered from
495 * the known fraction-digits value. So, with fraction-digits 2, number 3.14 is stored as 314 and number 1 is stored as 100.
496 * @param[in] frdigits The fraction-digits of the type in case of LY_TYPE_DEC64.
497 * @param[in] value String value of the range boundary.
498 * @param[out] len Number of the processed bytes from the value. Processing stops on the first character which is not part of the number boundary.
499 * @param[out] valcopy NULL-terminated string with the numeric value to parse and store.
500 * @return LY_ERR value - LY_SUCCESS, LY_EMEM, LY_EVALID (no number) or LY_EINVAL (decimal64 not matching fraction-digits value).
501 */
502static LY_ERR
503range_part_check_value_syntax(struct lysc_ctx *ctx, LY_DATA_TYPE basetype, uint8_t frdigits, const char *value,
504 size_t *len, char **valcopy)
505{
506 size_t fraction = 0, size;
507
508 *len = 0;
509
510 assert(value);
511 /* parse value */
512 if (!isdigit(value[*len]) && (value[*len] != '-') && (value[*len] != '+')) {
513 return LY_EVALID;
514 }
515
516 if ((value[*len] == '-') || (value[*len] == '+')) {
517 ++(*len);
518 }
519
520 while (isdigit(value[*len])) {
521 ++(*len);
522 }
523
524 if ((basetype != LY_TYPE_DEC64) || (value[*len] != '.') || !isdigit(value[*len + 1])) {
525 if (basetype == LY_TYPE_DEC64) {
526 goto decimal;
527 } else {
528 *valcopy = strndup(value, *len);
529 return LY_SUCCESS;
530 }
531 }
532 fraction = *len;
533
534 ++(*len);
535 while (isdigit(value[*len])) {
536 ++(*len);
537 }
538
539 if (basetype == LY_TYPE_DEC64) {
540decimal:
541 assert(frdigits);
542 if (fraction && (*len - 1 - fraction > frdigits)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100543 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200544 "Range boundary \"%.*s\" of decimal64 type exceeds defined number (%u) of fraction digits.",
Radek Krejci422afb12021-03-04 16:38:16 +0100545 (int)(*len), value, frdigits);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200546 return LY_EINVAL;
547 }
548 if (fraction) {
549 size = (*len) + (frdigits - ((*len) - 1 - fraction));
550 } else {
551 size = (*len) + frdigits + 1;
552 }
553 *valcopy = malloc(size * sizeof **valcopy);
554 LY_CHECK_ERR_RET(!(*valcopy), LOGMEM(ctx->ctx), LY_EMEM);
555
556 (*valcopy)[size - 1] = '\0';
557 if (fraction) {
558 memcpy(&(*valcopy)[0], &value[0], fraction);
559 memcpy(&(*valcopy)[fraction], &value[fraction + 1], (*len) - 1 - (fraction));
560 memset(&(*valcopy)[(*len) - 1], '0', frdigits - ((*len) - 1 - fraction));
561 } else {
562 memcpy(&(*valcopy)[0], &value[0], *len);
563 memset(&(*valcopy)[*len], '0', frdigits);
564 }
565 }
566 return LY_SUCCESS;
567}
568
569/**
570 * @brief Check that values in range are in ascendant order.
571 * @param[in] unsigned_value Flag to note that we are working with unsigned values.
572 * @param[in] max Flag to distinguish if checking min or max value. min value must be strictly higher than previous,
573 * max can be also equal.
574 * @param[in] value Current value to check.
575 * @param[in] prev_value The last seen value.
576 * @return LY_SUCCESS or LY_EEXIST for invalid order.
577 */
578static LY_ERR
579range_part_check_ascendancy(ly_bool unsigned_value, ly_bool max, int64_t value, int64_t prev_value)
580{
581 if (unsigned_value) {
582 if ((max && ((uint64_t)prev_value > (uint64_t)value)) || (!max && ((uint64_t)prev_value >= (uint64_t)value))) {
583 return LY_EEXIST;
584 }
585 } else {
586 if ((max && (prev_value > value)) || (!max && (prev_value >= value))) {
587 return LY_EEXIST;
588 }
589 }
590 return LY_SUCCESS;
591}
592
593/**
594 * @brief Set min/max value of the range part.
595 * @param[in] ctx Compile context.
596 * @param[in] part Range part structure to fill.
597 * @param[in] max Flag to distinguish if storing min or max value.
598 * @param[in] prev The last seen value to check that all values in range are specified in ascendant order.
599 * @param[in] basetype Type of the value to get know implicit min/max values and other checking rules.
600 * @param[in] first Flag for the first value of the range to avoid ascendancy order.
601 * @param[in] length_restr Flag to distinguish between range and length restrictions. Only for logging.
602 * @param[in] frdigits The fraction-digits value in case of LY_TYPE_DEC64 basetype.
603 * @param[in] base_range Range from the type from which the current type is derived (if not built-in) to get type's min and max values.
604 * @param[in,out] value Numeric range value to be stored, if not provided the type's min/max value is set.
605 * @return LY_ERR value - LY_SUCCESS, LY_EDENIED (value brokes type's boundaries), LY_EVALID (not a number),
606 * LY_EEXIST (value is smaller than the previous one), LY_EINVAL (decimal64 value does not corresponds with the
607 * frdigits value), LY_EMEM.
608 */
609static LY_ERR
610range_part_minmax(struct lysc_ctx *ctx, struct lysc_range_part *part, ly_bool max, int64_t prev, LY_DATA_TYPE basetype,
611 ly_bool first, ly_bool length_restr, uint8_t frdigits, struct lysc_range *base_range, const char **value)
612{
613 LY_ERR ret = LY_SUCCESS;
614 char *valcopy = NULL;
Radek Krejci2b18bf12020-11-06 11:20:20 +0100615 size_t len = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200616
617 if (value) {
618 ret = range_part_check_value_syntax(ctx, basetype, frdigits, *value, &len, &valcopy);
619 LY_CHECK_GOTO(ret, finalize);
620 }
621 if (!valcopy && base_range) {
622 if (max) {
623 part->max_64 = base_range->parts[LY_ARRAY_COUNT(base_range->parts) - 1].max_64;
624 } else {
625 part->min_64 = base_range->parts[0].min_64;
626 }
627 if (!first) {
628 ret = range_part_check_ascendancy(basetype <= LY_TYPE_STRING ? 1 : 0, max, max ? part->max_64 : part->min_64, prev);
629 }
630 goto finalize;
631 }
632
633 switch (basetype) {
634 case LY_TYPE_INT8: /* range */
635 if (valcopy) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100636 ret = ly_parse_int(valcopy, strlen(valcopy), INT64_C(-128), INT64_C(127), LY_BASE_DEC, max ? &part->max_64 : &part->min_64);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200637 } else if (max) {
638 part->max_64 = INT64_C(127);
639 } else {
640 part->min_64 = INT64_C(-128);
641 }
642 if (!ret && !first) {
643 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
644 }
645 break;
646 case LY_TYPE_INT16: /* range */
647 if (valcopy) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100648 ret = ly_parse_int(valcopy, strlen(valcopy), INT64_C(-32768), INT64_C(32767), LY_BASE_DEC,
649 max ? &part->max_64 : &part->min_64);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200650 } else if (max) {
651 part->max_64 = INT64_C(32767);
652 } else {
653 part->min_64 = INT64_C(-32768);
654 }
655 if (!ret && !first) {
656 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
657 }
658 break;
659 case LY_TYPE_INT32: /* range */
660 if (valcopy) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100661 ret = ly_parse_int(valcopy, strlen(valcopy), INT64_C(-2147483648), INT64_C(2147483647), LY_BASE_DEC,
662 max ? &part->max_64 : &part->min_64);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200663 } else if (max) {
664 part->max_64 = INT64_C(2147483647);
665 } else {
666 part->min_64 = INT64_C(-2147483648);
667 }
668 if (!ret && !first) {
669 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
670 }
671 break;
672 case LY_TYPE_INT64: /* range */
673 case LY_TYPE_DEC64: /* range */
674 if (valcopy) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100675 ret = ly_parse_int(valcopy, strlen(valcopy), INT64_C(-9223372036854775807) - INT64_C(1), INT64_C(9223372036854775807),
676 LY_BASE_DEC, max ? &part->max_64 : &part->min_64);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200677 } else if (max) {
678 part->max_64 = INT64_C(9223372036854775807);
679 } else {
680 part->min_64 = INT64_C(-9223372036854775807) - INT64_C(1);
681 }
682 if (!ret && !first) {
683 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
684 }
685 break;
686 case LY_TYPE_UINT8: /* range */
687 if (valcopy) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100688 ret = ly_parse_uint(valcopy, strlen(valcopy), UINT64_C(255), LY_BASE_DEC, max ? &part->max_u64 : &part->min_u64);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200689 } else if (max) {
690 part->max_u64 = UINT64_C(255);
691 } else {
692 part->min_u64 = UINT64_C(0);
693 }
694 if (!ret && !first) {
695 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
696 }
697 break;
698 case LY_TYPE_UINT16: /* range */
699 if (valcopy) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100700 ret = ly_parse_uint(valcopy, strlen(valcopy), UINT64_C(65535), LY_BASE_DEC, max ? &part->max_u64 : &part->min_u64);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200701 } else if (max) {
702 part->max_u64 = UINT64_C(65535);
703 } else {
704 part->min_u64 = UINT64_C(0);
705 }
706 if (!ret && !first) {
707 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
708 }
709 break;
710 case LY_TYPE_UINT32: /* range */
711 if (valcopy) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100712 ret = ly_parse_uint(valcopy, strlen(valcopy), UINT64_C(4294967295), LY_BASE_DEC,
713 max ? &part->max_u64 : &part->min_u64);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200714 } else if (max) {
715 part->max_u64 = UINT64_C(4294967295);
716 } else {
717 part->min_u64 = UINT64_C(0);
718 }
719 if (!ret && !first) {
720 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
721 }
722 break;
723 case LY_TYPE_UINT64: /* range */
724 case LY_TYPE_STRING: /* length */
725 case LY_TYPE_BINARY: /* length */
726 if (valcopy) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100727 ret = ly_parse_uint(valcopy, strlen(valcopy), UINT64_C(18446744073709551615), LY_BASE_DEC,
728 max ? &part->max_u64 : &part->min_u64);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200729 } else if (max) {
730 part->max_u64 = UINT64_C(18446744073709551615);
731 } else {
732 part->min_u64 = UINT64_C(0);
733 }
734 if (!ret && !first) {
735 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
736 }
737 break;
738 default:
739 LOGINT(ctx->ctx);
740 ret = LY_EINT;
741 }
742
743finalize:
744 if (ret == LY_EDENIED) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100745 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200746 "Invalid %s restriction - value \"%s\" does not fit the type limitations.",
747 length_restr ? "length" : "range", valcopy ? valcopy : *value);
748 } else if (ret == LY_EVALID) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100749 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200750 "Invalid %s restriction - invalid value \"%s\".",
751 length_restr ? "length" : "range", valcopy ? valcopy : *value);
752 } else if (ret == LY_EEXIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100753 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200754 "Invalid %s restriction - values are not in ascending order (%s).",
755 length_restr ? "length" : "range",
756 (valcopy && basetype != LY_TYPE_DEC64) ? valcopy : value ? *value : max ? "max" : "min");
757 } else if (!ret && value) {
758 *value = *value + len;
759 }
760 free(valcopy);
761 return ret;
762}
763
764/**
765 * @brief Compile the parsed range restriction.
766 * @param[in] ctx Compile context.
767 * @param[in] range_p Parsed range structure to compile.
768 * @param[in] basetype Base YANG built-in type of the node with the range restriction.
769 * @param[in] length_restr Flag to distinguish between range and length restrictions. Only for logging.
770 * @param[in] frdigits The fraction-digits value in case of LY_TYPE_DEC64 basetype.
771 * @param[in] base_range Range restriction of the type from which the current type is derived. The current
772 * range restriction must be more restrictive than the base_range.
773 * @param[in,out] range Pointer to the created current range structure.
774 * @return LY_ERR value.
775 */
776static LY_ERR
777lys_compile_type_range(struct lysc_ctx *ctx, struct lysp_restr *range_p, LY_DATA_TYPE basetype, ly_bool length_restr,
778 uint8_t frdigits, struct lysc_range *base_range, struct lysc_range **range)
779{
aPiecek1c4da362021-04-29 14:26:34 +0200780 LY_ERR ret = LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200781 const char *expr;
782 struct lysc_range_part *parts = NULL, *part;
783 ly_bool range_expected = 0, uns;
784 LY_ARRAY_COUNT_TYPE parts_done = 0, u, v;
785
786 assert(range);
787 assert(range_p);
788
789 expr = range_p->arg.str;
790 while (1) {
791 if (isspace(*expr)) {
792 ++expr;
793 } else if (*expr == '\0') {
794 if (range_expected) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100795 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200796 "Invalid %s restriction - unexpected end of the expression after \"..\" (%s).",
Michal Vasko20c0b9f2021-08-24 08:16:27 +0200797 length_restr ? "length" : "range", range_p->arg.str);
aPiecek1c4da362021-04-29 14:26:34 +0200798 ret = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200799 goto cleanup;
800 } else if (!parts || (parts_done == LY_ARRAY_COUNT(parts))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100801 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200802 "Invalid %s restriction - unexpected end of the expression (%s).",
Michal Vasko20c0b9f2021-08-24 08:16:27 +0200803 length_restr ? "length" : "range", range_p->arg.str);
aPiecek1c4da362021-04-29 14:26:34 +0200804 ret = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200805 goto cleanup;
806 }
807 parts_done++;
808 break;
Radek Krejcif13b87b2020-12-01 22:02:17 +0100809 } else if (!strncmp(expr, "min", ly_strlen_const("min"))) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200810 if (parts) {
811 /* min cannot be used elsewhere than in the first part */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100812 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200813 "Invalid %s restriction - unexpected data before min keyword (%.*s).", length_restr ? "length" : "range",
Radek Krejci52409202021-03-15 09:30:43 +0100814 (int)(expr - range_p->arg.str), range_p->arg.str);
aPiecek1c4da362021-04-29 14:26:34 +0200815 ret = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200816 goto cleanup;
817 }
Radek Krejcif13b87b2020-12-01 22:02:17 +0100818 expr += ly_strlen_const("min");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200819
820 LY_ARRAY_NEW_GOTO(ctx->ctx, parts, part, ret, cleanup);
aPiecek1c4da362021-04-29 14:26:34 +0200821 LY_CHECK_GOTO(ret = range_part_minmax(ctx, part, 0, 0, basetype, 1, length_restr, frdigits, base_range, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200822 part->max_64 = part->min_64;
823 } else if (*expr == '|') {
824 if (!parts || range_expected) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100825 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200826 "Invalid %s restriction - unexpected beginning of the expression (%s).", length_restr ? "length" : "range", expr);
aPiecek1c4da362021-04-29 14:26:34 +0200827 ret = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200828 goto cleanup;
829 }
830 expr++;
831 parts_done++;
832 /* process next part of the expression */
833 } else if (!strncmp(expr, "..", 2)) {
834 expr += 2;
835 while (isspace(*expr)) {
836 expr++;
837 }
838 if (!parts || (LY_ARRAY_COUNT(parts) == parts_done)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100839 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200840 "Invalid %s restriction - unexpected \"..\" without a lower bound.", length_restr ? "length" : "range");
aPiecek1c4da362021-04-29 14:26:34 +0200841 ret = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200842 goto cleanup;
843 }
844 /* continue expecting the upper boundary */
845 range_expected = 1;
846 } else if (isdigit(*expr) || (*expr == '-') || (*expr == '+')) {
847 /* number */
848 if (range_expected) {
849 part = &parts[LY_ARRAY_COUNT(parts) - 1];
aPiecek1c4da362021-04-29 14:26:34 +0200850 LY_CHECK_GOTO(ret = range_part_minmax(ctx, part, 1, part->min_64, basetype, 0, length_restr, frdigits, NULL, &expr), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200851 range_expected = 0;
852 } else {
853 LY_ARRAY_NEW_GOTO(ctx->ctx, parts, part, ret, cleanup);
aPiecek1c4da362021-04-29 14:26:34 +0200854 LY_CHECK_GOTO(ret = range_part_minmax(ctx, part, 0, parts_done ? parts[LY_ARRAY_COUNT(parts) - 2].max_64 : 0,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200855 basetype, parts_done ? 0 : 1, length_restr, frdigits, NULL, &expr), cleanup);
856 part->max_64 = part->min_64;
857 }
858
859 /* continue with possible another expression part */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100860 } else if (!strncmp(expr, "max", ly_strlen_const("max"))) {
861 expr += ly_strlen_const("max");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200862 while (isspace(*expr)) {
863 expr++;
864 }
865 if (*expr != '\0') {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100866 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Invalid %s restriction - unexpected data after max keyword (%s).",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200867 length_restr ? "length" : "range", expr);
aPiecek1c4da362021-04-29 14:26:34 +0200868 ret = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200869 goto cleanup;
870 }
871 if (range_expected) {
872 part = &parts[LY_ARRAY_COUNT(parts) - 1];
aPiecek1c4da362021-04-29 14:26:34 +0200873 LY_CHECK_GOTO(ret = range_part_minmax(ctx, part, 1, part->min_64, basetype, 0, length_restr, frdigits, base_range, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200874 range_expected = 0;
875 } else {
876 LY_ARRAY_NEW_GOTO(ctx->ctx, parts, part, ret, cleanup);
aPiecek1c4da362021-04-29 14:26:34 +0200877 LY_CHECK_GOTO(ret = range_part_minmax(ctx, part, 1, parts_done ? parts[LY_ARRAY_COUNT(parts) - 2].max_64 : 0,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200878 basetype, parts_done ? 0 : 1, length_restr, frdigits, base_range, NULL), cleanup);
879 part->min_64 = part->max_64;
880 }
881 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100882 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Invalid %s restriction - unexpected data (%s).",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200883 length_restr ? "length" : "range", expr);
aPiecek1c4da362021-04-29 14:26:34 +0200884 ret = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200885 goto cleanup;
886 }
887 }
888
889 /* check with the previous range/length restriction */
890 if (base_range) {
891 switch (basetype) {
892 case LY_TYPE_BINARY:
893 case LY_TYPE_UINT8:
894 case LY_TYPE_UINT16:
895 case LY_TYPE_UINT32:
896 case LY_TYPE_UINT64:
897 case LY_TYPE_STRING:
898 uns = 1;
899 break;
900 case LY_TYPE_DEC64:
901 case LY_TYPE_INT8:
902 case LY_TYPE_INT16:
903 case LY_TYPE_INT32:
904 case LY_TYPE_INT64:
905 uns = 0;
906 break;
907 default:
908 LOGINT(ctx->ctx);
909 ret = LY_EINT;
910 goto cleanup;
911 }
912 for (u = v = 0; u < parts_done && v < LY_ARRAY_COUNT(base_range->parts); ++u) {
913 if ((uns && (parts[u].min_u64 < base_range->parts[v].min_u64)) || (!uns && (parts[u].min_64 < base_range->parts[v].min_64))) {
914 goto baseerror;
915 }
916 /* current lower bound is not lower than the base */
917 if (base_range->parts[v].min_64 == base_range->parts[v].max_64) {
918 /* base has single value */
919 if (base_range->parts[v].min_64 == parts[u].min_64) {
920 /* both lower bounds are the same */
921 if (parts[u].min_64 != parts[u].max_64) {
922 /* current continues with a range */
923 goto baseerror;
924 } else {
925 /* equal single values, move both forward */
926 ++v;
927 continue;
928 }
929 } else {
930 /* base is single value lower than current range, so the
931 * value from base range is removed in the current,
932 * move only base and repeat checking */
933 ++v;
934 --u;
935 continue;
936 }
937 } else {
938 /* base is the range */
939 if (parts[u].min_64 == parts[u].max_64) {
940 /* current is a single value */
941 if ((uns && (parts[u].max_u64 > base_range->parts[v].max_u64)) || (!uns && (parts[u].max_64 > base_range->parts[v].max_64))) {
942 /* current is behind the base range, so base range is omitted,
943 * move the base and keep the current for further check */
944 ++v;
945 --u;
946 } /* else it is within the base range, so move the current, but keep the base */
947 continue;
948 } else {
949 /* both are ranges - check the higher bound, the lower was already checked */
950 if ((uns && (parts[u].max_u64 > base_range->parts[v].max_u64)) || (!uns && (parts[u].max_64 > base_range->parts[v].max_64))) {
951 /* higher bound is higher than the current higher bound */
952 if ((uns && (parts[u].min_u64 > base_range->parts[v].max_u64)) || (!uns && (parts[u].min_64 > base_range->parts[v].max_64))) {
953 /* but the current lower bound is also higher, so the base range is omitted,
954 * continue with the same current, but move the base */
955 --u;
956 ++v;
957 continue;
958 }
959 /* current range starts within the base range but end behind it */
960 goto baseerror;
961 } else {
962 /* current range is smaller than the base,
963 * move current, but stay with the base */
964 continue;
965 }
966 }
967 }
968 }
969 if (u != parts_done) {
970baseerror:
Radek Krejci2efc45b2020-12-22 16:25:44 +0100971 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200972 "Invalid %s restriction - the derived restriction (%s) is not equally or more limiting.",
Michal Vasko20c0b9f2021-08-24 08:16:27 +0200973 length_restr ? "length" : "range", range_p->arg.str);
aPiecek1c4da362021-04-29 14:26:34 +0200974 ret = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200975 goto cleanup;
976 }
977 }
978
979 if (!(*range)) {
980 *range = calloc(1, sizeof **range);
981 LY_CHECK_ERR_RET(!(*range), LOGMEM(ctx->ctx), LY_EMEM);
982 }
983
984 /* we rewrite the following values as the types chain is being processed */
985 if (range_p->eapptag) {
986 lydict_remove(ctx->ctx, (*range)->eapptag);
987 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->eapptag, 0, &(*range)->eapptag), cleanup);
988 }
989 if (range_p->emsg) {
990 lydict_remove(ctx->ctx, (*range)->emsg);
991 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->emsg, 0, &(*range)->emsg), cleanup);
992 }
993 if (range_p->dsc) {
994 lydict_remove(ctx->ctx, (*range)->dsc);
995 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->dsc, 0, &(*range)->dsc), cleanup);
996 }
997 if (range_p->ref) {
998 lydict_remove(ctx->ctx, (*range)->ref);
999 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->ref, 0, &(*range)->ref), cleanup);
1000 }
1001 /* extensions are taken only from the last range by the caller */
1002
1003 (*range)->parts = parts;
1004 parts = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001005cleanup:
1006 LY_ARRAY_FREE(parts);
1007
1008 return ret;
1009}
1010
Michal Vasko215d7fc2022-07-15 14:50:44 +02001011/**
1012 * @brief Transform characters block in an XML Schema pattern into Perl character ranges.
1013 *
1014 * @param[in] ctx libyang context.
1015 * @param[in] pattern Original pattern.
1016 * @param[in,out] regex Pattern to modify.
1017 * @return LY_ERR value.
1018 */
1019static LY_ERR
1020lys_compile_pattern_chblocks_xmlschema2perl(const struct ly_ctx *ctx, const char *pattern, char **regex)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001021{
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001022#define URANGE_LEN 19
1023 char *ublock2urange[][2] = {
1024 {"BasicLatin", "[\\x{0000}-\\x{007F}]"},
1025 {"Latin-1Supplement", "[\\x{0080}-\\x{00FF}]"},
1026 {"LatinExtended-A", "[\\x{0100}-\\x{017F}]"},
1027 {"LatinExtended-B", "[\\x{0180}-\\x{024F}]"},
1028 {"IPAExtensions", "[\\x{0250}-\\x{02AF}]"},
1029 {"SpacingModifierLetters", "[\\x{02B0}-\\x{02FF}]"},
1030 {"CombiningDiacriticalMarks", "[\\x{0300}-\\x{036F}]"},
1031 {"Greek", "[\\x{0370}-\\x{03FF}]"},
1032 {"Cyrillic", "[\\x{0400}-\\x{04FF}]"},
1033 {"Armenian", "[\\x{0530}-\\x{058F}]"},
1034 {"Hebrew", "[\\x{0590}-\\x{05FF}]"},
1035 {"Arabic", "[\\x{0600}-\\x{06FF}]"},
1036 {"Syriac", "[\\x{0700}-\\x{074F}]"},
1037 {"Thaana", "[\\x{0780}-\\x{07BF}]"},
1038 {"Devanagari", "[\\x{0900}-\\x{097F}]"},
1039 {"Bengali", "[\\x{0980}-\\x{09FF}]"},
1040 {"Gurmukhi", "[\\x{0A00}-\\x{0A7F}]"},
1041 {"Gujarati", "[\\x{0A80}-\\x{0AFF}]"},
1042 {"Oriya", "[\\x{0B00}-\\x{0B7F}]"},
1043 {"Tamil", "[\\x{0B80}-\\x{0BFF}]"},
1044 {"Telugu", "[\\x{0C00}-\\x{0C7F}]"},
1045 {"Kannada", "[\\x{0C80}-\\x{0CFF}]"},
1046 {"Malayalam", "[\\x{0D00}-\\x{0D7F}]"},
1047 {"Sinhala", "[\\x{0D80}-\\x{0DFF}]"},
1048 {"Thai", "[\\x{0E00}-\\x{0E7F}]"},
1049 {"Lao", "[\\x{0E80}-\\x{0EFF}]"},
1050 {"Tibetan", "[\\x{0F00}-\\x{0FFF}]"},
1051 {"Myanmar", "[\\x{1000}-\\x{109F}]"},
1052 {"Georgian", "[\\x{10A0}-\\x{10FF}]"},
1053 {"HangulJamo", "[\\x{1100}-\\x{11FF}]"},
1054 {"Ethiopic", "[\\x{1200}-\\x{137F}]"},
1055 {"Cherokee", "[\\x{13A0}-\\x{13FF}]"},
1056 {"UnifiedCanadianAboriginalSyllabics", "[\\x{1400}-\\x{167F}]"},
1057 {"Ogham", "[\\x{1680}-\\x{169F}]"},
1058 {"Runic", "[\\x{16A0}-\\x{16FF}]"},
1059 {"Khmer", "[\\x{1780}-\\x{17FF}]"},
1060 {"Mongolian", "[\\x{1800}-\\x{18AF}]"},
1061 {"LatinExtendedAdditional", "[\\x{1E00}-\\x{1EFF}]"},
1062 {"GreekExtended", "[\\x{1F00}-\\x{1FFF}]"},
1063 {"GeneralPunctuation", "[\\x{2000}-\\x{206F}]"},
1064 {"SuperscriptsandSubscripts", "[\\x{2070}-\\x{209F}]"},
1065 {"CurrencySymbols", "[\\x{20A0}-\\x{20CF}]"},
1066 {"CombiningMarksforSymbols", "[\\x{20D0}-\\x{20FF}]"},
1067 {"LetterlikeSymbols", "[\\x{2100}-\\x{214F}]"},
1068 {"NumberForms", "[\\x{2150}-\\x{218F}]"},
1069 {"Arrows", "[\\x{2190}-\\x{21FF}]"},
1070 {"MathematicalOperators", "[\\x{2200}-\\x{22FF}]"},
1071 {"MiscellaneousTechnical", "[\\x{2300}-\\x{23FF}]"},
1072 {"ControlPictures", "[\\x{2400}-\\x{243F}]"},
1073 {"OpticalCharacterRecognition", "[\\x{2440}-\\x{245F}]"},
1074 {"EnclosedAlphanumerics", "[\\x{2460}-\\x{24FF}]"},
1075 {"BoxDrawing", "[\\x{2500}-\\x{257F}]"},
1076 {"BlockElements", "[\\x{2580}-\\x{259F}]"},
1077 {"GeometricShapes", "[\\x{25A0}-\\x{25FF}]"},
1078 {"MiscellaneousSymbols", "[\\x{2600}-\\x{26FF}]"},
1079 {"Dingbats", "[\\x{2700}-\\x{27BF}]"},
1080 {"BraillePatterns", "[\\x{2800}-\\x{28FF}]"},
1081 {"CJKRadicalsSupplement", "[\\x{2E80}-\\x{2EFF}]"},
1082 {"KangxiRadicals", "[\\x{2F00}-\\x{2FDF}]"},
1083 {"IdeographicDescriptionCharacters", "[\\x{2FF0}-\\x{2FFF}]"},
1084 {"CJKSymbolsandPunctuation", "[\\x{3000}-\\x{303F}]"},
1085 {"Hiragana", "[\\x{3040}-\\x{309F}]"},
1086 {"Katakana", "[\\x{30A0}-\\x{30FF}]"},
1087 {"Bopomofo", "[\\x{3100}-\\x{312F}]"},
1088 {"HangulCompatibilityJamo", "[\\x{3130}-\\x{318F}]"},
1089 {"Kanbun", "[\\x{3190}-\\x{319F}]"},
1090 {"BopomofoExtended", "[\\x{31A0}-\\x{31BF}]"},
1091 {"EnclosedCJKLettersandMonths", "[\\x{3200}-\\x{32FF}]"},
1092 {"CJKCompatibility", "[\\x{3300}-\\x{33FF}]"},
1093 {"CJKUnifiedIdeographsExtensionA", "[\\x{3400}-\\x{4DB5}]"},
1094 {"CJKUnifiedIdeographs", "[\\x{4E00}-\\x{9FFF}]"},
1095 {"YiSyllables", "[\\x{A000}-\\x{A48F}]"},
1096 {"YiRadicals", "[\\x{A490}-\\x{A4CF}]"},
1097 {"HangulSyllables", "[\\x{AC00}-\\x{D7A3}]"},
1098 {"PrivateUse", "[\\x{E000}-\\x{F8FF}]"},
1099 {"CJKCompatibilityIdeographs", "[\\x{F900}-\\x{FAFF}]"},
1100 {"AlphabeticPresentationForms", "[\\x{FB00}-\\x{FB4F}]"},
1101 {"ArabicPresentationForms-A", "[\\x{FB50}-\\x{FDFF}]"},
1102 {"CombiningHalfMarks", "[\\x{FE20}-\\x{FE2F}]"},
1103 {"CJKCompatibilityForms", "[\\x{FE30}-\\x{FE4F}]"},
1104 {"SmallFormVariants", "[\\x{FE50}-\\x{FE6F}]"},
1105 {"ArabicPresentationForms-B", "[\\x{FE70}-\\x{FEFE}]"},
1106 {"HalfwidthandFullwidthForms", "[\\x{FF00}-\\x{FFEF}]"},
Michal Vasko2b71ab52020-12-01 16:44:11 +01001107 {"Specials", "[\\x{FEFF}|\\x{FFF0}-\\x{FFFD}]"},
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001108 {NULL, NULL}
1109 };
1110
Michal Vasko215d7fc2022-07-15 14:50:44 +02001111 size_t idx, idx2, start, end;
1112 char *perl_regex, *ptr;
1113
1114 perl_regex = *regex;
1115
1116 /* substitute Unicode Character Blocks with exact Character Ranges */
1117 while ((ptr = strstr(perl_regex, "\\p{Is"))) {
1118 start = ptr - perl_regex;
1119
1120 ptr = strchr(ptr, '}');
1121 if (!ptr) {
1122 LOGVAL(ctx, LY_VCODE_INREGEXP, pattern, perl_regex + start + 2, "unterminated character property");
1123 return LY_EVALID;
1124 }
1125 end = (ptr - perl_regex) + 1;
1126
1127 /* need more space */
1128 if (end - start < URANGE_LEN) {
1129 perl_regex = ly_realloc(perl_regex, strlen(perl_regex) + (URANGE_LEN - (end - start)) + 1);
Michal Vasko78419922022-07-15 15:15:20 +02001130 *regex = perl_regex;
Michal Vasko215d7fc2022-07-15 14:50:44 +02001131 LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx), LY_EMEM);
1132 }
1133
1134 /* find our range */
1135 for (idx = 0; ublock2urange[idx][0]; ++idx) {
1136 if (!strncmp(perl_regex + start + ly_strlen_const("\\p{Is"),
1137 ublock2urange[idx][0], strlen(ublock2urange[idx][0]))) {
1138 break;
1139 }
1140 }
1141 if (!ublock2urange[idx][0]) {
1142 LOGVAL(ctx, LY_VCODE_INREGEXP, pattern, perl_regex + start + 5, "unknown block name");
1143 return LY_EVALID;
1144 }
1145
1146 /* make the space in the string and replace the block (but we cannot include brackets if it was already enclosed in them) */
1147 for (idx2 = 0, idx = 0; idx2 < start; ++idx2) {
1148 if ((perl_regex[idx2] == '[') && (!idx2 || (perl_regex[idx2 - 1] != '\\'))) {
1149 ++idx;
1150 }
1151 if ((perl_regex[idx2] == ']') && (!idx2 || (perl_regex[idx2 - 1] != '\\'))) {
1152 --idx;
1153 }
1154 }
1155 if (idx) {
1156 /* skip brackets */
1157 memmove(perl_regex + start + (URANGE_LEN - 2), perl_regex + end, strlen(perl_regex + end) + 1);
1158 memcpy(perl_regex + start, ublock2urange[idx][1] + 1, URANGE_LEN - 2);
1159 } else {
1160 memmove(perl_regex + start + URANGE_LEN, perl_regex + end, strlen(perl_regex + end) + 1);
1161 memcpy(perl_regex + start, ublock2urange[idx][1], URANGE_LEN);
1162 }
1163 }
1164
Michal Vasko215d7fc2022-07-15 14:50:44 +02001165 return LY_SUCCESS;
1166}
1167
1168LY_ERR
1169lys_compile_type_pattern_check(struct ly_ctx *ctx, const char *pattern, pcre2_code **code)
1170{
1171 size_t idx, size, brack;
1172 char *perl_regex;
1173 int err_code, compile_opts;
1174 const char *orig_ptr;
1175 PCRE2_SIZE err_offset;
1176 pcre2_code *code_local;
aPiecek9e716992022-07-21 16:29:47 +02001177 ly_bool escaped;
Michal Vasko215d7fc2022-07-15 14:50:44 +02001178 LY_ERR r;
1179
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001180 /* adjust the expression to a Perl equivalent
1181 * http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#regexs */
1182
1183 /* allocate space for the transformed pattern */
1184 size = strlen(pattern) + 1;
Michal Vasko03d430c2022-07-22 09:05:56 +02001185 compile_opts = PCRE2_UTF | PCRE2_UCP | PCRE2_ANCHORED | PCRE2_DOLLAR_ENDONLY | PCRE2_NO_AUTO_CAPTURE;
Christian Hoppsdafed222021-03-22 13:02:42 -04001186#ifdef PCRE2_ENDANCHORED
1187 compile_opts |= PCRE2_ENDANCHORED;
1188#else
1189 /* add space for trailing $ anchor */
1190 size++;
1191#endif
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001192 perl_regex = malloc(size);
1193 LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx), LY_EMEM);
1194 perl_regex[0] = '\0';
1195
1196 /* we need to replace all "$" and "^" (that are not in "[]") with "\$" and "\^" */
1197 brack = 0;
1198 idx = 0;
aPiecek9e716992022-07-21 16:29:47 +02001199 escaped = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001200 orig_ptr = pattern;
1201 while (orig_ptr[0]) {
1202 switch (orig_ptr[0]) {
1203 case '$':
1204 case '^':
1205 if (!brack) {
1206 /* make space for the extra character */
1207 ++size;
1208 perl_regex = ly_realloc(perl_regex, size);
1209 LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx), LY_EMEM);
1210
1211 /* print escape slash */
1212 perl_regex[idx] = '\\';
1213 ++idx;
1214 }
1215 break;
aPiecek9e716992022-07-21 16:29:47 +02001216 case '\\':
1217 /* escape character found or backslash is escaped */
1218 escaped = !escaped;
1219 /* copy backslash and continue with the next character */
1220 perl_regex[idx] = orig_ptr[0];
1221 ++idx;
1222 ++orig_ptr;
1223 continue;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001224 case '[':
aPiecek9e716992022-07-21 16:29:47 +02001225 if (!escaped) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001226 ++brack;
1227 }
1228 break;
1229 case ']':
aPiecek9e716992022-07-21 16:29:47 +02001230 if (!brack && !escaped) {
1231 /* If ']' does not terminate a character class expression, then pcre2_compile() implicitly escapes the
1232 * ']' character. But this seems to be against the regular expressions rules declared in
1233 * "XML schema: Datatypes" and therefore an error is returned. So for example if pattern is '\[a]' then
1234 * pcre2 match characters '[a]' literally but in YANG such pattern is not allowed.
1235 */
1236 LOGVAL(ctx, LY_VCODE_INREGEXP, pattern, orig_ptr, "character group doesn't begin with '['");
1237 free(perl_regex);
1238 return LY_EVALID;
1239 } else if (!escaped) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001240 --brack;
1241 }
1242 break;
1243 default:
1244 break;
1245 }
1246
1247 /* copy char */
1248 perl_regex[idx] = orig_ptr[0];
1249
1250 ++idx;
1251 ++orig_ptr;
aPiecek9e716992022-07-21 16:29:47 +02001252 escaped = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001253 }
Christian Hoppsdafed222021-03-22 13:02:42 -04001254#ifndef PCRE2_ENDANCHORED
1255 /* anchor match to end of subject */
1256 perl_regex[idx++] = '$';
1257#endif
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001258 perl_regex[idx] = '\0';
1259
Michal Vasko215d7fc2022-07-15 14:50:44 +02001260 /* transform character blocks */
1261 if ((r = lys_compile_pattern_chblocks_xmlschema2perl(ctx, pattern, &perl_regex))) {
1262 free(perl_regex);
1263 return r;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001264 }
1265
1266 /* must return 0, already checked during parsing */
Christian Hoppsdafed222021-03-22 13:02:42 -04001267 code_local = pcre2_compile((PCRE2_SPTR)perl_regex, PCRE2_ZERO_TERMINATED, compile_opts,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001268 &err_code, &err_offset, NULL);
1269 if (!code_local) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01001270 PCRE2_UCHAR err_msg[LY_PCRE2_MSG_LIMIT] = {0};
1271 pcre2_get_error_message(err_code, err_msg, LY_PCRE2_MSG_LIMIT);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001272 LOGVAL(ctx, LY_VCODE_INREGEXP, pattern, perl_regex + err_offset, err_msg);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001273 free(perl_regex);
1274 return LY_EVALID;
1275 }
1276 free(perl_regex);
1277
1278 if (code) {
1279 *code = code_local;
1280 } else {
1281 free(code_local);
1282 }
1283
1284 return LY_SUCCESS;
1285
1286#undef URANGE_LEN
1287}
1288
Michal Vasko51de7b72022-04-29 09:50:22 +02001289LY_ERR
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001290lys_compile_type_patterns(struct lysc_ctx *ctx, struct lysp_restr *patterns_p,
1291 struct lysc_pattern **base_patterns, struct lysc_pattern ***patterns)
1292{
1293 struct lysc_pattern **pattern;
1294 LY_ARRAY_COUNT_TYPE u;
1295 LY_ERR ret = LY_SUCCESS;
1296
1297 /* first, copy the patterns from the base type */
1298 if (base_patterns) {
1299 *patterns = lysc_patterns_dup(ctx->ctx, base_patterns);
1300 LY_CHECK_ERR_RET(!(*patterns), LOGMEM(ctx->ctx), LY_EMEM);
1301 }
1302
1303 LY_ARRAY_FOR(patterns_p, u) {
1304 LY_ARRAY_NEW_RET(ctx->ctx, (*patterns), pattern, LY_EMEM);
1305 *pattern = calloc(1, sizeof **pattern);
1306 ++(*pattern)->refcount;
1307
Radek Krejci2efc45b2020-12-22 16:25:44 +01001308 ret = lys_compile_type_pattern_check(ctx->ctx, &patterns_p[u].arg.str[1], &(*pattern)->code);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001309 LY_CHECK_RET(ret);
1310
Radek Krejcif13b87b2020-12-01 22:02:17 +01001311 if (patterns_p[u].arg.str[0] == LYSP_RESTR_PATTERN_NACK) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001312 (*pattern)->inverted = 1;
1313 }
1314 DUP_STRING_GOTO(ctx->ctx, &patterns_p[u].arg.str[1], (*pattern)->expr, ret, done);
1315 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].eapptag, (*pattern)->eapptag, ret, done);
1316 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].emsg, (*pattern)->emsg, ret, done);
1317 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].dsc, (*pattern)->dsc, ret, done);
1318 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].ref, (*pattern)->ref, ret, done);
Radek Krejciab430862021-03-02 20:13:40 +01001319 COMPILE_EXTS_GOTO(ctx, patterns_p[u].exts, (*pattern)->exts, (*pattern), ret, done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001320 }
1321done:
1322 return ret;
1323}
1324
1325/**
1326 * @brief map of the possible restrictions combination for the specific built-in type.
1327 */
1328static uint16_t type_substmt_map[LY_DATA_TYPE_COUNT] = {
1329 0 /* LY_TYPE_UNKNOWN */,
1330 LYS_SET_LENGTH /* LY_TYPE_BINARY */,
1331 LYS_SET_RANGE /* LY_TYPE_UINT8 */,
1332 LYS_SET_RANGE /* LY_TYPE_UINT16 */,
1333 LYS_SET_RANGE /* LY_TYPE_UINT32 */,
1334 LYS_SET_RANGE /* LY_TYPE_UINT64 */,
1335 LYS_SET_LENGTH | LYS_SET_PATTERN /* LY_TYPE_STRING */,
1336 LYS_SET_BIT /* LY_TYPE_BITS */,
1337 0 /* LY_TYPE_BOOL */,
1338 LYS_SET_FRDIGITS | LYS_SET_RANGE /* LY_TYPE_DEC64 */,
1339 0 /* LY_TYPE_EMPTY */,
1340 LYS_SET_ENUM /* LY_TYPE_ENUM */,
1341 LYS_SET_BASE /* LY_TYPE_IDENT */,
1342 LYS_SET_REQINST /* LY_TYPE_INST */,
1343 LYS_SET_REQINST | LYS_SET_PATH /* LY_TYPE_LEAFREF */,
1344 LYS_SET_TYPE /* LY_TYPE_UNION */,
1345 LYS_SET_RANGE /* LY_TYPE_INT8 */,
1346 LYS_SET_RANGE /* LY_TYPE_INT16 */,
1347 LYS_SET_RANGE /* LY_TYPE_INT32 */,
1348 LYS_SET_RANGE /* LY_TYPE_INT64 */
1349};
1350
1351/**
1352 * @brief stringification of the YANG built-in data types
1353 */
1354const char *ly_data_type2str[LY_DATA_TYPE_COUNT] = {
Radek Krejci04699f02021-03-22 21:50:29 +01001355 LY_TYPE_UNKNOWN_STR,
1356 LY_TYPE_BINARY_STR,
1357 LY_TYPE_UINT8_STR,
1358 LY_TYPE_UINT16_STR,
1359 LY_TYPE_UINT32_STR,
1360 LY_TYPE_UINT64_STR,
1361 LY_TYPE_STRING_STR,
1362 LY_TYPE_BITS_STR,
1363 LY_TYPE_BOOL_STR,
1364 LY_TYPE_DEC64_STR,
1365 LY_TYPE_EMPTY_STR,
1366 LY_TYPE_ENUM_STR,
1367 LY_TYPE_IDENT_STR,
1368 LY_TYPE_INST_STR,
1369 LY_TYPE_LEAFREF_STR,
1370 LY_TYPE_UNION_STR,
1371 LY_TYPE_INT8_STR,
1372 LY_TYPE_INT16_STR,
1373 LY_TYPE_INT32_STR,
1374 LY_TYPE_INT64_STR
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001375};
1376
1377/**
1378 * @brief Compile parsed type's enum structures (for enumeration and bits types).
1379 * @param[in] ctx Compile context.
1380 * @param[in] enums_p Array of the parsed enum structures to compile.
1381 * @param[in] basetype Base YANG built-in type from which the current type is derived. Only LY_TYPE_ENUM and LY_TYPE_BITS are expected.
1382 * @param[in] base_enums Array of the compiled enums information from the (latest) base type to check if the current enums are compatible.
Radek IÅ¡a0fe25a92021-03-18 08:45:18 +01001383 * @param[out] bitenums Newly created array of the compiled bitenums information for the current type.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001384 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
1385 */
1386static LY_ERR
1387lys_compile_type_enums(struct lysc_ctx *ctx, struct lysp_type_enum *enums_p, LY_DATA_TYPE basetype,
Radek IÅ¡a0fe25a92021-03-18 08:45:18 +01001388 struct lysc_type_bitenum_item *base_enums, struct lysc_type_bitenum_item **bitenums)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001389{
1390 LY_ERR ret = LY_SUCCESS;
1391 LY_ARRAY_COUNT_TYPE u, v, match = 0;
Radek Krejci430a5582020-12-01 13:35:18 +01001392 int32_t highest_value = INT32_MIN, cur_val = INT32_MIN;
1393 uint32_t highest_position = 0, cur_pos = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001394 struct lysc_type_bitenum_item *e, storage;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001395 ly_bool enabled;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001396
1397 if (base_enums && (ctx->pmod->version < LYS_VERSION_1_1)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001398 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "%s type can be subtyped only in YANG 1.1 modules.",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001399 basetype == LY_TYPE_ENUM ? "Enumeration" : "Bits");
1400 return LY_EVALID;
1401 }
1402
1403 LY_ARRAY_FOR(enums_p, u) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001404 /* perform all checks */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001405 if (base_enums) {
1406 /* check the enum/bit presence in the base type - the set of enums/bits in the derived type must be a subset */
1407 LY_ARRAY_FOR(base_enums, v) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001408 if (!strcmp(enums_p[u].name, base_enums[v].name)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001409 break;
1410 }
1411 }
1412 if (v == LY_ARRAY_COUNT(base_enums)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001413 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001414 "Invalid %s - derived type adds new item \"%s\".",
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001415 basetype == LY_TYPE_ENUM ? "enumeration" : "bits", enums_p[u].name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001416 return LY_EVALID;
1417 }
1418 match = v;
1419 }
1420
1421 if (basetype == LY_TYPE_ENUM) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001422 if (enums_p[u].flags & LYS_SET_VALUE) {
Radek IÅ¡a038b60d2020-11-26 11:37:15 +01001423 /* value assigned by model */
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001424 cur_val = (int32_t)enums_p[u].value;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001425 /* check collision with other values */
Radek IÅ¡a0fe25a92021-03-18 08:45:18 +01001426 LY_ARRAY_FOR(*bitenums, v) {
1427 if (cur_val == (*bitenums)[v].value) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001428 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001429 "Invalid enumeration - value %d collide in items \"%s\" and \"%s\".",
Radek IÅ¡a0fe25a92021-03-18 08:45:18 +01001430 cur_val, enums_p[u].name, (*bitenums)[v].name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001431 return LY_EVALID;
1432 }
1433 }
1434 } else if (base_enums) {
1435 /* inherit the assigned value */
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001436 cur_val = base_enums[match].value;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001437 } else {
1438 /* assign value automatically */
Radek IÅ¡a038b60d2020-11-26 11:37:15 +01001439 if (u == 0) {
1440 cur_val = 0;
1441 } else if (highest_value == INT32_MAX) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001442 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001443 "Invalid enumeration - it is not possible to auto-assign enum value for "
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001444 "\"%s\" since the highest value is already 2147483647.", enums_p[u].name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001445 return LY_EVALID;
Radek IÅ¡a038b60d2020-11-26 11:37:15 +01001446 } else {
1447 cur_val = highest_value + 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001448 }
Radek IÅ¡a038b60d2020-11-26 11:37:15 +01001449 }
1450
1451 /* save highest value for auto assing */
1452 if (highest_value < cur_val) {
1453 highest_value = cur_val;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001454 }
1455 } else { /* LY_TYPE_BITS */
1456 if (enums_p[u].flags & LYS_SET_VALUE) {
Radek IÅ¡aca013ee2020-11-26 17:51:26 +01001457 /* value assigned by model */
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001458 cur_pos = (uint32_t)enums_p[u].value;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001459 /* check collision with other values */
Radek IÅ¡a0fe25a92021-03-18 08:45:18 +01001460 LY_ARRAY_FOR(*bitenums, v) {
1461 if (cur_pos == (*bitenums)[v].position) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001462 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001463 "Invalid bits - position %u collide in items \"%s\" and \"%s\".",
Radek IÅ¡a0fe25a92021-03-18 08:45:18 +01001464 cur_pos, enums_p[u].name, (*bitenums)[v].name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001465 return LY_EVALID;
1466 }
1467 }
1468 } else if (base_enums) {
1469 /* inherit the assigned value */
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001470 cur_pos = base_enums[match].position;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001471 } else {
1472 /* assign value automatically */
Radek IÅ¡aca013ee2020-11-26 17:51:26 +01001473 if (u == 0) {
1474 cur_pos = 0;
1475 } else if (highest_position == UINT32_MAX) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001476 /* counter overflow */
Radek Krejci2efc45b2020-12-22 16:25:44 +01001477 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001478 "Invalid bits - it is not possible to auto-assign bit position for "
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001479 "\"%s\" since the highest value is already 4294967295.", enums_p[u].name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001480 return LY_EVALID;
Radek IÅ¡aca013ee2020-11-26 17:51:26 +01001481 } else {
1482 cur_pos = highest_position + 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001483 }
Radek IÅ¡aca013ee2020-11-26 17:51:26 +01001484 }
1485
1486 /* save highest position for auto assing */
1487 if (highest_position < cur_pos) {
1488 highest_position = cur_pos;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001489 }
1490 }
1491
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001492 /* the assigned values must not change from the derived type */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001493 if (base_enums) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001494 if (basetype == LY_TYPE_ENUM) {
1495 if (cur_val != base_enums[match].value) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001496 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001497 "Invalid enumeration - value of the item \"%s\" has changed from %d to %d in the derived type.",
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001498 enums_p[u].name, base_enums[match].value, cur_val);
1499 return LY_EVALID;
1500 }
1501 } else {
1502 if (cur_pos != base_enums[match].position) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001503 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001504 "Invalid bits - position of the item \"%s\" has changed from %u to %u in the derived type.",
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001505 enums_p[u].name, base_enums[match].position, cur_pos);
1506 return LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001507 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001508 }
1509 }
1510
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001511 /* add new enum/bit */
Radek IÅ¡a0fe25a92021-03-18 08:45:18 +01001512 LY_ARRAY_NEW_RET(ctx->ctx, *bitenums, e, LY_EMEM);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001513 DUP_STRING_GOTO(ctx->ctx, enums_p[u].name, e->name, ret, done);
1514 DUP_STRING_GOTO(ctx->ctx, enums_p[u].dsc, e->dsc, ret, done);
1515 DUP_STRING_GOTO(ctx->ctx, enums_p[u].ref, e->ref, ret, done);
Michal Vaskod1e53b92021-01-28 13:11:06 +01001516 e->flags = (enums_p[u].flags & LYS_FLAGS_COMPILED_MASK) | (basetype == LY_TYPE_ENUM ? LYS_IS_ENUM : 0);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001517 if (basetype == LY_TYPE_ENUM) {
1518 e->value = cur_val;
1519 } else {
1520 e->position = cur_pos;
1521 }
Radek Krejciab430862021-03-02 20:13:40 +01001522 COMPILE_EXTS_GOTO(ctx, enums_p[u].exts, e->exts, e, ret, done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001523
Michal Vaskof4fa90d2021-11-11 15:05:19 +01001524 /* evaluate if-ffeatures */
1525 LY_CHECK_RET(lys_eval_iffeatures(ctx->ctx, enums_p[u].iffeatures, &enabled));
1526 if (!enabled) {
1527 /* set only flag, later resolved and removed */
1528 e->flags |= LYS_DISABLED;
1529 }
1530
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001531 if (basetype == LY_TYPE_BITS) {
1532 /* keep bits ordered by position */
Radek IÅ¡a0fe25a92021-03-18 08:45:18 +01001533 for (v = u; v && (*bitenums)[v - 1].position > e->position; --v) {}
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001534 if (v != u) {
1535 memcpy(&storage, e, sizeof *e);
Radek IÅ¡a0fe25a92021-03-18 08:45:18 +01001536 memmove(&(*bitenums)[v + 1], &(*bitenums)[v], (u - v) * sizeof **bitenums);
1537 memcpy(&(*bitenums)[v], &storage, sizeof storage);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001538 }
1539 }
1540 }
1541
1542done:
1543 return ret;
1544}
1545
Radek Krejci6a205692020-12-09 13:58:22 +01001546static LY_ERR
1547lys_compile_type_union(struct lysc_ctx *ctx, struct lysp_type *ptypes, struct lysp_node *context_pnode, uint16_t context_flags,
Michal Vaskoa99b3572021-02-01 11:54:58 +01001548 const char *context_name, struct lysc_type ***utypes_p)
Radek Krejci6a205692020-12-09 13:58:22 +01001549{
1550 LY_ERR ret = LY_SUCCESS;
1551 struct lysc_type **utypes = *utypes_p;
1552 struct lysc_type_union *un_aux = NULL;
1553
1554 LY_ARRAY_CREATE_GOTO(ctx->ctx, utypes, LY_ARRAY_COUNT(ptypes), ret, error);
1555 for (LY_ARRAY_COUNT_TYPE u = 0, additional = 0; u < LY_ARRAY_COUNT(ptypes); ++u) {
Michal Vaskoa99b3572021-02-01 11:54:58 +01001556 ret = lys_compile_type(ctx, context_pnode, context_flags, context_name, &ptypes[u], &utypes[u + additional],
1557 NULL, NULL);
Radek Krejci6a205692020-12-09 13:58:22 +01001558 LY_CHECK_GOTO(ret, error);
1559 if (utypes[u + additional]->basetype == LY_TYPE_UNION) {
1560 /* add space for additional types from the union subtype */
1561 un_aux = (struct lysc_type_union *)utypes[u + additional];
1562 LY_ARRAY_CREATE_GOTO(ctx->ctx, utypes,
1563 LY_ARRAY_COUNT(ptypes) + additional + LY_ARRAY_COUNT(un_aux->types) - LY_ARRAY_COUNT(utypes), ret, error);
1564
1565 /* copy subtypes of the subtype union */
1566 for (LY_ARRAY_COUNT_TYPE v = 0; v < LY_ARRAY_COUNT(un_aux->types); ++v) {
1567 if (un_aux->types[v]->basetype == LY_TYPE_LEAFREF) {
1568 struct lysc_type_leafref *lref;
1569
1570 /* duplicate the whole structure because of the instance-specific path resolving for realtype */
1571 utypes[u + additional] = calloc(1, sizeof(struct lysc_type_leafref));
1572 LY_CHECK_ERR_GOTO(!utypes[u + additional], LOGMEM(ctx->ctx); ret = LY_EMEM, error);
1573 lref = (struct lysc_type_leafref *)utypes[u + additional];
1574
1575 lref->basetype = LY_TYPE_LEAFREF;
Michal Vaskoe33134a2022-07-29 14:54:40 +02001576 ret = lyxp_expr_dup(ctx->ctx, ((struct lysc_type_leafref *)un_aux->types[v])->path, 0, 0, &lref->path);
Radek Krejci6a205692020-12-09 13:58:22 +01001577 LY_CHECK_GOTO(ret, error);
Michal Vasko080064b2021-08-31 15:20:44 +02001578 lref->refcount = 1;
Radek Krejci6a205692020-12-09 13:58:22 +01001579 lref->require_instance = ((struct lysc_type_leafref *)un_aux->types[v])->require_instance;
Radek Krejci8df109d2021-04-23 12:19:08 +02001580 ret = lyplg_type_prefix_data_dup(ctx->ctx, LY_VALUE_SCHEMA_RESOLVED,
Radek Krejci2926c1b2021-03-16 14:45:45 +01001581 ((struct lysc_type_leafref *)un_aux->types[v])->prefixes, (void **)&lref->prefixes);
Radek Krejci6a205692020-12-09 13:58:22 +01001582 LY_CHECK_GOTO(ret, error);
1583 /* TODO extensions */
1584
1585 } else {
1586 utypes[u + additional] = un_aux->types[v];
Michal Vasko04338d92021-09-01 07:58:14 +02001587 LY_ATOMIC_INC_BARRIER(un_aux->types[v]->refcount);
Radek Krejci6a205692020-12-09 13:58:22 +01001588 }
1589 ++additional;
1590 LY_ARRAY_INCREMENT(utypes);
1591 }
1592 /* compensate u increment in main loop */
1593 --additional;
1594
1595 /* free the replaced union subtype */
Michal Vaskoc636ea42022-09-16 10:20:31 +02001596 lysc_type_free(&ctx->free_ctx, (struct lysc_type *)un_aux);
Radek Krejci6a205692020-12-09 13:58:22 +01001597 un_aux = NULL;
1598 } else {
1599 LY_ARRAY_INCREMENT(utypes);
1600 }
1601 }
1602
1603 *utypes_p = utypes;
1604 return LY_SUCCESS;
1605
1606error:
1607 if (un_aux) {
Michal Vaskoc636ea42022-09-16 10:20:31 +02001608 lysc_type_free(&ctx->free_ctx, (struct lysc_type *)un_aux);
Radek Krejci6a205692020-12-09 13:58:22 +01001609 }
1610 *utypes_p = utypes;
1611 return ret;
1612}
1613
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001614/**
1615 * @brief The core of the lys_compile_type() - compile information about the given type (from typedef or leaf/leaf-list).
1616 * @param[in] ctx Compile context.
1617 * @param[in] context_pnode Schema node where the type/typedef is placed to correctly find the base types.
1618 * @param[in] context_flags Flags of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001619 * @param[in] context_name Name of the context node or referencing typedef for logging.
1620 * @param[in] type_p Parsed type to compile.
1621 * @param[in] basetype Base YANG built-in type of the type to compile.
1622 * @param[in] tpdfname Name of the type's typedef, serves as a flag - if it is leaf/leaf-list's type, it is NULL.
1623 * @param[in] base The latest base (compiled) type from which the current type is being derived.
1624 * @param[out] type Newly created type structure with the filled information about the type.
1625 * @return LY_ERR value.
1626 */
1627static LY_ERR
Michal Vaskoa99b3572021-02-01 11:54:58 +01001628lys_compile_type_(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags, const char *context_name,
1629 struct lysp_type *type_p, LY_DATA_TYPE basetype, const char *tpdfname, struct lysc_type *base, struct lysc_type **type)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001630{
1631 LY_ERR ret = LY_SUCCESS;
1632 struct lysc_type_bin *bin;
1633 struct lysc_type_num *num;
1634 struct lysc_type_str *str;
1635 struct lysc_type_bits *bits;
1636 struct lysc_type_enum *enumeration;
1637 struct lysc_type_dec *dec;
1638 struct lysc_type_identityref *idref;
1639 struct lysc_type_leafref *lref;
Radek Krejci6a205692020-12-09 13:58:22 +01001640 struct lysc_type_union *un;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001641
1642 switch (basetype) {
1643 case LY_TYPE_BINARY:
1644 bin = (struct lysc_type_bin *)(*type);
1645
1646 /* RFC 7950 9.8.1, 9.4.4 - length, number of octets it contains */
1647 if (type_p->length) {
1648 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->length, basetype, 1, 0,
1649 base ? ((struct lysc_type_bin *)base)->length : NULL, &bin->length));
1650 if (!tpdfname) {
Radek Krejciab430862021-03-02 20:13:40 +01001651 COMPILE_EXTS_GOTO(ctx, type_p->length->exts, bin->length->exts, bin->length, ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001652 }
1653 }
1654 break;
1655 case LY_TYPE_BITS:
1656 /* RFC 7950 9.7 - bits */
1657 bits = (struct lysc_type_bits *)(*type);
1658 if (type_p->bits) {
1659 LY_CHECK_RET(lys_compile_type_enums(ctx, type_p->bits, basetype,
1660 base ? (struct lysc_type_bitenum_item *)((struct lysc_type_bits *)base)->bits : NULL,
1661 (struct lysc_type_bitenum_item **)&bits->bits));
1662 }
1663
1664 if (!base && !type_p->flags) {
1665 /* type derived from bits built-in type must contain at least one bit */
1666 if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001667 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "bit", "bits type ", tpdfname);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001668 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001669 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "bit", "bits type", "");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001670 }
1671 return LY_EVALID;
1672 }
1673 break;
1674 case LY_TYPE_DEC64:
1675 dec = (struct lysc_type_dec *)(*type);
1676
1677 /* RFC 7950 9.3.4 - fraction-digits */
1678 if (!base) {
1679 if (!type_p->fraction_digits) {
1680 if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001681 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "fraction-digits", "decimal64 type ", tpdfname);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001682 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001683 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "fraction-digits", "decimal64 type", "");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001684 }
1685 return LY_EVALID;
1686 }
1687 dec->fraction_digits = type_p->fraction_digits;
1688 } else {
1689 if (type_p->fraction_digits) {
1690 /* fraction digits is prohibited in types not directly derived from built-in decimal64 */
1691 if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001692 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001693 "Invalid fraction-digits substatement for type \"%s\" not directly derived from decimal64 built-in type.",
1694 tpdfname);
1695 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001696 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001697 "Invalid fraction-digits substatement for type not directly derived from decimal64 built-in type.");
1698 }
1699 return LY_EVALID;
1700 }
1701 dec->fraction_digits = ((struct lysc_type_dec *)base)->fraction_digits;
1702 }
1703
1704 /* RFC 7950 9.2.4 - range */
1705 if (type_p->range) {
1706 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->range, basetype, 0, dec->fraction_digits,
1707 base ? ((struct lysc_type_dec *)base)->range : NULL, &dec->range));
1708 if (!tpdfname) {
Radek Krejciab430862021-03-02 20:13:40 +01001709 COMPILE_EXTS_GOTO(ctx, type_p->range->exts, dec->range->exts, dec->range, ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001710 }
1711 }
1712 break;
1713 case LY_TYPE_STRING:
1714 str = (struct lysc_type_str *)(*type);
1715
1716 /* RFC 7950 9.4.4 - length */
1717 if (type_p->length) {
1718 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->length, basetype, 1, 0,
1719 base ? ((struct lysc_type_str *)base)->length : NULL, &str->length));
1720 if (!tpdfname) {
Radek Krejciab430862021-03-02 20:13:40 +01001721 COMPILE_EXTS_GOTO(ctx, type_p->length->exts, str->length->exts, str->length, ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001722 }
1723 } else if (base && ((struct lysc_type_str *)base)->length) {
1724 str->length = lysc_range_dup(ctx->ctx, ((struct lysc_type_str *)base)->length);
1725 }
1726
1727 /* RFC 7950 9.4.5 - pattern */
1728 if (type_p->patterns) {
1729 LY_CHECK_RET(lys_compile_type_patterns(ctx, type_p->patterns,
1730 base ? ((struct lysc_type_str *)base)->patterns : NULL, &str->patterns));
1731 } else if (base && ((struct lysc_type_str *)base)->patterns) {
1732 str->patterns = lysc_patterns_dup(ctx->ctx, ((struct lysc_type_str *)base)->patterns);
1733 }
1734 break;
1735 case LY_TYPE_ENUM:
1736 enumeration = (struct lysc_type_enum *)(*type);
1737
1738 /* RFC 7950 9.6 - enum */
1739 if (type_p->enums) {
1740 LY_CHECK_RET(lys_compile_type_enums(ctx, type_p->enums, basetype,
1741 base ? ((struct lysc_type_enum *)base)->enums : NULL, &enumeration->enums));
1742 }
1743
1744 if (!base && !type_p->flags) {
1745 /* type derived from enumerations built-in type must contain at least one enum */
1746 if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001747 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "enum", "enumeration type ", tpdfname);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001748 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001749 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "enum", "enumeration type", "");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001750 }
1751 return LY_EVALID;
1752 }
1753 break;
1754 case LY_TYPE_INT8:
1755 case LY_TYPE_UINT8:
1756 case LY_TYPE_INT16:
1757 case LY_TYPE_UINT16:
1758 case LY_TYPE_INT32:
1759 case LY_TYPE_UINT32:
1760 case LY_TYPE_INT64:
1761 case LY_TYPE_UINT64:
1762 num = (struct lysc_type_num *)(*type);
1763
1764 /* RFC 6020 9.2.4 - range */
1765 if (type_p->range) {
1766 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->range, basetype, 0, 0,
1767 base ? ((struct lysc_type_num *)base)->range : NULL, &num->range));
1768 if (!tpdfname) {
Radek Krejciab430862021-03-02 20:13:40 +01001769 COMPILE_EXTS_GOTO(ctx, type_p->range->exts, num->range->exts, num->range, ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001770 }
1771 }
1772 break;
1773 case LY_TYPE_IDENT:
1774 idref = (struct lysc_type_identityref *)(*type);
1775
1776 /* RFC 7950 9.10.2 - base */
1777 if (type_p->bases) {
1778 if (base) {
1779 /* only the directly derived identityrefs can contain base specification */
1780 if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001781 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001782 "Invalid base substatement for the type \"%s\" not directly derived from identityref built-in type.",
1783 tpdfname);
1784 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001785 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001786 "Invalid base substatement for the type not directly derived from identityref built-in type.");
1787 }
1788 return LY_EVALID;
1789 }
aPiecekf4a0a192021-08-03 15:14:17 +02001790 LY_CHECK_RET(lys_compile_identity_bases(ctx, type_p->pmod, type_p->bases, NULL, &idref->bases));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001791 }
1792
1793 if (!base && !type_p->flags) {
1794 /* type derived from identityref built-in type must contain at least one base */
1795 if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001796 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "base", "identityref type ", tpdfname);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001797 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001798 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "base", "identityref type", "");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001799 }
1800 return LY_EVALID;
1801 }
1802 break;
1803 case LY_TYPE_LEAFREF:
1804 lref = (struct lysc_type_leafref *)*type;
1805
1806 /* RFC 7950 9.9.3 - require-instance */
1807 if (type_p->flags & LYS_SET_REQINST) {
Michal Vaskoa99b3572021-02-01 11:54:58 +01001808 if (type_p->pmod->version < LYS_VERSION_1_1) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001809 if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001810 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001811 "Leafref type \"%s\" can be restricted by require-instance statement only in YANG 1.1 modules.", tpdfname);
1812 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001813 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001814 "Leafref type can be restricted by require-instance statement only in YANG 1.1 modules.");
1815 }
1816 return LY_EVALID;
1817 }
1818 lref->require_instance = type_p->require_instance;
1819 } else if (base) {
1820 /* inherit */
1821 lref->require_instance = ((struct lysc_type_leafref *)base)->require_instance;
1822 } else {
1823 /* default is true */
1824 lref->require_instance = 1;
1825 }
1826 if (type_p->path) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001827 LY_VALUE_FORMAT format;
Radek Krejci2926c1b2021-03-16 14:45:45 +01001828
Michal Vaskoe33134a2022-07-29 14:54:40 +02001829 LY_CHECK_RET(lyxp_expr_dup(ctx->ctx, type_p->path, 0, 0, &lref->path));
Radek Krejci0b013302021-03-29 15:22:32 +02001830 LY_CHECK_RET(lyplg_type_prefix_data_new(ctx->ctx, type_p->path->expr, strlen(type_p->path->expr),
Radek Krejci8df109d2021-04-23 12:19:08 +02001831 LY_VALUE_SCHEMA, type_p->pmod, &format, (void **)&lref->prefixes));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001832 } else if (base) {
Michal Vaskoe33134a2022-07-29 14:54:40 +02001833 LY_CHECK_RET(lyxp_expr_dup(ctx->ctx, ((struct lysc_type_leafref *)base)->path, 0, 0, &lref->path));
Radek Krejci8df109d2021-04-23 12:19:08 +02001834 LY_CHECK_RET(lyplg_type_prefix_data_dup(ctx->ctx, LY_VALUE_SCHEMA_RESOLVED,
Radek Krejci2926c1b2021-03-16 14:45:45 +01001835 ((struct lysc_type_leafref *)base)->prefixes, (void **)&lref->prefixes));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001836 } else if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001837 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "path", "leafref type ", tpdfname);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001838 return LY_EVALID;
1839 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001840 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "path", "leafref type", "");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001841 return LY_EVALID;
1842 }
1843 break;
1844 case LY_TYPE_INST:
1845 /* RFC 7950 9.9.3 - require-instance */
1846 if (type_p->flags & LYS_SET_REQINST) {
1847 ((struct lysc_type_instanceid *)(*type))->require_instance = type_p->require_instance;
1848 } else {
1849 /* default is true */
1850 ((struct lysc_type_instanceid *)(*type))->require_instance = 1;
1851 }
1852 break;
1853 case LY_TYPE_UNION:
1854 un = (struct lysc_type_union *)(*type);
1855
1856 /* RFC 7950 7.4 - type */
1857 if (type_p->types) {
1858 if (base) {
1859 /* only the directly derived union can contain types specification */
1860 if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001861 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001862 "Invalid type substatement for the type \"%s\" not directly derived from union built-in type.",
1863 tpdfname);
1864 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001865 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001866 "Invalid type substatement for the type not directly derived from union built-in type.");
1867 }
1868 return LY_EVALID;
1869 }
1870 /* compile the type */
Michal Vaskoa99b3572021-02-01 11:54:58 +01001871 LY_CHECK_RET(lys_compile_type_union(ctx, type_p->types, context_pnode, context_flags, context_name, &un->types));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001872 }
1873
1874 if (!base && !type_p->flags) {
1875 /* type derived from union built-in type must contain at least one type */
1876 if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001877 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "type", "union type ", tpdfname);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001878 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001879 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "type", "union type", "");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001880 }
1881 return LY_EVALID;
1882 }
1883 break;
1884 case LY_TYPE_BOOL:
1885 case LY_TYPE_EMPTY:
1886 case LY_TYPE_UNKNOWN: /* just to complete switch */
1887 break;
1888 }
1889
1890 if (tpdfname) {
1891 switch (basetype) {
1892 case LY_TYPE_BINARY:
1893 type_p->compiled = *type;
1894 *type = calloc(1, sizeof(struct lysc_type_bin));
1895 break;
1896 case LY_TYPE_BITS:
1897 type_p->compiled = *type;
1898 *type = calloc(1, sizeof(struct lysc_type_bits));
1899 break;
1900 case LY_TYPE_DEC64:
1901 type_p->compiled = *type;
1902 *type = calloc(1, sizeof(struct lysc_type_dec));
1903 break;
1904 case LY_TYPE_STRING:
1905 type_p->compiled = *type;
1906 *type = calloc(1, sizeof(struct lysc_type_str));
1907 break;
1908 case LY_TYPE_ENUM:
1909 type_p->compiled = *type;
1910 *type = calloc(1, sizeof(struct lysc_type_enum));
1911 break;
1912 case LY_TYPE_INT8:
1913 case LY_TYPE_UINT8:
1914 case LY_TYPE_INT16:
1915 case LY_TYPE_UINT16:
1916 case LY_TYPE_INT32:
1917 case LY_TYPE_UINT32:
1918 case LY_TYPE_INT64:
1919 case LY_TYPE_UINT64:
1920 type_p->compiled = *type;
1921 *type = calloc(1, sizeof(struct lysc_type_num));
1922 break;
1923 case LY_TYPE_IDENT:
1924 type_p->compiled = *type;
1925 *type = calloc(1, sizeof(struct lysc_type_identityref));
1926 break;
1927 case LY_TYPE_LEAFREF:
1928 type_p->compiled = *type;
1929 *type = calloc(1, sizeof(struct lysc_type_leafref));
1930 break;
1931 case LY_TYPE_INST:
1932 type_p->compiled = *type;
1933 *type = calloc(1, sizeof(struct lysc_type_instanceid));
1934 break;
1935 case LY_TYPE_UNION:
1936 type_p->compiled = *type;
1937 *type = calloc(1, sizeof(struct lysc_type_union));
1938 break;
1939 case LY_TYPE_BOOL:
1940 case LY_TYPE_EMPTY:
1941 case LY_TYPE_UNKNOWN: /* just to complete switch */
1942 break;
1943 }
1944 }
1945 LY_CHECK_ERR_RET(!(*type), LOGMEM(ctx->ctx), LY_EMEM);
1946
1947cleanup:
1948 return ret;
1949}
1950
1951LY_ERR
Michal Vaskoa99b3572021-02-01 11:54:58 +01001952lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags, const char *context_name,
1953 struct lysp_type *type_p, struct lysc_type **type, const char **units, struct lysp_qname **dflt)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001954{
1955 LY_ERR ret = LY_SUCCESS;
1956 ly_bool dummyloops = 0;
1957 struct type_context {
1958 const struct lysp_tpdf *tpdf;
1959 struct lysp_node *node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001960 } *tctx, *tctx_prev = NULL, *tctx_iter;
1961 LY_DATA_TYPE basetype = LY_TYPE_UNKNOWN;
1962 struct lysc_type *base = NULL, *prev_type;
1963 struct ly_set tpdf_chain = {0};
Michal Vasko388a6632021-08-06 11:27:43 +02001964 struct lyplg_type *plugin;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001965
1966 (*type) = NULL;
1967 if (dflt) {
1968 *dflt = NULL;
1969 }
1970
1971 tctx = calloc(1, sizeof *tctx);
1972 LY_CHECK_ERR_RET(!tctx, LOGMEM(ctx->ctx), LY_EMEM);
Michal Vaskoedb0fa52022-10-04 10:36:00 +02001973 for (ret = lysp_type_find(type_p->name, context_pnode, type_p->pmod, ctx->ext, &basetype, &tctx->tpdf, &tctx->node);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001974 ret == LY_SUCCESS;
Michal Vaskoedb0fa52022-10-04 10:36:00 +02001975 ret = lysp_type_find(tctx_prev->tpdf->type.name, tctx_prev->node, tctx_prev->tpdf->type.pmod, ctx->ext,
Michal Vaskoa99b3572021-02-01 11:54:58 +01001976 &basetype, &tctx->tpdf, &tctx->node)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001977 if (basetype) {
1978 break;
1979 }
1980
1981 /* check status */
Michal Vaskoa99b3572021-02-01 11:54:58 +01001982 ret = lysc_check_status(ctx, context_flags, (void *)type_p->pmod, context_name, tctx->tpdf->flags,
1983 (void *)tctx->tpdf->type.pmod, tctx->node ? tctx->node->name : tctx->tpdf->name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001984 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
1985
1986 if (units && !*units) {
1987 /* inherit units */
1988 DUP_STRING(ctx->ctx, tctx->tpdf->units, *units, ret);
1989 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
1990 }
1991 if (dflt && !*dflt && tctx->tpdf->dflt.str) {
1992 /* inherit default */
1993 *dflt = (struct lysp_qname *)&tctx->tpdf->dflt;
1994 }
1995 if (dummyloops && (!units || *units) && dflt && *dflt) {
1996 basetype = ((struct type_context *)tpdf_chain.objs[tpdf_chain.count - 1])->tpdf->type.compiled->basetype;
1997 break;
1998 }
1999
Michal Vasko080064b2021-08-31 15:20:44 +02002000 if (tctx->tpdf->type.compiled && (tctx->tpdf->type.compiled->refcount == 1)) {
Radek Krejci720d2612021-03-03 19:44:22 +01002001 /* context recompilation - everything was freed previously (the only reference is from the parsed type itself)
2002 * and we need now recompile the type again in the updated context. */
Michal Vaskoc636ea42022-09-16 10:20:31 +02002003 lysc_type_free(&ctx->free_ctx, tctx->tpdf->type.compiled);
Radek Krejci720d2612021-03-03 19:44:22 +01002004 ((struct lysp_tpdf *)tctx->tpdf)->type.compiled = NULL;
2005 }
2006
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002007 if (tctx->tpdf->type.compiled) {
2008 /* it is not necessary to continue, the rest of the chain was already compiled,
2009 * but we still may need to inherit default and units values, so start dummy loops */
2010 basetype = tctx->tpdf->type.compiled->basetype;
2011 ret = ly_set_add(&tpdf_chain, tctx, 1, NULL);
2012 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
2013
2014 if ((units && !*units) || (dflt && !*dflt)) {
2015 dummyloops = 1;
2016 goto preparenext;
2017 } else {
2018 tctx = NULL;
2019 break;
2020 }
2021 }
2022
2023 /* circular typedef reference detection */
2024 for (uint32_t u = 0; u < tpdf_chain.count; u++) {
2025 /* local part */
2026 tctx_iter = (struct type_context *)tpdf_chain.objs[u];
Michal Vaskoa99b3572021-02-01 11:54:58 +01002027 if (tctx_iter->tpdf == tctx->tpdf) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002028 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002029 "Invalid \"%s\" type reference - circular chain of types detected.", tctx->tpdf->name);
2030 free(tctx);
2031 ret = LY_EVALID;
2032 goto cleanup;
2033 }
2034 }
2035 for (uint32_t u = 0; u < ctx->tpdf_chain.count; u++) {
2036 /* global part for unions corner case */
2037 tctx_iter = (struct type_context *)ctx->tpdf_chain.objs[u];
Michal Vaskoa99b3572021-02-01 11:54:58 +01002038 if (tctx_iter->tpdf == tctx->tpdf) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002039 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002040 "Invalid \"%s\" type reference - circular chain of types detected.", tctx->tpdf->name);
2041 free(tctx);
2042 ret = LY_EVALID;
2043 goto cleanup;
2044 }
2045 }
2046
2047 /* store information for the following processing */
2048 ret = ly_set_add(&tpdf_chain, tctx, 1, NULL);
2049 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
2050
2051preparenext:
2052 /* prepare next loop */
2053 tctx_prev = tctx;
2054 tctx = calloc(1, sizeof *tctx);
2055 LY_CHECK_ERR_RET(!tctx, LOGMEM(ctx->ctx), LY_EMEM);
2056 }
2057 free(tctx);
2058
2059 /* allocate type according to the basetype */
2060 switch (basetype) {
2061 case LY_TYPE_BINARY:
2062 *type = calloc(1, sizeof(struct lysc_type_bin));
2063 break;
2064 case LY_TYPE_BITS:
2065 *type = calloc(1, sizeof(struct lysc_type_bits));
2066 break;
2067 case LY_TYPE_BOOL:
2068 case LY_TYPE_EMPTY:
2069 *type = calloc(1, sizeof(struct lysc_type));
2070 break;
2071 case LY_TYPE_DEC64:
2072 *type = calloc(1, sizeof(struct lysc_type_dec));
2073 break;
2074 case LY_TYPE_ENUM:
2075 *type = calloc(1, sizeof(struct lysc_type_enum));
2076 break;
2077 case LY_TYPE_IDENT:
2078 *type = calloc(1, sizeof(struct lysc_type_identityref));
2079 break;
2080 case LY_TYPE_INST:
2081 *type = calloc(1, sizeof(struct lysc_type_instanceid));
2082 break;
2083 case LY_TYPE_LEAFREF:
2084 *type = calloc(1, sizeof(struct lysc_type_leafref));
2085 break;
2086 case LY_TYPE_STRING:
2087 *type = calloc(1, sizeof(struct lysc_type_str));
2088 break;
2089 case LY_TYPE_UNION:
2090 *type = calloc(1, sizeof(struct lysc_type_union));
2091 break;
2092 case LY_TYPE_INT8:
2093 case LY_TYPE_UINT8:
2094 case LY_TYPE_INT16:
2095 case LY_TYPE_UINT16:
2096 case LY_TYPE_INT32:
2097 case LY_TYPE_UINT32:
2098 case LY_TYPE_INT64:
2099 case LY_TYPE_UINT64:
2100 *type = calloc(1, sizeof(struct lysc_type_num));
2101 break;
2102 case LY_TYPE_UNKNOWN:
Radek Krejci2efc45b2020-12-22 16:25:44 +01002103 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002104 "Referenced type \"%s\" not found.", tctx_prev ? tctx_prev->tpdf->type.name : type_p->name);
2105 ret = LY_EVALID;
2106 goto cleanup;
2107 }
2108 LY_CHECK_ERR_GOTO(!(*type), LOGMEM(ctx->ctx), cleanup);
2109 if (~type_substmt_map[basetype] & type_p->flags) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002110 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Invalid type restrictions for %s type.",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002111 ly_data_type2str[basetype]);
2112 free(*type);
2113 (*type) = NULL;
2114 ret = LY_EVALID;
2115 goto cleanup;
2116 }
2117
2118 /* get restrictions from the referred typedefs */
2119 for (uint32_t u = tpdf_chain.count - 1; u + 1 > 0; --u) {
2120 tctx = (struct type_context *)tpdf_chain.objs[u];
2121
2122 /* remember the typedef context for circular check */
2123 ret = ly_set_add(&ctx->tpdf_chain, tctx, 1, NULL);
2124 LY_CHECK_GOTO(ret, cleanup);
2125
2126 if (tctx->tpdf->type.compiled) {
Michal Vasko388a6632021-08-06 11:27:43 +02002127 /* already compiled */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002128 base = tctx->tpdf->type.compiled;
2129 continue;
Michal Vasko388a6632021-08-06 11:27:43 +02002130 }
2131
Michal Vaskoddd76592022-01-17 13:34:48 +01002132 /* try to find loaded user type plugins */
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02002133 plugin = lyplg_type_plugin_find(tctx->tpdf->type.pmod->mod->name, tctx->tpdf->type.pmod->mod->revision,
Michal Vaskoddd76592022-01-17 13:34:48 +01002134 tctx->tpdf->name);
Haithem Ben Ghorbal45be15f2022-07-12 18:02:36 +02002135 if (!plugin && base) {
2136 /* use the base type implementation if available */
2137 plugin = base->plugin;
2138 }
Michal Vaskoddd76592022-01-17 13:34:48 +01002139 if (!plugin) {
2140 /* use the internal built-in type implementation */
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02002141 plugin = lyplg_type_plugin_find("", NULL, ly_data_type2str[basetype]);
Michal Vaskoddd76592022-01-17 13:34:48 +01002142 }
Michal Vasko388a6632021-08-06 11:27:43 +02002143 assert(plugin);
2144
2145 if ((basetype != LY_TYPE_LEAFREF) && (u != tpdf_chain.count - 1) && !(tctx->tpdf->type.flags) &&
2146 (plugin == base->plugin)) {
2147 /* no change, reuse the compiled base */
2148 ((struct lysp_tpdf *)tctx->tpdf)->type.compiled = base;
Michal Vasko04338d92021-09-01 07:58:14 +02002149 LY_ATOMIC_INC_BARRIER(base->refcount);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002150 continue;
2151 }
2152
Michal Vasko04338d92021-09-01 07:58:14 +02002153 LY_ATOMIC_INC_BARRIER((*type)->refcount);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002154 if (~type_substmt_map[basetype] & tctx->tpdf->type.flags) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002155 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Invalid type \"%s\" restriction(s) for %s type.",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002156 tctx->tpdf->name, ly_data_type2str[basetype]);
2157 ret = LY_EVALID;
2158 goto cleanup;
2159 } else if ((basetype == LY_TYPE_EMPTY) && tctx->tpdf->dflt.str) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002160 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002161 "Invalid type \"%s\" - \"empty\" type must not have a default value (%s).",
2162 tctx->tpdf->name, tctx->tpdf->dflt.str);
2163 ret = LY_EVALID;
2164 goto cleanup;
2165 }
2166
2167 (*type)->basetype = basetype;
Michal Vasko388a6632021-08-06 11:27:43 +02002168 (*type)->plugin = plugin;
2169
Radek Krejci4f2e3e52021-03-30 14:20:28 +02002170 /* collect extensions */
2171 COMPILE_EXTS_GOTO(ctx, tctx->tpdf->type.exts, (*type)->exts, (*type), ret, cleanup);
Michal Vasko388a6632021-08-06 11:27:43 +02002172
2173 /* compile the new typedef */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002174 prev_type = *type;
Michal Vaskoa99b3572021-02-01 11:54:58 +01002175 ret = lys_compile_type_(ctx, tctx->node, tctx->tpdf->flags, tctx->tpdf->name,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002176 &((struct lysp_tpdf *)tctx->tpdf)->type, basetype, tctx->tpdf->name, base, type);
2177 LY_CHECK_GOTO(ret, cleanup);
2178 base = prev_type;
2179 }
2180 /* remove the processed typedef contexts from the stack for circular check */
2181 ctx->tpdf_chain.count = ctx->tpdf_chain.count - tpdf_chain.count;
2182
2183 /* process the type definition in leaf */
2184 if (type_p->flags || !base || (basetype == LY_TYPE_LEAFREF)) {
2185 /* get restrictions from the node itself */
2186 (*type)->basetype = basetype;
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02002187 (*type)->plugin = base ? base->plugin : lyplg_type_plugin_find("", NULL, ly_data_type2str[basetype]);
Michal Vasko04338d92021-09-01 07:58:14 +02002188 LY_ATOMIC_INC_BARRIER((*type)->refcount);
Michal Vaskoa99b3572021-02-01 11:54:58 +01002189 ret = lys_compile_type_(ctx, context_pnode, context_flags, context_name, type_p, basetype, NULL, base, type);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002190 LY_CHECK_GOTO(ret, cleanup);
2191 } else if ((basetype != LY_TYPE_BOOL) && (basetype != LY_TYPE_EMPTY)) {
2192 /* no specific restriction in leaf's type definition, copy from the base */
2193 free(*type);
2194 (*type) = base;
Michal Vasko04338d92021-09-01 07:58:14 +02002195 LY_ATOMIC_INC_BARRIER((*type)->refcount);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002196 }
2197
Radek Krejciab430862021-03-02 20:13:40 +01002198 COMPILE_EXTS_GOTO(ctx, type_p->exts, (*type)->exts, (*type), ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002199
2200cleanup:
2201 ly_set_erase(&tpdf_chain, free);
2202 return ret;
2203}
2204
2205/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002206 * @brief Check uniqness of the node/action/notification name.
2207 *
2208 * Data nodes, actions/RPCs and Notifications are stored separately (in distinguish lists) in the schema
2209 * structures, but they share the namespace so we need to check their name collisions.
2210 *
2211 * @param[in] ctx Compile context.
2212 * @param[in] parent Parent of the nodes to check, can be NULL.
2213 * @param[in] name Name of the item to find in the given lists.
2214 * @param[in] exclude Node that was just added that should be excluded from the name checking.
2215 * @return LY_SUCCESS in case of unique name, LY_EEXIST otherwise.
2216 */
2217static LY_ERR
2218lys_compile_node_uniqness(struct lysc_ctx *ctx, const struct lysc_node *parent, const char *name,
2219 const struct lysc_node *exclude)
2220{
2221 const struct lysc_node *iter, *iter2;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002222 const struct lysc_node_action *actions;
2223 const struct lysc_node_notif *notifs;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002224 uint32_t getnext_flags;
Radek Krejci078e4342021-02-12 18:17:26 +01002225 struct ly_set parent_choices = {0};
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002226
2227#define CHECK_NODE(iter, exclude, name) (iter != (void *)exclude && (iter)->module == exclude->module && !strcmp(name, (iter)->name))
2228
2229 if (exclude->nodetype == LYS_CASE) {
2230 /* check restricted only to all the cases */
2231 assert(parent->nodetype == LYS_CHOICE);
Michal Vasko544e58a2021-01-28 14:33:41 +01002232 LY_LIST_FOR(lysc_node_child(parent), iter) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002233 if (CHECK_NODE(iter, exclude, name)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002234 LOGVAL(ctx->ctx, LY_VCODE_DUPIDENT, name, "case");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002235 return LY_EEXIST;
2236 }
2237 }
2238
2239 return LY_SUCCESS;
2240 }
2241
2242 /* no reason for our parent to be choice anymore */
2243 assert(!parent || (parent->nodetype != LYS_CHOICE));
2244
2245 if (parent && (parent->nodetype == LYS_CASE)) {
2246 /* move to the first data definition parent */
Radek Krejci078e4342021-02-12 18:17:26 +01002247
2248 /* but remember the choice nodes on the parents path to avoid believe they collide with our node */
2249 iter = lysc_data_parent(parent);
2250 do {
2251 parent = parent->parent;
2252 if (parent && (parent->nodetype == LYS_CHOICE)) {
2253 ly_set_add(&parent_choices, (void *)parent, 1, NULL);
2254 }
2255 } while (parent != iter);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002256 }
2257
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01002258 getnext_flags = LYS_GETNEXT_WITHCHOICE;
Michal Vaskob322b7d2021-01-29 17:22:24 +01002259 if (parent && (parent->nodetype & (LYS_RPC | LYS_ACTION))) {
2260 /* move to the inout to avoid traversing a not-filled-yet (the other) node */
2261 if (exclude->flags & LYS_IS_OUTPUT) {
2262 getnext_flags |= LYS_GETNEXT_OUTPUT;
2263 parent = lysc_node_child(parent)->next;
2264 } else {
2265 parent = lysc_node_child(parent);
2266 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002267 }
2268
2269 iter = NULL;
Radek Krejci5fa32a32021-02-08 18:12:38 +01002270 if (!parent && ctx->ext) {
2271 while ((iter = lys_getnext_ext(iter, parent, ctx->ext, getnext_flags))) {
2272 if (!ly_set_contains(&parent_choices, (void *)iter, NULL) && CHECK_NODE(iter, exclude, name)) {
2273 goto error;
2274 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002275
Radek Krejci5fa32a32021-02-08 18:12:38 +01002276 /* we must compare with both the choice and all its nested data-definiition nodes (but not recursively) */
2277 if (iter->nodetype == LYS_CHOICE) {
2278 iter2 = NULL;
2279 while ((iter2 = lys_getnext_ext(iter2, iter, NULL, 0))) {
2280 if (CHECK_NODE(iter2, exclude, name)) {
2281 goto error;
2282 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002283 }
2284 }
2285 }
Radek Krejci5fa32a32021-02-08 18:12:38 +01002286 } else {
2287 while ((iter = lys_getnext(iter, parent, ctx->cur_mod->compiled, getnext_flags))) {
2288 if (!ly_set_contains(&parent_choices, (void *)iter, NULL) && CHECK_NODE(iter, exclude, name)) {
2289 goto error;
2290 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002291
Radek Krejci5fa32a32021-02-08 18:12:38 +01002292 /* we must compare with both the choice and all its nested data-definiition nodes (but not recursively) */
2293 if (iter->nodetype == LYS_CHOICE) {
2294 iter2 = NULL;
2295 while ((iter2 = lys_getnext(iter2, iter, NULL, 0))) {
2296 if (CHECK_NODE(iter2, exclude, name)) {
2297 goto error;
2298 }
2299 }
2300 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002301 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002302
Radek Krejci5fa32a32021-02-08 18:12:38 +01002303 actions = parent ? lysc_node_actions(parent) : ctx->cur_mod->compiled->rpcs;
2304 LY_LIST_FOR((struct lysc_node *)actions, iter) {
2305 if (CHECK_NODE(iter, exclude, name)) {
2306 goto error;
2307 }
2308 }
2309
2310 notifs = parent ? lysc_node_notifs(parent) : ctx->cur_mod->compiled->notifs;
2311 LY_LIST_FOR((struct lysc_node *)notifs, iter) {
2312 if (CHECK_NODE(iter, exclude, name)) {
2313 goto error;
2314 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002315 }
2316 }
Radek Krejci078e4342021-02-12 18:17:26 +01002317 ly_set_erase(&parent_choices, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002318 return LY_SUCCESS;
2319
2320error:
Radek Krejci078e4342021-02-12 18:17:26 +01002321 ly_set_erase(&parent_choices, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +01002322 LOGVAL(ctx->ctx, LY_VCODE_DUPIDENT, name, "data definition/RPC/action/notification");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002323 return LY_EEXIST;
2324
2325#undef CHECK_NODE
2326}
2327
Radek Krejci2a9fc652021-01-22 17:44:34 +01002328/**
2329 * @brief Connect the node into the siblings list and check its name uniqueness. Also,
2330 * keep specific order of augments targetting the same node.
2331 *
2332 * @param[in] ctx Compile context
2333 * @param[in] parent Parent node holding the children list, in case of node from a choice's case,
2334 * the choice itself is expected instead of a specific case node.
2335 * @param[in] node Schema node to connect into the list.
2336 * @return LY_ERR value - LY_SUCCESS or LY_EEXIST.
2337 * In case of LY_EEXIST, the node is actually kept in the tree, so do not free it directly.
2338 */
2339static LY_ERR
2340lys_compile_node_connect(struct lysc_ctx *ctx, struct lysc_node *parent, struct lysc_node *node)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002341{
Radek Krejci2a9fc652021-01-22 17:44:34 +01002342 struct lysc_node **children, *anchor = NULL;
2343 int insert_after = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002344
Radek Krejci2a9fc652021-01-22 17:44:34 +01002345 node->parent = parent;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002346
Radek Krejci2a9fc652021-01-22 17:44:34 +01002347 if (parent) {
Michal Vasko544e58a2021-01-28 14:33:41 +01002348 if (node->nodetype == LYS_INPUT) {
2349 assert(parent->nodetype & (LYS_ACTION | LYS_RPC));
2350 /* input node is part of the action but link it with output */
2351 node->next = &((struct lysc_node_action *)parent)->output.node;
2352 node->prev = node->next;
2353 return LY_SUCCESS;
2354 } else if (node->nodetype == LYS_OUTPUT) {
2355 /* output node is part of the action but link it with input */
2356 node->next = NULL;
2357 node->prev = &((struct lysc_node_action *)parent)->input.node;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002358 return LY_SUCCESS;
2359 } else if (node->nodetype == LYS_ACTION) {
2360 children = (struct lysc_node **)lysc_node_actions_p(parent);
2361 } else if (node->nodetype == LYS_NOTIF) {
2362 children = (struct lysc_node **)lysc_node_notifs_p(parent);
2363 } else {
Michal Vasko544e58a2021-01-28 14:33:41 +01002364 children = lysc_node_child_p(parent);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002365 }
2366 assert(children);
2367
2368 if (!(*children)) {
2369 /* first child */
2370 *children = node;
2371 } else if (node->flags & LYS_KEY) {
2372 /* special handling of adding keys */
2373 assert(node->module == parent->module);
2374 anchor = *children;
2375 if (anchor->flags & LYS_KEY) {
2376 while ((anchor->flags & LYS_KEY) && anchor->next) {
2377 anchor = anchor->next;
2378 }
2379 /* insert after the last key */
2380 insert_after = 1;
2381 } /* else insert before anchor (at the beginning) */
2382 } else if ((*children)->prev->module == node->module) {
2383 /* last child is from the same module, keep the order and insert at the end */
2384 anchor = (*children)->prev;
2385 insert_after = 1;
2386 } else if (parent->module == node->module) {
2387 /* adding module child after some augments were connected */
2388 for (anchor = *children; anchor->module == node->module; anchor = anchor->next) {}
2389 } else {
2390 /* some augments are already connected and we are connecting new ones,
2391 * keep module name order and insert the node into the children list */
2392 anchor = *children;
2393 do {
2394 anchor = anchor->prev;
2395
2396 /* check that we have not found the last augment node from our module or
2397 * the first augment node from a "smaller" module or
2398 * the first node from a local module */
2399 if ((anchor->module == node->module) || (strcmp(anchor->module->name, node->module->name) < 0) ||
2400 (anchor->module == parent->module)) {
2401 /* insert after */
2402 insert_after = 1;
2403 break;
2404 }
2405
2406 /* we have traversed all the nodes, insert before anchor (as the first node) */
2407 } while (anchor->prev->next);
2408 }
2409
2410 /* insert */
2411 if (anchor) {
2412 if (insert_after) {
2413 node->next = anchor->next;
2414 node->prev = anchor;
2415 anchor->next = node;
2416 if (node->next) {
2417 /* middle node */
2418 node->next->prev = node;
2419 } else {
2420 /* last node */
2421 (*children)->prev = node;
2422 }
2423 } else {
2424 node->next = anchor;
2425 node->prev = anchor->prev;
2426 anchor->prev = node;
2427 if (anchor == *children) {
2428 /* first node */
2429 *children = node;
2430 } else {
2431 /* middle node */
2432 node->prev->next = node;
2433 }
2434 }
2435 }
2436
2437 /* check the name uniqueness (even for an only child, it may be in case) */
2438 if (lys_compile_node_uniqness(ctx, parent, node->name, node)) {
2439 return LY_EEXIST;
2440 }
2441 } else {
2442 /* top-level element */
2443 struct lysc_node **list;
2444
Radek Krejci6b88a462021-02-17 12:39:34 +01002445 if (ctx->ext) {
Michal Vasko55bce0e2022-02-15 10:46:08 +01002446 /* container matches all data nodes */
Michal Vasko9c3556a2022-10-06 16:08:47 +02002447 lysc_ext_substmt(ctx->ext, LY_STMT_CONTAINER, (void **)&list);
Radek Krejci6b88a462021-02-17 12:39:34 +01002448 } else if (node->nodetype == LYS_RPC) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01002449 list = (struct lysc_node **)&ctx->cur_mod->compiled->rpcs;
2450 } else if (node->nodetype == LYS_NOTIF) {
2451 list = (struct lysc_node **)&ctx->cur_mod->compiled->notifs;
2452 } else {
2453 list = &ctx->cur_mod->compiled->data;
2454 }
2455 if (!(*list)) {
2456 *list = node;
2457 } else {
2458 /* insert at the end of the module's top-level nodes list */
2459 (*list)->prev->next = node;
2460 node->prev = (*list)->prev;
2461 (*list)->prev = node;
2462 }
2463
2464 /* check the name uniqueness on top-level */
2465 if (lys_compile_node_uniqness(ctx, NULL, node->name, node)) {
2466 return LY_EEXIST;
2467 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002468 }
2469
Radek Krejci2a9fc652021-01-22 17:44:34 +01002470 return LY_SUCCESS;
2471}
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002472
Radek Krejci2a9fc652021-01-22 17:44:34 +01002473/**
Michal Vaskod1e53b92021-01-28 13:11:06 +01002474 * @brief Set config and operation flags for a node.
Radek Krejci2a9fc652021-01-22 17:44:34 +01002475 *
2476 * @param[in] ctx Compile context.
Michal Vaskod1e53b92021-01-28 13:11:06 +01002477 * @param[in] node Compiled node flags to set.
Radek Krejci2a9fc652021-01-22 17:44:34 +01002478 * @return LY_ERR value.
2479 */
2480static LY_ERR
Radek Krejci91531e12021-02-08 19:57:54 +01002481lys_compile_config(struct lysc_ctx *ctx, struct lysc_node *node)
Radek Krejci2a9fc652021-01-22 17:44:34 +01002482{
2483 /* case never has any explicit config */
2484 assert((node->nodetype != LYS_CASE) || !(node->flags & LYS_CONFIG_MASK));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002485
Michal Vasko7c565922021-06-10 14:58:27 +02002486 if (ctx->compile_opts & LYS_COMPILE_NO_CONFIG) {
Radek Krejci91531e12021-02-08 19:57:54 +01002487 /* ignore config statements inside Notification/RPC/action/... data */
Radek Krejci2a9fc652021-01-22 17:44:34 +01002488 node->flags &= ~LYS_CONFIG_MASK;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002489 } else if (!(node->flags & LYS_CONFIG_MASK)) {
2490 /* config not explicitly set, inherit it from parent */
Michal Vaskoecdc2222022-01-24 08:45:44 +01002491 assert(!node->parent || (node->parent->flags & LYS_CONFIG_MASK) || (node->parent->nodetype & LYS_AUGMENT));
2492 if (node->parent && (node->parent->flags & LYS_CONFIG_MASK)) {
Radek Krejci91531e12021-02-08 19:57:54 +01002493 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002494 } else {
2495 /* default is config true */
2496 node->flags |= LYS_CONFIG_W;
2497 }
2498 } else {
2499 /* config set explicitly */
2500 node->flags |= LYS_SET_CONFIG;
2501 }
2502
Radek Krejci91531e12021-02-08 19:57:54 +01002503 if (node->parent && (node->parent->flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
Michal Vaskod1e53b92021-01-28 13:11:06 +01002504 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Configuration node cannot be child of any state data node.");
Radek Krejci2a9fc652021-01-22 17:44:34 +01002505 return LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002506 }
2507
Radek Krejci2a9fc652021-01-22 17:44:34 +01002508 return LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002509}
2510
Radek Krejci91531e12021-02-08 19:57:54 +01002511/**
2512 * @brief Set various flags of the compiled nodes
2513 *
2514 * @param[in] ctx Compile context.
2515 * @param[in] node Compiled node where the flags will be set.
Michal Vaskoedb0fa52022-10-04 10:36:00 +02002516 * @param[in] inherited_status Explicitly inherited status (from uses/extension instance), if any.
Radek Krejci91531e12021-02-08 19:57:54 +01002517 */
2518static LY_ERR
Michal Vaskoedb0fa52022-10-04 10:36:00 +02002519lys_compile_node_flags(struct lysc_ctx *ctx, struct lysc_node *node, const uint16_t *inherited_status)
Radek Krejci91531e12021-02-08 19:57:54 +01002520{
Michal Vaskoedb0fa52022-10-04 10:36:00 +02002521 uint16_t parent_flags;
2522 const char *parent_name;
2523
Radek Krejci91531e12021-02-08 19:57:54 +01002524 /* inherit config flags */
2525 LY_CHECK_RET(lys_compile_config(ctx, node));
2526
2527 /* status - it is not inherited by specification, but it does not make sense to have
2528 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
Michal Vaskoedb0fa52022-10-04 10:36:00 +02002529 parent_flags = inherited_status ? *inherited_status : (node->parent ? node->parent->flags : 0);
2530 parent_name = inherited_status ? "<schema-only-node>" : (node->parent ? node->parent->name : NULL);
2531 LY_CHECK_RET(lys_compile_status(ctx, &node->flags, node->name, parent_flags, parent_name, inherited_status ? 1 : 0));
Radek Krejci91531e12021-02-08 19:57:54 +01002532
2533 /* other flags */
Michal Vasko7c565922021-06-10 14:58:27 +02002534 if ((ctx->compile_opts & LYS_IS_INPUT) && (node->nodetype != LYS_INPUT)) {
Radek Krejci91531e12021-02-08 19:57:54 +01002535 node->flags |= LYS_IS_INPUT;
Michal Vasko7c565922021-06-10 14:58:27 +02002536 } else if ((ctx->compile_opts & LYS_IS_OUTPUT) && (node->nodetype != LYS_OUTPUT)) {
Radek Krejci91531e12021-02-08 19:57:54 +01002537 node->flags |= LYS_IS_OUTPUT;
Michal Vasko7c565922021-06-10 14:58:27 +02002538 } else if ((ctx->compile_opts & LYS_IS_NOTIF) && (node->nodetype != LYS_NOTIF)) {
Radek Krejci91531e12021-02-08 19:57:54 +01002539 node->flags |= LYS_IS_NOTIF;
2540 }
2541
2542 return LY_SUCCESS;
2543}
2544
Michal Vaskoedb0fa52022-10-04 10:36:00 +02002545static LY_ERR
2546lys_compile_node_(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *parent, const uint16_t *inherited_status,
Radek Krejci2a9fc652021-01-22 17:44:34 +01002547 LY_ERR (*node_compile_spec)(struct lysc_ctx *, struct lysp_node *, struct lysc_node *),
2548 struct lysc_node *node, struct ly_set *child_set)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002549{
2550 LY_ERR ret = LY_SUCCESS;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01002551 ly_bool not_supported, enabled;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002552 struct lysp_node *dev_pnode = NULL;
Radek Krejci9a3823e2021-01-27 20:26:46 +01002553 struct lysp_when *pwhen = NULL;
Michal Vaskoe02e7402021-07-23 08:29:28 +02002554 uint32_t prev_opts = ctx->compile_opts;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002555
Radek Krejci2a9fc652021-01-22 17:44:34 +01002556 node->nodetype = pnode->nodetype;
2557 node->module = ctx->cur_mod;
Radek Krejci91531e12021-02-08 19:57:54 +01002558 node->parent = parent;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002559 node->prev = node;
aPiecek9922ea92021-04-12 07:59:20 +02002560 node->priv = ctx->ctx->flags & LY_CTX_SET_PRIV_PARSED ? pnode : NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002561
Radek Krejci2a9fc652021-01-22 17:44:34 +01002562 /* compile any deviations for this node */
2563 LY_CHECK_GOTO(ret = lys_compile_node_deviations_refines(ctx, pnode, parent, &dev_pnode, &not_supported), error);
Michal Vaskoe02e7402021-07-23 08:29:28 +02002564 if (not_supported && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
2565 /* if not supported, keep it just like disabled nodes by if-feature */
2566 ly_set_add(&ctx->unres->disabled, node, 1, NULL);
2567 ctx->compile_opts |= LYS_COMPILE_DISABLED;
2568 }
2569 if (dev_pnode) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01002570 pnode = dev_pnode;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002571 }
2572
Radek Krejci2a9fc652021-01-22 17:44:34 +01002573 node->flags = pnode->flags & LYS_FLAGS_COMPILED_MASK;
Michal Vaskodfd254d2021-06-24 09:24:59 +02002574 DUP_STRING_GOTO(ctx->ctx, pnode->name, node->name, ret, error);
2575 DUP_STRING_GOTO(ctx->ctx, pnode->dsc, node->dsc, ret, error);
2576 DUP_STRING_GOTO(ctx->ctx, pnode->ref, node->ref, ret, error);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002577
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01002578 /* if-features */
Radek Krejci2a9fc652021-01-22 17:44:34 +01002579 LY_CHECK_GOTO(ret = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), error);
Michal Vasko7c565922021-06-10 14:58:27 +02002580 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
Michal Vasko30ab8e72021-04-19 12:47:52 +02002581 ly_set_add(&ctx->unres->disabled, node, 1, NULL);
Michal Vasko7c565922021-06-10 14:58:27 +02002582 ctx->compile_opts |= LYS_COMPILE_DISABLED;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01002583 }
2584
Radek Krejci91531e12021-02-08 19:57:54 +01002585 /* config, status and other flags */
Michal Vaskoedb0fa52022-10-04 10:36:00 +02002586 ret = lys_compile_node_flags(ctx, node, inherited_status);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002587 LY_CHECK_GOTO(ret, error);
2588
2589 /* list ordering */
2590 if (node->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
Michal Vaskod1e53b92021-01-28 13:11:06 +01002591 if ((node->flags & (LYS_CONFIG_R | LYS_IS_OUTPUT | LYS_IS_NOTIF)) && (node->flags & LYS_ORDBY_MASK)) {
Michal Vasko5676f4e2021-04-06 17:14:45 +02002592 LOGVRB("The ordered-by statement is ignored in lists representing %s (%s).",
Radek Krejci91531e12021-02-08 19:57:54 +01002593 (node->flags & LYS_IS_OUTPUT) ? "RPC/action output parameters" :
Michal Vasko7c565922021-06-10 14:58:27 +02002594 (ctx->compile_opts & LYS_IS_NOTIF) ? "notification content" : "state data", ctx->path);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002595 node->flags &= ~LYS_ORDBY_MASK;
2596 node->flags |= LYS_ORDBY_SYSTEM;
2597 } else if (!(node->flags & LYS_ORDBY_MASK)) {
2598 /* default ordering is system */
2599 node->flags |= LYS_ORDBY_SYSTEM;
2600 }
2601 }
2602
Radek Krejci2a9fc652021-01-22 17:44:34 +01002603 /* insert into parent's children/compiled module (we can no longer free the node separately on error) */
2604 LY_CHECK_GOTO(ret = lys_compile_node_connect(ctx, parent, node), cleanup);
2605
Radek Krejci9a3823e2021-01-27 20:26:46 +01002606 if ((pwhen = lysp_node_when(pnode))) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01002607 /* compile when */
Michal Vaskodfd254d2021-06-24 09:24:59 +02002608 ret = lys_compile_when(ctx, pwhen, pnode->flags, node, lysc_data_node(node), node, NULL);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002609 LY_CHECK_GOTO(ret, cleanup);
2610 }
2611
Radek Krejci2a9fc652021-01-22 17:44:34 +01002612 /* nodetype-specific part */
2613 LY_CHECK_GOTO(ret = node_compile_spec(ctx, pnode, node), cleanup);
2614
2615 /* final compilation tasks that require the node to be connected */
Radek Krejciab430862021-03-02 20:13:40 +01002616 COMPILE_EXTS_GOTO(ctx, pnode->exts, node->exts, node, ret, cleanup);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002617 if (node->flags & LYS_MAND_TRUE) {
2618 /* inherit LYS_MAND_TRUE in parent containers */
2619 lys_compile_mandatory_parents(parent, 1);
2620 }
2621
2622 if (child_set) {
2623 /* add the new node into set */
2624 LY_CHECK_GOTO(ret = ly_set_add(child_set, node, 1, NULL), cleanup);
2625 }
2626
2627 goto cleanup;
2628
2629error:
Michal Vaskoc636ea42022-09-16 10:20:31 +02002630 lysc_node_free(&ctx->free_ctx, node, 0);
2631
Radek Krejci2a9fc652021-01-22 17:44:34 +01002632cleanup:
2633 if (ret && dev_pnode) {
2634 LOGVAL(ctx->ctx, LYVE_OTHER, "Compilation of a deviated and/or refined node failed.");
2635 }
Michal Vaskoe02e7402021-07-23 08:29:28 +02002636 ctx->compile_opts = prev_opts;
Michal Vaskoc636ea42022-09-16 10:20:31 +02002637 lysp_dev_node_free(ctx, dev_pnode);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002638 return ret;
2639}
2640
2641/**
2642 * @brief Compile parsed action's input/output node information.
2643 * @param[in] ctx Compile context
2644 * @param[in] pnode Parsed inout node.
2645 * @param[in,out] node Pre-prepared structure from lys_compile_node_() with filled generic node information
2646 * is enriched with the inout-specific information.
2647 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
2648 */
2649LY_ERR
2650lys_compile_node_action_inout(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
2651{
2652 LY_ERR ret = LY_SUCCESS;
2653 struct lysp_node *child_p;
Michal Vasko7c565922021-06-10 14:58:27 +02002654 uint32_t prev_options = ctx->compile_opts;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002655
2656 struct lysp_node_action_inout *inout_p = (struct lysp_node_action_inout *)pnode;
2657 struct lysc_node_action_inout *inout = (struct lysc_node_action_inout *)node;
2658
2659 COMPILE_ARRAY_GOTO(ctx, inout_p->musts, inout->musts, lys_compile_must, ret, done);
Radek Krejciab430862021-03-02 20:13:40 +01002660 COMPILE_EXTS_GOTO(ctx, inout_p->exts, inout->exts, inout, ret, done);
Michal Vasko7c565922021-06-10 14:58:27 +02002661 ctx->compile_opts |= (inout_p->nodetype == LYS_INPUT) ? LYS_COMPILE_RPC_INPUT : LYS_COMPILE_RPC_OUTPUT;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002662
Radek Krejci01180ac2021-01-27 08:48:22 +01002663 LY_LIST_FOR(inout_p->child, child_p) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01002664 LY_CHECK_GOTO(ret = lys_compile_node(ctx, child_p, node, 0, NULL), done);
2665 }
2666
Michal Vasko95f736c2022-06-08 12:03:31 +02002667 /* connect any augments */
2668 LY_CHECK_GOTO(ret = lys_compile_node_augments(ctx, node), done);
2669
Michal Vasko7c565922021-06-10 14:58:27 +02002670 ctx->compile_opts = prev_options;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002671
2672done:
2673 return ret;
2674}
2675
2676/**
2677 * @brief Compile parsed action node information.
2678 * @param[in] ctx Compile context
2679 * @param[in] pnode Parsed action node.
2680 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
2681 * is enriched with the action-specific information.
2682 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
2683 */
2684LY_ERR
2685lys_compile_node_action(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
2686{
2687 LY_ERR ret;
2688 struct lysp_node_action *action_p = (struct lysp_node_action *)pnode;
2689 struct lysc_node_action *action = (struct lysc_node_action *)node;
2690 struct lysp_node_action_inout *input, implicit_input = {
2691 .nodetype = LYS_INPUT,
2692 .name = "input",
2693 .parent = pnode,
2694 };
2695 struct lysp_node_action_inout *output, implicit_output = {
2696 .nodetype = LYS_OUTPUT,
2697 .name = "output",
2698 .parent = pnode,
2699 };
2700
Michal Vaskoe17ff5f2021-01-29 17:23:03 +01002701 /* input */
Radek Krejcia6016992021-03-03 10:13:41 +01002702 lysc_update_path(ctx, action->module, "input");
Radek Krejci2a9fc652021-01-22 17:44:34 +01002703 if (action_p->input.nodetype == LYS_UNKNOWN) {
2704 input = &implicit_input;
2705 } else {
2706 input = &action_p->input;
2707 }
Michal Vasko14ed9cd2021-01-28 14:16:25 +01002708 ret = lys_compile_node_(ctx, &input->node, &action->node, 0, lys_compile_node_action_inout, &action->input.node, NULL);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002709 lysc_update_path(ctx, NULL, NULL);
2710 LY_CHECK_GOTO(ret, done);
2711
Michal Vaskoc130e162021-10-19 11:30:00 +02002712 /* add must(s) to unres */
2713 ret = lysc_unres_must_add(ctx, &action->input.node, &input->node);
2714 LY_CHECK_GOTO(ret, done);
2715
Radek Krejci2a9fc652021-01-22 17:44:34 +01002716 /* output */
Radek Krejcia6016992021-03-03 10:13:41 +01002717 lysc_update_path(ctx, action->module, "output");
Michal Vasko9149efd2021-01-29 11:16:59 +01002718 if (action_p->output.nodetype == LYS_UNKNOWN) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01002719 output = &implicit_output;
2720 } else {
2721 output = &action_p->output;
2722 }
Michal Vasko14ed9cd2021-01-28 14:16:25 +01002723 ret = lys_compile_node_(ctx, &output->node, &action->node, 0, lys_compile_node_action_inout, &action->output.node, NULL);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002724 lysc_update_path(ctx, NULL, NULL);
2725 LY_CHECK_GOTO(ret, done);
2726
Michal Vaskoc130e162021-10-19 11:30:00 +02002727 /* add must(s) to unres */
2728 ret = lysc_unres_must_add(ctx, &action->output.node, &output->node);
2729 LY_CHECK_GOTO(ret, done);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002730
2731done:
2732 return ret;
2733}
2734
2735/**
2736 * @brief Compile parsed action node information.
2737 * @param[in] ctx Compile context
2738 * @param[in] pnode Parsed action node.
2739 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
2740 * is enriched with the action-specific information.
2741 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
2742 */
2743LY_ERR
2744lys_compile_node_notif(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
2745{
2746 LY_ERR ret = LY_SUCCESS;
2747 struct lysp_node_notif *notif_p = (struct lysp_node_notif *)pnode;
2748 struct lysc_node_notif *notif = (struct lysc_node_notif *)node;
2749 struct lysp_node *child_p;
2750
2751 COMPILE_ARRAY_GOTO(ctx, notif_p->musts, notif->musts, lys_compile_must, ret, done);
Michal Vaskoc130e162021-10-19 11:30:00 +02002752
2753 /* add must(s) to unres */
2754 ret = lysc_unres_must_add(ctx, node, pnode);
2755 LY_CHECK_GOTO(ret, done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002756
Radek Krejci01180ac2021-01-27 08:48:22 +01002757 LY_LIST_FOR(notif_p->child, child_p) {
Michal Vasko14ed9cd2021-01-28 14:16:25 +01002758 ret = lys_compile_node(ctx, child_p, node, 0, NULL);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002759 LY_CHECK_GOTO(ret, done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002760 }
2761
Michal Vasko95f736c2022-06-08 12:03:31 +02002762 /* connect any augments */
2763 LY_CHECK_GOTO(ret = lys_compile_node_augments(ctx, node), done);
2764
Radek Krejci2a9fc652021-01-22 17:44:34 +01002765done:
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002766 return ret;
2767}
2768
2769/**
2770 * @brief Compile parsed container node information.
2771 * @param[in] ctx Compile context
2772 * @param[in] pnode Parsed container node.
2773 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
2774 * is enriched with the container-specific information.
2775 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
2776 */
2777static LY_ERR
2778lys_compile_node_container(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
2779{
2780 struct lysp_node_container *cont_p = (struct lysp_node_container *)pnode;
2781 struct lysc_node_container *cont = (struct lysc_node_container *)node;
2782 struct lysp_node *child_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002783 LY_ERR ret = LY_SUCCESS;
2784
2785 if (cont_p->presence) {
Michal Vaskoe16c7b72021-02-26 10:39:06 +01002786 /* presence container */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002787 cont->flags |= LYS_PRESENCE;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002788 }
2789
2790 /* more cases when the container has meaning but is kept NP for convenience:
2791 * - when condition
2792 * - direct child action/notification
2793 */
2794
2795 LY_LIST_FOR(cont_p->child, child_p) {
2796 ret = lys_compile_node(ctx, child_p, node, 0, NULL);
2797 LY_CHECK_GOTO(ret, done);
2798 }
2799
Michal Vasko5347e3a2020-11-03 17:14:57 +01002800 COMPILE_ARRAY_GOTO(ctx, cont_p->musts, cont->musts, lys_compile_must, ret, done);
Michal Vaskoc130e162021-10-19 11:30:00 +02002801
2802 /* add must(s) to unres */
2803 ret = lysc_unres_must_add(ctx, node, pnode);
2804 LY_CHECK_GOTO(ret, done);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002805
Michal Vasko95f736c2022-06-08 12:03:31 +02002806 /* connect any augments */
2807 LY_CHECK_GOTO(ret = lys_compile_node_augments(ctx, node), done);
2808
Radek Krejci2a9fc652021-01-22 17:44:34 +01002809 LY_LIST_FOR((struct lysp_node *)cont_p->actions, child_p) {
2810 ret = lys_compile_node(ctx, child_p, node, 0, NULL);
2811 LY_CHECK_GOTO(ret, done);
2812 }
2813 LY_LIST_FOR((struct lysp_node *)cont_p->notifs, child_p) {
2814 ret = lys_compile_node(ctx, child_p, node, 0, NULL);
2815 LY_CHECK_GOTO(ret, done);
2816 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002817
2818done:
2819 return ret;
2820}
2821
Michal Vasko72244882021-01-12 15:21:05 +01002822/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002823 * @brief Compile type in leaf/leaf-list node and do all the necessary checks.
2824 * @param[in] ctx Compile context.
2825 * @param[in] context_node Schema node where the type/typedef is placed to correctly find the base types.
2826 * @param[in] type_p Parsed type to compile.
2827 * @param[in,out] leaf Compiled leaf structure (possibly cast leaf-list) to provide node information and to store the compiled type information.
2828 * @return LY_ERR value.
2829 */
2830static LY_ERR
2831lys_compile_node_type(struct lysc_ctx *ctx, struct lysp_node *context_node, struct lysp_type *type_p,
2832 struct lysc_node_leaf *leaf)
2833{
2834 struct lysp_qname *dflt;
Michal Vaskof4fa90d2021-11-11 15:05:19 +01002835 struct lysc_type **t;
2836 LY_ARRAY_COUNT_TYPE u, count;
2837 ly_bool in_unres = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002838
Michal Vaskoa99b3572021-02-01 11:54:58 +01002839 LY_CHECK_RET(lys_compile_type(ctx, context_node, leaf->flags, leaf->name, type_p, &leaf->type,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002840 leaf->units ? NULL : &leaf->units, &dflt));
2841
2842 /* store default value, if any */
2843 if (dflt && !(leaf->flags & LYS_SET_DFLT)) {
2844 LY_CHECK_RET(lysc_unres_leaf_dflt_add(ctx, leaf, dflt));
2845 }
2846
Michal Vaskoc130e162021-10-19 11:30:00 +02002847 /* store leafref(s) to be resolved */
2848 LY_CHECK_RET(lysc_unres_leafref_add(ctx, leaf, type_p->pmod));
2849
Michal Vaskof4fa90d2021-11-11 15:05:19 +01002850 /* type-specific checks */
2851 if (leaf->type->basetype == LY_TYPE_UNION) {
2852 t = ((struct lysc_type_union *)leaf->type)->types;
2853 count = LY_ARRAY_COUNT(t);
2854 } else {
2855 t = &leaf->type;
2856 count = 1;
2857 }
2858 for (u = 0; u < count; ++u) {
2859 if (t[u]->basetype == LY_TYPE_EMPTY) {
2860 if ((leaf->nodetype == LYS_LEAFLIST) && (ctx->pmod->version < LYS_VERSION_1_1)) {
2861 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Leaf-list of type \"empty\" is allowed only in YANG 1.1 modules.");
2862 return LY_EVALID;
2863 }
2864 } else if (!in_unres && ((t[u]->basetype == LY_TYPE_BITS) || (t[u]->basetype == LY_TYPE_ENUM))) {
2865 /* store in unres for all disabled bits/enums to be removed */
2866 LY_CHECK_RET(lysc_unres_bitenum_add(ctx, leaf));
2867 in_unres = 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002868 }
2869 }
2870
2871 return LY_SUCCESS;
2872}
2873
2874/**
2875 * @brief Compile parsed leaf node information.
2876 * @param[in] ctx Compile context
2877 * @param[in] pnode Parsed leaf node.
2878 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
2879 * is enriched with the leaf-specific information.
2880 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
2881 */
2882static LY_ERR
2883lys_compile_node_leaf(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
2884{
2885 struct lysp_node_leaf *leaf_p = (struct lysp_node_leaf *)pnode;
2886 struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002887 LY_ERR ret = LY_SUCCESS;
2888
Michal Vasko5347e3a2020-11-03 17:14:57 +01002889 COMPILE_ARRAY_GOTO(ctx, leaf_p->musts, leaf->musts, lys_compile_must, ret, done);
Michal Vaskoc130e162021-10-19 11:30:00 +02002890
2891 /* add must(s) to unres */
2892 ret = lysc_unres_must_add(ctx, node, pnode);
2893 LY_CHECK_GOTO(ret, done);
2894
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002895 if (leaf_p->units) {
2896 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, leaf_p->units, 0, &leaf->units), done);
2897 leaf->flags |= LYS_SET_UNITS;
2898 }
2899
2900 /* compile type */
2901 ret = lys_compile_node_type(ctx, pnode, &leaf_p->type, leaf);
2902 LY_CHECK_GOTO(ret, done);
2903
2904 /* store/update default value */
2905 if (leaf_p->dflt.str) {
2906 LY_CHECK_RET(lysc_unres_leaf_dflt_add(ctx, leaf, &leaf_p->dflt));
2907 leaf->flags |= LYS_SET_DFLT;
2908 }
2909
2910 /* checks */
2911 if ((leaf->flags & LYS_SET_DFLT) && (leaf->flags & LYS_MAND_TRUE)) {
Michal Vasko6b8c5102021-10-19 11:29:32 +02002912 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Invalid mandatory leaf with a default value.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002913 return LY_EVALID;
2914 }
2915
2916done:
2917 return ret;
2918}
2919
2920/**
2921 * @brief Compile parsed leaf-list node information.
2922 * @param[in] ctx Compile context
2923 * @param[in] pnode Parsed leaf-list node.
2924 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
2925 * is enriched with the leaf-list-specific information.
2926 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
2927 */
2928static LY_ERR
2929lys_compile_node_leaflist(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
2930{
2931 struct lysp_node_leaflist *llist_p = (struct lysp_node_leaflist *)pnode;
2932 struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002933 LY_ERR ret = LY_SUCCESS;
2934
Michal Vasko5347e3a2020-11-03 17:14:57 +01002935 COMPILE_ARRAY_GOTO(ctx, llist_p->musts, llist->musts, lys_compile_must, ret, done);
Michal Vaskoc130e162021-10-19 11:30:00 +02002936
2937 /* add must(s) to unres */
2938 ret = lysc_unres_must_add(ctx, node, pnode);
2939 LY_CHECK_GOTO(ret, done);
2940
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002941 if (llist_p->units) {
2942 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, llist_p->units, 0, &llist->units), done);
2943 llist->flags |= LYS_SET_UNITS;
2944 }
2945
2946 /* compile type */
2947 ret = lys_compile_node_type(ctx, pnode, &llist_p->type, (struct lysc_node_leaf *)llist);
2948 LY_CHECK_GOTO(ret, done);
2949
2950 /* store/update default values */
2951 if (llist_p->dflts) {
2952 if (ctx->pmod->version < LYS_VERSION_1_1) {
Michal Vasko6b8c5102021-10-19 11:29:32 +02002953 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Leaf-list default values are allowed only in YANG 1.1 modules.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002954 return LY_EVALID;
2955 }
2956
2957 LY_CHECK_GOTO(lysc_unres_llist_dflts_add(ctx, llist, llist_p->dflts), done);
2958 llist->flags |= LYS_SET_DFLT;
2959 }
2960
2961 llist->min = llist_p->min;
2962 if (llist->min) {
2963 llist->flags |= LYS_MAND_TRUE;
2964 }
Michal Vaskoe78faec2021-04-08 17:24:43 +02002965 llist->max = llist_p->max ? llist_p->max : UINT32_MAX;
2966
2967 if (llist->flags & LYS_CONFIG_R) {
2968 /* state leaf-list is always ordered-by user */
2969 llist->flags &= ~LYS_ORDBY_SYSTEM;
2970 llist->flags |= LYS_ORDBY_USER;
2971 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002972
2973 /* checks */
2974 if ((llist->flags & LYS_SET_DFLT) && (llist->flags & LYS_MAND_TRUE)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002975 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "The default statement is present on leaf-list with a nonzero min-elements.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002976 return LY_EVALID;
2977 }
2978
2979 if (llist->min > llist->max) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002980 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Leaf-list min-elements %u is bigger than max-elements %u.",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002981 llist->min, llist->max);
2982 return LY_EVALID;
2983 }
2984
2985done:
2986 return ret;
2987}
2988
Michal Vasko0b50f6b2022-10-05 15:07:55 +02002989LY_ERR
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002990lysc_resolve_schema_nodeid(struct lysc_ctx *ctx, const char *nodeid, size_t nodeid_len, const struct lysc_node *ctx_node,
Michal Vasko56d8da82021-12-16 15:41:30 +01002991 LY_VALUE_FORMAT format, void *prefix_data, uint16_t nodetype, const struct lysc_node **target, uint16_t *result_flag)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002992{
2993 LY_ERR ret = LY_EVALID;
2994 const char *name, *prefix, *id;
2995 size_t name_len, prefix_len;
Radek Krejci2b18bf12020-11-06 11:20:20 +01002996 const struct lys_module *mod = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002997 const char *nodeid_type;
2998 uint32_t getnext_extra_flag = 0;
2999 uint16_t current_nodetype = 0;
3000
3001 assert(nodeid);
3002 assert(target);
3003 assert(result_flag);
3004 *target = NULL;
3005 *result_flag = 0;
3006
3007 id = nodeid;
3008
3009 if (ctx_node) {
3010 /* descendant-schema-nodeid */
3011 nodeid_type = "descendant";
3012
3013 if (*id == '/') {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003014 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003015 "Invalid descendant-schema-nodeid value \"%.*s\" - absolute-schema-nodeid used.",
Radek Krejci422afb12021-03-04 16:38:16 +01003016 (int)(nodeid_len ? nodeid_len : strlen(nodeid)), nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003017 return LY_EVALID;
3018 }
3019 } else {
3020 /* absolute-schema-nodeid */
3021 nodeid_type = "absolute";
3022
3023 if (*id != '/') {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003024 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003025 "Invalid absolute-schema-nodeid value \"%.*s\" - missing starting \"/\".",
Radek Krejci422afb12021-03-04 16:38:16 +01003026 (int)(nodeid_len ? nodeid_len : strlen(nodeid)), nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003027 return LY_EVALID;
3028 }
3029 ++id;
3030 }
3031
3032 while (*id && (ret = ly_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len)) == LY_SUCCESS) {
3033 if (prefix) {
3034 mod = ly_resolve_prefix(ctx->ctx, prefix, prefix_len, format, prefix_data);
3035 if (!mod) {
3036 /* module must always be found */
3037 assert(prefix);
Radek Krejci2efc45b2020-12-22 16:25:44 +01003038 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003039 "Invalid %s-schema-nodeid value \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01003040 nodeid_type, (int)(id - nodeid), nodeid, (int)prefix_len, prefix, LYSP_MODULE_NAME(ctx->pmod));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003041 return LY_ENOTFOUND;
3042 }
3043 } else {
3044 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02003045 case LY_VALUE_SCHEMA:
3046 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003047 /* use the current module */
Michal Vasko56d8da82021-12-16 15:41:30 +01003048 mod = ctx->cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003049 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02003050 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02003051 case LY_VALUE_LYB:
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003052 if (!ctx_node) {
3053 LOGINT_RET(ctx->ctx);
3054 }
3055 /* inherit the module of the previous context node */
3056 mod = ctx_node->module;
3057 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02003058 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02003059 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01003060 case LY_VALUE_STR_NS:
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003061 /* not really defined */
3062 LOGINT_RET(ctx->ctx);
3063 }
3064 }
3065
3066 if (ctx_node && (ctx_node->nodetype & (LYS_RPC | LYS_ACTION))) {
3067 /* move through input/output manually */
3068 if (mod != ctx_node->module) {
Radek Krejci422afb12021-03-04 16:38:16 +01003069 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.",
3070 nodeid_type, (int)(id - nodeid), nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003071 return LY_ENOTFOUND;
3072 }
3073 if (!ly_strncmp("input", name, name_len)) {
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003074 ctx_node = &((struct lysc_node_action *)ctx_node)->input.node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003075 } else if (!ly_strncmp("output", name, name_len)) {
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003076 ctx_node = &((struct lysc_node_action *)ctx_node)->output.node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003077 getnext_extra_flag = LYS_GETNEXT_OUTPUT;
3078 } else {
3079 /* only input or output is valid */
3080 ctx_node = NULL;
3081 }
Michal Vasko0b50f6b2022-10-05 15:07:55 +02003082 } else if (ctx->ext && !ctx_node) {
3083 /* top-level extension nodes */
3084 ctx_node = lysc_ext_find_node(ctx->ext, mod, name, name_len, 0, LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003085 } else {
3086 ctx_node = lys_find_child(ctx_node, mod, name, name_len, 0,
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01003087 getnext_extra_flag | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003088 getnext_extra_flag = 0;
3089 }
3090 if (!ctx_node) {
Radek Krejci422afb12021-03-04 16:38:16 +01003091 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.",
3092 nodeid_type, (int)(id - nodeid), nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003093 return LY_ENOTFOUND;
3094 }
3095 current_nodetype = ctx_node->nodetype;
3096
3097 if (current_nodetype == LYS_NOTIF) {
3098 (*result_flag) |= LYS_COMPILE_NOTIFICATION;
3099 } else if (current_nodetype == LYS_INPUT) {
3100 (*result_flag) |= LYS_COMPILE_RPC_INPUT;
3101 } else if (current_nodetype == LYS_OUTPUT) {
3102 (*result_flag) |= LYS_COMPILE_RPC_OUTPUT;
3103 }
3104
3105 if (!*id || (nodeid_len && ((size_t)(id - nodeid) >= nodeid_len))) {
3106 break;
3107 }
3108 if (*id != '/') {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003109 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003110 "Invalid %s-schema-nodeid value \"%.*s\" - missing \"/\" as node-identifier separator.",
Radek Krejci422afb12021-03-04 16:38:16 +01003111 nodeid_type, (int)(id - nodeid + 1), nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003112 return LY_EVALID;
3113 }
3114 ++id;
3115 }
3116
3117 if (ret == LY_SUCCESS) {
3118 *target = ctx_node;
3119 if (nodetype && !(current_nodetype & nodetype)) {
3120 return LY_EDENIED;
3121 }
3122 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003123 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003124 "Invalid %s-schema-nodeid value \"%.*s\" - unexpected end of expression.",
Radek Krejci422afb12021-03-04 16:38:16 +01003125 nodeid_type, (int)(nodeid_len ? nodeid_len : strlen(nodeid)), nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003126 }
3127
3128 return ret;
3129}
3130
3131/**
3132 * @brief Compile information about list's uniques.
3133 * @param[in] ctx Compile context.
3134 * @param[in] uniques Sized array list of unique statements.
3135 * @param[in] list Compiled list where the uniques are supposed to be resolved and stored.
3136 * @return LY_ERR value.
3137 */
3138static LY_ERR
3139lys_compile_node_list_unique(struct lysc_ctx *ctx, struct lysp_qname *uniques, struct lysc_node_list *list)
3140{
3141 LY_ERR ret = LY_SUCCESS;
3142 struct lysc_node_leaf **key, ***unique;
3143 struct lysc_node *parent;
3144 const char *keystr, *delim;
3145 size_t len;
3146 LY_ARRAY_COUNT_TYPE v;
3147 int8_t config; /* -1 - not yet seen; 0 - LYS_CONFIG_R; 1 - LYS_CONFIG_W */
3148 uint16_t flags;
3149
3150 LY_ARRAY_FOR(uniques, v) {
3151 config = -1;
3152 LY_ARRAY_NEW_RET(ctx->ctx, list->uniques, unique, LY_EMEM);
3153 keystr = uniques[v].str;
3154 while (keystr) {
3155 delim = strpbrk(keystr, " \t\n");
3156 if (delim) {
3157 len = delim - keystr;
3158 while (isspace(*delim)) {
3159 ++delim;
3160 }
3161 } else {
3162 len = strlen(keystr);
3163 }
3164
3165 /* unique node must be present */
3166 LY_ARRAY_NEW_RET(ctx->ctx, *unique, key, LY_EMEM);
Michal Vasko56d8da82021-12-16 15:41:30 +01003167 ret = lysc_resolve_schema_nodeid(ctx, keystr, len, &list->node, LY_VALUE_SCHEMA, (void *)uniques[v].mod,
3168 LYS_LEAF, (const struct lysc_node **)key, &flags);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003169 if (ret != LY_SUCCESS) {
3170 if (ret == LY_EDENIED) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003171 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003172 "Unique's descendant-schema-nodeid \"%.*s\" refers to %s node instead of a leaf.",
Radek Krejci422afb12021-03-04 16:38:16 +01003173 (int)len, keystr, lys_nodetype2str((*key)->nodetype));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003174 }
3175 return LY_EVALID;
3176 } else if (flags) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003177 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003178 "Unique's descendant-schema-nodeid \"%.*s\" refers into %s node.",
Radek Krejci422afb12021-03-04 16:38:16 +01003179 (int)len, keystr, flags & LYS_IS_NOTIF ? "notification" : "RPC/action");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003180 return LY_EVALID;
3181 }
3182
3183 /* all referenced leafs must be of the same config type */
3184 if ((config != -1) && ((((*key)->flags & LYS_CONFIG_W) && (config == 0)) ||
3185 (((*key)->flags & LYS_CONFIG_R) && (config == 1)))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003186 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003187 "Unique statement \"%s\" refers to leaves with different config type.", uniques[v].str);
3188 return LY_EVALID;
3189 } else if ((*key)->flags & LYS_CONFIG_W) {
3190 config = 1;
3191 } else { /* LYS_CONFIG_R */
3192 config = 0;
3193 }
3194
3195 /* we forbid referencing nested lists because it is unspecified what instance of such a list to use */
3196 for (parent = (*key)->parent; parent != (struct lysc_node *)list; parent = parent->parent) {
3197 if (parent->nodetype == LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003198 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003199 "Unique statement \"%s\" refers to a leaf in nested list \"%s\".", uniques[v].str, parent->name);
3200 return LY_EVALID;
3201 }
3202 }
3203
3204 /* check status */
Michal Vaskoc130e162021-10-19 11:30:00 +02003205 LY_CHECK_RET(lysc_check_status(ctx, list->flags, uniques[v].mod->mod, list->name,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003206 (*key)->flags, (*key)->module, (*key)->name));
3207
3208 /* mark leaf as unique */
3209 (*key)->flags |= LYS_UNIQUE;
3210
3211 /* next unique value in line */
3212 keystr = delim;
3213 }
3214 /* next unique definition */
3215 }
3216
3217 return LY_SUCCESS;
3218}
3219
3220/**
3221 * @brief Compile parsed list node information.
3222 * @param[in] ctx Compile context
3223 * @param[in] pnode Parsed list node.
3224 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
3225 * is enriched with the list-specific information.
3226 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3227 */
3228static LY_ERR
3229lys_compile_node_list(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
3230{
3231 struct lysp_node_list *list_p = (struct lysp_node_list *)pnode;
3232 struct lysc_node_list *list = (struct lysc_node_list *)node;
3233 struct lysp_node *child_p;
Michal Vasko2d6507a2022-03-16 09:40:52 +01003234 struct lysc_node *parent;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003235 struct lysc_node_leaf *key, *prev_key = NULL;
3236 size_t len;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003237 const char *keystr, *delim;
3238 LY_ERR ret = LY_SUCCESS;
3239
3240 list->min = list_p->min;
3241 if (list->min) {
3242 list->flags |= LYS_MAND_TRUE;
3243 }
3244 list->max = list_p->max ? list_p->max : (uint32_t)-1;
3245
3246 LY_LIST_FOR(list_p->child, child_p) {
3247 LY_CHECK_RET(lys_compile_node(ctx, child_p, node, 0, NULL));
3248 }
3249
Michal Vasko5347e3a2020-11-03 17:14:57 +01003250 COMPILE_ARRAY_GOTO(ctx, list_p->musts, list->musts, lys_compile_must, ret, done);
Michal Vaskoc130e162021-10-19 11:30:00 +02003251
3252 /* add must(s) to unres */
3253 ret = lysc_unres_must_add(ctx, node, pnode);
3254 LY_CHECK_GOTO(ret, done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003255
3256 /* keys */
Michal Vasko2d6507a2022-03-16 09:40:52 +01003257 if (list->flags & LYS_CONFIG_W) {
3258 parent = node;
3259 if (ctx->compile_opts & LYS_COMPILE_GROUPING) {
3260 /* compiling individual grouping, we can check this only if there is an explicit config set */
3261 while (parent) {
3262 if (parent->flags & LYS_SET_CONFIG) {
3263 break;
3264 }
3265 parent = parent->parent;
3266 }
3267 }
3268
3269 if (parent && (!list_p->key || !list_p->key[0])) {
3270 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Missing key in list representing configuration data.");
3271 return LY_EVALID;
3272 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003273 }
3274
3275 /* find all the keys (must be direct children) */
3276 keystr = list_p->key;
3277 if (!keystr) {
3278 /* keyless list */
Michal Vaskoe78faec2021-04-08 17:24:43 +02003279 list->flags &= ~LYS_ORDBY_SYSTEM;
3280 list->flags |= LYS_KEYLESS | LYS_ORDBY_USER;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003281 }
3282 while (keystr) {
3283 delim = strpbrk(keystr, " \t\n");
3284 if (delim) {
3285 len = delim - keystr;
3286 while (isspace(*delim)) {
3287 ++delim;
3288 }
3289 } else {
3290 len = strlen(keystr);
3291 }
3292
3293 /* key node must be present */
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01003294 key = (struct lysc_node_leaf *)lys_find_child(node, node->module, keystr, len, LYS_LEAF, LYS_GETNEXT_NOCHOICE);
3295 if (!key) {
Radek Krejci422afb12021-03-04 16:38:16 +01003296 LOGVAL(ctx->ctx, LYVE_REFERENCE, "The list's key \"%.*s\" not found.", (int)len, keystr);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003297 return LY_EVALID;
3298 }
3299 /* keys must be unique */
3300 if (key->flags & LYS_KEY) {
3301 /* the node was already marked as a key */
Radek Krejci422afb12021-03-04 16:38:16 +01003302 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Duplicated key identifier \"%.*s\".", (int)len, keystr);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003303 return LY_EVALID;
3304 }
3305
Radek Krejcia6016992021-03-03 10:13:41 +01003306 lysc_update_path(ctx, list->module, key->name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003307 /* key must have the same config flag as the list itself */
3308 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Michal Vasko6b8c5102021-10-19 11:29:32 +02003309 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Key of a configuration list must not be a state leaf.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003310 return LY_EVALID;
3311 }
3312 if (ctx->pmod->version < LYS_VERSION_1_1) {
3313 /* YANG 1.0 denies key to be of empty type */
3314 if (key->type->basetype == LY_TYPE_EMPTY) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003315 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003316 "List's key cannot be of \"empty\" type until it is in YANG 1.1 module.");
3317 return LY_EVALID;
3318 }
3319 } else {
3320 /* when and if-feature are illegal on list keys */
3321 if (key->when) {
Michal Vasko6b8c5102021-10-19 11:29:32 +02003322 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "List's key must not have any \"when\" statement.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003323 return LY_EVALID;
3324 }
Michal Vasko93b4ab92022-05-13 12:29:59 +02003325 /* unable to check if-features but compilation would fail if disabled */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003326 }
3327
3328 /* check status */
Michal Vaskoc636ea42022-09-16 10:20:31 +02003329 LY_CHECK_RET(lysc_check_status(ctx, list->flags, list->module, list->name, key->flags, key->module, key->name));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003330
3331 /* ignore default values of the key */
3332 if (key->dflt) {
3333 key->dflt->realtype->plugin->free(ctx->ctx, key->dflt);
Michal Vaskoc636ea42022-09-16 10:20:31 +02003334 lysc_type_free(&ctx->free_ctx, (struct lysc_type *)key->dflt->realtype);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003335 free(key->dflt);
3336 key->dflt = NULL;
3337 }
3338 /* mark leaf as key */
3339 key->flags |= LYS_KEY;
3340
3341 /* move it to the correct position */
3342 if ((prev_key && ((struct lysc_node *)prev_key != key->prev)) || (!prev_key && key->prev->next)) {
3343 /* fix links in closest previous siblings of the key */
3344 if (key->next) {
3345 key->next->prev = key->prev;
3346 } else {
3347 /* last child */
3348 list->child->prev = key->prev;
3349 }
3350 if (key->prev->next) {
3351 key->prev->next = key->next;
3352 }
3353 /* fix links in the key */
3354 if (prev_key) {
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003355 key->prev = &prev_key->node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003356 key->next = prev_key->next;
3357 } else {
3358 key->prev = list->child->prev;
3359 key->next = list->child;
3360 }
3361 /* fix links in closes future siblings of the key */
3362 if (prev_key) {
3363 if (prev_key->next) {
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003364 prev_key->next->prev = &key->node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003365 } else {
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003366 list->child->prev = &key->node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003367 }
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003368 prev_key->next = &key->node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003369 } else {
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003370 list->child->prev = &key->node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003371 }
3372 /* fix links in parent */
3373 if (!key->prev->next) {
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003374 list->child = &key->node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003375 }
3376 }
3377
3378 /* next key value */
3379 prev_key = key;
3380 keystr = delim;
3381 lysc_update_path(ctx, NULL, NULL);
3382 }
3383
Michal Vasko95f736c2022-06-08 12:03:31 +02003384 /* connect any augments */
3385 LY_CHECK_GOTO(ret = lys_compile_node_augments(ctx, node), done);
3386
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003387 /* uniques */
3388 if (list_p->uniques) {
3389 LY_CHECK_RET(lys_compile_node_list_unique(ctx, list_p->uniques, list));
3390 }
3391
Radek Krejci2a9fc652021-01-22 17:44:34 +01003392 LY_LIST_FOR((struct lysp_node *)list_p->actions, child_p) {
3393 ret = lys_compile_node(ctx, child_p, node, 0, NULL);
3394 LY_CHECK_GOTO(ret, done);
3395 }
3396 LY_LIST_FOR((struct lysp_node *)list_p->notifs, child_p) {
3397 ret = lys_compile_node(ctx, child_p, node, 0, NULL);
3398 LY_CHECK_GOTO(ret, done);
3399 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003400
3401 /* checks */
3402 if (list->min > list->max) {
Michal Vasko6b8c5102021-10-19 11:29:32 +02003403 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "List min-elements %u is bigger than max-elements %u.", list->min, list->max);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003404 return LY_EVALID;
3405 }
3406
3407done:
3408 return ret;
3409}
3410
3411/**
3412 * @brief Do some checks and set the default choice's case.
3413 *
3414 * Selects (and stores into ::lysc_node_choice#dflt) the default case and set LYS_SET_DFLT flag on it.
3415 *
3416 * @param[in] ctx Compile context.
3417 * @param[in] dflt Name of the default branch. Can even contain a prefix.
3418 * @param[in,out] ch The compiled choice node, its dflt member is filled to point to the default case node of the choice.
3419 * @return LY_ERR value.
3420 */
3421static LY_ERR
3422lys_compile_node_choice_dflt(struct lysc_ctx *ctx, struct lysp_qname *dflt, struct lysc_node_choice *ch)
3423{
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003424 struct lysc_node *iter;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003425 const struct lys_module *mod;
3426 const char *prefix = NULL, *name;
3427 size_t prefix_len = 0;
3428
3429 /* could use lys_parse_nodeid(), but it checks syntax which is already done in this case by the parsers */
3430 name = strchr(dflt->str, ':');
3431 if (name) {
3432 prefix = dflt->str;
3433 prefix_len = name - prefix;
3434 ++name;
3435 } else {
3436 name = dflt->str;
3437 }
3438 if (prefix) {
Radek Krejci8df109d2021-04-23 12:19:08 +02003439 mod = ly_resolve_prefix(ctx->ctx, prefix, prefix_len, LY_VALUE_SCHEMA, (void *)dflt->mod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003440 if (!mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003441 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Default case prefix \"%.*s\" not found "
Radek Krejci422afb12021-03-04 16:38:16 +01003442 "in imports of \"%s\".", (int)prefix_len, prefix, LYSP_MODULE_NAME(dflt->mod));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003443 return LY_EVALID;
3444 }
3445 } else {
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003446 mod = ch->module;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003447 }
3448
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003449 ch->dflt = (struct lysc_node_case *)lys_find_child(&ch->node, mod, name, 0, LYS_CASE, LYS_GETNEXT_WITHCASE);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003450 if (!ch->dflt) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003451 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003452 "Default case \"%s\" not found.", dflt->str);
3453 return LY_EVALID;
3454 }
3455
3456 /* no mandatory nodes directly under the default case */
3457 LY_LIST_FOR(ch->dflt->child, iter) {
3458 if (iter->parent != (struct lysc_node *)ch->dflt) {
3459 break;
3460 }
3461 if (iter->flags & LYS_MAND_TRUE) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003462 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003463 "Mandatory node \"%s\" under the default case \"%s\".", iter->name, dflt->str);
3464 return LY_EVALID;
3465 }
3466 }
3467
3468 if (ch->flags & LYS_MAND_TRUE) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003469 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Invalid mandatory choice with a default case.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003470 return LY_EVALID;
3471 }
3472
3473 ch->dflt->flags |= LYS_SET_DFLT;
3474 return LY_SUCCESS;
3475}
3476
3477LY_ERR
3478lys_compile_node_choice_child(struct lysc_ctx *ctx, struct lysp_node *child_p, struct lysc_node *node,
3479 struct ly_set *child_set)
3480{
3481 LY_ERR ret = LY_SUCCESS;
3482 struct lysp_node *child_p_next = child_p->next;
3483 struct lysp_node_case *cs_p;
Michal Vasko4eb49d52022-02-17 15:05:00 +01003484 struct lysc_node_case *cs_c;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003485
3486 if (child_p->nodetype == LYS_CASE) {
3487 /* standard case under choice */
3488 ret = lys_compile_node(ctx, child_p, node, 0, child_set);
3489 } else {
Michal Vaskoa6cf80a2021-06-25 07:42:19 +02003490 /* we need the implicit case first, so create a fake parsed (shorthand) case */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003491 cs_p = calloc(1, sizeof *cs_p);
3492 cs_p->nodetype = LYS_CASE;
Michal Vaskoa6cf80a2021-06-25 07:42:19 +02003493 DUP_STRING_GOTO(ctx->ctx, child_p->name, cs_p->name, ret, revert_sh_case);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003494 cs_p->child = child_p;
3495
3496 /* make the child the only case child */
3497 child_p->next = NULL;
3498
3499 /* compile it normally */
Michal Vaskoa6cf80a2021-06-25 07:42:19 +02003500 LY_CHECK_GOTO(ret = lys_compile_node(ctx, (struct lysp_node *)cs_p, node, 0, child_set), revert_sh_case);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003501
Michal Vaskoa6cf80a2021-06-25 07:42:19 +02003502 if (((struct lysc_node_choice *)node)->cases) {
Michal Vasko4eb49d52022-02-17 15:05:00 +01003503 /* find our case node */
3504 cs_c = (struct lysc_node_case *)((struct lysc_node_choice *)node)->cases;
3505 while (cs_c->name != cs_p->name) {
3506 cs_c = (struct lysc_node_case *)cs_c->next;
3507 assert(cs_c);
Michal Vaskoa6cf80a2021-06-25 07:42:19 +02003508 }
aPiecekaa320c92021-05-21 07:34:24 +02003509
Michal Vasko4eb49d52022-02-17 15:05:00 +01003510 if (ctx->ctx->flags & LY_CTX_SET_PRIV_PARSED) {
3511 /* compiled case node cannot point to his corresponding parsed node
3512 * because it exists temporarily so it must be set to NULL
3513 */
3514 assert(cs_c->priv == cs_p);
3515 cs_c->priv = NULL;
3516 }
3517
3518 /* status is copied from his child and not from his parent as usual. */
3519 if (cs_c->child) {
3520 cs_c->flags &= ~LYS_STATUS_MASK;
3521 cs_c->flags |= (LYS_STATUS_MASK & cs_c->child->flags);
Michal Vaskoa6cf80a2021-06-25 07:42:19 +02003522 }
3523 } /* else it was removed by a deviation */
aPiecekaa320c92021-05-21 07:34:24 +02003524
Michal Vaskoa6cf80a2021-06-25 07:42:19 +02003525revert_sh_case:
3526 /* free the parsed shorthand case and correct pointers back */
aPiecekaa320c92021-05-21 07:34:24 +02003527 cs_p->child = NULL;
Michal Vaskoc636ea42022-09-16 10:20:31 +02003528 lysp_node_free(&ctx->free_ctx, (struct lysp_node *)cs_p);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003529 child_p->next = child_p_next;
3530 }
3531
3532 return ret;
3533}
3534
3535/**
3536 * @brief Compile parsed choice node information.
3537 *
3538 * @param[in] ctx Compile context
3539 * @param[in] pnode Parsed choice node.
3540 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
3541 * is enriched with the choice-specific information.
3542 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3543 */
3544static LY_ERR
3545lys_compile_node_choice(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
3546{
3547 struct lysp_node_choice *ch_p = (struct lysp_node_choice *)pnode;
3548 struct lysc_node_choice *ch = (struct lysc_node_choice *)node;
3549 struct lysp_node *child_p;
3550 LY_ERR ret = LY_SUCCESS;
3551
3552 assert(node->nodetype == LYS_CHOICE);
3553
3554 LY_LIST_FOR(ch_p->child, child_p) {
Michal Vasko95f736c2022-06-08 12:03:31 +02003555 LY_CHECK_GOTO(ret = lys_compile_node_choice_child(ctx, child_p, node, NULL), done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003556 }
3557
Michal Vasko95f736c2022-06-08 12:03:31 +02003558 /* connect any augments */
3559 LY_CHECK_GOTO(ret = lys_compile_node_augments(ctx, node), done);
3560
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003561 /* default branch */
3562 if (ch_p->dflt.str) {
Michal Vasko95f736c2022-06-08 12:03:31 +02003563 LY_CHECK_GOTO(ret = lys_compile_node_choice_dflt(ctx, &ch_p->dflt, ch), done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003564 }
3565
Michal Vasko95f736c2022-06-08 12:03:31 +02003566done:
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003567 return ret;
3568}
3569
3570/**
3571 * @brief Compile parsed anydata or anyxml node information.
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003572 *
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003573 * @param[in] ctx Compile context
3574 * @param[in] pnode Parsed anydata or anyxml node.
3575 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
3576 * is enriched with the any-specific information.
3577 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3578 */
3579static LY_ERR
3580lys_compile_node_any(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
3581{
3582 struct lysp_node_anydata *any_p = (struct lysp_node_anydata *)pnode;
3583 struct lysc_node_anydata *any = (struct lysc_node_anydata *)node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003584 LY_ERR ret = LY_SUCCESS;
3585
Michal Vasko5347e3a2020-11-03 17:14:57 +01003586 COMPILE_ARRAY_GOTO(ctx, any_p->musts, any->musts, lys_compile_must, ret, done);
Michal Vaskoc130e162021-10-19 11:30:00 +02003587
3588 /* add must(s) to unres */
3589 ret = lysc_unres_must_add(ctx, node, pnode);
3590 LY_CHECK_GOTO(ret, done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003591
Radek Krejci91531e12021-02-08 19:57:54 +01003592 if (any->flags & LYS_CONFIG_W) {
Michal Vasko5676f4e2021-04-06 17:14:45 +02003593 LOGVRB("Use of %s to define configuration data is not recommended. %s",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003594 ly_stmt2str(any->nodetype == LYS_ANYDATA ? LY_STMT_ANYDATA : LY_STMT_ANYXML), ctx->path);
3595 }
3596done:
3597 return ret;
3598}
3599
3600/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003601 * @brief Prepare the case structure in choice node for the new data node.
3602 *
3603 * It is able to handle implicit as well as explicit cases and the situation when the case has multiple data nodes and the case was already
3604 * created in the choice when the first child was processed.
3605 *
3606 * @param[in] ctx Compile context.
3607 * @param[in] pnode Node image from the parsed tree. If the case is explicit, it is the LYS_CASE node, but in case of implicit case,
3608 * it is the LYS_CHOICE, LYS_AUGMENT or LYS_GROUPING node.
3609 * @param[in] ch The compiled choice structure where the new case structures are created (if needed).
3610 * @param[in] child The new data node being part of a case (no matter if explicit or implicit).
3611 * @return The case structure where the child node belongs to, NULL in case of error. Note that the child is not connected into the siblings list,
3612 * it is linked from the case structure only in case it is its first child.
3613 */
3614static LY_ERR
3615lys_compile_node_case(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
3616{
Michal Vasko95f736c2022-06-08 12:03:31 +02003617 LY_ERR ret = LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003618 struct lysp_node *child_p;
3619 struct lysp_node_case *cs_p = (struct lysp_node_case *)pnode;
3620
3621 if (pnode->nodetype & (LYS_CHOICE | LYS_AUGMENT | LYS_GROUPING)) {
3622 /* we have to add an implicit case node into the parent choice */
3623 } else if (pnode->nodetype == LYS_CASE) {
3624 /* explicit parent case */
3625 LY_LIST_FOR(cs_p->child, child_p) {
Michal Vasko95f736c2022-06-08 12:03:31 +02003626 LY_CHECK_GOTO(ret = lys_compile_node(ctx, child_p, node, 0, NULL), done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003627 }
3628 } else {
3629 LOGINT_RET(ctx->ctx);
3630 }
3631
Michal Vasko95f736c2022-06-08 12:03:31 +02003632 /* connect any augments */
3633 LY_CHECK_GOTO(ret = lys_compile_node_augments(ctx, node), done);
3634
3635done:
3636 return ret;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003637}
3638
3639void
3640lys_compile_mandatory_parents(struct lysc_node *parent, ly_bool add)
3641{
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003642 const struct lysc_node *iter;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003643
3644 if (add) { /* set flag */
3645 for ( ; parent && parent->nodetype == LYS_CONTAINER && !(parent->flags & LYS_MAND_TRUE) && !(parent->flags & LYS_PRESENCE);
3646 parent = parent->parent) {
3647 parent->flags |= LYS_MAND_TRUE;
3648 }
3649 } else { /* unset flag */
3650 for ( ; parent && parent->nodetype == LYS_CONTAINER && (parent->flags & LYS_MAND_TRUE); parent = parent->parent) {
Michal Vasko544e58a2021-01-28 14:33:41 +01003651 for (iter = lysc_node_child(parent); iter; iter = iter->next) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003652 if (iter->flags & LYS_MAND_TRUE) {
3653 /* there is another mandatory node */
3654 return;
3655 }
3656 }
3657 /* unset mandatory flag - there is no mandatory children in the non-presence container */
3658 parent->flags &= ~LYS_MAND_TRUE;
3659 }
3660 }
3661}
3662
3663/**
Radek Krejciabd33a42021-01-20 17:18:59 +01003664 * @brief Get the grouping with the specified name from given groupings sized array.
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003665 *
3666 * @param[in] node Linked list of nodes with groupings.
Radek Krejciabd33a42021-01-20 17:18:59 +01003667 * @param[in] name Name of the grouping to find,
3668 * @return NULL when there is no grouping with the specified name
3669 * @return Pointer to the grouping of the specified @p name.
3670 */
Radek Krejci2a9fc652021-01-22 17:44:34 +01003671static struct lysp_node_grp *
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003672match_grouping(const struct lysp_node_grp *node, const char *name)
Radek Krejciabd33a42021-01-20 17:18:59 +01003673{
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003674 LY_LIST_FOR(node, node) {
3675 if ((node->nodetype == LYS_GROUPING) && !strcmp(node->name, name)) {
3676 return (struct lysp_node_grp *)node;
Radek Krejciabd33a42021-01-20 17:18:59 +01003677 }
3678 }
3679
3680 return NULL;
3681}
3682
3683/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003684 * @brief Find grouping for a uses.
3685 *
3686 * @param[in] ctx Compile context.
3687 * @param[in] uses_p Parsed uses node.
3688 * @param[out] gpr_p Found grouping on success.
3689 * @param[out] grp_pmod Module of @p grp_p on success.
3690 * @return LY_ERR value.
3691 */
3692static LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01003693lys_compile_uses_find_grouping(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, struct lysp_node_grp **grp_p,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003694 struct lysp_module **grp_pmod)
3695{
3696 struct lysp_node *pnode;
Radek Krejci2a9fc652021-01-22 17:44:34 +01003697 struct lysp_node_grp *grp;
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003698 struct lysp_node_grp * const *ext_grp;
Radek Krejciabd33a42021-01-20 17:18:59 +01003699 LY_ARRAY_COUNT_TYPE u;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003700 const char *id, *name, *prefix, *local_pref;
3701 size_t prefix_len, name_len;
3702 struct lysp_module *pmod, *found = NULL;
Michal Vaskob2d55bf2020-11-02 15:42:43 +01003703 const struct lys_module *mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003704
3705 *grp_p = NULL;
3706 *grp_pmod = NULL;
3707
3708 /* search for the grouping definition */
3709 id = uses_p->name;
3710 LY_CHECK_RET(ly_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len), LY_EVALID);
3711 local_pref = ctx->pmod->is_submod ? ((struct lysp_submodule *)ctx->pmod)->prefix : ctx->pmod->mod->prefix;
3712 if (!prefix || !ly_strncmp(local_pref, prefix, prefix_len)) {
3713 /* current module, search local groupings first */
Radek Krejciabd33a42021-01-20 17:18:59 +01003714 pmod = ctx->pmod->mod->parsed; /* make sure that we will start in main_module, not submodule */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003715 for (pnode = uses_p->parent; !found && pnode; pnode = pnode->parent) {
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003716 if ((grp = match_grouping(lysp_node_groupings(pnode), name))) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01003717 found = ctx->pmod;
3718 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003719 }
3720 }
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003721
3722 /* if in an extension, search possible groupings in it */
3723 if (ctx->ext) {
3724 ext_grp = lys_compile_ext_instance_get_storage(ctx->ext, LY_STMT_GROUPING);
3725 if (ext_grp && (grp = match_grouping(*ext_grp, name))) {
3726 found = ctx->pmod;
3727 }
3728 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003729 } else {
3730 /* foreign module, find it first */
Radek Krejci8df109d2021-04-23 12:19:08 +02003731 mod = ly_resolve_prefix(ctx->ctx, prefix, prefix_len, LY_VALUE_SCHEMA, ctx->pmod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003732 if (!mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003733 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003734 "Invalid prefix used for grouping reference.", uses_p->name);
3735 return LY_EVALID;
3736 }
3737 pmod = mod->parsed;
3738 }
3739
3740 if (!found) {
3741 /* search in top-level groupings of the main module ... */
Radek Krejciabd33a42021-01-20 17:18:59 +01003742 if ((grp = match_grouping(pmod->groupings, name))) {
3743 found = pmod;
3744 } else {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003745 /* ... and all the submodules */
3746 LY_ARRAY_FOR(pmod->includes, u) {
Radek Krejciabd33a42021-01-20 17:18:59 +01003747 if ((grp = match_grouping(pmod->includes[u].submodule->groupings, name))) {
3748 found = (struct lysp_module *)pmod->includes[u].submodule;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003749 break;
3750 }
3751 }
3752 }
3753 }
3754 if (!found) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003755 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003756 "Grouping \"%s\" referenced by a uses statement not found.", uses_p->name);
3757 return LY_EVALID;
3758 }
3759
Michal Vasko7c565922021-06-10 14:58:27 +02003760 if (!(ctx->compile_opts & LYS_COMPILE_GROUPING)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003761 /* remember that the grouping is instantiated to avoid its standalone validation */
3762 grp->flags |= LYS_USED_GRP;
3763 }
3764
3765 *grp_p = grp;
3766 *grp_pmod = found;
3767 return LY_SUCCESS;
3768}
3769
3770/**
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003771 * @brief Compile uses grouping children.
3772 *
3773 * @param[in] ctx Compile context.
3774 * @param[in] uses_p Parsed uses.
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003775 * @param[in] parent_status Parent status flags to inherit.
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003776 * @param[in] child First grouping child to compile.
3777 * @param[in] grp_mod Grouping parsed module.
3778 * @param[in] parent Uses compiled parent, may be NULL if top-level.
3779 * @param[in,out] child_set Set of all compiled child nodes.
3780 * @param[in] child_unres_disabled Whether the children are to be put into unres disabled set or not.
3781 * @return LY_SUCCESS on success.
3782 * @return LY_EVALID on failure.
3783 */
3784static LY_ERR
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003785lys_compile_uses_children(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, uint16_t parent_status,
3786 struct lysp_node *child, struct lysp_module *grp_mod, struct lysc_node *parent, struct ly_set *child_set,
3787 ly_bool child_unres_disabled)
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003788{
3789 LY_ERR rc = LY_SUCCESS;
3790 struct lysp_module *mod_old = ctx->pmod;
3791 uint32_t child_i, opt_prev = ctx->compile_opts;
3792 ly_bool enabled;
3793 struct lysp_node *pnode;
3794 struct lysc_node *node;
3795 struct lysc_when *when_shared = NULL;
3796
3797 assert(child_set);
3798
Michal Vasko5940c302022-07-14 13:54:38 +02003799 child_i = child_set->count;
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003800 LY_LIST_FOR(child, pnode) {
3801 /* compile the nodes with their parsed (grouping) module */
3802 ctx->pmod = grp_mod;
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003803 LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, parent, &parent_status, child_set), cleanup);
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003804
3805 /* eval if-features again for the rest of this node processing */
3806 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
3807 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
3808 ctx->compile_opts |= LYS_COMPILE_DISABLED;
3809 }
3810
3811 /* restore the parsed module */
3812 ctx->pmod = mod_old;
3813
3814 /* since the uses node is not present in the compiled tree, we need to pass some of its
3815 * statements to all its children */
3816 while (child_i < child_set->count) {
3817 node = child_set->snodes[child_i];
3818
3819 if (uses_p->when) {
3820 /* pass uses when to all the children */
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003821 rc = lys_compile_when(ctx, uses_p->when, parent_status, parent, lysc_data_node(parent), node, &when_shared);
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003822 LY_CHECK_GOTO(rc, cleanup);
3823 }
3824
3825 if (child_unres_disabled) {
3826 /* child is disabled by the uses if-features */
3827 ly_set_add(&ctx->unres->disabled, node, 1, NULL);
3828 }
3829
3830 /* child processed */
3831 ++child_i;
3832 }
3833
3834 /* next iter */
3835 ctx->compile_opts = opt_prev;
3836 }
3837
3838cleanup:
3839 ctx->compile_opts = opt_prev;
3840 return rc;
3841}
3842
3843/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003844 * @brief Compile parsed uses statement - resolve target grouping and connect its content into parent.
3845 * If present, also apply uses's modificators.
3846 *
3847 * @param[in] ctx Compile context
3848 * @param[in] uses_p Parsed uses schema node.
3849 * @param[in] parent Compiled parent node where the content of the referenced grouping is supposed to be connected. It is
3850 * NULL for top-level nodes, in such a case the module where the node will be connected is taken from
3851 * the compile context.
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003852 * @param[in] inherited_status Explicitly inherited status (from uses/extension instance), if any.
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003853 * @param[in] child_set Optional set of all the compiled children.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003854 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3855 */
3856static LY_ERR
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003857lys_compile_uses(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, struct lysc_node *parent,
3858 const uint16_t *inherited_status, struct ly_set *child_set)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003859{
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003860 LY_ERR rc = LY_SUCCESS;
3861 ly_bool enabled, child_unres_disabled = 0;
3862 uint32_t i, grp_stack_count, opt_prev = ctx->compile_opts;
Radek Krejci2a9fc652021-01-22 17:44:34 +01003863 struct lysp_node_grp *grp = NULL;
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003864 uint16_t uses_flags, parent_flags;
3865 const char *parent_name;
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003866 struct lysp_module *grp_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003867 struct ly_set uses_child_set = {0};
3868
3869 /* find the referenced grouping */
3870 LY_CHECK_RET(lys_compile_uses_find_grouping(ctx, uses_p, &grp, &grp_mod));
3871
3872 /* grouping must not reference themselves - stack in ctx maintains list of groupings currently being applied */
3873 grp_stack_count = ctx->groupings.count;
3874 LY_CHECK_RET(ly_set_add(&ctx->groupings, (void *)grp, 0, NULL));
3875 if (grp_stack_count == ctx->groupings.count) {
3876 /* the target grouping is already in the stack, so we are already inside it -> circular dependency */
Radek Krejci2efc45b2020-12-22 16:25:44 +01003877 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003878 "Grouping \"%s\" references itself through a uses statement.", grp->name);
3879 return LY_EVALID;
3880 }
3881
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003882 /* nodetype checks */
3883 if (grp->actions && (parent && !lysc_node_actions_p(parent))) {
3884 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid child %s \"%s\" of uses parent %s \"%s\" node.",
3885 grp->actions->name, lys_nodetype2str(grp->actions->nodetype),
3886 parent->name, lys_nodetype2str(parent->nodetype));
3887 rc = LY_EVALID;
3888 goto cleanup;
3889 }
3890 if (grp->notifs && (parent && !lysc_node_notifs_p(parent))) {
3891 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid child %s \"%s\" of uses parent %s \"%s\" node.",
3892 grp->notifs->name, lys_nodetype2str(grp->notifs->nodetype),
3893 parent->name, lys_nodetype2str(parent->nodetype));
3894 rc = LY_EVALID;
3895 goto cleanup;
3896 }
3897
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003898 /* check status */
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003899 rc = lysc_check_status(ctx, uses_p->flags, ctx->pmod, uses_p->name, grp->flags, grp_mod, grp->name);
3900 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003901
3902 /* compile any augments and refines so they can be applied during the grouping nodes compilation */
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003903 rc = lys_precompile_uses_augments_refines(ctx, uses_p, parent);
3904 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003905
Michal Vasko10b6b1c2021-07-20 10:43:12 +02003906 /* compile special uses status flags */
3907 uses_flags = uses_p->flags;
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003908 parent_flags = inherited_status ? *inherited_status : (parent ? parent->flags : 0);
3909 parent_name = inherited_status ? "<schema-only-node>" : (parent ? parent->name : NULL);
3910 rc = lys_compile_status(ctx, &uses_flags, "<uses>", parent_flags, parent_name, inherited_status ? 1 : 0);
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003911 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko10b6b1c2021-07-20 10:43:12 +02003912
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003913 /* uses if-features */
3914 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, uses_p->iffeatures, &enabled), cleanup);
3915 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
3916 ctx->compile_opts |= LYS_COMPILE_DISABLED;
3917 child_unres_disabled = 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003918 }
3919
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003920 /* uses grouping children */
3921 rc = lys_compile_uses_children(ctx, uses_p, uses_flags, grp->child, grp_mod, parent,
3922 child_set ? child_set : &uses_child_set, child_unres_disabled);
3923 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003924
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003925 /* uses grouping RPCs/actions */
3926 rc = lys_compile_uses_children(ctx, uses_p, uses_flags, (struct lysp_node *)grp->actions, grp_mod, parent,
3927 child_set ? child_set : &uses_child_set, child_unres_disabled);
3928 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003929
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003930 /* uses grouping notifications */
3931 rc = lys_compile_uses_children(ctx, uses_p, uses_flags, (struct lysp_node *)grp->notifs, grp_mod, parent,
3932 child_set ? child_set : &uses_child_set, child_unres_disabled);
3933 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003934
3935 /* check that all augments were applied */
3936 for (i = 0; i < ctx->uses_augs.count; ++i) {
Michal Vaskod8655722021-01-12 15:20:36 +01003937 if (((struct lysc_augment *)ctx->uses_augs.objs[i])->aug_p->parent != (struct lysp_node *)uses_p) {
3938 /* augment of some parent uses, irrelevant now */
3939 continue;
3940 }
3941
3942 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Augment target node \"%s\" in grouping \"%s\" was not found.",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003943 ((struct lysc_augment *)ctx->uses_augs.objs[i])->nodeid->expr, grp->name);
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003944 rc = LY_ENOTFOUND;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003945 }
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003946 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003947
3948 /* check that all refines were applied */
3949 for (i = 0; i < ctx->uses_rfns.count; ++i) {
Michal Vaskod8655722021-01-12 15:20:36 +01003950 if (((struct lysc_refine *)ctx->uses_rfns.objs[i])->uses_p != uses_p) {
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003951 /* refine of some parent uses, irrelevant now */
Michal Vaskod8655722021-01-12 15:20:36 +01003952 continue;
3953 }
3954
3955 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Refine(s) target node \"%s\" in grouping \"%s\" was not found.",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003956 ((struct lysc_refine *)ctx->uses_rfns.objs[i])->nodeid->expr, grp->name);
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003957 rc = LY_ENOTFOUND;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003958 }
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003959 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003960
3961cleanup:
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003962 /* restore previous context */
3963 ctx->compile_opts = opt_prev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003964
3965 /* remove the grouping from the stack for circular groupings dependency check */
3966 ly_set_rm_index(&ctx->groupings, ctx->groupings.count - 1, NULL);
3967 assert(ctx->groupings.count == grp_stack_count);
3968
3969 ly_set_erase(&uses_child_set, NULL);
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003970 return rc;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003971}
3972
3973static int
3974lys_compile_grouping_pathlog(struct lysc_ctx *ctx, struct lysp_node *node, char **path)
3975{
3976 struct lysp_node *iter;
3977 int len = 0;
3978
3979 *path = NULL;
3980 for (iter = node; iter && len >= 0; iter = iter->parent) {
3981 char *s = *path;
3982 char *id;
3983
3984 switch (iter->nodetype) {
3985 case LYS_USES:
3986 LY_CHECK_RET(asprintf(&id, "{uses='%s'}", iter->name) == -1, -1);
3987 break;
3988 case LYS_GROUPING:
3989 LY_CHECK_RET(asprintf(&id, "{grouping='%s'}", iter->name) == -1, -1);
3990 break;
3991 case LYS_AUGMENT:
3992 LY_CHECK_RET(asprintf(&id, "{augment='%s'}", iter->name) == -1, -1);
3993 break;
3994 default:
3995 id = strdup(iter->name);
3996 break;
3997 }
3998
3999 if (!iter->parent) {
4000 /* print prefix */
4001 len = asprintf(path, "/%s:%s%s", ctx->cur_mod->name, id, s ? s : "");
4002 } else {
4003 /* prefix is the same as in parent */
4004 len = asprintf(path, "/%s%s", id, s ? s : "");
4005 }
4006 free(s);
4007 free(id);
4008 }
4009
4010 if (len < 0) {
4011 free(*path);
4012 *path = NULL;
4013 } else if (len == 0) {
4014 *path = strdup("/");
4015 len = 1;
4016 }
4017 return len;
4018}
4019
4020LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01004021lys_compile_grouping(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysp_node_grp *grp)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004022{
4023 LY_ERR ret;
4024 char *path;
4025 int len;
Michal Vaskoecdc2222022-01-24 08:45:44 +01004026 uint16_t cont_flags;
4027
4028 cont_flags = pnode ? pnode->flags & LYS_FLAGS_COMPILED_MASK : 0;
4029 if (!(cont_flags & LYS_CONFIG_MASK)) {
4030 /* default config */
4031 cont_flags |= LYS_CONFIG_W;
4032 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004033
Michal Vasko8254d852022-04-25 10:05:59 +02004034 /* use grouping status to avoid errors */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004035 struct lysp_node_uses fake_uses = {
4036 .parent = pnode,
4037 .nodetype = LYS_USES,
Michal Vasko8254d852022-04-25 10:05:59 +02004038 .flags = grp->flags & LYS_STATUS_MASK, .next = NULL,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004039 .name = grp->name,
4040 .dsc = NULL, .ref = NULL, .when = NULL, .iffeatures = NULL, .exts = NULL,
4041 .refines = NULL, .augments = NULL
4042 };
4043 struct lysc_node_container fake_container = {
4044 .nodetype = LYS_CONTAINER,
Michal Vaskoecdc2222022-01-24 08:45:44 +01004045 .flags = cont_flags,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004046 .module = ctx->cur_mod,
Michal Vaskobd6de2b2020-10-22 14:45:03 +02004047 .parent = NULL, .next = NULL,
Michal Vasko14ed9cd2021-01-28 14:16:25 +01004048 .prev = &fake_container.node,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004049 .name = "fake",
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01004050 .dsc = NULL, .ref = NULL, .exts = NULL, .when = NULL,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004051 .child = NULL, .musts = NULL, .actions = NULL, .notifs = NULL
4052 };
4053
4054 if (grp->parent) {
4055 LOGWRN(ctx->ctx, "Locally scoped grouping \"%s\" not used.", grp->name);
4056 }
4057
4058 len = lys_compile_grouping_pathlog(ctx, grp->parent, &path);
4059 if (len < 0) {
4060 LOGMEM(ctx->ctx);
4061 return LY_EMEM;
4062 }
4063 strncpy(ctx->path, path, LYSC_CTX_BUFSIZE - 1);
4064 ctx->path_len = (uint32_t)len;
4065 free(path);
4066
4067 lysc_update_path(ctx, NULL, "{grouping}");
4068 lysc_update_path(ctx, NULL, grp->name);
Michal Vaskoedb0fa52022-10-04 10:36:00 +02004069 ret = lys_compile_uses(ctx, &fake_uses, &fake_container.node, NULL, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004070 lysc_update_path(ctx, NULL, NULL);
4071 lysc_update_path(ctx, NULL, NULL);
4072
4073 ctx->path_len = 1;
4074 ctx->path[1] = '\0';
4075
4076 /* cleanup */
Michal Vaskoc636ea42022-09-16 10:20:31 +02004077 lysc_node_container_free(&ctx->free_ctx, &fake_container);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004078
4079 return ret;
4080}
4081
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004082LY_ERR
Michal Vaskoedb0fa52022-10-04 10:36:00 +02004083lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *parent, const uint16_t *inherited_status,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004084 struct ly_set *child_set)
4085{
4086 LY_ERR ret = LY_SUCCESS;
4087 struct lysc_node *node = NULL;
Michal Vasko7c565922021-06-10 14:58:27 +02004088 uint32_t prev_opts = ctx->compile_opts;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004089
4090 LY_ERR (*node_compile_spec)(struct lysc_ctx *, struct lysp_node *, struct lysc_node *);
4091
4092 if (pnode->nodetype != LYS_USES) {
Radek Krejcia6016992021-03-03 10:13:41 +01004093 lysc_update_path(ctx, parent ? parent->module : NULL, pnode->name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004094 } else {
4095 lysc_update_path(ctx, NULL, "{uses}");
4096 lysc_update_path(ctx, NULL, pnode->name);
4097 }
4098
4099 switch (pnode->nodetype) {
4100 case LYS_CONTAINER:
4101 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_container));
4102 node_compile_spec = lys_compile_node_container;
4103 break;
4104 case LYS_LEAF:
4105 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_leaf));
4106 node_compile_spec = lys_compile_node_leaf;
4107 break;
4108 case LYS_LIST:
4109 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_list));
4110 node_compile_spec = lys_compile_node_list;
4111 break;
4112 case LYS_LEAFLIST:
4113 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_leaflist));
4114 node_compile_spec = lys_compile_node_leaflist;
4115 break;
4116 case LYS_CHOICE:
4117 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_choice));
4118 node_compile_spec = lys_compile_node_choice;
4119 break;
4120 case LYS_CASE:
4121 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_case));
4122 node_compile_spec = lys_compile_node_case;
4123 break;
4124 case LYS_ANYXML:
4125 case LYS_ANYDATA:
4126 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_anydata));
4127 node_compile_spec = lys_compile_node_any;
4128 break;
Radek Krejci2a9fc652021-01-22 17:44:34 +01004129 case LYS_RPC:
4130 case LYS_ACTION:
Michal Vasko7c565922021-06-10 14:58:27 +02004131 if (ctx->compile_opts & (LYS_IS_INPUT | LYS_IS_OUTPUT | LYS_IS_NOTIF)) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01004132 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
4133 "Action \"%s\" is placed inside %s.", pnode->name,
Michal Vasko7c565922021-06-10 14:58:27 +02004134 (ctx->compile_opts & LYS_IS_NOTIF) ? "notification" : "another RPC/action");
Radek Krejci2a9fc652021-01-22 17:44:34 +01004135 return LY_EVALID;
4136 }
4137 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_action));
4138 node_compile_spec = lys_compile_node_action;
Michal Vasko7c565922021-06-10 14:58:27 +02004139 ctx->compile_opts |= LYS_COMPILE_NO_CONFIG;
Radek Krejci2a9fc652021-01-22 17:44:34 +01004140 break;
4141 case LYS_NOTIF:
Michal Vasko7c565922021-06-10 14:58:27 +02004142 if (ctx->compile_opts & (LYS_IS_INPUT | LYS_IS_OUTPUT | LYS_IS_NOTIF)) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01004143 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
4144 "Notification \"%s\" is placed inside %s.", pnode->name,
Michal Vasko7c565922021-06-10 14:58:27 +02004145 (ctx->compile_opts & LYS_IS_NOTIF) ? "another notification" : "RPC/action");
Radek Krejci2a9fc652021-01-22 17:44:34 +01004146 return LY_EVALID;
4147 }
4148 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_notif));
4149 node_compile_spec = lys_compile_node_notif;
Michal Vasko7c565922021-06-10 14:58:27 +02004150 ctx->compile_opts |= LYS_COMPILE_NOTIFICATION;
Radek Krejci2a9fc652021-01-22 17:44:34 +01004151 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004152 case LYS_USES:
Michal Vaskoedb0fa52022-10-04 10:36:00 +02004153 ret = lys_compile_uses(ctx, (struct lysp_node_uses *)pnode, parent, inherited_status, child_set);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004154 lysc_update_path(ctx, NULL, NULL);
4155 lysc_update_path(ctx, NULL, NULL);
4156 return ret;
4157 default:
4158 LOGINT(ctx->ctx);
4159 return LY_EINT;
4160 }
4161 LY_CHECK_ERR_RET(!node, LOGMEM(ctx->ctx), LY_EMEM);
4162
Michal Vaskoedb0fa52022-10-04 10:36:00 +02004163 ret = lys_compile_node_(ctx, pnode, parent, inherited_status, node_compile_spec, node, child_set);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004164
Michal Vasko7c565922021-06-10 14:58:27 +02004165 ctx->compile_opts = prev_opts;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01004166 lysc_update_path(ctx, NULL, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004167 return ret;
4168}