blob: c98c1d695ad74367611caba80a22d242892ca8d7 [file] [log] [blame]
Radek Krejci19a96102018-11-15 13:38:09 +01001/**
2 * @file tree_schema.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Schema tree implementation
5 *
6 * Copyright (c) 2015 - 2018 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
Radek Krejci535ea9f2020-05-29 16:01:05 +020015#define _GNU_SOURCE
Radek Krejci19a96102018-11-15 13:38:09 +010016
Radek Krejcie7b95092019-05-15 11:03:07 +020017#include <assert.h>
Radek Krejci19a96102018-11-15 13:38:09 +010018#include <ctype.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020019#include <stddef.h>
20#include <stdint.h>
Radek Krejci19a96102018-11-15 13:38:09 +010021#include <stdio.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020022#include <stdlib.h>
23#include <string.h>
Radek Krejci19a96102018-11-15 13:38:09 +010024
Radek Krejci535ea9f2020-05-29 16:01:05 +020025#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020026#include "compat.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020027#include "context.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020028#include "dict.h"
29#include "log.h"
Michal Vasko004d3152020-06-11 19:59:22 +020030#include "path.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020031#include "parser.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020032#include "parser_schema.h"
Radek Krejci0935f412019-08-20 16:15:18 +020033#include "plugins_exts.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020034#include "plugins_types.h"
Radek Krejci0935f412019-08-20 16:15:18 +020035#include "plugins_exts_internal.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020036#include "set.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020037#include "tree.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020038#include "tree_data.h"
Michal Vasko7c8439f2020-08-05 13:25:19 +020039#include "tree_data_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020040#include "tree_schema.h"
Radek Krejci19a96102018-11-15 13:38:09 +010041#include "tree_schema_internal.h"
42#include "xpath.h"
43
Michal Vasko5fe75f12020-03-02 13:52:37 +010044static LY_ERR lys_compile_ext(struct lysc_ctx *ctx, struct lysp_ext_instance *ext_p, struct lysc_ext_instance *ext,
Radek Krejci0f969882020-08-21 16:56:47 +020045 void *parent, LYEXT_PARENT parent_type, const struct lys_module *ext_mod);
Michal Vasko5fe75f12020-03-02 13:52:37 +010046
Michal Vasko7f45cf22020-10-01 12:49:44 +020047static LY_ERR lysp_qname_dup(const struct ly_ctx *ctx, struct lysp_qname *qname, const struct lysp_qname *orig_qname);
48
Radek Krejci19a96102018-11-15 13:38:09 +010049/**
50 * @brief Duplicate string into dictionary
51 * @param[in] CTX libyang context of the dictionary.
52 * @param[in] ORIG String to duplicate.
53 * @param[out] DUP Where to store the result.
54 */
Radek Krejci011e4aa2020-09-04 15:22:31 +020055#define DUP_STRING(CTX, ORIG, DUP, RET) if (ORIG) {RET = lydict_insert(CTX, ORIG, 0, &DUP);}
56
57#define DUP_STRING_GOTO(CTX, ORIG, DUP, RET, GOTO) if (ORIG) {LY_CHECK_GOTO(RET = lydict_insert(CTX, ORIG, 0, &DUP), GOTO);}
Radek Krejci19a96102018-11-15 13:38:09 +010058
Michal Vasko7f45cf22020-10-01 12:49:44 +020059#define DUP_ARRAY(CTX, ORIG_ARRAY, NEW_ARRAY, DUP_FUNC) \
60 if (ORIG_ARRAY) { \
61 LY_ARRAY_COUNT_TYPE u; \
62 LY_ARRAY_CREATE_RET(CTX, NEW_ARRAY, LY_ARRAY_COUNT(ORIG_ARRAY), LY_EMEM); \
63 LY_ARRAY_FOR(ORIG_ARRAY, u) { \
64 LY_ARRAY_INCREMENT(NEW_ARRAY); \
65 LY_CHECK_RET(DUP_FUNC(CTX, &(NEW_ARRAY)[u], &(ORIG_ARRAY)[u])); \
66 } \
67 }
68
Radek Krejciec4da802019-05-02 13:02:41 +020069#define COMPILE_ARRAY_GOTO(CTX, ARRAY_P, ARRAY_C, ITER, FUNC, RET, GOTO) \
Radek Krejci19a96102018-11-15 13:38:09 +010070 if (ARRAY_P) { \
Michal Vaskofd69e1d2020-07-03 11:57:17 +020071 LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, LY_ARRAY_COUNT(ARRAY_P), RET, GOTO); \
72 LY_ARRAY_COUNT_TYPE __array_offset = LY_ARRAY_COUNT(ARRAY_C); \
73 for (ITER = 0; ITER < LY_ARRAY_COUNT(ARRAY_P); ++ITER) { \
Radek Krejci19a96102018-11-15 13:38:09 +010074 LY_ARRAY_INCREMENT(ARRAY_C); \
Radek Krejciec4da802019-05-02 13:02:41 +020075 RET = FUNC(CTX, &(ARRAY_P)[ITER], &(ARRAY_C)[ITER + __array_offset]); \
Radek Krejcid05cbd92018-12-05 14:26:40 +010076 LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
77 } \
78 }
79
Michal Vasko7f45cf22020-10-01 12:49:44 +020080#define COMPILE_OP_ARRAY_GOTO(CTX, ARRAY_P, ARRAY_C, PARENT, ITER, FUNC, USES_STATUS, RET, GOTO) \
Radek Krejci6eeb58f2019-02-22 16:29:37 +010081 if (ARRAY_P) { \
Michal Vaskofd69e1d2020-07-03 11:57:17 +020082 LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, LY_ARRAY_COUNT(ARRAY_P), RET, GOTO); \
83 LY_ARRAY_COUNT_TYPE __array_offset = LY_ARRAY_COUNT(ARRAY_C); \
84 for (ITER = 0; ITER < LY_ARRAY_COUNT(ARRAY_P); ++ITER) { \
Radek Krejci6eeb58f2019-02-22 16:29:37 +010085 LY_ARRAY_INCREMENT(ARRAY_C); \
Radek Krejciec4da802019-05-02 13:02:41 +020086 RET = FUNC(CTX, &(ARRAY_P)[ITER], PARENT, &(ARRAY_C)[ITER + __array_offset], USES_STATUS); \
Michal Vasko7f45cf22020-10-01 12:49:44 +020087 if (RET == LY_EDENIED) { \
88 LY_ARRAY_DECREMENT(ARRAY_C); \
89 } else if (RET != LY_SUCCESS) { \
90 goto GOTO; \
91 } \
Radek Krejci6eeb58f2019-02-22 16:29:37 +010092 } \
93 }
94
Radek Krejci0935f412019-08-20 16:15:18 +020095#define COMPILE_EXTS_GOTO(CTX, EXTS_P, EXT_C, PARENT, PARENT_TYPE, RET, GOTO) \
96 if (EXTS_P) { \
Michal Vaskofd69e1d2020-07-03 11:57:17 +020097 LY_ARRAY_CREATE_GOTO((CTX)->ctx, EXT_C, LY_ARRAY_COUNT(EXTS_P), RET, GOTO); \
98 for (LY_ARRAY_COUNT_TYPE __exts_iter = 0, __array_offset = LY_ARRAY_COUNT(EXT_C); __exts_iter < LY_ARRAY_COUNT(EXTS_P); ++__exts_iter) { \
Radek Krejci0935f412019-08-20 16:15:18 +020099 LY_ARRAY_INCREMENT(EXT_C); \
Michal Vasko8d544252020-03-02 10:19:52 +0100100 RET = lys_compile_ext(CTX, &(EXTS_P)[__exts_iter], &(EXT_C)[__exts_iter + __array_offset], PARENT, PARENT_TYPE, NULL); \
Radek Krejci0935f412019-08-20 16:15:18 +0200101 LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
102 } \
103 }
104
Radek Krejciec4da802019-05-02 13:02:41 +0200105#define COMPILE_ARRAY_UNIQUE_GOTO(CTX, ARRAY_P, ARRAY_C, ITER, FUNC, RET, GOTO) \
Radek Krejcid05cbd92018-12-05 14:26:40 +0100106 if (ARRAY_P) { \
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200107 LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, LY_ARRAY_COUNT(ARRAY_P), RET, GOTO); \
108 LY_ARRAY_COUNT_TYPE __array_offset = LY_ARRAY_COUNT(ARRAY_C); \
109 for (ITER = 0; ITER < LY_ARRAY_COUNT(ARRAY_P); ++ITER) { \
Radek Krejcid05cbd92018-12-05 14:26:40 +0100110 LY_ARRAY_INCREMENT(ARRAY_C); \
Radek Krejciec4da802019-05-02 13:02:41 +0200111 RET = FUNC(CTX, &(ARRAY_P)[ITER], ARRAY_C, &(ARRAY_C)[ITER + __array_offset]); \
Radek Krejci19a96102018-11-15 13:38:09 +0100112 LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
113 } \
114 }
115
Radek Krejciec4da802019-05-02 13:02:41 +0200116#define COMPILE_MEMBER_GOTO(CTX, MEMBER_P, MEMBER_C, FUNC, RET, GOTO) \
Radek Krejci19a96102018-11-15 13:38:09 +0100117 if (MEMBER_P) { \
118 MEMBER_C = calloc(1, sizeof *(MEMBER_C)); \
119 LY_CHECK_ERR_GOTO(!(MEMBER_C), LOGMEM((CTX)->ctx); RET = LY_EMEM, GOTO); \
Radek Krejciec4da802019-05-02 13:02:41 +0200120 RET = FUNC(CTX, MEMBER_P, MEMBER_C); \
Radek Krejci19a96102018-11-15 13:38:09 +0100121 LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
122 }
123
Radek Krejciec4da802019-05-02 13:02:41 +0200124#define COMPILE_MEMBER_ARRAY_GOTO(CTX, MEMBER_P, ARRAY_C, FUNC, RET, GOTO) \
Radek Krejci00b874b2019-02-12 10:54:50 +0100125 if (MEMBER_P) { \
126 LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, 1, RET, GOTO); \
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200127 LY_ARRAY_COUNT_TYPE __array_offset = LY_ARRAY_COUNT(ARRAY_C); \
Radek Krejci00b874b2019-02-12 10:54:50 +0100128 LY_ARRAY_INCREMENT(ARRAY_C); \
Radek Krejciec4da802019-05-02 13:02:41 +0200129 RET = FUNC(CTX, MEMBER_P, &(ARRAY_C)[__array_offset]); \
Radek Krejci00b874b2019-02-12 10:54:50 +0100130 LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
131 }
132
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100133#define COMPILE_CHECK_UNIQUENESS_ARRAY(CTX, ARRAY, MEMBER, EXCL, STMT, IDENT) \
Radek Krejcid05cbd92018-12-05 14:26:40 +0100134 if (ARRAY) { \
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200135 for (LY_ARRAY_COUNT_TYPE u__ = 0; u__ < LY_ARRAY_COUNT(ARRAY); ++u__) { \
Radek Krejci0af46292019-01-11 16:02:31 +0100136 if (&(ARRAY)[u__] != EXCL && (void*)((ARRAY)[u__].MEMBER) == (void*)(IDENT)) { \
Radek Krejcid05cbd92018-12-05 14:26:40 +0100137 LOGVAL((CTX)->ctx, LY_VLOG_STR, (CTX)->path, LY_VCODE_DUPIDENT, IDENT, STMT); \
138 return LY_EVALID; \
139 } \
140 } \
141 }
142
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100143#define COMPILE_CHECK_UNIQUENESS_PARRAY(CTX, ARRAY, MEMBER, EXCL, STMT, IDENT) \
144 if (ARRAY) { \
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200145 for (LY_ARRAY_COUNT_TYPE u__ = 0; u__ < LY_ARRAY_COUNT(ARRAY); ++u__) { \
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100146 if (&(ARRAY)[u__] != EXCL && (void*)((ARRAY)[u__]->MEMBER) == (void*)(IDENT)) { \
147 LOGVAL((CTX)->ctx, LY_VLOG_STR, (CTX)->path, LY_VCODE_DUPIDENT, IDENT, STMT); \
148 return LY_EVALID; \
149 } \
150 } \
151 }
152
153struct lysc_ext *
154lysc_ext_dup(struct lysc_ext *orig)
155{
156 ++orig->refcount;
157 return orig;
158}
159
Radek Krejci19a96102018-11-15 13:38:09 +0100160static struct lysc_ext_instance *
161lysc_ext_instance_dup(struct ly_ctx *ctx, struct lysc_ext_instance *orig)
162{
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100163 /* TODO - extensions, increase refcount */
Radek Krejci19a96102018-11-15 13:38:09 +0100164 (void) ctx;
165 (void) orig;
166 return NULL;
167}
168
Michal Vasko7f45cf22020-10-01 12:49:44 +0200169/**
170 * @brief Add/replace a leaf default value in unres.
171 * Can also be used for a single leaf-list default value.
172 *
173 * @param[in] ctx Compile context.
174 * @param[in] leaf Leaf with the default value.
175 * @param[in] dflt Default value to use.
176 * @return LY_ERR value.
177 */
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200178static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +0200179lysc_unres_leaf_dflt_add(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, struct lysp_qname *dflt)
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200180{
Michal Vasko7f45cf22020-10-01 12:49:44 +0200181 struct lysc_unres_dflt *r = NULL;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200182 uint32_t i;
183
184 for (i = 0; i < ctx->dflts.count; ++i) {
Michal Vasko7f45cf22020-10-01 12:49:44 +0200185 if (((struct lysc_unres_dflt *)ctx->dflts.objs[i])->leaf == leaf) {
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200186 /* just replace the default */
Michal Vasko7f45cf22020-10-01 12:49:44 +0200187 r = ctx->dflts.objs[i];
188 lysp_qname_free(ctx->ctx, r->dflt);
189 free(r->dflt);
190 break;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200191 }
192 }
Michal Vasko7f45cf22020-10-01 12:49:44 +0200193 if (!r) {
194 /* add new unres item */
195 r = calloc(1, sizeof *r);
196 LY_CHECK_ERR_RET(!r, LOGMEM(ctx->ctx), LY_EMEM);
197 r->leaf = leaf;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200198
Michal Vasko7f45cf22020-10-01 12:49:44 +0200199 LY_CHECK_RET(ly_set_add(&ctx->dflts, r, LY_SET_OPT_USEASLIST, NULL));
200 }
201
202 r->dflt = malloc(sizeof *r->dflt);
203 lysp_qname_dup(ctx->ctx, r->dflt, dflt);
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200204
205 return LY_SUCCESS;
206}
207
Radek Krejcib56c7502019-02-13 14:19:54 +0100208/**
Michal Vasko7f45cf22020-10-01 12:49:44 +0200209 * @brief Add/replace a leaf-list default value(s) in unres.
210 *
211 * @param[in] ctx Compile context.
212 * @param[in] llist Leaf-list with the default value.
213 * @param[in] dflts Sized array of the default values.
214 * @return LY_ERR value.
Radek Krejci474f9b82019-07-24 11:36:37 +0200215 */
216static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +0200217lysc_unres_llist_dflts_add(struct lysc_ctx *ctx, struct lysc_node_leaflist *llist, struct lysp_qname *dflts)
Radek Krejci474f9b82019-07-24 11:36:37 +0200218{
Michal Vasko7f45cf22020-10-01 12:49:44 +0200219 struct lysc_unres_dflt *r = NULL;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200220 uint32_t i;
221
222 for (i = 0; i < ctx->dflts.count; ++i) {
Michal Vasko7f45cf22020-10-01 12:49:44 +0200223 if (((struct lysc_unres_dflt *)ctx->dflts.objs[i])->llist == llist) {
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200224 /* just replace the defaults */
Michal Vasko7f45cf22020-10-01 12:49:44 +0200225 r = ctx->dflts.objs[i];
226 lysp_qname_free(ctx->ctx, r->dflt);
227 free(r->dflt);
228 r->dflt = NULL;
229 FREE_ARRAY(ctx->ctx, r->dflts, lysp_qname_free);
230 r->dflts = NULL;
231 break;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200232 }
233 }
Michal Vasko7f45cf22020-10-01 12:49:44 +0200234 if (!r) {
235 r = calloc(1, sizeof *r);
236 LY_CHECK_ERR_RET(!r, LOGMEM(ctx->ctx), LY_EMEM);
237 r->llist = llist;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200238
Michal Vasko7f45cf22020-10-01 12:49:44 +0200239 LY_CHECK_RET(ly_set_add(&ctx->dflts, r, LY_SET_OPT_USEASLIST, NULL));
240 }
241
242 DUP_ARRAY(ctx->ctx, dflts, r->dflts, lysp_qname_dup);
Radek Krejci474f9b82019-07-24 11:36:37 +0200243
244 return LY_SUCCESS;
245}
246
Radek Krejci474f9b82019-07-24 11:36:37 +0200247static void
Michal Vasko7f45cf22020-10-01 12:49:44 +0200248lysc_unres_dflt_free(const struct ly_ctx *ctx, struct lysc_unres_dflt *r)
Radek Krejci474f9b82019-07-24 11:36:37 +0200249{
Michal Vasko7f45cf22020-10-01 12:49:44 +0200250 assert(!r->dflt || !r->dflts);
251 if (r->dflt) {
252 lysp_qname_free((struct ly_ctx *)ctx, r->dflt);
253 free(r->dflt);
254 } else {
255 FREE_ARRAY((struct ly_ctx *)ctx, r->dflts, lysp_qname_free);
Radek Krejci474f9b82019-07-24 11:36:37 +0200256 }
Michal Vasko7f45cf22020-10-01 12:49:44 +0200257 free(r);
Radek Krejci474f9b82019-07-24 11:36:37 +0200258}
259
Radek Krejci0e59c312019-08-15 15:34:15 +0200260void
Radek Krejci327de162019-06-14 12:52:07 +0200261lysc_update_path(struct lysc_ctx *ctx, struct lysc_node *parent, const char *name)
262{
263 int len;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200264 uint8_t nextlevel = 0; /* 0 - no starttag, 1 - '/' starttag, 2 - '=' starttag + '}' endtag */
Radek Krejci327de162019-06-14 12:52:07 +0200265
266 if (!name) {
267 /* removing last path segment */
268 if (ctx->path[ctx->path_len - 1] == '}') {
Michal Vaskod989ba02020-08-24 10:59:24 +0200269 for ( ; ctx->path[ctx->path_len] != '=' && ctx->path[ctx->path_len] != '{'; --ctx->path_len) {}
Radek Krejci327de162019-06-14 12:52:07 +0200270 if (ctx->path[ctx->path_len] == '=') {
271 ctx->path[ctx->path_len++] = '}';
272 } else {
273 /* not a top-level special tag, remove also preceiding '/' */
274 goto remove_nodelevel;
275 }
276 } else {
277remove_nodelevel:
Michal Vaskod989ba02020-08-24 10:59:24 +0200278 for ( ; ctx->path[ctx->path_len] != '/'; --ctx->path_len) {}
Radek Krejci327de162019-06-14 12:52:07 +0200279 if (ctx->path_len == 0) {
280 /* top-level (last segment) */
Radek Krejciacc79042019-07-25 14:14:57 +0200281 ctx->path_len = 1;
Radek Krejci327de162019-06-14 12:52:07 +0200282 }
283 }
284 /* set new terminating NULL-byte */
285 ctx->path[ctx->path_len] = '\0';
286 } else {
287 if (ctx->path_len > 1) {
288 if (!parent && ctx->path[ctx->path_len - 1] == '}' && ctx->path[ctx->path_len - 2] != '\'') {
289 /* extension of the special tag */
290 nextlevel = 2;
291 --ctx->path_len;
292 } else {
293 /* there is already some path, so add next level */
294 nextlevel = 1;
295 }
296 } /* else the path is just initiated with '/', so do not add additional slash in case of top-level nodes */
297
298 if (nextlevel != 2) {
299 if ((parent && parent->module == ctx->mod) || (!parent && ctx->path_len > 1 && name[0] == '{')) {
300 /* module not changed, print the name unprefixed */
Radek Krejci70ee9152019-07-25 11:27:27 +0200301 len = snprintf(&ctx->path[ctx->path_len], LYSC_CTX_BUFSIZE - ctx->path_len, "%s%s", nextlevel ? "/" : "", name);
Radek Krejci327de162019-06-14 12:52:07 +0200302 } else {
Radek Krejci70ee9152019-07-25 11:27:27 +0200303 len = snprintf(&ctx->path[ctx->path_len], LYSC_CTX_BUFSIZE - ctx->path_len, "%s%s:%s", nextlevel ? "/" : "", ctx->mod->name, name);
Radek Krejci327de162019-06-14 12:52:07 +0200304 }
305 } else {
Radek Krejci70ee9152019-07-25 11:27:27 +0200306 len = snprintf(&ctx->path[ctx->path_len], LYSC_CTX_BUFSIZE - ctx->path_len, "='%s'}", name);
Radek Krejci327de162019-06-14 12:52:07 +0200307 }
Radek Krejci1deb5be2020-08-26 16:43:36 +0200308 if (len >= LYSC_CTX_BUFSIZE - (int)ctx->path_len) {
Radek Krejciacc79042019-07-25 14:14:57 +0200309 /* output truncated */
310 ctx->path_len = LYSC_CTX_BUFSIZE - 1;
311 } else {
312 ctx->path_len += len;
313 }
Radek Krejci327de162019-06-14 12:52:07 +0200314 }
315}
316
317/**
Radek Krejcib56c7502019-02-13 14:19:54 +0100318 * @brief Duplicate the compiled pattern structure.
319 *
320 * Instead of duplicating memory, the reference counter in the @p orig is increased.
321 *
322 * @param[in] orig The pattern structure to duplicate.
323 * @return The duplicated structure to use.
324 */
Michal Vasko22df3f02020-08-24 13:29:22 +0200325static struct lysc_pattern *
Radek Krejci19a96102018-11-15 13:38:09 +0100326lysc_pattern_dup(struct lysc_pattern *orig)
327{
328 ++orig->refcount;
329 return orig;
330}
331
Radek Krejcib56c7502019-02-13 14:19:54 +0100332/**
333 * @brief Duplicate the array of compiled patterns.
334 *
335 * The sized array itself is duplicated, but the pattern structures are just shadowed by increasing their reference counter.
336 *
337 * @param[in] ctx Libyang context for logging.
338 * @param[in] orig The patterns sized array to duplicate.
339 * @return New sized array as a copy of @p orig.
340 * @return NULL in case of memory allocation error.
341 */
Michal Vasko22df3f02020-08-24 13:29:22 +0200342static struct lysc_pattern **
Radek Krejci19a96102018-11-15 13:38:09 +0100343lysc_patterns_dup(struct ly_ctx *ctx, struct lysc_pattern **orig)
344{
Radek Krejcid05cbd92018-12-05 14:26:40 +0100345 struct lysc_pattern **dup = NULL;
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200346 LY_ARRAY_COUNT_TYPE u;
Radek Krejci19a96102018-11-15 13:38:09 +0100347
Radek Krejcib56c7502019-02-13 14:19:54 +0100348 assert(orig);
349
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200350 LY_ARRAY_CREATE_RET(ctx, dup, LY_ARRAY_COUNT(orig), NULL);
Radek Krejci19a96102018-11-15 13:38:09 +0100351 LY_ARRAY_FOR(orig, u) {
352 dup[u] = lysc_pattern_dup(orig[u]);
353 LY_ARRAY_INCREMENT(dup);
354 }
355 return dup;
356}
357
Radek Krejcib56c7502019-02-13 14:19:54 +0100358/**
359 * @brief Duplicate compiled range structure.
360 *
361 * @param[in] ctx Libyang context for logging.
362 * @param[in] orig The range structure to be duplicated.
363 * @return New compiled range structure as a copy of @p orig.
364 * @return NULL in case of memory allocation error.
365 */
Michal Vasko22df3f02020-08-24 13:29:22 +0200366struct lysc_range *
Radek Krejci19a96102018-11-15 13:38:09 +0100367lysc_range_dup(struct ly_ctx *ctx, const struct lysc_range *orig)
368{
369 struct lysc_range *dup;
370 LY_ERR ret;
371
Radek Krejcib56c7502019-02-13 14:19:54 +0100372 assert(orig);
373
Radek Krejci19a96102018-11-15 13:38:09 +0100374 dup = calloc(1, sizeof *dup);
375 LY_CHECK_ERR_RET(!dup, LOGMEM(ctx), NULL);
376 if (orig->parts) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200377 LY_ARRAY_CREATE_GOTO(ctx, dup->parts, LY_ARRAY_COUNT(orig->parts), ret, cleanup);
378 LY_ARRAY_COUNT(dup->parts) = LY_ARRAY_COUNT(orig->parts);
379 memcpy(dup->parts, orig->parts, LY_ARRAY_COUNT(dup->parts) * sizeof *dup->parts);
Radek Krejci19a96102018-11-15 13:38:09 +0100380 }
Radek Krejci011e4aa2020-09-04 15:22:31 +0200381 DUP_STRING_GOTO(ctx, orig->eapptag, dup->eapptag, ret, cleanup);
382 DUP_STRING_GOTO(ctx, orig->emsg, dup->emsg, ret, cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +0100383 dup->exts = lysc_ext_instance_dup(ctx, orig->exts);
384
385 return dup;
386cleanup:
387 free(dup);
388 (void) ret; /* set but not used due to the return type */
389 return NULL;
390}
391
Radek Krejcib56c7502019-02-13 14:19:54 +0100392/**
393 * @brief Stack for processing if-feature expressions.
394 */
Radek Krejci19a96102018-11-15 13:38:09 +0100395struct iff_stack {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200396 size_t size; /**< number of items in the stack */
397 size_t index; /**< first empty item */
398 uint8_t *stack; /**< stack - array of @ref ifftokens to create the if-feature expression in prefix format */
Radek Krejci19a96102018-11-15 13:38:09 +0100399};
400
Radek Krejcib56c7502019-02-13 14:19:54 +0100401/**
402 * @brief Add @ref ifftokens into the stack.
403 * @param[in] stack The if-feature stack to use.
404 * @param[in] value One of the @ref ifftokens to store in the stack.
405 * @return LY_EMEM in case of memory allocation error
406 * @return LY_ESUCCESS if the value successfully stored.
407 */
Radek Krejci19a96102018-11-15 13:38:09 +0100408static LY_ERR
409iff_stack_push(struct iff_stack *stack, uint8_t value)
410{
411 if (stack->index == stack->size) {
412 stack->size += 4;
413 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
414 LY_CHECK_ERR_RET(!stack->stack, LOGMEM(NULL); stack->size = 0, LY_EMEM);
415 }
416 stack->stack[stack->index++] = value;
417 return LY_SUCCESS;
418}
419
Radek Krejcib56c7502019-02-13 14:19:54 +0100420/**
421 * @brief Get (and remove) the last item form the stack.
422 * @param[in] stack The if-feature stack to use.
423 * @return The value from the top of the stack.
424 */
Radek Krejci19a96102018-11-15 13:38:09 +0100425static uint8_t
426iff_stack_pop(struct iff_stack *stack)
427{
Radek Krejcib56c7502019-02-13 14:19:54 +0100428 assert(stack && stack->index);
429
Radek Krejci19a96102018-11-15 13:38:09 +0100430 stack->index--;
431 return stack->stack[stack->index];
432}
433
Radek Krejcib56c7502019-02-13 14:19:54 +0100434/**
435 * @brief Clean up the stack.
436 * @param[in] stack The if-feature stack to use.
437 */
Radek Krejci19a96102018-11-15 13:38:09 +0100438static void
439iff_stack_clean(struct iff_stack *stack)
440{
441 stack->size = 0;
442 free(stack->stack);
443}
444
Radek Krejcib56c7502019-02-13 14:19:54 +0100445/**
446 * @brief Store the @ref ifftokens (@p op) on the given position in the 2bits array
447 * (libyang format of the if-feature expression).
448 * @param[in,out] list The 2bits array to modify.
449 * @param[in] op The operand (@ref ifftokens) to store.
450 * @param[in] pos Position (0-based) where to store the given @p op.
451 */
Radek Krejci19a96102018-11-15 13:38:09 +0100452static void
Radek Krejci1deb5be2020-08-26 16:43:36 +0200453iff_setop(uint8_t *list, uint8_t op, size_t pos)
Radek Krejci19a96102018-11-15 13:38:09 +0100454{
455 uint8_t *item;
456 uint8_t mask = 3;
457
Radek Krejci19a96102018-11-15 13:38:09 +0100458 assert(op <= 3); /* max 2 bits */
459
460 item = &list[pos / 4];
461 mask = mask << 2 * (pos % 4);
462 *item = (*item) & ~mask;
463 *item = (*item) | (op << 2 * (pos % 4));
464}
465
Radek Krejcib56c7502019-02-13 14:19:54 +0100466#define LYS_IFF_LP 0x04 /**< Additional, temporary, value of @ref ifftokens: ( */
467#define LYS_IFF_RP 0x08 /**< Additional, temporary, value of @ref ifftokens: ) */
Radek Krejci19a96102018-11-15 13:38:09 +0100468
Radek Krejci0af46292019-01-11 16:02:31 +0100469/**
470 * @brief Find a feature of the given name and referenced in the given module.
471 *
472 * If the compiled schema is available (the schema is implemented), the feature from the compiled schema is
473 * returned. Otherwise, the special array of pre-compiled features is used to search for the feature. Such
474 * features are always disabled (feature from not implemented schema cannot be enabled), but in case the schema
475 * will be made implemented in future (no matter if implicitly via augmenting/deviating it or explicitly via
476 * ly_ctx_module_implement()), the compilation of these feature structure is finished, but the pointers
477 * assigned till that time will be still valid.
478 *
479 * @param[in] mod Module where the feature was referenced (used to resolve prefix of the feature).
480 * @param[in] name Name of the feature including possible prefix.
481 * @param[in] len Length of the string representing the feature identifier in the name variable (mandatory!).
482 * @return Pointer to the feature structure if found, NULL otherwise.
483 */
Radek Krejci19a96102018-11-15 13:38:09 +0100484static struct lysc_feature *
Michal Vasko7f45cf22020-10-01 12:49:44 +0200485lys_feature_find(const struct lys_module *mod, const char *name, size_t len)
Radek Krejci19a96102018-11-15 13:38:09 +0100486{
487 size_t i;
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200488 LY_ARRAY_COUNT_TYPE u;
Radek Krejci14915cc2020-09-14 17:28:13 +0200489 struct lysc_feature *f;
Radek Krejci19a96102018-11-15 13:38:09 +0100490
Radek Krejci120d8542020-08-12 09:29:16 +0200491 assert(mod);
492
Radek Krejci19a96102018-11-15 13:38:09 +0100493 for (i = 0; i < len; ++i) {
494 if (name[i] == ':') {
495 /* we have a prefixed feature */
Radek Krejci0af46292019-01-11 16:02:31 +0100496 mod = lys_module_find_prefix(mod, name, i);
Radek Krejci19a96102018-11-15 13:38:09 +0100497 LY_CHECK_RET(!mod, NULL);
498
499 name = &name[i + 1];
500 len = len - i - 1;
501 }
502 }
503
504 /* we have the correct module, get the feature */
Radek Krejci14915cc2020-09-14 17:28:13 +0200505 LY_ARRAY_FOR(mod->features, u) {
506 f = &mod->features[u];
Radek Krejci7f9b6512019-09-18 13:11:09 +0200507 if (!ly_strncmp(f->name, name, len)) {
Radek Krejci19a96102018-11-15 13:38:09 +0100508 return f;
509 }
510 }
511
512 return NULL;
513}
514
Michal Vasko8d544252020-03-02 10:19:52 +0100515/**
Michal Vasko5fe75f12020-03-02 13:52:37 +0100516 * @brief Fill in the prepared compiled extensions definition structure according to the parsed extension definition.
517 */
518static LY_ERR
519lys_compile_extension(struct lysc_ctx *ctx, const struct lys_module *ext_mod, struct lysp_ext *ext_p, struct lysc_ext **ext)
520{
521 LY_ERR ret = LY_SUCCESS;
522
523 if (!ext_p->compiled) {
524 lysc_update_path(ctx, NULL, "{extension}");
525 lysc_update_path(ctx, NULL, ext_p->name);
526
527 /* compile the extension definition */
528 ext_p->compiled = calloc(1, sizeof **ext);
529 ext_p->compiled->refcount = 1;
Radek Krejci011e4aa2020-09-04 15:22:31 +0200530 DUP_STRING_GOTO(ctx->ctx, ext_p->name, ext_p->compiled->name, ret, done);
531 DUP_STRING_GOTO(ctx->ctx, ext_p->argument, ext_p->compiled->argument, ret, done);
Michal Vasko5fe75f12020-03-02 13:52:37 +0100532 ext_p->compiled->module = (struct lys_module *)ext_mod;
533 COMPILE_EXTS_GOTO(ctx, ext_p->exts, ext_p->compiled->exts, *ext, LYEXT_PAR_EXT, ret, done);
534
535 lysc_update_path(ctx, NULL, NULL);
536 lysc_update_path(ctx, NULL, NULL);
537
538 /* find extension definition plugin */
539 ext_p->compiled->plugin = lyext_get_plugin(ext_p->compiled);
540 }
541
542 *ext = lysc_ext_dup(ext_p->compiled);
543
544done:
545 return ret;
546}
547
548/**
Michal Vasko8d544252020-03-02 10:19:52 +0100549 * @brief Fill in the prepared compiled extension instance structure according to the parsed extension instance.
550 *
551 * @param[in] ctx Compilation context.
552 * @param[in] ext_p Parsed extension instance.
553 * @param[in,out] ext Prepared compiled extension instance.
554 * @param[in] parent Extension instance parent.
555 * @param[in] parent_type Extension instance parent type.
556 * @param[in] ext_mod Optional module with the extension instance extension definition, set only for internal annotations.
557 */
Radek Krejci19a96102018-11-15 13:38:09 +0100558static LY_ERR
Michal Vasko8d544252020-03-02 10:19:52 +0100559lys_compile_ext(struct lysc_ctx *ctx, struct lysp_ext_instance *ext_p, struct lysc_ext_instance *ext, void *parent,
Radek Krejci0f969882020-08-21 16:56:47 +0200560 LYEXT_PARENT parent_type, const struct lys_module *ext_mod)
Radek Krejci19a96102018-11-15 13:38:09 +0100561{
Radek Krejci011e4aa2020-09-04 15:22:31 +0200562 LY_ERR ret = LY_SUCCESS;
Radek Krejci19a96102018-11-15 13:38:09 +0100563 const char *name;
Radek Krejci7eb54ba2020-05-18 16:30:04 +0200564 size_t u;
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200565 LY_ARRAY_COUNT_TYPE v;
Radek Krejci7c960162019-09-18 14:16:12 +0200566 const char *prefixed_name = NULL;
Radek Krejci19a96102018-11-15 13:38:09 +0100567
Radek Krejci011e4aa2020-09-04 15:22:31 +0200568 DUP_STRING(ctx->ctx, ext_p->argument, ext->argument, ret);
569 LY_CHECK_RET(ret);
570
Radek Krejci19a96102018-11-15 13:38:09 +0100571 ext->insubstmt = ext_p->insubstmt;
572 ext->insubstmt_index = ext_p->insubstmt_index;
Radek Krejci28681fa2019-09-06 13:08:45 +0200573 ext->module = ctx->mod_def;
Radek Krejci0935f412019-08-20 16:15:18 +0200574 ext->parent = parent;
575 ext->parent_type = parent_type;
Radek Krejci19a96102018-11-15 13:38:09 +0100576
Michal Vasko22df3f02020-08-24 13:29:22 +0200577 lysc_update_path(ctx, ext->parent_type == LYEXT_PAR_NODE ? (struct lysc_node *)ext->parent : NULL, "{extension}");
Radek Krejcif56e2a42019-09-09 14:15:25 +0200578
Radek Krejci19a96102018-11-15 13:38:09 +0100579 /* get module where the extension definition should be placed */
Radek Krejci1e008d22020-08-17 11:37:37 +0200580 for (u = strlen(ext_p->name); u && ext_p->name[u - 1] != ':'; --u) {}
Radek Krejci7c960162019-09-18 14:16:12 +0200581 if (ext_p->yin) {
582 /* YIN parser has to replace prefixes by the namespace - XML namespace/prefix pairs may differs form the YANG schema's
583 * namespace/prefix pair. YIN parser does not have the imports available, so mapping from XML namespace to the
584 * YANG (import) prefix must be done here. */
585 if (!ly_strncmp(ctx->mod_def->ns, ext_p->name, u - 1)) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200586 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, &ext_p->name[u], 0, &prefixed_name), cleanup);
Radek Krejci7c960162019-09-18 14:16:12 +0200587 u = 0;
Michal Vasko7c8439f2020-08-05 13:25:19 +0200588 } else {
589 assert(ctx->mod_def->parsed);
590 LY_ARRAY_FOR(ctx->mod_def->parsed->imports, v) {
591 if (!ly_strncmp(ctx->mod_def->parsed->imports[v].module->ns, ext_p->name, u - 1)) {
Radek Krejci7c960162019-09-18 14:16:12 +0200592 char *s;
Michal Vasko7c8439f2020-08-05 13:25:19 +0200593 LY_CHECK_ERR_GOTO(asprintf(&s, "%s:%s", ctx->mod_def->parsed->imports[v].prefix, &ext_p->name[u]) == -1,
Radek Krejci200f1062020-07-11 22:51:03 +0200594 ret = LY_EMEM, cleanup);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200595 LY_CHECK_GOTO(ret = lydict_insert_zc(ctx->ctx, s, &prefixed_name), cleanup);
Michal Vasko7c8439f2020-08-05 13:25:19 +0200596 u = strlen(ctx->mod_def->parsed->imports[v].prefix) + 1; /* add semicolon */
Radek Krejci7c960162019-09-18 14:16:12 +0200597 break;
598 }
599 }
600 }
601 if (!prefixed_name) {
602 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
603 "Invalid XML prefix of \"%.*s\" namespace used for extension instance identifier.", u, ext_p->name);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200604 ret = LY_EVALID;
Radek Krejci7c960162019-09-18 14:16:12 +0200605 goto cleanup;
606 }
607 } else {
608 prefixed_name = ext_p->name;
609 }
610 lysc_update_path(ctx, NULL, prefixed_name);
611
Michal Vasko8d544252020-03-02 10:19:52 +0100612 if (!ext_mod) {
Radek Krejci63f55512020-05-20 14:37:18 +0200613 ext_mod = u ? lys_module_find_prefix(ctx->mod_def, prefixed_name, u - 1) : ctx->mod_def;
Michal Vasko8d544252020-03-02 10:19:52 +0100614 if (!ext_mod) {
615 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
616 "Invalid prefix \"%.*s\" used for extension instance identifier.", u, prefixed_name);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200617 ret = LY_EVALID;
Michal Vasko8d544252020-03-02 10:19:52 +0100618 goto cleanup;
619 } else if (!ext_mod->parsed->extensions) {
620 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
621 "Extension instance \"%s\" refers \"%s\" module that does not contain extension definitions.",
622 prefixed_name, ext_mod->name);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200623 ret = LY_EVALID;
Michal Vasko8d544252020-03-02 10:19:52 +0100624 goto cleanup;
625 }
Radek Krejci7c960162019-09-18 14:16:12 +0200626 }
627 name = &prefixed_name[u];
Radek Krejci0935f412019-08-20 16:15:18 +0200628
Michal Vasko5fe75f12020-03-02 13:52:37 +0100629 /* find the parsed extension definition there */
Radek Krejci7eb54ba2020-05-18 16:30:04 +0200630 LY_ARRAY_FOR(ext_mod->parsed->extensions, v) {
631 if (!strcmp(name, ext_mod->parsed->extensions[v].name)) {
Michal Vasko5fe75f12020-03-02 13:52:37 +0100632 /* compile extension definition and assign it */
Radek Krejci011e4aa2020-09-04 15:22:31 +0200633 LY_CHECK_GOTO(ret = lys_compile_extension(ctx, ext_mod, &ext_mod->parsed->extensions[v], &ext->def), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +0100634 break;
635 }
636 }
Radek Krejci7c960162019-09-18 14:16:12 +0200637 if (!ext->def) {
638 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
639 "Extension definition of extension instance \"%s\" not found.", prefixed_name);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200640 ret = LY_EVALID;
Radek Krejci7c960162019-09-18 14:16:12 +0200641 goto cleanup;
642 }
Radek Krejci0935f412019-08-20 16:15:18 +0200643
Radek Krejcif56e2a42019-09-09 14:15:25 +0200644 /* unify the parsed extension from YIN and YANG sources. Without extension definition, it is not possible
645 * to get extension's argument from YIN source, so it is stored as one of the substatements. Here we have
646 * to find it, mark it with LYS_YIN_ARGUMENT and store it in the compiled structure. */
Radek Krejci7c960162019-09-18 14:16:12 +0200647 if (ext_p->yin && ext->def->argument && !ext->argument) {
Radek Krejcif56e2a42019-09-09 14:15:25 +0200648 /* Schema was parsed from YIN and an argument is expected, ... */
649 struct lysp_stmt *stmt = NULL;
650
651 if (ext->def->flags & LYS_YINELEM_TRUE) {
652 /* ... argument was the first XML child element */
653 if (ext_p->child && !(ext_p->child->flags & LYS_YIN_ATTR)) {
654 /* TODO check namespace of the statement */
655 if (!strcmp(ext_p->child->stmt, ext->def->argument)) {
656 stmt = ext_p->child;
657 }
658 }
659 } else {
660 /* ... argument was one of the XML attributes which are represented as child stmt
661 * with LYS_YIN_ATTR flag */
662 for (stmt = ext_p->child; stmt && (stmt->flags & LYS_YIN_ATTR); stmt = stmt->next) {
663 if (!strcmp(stmt->stmt, ext->def->argument)) {
664 /* this is the extension's argument */
Radek Krejcif56e2a42019-09-09 14:15:25 +0200665 break;
666 }
667 }
668 }
669 if (!stmt) {
670 /* missing extension's argument */
671 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejci7c960162019-09-18 14:16:12 +0200672 "Extension instance \"%s\" misses argument \"%s\".", prefixed_name, ext->def->argument);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200673 ret = LY_EVALID;
Radek Krejci7c960162019-09-18 14:16:12 +0200674 goto cleanup;
Radek Krejcif56e2a42019-09-09 14:15:25 +0200675
676 }
Radek Krejci011e4aa2020-09-04 15:22:31 +0200677 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, stmt->arg, 0, &ext->argument), cleanup);
Radek Krejcif56e2a42019-09-09 14:15:25 +0200678 stmt->flags |= LYS_YIN_ARGUMENT;
679 }
Radek Krejci7c960162019-09-18 14:16:12 +0200680 if (prefixed_name != ext_p->name) {
681 lydict_remove(ctx->ctx, ext_p->name);
682 ext_p->name = prefixed_name;
683 if (!ext_p->argument && ext->argument) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200684 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, ext->argument, 0, &ext_p->argument), cleanup);
Radek Krejci7c960162019-09-18 14:16:12 +0200685 }
686 }
Radek Krejcif56e2a42019-09-09 14:15:25 +0200687
Radek Krejci0935f412019-08-20 16:15:18 +0200688 if (ext->def->plugin && ext->def->plugin->compile) {
Radek Krejciad5963b2019-09-06 16:03:05 +0200689 if (ext->argument) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200690 lysc_update_path(ctx, (struct lysc_node *)ext, ext->argument);
Radek Krejciad5963b2019-09-06 16:03:05 +0200691 }
Radek Krejci011e4aa2020-09-04 15:22:31 +0200692 LY_CHECK_GOTO(ret = ext->def->plugin->compile(ctx, ext_p, ext), cleanup);
Radek Krejciad5963b2019-09-06 16:03:05 +0200693 if (ext->argument) {
694 lysc_update_path(ctx, NULL, NULL);
695 }
Radek Krejci0935f412019-08-20 16:15:18 +0200696 }
Radek Krejcif56e2a42019-09-09 14:15:25 +0200697 ext_p->compiled = ext;
698
Radek Krejci7c960162019-09-18 14:16:12 +0200699cleanup:
700 if (prefixed_name && prefixed_name != ext_p->name) {
701 lydict_remove(ctx->ctx, prefixed_name);
702 }
703
Radek Krejcif56e2a42019-09-09 14:15:25 +0200704 lysc_update_path(ctx, NULL, NULL);
705 lysc_update_path(ctx, NULL, NULL);
Radek Krejci0935f412019-08-20 16:15:18 +0200706
Radek Krejci7c960162019-09-18 14:16:12 +0200707 return ret;
Radek Krejci0935f412019-08-20 16:15:18 +0200708}
709
710/**
Radek Krejcib56c7502019-02-13 14:19:54 +0100711 * @brief Compile information from the if-feature statement
712 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +0200713 * @param[in] qname The if-feature argument to process. It is pointer-to-qname just to unify the compile functions.
Radek Krejcib56c7502019-02-13 14:19:54 +0100714 * @param[in,out] iff Prepared (empty) compiled if-feature structure to fill.
715 * @return LY_ERR value.
716 */
Radek Krejci19a96102018-11-15 13:38:09 +0100717static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +0200718lys_compile_iffeature(struct lysc_ctx *ctx, struct lysp_qname *qname, struct lysc_iffeature *iff)
Radek Krejci19a96102018-11-15 13:38:09 +0100719{
Radek Krejci1deb5be2020-08-26 16:43:36 +0200720 LY_ERR rc = LY_SUCCESS;
Michal Vasko7f45cf22020-10-01 12:49:44 +0200721 const char *c = qname->str;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200722 int64_t i, j;
723 int8_t op_len, last_not = 0, checkversion = 0;
724 LY_ARRAY_COUNT_TYPE f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci19a96102018-11-15 13:38:09 +0100725 uint8_t op;
726 struct iff_stack stack = {0, 0, NULL};
727 struct lysc_feature *f;
728
729 assert(c);
730
731 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
Radek Krejci1deb5be2020-08-26 16:43:36 +0200732 for (i = j = 0; c[i]; i++) {
Radek Krejci19a96102018-11-15 13:38:09 +0100733 if (c[i] == '(') {
734 j++;
735 checkversion = 1;
736 continue;
737 } else if (c[i] == ')') {
738 j--;
739 continue;
740 } else if (isspace(c[i])) {
741 checkversion = 1;
742 continue;
743 }
744
Radek Krejci1deb5be2020-08-26 16:43:36 +0200745 if (!strncmp(&c[i], "not", op_len = 3) || !strncmp(&c[i], "and", op_len = 3) || !strncmp(&c[i], "or", op_len = 2)) {
746 uint64_t spaces;
747 for (spaces = 0; c[i + op_len + spaces] && isspace(c[i + op_len + spaces]); spaces++);
748 if (c[i + op_len + spaces] == '\0') {
Radek Krejci19a96102018-11-15 13:38:09 +0100749 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko7f45cf22020-10-01 12:49:44 +0200750 "Invalid value \"%s\" of if-feature - unexpected end of expression.", qname->str);
Radek Krejci19a96102018-11-15 13:38:09 +0100751 return LY_EVALID;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200752 } else if (!isspace(c[i + op_len])) {
Radek Krejci19a96102018-11-15 13:38:09 +0100753 /* feature name starting with the not/and/or */
754 last_not = 0;
755 f_size++;
756 } else if (c[i] == 'n') { /* not operation */
757 if (last_not) {
758 /* double not */
759 expr_size = expr_size - 2;
760 last_not = 0;
761 } else {
762 last_not = 1;
763 }
764 } else { /* and, or */
Radek Krejci6788abc2019-06-14 13:56:49 +0200765 if (f_exp != f_size) {
766 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko7f45cf22020-10-01 12:49:44 +0200767 "Invalid value \"%s\" of if-feature - missing feature/expression before \"%.*s\" operation.",
768 qname->str, op_len, &c[i]);
Radek Krejci6788abc2019-06-14 13:56:49 +0200769 return LY_EVALID;
770 }
Radek Krejci19a96102018-11-15 13:38:09 +0100771 f_exp++;
Radek Krejci6788abc2019-06-14 13:56:49 +0200772
Radek Krejci19a96102018-11-15 13:38:09 +0100773 /* not a not operation */
774 last_not = 0;
775 }
Radek Krejci1deb5be2020-08-26 16:43:36 +0200776 i += op_len;
Radek Krejci19a96102018-11-15 13:38:09 +0100777 } else {
778 f_size++;
779 last_not = 0;
780 }
781 expr_size++;
782
783 while (!isspace(c[i])) {
Radek Krejci6788abc2019-06-14 13:56:49 +0200784 if (!c[i] || c[i] == ')' || c[i] == '(') {
Radek Krejci19a96102018-11-15 13:38:09 +0100785 i--;
786 break;
787 }
788 i++;
789 }
790 }
Radek Krejci6788abc2019-06-14 13:56:49 +0200791 if (j) {
Radek Krejci19a96102018-11-15 13:38:09 +0100792 /* not matching count of ( and ) */
793 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko7f45cf22020-10-01 12:49:44 +0200794 "Invalid value \"%s\" of if-feature - non-matching opening and closing parentheses.", qname->str);
Radek Krejci19a96102018-11-15 13:38:09 +0100795 return LY_EVALID;
796 }
Radek Krejci6788abc2019-06-14 13:56:49 +0200797 if (f_exp != f_size) {
798 /* features do not match the needed arguments for the logical operations */
799 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
800 "Invalid value \"%s\" of if-feature - number of features in expression does not match "
Michal Vasko7f45cf22020-10-01 12:49:44 +0200801 "the required number of operands for the operations.", qname->str);
Radek Krejci6788abc2019-06-14 13:56:49 +0200802 return LY_EVALID;
803 }
Radek Krejci19a96102018-11-15 13:38:09 +0100804
805 if (checkversion || expr_size > 1) {
806 /* check that we have 1.1 module */
Michal Vasko7f45cf22020-10-01 12:49:44 +0200807 if (qname->mod->version != LYS_VERSION_1_1) {
Radek Krejci19a96102018-11-15 13:38:09 +0100808 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko7f45cf22020-10-01 12:49:44 +0200809 "Invalid value \"%s\" of if-feature - YANG 1.1 expression in YANG 1.0 module.", qname->str);
Radek Krejci19a96102018-11-15 13:38:09 +0100810 return LY_EVALID;
811 }
812 }
813
814 /* allocate the memory */
815 LY_ARRAY_CREATE_RET(ctx->ctx, iff->features, f_size, LY_EMEM);
816 iff->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iff->expr);
817 stack.stack = malloc(expr_size * sizeof *stack.stack);
Radek Krejci1deb5be2020-08-26 16:43:36 +0200818 LY_CHECK_ERR_GOTO(!stack.stack || !iff->expr, LOGMEM(ctx->ctx); rc = LY_EMEM, error);
Radek Krejci19a96102018-11-15 13:38:09 +0100819
820 stack.size = expr_size;
821 f_size--; expr_size--; /* used as indexes from now */
822
823 for (i--; i >= 0; i--) {
824 if (c[i] == ')') {
825 /* push it on stack */
826 iff_stack_push(&stack, LYS_IFF_RP);
827 continue;
828 } else if (c[i] == '(') {
829 /* pop from the stack into result all operators until ) */
Michal Vaskod989ba02020-08-24 10:59:24 +0200830 while ((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
Radek Krejci19a96102018-11-15 13:38:09 +0100831 iff_setop(iff->expr, op, expr_size--);
832 }
833 continue;
834 } else if (isspace(c[i])) {
835 continue;
836 }
837
838 /* end of operator or operand -> find beginning and get what is it */
839 j = i + 1;
840 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
841 i--;
842 }
843 i++; /* go back by one step */
844
845 if (!strncmp(&c[i], "not", 3) && isspace(c[i + 3])) {
846 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
847 /* double not */
848 iff_stack_pop(&stack);
849 } else {
850 /* not has the highest priority, so do not pop from the stack
851 * as in case of AND and OR */
852 iff_stack_push(&stack, LYS_IFF_NOT);
853 }
854 } else if (!strncmp(&c[i], "and", 3) && isspace(c[i + 3])) {
855 /* as for OR - pop from the stack all operators with the same or higher
856 * priority and store them to the result, then push the AND to the stack */
857 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
858 op = iff_stack_pop(&stack);
859 iff_setop(iff->expr, op, expr_size--);
860 }
861 iff_stack_push(&stack, LYS_IFF_AND);
862 } else if (!strncmp(&c[i], "or", 2) && isspace(c[i + 2])) {
863 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
864 op = iff_stack_pop(&stack);
865 iff_setop(iff->expr, op, expr_size--);
866 }
867 iff_stack_push(&stack, LYS_IFF_OR);
868 } else {
869 /* feature name, length is j - i */
870
871 /* add it to the expression */
872 iff_setop(iff->expr, LYS_IFF_F, expr_size--);
873
874 /* now get the link to the feature definition */
Michal Vasko7f45cf22020-10-01 12:49:44 +0200875 f = lys_feature_find(qname->mod, &c[i], j - i);
Radek Krejci0af46292019-01-11 16:02:31 +0100876 LY_CHECK_ERR_GOTO(!f, LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko7f45cf22020-10-01 12:49:44 +0200877 "Invalid value \"%s\" of if-feature - unable to find feature \"%.*s\".", qname->str, j - i, &c[i]);
878 rc = LY_EVALID, error)
Radek Krejci19a96102018-11-15 13:38:09 +0100879 iff->features[f_size] = f;
880 LY_ARRAY_INCREMENT(iff->features);
881 f_size--;
882 }
883 }
884 while (stack.index) {
885 op = iff_stack_pop(&stack);
886 iff_setop(iff->expr, op, expr_size--);
887 }
888
889 if (++expr_size || ++f_size) {
890 /* not all expected operators and operands found */
891 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko7f45cf22020-10-01 12:49:44 +0200892 "Invalid value \"%s\" of if-feature - processing error.", qname->str);
Radek Krejci19a96102018-11-15 13:38:09 +0100893 rc = LY_EINT;
894 } else {
895 rc = LY_SUCCESS;
896 }
897
898error:
899 /* cleanup */
900 iff_stack_clean(&stack);
901
902 return rc;
903}
904
Radek Krejcib56c7502019-02-13 14:19:54 +0100905/**
Michal Vasko175012e2019-11-06 15:49:14 +0100906 * @brief Get the XPath context node for the given schema node.
907 * @param[in] start The schema node where the XPath expression appears.
908 * @return The context node to evaluate XPath expression in given schema node.
909 * @return NULL in case the context node is the root node.
910 */
911static struct lysc_node *
912lysc_xpath_context(struct lysc_node *start)
913{
Michal Vasko1bf09392020-03-27 12:38:10 +0100914 for (; start && !(start->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_RPC | LYS_ACTION | LYS_NOTIF));
Radek Krejci1e008d22020-08-17 11:37:37 +0200915 start = start->parent) {}
Michal Vasko175012e2019-11-06 15:49:14 +0100916 return start;
917}
918
919/**
Radek Krejcib56c7502019-02-13 14:19:54 +0100920 * @brief Compile information from the when statement
921 * @param[in] ctx Compile context.
922 * @param[in] when_p The parsed when statement structure.
Michal Vasko175012e2019-11-06 15:49:14 +0100923 * @param[in] flags Flags of the node with the "when" defiition.
924 * @param[in] node Node that inherited the "when" definition, must be connected to parents.
Radek Krejcib56c7502019-02-13 14:19:54 +0100925 * @param[out] when Pointer where to store pointer to the created compiled when structure.
926 * @return LY_ERR value.
927 */
Radek Krejci19a96102018-11-15 13:38:09 +0100928static LY_ERR
Michal Vasko175012e2019-11-06 15:49:14 +0100929lys_compile_when(struct lysc_ctx *ctx, struct lysp_when *when_p, uint16_t flags, struct lysc_node *node, struct lysc_when **when)
Radek Krejci19a96102018-11-15 13:38:09 +0100930{
Radek Krejci19a96102018-11-15 13:38:09 +0100931 LY_ERR ret = LY_SUCCESS;
932
Radek Krejci00b874b2019-02-12 10:54:50 +0100933 *when = calloc(1, sizeof **when);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200934 LY_CHECK_ERR_RET(!(*when), LOGMEM(ctx->ctx), LY_EMEM);
Radek Krejci00b874b2019-02-12 10:54:50 +0100935 (*when)->refcount = 1;
Radek Krejcif03a9e22020-09-18 20:09:31 +0200936 LY_CHECK_RET(lyxp_expr_parse(ctx->ctx, when_p->cond, 0, 1, &(*when)->cond));
Radek Krejcia0f704a2019-09-09 16:12:23 +0200937 (*when)->module = ctx->mod_def;
Michal Vasko175012e2019-11-06 15:49:14 +0100938 (*when)->context = lysc_xpath_context(node);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200939 DUP_STRING_GOTO(ctx->ctx, when_p->dsc, (*when)->dsc, ret, done);
940 DUP_STRING_GOTO(ctx->ctx, when_p->ref, (*when)->ref, ret, done);
Radek Krejci0935f412019-08-20 16:15:18 +0200941 COMPILE_EXTS_GOTO(ctx, when_p->exts, (*when)->exts, (*when), LYEXT_PAR_WHEN, ret, done);
Michal Vasko175012e2019-11-06 15:49:14 +0100942 (*when)->flags = flags & LYS_STATUS_MASK;
Radek Krejci19a96102018-11-15 13:38:09 +0100943
944done:
945 return ret;
946}
947
Radek Krejcib56c7502019-02-13 14:19:54 +0100948/**
949 * @brief Compile information from the must statement
950 * @param[in] ctx Compile context.
951 * @param[in] must_p The parsed must statement structure.
Radek Krejcib56c7502019-02-13 14:19:54 +0100952 * @param[in,out] must Prepared (empty) compiled must structure to fill.
953 * @return LY_ERR value.
954 */
Radek Krejci19a96102018-11-15 13:38:09 +0100955static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +0200956lys_compile_must(struct lysc_ctx *ctx, struct lysp_restr *must_p, struct lysc_must *must)
Radek Krejci19a96102018-11-15 13:38:09 +0100957{
Radek Krejci19a96102018-11-15 13:38:09 +0100958 LY_ERR ret = LY_SUCCESS;
959
Michal Vasko7f45cf22020-10-01 12:49:44 +0200960 LY_CHECK_RET(lyxp_expr_parse(ctx->ctx, must_p->arg.str, 0, 1, &must->cond));
961 must->module = (struct lys_module *)must_p->arg.mod;
Radek Krejci011e4aa2020-09-04 15:22:31 +0200962 DUP_STRING_GOTO(ctx->ctx, must_p->eapptag, must->eapptag, ret, done);
963 DUP_STRING_GOTO(ctx->ctx, must_p->emsg, must->emsg, ret, done);
964 DUP_STRING_GOTO(ctx->ctx, must_p->dsc, must->dsc, ret, done);
965 DUP_STRING_GOTO(ctx->ctx, must_p->ref, must->ref, ret, done);
Radek Krejci0935f412019-08-20 16:15:18 +0200966 COMPILE_EXTS_GOTO(ctx, must_p->exts, must->exts, must, LYEXT_PAR_MUST, ret, done);
Radek Krejci19a96102018-11-15 13:38:09 +0100967
968done:
969 return ret;
970}
971
Radek Krejcib56c7502019-02-13 14:19:54 +0100972/**
Michal Vasko7c8439f2020-08-05 13:25:19 +0200973 * @brief Compile information in the import statement - make sure there is the target module
Radek Krejcib56c7502019-02-13 14:19:54 +0100974 * @param[in] ctx Compile context.
Michal Vasko7c8439f2020-08-05 13:25:19 +0200975 * @param[in] imp_p The parsed import statement structure to fill the module to.
Radek Krejcib56c7502019-02-13 14:19:54 +0100976 * @return LY_ERR value.
977 */
Radek Krejci19a96102018-11-15 13:38:09 +0100978static LY_ERR
Michal Vasko7c8439f2020-08-05 13:25:19 +0200979lys_compile_import(struct lysc_ctx *ctx, struct lysp_import *imp_p)
Radek Krejci19a96102018-11-15 13:38:09 +0100980{
Michal Vasko3a41dff2020-07-15 14:30:28 +0200981 const struct lys_module *mod = NULL;
Radek Krejci19a96102018-11-15 13:38:09 +0100982 LY_ERR ret = LY_SUCCESS;
983
Radek Krejci7f2a5362018-11-28 13:05:37 +0100984 /* make sure that we have the parsed version (lysp_) of the imported module to import groupings or typedefs.
985 * The compiled version is needed only for augments, deviates and leafrefs, so they are checked (and added,
Radek Krejci0e5d8382018-11-28 16:37:53 +0100986 * if needed) when these nodes are finally being instantiated and validated at the end of schema compilation. */
Michal Vasko7c8439f2020-08-05 13:25:19 +0200987 if (!imp_p->module->parsed) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100988 /* try to use filepath if present */
Michal Vasko7c8439f2020-08-05 13:25:19 +0200989 if (imp_p->module->filepath) {
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200990 struct ly_in *in;
Michal Vasko7c8439f2020-08-05 13:25:19 +0200991 if (ly_in_new_filepath(imp_p->module->filepath, 0, &in)) {
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200992 LOGINT(ctx->ctx);
993 } else {
Michal Vasko7c8439f2020-08-05 13:25:19 +0200994 LY_CHECK_RET(lys_parse(ctx->ctx, in, !strcmp(&imp_p->module->filepath[strlen(imp_p->module->filepath - 4)],
Michal Vasko3a41dff2020-07-15 14:30:28 +0200995 ".yin") ? LYS_IN_YIN : LYS_IN_YANG, &mod));
Michal Vasko7c8439f2020-08-05 13:25:19 +0200996 if (mod != imp_p->module) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200997 LOGERR(ctx->ctx, LY_EINT, "Filepath \"%s\" of the module \"%s\" does not match.",
Michal Vasko7c8439f2020-08-05 13:25:19 +0200998 imp_p->module->filepath, imp_p->module->name);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200999 mod = NULL;
1000 }
Radek Krejci19a96102018-11-15 13:38:09 +01001001 }
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001002 ly_in_free(in, 1);
Radek Krejci19a96102018-11-15 13:38:09 +01001003 }
1004 if (!mod) {
Michal Vasko7c8439f2020-08-05 13:25:19 +02001005 if (lysp_load_module(ctx->ctx, imp_p->module->name, imp_p->module->revision, 0, 1, (struct lys_module **)&mod)) {
Radek Krejci19a96102018-11-15 13:38:09 +01001006 LOGERR(ctx->ctx, LY_ENOTFOUND, "Unable to reload \"%s\" module to import it into \"%s\", source data not found.",
Michal Vasko7c8439f2020-08-05 13:25:19 +02001007 imp_p->module->name, ctx->mod->name);
Radek Krejci19a96102018-11-15 13:38:09 +01001008 return LY_ENOTFOUND;
1009 }
1010 }
Radek Krejci19a96102018-11-15 13:38:09 +01001011 }
1012
Radek Krejci19a96102018-11-15 13:38:09 +01001013 return ret;
1014}
1015
Michal Vasko33ff9422020-07-03 09:50:39 +02001016LY_ERR
1017lys_identity_precompile(struct lysc_ctx *ctx_sc, struct ly_ctx *ctx, struct lys_module *module,
Radek Krejci0f969882020-08-21 16:56:47 +02001018 struct lysp_ident *identities_p, struct lysc_ident **identities)
Radek Krejci19a96102018-11-15 13:38:09 +01001019{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001020 LY_ARRAY_COUNT_TYPE offset = 0, u, v;
Michal Vasko33ff9422020-07-03 09:50:39 +02001021 struct lysc_ctx context = {0};
Radek Krejci19a96102018-11-15 13:38:09 +01001022 LY_ERR ret = LY_SUCCESS;
1023
Michal Vasko33ff9422020-07-03 09:50:39 +02001024 assert(ctx_sc || ctx);
Radek Krejci327de162019-06-14 12:52:07 +02001025
Michal Vasko33ff9422020-07-03 09:50:39 +02001026 if (!ctx_sc) {
1027 context.ctx = ctx;
1028 context.mod = module;
Radek Krejci120d8542020-08-12 09:29:16 +02001029 context.mod_def = module;
Michal Vasko33ff9422020-07-03 09:50:39 +02001030 context.path_len = 1;
1031 context.path[0] = '/';
1032 ctx_sc = &context;
1033 }
Radek Krejci19a96102018-11-15 13:38:09 +01001034
Michal Vasko33ff9422020-07-03 09:50:39 +02001035 if (!identities_p) {
1036 return LY_SUCCESS;
1037 }
1038 if (*identities) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001039 offset = LY_ARRAY_COUNT(*identities);
Michal Vasko33ff9422020-07-03 09:50:39 +02001040 }
1041
1042 lysc_update_path(ctx_sc, NULL, "{identity}");
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001043 LY_ARRAY_CREATE_RET(ctx_sc->ctx, *identities, LY_ARRAY_COUNT(identities_p), LY_EMEM);
Michal Vasko33ff9422020-07-03 09:50:39 +02001044 LY_ARRAY_FOR(identities_p, u) {
1045 lysc_update_path(ctx_sc, NULL, identities_p[u].name);
1046
1047 LY_ARRAY_INCREMENT(*identities);
1048 COMPILE_CHECK_UNIQUENESS_ARRAY(ctx_sc, *identities, name, &(*identities)[offset + u], "identity", identities_p[u].name);
Radek Krejci011e4aa2020-09-04 15:22:31 +02001049 DUP_STRING_GOTO(ctx_sc->ctx, identities_p[u].name, (*identities)[offset + u].name, ret, done);
1050 DUP_STRING_GOTO(ctx_sc->ctx, identities_p[u].dsc, (*identities)[offset + u].dsc, ret, done);
1051 DUP_STRING_GOTO(ctx_sc->ctx, identities_p[u].ref, (*identities)[offset + u].ref, ret, done);
Michal Vasko33ff9422020-07-03 09:50:39 +02001052 (*identities)[offset + u].module = ctx_sc->mod;
1053 COMPILE_ARRAY_GOTO(ctx_sc, identities_p[u].iffeatures, (*identities)[offset + u].iffeatures, v,
1054 lys_compile_iffeature, ret, done);
1055 /* backlinks (derived) can be added no sooner than when all the identities in the current module are present */
1056 COMPILE_EXTS_GOTO(ctx_sc, identities_p[u].exts, (*identities)[offset + u].exts, &(*identities)[offset + u],
1057 LYEXT_PAR_IDENT, ret, done);
1058 (*identities)[offset + u].flags = identities_p[u].flags;
1059
1060 lysc_update_path(ctx_sc, NULL, NULL);
1061 }
1062 lysc_update_path(ctx_sc, NULL, NULL);
Radek Krejci19a96102018-11-15 13:38:09 +01001063done:
1064 return ret;
1065}
1066
Radek Krejcib56c7502019-02-13 14:19:54 +01001067/**
1068 * @brief Check circular dependency of identities - identity MUST NOT reference itself (via their base statement).
1069 *
1070 * The function works in the same way as lys_compile_feature_circular_check() with different structures and error messages.
1071 *
1072 * @param[in] ctx Compile context for logging.
1073 * @param[in] ident The base identity (its derived list is being extended by the identity being currently processed).
1074 * @param[in] derived The list of derived identities of the identity being currently processed (not the one provided as @p ident)
1075 * @return LY_SUCCESS if everything is ok.
1076 * @return LY_EVALID if the identity is derived from itself.
1077 */
Radek Krejci38222632019-02-12 16:55:05 +01001078static LY_ERR
1079lys_compile_identity_circular_check(struct lysc_ctx *ctx, struct lysc_ident *ident, struct lysc_ident **derived)
1080{
Radek Krejciba03a5a2020-08-27 14:40:41 +02001081 LY_ERR ret = LY_SUCCESS;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001082 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci38222632019-02-12 16:55:05 +01001083 struct ly_set recursion = {0};
1084 struct lysc_ident *drv;
1085
1086 if (!derived) {
1087 return LY_SUCCESS;
1088 }
1089
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001090 for (u = 0; u < LY_ARRAY_COUNT(derived); ++u) {
Radek Krejci38222632019-02-12 16:55:05 +01001091 if (ident == derived[u]) {
1092 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
1093 "Identity \"%s\" is indirectly derived from itself.", ident->name);
Radek Krejciba03a5a2020-08-27 14:40:41 +02001094 ret = LY_EVALID;
Radek Krejci38222632019-02-12 16:55:05 +01001095 goto cleanup;
1096 }
Radek Krejciba03a5a2020-08-27 14:40:41 +02001097 ret = ly_set_add(&recursion, derived[u], 0, NULL);
1098 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci38222632019-02-12 16:55:05 +01001099 }
1100
1101 for (v = 0; v < recursion.count; ++v) {
1102 drv = recursion.objs[v];
1103 if (!drv->derived) {
1104 continue;
1105 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001106 for (u = 0; u < LY_ARRAY_COUNT(drv->derived); ++u) {
Radek Krejci38222632019-02-12 16:55:05 +01001107 if (ident == drv->derived[u]) {
1108 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
1109 "Identity \"%s\" is indirectly derived from itself.", ident->name);
Radek Krejciba03a5a2020-08-27 14:40:41 +02001110 ret = LY_EVALID;
Radek Krejci38222632019-02-12 16:55:05 +01001111 goto cleanup;
1112 }
Radek Krejciba03a5a2020-08-27 14:40:41 +02001113 ret = ly_set_add(&recursion, drv->derived[u], 0, NULL);
1114 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci38222632019-02-12 16:55:05 +01001115 }
1116 }
Radek Krejci38222632019-02-12 16:55:05 +01001117
1118cleanup:
1119 ly_set_erase(&recursion, NULL);
1120 return ret;
1121}
1122
Radek Krejcia3045382018-11-22 14:30:31 +01001123/**
1124 * @brief Find and process the referenced base identities from another identity or identityref
1125 *
Radek Krejciaca74032019-06-04 08:53:06 +02001126 * For bases in identity set backlinks to them from the base identities. For identityref, store
Radek Krejcia3045382018-11-22 14:30:31 +01001127 * the array of pointers to the base identities. So one of the ident or bases parameter must be set
1128 * to distinguish these two use cases.
1129 *
1130 * @param[in] ctx Compile context, not only for logging but also to get the current module to resolve prefixes.
1131 * @param[in] bases_p Array of names (including prefix if necessary) of base identities.
Michal Vasko33ff9422020-07-03 09:50:39 +02001132 * @param[in] ident Referencing identity to work with, NULL for identityref.
Radek Krejcia3045382018-11-22 14:30:31 +01001133 * @param[in] bases Array of bases of identityref to fill in.
1134 * @return LY_ERR value.
1135 */
Radek Krejci19a96102018-11-15 13:38:09 +01001136static LY_ERR
Michal Vasko33ff9422020-07-03 09:50:39 +02001137lys_compile_identity_bases(struct lysc_ctx *ctx, struct lys_module *context_module, const char **bases_p,
Radek Krejci0f969882020-08-21 16:56:47 +02001138 struct lysc_ident *ident, struct lysc_ident ***bases)
Radek Krejci19a96102018-11-15 13:38:09 +01001139{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001140 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci19a96102018-11-15 13:38:09 +01001141 const char *s, *name;
Radek Krejcie86bf772018-12-14 11:39:53 +01001142 struct lys_module *mod;
Radek Krejci80d281e2020-09-14 17:42:54 +02001143 struct lysc_ident **idref;
Radek Krejci555cb5b2018-11-16 14:54:33 +01001144
1145 assert(ident || bases);
1146
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001147 if (LY_ARRAY_COUNT(bases_p) > 1 && ctx->mod_def->version < 2) {
Radek Krejci555cb5b2018-11-16 14:54:33 +01001148 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1149 "Multiple bases in %s are allowed only in YANG 1.1 modules.", ident ? "identity" : "identityref type");
1150 return LY_EVALID;
1151 }
1152
Michal Vasko33ff9422020-07-03 09:50:39 +02001153 LY_ARRAY_FOR(bases_p, u) {
Radek Krejci555cb5b2018-11-16 14:54:33 +01001154 s = strchr(bases_p[u], ':');
1155 if (s) {
1156 /* prefixed identity */
1157 name = &s[1];
Radek Krejci0a33b042020-05-27 10:05:06 +02001158 mod = lys_module_find_prefix(context_module, bases_p[u], s - bases_p[u]);
Radek Krejci555cb5b2018-11-16 14:54:33 +01001159 } else {
1160 name = bases_p[u];
Radek Krejci0a33b042020-05-27 10:05:06 +02001161 mod = context_module;
Radek Krejci555cb5b2018-11-16 14:54:33 +01001162 }
1163 if (!mod) {
1164 if (ident) {
1165 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1166 "Invalid prefix used for base (%s) of identity \"%s\".", bases_p[u], ident->name);
1167 } else {
1168 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1169 "Invalid prefix used for base (%s) of identityref.", bases_p[u]);
1170 }
1171 return LY_EVALID;
1172 }
Michal Vasko33ff9422020-07-03 09:50:39 +02001173
Radek Krejci555cb5b2018-11-16 14:54:33 +01001174 idref = NULL;
Radek Krejci80d281e2020-09-14 17:42:54 +02001175 LY_ARRAY_FOR(mod->identities, v) {
1176 if (!strcmp(name, mod->identities[v].name)) {
Michal Vasko33ff9422020-07-03 09:50:39 +02001177 if (ident) {
Radek Krejci80d281e2020-09-14 17:42:54 +02001178 if (ident == &mod->identities[v]) {
Michal Vasko33ff9422020-07-03 09:50:39 +02001179 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
1180 "Identity \"%s\" is derived from itself.", ident->name);
1181 return LY_EVALID;
Radek Krejci555cb5b2018-11-16 14:54:33 +01001182 }
Radek Krejci80d281e2020-09-14 17:42:54 +02001183 LY_CHECK_RET(lys_compile_identity_circular_check(ctx, &mod->identities[v], ident->derived));
Michal Vasko33ff9422020-07-03 09:50:39 +02001184 /* we have match! store the backlink */
Radek Krejci80d281e2020-09-14 17:42:54 +02001185 LY_ARRAY_NEW_RET(ctx->ctx, mod->identities[v].derived, idref, LY_EMEM);
Michal Vasko33ff9422020-07-03 09:50:39 +02001186 *idref = ident;
1187 } else {
1188 /* we have match! store the found identity */
1189 LY_ARRAY_NEW_RET(ctx->ctx, *bases, idref, LY_EMEM);
Radek Krejci80d281e2020-09-14 17:42:54 +02001190 *idref = &mod->identities[v];
Radek Krejci555cb5b2018-11-16 14:54:33 +01001191 }
Michal Vasko33ff9422020-07-03 09:50:39 +02001192 break;
Radek Krejci555cb5b2018-11-16 14:54:33 +01001193 }
1194 }
1195 if (!idref || !(*idref)) {
1196 if (ident) {
1197 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1198 "Unable to find base (%s) of identity \"%s\".", bases_p[u], ident->name);
1199 } else {
1200 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1201 "Unable to find base (%s) of identityref.", bases_p[u]);
1202 }
1203 return LY_EVALID;
1204 }
1205 }
1206 return LY_SUCCESS;
1207}
1208
Radek Krejcia3045382018-11-22 14:30:31 +01001209/**
1210 * @brief For the given array of identities, set the backlinks from all their base identities.
1211 * @param[in] ctx Compile context, not only for logging but also to get the current module to resolve prefixes.
1212 * @param[in] idents_p Array of identities definitions from the parsed schema structure.
1213 * @param[in] idents Array of referencing identities to which the backlinks are supposed to be set.
1214 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
1215 */
Radek Krejci555cb5b2018-11-16 14:54:33 +01001216static LY_ERR
1217lys_compile_identities_derived(struct lysc_ctx *ctx, struct lysp_ident *idents_p, struct lysc_ident *idents)
1218{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001219 LY_ARRAY_COUNT_TYPE u;
Radek Krejci19a96102018-11-15 13:38:09 +01001220
Michal Vasko33ff9422020-07-03 09:50:39 +02001221 lysc_update_path(ctx, NULL, "{identity}");
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001222 for (u = 0; u < LY_ARRAY_COUNT(idents_p); ++u) {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001223 if (!idents_p[u].bases) {
Radek Krejci19a96102018-11-15 13:38:09 +01001224 continue;
1225 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001226 lysc_update_path(ctx, NULL, idents[u].name);
Radek Krejci0a33b042020-05-27 10:05:06 +02001227 LY_CHECK_RET(lys_compile_identity_bases(ctx, idents[u].module, idents_p[u].bases, &idents[u], NULL));
Radek Krejci327de162019-06-14 12:52:07 +02001228 lysc_update_path(ctx, NULL, NULL);
Radek Krejci19a96102018-11-15 13:38:09 +01001229 }
Michal Vasko33ff9422020-07-03 09:50:39 +02001230 lysc_update_path(ctx, NULL, NULL);
Radek Krejci19a96102018-11-15 13:38:09 +01001231 return LY_SUCCESS;
1232}
1233
Radek Krejci0af46292019-01-11 16:02:31 +01001234LY_ERR
Michal Vasko33ff9422020-07-03 09:50:39 +02001235lys_feature_precompile(struct lysc_ctx *ctx_sc, struct ly_ctx *ctx, struct lys_module *module,
Radek Krejci0f969882020-08-21 16:56:47 +02001236 struct lysp_feature *features_p, struct lysc_feature **features)
Radek Krejci0af46292019-01-11 16:02:31 +01001237{
Radek Krejci011e4aa2020-09-04 15:22:31 +02001238 LY_ERR ret = LY_SUCCESS;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001239 LY_ARRAY_COUNT_TYPE offset = 0, u;
Radek Krejci0af46292019-01-11 16:02:31 +01001240 struct lysc_ctx context = {0};
1241
Radek Krejci327de162019-06-14 12:52:07 +02001242 assert(ctx_sc || ctx);
1243
1244 if (!ctx_sc) {
1245 context.ctx = ctx;
1246 context.mod = module;
1247 context.path_len = 1;
1248 context.path[0] = '/';
1249 ctx_sc = &context;
1250 }
Radek Krejci0af46292019-01-11 16:02:31 +01001251
1252 if (!features_p) {
1253 return LY_SUCCESS;
1254 }
1255 if (*features) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001256 offset = LY_ARRAY_COUNT(*features);
Radek Krejci0af46292019-01-11 16:02:31 +01001257 }
1258
Radek Krejci327de162019-06-14 12:52:07 +02001259 lysc_update_path(ctx_sc, NULL, "{feature}");
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001260 LY_ARRAY_CREATE_RET(ctx_sc->ctx, *features, LY_ARRAY_COUNT(features_p), LY_EMEM);
Radek Krejci0af46292019-01-11 16:02:31 +01001261 LY_ARRAY_FOR(features_p, u) {
Radek Krejci327de162019-06-14 12:52:07 +02001262 lysc_update_path(ctx_sc, NULL, features_p[u].name);
1263
Radek Krejci0af46292019-01-11 16:02:31 +01001264 LY_ARRAY_INCREMENT(*features);
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001265 COMPILE_CHECK_UNIQUENESS_ARRAY(ctx_sc, *features, name, &(*features)[offset + u], "feature", features_p[u].name);
Radek Krejci011e4aa2020-09-04 15:22:31 +02001266 DUP_STRING_GOTO(ctx_sc->ctx, features_p[u].name, (*features)[offset + u].name, ret, done);
1267 DUP_STRING_GOTO(ctx_sc->ctx, features_p[u].dsc, (*features)[offset + u].dsc, ret, done);
1268 DUP_STRING_GOTO(ctx_sc->ctx, features_p[u].ref, (*features)[offset + u].ref, ret, done);
Radek Krejci0af46292019-01-11 16:02:31 +01001269 (*features)[offset + u].flags = features_p[u].flags;
Radek Krejci327de162019-06-14 12:52:07 +02001270 (*features)[offset + u].module = ctx_sc->mod;
1271
1272 lysc_update_path(ctx_sc, NULL, NULL);
Radek Krejci0af46292019-01-11 16:02:31 +01001273 }
Radek Krejci327de162019-06-14 12:52:07 +02001274 lysc_update_path(ctx_sc, NULL, NULL);
Radek Krejci0af46292019-01-11 16:02:31 +01001275
Radek Krejci011e4aa2020-09-04 15:22:31 +02001276done:
1277 return ret;
Radek Krejci0af46292019-01-11 16:02:31 +01001278}
1279
Radek Krejcia3045382018-11-22 14:30:31 +01001280/**
Radek Krejci09a1fc52019-02-13 10:55:17 +01001281 * @brief Check circular dependency of features - feature MUST NOT reference itself (via their if-feature statement).
Radek Krejcib56c7502019-02-13 14:19:54 +01001282 *
1283 * The function works in the same way as lys_compile_identity_circular_check() with different structures and error messages.
1284 *
Radek Krejci09a1fc52019-02-13 10:55:17 +01001285 * @param[in] ctx Compile context for logging.
Radek Krejcib56c7502019-02-13 14:19:54 +01001286 * @param[in] feature The feature referenced in if-feature statement (its depfeatures list is being extended by the feature
1287 * being currently processed).
1288 * @param[in] depfeatures The list of depending features of the feature being currently processed (not the one provided as @p feature)
Radek Krejci09a1fc52019-02-13 10:55:17 +01001289 * @return LY_SUCCESS if everything is ok.
1290 * @return LY_EVALID if the feature references indirectly itself.
1291 */
1292static LY_ERR
1293lys_compile_feature_circular_check(struct lysc_ctx *ctx, struct lysc_feature *feature, struct lysc_feature **depfeatures)
1294{
Radek Krejciba03a5a2020-08-27 14:40:41 +02001295 LY_ERR ret = LY_SUCCESS;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001296 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci09a1fc52019-02-13 10:55:17 +01001297 struct ly_set recursion = {0};
1298 struct lysc_feature *drv;
1299
1300 if (!depfeatures) {
1301 return LY_SUCCESS;
1302 }
1303
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001304 for (u = 0; u < LY_ARRAY_COUNT(depfeatures); ++u) {
Radek Krejci09a1fc52019-02-13 10:55:17 +01001305 if (feature == depfeatures[u]) {
1306 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
1307 "Feature \"%s\" is indirectly referenced from itself.", feature->name);
Radek Krejciba03a5a2020-08-27 14:40:41 +02001308 ret = LY_EVALID;
Radek Krejci09a1fc52019-02-13 10:55:17 +01001309 goto cleanup;
1310 }
Radek Krejciba03a5a2020-08-27 14:40:41 +02001311 ret = ly_set_add(&recursion, depfeatures[u], 0, NULL);
1312 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci09a1fc52019-02-13 10:55:17 +01001313 }
1314
1315 for (v = 0; v < recursion.count; ++v) {
1316 drv = recursion.objs[v];
1317 if (!drv->depfeatures) {
1318 continue;
1319 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001320 for (u = 0; u < LY_ARRAY_COUNT(drv->depfeatures); ++u) {
Radek Krejci09a1fc52019-02-13 10:55:17 +01001321 if (feature == drv->depfeatures[u]) {
1322 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
1323 "Feature \"%s\" is indirectly referenced from itself.", feature->name);
Radek Krejciba03a5a2020-08-27 14:40:41 +02001324 ret = LY_EVALID;
Radek Krejci09a1fc52019-02-13 10:55:17 +01001325 goto cleanup;
1326 }
Radek Krejciba03a5a2020-08-27 14:40:41 +02001327 ly_set_add(&recursion, drv->depfeatures[u], 0, NULL);
1328 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci09a1fc52019-02-13 10:55:17 +01001329 }
1330 }
Radek Krejci09a1fc52019-02-13 10:55:17 +01001331
1332cleanup:
1333 ly_set_erase(&recursion, NULL);
1334 return ret;
1335}
1336
1337/**
Radek Krejci0af46292019-01-11 16:02:31 +01001338 * @brief Create pre-compiled features array.
1339 *
1340 * See lys_feature_precompile() for more details.
1341 *
Radek Krejcia3045382018-11-22 14:30:31 +01001342 * @param[in] ctx Compile context.
1343 * @param[in] feature_p Parsed feature definition to compile.
Radek Krejci0af46292019-01-11 16:02:31 +01001344 * @param[in,out] features List of already (pre)compiled features to find the corresponding precompiled feature structure.
Radek Krejcia3045382018-11-22 14:30:31 +01001345 * @return LY_ERR value.
1346 */
Radek Krejci19a96102018-11-15 13:38:09 +01001347static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02001348lys_feature_precompile_finish(struct lysc_ctx *ctx, struct lysp_feature *feature_p, struct lysc_feature *features)
Radek Krejci19a96102018-11-15 13:38:09 +01001349{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001350 LY_ARRAY_COUNT_TYPE u, v, x;
Radek Krejci0af46292019-01-11 16:02:31 +01001351 struct lysc_feature *feature, **df;
Radek Krejci19a96102018-11-15 13:38:09 +01001352 LY_ERR ret = LY_SUCCESS;
Radek Krejci19a96102018-11-15 13:38:09 +01001353
Radek Krejci0af46292019-01-11 16:02:31 +01001354 /* find the preprecompiled feature */
1355 LY_ARRAY_FOR(features, x) {
1356 if (strcmp(features[x].name, feature_p->name)) {
1357 continue;
1358 }
1359 feature = &features[x];
Radek Krejci327de162019-06-14 12:52:07 +02001360 lysc_update_path(ctx, NULL, "{feature}");
1361 lysc_update_path(ctx, NULL, feature_p->name);
Radek Krejci19a96102018-11-15 13:38:09 +01001362
Radek Krejci0af46292019-01-11 16:02:31 +01001363 /* finish compilation started in lys_feature_precompile() */
Radek Krejci0935f412019-08-20 16:15:18 +02001364 COMPILE_EXTS_GOTO(ctx, feature_p->exts, feature->exts, feature, LYEXT_PAR_FEATURE, ret, done);
Radek Krejciec4da802019-05-02 13:02:41 +02001365 COMPILE_ARRAY_GOTO(ctx, feature_p->iffeatures, feature->iffeatures, u, lys_compile_iffeature, ret, done);
Radek Krejci0af46292019-01-11 16:02:31 +01001366 if (feature->iffeatures) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001367 for (u = 0; u < LY_ARRAY_COUNT(feature->iffeatures); ++u) {
Radek Krejci0af46292019-01-11 16:02:31 +01001368 if (feature->iffeatures[u].features) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001369 for (v = 0; v < LY_ARRAY_COUNT(feature->iffeatures[u].features); ++v) {
Radek Krejci09a1fc52019-02-13 10:55:17 +01001370 /* check for circular dependency - direct reference first,... */
1371 if (feature == feature->iffeatures[u].features[v]) {
1372 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
1373 "Feature \"%s\" is referenced from itself.", feature->name);
1374 return LY_EVALID;
1375 }
1376 /* ... and indirect circular reference */
1377 LY_CHECK_RET(lys_compile_feature_circular_check(ctx, feature->iffeatures[u].features[v], feature->depfeatures));
1378
Radek Krejci0af46292019-01-11 16:02:31 +01001379 /* add itself into the dependants list */
1380 LY_ARRAY_NEW_RET(ctx->ctx, feature->iffeatures[u].features[v]->depfeatures, df, LY_EMEM);
1381 *df = feature;
1382 }
Radek Krejci19a96102018-11-15 13:38:09 +01001383 }
Radek Krejci19a96102018-11-15 13:38:09 +01001384 }
1385 }
Radek Krejci327de162019-06-14 12:52:07 +02001386 lysc_update_path(ctx, NULL, NULL);
1387 lysc_update_path(ctx, NULL, NULL);
Radek Krejci0af46292019-01-11 16:02:31 +01001388 done:
1389 return ret;
Radek Krejci19a96102018-11-15 13:38:09 +01001390 }
Radek Krejci0af46292019-01-11 16:02:31 +01001391
1392 LOGINT(ctx->ctx);
1393 return LY_EINT;
Radek Krejci19a96102018-11-15 13:38:09 +01001394}
1395
Radek Krejcib56c7502019-02-13 14:19:54 +01001396/**
1397 * @brief Revert compiled list of features back to the precompiled state.
1398 *
1399 * Function is needed in case the compilation failed and the schema is expected to revert back to the non-compiled status.
Radek Krejcib56c7502019-02-13 14:19:54 +01001400 *
1401 * @param[in] ctx Compilation context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02001402 * @param[in] mod The module structure with the features to decompile.
Radek Krejcib56c7502019-02-13 14:19:54 +01001403 */
Radek Krejci95710c92019-02-11 15:49:55 +01001404static void
1405lys_feature_precompile_revert(struct lysc_ctx *ctx, struct lys_module *mod)
1406{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001407 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci95710c92019-02-11 15:49:55 +01001408
Michal Vasko33ff9422020-07-03 09:50:39 +02001409 /* in the dis_features list, remove all the parts (from finished compiling process)
Radek Krejci95710c92019-02-11 15:49:55 +01001410 * which may points into the data being freed here */
Radek Krejci14915cc2020-09-14 17:28:13 +02001411 LY_ARRAY_FOR(mod->features, u) {
1412 LY_ARRAY_FOR(mod->features[u].iffeatures, v) {
1413 lysc_iffeature_free(ctx->ctx, &mod->features[u].iffeatures[v]);
Radek Krejci95710c92019-02-11 15:49:55 +01001414 }
Radek Krejci14915cc2020-09-14 17:28:13 +02001415 LY_ARRAY_FREE(mod->features[u].iffeatures);
1416 mod->features[u].iffeatures = NULL;
Radek Krejci95710c92019-02-11 15:49:55 +01001417
Radek Krejci14915cc2020-09-14 17:28:13 +02001418 LY_ARRAY_FOR(mod->features[u].exts, v) {
1419 lysc_ext_instance_free(ctx->ctx, &(mod->features[u].exts)[v]);
Radek Krejci95710c92019-02-11 15:49:55 +01001420 }
Radek Krejci14915cc2020-09-14 17:28:13 +02001421 LY_ARRAY_FREE(mod->features[u].exts);
1422 mod->features[u].exts = NULL;
Radek Krejci95710c92019-02-11 15:49:55 +01001423 }
1424}
1425
Radek Krejcia3045382018-11-22 14:30:31 +01001426/**
1427 * @brief Validate and normalize numeric value from a range definition.
1428 * @param[in] ctx Compile context.
1429 * @param[in] basetype Base YANG built-in type of the node connected with the range restriction. Actually only LY_TYPE_DEC64 is important to
1430 * allow processing of the fractions. The fraction point is extracted from the value which is then normalize according to given frdigits into
1431 * valcopy to allow easy parsing and storing of the value. libyang stores decimal number without the decimal point which is always recovered from
1432 * the known fraction-digits value. So, with fraction-digits 2, number 3.14 is stored as 314 and number 1 is stored as 100.
1433 * @param[in] frdigits The fraction-digits of the type in case of LY_TYPE_DEC64.
1434 * @param[in] value String value of the range boundary.
1435 * @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.
1436 * @param[out] valcopy NULL-terminated string with the numeric value to parse and store.
1437 * @return LY_ERR value - LY_SUCCESS, LY_EMEM, LY_EVALID (no number) or LY_EINVAL (decimal64 not matching fraction-digits value).
1438 */
Radek Krejcie88beef2019-05-30 15:47:19 +02001439LY_ERR
Radek Krejci6cba4292018-11-15 17:33:29 +01001440range_part_check_value_syntax(struct lysc_ctx *ctx, LY_DATA_TYPE basetype, uint8_t frdigits, const char *value, size_t *len, char **valcopy)
Radek Krejci19a96102018-11-15 13:38:09 +01001441{
Radek Krejci6cba4292018-11-15 17:33:29 +01001442 size_t fraction = 0, size;
1443
Radek Krejci19a96102018-11-15 13:38:09 +01001444 *len = 0;
1445
1446 assert(value);
1447 /* parse value */
1448 if (!isdigit(value[*len]) && (value[*len] != '-') && (value[*len] != '+')) {
1449 return LY_EVALID;
1450 }
1451
1452 if ((value[*len] == '-') || (value[*len] == '+')) {
1453 ++(*len);
1454 }
1455
1456 while (isdigit(value[*len])) {
1457 ++(*len);
1458 }
1459
1460 if ((basetype != LY_TYPE_DEC64) || (value[*len] != '.') || !isdigit(value[*len + 1])) {
Radek Krejci6cba4292018-11-15 17:33:29 +01001461 if (basetype == LY_TYPE_DEC64) {
1462 goto decimal;
1463 } else {
1464 *valcopy = strndup(value, *len);
1465 return LY_SUCCESS;
1466 }
Radek Krejci19a96102018-11-15 13:38:09 +01001467 }
1468 fraction = *len;
1469
1470 ++(*len);
1471 while (isdigit(value[*len])) {
1472 ++(*len);
1473 }
1474
Radek Krejci6cba4292018-11-15 17:33:29 +01001475 if (basetype == LY_TYPE_DEC64) {
1476decimal:
1477 assert(frdigits);
Radek Krejci943177f2019-06-14 16:32:43 +02001478 if (fraction && (*len - 1 - fraction > frdigits)) {
Radek Krejci6cba4292018-11-15 17:33:29 +01001479 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1480 "Range boundary \"%.*s\" of decimal64 type exceeds defined number (%u) of fraction digits.",
1481 *len, value, frdigits);
1482 return LY_EINVAL;
1483 }
1484 if (fraction) {
1485 size = (*len) + (frdigits - ((*len) - 1 - fraction));
1486 } else {
1487 size = (*len) + frdigits + 1;
1488 }
1489 *valcopy = malloc(size * sizeof **valcopy);
Radek Krejci19a96102018-11-15 13:38:09 +01001490 LY_CHECK_ERR_RET(!(*valcopy), LOGMEM(ctx->ctx), LY_EMEM);
1491
Radek Krejci6cba4292018-11-15 17:33:29 +01001492 (*valcopy)[size - 1] = '\0';
1493 if (fraction) {
1494 memcpy(&(*valcopy)[0], &value[0], fraction);
1495 memcpy(&(*valcopy)[fraction], &value[fraction + 1], (*len) - 1 - (fraction));
1496 memset(&(*valcopy)[(*len) - 1], '0', frdigits - ((*len) - 1 - fraction));
1497 } else {
1498 memcpy(&(*valcopy)[0], &value[0], *len);
1499 memset(&(*valcopy)[*len], '0', frdigits);
1500 }
Radek Krejci19a96102018-11-15 13:38:09 +01001501 }
1502 return LY_SUCCESS;
1503}
1504
Radek Krejcia3045382018-11-22 14:30:31 +01001505/**
1506 * @brief Check that values in range are in ascendant order.
1507 * @param[in] unsigned_value Flag to note that we are working with unsigned values.
Radek Krejci5969f272018-11-23 10:03:58 +01001508 * @param[in] max Flag to distinguish if checking min or max value. min value must be strictly higher than previous,
1509 * max can be also equal.
Radek Krejcia3045382018-11-22 14:30:31 +01001510 * @param[in] value Current value to check.
1511 * @param[in] prev_value The last seen value.
1512 * @return LY_SUCCESS or LY_EEXIST for invalid order.
1513 */
Radek Krejci19a96102018-11-15 13:38:09 +01001514static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02001515range_part_check_ascendancy(ly_bool unsigned_value, ly_bool max, int64_t value, int64_t prev_value)
Radek Krejci19a96102018-11-15 13:38:09 +01001516{
1517 if (unsigned_value) {
Radek Krejci5969f272018-11-23 10:03:58 +01001518 if ((max && (uint64_t)prev_value > (uint64_t)value) || (!max && (uint64_t)prev_value >= (uint64_t)value)) {
Radek Krejci19a96102018-11-15 13:38:09 +01001519 return LY_EEXIST;
1520 }
1521 } else {
Radek Krejci5969f272018-11-23 10:03:58 +01001522 if ((max && prev_value > value) || (!max && prev_value >= value)) {
Radek Krejci19a96102018-11-15 13:38:09 +01001523 return LY_EEXIST;
1524 }
1525 }
1526 return LY_SUCCESS;
1527}
1528
Radek Krejcia3045382018-11-22 14:30:31 +01001529/**
1530 * @brief Set min/max value of the range part.
1531 * @param[in] ctx Compile context.
1532 * @param[in] part Range part structure to fill.
1533 * @param[in] max Flag to distinguish if storing min or max value.
1534 * @param[in] prev The last seen value to check that all values in range are specified in ascendant order.
1535 * @param[in] basetype Type of the value to get know implicit min/max values and other checking rules.
1536 * @param[in] first Flag for the first value of the range to avoid ascendancy order.
1537 * @param[in] length_restr Flag to distinguish between range and length restrictions. Only for logging.
1538 * @param[in] frdigits The fraction-digits value in case of LY_TYPE_DEC64 basetype.
Radek Krejci5969f272018-11-23 10:03:58 +01001539 * @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.
Radek Krejcia3045382018-11-22 14:30:31 +01001540 * @param[in,out] value Numeric range value to be stored, if not provided the type's min/max value is set.
1541 * @return LY_ERR value - LY_SUCCESS, LY_EDENIED (value brokes type's boundaries), LY_EVALID (not a number),
1542 * LY_EEXIST (value is smaller than the previous one), LY_EINVAL (decimal64 value does not corresponds with the
1543 * frdigits value), LY_EMEM.
1544 */
Radek Krejci19a96102018-11-15 13:38:09 +01001545static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02001546range_part_minmax(struct lysc_ctx *ctx, struct lysc_range_part *part, ly_bool max, int64_t prev, LY_DATA_TYPE basetype,
1547 ly_bool first, ly_bool length_restr, uint8_t frdigits, struct lysc_range *base_range, const char **value)
Radek Krejci19a96102018-11-15 13:38:09 +01001548{
1549 LY_ERR ret = LY_SUCCESS;
1550 char *valcopy = NULL;
1551 size_t len;
1552
1553 if (value) {
Radek Krejci6cba4292018-11-15 17:33:29 +01001554 ret = range_part_check_value_syntax(ctx, basetype, frdigits, *value, &len, &valcopy);
Radek Krejci5969f272018-11-23 10:03:58 +01001555 LY_CHECK_GOTO(ret, finalize);
1556 }
1557 if (!valcopy && base_range) {
1558 if (max) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001559 part->max_64 = base_range->parts[LY_ARRAY_COUNT(base_range->parts) - 1].max_64;
Radek Krejci5969f272018-11-23 10:03:58 +01001560 } else {
1561 part->min_64 = base_range->parts[0].min_64;
1562 }
1563 if (!first) {
1564 ret = range_part_check_ascendancy(basetype <= LY_TYPE_STRING ? 1 : 0, max, max ? part->max_64 : part->min_64, prev);
1565 }
1566 goto finalize;
Radek Krejci19a96102018-11-15 13:38:09 +01001567 }
1568
1569 switch (basetype) {
Radek Krejci19a96102018-11-15 13:38:09 +01001570 case LY_TYPE_INT8: /* range */
1571 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001572 ret = ly_parse_int(valcopy, strlen(valcopy), INT64_C(-128), INT64_C(127), 10, max ? &part->max_64 : &part->min_64);
Radek Krejci19a96102018-11-15 13:38:09 +01001573 } else if (max) {
1574 part->max_64 = INT64_C(127);
1575 } else {
1576 part->min_64 = INT64_C(-128);
1577 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001578 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001579 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001580 }
1581 break;
1582 case LY_TYPE_INT16: /* range */
1583 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001584 ret = ly_parse_int(valcopy, strlen(valcopy), INT64_C(-32768), INT64_C(32767), 10, max ? &part->max_64 : &part->min_64);
Radek Krejci19a96102018-11-15 13:38:09 +01001585 } else if (max) {
1586 part->max_64 = INT64_C(32767);
1587 } else {
1588 part->min_64 = INT64_C(-32768);
1589 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001590 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001591 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001592 }
1593 break;
1594 case LY_TYPE_INT32: /* range */
1595 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001596 ret = ly_parse_int(valcopy, strlen(valcopy), INT64_C(-2147483648), INT64_C(2147483647), 10, max ? &part->max_64 : &part->min_64);
Radek Krejci19a96102018-11-15 13:38:09 +01001597 } else if (max) {
1598 part->max_64 = INT64_C(2147483647);
1599 } else {
1600 part->min_64 = INT64_C(-2147483648);
1601 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001602 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001603 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001604 }
1605 break;
1606 case LY_TYPE_INT64: /* range */
Radek Krejci25cfef72018-11-23 14:15:52 +01001607 case LY_TYPE_DEC64: /* range */
Radek Krejci19a96102018-11-15 13:38:09 +01001608 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001609 ret = ly_parse_int(valcopy, strlen(valcopy), INT64_C(-9223372036854775807) - INT64_C(1), INT64_C(9223372036854775807), 10,
Radek Krejci19a96102018-11-15 13:38:09 +01001610 max ? &part->max_64 : &part->min_64);
1611 } else if (max) {
1612 part->max_64 = INT64_C(9223372036854775807);
1613 } else {
1614 part->min_64 = INT64_C(-9223372036854775807) - INT64_C(1);
1615 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001616 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001617 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001618 }
1619 break;
1620 case LY_TYPE_UINT8: /* range */
1621 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001622 ret = ly_parse_uint(valcopy, strlen(valcopy), UINT64_C(255), 10, max ? &part->max_u64 : &part->min_u64);
Radek Krejci19a96102018-11-15 13:38:09 +01001623 } else if (max) {
1624 part->max_u64 = UINT64_C(255);
1625 } else {
1626 part->min_u64 = UINT64_C(0);
1627 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001628 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001629 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001630 }
1631 break;
1632 case LY_TYPE_UINT16: /* range */
1633 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001634 ret = ly_parse_uint(valcopy, strlen(valcopy), UINT64_C(65535), 10, max ? &part->max_u64 : &part->min_u64);
Radek Krejci19a96102018-11-15 13:38:09 +01001635 } else if (max) {
1636 part->max_u64 = UINT64_C(65535);
1637 } else {
1638 part->min_u64 = UINT64_C(0);
1639 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001640 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001641 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001642 }
1643 break;
1644 case LY_TYPE_UINT32: /* range */
1645 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001646 ret = ly_parse_uint(valcopy, strlen(valcopy), UINT64_C(4294967295), 10, max ? &part->max_u64 : &part->min_u64);
Radek Krejci19a96102018-11-15 13:38:09 +01001647 } else if (max) {
1648 part->max_u64 = UINT64_C(4294967295);
1649 } else {
1650 part->min_u64 = UINT64_C(0);
1651 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001652 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001653 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001654 }
1655 break;
1656 case LY_TYPE_UINT64: /* range */
Radek Krejci19a96102018-11-15 13:38:09 +01001657 case LY_TYPE_STRING: /* length */
Radek Krejci25cfef72018-11-23 14:15:52 +01001658 case LY_TYPE_BINARY: /* length */
Radek Krejci19a96102018-11-15 13:38:09 +01001659 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001660 ret = ly_parse_uint(valcopy, strlen(valcopy), UINT64_C(18446744073709551615), 10, max ? &part->max_u64 : &part->min_u64);
Radek Krejci19a96102018-11-15 13:38:09 +01001661 } else if (max) {
1662 part->max_u64 = UINT64_C(18446744073709551615);
1663 } else {
1664 part->min_u64 = UINT64_C(0);
1665 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001666 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001667 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001668 }
1669 break;
1670 default:
1671 LOGINT(ctx->ctx);
1672 ret = LY_EINT;
1673 }
1674
Radek Krejci5969f272018-11-23 10:03:58 +01001675finalize:
Radek Krejci19a96102018-11-15 13:38:09 +01001676 if (ret == LY_EDENIED) {
1677 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1678 "Invalid %s restriction - value \"%s\" does not fit the type limitations.",
1679 length_restr ? "length" : "range", valcopy ? valcopy : *value);
1680 } else if (ret == LY_EVALID) {
1681 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1682 "Invalid %s restriction - invalid value \"%s\".",
1683 length_restr ? "length" : "range", valcopy ? valcopy : *value);
1684 } else if (ret == LY_EEXIST) {
1685 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1686 "Invalid %s restriction - values are not in ascending order (%s).",
Radek Krejci6cba4292018-11-15 17:33:29 +01001687 length_restr ? "length" : "range",
Radek Krejci0f969882020-08-21 16:56:47 +02001688 (valcopy && basetype != LY_TYPE_DEC64) ? valcopy : value ? *value : max ? "max" : "min");
Radek Krejci19a96102018-11-15 13:38:09 +01001689 } else if (!ret && value) {
1690 *value = *value + len;
1691 }
1692 free(valcopy);
1693 return ret;
1694}
1695
Radek Krejcia3045382018-11-22 14:30:31 +01001696/**
1697 * @brief Compile the parsed range restriction.
1698 * @param[in] ctx Compile context.
1699 * @param[in] range_p Parsed range structure to compile.
1700 * @param[in] basetype Base YANG built-in type of the node with the range restriction.
1701 * @param[in] length_restr Flag to distinguish between range and length restrictions. Only for logging.
1702 * @param[in] frdigits The fraction-digits value in case of LY_TYPE_DEC64 basetype.
1703 * @param[in] base_range Range restriction of the type from which the current type is derived. The current
1704 * range restriction must be more restrictive than the base_range.
1705 * @param[in,out] range Pointer to the created current range structure.
1706 * @return LY_ERR value.
1707 */
Radek Krejci19a96102018-11-15 13:38:09 +01001708static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02001709lys_compile_type_range(struct lysc_ctx *ctx, struct lysp_restr *range_p, LY_DATA_TYPE basetype, ly_bool length_restr,
Radek Krejci0f969882020-08-21 16:56:47 +02001710 uint8_t frdigits, struct lysc_range *base_range, struct lysc_range **range)
Radek Krejci19a96102018-11-15 13:38:09 +01001711{
1712 LY_ERR ret = LY_EVALID;
1713 const char *expr;
1714 struct lysc_range_part *parts = NULL, *part;
Radek Krejci857189e2020-09-01 13:26:36 +02001715 ly_bool range_expected = 0, uns;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001716 LY_ARRAY_COUNT_TYPE parts_done = 0, u, v;
Radek Krejci19a96102018-11-15 13:38:09 +01001717
1718 assert(range);
1719 assert(range_p);
1720
Michal Vasko7f45cf22020-10-01 12:49:44 +02001721 expr = range_p->arg.str;
Michal Vaskod989ba02020-08-24 10:59:24 +02001722 while (1) {
Radek Krejci19a96102018-11-15 13:38:09 +01001723 if (isspace(*expr)) {
1724 ++expr;
1725 } else if (*expr == '\0') {
1726 if (range_expected) {
1727 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1728 "Invalid %s restriction - unexpected end of the expression after \"..\" (%s).",
1729 length_restr ? "length" : "range", range_p->arg);
1730 goto cleanup;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001731 } else if (!parts || parts_done == LY_ARRAY_COUNT(parts)) {
Radek Krejci19a96102018-11-15 13:38:09 +01001732 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1733 "Invalid %s restriction - unexpected end of the expression (%s).",
1734 length_restr ? "length" : "range", range_p->arg);
1735 goto cleanup;
1736 }
1737 parts_done++;
1738 break;
1739 } else if (!strncmp(expr, "min", 3)) {
1740 if (parts) {
1741 /* min cannot be used elsewhere than in the first part */
1742 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1743 "Invalid %s restriction - unexpected data before min keyword (%.*s).", length_restr ? "length" : "range",
Michal Vasko7f45cf22020-10-01 12:49:44 +02001744 expr - range_p->arg.str, range_p->arg.str);
Radek Krejci19a96102018-11-15 13:38:09 +01001745 goto cleanup;
1746 }
1747 expr += 3;
1748
1749 LY_ARRAY_NEW_GOTO(ctx->ctx, parts, part, ret, cleanup);
Radek Krejci5969f272018-11-23 10:03:58 +01001750 LY_CHECK_GOTO(range_part_minmax(ctx, part, 0, 0, basetype, 1, length_restr, frdigits, base_range, NULL), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01001751 part->max_64 = part->min_64;
1752 } else if (*expr == '|') {
1753 if (!parts || range_expected) {
1754 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1755 "Invalid %s restriction - unexpected beginning of the expression (%s).", length_restr ? "length" : "range", expr);
1756 goto cleanup;
1757 }
1758 expr++;
1759 parts_done++;
1760 /* process next part of the expression */
1761 } else if (!strncmp(expr, "..", 2)) {
1762 expr += 2;
1763 while (isspace(*expr)) {
1764 expr++;
1765 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001766 if (!parts || LY_ARRAY_COUNT(parts) == parts_done) {
Radek Krejci19a96102018-11-15 13:38:09 +01001767 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1768 "Invalid %s restriction - unexpected \"..\" without a lower bound.", length_restr ? "length" : "range");
1769 goto cleanup;
1770 }
1771 /* continue expecting the upper boundary */
1772 range_expected = 1;
1773 } else if (isdigit(*expr) || (*expr == '-') || (*expr == '+')) {
1774 /* number */
1775 if (range_expected) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001776 part = &parts[LY_ARRAY_COUNT(parts) - 1];
Radek Krejci5969f272018-11-23 10:03:58 +01001777 LY_CHECK_GOTO(range_part_minmax(ctx, part, 1, part->min_64, basetype, 0, length_restr, frdigits, NULL, &expr), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01001778 range_expected = 0;
1779 } else {
1780 LY_ARRAY_NEW_GOTO(ctx->ctx, parts, part, ret, cleanup);
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001781 LY_CHECK_GOTO(range_part_minmax(ctx, part, 0, parts_done ? parts[LY_ARRAY_COUNT(parts) - 2].max_64 : 0,
Radek Krejci5969f272018-11-23 10:03:58 +01001782 basetype, parts_done ? 0 : 1, length_restr, frdigits, NULL, &expr), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01001783 part->max_64 = part->min_64;
1784 }
1785
1786 /* continue with possible another expression part */
1787 } else if (!strncmp(expr, "max", 3)) {
1788 expr += 3;
1789 while (isspace(*expr)) {
1790 expr++;
1791 }
1792 if (*expr != '\0') {
1793 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid %s restriction - unexpected data after max keyword (%s).",
1794 length_restr ? "length" : "range", expr);
1795 goto cleanup;
1796 }
1797 if (range_expected) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001798 part = &parts[LY_ARRAY_COUNT(parts) - 1];
Radek Krejci5969f272018-11-23 10:03:58 +01001799 LY_CHECK_GOTO(range_part_minmax(ctx, part, 1, part->min_64, basetype, 0, length_restr, frdigits, base_range, NULL), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01001800 range_expected = 0;
1801 } else {
1802 LY_ARRAY_NEW_GOTO(ctx->ctx, parts, part, ret, cleanup);
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001803 LY_CHECK_GOTO(range_part_minmax(ctx, part, 1, parts_done ? parts[LY_ARRAY_COUNT(parts) - 2].max_64 : 0,
Radek Krejci5969f272018-11-23 10:03:58 +01001804 basetype, parts_done ? 0 : 1, length_restr, frdigits, base_range, NULL), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01001805 part->min_64 = part->max_64;
1806 }
1807 } else {
1808 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid %s restriction - unexpected data (%s).",
1809 length_restr ? "length" : "range", expr);
1810 goto cleanup;
1811 }
1812 }
1813
1814 /* check with the previous range/length restriction */
1815 if (base_range) {
1816 switch (basetype) {
1817 case LY_TYPE_BINARY:
1818 case LY_TYPE_UINT8:
1819 case LY_TYPE_UINT16:
1820 case LY_TYPE_UINT32:
1821 case LY_TYPE_UINT64:
1822 case LY_TYPE_STRING:
1823 uns = 1;
1824 break;
1825 case LY_TYPE_DEC64:
1826 case LY_TYPE_INT8:
1827 case LY_TYPE_INT16:
1828 case LY_TYPE_INT32:
1829 case LY_TYPE_INT64:
1830 uns = 0;
1831 break;
1832 default:
1833 LOGINT(ctx->ctx);
1834 ret = LY_EINT;
1835 goto cleanup;
1836 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001837 for (u = v = 0; u < parts_done && v < LY_ARRAY_COUNT(base_range->parts); ++u) {
Radek Krejci19a96102018-11-15 13:38:09 +01001838 if ((uns && parts[u].min_u64 < base_range->parts[v].min_u64) || (!uns && parts[u].min_64 < base_range->parts[v].min_64)) {
1839 goto baseerror;
1840 }
1841 /* current lower bound is not lower than the base */
1842 if (base_range->parts[v].min_64 == base_range->parts[v].max_64) {
1843 /* base has single value */
1844 if (base_range->parts[v].min_64 == parts[u].min_64) {
1845 /* both lower bounds are the same */
1846 if (parts[u].min_64 != parts[u].max_64) {
1847 /* current continues with a range */
1848 goto baseerror;
1849 } else {
1850 /* equal single values, move both forward */
1851 ++v;
1852 continue;
1853 }
1854 } else {
1855 /* base is single value lower than current range, so the
1856 * value from base range is removed in the current,
1857 * move only base and repeat checking */
1858 ++v;
1859 --u;
1860 continue;
1861 }
1862 } else {
1863 /* base is the range */
1864 if (parts[u].min_64 == parts[u].max_64) {
1865 /* current is a single value */
1866 if ((uns && parts[u].max_u64 > base_range->parts[v].max_u64) || (!uns && parts[u].max_64 > base_range->parts[v].max_64)) {
1867 /* current is behind the base range, so base range is omitted,
1868 * move the base and keep the current for further check */
1869 ++v;
1870 --u;
1871 } /* else it is within the base range, so move the current, but keep the base */
1872 continue;
1873 } else {
1874 /* both are ranges - check the higher bound, the lower was already checked */
1875 if ((uns && parts[u].max_u64 > base_range->parts[v].max_u64) || (!uns && parts[u].max_64 > base_range->parts[v].max_64)) {
1876 /* higher bound is higher than the current higher bound */
1877 if ((uns && parts[u].min_u64 > base_range->parts[v].max_u64) || (!uns && parts[u].min_64 > base_range->parts[v].max_64)) {
1878 /* but the current lower bound is also higher, so the base range is omitted,
1879 * continue with the same current, but move the base */
1880 --u;
1881 ++v;
1882 continue;
1883 }
1884 /* current range starts within the base range but end behind it */
1885 goto baseerror;
1886 } else {
1887 /* current range is smaller than the base,
1888 * move current, but stay with the base */
1889 continue;
1890 }
1891 }
1892 }
1893 }
1894 if (u != parts_done) {
1895baseerror:
1896 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1897 "Invalid %s restriction - the derived restriction (%s) is not equally or more limiting.",
1898 length_restr ? "length" : "range", range_p->arg);
1899 goto cleanup;
1900 }
1901 }
1902
1903 if (!(*range)) {
1904 *range = calloc(1, sizeof **range);
1905 LY_CHECK_ERR_RET(!(*range), LOGMEM(ctx->ctx), LY_EMEM);
1906 }
1907
Radek Krejcic8b31002019-01-08 10:24:45 +01001908 /* we rewrite the following values as the types chain is being processed */
Radek Krejci19a96102018-11-15 13:38:09 +01001909 if (range_p->eapptag) {
1910 lydict_remove(ctx->ctx, (*range)->eapptag);
Radek Krejci011e4aa2020-09-04 15:22:31 +02001911 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->eapptag, 0, &(*range)->eapptag), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01001912 }
1913 if (range_p->emsg) {
1914 lydict_remove(ctx->ctx, (*range)->emsg);
Radek Krejci011e4aa2020-09-04 15:22:31 +02001915 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->emsg, 0, &(*range)->emsg), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01001916 }
Radek Krejcic8b31002019-01-08 10:24:45 +01001917 if (range_p->dsc) {
1918 lydict_remove(ctx->ctx, (*range)->dsc);
Radek Krejci011e4aa2020-09-04 15:22:31 +02001919 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->dsc, 0, &(*range)->dsc), cleanup);
Radek Krejcic8b31002019-01-08 10:24:45 +01001920 }
1921 if (range_p->ref) {
1922 lydict_remove(ctx->ctx, (*range)->ref);
Radek Krejci011e4aa2020-09-04 15:22:31 +02001923 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->ref, 0, &(*range)->ref), cleanup);
Radek Krejcic8b31002019-01-08 10:24:45 +01001924 }
Radek Krejci19a96102018-11-15 13:38:09 +01001925 /* extensions are taken only from the last range by the caller */
1926
1927 (*range)->parts = parts;
1928 parts = NULL;
1929 ret = LY_SUCCESS;
1930cleanup:
Radek Krejci19a96102018-11-15 13:38:09 +01001931 LY_ARRAY_FREE(parts);
1932
1933 return ret;
1934}
1935
1936/**
1937 * @brief Checks pattern syntax.
1938 *
Michal Vasko03ff5a72019-09-11 13:49:33 +02001939 * @param[in] ctx Context.
1940 * @param[in] log_path Path for logging errors.
Radek Krejci19a96102018-11-15 13:38:09 +01001941 * @param[in] pattern Pattern to check.
Radek Krejci54579462019-04-30 12:47:06 +02001942 * @param[in,out] pcre2_code Compiled PCRE2 pattern. If NULL, the compiled information used to validate pattern are freed.
Radek Krejcia3045382018-11-22 14:30:31 +01001943 * @return LY_ERR value - LY_SUCCESS, LY_EMEM, LY_EVALID.
Radek Krejci19a96102018-11-15 13:38:09 +01001944 */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001945LY_ERR
1946lys_compile_type_pattern_check(struct ly_ctx *ctx, const char *log_path, const char *pattern, pcre2_code **code)
Radek Krejci19a96102018-11-15 13:38:09 +01001947{
Radek Krejci1deb5be2020-08-26 16:43:36 +02001948 size_t idx, idx2, start, end, size, brack;
Radek Krejci19a96102018-11-15 13:38:09 +01001949 char *perl_regex, *ptr;
Radek Krejci54579462019-04-30 12:47:06 +02001950 int err_code;
1951 const char *orig_ptr;
1952 PCRE2_SIZE err_offset;
1953 pcre2_code *code_local;
Radek Krejci19a96102018-11-15 13:38:09 +01001954#define URANGE_LEN 19
1955 char *ublock2urange[][2] = {
1956 {"BasicLatin", "[\\x{0000}-\\x{007F}]"},
1957 {"Latin-1Supplement", "[\\x{0080}-\\x{00FF}]"},
1958 {"LatinExtended-A", "[\\x{0100}-\\x{017F}]"},
1959 {"LatinExtended-B", "[\\x{0180}-\\x{024F}]"},
1960 {"IPAExtensions", "[\\x{0250}-\\x{02AF}]"},
1961 {"SpacingModifierLetters", "[\\x{02B0}-\\x{02FF}]"},
1962 {"CombiningDiacriticalMarks", "[\\x{0300}-\\x{036F}]"},
1963 {"Greek", "[\\x{0370}-\\x{03FF}]"},
1964 {"Cyrillic", "[\\x{0400}-\\x{04FF}]"},
1965 {"Armenian", "[\\x{0530}-\\x{058F}]"},
1966 {"Hebrew", "[\\x{0590}-\\x{05FF}]"},
1967 {"Arabic", "[\\x{0600}-\\x{06FF}]"},
1968 {"Syriac", "[\\x{0700}-\\x{074F}]"},
1969 {"Thaana", "[\\x{0780}-\\x{07BF}]"},
1970 {"Devanagari", "[\\x{0900}-\\x{097F}]"},
1971 {"Bengali", "[\\x{0980}-\\x{09FF}]"},
1972 {"Gurmukhi", "[\\x{0A00}-\\x{0A7F}]"},
1973 {"Gujarati", "[\\x{0A80}-\\x{0AFF}]"},
1974 {"Oriya", "[\\x{0B00}-\\x{0B7F}]"},
1975 {"Tamil", "[\\x{0B80}-\\x{0BFF}]"},
1976 {"Telugu", "[\\x{0C00}-\\x{0C7F}]"},
1977 {"Kannada", "[\\x{0C80}-\\x{0CFF}]"},
1978 {"Malayalam", "[\\x{0D00}-\\x{0D7F}]"},
1979 {"Sinhala", "[\\x{0D80}-\\x{0DFF}]"},
1980 {"Thai", "[\\x{0E00}-\\x{0E7F}]"},
1981 {"Lao", "[\\x{0E80}-\\x{0EFF}]"},
1982 {"Tibetan", "[\\x{0F00}-\\x{0FFF}]"},
1983 {"Myanmar", "[\\x{1000}-\\x{109F}]"},
1984 {"Georgian", "[\\x{10A0}-\\x{10FF}]"},
1985 {"HangulJamo", "[\\x{1100}-\\x{11FF}]"},
1986 {"Ethiopic", "[\\x{1200}-\\x{137F}]"},
1987 {"Cherokee", "[\\x{13A0}-\\x{13FF}]"},
1988 {"UnifiedCanadianAboriginalSyllabics", "[\\x{1400}-\\x{167F}]"},
1989 {"Ogham", "[\\x{1680}-\\x{169F}]"},
1990 {"Runic", "[\\x{16A0}-\\x{16FF}]"},
1991 {"Khmer", "[\\x{1780}-\\x{17FF}]"},
1992 {"Mongolian", "[\\x{1800}-\\x{18AF}]"},
1993 {"LatinExtendedAdditional", "[\\x{1E00}-\\x{1EFF}]"},
1994 {"GreekExtended", "[\\x{1F00}-\\x{1FFF}]"},
1995 {"GeneralPunctuation", "[\\x{2000}-\\x{206F}]"},
1996 {"SuperscriptsandSubscripts", "[\\x{2070}-\\x{209F}]"},
1997 {"CurrencySymbols", "[\\x{20A0}-\\x{20CF}]"},
1998 {"CombiningMarksforSymbols", "[\\x{20D0}-\\x{20FF}]"},
1999 {"LetterlikeSymbols", "[\\x{2100}-\\x{214F}]"},
2000 {"NumberForms", "[\\x{2150}-\\x{218F}]"},
2001 {"Arrows", "[\\x{2190}-\\x{21FF}]"},
2002 {"MathematicalOperators", "[\\x{2200}-\\x{22FF}]"},
2003 {"MiscellaneousTechnical", "[\\x{2300}-\\x{23FF}]"},
2004 {"ControlPictures", "[\\x{2400}-\\x{243F}]"},
2005 {"OpticalCharacterRecognition", "[\\x{2440}-\\x{245F}]"},
2006 {"EnclosedAlphanumerics", "[\\x{2460}-\\x{24FF}]"},
2007 {"BoxDrawing", "[\\x{2500}-\\x{257F}]"},
2008 {"BlockElements", "[\\x{2580}-\\x{259F}]"},
2009 {"GeometricShapes", "[\\x{25A0}-\\x{25FF}]"},
2010 {"MiscellaneousSymbols", "[\\x{2600}-\\x{26FF}]"},
2011 {"Dingbats", "[\\x{2700}-\\x{27BF}]"},
2012 {"BraillePatterns", "[\\x{2800}-\\x{28FF}]"},
2013 {"CJKRadicalsSupplement", "[\\x{2E80}-\\x{2EFF}]"},
2014 {"KangxiRadicals", "[\\x{2F00}-\\x{2FDF}]"},
2015 {"IdeographicDescriptionCharacters", "[\\x{2FF0}-\\x{2FFF}]"},
2016 {"CJKSymbolsandPunctuation", "[\\x{3000}-\\x{303F}]"},
2017 {"Hiragana", "[\\x{3040}-\\x{309F}]"},
2018 {"Katakana", "[\\x{30A0}-\\x{30FF}]"},
2019 {"Bopomofo", "[\\x{3100}-\\x{312F}]"},
2020 {"HangulCompatibilityJamo", "[\\x{3130}-\\x{318F}]"},
2021 {"Kanbun", "[\\x{3190}-\\x{319F}]"},
2022 {"BopomofoExtended", "[\\x{31A0}-\\x{31BF}]"},
2023 {"EnclosedCJKLettersandMonths", "[\\x{3200}-\\x{32FF}]"},
2024 {"CJKCompatibility", "[\\x{3300}-\\x{33FF}]"},
2025 {"CJKUnifiedIdeographsExtensionA", "[\\x{3400}-\\x{4DB5}]"},
2026 {"CJKUnifiedIdeographs", "[\\x{4E00}-\\x{9FFF}]"},
2027 {"YiSyllables", "[\\x{A000}-\\x{A48F}]"},
2028 {"YiRadicals", "[\\x{A490}-\\x{A4CF}]"},
2029 {"HangulSyllables", "[\\x{AC00}-\\x{D7A3}]"},
2030 {"PrivateUse", "[\\x{E000}-\\x{F8FF}]"},
2031 {"CJKCompatibilityIdeographs", "[\\x{F900}-\\x{FAFF}]"},
2032 {"AlphabeticPresentationForms", "[\\x{FB00}-\\x{FB4F}]"},
2033 {"ArabicPresentationForms-A", "[\\x{FB50}-\\x{FDFF}]"},
2034 {"CombiningHalfMarks", "[\\x{FE20}-\\x{FE2F}]"},
2035 {"CJKCompatibilityForms", "[\\x{FE30}-\\x{FE4F}]"},
2036 {"SmallFormVariants", "[\\x{FE50}-\\x{FE6F}]"},
2037 {"ArabicPresentationForms-B", "[\\x{FE70}-\\x{FEFE}]"},
2038 {"HalfwidthandFullwidthForms", "[\\x{FF00}-\\x{FFEF}]"},
2039 {NULL, NULL}
2040 };
2041
2042 /* adjust the expression to a Perl equivalent
2043 * http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#regexs */
2044
Michal Vasko40a00082020-05-27 15:20:01 +02002045 /* allocate space for the transformed pattern */
2046 size = strlen(pattern) + 1;
2047 perl_regex = malloc(size);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002048 LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx), LY_EMEM);
Radek Krejci19a96102018-11-15 13:38:09 +01002049 perl_regex[0] = '\0';
2050
Michal Vasko40a00082020-05-27 15:20:01 +02002051 /* we need to replace all "$" and "^" (that are not in "[]") with "\$" and "\^" */
2052 brack = 0;
2053 idx = 0;
2054 orig_ptr = pattern;
2055 while (orig_ptr[0]) {
2056 switch (orig_ptr[0]) {
2057 case '$':
2058 case '^':
2059 if (!brack) {
2060 /* make space for the extra character */
2061 ++size;
2062 perl_regex = ly_realloc(perl_regex, size);
2063 LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx), LY_EMEM);
Radek Krejci19a96102018-11-15 13:38:09 +01002064
Michal Vasko40a00082020-05-27 15:20:01 +02002065 /* print escape slash */
2066 perl_regex[idx] = '\\';
2067 ++idx;
2068 }
2069 break;
2070 case '[':
2071 /* must not be escaped */
2072 if ((orig_ptr == pattern) || (orig_ptr[-1] != '\\')) {
2073 ++brack;
2074 }
2075 break;
2076 case ']':
2077 if ((orig_ptr == pattern) || (orig_ptr[-1] != '\\')) {
2078 /* pattern was checked and compiled already */
2079 assert(brack);
2080 --brack;
2081 }
2082 break;
2083 default:
2084 break;
Radek Krejci19a96102018-11-15 13:38:09 +01002085 }
Michal Vasko40a00082020-05-27 15:20:01 +02002086
2087 /* copy char */
2088 perl_regex[idx] = orig_ptr[0];
2089
2090 ++idx;
2091 ++orig_ptr;
Radek Krejci19a96102018-11-15 13:38:09 +01002092 }
Michal Vasko40a00082020-05-27 15:20:01 +02002093 perl_regex[idx] = '\0';
Radek Krejci19a96102018-11-15 13:38:09 +01002094
2095 /* substitute Unicode Character Blocks with exact Character Ranges */
2096 while ((ptr = strstr(perl_regex, "\\p{Is"))) {
2097 start = ptr - perl_regex;
2098
2099 ptr = strchr(ptr, '}');
2100 if (!ptr) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002101 LOGVAL(ctx, LY_VLOG_STR, log_path, LY_VCODE_INREGEXP,
Radek Krejci19a96102018-11-15 13:38:09 +01002102 pattern, perl_regex + start + 2, "unterminated character property");
2103 free(perl_regex);
2104 return LY_EVALID;
2105 }
2106 end = (ptr - perl_regex) + 1;
2107
2108 /* need more space */
2109 if (end - start < URANGE_LEN) {
2110 perl_regex = ly_realloc(perl_regex, strlen(perl_regex) + (URANGE_LEN - (end - start)) + 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002111 LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx); free(perl_regex), LY_EMEM);
Radek Krejci19a96102018-11-15 13:38:09 +01002112 }
2113
2114 /* find our range */
2115 for (idx = 0; ublock2urange[idx][0]; ++idx) {
2116 if (!strncmp(perl_regex + start + 5, ublock2urange[idx][0], strlen(ublock2urange[idx][0]))) {
2117 break;
2118 }
2119 }
2120 if (!ublock2urange[idx][0]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002121 LOGVAL(ctx, LY_VLOG_STR, log_path, LY_VCODE_INREGEXP,
Radek Krejci19a96102018-11-15 13:38:09 +01002122 pattern, perl_regex + start + 5, "unknown block name");
2123 free(perl_regex);
2124 return LY_EVALID;
2125 }
2126
2127 /* make the space in the string and replace the block (but we cannot include brackets if it was already enclosed in them) */
Michal Vasko40a00082020-05-27 15:20:01 +02002128 for (idx2 = 0, idx = 0; idx2 < start; ++idx2) {
Radek Krejci19a96102018-11-15 13:38:09 +01002129 if ((perl_regex[idx2] == '[') && (!idx2 || (perl_regex[idx2 - 1] != '\\'))) {
Michal Vasko40a00082020-05-27 15:20:01 +02002130 ++idx;
Radek Krejci19a96102018-11-15 13:38:09 +01002131 }
2132 if ((perl_regex[idx2] == ']') && (!idx2 || (perl_regex[idx2 - 1] != '\\'))) {
Michal Vasko40a00082020-05-27 15:20:01 +02002133 --idx;
Radek Krejci19a96102018-11-15 13:38:09 +01002134 }
2135 }
Michal Vasko40a00082020-05-27 15:20:01 +02002136 if (idx) {
Radek Krejci19a96102018-11-15 13:38:09 +01002137 /* skip brackets */
2138 memmove(perl_regex + start + (URANGE_LEN - 2), perl_regex + end, strlen(perl_regex + end) + 1);
2139 memcpy(perl_regex + start, ublock2urange[idx][1] + 1, URANGE_LEN - 2);
2140 } else {
2141 memmove(perl_regex + start + URANGE_LEN, perl_regex + end, strlen(perl_regex + end) + 1);
2142 memcpy(perl_regex + start, ublock2urange[idx][1], URANGE_LEN);
2143 }
2144 }
2145
2146 /* must return 0, already checked during parsing */
Radek Krejci5819f7c2019-05-31 14:53:29 +02002147 code_local = pcre2_compile((PCRE2_SPTR)perl_regex, PCRE2_ZERO_TERMINATED,
2148 PCRE2_UTF | PCRE2_ANCHORED | PCRE2_ENDANCHORED | PCRE2_DOLLAR_ENDONLY | PCRE2_NO_AUTO_CAPTURE,
Radek Krejci54579462019-04-30 12:47:06 +02002149 &err_code, &err_offset, NULL);
2150 if (!code_local) {
2151 PCRE2_UCHAR err_msg[256] = {0};
2152 pcre2_get_error_message(err_code, err_msg, 256);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002153 LOGVAL(ctx, LY_VLOG_STR, log_path, LY_VCODE_INREGEXP, pattern, perl_regex + err_offset, err_msg);
Radek Krejci19a96102018-11-15 13:38:09 +01002154 free(perl_regex);
2155 return LY_EVALID;
2156 }
2157 free(perl_regex);
2158
Radek Krejci54579462019-04-30 12:47:06 +02002159 if (code) {
2160 *code = code_local;
Radek Krejci19a96102018-11-15 13:38:09 +01002161 } else {
Radek Krejci54579462019-04-30 12:47:06 +02002162 free(code_local);
Radek Krejci19a96102018-11-15 13:38:09 +01002163 }
2164
2165 return LY_SUCCESS;
2166
2167#undef URANGE_LEN
2168}
2169
Radek Krejcia3045382018-11-22 14:30:31 +01002170/**
2171 * @brief Compile parsed pattern restriction in conjunction with the patterns from base type.
2172 * @param[in] ctx Compile context.
2173 * @param[in] patterns_p Array of parsed patterns from the current type to compile.
Radek Krejcia3045382018-11-22 14:30:31 +01002174 * @param[in] base_patterns Compiled patterns from the type from which the current type is derived.
2175 * Patterns from the base type are inherited to have all the patterns that have to match at one place.
2176 * @param[out] patterns Pointer to the storage for the patterns of the current type.
2177 * @return LY_ERR LY_SUCCESS, LY_EMEM, LY_EVALID.
2178 */
Radek Krejci19a96102018-11-15 13:38:09 +01002179static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02002180lys_compile_type_patterns(struct lysc_ctx *ctx, struct lysp_restr *patterns_p,
Radek Krejci0f969882020-08-21 16:56:47 +02002181 struct lysc_pattern **base_patterns, struct lysc_pattern ***patterns)
Radek Krejci19a96102018-11-15 13:38:09 +01002182{
2183 struct lysc_pattern **pattern;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002184 LY_ARRAY_COUNT_TYPE u;
Radek Krejci19a96102018-11-15 13:38:09 +01002185 LY_ERR ret = LY_SUCCESS;
2186
2187 /* first, copy the patterns from the base type */
2188 if (base_patterns) {
2189 *patterns = lysc_patterns_dup(ctx->ctx, base_patterns);
2190 LY_CHECK_ERR_RET(!(*patterns), LOGMEM(ctx->ctx), LY_EMEM);
2191 }
2192
2193 LY_ARRAY_FOR(patterns_p, u) {
2194 LY_ARRAY_NEW_RET(ctx->ctx, (*patterns), pattern, LY_EMEM);
2195 *pattern = calloc(1, sizeof **pattern);
2196 ++(*pattern)->refcount;
2197
Michal Vasko7f45cf22020-10-01 12:49:44 +02002198 ret = lys_compile_type_pattern_check(ctx->ctx, ctx->path, &patterns_p[u].arg.str[1], &(*pattern)->code);
Radek Krejci19a96102018-11-15 13:38:09 +01002199 LY_CHECK_RET(ret);
Radek Krejci19a96102018-11-15 13:38:09 +01002200
Michal Vasko7f45cf22020-10-01 12:49:44 +02002201 if (patterns_p[u].arg.str[0] == 0x15) {
Radek Krejci19a96102018-11-15 13:38:09 +01002202 (*pattern)->inverted = 1;
2203 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02002204 DUP_STRING_GOTO(ctx->ctx, &patterns_p[u].arg.str[1], (*pattern)->expr, ret, done);
Radek Krejci011e4aa2020-09-04 15:22:31 +02002205 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].eapptag, (*pattern)->eapptag, ret, done);
2206 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].emsg, (*pattern)->emsg, ret, done);
2207 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].dsc, (*pattern)->dsc, ret, done);
2208 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].ref, (*pattern)->ref, ret, done);
Radek Krejci0935f412019-08-20 16:15:18 +02002209 COMPILE_EXTS_GOTO(ctx, patterns_p[u].exts, (*pattern)->exts, (*pattern), LYEXT_PAR_PATTERN, ret, done);
Radek Krejci19a96102018-11-15 13:38:09 +01002210 }
2211done:
2212 return ret;
2213}
2214
Radek Krejcia3045382018-11-22 14:30:31 +01002215/**
2216 * @brief map of the possible restrictions combination for the specific built-in type.
2217 */
Radek Krejci19a96102018-11-15 13:38:09 +01002218static uint16_t type_substmt_map[LY_DATA_TYPE_COUNT] = {
2219 0 /* LY_TYPE_UNKNOWN */,
2220 LYS_SET_LENGTH /* LY_TYPE_BINARY */,
Radek Krejci5969f272018-11-23 10:03:58 +01002221 LYS_SET_RANGE /* LY_TYPE_UINT8 */,
2222 LYS_SET_RANGE /* LY_TYPE_UINT16 */,
2223 LYS_SET_RANGE /* LY_TYPE_UINT32 */,
2224 LYS_SET_RANGE /* LY_TYPE_UINT64 */,
2225 LYS_SET_LENGTH | LYS_SET_PATTERN /* LY_TYPE_STRING */,
Radek Krejci19a96102018-11-15 13:38:09 +01002226 LYS_SET_BIT /* LY_TYPE_BITS */,
2227 0 /* LY_TYPE_BOOL */,
2228 LYS_SET_FRDIGITS | LYS_SET_RANGE /* LY_TYPE_DEC64 */,
2229 0 /* LY_TYPE_EMPTY */,
2230 LYS_SET_ENUM /* LY_TYPE_ENUM */,
2231 LYS_SET_BASE /* LY_TYPE_IDENT */,
2232 LYS_SET_REQINST /* LY_TYPE_INST */,
2233 LYS_SET_REQINST | LYS_SET_PATH /* LY_TYPE_LEAFREF */,
Radek Krejci19a96102018-11-15 13:38:09 +01002234 LYS_SET_TYPE /* LY_TYPE_UNION */,
2235 LYS_SET_RANGE /* LY_TYPE_INT8 */,
Radek Krejci19a96102018-11-15 13:38:09 +01002236 LYS_SET_RANGE /* LY_TYPE_INT16 */,
Radek Krejci19a96102018-11-15 13:38:09 +01002237 LYS_SET_RANGE /* LY_TYPE_INT32 */,
Radek Krejci5969f272018-11-23 10:03:58 +01002238 LYS_SET_RANGE /* LY_TYPE_INT64 */
2239};
2240
2241/**
2242 * @brief stringification of the YANG built-in data types
2243 */
Michal Vasko22df3f02020-08-24 13:29:22 +02002244const char *ly_data_type2str[LY_DATA_TYPE_COUNT] = {"unknown", "binary", "8bit unsigned integer", "16bit unsigned integer",
Radek Krejci5969f272018-11-23 10:03:58 +01002245 "32bit unsigned integer", "64bit unsigned integer", "string", "bits", "boolean", "decimal64", "empty", "enumeration",
Radek Krejci0f969882020-08-21 16:56:47 +02002246 "identityref", "instance-identifier", "leafref", "union", "8bit integer", "16bit integer", "32bit integer", "64bit integer"};
Radek Krejci19a96102018-11-15 13:38:09 +01002247
Radek Krejcia3045382018-11-22 14:30:31 +01002248/**
2249 * @brief Compile parsed type's enum structures (for enumeration and bits types).
2250 * @param[in] ctx Compile context.
2251 * @param[in] enums_p Array of the parsed enum structures to compile.
2252 * @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.
Radek Krejcia3045382018-11-22 14:30:31 +01002253 * @param[in] base_enums Array of the compiled enums information from the (latest) base type to check if the current enums are compatible.
2254 * @param[out] enums Newly created array of the compiled enums information for the current type.
2255 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
2256 */
Radek Krejci19a96102018-11-15 13:38:09 +01002257static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02002258lys_compile_type_enums(struct lysc_ctx *ctx, struct lysp_type_enum *enums_p, LY_DATA_TYPE basetype,
Radek Krejci0f969882020-08-21 16:56:47 +02002259 struct lysc_type_bitenum_item *base_enums, struct lysc_type_bitenum_item **enums)
Radek Krejci19a96102018-11-15 13:38:09 +01002260{
2261 LY_ERR ret = LY_SUCCESS;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002262 LY_ARRAY_COUNT_TYPE u, v, match = 0;
Radek Krejci19a96102018-11-15 13:38:09 +01002263 int32_t value = 0;
2264 uint32_t position = 0;
Radek Krejci693262f2019-04-29 15:23:20 +02002265 struct lysc_type_bitenum_item *e, storage;
Radek Krejci19a96102018-11-15 13:38:09 +01002266
Radek Krejci0bcdaed2019-01-10 10:21:34 +01002267 if (base_enums && ctx->mod_def->version < 2) {
Radek Krejci19a96102018-11-15 13:38:09 +01002268 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "%s type can be subtyped only in YANG 1.1 modules.",
2269 basetype == LY_TYPE_ENUM ? "Enumeration" : "Bits");
2270 return LY_EVALID;
2271 }
2272
2273 LY_ARRAY_FOR(enums_p, u) {
2274 LY_ARRAY_NEW_RET(ctx->ctx, *enums, e, LY_EMEM);
Radek Krejci011e4aa2020-09-04 15:22:31 +02002275 DUP_STRING_GOTO(ctx->ctx, enums_p[u].name, e->name, ret, done);
2276 DUP_STRING_GOTO(ctx->ctx, enums_p[u].ref, e->dsc, ret, done);
2277 DUP_STRING_GOTO(ctx->ctx, enums_p[u].ref, e->ref, ret, done);
Radek Krejci693262f2019-04-29 15:23:20 +02002278 e->flags = enums_p[u].flags & LYS_FLAGS_COMPILED_MASK;
Radek Krejci19a96102018-11-15 13:38:09 +01002279 if (base_enums) {
2280 /* check the enum/bit presence in the base type - the set of enums/bits in the derived type must be a subset */
2281 LY_ARRAY_FOR(base_enums, v) {
2282 if (!strcmp(e->name, base_enums[v].name)) {
2283 break;
2284 }
2285 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002286 if (v == LY_ARRAY_COUNT(base_enums)) {
Radek Krejci19a96102018-11-15 13:38:09 +01002287 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
2288 "Invalid %s - derived type adds new item \"%s\".",
2289 basetype == LY_TYPE_ENUM ? "enumeration" : "bits", e->name);
2290 return LY_EVALID;
2291 }
2292 match = v;
2293 }
2294
2295 if (basetype == LY_TYPE_ENUM) {
Radek Krejci693262f2019-04-29 15:23:20 +02002296 e->flags |= LYS_ISENUM;
Radek Krejci19a96102018-11-15 13:38:09 +01002297 if (enums_p[u].flags & LYS_SET_VALUE) {
2298 e->value = (int32_t)enums_p[u].value;
2299 if (!u || e->value >= value) {
2300 value = e->value + 1;
2301 }
2302 /* check collision with other values */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002303 for (v = 0; v < LY_ARRAY_COUNT(*enums) - 1; ++v) {
Radek Krejci19a96102018-11-15 13:38:09 +01002304 if (e->value == (*enums)[v].value) {
2305 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
2306 "Invalid enumeration - value %d collide in items \"%s\" and \"%s\".",
2307 e->value, e->name, (*enums)[v].name);
2308 return LY_EVALID;
2309 }
2310 }
2311 } else if (base_enums) {
2312 /* inherit the assigned value */
2313 e->value = base_enums[match].value;
2314 if (!u || e->value >= value) {
2315 value = e->value + 1;
2316 }
2317 } else {
2318 /* assign value automatically */
2319 if (u && value == INT32_MIN) {
2320 /* counter overflow */
2321 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
2322 "Invalid enumeration - it is not possible to auto-assign enum value for "
2323 "\"%s\" since the highest value is already 2147483647.", e->name);
2324 return LY_EVALID;
2325 }
2326 e->value = value++;
2327 }
2328 } else { /* LY_TYPE_BITS */
2329 if (enums_p[u].flags & LYS_SET_VALUE) {
2330 e->value = (int32_t)enums_p[u].value;
2331 if (!u || (uint32_t)e->value >= position) {
2332 position = (uint32_t)e->value + 1;
2333 }
2334 /* check collision with other values */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002335 for (v = 0; v < LY_ARRAY_COUNT(*enums) - 1; ++v) {
Radek Krejci19a96102018-11-15 13:38:09 +01002336 if (e->value == (*enums)[v].value) {
2337 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
2338 "Invalid bits - position %u collide in items \"%s\" and \"%s\".",
Radek Krejci0f969882020-08-21 16:56:47 +02002339 (uint32_t)e->value, e->name, (*enums)[v].name);
Radek Krejci19a96102018-11-15 13:38:09 +01002340 return LY_EVALID;
2341 }
2342 }
2343 } else if (base_enums) {
2344 /* inherit the assigned value */
2345 e->value = base_enums[match].value;
2346 if (!u || (uint32_t)e->value >= position) {
2347 position = (uint32_t)e->value + 1;
2348 }
2349 } else {
2350 /* assign value automatically */
2351 if (u && position == 0) {
2352 /* counter overflow */
2353 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
2354 "Invalid bits - it is not possible to auto-assign bit position for "
2355 "\"%s\" since the highest value is already 4294967295.", e->name);
2356 return LY_EVALID;
2357 }
2358 e->value = position++;
2359 }
2360 }
2361
2362 if (base_enums) {
2363 /* the assigned values must not change from the derived type */
2364 if (e->value != base_enums[match].value) {
2365 if (basetype == LY_TYPE_ENUM) {
2366 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
2367 "Invalid enumeration - value of the item \"%s\" has changed from %d to %d in the derived type.",
2368 e->name, base_enums[match].value, e->value);
2369 } else {
2370 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
2371 "Invalid bits - position of the item \"%s\" has changed from %u to %u in the derived type.",
2372 e->name, (uint32_t)base_enums[match].value, (uint32_t)e->value);
2373 }
2374 return LY_EVALID;
2375 }
2376 }
2377
Radek Krejciec4da802019-05-02 13:02:41 +02002378 COMPILE_ARRAY_GOTO(ctx, enums_p[u].iffeatures, e->iffeatures, v, lys_compile_iffeature, ret, done);
Radek Krejci0935f412019-08-20 16:15:18 +02002379 COMPILE_EXTS_GOTO(ctx, enums_p[u].exts, e->exts, e, basetype == LY_TYPE_ENUM ? LYEXT_PAR_TYPE_ENUM : LYEXT_PAR_TYPE_BIT, ret, done);
Radek Krejci19a96102018-11-15 13:38:09 +01002380
2381 if (basetype == LY_TYPE_BITS) {
2382 /* keep bits ordered by position */
Radek Krejci1e008d22020-08-17 11:37:37 +02002383 for (v = u; v && (*enums)[v - 1].value > e->value; --v) {}
Radek Krejci19a96102018-11-15 13:38:09 +01002384 if (v != u) {
2385 memcpy(&storage, e, sizeof *e);
2386 memmove(&(*enums)[v + 1], &(*enums)[v], (u - v) * sizeof **enums);
2387 memcpy(&(*enums)[v], &storage, sizeof storage);
2388 }
2389 }
2390 }
2391
2392done:
2393 return ret;
2394}
2395
Radek Krejcia3045382018-11-22 14:30:31 +01002396/**
2397 * @brief Parse path-arg (leafref). Get tokens of the path by repetitive calls of the function.
2398 *
2399 * path-arg = absolute-path / relative-path
2400 * absolute-path = 1*("/" (node-identifier *path-predicate))
2401 * relative-path = 1*(".." "/") descendant-path
2402 *
2403 * @param[in,out] path Path to parse.
2404 * @param[out] prefix Prefix of the token, NULL if there is not any.
2405 * @param[out] pref_len Length of the prefix, 0 if there is not any.
2406 * @param[out] name Name of the token.
2407 * @param[out] nam_len Length of the name.
2408 * @param[out] parent_times Number of leading ".." in the path. Must be 0 on the first call,
2409 * must not be changed between consecutive calls. -1 if the
2410 * path is absolute.
2411 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
2412 * @return LY_ERR value: LY_SUCCESS or LY_EINVAL in case of invalid character in the path.
2413 */
Radek Krejci2d7a47b2019-05-16 13:34:10 +02002414LY_ERR
Radek Krejcia3045382018-11-22 14:30:31 +01002415lys_path_token(const char **path, const char **prefix, size_t *prefix_len, const char **name, size_t *name_len,
Radek Krejci857189e2020-09-01 13:26:36 +02002416 int32_t *parent_times, ly_bool *has_predicate)
Radek Krejcia3045382018-11-22 14:30:31 +01002417{
Radek Krejci1deb5be2020-08-26 16:43:36 +02002418 int32_t par_times = 0;
Radek Krejcia3045382018-11-22 14:30:31 +01002419
2420 assert(path && *path);
2421 assert(parent_times);
2422 assert(prefix);
2423 assert(prefix_len);
2424 assert(name);
2425 assert(name_len);
2426 assert(has_predicate);
2427
2428 *prefix = NULL;
2429 *prefix_len = 0;
2430 *name = NULL;
2431 *name_len = 0;
2432 *has_predicate = 0;
2433
2434 if (!*parent_times) {
2435 if (!strncmp(*path, "..", 2)) {
2436 *path += 2;
2437 ++par_times;
2438 while (!strncmp(*path, "/..", 3)) {
2439 *path += 3;
2440 ++par_times;
2441 }
2442 }
2443 if (par_times) {
2444 *parent_times = par_times;
2445 } else {
2446 *parent_times = -1;
2447 }
2448 }
2449
2450 if (**path != '/') {
2451 return LY_EINVAL;
2452 }
2453 /* skip '/' */
2454 ++(*path);
2455
2456 /* node-identifier ([prefix:]name) */
Radek Krejcib4a4a272019-06-10 12:44:52 +02002457 LY_CHECK_RET(ly_parse_nodeid(path, prefix, prefix_len, name, name_len));
Radek Krejcia3045382018-11-22 14:30:31 +01002458
2459 if ((**path == '/' && (*path)[1]) || !**path) {
2460 /* path continues by another token or this is the last token */
2461 return LY_SUCCESS;
2462 } else if ((*path)[0] != '[') {
2463 /* unexpected character */
2464 return LY_EINVAL;
2465 } else {
2466 /* predicate starting with [ */
2467 *has_predicate = 1;
2468 return LY_SUCCESS;
2469 }
2470}
2471
2472/**
Radek Krejci58d171e2018-11-23 13:50:55 +01002473 * @brief Check the features used in if-feature statements applicable to the leafref and its target.
2474 *
2475 * The set of features used for target must be a subset of features used for the leafref.
2476 * This is not a perfect, we should compare the truth tables but it could require too much resources
2477 * and RFC 7950 does not require it explicitely, so we simplify that.
2478 *
2479 * @param[in] refnode The leafref node.
2480 * @param[in] target Tha target node of the leafref.
2481 * @return LY_SUCCESS or LY_EVALID;
2482 */
2483static LY_ERR
2484lys_compile_leafref_features_validate(const struct lysc_node *refnode, const struct lysc_node *target)
2485{
2486 LY_ERR ret = LY_EVALID;
2487 const struct lysc_node *iter;
Radek Krejci1deb5be2020-08-26 16:43:36 +02002488 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci58d171e2018-11-23 13:50:55 +01002489 struct ly_set features = {0};
2490
2491 for (iter = refnode; iter; iter = iter->parent) {
Radek Krejci056d0a82018-12-06 16:57:25 +01002492 if (iter->iffeatures) {
2493 LY_ARRAY_FOR(iter->iffeatures, u) {
2494 LY_ARRAY_FOR(iter->iffeatures[u].features, v) {
Radek Krejciba03a5a2020-08-27 14:40:41 +02002495 LY_CHECK_GOTO(ly_set_add(&features, iter->iffeatures[u].features[v], 0, NULL), cleanup);
Radek Krejci58d171e2018-11-23 13:50:55 +01002496 }
2497 }
2498 }
2499 }
2500
2501 /* we should have, in features set, a superset of features applicable to the target node.
Radek Krejciba03a5a2020-08-27 14:40:41 +02002502 * If the feature is not present, we don;t have a subset of features applicable
Radek Krejci58d171e2018-11-23 13:50:55 +01002503 * to the leafref itself. */
Radek Krejci58d171e2018-11-23 13:50:55 +01002504 for (iter = target; iter; iter = iter->parent) {
Radek Krejci056d0a82018-12-06 16:57:25 +01002505 if (iter->iffeatures) {
2506 LY_ARRAY_FOR(iter->iffeatures, u) {
2507 LY_ARRAY_FOR(iter->iffeatures[u].features, v) {
Radek Krejciba03a5a2020-08-27 14:40:41 +02002508 if (!ly_set_contains(&features, iter->iffeatures[u].features[v], NULL)) {
2509 /* feature not present */
Radek Krejci58d171e2018-11-23 13:50:55 +01002510 goto cleanup;
2511 }
2512 }
2513 }
2514 }
2515 }
2516 ret = LY_SUCCESS;
2517
2518cleanup:
2519 ly_set_erase(&features, NULL);
2520 return ret;
2521}
2522
Michal Vasko7f45cf22020-10-01 12:49:44 +02002523static LY_ERR lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags,
Radek Krejci0f969882020-08-21 16:56:47 +02002524 struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p,
Michal Vasko7f45cf22020-10-01 12:49:44 +02002525 struct lysc_type **type, const char **units, struct lysp_qname **dflt);
Radek Krejcia3045382018-11-22 14:30:31 +01002526
Radek Krejcia3045382018-11-22 14:30:31 +01002527/**
2528 * @brief The core of the lys_compile_type() - compile information about the given type (from typedef or leaf/leaf-list).
2529 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02002530 * @param[in] context_pnode Schema node where the type/typedef is placed to correctly find the base types.
Radek Krejcicdfecd92018-11-26 11:27:32 +01002531 * @param[in] context_flags Flags of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
2532 * @param[in] context_mod Module of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
2533 * @param[in] context_name Name of the context node or referencing typedef for logging.
Radek Krejcia3045382018-11-22 14:30:31 +01002534 * @param[in] type_p Parsed type to compile.
Radek Krejci0a33b042020-05-27 10:05:06 +02002535 * @param[in] module Context module for the leafref path and identityref (to correctly resolve prefixes)
Radek Krejcia3045382018-11-22 14:30:31 +01002536 * @param[in] basetype Base YANG built-in type of the type to compile.
Radek Krejcia3045382018-11-22 14:30:31 +01002537 * @param[in] tpdfname Name of the type's typedef, serves as a flag - if it is leaf/leaf-list's type, it is NULL.
2538 * @param[in] base The latest base (compiled) type from which the current type is being derived.
2539 * @param[out] type Newly created type structure with the filled information about the type.
2540 * @return LY_ERR value.
2541 */
Radek Krejci19a96102018-11-15 13:38:09 +01002542static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02002543lys_compile_type_(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags,
Michal Vasko1734be92020-09-22 08:55:10 +02002544 struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p, struct lys_module *module,
2545 LY_DATA_TYPE basetype, const char *tpdfname, struct lysc_type *base, struct lysc_type **type)
Radek Krejcic5c27e52018-11-15 14:38:11 +01002546{
2547 LY_ERR ret = LY_SUCCESS;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002548 struct lysc_type_bin *bin;
2549 struct lysc_type_num *num;
2550 struct lysc_type_str *str;
2551 struct lysc_type_bits *bits;
2552 struct lysc_type_enum *enumeration;
Radek Krejci6cba4292018-11-15 17:33:29 +01002553 struct lysc_type_dec *dec;
Radek Krejci555cb5b2018-11-16 14:54:33 +01002554 struct lysc_type_identityref *idref;
Michal Vasko004d3152020-06-11 19:59:22 +02002555 struct lysc_type_leafref *lref;
Radek Krejcicdfecd92018-11-26 11:27:32 +01002556 struct lysc_type_union *un, *un_aux;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002557
2558 switch (basetype) {
2559 case LY_TYPE_BINARY:
Michal Vasko22df3f02020-08-24 13:29:22 +02002560 bin = (struct lysc_type_bin *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002561
2562 /* RFC 7950 9.8.1, 9.4.4 - length, number of octets it contains */
Radek Krejcic5c27e52018-11-15 14:38:11 +01002563 if (type_p->length) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002564 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->length, basetype, 1, 0,
Michal Vasko22df3f02020-08-24 13:29:22 +02002565 base ? ((struct lysc_type_bin *)base)->length : NULL, &bin->length));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002566 if (!tpdfname) {
Michal Vasko1734be92020-09-22 08:55:10 +02002567 COMPILE_EXTS_GOTO(ctx, type_p->length->exts, bin->length->exts, bin->length, LYEXT_PAR_LENGTH, ret, cleanup);
Radek Krejcic5c27e52018-11-15 14:38:11 +01002568 }
2569 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002570 break;
2571 case LY_TYPE_BITS:
2572 /* RFC 7950 9.7 - bits */
Michal Vasko22df3f02020-08-24 13:29:22 +02002573 bits = (struct lysc_type_bits *)(*type);
Radek Krejcic5c27e52018-11-15 14:38:11 +01002574 if (type_p->bits) {
Radek Krejciec4da802019-05-02 13:02:41 +02002575 LY_CHECK_RET(lys_compile_type_enums(ctx, type_p->bits, basetype,
Michal Vasko22df3f02020-08-24 13:29:22 +02002576 base ? (struct lysc_type_bitenum_item *)((struct lysc_type_bits *)base)->bits : NULL,
2577 (struct lysc_type_bitenum_item **)&bits->bits));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002578 }
2579
Radek Krejci555cb5b2018-11-16 14:54:33 +01002580 if (!base && !type_p->flags) {
Radek Krejcic5c27e52018-11-15 14:38:11 +01002581 /* type derived from bits built-in type must contain at least one bit */
Radek Krejci6cba4292018-11-15 17:33:29 +01002582 if (tpdfname) {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002583 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "bit", "bits type ", tpdfname);
Radek Krejci6cba4292018-11-15 17:33:29 +01002584 } else {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002585 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "bit", "bits type", "");
Radek Krejcic5c27e52018-11-15 14:38:11 +01002586 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002587 return LY_EVALID;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002588 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002589 break;
Radek Krejci6cba4292018-11-15 17:33:29 +01002590 case LY_TYPE_DEC64:
Radek Krejci115a74d2020-08-14 22:18:12 +02002591 dec = (struct lysc_type_dec *)(*type);
Radek Krejci6cba4292018-11-15 17:33:29 +01002592
2593 /* RFC 7950 9.3.4 - fraction-digits */
Radek Krejci555cb5b2018-11-16 14:54:33 +01002594 if (!base) {
Radek Krejci643c8242018-11-15 17:51:11 +01002595 if (!type_p->fraction_digits) {
2596 if (tpdfname) {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002597 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "fraction-digits", "decimal64 type ", tpdfname);
Radek Krejci643c8242018-11-15 17:51:11 +01002598 } else {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002599 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "fraction-digits", "decimal64 type", "");
Radek Krejci643c8242018-11-15 17:51:11 +01002600 }
2601 return LY_EVALID;
2602 }
Radek Krejci115a74d2020-08-14 22:18:12 +02002603 dec->fraction_digits = type_p->fraction_digits;
2604 } else {
2605 if (type_p->fraction_digits) {
2606 /* fraction digits is prohibited in types not directly derived from built-in decimal64 */
2607 if (tpdfname) {
2608 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
2609 "Invalid fraction-digits substatement for type \"%s\" not directly derived from decimal64 built-in type.",
2610 tpdfname);
2611 } else {
2612 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
2613 "Invalid fraction-digits substatement for type not directly derived from decimal64 built-in type.");
Radek Krejci115a74d2020-08-14 22:18:12 +02002614 }
2615 return LY_EVALID;
Radek Krejci6cba4292018-11-15 17:33:29 +01002616 }
Radek Krejci115a74d2020-08-14 22:18:12 +02002617 dec->fraction_digits = ((struct lysc_type_dec *)base)->fraction_digits;
Radek Krejci6cba4292018-11-15 17:33:29 +01002618 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002619
2620 /* RFC 7950 9.2.4 - range */
2621 if (type_p->range) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002622 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->range, basetype, 0, dec->fraction_digits,
Radek Krejci115a74d2020-08-14 22:18:12 +02002623 base ? ((struct lysc_type_dec *)base)->range : NULL, &dec->range));
Radek Krejci6cba4292018-11-15 17:33:29 +01002624 if (!tpdfname) {
Michal Vasko1734be92020-09-22 08:55:10 +02002625 COMPILE_EXTS_GOTO(ctx, type_p->range->exts, dec->range->exts, dec->range, LYEXT_PAR_RANGE, ret, cleanup);
Radek Krejci6cba4292018-11-15 17:33:29 +01002626 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002627 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002628 break;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002629 case LY_TYPE_STRING:
Michal Vasko22df3f02020-08-24 13:29:22 +02002630 str = (struct lysc_type_str *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002631
2632 /* RFC 7950 9.4.4 - length */
Radek Krejcic5c27e52018-11-15 14:38:11 +01002633 if (type_p->length) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002634 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->length, basetype, 1, 0,
Michal Vasko22df3f02020-08-24 13:29:22 +02002635 base ? ((struct lysc_type_str *)base)->length : NULL, &str->length));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002636 if (!tpdfname) {
Michal Vasko1734be92020-09-22 08:55:10 +02002637 COMPILE_EXTS_GOTO(ctx, type_p->length->exts, str->length->exts, str->length, LYEXT_PAR_LENGTH, ret, cleanup);
Radek Krejcic5c27e52018-11-15 14:38:11 +01002638 }
Michal Vasko22df3f02020-08-24 13:29:22 +02002639 } else if (base && ((struct lysc_type_str *)base)->length) {
2640 str->length = lysc_range_dup(ctx->ctx, ((struct lysc_type_str *)base)->length);
Radek Krejcic5c27e52018-11-15 14:38:11 +01002641 }
2642
2643 /* RFC 7950 9.4.5 - pattern */
2644 if (type_p->patterns) {
Radek Krejciec4da802019-05-02 13:02:41 +02002645 LY_CHECK_RET(lys_compile_type_patterns(ctx, type_p->patterns,
Michal Vasko22df3f02020-08-24 13:29:22 +02002646 base ? ((struct lysc_type_str *)base)->patterns : NULL, &str->patterns));
2647 } else if (base && ((struct lysc_type_str *)base)->patterns) {
2648 str->patterns = lysc_patterns_dup(ctx->ctx, ((struct lysc_type_str *)base)->patterns);
Radek Krejcic5c27e52018-11-15 14:38:11 +01002649 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002650 break;
2651 case LY_TYPE_ENUM:
Michal Vasko22df3f02020-08-24 13:29:22 +02002652 enumeration = (struct lysc_type_enum *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002653
2654 /* RFC 7950 9.6 - enum */
Radek Krejcic5c27e52018-11-15 14:38:11 +01002655 if (type_p->enums) {
Radek Krejciec4da802019-05-02 13:02:41 +02002656 LY_CHECK_RET(lys_compile_type_enums(ctx, type_p->enums, basetype,
Michal Vasko22df3f02020-08-24 13:29:22 +02002657 base ? ((struct lysc_type_enum *)base)->enums : NULL, &enumeration->enums));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002658 }
2659
Radek Krejci555cb5b2018-11-16 14:54:33 +01002660 if (!base && !type_p->flags) {
Radek Krejcic5c27e52018-11-15 14:38:11 +01002661 /* type derived from enumerations built-in type must contain at least one enum */
Radek Krejci6cba4292018-11-15 17:33:29 +01002662 if (tpdfname) {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002663 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "enum", "enumeration type ", tpdfname);
Radek Krejci6cba4292018-11-15 17:33:29 +01002664 } else {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002665 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "enum", "enumeration type", "");
Radek Krejcic5c27e52018-11-15 14:38:11 +01002666 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002667 return LY_EVALID;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002668 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002669 break;
2670 case LY_TYPE_INT8:
2671 case LY_TYPE_UINT8:
2672 case LY_TYPE_INT16:
2673 case LY_TYPE_UINT16:
2674 case LY_TYPE_INT32:
2675 case LY_TYPE_UINT32:
2676 case LY_TYPE_INT64:
2677 case LY_TYPE_UINT64:
Michal Vasko22df3f02020-08-24 13:29:22 +02002678 num = (struct lysc_type_num *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002679
2680 /* RFC 6020 9.2.4 - range */
Radek Krejcic5c27e52018-11-15 14:38:11 +01002681 if (type_p->range) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002682 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->range, basetype, 0, 0,
Michal Vasko22df3f02020-08-24 13:29:22 +02002683 base ? ((struct lysc_type_num *)base)->range : NULL, &num->range));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002684 if (!tpdfname) {
Michal Vasko1734be92020-09-22 08:55:10 +02002685 COMPILE_EXTS_GOTO(ctx, type_p->range->exts, num->range->exts, num->range, LYEXT_PAR_RANGE, ret, cleanup);
Radek Krejcic5c27e52018-11-15 14:38:11 +01002686 }
2687 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002688 break;
Radek Krejci555cb5b2018-11-16 14:54:33 +01002689 case LY_TYPE_IDENT:
Michal Vasko22df3f02020-08-24 13:29:22 +02002690 idref = (struct lysc_type_identityref *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002691
2692 /* RFC 7950 9.10.2 - base */
2693 if (type_p->bases) {
2694 if (base) {
2695 /* only the directly derived identityrefs can contain base specification */
2696 if (tpdfname) {
2697 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcicdfecd92018-11-26 11:27:32 +01002698 "Invalid base substatement for the type \"%s\" not directly derived from identityref built-in type.",
Radek Krejci555cb5b2018-11-16 14:54:33 +01002699 tpdfname);
2700 } else {
2701 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcicdfecd92018-11-26 11:27:32 +01002702 "Invalid base substatement for the type not directly derived from identityref built-in type.");
Radek Krejci555cb5b2018-11-16 14:54:33 +01002703 }
2704 return LY_EVALID;
2705 }
Radek Krejci0a33b042020-05-27 10:05:06 +02002706 LY_CHECK_RET(lys_compile_identity_bases(ctx, module, type_p->bases, NULL, &idref->bases));
Radek Krejci555cb5b2018-11-16 14:54:33 +01002707 }
2708
2709 if (!base && !type_p->flags) {
2710 /* type derived from identityref built-in type must contain at least one base */
2711 if (tpdfname) {
2712 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "base", "identityref type ", tpdfname);
2713 } else {
2714 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "base", "identityref type", "");
Radek Krejci555cb5b2018-11-16 14:54:33 +01002715 }
2716 return LY_EVALID;
2717 }
Radek Krejci555cb5b2018-11-16 14:54:33 +01002718 break;
Radek Krejcia3045382018-11-22 14:30:31 +01002719 case LY_TYPE_LEAFREF:
Michal Vasko22df3f02020-08-24 13:29:22 +02002720 lref = (struct lysc_type_leafref *)*type;
Michal Vasko004d3152020-06-11 19:59:22 +02002721
Radek Krejcia3045382018-11-22 14:30:31 +01002722 /* RFC 7950 9.9.3 - require-instance */
2723 if (type_p->flags & LYS_SET_REQINST) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +01002724 if (context_mod->mod->version < LYS_VERSION_1_1) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01002725 if (tpdfname) {
2726 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
2727 "Leafref type \"%s\" can be restricted by require-instance statement only in YANG 1.1 modules.", tpdfname);
2728 } else {
2729 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
2730 "Leafref type can be restricted by require-instance statement only in YANG 1.1 modules.");
Radek Krejci9bb94eb2018-12-04 16:48:35 +01002731 }
2732 return LY_EVALID;
2733 }
Michal Vasko004d3152020-06-11 19:59:22 +02002734 lref->require_instance = type_p->require_instance;
Radek Krejci412ddfa2018-11-23 11:44:11 +01002735 } else if (base) {
2736 /* inherit */
Michal Vasko004d3152020-06-11 19:59:22 +02002737 lref->require_instance = ((struct lysc_type_leafref *)base)->require_instance;
Radek Krejcia3045382018-11-22 14:30:31 +01002738 } else {
2739 /* default is true */
Michal Vasko004d3152020-06-11 19:59:22 +02002740 lref->require_instance = 1;
Radek Krejcia3045382018-11-22 14:30:31 +01002741 }
2742 if (type_p->path) {
Michal Vasko1734be92020-09-22 08:55:10 +02002743 LY_CHECK_RET(lyxp_expr_dup(ctx->ctx, type_p->path, &lref->path));
Michal Vasko004d3152020-06-11 19:59:22 +02002744 lref->path_context = module;
Radek Krejcia3045382018-11-22 14:30:31 +01002745 } else if (base) {
Michal Vasko1734be92020-09-22 08:55:10 +02002746 LY_CHECK_RET(lyxp_expr_dup(ctx->ctx, ((struct lysc_type_leafref *)base)->path, &lref->path));
Michal Vasko22df3f02020-08-24 13:29:22 +02002747 lref->path_context = ((struct lysc_type_leafref *)base)->path_context;
Radek Krejcia3045382018-11-22 14:30:31 +01002748 } else if (tpdfname) {
2749 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "path", "leafref type ", tpdfname);
2750 return LY_EVALID;
2751 } else {
2752 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "path", "leafref type", "");
Radek Krejcia3045382018-11-22 14:30:31 +01002753 return LY_EVALID;
2754 }
Radek Krejcia3045382018-11-22 14:30:31 +01002755 break;
Radek Krejci16c0f822018-11-16 10:46:10 +01002756 case LY_TYPE_INST:
2757 /* RFC 7950 9.9.3 - require-instance */
2758 if (type_p->flags & LYS_SET_REQINST) {
Michal Vasko22df3f02020-08-24 13:29:22 +02002759 ((struct lysc_type_instanceid *)(*type))->require_instance = type_p->require_instance;
Radek Krejci16c0f822018-11-16 10:46:10 +01002760 } else {
2761 /* default is true */
Michal Vasko22df3f02020-08-24 13:29:22 +02002762 ((struct lysc_type_instanceid *)(*type))->require_instance = 1;
Radek Krejci16c0f822018-11-16 10:46:10 +01002763 }
Radek Krejci16c0f822018-11-16 10:46:10 +01002764 break;
Radek Krejcicdfecd92018-11-26 11:27:32 +01002765 case LY_TYPE_UNION:
Michal Vasko22df3f02020-08-24 13:29:22 +02002766 un = (struct lysc_type_union *)(*type);
Radek Krejcicdfecd92018-11-26 11:27:32 +01002767
2768 /* RFC 7950 7.4 - type */
2769 if (type_p->types) {
2770 if (base) {
2771 /* only the directly derived union can contain types specification */
2772 if (tpdfname) {
2773 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
2774 "Invalid type substatement for the type \"%s\" not directly derived from union built-in type.",
2775 tpdfname);
2776 } else {
2777 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
2778 "Invalid type substatement for the type not directly derived from union built-in type.");
Radek Krejcicdfecd92018-11-26 11:27:32 +01002779 }
2780 return LY_EVALID;
2781 }
2782 /* compile the type */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002783 LY_ARRAY_CREATE_RET(ctx->ctx, un->types, LY_ARRAY_COUNT(type_p->types), LY_EVALID);
2784 for (LY_ARRAY_COUNT_TYPE u = 0, additional = 0; u < LY_ARRAY_COUNT(type_p->types); ++u) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02002785 LY_CHECK_RET(lys_compile_type(ctx, context_pnode, context_flags, context_mod, context_name,
2786 &type_p->types[u], &un->types[u + additional], NULL, NULL));
Radek Krejcicdfecd92018-11-26 11:27:32 +01002787 if (un->types[u + additional]->basetype == LY_TYPE_UNION) {
2788 /* add space for additional types from the union subtype */
2789 un_aux = (struct lysc_type_union *)un->types[u + additional];
Michal Vasko22df3f02020-08-24 13:29:22 +02002790 LY_ARRAY_RESIZE_ERR_RET(ctx->ctx, un->types, (*((uint64_t *)(type_p->types) - 1)) + additional + LY_ARRAY_COUNT(un_aux->types) - 1,
2791 lysc_type_free(ctx->ctx, (struct lysc_type *)un_aux), LY_EMEM);
Radek Krejcicdfecd92018-11-26 11:27:32 +01002792
2793 /* copy subtypes of the subtype union */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002794 for (LY_ARRAY_COUNT_TYPE v = 0; v < LY_ARRAY_COUNT(un_aux->types); ++v) {
Radek Krejcicdfecd92018-11-26 11:27:32 +01002795 if (un_aux->types[v]->basetype == LY_TYPE_LEAFREF) {
2796 /* duplicate the whole structure because of the instance-specific path resolving for realtype */
2797 un->types[u + additional] = calloc(1, sizeof(struct lysc_type_leafref));
Michal Vasko22df3f02020-08-24 13:29:22 +02002798 LY_CHECK_ERR_RET(!un->types[u + additional], LOGMEM(ctx->ctx); lysc_type_free(ctx->ctx, (struct lysc_type *)un_aux), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02002799 lref = (struct lysc_type_leafref *)un->types[u + additional];
2800
2801 lref->basetype = LY_TYPE_LEAFREF;
Michal Vasko1734be92020-09-22 08:55:10 +02002802 LY_CHECK_RET(lyxp_expr_dup(ctx->ctx, ((struct lysc_type_leafref *)un_aux->types[v])->path, &lref->path));
Michal Vasko004d3152020-06-11 19:59:22 +02002803 lref->refcount = 1;
Michal Vasko22df3f02020-08-24 13:29:22 +02002804 lref->require_instance = ((struct lysc_type_leafref *)un_aux->types[v])->require_instance;
2805 lref->path_context = ((struct lysc_type_leafref *)un_aux->types[v])->path_context;
Radek Krejcicdfecd92018-11-26 11:27:32 +01002806 /* TODO extensions */
2807
2808 } else {
2809 un->types[u + additional] = un_aux->types[v];
2810 ++un_aux->types[v]->refcount;
2811 }
2812 ++additional;
2813 LY_ARRAY_INCREMENT(un->types);
2814 }
2815 /* compensate u increment in main loop */
2816 --additional;
2817
2818 /* free the replaced union subtype */
Michal Vasko22df3f02020-08-24 13:29:22 +02002819 lysc_type_free(ctx->ctx, (struct lysc_type *)un_aux);
Radek Krejcicdfecd92018-11-26 11:27:32 +01002820 } else {
2821 LY_ARRAY_INCREMENT(un->types);
2822 }
Radek Krejcicdfecd92018-11-26 11:27:32 +01002823 }
2824 }
2825
2826 if (!base && !type_p->flags) {
2827 /* type derived from union built-in type must contain at least one type */
2828 if (tpdfname) {
2829 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "type", "union type ", tpdfname);
2830 } else {
2831 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "type", "union type", "");
Radek Krejcicdfecd92018-11-26 11:27:32 +01002832 }
2833 return LY_EVALID;
2834 }
Radek Krejcicdfecd92018-11-26 11:27:32 +01002835 break;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002836 case LY_TYPE_BOOL:
2837 case LY_TYPE_EMPTY:
2838 case LY_TYPE_UNKNOWN: /* just to complete switch */
2839 break;
2840 }
Michal Vasko1734be92020-09-22 08:55:10 +02002841
2842 if (tpdfname) {
2843 switch (basetype) {
2844 case LY_TYPE_BINARY:
2845 type_p->compiled = *type;
2846 *type = calloc(1, sizeof(struct lysc_type_bin));
2847 break;
2848 case LY_TYPE_BITS:
2849 type_p->compiled = *type;
2850 *type = calloc(1, sizeof(struct lysc_type_bits));
2851 break;
2852 case LY_TYPE_DEC64:
2853 type_p->compiled = *type;
2854 *type = calloc(1, sizeof(struct lysc_type_dec));
2855 break;
2856 case LY_TYPE_STRING:
2857 type_p->compiled = *type;
2858 *type = calloc(1, sizeof(struct lysc_type_str));
2859 break;
2860 case LY_TYPE_ENUM:
2861 type_p->compiled = *type;
2862 *type = calloc(1, sizeof(struct lysc_type_enum));
2863 break;
2864 case LY_TYPE_INT8:
2865 case LY_TYPE_UINT8:
2866 case LY_TYPE_INT16:
2867 case LY_TYPE_UINT16:
2868 case LY_TYPE_INT32:
2869 case LY_TYPE_UINT32:
2870 case LY_TYPE_INT64:
2871 case LY_TYPE_UINT64:
2872 type_p->compiled = *type;
2873 *type = calloc(1, sizeof(struct lysc_type_num));
2874 break;
2875 case LY_TYPE_IDENT:
2876 type_p->compiled = *type;
2877 *type = calloc(1, sizeof(struct lysc_type_identityref));
2878 break;
2879 case LY_TYPE_LEAFREF:
2880 type_p->compiled = *type;
2881 *type = calloc(1, sizeof(struct lysc_type_leafref));
2882 break;
2883 case LY_TYPE_INST:
2884 type_p->compiled = *type;
2885 *type = calloc(1, sizeof(struct lysc_type_instanceid));
2886 break;
2887 case LY_TYPE_UNION:
2888 type_p->compiled = *type;
2889 *type = calloc(1, sizeof(struct lysc_type_union));
2890 break;
2891 case LY_TYPE_BOOL:
2892 case LY_TYPE_EMPTY:
2893 case LY_TYPE_UNKNOWN: /* just to complete switch */
2894 break;
2895 }
2896 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002897 LY_CHECK_ERR_RET(!(*type), LOGMEM(ctx->ctx), LY_EMEM);
Michal Vasko1734be92020-09-22 08:55:10 +02002898
2899cleanup:
Radek Krejcic5c27e52018-11-15 14:38:11 +01002900 return ret;
2901}
2902
Radek Krejcia3045382018-11-22 14:30:31 +01002903/**
2904 * @brief Compile information about the leaf/leaf-list's type.
2905 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02002906 * @param[in] context_pnode Schema node where the type/typedef is placed to correctly find the base types.
Radek Krejcicdfecd92018-11-26 11:27:32 +01002907 * @param[in] context_flags Flags of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
2908 * @param[in] context_mod Module of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
2909 * @param[in] context_name Name of the context node or referencing typedef for logging.
2910 * @param[in] type_p Parsed type to compile.
Radek Krejcia3045382018-11-22 14:30:31 +01002911 * @param[out] type Newly created (or reused with increased refcount) type structure with the filled information about the type.
Radek Krejcicdfecd92018-11-26 11:27:32 +01002912 * @param[out] units Storage for inheriting units value from the typedefs the current type derives from.
Michal Vaskoba99a3e2020-08-18 15:50:05 +02002913 * @param[out] dflt Default value for the type.
Radek Krejcia3045382018-11-22 14:30:31 +01002914 * @return LY_ERR value.
2915 */
Radek Krejcic5c27e52018-11-15 14:38:11 +01002916static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02002917lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags,
Radek Krejci0f969882020-08-21 16:56:47 +02002918 struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p,
Michal Vasko7f45cf22020-10-01 12:49:44 +02002919 struct lysc_type **type, const char **units, struct lysp_qname **dflt)
Radek Krejci19a96102018-11-15 13:38:09 +01002920{
2921 LY_ERR ret = LY_SUCCESS;
Radek Krejci857189e2020-09-01 13:26:36 +02002922 ly_bool dummyloops = 0;
Radek Krejci19a96102018-11-15 13:38:09 +01002923 struct type_context {
2924 const struct lysp_tpdf *tpdf;
2925 struct lysp_node *node;
2926 struct lysp_module *mod;
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002927 } *tctx, *tctx_prev = NULL, *tctx_iter;
Radek Krejci19a96102018-11-15 13:38:09 +01002928 LY_DATA_TYPE basetype = LY_TYPE_UNKNOWN;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002929 struct lysc_type *base = NULL, *prev_type;
Radek Krejci19a96102018-11-15 13:38:09 +01002930 struct ly_set tpdf_chain = {0};
Michal Vaskoba99a3e2020-08-18 15:50:05 +02002931
Radek Krejci19a96102018-11-15 13:38:09 +01002932 (*type) = NULL;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02002933 if (dflt) {
2934 *dflt = NULL;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02002935 }
Radek Krejci19a96102018-11-15 13:38:09 +01002936
2937 tctx = calloc(1, sizeof *tctx);
2938 LY_CHECK_ERR_RET(!tctx, LOGMEM(ctx->ctx), LY_EMEM);
Michal Vasko7f45cf22020-10-01 12:49:44 +02002939 for (ret = lysp_type_find(type_p->name, context_pnode, ctx->mod_def->parsed,
Radek Krejci19a96102018-11-15 13:38:09 +01002940 &basetype, &tctx->tpdf, &tctx->node, &tctx->mod);
2941 ret == LY_SUCCESS;
2942 ret = lysp_type_find(tctx_prev->tpdf->type.name, tctx_prev->node, tctx_prev->mod,
2943 &basetype, &tctx->tpdf, &tctx->node, &tctx->mod)) {
2944 if (basetype) {
2945 break;
2946 }
2947
2948 /* check status */
Radek Krejcicdfecd92018-11-26 11:27:32 +01002949 ret = lysc_check_status(ctx, context_flags, context_mod, context_name,
2950 tctx->tpdf->flags, tctx->mod, tctx->node ? tctx->node->name : tctx->tpdf->name);
Radek Krejci87e25252020-09-15 13:28:31 +02002951 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01002952
Radek Krejcicdfecd92018-11-26 11:27:32 +01002953 if (units && !*units) {
2954 /* inherit units */
Radek Krejci87e25252020-09-15 13:28:31 +02002955 DUP_STRING(ctx->ctx, tctx->tpdf->units, *units, ret);
2956 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
Radek Krejcicdfecd92018-11-26 11:27:32 +01002957 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02002958 if (dflt && !*dflt && tctx->tpdf->dflt.str) {
Radek Krejcicdfecd92018-11-26 11:27:32 +01002959 /* inherit default */
Michal Vasko7f45cf22020-10-01 12:49:44 +02002960 *dflt = (struct lysp_qname *)&tctx->tpdf->dflt;
Radek Krejcicdfecd92018-11-26 11:27:32 +01002961 }
Michal Vaskoba99a3e2020-08-18 15:50:05 +02002962 if (dummyloops && (!units || *units) && dflt && *dflt) {
Michal Vasko22df3f02020-08-24 13:29:22 +02002963 basetype = ((struct type_context *)tpdf_chain.objs[tpdf_chain.count - 1])->tpdf->type.compiled->basetype;
Radek Krejcicdfecd92018-11-26 11:27:32 +01002964 break;
2965 }
2966
Radek Krejci19a96102018-11-15 13:38:09 +01002967 if (tctx->tpdf->type.compiled) {
Radek Krejcicdfecd92018-11-26 11:27:32 +01002968 /* it is not necessary to continue, the rest of the chain was already compiled,
2969 * but we still may need to inherit default and units values, so start dummy loops */
Radek Krejci19a96102018-11-15 13:38:09 +01002970 basetype = tctx->tpdf->type.compiled->basetype;
Radek Krejciba03a5a2020-08-27 14:40:41 +02002971 ret = ly_set_add(&tpdf_chain, tctx, LY_SET_OPT_USEASLIST, NULL);
Radek Krejci87e25252020-09-15 13:28:31 +02002972 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
Radek Krejciba03a5a2020-08-27 14:40:41 +02002973
Michal Vaskoba99a3e2020-08-18 15:50:05 +02002974 if ((units && !*units) || (dflt && !*dflt)) {
Radek Krejcicdfecd92018-11-26 11:27:32 +01002975 dummyloops = 1;
2976 goto preparenext;
2977 } else {
2978 tctx = NULL;
2979 break;
2980 }
Radek Krejci19a96102018-11-15 13:38:09 +01002981 }
2982
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002983 /* circular typedef reference detection */
Radek Krejci1deb5be2020-08-26 16:43:36 +02002984 for (uint32_t u = 0; u < tpdf_chain.count; u++) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002985 /* local part */
Michal Vasko22df3f02020-08-24 13:29:22 +02002986 tctx_iter = (struct type_context *)tpdf_chain.objs[u];
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002987 if (tctx_iter->mod == tctx->mod && tctx_iter->node == tctx->node && tctx_iter->tpdf == tctx->tpdf) {
2988 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
2989 "Invalid \"%s\" type reference - circular chain of types detected.", tctx->tpdf->name);
2990 free(tctx);
2991 ret = LY_EVALID;
2992 goto cleanup;
2993 }
2994 }
Radek Krejci1deb5be2020-08-26 16:43:36 +02002995 for (uint32_t u = 0; u < ctx->tpdf_chain.count; u++) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002996 /* global part for unions corner case */
Michal Vasko22df3f02020-08-24 13:29:22 +02002997 tctx_iter = (struct type_context *)ctx->tpdf_chain.objs[u];
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002998 if (tctx_iter->mod == tctx->mod && tctx_iter->node == tctx->node && tctx_iter->tpdf == tctx->tpdf) {
2999 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3000 "Invalid \"%s\" type reference - circular chain of types detected.", tctx->tpdf->name);
3001 free(tctx);
3002 ret = LY_EVALID;
3003 goto cleanup;
3004 }
3005 }
3006
Radek Krejci19a96102018-11-15 13:38:09 +01003007 /* store information for the following processing */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003008 ret = ly_set_add(&tpdf_chain, tctx, LY_SET_OPT_USEASLIST, NULL);
Radek Krejci87e25252020-09-15 13:28:31 +02003009 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01003010
Radek Krejcicdfecd92018-11-26 11:27:32 +01003011preparenext:
Radek Krejci19a96102018-11-15 13:38:09 +01003012 /* prepare next loop */
3013 tctx_prev = tctx;
3014 tctx = calloc(1, sizeof *tctx);
3015 LY_CHECK_ERR_RET(!tctx, LOGMEM(ctx->ctx), LY_EMEM);
3016 }
3017 free(tctx);
3018
3019 /* allocate type according to the basetype */
3020 switch (basetype) {
3021 case LY_TYPE_BINARY:
3022 *type = calloc(1, sizeof(struct lysc_type_bin));
Radek Krejci19a96102018-11-15 13:38:09 +01003023 break;
3024 case LY_TYPE_BITS:
3025 *type = calloc(1, sizeof(struct lysc_type_bits));
Radek Krejci19a96102018-11-15 13:38:09 +01003026 break;
3027 case LY_TYPE_BOOL:
3028 case LY_TYPE_EMPTY:
3029 *type = calloc(1, sizeof(struct lysc_type));
3030 break;
3031 case LY_TYPE_DEC64:
3032 *type = calloc(1, sizeof(struct lysc_type_dec));
3033 break;
3034 case LY_TYPE_ENUM:
3035 *type = calloc(1, sizeof(struct lysc_type_enum));
Radek Krejci19a96102018-11-15 13:38:09 +01003036 break;
3037 case LY_TYPE_IDENT:
3038 *type = calloc(1, sizeof(struct lysc_type_identityref));
3039 break;
3040 case LY_TYPE_INST:
3041 *type = calloc(1, sizeof(struct lysc_type_instanceid));
3042 break;
3043 case LY_TYPE_LEAFREF:
3044 *type = calloc(1, sizeof(struct lysc_type_leafref));
3045 break;
3046 case LY_TYPE_STRING:
3047 *type = calloc(1, sizeof(struct lysc_type_str));
Radek Krejci19a96102018-11-15 13:38:09 +01003048 break;
3049 case LY_TYPE_UNION:
3050 *type = calloc(1, sizeof(struct lysc_type_union));
3051 break;
3052 case LY_TYPE_INT8:
3053 case LY_TYPE_UINT8:
3054 case LY_TYPE_INT16:
3055 case LY_TYPE_UINT16:
3056 case LY_TYPE_INT32:
3057 case LY_TYPE_UINT32:
3058 case LY_TYPE_INT64:
3059 case LY_TYPE_UINT64:
3060 *type = calloc(1, sizeof(struct lysc_type_num));
Radek Krejci19a96102018-11-15 13:38:09 +01003061 break;
3062 case LY_TYPE_UNKNOWN:
3063 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3064 "Referenced type \"%s\" not found.", tctx_prev ? tctx_prev->tpdf->type.name : type_p->name);
3065 ret = LY_EVALID;
3066 goto cleanup;
3067 }
3068 LY_CHECK_ERR_GOTO(!(*type), LOGMEM(ctx->ctx), cleanup);
Radek Krejcicdfecd92018-11-26 11:27:32 +01003069 if (~type_substmt_map[basetype] & type_p->flags) {
Radek Krejci19a96102018-11-15 13:38:09 +01003070 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid type restrictions for %s type.",
3071 ly_data_type2str[basetype]);
3072 free(*type);
3073 (*type) = NULL;
3074 ret = LY_EVALID;
3075 goto cleanup;
3076 }
3077
3078 /* get restrictions from the referred typedefs */
Radek Krejci1deb5be2020-08-26 16:43:36 +02003079 for (uint32_t u = tpdf_chain.count - 1; u + 1 > 0; --u) {
Michal Vasko22df3f02020-08-24 13:29:22 +02003080 tctx = (struct type_context *)tpdf_chain.objs[u];
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003081
3082 /* remember the typedef context for circular check */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003083 ret = ly_set_add(&ctx->tpdf_chain, tctx, LY_SET_OPT_USEASLIST, NULL);
3084 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003085
Radek Krejci43699232018-11-23 14:59:46 +01003086 if (tctx->tpdf->type.compiled) {
Radek Krejci19a96102018-11-15 13:38:09 +01003087 base = tctx->tpdf->type.compiled;
3088 continue;
Radek Krejci43699232018-11-23 14:59:46 +01003089 } else if (basetype != LY_TYPE_LEAFREF && (u != tpdf_chain.count - 1) && !(tctx->tpdf->type.flags)) {
Radek Krejci19a96102018-11-15 13:38:09 +01003090 /* no change, just use the type information from the base */
Michal Vasko22df3f02020-08-24 13:29:22 +02003091 base = ((struct lysp_tpdf *)tctx->tpdf)->type.compiled = ((struct type_context *)tpdf_chain.objs[u + 1])->tpdf->type.compiled;
Radek Krejci19a96102018-11-15 13:38:09 +01003092 ++base->refcount;
3093 continue;
3094 }
3095
3096 ++(*type)->refcount;
Radek Krejci43699232018-11-23 14:59:46 +01003097 if (~type_substmt_map[basetype] & tctx->tpdf->type.flags) {
3098 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid type \"%s\" restriction(s) for %s type.",
3099 tctx->tpdf->name, ly_data_type2str[basetype]);
3100 ret = LY_EVALID;
3101 goto cleanup;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003102 } else if (basetype == LY_TYPE_EMPTY && tctx->tpdf->dflt.str) {
Radek Krejci43699232018-11-23 14:59:46 +01003103 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
3104 "Invalid type \"%s\" - \"empty\" type must not have a default value (%s).",
Michal Vasko7f45cf22020-10-01 12:49:44 +02003105 tctx->tpdf->name, tctx->tpdf->dflt.str);
Radek Krejci43699232018-11-23 14:59:46 +01003106 ret = LY_EVALID;
3107 goto cleanup;
3108 }
3109
Radek Krejci19a96102018-11-15 13:38:09 +01003110 (*type)->basetype = basetype;
Radek Krejcie7b95092019-05-15 11:03:07 +02003111 /* TODO user type plugins */
3112 (*type)->plugin = &ly_builtin_type_plugins[basetype];
Radek Krejcic5c27e52018-11-15 14:38:11 +01003113 prev_type = *type;
Michal Vasko22df3f02020-08-24 13:29:22 +02003114 ret = lys_compile_type_(ctx, tctx->node, tctx->tpdf->flags, tctx->mod, tctx->tpdf->name, &((struct lysp_tpdf *)tctx->tpdf)->type,
Radek Krejci96a0bfd2018-11-22 15:25:06 +01003115 basetype & (LY_TYPE_LEAFREF | LY_TYPE_UNION) ? lysp_find_module(ctx->ctx, tctx->mod) : NULL,
Radek Krejciec4da802019-05-02 13:02:41 +02003116 basetype, tctx->tpdf->name, base, type);
Radek Krejcic5c27e52018-11-15 14:38:11 +01003117 LY_CHECK_GOTO(ret, cleanup);
3118 base = prev_type;
Radek Krejci19a96102018-11-15 13:38:09 +01003119 }
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003120 /* remove the processed typedef contexts from the stack for circular check */
3121 ctx->tpdf_chain.count = ctx->tpdf_chain.count - tpdf_chain.count;
Radek Krejci19a96102018-11-15 13:38:09 +01003122
Radek Krejcic5c27e52018-11-15 14:38:11 +01003123 /* process the type definition in leaf */
Radek Krejcicdfecd92018-11-26 11:27:32 +01003124 if (type_p->flags || !base || basetype == LY_TYPE_LEAFREF) {
Radek Krejcia3045382018-11-22 14:30:31 +01003125 /* get restrictions from the node itself */
Radek Krejci19a96102018-11-15 13:38:09 +01003126 (*type)->basetype = basetype;
Radek Krejcie7b95092019-05-15 11:03:07 +02003127 /* TODO user type plugins */
3128 (*type)->plugin = &ly_builtin_type_plugins[basetype];
Radek Krejci19a96102018-11-15 13:38:09 +01003129 ++(*type)->refcount;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003130 ret = lys_compile_type_(ctx, context_pnode, context_flags, context_mod, context_name, type_p, ctx->mod_def, basetype, NULL, base, type);
Radek Krejcic5c27e52018-11-15 14:38:11 +01003131 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci90b148f2020-05-06 17:49:40 +02003132 } else if (basetype != LY_TYPE_BOOL && basetype != LY_TYPE_EMPTY) {
Radek Krejci19a96102018-11-15 13:38:09 +01003133 /* no specific restriction in leaf's type definition, copy from the base */
3134 free(*type);
3135 (*type) = base;
3136 ++(*type)->refcount;
Radek Krejci19a96102018-11-15 13:38:09 +01003137 }
3138
Radek Krejci0935f412019-08-20 16:15:18 +02003139 COMPILE_EXTS_GOTO(ctx, type_p->exts, (*type)->exts, (*type), LYEXT_PAR_TYPE, ret, cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01003140
3141cleanup:
3142 ly_set_erase(&tpdf_chain, free);
3143 return ret;
3144}
3145
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003146/**
3147 * @brief Compile status information of the given node.
3148 *
3149 * To simplify getting status of the node, the flags are set following inheritance rules, so all the nodes
3150 * has the status correctly set during the compilation.
3151 *
3152 * @param[in] ctx Compile context
3153 * @param[in,out] node_flags Flags of the compiled node which status is supposed to be resolved.
3154 * If the status was set explicitly on the node, it is already set in the flags value and we just check
3155 * the compatibility with the parent's status value.
3156 * @param[in] parent_flags Flags of the parent node to check/inherit the status value.
3157 * @return LY_ERR value.
3158 */
3159static LY_ERR
3160lys_compile_status(struct lysc_ctx *ctx, uint16_t *node_flags, uint16_t parent_flags)
3161{
3162 /* status - it is not inherited by specification, but it does not make sense to have
3163 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
3164 if (!((*node_flags) & LYS_STATUS_MASK)) {
3165 if (parent_flags & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) {
3166 if ((parent_flags & 0x3) != 0x3) {
3167 /* do not print the warning when inheriting status from uses - the uses_status value has a special
3168 * combination of bits (0x3) which marks the uses_status value */
3169 LOGWRN(ctx->ctx, "Missing explicit \"%s\" status that was already specified in parent, inheriting.",
Radek Krejci0f969882020-08-21 16:56:47 +02003170 (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003171 }
3172 (*node_flags) |= parent_flags & LYS_STATUS_MASK;
3173 } else {
3174 (*node_flags) |= LYS_STATUS_CURR;
3175 }
3176 } else if (parent_flags & LYS_STATUS_MASK) {
3177 /* check status compatibility with the parent */
3178 if ((parent_flags & LYS_STATUS_MASK) > ((*node_flags) & LYS_STATUS_MASK)) {
3179 if ((*node_flags) & LYS_STATUS_CURR) {
3180 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
3181 "A \"current\" status is in conflict with the parent's \"%s\" status.",
Radek Krejci0f969882020-08-21 16:56:47 +02003182 (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003183 } else { /* LYS_STATUS_DEPRC */
3184 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
3185 "A \"deprecated\" status is in conflict with the parent's \"obsolete\" status.");
3186 }
3187 return LY_EVALID;
3188 }
3189 }
3190 return LY_SUCCESS;
3191}
3192
Radek Krejci8cce8532019-03-05 11:27:45 +01003193/**
3194 * @brief Check uniqness of the node/action/notification name.
3195 *
3196 * Data nodes, actions/RPCs and Notifications are stored separately (in distinguish lists) in the schema
3197 * structures, but they share the namespace so we need to check their name collisions.
3198 *
3199 * @param[in] ctx Compile context.
Michal Vasko20424b42020-08-31 12:29:38 +02003200 * @param[in] parent Parent of the nodes to check, can be NULL.
Radek Krejci8cce8532019-03-05 11:27:45 +01003201 * @param[in] name Name of the item to find in the given lists.
Michal Vasko20424b42020-08-31 12:29:38 +02003202 * @param[in] exclude Node that was just added that should be excluded from the name checking.
Radek Krejci8cce8532019-03-05 11:27:45 +01003203 * @return LY_SUCCESS in case of unique name, LY_EEXIST otherwise.
3204 */
3205static LY_ERR
Michal Vasko20424b42020-08-31 12:29:38 +02003206lys_compile_node_uniqness(struct lysc_ctx *ctx, const struct lysc_node *parent, const char *name,
3207 const struct lysc_node *exclude)
Radek Krejci8cce8532019-03-05 11:27:45 +01003208{
Michal Vasko20424b42020-08-31 12:29:38 +02003209 const struct lysc_node *iter, *iter2;
3210 const struct lysc_action *actions;
3211 const struct lysc_notif *notifs;
3212 uint32_t getnext_flags;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003213 LY_ARRAY_COUNT_TYPE u;
Radek Krejci8cce8532019-03-05 11:27:45 +01003214
Michal Vasko20424b42020-08-31 12:29:38 +02003215#define CHECK_NODE(iter, exclude, name) (iter != (void *)exclude && (iter)->module == exclude->module && !strcmp(name, (iter)->name))
3216
3217 if (exclude->nodetype == LYS_CASE) {
3218 /* check restricted only to all the cases */
3219 assert(parent->nodetype == LYS_CHOICE);
3220 LY_LIST_FOR(lysc_node_children(parent, 0), iter) {
3221 if (CHECK_NODE(iter, exclude, name)) {
3222 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPIDENT, name, "case");
3223 return LY_EEXIST;
3224 }
3225 }
3226
3227 return LY_SUCCESS;
3228 }
3229
3230 /* no reason for our parent to be choice anymore */
3231 assert(!parent || (parent->nodetype != LYS_CHOICE));
3232
3233 if (parent && (parent->nodetype == LYS_CASE)) {
3234 /* move to the first data definition parent */
3235 parent = lysc_data_parent(parent);
3236 }
3237
3238 getnext_flags = LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE;
3239 if (parent && (parent->nodetype & (LYS_RPC | LYS_ACTION)) && (exclude->flags & LYS_CONFIG_R)) {
3240 getnext_flags |= LYS_GETNEXT_OUTPUT;
3241 }
3242
3243 iter = NULL;
3244 while ((iter = lys_getnext(iter, parent, ctx->mod->compiled, getnext_flags))) {
3245 if (CHECK_NODE(iter, exclude, name)) {
Radek Krejci8cce8532019-03-05 11:27:45 +01003246 goto error;
3247 }
Michal Vasko20424b42020-08-31 12:29:38 +02003248
3249 /* we must compare with both the choice and all its nested data-definiition nodes (but not recursively) */
3250 if (iter->nodetype == LYS_CHOICE) {
3251 iter2 = NULL;
3252 while ((iter2 = lys_getnext(iter2, iter, NULL, LYS_GETNEXT_NOSTATECHECK))) {
3253 if (CHECK_NODE(iter2, exclude, name)) {
3254 goto error;
3255 }
3256 }
3257 }
Radek Krejci8cce8532019-03-05 11:27:45 +01003258 }
Michal Vasko20424b42020-08-31 12:29:38 +02003259
3260 actions = parent ? lysc_node_actions(parent) : ctx->mod->compiled->rpcs;
Radek Krejci8cce8532019-03-05 11:27:45 +01003261 LY_ARRAY_FOR(actions, u) {
Michal Vasko20424b42020-08-31 12:29:38 +02003262 if (CHECK_NODE(&actions[u], exclude, name)) {
Radek Krejci8cce8532019-03-05 11:27:45 +01003263 goto error;
3264 }
3265 }
Michal Vasko20424b42020-08-31 12:29:38 +02003266
3267 notifs = parent ? lysc_node_notifs(parent) : ctx->mod->compiled->notifs;
Radek Krejci8cce8532019-03-05 11:27:45 +01003268 LY_ARRAY_FOR(notifs, u) {
Michal Vasko20424b42020-08-31 12:29:38 +02003269 if (CHECK_NODE(&notifs[u], exclude, name)) {
Radek Krejci8cce8532019-03-05 11:27:45 +01003270 goto error;
3271 }
3272 }
3273 return LY_SUCCESS;
Michal Vasko20424b42020-08-31 12:29:38 +02003274
Radek Krejci8cce8532019-03-05 11:27:45 +01003275error:
Michal Vaskoa3881362020-01-21 15:57:35 +01003276 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPIDENT, name, "data definition/RPC/action/notification");
Radek Krejci8cce8532019-03-05 11:27:45 +01003277 return LY_EEXIST;
Michal Vasko20424b42020-08-31 12:29:38 +02003278
3279#undef CHECK_NODE
Radek Krejci8cce8532019-03-05 11:27:45 +01003280}
3281
Michal Vasko7f45cf22020-10-01 12:49:44 +02003282static LY_ERR lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *parent,
3283 uint16_t uses_status, struct ly_set *child_set);
3284
3285static LY_ERR lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode,
3286 const struct lysc_node *parent, struct lysp_node **dev_pnode, ly_bool *not_supported);
3287
3288static LY_ERR lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node);
3289
3290static void lysp_dev_node_free(const struct ly_ctx *ctx, struct lysp_node *dev_pnode);
Radek Krejci19a96102018-11-15 13:38:09 +01003291
Radek Krejcia3045382018-11-22 14:30:31 +01003292/**
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003293 * @brief Compile parsed RPC/action schema node information.
3294 * @param[in] ctx Compile context
Radek Krejci43981a32019-04-12 09:44:11 +02003295 * @param[in] action_p Parsed RPC/action schema node.
Radek Krejci43981a32019-04-12 09:44:11 +02003296 * @param[in] parent Parent node of the action, NULL in case of RPC (top-level action)
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003297 * @param[in,out] action Prepared (empty) compiled action structure to fill.
3298 * @param[in] uses_status If the RPC/action is being placed instead of uses, here we have the uses's status value (as node's flags).
3299 * Zero means no uses, non-zero value with no status bit set mean the default status.
Michal Vasko7f45cf22020-10-01 12:49:44 +02003300 * @return LY_SUCCESS on success,
3301 * @return LY_EVALID on validation error,
3302 * @return LY_EDENIED on not-supported deviation.
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003303 */
3304static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02003305lys_compile_action(struct lysc_ctx *ctx, struct lysp_action *action_p,
Radek Krejci0f969882020-08-21 16:56:47 +02003306 struct lysc_node *parent, struct lysc_action *action, uint16_t uses_status)
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003307{
3308 LY_ERR ret = LY_SUCCESS;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003309 struct lysp_node *child_p, *dev_pnode = NULL, *dev_input_p = NULL, *dev_output_p = NULL;
3310 struct lysp_action *orig_action_p = action_p;
3311 struct lysp_action_inout *inout_p;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003312 LY_ARRAY_COUNT_TYPE u;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003313 ly_bool not_supported;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003314 uint32_t opt_prev = ctx->options;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003315
Radek Krejci327de162019-06-14 12:52:07 +02003316 lysc_update_path(ctx, parent, action_p->name);
3317
Michal Vasko7f45cf22020-10-01 12:49:44 +02003318 /* apply deviation on the action/RPC */
3319 LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)action_p, parent, &dev_pnode, &not_supported));
3320 if (not_supported) {
3321 lysc_update_path(ctx, NULL, NULL);
3322 return LY_EDENIED;
3323 } else if (dev_pnode) {
3324 action_p = (struct lysp_action *)dev_pnode;
3325 }
3326
Michal Vasko20424b42020-08-31 12:29:38 +02003327 /* member needed for uniqueness check lys_getnext() */
3328 action->nodetype = parent ? LYS_ACTION : LYS_RPC;
3329 action->module = ctx->mod;
3330 action->parent = parent;
3331
3332 LY_CHECK_RET(lys_compile_node_uniqness(ctx, parent, action_p->name, (struct lysc_node *)action));
Radek Krejci8cce8532019-03-05 11:27:45 +01003333
Radek Krejciec4da802019-05-02 13:02:41 +02003334 if (ctx->options & (LYSC_OPT_RPC_MASK | LYSC_OPT_NOTIFICATION)) {
Radek Krejci05b774b2019-02-25 13:26:18 +01003335 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Radek Krejcifc11bd72019-04-11 16:00:05 +02003336 "Action \"%s\" is placed inside %s.", action_p->name,
Michal Vaskoa3881362020-01-21 15:57:35 +01003337 ctx->options & LYSC_OPT_RPC_MASK ? "another RPC/action" : "notification");
Radek Krejci05b774b2019-02-25 13:26:18 +01003338 return LY_EVALID;
3339 }
3340
Radek Krejciec4da802019-05-02 13:02:41 +02003341 if (!(ctx->options & LYSC_OPT_FREE_SP)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003342 action->sp = orig_action_p;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003343 }
3344 action->flags = action_p->flags & LYS_FLAGS_COMPILED_MASK;
3345
3346 /* status - it is not inherited by specification, but it does not make sense to have
3347 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
Michal Vaskocc048b22020-03-27 15:52:38 +01003348 LY_CHECK_RET(lys_compile_status(ctx, &action->flags, uses_status ? uses_status : (parent ? parent->flags : 0)));
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003349
Radek Krejci011e4aa2020-09-04 15:22:31 +02003350 DUP_STRING_GOTO(ctx->ctx, action_p->name, action->name, ret, cleanup);
3351 DUP_STRING_GOTO(ctx->ctx, action_p->dsc, action->dsc, ret, cleanup);
3352 DUP_STRING_GOTO(ctx->ctx, action_p->ref, action->ref, ret, cleanup);
Radek Krejciec4da802019-05-02 13:02:41 +02003353 COMPILE_ARRAY_GOTO(ctx, action_p->iffeatures, action->iffeatures, u, lys_compile_iffeature, ret, cleanup);
Radek Krejci0935f412019-08-20 16:15:18 +02003354 COMPILE_EXTS_GOTO(ctx, action_p->exts, action->exts, action, LYEXT_PAR_NODE, ret, cleanup);
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003355
Michal Vasko7f45cf22020-10-01 12:49:44 +02003356 /* connect any action augments */
3357 LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)action));
3358
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003359 /* input */
Michal Vasko22df3f02020-08-24 13:29:22 +02003360 lysc_update_path(ctx, (struct lysc_node *)action, "input");
Michal Vasko7f45cf22020-10-01 12:49:44 +02003361
3362 /* apply deviations on input */
3363 LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)&action_p->input, (struct lysc_node *)action,
3364 &dev_input_p, &not_supported));
3365 if (not_supported) {
3366 inout_p = NULL;
3367 } else if (dev_input_p) {
3368 inout_p = (struct lysp_action_inout *)dev_input_p;
3369 } else {
3370 inout_p = &action_p->input;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003371 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02003372
3373 if (inout_p) {
3374 action->input.nodetype = LYS_INPUT;
3375 COMPILE_ARRAY_GOTO(ctx, inout_p->musts, action->input.musts, u, lys_compile_must, ret, cleanup);
3376 COMPILE_EXTS_GOTO(ctx, inout_p->exts, action->input_exts, &action->input, LYEXT_PAR_INPUT, ret, cleanup);
3377 ctx->options |= LYSC_OPT_RPC_INPUT;
3378
3379 /* connect any input augments */
3380 LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)&action->input));
3381
3382 LY_LIST_FOR(inout_p->data, child_p) {
3383 LY_CHECK_RET(lys_compile_node(ctx, child_p, (struct lysc_node *)action, uses_status, NULL));
3384 }
3385 ctx->options = opt_prev;
3386 }
3387
Radek Krejci327de162019-06-14 12:52:07 +02003388 lysc_update_path(ctx, NULL, NULL);
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003389
3390 /* output */
Michal Vasko22df3f02020-08-24 13:29:22 +02003391 lysc_update_path(ctx, (struct lysc_node *)action, "output");
Michal Vasko7f45cf22020-10-01 12:49:44 +02003392
3393 /* apply deviations on output */
3394 LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)&action_p->output, (struct lysc_node *)action,
3395 &dev_output_p, &not_supported));
3396 if (not_supported) {
3397 inout_p = NULL;
3398 } else if (dev_output_p) {
3399 inout_p = (struct lysp_action_inout *)dev_output_p;
3400 } else {
3401 inout_p = &action_p->output;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003402 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02003403
3404 if (inout_p) {
3405 action->output.nodetype = LYS_OUTPUT;
3406 COMPILE_ARRAY_GOTO(ctx, inout_p->musts, action->output.musts, u, lys_compile_must, ret, cleanup);
3407 COMPILE_EXTS_GOTO(ctx, inout_p->exts, action->output_exts, &action->output, LYEXT_PAR_OUTPUT, ret, cleanup);
3408 ctx->options |= LYSC_OPT_RPC_OUTPUT;
3409
3410 /* connect any output augments */
3411 LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)&action->output));
3412
3413 LY_LIST_FOR(inout_p->data, child_p) {
3414 LY_CHECK_RET(lys_compile_node(ctx, child_p, (struct lysc_node *)action, uses_status, NULL));
3415 }
3416 ctx->options = opt_prev;
3417 }
3418
Radek Krejci327de162019-06-14 12:52:07 +02003419 lysc_update_path(ctx, NULL, NULL);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003420
Michal Vasko7f45cf22020-10-01 12:49:44 +02003421 if ((action->input.musts || action->output.musts) && !(ctx->options & LYSC_OPT_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01003422 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003423 ret = ly_set_add(&ctx->xpath, action, 0, NULL);
3424 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003425 }
3426
Michal Vasko7f45cf22020-10-01 12:49:44 +02003427 lysc_update_path(ctx, NULL, NULL);
3428
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003429cleanup:
Michal Vasko7f45cf22020-10-01 12:49:44 +02003430 lysp_dev_node_free(ctx->ctx, dev_pnode);
3431 lysp_dev_node_free(ctx->ctx, dev_input_p);
3432 lysp_dev_node_free(ctx->ctx, dev_output_p);
Radek Krejciec4da802019-05-02 13:02:41 +02003433 ctx->options = opt_prev;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003434 return ret;
3435}
3436
3437/**
Radek Krejci43981a32019-04-12 09:44:11 +02003438 * @brief Compile parsed Notification schema node information.
Radek Krejcifc11bd72019-04-11 16:00:05 +02003439 * @param[in] ctx Compile context
Radek Krejci43981a32019-04-12 09:44:11 +02003440 * @param[in] notif_p Parsed Notification schema node.
Radek Krejci43981a32019-04-12 09:44:11 +02003441 * @param[in] parent Parent node of the Notification, NULL in case of top-level Notification
3442 * @param[in,out] notif Prepared (empty) compiled notification structure to fill.
3443 * @param[in] uses_status If the Notification is being placed instead of uses, here we have the uses's status value (as node's flags).
Radek Krejcifc11bd72019-04-11 16:00:05 +02003444 * Zero means no uses, non-zero value with no status bit set mean the default status.
Michal Vasko7f45cf22020-10-01 12:49:44 +02003445 * @return LY_SUCCESS on success,
3446 * @return LY_EVALID on validation error,
3447 * @return LY_EDENIED on not-supported deviation.
Radek Krejcifc11bd72019-04-11 16:00:05 +02003448 */
3449static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02003450lys_compile_notif(struct lysc_ctx *ctx, struct lysp_notif *notif_p,
Radek Krejci0f969882020-08-21 16:56:47 +02003451 struct lysc_node *parent, struct lysc_notif *notif, uint16_t uses_status)
Radek Krejcifc11bd72019-04-11 16:00:05 +02003452{
3453 LY_ERR ret = LY_SUCCESS;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003454 struct lysp_node *child_p, *dev_pnode = NULL;
3455 struct lysp_notif *orig_notif_p = notif_p;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003456 LY_ARRAY_COUNT_TYPE u;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003457 ly_bool not_supported;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003458 uint32_t opt_prev = ctx->options;
Radek Krejcifc11bd72019-04-11 16:00:05 +02003459
Radek Krejci327de162019-06-14 12:52:07 +02003460 lysc_update_path(ctx, parent, notif_p->name);
3461
Michal Vasko7f45cf22020-10-01 12:49:44 +02003462 LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)notif_p, parent, &dev_pnode, &not_supported));
3463 if (not_supported) {
3464 lysc_update_path(ctx, NULL, NULL);
3465 return LY_EDENIED;
3466 } else if (dev_pnode) {
3467 notif_p = (struct lysp_notif *)dev_pnode;
3468 }
3469
Michal Vasko20424b42020-08-31 12:29:38 +02003470 /* member needed for uniqueness check lys_getnext() */
3471 notif->nodetype = LYS_NOTIF;
3472 notif->module = ctx->mod;
3473 notif->parent = parent;
3474
3475 LY_CHECK_RET(lys_compile_node_uniqness(ctx, parent, notif_p->name, (struct lysc_node *)notif));
Radek Krejcifc11bd72019-04-11 16:00:05 +02003476
Radek Krejciec4da802019-05-02 13:02:41 +02003477 if (ctx->options & (LYSC_OPT_RPC_MASK | LYSC_OPT_NOTIFICATION)) {
Radek Krejcifc11bd72019-04-11 16:00:05 +02003478 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
3479 "Notification \"%s\" is placed inside %s.", notif_p->name,
Michal Vaskoa3881362020-01-21 15:57:35 +01003480 ctx->options & LYSC_OPT_RPC_MASK ? "RPC/action" : "another notification");
Radek Krejcifc11bd72019-04-11 16:00:05 +02003481 return LY_EVALID;
3482 }
3483
Radek Krejciec4da802019-05-02 13:02:41 +02003484 if (!(ctx->options & LYSC_OPT_FREE_SP)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003485 notif->sp = orig_notif_p;
Radek Krejcifc11bd72019-04-11 16:00:05 +02003486 }
3487 notif->flags = notif_p->flags & LYS_FLAGS_COMPILED_MASK;
3488
3489 /* status - it is not inherited by specification, but it does not make sense to have
3490 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003491 ret = lys_compile_status(ctx, &notif->flags, uses_status ? uses_status : (parent ? parent->flags : 0));
3492 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcifc11bd72019-04-11 16:00:05 +02003493
Radek Krejci011e4aa2020-09-04 15:22:31 +02003494 DUP_STRING_GOTO(ctx->ctx, notif_p->name, notif->name, ret, cleanup);
3495 DUP_STRING_GOTO(ctx->ctx, notif_p->dsc, notif->dsc, ret, cleanup);
3496 DUP_STRING_GOTO(ctx->ctx, notif_p->ref, notif->ref, ret, cleanup);
Radek Krejciec4da802019-05-02 13:02:41 +02003497 COMPILE_ARRAY_GOTO(ctx, notif_p->iffeatures, notif->iffeatures, u, lys_compile_iffeature, ret, cleanup);
Radek Krejcic71ac5b2019-09-10 15:34:22 +02003498 COMPILE_ARRAY_GOTO(ctx, notif_p->musts, notif->musts, u, lys_compile_must, ret, cleanup);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003499 if (notif_p->musts && !(ctx->options & LYSC_OPT_GROUPING)) {
3500 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003501 ret = ly_set_add(&ctx->xpath, notif, 0, NULL);
3502 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003503 }
Radek Krejci0935f412019-08-20 16:15:18 +02003504 COMPILE_EXTS_GOTO(ctx, notif_p->exts, notif->exts, notif, LYEXT_PAR_NODE, ret, cleanup);
Radek Krejcifc11bd72019-04-11 16:00:05 +02003505
Radek Krejciec4da802019-05-02 13:02:41 +02003506 ctx->options |= LYSC_OPT_NOTIFICATION;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003507
3508 /* connect any notification augments */
3509 LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)notif));
3510
Radek Krejcifc11bd72019-04-11 16:00:05 +02003511 LY_LIST_FOR(notif_p->data, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003512 ret = lys_compile_node(ctx, child_p, (struct lysc_node *)notif, uses_status, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003513 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcifc11bd72019-04-11 16:00:05 +02003514 }
3515
Radek Krejci327de162019-06-14 12:52:07 +02003516 lysc_update_path(ctx, NULL, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02003517
Radek Krejcifc11bd72019-04-11 16:00:05 +02003518cleanup:
Michal Vasko7f45cf22020-10-01 12:49:44 +02003519 lysp_dev_node_free(ctx->ctx, dev_pnode);
Radek Krejciec4da802019-05-02 13:02:41 +02003520 ctx->options = opt_prev;
Radek Krejcifc11bd72019-04-11 16:00:05 +02003521 return ret;
3522}
3523
3524/**
Radek Krejcia3045382018-11-22 14:30:31 +01003525 * @brief Compile parsed container node information.
3526 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02003527 * @param[in] pnode Parsed container node.
Radek Krejcia3045382018-11-22 14:30:31 +01003528 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
3529 * is enriched with the container-specific information.
3530 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3531 */
Radek Krejci19a96102018-11-15 13:38:09 +01003532static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02003533lys_compile_node_container(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci19a96102018-11-15 13:38:09 +01003534{
Michal Vasko7f45cf22020-10-01 12:49:44 +02003535 struct lysp_node_container *cont_p = (struct lysp_node_container *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02003536 struct lysc_node_container *cont = (struct lysc_node_container *)node;
Radek Krejci19a96102018-11-15 13:38:09 +01003537 struct lysp_node *child_p;
Michal Vaskoba417ac2020-08-06 14:48:20 +02003538 LY_ARRAY_COUNT_TYPE u;
Radek Krejci19a96102018-11-15 13:38:09 +01003539 LY_ERR ret = LY_SUCCESS;
3540
Radek Krejcife909632019-02-12 15:34:42 +01003541 if (cont_p->presence) {
Michal Vaskoba417ac2020-08-06 14:48:20 +02003542 /* explicit presence */
Radek Krejcife909632019-02-12 15:34:42 +01003543 cont->flags |= LYS_PRESENCE;
Michal Vaskoba417ac2020-08-06 14:48:20 +02003544 } else if (cont_p->musts) {
3545 /* container with a must condition */
Radek Krejci175f25b2020-08-13 12:02:36 +02003546 LOGWRN(ctx->ctx, "Container \"%s\" changed to presence because it has a meaning from its \"must\" condition.", cont_p->name);
3547 cont->flags |= LYS_PRESENCE;
3548 } else if (cont_p->when) {
3549 /* container with a when condition */
3550 LOGWRN(ctx->ctx, "Container \"%s\" changed to presence because it has a meaning from its \"when\" condition.", cont_p->name);
Michal Vaskoba417ac2020-08-06 14:48:20 +02003551 cont->flags |= LYS_PRESENCE;
3552 } else if (cont_p->parent) {
3553 if (cont_p->parent->nodetype == LYS_CHOICE) {
3554 /* container is an implicit case, so its existence decides the existence of the whole case */
Radek Krejci175f25b2020-08-13 12:02:36 +02003555 LOGWRN(ctx->ctx, "Container \"%s\" changed to presence because it has a meaning as a case of choice \"%s\".",
Michal Vaskoba417ac2020-08-06 14:48:20 +02003556 cont_p->name, cont_p->parent->name);
3557 cont->flags |= LYS_PRESENCE;
3558 } else if ((cont_p->parent->nodetype == LYS_CASE)
Michal Vasko7f45cf22020-10-01 12:49:44 +02003559 && (((struct lysp_node_case *)cont_p->parent)->child == pnode) && !cont_p->next) {
Michal Vaskoba417ac2020-08-06 14:48:20 +02003560 /* container is the only node in a case, so its existence decides the existence of the whole case */
Radek Krejci175f25b2020-08-13 12:02:36 +02003561 LOGWRN(ctx->ctx, "Container \"%s\" changed to presence because it has a meaning as a case of choice \"%s\".",
Michal Vaskoba417ac2020-08-06 14:48:20 +02003562 cont_p->name, cont_p->parent->name);
3563 cont->flags |= LYS_PRESENCE;
3564 }
Radek Krejcife909632019-02-12 15:34:42 +01003565 }
3566
Michal Vaskoba417ac2020-08-06 14:48:20 +02003567 /* more cases when the container has meaning but is kept NP for convenience:
3568 * - when condition
3569 * - direct child action/notification
3570 */
3571
Radek Krejci19a96102018-11-15 13:38:09 +01003572 LY_LIST_FOR(cont_p->child, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003573 ret = lys_compile_node(ctx, child_p, node, 0, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003574 LY_CHECK_GOTO(ret, done);
Radek Krejci19a96102018-11-15 13:38:09 +01003575 }
3576
Radek Krejcic71ac5b2019-09-10 15:34:22 +02003577 COMPILE_ARRAY_GOTO(ctx, cont_p->musts, cont->musts, u, lys_compile_must, ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003578 if (cont_p->musts && !(ctx->options & LYSC_OPT_GROUPING)) {
3579 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003580 ret = ly_set_add(&ctx->xpath, cont, 0, NULL);
3581 LY_CHECK_GOTO(ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003582 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02003583 COMPILE_OP_ARRAY_GOTO(ctx, cont_p->actions, cont->actions, node, u, lys_compile_action, 0, ret, done);
3584 COMPILE_OP_ARRAY_GOTO(ctx, cont_p->notifs, cont->notifs, node, u, lys_compile_notif, 0, ret, done);
Radek Krejci19a96102018-11-15 13:38:09 +01003585
3586done:
3587 return ret;
3588}
3589
Radek Krejci33f72892019-02-21 10:36:58 +01003590/*
3591 * @brief Compile type in leaf/leaf-list node and do all the necessary checks.
3592 * @param[in] ctx Compile context.
3593 * @param[in] context_node Schema node where the type/typedef is placed to correctly find the base types.
3594 * @param[in] type_p Parsed type to compile.
Radek Krejci33f72892019-02-21 10:36:58 +01003595 * @param[in,out] leaf Compiled leaf structure (possibly cast leaf-list) to provide node information and to store the compiled type information.
3596 * @return LY_ERR value.
3597 */
3598static LY_ERR
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003599lys_compile_node_type(struct lysc_ctx *ctx, struct lysp_node *context_node, struct lysp_type *type_p,
Radek Krejci0f969882020-08-21 16:56:47 +02003600 struct lysc_node_leaf *leaf)
Radek Krejci33f72892019-02-21 10:36:58 +01003601{
Michal Vasko7f45cf22020-10-01 12:49:44 +02003602 struct lysp_qname *dflt;
Radek Krejci33f72892019-02-21 10:36:58 +01003603
Radek Krejciec4da802019-05-02 13:02:41 +02003604 LY_CHECK_RET(lys_compile_type(ctx, context_node, leaf->flags, ctx->mod_def->parsed, leaf->name, type_p, &leaf->type,
Michal Vasko7f45cf22020-10-01 12:49:44 +02003605 leaf->units ? NULL : &leaf->units, &dflt));
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003606
3607 /* store default value, if any */
3608 if (dflt && !(leaf->flags & LYS_SET_DFLT)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003609 LY_CHECK_RET(lysc_unres_leaf_dflt_add(ctx, leaf, dflt));
Radek Krejci33f72892019-02-21 10:36:58 +01003610 }
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003611
Radek Krejci33f72892019-02-21 10:36:58 +01003612 if (leaf->type->basetype == LY_TYPE_LEAFREF) {
3613 /* store to validate the path in the current context at the end of schema compiling when all the nodes are present */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003614 LY_CHECK_RET(ly_set_add(&ctx->leafrefs, leaf, 0, NULL));
Radek Krejci33f72892019-02-21 10:36:58 +01003615 } else if (leaf->type->basetype == LY_TYPE_UNION) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003616 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003617 LY_ARRAY_FOR(((struct lysc_type_union *)leaf->type)->types, u) {
3618 if (((struct lysc_type_union *)leaf->type)->types[u]->basetype == LY_TYPE_LEAFREF) {
Radek Krejci33f72892019-02-21 10:36:58 +01003619 /* store to validate the path in the current context at the end of schema compiling when all the nodes are present */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003620 LY_CHECK_RET(ly_set_add(&ctx->leafrefs, leaf, 0, NULL));
Radek Krejci33f72892019-02-21 10:36:58 +01003621 }
3622 }
3623 } else if (leaf->type->basetype == LY_TYPE_EMPTY) {
Radek Krejci33f72892019-02-21 10:36:58 +01003624 if (leaf->nodetype == LYS_LEAFLIST && ctx->mod_def->version < LYS_VERSION_1_1) {
3625 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
3626 "Leaf-list of type \"empty\" is allowed only in YANG 1.1 modules.");
3627 return LY_EVALID;
3628 }
3629 }
3630
Radek Krejci33f72892019-02-21 10:36:58 +01003631 return LY_SUCCESS;
3632}
3633
Radek Krejcia3045382018-11-22 14:30:31 +01003634/**
3635 * @brief Compile parsed leaf node information.
3636 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02003637 * @param[in] pnode Parsed leaf node.
Radek Krejcia3045382018-11-22 14:30:31 +01003638 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
3639 * is enriched with the leaf-specific information.
3640 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3641 */
Radek Krejci19a96102018-11-15 13:38:09 +01003642static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02003643lys_compile_node_leaf(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci19a96102018-11-15 13:38:09 +01003644{
Michal Vasko7f45cf22020-10-01 12:49:44 +02003645 struct lysp_node_leaf *leaf_p = (struct lysp_node_leaf *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02003646 struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)node;
Michal Vasko7c8439f2020-08-05 13:25:19 +02003647 LY_ARRAY_COUNT_TYPE u;
Radek Krejci19a96102018-11-15 13:38:09 +01003648 LY_ERR ret = LY_SUCCESS;
3649
Radek Krejcic71ac5b2019-09-10 15:34:22 +02003650 COMPILE_ARRAY_GOTO(ctx, leaf_p->musts, leaf->musts, u, lys_compile_must, ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003651 if (leaf_p->musts && !(ctx->options & LYSC_OPT_GROUPING)) {
3652 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003653 ret = ly_set_add(&ctx->xpath, leaf, 0, NULL);
3654 LY_CHECK_GOTO(ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003655 }
Radek Krejciccd20f12019-02-15 14:12:27 +01003656 if (leaf_p->units) {
Radek Krejci011e4aa2020-09-04 15:22:31 +02003657 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, leaf_p->units, 0, &leaf->units), done);
Radek Krejciccd20f12019-02-15 14:12:27 +01003658 leaf->flags |= LYS_SET_UNITS;
3659 }
Radek Krejcia1911222019-07-22 17:24:50 +02003660
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003661 /* compile type */
Michal Vasko7f45cf22020-10-01 12:49:44 +02003662 ret = lys_compile_node_type(ctx, pnode, &leaf_p->type, leaf);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003663 LY_CHECK_GOTO(ret, done);
Radek Krejcia1911222019-07-22 17:24:50 +02003664
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003665 /* store/update default value */
Michal Vasko7f45cf22020-10-01 12:49:44 +02003666 if (leaf_p->dflt.str) {
3667 LY_CHECK_RET(lysc_unres_leaf_dflt_add(ctx, leaf, &leaf_p->dflt));
Radek Krejci76b3e962018-12-14 17:01:25 +01003668 leaf->flags |= LYS_SET_DFLT;
3669 }
Radek Krejci43699232018-11-23 14:59:46 +01003670
Michal Vasko7f45cf22020-10-01 12:49:44 +02003671 /* checks */
3672 if ((leaf->flags & LYS_SET_DFLT) && (leaf->flags & LYS_MAND_TRUE)) {
3673 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
3674 "Invalid mandatory leaf with a default value.");
3675 return LY_EVALID;
3676 }
3677
Radek Krejci19a96102018-11-15 13:38:09 +01003678done:
3679 return ret;
3680}
3681
Radek Krejcia3045382018-11-22 14:30:31 +01003682/**
Radek Krejci0e5d8382018-11-28 16:37:53 +01003683 * @brief Compile parsed leaf-list node information.
3684 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02003685 * @param[in] pnode Parsed leaf-list node.
Radek Krejci0e5d8382018-11-28 16:37:53 +01003686 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
3687 * is enriched with the leaf-list-specific information.
3688 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3689 */
3690static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02003691lys_compile_node_leaflist(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci0e5d8382018-11-28 16:37:53 +01003692{
Michal Vasko7f45cf22020-10-01 12:49:44 +02003693 struct lysp_node_leaflist *llist_p = (struct lysp_node_leaflist *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02003694 struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)node;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003695 LY_ARRAY_COUNT_TYPE u;
Radek Krejci0e5d8382018-11-28 16:37:53 +01003696 LY_ERR ret = LY_SUCCESS;
3697
Radek Krejcic71ac5b2019-09-10 15:34:22 +02003698 COMPILE_ARRAY_GOTO(ctx, llist_p->musts, llist->musts, u, lys_compile_must, ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003699 if (llist_p->musts && !(ctx->options & LYSC_OPT_GROUPING)) {
3700 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003701 ret = ly_set_add(&ctx->xpath, llist, 0, NULL);
3702 LY_CHECK_GOTO(ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003703 }
Radek Krejciccd20f12019-02-15 14:12:27 +01003704 if (llist_p->units) {
Radek Krejci011e4aa2020-09-04 15:22:31 +02003705 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, llist_p->units, 0, &llist->units), done);
Radek Krejciccd20f12019-02-15 14:12:27 +01003706 llist->flags |= LYS_SET_UNITS;
3707 }
Radek Krejci0e5d8382018-11-28 16:37:53 +01003708
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003709 /* compile type */
Michal Vasko7f45cf22020-10-01 12:49:44 +02003710 ret = lys_compile_node_type(ctx, pnode, &llist_p->type, (struct lysc_node_leaf *)llist);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003711 LY_CHECK_GOTO(ret, done);
Michal Vasko6a044b22020-01-15 12:25:39 +01003712
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003713 /* store/update default values */
Radek Krejci0e5d8382018-11-28 16:37:53 +01003714 if (llist_p->dflts) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003715 if (ctx->mod_def->version < LYS_VERSION_1_1) {
3716 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
3717 "Leaf-list default values are allowed only in YANG 1.1 modules.");
3718 return LY_EVALID;
3719 }
3720
3721 LY_CHECK_GOTO(lysc_unres_llist_dflts_add(ctx, llist, llist_p->dflts), done);
Radek Krejciccd20f12019-02-15 14:12:27 +01003722 llist->flags |= LYS_SET_DFLT;
Radek Krejci0e5d8382018-11-28 16:37:53 +01003723 }
3724
3725 llist->min = llist_p->min;
Radek Krejcife909632019-02-12 15:34:42 +01003726 if (llist->min) {
3727 llist->flags |= LYS_MAND_TRUE;
3728 }
Radek Krejcib7408632018-11-28 17:12:11 +01003729 llist->max = llist_p->max ? llist_p->max : (uint32_t)-1;
Radek Krejci0e5d8382018-11-28 16:37:53 +01003730
Michal Vasko7f45cf22020-10-01 12:49:44 +02003731 /* checks */
3732 if ((llist->flags & LYS_SET_DFLT) && (llist->flags & LYS_MAND_TRUE)) {
3733 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
3734 "Invalid mandatory leaf-list with default value(s).");
3735 return LY_EVALID;
3736 }
3737
3738 if (llist->min > llist->max) {
3739 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Leaf-list min-elements %u is bigger than max-elements %u.",
3740 llist->min, llist->max);
3741 return LY_EVALID;
3742 }
3743
Radek Krejci0e5d8382018-11-28 16:37:53 +01003744done:
3745 return ret;
3746}
3747
3748/**
Radek Krejci7af64242019-02-18 13:07:53 +01003749 * @brief Compile information about list's uniques.
3750 * @param[in] ctx Compile context.
Radek Krejci7af64242019-02-18 13:07:53 +01003751 * @param[in] uniques Sized array list of unique statements.
3752 * @param[in] list Compiled list where the uniques are supposed to be resolved and stored.
3753 * @return LY_ERR value.
3754 */
3755static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02003756lys_compile_node_list_unique(struct lysc_ctx *ctx, struct lysp_qname *uniques, struct lysc_node_list *list)
Radek Krejci7af64242019-02-18 13:07:53 +01003757{
3758 LY_ERR ret = LY_SUCCESS;
3759 struct lysc_node_leaf **key, ***unique;
Michal Vasko14654712020-02-06 08:35:21 +01003760 struct lysc_node *parent;
Radek Krejci7af64242019-02-18 13:07:53 +01003761 const char *keystr, *delim;
3762 size_t len;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003763 LY_ARRAY_COUNT_TYPE v;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003764 int8_t config; /* -1 - not yet seen; 0 - LYS_CONFIG_R; 1 - LYS_CONFIG_W */
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003765 uint16_t flags;
Radek Krejci7af64242019-02-18 13:07:53 +01003766
Michal Vasko7f45cf22020-10-01 12:49:44 +02003767 LY_ARRAY_FOR(uniques, v) {
Radek Krejci7af64242019-02-18 13:07:53 +01003768 config = -1;
3769 LY_ARRAY_NEW_RET(ctx->ctx, list->uniques, unique, LY_EMEM);
Michal Vasko7f45cf22020-10-01 12:49:44 +02003770 keystr = uniques[v].str;
Radek Krejci7af64242019-02-18 13:07:53 +01003771 while (keystr) {
3772 delim = strpbrk(keystr, " \t\n");
3773 if (delim) {
3774 len = delim - keystr;
3775 while (isspace(*delim)) {
3776 ++delim;
3777 }
3778 } else {
3779 len = strlen(keystr);
3780 }
3781
3782 /* unique node must be present */
3783 LY_ARRAY_NEW_RET(ctx->ctx, *unique, key, LY_EMEM);
Michal Vasko7f45cf22020-10-01 12:49:44 +02003784 ret = lysc_resolve_schema_nodeid(ctx, keystr, len, (struct lysc_node *)list, uniques[v].mod, LYS_LEAF,
Michal Vasko22df3f02020-08-24 13:29:22 +02003785 (const struct lysc_node **)key, &flags);
Radek Krejci7af64242019-02-18 13:07:53 +01003786 if (ret != LY_SUCCESS) {
3787 if (ret == LY_EDENIED) {
3788 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003789 "Unique's descendant-schema-nodeid \"%.*s\" refers to %s node instead of a leaf.",
Radek Krejci7af64242019-02-18 13:07:53 +01003790 len, keystr, lys_nodetype2str((*key)->nodetype));
3791 }
3792 return LY_EVALID;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003793 } else if (flags) {
3794 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3795 "Unique's descendant-schema-nodeid \"%.*s\" refers into %s node.",
Michal Vaskoa3881362020-01-21 15:57:35 +01003796 len, keystr, flags & LYSC_OPT_NOTIFICATION ? "notification" : "RPC/action");
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003797 return LY_EVALID;
Radek Krejci7af64242019-02-18 13:07:53 +01003798 }
3799
3800 /* all referenced leafs must be of the same config type */
3801 if (config != -1 && ((((*key)->flags & LYS_CONFIG_W) && config == 0) || (((*key)->flags & LYS_CONFIG_R) && config == 1))) {
3802 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko7f45cf22020-10-01 12:49:44 +02003803 "Unique statement \"%s\" refers to leaves with different config type.", uniques[v].str);
Radek Krejci7af64242019-02-18 13:07:53 +01003804 return LY_EVALID;
3805 } else if ((*key)->flags & LYS_CONFIG_W) {
3806 config = 1;
3807 } else { /* LYS_CONFIG_R */
3808 config = 0;
3809 }
3810
Michal Vasko14654712020-02-06 08:35:21 +01003811 /* we forbid referencing nested lists because it is unspecified what instance of such a list to use */
3812 for (parent = (*key)->parent; parent != (struct lysc_node *)list; parent = parent->parent) {
3813 if (parent->nodetype == LYS_LIST) {
3814 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko7f45cf22020-10-01 12:49:44 +02003815 "Unique statement \"%s\" refers to a leaf in nested list \"%s\".", uniques[v].str, parent->name);
Michal Vasko14654712020-02-06 08:35:21 +01003816 return LY_EVALID;
3817 }
3818 }
3819
Radek Krejci7af64242019-02-18 13:07:53 +01003820 /* check status */
3821 LY_CHECK_RET(lysc_check_status(ctx, list->flags, list->module, list->name,
Radek Krejci0f969882020-08-21 16:56:47 +02003822 (*key)->flags, (*key)->module, (*key)->name));
Radek Krejci7af64242019-02-18 13:07:53 +01003823
3824 /* mark leaf as unique */
3825 (*key)->flags |= LYS_UNIQUE;
3826
3827 /* next unique value in line */
3828 keystr = delim;
3829 }
3830 /* next unique definition */
3831 }
3832
3833 return LY_SUCCESS;
3834}
3835
3836/**
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003837 * @brief Compile parsed list node information.
3838 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02003839 * @param[in] pnode Parsed list node.
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003840 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
3841 * is enriched with the list-specific information.
3842 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3843 */
3844static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02003845lys_compile_node_list(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003846{
Michal Vasko7f45cf22020-10-01 12:49:44 +02003847 struct lysp_node_list *list_p = (struct lysp_node_list *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02003848 struct lysc_node_list *list = (struct lysc_node_list *)node;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003849 struct lysp_node *child_p;
Radek Krejci0fe9b512019-07-26 17:51:05 +02003850 struct lysc_node_leaf *key, *prev_key = NULL;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003851 size_t len;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003852 LY_ARRAY_COUNT_TYPE u;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003853 const char *keystr, *delim;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003854 LY_ERR ret = LY_SUCCESS;
3855
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003856 list->min = list_p->min;
Radek Krejcife909632019-02-12 15:34:42 +01003857 if (list->min) {
3858 list->flags |= LYS_MAND_TRUE;
3859 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003860 list->max = list_p->max ? list_p->max : (uint32_t)-1;
3861
3862 LY_LIST_FOR(list_p->child, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003863 LY_CHECK_RET(lys_compile_node(ctx, child_p, node, 0, NULL));
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003864 }
3865
Radek Krejcic71ac5b2019-09-10 15:34:22 +02003866 COMPILE_ARRAY_GOTO(ctx, list_p->musts, list->musts, u, lys_compile_must, ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003867 if (list_p->musts && !(ctx->options & LYSC_OPT_GROUPING)) {
3868 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003869 LY_CHECK_RET(ly_set_add(&ctx->xpath, list, 0, NULL));
Michal Vasko5d8756a2019-11-07 15:21:00 +01003870 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003871
3872 /* keys */
3873 if ((list->flags & LYS_CONFIG_W) && (!list_p->key || !list_p->key[0])) {
3874 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Missing key in list representing configuration data.");
3875 return LY_EVALID;
3876 }
3877
3878 /* find all the keys (must be direct children) */
3879 keystr = list_p->key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02003880 if (!keystr) {
3881 /* keyless list */
3882 list->flags |= LYS_KEYLESS;
3883 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003884 while (keystr) {
3885 delim = strpbrk(keystr, " \t\n");
3886 if (delim) {
3887 len = delim - keystr;
3888 while (isspace(*delim)) {
3889 ++delim;
3890 }
3891 } else {
3892 len = strlen(keystr);
3893 }
3894
3895 /* key node must be present */
Michal Vasko22df3f02020-08-24 13:29:22 +02003896 key = (struct lysc_node_leaf *)lys_find_child(node, node->module, keystr, len, LYS_LEAF, LYS_GETNEXT_NOCHOICE | LYS_GETNEXT_NOSTATECHECK);
Radek Krejci0fe9b512019-07-26 17:51:05 +02003897 if (!(key)) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003898 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3899 "The list's key \"%.*s\" not found.", len, keystr);
3900 return LY_EVALID;
3901 }
3902 /* keys must be unique */
Radek Krejci0fe9b512019-07-26 17:51:05 +02003903 if (key->flags & LYS_KEY) {
3904 /* the node was already marked as a key */
3905 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
3906 "Duplicated key identifier \"%.*s\".", len, keystr);
3907 return LY_EVALID;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003908 }
Radek Krejci0fe9b512019-07-26 17:51:05 +02003909
Michal Vasko22df3f02020-08-24 13:29:22 +02003910 lysc_update_path(ctx, (struct lysc_node *)list, key->name);
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003911 /* key must have the same config flag as the list itself */
Radek Krejci0fe9b512019-07-26 17:51:05 +02003912 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003913 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Key of the configuration list must not be status leaf.");
3914 return LY_EVALID;
3915 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +01003916 if (ctx->mod_def->version < LYS_VERSION_1_1) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003917 /* YANG 1.0 denies key to be of empty type */
Radek Krejci0fe9b512019-07-26 17:51:05 +02003918 if (key->type->basetype == LY_TYPE_EMPTY) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003919 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Radek Krejci327de162019-06-14 12:52:07 +02003920 "List's key cannot be of \"empty\" type until it is in YANG 1.1 module.");
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003921 return LY_EVALID;
3922 }
3923 } else {
3924 /* when and if-feature are illegal on list keys */
Radek Krejci0fe9b512019-07-26 17:51:05 +02003925 if (key->when) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003926 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Radek Krejci327de162019-06-14 12:52:07 +02003927 "List's key must not have any \"when\" statement.");
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003928 return LY_EVALID;
3929 }
Radek Krejci0fe9b512019-07-26 17:51:05 +02003930 if (key->iffeatures) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003931 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Radek Krejci327de162019-06-14 12:52:07 +02003932 "List's key must not have any \"if-feature\" statement.");
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003933 return LY_EVALID;
3934 }
3935 }
Radek Krejci76b3e962018-12-14 17:01:25 +01003936
3937 /* check status */
3938 LY_CHECK_RET(lysc_check_status(ctx, list->flags, list->module, list->name,
Radek Krejci0fe9b512019-07-26 17:51:05 +02003939 key->flags, key->module, key->name));
Radek Krejci76b3e962018-12-14 17:01:25 +01003940
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003941 /* ignore default values of the key */
Radek Krejci0fe9b512019-07-26 17:51:05 +02003942 if (key->dflt) {
3943 key->dflt->realtype->plugin->free(ctx->ctx, key->dflt);
3944 lysc_type_free(ctx->ctx, key->dflt->realtype);
3945 free(key->dflt);
3946 key->dflt = NULL;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003947 }
3948 /* mark leaf as key */
Radek Krejci0fe9b512019-07-26 17:51:05 +02003949 key->flags |= LYS_KEY;
3950
3951 /* move it to the correct position */
Michal Vasko22df3f02020-08-24 13:29:22 +02003952 if ((prev_key && (struct lysc_node *)prev_key != key->prev) || (!prev_key && key->prev->next)) {
Radek Krejci0fe9b512019-07-26 17:51:05 +02003953 /* fix links in closest previous siblings of the key */
3954 if (key->next) {
3955 key->next->prev = key->prev;
3956 } else {
3957 /* last child */
3958 list->child->prev = key->prev;
3959 }
3960 if (key->prev->next) {
3961 key->prev->next = key->next;
3962 }
3963 /* fix links in the key */
3964 if (prev_key) {
Michal Vasko22df3f02020-08-24 13:29:22 +02003965 key->prev = (struct lysc_node *)prev_key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02003966 key->next = prev_key->next;
3967 } else {
3968 key->prev = list->child->prev;
3969 key->next = list->child;
3970 }
3971 /* fix links in closes future siblings of the key */
3972 if (prev_key) {
3973 if (prev_key->next) {
Michal Vasko22df3f02020-08-24 13:29:22 +02003974 prev_key->next->prev = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02003975 } else {
Michal Vasko22df3f02020-08-24 13:29:22 +02003976 list->child->prev = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02003977 }
Michal Vasko22df3f02020-08-24 13:29:22 +02003978 prev_key->next = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02003979 } else {
Michal Vasko22df3f02020-08-24 13:29:22 +02003980 list->child->prev = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02003981 }
3982 /* fix links in parent */
3983 if (!key->prev->next) {
Michal Vasko22df3f02020-08-24 13:29:22 +02003984 list->child = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02003985 }
3986 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003987
3988 /* next key value */
Radek Krejci0fe9b512019-07-26 17:51:05 +02003989 prev_key = key;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003990 keystr = delim;
Radek Krejci327de162019-06-14 12:52:07 +02003991 lysc_update_path(ctx, NULL, NULL);
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003992 }
3993
3994 /* uniques */
3995 if (list_p->uniques) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003996 LY_CHECK_RET(lys_compile_node_list_unique(ctx, list_p->uniques, list));
Radek Krejci9bb94eb2018-12-04 16:48:35 +01003997 }
3998
Michal Vasko7f45cf22020-10-01 12:49:44 +02003999 COMPILE_OP_ARRAY_GOTO(ctx, list_p->actions, list->actions, node, u, lys_compile_action, 0, ret, done);
4000 COMPILE_OP_ARRAY_GOTO(ctx, list_p->notifs, list->notifs, node, u, lys_compile_notif, 0, ret, done);
4001
4002 /* checks */
4003 if (list->min > list->max) {
4004 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "List min-elements %u is bigger than max-elements %u.",
4005 list->min, list->max);
4006 return LY_EVALID;
4007 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004008
4009done:
4010 return ret;
4011}
4012
Radek Krejcib56c7502019-02-13 14:19:54 +01004013/**
4014 * @brief Do some checks and set the default choice's case.
4015 *
4016 * Selects (and stores into ::lysc_node_choice#dflt) the default case and set LYS_SET_DFLT flag on it.
4017 *
4018 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02004019 * @param[in] dflt Name of the default branch. Can even contain a prefix.
Radek Krejcib56c7502019-02-13 14:19:54 +01004020 * @param[in,out] ch The compiled choice node, its dflt member is filled to point to the default case node of the choice.
4021 * @return LY_ERR value.
4022 */
Radek Krejci76b3e962018-12-14 17:01:25 +01004023static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004024lys_compile_node_choice_dflt(struct lysc_ctx *ctx, struct lysp_qname *dflt, struct lysc_node_choice *ch)
Radek Krejci76b3e962018-12-14 17:01:25 +01004025{
Michal Vasko22df3f02020-08-24 13:29:22 +02004026 struct lysc_node *iter, *node = (struct lysc_node *)ch;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004027 const struct lys_module *mod;
Radek Krejci76b3e962018-12-14 17:01:25 +01004028 const char *prefix = NULL, *name;
4029 size_t prefix_len = 0;
4030
4031 /* could use lys_parse_nodeid(), but it checks syntax which is already done in this case by the parsers */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004032 name = strchr(dflt->str, ':');
Radek Krejci76b3e962018-12-14 17:01:25 +01004033 if (name) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004034 prefix = dflt->str;
Radek Krejci76b3e962018-12-14 17:01:25 +01004035 prefix_len = name - prefix;
4036 ++name;
4037 } else {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004038 name = dflt->str;
Radek Krejci76b3e962018-12-14 17:01:25 +01004039 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004040 if (prefix) {
4041 mod = ly_resolve_prefix(ctx->ctx, prefix, prefix_len, LY_PREF_SCHEMA, (void *)dflt->mod);
4042 if (!mod) {
4043 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
4044 "Default case prefix \"%.*s\" not found in imports of \"%s\".", prefix_len, prefix, dflt->mod->name);
4045 return LY_EVALID;
4046 }
4047 } else {
4048 mod = node->module;
Radek Krejci76b3e962018-12-14 17:01:25 +01004049 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004050
4051 ch->dflt = (struct lysc_node_case *)lys_find_child(node, mod, name, 0, LYS_CASE, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCASE);
Radek Krejci76b3e962018-12-14 17:01:25 +01004052 if (!ch->dflt) {
4053 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko7f45cf22020-10-01 12:49:44 +02004054 "Default case \"%s\" not found.", dflt->str);
Radek Krejci76b3e962018-12-14 17:01:25 +01004055 return LY_EVALID;
4056 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004057
Radek Krejci76b3e962018-12-14 17:01:25 +01004058 /* no mandatory nodes directly under the default case */
4059 LY_LIST_FOR(ch->dflt->child, iter) {
Michal Vasko22df3f02020-08-24 13:29:22 +02004060 if (iter->parent != (struct lysc_node *)ch->dflt) {
Radek Krejcife13da42019-02-15 14:51:01 +01004061 break;
4062 }
Radek Krejci76b3e962018-12-14 17:01:25 +01004063 if (iter->flags & LYS_MAND_TRUE) {
4064 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko7f45cf22020-10-01 12:49:44 +02004065 "Mandatory node \"%s\" under the default case \"%s\".", iter->name, dflt->str);
Radek Krejci76b3e962018-12-14 17:01:25 +01004066 return LY_EVALID;
4067 }
4068 }
Radek Krejci76b3e962018-12-14 17:01:25 +01004069
Michal Vasko7f45cf22020-10-01 12:49:44 +02004070 if (ch->flags & LYS_MAND_TRUE) {
4071 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid mandatory choice with a default case.");
Radek Krejciccd20f12019-02-15 14:12:27 +01004072 return LY_EVALID;
4073 }
4074
Michal Vasko7f45cf22020-10-01 12:49:44 +02004075 ch->dflt->flags |= LYS_SET_DFLT;
Radek Krejciccd20f12019-02-15 14:12:27 +01004076 return LY_SUCCESS;
4077}
4078
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004079/**
Michal Vasko20424b42020-08-31 12:29:38 +02004080 * @brief Compile choice children.
4081 *
4082 * @param[in] ctx Compile context
4083 * @param[in] child_p Parsed choice children nodes.
4084 * @param[in] node Compiled choice node to compile and add children to.
4085 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
4086 */
4087static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004088lys_compile_node_choice_child(struct lysc_ctx *ctx, struct lysp_node *child_p, struct lysc_node *node,
4089 struct ly_set *child_set)
Michal Vasko20424b42020-08-31 12:29:38 +02004090{
4091 LY_ERR ret = LY_SUCCESS;
Radek Krejci8f5fad22020-09-15 16:50:54 +02004092 struct lysp_node *child_p_next = child_p->next;
Michal Vasko20424b42020-08-31 12:29:38 +02004093 struct lysp_node_case *cs_p;
4094
4095 if (child_p->nodetype == LYS_CASE) {
4096 /* standard case under choice */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004097 ret = lys_compile_node(ctx, child_p, node, 0, child_set);
Michal Vasko20424b42020-08-31 12:29:38 +02004098 } else {
4099 /* we need the implicit case first, so create a fake parsed case */
4100 cs_p = calloc(1, sizeof *cs_p);
4101 cs_p->nodetype = LYS_CASE;
Radek Krejci87e25252020-09-15 13:28:31 +02004102 DUP_STRING_GOTO(ctx->ctx, child_p->name, cs_p->name, ret, free_fake_node);
Michal Vasko20424b42020-08-31 12:29:38 +02004103 cs_p->child = child_p;
4104
4105 /* make the child the only case child */
Michal Vasko20424b42020-08-31 12:29:38 +02004106 child_p->next = NULL;
4107
4108 /* compile it normally */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004109 ret = lys_compile_node(ctx, (struct lysp_node *)cs_p, node, 0, child_set);
Michal Vasko20424b42020-08-31 12:29:38 +02004110
Radek Krejci87e25252020-09-15 13:28:31 +02004111free_fake_node:
Michal Vasko20424b42020-08-31 12:29:38 +02004112 /* free the fake parsed node and correct pointers back */
4113 cs_p->child = NULL;
4114 lysp_node_free(ctx->ctx, (struct lysp_node *)cs_p);
Radek Krejci8f5fad22020-09-15 16:50:54 +02004115 child_p->next = child_p_next;
Michal Vasko20424b42020-08-31 12:29:38 +02004116 }
4117
4118 return ret;
4119}
4120
4121/**
Radek Krejci056d0a82018-12-06 16:57:25 +01004122 * @brief Compile parsed choice node information.
Michal Vasko20424b42020-08-31 12:29:38 +02004123 *
Radek Krejci056d0a82018-12-06 16:57:25 +01004124 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02004125 * @param[in] pnode Parsed choice node.
Radek Krejci056d0a82018-12-06 16:57:25 +01004126 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
Radek Krejci76b3e962018-12-14 17:01:25 +01004127 * is enriched with the choice-specific information.
Radek Krejci056d0a82018-12-06 16:57:25 +01004128 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
4129 */
4130static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004131lys_compile_node_choice(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci056d0a82018-12-06 16:57:25 +01004132{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004133 struct lysp_node_choice *ch_p = (struct lysp_node_choice *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02004134 struct lysc_node_choice *ch = (struct lysc_node_choice *)node;
Michal Vasko20424b42020-08-31 12:29:38 +02004135 struct lysp_node *child_p;
Radek Krejci056d0a82018-12-06 16:57:25 +01004136 LY_ERR ret = LY_SUCCESS;
4137
Michal Vasko20424b42020-08-31 12:29:38 +02004138 assert(node->nodetype == LYS_CHOICE);
4139
Radek Krejci056d0a82018-12-06 16:57:25 +01004140 LY_LIST_FOR(ch_p->child, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004141 LY_CHECK_RET(lys_compile_node_choice_child(ctx, child_p, node, NULL));
Radek Krejci056d0a82018-12-06 16:57:25 +01004142 }
4143
4144 /* default branch */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004145 if (ch_p->dflt.str) {
4146 LY_CHECK_RET(lys_compile_node_choice_dflt(ctx, &ch_p->dflt, ch));
Radek Krejcia9026eb2018-12-12 16:04:47 +01004147 }
Radek Krejci056d0a82018-12-06 16:57:25 +01004148
Radek Krejci9800fb82018-12-13 14:26:23 +01004149 return ret;
4150}
4151
4152/**
4153 * @brief Compile parsed anydata or anyxml node information.
4154 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02004155 * @param[in] pnode Parsed anydata or anyxml node.
Radek Krejci9800fb82018-12-13 14:26:23 +01004156 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
4157 * is enriched with the any-specific information.
4158 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
4159 */
4160static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004161lys_compile_node_any(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci9800fb82018-12-13 14:26:23 +01004162{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004163 struct lysp_node_anydata *any_p = (struct lysp_node_anydata *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02004164 struct lysc_node_anydata *any = (struct lysc_node_anydata *)node;
Radek Krejci1deb5be2020-08-26 16:43:36 +02004165 LY_ARRAY_COUNT_TYPE u;
Radek Krejci9800fb82018-12-13 14:26:23 +01004166 LY_ERR ret = LY_SUCCESS;
4167
Radek Krejcic71ac5b2019-09-10 15:34:22 +02004168 COMPILE_ARRAY_GOTO(ctx, any_p->musts, any->musts, u, lys_compile_must, ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01004169 if (any_p->musts && !(ctx->options & LYSC_OPT_GROUPING)) {
4170 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02004171 ret = ly_set_add(&ctx->xpath, any, 0, NULL);
4172 LY_CHECK_GOTO(ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01004173 }
Radek Krejci9800fb82018-12-13 14:26:23 +01004174
4175 if (any->flags & LYS_CONFIG_W) {
Radek Krejci5c4ed7b2020-08-12 11:29:44 +02004176 LOGWRN(ctx->ctx, "Use of %s to define configuration data is not recommended. %s",
4177 ly_stmt2str(any->nodetype == LYS_ANYDATA ? LY_STMT_ANYDATA : LY_STMT_ANYXML), ctx->path);
Radek Krejci9800fb82018-12-13 14:26:23 +01004178 }
Radek Krejci056d0a82018-12-06 16:57:25 +01004179done:
4180 return ret;
4181}
4182
Radek Krejcib56c7502019-02-13 14:19:54 +01004183/**
Michal Vasko795b3752020-07-13 15:24:27 +02004184 * @brief Connect the node into the siblings list and check its name uniqueness. Also,
4185 * keep specific order of augments targetting the same node.
Radek Krejci056d0a82018-12-06 16:57:25 +01004186 *
4187 * @param[in] ctx Compile context
4188 * @param[in] parent Parent node holding the children list, in case of node from a choice's case,
4189 * the choice itself is expected instead of a specific case node.
4190 * @param[in] node Schema node to connect into the list.
4191 * @return LY_ERR value - LY_SUCCESS or LY_EEXIST.
Radek Krejci1c54f462020-05-12 17:25:34 +02004192 * In case of LY_EEXIST, the node is actually kept in the tree, so do not free it directly.
Radek Krejci056d0a82018-12-06 16:57:25 +01004193 */
4194static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02004195lys_compile_node_connect(struct lysc_ctx *ctx, struct lysc_node *parent, struct lysc_node *node)
Radek Krejci056d0a82018-12-06 16:57:25 +01004196{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004197 struct lysc_node **children, *anchor = NULL;
4198 int insert_after = 0;
Radek Krejci056d0a82018-12-06 16:57:25 +01004199
Michal Vasko20424b42020-08-31 12:29:38 +02004200 node->parent = parent;
4201
4202 if (parent) {
4203 if (parent->nodetype == LYS_CHOICE) {
4204 assert(node->nodetype == LYS_CASE);
4205 children = (struct lysc_node **)&((struct lysc_node_choice *)parent)->cases;
4206 } else {
4207 children = lysc_node_children_p(parent, ctx->options);
4208 }
4209 assert(children);
4210
Radek Krejci056d0a82018-12-06 16:57:25 +01004211 if (!(*children)) {
4212 /* first child */
4213 *children = node;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004214 } else if (node->flags & LYS_KEY) {
4215 /* special handling of adding keys */
4216 assert(node->module == parent->module);
4217 anchor = *children;
4218 if (anchor->flags & LYS_KEY) {
4219 while ((anchor->flags & LYS_KEY) && anchor->next) {
4220 anchor = anchor->next;
4221 }
4222 /* insert after the last key */
4223 insert_after = 1;
4224 } /* else insert before anchor (at the beginning) */
4225 } else if ((*children)->prev->module == node->module) {
4226 /* last child is from the same module, keep the order and insert at the end */
4227 anchor = (*children)->prev;
4228 insert_after = 1;
4229 } else if (parent->module == node->module) {
4230 /* adding module child after some augments were connected */
4231 for (anchor = *children; anchor->module == node->module; anchor = anchor->next) {}
4232 } else {
4233 /* some augments are already connected and we are connecting new ones,
4234 * keep module name order and insert the node into the children list */
4235 anchor = *children;
4236 do {
4237 anchor = anchor->prev;
Michal Vasko795b3752020-07-13 15:24:27 +02004238
Michal Vasko7f45cf22020-10-01 12:49:44 +02004239 /* check that we have not found the last augment node from our module or
4240 * the first augment node from a "smaller" module or
4241 * the first node from a local module */
4242 if ((anchor->module == node->module) || (strcmp(anchor->module->name, node->module->name) < 0)
4243 || (anchor->module == parent->module)) {
4244 /* insert after */
4245 insert_after = 1;
4246 break;
4247 }
4248
4249 /* we have traversed all the nodes, insert before anchor (as the first node) */
4250 } while (anchor->prev->next);
4251 }
4252
4253 /* insert */
4254 if (anchor) {
4255 if (insert_after) {
4256 node->next = anchor->next;
4257 node->prev = anchor;
4258 anchor->next = node;
4259 if (node->next) {
4260 /* middle node */
4261 node->next->prev = node;
4262 } else {
4263 /* last node */
4264 (*children)->prev = node;
4265 }
Michal Vasko795b3752020-07-13 15:24:27 +02004266 } else {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004267 node->next = anchor;
4268 node->prev = anchor->prev;
4269 anchor->prev = node;
4270 if (anchor == *children) {
4271 /* first node */
4272 *children = node;
4273 } else {
4274 /* middle node */
4275 node->prev->next = node;
4276 }
Michal Vasko795b3752020-07-13 15:24:27 +02004277 }
Michal Vasko20424b42020-08-31 12:29:38 +02004278 }
Radek Krejci056d0a82018-12-06 16:57:25 +01004279
Michal Vasko20424b42020-08-31 12:29:38 +02004280 /* check the name uniqueness (even for an only child, it may be in case) */
4281 if (lys_compile_node_uniqness(ctx, parent, node->name, node)) {
4282 return LY_EEXIST;
4283 }
4284 } else {
4285 /* top-level element */
4286 if (!ctx->mod->compiled->data) {
4287 ctx->mod->compiled->data = node;
4288 } else {
4289 /* insert at the end of the module's top-level nodes list */
4290 ctx->mod->compiled->data->prev->next = node;
4291 node->prev = ctx->mod->compiled->data->prev;
4292 ctx->mod->compiled->data->prev = node;
4293 }
4294
4295 /* check the name uniqueness on top-level */
4296 if (lys_compile_node_uniqness(ctx, NULL, node->name, node)) {
4297 return LY_EEXIST;
Radek Krejci056d0a82018-12-06 16:57:25 +01004298 }
4299 }
Michal Vasko20424b42020-08-31 12:29:38 +02004300
Radek Krejci056d0a82018-12-06 16:57:25 +01004301 return LY_SUCCESS;
4302}
4303
Radek Krejci95710c92019-02-11 15:49:55 +01004304/**
Radek Krejcib56c7502019-02-13 14:19:54 +01004305 * @brief Prepare the case structure in choice node for the new data node.
4306 *
4307 * 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
4308 * created in the choice when the first child was processed.
4309 *
4310 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02004311 * @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,
Radek Krejci39424802020-08-12 09:31:00 +02004312 * it is the LYS_CHOICE, LYS_AUGMENT or LYS_GROUPING node.
Radek Krejcib56c7502019-02-13 14:19:54 +01004313 * @param[in] ch The compiled choice structure where the new case structures are created (if needed).
4314 * @param[in] child The new data node being part of a case (no matter if explicit or implicit).
4315 * @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,
4316 * it is linked from the case structure only in case it is its first child.
Radek Krejci95710c92019-02-11 15:49:55 +01004317 */
Michal Vasko20424b42020-08-31 12:29:38 +02004318static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004319lys_compile_node_case(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci056d0a82018-12-06 16:57:25 +01004320{
Michal Vasko20424b42020-08-31 12:29:38 +02004321 struct lysp_node *child_p;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004322 struct lysp_node_case *cs_p = (struct lysp_node_case *)pnode;
Radek Krejci056d0a82018-12-06 16:57:25 +01004323
Michal Vasko7f45cf22020-10-01 12:49:44 +02004324 if (pnode->nodetype & (LYS_CHOICE | LYS_AUGMENT | LYS_GROUPING)) {
Radek Krejci056d0a82018-12-06 16:57:25 +01004325 /* we have to add an implicit case node into the parent choice */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004326 } else if (pnode->nodetype == LYS_CASE) {
Michal Vasko20424b42020-08-31 12:29:38 +02004327 /* explicit parent case */
4328 LY_LIST_FOR(cs_p->child, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004329 LY_CHECK_RET(lys_compile_node(ctx, child_p, node, 0, NULL));
Radek Krejci056d0a82018-12-06 16:57:25 +01004330 }
Radek Krejci95710c92019-02-11 15:49:55 +01004331 } else {
Michal Vasko20424b42020-08-31 12:29:38 +02004332 LOGINT_RET(ctx->ctx);
Radek Krejci056d0a82018-12-06 16:57:25 +01004333 }
Radek Krejci056d0a82018-12-06 16:57:25 +01004334
Michal Vasko20424b42020-08-31 12:29:38 +02004335 return LY_SUCCESS;
Radek Krejci056d0a82018-12-06 16:57:25 +01004336}
4337
Radek Krejcib56c7502019-02-13 14:19:54 +01004338/**
Radek Krejcib56c7502019-02-13 14:19:54 +01004339 * @brief Set LYS_MAND_TRUE flag for the non-presence container parents.
4340 *
4341 * A non-presence container is mandatory in case it has at least one mandatory children. This function propagate
4342 * the flag to such parents from a mandatory children.
4343 *
4344 * @param[in] parent A schema node to be examined if the mandatory child make it also mandatory.
4345 * @param[in] add Flag to distinguish adding the mandatory flag (new mandatory children appeared) or removing the flag
4346 * (mandatory children was removed).
4347 */
Radek Krejci1deb5be2020-08-26 16:43:36 +02004348static void
Radek Krejci857189e2020-09-01 13:26:36 +02004349lys_compile_mandatory_parents(struct lysc_node *parent, ly_bool add)
Radek Krejcife909632019-02-12 15:34:42 +01004350{
4351 struct lysc_node *iter;
4352
4353 if (add) { /* set flag */
Michal Vaskod989ba02020-08-24 10:59:24 +02004354 for ( ; parent && parent->nodetype == LYS_CONTAINER && !(parent->flags & LYS_MAND_TRUE) && !(parent->flags & LYS_PRESENCE);
Radek Krejcife909632019-02-12 15:34:42 +01004355 parent = parent->parent) {
4356 parent->flags |= LYS_MAND_TRUE;
4357 }
4358 } else { /* unset flag */
Michal Vaskod989ba02020-08-24 10:59:24 +02004359 for ( ; parent && parent->nodetype == LYS_CONTAINER && (parent->flags & LYS_MAND_TRUE); parent = parent->parent) {
Michal Vasko22df3f02020-08-24 13:29:22 +02004360 for (iter = (struct lysc_node *)lysc_node_children(parent, 0); iter; iter = iter->next) {
Radek Krejcif1421c22019-02-19 13:05:20 +01004361 if (iter->flags & LYS_MAND_TRUE) {
Radek Krejcife909632019-02-12 15:34:42 +01004362 /* there is another mandatory node */
4363 return;
4364 }
4365 }
4366 /* unset mandatory flag - there is no mandatory children in the non-presence container */
4367 parent->flags &= ~LYS_MAND_TRUE;
4368 }
4369 }
4370}
4371
Radek Krejci056d0a82018-12-06 16:57:25 +01004372/**
Radek Krejci3641f562019-02-13 15:38:40 +01004373 * @brief Compile the parsed augment connecting it into its target.
4374 *
4375 * It is expected that all the data referenced in path are present - augments are ordered so that augment B
4376 * targeting data from augment A is being compiled after augment A. Also the modules referenced in the path
4377 * are already implemented and compiled.
4378 *
4379 * @param[in] ctx Compile context.
4380 * @param[in] aug_p Parsed augment to compile.
Michal Vasko7f45cf22020-10-01 12:49:44 +02004381 * @param[in] target Target node of the augment.
Radek Krejci3641f562019-02-13 15:38:40 +01004382 * @return LY_SUCCESS on success.
4383 * @return LY_EVALID on failure.
4384 */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004385static LY_ERR
4386lys_compile_augment(struct lysc_ctx *ctx, struct lysp_augment *aug_p, struct lysc_node *target)
Radek Krejci3641f562019-02-13 15:38:40 +01004387{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004388 LY_ERR ret = LY_SUCCESS;
4389 struct lysp_node *pnode;
Radek Krejci3641f562019-02-13 15:38:40 +01004390 struct lysc_node *node;
Radek Krejci3641f562019-02-13 15:38:40 +01004391 struct lysc_when **when, *when_shared;
Radek Krejci857189e2020-09-01 13:26:36 +02004392 ly_bool allow_mandatory = 0;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004393 LY_ARRAY_COUNT_TYPE u;
4394 struct ly_set child_set = {0};
4395 uint32_t i;
Radek Krejci3641f562019-02-13 15:38:40 +01004396
Michal Vasko7f45cf22020-10-01 12:49:44 +02004397 if (!(target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF))) {
4398 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
4399 "Augment's %s-schema-nodeid \"%s\" refers to a %s node which is not an allowed augment's target.",
4400 aug_p->nodeid[0] == '/' ? "absolute" : "descendant", aug_p->nodeid, lys_nodetype2str(target->nodetype));
4401 ret = LY_EVALID;
4402 goto cleanup;
Radek Krejci3641f562019-02-13 15:38:40 +01004403 }
4404
4405 /* check for mandatory nodes
4406 * - new cases augmenting some choice can have mandatory nodes
4407 * - mandatory nodes are allowed only in case the augmentation is made conditional with a when statement
4408 */
Radek Krejci733988a2019-02-15 15:12:44 +01004409 if (aug_p->when || target->nodetype == LYS_CHOICE || ctx->mod == target->module) {
Radek Krejci3641f562019-02-13 15:38:40 +01004410 allow_mandatory = 1;
4411 }
4412
4413 when_shared = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004414 LY_LIST_FOR(aug_p->child, pnode) {
Radek Krejci3641f562019-02-13 15:38:40 +01004415 /* check if the subnode can be connected to the found target (e.g. case cannot be inserted into container) */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004416 if ((pnode->nodetype == LYS_CASE && target->nodetype != LYS_CHOICE)
4417 || ((pnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && !(target->nodetype & (LYS_CONTAINER | LYS_LIST)))
4418 || (pnode->nodetype == LYS_USES && target->nodetype == LYS_CHOICE)) {
Radek Krejci3641f562019-02-13 15:38:40 +01004419 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejci327de162019-06-14 12:52:07 +02004420 "Invalid augment of %s node which is not allowed to contain %s node \"%s\".",
Michal Vasko7f45cf22020-10-01 12:49:44 +02004421 lys_nodetype2str(target->nodetype), lys_nodetype2str(pnode->nodetype), pnode->name);
4422 ret = LY_EVALID;
4423 goto cleanup;
Radek Krejci3641f562019-02-13 15:38:40 +01004424 }
4425
4426 /* compile the children */
Michal Vasko20424b42020-08-31 12:29:38 +02004427 if (target->nodetype == LYS_CHOICE) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004428 LY_CHECK_GOTO(ret = lys_compile_node_choice_child(ctx, pnode, target, &child_set), cleanup);
Radek Krejci3641f562019-02-13 15:38:40 +01004429 } else {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004430 LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
Radek Krejci3641f562019-02-13 15:38:40 +01004431 }
4432
Michal Vasko7f45cf22020-10-01 12:49:44 +02004433 /* since the augment node is not present in the compiled tree, we need to pass some of its
4434 * statements to all its children */
4435 for (i = 0; i < child_set.count; ++i) {
4436 node = child_set.snodes[i];
4437 if (!allow_mandatory && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
4438 node->flags &= ~LYS_MAND_TRUE;
4439 lys_compile_mandatory_parents(target, 0);
4440 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
4441 "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.", node->name);
4442 ret = LY_EVALID;
4443 goto cleanup;
Radek Krejci7c7783d2020-04-08 15:34:39 +02004444 }
Radek Krejci3641f562019-02-13 15:38:40 +01004445
Michal Vasko7f45cf22020-10-01 12:49:44 +02004446 /* pass augment's when to all the children TODO this way even action and notif should have "when" (code below) */
4447 if (aug_p->when) {
4448 LY_ARRAY_NEW_GOTO(ctx->ctx, node->when, when, ret, cleanup);
4449 if (!when_shared) {
4450 LY_CHECK_GOTO(ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, target, when), cleanup);
Radek Krejci3641f562019-02-13 15:38:40 +01004451
Michal Vasko7f45cf22020-10-01 12:49:44 +02004452 if (!(ctx->options & LYSC_OPT_GROUPING)) {
4453 /* do not check "when" semantics in a grouping */
4454 LY_CHECK_GOTO(ret = ly_set_add(&ctx->xpath, node, 0, NULL), cleanup);
4455 }
Michal Vasko175012e2019-11-06 15:49:14 +01004456
Michal Vasko7f45cf22020-10-01 12:49:44 +02004457 when_shared = *when;
4458 } else {
4459 ++when_shared->refcount;
4460 (*when) = when_shared;
Michal Vasko175012e2019-11-06 15:49:14 +01004461
Michal Vasko7f45cf22020-10-01 12:49:44 +02004462 if (!(ctx->options & LYSC_OPT_GROUPING)) {
4463 /* in this case check "when" again for all children because of dummy node check */
4464 LY_CHECK_GOTO(ret = ly_set_add(&ctx->xpath, node, 0, NULL), cleanup);
4465 }
Michal Vasko5c4e5892019-11-14 12:31:38 +01004466 }
Radek Krejci3641f562019-02-13 15:38:40 +01004467 }
4468 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004469 ly_set_erase(&child_set, NULL);
Radek Krejci3641f562019-02-13 15:38:40 +01004470 }
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004471
4472 switch (target->nodetype) {
4473 case LYS_CONTAINER:
Michal Vasko7f45cf22020-10-01 12:49:44 +02004474 COMPILE_OP_ARRAY_GOTO(ctx, aug_p->actions, ((struct lysc_node_container *)target)->actions, target,
4475 u, lys_compile_action, 0, ret, cleanup);
4476 COMPILE_OP_ARRAY_GOTO(ctx, aug_p->notifs, ((struct lysc_node_container *)target)->notifs, target,
4477 u, lys_compile_notif, 0, ret, cleanup);
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004478 break;
4479 case LYS_LIST:
Michal Vasko7f45cf22020-10-01 12:49:44 +02004480 COMPILE_OP_ARRAY_GOTO(ctx, aug_p->actions, ((struct lysc_node_list *)target)->actions, target,
4481 u, lys_compile_action, 0, ret, cleanup);
4482 COMPILE_OP_ARRAY_GOTO(ctx, aug_p->notifs, ((struct lysc_node_list *)target)->notifs, target,
4483 u, lys_compile_notif, 0, ret, cleanup);
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004484 break;
4485 default:
4486 if (aug_p->actions) {
4487 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejci327de162019-06-14 12:52:07 +02004488 "Invalid augment of %s node which is not allowed to contain RPC/action node \"%s\".",
4489 lys_nodetype2str(target->nodetype), aug_p->actions[0].name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004490 ret = LY_EVALID;
4491 goto cleanup;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004492 }
4493 if (aug_p->notifs) {
4494 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vaskoa3881362020-01-21 15:57:35 +01004495 "Invalid augment of %s node which is not allowed to contain notification node \"%s\".",
Radek Krejci327de162019-06-14 12:52:07 +02004496 lys_nodetype2str(target->nodetype), aug_p->notifs[0].name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004497 ret = LY_EVALID;
4498 goto cleanup;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004499 }
4500 }
Radek Krejci3641f562019-02-13 15:38:40 +01004501
Michal Vasko7f45cf22020-10-01 12:49:44 +02004502cleanup:
4503 ly_set_erase(&child_set, NULL);
Radek Krejci3641f562019-02-13 15:38:40 +01004504 return ret;
4505}
4506
4507/**
Michal Vasko601ddb32020-08-31 16:25:35 +02004508 * @brief Find grouping for a uses.
Radek Krejcie86bf772018-12-14 11:39:53 +01004509 *
Michal Vasko601ddb32020-08-31 16:25:35 +02004510 * @param[in] ctx Compile context.
4511 * @param[in] uses_p Parsed uses node.
4512 * @param[out] gpr_p Found grouping on success.
4513 * @param[out] grp_mod Module of @p grp_p on success.
4514 * @return LY_ERR value.
Radek Krejcie86bf772018-12-14 11:39:53 +01004515 */
4516static LY_ERR
Michal Vasko601ddb32020-08-31 16:25:35 +02004517lys_compile_uses_find_grouping(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, struct lysp_grp **grp_p,
4518 struct lys_module **grp_mod)
Radek Krejcie86bf772018-12-14 11:39:53 +01004519{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004520 struct lysp_node *pnode;
Michal Vasko601ddb32020-08-31 16:25:35 +02004521 struct lysp_grp *grp;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02004522 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci857189e2020-09-01 13:26:36 +02004523 ly_bool found = 0;
Radek Krejcie86bf772018-12-14 11:39:53 +01004524 const char *id, *name, *prefix;
4525 size_t prefix_len, name_len;
Michal Vasko601ddb32020-08-31 16:25:35 +02004526 struct lys_module *mod;
4527
4528 *grp_p = NULL;
4529 *grp_mod = NULL;
Radek Krejcie86bf772018-12-14 11:39:53 +01004530
4531 /* search for the grouping definition */
Radek Krejcie86bf772018-12-14 11:39:53 +01004532 id = uses_p->name;
Radek Krejcib4a4a272019-06-10 12:44:52 +02004533 LY_CHECK_RET(ly_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len), LY_EVALID);
Radek Krejcie86bf772018-12-14 11:39:53 +01004534 if (prefix) {
4535 mod = lys_module_find_prefix(ctx->mod_def, prefix, prefix_len);
4536 if (!mod) {
4537 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejci327de162019-06-14 12:52:07 +02004538 "Invalid prefix used for grouping reference.", uses_p->name);
Radek Krejcie86bf772018-12-14 11:39:53 +01004539 return LY_EVALID;
4540 }
4541 } else {
4542 mod = ctx->mod_def;
4543 }
4544 if (mod == ctx->mod_def) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004545 for (pnode = uses_p->parent; !found && pnode; pnode = pnode->parent) {
4546 grp = (struct lysp_grp *)lysp_node_groupings(pnode);
Radek Krejcie86bf772018-12-14 11:39:53 +01004547 LY_ARRAY_FOR(grp, u) {
4548 if (!strcmp(grp[u].name, name)) {
4549 grp = &grp[u];
4550 found = 1;
4551 break;
4552 }
4553 }
4554 }
4555 }
4556 if (!found) {
Radek Krejci76b3e962018-12-14 17:01:25 +01004557 /* search in top-level groupings of the main module ... */
Radek Krejcie86bf772018-12-14 11:39:53 +01004558 grp = mod->parsed->groupings;
Michal Vasko601ddb32020-08-31 16:25:35 +02004559 LY_ARRAY_FOR(grp, u) {
4560 if (!strcmp(grp[u].name, name)) {
4561 grp = &grp[u];
4562 found = 1;
4563 break;
Radek Krejci76b3e962018-12-14 17:01:25 +01004564 }
4565 }
Michal Vasko601ddb32020-08-31 16:25:35 +02004566 if (!found) {
Radek Krejci76b3e962018-12-14 17:01:25 +01004567 /* ... and all the submodules */
Michal Vasko601ddb32020-08-31 16:25:35 +02004568 LY_ARRAY_FOR(mod->parsed->includes, u) {
Radek Krejci76b3e962018-12-14 17:01:25 +01004569 grp = mod->parsed->includes[u].submodule->groupings;
Michal Vasko601ddb32020-08-31 16:25:35 +02004570 LY_ARRAY_FOR(grp, v) {
4571 if (!strcmp(grp[v].name, name)) {
4572 grp = &grp[v];
4573 found = 1;
4574 break;
Radek Krejci76b3e962018-12-14 17:01:25 +01004575 }
4576 }
Michal Vasko601ddb32020-08-31 16:25:35 +02004577 if (found) {
4578 break;
4579 }
Radek Krejcie86bf772018-12-14 11:39:53 +01004580 }
4581 }
4582 }
4583 if (!found) {
4584 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
4585 "Grouping \"%s\" referenced by a uses statement not found.", uses_p->name);
4586 return LY_EVALID;
4587 }
4588
Radek Krejcif2de0ed2019-05-02 14:13:18 +02004589 if (!(ctx->options & LYSC_OPT_GROUPING)) {
4590 /* remember that the grouping is instantiated to avoid its standalone validation */
4591 grp->flags |= LYS_USED_GRP;
4592 }
Radek Krejcie86bf772018-12-14 11:39:53 +01004593
Michal Vasko601ddb32020-08-31 16:25:35 +02004594 *grp_p = grp;
4595 *grp_mod = mod;
4596 return LY_SUCCESS;
4597}
Radek Krejcie86bf772018-12-14 11:39:53 +01004598
Michal Vasko7f45cf22020-10-01 12:49:44 +02004599static const struct lys_module *lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest,
4600 size_t nametest_len, const struct lys_module *local_mod, const char **name, size_t *name_len);
4601
Michal Vasko601ddb32020-08-31 16:25:35 +02004602static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004603lys_nodeid_check(struct lysc_ctx *ctx, const char *nodeid, ly_bool abs, struct lys_module **target_mod,
4604 struct lyxp_expr **expr)
Michal Vasko601ddb32020-08-31 16:25:35 +02004605{
Michal Vasko601ddb32020-08-31 16:25:35 +02004606 LY_ERR ret = LY_SUCCESS;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004607 struct lyxp_expr *e = NULL;
4608 struct lys_module *tmod = NULL, *mod;
4609 const char *nodeid_type = abs ? "absolute-schema-nodeid" : "descendant-schema-nodeid";
4610 uint32_t i;
Radek Krejcie86bf772018-12-14 11:39:53 +01004611
Michal Vasko7f45cf22020-10-01 12:49:44 +02004612 /* parse */
4613 ret = lyxp_expr_parse(ctx->ctx, nodeid, strlen(nodeid), 0, &e);
4614 if (ret) {
4615 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid %s value \"%s\" - invalid syntax.",
4616 nodeid_type, nodeid);
4617 ret = LY_EVALID;
4618 goto cleanup;
Radek Krejci01342af2019-01-03 15:18:08 +01004619 }
Radek Krejcie86bf772018-12-14 11:39:53 +01004620
Michal Vasko7f45cf22020-10-01 12:49:44 +02004621 if (abs) {
4622 /* absolute schema nodeid */
4623 i = 0;
4624 } else {
4625 /* descendant schema nodeid */
4626 if (e->tokens[0] != LYXP_TOKEN_NAMETEST) {
4627 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
4628 nodeid_type, nodeid, e->tok_len[0], e->expr + e->tok_pos[0]);
Michal Vasko20424b42020-08-31 12:29:38 +02004629 ret = LY_EVALID;
Radek Krejcifc11bd72019-04-11 16:00:05 +02004630 goto cleanup;
Radek Krejcif2271f12019-01-07 16:42:23 +01004631 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004632 i = 1;
4633 }
Radek Krejcif2271f12019-01-07 16:42:23 +01004634
Michal Vasko7f45cf22020-10-01 12:49:44 +02004635 /* check all the tokens */
4636 for ( ; i < e->used; i += 2) {
4637 if (e->tokens[i] != LYXP_TOKEN_OPER_PATH) {
4638 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s value \"%s\" - \"/\" expected instead of \"%.*s\".",
4639 nodeid_type, nodeid, e->tok_len[i], e->expr + e->tok_pos[i]);
4640 ret = LY_EVALID;
4641 goto cleanup;
4642 } else if (e->used == i + 1) {
4643 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
4644 "Invalid %s value \"%s\" - unexpected end of expression.", nodeid_type, e->expr);
4645 ret = LY_EVALID;
4646 goto cleanup;
4647 } else if (e->tokens[i + 1] != LYXP_TOKEN_NAMETEST) {
4648 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
4649 nodeid_type, nodeid, e->tok_len[i + 1], e->expr + e->tok_pos[i + 1]);
4650 ret = LY_EVALID;
4651 goto cleanup;
4652 } else if (abs) {
4653 mod = (struct lys_module *)lys_schema_node_get_module(ctx->ctx, e->expr + e->tok_pos[i + 1],
4654 e->tok_len[i + 1], ctx->mod_def, NULL, NULL);
4655 LY_CHECK_ERR_GOTO(!mod, ret = LY_EVALID, cleanup);
4656
4657 /* only keep the first module */
4658 if (!tmod) {
4659 tmod = mod;
Radek Krejcif2271f12019-01-07 16:42:23 +01004660 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004661
4662 /* all the modules must be implemented */
4663 if (!mod->implemented) {
4664 ret = lys_set_implemented_internal(mod, ctx->ctx->module_set_id);
4665 LY_CHECK_GOTO(ret, cleanup);
4666 }
4667 }
4668 }
4669
4670cleanup:
4671 if (ret || !expr) {
4672 lyxp_expr_free(ctx->ctx, e);
4673 e = NULL;
4674 }
4675 if (expr) {
4676 *expr = ret ? NULL : e;
4677 }
4678 if (target_mod) {
4679 *target_mod = ret ? NULL : tmod;
4680 }
4681 return ret;
4682}
4683
4684/**
4685 * @brief Check whether 2 schema nodeids match.
4686 *
4687 * @param[in] ctx libyang context.
4688 * @param[in] exp1 First schema nodeid.
4689 * @param[in] exp1_mod Module of @p exp1 nodes without any prefix.
4690 * @param[in] exp2 Second schema nodeid.
4691 * @param[in] exp2_mod Module of @p exp2 nodes without any prefix.
4692 * @return Whether the schema nodeids match or not.
4693 */
4694static ly_bool
4695lys_abs_schema_nodeid_match(const struct ly_ctx *ctx, const struct lyxp_expr *exp1, const struct lys_module *exp1_mod,
4696 const struct lyxp_expr *exp2, const struct lys_module *exp2_mod)
4697{
4698 uint32_t i;
4699 const struct lys_module *mod1, *mod2;
4700 const char *name1, *name2;
4701 size_t name1_len, name2_len;
4702
4703 if (exp1->used != exp2->used) {
4704 return 0;
4705 }
4706
4707 for (i = 0; i < exp1->used; ++i) {
4708 assert(exp1->tokens[i] == exp2->tokens[i]);
4709
4710 if (exp1->tokens[i] == LYXP_TOKEN_NAMETEST) {
4711 /* check modules of all the nodes in the node ID */
4712 mod1 = lys_schema_node_get_module(ctx, exp1->expr + exp1->tok_pos[i], exp1->tok_len[i], exp1_mod,
4713 &name1, &name1_len);
4714 assert(mod1);
4715 mod2 = lys_schema_node_get_module(ctx, exp2->expr + exp2->tok_pos[i], exp2->tok_len[i], exp2_mod,
4716 &name2, &name2_len);
4717 assert(mod2);
4718
4719 /* compare modules */
4720 if (mod1 != mod2) {
4721 return 0;
4722 }
4723
4724 /* compare names */
4725 if ((name1_len != name2_len) || strncmp(name1, name2, name1_len)) {
4726 return 0;
4727 }
4728 }
4729 }
4730
4731 return 1;
4732}
4733
4734/**
4735 * @brief Prepare any uses augments and refines in the context to be applied during uses descendant node compilation.
4736 *
4737 * @param[in] ctx Compile context.
4738 * @param[in] uses_p Parsed uses structure with augments and refines.
4739 * @param[in] ctx_node Context node of @p uses_p meaning its first data definiition parent.
4740 * @return LY_ERR value.
4741 */
4742static LY_ERR
4743lys_precompile_uses_augments_refines(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, const struct lysc_node *ctx_node)
4744{
4745 LY_ERR ret = LY_SUCCESS;
4746 LY_ARRAY_COUNT_TYPE u;
4747 struct lyxp_expr *exp = NULL;
4748 struct lysc_augment *aug;
4749 struct lysc_refine *rfn;
4750 struct lysp_refine **new_rfn;
4751 uint32_t i;
4752
4753 LY_ARRAY_FOR(uses_p->augments, u) {
4754 lysc_update_path(ctx, NULL, "{augment}");
4755 lysc_update_path(ctx, NULL, uses_p->augments[u].nodeid);
4756
4757 /* parse the nodeid */
4758 LY_CHECK_GOTO(ret = lys_nodeid_check(ctx, uses_p->augments[u].nodeid, 0, NULL, &exp), cleanup);
4759
4760 /* allocate new compiled augment and store it in the set */
4761 aug = calloc(1, sizeof *aug);
4762 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
4763 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_augs, aug, LY_SET_OPT_USEASLIST, NULL), cleanup);
4764
4765 aug->nodeid = exp;
4766 exp = NULL;
4767 aug->nodeid_ctx_node = ctx_node;
4768 aug->aug_p = &uses_p->augments[u];
4769
4770 lysc_update_path(ctx, NULL, NULL);
4771 lysc_update_path(ctx, NULL, NULL);
4772 }
4773
4774 LY_ARRAY_FOR(uses_p->refines, u) {
4775 lysc_update_path(ctx, NULL, "{refine}");
4776 lysc_update_path(ctx, NULL, uses_p->refines[u].nodeid);
4777
4778 /* parse the nodeid */
4779 LY_CHECK_GOTO(ret = lys_nodeid_check(ctx, uses_p->refines[u].nodeid, 0, NULL, &exp), cleanup);
4780
4781 /* try to find the node in already compiled refines */
4782 rfn = NULL;
4783 for (i = 0; i < ctx->uses_rfns.count; ++i) {
4784 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, ctx->mod_def, ((struct lysc_refine *)ctx->uses_rfns.objs[i])->nodeid,
4785 ctx->mod_def)) {
4786 rfn = ctx->uses_rfns.objs[i];
4787 break;
Radek Krejcif2271f12019-01-07 16:42:23 +01004788 }
4789 }
Michal Vasko601ddb32020-08-31 16:25:35 +02004790
Michal Vasko7f45cf22020-10-01 12:49:44 +02004791 if (!rfn) {
4792 /* allocate new compiled refine */
4793 rfn = calloc(1, sizeof *rfn);
4794 LY_CHECK_ERR_GOTO(!rfn, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
4795 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_rfns, rfn, LY_SET_OPT_USEASLIST, NULL), cleanup);
4796
4797 rfn->nodeid = exp;
4798 exp = NULL;
4799 rfn->nodeid_ctx_node = ctx_node;
4800 } else {
4801 /* just free exp */
4802 lyxp_expr_free(ctx->ctx, exp);
4803 exp = NULL;
4804 }
4805
4806 /* add new parsed refine structure */
4807 LY_ARRAY_NEW_GOTO(ctx->ctx, rfn->rfns, new_rfn, ret, cleanup);
4808 *new_rfn = &uses_p->refines[u];
4809
4810 lysc_update_path(ctx, NULL, NULL);
Michal Vasko601ddb32020-08-31 16:25:35 +02004811 lysc_update_path(ctx, NULL, NULL);
Radek Krejcif2271f12019-01-07 16:42:23 +01004812 }
4813
Michal Vasko601ddb32020-08-31 16:25:35 +02004814cleanup:
Michal Vasko7f45cf22020-10-01 12:49:44 +02004815 lyxp_expr_free(ctx->ctx, exp);
Michal Vasko601ddb32020-08-31 16:25:35 +02004816 return ret;
4817}
4818
4819/**
4820 * @brief Compile parsed uses statement - resolve target grouping and connect its content into parent.
4821 * If present, also apply uses's modificators.
4822 *
4823 * @param[in] ctx Compile context
4824 * @param[in] uses_p Parsed uses schema node.
4825 * @param[in] parent Compiled parent node where the content of the referenced grouping is supposed to be connected. It is
4826 * NULL for top-level nodes, in such a case the module where the node will be connected is taken from
4827 * the compile context.
4828 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
4829 */
4830static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004831lys_compile_uses(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, struct lysc_node *parent, struct ly_set *child_set)
Michal Vasko601ddb32020-08-31 16:25:35 +02004832{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004833 struct lysp_node *pnode;
4834 struct lysc_node *child;
Michal Vasko601ddb32020-08-31 16:25:35 +02004835 struct lysp_grp *grp = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004836 uint32_t i, grp_stack_count;
Michal Vasko601ddb32020-08-31 16:25:35 +02004837 struct lys_module *grp_mod, *mod_old;
4838 LY_ERR ret = LY_SUCCESS;
4839 struct lysc_when **when, *when_shared;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004840 LY_ARRAY_COUNT_TYPE u;
Michal Vasko601ddb32020-08-31 16:25:35 +02004841 struct lysc_notif **notifs = NULL;
4842 struct lysc_action **actions = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004843 struct ly_set uses_child_set = {0};
Michal Vasko601ddb32020-08-31 16:25:35 +02004844
4845 /* find the referenced grouping */
4846 LY_CHECK_RET(lys_compile_uses_find_grouping(ctx, uses_p, &grp, &grp_mod));
4847
4848 /* grouping must not reference themselves - stack in ctx maintains list of groupings currently being applied */
4849 grp_stack_count = ctx->groupings.count;
4850 LY_CHECK_RET(ly_set_add(&ctx->groupings, (void *)grp, 0, NULL));
4851 if (grp_stack_count == ctx->groupings.count) {
4852 /* the target grouping is already in the stack, so we are already inside it -> circular dependency */
4853 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
4854 "Grouping \"%s\" references itself through a uses statement.", grp->name);
4855 return LY_EVALID;
4856 }
4857
Michal Vasko7f45cf22020-10-01 12:49:44 +02004858 /* check status */
4859 ret = lysc_check_status(ctx, uses_p->flags, ctx->mod_def, uses_p->name, grp->flags, grp_mod, grp->name);
4860 LY_CHECK_GOTO(ret, cleanup);
4861
4862 /* compile any augments and refines so they can be applied during the grouping nodes compilation */
4863 ret = lys_precompile_uses_augments_refines(ctx, uses_p, parent);
4864 LY_CHECK_GOTO(ret, cleanup);
4865
Michal Vasko601ddb32020-08-31 16:25:35 +02004866 /* switch context's mod_def */
4867 mod_old = ctx->mod_def;
4868 ctx->mod_def = grp_mod;
4869
Michal Vasko601ddb32020-08-31 16:25:35 +02004870 /* compile data nodes */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004871 LY_LIST_FOR(grp->data, pnode) {
Michal Vasko601ddb32020-08-31 16:25:35 +02004872 /* 0x3 in uses_status is a special bits combination to be able to detect status flags from uses */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004873 ret = lys_compile_node(ctx, pnode, parent, (uses_p->flags & LYS_STATUS_MASK) | 0x3, &uses_child_set);
Michal Vasko601ddb32020-08-31 16:25:35 +02004874 LY_CHECK_GOTO(ret, cleanup);
4875 }
4876
Michal Vasko7f45cf22020-10-01 12:49:44 +02004877 if (child_set) {
4878 /* add these children to our compiled child_set as well since uses is a schema-only node */
4879 LY_CHECK_GOTO(ret = ly_set_merge(child_set, &uses_child_set, LY_SET_OPT_USEASLIST, NULL), cleanup);
Michal Vasko601ddb32020-08-31 16:25:35 +02004880 }
4881
Michal Vasko7f45cf22020-10-01 12:49:44 +02004882 if (uses_p->when) {
Michal Vasko601ddb32020-08-31 16:25:35 +02004883 /* pass uses's when to all the data children, actions and notifications are ignored */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004884 when_shared = NULL;
4885 for (i = 0; i < uses_child_set.count; ++i) {
4886 child = uses_child_set.snodes[i];
4887
4888 LY_ARRAY_NEW_GOTO(ctx->ctx, child->when, when, ret, cleanup);
Michal Vasko601ddb32020-08-31 16:25:35 +02004889 if (!when_shared) {
4890 ret = lys_compile_when(ctx, uses_p->when, uses_p->flags, parent, when);
4891 LY_CHECK_GOTO(ret, cleanup);
4892
4893 if (!(ctx->options & LYSC_OPT_GROUPING)) {
4894 /* do not check "when" semantics in a grouping */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004895 ret = ly_set_add(&ctx->xpath, child, 0, NULL);
Michal Vasko601ddb32020-08-31 16:25:35 +02004896 LY_CHECK_GOTO(ret, cleanup);
4897 }
4898
4899 when_shared = *when;
4900 } else {
4901 ++when_shared->refcount;
4902 (*when) = when_shared;
4903
4904 if (!(ctx->options & LYSC_OPT_GROUPING)) {
4905 /* in this case check "when" again for all children because of dummy node check */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004906 ret = ly_set_add(&ctx->xpath, child, 0, NULL);
Michal Vasko601ddb32020-08-31 16:25:35 +02004907 LY_CHECK_GOTO(ret, cleanup);
4908 }
4909 }
4910 }
4911 }
4912
4913 /* compile actions */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004914 if (grp->actions) {
4915 actions = parent ? lysc_node_actions_p(parent) : &ctx->mod->compiled->rpcs;
4916 if (!actions) {
4917 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid child %s \"%s\" of uses parent %s \"%s\" node.",
4918 grp->actions[0].name, lys_nodetype2str(grp->actions[0].nodetype), parent->name,
4919 lys_nodetype2str(parent->nodetype));
4920 ret = LY_EVALID;
4921 goto cleanup;
Michal Vasko601ddb32020-08-31 16:25:35 +02004922 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004923 COMPILE_OP_ARRAY_GOTO(ctx, grp->actions, *actions, parent, u, lys_compile_action, 0, ret, cleanup);
Michal Vasko601ddb32020-08-31 16:25:35 +02004924 }
4925
4926 /* compile notifications */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004927 if (grp->notifs) {
4928 notifs = parent ? lysc_node_notifs_p(parent) : &ctx->mod->compiled->notifs;
4929 if (!notifs) {
4930 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid child %s \"%s\" of uses parent %s \"%s\" node.",
4931 grp->notifs[0].name, lys_nodetype2str(grp->notifs[0].nodetype), parent->name,
4932 lys_nodetype2str(parent->nodetype));
4933 ret = LY_EVALID;
4934 goto cleanup;
Michal Vasko601ddb32020-08-31 16:25:35 +02004935 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004936 COMPILE_OP_ARRAY_GOTO(ctx, grp->notifs, *notifs, parent, u, lys_compile_notif, 0, ret, cleanup);
Michal Vasko601ddb32020-08-31 16:25:35 +02004937 }
4938
Michal Vasko7f45cf22020-10-01 12:49:44 +02004939 /* check that all augments were applied */
4940 for (i = 0; i < ctx->uses_augs.count; ++i) {
4941 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
4942 "Augment target node \"%s\" in grouping \"%s\" was not found.",
4943 ((struct lysc_augment *)ctx->uses_augs.objs[i])->nodeid->expr, grp->name);
4944 ret = LY_ENOTFOUND;
Michal Vasko601ddb32020-08-31 16:25:35 +02004945 }
Michal Vasko601ddb32020-08-31 16:25:35 +02004946 LY_CHECK_GOTO(ret, cleanup);
4947
Michal Vasko7f45cf22020-10-01 12:49:44 +02004948 /* check that all refines were applied */
4949 for (i = 0; i < ctx->uses_rfns.count; ++i) {
4950 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
4951 "Refine(s) target node \"%s\" in grouping \"%s\" was not found.",
4952 ((struct lysc_refine *)ctx->uses_rfns.objs[i])->nodeid->expr, grp->name);
4953 ret = LY_ENOTFOUND;
Radek Krejcic6b4f442020-08-12 14:45:18 +02004954 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004955 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcifc11bd72019-04-11 16:00:05 +02004956
4957cleanup:
Radek Krejcie86bf772018-12-14 11:39:53 +01004958 /* reload previous context's mod_def */
4959 ctx->mod_def = mod_old;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004960
Radek Krejcie86bf772018-12-14 11:39:53 +01004961 /* remove the grouping from the stack for circular groupings dependency check */
4962 ly_set_rm_index(&ctx->groupings, ctx->groupings.count - 1, NULL);
4963 assert(ctx->groupings.count == grp_stack_count);
4964
Michal Vasko7f45cf22020-10-01 12:49:44 +02004965 ly_set_erase(&uses_child_set, NULL);
Radek Krejcie86bf772018-12-14 11:39:53 +01004966 return ret;
4967}
4968
Radek Krejci327de162019-06-14 12:52:07 +02004969static int
4970lys_compile_grouping_pathlog(struct lysc_ctx *ctx, struct lysp_node *node, char **path)
4971{
4972 struct lysp_node *iter;
4973 int len = 0;
4974
4975 *path = NULL;
4976 for (iter = node; iter && len >= 0; iter = iter->parent) {
4977 char *s = *path;
4978 char *id;
4979
4980 switch (iter->nodetype) {
4981 case LYS_USES:
Radek Krejci200f1062020-07-11 22:51:03 +02004982 LY_CHECK_RET(asprintf(&id, "{uses='%s'}", iter->name) == -1, -1);
Radek Krejci327de162019-06-14 12:52:07 +02004983 break;
4984 case LYS_GROUPING:
Radek Krejci200f1062020-07-11 22:51:03 +02004985 LY_CHECK_RET(asprintf(&id, "{grouping='%s'}", iter->name) == -1, -1);
Radek Krejci327de162019-06-14 12:52:07 +02004986 break;
4987 case LYS_AUGMENT:
Radek Krejci200f1062020-07-11 22:51:03 +02004988 LY_CHECK_RET(asprintf(&id, "{augment='%s'}", iter->name) == -1, -1);
Radek Krejci327de162019-06-14 12:52:07 +02004989 break;
4990 default:
4991 id = strdup(iter->name);
4992 break;
4993 }
4994
4995 if (!iter->parent) {
4996 /* print prefix */
4997 len = asprintf(path, "/%s:%s%s", ctx->mod->name, id, s ? s : "");
4998 } else {
4999 /* prefix is the same as in parent */
5000 len = asprintf(path, "/%s%s", id, s ? s : "");
5001 }
5002 free(s);
5003 free(id);
5004 }
5005
5006 if (len < 0) {
5007 free(*path);
5008 *path = NULL;
5009 } else if (len == 0) {
5010 *path = strdup("/");
5011 len = 1;
5012 }
5013 return len;
5014}
5015
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005016/**
5017 * @brief Validate groupings that were defined but not directly used in the schema itself.
5018 *
5019 * The grouping does not need to be compiled (and it is compiled here, but the result is forgotten immediately),
5020 * but to have the complete result of the schema validity, even such groupings are supposed to be checked.
5021 */
5022static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02005023lys_compile_grouping(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysp_grp *grp)
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005024{
5025 LY_ERR ret;
Radek Krejci327de162019-06-14 12:52:07 +02005026 char *path;
5027 int len;
5028
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005029 struct lysp_node_uses fake_uses = {
Michal Vasko7f45cf22020-10-01 12:49:44 +02005030 .parent = pnode,
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005031 .nodetype = LYS_USES,
5032 .flags = 0, .next = NULL,
5033 .name = grp->name,
5034 .dsc = NULL, .ref = NULL, .when = NULL, .iffeatures = NULL, .exts = NULL,
5035 .refines = NULL, .augments = NULL
5036 };
5037 struct lysc_node_container fake_container = {
5038 .nodetype = LYS_CONTAINER,
Michal Vasko7f45cf22020-10-01 12:49:44 +02005039 .flags = pnode ? (pnode->flags & LYS_FLAGS_COMPILED_MASK) : 0,
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005040 .module = ctx->mod,
5041 .sp = NULL, .parent = NULL, .next = NULL,
Michal Vasko22df3f02020-08-24 13:29:22 +02005042 .prev = (struct lysc_node *)&fake_container,
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005043 .name = "fake",
5044 .dsc = NULL, .ref = NULL, .exts = NULL, .iffeatures = NULL, .when = NULL,
5045 .child = NULL, .musts = NULL, .actions = NULL, .notifs = NULL
5046 };
5047
5048 if (grp->parent) {
5049 LOGWRN(ctx->ctx, "Locally scoped grouping \"%s\" not used.", grp->name);
5050 }
Radek Krejci327de162019-06-14 12:52:07 +02005051
5052 len = lys_compile_grouping_pathlog(ctx, grp->parent, &path);
5053 if (len < 0) {
5054 LOGMEM(ctx->ctx);
5055 return LY_EMEM;
5056 }
5057 strncpy(ctx->path, path, LYSC_CTX_BUFSIZE - 1);
Radek Krejci1deb5be2020-08-26 16:43:36 +02005058 ctx->path_len = (uint32_t)len;
Radek Krejci327de162019-06-14 12:52:07 +02005059 free(path);
5060
5061 lysc_update_path(ctx, NULL, "{grouping}");
5062 lysc_update_path(ctx, NULL, grp->name);
Michal Vasko22df3f02020-08-24 13:29:22 +02005063 ret = lys_compile_uses(ctx, &fake_uses, (struct lysc_node *)&fake_container, NULL);
Radek Krejci327de162019-06-14 12:52:07 +02005064 lysc_update_path(ctx, NULL, NULL);
5065 lysc_update_path(ctx, NULL, NULL);
5066
5067 ctx->path_len = 1;
5068 ctx->path[1] = '\0';
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005069
5070 /* cleanup */
5071 lysc_node_container_free(ctx->ctx, &fake_container);
5072
5073 return ret;
5074}
Radek Krejcife909632019-02-12 15:34:42 +01005075
Radek Krejcie86bf772018-12-14 11:39:53 +01005076/**
Michal Vasko20424b42020-08-31 12:29:38 +02005077 * @brief Set config flags for a node.
5078 *
5079 * @param[in] ctx Compile context.
5080 * @param[in] node Compiled node config to set.
5081 * @param[in] parent Parent of @p node.
5082 * @return LY_ERR value.
5083 */
5084static LY_ERR
5085lys_compile_config(struct lysc_ctx *ctx, struct lysc_node *node, struct lysc_node *parent)
5086{
5087 if (node->nodetype == LYS_CASE) {
5088 /* case never has any config */
5089 assert(!(node->flags & LYS_CONFIG_MASK));
5090 return LY_SUCCESS;
5091 }
5092
5093 /* adjust parent to always get the ancestor with config */
5094 if (parent && (parent->nodetype == LYS_CASE)) {
5095 parent = parent->parent;
5096 assert(parent);
5097 }
5098
5099 if (ctx->options & (LYSC_OPT_RPC_INPUT | LYSC_OPT_RPC_OUTPUT)) {
5100 /* ignore config statements inside RPC/action data */
5101 node->flags &= ~LYS_CONFIG_MASK;
5102 node->flags |= (ctx->options & LYSC_OPT_RPC_INPUT) ? LYS_CONFIG_W : LYS_CONFIG_R;
5103 } else if (ctx->options & LYSC_OPT_NOTIFICATION) {
5104 /* ignore config statements inside Notification data */
5105 node->flags &= ~LYS_CONFIG_MASK;
5106 node->flags |= LYS_CONFIG_R;
5107 } else if (!(node->flags & LYS_CONFIG_MASK)) {
5108 /* config not explicitely set, inherit it from parent */
5109 if (parent) {
5110 node->flags |= parent->flags & LYS_CONFIG_MASK;
5111 } else {
5112 /* default is config true */
5113 node->flags |= LYS_CONFIG_W;
5114 }
5115 } else {
5116 /* config set explicitely */
5117 node->flags |= LYS_SET_CONFIG;
5118 }
5119
5120 if (parent && (parent->flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
5121 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
5122 "Configuration node cannot be child of any state data node.");
5123 return LY_EVALID;
5124 }
5125
5126 return LY_SUCCESS;
5127}
5128
Michal Vasko7f45cf22020-10-01 12:49:44 +02005129static LY_ERR
5130lysp_ext_dup(const struct ly_ctx *ctx, struct lysp_ext_instance *ext, const struct lysp_ext_instance *orig_ext)
5131{
5132 LY_ERR ret = LY_SUCCESS;
5133
5134 *ext = *orig_ext;
5135 DUP_STRING(ctx, orig_ext->name, ext->name, ret);
5136 DUP_STRING(ctx, orig_ext->argument, ext->argument, ret);
5137
5138 return ret;
5139}
5140
5141static LY_ERR
5142lysp_restr_dup(const struct ly_ctx *ctx, struct lysp_restr *restr, const struct lysp_restr *orig_restr)
5143{
5144 LY_ERR ret = LY_SUCCESS;
5145
5146 if (orig_restr) {
5147 DUP_STRING(ctx, orig_restr->arg.str, restr->arg.str, ret);
5148 restr->arg.mod = orig_restr->arg.mod;
5149 DUP_STRING(ctx, orig_restr->emsg, restr->emsg, ret);
5150 DUP_STRING(ctx, orig_restr->eapptag, restr->eapptag, ret);
5151 DUP_STRING(ctx, orig_restr->dsc, restr->dsc, ret);
5152 DUP_STRING(ctx, orig_restr->ref, restr->ref, ret);
5153 DUP_ARRAY(ctx, orig_restr->exts, restr->exts, lysp_ext_dup);
5154 }
5155
5156 return ret;
5157}
5158
5159static LY_ERR
5160lysp_string_dup(const struct ly_ctx *ctx, const char **str, const char **orig_str)
5161{
5162 LY_ERR ret = LY_SUCCESS;
5163
5164 DUP_STRING(ctx, *orig_str, *str, ret);
5165
5166 return ret;
5167}
5168
5169static LY_ERR
5170lysp_qname_dup(const struct ly_ctx *ctx, struct lysp_qname *qname, const struct lysp_qname *orig_qname)
5171{
5172 LY_ERR ret = LY_SUCCESS;
5173
5174 DUP_STRING(ctx, orig_qname->str, qname->str, ret);
5175 qname->mod = orig_qname->mod;
5176
5177 return ret;
5178}
5179
5180static LY_ERR
5181lysp_type_enum_dup(const struct ly_ctx *ctx, struct lysp_type_enum *enm, const struct lysp_type_enum *orig_enm)
5182{
5183 LY_ERR ret = LY_SUCCESS;
5184
5185 DUP_STRING(ctx, orig_enm->name, enm->name, ret);
5186 DUP_STRING(ctx, orig_enm->dsc, enm->dsc, ret);
5187 DUP_STRING(ctx, orig_enm->ref, enm->ref, ret);
5188 enm->value = orig_enm->value;
5189 DUP_ARRAY(ctx, orig_enm->iffeatures, enm->iffeatures, lysp_qname_dup);
5190 DUP_ARRAY(ctx, orig_enm->exts, enm->exts, lysp_ext_dup);
5191 enm->flags = orig_enm->flags;
5192
5193 return ret;
5194}
5195
5196static LY_ERR
5197lysp_type_dup(const struct ly_ctx *ctx, struct lysp_type *type, const struct lysp_type *orig_type)
5198{
5199 LY_ERR ret = LY_SUCCESS;
5200
5201 DUP_STRING_GOTO(ctx, orig_type->name, type->name, ret, done);
5202
5203 if (orig_type->range) {
5204 type->range = calloc(1, sizeof *type->range);
5205 LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx), LY_EMEM);
5206 LY_CHECK_RET(lysp_restr_dup(ctx, type->range, orig_type->range));
5207 }
5208
5209 if (orig_type->length) {
5210 type->length = calloc(1, sizeof *type->length);
5211 LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx), LY_EMEM);
5212 LY_CHECK_RET(lysp_restr_dup(ctx, type->length, orig_type->length));
5213 }
5214
5215 DUP_ARRAY(ctx, orig_type->patterns, type->patterns, lysp_restr_dup);
5216 DUP_ARRAY(ctx, orig_type->enums, type->enums, lysp_type_enum_dup);
5217 DUP_ARRAY(ctx, orig_type->bits, type->bits, lysp_type_enum_dup);
5218 LY_CHECK_GOTO(ret = lyxp_expr_dup(ctx, orig_type->path, &type->path), done);
5219 DUP_ARRAY(ctx, orig_type->bases, type->bases, lysp_string_dup);
5220 DUP_ARRAY(ctx, orig_type->types, type->types, lysp_type_dup);
5221 DUP_ARRAY(ctx, orig_type->exts, type->exts, lysp_ext_dup);
5222
5223 type->compiled = orig_type->compiled;
5224
5225 type->fraction_digits = orig_type->fraction_digits;
5226 type->require_instance = orig_type->require_instance;
5227 type->flags = orig_type->flags;
5228
5229done:
5230 return ret;
5231}
5232
5233static LY_ERR
5234lysp_when_dup(const struct ly_ctx *ctx, struct lysp_when *when, const struct lysp_when *orig_when)
5235{
5236 LY_ERR ret = LY_SUCCESS;
5237
5238 DUP_STRING(ctx, orig_when->cond, when->cond, ret);
5239 DUP_STRING(ctx, orig_when->dsc, when->dsc, ret);
5240 DUP_STRING(ctx, orig_when->ref, when->ref, ret);
5241 DUP_ARRAY(ctx, orig_when->exts, when->exts, lysp_ext_dup);
5242
5243 return ret;
5244}
5245
5246static LY_ERR
5247lysp_node_common_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
5248{
5249 LY_ERR ret = LY_SUCCESS;
5250
5251 node->parent = NULL;
5252 node->nodetype = orig->nodetype;
5253 node->flags = orig->flags;
5254 node->next = NULL;
5255 DUP_STRING(ctx, orig->name, node->name, ret);
5256 DUP_STRING(ctx, orig->dsc, node->dsc, ret);
5257 DUP_STRING(ctx, orig->ref, node->ref, ret);
5258
5259 if (orig->when) {
5260 node->when = calloc(1, sizeof *node->when);
5261 LY_CHECK_ERR_RET(!node->when, LOGMEM(ctx), LY_EMEM);
5262 LY_CHECK_RET(lysp_when_dup(ctx, node->when, orig->when));
5263 }
5264
5265 DUP_ARRAY(ctx, orig->iffeatures, node->iffeatures, lysp_qname_dup);
5266 DUP_ARRAY(ctx, orig->exts, node->exts, lysp_ext_dup);
5267
5268 return ret;
5269}
5270
5271static LY_ERR
5272lysp_node_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
5273{
5274 LY_ERR ret = LY_SUCCESS;
5275 struct lysp_node_container *cont;
5276 const struct lysp_node_container *orig_cont;
5277 struct lysp_node_leaf *leaf;
5278 const struct lysp_node_leaf *orig_leaf;
5279 struct lysp_node_leaflist *llist;
5280 const struct lysp_node_leaflist *orig_llist;
5281 struct lysp_node_list *list;
5282 const struct lysp_node_list *orig_list;
5283 struct lysp_node_choice *choice;
5284 const struct lysp_node_choice *orig_choice;
5285 struct lysp_node_case *cas;
5286 const struct lysp_node_case *orig_cas;
5287 struct lysp_node_anydata *any;
5288 const struct lysp_node_anydata *orig_any;
5289
5290 assert(orig->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_ANYDATA));
5291
5292 /* common part */
5293 LY_CHECK_RET(lysp_node_common_dup(ctx, node, orig));
5294
5295 /* specific part */
5296 switch (node->nodetype) {
5297 case LYS_CONTAINER:
5298 cont = (struct lysp_node_container *)node;
5299 orig_cont = (const struct lysp_node_container *)orig;
5300
5301 DUP_ARRAY(ctx, orig_cont->musts, cont->musts, lysp_restr_dup);
5302 DUP_STRING(ctx, orig_cont->presence, cont->presence, ret);
5303 /* we do not need the rest */
5304 break;
5305 case LYS_LEAF:
5306 leaf = (struct lysp_node_leaf *)node;
5307 orig_leaf = (const struct lysp_node_leaf *)orig;
5308
5309 DUP_ARRAY(ctx, orig_leaf->musts, leaf->musts, lysp_restr_dup);
5310 LY_CHECK_RET(lysp_type_dup(ctx, &leaf->type, &orig_leaf->type));
5311 DUP_STRING(ctx, orig_leaf->units, leaf->units, ret);
5312 DUP_STRING(ctx, orig_leaf->dflt.str, leaf->dflt.str, ret);
5313 break;
5314 case LYS_LEAFLIST:
5315 llist = (struct lysp_node_leaflist *)node;
5316 orig_llist = (const struct lysp_node_leaflist *)orig;
5317
5318 DUP_ARRAY(ctx, orig_llist->musts, llist->musts, lysp_restr_dup);
5319 LY_CHECK_RET(lysp_type_dup(ctx, &llist->type, &orig_llist->type));
5320 DUP_STRING(ctx, orig_llist->units, llist->units, ret);
5321 DUP_ARRAY(ctx, orig_llist->dflts, llist->dflts, lysp_qname_dup);
5322 llist->min = orig_llist->min;
5323 llist->max = orig_llist->max;
5324 break;
5325 case LYS_LIST:
5326 list = (struct lysp_node_list *)node;
5327 orig_list = (const struct lysp_node_list *)orig;
5328
5329 DUP_ARRAY(ctx, orig_list->musts, list->musts, lysp_restr_dup);
5330 DUP_STRING(ctx, orig_list->key, list->key, ret);
5331 /* we do not need these arrays */
5332 DUP_ARRAY(ctx, orig_list->uniques, list->uniques, lysp_qname_dup);
5333 list->min = orig_list->min;
5334 list->max = orig_list->max;
5335 break;
5336 case LYS_CHOICE:
5337 choice = (struct lysp_node_choice *)node;
5338 orig_choice = (const struct lysp_node_choice *)orig;
5339
5340 /* we do not need children */
5341 LY_CHECK_RET(lysp_qname_dup(ctx, &choice->dflt, &orig_choice->dflt));
5342 break;
5343 case LYS_CASE:
5344 cas = (struct lysp_node_case *)node;
5345 orig_cas = (const struct lysp_node_case *)orig;
5346
5347 /* we do not need children */
5348 (void)cas;
5349 (void)orig_cas;
5350 break;
5351 case LYS_ANYDATA:
5352 case LYS_ANYXML:
5353 any = (struct lysp_node_anydata *)node;
5354 orig_any = (const struct lysp_node_anydata *)orig;
5355
5356 DUP_ARRAY(ctx, orig_any->musts, any->musts, lysp_restr_dup);
5357 break;
5358 default:
5359 LOGINT_RET(ctx);
5360 }
5361
5362 return ret;
5363}
5364
5365static LY_ERR
5366lysp_action_inout_dup(const struct ly_ctx *ctx, struct lysp_action_inout *inout, const struct lysp_action_inout *orig)
5367{
5368 inout->parent = NULL;
5369 inout->nodetype = orig->nodetype;
5370 DUP_ARRAY(ctx, orig->musts, inout->musts, lysp_restr_dup);
5371 /* we dot need these arrays */
5372 DUP_ARRAY(ctx, orig->exts, inout->exts, lysp_ext_dup);
5373
5374 return LY_SUCCESS;
5375}
5376
5377static LY_ERR
5378lysp_action_dup(const struct ly_ctx *ctx, struct lysp_action *act, const struct lysp_action *orig)
5379{
5380 LY_ERR ret = LY_SUCCESS;
5381
5382 act->parent = NULL;
5383 act->nodetype = orig->nodetype;
5384 act->flags = orig->flags;
5385 DUP_STRING(ctx, orig->name, act->name, ret);
5386 DUP_STRING(ctx, orig->dsc, act->dsc, ret);
5387 DUP_STRING(ctx, orig->ref, act->ref, ret);
5388 DUP_ARRAY(ctx, orig->iffeatures, act->iffeatures, lysp_qname_dup);
5389
5390 act->input.nodetype = orig->input.nodetype;
5391 act->output.nodetype = orig->output.nodetype;
5392 /* we do not need choldren of in/out */
5393 DUP_ARRAY(ctx, orig->exts, act->exts, lysp_ext_dup);
5394
5395 return ret;
5396}
5397
5398static LY_ERR
5399lysp_notif_dup(const struct ly_ctx *ctx, struct lysp_notif *notif, const struct lysp_notif *orig)
5400{
5401 LY_ERR ret = LY_SUCCESS;
5402
5403 notif->parent = NULL;
5404 notif->nodetype = orig->nodetype;
5405 notif->flags = orig->flags;
5406 DUP_STRING(ctx, orig->name, notif->name, ret);
5407 DUP_STRING(ctx, orig->dsc, notif->dsc, ret);
5408 DUP_STRING(ctx, orig->ref, notif->ref, ret);
5409 DUP_ARRAY(ctx, orig->iffeatures, notif->iffeatures, lysp_qname_dup);
5410 DUP_ARRAY(ctx, orig->musts, notif->musts, lysp_restr_dup);
5411 /* we do not need these arrays */
5412 DUP_ARRAY(ctx, orig->exts, notif->exts, lysp_ext_dup);
5413
5414 return ret;
5415}
5416
5417/**
5418 * @brief Duplicate a single parsed node. Only attributes that are used in compilation are copied.
5419 *
5420 * @param[in] ctx libyang context.
5421 * @param[in] pnode Node to duplicate.
5422 * @param[in] with_links Whether to also copy any links (child, parent pointers).
5423 * @param[out] dup_p Duplicated parsed node.
5424 * @return LY_ERR value.
5425 */
5426static LY_ERR
5427lysp_dup_single(const struct ly_ctx *ctx, const struct lysp_node *pnode, ly_bool with_links, struct lysp_node **dup_p)
5428{
5429 void *mem;
5430
5431 if (!pnode) {
5432 *dup_p = NULL;
5433 return LY_SUCCESS;
5434 }
5435
5436 switch (pnode->nodetype) {
5437 case LYS_CONTAINER:
5438 mem = calloc(1, sizeof(struct lysp_node_container));
5439 LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
5440 LY_CHECK_RET(lysp_node_dup(ctx, mem, pnode));
5441 break;
5442 case LYS_LEAF:
5443 mem = calloc(1, sizeof(struct lysp_node_leaf));
5444 LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
5445 LY_CHECK_RET(lysp_node_dup(ctx, mem, pnode));
5446 break;
5447 case LYS_LEAFLIST:
5448 mem = calloc(1, sizeof(struct lysp_node_leaflist));
5449 LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
5450 LY_CHECK_RET(lysp_node_dup(ctx, mem, pnode));
5451 break;
5452 case LYS_LIST:
5453 mem = calloc(1, sizeof(struct lysp_node_list));
5454 LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
5455 LY_CHECK_RET(lysp_node_dup(ctx, mem, pnode));
5456 break;
5457 case LYS_CHOICE:
5458 mem = calloc(1, sizeof(struct lysp_node_choice));
5459 LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
5460 LY_CHECK_RET(lysp_node_dup(ctx, mem, pnode));
5461 break;
5462 case LYS_CASE:
5463 mem = calloc(1, sizeof(struct lysp_node_case));
5464 LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
5465 LY_CHECK_RET(lysp_node_dup(ctx, mem, pnode));
5466 break;
5467 case LYS_ANYDATA:
5468 case LYS_ANYXML:
5469 mem = calloc(1, sizeof(struct lysp_node_anydata));
5470 LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
5471 LY_CHECK_RET(lysp_node_dup(ctx, mem, pnode));
5472 break;
5473 case LYS_INPUT:
5474 case LYS_OUTPUT:
5475 mem = calloc(1, sizeof(struct lysp_action_inout));
5476 LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
5477 LY_CHECK_RET(lysp_action_inout_dup(ctx, mem, (struct lysp_action_inout *)pnode));
5478 break;
5479 case LYS_ACTION:
5480 case LYS_RPC:
5481 mem = calloc(1, sizeof(struct lysp_action));
5482 LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
5483 LY_CHECK_RET(lysp_action_dup(ctx, mem, (struct lysp_action *)pnode));
5484 break;
5485 case LYS_NOTIF:
5486 mem = calloc(1, sizeof(struct lysp_notif));
5487 LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
5488 LY_CHECK_RET(lysp_notif_dup(ctx, mem, (struct lysp_notif *)pnode));
5489 break;
5490 default:
5491 LOGINT_RET(ctx);
5492 }
5493
5494 if (with_links) {
5495 /* copy also parent and child pointers */
5496 ((struct lysp_node *)mem)->parent = pnode->parent;
5497 switch (pnode->nodetype) {
5498 case LYS_CONTAINER:
5499 ((struct lysp_node_container *)mem)->child = ((struct lysp_node_container *)pnode)->child;
5500 break;
5501 case LYS_LIST:
5502 ((struct lysp_node_list *)mem)->child = ((struct lysp_node_list *)pnode)->child;
5503 break;
5504 case LYS_CHOICE:
5505 ((struct lysp_node_choice *)mem)->child = ((struct lysp_node_choice *)pnode)->child;
5506 break;
5507 case LYS_CASE:
5508 ((struct lysp_node_case *)mem)->child = ((struct lysp_node_case *)pnode)->child;
5509 break;
5510 default:
5511 break;
5512 }
5513 }
5514
5515 *dup_p = mem;
5516 return LY_SUCCESS;
5517}
5518
5519#define AMEND_WRONG_NODETYPE(AMEND_STR, OP_STR, PROPERTY) \
5520 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s of %s node - it is not possible to %s \"%s\" property.", \
5521 AMEND_STR, lys_nodetype2str(target->nodetype), OP_STR, PROPERTY);\
5522 ret = LY_EVALID; \
5523 goto cleanup;
5524
5525#define AMEND_CHECK_CARDINALITY(ARRAY, MAX, AMEND_STR, PROPERTY) \
5526 if (LY_ARRAY_COUNT(ARRAY) > MAX) { \
5527 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid %s of %s with too many (%"LY_PRI_ARRAY_COUNT_TYPE") %s properties.", \
5528 AMEND_STR, lys_nodetype2str(target->nodetype), LY_ARRAY_COUNT(ARRAY), PROPERTY); \
5529 ret = LY_EVALID; \
5530 goto cleanup; \
5531 }
5532
5533/**
5534 * @brief Apply refine.
5535 *
5536 * @param[in] ctx Compile context.
5537 * @param[in] rfn Refine to apply.
5538 * @param[in,out] target Refine target.
5539 * @return LY_ERR value.
5540 */
5541static LY_ERR
5542lys_apply_refine(struct lysc_ctx *ctx, struct lysp_refine *rfn, struct lysp_node *target)
5543{
5544 LY_ERR ret = LY_SUCCESS;
5545 LY_ARRAY_COUNT_TYPE u;
5546 struct lysp_qname *qname;
5547 struct lysp_restr **musts, *must;
5548 uint32_t *num;
5549
5550 /* default value */
5551 if (rfn->dflts) {
5552 switch (target->nodetype) {
5553 case LYS_LEAF:
5554 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
5555
5556 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
5557 DUP_STRING_GOTO(ctx->ctx, rfn->dflts[0], ((struct lysp_node_leaf *)target)->dflt.str, ret, cleanup);
5558 ((struct lysp_node_leaf *)target)->dflt.mod = ctx->mod;
5559 break;
5560 case LYS_LEAFLIST:
5561 if (ctx->mod->version < LYS_VERSION_1_1) {
5562 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
5563 "Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.");
5564 ret = LY_EVALID;
5565 goto cleanup;
5566 }
5567
5568 FREE_ARRAY(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, lysp_qname_free);
5569 ((struct lysp_node_leaflist *)target)->dflts = NULL;
5570 LY_ARRAY_FOR(rfn->dflts, u) {
5571 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
5572 DUP_STRING_GOTO(ctx->ctx, rfn->dflts[u], qname->str, ret, cleanup);
5573 qname->mod = ctx->mod;
5574 }
5575 break;
5576 case LYS_CHOICE:
5577 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
5578
5579 FREE_STRING(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
5580 DUP_STRING_GOTO(ctx->ctx, rfn->dflts[0], ((struct lysp_node_choice *)target)->dflt.str, ret, cleanup);
5581 ((struct lysp_node_choice *)target)->dflt.mod = ctx->mod;
5582 break;
5583 default:
5584 AMEND_WRONG_NODETYPE("refine", "replace", "default");
5585 }
5586 }
5587
5588 /* description */
5589 if (rfn->dsc) {
5590 FREE_STRING(ctx->ctx, target->dsc);
5591 DUP_STRING_GOTO(ctx->ctx, rfn->dsc, target->dsc, ret, cleanup);
5592 }
5593
5594 /* reference */
5595 if (rfn->ref) {
5596 FREE_STRING(ctx->ctx, target->ref);
5597 DUP_STRING_GOTO(ctx->ctx, rfn->ref, target->ref, ret, cleanup);
5598 }
5599
5600 /* config */
5601 if (rfn->flags & LYS_CONFIG_MASK) {
5602 if (ctx->options & (LYSC_OPT_NOTIFICATION | LYSC_OPT_RPC_INPUT | LYSC_OPT_RPC_OUTPUT)) {
5603 LOGWRN(ctx->ctx, "Refining config inside %s has no effect (%s).",
5604 ctx->options & LYSC_OPT_NOTIFICATION ? "notification" : "RPC/action", ctx->path);
5605 } else {
5606 target->flags &= ~LYS_CONFIG_MASK;
5607 target->flags |= rfn->flags & LYS_CONFIG_MASK;
5608 }
5609 }
5610
5611 /* mandatory */
5612 if (rfn->flags & LYS_MAND_MASK) {
5613 switch (target->nodetype) {
5614 case LYS_LEAF:
5615 case LYS_CHOICE:
5616 case LYS_ANYDATA:
5617 case LYS_ANYXML:
5618 break;
5619 default:
5620 AMEND_WRONG_NODETYPE("refine", "replace", "mandatory");
5621 }
5622
5623 target->flags &= ~LYS_MAND_MASK;
5624 target->flags |= rfn->flags & LYS_MAND_MASK;
5625 }
5626
5627 /* presence */
5628 if (rfn->presence) {
5629 switch (target->nodetype) {
5630 case LYS_CONTAINER:
5631 break;
5632 default:
5633 AMEND_WRONG_NODETYPE("refine", "replace", "presence");
5634 }
5635
5636 FREE_STRING(ctx->ctx, ((struct lysp_node_container *)target)->presence);
5637 DUP_STRING_GOTO(ctx->ctx, rfn->presence, ((struct lysp_node_container *)target)->presence, ret, cleanup);
5638 }
5639
5640 /* must */
5641 if (rfn->musts) {
5642 switch (target->nodetype) {
5643 case LYS_CONTAINER:
5644 case LYS_LIST:
5645 case LYS_LEAF:
5646 case LYS_LEAFLIST:
5647 case LYS_ANYDATA:
5648 case LYS_ANYXML:
5649 musts = &((struct lysp_node_container *)target)->musts;
5650 break;
5651 default:
5652 AMEND_WRONG_NODETYPE("refine", "add", "must");
5653 }
5654
5655 LY_ARRAY_FOR(rfn->musts, u) {
5656 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
5657 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &rfn->musts[u]), cleanup);
5658 }
5659 }
5660
5661 /* min-elements */
5662 if (rfn->flags & LYS_SET_MIN) {
5663 switch (target->nodetype) {
5664 case LYS_LEAFLIST:
5665 num = &((struct lysp_node_leaflist *)target)->min;
5666 break;
5667 case LYS_LIST:
5668 num = &((struct lysp_node_list *)target)->min;
5669 break;
5670 default:
5671 AMEND_WRONG_NODETYPE("refine", "replace", "min-elements");
5672 }
5673
5674 *num = rfn->min;
5675 }
5676
5677 /* max-elements */
5678 if (rfn->flags & LYS_SET_MAX) {
5679 switch (target->nodetype) {
5680 case LYS_LEAFLIST:
5681 num = &((struct lysp_node_leaflist *)target)->max;
5682 break;
5683 case LYS_LIST:
5684 num = &((struct lysp_node_list *)target)->max;
5685 break;
5686 default:
5687 AMEND_WRONG_NODETYPE("refine", "replace", "max-elements");
5688 }
5689
5690 *num = rfn->max;
5691 }
5692
5693 /* if-feature */
5694 if (rfn->iffeatures) {
5695 switch (target->nodetype) {
5696 case LYS_LEAF:
5697 case LYS_LEAFLIST:
5698 case LYS_LIST:
5699 case LYS_CONTAINER:
5700 case LYS_CHOICE:
5701 case LYS_CASE:
5702 case LYS_ANYDATA:
5703 case LYS_ANYXML:
5704 break;
5705 default:
5706 AMEND_WRONG_NODETYPE("refine", "add", "if-feature");
5707 }
5708
5709 LY_ARRAY_FOR(rfn->iffeatures, u) {
5710 LY_ARRAY_NEW_GOTO(ctx->ctx, target->iffeatures, qname, ret, cleanup);
5711 DUP_STRING_GOTO(ctx->ctx, rfn->iffeatures[u].str, qname->str, ret, cleanup);
5712 qname->mod = ctx->mod;
5713 }
5714 }
5715
5716 /* extension */
5717 /* TODO refine extensions */
5718
5719cleanup:
5720 return ret;
5721}
5722
5723/**
5724 * @brief Apply deviate add.
5725 *
5726 * @param[in] ctx Compile context.
5727 * @param[in] d Deviate add to apply.
5728 * @param[in,out] target Deviation target.
5729 * @return LY_ERR value.
5730 */
5731static LY_ERR
5732lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysp_deviate_add *d, struct lysp_node *target)
5733{
5734 LY_ERR ret = LY_SUCCESS;
5735 LY_ARRAY_COUNT_TYPE u;
5736 struct lysp_qname *qname;
5737 uint32_t *num;
5738 struct lysp_restr **musts, *must;
5739
5740#define DEV_CHECK_NONPRESENCE(TYPE, MEMBER, PROPERTY, VALUEMEMBER) \
5741 if (((TYPE)target)->MEMBER) { \
5742 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
5743 "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", \
5744 PROPERTY, ((TYPE)target)->VALUEMEMBER); \
5745 ret = LY_EVALID; \
5746 goto cleanup; \
5747 }
5748
5749 /* [units-stmt] */
5750 if (d->units) {
5751 switch (target->nodetype) {
5752 case LYS_LEAF:
5753 case LYS_LEAFLIST:
5754 break;
5755 default:
5756 AMEND_WRONG_NODETYPE("deviation", "add", "units");
5757 }
5758
5759 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, units, "units", units);
5760 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
5761 }
5762
5763 /* *must-stmt */
5764 if (d->musts) {
5765 switch (target->nodetype) {
5766 case LYS_CONTAINER:
5767 case LYS_LIST:
5768 case LYS_LEAF:
5769 case LYS_LEAFLIST:
5770 case LYS_ANYDATA:
5771 case LYS_ANYXML:
5772 musts = &((struct lysp_node_container *)target)->musts;
5773 break;
5774 case LYS_NOTIF:
5775 musts = &((struct lysp_notif *)target)->musts;
5776 break;
5777 case LYS_INPUT:
5778 case LYS_OUTPUT:
5779 musts = &((struct lysp_action_inout *)target)->musts;
5780 break;
5781 default:
5782 AMEND_WRONG_NODETYPE("deviation", "add", "must");
5783 }
5784
5785 LY_ARRAY_FOR(d->musts, u) {
5786 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
5787 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &d->musts[u]), cleanup);
5788 }
5789 }
5790
5791 /* *unique-stmt */
5792 if (d->uniques) {
5793 switch (target->nodetype) {
5794 case LYS_LIST:
5795 break;
5796 default:
5797 AMEND_WRONG_NODETYPE("deviation", "add", "unique");
5798 }
5799
5800 LY_ARRAY_FOR(d->uniques, u) {
5801 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_list *)target)->uniques, qname, ret, cleanup);
5802 DUP_STRING_GOTO(ctx->ctx, d->uniques[u], qname->str, ret, cleanup);
5803 qname->mod = ctx->mod;
5804 }
5805 }
5806
5807 /* *default-stmt */
5808 if (d->dflts) {
5809 switch (target->nodetype) {
5810 case LYS_LEAF:
5811 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
5812 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, dflt.str, "default", dflt.str);
5813
5814 DUP_STRING_GOTO(ctx->ctx, d->dflts[0], ((struct lysp_node_leaf *)target)->dflt.str, ret, cleanup);
5815 ((struct lysp_node_leaf *)target)->dflt.mod = ctx->mod;
5816 break;
5817 case LYS_LEAFLIST:
5818 LY_ARRAY_FOR(d->dflts, u) {
5819 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
5820 DUP_STRING_GOTO(ctx->ctx, d->dflts[u], qname->str, ret, cleanup);
5821 qname->mod = ctx->mod;
5822 }
5823 break;
5824 case LYS_CHOICE:
5825 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
5826 DEV_CHECK_NONPRESENCE(struct lysp_node_choice *, dflt.str, "default", dflt.str);
5827
5828 DUP_STRING_GOTO(ctx->ctx, d->dflts[0], ((struct lysp_node_choice *)target)->dflt.str, ret, cleanup);
5829 ((struct lysp_node_choice *)target)->dflt.mod = ctx->mod;
5830 break;
5831 default:
5832 AMEND_WRONG_NODETYPE("deviation", "add", "default");
5833 }
5834 }
5835
5836 /* [config-stmt] */
5837 if (d->flags & LYS_CONFIG_MASK) {
5838 switch (target->nodetype) {
5839 case LYS_CONTAINER:
5840 case LYS_LEAF:
5841 case LYS_LEAFLIST:
5842 case LYS_LIST:
5843 case LYS_CHOICE:
5844 case LYS_ANYDATA:
5845 case LYS_ANYXML:
5846 break;
5847 default:
5848 AMEND_WRONG_NODETYPE("deviation", "add", "config");
5849 }
5850
5851 if (target->flags & LYS_CONFIG_MASK) {
5852 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
5853 "Invalid deviation adding \"config\" property which already exists (with value \"config %s\").",
5854 target->flags & LYS_CONFIG_W ? "true" : "false");
5855 ret = LY_EVALID;
5856 goto cleanup;
5857 }
5858
5859 target->flags |= d->flags & LYS_CONFIG_MASK;
5860 }
5861
5862 /* [mandatory-stmt] */
5863 if (d->flags & LYS_MAND_MASK) {
5864 switch (target->nodetype) {
5865 case LYS_LEAF:
5866 case LYS_CHOICE:
5867 case LYS_ANYDATA:
5868 case LYS_ANYXML:
5869 break;
5870 default:
5871 AMEND_WRONG_NODETYPE("deviation", "add", "mandatory");
5872 }
5873
5874 if (target->flags & LYS_MAND_MASK) {
5875 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
5876 "Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory %s\").",
5877 target->flags & LYS_MAND_TRUE ? "true" : "false");
5878 ret = LY_EVALID;
5879 goto cleanup;
5880 }
5881
5882 target->flags |= d->flags & LYS_MAND_MASK;
5883 }
5884
5885 /* [min-elements-stmt] */
5886 if (d->flags & LYS_SET_MIN) {
5887 switch (target->nodetype) {
5888 case LYS_LEAFLIST:
5889 num = &((struct lysp_node_leaflist *)target)->min;
5890 break;
5891 case LYS_LIST:
5892 num = &((struct lysp_node_list *)target)->min;
5893 break;
5894 default:
5895 AMEND_WRONG_NODETYPE("deviation", "add", "min-elements");
5896 }
5897
5898 if (target->flags & LYS_SET_MIN) {
5899 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
5900 "Invalid deviation adding \"min-elements\" property which already exists (with value \"%u\").", *num);
5901 ret = LY_EVALID;
5902 goto cleanup;
5903 }
5904
5905 *num = d->min;
5906 }
5907
5908 /* [max-elements-stmt] */
5909 if (d->flags & LYS_SET_MAX) {
5910 switch (target->nodetype) {
5911 case LYS_LEAFLIST:
5912 num = &((struct lysp_node_leaflist *)target)->max;
5913 break;
5914 case LYS_LIST:
5915 num = &((struct lysp_node_list *)target)->max;
5916 break;
5917 default:
5918 AMEND_WRONG_NODETYPE("deviation", "add", "max-elements");
5919 }
5920
5921 if (target->flags & LYS_SET_MAX) {
5922 if (*num) {
5923 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
5924 "Invalid deviation adding \"max-elements\" property which already exists (with value \"%u\").",
5925 *num);
5926 } else {
5927 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
5928 "Invalid deviation adding \"max-elements\" property which already exists (with value \"unbounded\").");
5929 }
5930 ret = LY_EVALID;
5931 goto cleanup;
5932 }
5933
5934 *num = d->max;
5935 }
5936
5937cleanup:
5938 return ret;
5939}
5940
5941/**
5942 * @brief Apply deviate delete.
5943 *
5944 * @param[in] ctx Compile context.
5945 * @param[in] d Deviate delete to apply.
5946 * @param[in,out] target Deviation target.
5947 * @return LY_ERR value.
5948 */
5949static LY_ERR
5950lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysp_deviate_del *d, struct lysp_node *target)
5951{
5952 LY_ERR ret = LY_SUCCESS;
5953 struct lysp_restr **musts;
5954 LY_ARRAY_COUNT_TYPE u, v;
5955 struct lysp_qname **uniques, **dflts;
5956
5957#define DEV_DEL_ARRAY(DEV_ARRAY, ORIG_ARRAY, DEV_MEMBER, ORIG_MEMBER, FREE_FUNC, PROPERTY) \
5958 LY_ARRAY_FOR(d->DEV_ARRAY, u) { \
5959 int found = 0; \
5960 LY_ARRAY_FOR(ORIG_ARRAY, v) { \
5961 if (!strcmp(d->DEV_ARRAY[u]DEV_MEMBER, (ORIG_ARRAY)[v]ORIG_MEMBER)) { \
5962 found = 1; \
5963 break; \
5964 } \
5965 } \
5966 if (!found) { \
5967 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
5968 "Invalid deviation deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
5969 PROPERTY, d->DEV_ARRAY[u]DEV_MEMBER); \
5970 ret = LY_EVALID; \
5971 goto cleanup; \
5972 } \
5973 LY_ARRAY_DECREMENT(ORIG_ARRAY); \
5974 FREE_FUNC(ctx->ctx, &(ORIG_ARRAY)[v]); \
5975 memmove(&(ORIG_ARRAY)[v], &(ORIG_ARRAY)[v + 1], (LY_ARRAY_COUNT(ORIG_ARRAY) - v) * sizeof *(ORIG_ARRAY)); \
5976 } \
5977 if (!LY_ARRAY_COUNT(ORIG_ARRAY)) { \
5978 LY_ARRAY_FREE(ORIG_ARRAY); \
5979 ORIG_ARRAY = NULL; \
5980 }
5981
5982#define DEV_CHECK_PRESENCE_VALUE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
5983 if (!((TYPE)target)->MEMBER) { \
5984 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
5985 ret = LY_EVALID; \
5986 goto cleanup; \
5987 } else if (strcmp(((TYPE)target)->MEMBER, VALUE)) { \
5988 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
5989 "Invalid deviation deleting \"%s\" property \"%s\" which does not match the target's property value \"%s\".", \
5990 PROPERTY, VALUE, ((TYPE)target)->MEMBER); \
5991 ret = LY_EVALID; \
5992 goto cleanup; \
5993 }
5994
5995 /* [units-stmt] */
5996 if (d->units) {
5997 switch (target->nodetype) {
5998 case LYS_LEAF:
5999 case LYS_LEAFLIST:
6000 break;
6001 default:
6002 AMEND_WRONG_NODETYPE("deviation", "delete", "units");
6003 }
6004
6005 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, units, "deleting", "units", d->units);
6006 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
6007 ((struct lysp_node_leaf *)target)->units = NULL;
6008 }
6009
6010 /* *must-stmt */
6011 if (d->musts) {
6012 switch (target->nodetype) {
6013 case LYS_CONTAINER:
6014 case LYS_LIST:
6015 case LYS_LEAF:
6016 case LYS_LEAFLIST:
6017 case LYS_ANYDATA:
6018 case LYS_ANYXML:
6019 musts = &((struct lysp_node_container *)target)->musts;
6020 break;
6021 case LYS_NOTIF:
6022 musts = &((struct lysp_notif *)target)->musts;
6023 break;
6024 case LYS_INPUT:
6025 case LYS_OUTPUT:
6026 musts = &((struct lysp_action_inout *)target)->musts;
6027 break;
6028 default:
6029 AMEND_WRONG_NODETYPE("deviation", "delete", "must");
6030 }
6031
6032 DEV_DEL_ARRAY(musts, *musts, .arg.str, .arg.str, lysp_restr_free, "must");
6033 }
6034
6035 /* *unique-stmt */
6036 if (d->uniques) {
6037 switch (target->nodetype) {
6038 case LYS_LIST:
6039 break;
6040 default:
6041 AMEND_WRONG_NODETYPE("deviation", "delete", "unique");
6042 }
6043
6044 uniques = &((struct lysp_node_list *)target)->uniques;
6045 DEV_DEL_ARRAY(uniques, *uniques, , .str, lysp_qname_free, "unique");
6046 }
6047
6048 /* *default-stmt */
6049 if (d->dflts) {
6050 switch (target->nodetype) {
6051 case LYS_LEAF:
6052 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
6053 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, dflt.str, "deleting", "default", d->dflts[0]);
6054
6055 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
6056 ((struct lysp_node_leaf *)target)->dflt.str = NULL;
6057 break;
6058 case LYS_LEAFLIST:
6059 dflts = &((struct lysp_node_leaflist *)target)->dflts;
6060 DEV_DEL_ARRAY(dflts, *dflts, , .str, lysp_qname_free, "default");
6061 break;
6062 case LYS_CHOICE:
6063 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
6064 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_choice *, dflt.str, "deleting", "default", d->dflts[0]);
6065
6066 FREE_STRING(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
6067 ((struct lysp_node_choice *)target)->dflt.str = NULL;
6068 break;
6069 default:
6070 AMEND_WRONG_NODETYPE("deviation", "delete", "default");
6071 }
6072 }
6073
6074cleanup:
6075 return ret;
6076}
6077
6078/**
6079 * @brief Apply deviate replace.
6080 *
6081 * @param[in] ctx Compile context.
6082 * @param[in] d Deviate replace to apply.
6083 * @param[in,out] target Deviation target.
6084 * @return LY_ERR value.
6085 */
6086static LY_ERR
6087lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysp_deviate_rpl *d, struct lysp_node *target)
6088{
6089 LY_ERR ret = LY_SUCCESS;
6090 uint32_t *num;
6091
6092#define DEV_CHECK_PRESENCE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
6093 if (!((TYPE)target)->MEMBER) { \
6094 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
6095 ret = LY_EVALID; \
6096 goto cleanup; \
6097 }
6098
6099 /* [type-stmt] */
6100 if (d->type) {
6101 switch (target->nodetype) {
6102 case LYS_LEAF:
6103 case LYS_LEAFLIST:
6104 break;
6105 default:
6106 AMEND_WRONG_NODETYPE("deviation", "replace", "type");
6107 }
6108
6109 lysp_type_free(ctx->ctx, &((struct lysp_node_leaf *)target)->type);
6110 lysp_type_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->type, d->type);
6111 }
6112
6113 /* [units-stmt] */
6114 if (d->units) {
6115 switch (target->nodetype) {
6116 case LYS_LEAF:
6117 case LYS_LEAFLIST:
6118 break;
6119 default:
6120 AMEND_WRONG_NODETYPE("deviation", "replace", "units");
6121 }
6122
6123 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, units, "replacing", "units", d->units);
6124 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
6125 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
6126 }
6127
6128 /* [default-stmt] */
6129 if (d->dflt) {
6130 switch (target->nodetype) {
6131 case LYS_LEAF:
6132 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, dflt.str, "replacing", "default", d->dflt);
6133
6134 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
6135 DUP_STRING_GOTO(ctx->ctx, d->dflt, ((struct lysp_node_leaf *)target)->dflt.str, ret, cleanup);
6136 ((struct lysp_node_leaf *)target)->dflt.mod = ctx->mod;
6137 break;
6138 case LYS_CHOICE:
6139 DEV_CHECK_PRESENCE(struct lysp_node_choice *, dflt.str, "replacing", "default", d->dflt);
6140
6141 FREE_STRING(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
6142 DUP_STRING_GOTO(ctx->ctx, d->dflt, ((struct lysp_node_choice *)target)->dflt.str, ret, cleanup);
6143 ((struct lysp_node_choice *)target)->dflt.mod = ctx->mod;
6144 break;
6145 default:
6146 AMEND_WRONG_NODETYPE("deviation", "replace", "default");
6147 }
6148 }
6149
6150 /* [config-stmt] */
6151 if (d->flags & LYS_CONFIG_MASK) {
6152 switch (target->nodetype) {
6153 case LYS_CONTAINER:
6154 case LYS_LEAF:
6155 case LYS_LEAFLIST:
6156 case LYS_LIST:
6157 case LYS_CHOICE:
6158 case LYS_ANYDATA:
6159 case LYS_ANYXML:
6160 break;
6161 default:
6162 AMEND_WRONG_NODETYPE("deviation", "replace", "config");
6163 }
6164
6165 if (!(target->flags & LYS_CONFIG_MASK)) {
6166 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT,
6167 "replacing", "config", d->flags & LYS_CONFIG_W ? "config true" : "config false");
6168 ret = LY_EVALID;
6169 goto cleanup;
6170 }
6171
6172 target->flags &= ~LYS_CONFIG_MASK;
6173 target->flags |= d->flags & LYS_CONFIG_MASK;
6174 }
6175
6176 /* [mandatory-stmt] */
6177 if (d->flags & LYS_MAND_MASK) {
6178 switch (target->nodetype) {
6179 case LYS_LEAF:
6180 case LYS_CHOICE:
6181 case LYS_ANYDATA:
6182 case LYS_ANYXML:
6183 break;
6184 default:
6185 AMEND_WRONG_NODETYPE("deviation", "replace", "mandatory");
6186 }
6187
6188 if (!(target->flags & LYS_MAND_MASK)) {
6189 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT,
6190 "replacing", "mandatory", d->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
6191 ret = LY_EVALID;
6192 goto cleanup;
6193 }
6194
6195 target->flags &= ~LYS_MAND_MASK;
6196 target->flags |= d->flags & LYS_MAND_MASK;
6197 }
6198
6199 /* [min-elements-stmt] */
6200 if (d->flags & LYS_SET_MIN) {
6201 switch (target->nodetype) {
6202 case LYS_LEAFLIST:
6203 num = &((struct lysp_node_leaflist *)target)->min;
6204 break;
6205 case LYS_LIST:
6206 num = &((struct lysp_node_list *)target)->min;
6207 break;
6208 default:
6209 AMEND_WRONG_NODETYPE("deviation", "replace", "min-elements");
6210 }
6211
6212 if (!(target->flags & LYS_SET_MIN)) {
6213 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6214 "Invalid deviation replacing \"min-elements\" property which is not present.");
6215 ret = LY_EVALID;
6216 goto cleanup;
6217 }
6218
6219 *num = d->min;
6220 }
6221
6222 /* [max-elements-stmt] */
6223 if (d->flags & LYS_SET_MAX) {
6224 switch (target->nodetype) {
6225 case LYS_LEAFLIST:
6226 num = &((struct lysp_node_leaflist *)target)->max;
6227 break;
6228 case LYS_LIST:
6229 num = &((struct lysp_node_list *)target)->max;
6230 break;
6231 default:
6232 AMEND_WRONG_NODETYPE("deviation", "replace", "max-elements");
6233 }
6234
6235 if (!(target->flags & LYS_SET_MAX)) {
6236 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6237 "Invalid deviation replacing \"max-elements\" property which is not present.");
6238 ret = LY_EVALID;
6239 goto cleanup;
6240 }
6241
6242 *num = d->max;
6243 }
6244
6245cleanup:
6246 return ret;
6247}
6248
6249/**
6250 * @brief Get module of a single nodeid node name test.
6251 *
6252 * @param[in] ctx libyang context.
6253 * @param[in] nametest Nametest with an optional prefix.
6254 * @param[in] nametest_len Length of @p nametest.
6255 * @param[in] local_mod Module to return in case of no prefix.
6256 * @param[out] name Optional pointer to the name test without the prefix.
6257 * @param[out] name_len Length of @p name.
6258 * @return Resolved module.
6259 */
6260static const struct lys_module *
6261lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest, size_t nametest_len,
6262 const struct lys_module *local_mod, const char **name, size_t *name_len)
6263{
6264 const struct lys_module *target_mod;
6265 const char *ptr;
6266
6267 ptr = ly_strnchr(nametest, ':', nametest_len);
6268 if (ptr) {
6269 target_mod = ly_resolve_prefix(ctx, nametest, ptr - nametest, LY_PREF_SCHEMA, (void *)local_mod);
6270 if (!target_mod) {
6271 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
6272 "Invalid absolute-schema-nodeid nametest \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
6273 nametest_len, nametest, ptr - nametest, nametest, local_mod->name);
6274 return NULL;
6275 }
6276
6277 if (name) {
6278 *name = ptr + 1;
6279 *name_len = nametest_len - ((ptr - nametest) + 1);
6280 }
6281 } else {
6282 target_mod = local_mod;
6283 if (name) {
6284 *name = nametest;
6285 *name_len = nametest_len;
6286 }
6287 }
6288
6289 return target_mod;
6290}
6291
6292/**
6293 * @brief Check whether a parsed node matches a single schema nodeid name test.
6294 *
6295 * @param[in] pnode Parsed node to consider.
6296 * @param[in] pnode_mod Compiled @p pnode to-be module.
6297 * @param[in] mod Expected module.
6298 * @param[in] name Expected name.
6299 * @param[in] name_len Length of @p name.
6300 * @return Whether it is a match or not.
6301 */
6302static ly_bool
6303lysp_schema_nodeid_match_pnode(const struct lysp_node *pnode, const struct lys_module *pnode_mod,
6304 const struct lys_module *mod, const char *name, size_t name_len)
6305{
6306 const char *pname;
6307
6308 /* compare with the module of the node */
6309 if (pnode_mod != mod) {
6310 return 0;
6311 }
6312
6313 /* compare names */
6314 if (pnode->nodetype & (LYS_ACTION | LYS_RPC)) {
6315 pname = ((struct lysp_action *)pnode)->name;
6316 } else if (pnode->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6317 pname = (pnode->nodetype & LYS_INPUT) ? "input" : "output";
6318 } else {
6319 pname = pnode->name;
6320 }
6321 if (ly_strncmp(pname, name, name_len)) {
6322 return 0;
6323 }
6324
6325 return 1;
6326}
6327
6328/**
6329 * @brief Check whether a compiled node matches a single schema nodeid name test.
6330 *
6331 * @param[in,out] node Compiled node to consider. On a match it is moved to its parent.
6332 * @param[in] mod Expected module.
6333 * @param[in] name Expected name.
6334 * @param[in] name_len Length of @p name.
6335 * @return Whether it is a match or not.
6336 */
6337static ly_bool
6338lysp_schema_nodeid_match_node(const struct lysc_node **node, const struct lys_module *mod, const char *name,
6339 size_t name_len)
6340{
6341 const struct lys_module *node_mod;
6342 const char *node_name;
6343
6344 /* compare with the module of the node */
6345 if ((*node)->nodetype == LYS_INPUT) {
6346 node_mod = ((struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, input)))->module;
6347 } else if ((*node)->nodetype == LYS_OUTPUT) {
6348 node_mod = ((struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, output)))->module;
6349 } else {
6350 node_mod = (*node)->module;
6351 }
6352 if (node_mod != mod) {
6353 return 0;
6354 }
6355
6356 /* compare names */
6357 if ((*node)->nodetype == LYS_INPUT) {
6358 node_name = "input";
6359 } else if ((*node)->nodetype == LYS_OUTPUT) {
6360 node_name = "output";
6361 } else {
6362 node_name = (*node)->name;
6363 }
6364 if (ly_strncmp(node_name, name, name_len)) {
6365 return 0;
6366 }
6367
6368 if ((*node)->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6369 /* move up from input/output */
6370 if ((*node)->nodetype == LYS_INPUT) {
6371 (*node) = (struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, input));
6372 } else {
6373 (*node) = (struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, output));
6374 }
6375 } else if ((*node)->parent && ((*node)->parent->nodetype & (LYS_RPC | LYS_ACTION))) {
6376 /* move to the input/output */
6377 if ((*node)->flags & LYS_CONFIG_W) {
6378 *node = (struct lysc_node *)&((struct lysc_action *)(*node)->parent)->input;
6379 } else {
6380 *node = (struct lysc_node *)&((struct lysc_action *)(*node)->parent)->output;
6381 }
6382 } else {
6383 /* move to next parent */
6384 *node = (*node)->parent;
6385 }
6386
6387 return 1;
6388}
6389
6390/**
6391 * @brief Check whether a node matches specific schema nodeid.
6392 *
6393 * @param[in] exp Parsed nodeid to match.
6394 * @param[in] exp_mod Module to use for nodes in @p exp without a prefix.
6395 * @param[in] ctx_node Initial context node that should match, only for descendant paths.
6396 * @param[in] parent First compiled parent to consider. If @p pnode is NULL, it is condered the node to be matched.
6397 * @param[in] pnode Parsed node to be matched. May be NULL if the target node was already compiled.
6398 * @param[in] pnode_mod Compiled @p pnode to-be module.
6399 * @return Whether it is a match or not.
6400 */
6401static ly_bool
6402lysp_schema_nodeid_match(const struct lyxp_expr *exp, const struct lys_module *exp_mod, const struct lysc_node *ctx_node,
6403 const struct lysc_node *parent, const struct lysp_node *pnode, const struct lys_module *pnode_mod)
6404{
6405 uint32_t i;
6406 const struct lys_module *mod;
6407 const char *name;
6408 size_t name_len;
6409
6410 /* compare last node in the node ID */
6411 i = exp->used - 1;
6412
6413 /* get exp node ID module */
6414 mod = lys_schema_node_get_module(exp_mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_mod, &name, &name_len);
6415 assert(mod);
6416
6417 if (pnode) {
6418 /* compare on the last parsed-only node */
6419 if (!lysp_schema_nodeid_match_pnode(pnode, pnode_mod, mod, name, name_len)) {
6420 return 0;
6421 }
6422 } else {
6423 /* using parent directly */
6424 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
6425 return 0;
6426 }
6427 }
6428
6429 /* now compare all the compiled parents */
6430 while (i > 1) {
6431 i -= 2;
6432 assert(exp->tokens[i] == LYXP_TOKEN_NAMETEST);
6433
6434 if (!parent) {
6435 /* no more parents but path continues */
6436 return 0;
6437 }
6438
6439 /* get exp node ID module */
6440 mod = lys_schema_node_get_module(exp_mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_mod, &name,
6441 &name_len);
6442 assert(mod);
6443
6444 /* compare with the parent */
6445 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
6446 return 0;
6447 }
6448 }
6449
6450 if (ctx_node && (ctx_node != parent)) {
6451 /* descendant path has not finished in the context node */
6452 return 0;
6453 } else if (!ctx_node && parent) {
6454 /* some parent was not matched */
6455 return 0;
6456 }
6457
6458 return 1;
6459}
6460
6461static void
6462lysc_augment_free(const struct ly_ctx *ctx, struct lysc_augment *aug)
6463{
6464 if (aug) {
6465 lyxp_expr_free(ctx, aug->nodeid);
6466
6467 free(aug);
6468 }
6469}
6470
6471static void
6472lysc_deviation_free(const struct ly_ctx *ctx, struct lysc_deviation *dev)
6473{
6474 if (dev) {
6475 lyxp_expr_free(ctx, dev->nodeid);
6476 LY_ARRAY_FREE(dev->devs);
6477 LY_ARRAY_FREE(dev->dev_mods);
6478
6479 free(dev);
6480 }
6481}
6482
6483static void
6484lysc_refine_free(const struct ly_ctx *ctx, struct lysc_refine *rfn)
6485{
6486 if (rfn) {
6487 lyxp_expr_free(ctx, rfn->nodeid);
6488 LY_ARRAY_FREE(rfn->rfns);
6489
6490 free(rfn);
6491 }
6492}
6493
6494static void
6495lysp_dev_node_free(const struct ly_ctx *ctx, struct lysp_node *dev_pnode)
6496{
6497 if (!dev_pnode) {
6498 return;
6499 }
6500
6501 switch (dev_pnode->nodetype) {
6502 case LYS_CONTAINER:
6503 ((struct lysp_node_container *)dev_pnode)->child = NULL;
6504 break;
6505 case LYS_LIST:
6506 ((struct lysp_node_list *)dev_pnode)->child = NULL;
6507 break;
6508 case LYS_CHOICE:
6509 ((struct lysp_node_choice *)dev_pnode)->child = NULL;
6510 break;
6511 case LYS_CASE:
6512 ((struct lysp_node_case *)dev_pnode)->child = NULL;
6513 break;
6514 case LYS_LEAF:
6515 case LYS_LEAFLIST:
6516 case LYS_ANYXML:
6517 case LYS_ANYDATA:
6518 /* no children */
6519 break;
6520 case LYS_NOTIF:
6521 ((struct lysp_notif *)dev_pnode)->data = NULL;
6522 lysp_notif_free((struct ly_ctx *)ctx, (struct lysp_notif *)dev_pnode);
6523 free(dev_pnode);
6524 return;
6525 case LYS_RPC:
6526 case LYS_ACTION:
6527 ((struct lysp_action *)dev_pnode)->input.data = NULL;
6528 ((struct lysp_action *)dev_pnode)->output.data = NULL;
6529 lysp_action_free((struct ly_ctx *)ctx, (struct lysp_action *)dev_pnode);
6530 free(dev_pnode);
6531 return;
6532 case LYS_INPUT:
6533 case LYS_OUTPUT:
6534 ((struct lysp_action_inout *)dev_pnode)->data = NULL;
6535 lysp_action_inout_free((struct ly_ctx *)ctx, (struct lysp_action_inout *)dev_pnode);
6536 free(dev_pnode);
6537 return;
6538 default:
6539 LOGINT(ctx);
6540 return;
6541 }
6542
6543 lysp_node_free((struct ly_ctx *)ctx, dev_pnode);
6544}
6545
6546/**
6547 * @brief Compile and apply any precompiled deviations and refines targetting a node.
6548 *
6549 * @param[in] ctx Compile context.
6550 * @param[in] pnode Parsed node to consider.
6551 * @param[in] parent First compiled parent of @p pnode.
6552 * @param[out] dev_pnode Copy of parsed node @p pnode with deviations and refines, if any. NULL if there are none.
6553 * @param[out] no_supported Whether a not-supported deviation is defined for the node.
6554 * @return LY_ERR value.
6555 */
6556static LY_ERR
6557lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode, const struct lysc_node *parent,
6558 struct lysp_node **dev_pnode, ly_bool *not_supported)
6559{
6560 LY_ERR ret = LY_SUCCESS;
6561 uint32_t i;
6562 LY_ARRAY_COUNT_TYPE u;
6563 struct lys_module *orig_mod = ctx->mod, *orig_mod_def = ctx->mod_def;
6564 char orig_path[LYSC_CTX_BUFSIZE];
6565 struct lysc_refine *rfn;
6566 struct lysc_deviation *dev;
6567 struct lysp_deviation *dev_p;
6568 struct lysp_deviate *d;
6569
6570 *dev_pnode = NULL;
6571 *not_supported = 0;
6572
6573 for (i = 0; i < ctx->uses_rfns.count; ++i) {
6574 rfn = ctx->uses_rfns.objs[i];
6575
6576 if (!lysp_schema_nodeid_match(rfn->nodeid, ctx->mod, rfn->nodeid_ctx_node, parent, pnode, ctx->mod)) {
6577 /* not our target node */
6578 continue;
6579 }
6580
6581 if (!*dev_pnode) {
6582 /* first refine on this node, create a copy first */
6583 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
6584 }
6585
6586 /* apply all the refines by changing (the copy of) the parsed node */
6587 LY_ARRAY_FOR(rfn->rfns, u) {
6588 /* apply refine, keep the current path and add to it */
6589 lysc_update_path(ctx, NULL, "{refine}");
6590 lysc_update_path(ctx, NULL, rfn->rfns[u]->nodeid);
6591 ret = lys_apply_refine(ctx, rfn->rfns[u], *dev_pnode);
6592 lysc_update_path(ctx, NULL, NULL);
6593 lysc_update_path(ctx, NULL, NULL);
6594 LY_CHECK_GOTO(ret, cleanup);
6595 }
6596
6597 /* refine was applied, remove it */
6598 lysc_refine_free(ctx->ctx, rfn);
6599 ly_set_rm_index(&ctx->uses_rfns, i, NULL);
6600
6601 /* all the refines for one target node are in one structure, we are done */
6602 break;
6603 }
6604
6605 for (i = 0; i < ctx->devs.count; ++i) {
6606 dev = ctx->devs.objs[i];
6607
6608 if (!lysp_schema_nodeid_match(dev->nodeid, dev->nodeid_mod, NULL, parent, pnode, ctx->mod_def)) {
6609 /* not our target node */
6610 continue;
6611 }
6612
6613 if (dev->not_supported) {
6614 /* it is not supported, no more deviations */
6615 *not_supported = 1;
6616 goto dev_applied;
6617 }
6618
6619 if (!*dev_pnode) {
6620 /* first deviation on this node, create a copy first */
6621 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
6622 }
6623
6624 /* apply all the deviates by changing (the copy of) the parsed node */
6625 LY_ARRAY_FOR(dev->devs, u) {
6626 dev_p = dev->devs[u];
6627 LY_LIST_FOR(dev_p->deviates, d) {
6628 /* generate correct path */
6629 strcpy(orig_path, ctx->path);
6630 ctx->path_len = 1;
6631 ctx->mod = (struct lys_module *)dev->dev_mods[u];
6632 ctx->mod_def = (struct lys_module *)dev->dev_mods[u];
6633 lysc_update_path(ctx, NULL, "{deviation}");
6634 lysc_update_path(ctx, NULL, dev_p->nodeid);
6635
6636 switch (d->mod) {
6637 case LYS_DEV_ADD:
6638 ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, *dev_pnode);
6639 break;
6640 case LYS_DEV_DELETE:
6641 ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, *dev_pnode);
6642 break;
6643 case LYS_DEV_REPLACE:
6644 ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, *dev_pnode);
6645 break;
6646 default:
6647 LOGINT(ctx->ctx);
6648 ret = LY_EINT;
6649 }
6650
6651 /* restore previous path */
6652 strcpy(ctx->path, orig_path);
6653 ctx->path_len = strlen(ctx->path);
6654 ctx->mod = orig_mod;
6655 ctx->mod_def = orig_mod_def;
6656
6657 LY_CHECK_GOTO(ret, cleanup);
6658 }
6659 }
6660
6661dev_applied:
6662 /* deviation was applied, remove it */
6663 lysc_deviation_free(ctx->ctx, dev);
6664 ly_set_rm_index(&ctx->devs, i, NULL);
6665
6666 /* all the deviations for one target node are in one structure, we are done */
6667 break;
6668 }
6669
6670cleanup:
6671 if (ret) {
6672 lysp_dev_node_free(ctx->ctx, *dev_pnode);
6673 *dev_pnode = NULL;
6674 *not_supported = 0;
6675 }
6676 return ret;
6677}
6678
6679/**
6680 * @brief Compile and apply any precompiled top-level or uses augments targetting a node.
6681 *
6682 * @param[in] ctx Compile context.
6683 * @param[in] node Compiled node to consider.
6684 * @return LY_ERR value.
6685 */
6686static LY_ERR
6687lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
6688{
6689 LY_ERR ret = LY_SUCCESS;
6690 struct lys_module *orig_mod = ctx->mod, *orig_mod_def = ctx->mod_def;
6691 uint32_t i;
6692 char orig_path[LYSC_CTX_BUFSIZE];
6693 struct lysc_augment *aug;
6694
6695 /* uses augments */
6696 for (i = 0; i < ctx->uses_augs.count; ) {
6697 aug = ctx->uses_augs.objs[i];
6698
6699 if (!lysp_schema_nodeid_match(aug->nodeid, ctx->mod, aug->nodeid_ctx_node, node, NULL, NULL)) {
6700 /* not our target node */
6701 ++i;
6702 continue;
6703 }
6704
6705 /* apply augment, keep the current path and add to it */
6706 lysc_update_path(ctx, NULL, "{augment}");
6707 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
6708 ret = lys_compile_augment(ctx, aug->aug_p, node);
6709 lysc_update_path(ctx, NULL, NULL);
6710 lysc_update_path(ctx, NULL, NULL);
6711 LY_CHECK_GOTO(ret, cleanup);
6712
6713 /* augment was applied, remove it (index may have changed because other augments could have been applied) */
6714 lysc_augment_free(ctx->ctx, aug);
6715 ly_set_rm(&ctx->uses_augs, aug, NULL);
6716 }
6717
6718 /* top-level augments */
6719 for (i = 0; i < ctx->augs.count; ) {
6720 aug = ctx->augs.objs[i];
6721
6722 if (!lysp_schema_nodeid_match(aug->nodeid, aug->nodeid_mod, NULL, node, NULL, NULL)) {
6723 /* not our target node */
6724 ++i;
6725 continue;
6726 }
6727
6728 /* apply augment, use the path and modules from the augment */
6729 strcpy(orig_path, ctx->path);
6730 ctx->path_len = 1;
6731 lysc_update_path(ctx, NULL, "{augment}");
6732 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
6733 ctx->mod = (struct lys_module *)aug->nodeid_mod;
6734 ctx->mod_def = (struct lys_module *)aug->nodeid_mod;
6735 ret = lys_compile_augment(ctx, aug->aug_p, node);
6736 strcpy(ctx->path, orig_path);
6737 ctx->path_len = strlen(ctx->path);
6738 LY_CHECK_GOTO(ret, cleanup);
6739
6740 /* augment was applied, remove it */
6741 lysc_augment_free(ctx->ctx, aug);
6742 ly_set_rm(&ctx->augs, aug, NULL);
6743 }
6744
6745cleanup:
6746 ctx->mod = orig_mod;
6747 ctx->mod_def = orig_mod_def;
6748 return ret;
6749}
6750
6751/**
6752 * @brief Prepare a top-level augment to be applied during data nodes compilation.
6753 *
6754 * @param[in] ctx Compile context.
6755 * @param[in] aug_p Parsed augment to be applied.
6756 * @param[in] mod_def Local module for @p aug_p.
6757 * @return LY_ERR value.
6758 */
6759static LY_ERR
6760lys_precompile_own_augment(struct lysc_ctx *ctx, struct lysp_augment *aug_p, const struct lys_module *mod_def)
6761{
6762 LY_ERR ret = LY_SUCCESS;
6763 struct lyxp_expr *exp = NULL;
6764 struct lysc_augment *aug;
6765 const struct lys_module *mod;
6766
6767 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
6768 ret = lyxp_expr_parse(ctx->ctx, aug_p->nodeid, strlen(aug_p->nodeid), 0, &exp);
6769 LY_CHECK_GOTO(ret, cleanup);
6770
6771 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], mod_def, NULL, NULL);
6772 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
6773 if (mod != ctx->mod) {
6774 /* augment for another module, ignore */
6775 goto cleanup;
6776 }
6777
6778 /* allocate new compiled augment and store it in the set */
6779 aug = calloc(1, sizeof *aug);
6780 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
6781 LY_CHECK_GOTO(ret = ly_set_add(&ctx->augs, aug, LY_SET_OPT_USEASLIST, NULL), cleanup);
6782
6783 aug->nodeid = exp;
6784 exp = NULL;
6785 aug->nodeid_mod = mod_def;
6786 aug->aug_p = aug_p;
6787
6788cleanup:
6789 lyxp_expr_free(ctx->ctx, exp);
6790 return ret;
6791}
6792
6793/**
6794 * @brief Prepare all top-level augments for the current module to be applied during data nodes compilation.
6795 *
6796 * @param[in] ctx Compile context.
6797 * @return LY_ERR value.
6798 */
6799static LY_ERR
6800lys_precompile_own_augments(struct lysc_ctx *ctx)
6801{
6802 LY_ARRAY_COUNT_TYPE u, v, w;
6803 const struct lys_module *aug_mod;
6804
6805 LY_ARRAY_FOR(ctx->mod->augmented_by, u) {
6806 aug_mod = ctx->mod->augmented_by[u];
6807
6808 /* collect all module augments */
6809 LY_ARRAY_FOR(aug_mod->parsed->augments, v) {
6810 LY_CHECK_RET(lys_precompile_own_augment(ctx, &aug_mod->parsed->augments[v], aug_mod));
6811 }
6812
6813 /* collect all submodules augments */
6814 LY_ARRAY_FOR(aug_mod->parsed->includes, v) {
6815 LY_ARRAY_FOR(aug_mod->parsed->includes[v].submodule->augments, w) {
6816 LY_CHECK_RET(lys_precompile_own_augment(ctx, &aug_mod->parsed->includes[v].submodule->augments[w], aug_mod));
6817 }
6818 }
6819 }
6820
6821 return LY_SUCCESS;
6822}
6823
6824/**
6825 * @brief Prepare a deviation to be applied during data nodes compilation.
6826 *
6827 * @param[in] ctx Compile context.
6828 * @param[in] dev_p Parsed deviation to be applied.
6829 * @param[in] mod_def Local module for @p dev_p.
6830 * @return LY_ERR value.
6831 */
6832static LY_ERR
6833lys_precompile_own_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev_p, const struct lys_module *mod_def)
6834{
6835 LY_ERR ret = LY_SUCCESS;
6836 struct lysc_deviation *dev = NULL;
6837 struct lyxp_expr *exp = NULL;
6838 struct lysp_deviation **new_dev;
6839 const struct lys_module *mod, **new_dev_mod;
6840 uint32_t i;
6841
6842 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
6843 ret = lyxp_expr_parse(ctx->ctx, dev_p->nodeid, strlen(dev_p->nodeid), 0, &exp);
6844 LY_CHECK_GOTO(ret, cleanup);
6845
6846 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], mod_def, NULL, NULL);
6847 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
6848 if (mod != ctx->mod) {
6849 /* deviation for another module, ignore */
6850 goto cleanup;
6851 }
6852
6853 /* try to find the node in already compiled deviations */
6854 for (i = 0; i < ctx->devs.count; ++i) {
6855 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, mod_def, ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid,
6856 ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid_mod)) {
6857 dev = ctx->devs.objs[i];
6858 break;
6859 }
6860 }
6861
6862 if (!dev) {
6863 /* allocate new compiled deviation */
6864 dev = calloc(1, sizeof *dev);
6865 LY_CHECK_ERR_GOTO(!dev, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
6866 LY_CHECK_GOTO(ret = ly_set_add(&ctx->devs, dev, LY_SET_OPT_USEASLIST, NULL), cleanup);
6867
6868 dev->nodeid = exp;
6869 exp = NULL;
6870 dev->nodeid_mod = mod_def;
6871 }
6872
6873 /* add new parsed deviation structure */
6874 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->devs, new_dev, ret, cleanup);
6875 *new_dev = dev_p;
6876 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->dev_mods, new_dev_mod, ret, cleanup);
6877 *new_dev_mod = mod_def;
6878
6879cleanup:
6880 lyxp_expr_free(ctx->ctx, exp);
6881 return ret;
6882}
6883
6884/**
6885 * @brief Prepare all deviations for the current module to be applied during data nodes compilation.
6886 *
6887 * @param[in] ctx Compile context.
6888 * @return LY_ERR value.
6889 */
6890static LY_ERR
6891lys_precompile_own_deviations(struct lysc_ctx *ctx)
6892{
6893 LY_ARRAY_COUNT_TYPE u, v, w;
6894 const struct lys_module *dev_mod;
6895 struct lysc_deviation *dev;
6896 struct lysp_deviate *d;
6897 int not_supported;
6898 uint32_t i;
6899
6900 LY_ARRAY_FOR(ctx->mod->deviated_by, u) {
6901 dev_mod = ctx->mod->deviated_by[u];
6902
6903 /* compile all module deviations */
6904 LY_ARRAY_FOR(dev_mod->parsed->deviations, v) {
6905 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->deviations[v], dev_mod));
6906 }
6907
6908 /* compile all submodules deviations */
6909 LY_ARRAY_FOR(dev_mod->parsed->includes, v) {
6910 LY_ARRAY_FOR(dev_mod->parsed->includes[v].submodule->deviations, w) {
6911 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->includes[v].submodule->deviations[w], dev_mod));
6912 }
6913 }
6914 }
6915
6916 /* set not-supported flags for all the deviations */
6917 for (i = 0; i < ctx->devs.count; ++i) {
6918 dev = ctx->devs.objs[i];
6919 not_supported = 0;
6920
6921 LY_ARRAY_FOR(dev->devs, u) {
6922 LY_LIST_FOR(dev->devs[u]->deviates, d) {
6923 if (d->mod == LYS_DEV_NOT_SUPPORTED) {
6924 not_supported = 1;
6925 break;
6926 }
6927 }
6928 if (not_supported) {
6929 break;
6930 }
6931 }
6932 if (not_supported && (LY_ARRAY_COUNT(dev->devs) > 1)) {
6933 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
6934 "Multiple deviations of \"%s\" with one of them being \"not-supported\".", dev->nodeid->expr);
6935 return LY_EVALID;
6936 }
6937
6938 dev->not_supported = not_supported;
6939 }
6940
6941 return LY_SUCCESS;
6942}
6943
Michal Vasko20424b42020-08-31 12:29:38 +02006944/**
Radek Krejcia3045382018-11-22 14:30:31 +01006945 * @brief Compile parsed schema node information.
6946 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02006947 * @param[in] pnode Parsed schema node.
Radek Krejcia3045382018-11-22 14:30:31 +01006948 * @param[in] parent Compiled parent node where the current node is supposed to be connected. It is
6949 * NULL for top-level nodes, in such a case the module where the node will be connected is taken from
6950 * the compile context.
Radek Krejcib1b59152019-01-07 13:21:56 +01006951 * @param[in] uses_status If the node is being placed instead of uses, here we have the uses's status value (as node's flags).
6952 * Zero means no uses, non-zero value with no status bit set mean the default status.
Radek Krejcia3045382018-11-22 14:30:31 +01006953 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
6954 */
Radek Krejci19a96102018-11-15 13:38:09 +01006955static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02006956lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *parent, uint16_t uses_status,
6957 struct ly_set *child_set)
Radek Krejci19a96102018-11-15 13:38:09 +01006958{
Radek Krejci1c54f462020-05-12 17:25:34 +02006959 LY_ERR ret = LY_SUCCESS;
Radek Krejcic6b4f442020-08-12 14:45:18 +02006960 struct lysc_node *node = NULL;
Radek Krejci00b874b2019-02-12 10:54:50 +01006961 struct lysc_when **when;
Michal Vasko7f45cf22020-10-01 12:49:44 +02006962 struct lysp_node *dev_pnode = NULL, *orig_pnode = pnode;
Radek Krejci1deb5be2020-08-26 16:43:36 +02006963 LY_ARRAY_COUNT_TYPE u;
Michal Vasko7f45cf22020-10-01 12:49:44 +02006964 ly_bool not_supported;
Michal Vasko22df3f02020-08-24 13:29:22 +02006965 LY_ERR (*node_compile_spec)(struct lysc_ctx *, struct lysp_node *, struct lysc_node *);
Radek Krejci19a96102018-11-15 13:38:09 +01006966
Michal Vasko7f45cf22020-10-01 12:49:44 +02006967 if (pnode->nodetype != LYS_USES) {
6968 lysc_update_path(ctx, parent, pnode->name);
Radek Krejci327de162019-06-14 12:52:07 +02006969 } else {
6970 lysc_update_path(ctx, NULL, "{uses}");
Michal Vasko7f45cf22020-10-01 12:49:44 +02006971 lysc_update_path(ctx, NULL, pnode->name);
Radek Krejci327de162019-06-14 12:52:07 +02006972 }
6973
Michal Vasko7f45cf22020-10-01 12:49:44 +02006974 switch (pnode->nodetype) {
Radek Krejci19a96102018-11-15 13:38:09 +01006975 case LYS_CONTAINER:
Michal Vasko22df3f02020-08-24 13:29:22 +02006976 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_container));
Radek Krejci19a96102018-11-15 13:38:09 +01006977 node_compile_spec = lys_compile_node_container;
6978 break;
6979 case LYS_LEAF:
Michal Vasko22df3f02020-08-24 13:29:22 +02006980 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_leaf));
Radek Krejci19a96102018-11-15 13:38:09 +01006981 node_compile_spec = lys_compile_node_leaf;
6982 break;
6983 case LYS_LIST:
Michal Vasko22df3f02020-08-24 13:29:22 +02006984 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_list));
Radek Krejci9bb94eb2018-12-04 16:48:35 +01006985 node_compile_spec = lys_compile_node_list;
Radek Krejci19a96102018-11-15 13:38:09 +01006986 break;
6987 case LYS_LEAFLIST:
Michal Vasko22df3f02020-08-24 13:29:22 +02006988 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_leaflist));
Radek Krejci0e5d8382018-11-28 16:37:53 +01006989 node_compile_spec = lys_compile_node_leaflist;
Radek Krejci19a96102018-11-15 13:38:09 +01006990 break;
Radek Krejci19a96102018-11-15 13:38:09 +01006991 case LYS_CHOICE:
Michal Vasko22df3f02020-08-24 13:29:22 +02006992 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_choice));
Radek Krejci056d0a82018-12-06 16:57:25 +01006993 node_compile_spec = lys_compile_node_choice;
Radek Krejci19a96102018-11-15 13:38:09 +01006994 break;
Michal Vasko7f45cf22020-10-01 12:49:44 +02006995 case LYS_CASE:
Michal Vasko20424b42020-08-31 12:29:38 +02006996 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_case));
6997 node_compile_spec = lys_compile_node_case;
6998 break;
Radek Krejci19a96102018-11-15 13:38:09 +01006999 case LYS_ANYXML:
7000 case LYS_ANYDATA:
Michal Vasko22df3f02020-08-24 13:29:22 +02007001 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_anydata));
Radek Krejci9800fb82018-12-13 14:26:23 +01007002 node_compile_spec = lys_compile_node_any;
Radek Krejci19a96102018-11-15 13:38:09 +01007003 break;
Radek Krejcie86bf772018-12-14 11:39:53 +01007004 case LYS_USES:
Michal Vasko7f45cf22020-10-01 12:49:44 +02007005 ret = lys_compile_uses(ctx, (struct lysp_node_uses *)pnode, parent, child_set);
Radek Krejci327de162019-06-14 12:52:07 +02007006 lysc_update_path(ctx, NULL, NULL);
7007 lysc_update_path(ctx, NULL, NULL);
7008 return ret;
Radek Krejci19a96102018-11-15 13:38:09 +01007009 default:
7010 LOGINT(ctx->ctx);
7011 return LY_EINT;
7012 }
7013 LY_CHECK_ERR_RET(!node, LOGMEM(ctx->ctx), LY_EMEM);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007014
7015 /* compile any deviations for this node */
7016 LY_CHECK_ERR_RET(ret = lys_compile_node_deviations_refines(ctx, pnode, parent, &dev_pnode, &not_supported),
7017 free(node), ret);
7018 if (not_supported) {
7019 free(node);
7020 lysc_update_path(ctx, NULL, NULL);
7021 return LY_SUCCESS;
7022 } else if (dev_pnode) {
7023 pnode = dev_pnode;
7024 }
7025
7026 node->nodetype = pnode->nodetype;
Radek Krejci19a96102018-11-15 13:38:09 +01007027 node->module = ctx->mod;
7028 node->prev = node;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007029 node->flags = pnode->flags & LYS_FLAGS_COMPILED_MASK;
Radek Krejci19a96102018-11-15 13:38:09 +01007030
7031 /* config */
Michal Vasko20424b42020-08-31 12:29:38 +02007032 ret = lys_compile_config(ctx, node, parent);
7033 LY_CHECK_GOTO(ret, error);
Radek Krejci19a96102018-11-15 13:38:09 +01007034
Michal Vasko20424b42020-08-31 12:29:38 +02007035 /* list ordering */
Radek Krejcia6d57732018-11-29 13:40:37 +01007036 if (node->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
7037 if ((node->flags & LYS_CONFIG_R) && (node->flags & LYS_ORDBY_MASK)) {
Radek Krejcifc11bd72019-04-11 16:00:05 +02007038 LOGWRN(ctx->ctx, "The ordered-by statement is ignored in lists representing %s (%s).",
Radek Krejci0f969882020-08-21 16:56:47 +02007039 (ctx->options & LYSC_OPT_RPC_OUTPUT) ? "RPC/action output parameters" :
7040 (ctx->options & LYSC_OPT_NOTIFICATION) ? "notification content" : "state data", ctx->path);
Radek Krejcia6d57732018-11-29 13:40:37 +01007041 node->flags &= ~LYS_ORDBY_MASK;
7042 node->flags |= LYS_ORDBY_SYSTEM;
7043 } else if (!(node->flags & LYS_ORDBY_MASK)) {
7044 /* default ordering is system */
7045 node->flags |= LYS_ORDBY_SYSTEM;
7046 }
7047 }
7048
Radek Krejci19a96102018-11-15 13:38:09 +01007049 /* status - it is not inherited by specification, but it does not make sense to have
7050 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
Michal Vasko20424b42020-08-31 12:29:38 +02007051 LY_CHECK_GOTO(ret = lys_compile_status(ctx, &node->flags, uses_status ? uses_status : (parent ? parent->flags : 0)), error);
Radek Krejci19a96102018-11-15 13:38:09 +01007052
Radek Krejciec4da802019-05-02 13:02:41 +02007053 if (!(ctx->options & LYSC_OPT_FREE_SP)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02007054 node->sp = orig_pnode;
Radek Krejci19a96102018-11-15 13:38:09 +01007055 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02007056 DUP_STRING_GOTO(ctx->ctx, pnode->name, node->name, ret, error);
7057 DUP_STRING_GOTO(ctx->ctx, pnode->dsc, node->dsc, ret, error);
7058 DUP_STRING_GOTO(ctx->ctx, pnode->ref, node->ref, ret, error);
7059 if (pnode->when) {
Radek Krejci00b874b2019-02-12 10:54:50 +01007060 LY_ARRAY_NEW_GOTO(ctx->ctx, node->when, when, ret, error);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007061 LY_CHECK_GOTO(ret = lys_compile_when(ctx, pnode->when, pnode->flags, node, when), error);
Michal Vasko175012e2019-11-06 15:49:14 +01007062
7063 if (!(ctx->options & LYSC_OPT_GROUPING)) {
7064 /* do not check "when" semantics in a grouping */
Michal Vasko7f45cf22020-10-01 12:49:44 +02007065 LY_CHECK_GOTO(ret = ly_set_add(&ctx->xpath, node, 0, NULL), error);
Michal Vasko175012e2019-11-06 15:49:14 +01007066 }
Radek Krejci00b874b2019-02-12 10:54:50 +01007067 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02007068 COMPILE_ARRAY_GOTO(ctx, pnode->iffeatures, node->iffeatures, u, lys_compile_iffeature, ret, error);
Radek Krejci19a96102018-11-15 13:38:09 +01007069
Michal Vasko20424b42020-08-31 12:29:38 +02007070 /* insert into parent's children/compiled module (we can no longer free the node separately on error) */
Michal Vasko7f45cf22020-10-01 12:49:44 +02007071 LY_CHECK_GOTO(ret = lys_compile_node_connect(ctx, parent, node), cleanup);
7072
7073 /* connect any augments */
7074 LY_CHECK_GOTO(ret = lys_compile_node_augments(ctx, node), cleanup);
Michal Vasko20424b42020-08-31 12:29:38 +02007075
Radek Krejci19a96102018-11-15 13:38:09 +01007076 /* nodetype-specific part */
Michal Vasko7f45cf22020-10-01 12:49:44 +02007077 LY_CHECK_GOTO(ret = node_compile_spec(ctx, pnode, node), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01007078
Michal Vasko20424b42020-08-31 12:29:38 +02007079 /* final compilation tasks that require the node to be connected */
Michal Vasko7f45cf22020-10-01 12:49:44 +02007080 COMPILE_EXTS_GOTO(ctx, pnode->exts, node->exts, node, LYEXT_PAR_NODE, ret, cleanup);
Radek Krejcife909632019-02-12 15:34:42 +01007081 if (node->flags & LYS_MAND_TRUE) {
Michal Vasko20424b42020-08-31 12:29:38 +02007082 /* inherit LYS_MAND_TRUE in parent containers */
Radek Krejcife909632019-02-12 15:34:42 +01007083 lys_compile_mandatory_parents(parent, 1);
7084 }
7085
Michal Vasko7f45cf22020-10-01 12:49:44 +02007086 if (child_set) {
7087 /* add the new node into set */
7088 LY_CHECK_GOTO(ret = ly_set_add(child_set, node, LY_SET_OPT_USEASLIST, NULL), cleanup);
7089 }
7090
Radek Krejci327de162019-06-14 12:52:07 +02007091 lysc_update_path(ctx, NULL, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007092 lysp_dev_node_free(ctx->ctx, dev_pnode);
Radek Krejci19a96102018-11-15 13:38:09 +01007093 return LY_SUCCESS;
7094
7095error:
7096 lysc_node_free(ctx->ctx, node);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007097cleanup:
7098 if (dev_pnode) {
7099 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_OTHER, "Compilation of a deviated and/or refined node failed.");
7100 lysp_dev_node_free(ctx->ctx, dev_pnode);
7101 }
Radek Krejci19a96102018-11-15 13:38:09 +01007102 return ret;
7103}
7104
Michal Vaskoccc062a2020-08-13 08:34:50 +02007105/**
Michal Vasko7f45cf22020-10-01 12:49:44 +02007106 * @brief Add a module reference into an array, checks for duplicities.
Michal Vaskoccc062a2020-08-13 08:34:50 +02007107 *
7108 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02007109 * @param[in] mod Module reference to add.
7110 * @param[in,out] mod_array Module sized array to add to.
Michal Vaskoccc062a2020-08-13 08:34:50 +02007111 * @return LY_ERR value.
7112 */
7113static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02007114lys_array_add_mod_ref(struct lysc_ctx *ctx, struct lys_module *mod, struct lys_module ***mod_array)
Michal Vaskoccc062a2020-08-13 08:34:50 +02007115{
Michal Vasko7f45cf22020-10-01 12:49:44 +02007116 LY_ARRAY_COUNT_TYPE u;
7117 struct lys_module **new_mod;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007118
Michal Vasko7f45cf22020-10-01 12:49:44 +02007119 LY_ARRAY_FOR(*mod_array, u) {
7120 if ((*mod_array)[u] == mod) {
7121 /* already there */
7122 return LY_EEXIST;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007123 }
7124 }
7125
Michal Vasko7f45cf22020-10-01 12:49:44 +02007126 /* add the new module ref */
7127 LY_ARRAY_NEW_RET(ctx->ctx, *mod_array, new_mod, LY_EMEM);
7128 *new_mod = mod;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007129
7130 return LY_SUCCESS;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007131}
7132
Michal Vaskoccc062a2020-08-13 08:34:50 +02007133/**
Michal Vasko7f45cf22020-10-01 12:49:44 +02007134 * @brief Compile top-level augments and deviations defined in the current module.
7135 * Generally, just add the module refence to the target modules.
Michal Vaskoccc062a2020-08-13 08:34:50 +02007136 *
7137 * @param[in] ctx Compile context.
Michal Vaskoccc062a2020-08-13 08:34:50 +02007138 * @return LY_ERR value.
7139 */
7140static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02007141lys_precompile_augments_deviations(struct lysc_ctx *ctx)
Michal Vaskoccc062a2020-08-13 08:34:50 +02007142{
Michal Vasko7f45cf22020-10-01 12:49:44 +02007143 LY_ERR ret = LY_SUCCESS;
7144 LY_ARRAY_COUNT_TYPE u, v;
7145 const struct lysp_module *mod_p;
7146 const struct lysc_node *target;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007147 struct lys_module *mod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007148 struct lysp_submodule *submod;
7149 ly_bool has_dev = 0;
7150 uint16_t flags;
7151 uint32_t idx, opt_prev = ctx->options;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007152
Michal Vasko7f45cf22020-10-01 12:49:44 +02007153 mod_p = ctx->mod->parsed;
7154
7155 if (mod_p->mod->implemented == 1) {
7156 /* it was already implemented and all the augments and deviations fully applied */
7157 return LY_SUCCESS;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007158 }
7159
Michal Vasko7f45cf22020-10-01 12:49:44 +02007160 LY_ARRAY_FOR(mod_p->augments, u) {
7161 lysc_update_path(ctx, NULL, "{augment}");
7162 lysc_update_path(ctx, NULL, mod_p->augments[u].nodeid);
Michal Vaskoccc062a2020-08-13 08:34:50 +02007163
Michal Vasko7f45cf22020-10-01 12:49:44 +02007164 /* get target module */
7165 ret = lys_nodeid_check(ctx, mod_p->augments[u].nodeid, 1, &mod, NULL);
7166 LY_CHECK_RET(ret);
Michal Vaskoccc062a2020-08-13 08:34:50 +02007167
Michal Vasko7f45cf22020-10-01 12:49:44 +02007168 /* add this module into the target module augmented_by, if not there already from previous augments */
7169 lys_array_add_mod_ref(ctx, ctx->mod, &mod->augmented_by);
Michal Vaskoccc062a2020-08-13 08:34:50 +02007170
Michal Vasko7f45cf22020-10-01 12:49:44 +02007171 /* if we are compiling this module, we cannot add augments to it yet */
7172 if (mod != ctx->mod) {
7173 /* apply the augment, find the target node first */
7174 flags = 0;
7175 ret = lysc_resolve_schema_nodeid(ctx, mod_p->augments[u].nodeid, 0, NULL, ctx->mod_def, 0, &target, &flags);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007176 LY_CHECK_RET(ret);
7177
Michal Vasko7f45cf22020-10-01 12:49:44 +02007178 /* apply the augment */
7179 ctx->options |= flags;
7180 ret = lys_compile_augment(ctx, &mod_p->augments[u], (struct lysc_node *)target);
7181 ctx->options = opt_prev;
7182 LY_CHECK_RET(ret);
Radek Krejciccd20f12019-02-15 14:12:27 +01007183 }
Radek Krejci327de162019-06-14 12:52:07 +02007184
7185 lysc_update_path(ctx, NULL, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007186 lysc_update_path(ctx, NULL, NULL);
Radek Krejciccd20f12019-02-15 14:12:27 +01007187 }
7188
Michal Vasko7f45cf22020-10-01 12:49:44 +02007189 LY_ARRAY_FOR(mod_p->deviations, u) {
7190 /* get target module */
7191 lysc_update_path(ctx, NULL, "{deviation}");
7192 lysc_update_path(ctx, NULL, mod_p->deviations[u].nodeid);
7193 ret = lys_nodeid_check(ctx, mod_p->deviations[u].nodeid, 1, &mod, NULL);
7194 lysc_update_path(ctx, NULL, NULL);
7195 lysc_update_path(ctx, NULL, NULL);
7196 LY_CHECK_RET(ret);
Radek Krejciba03a5a2020-08-27 14:40:41 +02007197
Michal Vasko7f45cf22020-10-01 12:49:44 +02007198 /* add this module into the target module deviated_by, if not there already from previous deviations */
7199 lys_array_add_mod_ref(ctx, ctx->mod, &mod->deviated_by);
7200
7201 /* new deviation added to the target module */
7202 has_dev = 1;
7203 }
7204
7205 /* the same for augments and deviations in submodules */
7206 LY_ARRAY_FOR(mod_p->includes, v) {
7207 submod = mod_p->includes[v].submodule;
7208 LY_ARRAY_FOR(submod->augments, u) {
7209 lysc_update_path(ctx, NULL, "{augment}");
7210 lysc_update_path(ctx, NULL, submod->augments[u].nodeid);
7211
7212 ret = lys_nodeid_check(ctx, submod->augments[u].nodeid, 1, &mod, NULL);
7213 LY_CHECK_RET(ret);
7214
7215 lys_array_add_mod_ref(ctx, ctx->mod, &mod->augmented_by);
7216 if (mod != ctx->mod) {
7217 flags = 0;
7218 ret = lysc_resolve_schema_nodeid(ctx, mod_p->augments[u].nodeid, 0, NULL, ctx->mod_def, 0, &target, &flags);
7219 LY_CHECK_RET(ret);
7220
7221 ctx->options |= flags;
7222 ret = lys_compile_augment(ctx, &submod->augments[u], (struct lysc_node *)target);
7223 ctx->options = opt_prev;
7224 LY_CHECK_RET(ret);
Radek Krejcif538ce52019-03-05 10:46:14 +01007225 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02007226
7227 lysc_update_path(ctx, NULL, NULL);
7228 lysc_update_path(ctx, NULL, NULL);
Radek Krejcif538ce52019-03-05 10:46:14 +01007229 }
7230
Michal Vasko7f45cf22020-10-01 12:49:44 +02007231 LY_ARRAY_FOR(submod->deviations, u) {
7232 lysc_update_path(ctx, NULL, "{deviation}");
7233 lysc_update_path(ctx, NULL, submod->deviations[u].nodeid);
7234 ret = lys_nodeid_check(ctx, submod->deviations[u].nodeid, 1, &mod, NULL);
7235 lysc_update_path(ctx, NULL, NULL);
7236 lysc_update_path(ctx, NULL, NULL);
7237 LY_CHECK_RET(ret);
Radek Krejcifc11bd72019-04-11 16:00:05 +02007238
Michal Vasko7f45cf22020-10-01 12:49:44 +02007239 lys_array_add_mod_ref(ctx, ctx->mod, &mod->deviated_by);
7240 has_dev = 1;
Michal Vaskoe6143202020-07-03 13:02:08 +02007241 }
Radek Krejciccd20f12019-02-15 14:12:27 +01007242 }
7243
Michal Vasko7f45cf22020-10-01 12:49:44 +02007244 if (!has_dev) {
7245 /* no need to recompile any modules */
7246 return LY_SUCCESS;
7247 }
7248
7249 /* free all the modules in descending order */
7250 idx = ctx->ctx->list.count;
7251 do {
7252 --idx;
7253 mod = ctx->ctx->list.objs[idx];
7254 /* skip this module */
7255 if (mod == mod_p->mod) {
7256 continue;
7257 }
7258
7259 if (mod->implemented && mod->compiled) {
7260 /* keep information about features state in the module */
7261 lys_feature_precompile_revert(ctx, mod);
7262
7263 /* free the module */
7264 lysc_module_free(mod->compiled, NULL);
7265 mod->compiled = NULL;
7266 }
7267 } while (idx);
7268
7269 /* recompile all the modules in ascending order */
7270 for (idx = 0; idx < ctx->ctx->list.count; ++idx) {
7271 mod = ctx->ctx->list.objs[idx];
7272
7273 /* skip this module */
7274 if (mod == mod_p->mod) {
7275 continue;
7276 }
7277
7278 if (mod->implemented) {
7279 /* compile */
7280 LY_CHECK_GOTO(ret = lys_compile(mod, LYSC_OPT_INTERNAL), cleanup);
7281 }
7282 }
Radek Krejciccd20f12019-02-15 14:12:27 +01007283
7284cleanup:
Radek Krejcid05cbd92018-12-05 14:26:40 +01007285 return ret;
7286}
7287
Radek Krejci335332a2019-09-05 13:03:35 +02007288static void *
7289lys_compile_extension_instance_storage(enum ly_stmt stmt, struct lysc_ext_substmt *substmts)
7290{
Radek Krejci1deb5be2020-08-26 16:43:36 +02007291 for (LY_ARRAY_COUNT_TYPE u = 0; substmts[u].stmt; ++u) {
Radek Krejci335332a2019-09-05 13:03:35 +02007292 if (substmts[u].stmt == stmt) {
7293 return substmts[u].storage;
7294 }
7295 }
7296 return NULL;
7297}
7298
7299LY_ERR
7300lys_compile_extension_instance(struct lysc_ctx *ctx, const struct lysp_ext_instance *ext, struct lysc_ext_substmt *substmts)
7301{
7302 LY_ERR ret = LY_EVALID, r;
Radek Krejci1deb5be2020-08-26 16:43:36 +02007303 LY_ARRAY_COUNT_TYPE u;
Radek Krejci335332a2019-09-05 13:03:35 +02007304 struct lysp_stmt *stmt;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007305 struct lysp_qname qname;
Radek Krejci335332a2019-09-05 13:03:35 +02007306 void *parsed = NULL, **compiled = NULL;
Radek Krejci335332a2019-09-05 13:03:35 +02007307
7308 /* check for invalid substatements */
7309 for (stmt = ext->child; stmt; stmt = stmt->next) {
Radek Krejcif56e2a42019-09-09 14:15:25 +02007310 if (stmt->flags & (LYS_YIN_ATTR | LYS_YIN_ARGUMENT)) {
7311 continue;
7312 }
Radek Krejci335332a2019-09-05 13:03:35 +02007313 for (u = 0; substmts[u].stmt; ++u) {
7314 if (substmts[u].stmt == stmt->kw) {
7315 break;
7316 }
7317 }
7318 if (!substmts[u].stmt) {
Radek Krejciad5963b2019-09-06 16:03:05 +02007319 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s%s%s\" extension instance.",
7320 stmt->stmt, ext->name, ext->argument ? " " : "", ext->argument ? ext->argument : "");
Radek Krejci335332a2019-09-05 13:03:35 +02007321 goto cleanup;
7322 }
Radek Krejci335332a2019-09-05 13:03:35 +02007323 }
7324
Radek Krejciad5963b2019-09-06 16:03:05 +02007325 /* TODO store inherited data, e.g. status first, but mark them somehow to allow to overwrite them and not detect duplicity */
7326
Radek Krejci335332a2019-09-05 13:03:35 +02007327 /* keep order of the processing the same as the order in the defined substmts,
7328 * the order is important for some of the statements depending on others (e.g. type needs status and units) */
7329 for (u = 0; substmts[u].stmt; ++u) {
Radek Krejci857189e2020-09-01 13:26:36 +02007330 ly_bool stmt_present = 0;
Radek Krejciad5963b2019-09-06 16:03:05 +02007331
Radek Krejci335332a2019-09-05 13:03:35 +02007332 for (stmt = ext->child; stmt; stmt = stmt->next) {
7333 if (substmts[u].stmt != stmt->kw) {
7334 continue;
7335 }
7336
Radek Krejciad5963b2019-09-06 16:03:05 +02007337 stmt_present = 1;
Radek Krejci335332a2019-09-05 13:03:35 +02007338 if (substmts[u].storage) {
7339 switch (stmt->kw) {
Radek Krejciad5963b2019-09-06 16:03:05 +02007340 case LY_STMT_STATUS:
7341 assert(substmts[u].cardinality < LY_STMT_CARD_SOME);
7342 LY_CHECK_ERR_GOTO(r = lysp_stmt_parse(ctx, stmt, stmt->kw, &substmts[u].storage, /* TODO */ NULL), ret = r, cleanup);
7343 break;
7344 case LY_STMT_UNITS: {
7345 const char **units;
7346
7347 if (substmts[u].cardinality < LY_STMT_CARD_SOME) {
7348 /* single item */
7349 if (*((const char **)substmts[u].storage)) {
7350 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPSTMT, stmt->stmt);
7351 goto cleanup;
7352 }
7353 units = (const char **)substmts[u].storage;
7354 } else {
7355 /* sized array */
7356 const char ***units_array = (const char ***)substmts[u].storage;
7357 LY_ARRAY_NEW_GOTO(ctx->ctx, *units_array, units, ret, cleanup);
7358 }
Radek Krejci011e4aa2020-09-04 15:22:31 +02007359 r = lydict_insert(ctx->ctx, stmt->arg, 0, units);
7360 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
Radek Krejciad5963b2019-09-06 16:03:05 +02007361 break;
7362 }
Radek Krejci335332a2019-09-05 13:03:35 +02007363 case LY_STMT_TYPE: {
7364 uint16_t *flags = lys_compile_extension_instance_storage(LY_STMT_STATUS, substmts);
7365 const char **units = lys_compile_extension_instance_storage(LY_STMT_UNITS, substmts);
7366
7367 if (substmts[u].cardinality < LY_STMT_CARD_SOME) {
7368 /* single item */
Michal Vasko22df3f02020-08-24 13:29:22 +02007369 if (*(struct lysc_type **)substmts[u].storage) {
Radek Krejci335332a2019-09-05 13:03:35 +02007370 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPSTMT, stmt->stmt);
7371 goto cleanup;
7372 }
7373 compiled = substmts[u].storage;
7374 } else {
7375 /* sized array */
Michal Vasko22df3f02020-08-24 13:29:22 +02007376 struct lysc_type ***types = (struct lysc_type ***)substmts[u].storage, **type = NULL;
Radek Krejci335332a2019-09-05 13:03:35 +02007377 LY_ARRAY_NEW_GOTO(ctx->ctx, *types, type, ret, cleanup);
Michal Vasko22df3f02020-08-24 13:29:22 +02007378 compiled = (void *)type;
Radek Krejci335332a2019-09-05 13:03:35 +02007379 }
7380
Radek Krejciad5963b2019-09-06 16:03:05 +02007381 LY_CHECK_ERR_GOTO(r = lysp_stmt_parse(ctx, stmt, stmt->kw, &parsed, NULL), ret = r, cleanup);
Michal Vasko22df3f02020-08-24 13:29:22 +02007382 LY_CHECK_ERR_GOTO(r = lys_compile_type(ctx, ext->parent_type == LYEXT_PAR_NODE ? ((struct lysc_node *)ext->parent)->sp : NULL,
7383 flags ? *flags : 0, ctx->mod_def->parsed, ext->name, parsed, (struct lysc_type **)compiled,
Michal Vasko7f45cf22020-10-01 12:49:44 +02007384 units && !*units ? units : NULL, NULL), lysp_type_free(ctx->ctx, parsed); free(parsed); ret = r, cleanup);
Radek Krejci38d85362019-09-05 16:26:38 +02007385 lysp_type_free(ctx->ctx, parsed);
7386 free(parsed);
Radek Krejci335332a2019-09-05 13:03:35 +02007387 break;
7388 }
Radek Krejciad5963b2019-09-06 16:03:05 +02007389 case LY_STMT_IF_FEATURE: {
7390 struct lysc_iffeature *iff = NULL;
7391
7392 if (substmts[u].cardinality < LY_STMT_CARD_SOME) {
7393 /* single item */
Michal Vasko22df3f02020-08-24 13:29:22 +02007394 if (((struct lysc_iffeature *)substmts[u].storage)->features) {
Radek Krejciad5963b2019-09-06 16:03:05 +02007395 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPSTMT, stmt->stmt);
7396 goto cleanup;
7397 }
Michal Vasko22df3f02020-08-24 13:29:22 +02007398 iff = (struct lysc_iffeature *)substmts[u].storage;
Radek Krejciad5963b2019-09-06 16:03:05 +02007399 } else {
7400 /* sized array */
Michal Vasko22df3f02020-08-24 13:29:22 +02007401 struct lysc_iffeature **iffs = (struct lysc_iffeature **)substmts[u].storage;
Radek Krejciad5963b2019-09-06 16:03:05 +02007402 LY_ARRAY_NEW_GOTO(ctx->ctx, *iffs, iff, ret, cleanup);
7403 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02007404 qname.str = stmt->arg;
7405 qname.mod = ctx->mod_def;
7406 LY_CHECK_ERR_GOTO(r = lys_compile_iffeature(ctx, &qname, iff), ret = r, cleanup);
Radek Krejciad5963b2019-09-06 16:03:05 +02007407 break;
7408 }
7409 /* TODO support other substatements (parse stmt to lysp and then compile lysp to lysc),
7410 * also note that in many statements their extensions are not taken into account */
Radek Krejci335332a2019-09-05 13:03:35 +02007411 default:
Radek Krejciad5963b2019-09-06 16:03:05 +02007412 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Statement \"%s\" is not supported as an extension (found in \"%s%s%s\") substatement.",
7413 stmt->stmt, ext->name, ext->argument ? " " : "", ext->argument ? ext->argument : "");
Radek Krejci335332a2019-09-05 13:03:35 +02007414 goto cleanup;
7415 }
7416 }
Radek Krejci335332a2019-09-05 13:03:35 +02007417 }
Radek Krejci335332a2019-09-05 13:03:35 +02007418
Radek Krejciad5963b2019-09-06 16:03:05 +02007419 if ((substmts[u].cardinality == LY_STMT_CARD_MAND || substmts[u].cardinality == LY_STMT_CARD_SOME) && !stmt_present) {
7420 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Missing mandatory keyword \"%s\" as a child of \"%s%s%s\".",
7421 ly_stmt2str(substmts[u].stmt), ext->name, ext->argument ? " " : "", ext->argument ? ext->argument : "");
7422 goto cleanup;
7423 }
Radek Krejci335332a2019-09-05 13:03:35 +02007424 }
7425
7426 ret = LY_SUCCESS;
7427
7428cleanup:
Radek Krejci335332a2019-09-05 13:03:35 +02007429 return ret;
7430}
7431
Michal Vasko175012e2019-11-06 15:49:14 +01007432/**
Michal Vaskoecd62de2019-11-13 12:35:11 +01007433 * @brief Check when for cyclic dependencies.
Michal Vasko7f45cf22020-10-01 12:49:44 +02007434 *
Michal Vaskoecd62de2019-11-13 12:35:11 +01007435 * @param[in] set Set with all the referenced nodes.
7436 * @param[in] node Node whose "when" referenced nodes are in @p set.
7437 * @return LY_ERR value
7438 */
7439static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02007440lys_compile_unres_when_cyclic(struct lyxp_set *set, const struct lysc_node *node)
Michal Vaskoecd62de2019-11-13 12:35:11 +01007441{
7442 struct lyxp_set tmp_set;
7443 struct lyxp_set_scnode *xp_scnode;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007444 uint32_t i, j;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02007445 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoecd62de2019-11-13 12:35:11 +01007446 struct lysc_when *when;
7447 LY_ERR ret = LY_SUCCESS;
7448
7449 memset(&tmp_set, 0, sizeof tmp_set);
7450
7451 /* prepare in_ctx of the set */
Michal Vaskod989ba02020-08-24 10:59:24 +02007452 for (i = 0; i < set->used; ++i) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007453 xp_scnode = &set->val.scnodes[i];
7454
Michal Vasko5c4e5892019-11-14 12:31:38 +01007455 if (xp_scnode->in_ctx != -1) {
7456 /* check node when, skip the context node (it was just checked) */
Michal Vaskoecd62de2019-11-13 12:35:11 +01007457 xp_scnode->in_ctx = 1;
7458 }
7459 }
7460
7461 for (i = 0; i < set->used; ++i) {
7462 xp_scnode = &set->val.scnodes[i];
7463 if (xp_scnode->in_ctx != 1) {
7464 /* already checked */
7465 continue;
7466 }
7467
Michal Vasko1bf09392020-03-27 12:38:10 +01007468 if ((xp_scnode->type != LYXP_NODE_ELEM) || (xp_scnode->scnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF))
Michal Vasko2ff7efe2019-12-10 14:50:59 +01007469 || !xp_scnode->scnode->when) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007470 /* no when to check */
7471 xp_scnode->in_ctx = 0;
7472 continue;
7473 }
7474
7475 node = xp_scnode->scnode;
7476 do {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007477 LY_ARRAY_FOR(node->when, u) {
7478 when = node->when[u];
Michal Vaskoc8a230d2020-08-14 12:17:10 +02007479 ret = lyxp_atomize(when->cond, LY_PREF_SCHEMA, when->module, when->context,
Michal Vaskoecd62de2019-11-13 12:35:11 +01007480 when->context ? LYXP_NODE_ELEM : LYXP_NODE_ROOT_CONFIG, &tmp_set, LYXP_SCNODE_SCHEMA);
7481 if (ret != LY_SUCCESS) {
Michal Vaskof6e51882019-12-16 09:59:45 +01007482 LOGVAL(set->ctx, LY_VLOG_LYSC, node, LYVE_SEMANTICS, "Invalid when condition \"%s\".", when->cond->expr);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007483 goto cleanup;
7484 }
7485
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007486 for (j = 0; j < tmp_set.used; ++j) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007487 /* skip roots'n'stuff */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007488 if (tmp_set.val.scnodes[j].type == LYXP_NODE_ELEM) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007489 /* try to find this node in our set */
Radek Krejciaa6b53f2020-08-27 15:19:03 +02007490 uint32_t idx;
7491 if (lyxp_set_scnode_contains(set, tmp_set.val.scnodes[j].scnode, LYXP_NODE_ELEM, -1, &idx) && (set->val.scnodes[idx].in_ctx == -1)) {
Michal Vaskof6e51882019-12-16 09:59:45 +01007492 LOGVAL(set->ctx, LY_VLOG_LYSC, node, LY_VCODE_CIRC_WHEN, node->name, set->val.scnodes[idx].scnode->name);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007493 ret = LY_EVALID;
7494 goto cleanup;
7495 }
7496
7497 /* needs to be checked, if in both sets, will be ignored */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007498 tmp_set.val.scnodes[j].in_ctx = 1;
Michal Vaskoecd62de2019-11-13 12:35:11 +01007499 } else {
7500 /* no when, nothing to check */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007501 tmp_set.val.scnodes[j].in_ctx = 0;
Michal Vaskoecd62de2019-11-13 12:35:11 +01007502 }
7503 }
7504
7505 /* merge this set into the global when set */
7506 lyxp_set_scnode_merge(set, &tmp_set);
7507 }
7508
7509 /* check when of non-data parents as well */
7510 node = node->parent;
7511 } while (node && (node->nodetype & (LYS_CASE | LYS_CHOICE)));
7512
Michal Vasko251f56e2019-11-14 16:06:47 +01007513 /* this node when was checked (xp_scnode could have been reallocd) */
7514 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoecd62de2019-11-13 12:35:11 +01007515 }
7516
7517cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02007518 lyxp_set_free_content(&tmp_set);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007519 return ret;
7520}
7521
7522/**
Michal Vasko7f45cf22020-10-01 12:49:44 +02007523 * @brief Check when/must expressions of a node on a complete compiled schema tree.
7524 *
Michal Vasko175012e2019-11-06 15:49:14 +01007525 * @param[in] ctx Compile context.
7526 * @param[in] node Node to check.
7527 * @return LY_ERR value
7528 */
7529static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02007530lys_compile_unres_xpath(struct lysc_ctx *ctx, const struct lysc_node *node)
Michal Vasko175012e2019-11-06 15:49:14 +01007531{
Michal Vasko175012e2019-11-06 15:49:14 +01007532 struct lyxp_set tmp_set;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007533 uint32_t i;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02007534 LY_ARRAY_COUNT_TYPE u;
Radek Krejci1deb5be2020-08-26 16:43:36 +02007535 uint32_t opts;
Radek Krejci857189e2020-09-01 13:26:36 +02007536 ly_bool input_done = 0;
Michal Vasko175012e2019-11-06 15:49:14 +01007537 struct lysc_when **when = NULL;
7538 struct lysc_must *musts = NULL;
7539 LY_ERR ret = LY_SUCCESS;
Michal Vasko6b26e742020-07-17 15:02:10 +02007540 const struct lysc_node *op;
Michal Vasko175012e2019-11-06 15:49:14 +01007541
7542 memset(&tmp_set, 0, sizeof tmp_set);
Michal Vasko5d8756a2019-11-07 15:21:00 +01007543 opts = LYXP_SCNODE_SCHEMA;
Michal Vasko6b26e742020-07-17 15:02:10 +02007544 if (node->flags & LYS_CONFIG_R) {
7545 for (op = node->parent; op && !(op->nodetype & (LYS_RPC | LYS_ACTION)); op = op->parent);
7546 if (op) {
7547 /* we are actually in output */
7548 opts = LYXP_SCNODE_OUTPUT;
7549 }
7550 }
Michal Vasko175012e2019-11-06 15:49:14 +01007551
7552 switch (node->nodetype) {
7553 case LYS_CONTAINER:
7554 when = ((struct lysc_node_container *)node)->when;
7555 musts = ((struct lysc_node_container *)node)->musts;
7556 break;
7557 case LYS_CHOICE:
7558 when = ((struct lysc_node_choice *)node)->when;
7559 break;
7560 case LYS_LEAF:
7561 when = ((struct lysc_node_leaf *)node)->when;
7562 musts = ((struct lysc_node_leaf *)node)->musts;
7563 break;
7564 case LYS_LEAFLIST:
7565 when = ((struct lysc_node_leaflist *)node)->when;
7566 musts = ((struct lysc_node_leaflist *)node)->musts;
7567 break;
7568 case LYS_LIST:
7569 when = ((struct lysc_node_list *)node)->when;
7570 musts = ((struct lysc_node_list *)node)->musts;
7571 break;
7572 case LYS_ANYXML:
7573 case LYS_ANYDATA:
7574 when = ((struct lysc_node_anydata *)node)->when;
7575 musts = ((struct lysc_node_anydata *)node)->musts;
7576 break;
7577 case LYS_CASE:
7578 when = ((struct lysc_node_case *)node)->when;
7579 break;
7580 case LYS_NOTIF:
7581 musts = ((struct lysc_notif *)node)->musts;
7582 break;
Michal Vasko1bf09392020-03-27 12:38:10 +01007583 case LYS_RPC:
Michal Vasko5d8756a2019-11-07 15:21:00 +01007584 case LYS_ACTION:
7585 /* first process input musts */
7586 musts = ((struct lysc_action *)node)->input.musts;
7587 break;
Michal Vasko175012e2019-11-06 15:49:14 +01007588 default:
7589 /* nothing to check */
7590 break;
7591 }
7592
Michal Vasko175012e2019-11-06 15:49:14 +01007593 /* check "when" */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007594 LY_ARRAY_FOR(when, u) {
Michal Vaskoc8a230d2020-08-14 12:17:10 +02007595 ret = lyxp_atomize(when[u]->cond, LY_PREF_SCHEMA, when[u]->module, when[u]->context ? when[u]->context : node,
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007596 when[u]->context ? LYXP_NODE_ELEM : LYXP_NODE_ROOT_CONFIG, &tmp_set, opts);
Michal Vasko175012e2019-11-06 15:49:14 +01007597 if (ret != LY_SUCCESS) {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007598 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_SEMANTICS, "Invalid when condition \"%s\".", when[u]->cond->expr);
Michal Vasko175012e2019-11-06 15:49:14 +01007599 goto cleanup;
7600 }
7601
Michal Vaskodc052f32019-11-07 11:11:38 +01007602 ctx->path[0] = '\0';
7603 lysc_path((struct lysc_node *)node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007604 for (i = 0; i < tmp_set.used; ++i) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01007605 /* skip roots'n'stuff */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007606 if ((tmp_set.val.scnodes[i].type == LYXP_NODE_ELEM) && (tmp_set.val.scnodes[i].in_ctx != -1)) {
7607 struct lysc_node *schema = tmp_set.val.scnodes[i].scnode;
Michal Vasko175012e2019-11-06 15:49:14 +01007608
Michal Vaskoecd62de2019-11-13 12:35:11 +01007609 /* XPath expression cannot reference "lower" status than the node that has the definition */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007610 ret = lysc_check_status(ctx, when[u]->flags, when[u]->module, node->name, schema->flags, schema->module,
Michal Vaskoecd62de2019-11-13 12:35:11 +01007611 schema->name);
7612 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko5c4e5892019-11-14 12:31:38 +01007613
7614 /* check dummy node accessing */
7615 if (schema == node) {
Michal Vaskof6e51882019-12-16 09:59:45 +01007616 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LY_VCODE_DUMMY_WHEN, node->name);
Michal Vasko5c4e5892019-11-14 12:31:38 +01007617 ret = LY_EVALID;
7618 goto cleanup;
7619 }
Michal Vasko175012e2019-11-06 15:49:14 +01007620 }
7621 }
7622
Michal Vaskoecd62de2019-11-13 12:35:11 +01007623 /* check cyclic dependencies */
Michal Vasko004d3152020-06-11 19:59:22 +02007624 ret = lys_compile_unres_when_cyclic(&tmp_set, node);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007625 LY_CHECK_GOTO(ret, cleanup);
7626
Michal Vaskod3678892020-05-21 10:06:58 +02007627 lyxp_set_free_content(&tmp_set);
Michal Vasko175012e2019-11-06 15:49:14 +01007628 }
7629
Michal Vasko5d8756a2019-11-07 15:21:00 +01007630check_musts:
Michal Vasko175012e2019-11-06 15:49:14 +01007631 /* check "must" */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007632 LY_ARRAY_FOR(musts, u) {
Michal Vaskoc8a230d2020-08-14 12:17:10 +02007633 ret = lyxp_atomize(musts[u].cond, LY_PREF_SCHEMA, musts[u].module, node, LYXP_NODE_ELEM, &tmp_set, opts);
Michal Vasko175012e2019-11-06 15:49:14 +01007634 if (ret != LY_SUCCESS) {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007635 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_SEMANTICS, "Invalid must restriction \"%s\".", musts[u].cond->expr);
Michal Vasko175012e2019-11-06 15:49:14 +01007636 goto cleanup;
7637 }
7638
Michal Vaskodc052f32019-11-07 11:11:38 +01007639 ctx->path[0] = '\0';
7640 lysc_path((struct lysc_node *)node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007641 for (i = 0; i < tmp_set.used; ++i) {
Michal Vasko175012e2019-11-06 15:49:14 +01007642 /* skip roots'n'stuff */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007643 if (tmp_set.val.scnodes[i].type == LYXP_NODE_ELEM) {
Michal Vasko175012e2019-11-06 15:49:14 +01007644 /* XPath expression cannot reference "lower" status than the node that has the definition */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007645 ret = lysc_check_status(ctx, node->flags, musts[u].module, node->name, tmp_set.val.scnodes[i].scnode->flags,
7646 tmp_set.val.scnodes[i].scnode->module, tmp_set.val.scnodes[i].scnode->name);
Michal Vasko175012e2019-11-06 15:49:14 +01007647 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko175012e2019-11-06 15:49:14 +01007648 }
7649 }
7650
Michal Vaskod3678892020-05-21 10:06:58 +02007651 lyxp_set_free_content(&tmp_set);
Michal Vasko175012e2019-11-06 15:49:14 +01007652 }
7653
Michal Vasko1bf09392020-03-27 12:38:10 +01007654 if ((node->nodetype & (LYS_RPC | LYS_ACTION)) && !input_done) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01007655 /* now check output musts */
7656 input_done = 1;
7657 musts = ((struct lysc_action *)node)->output.musts;
7658 opts = LYXP_SCNODE_OUTPUT;
7659 goto check_musts;
7660 }
7661
Michal Vasko175012e2019-11-06 15:49:14 +01007662cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02007663 lyxp_set_free_content(&tmp_set);
Michal Vasko175012e2019-11-06 15:49:14 +01007664 return ret;
7665}
7666
Michal Vasko7f45cf22020-10-01 12:49:44 +02007667/**
7668 * @brief Check leafref for its target existence on a complete compiled schema tree.
7669 *
7670 * @param[in] ctx Compile context.
7671 * @param[in] node Context node for the leafref.
7672 * @param[in] lref Leafref to resolve.
7673 * @return LY_ERR value.
7674 */
Michal Vasko8d544252020-03-02 10:19:52 +01007675static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02007676lys_compile_unres_leafref(struct lysc_ctx *ctx, const struct lysc_node *node, struct lysc_type_leafref *lref)
7677{
Michal Vasko6b26e742020-07-17 15:02:10 +02007678 const struct lysc_node *target = NULL, *siter;
Michal Vasko004d3152020-06-11 19:59:22 +02007679 struct ly_path *p;
7680 struct lysc_type *type;
7681
7682 assert(node->nodetype & (LYS_LEAF | LYS_LEAFLIST));
7683
7684 /* try to find the target */
Michal Vasko00cbf532020-06-15 13:58:47 +02007685 LY_CHECK_RET(ly_path_compile(ctx->ctx, node->module, node, lref->path, LY_PATH_LREF_TRUE,
7686 lysc_is_output(node) ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_MANY,
Michal Vaskoc8a230d2020-08-14 12:17:10 +02007687 LY_PREF_SCHEMA, lref->path_context, &p));
Michal Vasko004d3152020-06-11 19:59:22 +02007688
7689 /* get the target node */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02007690 target = p[LY_ARRAY_COUNT(p) - 1].node;
Michal Vasko004d3152020-06-11 19:59:22 +02007691 ly_path_free(node->module->ctx, p);
7692
7693 if (!(target->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
7694 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE,
7695 "Invalid leafref path \"%s\" - target node is %s instead of leaf or leaf-list.",
7696 lref->path->expr, lys_nodetype2str(target->nodetype));
7697 return LY_EVALID;
7698 }
7699
7700 /* check status */
7701 ctx->path[0] = '\0';
7702 lysc_path(node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
7703 ctx->path_len = strlen(ctx->path);
7704 if (lysc_check_status(ctx, node->flags, node->module, node->name, target->flags, target->module, target->name)) {
7705 return LY_EVALID;
7706 }
7707 ctx->path_len = 1;
7708 ctx->path[1] = '\0';
7709
7710 /* check config */
Michal Vasko6b26e742020-07-17 15:02:10 +02007711 if (lref->require_instance) {
Radek Krejci1e008d22020-08-17 11:37:37 +02007712 for (siter = node->parent; siter && !(siter->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); siter = siter->parent) {}
Michal Vasko6b26e742020-07-17 15:02:10 +02007713 if (!siter && (node->flags & LYS_CONFIG_W) && (target->flags & LYS_CONFIG_R)) {
Michal Vasko004d3152020-06-11 19:59:22 +02007714 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE, "Invalid leafref path \"%s\" - target is supposed"
7715 " to represent configuration data (as the leafref does), but it does not.", lref->path->expr);
7716 return LY_EVALID;
7717 }
7718 }
7719
7720 /* store the target's type and check for circular chain of leafrefs */
7721 lref->realtype = ((struct lysc_node_leaf *)target)->type;
7722 for (type = lref->realtype; type && type->basetype == LY_TYPE_LEAFREF; type = ((struct lysc_type_leafref *)type)->realtype) {
7723 if (type == (struct lysc_type *)lref) {
7724 /* circular chain detected */
7725 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE,
7726 "Invalid leafref path \"%s\" - circular chain of leafrefs detected.", lref->path->expr);
7727 return LY_EVALID;
7728 }
7729 }
7730
7731 /* check if leafref and its target are under common if-features */
7732 if (lys_compile_leafref_features_validate(node, target)) {
7733 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE,
7734 "Invalid leafref path \"%s\" - set of features applicable to the leafref target is not a subset of"
7735 " features applicable to the leafref itself.", lref->path->expr);
7736 return LY_EVALID;
7737 }
7738
7739 return LY_SUCCESS;
7740}
7741
7742static LY_ERR
Michal Vasko8d544252020-03-02 10:19:52 +01007743lys_compile_ietf_netconf_wd_annotation(struct lysc_ctx *ctx, struct lys_module *mod)
7744{
7745 struct lysc_ext_instance *ext;
7746 struct lysp_ext_instance *ext_p = NULL;
7747 struct lysp_stmt *stmt;
7748 const struct lys_module *ext_mod;
7749 LY_ERR ret = LY_SUCCESS;
7750
7751 /* create the parsed extension instance manually */
7752 ext_p = calloc(1, sizeof *ext_p);
7753 LY_CHECK_ERR_GOTO(!ext_p, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci011e4aa2020-09-04 15:22:31 +02007754 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "md:annotation", 0, &ext_p->name), cleanup);
7755 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "default", 0, &ext_p->argument), cleanup);
Michal Vasko8d544252020-03-02 10:19:52 +01007756 ext_p->insubstmt = LYEXT_SUBSTMT_SELF;
7757 ext_p->insubstmt_index = 0;
7758
Radek Krejci87e25252020-09-15 13:28:31 +02007759 ext_p->child = stmt = calloc(1, sizeof *ext_p->child);
7760 LY_CHECK_ERR_GOTO(!stmt, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci011e4aa2020-09-04 15:22:31 +02007761 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "type", 0, &stmt->stmt), cleanup);
7762 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "boolean", 0, &stmt->arg), cleanup);
Michal Vasko8d544252020-03-02 10:19:52 +01007763 stmt->kw = LY_STMT_TYPE;
Michal Vasko8d544252020-03-02 10:19:52 +01007764
7765 /* allocate new extension instance */
7766 LY_ARRAY_NEW_GOTO(mod->ctx, mod->compiled->exts, ext, ret, cleanup);
7767
7768 /* manually get extension definition module */
7769 ext_mod = ly_ctx_get_module_latest(ctx->ctx, "ietf-yang-metadata");
7770
7771 /* compile the extension instance */
7772 LY_CHECK_GOTO(ret = lys_compile_ext(ctx, ext_p, ext, mod->compiled, LYEXT_PAR_MODULE, ext_mod), cleanup);
7773
7774cleanup:
7775 lysp_ext_instance_free(ctx->ctx, ext_p);
7776 free(ext_p);
7777 return ret;
7778}
7779
Michal Vasko7f45cf22020-10-01 12:49:44 +02007780/**
7781 * @brief Compile default value(s) for leaf or leaf-list expecting a complete compiled schema tree.
7782 *
7783 * @param[in] ctx Compile context.
7784 * @param[in] node Leaf or leaf-list to compile the default value(s) for.
7785 * @param[in] type Type of the default value.
7786 * @param[in] dflt Default value.
7787 * @param[in] dflt_mod Local module for @p dflt.
7788 * @param[in,out] storage Storage for the compiled default value.
7789 * @return LY_ERR value.
7790 */
Michal Vasko004d3152020-06-11 19:59:22 +02007791static LY_ERR
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007792lys_compile_unres_dflt(struct lysc_ctx *ctx, struct lysc_node *node, struct lysc_type *type, const char *dflt,
Radek Krejci0f969882020-08-21 16:56:47 +02007793 const struct lys_module *dflt_mod, struct lyd_value *storage)
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007794{
7795 LY_ERR ret;
7796 struct ly_err_item *err = NULL;
7797
7798 ret = type->plugin->store(ctx->ctx, type, dflt, strlen(dflt), LY_TYPE_OPTS_SCHEMA,
7799 LY_PREF_SCHEMA, (void *)dflt_mod, node, NULL, storage, &err);
7800 if (err) {
7801 ly_err_print(err);
7802 ctx->path[0] = '\0';
7803 lysc_path(node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
7804 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
7805 "Invalid default - value does not fit the type (%s).", err->msg);
7806 ly_err_free(err);
7807 }
7808 if (!ret) {
7809 ++storage->realtype->refcount;
7810 return LY_SUCCESS;
7811 }
7812 return ret;
7813}
7814
Michal Vasko7f45cf22020-10-01 12:49:44 +02007815/**
7816 * @brief Compile default value of a leaf expecting a complete compiled schema tree.
7817 *
7818 * @param[in] ctx Compile context.
7819 * @param[in] leaf Leaf that the default value is for.
7820 * @param[in] dflt Default value to compile.
7821 * @return LY_ERR value.
7822 */
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007823static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02007824lys_compile_unres_leaf_dlft(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, struct lysp_qname *dflt)
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007825{
7826 LY_ERR ret;
7827
7828 assert(!leaf->dflt);
7829
7830 if (leaf->flags & (LYS_MAND_TRUE | LYS_KEY)) {
7831 /* ignore default values for keys and mandatory leaves */
7832 return LY_SUCCESS;
7833 }
7834
7835 /* allocate the default value */
7836 leaf->dflt = calloc(1, sizeof *leaf->dflt);
7837 LY_CHECK_ERR_RET(!leaf->dflt, LOGMEM(ctx->ctx), LY_EMEM);
7838
7839 /* store the default value */
Michal Vasko7f45cf22020-10-01 12:49:44 +02007840 ret = lys_compile_unres_dflt(ctx, (struct lysc_node *)leaf, leaf->type, dflt->str, dflt->mod, leaf->dflt);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007841 if (ret) {
7842 free(leaf->dflt);
7843 leaf->dflt = NULL;
7844 }
7845
7846 return ret;
7847}
7848
Michal Vasko7f45cf22020-10-01 12:49:44 +02007849/**
7850 * @brief Compile default values of a leaf-list expecting a complete compiled schema tree.
7851 *
7852 * @param[in] ctx Compile context.
7853 * @param[in] llist Leaf-list that the default value(s) are for.
7854 * @param[in] dflt Default value to compile, in case of a single value.
7855 * @param[in] dflts Sized array of default values, in case of more values.
7856 * @return LY_ERR value.
7857 */
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007858static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02007859lys_compile_unres_llist_dflts(struct lysc_ctx *ctx, struct lysc_node_leaflist *llist, struct lysp_qname *dflt,
7860 struct lysp_qname *dflts)
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007861{
7862 LY_ERR ret;
7863 LY_ARRAY_COUNT_TYPE orig_count, u, v;
7864
7865 assert(dflt || dflts);
7866
7867 if (llist->dflts) {
7868 /* there were already some defaults and we are adding new by deviations */
7869 assert(dflts);
7870 orig_count = LY_ARRAY_COUNT(llist->dflts);
7871 } else {
7872 orig_count = 0;
7873 }
7874
7875 /* allocate new items */
7876 if (dflts) {
7877 LY_ARRAY_CREATE_RET(ctx->ctx, llist->dflts, orig_count + LY_ARRAY_COUNT(dflts), LY_EMEM);
7878 } else {
7879 LY_ARRAY_CREATE_RET(ctx->ctx, llist->dflts, orig_count + 1, LY_EMEM);
7880 }
7881
7882 /* fill each new default value */
7883 if (dflts) {
7884 LY_ARRAY_FOR(dflts, u) {
7885 llist->dflts[orig_count + u] = calloc(1, sizeof **llist->dflts);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007886 ret = lys_compile_unres_dflt(ctx, (struct lysc_node *)llist, llist->type, dflts[u].str, dflts[u].mod,
7887 llist->dflts[orig_count + u]);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007888 LY_CHECK_ERR_RET(ret, free(llist->dflts[orig_count + u]), ret);
7889 LY_ARRAY_INCREMENT(llist->dflts);
7890 }
7891 } else {
7892 llist->dflts[orig_count] = calloc(1, sizeof **llist->dflts);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007893 ret = lys_compile_unres_dflt(ctx, (struct lysc_node *)llist, llist->type, dflt->str, dflt->mod,
7894 llist->dflts[orig_count]);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007895 LY_CHECK_ERR_RET(ret, free(llist->dflts[orig_count]), ret);
7896 LY_ARRAY_INCREMENT(llist->dflts);
7897 }
7898
7899 /* check default value uniqueness */
7900 if (llist->flags & LYS_CONFIG_W) {
7901 /* configuration data values must be unique - so check the default values */
7902 for (u = orig_count; u < LY_ARRAY_COUNT(llist->dflts); ++u) {
7903 for (v = 0; v < u; ++v) {
7904 if (!llist->dflts[u]->realtype->plugin->compare(llist->dflts[u], llist->dflts[v])) {
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007905 lysc_update_path(ctx, llist->parent, llist->name);
7906 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko7f45cf22020-10-01 12:49:44 +02007907 "Configuration leaf-list has multiple defaults of the same value \"%s\".",
7908 llist->dflts[u]->canonical);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007909 lysc_update_path(ctx, NULL, NULL);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007910 return LY_EVALID;
7911 }
7912 }
7913 }
7914 }
7915
7916 return LY_SUCCESS;
7917}
7918
Michal Vasko7f45cf22020-10-01 12:49:44 +02007919/**
7920 * @brief Finish compilation of all the unres sets of a compile context.
7921 *
7922 * @param[in] ctx Compile context with unres sets.
7923 * @return LY_ERR value.
7924 */
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007925static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02007926lys_compile_unres(struct lysc_ctx *ctx)
7927{
7928 struct lysc_node *node;
7929 struct lysc_type *type, *typeiter;
7930 struct lysc_type_leafref *lref;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007931 struct lysc_augment *aug;
7932 struct lysc_deviation *dev;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02007933 LY_ARRAY_COUNT_TYPE v;
Michal Vasko004d3152020-06-11 19:59:22 +02007934 uint32_t i;
7935
7936 /* for leafref, we need 2 rounds - first detects circular chain by storing the first referred type (which
7937 * can be also leafref, in case it is already resolved, go through the chain and check that it does not
7938 * point to the starting leafref type). The second round stores the first non-leafref type for later data validation. */
7939 for (i = 0; i < ctx->leafrefs.count; ++i) {
7940 node = ctx->leafrefs.objs[i];
7941 assert(node->nodetype & (LYS_LEAF | LYS_LEAFLIST));
7942 type = ((struct lysc_node_leaf *)node)->type;
7943 if (type->basetype == LY_TYPE_LEAFREF) {
7944 LY_CHECK_RET(lys_compile_unres_leafref(ctx, node, (struct lysc_type_leafref *)type));
7945 } else if (type->basetype == LY_TYPE_UNION) {
7946 LY_ARRAY_FOR(((struct lysc_type_union *)type)->types, v) {
7947 if (((struct lysc_type_union *)type)->types[v]->basetype == LY_TYPE_LEAFREF) {
7948 lref = (struct lysc_type_leafref *)((struct lysc_type_union *)type)->types[v];
7949 LY_CHECK_RET(lys_compile_unres_leafref(ctx, node, lref));
7950 }
7951 }
7952 }
7953 }
7954 for (i = 0; i < ctx->leafrefs.count; ++i) {
7955 /* store pointer to the real type */
7956 type = ((struct lysc_node_leaf *)ctx->leafrefs.objs[i])->type;
7957 if (type->basetype == LY_TYPE_LEAFREF) {
Michal Vasko22df3f02020-08-24 13:29:22 +02007958 for (typeiter = ((struct lysc_type_leafref *)type)->realtype;
Michal Vasko004d3152020-06-11 19:59:22 +02007959 typeiter->basetype == LY_TYPE_LEAFREF;
Michal Vasko22df3f02020-08-24 13:29:22 +02007960 typeiter = ((struct lysc_type_leafref *)typeiter)->realtype) {}
7961 ((struct lysc_type_leafref *)type)->realtype = typeiter;
Michal Vasko004d3152020-06-11 19:59:22 +02007962 } else if (type->basetype == LY_TYPE_UNION) {
Michal Vasko22df3f02020-08-24 13:29:22 +02007963 LY_ARRAY_FOR(((struct lysc_type_union *)type)->types, v) {
7964 if (((struct lysc_type_union *)type)->types[v]->basetype == LY_TYPE_LEAFREF) {
7965 for (typeiter = ((struct lysc_type_leafref *)((struct lysc_type_union *)type)->types[v])->realtype;
Michal Vasko004d3152020-06-11 19:59:22 +02007966 typeiter->basetype == LY_TYPE_LEAFREF;
Michal Vasko22df3f02020-08-24 13:29:22 +02007967 typeiter = ((struct lysc_type_leafref *)typeiter)->realtype) {}
7968 ((struct lysc_type_leafref *)((struct lysc_type_union *)type)->types[v])->realtype = typeiter;
Michal Vasko004d3152020-06-11 19:59:22 +02007969 }
7970 }
7971 }
7972 }
7973
7974 /* check xpath */
7975 for (i = 0; i < ctx->xpath.count; ++i) {
7976 LY_CHECK_RET(lys_compile_unres_xpath(ctx, ctx->xpath.objs[i]));
7977 }
7978
7979 /* finish incomplete default values compilation */
7980 for (i = 0; i < ctx->dflts.count; ++i) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02007981 struct lysc_unres_dflt *r = ctx->dflts.objs[i];
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007982 if (r->leaf->nodetype == LYS_LEAF) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02007983 LY_CHECK_RET(lys_compile_unres_leaf_dlft(ctx, r->leaf, r->dflt));
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007984 } else {
Michal Vasko7f45cf22020-10-01 12:49:44 +02007985 LY_CHECK_RET(lys_compile_unres_llist_dflts(ctx, r->llist, r->dflt, r->dflts));
Michal Vasko004d3152020-06-11 19:59:22 +02007986 }
Michal Vasko004d3152020-06-11 19:59:22 +02007987 }
7988
Michal Vasko7f45cf22020-10-01 12:49:44 +02007989 /* check that all augments were applied */
7990 for (i = 0; i < ctx->augs.count; ++i) {
7991 aug = ctx->augs.objs[i];
7992 LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
7993 "Augment target node \"%s\" from module \"%s\" was not found.", aug->nodeid->expr,
7994 aug->nodeid_mod->name);
7995 }
7996 if (ctx->augs.count) {
7997 return LY_ENOTFOUND;
7998 }
7999
8000 /* check that all deviations were applied */
8001 for (i = 0; i < ctx->devs.count; ++i) {
8002 dev = ctx->devs.objs[i];
8003 LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
8004 "Deviation(s) target node \"%s\" from module \"%s\" was not found.", dev->nodeid->expr,
8005 dev->nodeid_mod->name);
8006 }
8007 if (ctx->devs.count) {
8008 return LY_ENOTFOUND;
8009 }
8010
8011 return LY_SUCCESS;
8012}
8013
8014/**
8015 * @brief Revert precompilation of module augments and deviations. Meaning remove its reference from
8016 * all the target modules.
8017 *
8018 * @param[in] ctx Compile context.
8019 * @param[in] mod Mod whose precompilation to revert.
8020 */
8021static void
8022lys_precompile_augments_deviations_revert(struct lysc_ctx *ctx, const struct lys_module *mod)
8023{
8024 uint32_t i;
8025 LY_ARRAY_COUNT_TYPE u, count;
8026 struct lys_module *m;
8027
8028 for (i = 0; i < ctx->ctx->list.count; ++i) {
8029 m = ctx->ctx->list.objs[i];
8030
8031 if (m->augmented_by) {
8032 count = LY_ARRAY_COUNT(m->augmented_by);
8033 for (u = 0; u < count; ++u) {
8034 if (m->augmented_by[u] == mod) {
8035 /* keep the order */
8036 if (u < count - 1) {
8037 memmove(m->augmented_by + u, m->augmented_by + u + 1, (count - u) * sizeof *m->augmented_by);
8038 }
8039 LY_ARRAY_DECREMENT(m->augmented_by);
8040 break;
8041 }
8042 }
8043 if (!LY_ARRAY_COUNT(m->augmented_by)) {
8044 LY_ARRAY_FREE(m->augmented_by);
8045 m->augmented_by = NULL;
8046 }
8047 }
8048
8049 if (m->deviated_by) {
8050 count = LY_ARRAY_COUNT(m->deviated_by);
8051 for (u = 0; u < count; ++u) {
8052 if (m->deviated_by[u] == mod) {
8053 /* keep the order */
8054 if (u < count - 1) {
8055 memmove(m->deviated_by + u, m->deviated_by + u + 1, (count - u) * sizeof *m->deviated_by);
8056 }
8057 LY_ARRAY_DECREMENT(m->deviated_by);
8058 break;
8059 }
8060 }
8061 if (!LY_ARRAY_COUNT(m->deviated_by)) {
8062 LY_ARRAY_FREE(m->deviated_by);
8063 m->deviated_by = NULL;
8064 }
8065 }
8066 }
8067}
8068
8069/**
8070 * @brief Compile features in the current module and all its submodules.
8071 *
8072 * @param[in] ctx Compile context.
8073 * @return LY_ERR value.
8074 */
8075static LY_ERR
8076lys_compile_features(struct lysc_ctx *ctx)
8077{
8078 struct lysp_submodule *submod;
8079 LY_ARRAY_COUNT_TYPE u, v;
8080
8081 if (!ctx->mod->features) {
8082 /* features are compiled directly into the module structure,
8083 * but it must be done in two steps to allow forward references (via if-feature) between the features themselves */
8084 LY_CHECK_RET(lys_feature_precompile(ctx, NULL, NULL, ctx->mod->parsed->features, &ctx->mod->features));
8085 LY_ARRAY_FOR(ctx->mod->parsed->includes, v) {
8086 submod = ctx->mod->parsed->includes[v].submodule;
8087 LY_CHECK_RET(lys_feature_precompile(ctx, NULL, NULL, submod->features, &ctx->mod->features));
8088 }
8089 }
8090
8091 /* finish feature compilation, not only for the main module, but also for the submodules.
8092 * Due to possible forward references, it must be done when all the features (including submodules)
8093 * are present. */
8094 LY_ARRAY_FOR(ctx->mod->parsed->features, u) {
8095 LY_CHECK_RET(lys_feature_precompile_finish(ctx, &ctx->mod->parsed->features[u], ctx->mod->features));
8096 }
8097
8098 lysc_update_path(ctx, NULL, "{submodule}");
8099 LY_ARRAY_FOR(ctx->mod->parsed->includes, v) {
8100 submod = ctx->mod->parsed->includes[v].submodule;
8101
8102 lysc_update_path(ctx, NULL, submod->name);
8103 LY_ARRAY_FOR(submod->features, u) {
8104 LY_CHECK_RET(lys_feature_precompile_finish(ctx, &submod->features[u], ctx->mod->features));
8105 }
8106 lysc_update_path(ctx, NULL, NULL);
8107 }
8108 lysc_update_path(ctx, NULL, NULL);
8109
8110 return LY_SUCCESS;
8111}
8112
8113/**
8114 * @brief Compile identites in the current module and all its submodules.
8115 *
8116 * @param[in] ctx Compile context.
8117 * @return LY_ERR value.
8118 */
8119static LY_ERR
8120lys_compile_identities(struct lysc_ctx *ctx)
8121{
8122 struct lysp_submodule *submod;
8123 LY_ARRAY_COUNT_TYPE u;
8124
8125 if (!ctx->mod->identities) {
8126 LY_CHECK_RET(lys_identity_precompile(ctx, NULL, NULL, ctx->mod->parsed->identities, &ctx->mod->identities));
8127 LY_ARRAY_FOR(ctx->mod->parsed->includes, u) {
8128 submod = ctx->mod->parsed->includes[u].submodule;
8129 LY_CHECK_RET(lys_identity_precompile(ctx, NULL, NULL, submod->identities, &ctx->mod->identities));
8130 }
8131 }
8132
8133 if (ctx->mod->parsed->identities) {
8134 LY_CHECK_RET(lys_compile_identities_derived(ctx, ctx->mod->parsed->identities, ctx->mod->identities));
8135 }
8136 lysc_update_path(ctx, NULL, "{submodule}");
8137 LY_ARRAY_FOR(ctx->mod->parsed->includes, u) {
8138
8139 submod = ctx->mod->parsed->includes[u].submodule;
8140 if (submod->identities) {
8141 lysc_update_path(ctx, NULL, submod->name);
8142 LY_CHECK_RET(lys_compile_identities_derived(ctx, submod->identities, ctx->mod->identities));
8143 lysc_update_path(ctx, NULL, NULL);
8144 }
8145 }
8146 lysc_update_path(ctx, NULL, NULL);
8147
Michal Vasko004d3152020-06-11 19:59:22 +02008148 return LY_SUCCESS;
8149}
8150
Radek Krejci19a96102018-11-15 13:38:09 +01008151LY_ERR
Michal Vasko7a0b0762020-09-02 16:37:01 +02008152lys_compile(struct lys_module *mod, uint32_t options)
Radek Krejci19a96102018-11-15 13:38:09 +01008153{
8154 struct lysc_ctx ctx = {0};
8155 struct lysc_module *mod_c;
8156 struct lysp_module *sp;
Michal Vasko7f45cf22020-10-01 12:49:44 +02008157 struct lysp_submodule *submod;
8158 struct lysp_node *pnode;
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008159 struct lysp_grp *grps;
Radek Krejci95710c92019-02-11 15:49:55 +01008160 struct lys_module *m;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02008161 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02008162 uint32_t i;
Radek Krejcid05cbd92018-12-05 14:26:40 +01008163 LY_ERR ret = LY_SUCCESS;
Radek Krejci19a96102018-11-15 13:38:09 +01008164
Michal Vasko7a0b0762020-09-02 16:37:01 +02008165 LY_CHECK_ARG_RET(NULL, mod, mod->parsed, !mod->compiled, mod->ctx, LY_EINVAL);
Radek Krejci096235c2019-01-11 11:12:19 +01008166
Michal Vasko7a0b0762020-09-02 16:37:01 +02008167 if (!mod->implemented) {
Radek Krejci096235c2019-01-11 11:12:19 +01008168 /* just imported modules are not compiled */
8169 return LY_SUCCESS;
8170 }
8171
Michal Vasko7f45cf22020-10-01 12:49:44 +02008172 /* context will be changed */
8173 ++mod->ctx->module_set_id;
8174
Michal Vasko7a0b0762020-09-02 16:37:01 +02008175 sp = mod->parsed;
Radek Krejci19a96102018-11-15 13:38:09 +01008176
Michal Vasko7a0b0762020-09-02 16:37:01 +02008177 ctx.ctx = mod->ctx;
8178 ctx.mod = mod;
8179 ctx.mod_def = mod;
Radek Krejciec4da802019-05-02 13:02:41 +02008180 ctx.options = options;
Radek Krejci327de162019-06-14 12:52:07 +02008181 ctx.path_len = 1;
8182 ctx.path[0] = '/';
Radek Krejci19a96102018-11-15 13:38:09 +01008183
Michal Vasko7a0b0762020-09-02 16:37:01 +02008184 mod->compiled = mod_c = calloc(1, sizeof *mod_c);
8185 LY_CHECK_ERR_RET(!mod_c, LOGMEM(mod->ctx), LY_EMEM);
8186 mod_c->mod = mod;
Radek Krejci19a96102018-11-15 13:38:09 +01008187
Michal Vasko7f45cf22020-10-01 12:49:44 +02008188 /* process imports */
Michal Vasko7c8439f2020-08-05 13:25:19 +02008189 LY_ARRAY_FOR(sp->imports, u) {
8190 LY_CHECK_GOTO(ret = lys_compile_import(&ctx, &sp->imports[u]), error);
8191 }
Radek Krejci0935f412019-08-20 16:15:18 +02008192
Michal Vasko7f45cf22020-10-01 12:49:44 +02008193 /* features */
8194 LY_CHECK_GOTO(ret = lys_compile_features(&ctx), error);
Radek Krejci14915cc2020-09-14 17:28:13 +02008195
8196 /* identities, work similarly to features with the precompilation */
Michal Vasko7f45cf22020-10-01 12:49:44 +02008197 LY_CHECK_GOTO(ret = lys_compile_identities(&ctx), error);
8198
8199 /* augments and deviations */
8200 LY_CHECK_GOTO(ret = lys_precompile_augments_deviations(&ctx), error);
8201
8202 /* compile augments and deviations of our module from other modules so they can be applied during compilation */
8203 LY_CHECK_GOTO(ret = lys_precompile_own_augments(&ctx), error);
8204 LY_CHECK_GOTO(ret = lys_precompile_own_deviations(&ctx), error);
Radek Krejci19a96102018-11-15 13:38:09 +01008205
Radek Krejci95710c92019-02-11 15:49:55 +01008206 /* data nodes */
Michal Vasko7f45cf22020-10-01 12:49:44 +02008207 LY_LIST_FOR(sp->data, pnode) {
8208 LY_CHECK_GOTO(ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL), error);
Radek Krejci19a96102018-11-15 13:38:09 +01008209 }
Radek Krejci95710c92019-02-11 15:49:55 +01008210
Michal Vasko7f45cf22020-10-01 12:49:44 +02008211 /* top-level RPCs and notifications */
8212 COMPILE_OP_ARRAY_GOTO(&ctx, sp->rpcs, mod_c->rpcs, NULL, u, lys_compile_action, 0, ret, error);
8213 COMPILE_OP_ARRAY_GOTO(&ctx, sp->notifs, mod_c->notifs, NULL, u, lys_compile_notif, 0, ret, error);
Radek Krejciccd20f12019-02-15 14:12:27 +01008214
Michal Vasko7f45cf22020-10-01 12:49:44 +02008215 /* extension instances */
Radek Krejci0935f412019-08-20 16:15:18 +02008216 COMPILE_EXTS_GOTO(&ctx, sp->exts, mod_c->exts, mod_c, LYEXT_PAR_MODULE, ret, error);
Radek Krejci19a96102018-11-15 13:38:09 +01008217
Michal Vasko7f45cf22020-10-01 12:49:44 +02008218 /* the same for submodules */
8219 LY_ARRAY_FOR(sp->includes, u) {
8220 submod = sp->includes[u].submodule;
8221 LY_LIST_FOR(submod->data, pnode) {
8222 ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL);
8223 LY_CHECK_GOTO(ret, error);
8224 }
8225
8226 COMPILE_OP_ARRAY_GOTO(&ctx, submod->rpcs, mod_c->rpcs, NULL, v, lys_compile_action, 0, ret, error);
8227 COMPILE_OP_ARRAY_GOTO(&ctx, submod->notifs, mod_c->notifs, NULL, v, lys_compile_notif, 0, ret, error);
8228
8229 COMPILE_EXTS_GOTO(&ctx, submod->exts, mod_c->exts, mod_c, LYEXT_PAR_MODULE, ret, error);
8230 }
8231
Michal Vasko004d3152020-06-11 19:59:22 +02008232 /* finish compilation for all unresolved items in the context */
8233 LY_CHECK_GOTO(ret = lys_compile_unres(&ctx), error);
Radek Krejci474f9b82019-07-24 11:36:37 +02008234
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008235 /* validate non-instantiated groupings from the parsed schema,
8236 * without it we would accept even the schemas with invalid grouping specification */
8237 ctx.options |= LYSC_OPT_GROUPING;
8238 LY_ARRAY_FOR(sp->groupings, u) {
8239 if (!(sp->groupings[u].flags & LYS_USED_GRP)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008240 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &sp->groupings[u]), error);
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008241 }
8242 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02008243 LY_LIST_FOR(sp->data, pnode) {
8244 grps = (struct lysp_grp *)lysp_node_groupings(pnode);
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008245 LY_ARRAY_FOR(grps, u) {
8246 if (!(grps[u].flags & LYS_USED_GRP)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008247 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &grps[u]), error);
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008248 }
8249 }
8250 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02008251 LY_ARRAY_FOR(sp->includes, u) {
8252 submod = sp->includes[u].submodule;
8253 LY_ARRAY_FOR(submod->groupings, u) {
8254 if (!(submod->groupings[u].flags & LYS_USED_GRP)) {
8255 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &submod->groupings[u]), error);
8256 }
8257 }
8258 LY_LIST_FOR(submod->data, pnode) {
8259 grps = (struct lysp_grp *)lysp_node_groupings(pnode);
8260 LY_ARRAY_FOR(grps, u) {
8261 if (!(grps[u].flags & LYS_USED_GRP)) {
8262 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &grps[u]), error);
8263 }
8264 }
8265 }
Radek Krejci474f9b82019-07-24 11:36:37 +02008266 }
8267
Michal Vasko8d544252020-03-02 10:19:52 +01008268#if 0
8269 /* hack for NETCONF's edit-config's operation attribute. It is not defined in the schema, but since libyang
8270 * implements YANG metadata (annotations), we need its definition. Because the ietf-netconf schema is not the
8271 * internal part of libyang, we cannot add the annotation into the schema source, but we do it here to have
8272 * the anotation definitions available in the internal schema structure. */
8273 if (ly_strequal(mod->name, "ietf-netconf", 0)) {
8274 if (lyp_add_ietf_netconf_annotations(mod)) {
8275 lys_free(mod, NULL, 1, 1);
8276 return NULL;
8277 }
8278 }
8279#endif
8280
8281 /* add ietf-netconf-with-defaults "default" metadata to the compiled module */
Michal Vasko7a0b0762020-09-02 16:37:01 +02008282 if (!strcmp(mod->name, "ietf-netconf-with-defaults")) {
8283 LY_CHECK_GOTO(ret = lys_compile_ietf_netconf_wd_annotation(&ctx, mod), error);
Michal Vasko8d544252020-03-02 10:19:52 +01008284 }
8285
Michal Vasko7f45cf22020-10-01 12:49:44 +02008286 /* there can be no leftover deviations */
8287 LY_CHECK_ERR_GOTO(ctx.devs.count, LOGINT(ctx.ctx); ret = LY_EINT, error);
8288
8289 for (i = 0; i < ctx.dflts.count; ++i) {
8290 lysc_unres_dflt_free(ctx.ctx, ctx.dflts.objs[i]);
8291 }
8292 ly_set_erase(&ctx.dflts, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +02008293 ly_set_erase(&ctx.xpath, NULL);
8294 ly_set_erase(&ctx.leafrefs, NULL);
Radek Krejcie86bf772018-12-14 11:39:53 +01008295 ly_set_erase(&ctx.groupings, NULL);
Radek Krejci99b5b2a2019-04-30 16:57:04 +02008296 ly_set_erase(&ctx.tpdf_chain, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02008297 ly_set_erase(&ctx.augs, NULL);
8298 ly_set_erase(&ctx.devs, NULL);
8299 ly_set_erase(&ctx.uses_augs, NULL);
8300 ly_set_erase(&ctx.uses_rfns, NULL);
Radek Krejcia3045382018-11-22 14:30:31 +01008301
Radek Krejciec4da802019-05-02 13:02:41 +02008302 if (ctx.options & LYSC_OPT_FREE_SP) {
Michal Vasko7a0b0762020-09-02 16:37:01 +02008303 lysp_module_free(mod->parsed);
8304 mod->parsed = NULL;
Radek Krejci19a96102018-11-15 13:38:09 +01008305 }
8306
Radek Krejciec4da802019-05-02 13:02:41 +02008307 if (!(ctx.options & LYSC_OPT_INTERNAL)) {
Radek Krejci95710c92019-02-11 15:49:55 +01008308 /* remove flag of the modules implemented by dependency */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02008309 for (i = 0; i < ctx.ctx->list.count; ++i) {
8310 m = ctx.ctx->list.objs[i];
Radek Krejcia46012b2020-08-12 15:41:04 +02008311 if (m->implemented > 1) {
Radek Krejci95710c92019-02-11 15:49:55 +01008312 m->implemented = 1;
8313 }
8314 }
8315 }
8316
Radek Krejci19a96102018-11-15 13:38:09 +01008317 return LY_SUCCESS;
8318
8319error:
Michal Vasko7f45cf22020-10-01 12:49:44 +02008320 lys_precompile_augments_deviations_revert(&ctx, mod);
Michal Vasko7a0b0762020-09-02 16:37:01 +02008321 lys_feature_precompile_revert(&ctx, mod);
Michal Vasko7f45cf22020-10-01 12:49:44 +02008322 for (i = 0; i < ctx.dflts.count; ++i) {
8323 lysc_unres_dflt_free(ctx.ctx, ctx.dflts.objs[i]);
8324 }
8325 ly_set_erase(&ctx.dflts, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +02008326 ly_set_erase(&ctx.xpath, NULL);
8327 ly_set_erase(&ctx.leafrefs, NULL);
Radek Krejcie86bf772018-12-14 11:39:53 +01008328 ly_set_erase(&ctx.groupings, NULL);
Radek Krejci99b5b2a2019-04-30 16:57:04 +02008329 ly_set_erase(&ctx.tpdf_chain, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02008330 for (i = 0; i < ctx.augs.count; ++i) {
8331 lysc_augment_free(ctx.ctx, ctx.augs.objs[i]);
8332 }
8333 ly_set_erase(&ctx.augs, NULL);
8334 for (i = 0; i < ctx.devs.count; ++i) {
8335 lysc_deviation_free(ctx.ctx, ctx.devs.objs[i]);
8336 }
8337 ly_set_erase(&ctx.devs, NULL);
8338 for (i = 0; i < ctx.uses_augs.count; ++i) {
8339 lysc_augment_free(ctx.ctx, ctx.uses_augs.objs[i]);
8340 }
8341 ly_set_erase(&ctx.uses_augs, NULL);
8342 for (i = 0; i < ctx.uses_rfns.count; ++i) {
8343 lysc_refine_free(ctx.ctx, ctx.uses_rfns.objs[i]);
8344 }
8345 ly_set_erase(&ctx.uses_rfns, NULL);
Radek Krejci19a96102018-11-15 13:38:09 +01008346 lysc_module_free(mod_c, NULL);
Michal Vasko7a0b0762020-09-02 16:37:01 +02008347 mod->compiled = NULL;
Radek Krejci95710c92019-02-11 15:49:55 +01008348
Michal Vasko7f45cf22020-10-01 12:49:44 +02008349 /* revert compilation of modules implemented by dependency */
8350 if (!(ctx.options & LYSC_OPT_INTERNAL)) {
8351 for (i = 0; i < ctx.ctx->list.count; ++i) {
8352 m = ctx.ctx->list.objs[i];
8353 if (m->implemented > 1) {
8354 /* make the module non-implemented */
8355 m->implemented = 0;
8356 }
8357
8358 /* free the compiled version of the module, if any */
Radek Krejci95710c92019-02-11 15:49:55 +01008359 lysc_module_free(m->compiled, NULL);
8360 m->compiled = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02008361
8362 if (m->implemented) {
8363 /* recompile, must succeed because it was already compiled; hide messages because any
8364 * warnings were already printed, are not really relevant, and would hide the real error */
8365 uint32_t prev_lo = ly_log_options(0);
8366 LY_ERR r = lys_compile(m, LYSC_OPT_INTERNAL);
8367 ly_log_options(prev_lo);
8368 if (r) {
8369 LOGERR(ctx.ctx, r, "Recompilation of module \"%s\" failed.", m->name);
8370 }
8371 }
Radek Krejci95710c92019-02-11 15:49:55 +01008372 }
8373 }
8374
Radek Krejci19a96102018-11-15 13:38:09 +01008375 return ret;
8376}