blob: 9263c95551a666121015892d3767ff6cc8fd241f [file] [log] [blame]
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001/**
2 * @file schema_compile_node.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Schema compilation of common nodes.
5 *
6 * Copyright (c) 2015 - 2020 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
Christian Hopps32874e12021-05-01 09:43:54 -040015#define _GNU_SOURCE /* asprintf, strdup */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020016
17#include "schema_compile_node.h"
18
19#include <assert.h>
20#include <ctype.h>
21#include <stddef.h>
22#include <stdint.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include "common.h"
28#include "compat.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020029#include "dict.h"
30#include "log.h"
Radek Krejci0aa1f702021-04-01 16:16:19 +020031#include "plugins.h"
Radek Krejci77114102021-03-10 15:21:57 +010032#include "plugins_exts_compile.h"
Radek Krejci04699f02021-03-22 21:50:29 +010033#include "plugins_internal.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020034#include "plugins_types.h"
35#include "schema_compile.h"
36#include "schema_compile_amend.h"
Michal Vasko7b1ad1a2020-11-02 15:41:27 +010037#include "schema_features.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020038#include "set.h"
39#include "tree.h"
40#include "tree_data.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010041#include "tree_edit.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020042#include "tree_schema.h"
43#include "tree_schema_internal.h"
44#include "xpath.h"
45
46static struct lysc_ext_instance *
47lysc_ext_instance_dup(struct ly_ctx *ctx, struct lysc_ext_instance *orig)
48{
49 /* TODO - extensions, increase refcount */
50 (void) ctx;
51 (void) orig;
52 return NULL;
53}
54
55/**
Michal Vaskoc130e162021-10-19 11:30:00 +020056 * @brief Add a node with must(s) to unres.
57 *
58 * @param[in] ctx Compile context.
59 * @param[in] node Compiled node with must(s).
60 * @param[in] pnode Parsed ndoe with must(s).
61 * @return LY_ERR value.
62 */
63static LY_ERR
64lysc_unres_must_add(struct lysc_ctx *ctx, struct lysc_node *node, struct lysp_node *pnode)
65{
66 struct lysc_unres_must *m = NULL;
67 LY_ARRAY_COUNT_TYPE u;
68 struct lysc_must *musts;
69 struct lysp_restr *pmusts;
70 LY_ERR ret;
71
72 /* do not check must(s) in a grouping */
73 if (ctx->compile_opts & LYS_COMPILE_GROUPING) {
74 return LY_SUCCESS;
75 }
76
77 musts = lysc_node_musts(node);
78 pmusts = lysp_node_musts(pnode);
79 assert(LY_ARRAY_COUNT(musts) == LY_ARRAY_COUNT(pmusts));
80
81 if (!musts) {
82 /* no must */
83 return LY_SUCCESS;
84 }
85
86 /* add new unres must */
87 m = calloc(1, sizeof *m);
88 LY_CHECK_ERR_GOTO(!m, ret = LY_EMEM, error);
89 m->node = node;
90
91 /* add must local modules */
92 LY_ARRAY_CREATE_GOTO(ctx->ctx, m->local_mods, LY_ARRAY_COUNT(pmusts), ret, error);
93 LY_ARRAY_FOR(pmusts, u) {
94 m->local_mods[u] = pmusts[u].arg.mod;
95 LY_ARRAY_INCREMENT(m->local_mods);
96 }
97
Michal Vaskoedb0fa52022-10-04 10:36:00 +020098 /* store ext */
99 m->ext = ctx->ext;
100
Michal Vaskoc130e162021-10-19 11:30:00 +0200101 LY_CHECK_ERR_GOTO(ly_set_add(&ctx->unres->musts, m, 1, NULL), ret = LY_EMEM, error);
102
103 return LY_SUCCESS;
104
105error:
106 if (m) {
107 LY_ARRAY_FREE(m->local_mods);
108 free(m);
109 }
110 LOGMEM(ctx->ctx);
111 return ret;
112}
113
114static LY_ERR
115lysc_unres_leafref_add(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, const struct lysp_module *local_mod)
116{
117 struct lysc_unres_leafref *l = NULL;
118 struct ly_set *leafrefs_set;
119 LY_ARRAY_COUNT_TYPE u;
120 int is_lref = 0;
121
122 if (ctx->compile_opts & LYS_COMPILE_GROUPING) {
123 /* do not check leafrefs in groupings */
124 return LY_SUCCESS;
125 }
126
127 /* use special set for disabled leafrefs */
128 leafrefs_set = ctx->compile_opts & LYS_COMPILE_DISABLED ? &ctx->unres->disabled_leafrefs : &ctx->unres->leafrefs;
129
130 if (leaf->type->basetype == LY_TYPE_LEAFREF) {
131 /* leafref */
132 is_lref = 1;
133 } else if (leaf->type->basetype == LY_TYPE_UNION) {
134 /* union with leafrefs */
135 LY_ARRAY_FOR(((struct lysc_type_union *)leaf->type)->types, u) {
136 if (((struct lysc_type_union *)leaf->type)->types[u]->basetype == LY_TYPE_LEAFREF) {
137 is_lref = 1;
138 break;
139 }
140 }
141 }
142
143 if (is_lref) {
144 /* add new unresolved leafref node */
145 l = calloc(1, sizeof *l);
146 LY_CHECK_ERR_RET(!l, LOGMEM(ctx->ctx), LY_EMEM);
147
148 l->node = &leaf->node;
149 l->local_mod = local_mod;
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200150 l->ext = ctx->ext;
Michal Vaskoc130e162021-10-19 11:30:00 +0200151
152 LY_CHECK_ERR_RET(ly_set_add(leafrefs_set, l, 1, NULL), free(l); LOGMEM(ctx->ctx), LY_EMEM);
153 }
154
155 return LY_SUCCESS;
156}
157
158/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200159 * @brief Add/replace a leaf default value in unres.
160 * Can also be used for a single leaf-list default value.
161 *
162 * @param[in] ctx Compile context.
163 * @param[in] leaf Leaf with the default value.
164 * @param[in] dflt Default value to use.
165 * @return LY_ERR value.
166 */
167static LY_ERR
168lysc_unres_leaf_dflt_add(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, struct lysp_qname *dflt)
169{
170 struct lysc_unres_dflt *r = NULL;
171 uint32_t i;
172
Michal Vasko7c565922021-06-10 14:58:27 +0200173 if (ctx->compile_opts & (LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING)) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100174 return LY_SUCCESS;
175 }
176
Michal Vasko405cc9e2020-12-01 12:01:27 +0100177 for (i = 0; i < ctx->unres->dflts.count; ++i) {
178 if (((struct lysc_unres_dflt *)ctx->unres->dflts.objs[i])->leaf == leaf) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200179 /* just replace the default */
Michal Vasko405cc9e2020-12-01 12:01:27 +0100180 r = ctx->unres->dflts.objs[i];
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200181 lysp_qname_free(ctx->ctx, r->dflt);
182 free(r->dflt);
183 break;
184 }
185 }
186 if (!r) {
187 /* add new unres item */
188 r = calloc(1, sizeof *r);
189 LY_CHECK_ERR_RET(!r, LOGMEM(ctx->ctx), LY_EMEM);
190 r->leaf = leaf;
191
Michal Vasko405cc9e2020-12-01 12:01:27 +0100192 LY_CHECK_RET(ly_set_add(&ctx->unres->dflts, r, 1, NULL));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200193 }
194
195 r->dflt = malloc(sizeof *r->dflt);
196 LY_CHECK_GOTO(!r->dflt, error);
197 LY_CHECK_GOTO(lysp_qname_dup(ctx->ctx, r->dflt, dflt), error);
198
199 return LY_SUCCESS;
200
201error:
202 free(r->dflt);
203 LOGMEM(ctx->ctx);
204 return LY_EMEM;
205}
206
207/**
208 * @brief Add/replace a leaf-list default value(s) in unres.
209 *
210 * @param[in] ctx Compile context.
211 * @param[in] llist Leaf-list with the default value.
212 * @param[in] dflts Sized array of the default values.
213 * @return LY_ERR value.
214 */
215static LY_ERR
216lysc_unres_llist_dflts_add(struct lysc_ctx *ctx, struct lysc_node_leaflist *llist, struct lysp_qname *dflts)
217{
218 struct lysc_unres_dflt *r = NULL;
219 uint32_t i;
220
Michal Vasko7c565922021-06-10 14:58:27 +0200221 if (ctx->compile_opts & (LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING)) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100222 return LY_SUCCESS;
223 }
224
Michal Vasko405cc9e2020-12-01 12:01:27 +0100225 for (i = 0; i < ctx->unres->dflts.count; ++i) {
226 if (((struct lysc_unres_dflt *)ctx->unres->dflts.objs[i])->llist == llist) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200227 /* just replace the defaults */
Michal Vasko405cc9e2020-12-01 12:01:27 +0100228 r = ctx->unres->dflts.objs[i];
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200229 lysp_qname_free(ctx->ctx, r->dflt);
230 free(r->dflt);
231 r->dflt = NULL;
232 FREE_ARRAY(ctx->ctx, r->dflts, lysp_qname_free);
233 r->dflts = NULL;
234 break;
235 }
236 }
237 if (!r) {
238 r = calloc(1, sizeof *r);
239 LY_CHECK_ERR_RET(!r, LOGMEM(ctx->ctx), LY_EMEM);
240 r->llist = llist;
241
Michal Vasko405cc9e2020-12-01 12:01:27 +0100242 LY_CHECK_RET(ly_set_add(&ctx->unres->dflts, r, 1, NULL));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200243 }
244
245 DUP_ARRAY(ctx->ctx, dflts, r->dflts, lysp_qname_dup);
246
247 return LY_SUCCESS;
248}
249
250/**
Michal Vaskof4fa90d2021-11-11 15:05:19 +0100251 * @brief Add a bits/enumeration type to unres.
252 *
253 * @param[in] ctx Compile context.
254 * @param[in] leaf Leaf of type bits/enumeration whose disabled items to free.
255 * @return LY_ERR value.
256 */
257static LY_ERR
258lysc_unres_bitenum_add(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf)
259{
260 if (ctx->compile_opts & (LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING)) {
261 /* skip groupings and redundant for disabled nodes */
262 return LY_SUCCESS;
263 }
264
265 LY_CHECK_RET(ly_set_add(&ctx->unres->disabled_bitenums, leaf, 1, NULL));
266
267 return LY_SUCCESS;
268}
269
270/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200271 * @brief Duplicate the compiled pattern structure.
272 *
273 * Instead of duplicating memory, the reference counter in the @p orig is increased.
274 *
275 * @param[in] orig The pattern structure to duplicate.
276 * @return The duplicated structure to use.
277 */
278static struct lysc_pattern *
279lysc_pattern_dup(struct lysc_pattern *orig)
280{
281 ++orig->refcount;
282 return orig;
283}
284
285/**
286 * @brief Duplicate the array of compiled patterns.
287 *
288 * The sized array itself is duplicated, but the pattern structures are just shadowed by increasing their reference counter.
289 *
290 * @param[in] ctx Libyang context for logging.
291 * @param[in] orig The patterns sized array to duplicate.
292 * @return New sized array as a copy of @p orig.
293 * @return NULL in case of memory allocation error.
294 */
295static struct lysc_pattern **
296lysc_patterns_dup(struct ly_ctx *ctx, struct lysc_pattern **orig)
297{
298 struct lysc_pattern **dup = NULL;
299 LY_ARRAY_COUNT_TYPE u;
300
301 assert(orig);
302
303 LY_ARRAY_CREATE_RET(ctx, dup, LY_ARRAY_COUNT(orig), NULL);
304 LY_ARRAY_FOR(orig, u) {
305 dup[u] = lysc_pattern_dup(orig[u]);
306 LY_ARRAY_INCREMENT(dup);
307 }
308 return dup;
309}
310
311/**
312 * @brief Duplicate compiled range structure.
313 *
314 * @param[in] ctx Libyang context for logging.
315 * @param[in] orig The range structure to be duplicated.
316 * @return New compiled range structure as a copy of @p orig.
317 * @return NULL in case of memory allocation error.
318 */
319static struct lysc_range *
320lysc_range_dup(struct ly_ctx *ctx, const struct lysc_range *orig)
321{
322 struct lysc_range *dup;
323 LY_ERR ret;
324
325 assert(orig);
326
327 dup = calloc(1, sizeof *dup);
328 LY_CHECK_ERR_RET(!dup, LOGMEM(ctx), NULL);
329 if (orig->parts) {
330 LY_ARRAY_CREATE_GOTO(ctx, dup->parts, LY_ARRAY_COUNT(orig->parts), ret, cleanup);
Michal Vasko79135ae2020-12-16 10:08:35 +0100331 (*((LY_ARRAY_COUNT_TYPE *)(dup->parts) - 1)) = LY_ARRAY_COUNT(orig->parts);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200332 memcpy(dup->parts, orig->parts, LY_ARRAY_COUNT(dup->parts) * sizeof *dup->parts);
333 }
334 DUP_STRING_GOTO(ctx, orig->eapptag, dup->eapptag, ret, cleanup);
335 DUP_STRING_GOTO(ctx, orig->emsg, dup->emsg, ret, cleanup);
336 dup->exts = lysc_ext_instance_dup(ctx, orig->exts);
337
338 return dup;
339cleanup:
340 free(dup);
341 (void) ret; /* set but not used due to the return type */
342 return NULL;
343}
344
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200345/**
Michal Vaskodfd254d2021-06-24 09:24:59 +0200346 * @brief Compile status information of the given statement.
347 *
348 * To simplify getting status of the node, the flags are set following inheritance rules, so all the nodes
349 * has the status correctly set during the compilation.
350 *
351 * @param[in] ctx Compile context
352 * @param[in,out] stmt_flags Compiled flags to update. If the status was set explicitly, it is already set
353 * in the flags value and we just check the compatibility with the parent's status value.
354 * @param[in] stmt_name Statement name, for logging.
355 * @param[in] parent_flags Flags of the parent node to check/inherit the status value.
356 * @param[in] parent_name Name of the parent node, for logging.
357 * @param[in] inherit_log Whether to print inherit message.
358 * @return LY_ERR value.
359 */
360static LY_ERR
361lys_compile_status(struct lysc_ctx *ctx, uint16_t *stmt_flags, const char *stmt_name, uint16_t parent_flags,
362 const char *parent_name, ly_bool inherit_log)
363{
364 /* status - it is not inherited by specification, but it does not make sense to have
365 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
366 if (!(*stmt_flags & LYS_STATUS_MASK)) {
367 if (parent_flags & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) {
368 if (inherit_log) {
369 LOGVRB("Missing explicit \"%s\" status specified in parent \"%s\", inheriting for \"%s\".",
370 (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete", parent_name, stmt_name);
371 }
372 *stmt_flags |= parent_flags & LYS_STATUS_MASK;
373 } else {
374 *stmt_flags |= LYS_STATUS_CURR;
375 }
376 } else if (parent_flags & LYS_STATUS_MASK) {
377 /* check status compatibility with the parent */
378 if ((parent_flags & LYS_STATUS_MASK) > (*stmt_flags & LYS_STATUS_MASK)) {
379 if (*stmt_flags & LYS_STATUS_CURR) {
380 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
381 "Status \"current\" of \"%s\" is in conflict with the \"%s\" status of parent \"%s\".",
382 stmt_name, (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete", parent_name);
383 } else { /* LYS_STATUS_DEPRC */
384 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
385 "Status \"deprecated\" of \"%s\" is in conflict with the \"obsolete\" status of parent \"%s\".",
386 stmt_name, parent_name);
387 }
388 return LY_EVALID;
389 }
390 }
391 return LY_SUCCESS;
392}
393
394/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200395 * @brief Compile information from the when statement
396 *
397 * @param[in] ctx Compile context.
398 * @param[in] when_p Parsed when structure.
Michal Vaskodfd254d2021-06-24 09:24:59 +0200399 * @param[in] parent_flags Flags of the parsed node with the when statement.
400 * @param[in] compiled_parent Closest compiled parent of the when statement.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200401 * @param[in] ctx_node Context node for the when statement.
402 * @param[out] when Pointer where to store pointer to the created compiled when structure.
403 * @return LY_ERR value.
404 */
405static LY_ERR
Michal Vaskodfd254d2021-06-24 09:24:59 +0200406lys_compile_when_(struct lysc_ctx *ctx, struct lysp_when *when_p, uint16_t parent_flags,
407 const struct lysc_node *compiled_parent, const struct lysc_node *ctx_node, struct lysc_when **when)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200408{
409 LY_ERR ret = LY_SUCCESS;
Radek Krejci8df109d2021-04-23 12:19:08 +0200410 LY_VALUE_FORMAT format;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200411
412 *when = calloc(1, sizeof **when);
413 LY_CHECK_ERR_RET(!(*when), LOGMEM(ctx->ctx), LY_EMEM);
414 (*when)->refcount = 1;
415 LY_CHECK_RET(lyxp_expr_parse(ctx->ctx, when_p->cond, 0, 1, &(*when)->cond));
Radek Krejci0b013302021-03-29 15:22:32 +0200416 LY_CHECK_RET(lyplg_type_prefix_data_new(ctx->ctx, when_p->cond, strlen(when_p->cond),
Radek Krejci8df109d2021-04-23 12:19:08 +0200417 LY_VALUE_SCHEMA, ctx->pmod, &format, (void **)&(*when)->prefixes));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200418 (*when)->context = (struct lysc_node *)ctx_node;
419 DUP_STRING_GOTO(ctx->ctx, when_p->dsc, (*when)->dsc, ret, done);
420 DUP_STRING_GOTO(ctx->ctx, when_p->ref, (*when)->ref, ret, done);
Radek Krejciab430862021-03-02 20:13:40 +0100421 COMPILE_EXTS_GOTO(ctx, when_p->exts, (*when)->exts, (*when), ret, done);
Michal Vaskodfd254d2021-06-24 09:24:59 +0200422 (*when)->flags = (parent_flags & LYS_STATUS_MASK);
423 if (compiled_parent) {
424 LY_CHECK_RET(lys_compile_status(ctx, &(*when)->flags, "when", compiled_parent->flags, compiled_parent->name, 0));
425 } else {
426 LY_CHECK_RET(lys_compile_status(ctx, &(*when)->flags, "when", 0, NULL, 0));
427 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200428
429done:
430 return ret;
431}
432
433LY_ERR
Michal Vaskodfd254d2021-06-24 09:24:59 +0200434lys_compile_when(struct lysc_ctx *ctx, struct lysp_when *when_p, uint16_t parent_flags, const struct lysc_node *compiled_parent,
435 const struct lysc_node *ctx_node, struct lysc_node *node, struct lysc_when **when_c)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200436{
437 struct lysc_when **new_when, ***node_when;
438
439 assert(when_p);
440
441 /* get the when array */
Radek Krejci9a3823e2021-01-27 20:26:46 +0100442 node_when = lysc_node_when_p(node);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200443
444 /* create new when pointer */
445 LY_ARRAY_NEW_RET(ctx->ctx, *node_when, new_when, LY_EMEM);
446 if (!when_c || !(*when_c)) {
447 /* compile when */
Michal Vaskodfd254d2021-06-24 09:24:59 +0200448 LY_CHECK_RET(lys_compile_when_(ctx, when_p, parent_flags, compiled_parent, ctx_node, new_when));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200449
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200450 /* remember the compiled when for sharing */
451 if (when_c) {
452 *when_c = *new_when;
453 }
454 } else {
455 /* use the previously compiled when */
456 ++(*when_c)->refcount;
457 *new_when = *when_c;
Michal Vaskof01fd0b2020-11-23 16:53:07 +0100458 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200459
Michal Vasko6f08e962021-07-23 08:30:47 +0200460 if (!(ctx->compile_opts & LYS_COMPILE_GROUPING)) {
Michal Vaskof01fd0b2020-11-23 16:53:07 +0100461 /* do not check "when" semantics in a grouping, but repeat the check for different node because
462 * of dummy node check */
Michal Vaskoc130e162021-10-19 11:30:00 +0200463 LY_CHECK_RET(ly_set_add(&ctx->unres->whens, node, 0, NULL));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200464 }
465
466 return LY_SUCCESS;
467}
468
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200469LY_ERR
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200470lys_compile_must(struct lysc_ctx *ctx, struct lysp_restr *must_p, struct lysc_must *must)
471{
472 LY_ERR ret = LY_SUCCESS;
Radek Krejci8df109d2021-04-23 12:19:08 +0200473 LY_VALUE_FORMAT format;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200474
475 LY_CHECK_RET(lyxp_expr_parse(ctx->ctx, must_p->arg.str, 0, 1, &must->cond));
Radek Krejci0b013302021-03-29 15:22:32 +0200476 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 +0200477 LY_VALUE_SCHEMA, must_p->arg.mod, &format, (void **)&must->prefixes));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200478 DUP_STRING_GOTO(ctx->ctx, must_p->eapptag, must->eapptag, ret, done);
479 DUP_STRING_GOTO(ctx->ctx, must_p->emsg, must->emsg, ret, done);
480 DUP_STRING_GOTO(ctx->ctx, must_p->dsc, must->dsc, ret, done);
481 DUP_STRING_GOTO(ctx->ctx, must_p->ref, must->ref, ret, done);
Radek Krejciab430862021-03-02 20:13:40 +0100482 COMPILE_EXTS_GOTO(ctx, must_p->exts, must->exts, must, ret, done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200483
484done:
485 return ret;
486}
487
488/**
489 * @brief Validate and normalize numeric value from a range definition.
490 * @param[in] ctx Compile context.
491 * @param[in] basetype Base YANG built-in type of the node connected with the range restriction. Actually only LY_TYPE_DEC64 is important to
492 * allow processing of the fractions. The fraction point is extracted from the value which is then normalize according to given frdigits into
493 * valcopy to allow easy parsing and storing of the value. libyang stores decimal number without the decimal point which is always recovered from
494 * the known fraction-digits value. So, with fraction-digits 2, number 3.14 is stored as 314 and number 1 is stored as 100.
495 * @param[in] frdigits The fraction-digits of the type in case of LY_TYPE_DEC64.
496 * @param[in] value String value of the range boundary.
497 * @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.
498 * @param[out] valcopy NULL-terminated string with the numeric value to parse and store.
499 * @return LY_ERR value - LY_SUCCESS, LY_EMEM, LY_EVALID (no number) or LY_EINVAL (decimal64 not matching fraction-digits value).
500 */
501static LY_ERR
502range_part_check_value_syntax(struct lysc_ctx *ctx, LY_DATA_TYPE basetype, uint8_t frdigits, const char *value,
503 size_t *len, char **valcopy)
504{
505 size_t fraction = 0, size;
506
507 *len = 0;
508
509 assert(value);
510 /* parse value */
511 if (!isdigit(value[*len]) && (value[*len] != '-') && (value[*len] != '+')) {
512 return LY_EVALID;
513 }
514
515 if ((value[*len] == '-') || (value[*len] == '+')) {
516 ++(*len);
517 }
518
519 while (isdigit(value[*len])) {
520 ++(*len);
521 }
522
523 if ((basetype != LY_TYPE_DEC64) || (value[*len] != '.') || !isdigit(value[*len + 1])) {
524 if (basetype == LY_TYPE_DEC64) {
525 goto decimal;
526 } else {
527 *valcopy = strndup(value, *len);
528 return LY_SUCCESS;
529 }
530 }
531 fraction = *len;
532
533 ++(*len);
534 while (isdigit(value[*len])) {
535 ++(*len);
536 }
537
538 if (basetype == LY_TYPE_DEC64) {
539decimal:
540 assert(frdigits);
541 if (fraction && (*len - 1 - fraction > frdigits)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100542 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200543 "Range boundary \"%.*s\" of decimal64 type exceeds defined number (%u) of fraction digits.",
Radek Krejci422afb12021-03-04 16:38:16 +0100544 (int)(*len), value, frdigits);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200545 return LY_EINVAL;
546 }
547 if (fraction) {
548 size = (*len) + (frdigits - ((*len) - 1 - fraction));
549 } else {
550 size = (*len) + frdigits + 1;
551 }
552 *valcopy = malloc(size * sizeof **valcopy);
553 LY_CHECK_ERR_RET(!(*valcopy), LOGMEM(ctx->ctx), LY_EMEM);
554
555 (*valcopy)[size - 1] = '\0';
556 if (fraction) {
557 memcpy(&(*valcopy)[0], &value[0], fraction);
558 memcpy(&(*valcopy)[fraction], &value[fraction + 1], (*len) - 1 - (fraction));
559 memset(&(*valcopy)[(*len) - 1], '0', frdigits - ((*len) - 1 - fraction));
560 } else {
561 memcpy(&(*valcopy)[0], &value[0], *len);
562 memset(&(*valcopy)[*len], '0', frdigits);
563 }
564 }
565 return LY_SUCCESS;
566}
567
568/**
569 * @brief Check that values in range are in ascendant order.
570 * @param[in] unsigned_value Flag to note that we are working with unsigned values.
571 * @param[in] max Flag to distinguish if checking min or max value. min value must be strictly higher than previous,
572 * max can be also equal.
573 * @param[in] value Current value to check.
574 * @param[in] prev_value The last seen value.
575 * @return LY_SUCCESS or LY_EEXIST for invalid order.
576 */
577static LY_ERR
578range_part_check_ascendancy(ly_bool unsigned_value, ly_bool max, int64_t value, int64_t prev_value)
579{
580 if (unsigned_value) {
581 if ((max && ((uint64_t)prev_value > (uint64_t)value)) || (!max && ((uint64_t)prev_value >= (uint64_t)value))) {
582 return LY_EEXIST;
583 }
584 } else {
585 if ((max && (prev_value > value)) || (!max && (prev_value >= value))) {
586 return LY_EEXIST;
587 }
588 }
589 return LY_SUCCESS;
590}
591
592/**
593 * @brief Set min/max value of the range part.
594 * @param[in] ctx Compile context.
595 * @param[in] part Range part structure to fill.
596 * @param[in] max Flag to distinguish if storing min or max value.
597 * @param[in] prev The last seen value to check that all values in range are specified in ascendant order.
598 * @param[in] basetype Type of the value to get know implicit min/max values and other checking rules.
599 * @param[in] first Flag for the first value of the range to avoid ascendancy order.
600 * @param[in] length_restr Flag to distinguish between range and length restrictions. Only for logging.
601 * @param[in] frdigits The fraction-digits value in case of LY_TYPE_DEC64 basetype.
602 * @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.
603 * @param[in,out] value Numeric range value to be stored, if not provided the type's min/max value is set.
604 * @return LY_ERR value - LY_SUCCESS, LY_EDENIED (value brokes type's boundaries), LY_EVALID (not a number),
605 * LY_EEXIST (value is smaller than the previous one), LY_EINVAL (decimal64 value does not corresponds with the
606 * frdigits value), LY_EMEM.
607 */
608static LY_ERR
609range_part_minmax(struct lysc_ctx *ctx, struct lysc_range_part *part, ly_bool max, int64_t prev, LY_DATA_TYPE basetype,
610 ly_bool first, ly_bool length_restr, uint8_t frdigits, struct lysc_range *base_range, const char **value)
611{
612 LY_ERR ret = LY_SUCCESS;
613 char *valcopy = NULL;
Radek Krejci2b18bf12020-11-06 11:20:20 +0100614 size_t len = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200615
616 if (value) {
617 ret = range_part_check_value_syntax(ctx, basetype, frdigits, *value, &len, &valcopy);
618 LY_CHECK_GOTO(ret, finalize);
619 }
620 if (!valcopy && base_range) {
621 if (max) {
622 part->max_64 = base_range->parts[LY_ARRAY_COUNT(base_range->parts) - 1].max_64;
623 } else {
624 part->min_64 = base_range->parts[0].min_64;
625 }
626 if (!first) {
627 ret = range_part_check_ascendancy(basetype <= LY_TYPE_STRING ? 1 : 0, max, max ? part->max_64 : part->min_64, prev);
628 }
629 goto finalize;
630 }
631
632 switch (basetype) {
633 case LY_TYPE_INT8: /* range */
634 if (valcopy) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100635 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 +0200636 } else if (max) {
637 part->max_64 = INT64_C(127);
638 } else {
639 part->min_64 = INT64_C(-128);
640 }
641 if (!ret && !first) {
642 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
643 }
644 break;
645 case LY_TYPE_INT16: /* range */
646 if (valcopy) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100647 ret = ly_parse_int(valcopy, strlen(valcopy), INT64_C(-32768), INT64_C(32767), LY_BASE_DEC,
648 max ? &part->max_64 : &part->min_64);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200649 } else if (max) {
650 part->max_64 = INT64_C(32767);
651 } else {
652 part->min_64 = INT64_C(-32768);
653 }
654 if (!ret && !first) {
655 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
656 }
657 break;
658 case LY_TYPE_INT32: /* range */
659 if (valcopy) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100660 ret = ly_parse_int(valcopy, strlen(valcopy), INT64_C(-2147483648), INT64_C(2147483647), LY_BASE_DEC,
661 max ? &part->max_64 : &part->min_64);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200662 } else if (max) {
663 part->max_64 = INT64_C(2147483647);
664 } else {
665 part->min_64 = INT64_C(-2147483648);
666 }
667 if (!ret && !first) {
668 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
669 }
670 break;
671 case LY_TYPE_INT64: /* range */
672 case LY_TYPE_DEC64: /* range */
673 if (valcopy) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100674 ret = ly_parse_int(valcopy, strlen(valcopy), INT64_C(-9223372036854775807) - INT64_C(1), INT64_C(9223372036854775807),
675 LY_BASE_DEC, max ? &part->max_64 : &part->min_64);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200676 } else if (max) {
677 part->max_64 = INT64_C(9223372036854775807);
678 } else {
679 part->min_64 = INT64_C(-9223372036854775807) - INT64_C(1);
680 }
681 if (!ret && !first) {
682 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
683 }
684 break;
685 case LY_TYPE_UINT8: /* range */
686 if (valcopy) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100687 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 +0200688 } else if (max) {
689 part->max_u64 = UINT64_C(255);
690 } else {
691 part->min_u64 = UINT64_C(0);
692 }
693 if (!ret && !first) {
694 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
695 }
696 break;
697 case LY_TYPE_UINT16: /* range */
698 if (valcopy) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100699 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 +0200700 } else if (max) {
701 part->max_u64 = UINT64_C(65535);
702 } else {
703 part->min_u64 = UINT64_C(0);
704 }
705 if (!ret && !first) {
706 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
707 }
708 break;
709 case LY_TYPE_UINT32: /* range */
710 if (valcopy) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100711 ret = ly_parse_uint(valcopy, strlen(valcopy), UINT64_C(4294967295), LY_BASE_DEC,
712 max ? &part->max_u64 : &part->min_u64);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200713 } else if (max) {
714 part->max_u64 = UINT64_C(4294967295);
715 } else {
716 part->min_u64 = UINT64_C(0);
717 }
718 if (!ret && !first) {
719 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
720 }
721 break;
722 case LY_TYPE_UINT64: /* range */
723 case LY_TYPE_STRING: /* length */
724 case LY_TYPE_BINARY: /* length */
725 if (valcopy) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100726 ret = ly_parse_uint(valcopy, strlen(valcopy), UINT64_C(18446744073709551615), LY_BASE_DEC,
727 max ? &part->max_u64 : &part->min_u64);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200728 } else if (max) {
729 part->max_u64 = UINT64_C(18446744073709551615);
730 } else {
731 part->min_u64 = UINT64_C(0);
732 }
733 if (!ret && !first) {
734 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
735 }
736 break;
737 default:
738 LOGINT(ctx->ctx);
739 ret = LY_EINT;
740 }
741
742finalize:
743 if (ret == LY_EDENIED) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100744 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200745 "Invalid %s restriction - value \"%s\" does not fit the type limitations.",
746 length_restr ? "length" : "range", valcopy ? valcopy : *value);
747 } else if (ret == LY_EVALID) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100748 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200749 "Invalid %s restriction - invalid value \"%s\".",
750 length_restr ? "length" : "range", valcopy ? valcopy : *value);
751 } else if (ret == LY_EEXIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100752 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200753 "Invalid %s restriction - values are not in ascending order (%s).",
754 length_restr ? "length" : "range",
755 (valcopy && basetype != LY_TYPE_DEC64) ? valcopy : value ? *value : max ? "max" : "min");
756 } else if (!ret && value) {
757 *value = *value + len;
758 }
759 free(valcopy);
760 return ret;
761}
762
763/**
764 * @brief Compile the parsed range restriction.
765 * @param[in] ctx Compile context.
766 * @param[in] range_p Parsed range structure to compile.
767 * @param[in] basetype Base YANG built-in type of the node with the range restriction.
768 * @param[in] length_restr Flag to distinguish between range and length restrictions. Only for logging.
769 * @param[in] frdigits The fraction-digits value in case of LY_TYPE_DEC64 basetype.
770 * @param[in] base_range Range restriction of the type from which the current type is derived. The current
771 * range restriction must be more restrictive than the base_range.
772 * @param[in,out] range Pointer to the created current range structure.
773 * @return LY_ERR value.
774 */
775static LY_ERR
776lys_compile_type_range(struct lysc_ctx *ctx, struct lysp_restr *range_p, LY_DATA_TYPE basetype, ly_bool length_restr,
777 uint8_t frdigits, struct lysc_range *base_range, struct lysc_range **range)
778{
aPiecek1c4da362021-04-29 14:26:34 +0200779 LY_ERR ret = LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200780 const char *expr;
781 struct lysc_range_part *parts = NULL, *part;
782 ly_bool range_expected = 0, uns;
783 LY_ARRAY_COUNT_TYPE parts_done = 0, u, v;
784
785 assert(range);
786 assert(range_p);
787
788 expr = range_p->arg.str;
789 while (1) {
790 if (isspace(*expr)) {
791 ++expr;
792 } else if (*expr == '\0') {
793 if (range_expected) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100794 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200795 "Invalid %s restriction - unexpected end of the expression after \"..\" (%s).",
Michal Vasko20c0b9f2021-08-24 08:16:27 +0200796 length_restr ? "length" : "range", range_p->arg.str);
aPiecek1c4da362021-04-29 14:26:34 +0200797 ret = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200798 goto cleanup;
799 } else if (!parts || (parts_done == LY_ARRAY_COUNT(parts))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100800 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200801 "Invalid %s restriction - unexpected end of the expression (%s).",
Michal Vasko20c0b9f2021-08-24 08:16:27 +0200802 length_restr ? "length" : "range", range_p->arg.str);
aPiecek1c4da362021-04-29 14:26:34 +0200803 ret = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200804 goto cleanup;
805 }
806 parts_done++;
807 break;
Radek Krejcif13b87b2020-12-01 22:02:17 +0100808 } else if (!strncmp(expr, "min", ly_strlen_const("min"))) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200809 if (parts) {
810 /* min cannot be used elsewhere than in the first part */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100811 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200812 "Invalid %s restriction - unexpected data before min keyword (%.*s).", length_restr ? "length" : "range",
Radek Krejci52409202021-03-15 09:30:43 +0100813 (int)(expr - range_p->arg.str), range_p->arg.str);
aPiecek1c4da362021-04-29 14:26:34 +0200814 ret = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200815 goto cleanup;
816 }
Radek Krejcif13b87b2020-12-01 22:02:17 +0100817 expr += ly_strlen_const("min");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200818
819 LY_ARRAY_NEW_GOTO(ctx->ctx, parts, part, ret, cleanup);
aPiecek1c4da362021-04-29 14:26:34 +0200820 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 +0200821 part->max_64 = part->min_64;
822 } else if (*expr == '|') {
823 if (!parts || range_expected) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100824 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200825 "Invalid %s restriction - unexpected beginning of the expression (%s).", length_restr ? "length" : "range", expr);
aPiecek1c4da362021-04-29 14:26:34 +0200826 ret = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200827 goto cleanup;
828 }
829 expr++;
830 parts_done++;
831 /* process next part of the expression */
832 } else if (!strncmp(expr, "..", 2)) {
833 expr += 2;
834 while (isspace(*expr)) {
835 expr++;
836 }
837 if (!parts || (LY_ARRAY_COUNT(parts) == parts_done)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100838 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200839 "Invalid %s restriction - unexpected \"..\" without a lower bound.", length_restr ? "length" : "range");
aPiecek1c4da362021-04-29 14:26:34 +0200840 ret = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200841 goto cleanup;
842 }
843 /* continue expecting the upper boundary */
844 range_expected = 1;
845 } else if (isdigit(*expr) || (*expr == '-') || (*expr == '+')) {
846 /* number */
847 if (range_expected) {
848 part = &parts[LY_ARRAY_COUNT(parts) - 1];
aPiecek1c4da362021-04-29 14:26:34 +0200849 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 +0200850 range_expected = 0;
851 } else {
852 LY_ARRAY_NEW_GOTO(ctx->ctx, parts, part, ret, cleanup);
aPiecek1c4da362021-04-29 14:26:34 +0200853 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 +0200854 basetype, parts_done ? 0 : 1, length_restr, frdigits, NULL, &expr), cleanup);
855 part->max_64 = part->min_64;
856 }
857
858 /* continue with possible another expression part */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100859 } else if (!strncmp(expr, "max", ly_strlen_const("max"))) {
860 expr += ly_strlen_const("max");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200861 while (isspace(*expr)) {
862 expr++;
863 }
864 if (*expr != '\0') {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100865 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Invalid %s restriction - unexpected data after max keyword (%s).",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200866 length_restr ? "length" : "range", expr);
aPiecek1c4da362021-04-29 14:26:34 +0200867 ret = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200868 goto cleanup;
869 }
870 if (range_expected) {
871 part = &parts[LY_ARRAY_COUNT(parts) - 1];
aPiecek1c4da362021-04-29 14:26:34 +0200872 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 +0200873 range_expected = 0;
874 } else {
875 LY_ARRAY_NEW_GOTO(ctx->ctx, parts, part, ret, cleanup);
aPiecek1c4da362021-04-29 14:26:34 +0200876 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 +0200877 basetype, parts_done ? 0 : 1, length_restr, frdigits, base_range, NULL), cleanup);
878 part->min_64 = part->max_64;
879 }
880 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100881 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Invalid %s restriction - unexpected data (%s).",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200882 length_restr ? "length" : "range", expr);
aPiecek1c4da362021-04-29 14:26:34 +0200883 ret = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200884 goto cleanup;
885 }
886 }
887
888 /* check with the previous range/length restriction */
889 if (base_range) {
890 switch (basetype) {
891 case LY_TYPE_BINARY:
892 case LY_TYPE_UINT8:
893 case LY_TYPE_UINT16:
894 case LY_TYPE_UINT32:
895 case LY_TYPE_UINT64:
896 case LY_TYPE_STRING:
897 uns = 1;
898 break;
899 case LY_TYPE_DEC64:
900 case LY_TYPE_INT8:
901 case LY_TYPE_INT16:
902 case LY_TYPE_INT32:
903 case LY_TYPE_INT64:
904 uns = 0;
905 break;
906 default:
907 LOGINT(ctx->ctx);
908 ret = LY_EINT;
909 goto cleanup;
910 }
911 for (u = v = 0; u < parts_done && v < LY_ARRAY_COUNT(base_range->parts); ++u) {
912 if ((uns && (parts[u].min_u64 < base_range->parts[v].min_u64)) || (!uns && (parts[u].min_64 < base_range->parts[v].min_64))) {
913 goto baseerror;
914 }
915 /* current lower bound is not lower than the base */
916 if (base_range->parts[v].min_64 == base_range->parts[v].max_64) {
917 /* base has single value */
918 if (base_range->parts[v].min_64 == parts[u].min_64) {
919 /* both lower bounds are the same */
920 if (parts[u].min_64 != parts[u].max_64) {
921 /* current continues with a range */
922 goto baseerror;
923 } else {
924 /* equal single values, move both forward */
925 ++v;
926 continue;
927 }
928 } else {
929 /* base is single value lower than current range, so the
930 * value from base range is removed in the current,
931 * move only base and repeat checking */
932 ++v;
933 --u;
934 continue;
935 }
936 } else {
937 /* base is the range */
938 if (parts[u].min_64 == parts[u].max_64) {
939 /* current is a single value */
940 if ((uns && (parts[u].max_u64 > base_range->parts[v].max_u64)) || (!uns && (parts[u].max_64 > base_range->parts[v].max_64))) {
941 /* current is behind the base range, so base range is omitted,
942 * move the base and keep the current for further check */
943 ++v;
944 --u;
945 } /* else it is within the base range, so move the current, but keep the base */
946 continue;
947 } else {
948 /* both are ranges - check the higher bound, the lower was already checked */
949 if ((uns && (parts[u].max_u64 > base_range->parts[v].max_u64)) || (!uns && (parts[u].max_64 > base_range->parts[v].max_64))) {
950 /* higher bound is higher than the current higher bound */
951 if ((uns && (parts[u].min_u64 > base_range->parts[v].max_u64)) || (!uns && (parts[u].min_64 > base_range->parts[v].max_64))) {
952 /* but the current lower bound is also higher, so the base range is omitted,
953 * continue with the same current, but move the base */
954 --u;
955 ++v;
956 continue;
957 }
958 /* current range starts within the base range but end behind it */
959 goto baseerror;
960 } else {
961 /* current range is smaller than the base,
962 * move current, but stay with the base */
963 continue;
964 }
965 }
966 }
967 }
968 if (u != parts_done) {
969baseerror:
Radek Krejci2efc45b2020-12-22 16:25:44 +0100970 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200971 "Invalid %s restriction - the derived restriction (%s) is not equally or more limiting.",
Michal Vasko20c0b9f2021-08-24 08:16:27 +0200972 length_restr ? "length" : "range", range_p->arg.str);
aPiecek1c4da362021-04-29 14:26:34 +0200973 ret = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200974 goto cleanup;
975 }
976 }
977
978 if (!(*range)) {
979 *range = calloc(1, sizeof **range);
980 LY_CHECK_ERR_RET(!(*range), LOGMEM(ctx->ctx), LY_EMEM);
981 }
982
983 /* we rewrite the following values as the types chain is being processed */
984 if (range_p->eapptag) {
985 lydict_remove(ctx->ctx, (*range)->eapptag);
986 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->eapptag, 0, &(*range)->eapptag), cleanup);
987 }
988 if (range_p->emsg) {
989 lydict_remove(ctx->ctx, (*range)->emsg);
990 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->emsg, 0, &(*range)->emsg), cleanup);
991 }
992 if (range_p->dsc) {
993 lydict_remove(ctx->ctx, (*range)->dsc);
994 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->dsc, 0, &(*range)->dsc), cleanup);
995 }
996 if (range_p->ref) {
997 lydict_remove(ctx->ctx, (*range)->ref);
998 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->ref, 0, &(*range)->ref), cleanup);
999 }
1000 /* extensions are taken only from the last range by the caller */
1001
1002 (*range)->parts = parts;
1003 parts = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001004cleanup:
1005 LY_ARRAY_FREE(parts);
1006
1007 return ret;
1008}
1009
Michal Vasko215d7fc2022-07-15 14:50:44 +02001010/**
1011 * @brief Transform characters block in an XML Schema pattern into Perl character ranges.
1012 *
1013 * @param[in] ctx libyang context.
1014 * @param[in] pattern Original pattern.
1015 * @param[in,out] regex Pattern to modify.
1016 * @return LY_ERR value.
1017 */
1018static LY_ERR
1019lys_compile_pattern_chblocks_xmlschema2perl(const struct ly_ctx *ctx, const char *pattern, char **regex)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001020{
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001021#define URANGE_LEN 19
1022 char *ublock2urange[][2] = {
1023 {"BasicLatin", "[\\x{0000}-\\x{007F}]"},
1024 {"Latin-1Supplement", "[\\x{0080}-\\x{00FF}]"},
1025 {"LatinExtended-A", "[\\x{0100}-\\x{017F}]"},
1026 {"LatinExtended-B", "[\\x{0180}-\\x{024F}]"},
1027 {"IPAExtensions", "[\\x{0250}-\\x{02AF}]"},
1028 {"SpacingModifierLetters", "[\\x{02B0}-\\x{02FF}]"},
1029 {"CombiningDiacriticalMarks", "[\\x{0300}-\\x{036F}]"},
1030 {"Greek", "[\\x{0370}-\\x{03FF}]"},
1031 {"Cyrillic", "[\\x{0400}-\\x{04FF}]"},
1032 {"Armenian", "[\\x{0530}-\\x{058F}]"},
1033 {"Hebrew", "[\\x{0590}-\\x{05FF}]"},
1034 {"Arabic", "[\\x{0600}-\\x{06FF}]"},
1035 {"Syriac", "[\\x{0700}-\\x{074F}]"},
1036 {"Thaana", "[\\x{0780}-\\x{07BF}]"},
1037 {"Devanagari", "[\\x{0900}-\\x{097F}]"},
1038 {"Bengali", "[\\x{0980}-\\x{09FF}]"},
1039 {"Gurmukhi", "[\\x{0A00}-\\x{0A7F}]"},
1040 {"Gujarati", "[\\x{0A80}-\\x{0AFF}]"},
1041 {"Oriya", "[\\x{0B00}-\\x{0B7F}]"},
1042 {"Tamil", "[\\x{0B80}-\\x{0BFF}]"},
1043 {"Telugu", "[\\x{0C00}-\\x{0C7F}]"},
1044 {"Kannada", "[\\x{0C80}-\\x{0CFF}]"},
1045 {"Malayalam", "[\\x{0D00}-\\x{0D7F}]"},
1046 {"Sinhala", "[\\x{0D80}-\\x{0DFF}]"},
1047 {"Thai", "[\\x{0E00}-\\x{0E7F}]"},
1048 {"Lao", "[\\x{0E80}-\\x{0EFF}]"},
1049 {"Tibetan", "[\\x{0F00}-\\x{0FFF}]"},
1050 {"Myanmar", "[\\x{1000}-\\x{109F}]"},
1051 {"Georgian", "[\\x{10A0}-\\x{10FF}]"},
1052 {"HangulJamo", "[\\x{1100}-\\x{11FF}]"},
1053 {"Ethiopic", "[\\x{1200}-\\x{137F}]"},
1054 {"Cherokee", "[\\x{13A0}-\\x{13FF}]"},
1055 {"UnifiedCanadianAboriginalSyllabics", "[\\x{1400}-\\x{167F}]"},
1056 {"Ogham", "[\\x{1680}-\\x{169F}]"},
1057 {"Runic", "[\\x{16A0}-\\x{16FF}]"},
1058 {"Khmer", "[\\x{1780}-\\x{17FF}]"},
1059 {"Mongolian", "[\\x{1800}-\\x{18AF}]"},
1060 {"LatinExtendedAdditional", "[\\x{1E00}-\\x{1EFF}]"},
1061 {"GreekExtended", "[\\x{1F00}-\\x{1FFF}]"},
1062 {"GeneralPunctuation", "[\\x{2000}-\\x{206F}]"},
1063 {"SuperscriptsandSubscripts", "[\\x{2070}-\\x{209F}]"},
1064 {"CurrencySymbols", "[\\x{20A0}-\\x{20CF}]"},
1065 {"CombiningMarksforSymbols", "[\\x{20D0}-\\x{20FF}]"},
1066 {"LetterlikeSymbols", "[\\x{2100}-\\x{214F}]"},
1067 {"NumberForms", "[\\x{2150}-\\x{218F}]"},
1068 {"Arrows", "[\\x{2190}-\\x{21FF}]"},
1069 {"MathematicalOperators", "[\\x{2200}-\\x{22FF}]"},
1070 {"MiscellaneousTechnical", "[\\x{2300}-\\x{23FF}]"},
1071 {"ControlPictures", "[\\x{2400}-\\x{243F}]"},
1072 {"OpticalCharacterRecognition", "[\\x{2440}-\\x{245F}]"},
1073 {"EnclosedAlphanumerics", "[\\x{2460}-\\x{24FF}]"},
1074 {"BoxDrawing", "[\\x{2500}-\\x{257F}]"},
1075 {"BlockElements", "[\\x{2580}-\\x{259F}]"},
1076 {"GeometricShapes", "[\\x{25A0}-\\x{25FF}]"},
1077 {"MiscellaneousSymbols", "[\\x{2600}-\\x{26FF}]"},
1078 {"Dingbats", "[\\x{2700}-\\x{27BF}]"},
1079 {"BraillePatterns", "[\\x{2800}-\\x{28FF}]"},
1080 {"CJKRadicalsSupplement", "[\\x{2E80}-\\x{2EFF}]"},
1081 {"KangxiRadicals", "[\\x{2F00}-\\x{2FDF}]"},
1082 {"IdeographicDescriptionCharacters", "[\\x{2FF0}-\\x{2FFF}]"},
1083 {"CJKSymbolsandPunctuation", "[\\x{3000}-\\x{303F}]"},
1084 {"Hiragana", "[\\x{3040}-\\x{309F}]"},
1085 {"Katakana", "[\\x{30A0}-\\x{30FF}]"},
1086 {"Bopomofo", "[\\x{3100}-\\x{312F}]"},
1087 {"HangulCompatibilityJamo", "[\\x{3130}-\\x{318F}]"},
1088 {"Kanbun", "[\\x{3190}-\\x{319F}]"},
1089 {"BopomofoExtended", "[\\x{31A0}-\\x{31BF}]"},
1090 {"EnclosedCJKLettersandMonths", "[\\x{3200}-\\x{32FF}]"},
1091 {"CJKCompatibility", "[\\x{3300}-\\x{33FF}]"},
1092 {"CJKUnifiedIdeographsExtensionA", "[\\x{3400}-\\x{4DB5}]"},
1093 {"CJKUnifiedIdeographs", "[\\x{4E00}-\\x{9FFF}]"},
1094 {"YiSyllables", "[\\x{A000}-\\x{A48F}]"},
1095 {"YiRadicals", "[\\x{A490}-\\x{A4CF}]"},
1096 {"HangulSyllables", "[\\x{AC00}-\\x{D7A3}]"},
1097 {"PrivateUse", "[\\x{E000}-\\x{F8FF}]"},
1098 {"CJKCompatibilityIdeographs", "[\\x{F900}-\\x{FAFF}]"},
1099 {"AlphabeticPresentationForms", "[\\x{FB00}-\\x{FB4F}]"},
1100 {"ArabicPresentationForms-A", "[\\x{FB50}-\\x{FDFF}]"},
1101 {"CombiningHalfMarks", "[\\x{FE20}-\\x{FE2F}]"},
1102 {"CJKCompatibilityForms", "[\\x{FE30}-\\x{FE4F}]"},
1103 {"SmallFormVariants", "[\\x{FE50}-\\x{FE6F}]"},
1104 {"ArabicPresentationForms-B", "[\\x{FE70}-\\x{FEFE}]"},
1105 {"HalfwidthandFullwidthForms", "[\\x{FF00}-\\x{FFEF}]"},
Michal Vasko2b71ab52020-12-01 16:44:11 +01001106 {"Specials", "[\\x{FEFF}|\\x{FFF0}-\\x{FFFD}]"},
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001107 {NULL, NULL}
1108 };
1109
Michal Vasko215d7fc2022-07-15 14:50:44 +02001110 size_t idx, idx2, start, end;
1111 char *perl_regex, *ptr;
1112
1113 perl_regex = *regex;
1114
1115 /* substitute Unicode Character Blocks with exact Character Ranges */
1116 while ((ptr = strstr(perl_regex, "\\p{Is"))) {
1117 start = ptr - perl_regex;
1118
1119 ptr = strchr(ptr, '}');
1120 if (!ptr) {
1121 LOGVAL(ctx, LY_VCODE_INREGEXP, pattern, perl_regex + start + 2, "unterminated character property");
1122 return LY_EVALID;
1123 }
1124 end = (ptr - perl_regex) + 1;
1125
1126 /* need more space */
1127 if (end - start < URANGE_LEN) {
1128 perl_regex = ly_realloc(perl_regex, strlen(perl_regex) + (URANGE_LEN - (end - start)) + 1);
Michal Vasko78419922022-07-15 15:15:20 +02001129 *regex = perl_regex;
Michal Vasko215d7fc2022-07-15 14:50:44 +02001130 LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx), LY_EMEM);
1131 }
1132
1133 /* find our range */
1134 for (idx = 0; ublock2urange[idx][0]; ++idx) {
1135 if (!strncmp(perl_regex + start + ly_strlen_const("\\p{Is"),
1136 ublock2urange[idx][0], strlen(ublock2urange[idx][0]))) {
1137 break;
1138 }
1139 }
1140 if (!ublock2urange[idx][0]) {
1141 LOGVAL(ctx, LY_VCODE_INREGEXP, pattern, perl_regex + start + 5, "unknown block name");
1142 return LY_EVALID;
1143 }
1144
1145 /* make the space in the string and replace the block (but we cannot include brackets if it was already enclosed in them) */
1146 for (idx2 = 0, idx = 0; idx2 < start; ++idx2) {
1147 if ((perl_regex[idx2] == '[') && (!idx2 || (perl_regex[idx2 - 1] != '\\'))) {
1148 ++idx;
1149 }
1150 if ((perl_regex[idx2] == ']') && (!idx2 || (perl_regex[idx2 - 1] != '\\'))) {
1151 --idx;
1152 }
1153 }
1154 if (idx) {
1155 /* skip brackets */
1156 memmove(perl_regex + start + (URANGE_LEN - 2), perl_regex + end, strlen(perl_regex + end) + 1);
1157 memcpy(perl_regex + start, ublock2urange[idx][1] + 1, URANGE_LEN - 2);
1158 } else {
1159 memmove(perl_regex + start + URANGE_LEN, perl_regex + end, strlen(perl_regex + end) + 1);
1160 memcpy(perl_regex + start, ublock2urange[idx][1], URANGE_LEN);
1161 }
1162 }
1163
Michal Vasko215d7fc2022-07-15 14:50:44 +02001164 return LY_SUCCESS;
1165}
1166
1167LY_ERR
1168lys_compile_type_pattern_check(struct ly_ctx *ctx, const char *pattern, pcre2_code **code)
1169{
1170 size_t idx, size, brack;
1171 char *perl_regex;
1172 int err_code, compile_opts;
1173 const char *orig_ptr;
1174 PCRE2_SIZE err_offset;
1175 pcre2_code *code_local;
aPiecek9e716992022-07-21 16:29:47 +02001176 ly_bool escaped;
Michal Vasko215d7fc2022-07-15 14:50:44 +02001177 LY_ERR r;
1178
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001179 /* adjust the expression to a Perl equivalent
1180 * http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#regexs */
1181
1182 /* allocate space for the transformed pattern */
1183 size = strlen(pattern) + 1;
Michal Vasko03d430c2022-07-22 09:05:56 +02001184 compile_opts = PCRE2_UTF | PCRE2_UCP | PCRE2_ANCHORED | PCRE2_DOLLAR_ENDONLY | PCRE2_NO_AUTO_CAPTURE;
Christian Hoppsdafed222021-03-22 13:02:42 -04001185#ifdef PCRE2_ENDANCHORED
1186 compile_opts |= PCRE2_ENDANCHORED;
1187#else
1188 /* add space for trailing $ anchor */
1189 size++;
1190#endif
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001191 perl_regex = malloc(size);
1192 LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx), LY_EMEM);
1193 perl_regex[0] = '\0';
1194
1195 /* we need to replace all "$" and "^" (that are not in "[]") with "\$" and "\^" */
1196 brack = 0;
1197 idx = 0;
aPiecek9e716992022-07-21 16:29:47 +02001198 escaped = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001199 orig_ptr = pattern;
1200 while (orig_ptr[0]) {
1201 switch (orig_ptr[0]) {
1202 case '$':
1203 case '^':
1204 if (!brack) {
1205 /* make space for the extra character */
1206 ++size;
1207 perl_regex = ly_realloc(perl_regex, size);
1208 LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx), LY_EMEM);
1209
1210 /* print escape slash */
1211 perl_regex[idx] = '\\';
1212 ++idx;
1213 }
1214 break;
aPiecek9e716992022-07-21 16:29:47 +02001215 case '\\':
1216 /* escape character found or backslash is escaped */
1217 escaped = !escaped;
1218 /* copy backslash and continue with the next character */
1219 perl_regex[idx] = orig_ptr[0];
1220 ++idx;
1221 ++orig_ptr;
1222 continue;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001223 case '[':
aPiecek9e716992022-07-21 16:29:47 +02001224 if (!escaped) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001225 ++brack;
1226 }
1227 break;
1228 case ']':
aPiecek9e716992022-07-21 16:29:47 +02001229 if (!brack && !escaped) {
1230 /* If ']' does not terminate a character class expression, then pcre2_compile() implicitly escapes the
1231 * ']' character. But this seems to be against the regular expressions rules declared in
1232 * "XML schema: Datatypes" and therefore an error is returned. So for example if pattern is '\[a]' then
1233 * pcre2 match characters '[a]' literally but in YANG such pattern is not allowed.
1234 */
1235 LOGVAL(ctx, LY_VCODE_INREGEXP, pattern, orig_ptr, "character group doesn't begin with '['");
1236 free(perl_regex);
1237 return LY_EVALID;
1238 } else if (!escaped) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001239 --brack;
1240 }
1241 break;
1242 default:
1243 break;
1244 }
1245
1246 /* copy char */
1247 perl_regex[idx] = orig_ptr[0];
1248
1249 ++idx;
1250 ++orig_ptr;
aPiecek9e716992022-07-21 16:29:47 +02001251 escaped = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001252 }
Christian Hoppsdafed222021-03-22 13:02:42 -04001253#ifndef PCRE2_ENDANCHORED
1254 /* anchor match to end of subject */
1255 perl_regex[idx++] = '$';
1256#endif
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001257 perl_regex[idx] = '\0';
1258
Michal Vasko215d7fc2022-07-15 14:50:44 +02001259 /* transform character blocks */
1260 if ((r = lys_compile_pattern_chblocks_xmlschema2perl(ctx, pattern, &perl_regex))) {
1261 free(perl_regex);
1262 return r;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001263 }
1264
1265 /* must return 0, already checked during parsing */
Christian Hoppsdafed222021-03-22 13:02:42 -04001266 code_local = pcre2_compile((PCRE2_SPTR)perl_regex, PCRE2_ZERO_TERMINATED, compile_opts,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001267 &err_code, &err_offset, NULL);
1268 if (!code_local) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01001269 PCRE2_UCHAR err_msg[LY_PCRE2_MSG_LIMIT] = {0};
1270 pcre2_get_error_message(err_code, err_msg, LY_PCRE2_MSG_LIMIT);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001271 LOGVAL(ctx, LY_VCODE_INREGEXP, pattern, perl_regex + err_offset, err_msg);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001272 free(perl_regex);
1273 return LY_EVALID;
1274 }
1275 free(perl_regex);
1276
1277 if (code) {
1278 *code = code_local;
1279 } else {
1280 free(code_local);
1281 }
1282
1283 return LY_SUCCESS;
1284
1285#undef URANGE_LEN
1286}
1287
Michal Vasko51de7b72022-04-29 09:50:22 +02001288LY_ERR
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001289lys_compile_type_patterns(struct lysc_ctx *ctx, struct lysp_restr *patterns_p,
1290 struct lysc_pattern **base_patterns, struct lysc_pattern ***patterns)
1291{
1292 struct lysc_pattern **pattern;
1293 LY_ARRAY_COUNT_TYPE u;
1294 LY_ERR ret = LY_SUCCESS;
1295
1296 /* first, copy the patterns from the base type */
1297 if (base_patterns) {
1298 *patterns = lysc_patterns_dup(ctx->ctx, base_patterns);
1299 LY_CHECK_ERR_RET(!(*patterns), LOGMEM(ctx->ctx), LY_EMEM);
1300 }
1301
1302 LY_ARRAY_FOR(patterns_p, u) {
1303 LY_ARRAY_NEW_RET(ctx->ctx, (*patterns), pattern, LY_EMEM);
1304 *pattern = calloc(1, sizeof **pattern);
1305 ++(*pattern)->refcount;
1306
Radek Krejci2efc45b2020-12-22 16:25:44 +01001307 ret = lys_compile_type_pattern_check(ctx->ctx, &patterns_p[u].arg.str[1], &(*pattern)->code);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001308 LY_CHECK_RET(ret);
1309
Radek Krejcif13b87b2020-12-01 22:02:17 +01001310 if (patterns_p[u].arg.str[0] == LYSP_RESTR_PATTERN_NACK) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001311 (*pattern)->inverted = 1;
1312 }
1313 DUP_STRING_GOTO(ctx->ctx, &patterns_p[u].arg.str[1], (*pattern)->expr, ret, done);
1314 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].eapptag, (*pattern)->eapptag, ret, done);
1315 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].emsg, (*pattern)->emsg, ret, done);
1316 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].dsc, (*pattern)->dsc, ret, done);
1317 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].ref, (*pattern)->ref, ret, done);
Radek Krejciab430862021-03-02 20:13:40 +01001318 COMPILE_EXTS_GOTO(ctx, patterns_p[u].exts, (*pattern)->exts, (*pattern), ret, done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001319 }
1320done:
1321 return ret;
1322}
1323
1324/**
1325 * @brief map of the possible restrictions combination for the specific built-in type.
1326 */
1327static uint16_t type_substmt_map[LY_DATA_TYPE_COUNT] = {
1328 0 /* LY_TYPE_UNKNOWN */,
1329 LYS_SET_LENGTH /* LY_TYPE_BINARY */,
1330 LYS_SET_RANGE /* LY_TYPE_UINT8 */,
1331 LYS_SET_RANGE /* LY_TYPE_UINT16 */,
1332 LYS_SET_RANGE /* LY_TYPE_UINT32 */,
1333 LYS_SET_RANGE /* LY_TYPE_UINT64 */,
1334 LYS_SET_LENGTH | LYS_SET_PATTERN /* LY_TYPE_STRING */,
1335 LYS_SET_BIT /* LY_TYPE_BITS */,
1336 0 /* LY_TYPE_BOOL */,
1337 LYS_SET_FRDIGITS | LYS_SET_RANGE /* LY_TYPE_DEC64 */,
1338 0 /* LY_TYPE_EMPTY */,
1339 LYS_SET_ENUM /* LY_TYPE_ENUM */,
1340 LYS_SET_BASE /* LY_TYPE_IDENT */,
1341 LYS_SET_REQINST /* LY_TYPE_INST */,
1342 LYS_SET_REQINST | LYS_SET_PATH /* LY_TYPE_LEAFREF */,
1343 LYS_SET_TYPE /* LY_TYPE_UNION */,
1344 LYS_SET_RANGE /* LY_TYPE_INT8 */,
1345 LYS_SET_RANGE /* LY_TYPE_INT16 */,
1346 LYS_SET_RANGE /* LY_TYPE_INT32 */,
1347 LYS_SET_RANGE /* LY_TYPE_INT64 */
1348};
1349
1350/**
1351 * @brief stringification of the YANG built-in data types
1352 */
1353const char *ly_data_type2str[LY_DATA_TYPE_COUNT] = {
Radek Krejci04699f02021-03-22 21:50:29 +01001354 LY_TYPE_UNKNOWN_STR,
1355 LY_TYPE_BINARY_STR,
1356 LY_TYPE_UINT8_STR,
1357 LY_TYPE_UINT16_STR,
1358 LY_TYPE_UINT32_STR,
1359 LY_TYPE_UINT64_STR,
1360 LY_TYPE_STRING_STR,
1361 LY_TYPE_BITS_STR,
1362 LY_TYPE_BOOL_STR,
1363 LY_TYPE_DEC64_STR,
1364 LY_TYPE_EMPTY_STR,
1365 LY_TYPE_ENUM_STR,
1366 LY_TYPE_IDENT_STR,
1367 LY_TYPE_INST_STR,
1368 LY_TYPE_LEAFREF_STR,
1369 LY_TYPE_UNION_STR,
1370 LY_TYPE_INT8_STR,
1371 LY_TYPE_INT16_STR,
1372 LY_TYPE_INT32_STR,
1373 LY_TYPE_INT64_STR
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001374};
1375
1376/**
1377 * @brief Compile parsed type's enum structures (for enumeration and bits types).
1378 * @param[in] ctx Compile context.
1379 * @param[in] enums_p Array of the parsed enum structures to compile.
1380 * @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.
1381 * @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 +01001382 * @param[out] bitenums Newly created array of the compiled bitenums information for the current type.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001383 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
1384 */
1385static LY_ERR
1386lys_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 +01001387 struct lysc_type_bitenum_item *base_enums, struct lysc_type_bitenum_item **bitenums)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001388{
1389 LY_ERR ret = LY_SUCCESS;
1390 LY_ARRAY_COUNT_TYPE u, v, match = 0;
Radek Krejci430a5582020-12-01 13:35:18 +01001391 int32_t highest_value = INT32_MIN, cur_val = INT32_MIN;
1392 uint32_t highest_position = 0, cur_pos = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001393 struct lysc_type_bitenum_item *e, storage;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001394 ly_bool enabled;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001395
1396 if (base_enums && (ctx->pmod->version < LYS_VERSION_1_1)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001397 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "%s type can be subtyped only in YANG 1.1 modules.",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001398 basetype == LY_TYPE_ENUM ? "Enumeration" : "Bits");
1399 return LY_EVALID;
1400 }
1401
1402 LY_ARRAY_FOR(enums_p, u) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001403 /* perform all checks */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001404 if (base_enums) {
1405 /* check the enum/bit presence in the base type - the set of enums/bits in the derived type must be a subset */
1406 LY_ARRAY_FOR(base_enums, v) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001407 if (!strcmp(enums_p[u].name, base_enums[v].name)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001408 break;
1409 }
1410 }
1411 if (v == LY_ARRAY_COUNT(base_enums)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001412 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001413 "Invalid %s - derived type adds new item \"%s\".",
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001414 basetype == LY_TYPE_ENUM ? "enumeration" : "bits", enums_p[u].name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001415 return LY_EVALID;
1416 }
1417 match = v;
1418 }
1419
1420 if (basetype == LY_TYPE_ENUM) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001421 if (enums_p[u].flags & LYS_SET_VALUE) {
Radek IÅ¡a038b60d2020-11-26 11:37:15 +01001422 /* value assigned by model */
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001423 cur_val = (int32_t)enums_p[u].value;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001424 /* check collision with other values */
Radek IÅ¡a0fe25a92021-03-18 08:45:18 +01001425 LY_ARRAY_FOR(*bitenums, v) {
1426 if (cur_val == (*bitenums)[v].value) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001427 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001428 "Invalid enumeration - value %d collide in items \"%s\" and \"%s\".",
Radek IÅ¡a0fe25a92021-03-18 08:45:18 +01001429 cur_val, enums_p[u].name, (*bitenums)[v].name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001430 return LY_EVALID;
1431 }
1432 }
1433 } else if (base_enums) {
1434 /* inherit the assigned value */
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001435 cur_val = base_enums[match].value;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001436 } else {
1437 /* assign value automatically */
Radek IÅ¡a038b60d2020-11-26 11:37:15 +01001438 if (u == 0) {
1439 cur_val = 0;
1440 } else if (highest_value == INT32_MAX) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001441 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001442 "Invalid enumeration - it is not possible to auto-assign enum value for "
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001443 "\"%s\" since the highest value is already 2147483647.", enums_p[u].name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001444 return LY_EVALID;
Radek IÅ¡a038b60d2020-11-26 11:37:15 +01001445 } else {
1446 cur_val = highest_value + 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001447 }
Radek IÅ¡a038b60d2020-11-26 11:37:15 +01001448 }
1449
1450 /* save highest value for auto assing */
1451 if (highest_value < cur_val) {
1452 highest_value = cur_val;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001453 }
1454 } else { /* LY_TYPE_BITS */
1455 if (enums_p[u].flags & LYS_SET_VALUE) {
Radek IÅ¡aca013ee2020-11-26 17:51:26 +01001456 /* value assigned by model */
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001457 cur_pos = (uint32_t)enums_p[u].value;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001458 /* check collision with other values */
Radek IÅ¡a0fe25a92021-03-18 08:45:18 +01001459 LY_ARRAY_FOR(*bitenums, v) {
1460 if (cur_pos == (*bitenums)[v].position) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001461 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001462 "Invalid bits - position %u collide in items \"%s\" and \"%s\".",
Radek IÅ¡a0fe25a92021-03-18 08:45:18 +01001463 cur_pos, enums_p[u].name, (*bitenums)[v].name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001464 return LY_EVALID;
1465 }
1466 }
1467 } else if (base_enums) {
1468 /* inherit the assigned value */
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001469 cur_pos = base_enums[match].position;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001470 } else {
1471 /* assign value automatically */
Radek IÅ¡aca013ee2020-11-26 17:51:26 +01001472 if (u == 0) {
1473 cur_pos = 0;
1474 } else if (highest_position == UINT32_MAX) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001475 /* counter overflow */
Radek Krejci2efc45b2020-12-22 16:25:44 +01001476 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001477 "Invalid bits - it is not possible to auto-assign bit position for "
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001478 "\"%s\" since the highest value is already 4294967295.", enums_p[u].name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001479 return LY_EVALID;
Radek IÅ¡aca013ee2020-11-26 17:51:26 +01001480 } else {
1481 cur_pos = highest_position + 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001482 }
Radek IÅ¡aca013ee2020-11-26 17:51:26 +01001483 }
1484
1485 /* save highest position for auto assing */
1486 if (highest_position < cur_pos) {
1487 highest_position = cur_pos;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001488 }
1489 }
1490
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001491 /* the assigned values must not change from the derived type */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001492 if (base_enums) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001493 if (basetype == LY_TYPE_ENUM) {
1494 if (cur_val != base_enums[match].value) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001495 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001496 "Invalid enumeration - value of the item \"%s\" has changed from %d to %d in the derived type.",
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001497 enums_p[u].name, base_enums[match].value, cur_val);
1498 return LY_EVALID;
1499 }
1500 } else {
1501 if (cur_pos != base_enums[match].position) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001502 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001503 "Invalid bits - position of the item \"%s\" has changed from %u to %u in the derived type.",
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001504 enums_p[u].name, base_enums[match].position, cur_pos);
1505 return LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001506 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001507 }
1508 }
1509
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001510 /* add new enum/bit */
Radek IÅ¡a0fe25a92021-03-18 08:45:18 +01001511 LY_ARRAY_NEW_RET(ctx->ctx, *bitenums, e, LY_EMEM);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001512 DUP_STRING_GOTO(ctx->ctx, enums_p[u].name, e->name, ret, done);
1513 DUP_STRING_GOTO(ctx->ctx, enums_p[u].dsc, e->dsc, ret, done);
1514 DUP_STRING_GOTO(ctx->ctx, enums_p[u].ref, e->ref, ret, done);
Michal Vaskod1e53b92021-01-28 13:11:06 +01001515 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 +01001516 if (basetype == LY_TYPE_ENUM) {
1517 e->value = cur_val;
1518 } else {
1519 e->position = cur_pos;
1520 }
Radek Krejciab430862021-03-02 20:13:40 +01001521 COMPILE_EXTS_GOTO(ctx, enums_p[u].exts, e->exts, e, ret, done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001522
Michal Vaskof4fa90d2021-11-11 15:05:19 +01001523 /* evaluate if-ffeatures */
1524 LY_CHECK_RET(lys_eval_iffeatures(ctx->ctx, enums_p[u].iffeatures, &enabled));
1525 if (!enabled) {
1526 /* set only flag, later resolved and removed */
1527 e->flags |= LYS_DISABLED;
1528 }
1529
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001530 if (basetype == LY_TYPE_BITS) {
1531 /* keep bits ordered by position */
Radek IÅ¡a0fe25a92021-03-18 08:45:18 +01001532 for (v = u; v && (*bitenums)[v - 1].position > e->position; --v) {}
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001533 if (v != u) {
1534 memcpy(&storage, e, sizeof *e);
Radek IÅ¡a0fe25a92021-03-18 08:45:18 +01001535 memmove(&(*bitenums)[v + 1], &(*bitenums)[v], (u - v) * sizeof **bitenums);
1536 memcpy(&(*bitenums)[v], &storage, sizeof storage);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001537 }
1538 }
1539 }
1540
1541done:
1542 return ret;
1543}
1544
Radek Krejci6a205692020-12-09 13:58:22 +01001545static LY_ERR
1546lys_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 +01001547 const char *context_name, struct lysc_type ***utypes_p)
Radek Krejci6a205692020-12-09 13:58:22 +01001548{
1549 LY_ERR ret = LY_SUCCESS;
1550 struct lysc_type **utypes = *utypes_p;
1551 struct lysc_type_union *un_aux = NULL;
1552
1553 LY_ARRAY_CREATE_GOTO(ctx->ctx, utypes, LY_ARRAY_COUNT(ptypes), ret, error);
1554 for (LY_ARRAY_COUNT_TYPE u = 0, additional = 0; u < LY_ARRAY_COUNT(ptypes); ++u) {
Michal Vaskoa99b3572021-02-01 11:54:58 +01001555 ret = lys_compile_type(ctx, context_pnode, context_flags, context_name, &ptypes[u], &utypes[u + additional],
1556 NULL, NULL);
Radek Krejci6a205692020-12-09 13:58:22 +01001557 LY_CHECK_GOTO(ret, error);
1558 if (utypes[u + additional]->basetype == LY_TYPE_UNION) {
1559 /* add space for additional types from the union subtype */
1560 un_aux = (struct lysc_type_union *)utypes[u + additional];
1561 LY_ARRAY_CREATE_GOTO(ctx->ctx, utypes,
1562 LY_ARRAY_COUNT(ptypes) + additional + LY_ARRAY_COUNT(un_aux->types) - LY_ARRAY_COUNT(utypes), ret, error);
1563
1564 /* copy subtypes of the subtype union */
1565 for (LY_ARRAY_COUNT_TYPE v = 0; v < LY_ARRAY_COUNT(un_aux->types); ++v) {
1566 if (un_aux->types[v]->basetype == LY_TYPE_LEAFREF) {
1567 struct lysc_type_leafref *lref;
1568
1569 /* duplicate the whole structure because of the instance-specific path resolving for realtype */
1570 utypes[u + additional] = calloc(1, sizeof(struct lysc_type_leafref));
1571 LY_CHECK_ERR_GOTO(!utypes[u + additional], LOGMEM(ctx->ctx); ret = LY_EMEM, error);
1572 lref = (struct lysc_type_leafref *)utypes[u + additional];
1573
1574 lref->basetype = LY_TYPE_LEAFREF;
Michal Vaskoe33134a2022-07-29 14:54:40 +02001575 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 +01001576 LY_CHECK_GOTO(ret, error);
Michal Vasko080064b2021-08-31 15:20:44 +02001577 lref->refcount = 1;
Radek Krejci6a205692020-12-09 13:58:22 +01001578 lref->require_instance = ((struct lysc_type_leafref *)un_aux->types[v])->require_instance;
Radek Krejci8df109d2021-04-23 12:19:08 +02001579 ret = lyplg_type_prefix_data_dup(ctx->ctx, LY_VALUE_SCHEMA_RESOLVED,
Radek Krejci2926c1b2021-03-16 14:45:45 +01001580 ((struct lysc_type_leafref *)un_aux->types[v])->prefixes, (void **)&lref->prefixes);
Radek Krejci6a205692020-12-09 13:58:22 +01001581 LY_CHECK_GOTO(ret, error);
1582 /* TODO extensions */
1583
1584 } else {
1585 utypes[u + additional] = un_aux->types[v];
Michal Vasko04338d92021-09-01 07:58:14 +02001586 LY_ATOMIC_INC_BARRIER(un_aux->types[v]->refcount);
Radek Krejci6a205692020-12-09 13:58:22 +01001587 }
1588 ++additional;
1589 LY_ARRAY_INCREMENT(utypes);
1590 }
1591 /* compensate u increment in main loop */
1592 --additional;
1593
1594 /* free the replaced union subtype */
Michal Vaskoc636ea42022-09-16 10:20:31 +02001595 lysc_type_free(&ctx->free_ctx, (struct lysc_type *)un_aux);
Radek Krejci6a205692020-12-09 13:58:22 +01001596 un_aux = NULL;
1597 } else {
1598 LY_ARRAY_INCREMENT(utypes);
1599 }
1600 }
1601
1602 *utypes_p = utypes;
1603 return LY_SUCCESS;
1604
1605error:
1606 if (un_aux) {
Michal Vaskoc636ea42022-09-16 10:20:31 +02001607 lysc_type_free(&ctx->free_ctx, (struct lysc_type *)un_aux);
Radek Krejci6a205692020-12-09 13:58:22 +01001608 }
1609 *utypes_p = utypes;
1610 return ret;
1611}
1612
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001613/**
1614 * @brief The core of the lys_compile_type() - compile information about the given type (from typedef or leaf/leaf-list).
1615 * @param[in] ctx Compile context.
1616 * @param[in] context_pnode Schema node where the type/typedef is placed to correctly find the base types.
1617 * @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 +02001618 * @param[in] context_name Name of the context node or referencing typedef for logging.
1619 * @param[in] type_p Parsed type to compile.
1620 * @param[in] basetype Base YANG built-in type of the type to compile.
1621 * @param[in] tpdfname Name of the type's typedef, serves as a flag - if it is leaf/leaf-list's type, it is NULL.
1622 * @param[in] base The latest base (compiled) type from which the current type is being derived.
1623 * @param[out] type Newly created type structure with the filled information about the type.
1624 * @return LY_ERR value.
1625 */
1626static LY_ERR
Michal Vaskoa99b3572021-02-01 11:54:58 +01001627lys_compile_type_(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags, const char *context_name,
1628 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 +02001629{
1630 LY_ERR ret = LY_SUCCESS;
1631 struct lysc_type_bin *bin;
1632 struct lysc_type_num *num;
1633 struct lysc_type_str *str;
1634 struct lysc_type_bits *bits;
1635 struct lysc_type_enum *enumeration;
1636 struct lysc_type_dec *dec;
1637 struct lysc_type_identityref *idref;
1638 struct lysc_type_leafref *lref;
Radek Krejci6a205692020-12-09 13:58:22 +01001639 struct lysc_type_union *un;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001640
1641 switch (basetype) {
1642 case LY_TYPE_BINARY:
1643 bin = (struct lysc_type_bin *)(*type);
1644
1645 /* RFC 7950 9.8.1, 9.4.4 - length, number of octets it contains */
1646 if (type_p->length) {
1647 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->length, basetype, 1, 0,
1648 base ? ((struct lysc_type_bin *)base)->length : NULL, &bin->length));
1649 if (!tpdfname) {
Radek Krejciab430862021-03-02 20:13:40 +01001650 COMPILE_EXTS_GOTO(ctx, type_p->length->exts, bin->length->exts, bin->length, ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001651 }
1652 }
1653 break;
1654 case LY_TYPE_BITS:
1655 /* RFC 7950 9.7 - bits */
1656 bits = (struct lysc_type_bits *)(*type);
1657 if (type_p->bits) {
1658 LY_CHECK_RET(lys_compile_type_enums(ctx, type_p->bits, basetype,
1659 base ? (struct lysc_type_bitenum_item *)((struct lysc_type_bits *)base)->bits : NULL,
1660 (struct lysc_type_bitenum_item **)&bits->bits));
1661 }
1662
1663 if (!base && !type_p->flags) {
1664 /* type derived from bits built-in type must contain at least one bit */
1665 if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001666 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "bit", "bits type ", tpdfname);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001667 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001668 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "bit", "bits type", "");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001669 }
1670 return LY_EVALID;
1671 }
1672 break;
1673 case LY_TYPE_DEC64:
1674 dec = (struct lysc_type_dec *)(*type);
1675
1676 /* RFC 7950 9.3.4 - fraction-digits */
1677 if (!base) {
1678 if (!type_p->fraction_digits) {
1679 if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001680 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "fraction-digits", "decimal64 type ", tpdfname);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001681 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001682 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "fraction-digits", "decimal64 type", "");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001683 }
1684 return LY_EVALID;
1685 }
1686 dec->fraction_digits = type_p->fraction_digits;
1687 } else {
1688 if (type_p->fraction_digits) {
1689 /* fraction digits is prohibited in types not directly derived from built-in decimal64 */
1690 if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001691 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001692 "Invalid fraction-digits substatement for type \"%s\" not directly derived from decimal64 built-in type.",
1693 tpdfname);
1694 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001695 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001696 "Invalid fraction-digits substatement for type not directly derived from decimal64 built-in type.");
1697 }
1698 return LY_EVALID;
1699 }
1700 dec->fraction_digits = ((struct lysc_type_dec *)base)->fraction_digits;
1701 }
1702
1703 /* RFC 7950 9.2.4 - range */
1704 if (type_p->range) {
1705 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->range, basetype, 0, dec->fraction_digits,
1706 base ? ((struct lysc_type_dec *)base)->range : NULL, &dec->range));
1707 if (!tpdfname) {
Radek Krejciab430862021-03-02 20:13:40 +01001708 COMPILE_EXTS_GOTO(ctx, type_p->range->exts, dec->range->exts, dec->range, ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001709 }
1710 }
1711 break;
1712 case LY_TYPE_STRING:
1713 str = (struct lysc_type_str *)(*type);
1714
1715 /* RFC 7950 9.4.4 - length */
1716 if (type_p->length) {
1717 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->length, basetype, 1, 0,
1718 base ? ((struct lysc_type_str *)base)->length : NULL, &str->length));
1719 if (!tpdfname) {
Radek Krejciab430862021-03-02 20:13:40 +01001720 COMPILE_EXTS_GOTO(ctx, type_p->length->exts, str->length->exts, str->length, ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001721 }
1722 } else if (base && ((struct lysc_type_str *)base)->length) {
1723 str->length = lysc_range_dup(ctx->ctx, ((struct lysc_type_str *)base)->length);
1724 }
1725
1726 /* RFC 7950 9.4.5 - pattern */
1727 if (type_p->patterns) {
1728 LY_CHECK_RET(lys_compile_type_patterns(ctx, type_p->patterns,
1729 base ? ((struct lysc_type_str *)base)->patterns : NULL, &str->patterns));
1730 } else if (base && ((struct lysc_type_str *)base)->patterns) {
1731 str->patterns = lysc_patterns_dup(ctx->ctx, ((struct lysc_type_str *)base)->patterns);
1732 }
1733 break;
1734 case LY_TYPE_ENUM:
1735 enumeration = (struct lysc_type_enum *)(*type);
1736
1737 /* RFC 7950 9.6 - enum */
1738 if (type_p->enums) {
1739 LY_CHECK_RET(lys_compile_type_enums(ctx, type_p->enums, basetype,
1740 base ? ((struct lysc_type_enum *)base)->enums : NULL, &enumeration->enums));
1741 }
1742
1743 if (!base && !type_p->flags) {
1744 /* type derived from enumerations built-in type must contain at least one enum */
1745 if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001746 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "enum", "enumeration type ", tpdfname);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001747 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001748 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "enum", "enumeration type", "");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001749 }
1750 return LY_EVALID;
1751 }
1752 break;
1753 case LY_TYPE_INT8:
1754 case LY_TYPE_UINT8:
1755 case LY_TYPE_INT16:
1756 case LY_TYPE_UINT16:
1757 case LY_TYPE_INT32:
1758 case LY_TYPE_UINT32:
1759 case LY_TYPE_INT64:
1760 case LY_TYPE_UINT64:
1761 num = (struct lysc_type_num *)(*type);
1762
1763 /* RFC 6020 9.2.4 - range */
1764 if (type_p->range) {
1765 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->range, basetype, 0, 0,
1766 base ? ((struct lysc_type_num *)base)->range : NULL, &num->range));
1767 if (!tpdfname) {
Radek Krejciab430862021-03-02 20:13:40 +01001768 COMPILE_EXTS_GOTO(ctx, type_p->range->exts, num->range->exts, num->range, ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001769 }
1770 }
1771 break;
1772 case LY_TYPE_IDENT:
1773 idref = (struct lysc_type_identityref *)(*type);
1774
1775 /* RFC 7950 9.10.2 - base */
1776 if (type_p->bases) {
1777 if (base) {
1778 /* only the directly derived identityrefs can contain base specification */
1779 if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001780 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001781 "Invalid base substatement for the type \"%s\" not directly derived from identityref built-in type.",
1782 tpdfname);
1783 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001784 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001785 "Invalid base substatement for the type not directly derived from identityref built-in type.");
1786 }
1787 return LY_EVALID;
1788 }
aPiecekf4a0a192021-08-03 15:14:17 +02001789 LY_CHECK_RET(lys_compile_identity_bases(ctx, type_p->pmod, type_p->bases, NULL, &idref->bases));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001790 }
1791
1792 if (!base && !type_p->flags) {
1793 /* type derived from identityref built-in type must contain at least one base */
1794 if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001795 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "base", "identityref type ", tpdfname);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001796 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001797 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "base", "identityref type", "");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001798 }
1799 return LY_EVALID;
1800 }
1801 break;
1802 case LY_TYPE_LEAFREF:
1803 lref = (struct lysc_type_leafref *)*type;
1804
1805 /* RFC 7950 9.9.3 - require-instance */
1806 if (type_p->flags & LYS_SET_REQINST) {
Michal Vaskoa99b3572021-02-01 11:54:58 +01001807 if (type_p->pmod->version < LYS_VERSION_1_1) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001808 if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001809 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001810 "Leafref type \"%s\" can be restricted by require-instance statement only in YANG 1.1 modules.", tpdfname);
1811 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001812 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001813 "Leafref type can be restricted by require-instance statement only in YANG 1.1 modules.");
1814 }
1815 return LY_EVALID;
1816 }
1817 lref->require_instance = type_p->require_instance;
1818 } else if (base) {
1819 /* inherit */
1820 lref->require_instance = ((struct lysc_type_leafref *)base)->require_instance;
1821 } else {
1822 /* default is true */
1823 lref->require_instance = 1;
1824 }
1825 if (type_p->path) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001826 LY_VALUE_FORMAT format;
Radek Krejci2926c1b2021-03-16 14:45:45 +01001827
Michal Vaskoe33134a2022-07-29 14:54:40 +02001828 LY_CHECK_RET(lyxp_expr_dup(ctx->ctx, type_p->path, 0, 0, &lref->path));
Radek Krejci0b013302021-03-29 15:22:32 +02001829 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 +02001830 LY_VALUE_SCHEMA, type_p->pmod, &format, (void **)&lref->prefixes));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001831 } else if (base) {
Michal Vaskoe33134a2022-07-29 14:54:40 +02001832 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 +02001833 LY_CHECK_RET(lyplg_type_prefix_data_dup(ctx->ctx, LY_VALUE_SCHEMA_RESOLVED,
Radek Krejci2926c1b2021-03-16 14:45:45 +01001834 ((struct lysc_type_leafref *)base)->prefixes, (void **)&lref->prefixes));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001835 } else if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001836 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "path", "leafref type ", tpdfname);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001837 return LY_EVALID;
1838 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001839 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "path", "leafref type", "");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001840 return LY_EVALID;
1841 }
1842 break;
1843 case LY_TYPE_INST:
1844 /* RFC 7950 9.9.3 - require-instance */
1845 if (type_p->flags & LYS_SET_REQINST) {
1846 ((struct lysc_type_instanceid *)(*type))->require_instance = type_p->require_instance;
1847 } else {
1848 /* default is true */
1849 ((struct lysc_type_instanceid *)(*type))->require_instance = 1;
1850 }
1851 break;
1852 case LY_TYPE_UNION:
1853 un = (struct lysc_type_union *)(*type);
1854
1855 /* RFC 7950 7.4 - type */
1856 if (type_p->types) {
1857 if (base) {
1858 /* only the directly derived union can contain types specification */
1859 if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001860 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001861 "Invalid type substatement for the type \"%s\" not directly derived from union built-in type.",
1862 tpdfname);
1863 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001864 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001865 "Invalid type substatement for the type not directly derived from union built-in type.");
1866 }
1867 return LY_EVALID;
1868 }
1869 /* compile the type */
Michal Vaskoa99b3572021-02-01 11:54:58 +01001870 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 +02001871 }
1872
1873 if (!base && !type_p->flags) {
1874 /* type derived from union built-in type must contain at least one type */
1875 if (tpdfname) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001876 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "type", "union type ", tpdfname);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001877 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001878 LOGVAL(ctx->ctx, LY_VCODE_MISSCHILDSTMT, "type", "union type", "");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001879 }
1880 return LY_EVALID;
1881 }
1882 break;
1883 case LY_TYPE_BOOL:
1884 case LY_TYPE_EMPTY:
1885 case LY_TYPE_UNKNOWN: /* just to complete switch */
1886 break;
1887 }
1888
1889 if (tpdfname) {
1890 switch (basetype) {
1891 case LY_TYPE_BINARY:
1892 type_p->compiled = *type;
1893 *type = calloc(1, sizeof(struct lysc_type_bin));
1894 break;
1895 case LY_TYPE_BITS:
1896 type_p->compiled = *type;
1897 *type = calloc(1, sizeof(struct lysc_type_bits));
1898 break;
1899 case LY_TYPE_DEC64:
1900 type_p->compiled = *type;
1901 *type = calloc(1, sizeof(struct lysc_type_dec));
1902 break;
1903 case LY_TYPE_STRING:
1904 type_p->compiled = *type;
1905 *type = calloc(1, sizeof(struct lysc_type_str));
1906 break;
1907 case LY_TYPE_ENUM:
1908 type_p->compiled = *type;
1909 *type = calloc(1, sizeof(struct lysc_type_enum));
1910 break;
1911 case LY_TYPE_INT8:
1912 case LY_TYPE_UINT8:
1913 case LY_TYPE_INT16:
1914 case LY_TYPE_UINT16:
1915 case LY_TYPE_INT32:
1916 case LY_TYPE_UINT32:
1917 case LY_TYPE_INT64:
1918 case LY_TYPE_UINT64:
1919 type_p->compiled = *type;
1920 *type = calloc(1, sizeof(struct lysc_type_num));
1921 break;
1922 case LY_TYPE_IDENT:
1923 type_p->compiled = *type;
1924 *type = calloc(1, sizeof(struct lysc_type_identityref));
1925 break;
1926 case LY_TYPE_LEAFREF:
1927 type_p->compiled = *type;
1928 *type = calloc(1, sizeof(struct lysc_type_leafref));
1929 break;
1930 case LY_TYPE_INST:
1931 type_p->compiled = *type;
1932 *type = calloc(1, sizeof(struct lysc_type_instanceid));
1933 break;
1934 case LY_TYPE_UNION:
1935 type_p->compiled = *type;
1936 *type = calloc(1, sizeof(struct lysc_type_union));
1937 break;
1938 case LY_TYPE_BOOL:
1939 case LY_TYPE_EMPTY:
1940 case LY_TYPE_UNKNOWN: /* just to complete switch */
1941 break;
1942 }
1943 }
1944 LY_CHECK_ERR_RET(!(*type), LOGMEM(ctx->ctx), LY_EMEM);
1945
1946cleanup:
1947 return ret;
1948}
1949
1950LY_ERR
Michal Vaskoa99b3572021-02-01 11:54:58 +01001951lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags, const char *context_name,
1952 struct lysp_type *type_p, struct lysc_type **type, const char **units, struct lysp_qname **dflt)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001953{
1954 LY_ERR ret = LY_SUCCESS;
1955 ly_bool dummyloops = 0;
1956 struct type_context {
1957 const struct lysp_tpdf *tpdf;
1958 struct lysp_node *node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001959 } *tctx, *tctx_prev = NULL, *tctx_iter;
1960 LY_DATA_TYPE basetype = LY_TYPE_UNKNOWN;
1961 struct lysc_type *base = NULL, *prev_type;
1962 struct ly_set tpdf_chain = {0};
Michal Vasko388a6632021-08-06 11:27:43 +02001963 struct lyplg_type *plugin;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001964
1965 (*type) = NULL;
1966 if (dflt) {
1967 *dflt = NULL;
1968 }
1969
1970 tctx = calloc(1, sizeof *tctx);
1971 LY_CHECK_ERR_RET(!tctx, LOGMEM(ctx->ctx), LY_EMEM);
Michal Vaskoedb0fa52022-10-04 10:36:00 +02001972 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 +02001973 ret == LY_SUCCESS;
Michal Vaskoedb0fa52022-10-04 10:36:00 +02001974 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 +01001975 &basetype, &tctx->tpdf, &tctx->node)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001976 if (basetype) {
1977 break;
1978 }
1979
1980 /* check status */
Michal Vaskoa99b3572021-02-01 11:54:58 +01001981 ret = lysc_check_status(ctx, context_flags, (void *)type_p->pmod, context_name, tctx->tpdf->flags,
1982 (void *)tctx->tpdf->type.pmod, tctx->node ? tctx->node->name : tctx->tpdf->name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001983 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
1984
1985 if (units && !*units) {
1986 /* inherit units */
1987 DUP_STRING(ctx->ctx, tctx->tpdf->units, *units, ret);
1988 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
1989 }
1990 if (dflt && !*dflt && tctx->tpdf->dflt.str) {
1991 /* inherit default */
1992 *dflt = (struct lysp_qname *)&tctx->tpdf->dflt;
1993 }
1994 if (dummyloops && (!units || *units) && dflt && *dflt) {
1995 basetype = ((struct type_context *)tpdf_chain.objs[tpdf_chain.count - 1])->tpdf->type.compiled->basetype;
1996 break;
1997 }
1998
Michal Vasko080064b2021-08-31 15:20:44 +02001999 if (tctx->tpdf->type.compiled && (tctx->tpdf->type.compiled->refcount == 1)) {
Radek Krejci720d2612021-03-03 19:44:22 +01002000 /* context recompilation - everything was freed previously (the only reference is from the parsed type itself)
2001 * and we need now recompile the type again in the updated context. */
Michal Vaskoc636ea42022-09-16 10:20:31 +02002002 lysc_type_free(&ctx->free_ctx, tctx->tpdf->type.compiled);
Radek Krejci720d2612021-03-03 19:44:22 +01002003 ((struct lysp_tpdf *)tctx->tpdf)->type.compiled = NULL;
2004 }
2005
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002006 if (tctx->tpdf->type.compiled) {
2007 /* it is not necessary to continue, the rest of the chain was already compiled,
2008 * but we still may need to inherit default and units values, so start dummy loops */
2009 basetype = tctx->tpdf->type.compiled->basetype;
2010 ret = ly_set_add(&tpdf_chain, tctx, 1, NULL);
2011 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
2012
2013 if ((units && !*units) || (dflt && !*dflt)) {
2014 dummyloops = 1;
2015 goto preparenext;
2016 } else {
2017 tctx = NULL;
2018 break;
2019 }
2020 }
2021
2022 /* circular typedef reference detection */
2023 for (uint32_t u = 0; u < tpdf_chain.count; u++) {
2024 /* local part */
2025 tctx_iter = (struct type_context *)tpdf_chain.objs[u];
Michal Vaskoa99b3572021-02-01 11:54:58 +01002026 if (tctx_iter->tpdf == tctx->tpdf) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002027 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002028 "Invalid \"%s\" type reference - circular chain of types detected.", tctx->tpdf->name);
2029 free(tctx);
2030 ret = LY_EVALID;
2031 goto cleanup;
2032 }
2033 }
2034 for (uint32_t u = 0; u < ctx->tpdf_chain.count; u++) {
2035 /* global part for unions corner case */
2036 tctx_iter = (struct type_context *)ctx->tpdf_chain.objs[u];
Michal Vaskoa99b3572021-02-01 11:54:58 +01002037 if (tctx_iter->tpdf == tctx->tpdf) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002038 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002039 "Invalid \"%s\" type reference - circular chain of types detected.", tctx->tpdf->name);
2040 free(tctx);
2041 ret = LY_EVALID;
2042 goto cleanup;
2043 }
2044 }
2045
2046 /* store information for the following processing */
2047 ret = ly_set_add(&tpdf_chain, tctx, 1, NULL);
2048 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
2049
2050preparenext:
2051 /* prepare next loop */
2052 tctx_prev = tctx;
2053 tctx = calloc(1, sizeof *tctx);
2054 LY_CHECK_ERR_RET(!tctx, LOGMEM(ctx->ctx), LY_EMEM);
2055 }
2056 free(tctx);
2057
2058 /* allocate type according to the basetype */
2059 switch (basetype) {
2060 case LY_TYPE_BINARY:
2061 *type = calloc(1, sizeof(struct lysc_type_bin));
2062 break;
2063 case LY_TYPE_BITS:
2064 *type = calloc(1, sizeof(struct lysc_type_bits));
2065 break;
2066 case LY_TYPE_BOOL:
2067 case LY_TYPE_EMPTY:
2068 *type = calloc(1, sizeof(struct lysc_type));
2069 break;
2070 case LY_TYPE_DEC64:
2071 *type = calloc(1, sizeof(struct lysc_type_dec));
2072 break;
2073 case LY_TYPE_ENUM:
2074 *type = calloc(1, sizeof(struct lysc_type_enum));
2075 break;
2076 case LY_TYPE_IDENT:
2077 *type = calloc(1, sizeof(struct lysc_type_identityref));
2078 break;
2079 case LY_TYPE_INST:
2080 *type = calloc(1, sizeof(struct lysc_type_instanceid));
2081 break;
2082 case LY_TYPE_LEAFREF:
2083 *type = calloc(1, sizeof(struct lysc_type_leafref));
2084 break;
2085 case LY_TYPE_STRING:
2086 *type = calloc(1, sizeof(struct lysc_type_str));
2087 break;
2088 case LY_TYPE_UNION:
2089 *type = calloc(1, sizeof(struct lysc_type_union));
2090 break;
2091 case LY_TYPE_INT8:
2092 case LY_TYPE_UINT8:
2093 case LY_TYPE_INT16:
2094 case LY_TYPE_UINT16:
2095 case LY_TYPE_INT32:
2096 case LY_TYPE_UINT32:
2097 case LY_TYPE_INT64:
2098 case LY_TYPE_UINT64:
2099 *type = calloc(1, sizeof(struct lysc_type_num));
2100 break;
2101 case LY_TYPE_UNKNOWN:
Radek Krejci2efc45b2020-12-22 16:25:44 +01002102 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002103 "Referenced type \"%s\" not found.", tctx_prev ? tctx_prev->tpdf->type.name : type_p->name);
2104 ret = LY_EVALID;
2105 goto cleanup;
2106 }
2107 LY_CHECK_ERR_GOTO(!(*type), LOGMEM(ctx->ctx), cleanup);
2108 if (~type_substmt_map[basetype] & type_p->flags) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002109 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Invalid type restrictions for %s type.",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002110 ly_data_type2str[basetype]);
2111 free(*type);
2112 (*type) = NULL;
2113 ret = LY_EVALID;
2114 goto cleanup;
2115 }
2116
2117 /* get restrictions from the referred typedefs */
2118 for (uint32_t u = tpdf_chain.count - 1; u + 1 > 0; --u) {
2119 tctx = (struct type_context *)tpdf_chain.objs[u];
2120
2121 /* remember the typedef context for circular check */
2122 ret = ly_set_add(&ctx->tpdf_chain, tctx, 1, NULL);
2123 LY_CHECK_GOTO(ret, cleanup);
2124
2125 if (tctx->tpdf->type.compiled) {
Michal Vasko388a6632021-08-06 11:27:43 +02002126 /* already compiled */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002127 base = tctx->tpdf->type.compiled;
2128 continue;
Michal Vasko388a6632021-08-06 11:27:43 +02002129 }
2130
Michal Vaskoddd76592022-01-17 13:34:48 +01002131 /* try to find loaded user type plugins */
2132 plugin = lyplg_find(LYPLG_TYPE, tctx->tpdf->type.pmod->mod->name, tctx->tpdf->type.pmod->mod->revision,
2133 tctx->tpdf->name);
Haithem Ben Ghorbal45be15f2022-07-12 18:02:36 +02002134 if (!plugin && base) {
2135 /* use the base type implementation if available */
2136 plugin = base->plugin;
2137 }
Michal Vaskoddd76592022-01-17 13:34:48 +01002138 if (!plugin) {
2139 /* use the internal built-in type implementation */
2140 plugin = lyplg_find(LYPLG_TYPE, "", NULL, ly_data_type2str[basetype]);
2141 }
Michal Vasko388a6632021-08-06 11:27:43 +02002142 assert(plugin);
2143
2144 if ((basetype != LY_TYPE_LEAFREF) && (u != tpdf_chain.count - 1) && !(tctx->tpdf->type.flags) &&
2145 (plugin == base->plugin)) {
2146 /* no change, reuse the compiled base */
2147 ((struct lysp_tpdf *)tctx->tpdf)->type.compiled = base;
Michal Vasko04338d92021-09-01 07:58:14 +02002148 LY_ATOMIC_INC_BARRIER(base->refcount);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002149 continue;
2150 }
2151
Michal Vasko04338d92021-09-01 07:58:14 +02002152 LY_ATOMIC_INC_BARRIER((*type)->refcount);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002153 if (~type_substmt_map[basetype] & tctx->tpdf->type.flags) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002154 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Invalid type \"%s\" restriction(s) for %s type.",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002155 tctx->tpdf->name, ly_data_type2str[basetype]);
2156 ret = LY_EVALID;
2157 goto cleanup;
2158 } else if ((basetype == LY_TYPE_EMPTY) && tctx->tpdf->dflt.str) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002159 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002160 "Invalid type \"%s\" - \"empty\" type must not have a default value (%s).",
2161 tctx->tpdf->name, tctx->tpdf->dflt.str);
2162 ret = LY_EVALID;
2163 goto cleanup;
2164 }
2165
2166 (*type)->basetype = basetype;
Michal Vasko388a6632021-08-06 11:27:43 +02002167 (*type)->plugin = plugin;
2168
Radek Krejci4f2e3e52021-03-30 14:20:28 +02002169 /* collect extensions */
2170 COMPILE_EXTS_GOTO(ctx, tctx->tpdf->type.exts, (*type)->exts, (*type), ret, cleanup);
Michal Vasko388a6632021-08-06 11:27:43 +02002171
2172 /* compile the new typedef */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002173 prev_type = *type;
Michal Vaskoa99b3572021-02-01 11:54:58 +01002174 ret = lys_compile_type_(ctx, tctx->node, tctx->tpdf->flags, tctx->tpdf->name,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002175 &((struct lysp_tpdf *)tctx->tpdf)->type, basetype, tctx->tpdf->name, base, type);
2176 LY_CHECK_GOTO(ret, cleanup);
2177 base = prev_type;
2178 }
2179 /* remove the processed typedef contexts from the stack for circular check */
2180 ctx->tpdf_chain.count = ctx->tpdf_chain.count - tpdf_chain.count;
2181
2182 /* process the type definition in leaf */
2183 if (type_p->flags || !base || (basetype == LY_TYPE_LEAFREF)) {
2184 /* get restrictions from the node itself */
2185 (*type)->basetype = basetype;
Radek Krejcibf940f92021-03-24 21:04:13 +01002186 (*type)->plugin = base ? base->plugin : lyplg_find(LYPLG_TYPE, "", NULL, ly_data_type2str[basetype]);
Michal Vasko04338d92021-09-01 07:58:14 +02002187 LY_ATOMIC_INC_BARRIER((*type)->refcount);
Michal Vaskoa99b3572021-02-01 11:54:58 +01002188 ret = lys_compile_type_(ctx, context_pnode, context_flags, context_name, type_p, basetype, NULL, base, type);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002189 LY_CHECK_GOTO(ret, cleanup);
2190 } else if ((basetype != LY_TYPE_BOOL) && (basetype != LY_TYPE_EMPTY)) {
2191 /* no specific restriction in leaf's type definition, copy from the base */
2192 free(*type);
2193 (*type) = base;
Michal Vasko04338d92021-09-01 07:58:14 +02002194 LY_ATOMIC_INC_BARRIER((*type)->refcount);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002195 }
2196
Radek Krejciab430862021-03-02 20:13:40 +01002197 COMPILE_EXTS_GOTO(ctx, type_p->exts, (*type)->exts, (*type), ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002198
2199cleanup:
2200 ly_set_erase(&tpdf_chain, free);
2201 return ret;
2202}
2203
2204/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002205 * @brief Check uniqness of the node/action/notification name.
2206 *
2207 * Data nodes, actions/RPCs and Notifications are stored separately (in distinguish lists) in the schema
2208 * structures, but they share the namespace so we need to check their name collisions.
2209 *
2210 * @param[in] ctx Compile context.
2211 * @param[in] parent Parent of the nodes to check, can be NULL.
2212 * @param[in] name Name of the item to find in the given lists.
2213 * @param[in] exclude Node that was just added that should be excluded from the name checking.
2214 * @return LY_SUCCESS in case of unique name, LY_EEXIST otherwise.
2215 */
2216static LY_ERR
2217lys_compile_node_uniqness(struct lysc_ctx *ctx, const struct lysc_node *parent, const char *name,
2218 const struct lysc_node *exclude)
2219{
2220 const struct lysc_node *iter, *iter2;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002221 const struct lysc_node_action *actions;
2222 const struct lysc_node_notif *notifs;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002223 uint32_t getnext_flags;
Radek Krejci078e4342021-02-12 18:17:26 +01002224 struct ly_set parent_choices = {0};
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002225
2226#define CHECK_NODE(iter, exclude, name) (iter != (void *)exclude && (iter)->module == exclude->module && !strcmp(name, (iter)->name))
2227
2228 if (exclude->nodetype == LYS_CASE) {
2229 /* check restricted only to all the cases */
2230 assert(parent->nodetype == LYS_CHOICE);
Michal Vasko544e58a2021-01-28 14:33:41 +01002231 LY_LIST_FOR(lysc_node_child(parent), iter) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002232 if (CHECK_NODE(iter, exclude, name)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002233 LOGVAL(ctx->ctx, LY_VCODE_DUPIDENT, name, "case");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002234 return LY_EEXIST;
2235 }
2236 }
2237
2238 return LY_SUCCESS;
2239 }
2240
2241 /* no reason for our parent to be choice anymore */
2242 assert(!parent || (parent->nodetype != LYS_CHOICE));
2243
2244 if (parent && (parent->nodetype == LYS_CASE)) {
2245 /* move to the first data definition parent */
Radek Krejci078e4342021-02-12 18:17:26 +01002246
2247 /* but remember the choice nodes on the parents path to avoid believe they collide with our node */
2248 iter = lysc_data_parent(parent);
2249 do {
2250 parent = parent->parent;
2251 if (parent && (parent->nodetype == LYS_CHOICE)) {
2252 ly_set_add(&parent_choices, (void *)parent, 1, NULL);
2253 }
2254 } while (parent != iter);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002255 }
2256
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01002257 getnext_flags = LYS_GETNEXT_WITHCHOICE;
Michal Vaskob322b7d2021-01-29 17:22:24 +01002258 if (parent && (parent->nodetype & (LYS_RPC | LYS_ACTION))) {
2259 /* move to the inout to avoid traversing a not-filled-yet (the other) node */
2260 if (exclude->flags & LYS_IS_OUTPUT) {
2261 getnext_flags |= LYS_GETNEXT_OUTPUT;
2262 parent = lysc_node_child(parent)->next;
2263 } else {
2264 parent = lysc_node_child(parent);
2265 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002266 }
2267
2268 iter = NULL;
Radek Krejci5fa32a32021-02-08 18:12:38 +01002269 if (!parent && ctx->ext) {
2270 while ((iter = lys_getnext_ext(iter, parent, ctx->ext, getnext_flags))) {
2271 if (!ly_set_contains(&parent_choices, (void *)iter, NULL) && CHECK_NODE(iter, exclude, name)) {
2272 goto error;
2273 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002274
Radek Krejci5fa32a32021-02-08 18:12:38 +01002275 /* we must compare with both the choice and all its nested data-definiition nodes (but not recursively) */
2276 if (iter->nodetype == LYS_CHOICE) {
2277 iter2 = NULL;
2278 while ((iter2 = lys_getnext_ext(iter2, iter, NULL, 0))) {
2279 if (CHECK_NODE(iter2, exclude, name)) {
2280 goto error;
2281 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002282 }
2283 }
2284 }
Radek Krejci5fa32a32021-02-08 18:12:38 +01002285 } else {
2286 while ((iter = lys_getnext(iter, parent, ctx->cur_mod->compiled, getnext_flags))) {
2287 if (!ly_set_contains(&parent_choices, (void *)iter, NULL) && CHECK_NODE(iter, exclude, name)) {
2288 goto error;
2289 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002290
Radek Krejci5fa32a32021-02-08 18:12:38 +01002291 /* we must compare with both the choice and all its nested data-definiition nodes (but not recursively) */
2292 if (iter->nodetype == LYS_CHOICE) {
2293 iter2 = NULL;
2294 while ((iter2 = lys_getnext(iter2, iter, NULL, 0))) {
2295 if (CHECK_NODE(iter2, exclude, name)) {
2296 goto error;
2297 }
2298 }
2299 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002300 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002301
Radek Krejci5fa32a32021-02-08 18:12:38 +01002302 actions = parent ? lysc_node_actions(parent) : ctx->cur_mod->compiled->rpcs;
2303 LY_LIST_FOR((struct lysc_node *)actions, iter) {
2304 if (CHECK_NODE(iter, exclude, name)) {
2305 goto error;
2306 }
2307 }
2308
2309 notifs = parent ? lysc_node_notifs(parent) : ctx->cur_mod->compiled->notifs;
2310 LY_LIST_FOR((struct lysc_node *)notifs, iter) {
2311 if (CHECK_NODE(iter, exclude, name)) {
2312 goto error;
2313 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002314 }
2315 }
Radek Krejci078e4342021-02-12 18:17:26 +01002316 ly_set_erase(&parent_choices, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002317 return LY_SUCCESS;
2318
2319error:
Radek Krejci078e4342021-02-12 18:17:26 +01002320 ly_set_erase(&parent_choices, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +01002321 LOGVAL(ctx->ctx, LY_VCODE_DUPIDENT, name, "data definition/RPC/action/notification");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002322 return LY_EEXIST;
2323
2324#undef CHECK_NODE
2325}
2326
Radek Krejci2a9fc652021-01-22 17:44:34 +01002327/**
2328 * @brief Connect the node into the siblings list and check its name uniqueness. Also,
2329 * keep specific order of augments targetting the same node.
2330 *
2331 * @param[in] ctx Compile context
2332 * @param[in] parent Parent node holding the children list, in case of node from a choice's case,
2333 * the choice itself is expected instead of a specific case node.
2334 * @param[in] node Schema node to connect into the list.
2335 * @return LY_ERR value - LY_SUCCESS or LY_EEXIST.
2336 * In case of LY_EEXIST, the node is actually kept in the tree, so do not free it directly.
2337 */
2338static LY_ERR
2339lys_compile_node_connect(struct lysc_ctx *ctx, struct lysc_node *parent, struct lysc_node *node)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002340{
Radek Krejci2a9fc652021-01-22 17:44:34 +01002341 struct lysc_node **children, *anchor = NULL;
2342 int insert_after = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002343
Radek Krejci2a9fc652021-01-22 17:44:34 +01002344 node->parent = parent;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002345
Radek Krejci2a9fc652021-01-22 17:44:34 +01002346 if (parent) {
Michal Vasko544e58a2021-01-28 14:33:41 +01002347 if (node->nodetype == LYS_INPUT) {
2348 assert(parent->nodetype & (LYS_ACTION | LYS_RPC));
2349 /* input node is part of the action but link it with output */
2350 node->next = &((struct lysc_node_action *)parent)->output.node;
2351 node->prev = node->next;
2352 return LY_SUCCESS;
2353 } else if (node->nodetype == LYS_OUTPUT) {
2354 /* output node is part of the action but link it with input */
2355 node->next = NULL;
2356 node->prev = &((struct lysc_node_action *)parent)->input.node;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002357 return LY_SUCCESS;
2358 } else if (node->nodetype == LYS_ACTION) {
2359 children = (struct lysc_node **)lysc_node_actions_p(parent);
2360 } else if (node->nodetype == LYS_NOTIF) {
2361 children = (struct lysc_node **)lysc_node_notifs_p(parent);
2362 } else {
Michal Vasko544e58a2021-01-28 14:33:41 +01002363 children = lysc_node_child_p(parent);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002364 }
2365 assert(children);
2366
2367 if (!(*children)) {
2368 /* first child */
2369 *children = node;
2370 } else if (node->flags & LYS_KEY) {
2371 /* special handling of adding keys */
2372 assert(node->module == parent->module);
2373 anchor = *children;
2374 if (anchor->flags & LYS_KEY) {
2375 while ((anchor->flags & LYS_KEY) && anchor->next) {
2376 anchor = anchor->next;
2377 }
2378 /* insert after the last key */
2379 insert_after = 1;
2380 } /* else insert before anchor (at the beginning) */
2381 } else if ((*children)->prev->module == node->module) {
2382 /* last child is from the same module, keep the order and insert at the end */
2383 anchor = (*children)->prev;
2384 insert_after = 1;
2385 } else if (parent->module == node->module) {
2386 /* adding module child after some augments were connected */
2387 for (anchor = *children; anchor->module == node->module; anchor = anchor->next) {}
2388 } else {
2389 /* some augments are already connected and we are connecting new ones,
2390 * keep module name order and insert the node into the children list */
2391 anchor = *children;
2392 do {
2393 anchor = anchor->prev;
2394
2395 /* check that we have not found the last augment node from our module or
2396 * the first augment node from a "smaller" module or
2397 * the first node from a local module */
2398 if ((anchor->module == node->module) || (strcmp(anchor->module->name, node->module->name) < 0) ||
2399 (anchor->module == parent->module)) {
2400 /* insert after */
2401 insert_after = 1;
2402 break;
2403 }
2404
2405 /* we have traversed all the nodes, insert before anchor (as the first node) */
2406 } while (anchor->prev->next);
2407 }
2408
2409 /* insert */
2410 if (anchor) {
2411 if (insert_after) {
2412 node->next = anchor->next;
2413 node->prev = anchor;
2414 anchor->next = node;
2415 if (node->next) {
2416 /* middle node */
2417 node->next->prev = node;
2418 } else {
2419 /* last node */
2420 (*children)->prev = node;
2421 }
2422 } else {
2423 node->next = anchor;
2424 node->prev = anchor->prev;
2425 anchor->prev = node;
2426 if (anchor == *children) {
2427 /* first node */
2428 *children = node;
2429 } else {
2430 /* middle node */
2431 node->prev->next = node;
2432 }
2433 }
2434 }
2435
2436 /* check the name uniqueness (even for an only child, it may be in case) */
2437 if (lys_compile_node_uniqness(ctx, parent, node->name, node)) {
2438 return LY_EEXIST;
2439 }
2440 } else {
2441 /* top-level element */
2442 struct lysc_node **list;
2443
Radek Krejci6b88a462021-02-17 12:39:34 +01002444 if (ctx->ext) {
Michal Vasko55bce0e2022-02-15 10:46:08 +01002445 /* container matches all data nodes */
2446 lysc_ext_substmt(ctx->ext, LY_STMT_CONTAINER, (void **)&list, NULL);
Radek Krejci6b88a462021-02-17 12:39:34 +01002447 } else if (node->nodetype == LYS_RPC) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01002448 list = (struct lysc_node **)&ctx->cur_mod->compiled->rpcs;
2449 } else if (node->nodetype == LYS_NOTIF) {
2450 list = (struct lysc_node **)&ctx->cur_mod->compiled->notifs;
2451 } else {
2452 list = &ctx->cur_mod->compiled->data;
2453 }
2454 if (!(*list)) {
2455 *list = node;
2456 } else {
2457 /* insert at the end of the module's top-level nodes list */
2458 (*list)->prev->next = node;
2459 node->prev = (*list)->prev;
2460 (*list)->prev = node;
2461 }
2462
2463 /* check the name uniqueness on top-level */
2464 if (lys_compile_node_uniqness(ctx, NULL, node->name, node)) {
2465 return LY_EEXIST;
2466 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002467 }
2468
Radek Krejci2a9fc652021-01-22 17:44:34 +01002469 return LY_SUCCESS;
2470}
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002471
Radek Krejci2a9fc652021-01-22 17:44:34 +01002472/**
Michal Vaskod1e53b92021-01-28 13:11:06 +01002473 * @brief Set config and operation flags for a node.
Radek Krejci2a9fc652021-01-22 17:44:34 +01002474 *
2475 * @param[in] ctx Compile context.
Michal Vaskod1e53b92021-01-28 13:11:06 +01002476 * @param[in] node Compiled node flags to set.
Radek Krejci2a9fc652021-01-22 17:44:34 +01002477 * @return LY_ERR value.
2478 */
2479static LY_ERR
Radek Krejci91531e12021-02-08 19:57:54 +01002480lys_compile_config(struct lysc_ctx *ctx, struct lysc_node *node)
Radek Krejci2a9fc652021-01-22 17:44:34 +01002481{
2482 /* case never has any explicit config */
2483 assert((node->nodetype != LYS_CASE) || !(node->flags & LYS_CONFIG_MASK));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002484
Michal Vasko7c565922021-06-10 14:58:27 +02002485 if (ctx->compile_opts & LYS_COMPILE_NO_CONFIG) {
Radek Krejci91531e12021-02-08 19:57:54 +01002486 /* ignore config statements inside Notification/RPC/action/... data */
Radek Krejci2a9fc652021-01-22 17:44:34 +01002487 node->flags &= ~LYS_CONFIG_MASK;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002488 } else if (!(node->flags & LYS_CONFIG_MASK)) {
2489 /* config not explicitly set, inherit it from parent */
Michal Vaskoecdc2222022-01-24 08:45:44 +01002490 assert(!node->parent || (node->parent->flags & LYS_CONFIG_MASK) || (node->parent->nodetype & LYS_AUGMENT));
2491 if (node->parent && (node->parent->flags & LYS_CONFIG_MASK)) {
Radek Krejci91531e12021-02-08 19:57:54 +01002492 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002493 } else {
2494 /* default is config true */
2495 node->flags |= LYS_CONFIG_W;
2496 }
2497 } else {
2498 /* config set explicitly */
2499 node->flags |= LYS_SET_CONFIG;
2500 }
2501
Radek Krejci91531e12021-02-08 19:57:54 +01002502 if (node->parent && (node->parent->flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
Michal Vaskod1e53b92021-01-28 13:11:06 +01002503 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Configuration node cannot be child of any state data node.");
Radek Krejci2a9fc652021-01-22 17:44:34 +01002504 return LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002505 }
2506
Radek Krejci2a9fc652021-01-22 17:44:34 +01002507 return LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002508}
2509
Radek Krejci91531e12021-02-08 19:57:54 +01002510/**
2511 * @brief Set various flags of the compiled nodes
2512 *
2513 * @param[in] ctx Compile context.
2514 * @param[in] node Compiled node where the flags will be set.
Michal Vaskoedb0fa52022-10-04 10:36:00 +02002515 * @param[in] inherited_status Explicitly inherited status (from uses/extension instance), if any.
Radek Krejci91531e12021-02-08 19:57:54 +01002516 */
2517static LY_ERR
Michal Vaskoedb0fa52022-10-04 10:36:00 +02002518lys_compile_node_flags(struct lysc_ctx *ctx, struct lysc_node *node, const uint16_t *inherited_status)
Radek Krejci91531e12021-02-08 19:57:54 +01002519{
Michal Vaskoedb0fa52022-10-04 10:36:00 +02002520 uint16_t parent_flags;
2521 const char *parent_name;
2522
Radek Krejci91531e12021-02-08 19:57:54 +01002523 /* inherit config flags */
2524 LY_CHECK_RET(lys_compile_config(ctx, node));
2525
2526 /* status - it is not inherited by specification, but it does not make sense to have
2527 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
Michal Vaskoedb0fa52022-10-04 10:36:00 +02002528 parent_flags = inherited_status ? *inherited_status : (node->parent ? node->parent->flags : 0);
2529 parent_name = inherited_status ? "<schema-only-node>" : (node->parent ? node->parent->name : NULL);
2530 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 +01002531
2532 /* other flags */
Michal Vasko7c565922021-06-10 14:58:27 +02002533 if ((ctx->compile_opts & LYS_IS_INPUT) && (node->nodetype != LYS_INPUT)) {
Radek Krejci91531e12021-02-08 19:57:54 +01002534 node->flags |= LYS_IS_INPUT;
Michal Vasko7c565922021-06-10 14:58:27 +02002535 } else if ((ctx->compile_opts & LYS_IS_OUTPUT) && (node->nodetype != LYS_OUTPUT)) {
Radek Krejci91531e12021-02-08 19:57:54 +01002536 node->flags |= LYS_IS_OUTPUT;
Michal Vasko7c565922021-06-10 14:58:27 +02002537 } else if ((ctx->compile_opts & LYS_IS_NOTIF) && (node->nodetype != LYS_NOTIF)) {
Radek Krejci91531e12021-02-08 19:57:54 +01002538 node->flags |= LYS_IS_NOTIF;
2539 }
2540
2541 return LY_SUCCESS;
2542}
2543
Michal Vaskoedb0fa52022-10-04 10:36:00 +02002544static LY_ERR
2545lys_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 +01002546 LY_ERR (*node_compile_spec)(struct lysc_ctx *, struct lysp_node *, struct lysc_node *),
2547 struct lysc_node *node, struct ly_set *child_set)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002548{
2549 LY_ERR ret = LY_SUCCESS;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01002550 ly_bool not_supported, enabled;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002551 struct lysp_node *dev_pnode = NULL;
Radek Krejci9a3823e2021-01-27 20:26:46 +01002552 struct lysp_when *pwhen = NULL;
Michal Vaskoe02e7402021-07-23 08:29:28 +02002553 uint32_t prev_opts = ctx->compile_opts;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002554
Radek Krejci2a9fc652021-01-22 17:44:34 +01002555 node->nodetype = pnode->nodetype;
2556 node->module = ctx->cur_mod;
Radek Krejci91531e12021-02-08 19:57:54 +01002557 node->parent = parent;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002558 node->prev = node;
aPiecek9922ea92021-04-12 07:59:20 +02002559 node->priv = ctx->ctx->flags & LY_CTX_SET_PRIV_PARSED ? pnode : NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002560
Radek Krejci2a9fc652021-01-22 17:44:34 +01002561 /* compile any deviations for this node */
2562 LY_CHECK_GOTO(ret = lys_compile_node_deviations_refines(ctx, pnode, parent, &dev_pnode, &not_supported), error);
Michal Vaskoe02e7402021-07-23 08:29:28 +02002563 if (not_supported && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
2564 /* if not supported, keep it just like disabled nodes by if-feature */
2565 ly_set_add(&ctx->unres->disabled, node, 1, NULL);
2566 ctx->compile_opts |= LYS_COMPILE_DISABLED;
2567 }
2568 if (dev_pnode) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01002569 pnode = dev_pnode;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002570 }
2571
Radek Krejci2a9fc652021-01-22 17:44:34 +01002572 node->flags = pnode->flags & LYS_FLAGS_COMPILED_MASK;
Michal Vaskodfd254d2021-06-24 09:24:59 +02002573 DUP_STRING_GOTO(ctx->ctx, pnode->name, node->name, ret, error);
2574 DUP_STRING_GOTO(ctx->ctx, pnode->dsc, node->dsc, ret, error);
2575 DUP_STRING_GOTO(ctx->ctx, pnode->ref, node->ref, ret, error);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002576
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01002577 /* if-features */
Radek Krejci2a9fc652021-01-22 17:44:34 +01002578 LY_CHECK_GOTO(ret = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), error);
Michal Vasko7c565922021-06-10 14:58:27 +02002579 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
Michal Vasko30ab8e72021-04-19 12:47:52 +02002580 ly_set_add(&ctx->unres->disabled, node, 1, NULL);
Michal Vasko7c565922021-06-10 14:58:27 +02002581 ctx->compile_opts |= LYS_COMPILE_DISABLED;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01002582 }
2583
Radek Krejci91531e12021-02-08 19:57:54 +01002584 /* config, status and other flags */
Michal Vaskoedb0fa52022-10-04 10:36:00 +02002585 ret = lys_compile_node_flags(ctx, node, inherited_status);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002586 LY_CHECK_GOTO(ret, error);
2587
2588 /* list ordering */
2589 if (node->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
Michal Vaskod1e53b92021-01-28 13:11:06 +01002590 if ((node->flags & (LYS_CONFIG_R | LYS_IS_OUTPUT | LYS_IS_NOTIF)) && (node->flags & LYS_ORDBY_MASK)) {
Michal Vasko5676f4e2021-04-06 17:14:45 +02002591 LOGVRB("The ordered-by statement is ignored in lists representing %s (%s).",
Radek Krejci91531e12021-02-08 19:57:54 +01002592 (node->flags & LYS_IS_OUTPUT) ? "RPC/action output parameters" :
Michal Vasko7c565922021-06-10 14:58:27 +02002593 (ctx->compile_opts & LYS_IS_NOTIF) ? "notification content" : "state data", ctx->path);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002594 node->flags &= ~LYS_ORDBY_MASK;
2595 node->flags |= LYS_ORDBY_SYSTEM;
2596 } else if (!(node->flags & LYS_ORDBY_MASK)) {
2597 /* default ordering is system */
2598 node->flags |= LYS_ORDBY_SYSTEM;
2599 }
2600 }
2601
Radek Krejci2a9fc652021-01-22 17:44:34 +01002602 /* insert into parent's children/compiled module (we can no longer free the node separately on error) */
2603 LY_CHECK_GOTO(ret = lys_compile_node_connect(ctx, parent, node), cleanup);
2604
Radek Krejci9a3823e2021-01-27 20:26:46 +01002605 if ((pwhen = lysp_node_when(pnode))) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01002606 /* compile when */
Michal Vaskodfd254d2021-06-24 09:24:59 +02002607 ret = lys_compile_when(ctx, pwhen, pnode->flags, node, lysc_data_node(node), node, NULL);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002608 LY_CHECK_GOTO(ret, cleanup);
2609 }
2610
Radek Krejci2a9fc652021-01-22 17:44:34 +01002611 /* nodetype-specific part */
2612 LY_CHECK_GOTO(ret = node_compile_spec(ctx, pnode, node), cleanup);
2613
2614 /* final compilation tasks that require the node to be connected */
Radek Krejciab430862021-03-02 20:13:40 +01002615 COMPILE_EXTS_GOTO(ctx, pnode->exts, node->exts, node, ret, cleanup);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002616 if (node->flags & LYS_MAND_TRUE) {
2617 /* inherit LYS_MAND_TRUE in parent containers */
2618 lys_compile_mandatory_parents(parent, 1);
2619 }
2620
2621 if (child_set) {
2622 /* add the new node into set */
2623 LY_CHECK_GOTO(ret = ly_set_add(child_set, node, 1, NULL), cleanup);
2624 }
2625
2626 goto cleanup;
2627
2628error:
Michal Vaskoc636ea42022-09-16 10:20:31 +02002629 lysc_node_free(&ctx->free_ctx, node, 0);
2630
Radek Krejci2a9fc652021-01-22 17:44:34 +01002631cleanup:
2632 if (ret && dev_pnode) {
2633 LOGVAL(ctx->ctx, LYVE_OTHER, "Compilation of a deviated and/or refined node failed.");
2634 }
Michal Vaskoe02e7402021-07-23 08:29:28 +02002635 ctx->compile_opts = prev_opts;
Michal Vaskoc636ea42022-09-16 10:20:31 +02002636 lysp_dev_node_free(ctx, dev_pnode);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002637 return ret;
2638}
2639
2640/**
2641 * @brief Compile parsed action's input/output node information.
2642 * @param[in] ctx Compile context
2643 * @param[in] pnode Parsed inout node.
2644 * @param[in,out] node Pre-prepared structure from lys_compile_node_() with filled generic node information
2645 * is enriched with the inout-specific information.
2646 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
2647 */
2648LY_ERR
2649lys_compile_node_action_inout(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
2650{
2651 LY_ERR ret = LY_SUCCESS;
2652 struct lysp_node *child_p;
Michal Vasko7c565922021-06-10 14:58:27 +02002653 uint32_t prev_options = ctx->compile_opts;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002654
2655 struct lysp_node_action_inout *inout_p = (struct lysp_node_action_inout *)pnode;
2656 struct lysc_node_action_inout *inout = (struct lysc_node_action_inout *)node;
2657
2658 COMPILE_ARRAY_GOTO(ctx, inout_p->musts, inout->musts, lys_compile_must, ret, done);
Radek Krejciab430862021-03-02 20:13:40 +01002659 COMPILE_EXTS_GOTO(ctx, inout_p->exts, inout->exts, inout, ret, done);
Michal Vasko7c565922021-06-10 14:58:27 +02002660 ctx->compile_opts |= (inout_p->nodetype == LYS_INPUT) ? LYS_COMPILE_RPC_INPUT : LYS_COMPILE_RPC_OUTPUT;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002661
Radek Krejci01180ac2021-01-27 08:48:22 +01002662 LY_LIST_FOR(inout_p->child, child_p) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01002663 LY_CHECK_GOTO(ret = lys_compile_node(ctx, child_p, node, 0, NULL), done);
2664 }
2665
Michal Vasko95f736c2022-06-08 12:03:31 +02002666 /* connect any augments */
2667 LY_CHECK_GOTO(ret = lys_compile_node_augments(ctx, node), done);
2668
Michal Vasko7c565922021-06-10 14:58:27 +02002669 ctx->compile_opts = prev_options;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002670
2671done:
2672 return ret;
2673}
2674
2675/**
2676 * @brief Compile parsed action node information.
2677 * @param[in] ctx Compile context
2678 * @param[in] pnode Parsed action node.
2679 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
2680 * is enriched with the action-specific information.
2681 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
2682 */
2683LY_ERR
2684lys_compile_node_action(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
2685{
2686 LY_ERR ret;
2687 struct lysp_node_action *action_p = (struct lysp_node_action *)pnode;
2688 struct lysc_node_action *action = (struct lysc_node_action *)node;
2689 struct lysp_node_action_inout *input, implicit_input = {
2690 .nodetype = LYS_INPUT,
2691 .name = "input",
2692 .parent = pnode,
2693 };
2694 struct lysp_node_action_inout *output, implicit_output = {
2695 .nodetype = LYS_OUTPUT,
2696 .name = "output",
2697 .parent = pnode,
2698 };
2699
Michal Vaskoe17ff5f2021-01-29 17:23:03 +01002700 /* input */
Radek Krejcia6016992021-03-03 10:13:41 +01002701 lysc_update_path(ctx, action->module, "input");
Radek Krejci2a9fc652021-01-22 17:44:34 +01002702 if (action_p->input.nodetype == LYS_UNKNOWN) {
2703 input = &implicit_input;
2704 } else {
2705 input = &action_p->input;
2706 }
Michal Vasko14ed9cd2021-01-28 14:16:25 +01002707 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 +01002708 lysc_update_path(ctx, NULL, NULL);
2709 LY_CHECK_GOTO(ret, done);
2710
Michal Vaskoc130e162021-10-19 11:30:00 +02002711 /* add must(s) to unres */
2712 ret = lysc_unres_must_add(ctx, &action->input.node, &input->node);
2713 LY_CHECK_GOTO(ret, done);
2714
Radek Krejci2a9fc652021-01-22 17:44:34 +01002715 /* output */
Radek Krejcia6016992021-03-03 10:13:41 +01002716 lysc_update_path(ctx, action->module, "output");
Michal Vasko9149efd2021-01-29 11:16:59 +01002717 if (action_p->output.nodetype == LYS_UNKNOWN) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01002718 output = &implicit_output;
2719 } else {
2720 output = &action_p->output;
2721 }
Michal Vasko14ed9cd2021-01-28 14:16:25 +01002722 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 +01002723 lysc_update_path(ctx, NULL, NULL);
2724 LY_CHECK_GOTO(ret, done);
2725
Michal Vaskoc130e162021-10-19 11:30:00 +02002726 /* add must(s) to unres */
2727 ret = lysc_unres_must_add(ctx, &action->output.node, &output->node);
2728 LY_CHECK_GOTO(ret, done);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002729
2730done:
2731 return ret;
2732}
2733
2734/**
2735 * @brief Compile parsed action node information.
2736 * @param[in] ctx Compile context
2737 * @param[in] pnode Parsed action node.
2738 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
2739 * is enriched with the action-specific information.
2740 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
2741 */
2742LY_ERR
2743lys_compile_node_notif(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
2744{
2745 LY_ERR ret = LY_SUCCESS;
2746 struct lysp_node_notif *notif_p = (struct lysp_node_notif *)pnode;
2747 struct lysc_node_notif *notif = (struct lysc_node_notif *)node;
2748 struct lysp_node *child_p;
2749
2750 COMPILE_ARRAY_GOTO(ctx, notif_p->musts, notif->musts, lys_compile_must, ret, done);
Michal Vaskoc130e162021-10-19 11:30:00 +02002751
2752 /* add must(s) to unres */
2753 ret = lysc_unres_must_add(ctx, node, pnode);
2754 LY_CHECK_GOTO(ret, done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002755
Radek Krejci01180ac2021-01-27 08:48:22 +01002756 LY_LIST_FOR(notif_p->child, child_p) {
Michal Vasko14ed9cd2021-01-28 14:16:25 +01002757 ret = lys_compile_node(ctx, child_p, node, 0, NULL);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002758 LY_CHECK_GOTO(ret, done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002759 }
2760
Michal Vasko95f736c2022-06-08 12:03:31 +02002761 /* connect any augments */
2762 LY_CHECK_GOTO(ret = lys_compile_node_augments(ctx, node), done);
2763
Radek Krejci2a9fc652021-01-22 17:44:34 +01002764done:
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002765 return ret;
2766}
2767
2768/**
2769 * @brief Compile parsed container node information.
2770 * @param[in] ctx Compile context
2771 * @param[in] pnode Parsed container node.
2772 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
2773 * is enriched with the container-specific information.
2774 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
2775 */
2776static LY_ERR
2777lys_compile_node_container(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
2778{
2779 struct lysp_node_container *cont_p = (struct lysp_node_container *)pnode;
2780 struct lysc_node_container *cont = (struct lysc_node_container *)node;
2781 struct lysp_node *child_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002782 LY_ERR ret = LY_SUCCESS;
2783
2784 if (cont_p->presence) {
Michal Vaskoe16c7b72021-02-26 10:39:06 +01002785 /* presence container */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002786 cont->flags |= LYS_PRESENCE;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002787 }
2788
2789 /* more cases when the container has meaning but is kept NP for convenience:
2790 * - when condition
2791 * - direct child action/notification
2792 */
2793
2794 LY_LIST_FOR(cont_p->child, child_p) {
2795 ret = lys_compile_node(ctx, child_p, node, 0, NULL);
2796 LY_CHECK_GOTO(ret, done);
2797 }
2798
Michal Vasko5347e3a2020-11-03 17:14:57 +01002799 COMPILE_ARRAY_GOTO(ctx, cont_p->musts, cont->musts, lys_compile_must, ret, done);
Michal Vaskoc130e162021-10-19 11:30:00 +02002800
2801 /* add must(s) to unres */
2802 ret = lysc_unres_must_add(ctx, node, pnode);
2803 LY_CHECK_GOTO(ret, done);
Radek Krejci2a9fc652021-01-22 17:44:34 +01002804
Michal Vasko95f736c2022-06-08 12:03:31 +02002805 /* connect any augments */
2806 LY_CHECK_GOTO(ret = lys_compile_node_augments(ctx, node), done);
2807
Radek Krejci2a9fc652021-01-22 17:44:34 +01002808 LY_LIST_FOR((struct lysp_node *)cont_p->actions, child_p) {
2809 ret = lys_compile_node(ctx, child_p, node, 0, NULL);
2810 LY_CHECK_GOTO(ret, done);
2811 }
2812 LY_LIST_FOR((struct lysp_node *)cont_p->notifs, child_p) {
2813 ret = lys_compile_node(ctx, child_p, node, 0, NULL);
2814 LY_CHECK_GOTO(ret, done);
2815 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002816
2817done:
2818 return ret;
2819}
2820
Michal Vasko72244882021-01-12 15:21:05 +01002821/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002822 * @brief Compile type in leaf/leaf-list node and do all the necessary checks.
2823 * @param[in] ctx Compile context.
2824 * @param[in] context_node Schema node where the type/typedef is placed to correctly find the base types.
2825 * @param[in] type_p Parsed type to compile.
2826 * @param[in,out] leaf Compiled leaf structure (possibly cast leaf-list) to provide node information and to store the compiled type information.
2827 * @return LY_ERR value.
2828 */
2829static LY_ERR
2830lys_compile_node_type(struct lysc_ctx *ctx, struct lysp_node *context_node, struct lysp_type *type_p,
2831 struct lysc_node_leaf *leaf)
2832{
2833 struct lysp_qname *dflt;
Michal Vaskof4fa90d2021-11-11 15:05:19 +01002834 struct lysc_type **t;
2835 LY_ARRAY_COUNT_TYPE u, count;
2836 ly_bool in_unres = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002837
Michal Vaskoa99b3572021-02-01 11:54:58 +01002838 LY_CHECK_RET(lys_compile_type(ctx, context_node, leaf->flags, leaf->name, type_p, &leaf->type,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002839 leaf->units ? NULL : &leaf->units, &dflt));
2840
2841 /* store default value, if any */
2842 if (dflt && !(leaf->flags & LYS_SET_DFLT)) {
2843 LY_CHECK_RET(lysc_unres_leaf_dflt_add(ctx, leaf, dflt));
2844 }
2845
Michal Vaskoc130e162021-10-19 11:30:00 +02002846 /* store leafref(s) to be resolved */
2847 LY_CHECK_RET(lysc_unres_leafref_add(ctx, leaf, type_p->pmod));
2848
Michal Vaskof4fa90d2021-11-11 15:05:19 +01002849 /* type-specific checks */
2850 if (leaf->type->basetype == LY_TYPE_UNION) {
2851 t = ((struct lysc_type_union *)leaf->type)->types;
2852 count = LY_ARRAY_COUNT(t);
2853 } else {
2854 t = &leaf->type;
2855 count = 1;
2856 }
2857 for (u = 0; u < count; ++u) {
2858 if (t[u]->basetype == LY_TYPE_EMPTY) {
2859 if ((leaf->nodetype == LYS_LEAFLIST) && (ctx->pmod->version < LYS_VERSION_1_1)) {
2860 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Leaf-list of type \"empty\" is allowed only in YANG 1.1 modules.");
2861 return LY_EVALID;
2862 }
2863 } else if (!in_unres && ((t[u]->basetype == LY_TYPE_BITS) || (t[u]->basetype == LY_TYPE_ENUM))) {
2864 /* store in unres for all disabled bits/enums to be removed */
2865 LY_CHECK_RET(lysc_unres_bitenum_add(ctx, leaf));
2866 in_unres = 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002867 }
2868 }
2869
2870 return LY_SUCCESS;
2871}
2872
2873/**
2874 * @brief Compile parsed leaf node information.
2875 * @param[in] ctx Compile context
2876 * @param[in] pnode Parsed leaf node.
2877 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
2878 * is enriched with the leaf-specific information.
2879 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
2880 */
2881static LY_ERR
2882lys_compile_node_leaf(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
2883{
2884 struct lysp_node_leaf *leaf_p = (struct lysp_node_leaf *)pnode;
2885 struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002886 LY_ERR ret = LY_SUCCESS;
2887
Michal Vasko5347e3a2020-11-03 17:14:57 +01002888 COMPILE_ARRAY_GOTO(ctx, leaf_p->musts, leaf->musts, lys_compile_must, ret, done);
Michal Vaskoc130e162021-10-19 11:30:00 +02002889
2890 /* add must(s) to unres */
2891 ret = lysc_unres_must_add(ctx, node, pnode);
2892 LY_CHECK_GOTO(ret, done);
2893
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002894 if (leaf_p->units) {
2895 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, leaf_p->units, 0, &leaf->units), done);
2896 leaf->flags |= LYS_SET_UNITS;
2897 }
2898
2899 /* compile type */
2900 ret = lys_compile_node_type(ctx, pnode, &leaf_p->type, leaf);
2901 LY_CHECK_GOTO(ret, done);
2902
2903 /* store/update default value */
2904 if (leaf_p->dflt.str) {
2905 LY_CHECK_RET(lysc_unres_leaf_dflt_add(ctx, leaf, &leaf_p->dflt));
2906 leaf->flags |= LYS_SET_DFLT;
2907 }
2908
2909 /* checks */
2910 if ((leaf->flags & LYS_SET_DFLT) && (leaf->flags & LYS_MAND_TRUE)) {
Michal Vasko6b8c5102021-10-19 11:29:32 +02002911 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Invalid mandatory leaf with a default value.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002912 return LY_EVALID;
2913 }
2914
2915done:
2916 return ret;
2917}
2918
2919/**
2920 * @brief Compile parsed leaf-list node information.
2921 * @param[in] ctx Compile context
2922 * @param[in] pnode Parsed leaf-list node.
2923 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
2924 * is enriched with the leaf-list-specific information.
2925 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
2926 */
2927static LY_ERR
2928lys_compile_node_leaflist(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
2929{
2930 struct lysp_node_leaflist *llist_p = (struct lysp_node_leaflist *)pnode;
2931 struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002932 LY_ERR ret = LY_SUCCESS;
2933
Michal Vasko5347e3a2020-11-03 17:14:57 +01002934 COMPILE_ARRAY_GOTO(ctx, llist_p->musts, llist->musts, lys_compile_must, ret, done);
Michal Vaskoc130e162021-10-19 11:30:00 +02002935
2936 /* add must(s) to unres */
2937 ret = lysc_unres_must_add(ctx, node, pnode);
2938 LY_CHECK_GOTO(ret, done);
2939
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002940 if (llist_p->units) {
2941 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, llist_p->units, 0, &llist->units), done);
2942 llist->flags |= LYS_SET_UNITS;
2943 }
2944
2945 /* compile type */
2946 ret = lys_compile_node_type(ctx, pnode, &llist_p->type, (struct lysc_node_leaf *)llist);
2947 LY_CHECK_GOTO(ret, done);
2948
2949 /* store/update default values */
2950 if (llist_p->dflts) {
2951 if (ctx->pmod->version < LYS_VERSION_1_1) {
Michal Vasko6b8c5102021-10-19 11:29:32 +02002952 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Leaf-list default values are allowed only in YANG 1.1 modules.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002953 return LY_EVALID;
2954 }
2955
2956 LY_CHECK_GOTO(lysc_unres_llist_dflts_add(ctx, llist, llist_p->dflts), done);
2957 llist->flags |= LYS_SET_DFLT;
2958 }
2959
2960 llist->min = llist_p->min;
2961 if (llist->min) {
2962 llist->flags |= LYS_MAND_TRUE;
2963 }
Michal Vaskoe78faec2021-04-08 17:24:43 +02002964 llist->max = llist_p->max ? llist_p->max : UINT32_MAX;
2965
2966 if (llist->flags & LYS_CONFIG_R) {
2967 /* state leaf-list is always ordered-by user */
2968 llist->flags &= ~LYS_ORDBY_SYSTEM;
2969 llist->flags |= LYS_ORDBY_USER;
2970 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002971
2972 /* checks */
2973 if ((llist->flags & LYS_SET_DFLT) && (llist->flags & LYS_MAND_TRUE)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002974 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 +02002975 return LY_EVALID;
2976 }
2977
2978 if (llist->min > llist->max) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002979 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Leaf-list min-elements %u is bigger than max-elements %u.",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002980 llist->min, llist->max);
2981 return LY_EVALID;
2982 }
2983
2984done:
2985 return ret;
2986}
2987
Michal Vaskob5a487d2021-12-14 10:31:04 +01002988/**
2989 * @brief Find the node according to the given descendant/absolute schema nodeid.
2990 * Used in unique, refine and augment statements.
2991 *
2992 * @param[in] ctx Compile context
2993 * @param[in] nodeid Descendant-schema-nodeid (according to the YANG grammar)
2994 * @param[in] nodeid_len Length of the given nodeid, if it is not NULL-terminated string.
2995 * @param[in] ctx_node Context node for a relative nodeid.
Michal Vaskob5a487d2021-12-14 10:31:04 +01002996 * @param[in] format Format of any prefixes.
2997 * @param[in] prefix_data Format-specific prefix data (see ::ly_resolve_prefix).
2998 * @param[in] nodetype Optional (can be 0) restriction for target's nodetype. If target exists, but does not match
2999 * the given nodetype, LY_EDENIED is returned (and target is provided), but no error message is printed.
3000 * The value can be even an ORed value to allow multiple nodetypes.
3001 * @param[out] target Found target node if any.
3002 * @param[out] result_flag Output parameter to announce if the schema nodeid goes through the action's input/output or a Notification.
3003 * The LYSC_OPT_RPC_INPUT, LYSC_OPT_RPC_OUTPUT and LYSC_OPT_NOTIFICATION are used as flags.
3004 * @return LY_ERR values - LY_ENOTFOUND, LY_EVALID, LY_EDENIED or LY_SUCCESS.
3005 */
3006static LY_ERR
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003007lysc_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 +01003008 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 +02003009{
3010 LY_ERR ret = LY_EVALID;
3011 const char *name, *prefix, *id;
3012 size_t name_len, prefix_len;
Radek Krejci2b18bf12020-11-06 11:20:20 +01003013 const struct lys_module *mod = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003014 const char *nodeid_type;
3015 uint32_t getnext_extra_flag = 0;
3016 uint16_t current_nodetype = 0;
3017
3018 assert(nodeid);
3019 assert(target);
3020 assert(result_flag);
3021 *target = NULL;
3022 *result_flag = 0;
3023
3024 id = nodeid;
3025
3026 if (ctx_node) {
3027 /* descendant-schema-nodeid */
3028 nodeid_type = "descendant";
3029
3030 if (*id == '/') {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003031 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003032 "Invalid descendant-schema-nodeid value \"%.*s\" - absolute-schema-nodeid used.",
Radek Krejci422afb12021-03-04 16:38:16 +01003033 (int)(nodeid_len ? nodeid_len : strlen(nodeid)), nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003034 return LY_EVALID;
3035 }
3036 } else {
3037 /* absolute-schema-nodeid */
3038 nodeid_type = "absolute";
3039
3040 if (*id != '/') {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003041 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003042 "Invalid absolute-schema-nodeid value \"%.*s\" - missing starting \"/\".",
Radek Krejci422afb12021-03-04 16:38:16 +01003043 (int)(nodeid_len ? nodeid_len : strlen(nodeid)), nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003044 return LY_EVALID;
3045 }
3046 ++id;
3047 }
3048
3049 while (*id && (ret = ly_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len)) == LY_SUCCESS) {
3050 if (prefix) {
3051 mod = ly_resolve_prefix(ctx->ctx, prefix, prefix_len, format, prefix_data);
3052 if (!mod) {
3053 /* module must always be found */
3054 assert(prefix);
Radek Krejci2efc45b2020-12-22 16:25:44 +01003055 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003056 "Invalid %s-schema-nodeid value \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01003057 nodeid_type, (int)(id - nodeid), nodeid, (int)prefix_len, prefix, LYSP_MODULE_NAME(ctx->pmod));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003058 return LY_ENOTFOUND;
3059 }
3060 } else {
3061 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02003062 case LY_VALUE_SCHEMA:
3063 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003064 /* use the current module */
Michal Vasko56d8da82021-12-16 15:41:30 +01003065 mod = ctx->cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003066 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02003067 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02003068 case LY_VALUE_LYB:
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003069 if (!ctx_node) {
3070 LOGINT_RET(ctx->ctx);
3071 }
3072 /* inherit the module of the previous context node */
3073 mod = ctx_node->module;
3074 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02003075 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02003076 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01003077 case LY_VALUE_STR_NS:
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003078 /* not really defined */
3079 LOGINT_RET(ctx->ctx);
3080 }
3081 }
3082
3083 if (ctx_node && (ctx_node->nodetype & (LYS_RPC | LYS_ACTION))) {
3084 /* move through input/output manually */
3085 if (mod != ctx_node->module) {
Radek Krejci422afb12021-03-04 16:38:16 +01003086 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.",
3087 nodeid_type, (int)(id - nodeid), nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003088 return LY_ENOTFOUND;
3089 }
3090 if (!ly_strncmp("input", name, name_len)) {
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003091 ctx_node = &((struct lysc_node_action *)ctx_node)->input.node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003092 } else if (!ly_strncmp("output", name, name_len)) {
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003093 ctx_node = &((struct lysc_node_action *)ctx_node)->output.node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003094 getnext_extra_flag = LYS_GETNEXT_OUTPUT;
3095 } else {
3096 /* only input or output is valid */
3097 ctx_node = NULL;
3098 }
3099 } else {
3100 ctx_node = lys_find_child(ctx_node, mod, name, name_len, 0,
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01003101 getnext_extra_flag | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003102 getnext_extra_flag = 0;
3103 }
3104 if (!ctx_node) {
Radek Krejci422afb12021-03-04 16:38:16 +01003105 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.",
3106 nodeid_type, (int)(id - nodeid), nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003107 return LY_ENOTFOUND;
3108 }
3109 current_nodetype = ctx_node->nodetype;
3110
3111 if (current_nodetype == LYS_NOTIF) {
3112 (*result_flag) |= LYS_COMPILE_NOTIFICATION;
3113 } else if (current_nodetype == LYS_INPUT) {
3114 (*result_flag) |= LYS_COMPILE_RPC_INPUT;
3115 } else if (current_nodetype == LYS_OUTPUT) {
3116 (*result_flag) |= LYS_COMPILE_RPC_OUTPUT;
3117 }
3118
3119 if (!*id || (nodeid_len && ((size_t)(id - nodeid) >= nodeid_len))) {
3120 break;
3121 }
3122 if (*id != '/') {
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\" - missing \"/\" as node-identifier separator.",
Radek Krejci422afb12021-03-04 16:38:16 +01003125 nodeid_type, (int)(id - nodeid + 1), nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003126 return LY_EVALID;
3127 }
3128 ++id;
3129 }
3130
3131 if (ret == LY_SUCCESS) {
3132 *target = ctx_node;
3133 if (nodetype && !(current_nodetype & nodetype)) {
3134 return LY_EDENIED;
3135 }
3136 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003137 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003138 "Invalid %s-schema-nodeid value \"%.*s\" - unexpected end of expression.",
Radek Krejci422afb12021-03-04 16:38:16 +01003139 nodeid_type, (int)(nodeid_len ? nodeid_len : strlen(nodeid)), nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003140 }
3141
3142 return ret;
3143}
3144
3145/**
3146 * @brief Compile information about list's uniques.
3147 * @param[in] ctx Compile context.
3148 * @param[in] uniques Sized array list of unique statements.
3149 * @param[in] list Compiled list where the uniques are supposed to be resolved and stored.
3150 * @return LY_ERR value.
3151 */
3152static LY_ERR
3153lys_compile_node_list_unique(struct lysc_ctx *ctx, struct lysp_qname *uniques, struct lysc_node_list *list)
3154{
3155 LY_ERR ret = LY_SUCCESS;
3156 struct lysc_node_leaf **key, ***unique;
3157 struct lysc_node *parent;
3158 const char *keystr, *delim;
3159 size_t len;
3160 LY_ARRAY_COUNT_TYPE v;
3161 int8_t config; /* -1 - not yet seen; 0 - LYS_CONFIG_R; 1 - LYS_CONFIG_W */
3162 uint16_t flags;
3163
3164 LY_ARRAY_FOR(uniques, v) {
3165 config = -1;
3166 LY_ARRAY_NEW_RET(ctx->ctx, list->uniques, unique, LY_EMEM);
3167 keystr = uniques[v].str;
3168 while (keystr) {
3169 delim = strpbrk(keystr, " \t\n");
3170 if (delim) {
3171 len = delim - keystr;
3172 while (isspace(*delim)) {
3173 ++delim;
3174 }
3175 } else {
3176 len = strlen(keystr);
3177 }
3178
3179 /* unique node must be present */
3180 LY_ARRAY_NEW_RET(ctx->ctx, *unique, key, LY_EMEM);
Michal Vasko56d8da82021-12-16 15:41:30 +01003181 ret = lysc_resolve_schema_nodeid(ctx, keystr, len, &list->node, LY_VALUE_SCHEMA, (void *)uniques[v].mod,
3182 LYS_LEAF, (const struct lysc_node **)key, &flags);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003183 if (ret != LY_SUCCESS) {
3184 if (ret == LY_EDENIED) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003185 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003186 "Unique's descendant-schema-nodeid \"%.*s\" refers to %s node instead of a leaf.",
Radek Krejci422afb12021-03-04 16:38:16 +01003187 (int)len, keystr, lys_nodetype2str((*key)->nodetype));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003188 }
3189 return LY_EVALID;
3190 } else if (flags) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003191 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003192 "Unique's descendant-schema-nodeid \"%.*s\" refers into %s node.",
Radek Krejci422afb12021-03-04 16:38:16 +01003193 (int)len, keystr, flags & LYS_IS_NOTIF ? "notification" : "RPC/action");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003194 return LY_EVALID;
3195 }
3196
3197 /* all referenced leafs must be of the same config type */
3198 if ((config != -1) && ((((*key)->flags & LYS_CONFIG_W) && (config == 0)) ||
3199 (((*key)->flags & LYS_CONFIG_R) && (config == 1)))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003200 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003201 "Unique statement \"%s\" refers to leaves with different config type.", uniques[v].str);
3202 return LY_EVALID;
3203 } else if ((*key)->flags & LYS_CONFIG_W) {
3204 config = 1;
3205 } else { /* LYS_CONFIG_R */
3206 config = 0;
3207 }
3208
3209 /* we forbid referencing nested lists because it is unspecified what instance of such a list to use */
3210 for (parent = (*key)->parent; parent != (struct lysc_node *)list; parent = parent->parent) {
3211 if (parent->nodetype == LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003212 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003213 "Unique statement \"%s\" refers to a leaf in nested list \"%s\".", uniques[v].str, parent->name);
3214 return LY_EVALID;
3215 }
3216 }
3217
3218 /* check status */
Michal Vaskoc130e162021-10-19 11:30:00 +02003219 LY_CHECK_RET(lysc_check_status(ctx, list->flags, uniques[v].mod->mod, list->name,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003220 (*key)->flags, (*key)->module, (*key)->name));
3221
3222 /* mark leaf as unique */
3223 (*key)->flags |= LYS_UNIQUE;
3224
3225 /* next unique value in line */
3226 keystr = delim;
3227 }
3228 /* next unique definition */
3229 }
3230
3231 return LY_SUCCESS;
3232}
3233
3234/**
3235 * @brief Compile parsed list node information.
3236 * @param[in] ctx Compile context
3237 * @param[in] pnode Parsed list node.
3238 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
3239 * is enriched with the list-specific information.
3240 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3241 */
3242static LY_ERR
3243lys_compile_node_list(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
3244{
3245 struct lysp_node_list *list_p = (struct lysp_node_list *)pnode;
3246 struct lysc_node_list *list = (struct lysc_node_list *)node;
3247 struct lysp_node *child_p;
Michal Vasko2d6507a2022-03-16 09:40:52 +01003248 struct lysc_node *parent;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003249 struct lysc_node_leaf *key, *prev_key = NULL;
3250 size_t len;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003251 const char *keystr, *delim;
3252 LY_ERR ret = LY_SUCCESS;
3253
3254 list->min = list_p->min;
3255 if (list->min) {
3256 list->flags |= LYS_MAND_TRUE;
3257 }
3258 list->max = list_p->max ? list_p->max : (uint32_t)-1;
3259
3260 LY_LIST_FOR(list_p->child, child_p) {
3261 LY_CHECK_RET(lys_compile_node(ctx, child_p, node, 0, NULL));
3262 }
3263
Michal Vasko5347e3a2020-11-03 17:14:57 +01003264 COMPILE_ARRAY_GOTO(ctx, list_p->musts, list->musts, lys_compile_must, ret, done);
Michal Vaskoc130e162021-10-19 11:30:00 +02003265
3266 /* add must(s) to unres */
3267 ret = lysc_unres_must_add(ctx, node, pnode);
3268 LY_CHECK_GOTO(ret, done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003269
3270 /* keys */
Michal Vasko2d6507a2022-03-16 09:40:52 +01003271 if (list->flags & LYS_CONFIG_W) {
3272 parent = node;
3273 if (ctx->compile_opts & LYS_COMPILE_GROUPING) {
3274 /* compiling individual grouping, we can check this only if there is an explicit config set */
3275 while (parent) {
3276 if (parent->flags & LYS_SET_CONFIG) {
3277 break;
3278 }
3279 parent = parent->parent;
3280 }
3281 }
3282
3283 if (parent && (!list_p->key || !list_p->key[0])) {
3284 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Missing key in list representing configuration data.");
3285 return LY_EVALID;
3286 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003287 }
3288
3289 /* find all the keys (must be direct children) */
3290 keystr = list_p->key;
3291 if (!keystr) {
3292 /* keyless list */
Michal Vaskoe78faec2021-04-08 17:24:43 +02003293 list->flags &= ~LYS_ORDBY_SYSTEM;
3294 list->flags |= LYS_KEYLESS | LYS_ORDBY_USER;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003295 }
3296 while (keystr) {
3297 delim = strpbrk(keystr, " \t\n");
3298 if (delim) {
3299 len = delim - keystr;
3300 while (isspace(*delim)) {
3301 ++delim;
3302 }
3303 } else {
3304 len = strlen(keystr);
3305 }
3306
3307 /* key node must be present */
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01003308 key = (struct lysc_node_leaf *)lys_find_child(node, node->module, keystr, len, LYS_LEAF, LYS_GETNEXT_NOCHOICE);
3309 if (!key) {
Radek Krejci422afb12021-03-04 16:38:16 +01003310 LOGVAL(ctx->ctx, LYVE_REFERENCE, "The list's key \"%.*s\" not found.", (int)len, keystr);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003311 return LY_EVALID;
3312 }
3313 /* keys must be unique */
3314 if (key->flags & LYS_KEY) {
3315 /* the node was already marked as a key */
Radek Krejci422afb12021-03-04 16:38:16 +01003316 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Duplicated key identifier \"%.*s\".", (int)len, keystr);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003317 return LY_EVALID;
3318 }
3319
Radek Krejcia6016992021-03-03 10:13:41 +01003320 lysc_update_path(ctx, list->module, key->name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003321 /* key must have the same config flag as the list itself */
3322 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Michal Vasko6b8c5102021-10-19 11:29:32 +02003323 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Key of a configuration list must not be a state leaf.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003324 return LY_EVALID;
3325 }
3326 if (ctx->pmod->version < LYS_VERSION_1_1) {
3327 /* YANG 1.0 denies key to be of empty type */
3328 if (key->type->basetype == LY_TYPE_EMPTY) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003329 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003330 "List's key cannot be of \"empty\" type until it is in YANG 1.1 module.");
3331 return LY_EVALID;
3332 }
3333 } else {
3334 /* when and if-feature are illegal on list keys */
3335 if (key->when) {
Michal Vasko6b8c5102021-10-19 11:29:32 +02003336 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "List's key must not have any \"when\" statement.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003337 return LY_EVALID;
3338 }
Michal Vasko93b4ab92022-05-13 12:29:59 +02003339 /* unable to check if-features but compilation would fail if disabled */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003340 }
3341
3342 /* check status */
Michal Vaskoc636ea42022-09-16 10:20:31 +02003343 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 +02003344
3345 /* ignore default values of the key */
3346 if (key->dflt) {
3347 key->dflt->realtype->plugin->free(ctx->ctx, key->dflt);
Michal Vaskoc636ea42022-09-16 10:20:31 +02003348 lysc_type_free(&ctx->free_ctx, (struct lysc_type *)key->dflt->realtype);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003349 free(key->dflt);
3350 key->dflt = NULL;
3351 }
3352 /* mark leaf as key */
3353 key->flags |= LYS_KEY;
3354
3355 /* move it to the correct position */
3356 if ((prev_key && ((struct lysc_node *)prev_key != key->prev)) || (!prev_key && key->prev->next)) {
3357 /* fix links in closest previous siblings of the key */
3358 if (key->next) {
3359 key->next->prev = key->prev;
3360 } else {
3361 /* last child */
3362 list->child->prev = key->prev;
3363 }
3364 if (key->prev->next) {
3365 key->prev->next = key->next;
3366 }
3367 /* fix links in the key */
3368 if (prev_key) {
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003369 key->prev = &prev_key->node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003370 key->next = prev_key->next;
3371 } else {
3372 key->prev = list->child->prev;
3373 key->next = list->child;
3374 }
3375 /* fix links in closes future siblings of the key */
3376 if (prev_key) {
3377 if (prev_key->next) {
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003378 prev_key->next->prev = &key->node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003379 } else {
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003380 list->child->prev = &key->node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003381 }
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003382 prev_key->next = &key->node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003383 } else {
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003384 list->child->prev = &key->node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003385 }
3386 /* fix links in parent */
3387 if (!key->prev->next) {
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003388 list->child = &key->node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003389 }
3390 }
3391
3392 /* next key value */
3393 prev_key = key;
3394 keystr = delim;
3395 lysc_update_path(ctx, NULL, NULL);
3396 }
3397
Michal Vasko95f736c2022-06-08 12:03:31 +02003398 /* connect any augments */
3399 LY_CHECK_GOTO(ret = lys_compile_node_augments(ctx, node), done);
3400
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003401 /* uniques */
3402 if (list_p->uniques) {
3403 LY_CHECK_RET(lys_compile_node_list_unique(ctx, list_p->uniques, list));
3404 }
3405
Radek Krejci2a9fc652021-01-22 17:44:34 +01003406 LY_LIST_FOR((struct lysp_node *)list_p->actions, child_p) {
3407 ret = lys_compile_node(ctx, child_p, node, 0, NULL);
3408 LY_CHECK_GOTO(ret, done);
3409 }
3410 LY_LIST_FOR((struct lysp_node *)list_p->notifs, child_p) {
3411 ret = lys_compile_node(ctx, child_p, node, 0, NULL);
3412 LY_CHECK_GOTO(ret, done);
3413 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003414
3415 /* checks */
3416 if (list->min > list->max) {
Michal Vasko6b8c5102021-10-19 11:29:32 +02003417 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 +02003418 return LY_EVALID;
3419 }
3420
3421done:
3422 return ret;
3423}
3424
3425/**
3426 * @brief Do some checks and set the default choice's case.
3427 *
3428 * Selects (and stores into ::lysc_node_choice#dflt) the default case and set LYS_SET_DFLT flag on it.
3429 *
3430 * @param[in] ctx Compile context.
3431 * @param[in] dflt Name of the default branch. Can even contain a prefix.
3432 * @param[in,out] ch The compiled choice node, its dflt member is filled to point to the default case node of the choice.
3433 * @return LY_ERR value.
3434 */
3435static LY_ERR
3436lys_compile_node_choice_dflt(struct lysc_ctx *ctx, struct lysp_qname *dflt, struct lysc_node_choice *ch)
3437{
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003438 struct lysc_node *iter;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003439 const struct lys_module *mod;
3440 const char *prefix = NULL, *name;
3441 size_t prefix_len = 0;
3442
3443 /* could use lys_parse_nodeid(), but it checks syntax which is already done in this case by the parsers */
3444 name = strchr(dflt->str, ':');
3445 if (name) {
3446 prefix = dflt->str;
3447 prefix_len = name - prefix;
3448 ++name;
3449 } else {
3450 name = dflt->str;
3451 }
3452 if (prefix) {
Radek Krejci8df109d2021-04-23 12:19:08 +02003453 mod = ly_resolve_prefix(ctx->ctx, prefix, prefix_len, LY_VALUE_SCHEMA, (void *)dflt->mod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003454 if (!mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003455 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Default case prefix \"%.*s\" not found "
Radek Krejci422afb12021-03-04 16:38:16 +01003456 "in imports of \"%s\".", (int)prefix_len, prefix, LYSP_MODULE_NAME(dflt->mod));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003457 return LY_EVALID;
3458 }
3459 } else {
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003460 mod = ch->module;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003461 }
3462
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003463 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 +02003464 if (!ch->dflt) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003465 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003466 "Default case \"%s\" not found.", dflt->str);
3467 return LY_EVALID;
3468 }
3469
3470 /* no mandatory nodes directly under the default case */
3471 LY_LIST_FOR(ch->dflt->child, iter) {
3472 if (iter->parent != (struct lysc_node *)ch->dflt) {
3473 break;
3474 }
3475 if (iter->flags & LYS_MAND_TRUE) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003476 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003477 "Mandatory node \"%s\" under the default case \"%s\".", iter->name, dflt->str);
3478 return LY_EVALID;
3479 }
3480 }
3481
3482 if (ch->flags & LYS_MAND_TRUE) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003483 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Invalid mandatory choice with a default case.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003484 return LY_EVALID;
3485 }
3486
3487 ch->dflt->flags |= LYS_SET_DFLT;
3488 return LY_SUCCESS;
3489}
3490
3491LY_ERR
3492lys_compile_node_choice_child(struct lysc_ctx *ctx, struct lysp_node *child_p, struct lysc_node *node,
3493 struct ly_set *child_set)
3494{
3495 LY_ERR ret = LY_SUCCESS;
3496 struct lysp_node *child_p_next = child_p->next;
3497 struct lysp_node_case *cs_p;
Michal Vasko4eb49d52022-02-17 15:05:00 +01003498 struct lysc_node_case *cs_c;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003499
3500 if (child_p->nodetype == LYS_CASE) {
3501 /* standard case under choice */
3502 ret = lys_compile_node(ctx, child_p, node, 0, child_set);
3503 } else {
Michal Vaskoa6cf80a2021-06-25 07:42:19 +02003504 /* we need the implicit case first, so create a fake parsed (shorthand) case */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003505 cs_p = calloc(1, sizeof *cs_p);
3506 cs_p->nodetype = LYS_CASE;
Michal Vaskoa6cf80a2021-06-25 07:42:19 +02003507 DUP_STRING_GOTO(ctx->ctx, child_p->name, cs_p->name, ret, revert_sh_case);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003508 cs_p->child = child_p;
3509
3510 /* make the child the only case child */
3511 child_p->next = NULL;
3512
3513 /* compile it normally */
Michal Vaskoa6cf80a2021-06-25 07:42:19 +02003514 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 +02003515
Michal Vaskoa6cf80a2021-06-25 07:42:19 +02003516 if (((struct lysc_node_choice *)node)->cases) {
Michal Vasko4eb49d52022-02-17 15:05:00 +01003517 /* find our case node */
3518 cs_c = (struct lysc_node_case *)((struct lysc_node_choice *)node)->cases;
3519 while (cs_c->name != cs_p->name) {
3520 cs_c = (struct lysc_node_case *)cs_c->next;
3521 assert(cs_c);
Michal Vaskoa6cf80a2021-06-25 07:42:19 +02003522 }
aPiecekaa320c92021-05-21 07:34:24 +02003523
Michal Vasko4eb49d52022-02-17 15:05:00 +01003524 if (ctx->ctx->flags & LY_CTX_SET_PRIV_PARSED) {
3525 /* compiled case node cannot point to his corresponding parsed node
3526 * because it exists temporarily so it must be set to NULL
3527 */
3528 assert(cs_c->priv == cs_p);
3529 cs_c->priv = NULL;
3530 }
3531
3532 /* status is copied from his child and not from his parent as usual. */
3533 if (cs_c->child) {
3534 cs_c->flags &= ~LYS_STATUS_MASK;
3535 cs_c->flags |= (LYS_STATUS_MASK & cs_c->child->flags);
Michal Vaskoa6cf80a2021-06-25 07:42:19 +02003536 }
3537 } /* else it was removed by a deviation */
aPiecekaa320c92021-05-21 07:34:24 +02003538
Michal Vaskoa6cf80a2021-06-25 07:42:19 +02003539revert_sh_case:
3540 /* free the parsed shorthand case and correct pointers back */
aPiecekaa320c92021-05-21 07:34:24 +02003541 cs_p->child = NULL;
Michal Vaskoc636ea42022-09-16 10:20:31 +02003542 lysp_node_free(&ctx->free_ctx, (struct lysp_node *)cs_p);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003543 child_p->next = child_p_next;
3544 }
3545
3546 return ret;
3547}
3548
3549/**
3550 * @brief Compile parsed choice node information.
3551 *
3552 * @param[in] ctx Compile context
3553 * @param[in] pnode Parsed choice node.
3554 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
3555 * is enriched with the choice-specific information.
3556 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3557 */
3558static LY_ERR
3559lys_compile_node_choice(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
3560{
3561 struct lysp_node_choice *ch_p = (struct lysp_node_choice *)pnode;
3562 struct lysc_node_choice *ch = (struct lysc_node_choice *)node;
3563 struct lysp_node *child_p;
3564 LY_ERR ret = LY_SUCCESS;
3565
3566 assert(node->nodetype == LYS_CHOICE);
3567
3568 LY_LIST_FOR(ch_p->child, child_p) {
Michal Vasko95f736c2022-06-08 12:03:31 +02003569 LY_CHECK_GOTO(ret = lys_compile_node_choice_child(ctx, child_p, node, NULL), done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003570 }
3571
Michal Vasko95f736c2022-06-08 12:03:31 +02003572 /* connect any augments */
3573 LY_CHECK_GOTO(ret = lys_compile_node_augments(ctx, node), done);
3574
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003575 /* default branch */
3576 if (ch_p->dflt.str) {
Michal Vasko95f736c2022-06-08 12:03:31 +02003577 LY_CHECK_GOTO(ret = lys_compile_node_choice_dflt(ctx, &ch_p->dflt, ch), done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003578 }
3579
Michal Vasko95f736c2022-06-08 12:03:31 +02003580done:
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003581 return ret;
3582}
3583
3584/**
3585 * @brief Compile parsed anydata or anyxml node information.
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003586 *
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003587 * @param[in] ctx Compile context
3588 * @param[in] pnode Parsed anydata or anyxml node.
3589 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
3590 * is enriched with the any-specific information.
3591 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3592 */
3593static LY_ERR
3594lys_compile_node_any(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
3595{
3596 struct lysp_node_anydata *any_p = (struct lysp_node_anydata *)pnode;
3597 struct lysc_node_anydata *any = (struct lysc_node_anydata *)node;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003598 LY_ERR ret = LY_SUCCESS;
3599
Michal Vasko5347e3a2020-11-03 17:14:57 +01003600 COMPILE_ARRAY_GOTO(ctx, any_p->musts, any->musts, lys_compile_must, ret, done);
Michal Vaskoc130e162021-10-19 11:30:00 +02003601
3602 /* add must(s) to unres */
3603 ret = lysc_unres_must_add(ctx, node, pnode);
3604 LY_CHECK_GOTO(ret, done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003605
Radek Krejci91531e12021-02-08 19:57:54 +01003606 if (any->flags & LYS_CONFIG_W) {
Michal Vasko5676f4e2021-04-06 17:14:45 +02003607 LOGVRB("Use of %s to define configuration data is not recommended. %s",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003608 ly_stmt2str(any->nodetype == LYS_ANYDATA ? LY_STMT_ANYDATA : LY_STMT_ANYXML), ctx->path);
3609 }
3610done:
3611 return ret;
3612}
3613
3614/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003615 * @brief Prepare the case structure in choice node for the new data node.
3616 *
3617 * 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
3618 * created in the choice when the first child was processed.
3619 *
3620 * @param[in] ctx Compile context.
3621 * @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,
3622 * it is the LYS_CHOICE, LYS_AUGMENT or LYS_GROUPING node.
3623 * @param[in] ch The compiled choice structure where the new case structures are created (if needed).
3624 * @param[in] child The new data node being part of a case (no matter if explicit or implicit).
3625 * @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,
3626 * it is linked from the case structure only in case it is its first child.
3627 */
3628static LY_ERR
3629lys_compile_node_case(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
3630{
Michal Vasko95f736c2022-06-08 12:03:31 +02003631 LY_ERR ret = LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003632 struct lysp_node *child_p;
3633 struct lysp_node_case *cs_p = (struct lysp_node_case *)pnode;
3634
3635 if (pnode->nodetype & (LYS_CHOICE | LYS_AUGMENT | LYS_GROUPING)) {
3636 /* we have to add an implicit case node into the parent choice */
3637 } else if (pnode->nodetype == LYS_CASE) {
3638 /* explicit parent case */
3639 LY_LIST_FOR(cs_p->child, child_p) {
Michal Vasko95f736c2022-06-08 12:03:31 +02003640 LY_CHECK_GOTO(ret = lys_compile_node(ctx, child_p, node, 0, NULL), done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003641 }
3642 } else {
3643 LOGINT_RET(ctx->ctx);
3644 }
3645
Michal Vasko95f736c2022-06-08 12:03:31 +02003646 /* connect any augments */
3647 LY_CHECK_GOTO(ret = lys_compile_node_augments(ctx, node), done);
3648
3649done:
3650 return ret;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003651}
3652
3653void
3654lys_compile_mandatory_parents(struct lysc_node *parent, ly_bool add)
3655{
Michal Vasko14ed9cd2021-01-28 14:16:25 +01003656 const struct lysc_node *iter;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003657
3658 if (add) { /* set flag */
3659 for ( ; parent && parent->nodetype == LYS_CONTAINER && !(parent->flags & LYS_MAND_TRUE) && !(parent->flags & LYS_PRESENCE);
3660 parent = parent->parent) {
3661 parent->flags |= LYS_MAND_TRUE;
3662 }
3663 } else { /* unset flag */
3664 for ( ; parent && parent->nodetype == LYS_CONTAINER && (parent->flags & LYS_MAND_TRUE); parent = parent->parent) {
Michal Vasko544e58a2021-01-28 14:33:41 +01003665 for (iter = lysc_node_child(parent); iter; iter = iter->next) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003666 if (iter->flags & LYS_MAND_TRUE) {
3667 /* there is another mandatory node */
3668 return;
3669 }
3670 }
3671 /* unset mandatory flag - there is no mandatory children in the non-presence container */
3672 parent->flags &= ~LYS_MAND_TRUE;
3673 }
3674 }
3675}
3676
3677/**
Radek Krejciabd33a42021-01-20 17:18:59 +01003678 * @brief Get the grouping with the specified name from given groupings sized array.
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003679 *
3680 * @param[in] node Linked list of nodes with groupings.
Radek Krejciabd33a42021-01-20 17:18:59 +01003681 * @param[in] name Name of the grouping to find,
3682 * @return NULL when there is no grouping with the specified name
3683 * @return Pointer to the grouping of the specified @p name.
3684 */
Radek Krejci2a9fc652021-01-22 17:44:34 +01003685static struct lysp_node_grp *
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003686match_grouping(const struct lysp_node_grp *node, const char *name)
Radek Krejciabd33a42021-01-20 17:18:59 +01003687{
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003688 LY_LIST_FOR(node, node) {
3689 if ((node->nodetype == LYS_GROUPING) && !strcmp(node->name, name)) {
3690 return (struct lysp_node_grp *)node;
Radek Krejciabd33a42021-01-20 17:18:59 +01003691 }
3692 }
3693
3694 return NULL;
3695}
3696
3697/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003698 * @brief Find grouping for a uses.
3699 *
3700 * @param[in] ctx Compile context.
3701 * @param[in] uses_p Parsed uses node.
3702 * @param[out] gpr_p Found grouping on success.
3703 * @param[out] grp_pmod Module of @p grp_p on success.
3704 * @return LY_ERR value.
3705 */
3706static LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01003707lys_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 +02003708 struct lysp_module **grp_pmod)
3709{
3710 struct lysp_node *pnode;
Radek Krejci2a9fc652021-01-22 17:44:34 +01003711 struct lysp_node_grp *grp;
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003712 struct lysp_node_grp * const *ext_grp;
Radek Krejciabd33a42021-01-20 17:18:59 +01003713 LY_ARRAY_COUNT_TYPE u;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003714 const char *id, *name, *prefix, *local_pref;
3715 size_t prefix_len, name_len;
3716 struct lysp_module *pmod, *found = NULL;
Michal Vaskob2d55bf2020-11-02 15:42:43 +01003717 const struct lys_module *mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003718
3719 *grp_p = NULL;
3720 *grp_pmod = NULL;
3721
3722 /* search for the grouping definition */
3723 id = uses_p->name;
3724 LY_CHECK_RET(ly_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len), LY_EVALID);
3725 local_pref = ctx->pmod->is_submod ? ((struct lysp_submodule *)ctx->pmod)->prefix : ctx->pmod->mod->prefix;
3726 if (!prefix || !ly_strncmp(local_pref, prefix, prefix_len)) {
3727 /* current module, search local groupings first */
Radek Krejciabd33a42021-01-20 17:18:59 +01003728 pmod = ctx->pmod->mod->parsed; /* make sure that we will start in main_module, not submodule */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003729 for (pnode = uses_p->parent; !found && pnode; pnode = pnode->parent) {
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003730 if ((grp = match_grouping(lysp_node_groupings(pnode), name))) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01003731 found = ctx->pmod;
3732 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003733 }
3734 }
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003735
3736 /* if in an extension, search possible groupings in it */
3737 if (ctx->ext) {
3738 ext_grp = lys_compile_ext_instance_get_storage(ctx->ext, LY_STMT_GROUPING);
3739 if (ext_grp && (grp = match_grouping(*ext_grp, name))) {
3740 found = ctx->pmod;
3741 }
3742 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003743 } else {
3744 /* foreign module, find it first */
Radek Krejci8df109d2021-04-23 12:19:08 +02003745 mod = ly_resolve_prefix(ctx->ctx, prefix, prefix_len, LY_VALUE_SCHEMA, ctx->pmod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003746 if (!mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003747 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003748 "Invalid prefix used for grouping reference.", uses_p->name);
3749 return LY_EVALID;
3750 }
3751 pmod = mod->parsed;
3752 }
3753
3754 if (!found) {
3755 /* search in top-level groupings of the main module ... */
Radek Krejciabd33a42021-01-20 17:18:59 +01003756 if ((grp = match_grouping(pmod->groupings, name))) {
3757 found = pmod;
3758 } else {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003759 /* ... and all the submodules */
3760 LY_ARRAY_FOR(pmod->includes, u) {
Radek Krejciabd33a42021-01-20 17:18:59 +01003761 if ((grp = match_grouping(pmod->includes[u].submodule->groupings, name))) {
3762 found = (struct lysp_module *)pmod->includes[u].submodule;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003763 break;
3764 }
3765 }
3766 }
3767 }
3768 if (!found) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003769 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003770 "Grouping \"%s\" referenced by a uses statement not found.", uses_p->name);
3771 return LY_EVALID;
3772 }
3773
Michal Vasko7c565922021-06-10 14:58:27 +02003774 if (!(ctx->compile_opts & LYS_COMPILE_GROUPING)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003775 /* remember that the grouping is instantiated to avoid its standalone validation */
3776 grp->flags |= LYS_USED_GRP;
3777 }
3778
3779 *grp_p = grp;
3780 *grp_pmod = found;
3781 return LY_SUCCESS;
3782}
3783
3784/**
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003785 * @brief Compile uses grouping children.
3786 *
3787 * @param[in] ctx Compile context.
3788 * @param[in] uses_p Parsed uses.
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003789 * @param[in] parent_status Parent status flags to inherit.
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003790 * @param[in] child First grouping child to compile.
3791 * @param[in] grp_mod Grouping parsed module.
3792 * @param[in] parent Uses compiled parent, may be NULL if top-level.
3793 * @param[in,out] child_set Set of all compiled child nodes.
3794 * @param[in] child_unres_disabled Whether the children are to be put into unres disabled set or not.
3795 * @return LY_SUCCESS on success.
3796 * @return LY_EVALID on failure.
3797 */
3798static LY_ERR
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003799lys_compile_uses_children(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, uint16_t parent_status,
3800 struct lysp_node *child, struct lysp_module *grp_mod, struct lysc_node *parent, struct ly_set *child_set,
3801 ly_bool child_unres_disabled)
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003802{
3803 LY_ERR rc = LY_SUCCESS;
3804 struct lysp_module *mod_old = ctx->pmod;
3805 uint32_t child_i, opt_prev = ctx->compile_opts;
3806 ly_bool enabled;
3807 struct lysp_node *pnode;
3808 struct lysc_node *node;
3809 struct lysc_when *when_shared = NULL;
3810
3811 assert(child_set);
3812
Michal Vasko5940c302022-07-14 13:54:38 +02003813 child_i = child_set->count;
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003814 LY_LIST_FOR(child, pnode) {
3815 /* compile the nodes with their parsed (grouping) module */
3816 ctx->pmod = grp_mod;
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003817 LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, parent, &parent_status, child_set), cleanup);
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003818
3819 /* eval if-features again for the rest of this node processing */
3820 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
3821 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
3822 ctx->compile_opts |= LYS_COMPILE_DISABLED;
3823 }
3824
3825 /* restore the parsed module */
3826 ctx->pmod = mod_old;
3827
3828 /* since the uses node is not present in the compiled tree, we need to pass some of its
3829 * statements to all its children */
3830 while (child_i < child_set->count) {
3831 node = child_set->snodes[child_i];
3832
3833 if (uses_p->when) {
3834 /* pass uses when to all the children */
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003835 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 +02003836 LY_CHECK_GOTO(rc, cleanup);
3837 }
3838
3839 if (child_unres_disabled) {
3840 /* child is disabled by the uses if-features */
3841 ly_set_add(&ctx->unres->disabled, node, 1, NULL);
3842 }
3843
3844 /* child processed */
3845 ++child_i;
3846 }
3847
3848 /* next iter */
3849 ctx->compile_opts = opt_prev;
3850 }
3851
3852cleanup:
3853 ctx->compile_opts = opt_prev;
3854 return rc;
3855}
3856
3857/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003858 * @brief Compile parsed uses statement - resolve target grouping and connect its content into parent.
3859 * If present, also apply uses's modificators.
3860 *
3861 * @param[in] ctx Compile context
3862 * @param[in] uses_p Parsed uses schema node.
3863 * @param[in] parent Compiled parent node where the content of the referenced grouping is supposed to be connected. It is
3864 * NULL for top-level nodes, in such a case the module where the node will be connected is taken from
3865 * the compile context.
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003866 * @param[in] inherited_status Explicitly inherited status (from uses/extension instance), if any.
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003867 * @param[in] child_set Optional set of all the compiled children.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003868 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3869 */
3870static LY_ERR
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003871lys_compile_uses(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, struct lysc_node *parent,
3872 const uint16_t *inherited_status, struct ly_set *child_set)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003873{
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003874 LY_ERR rc = LY_SUCCESS;
3875 ly_bool enabled, child_unres_disabled = 0;
3876 uint32_t i, grp_stack_count, opt_prev = ctx->compile_opts;
Radek Krejci2a9fc652021-01-22 17:44:34 +01003877 struct lysp_node_grp *grp = NULL;
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003878 uint16_t uses_flags, parent_flags;
3879 const char *parent_name;
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003880 struct lysp_module *grp_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003881 struct ly_set uses_child_set = {0};
3882
3883 /* find the referenced grouping */
3884 LY_CHECK_RET(lys_compile_uses_find_grouping(ctx, uses_p, &grp, &grp_mod));
3885
3886 /* grouping must not reference themselves - stack in ctx maintains list of groupings currently being applied */
3887 grp_stack_count = ctx->groupings.count;
3888 LY_CHECK_RET(ly_set_add(&ctx->groupings, (void *)grp, 0, NULL));
3889 if (grp_stack_count == ctx->groupings.count) {
3890 /* the target grouping is already in the stack, so we are already inside it -> circular dependency */
Radek Krejci2efc45b2020-12-22 16:25:44 +01003891 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003892 "Grouping \"%s\" references itself through a uses statement.", grp->name);
3893 return LY_EVALID;
3894 }
3895
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003896 /* nodetype checks */
3897 if (grp->actions && (parent && !lysc_node_actions_p(parent))) {
3898 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid child %s \"%s\" of uses parent %s \"%s\" node.",
3899 grp->actions->name, lys_nodetype2str(grp->actions->nodetype),
3900 parent->name, lys_nodetype2str(parent->nodetype));
3901 rc = LY_EVALID;
3902 goto cleanup;
3903 }
3904 if (grp->notifs && (parent && !lysc_node_notifs_p(parent))) {
3905 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid child %s \"%s\" of uses parent %s \"%s\" node.",
3906 grp->notifs->name, lys_nodetype2str(grp->notifs->nodetype),
3907 parent->name, lys_nodetype2str(parent->nodetype));
3908 rc = LY_EVALID;
3909 goto cleanup;
3910 }
3911
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003912 /* check status */
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003913 rc = lysc_check_status(ctx, uses_p->flags, ctx->pmod, uses_p->name, grp->flags, grp_mod, grp->name);
3914 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003915
3916 /* compile any augments and refines so they can be applied during the grouping nodes compilation */
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003917 rc = lys_precompile_uses_augments_refines(ctx, uses_p, parent);
3918 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003919
Michal Vasko10b6b1c2021-07-20 10:43:12 +02003920 /* compile special uses status flags */
3921 uses_flags = uses_p->flags;
Michal Vaskoedb0fa52022-10-04 10:36:00 +02003922 parent_flags = inherited_status ? *inherited_status : (parent ? parent->flags : 0);
3923 parent_name = inherited_status ? "<schema-only-node>" : (parent ? parent->name : NULL);
3924 rc = lys_compile_status(ctx, &uses_flags, "<uses>", parent_flags, parent_name, inherited_status ? 1 : 0);
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003925 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko10b6b1c2021-07-20 10:43:12 +02003926
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003927 /* uses if-features */
3928 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, uses_p->iffeatures, &enabled), cleanup);
3929 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
3930 ctx->compile_opts |= LYS_COMPILE_DISABLED;
3931 child_unres_disabled = 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003932 }
3933
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003934 /* uses grouping children */
3935 rc = lys_compile_uses_children(ctx, uses_p, uses_flags, grp->child, grp_mod, parent,
3936 child_set ? child_set : &uses_child_set, child_unres_disabled);
3937 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003938
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003939 /* uses grouping RPCs/actions */
3940 rc = lys_compile_uses_children(ctx, uses_p, uses_flags, (struct lysp_node *)grp->actions, grp_mod, parent,
3941 child_set ? child_set : &uses_child_set, child_unres_disabled);
3942 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003943
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003944 /* uses grouping notifications */
3945 rc = lys_compile_uses_children(ctx, uses_p, uses_flags, (struct lysp_node *)grp->notifs, grp_mod, parent,
3946 child_set ? child_set : &uses_child_set, child_unres_disabled);
3947 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003948
3949 /* check that all augments were applied */
3950 for (i = 0; i < ctx->uses_augs.count; ++i) {
Michal Vaskod8655722021-01-12 15:20:36 +01003951 if (((struct lysc_augment *)ctx->uses_augs.objs[i])->aug_p->parent != (struct lysp_node *)uses_p) {
3952 /* augment of some parent uses, irrelevant now */
3953 continue;
3954 }
3955
3956 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Augment target node \"%s\" in grouping \"%s\" was not found.",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003957 ((struct lysc_augment *)ctx->uses_augs.objs[i])->nodeid->expr, grp->name);
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003958 rc = LY_ENOTFOUND;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003959 }
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003960 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003961
3962 /* check that all refines were applied */
3963 for (i = 0; i < ctx->uses_rfns.count; ++i) {
Michal Vaskod8655722021-01-12 15:20:36 +01003964 if (((struct lysc_refine *)ctx->uses_rfns.objs[i])->uses_p != uses_p) {
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003965 /* refine of some parent uses, irrelevant now */
Michal Vaskod8655722021-01-12 15:20:36 +01003966 continue;
3967 }
3968
3969 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Refine(s) target node \"%s\" in grouping \"%s\" was not found.",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003970 ((struct lysc_refine *)ctx->uses_rfns.objs[i])->nodeid->expr, grp->name);
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003971 rc = LY_ENOTFOUND;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003972 }
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003973 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003974
3975cleanup:
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003976 /* restore previous context */
3977 ctx->compile_opts = opt_prev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003978
3979 /* remove the grouping from the stack for circular groupings dependency check */
3980 ly_set_rm_index(&ctx->groupings, ctx->groupings.count - 1, NULL);
3981 assert(ctx->groupings.count == grp_stack_count);
3982
3983 ly_set_erase(&uses_child_set, NULL);
Michal Vaskobf8e65d2022-05-30 09:27:49 +02003984 return rc;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02003985}
3986
3987static int
3988lys_compile_grouping_pathlog(struct lysc_ctx *ctx, struct lysp_node *node, char **path)
3989{
3990 struct lysp_node *iter;
3991 int len = 0;
3992
3993 *path = NULL;
3994 for (iter = node; iter && len >= 0; iter = iter->parent) {
3995 char *s = *path;
3996 char *id;
3997
3998 switch (iter->nodetype) {
3999 case LYS_USES:
4000 LY_CHECK_RET(asprintf(&id, "{uses='%s'}", iter->name) == -1, -1);
4001 break;
4002 case LYS_GROUPING:
4003 LY_CHECK_RET(asprintf(&id, "{grouping='%s'}", iter->name) == -1, -1);
4004 break;
4005 case LYS_AUGMENT:
4006 LY_CHECK_RET(asprintf(&id, "{augment='%s'}", iter->name) == -1, -1);
4007 break;
4008 default:
4009 id = strdup(iter->name);
4010 break;
4011 }
4012
4013 if (!iter->parent) {
4014 /* print prefix */
4015 len = asprintf(path, "/%s:%s%s", ctx->cur_mod->name, id, s ? s : "");
4016 } else {
4017 /* prefix is the same as in parent */
4018 len = asprintf(path, "/%s%s", id, s ? s : "");
4019 }
4020 free(s);
4021 free(id);
4022 }
4023
4024 if (len < 0) {
4025 free(*path);
4026 *path = NULL;
4027 } else if (len == 0) {
4028 *path = strdup("/");
4029 len = 1;
4030 }
4031 return len;
4032}
4033
4034LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01004035lys_compile_grouping(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysp_node_grp *grp)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004036{
4037 LY_ERR ret;
4038 char *path;
4039 int len;
Michal Vaskoecdc2222022-01-24 08:45:44 +01004040 uint16_t cont_flags;
4041
4042 cont_flags = pnode ? pnode->flags & LYS_FLAGS_COMPILED_MASK : 0;
4043 if (!(cont_flags & LYS_CONFIG_MASK)) {
4044 /* default config */
4045 cont_flags |= LYS_CONFIG_W;
4046 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004047
Michal Vasko8254d852022-04-25 10:05:59 +02004048 /* use grouping status to avoid errors */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004049 struct lysp_node_uses fake_uses = {
4050 .parent = pnode,
4051 .nodetype = LYS_USES,
Michal Vasko8254d852022-04-25 10:05:59 +02004052 .flags = grp->flags & LYS_STATUS_MASK, .next = NULL,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004053 .name = grp->name,
4054 .dsc = NULL, .ref = NULL, .when = NULL, .iffeatures = NULL, .exts = NULL,
4055 .refines = NULL, .augments = NULL
4056 };
4057 struct lysc_node_container fake_container = {
4058 .nodetype = LYS_CONTAINER,
Michal Vaskoecdc2222022-01-24 08:45:44 +01004059 .flags = cont_flags,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004060 .module = ctx->cur_mod,
Michal Vaskobd6de2b2020-10-22 14:45:03 +02004061 .parent = NULL, .next = NULL,
Michal Vasko14ed9cd2021-01-28 14:16:25 +01004062 .prev = &fake_container.node,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004063 .name = "fake",
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01004064 .dsc = NULL, .ref = NULL, .exts = NULL, .when = NULL,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004065 .child = NULL, .musts = NULL, .actions = NULL, .notifs = NULL
4066 };
4067
4068 if (grp->parent) {
4069 LOGWRN(ctx->ctx, "Locally scoped grouping \"%s\" not used.", grp->name);
4070 }
4071
4072 len = lys_compile_grouping_pathlog(ctx, grp->parent, &path);
4073 if (len < 0) {
4074 LOGMEM(ctx->ctx);
4075 return LY_EMEM;
4076 }
4077 strncpy(ctx->path, path, LYSC_CTX_BUFSIZE - 1);
4078 ctx->path_len = (uint32_t)len;
4079 free(path);
4080
4081 lysc_update_path(ctx, NULL, "{grouping}");
4082 lysc_update_path(ctx, NULL, grp->name);
Michal Vaskoedb0fa52022-10-04 10:36:00 +02004083 ret = lys_compile_uses(ctx, &fake_uses, &fake_container.node, NULL, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004084 lysc_update_path(ctx, NULL, NULL);
4085 lysc_update_path(ctx, NULL, NULL);
4086
4087 ctx->path_len = 1;
4088 ctx->path[1] = '\0';
4089
4090 /* cleanup */
Michal Vaskoc636ea42022-09-16 10:20:31 +02004091 lysc_node_container_free(&ctx->free_ctx, &fake_container);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004092
4093 return ret;
4094}
4095
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004096LY_ERR
Michal Vaskoedb0fa52022-10-04 10:36:00 +02004097lys_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 +02004098 struct ly_set *child_set)
4099{
4100 LY_ERR ret = LY_SUCCESS;
4101 struct lysc_node *node = NULL;
Michal Vasko7c565922021-06-10 14:58:27 +02004102 uint32_t prev_opts = ctx->compile_opts;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004103
4104 LY_ERR (*node_compile_spec)(struct lysc_ctx *, struct lysp_node *, struct lysc_node *);
4105
4106 if (pnode->nodetype != LYS_USES) {
Radek Krejcia6016992021-03-03 10:13:41 +01004107 lysc_update_path(ctx, parent ? parent->module : NULL, pnode->name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004108 } else {
4109 lysc_update_path(ctx, NULL, "{uses}");
4110 lysc_update_path(ctx, NULL, pnode->name);
4111 }
4112
4113 switch (pnode->nodetype) {
4114 case LYS_CONTAINER:
4115 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_container));
4116 node_compile_spec = lys_compile_node_container;
4117 break;
4118 case LYS_LEAF:
4119 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_leaf));
4120 node_compile_spec = lys_compile_node_leaf;
4121 break;
4122 case LYS_LIST:
4123 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_list));
4124 node_compile_spec = lys_compile_node_list;
4125 break;
4126 case LYS_LEAFLIST:
4127 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_leaflist));
4128 node_compile_spec = lys_compile_node_leaflist;
4129 break;
4130 case LYS_CHOICE:
4131 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_choice));
4132 node_compile_spec = lys_compile_node_choice;
4133 break;
4134 case LYS_CASE:
4135 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_case));
4136 node_compile_spec = lys_compile_node_case;
4137 break;
4138 case LYS_ANYXML:
4139 case LYS_ANYDATA:
4140 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_anydata));
4141 node_compile_spec = lys_compile_node_any;
4142 break;
Radek Krejci2a9fc652021-01-22 17:44:34 +01004143 case LYS_RPC:
4144 case LYS_ACTION:
Michal Vasko7c565922021-06-10 14:58:27 +02004145 if (ctx->compile_opts & (LYS_IS_INPUT | LYS_IS_OUTPUT | LYS_IS_NOTIF)) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01004146 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
4147 "Action \"%s\" is placed inside %s.", pnode->name,
Michal Vasko7c565922021-06-10 14:58:27 +02004148 (ctx->compile_opts & LYS_IS_NOTIF) ? "notification" : "another RPC/action");
Radek Krejci2a9fc652021-01-22 17:44:34 +01004149 return LY_EVALID;
4150 }
4151 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_action));
4152 node_compile_spec = lys_compile_node_action;
Michal Vasko7c565922021-06-10 14:58:27 +02004153 ctx->compile_opts |= LYS_COMPILE_NO_CONFIG;
Radek Krejci2a9fc652021-01-22 17:44:34 +01004154 break;
4155 case LYS_NOTIF:
Michal Vasko7c565922021-06-10 14:58:27 +02004156 if (ctx->compile_opts & (LYS_IS_INPUT | LYS_IS_OUTPUT | LYS_IS_NOTIF)) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01004157 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
4158 "Notification \"%s\" is placed inside %s.", pnode->name,
Michal Vasko7c565922021-06-10 14:58:27 +02004159 (ctx->compile_opts & LYS_IS_NOTIF) ? "another notification" : "RPC/action");
Radek Krejci2a9fc652021-01-22 17:44:34 +01004160 return LY_EVALID;
4161 }
4162 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_notif));
4163 node_compile_spec = lys_compile_node_notif;
Michal Vasko7c565922021-06-10 14:58:27 +02004164 ctx->compile_opts |= LYS_COMPILE_NOTIFICATION;
Radek Krejci2a9fc652021-01-22 17:44:34 +01004165 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004166 case LYS_USES:
Michal Vaskoedb0fa52022-10-04 10:36:00 +02004167 ret = lys_compile_uses(ctx, (struct lysp_node_uses *)pnode, parent, inherited_status, child_set);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004168 lysc_update_path(ctx, NULL, NULL);
4169 lysc_update_path(ctx, NULL, NULL);
4170 return ret;
4171 default:
4172 LOGINT(ctx->ctx);
4173 return LY_EINT;
4174 }
4175 LY_CHECK_ERR_RET(!node, LOGMEM(ctx->ctx), LY_EMEM);
4176
Michal Vaskoedb0fa52022-10-04 10:36:00 +02004177 ret = lys_compile_node_(ctx, pnode, parent, inherited_status, node_compile_spec, node, child_set);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004178
Michal Vasko7c565922021-06-10 14:58:27 +02004179 ctx->compile_opts = prev_opts;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01004180 lysc_update_path(ctx, NULL, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02004181 return ret;
4182}