blob: bd5c754b6886904fb716e02ce5d3241a9e423366 [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"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020030#include "parser.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020031#include "parser_schema.h"
Michal Vasko69730152020-10-09 16:30:07 +020032#include "path.h"
Radek Krejci0935f412019-08-20 16:15:18 +020033#include "plugins_exts.h"
Radek Krejci0935f412019-08-20 16:15:18 +020034#include "plugins_exts_internal.h"
Michal Vasko69730152020-10-09 16:30:07 +020035#include "plugins_types.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/**
Radek Krejci90d4e922020-10-12 15:55:33 +020050 * @defgroup scflags Schema compile flags
51 *
52 * Flags are currently used only internally - the compilation process does not have a public interface and it is
53 * integrated in the schema parsers. The current options set does not make sense for public used, but it can be a way
54 * to modify behavior of the compilation process in future.
55 *
56 * @{
57 */
58#define LYS_COMPILE_RPC_INPUT LYS_CONFIG_W /**< Internal option when compiling schema tree of RPC/action input */
59#define LYS_COMPILE_RPC_OUTPUT LYS_CONFIG_R /**< Internal option when compiling schema tree of RPC/action output */
60#define LYS_COMPILE_RPC_MASK LYS_CONFIG_MASK /**< mask for the internal RPC options */
61#define LYS_COMPILE_NOTIFICATION 0x08 /**< Internal option when compiling schema tree of Notification */
62
63#define LYS_COMPILE_GROUPING 0x10 /** Compiling (validation) of a non-instantiated grouping.
64 In this case not all the restrictions are checked since they can be valid only
65 in the real placement of the grouping. TODO - what specifically is not done */
66/** @} scflags */
67
68/**
Radek Krejci19a96102018-11-15 13:38:09 +010069 * @brief Duplicate string into dictionary
70 * @param[in] CTX libyang context of the dictionary.
71 * @param[in] ORIG String to duplicate.
72 * @param[out] DUP Where to store the result.
73 */
Radek Krejci011e4aa2020-09-04 15:22:31 +020074#define DUP_STRING(CTX, ORIG, DUP, RET) if (ORIG) {RET = lydict_insert(CTX, ORIG, 0, &DUP);}
75
76#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 +010077
Michal Vasko7f45cf22020-10-01 12:49:44 +020078#define DUP_ARRAY(CTX, ORIG_ARRAY, NEW_ARRAY, DUP_FUNC) \
79 if (ORIG_ARRAY) { \
80 LY_ARRAY_COUNT_TYPE u; \
81 LY_ARRAY_CREATE_RET(CTX, NEW_ARRAY, LY_ARRAY_COUNT(ORIG_ARRAY), LY_EMEM); \
82 LY_ARRAY_FOR(ORIG_ARRAY, u) { \
83 LY_ARRAY_INCREMENT(NEW_ARRAY); \
84 LY_CHECK_RET(DUP_FUNC(CTX, &(NEW_ARRAY)[u], &(ORIG_ARRAY)[u])); \
85 } \
86 }
87
Radek Krejciec4da802019-05-02 13:02:41 +020088#define COMPILE_ARRAY_GOTO(CTX, ARRAY_P, ARRAY_C, ITER, FUNC, RET, GOTO) \
Radek Krejci19a96102018-11-15 13:38:09 +010089 if (ARRAY_P) { \
Michal Vaskofd69e1d2020-07-03 11:57:17 +020090 LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, LY_ARRAY_COUNT(ARRAY_P), RET, GOTO); \
91 LY_ARRAY_COUNT_TYPE __array_offset = LY_ARRAY_COUNT(ARRAY_C); \
92 for (ITER = 0; ITER < LY_ARRAY_COUNT(ARRAY_P); ++ITER) { \
Radek Krejci19a96102018-11-15 13:38:09 +010093 LY_ARRAY_INCREMENT(ARRAY_C); \
Radek Krejciec4da802019-05-02 13:02:41 +020094 RET = FUNC(CTX, &(ARRAY_P)[ITER], &(ARRAY_C)[ITER + __array_offset]); \
Radek Krejcid05cbd92018-12-05 14:26:40 +010095 LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
96 } \
97 }
98
Michal Vasko7f45cf22020-10-01 12:49:44 +020099#define COMPILE_OP_ARRAY_GOTO(CTX, ARRAY_P, ARRAY_C, PARENT, ITER, FUNC, USES_STATUS, RET, GOTO) \
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100100 if (ARRAY_P) { \
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200101 LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, LY_ARRAY_COUNT(ARRAY_P), RET, GOTO); \
102 LY_ARRAY_COUNT_TYPE __array_offset = LY_ARRAY_COUNT(ARRAY_C); \
103 for (ITER = 0; ITER < LY_ARRAY_COUNT(ARRAY_P); ++ITER) { \
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100104 LY_ARRAY_INCREMENT(ARRAY_C); \
Radek Krejciec4da802019-05-02 13:02:41 +0200105 RET = FUNC(CTX, &(ARRAY_P)[ITER], PARENT, &(ARRAY_C)[ITER + __array_offset], USES_STATUS); \
Michal Vasko7f45cf22020-10-01 12:49:44 +0200106 if (RET == LY_EDENIED) { \
107 LY_ARRAY_DECREMENT(ARRAY_C); \
108 } else if (RET != LY_SUCCESS) { \
109 goto GOTO; \
110 } \
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100111 } \
112 }
113
Radek Krejci0935f412019-08-20 16:15:18 +0200114#define COMPILE_EXTS_GOTO(CTX, EXTS_P, EXT_C, PARENT, PARENT_TYPE, RET, GOTO) \
115 if (EXTS_P) { \
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200116 LY_ARRAY_CREATE_GOTO((CTX)->ctx, EXT_C, LY_ARRAY_COUNT(EXTS_P), RET, GOTO); \
117 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 +0200118 LY_ARRAY_INCREMENT(EXT_C); \
Michal Vasko8d544252020-03-02 10:19:52 +0100119 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 +0200120 LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
121 } \
122 }
123
Radek Krejciec4da802019-05-02 13:02:41 +0200124#define COMPILE_ARRAY_UNIQUE_GOTO(CTX, ARRAY_P, ARRAY_C, ITER, FUNC, RET, GOTO) \
Radek Krejcid05cbd92018-12-05 14:26:40 +0100125 if (ARRAY_P) { \
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200126 LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, LY_ARRAY_COUNT(ARRAY_P), RET, GOTO); \
127 LY_ARRAY_COUNT_TYPE __array_offset = LY_ARRAY_COUNT(ARRAY_C); \
128 for (ITER = 0; ITER < LY_ARRAY_COUNT(ARRAY_P); ++ITER) { \
Radek Krejcid05cbd92018-12-05 14:26:40 +0100129 LY_ARRAY_INCREMENT(ARRAY_C); \
Radek Krejciec4da802019-05-02 13:02:41 +0200130 RET = FUNC(CTX, &(ARRAY_P)[ITER], ARRAY_C, &(ARRAY_C)[ITER + __array_offset]); \
Radek Krejci19a96102018-11-15 13:38:09 +0100131 LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
132 } \
133 }
134
Radek Krejciec4da802019-05-02 13:02:41 +0200135#define COMPILE_MEMBER_GOTO(CTX, MEMBER_P, MEMBER_C, FUNC, RET, GOTO) \
Radek Krejci19a96102018-11-15 13:38:09 +0100136 if (MEMBER_P) { \
137 MEMBER_C = calloc(1, sizeof *(MEMBER_C)); \
138 LY_CHECK_ERR_GOTO(!(MEMBER_C), LOGMEM((CTX)->ctx); RET = LY_EMEM, GOTO); \
Radek Krejciec4da802019-05-02 13:02:41 +0200139 RET = FUNC(CTX, MEMBER_P, MEMBER_C); \
Radek Krejci19a96102018-11-15 13:38:09 +0100140 LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
141 }
142
Radek Krejciec4da802019-05-02 13:02:41 +0200143#define COMPILE_MEMBER_ARRAY_GOTO(CTX, MEMBER_P, ARRAY_C, FUNC, RET, GOTO) \
Radek Krejci00b874b2019-02-12 10:54:50 +0100144 if (MEMBER_P) { \
145 LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, 1, RET, GOTO); \
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200146 LY_ARRAY_COUNT_TYPE __array_offset = LY_ARRAY_COUNT(ARRAY_C); \
Radek Krejci00b874b2019-02-12 10:54:50 +0100147 LY_ARRAY_INCREMENT(ARRAY_C); \
Radek Krejciec4da802019-05-02 13:02:41 +0200148 RET = FUNC(CTX, MEMBER_P, &(ARRAY_C)[__array_offset]); \
Radek Krejci00b874b2019-02-12 10:54:50 +0100149 LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
150 }
151
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100152#define COMPILE_CHECK_UNIQUENESS_ARRAY(CTX, ARRAY, MEMBER, EXCL, STMT, IDENT) \
Radek Krejcid05cbd92018-12-05 14:26:40 +0100153 if (ARRAY) { \
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200154 for (LY_ARRAY_COUNT_TYPE u__ = 0; u__ < LY_ARRAY_COUNT(ARRAY); ++u__) { \
Radek Krejci0af46292019-01-11 16:02:31 +0100155 if (&(ARRAY)[u__] != EXCL && (void*)((ARRAY)[u__].MEMBER) == (void*)(IDENT)) { \
Radek Krejcid05cbd92018-12-05 14:26:40 +0100156 LOGVAL((CTX)->ctx, LY_VLOG_STR, (CTX)->path, LY_VCODE_DUPIDENT, IDENT, STMT); \
157 return LY_EVALID; \
158 } \
159 } \
160 }
161
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100162#define COMPILE_CHECK_UNIQUENESS_PARRAY(CTX, ARRAY, MEMBER, EXCL, STMT, IDENT) \
163 if (ARRAY) { \
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200164 for (LY_ARRAY_COUNT_TYPE u__ = 0; u__ < LY_ARRAY_COUNT(ARRAY); ++u__) { \
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100165 if (&(ARRAY)[u__] != EXCL && (void*)((ARRAY)[u__]->MEMBER) == (void*)(IDENT)) { \
166 LOGVAL((CTX)->ctx, LY_VLOG_STR, (CTX)->path, LY_VCODE_DUPIDENT, IDENT, STMT); \
167 return LY_EVALID; \
168 } \
169 } \
170 }
171
172struct lysc_ext *
173lysc_ext_dup(struct lysc_ext *orig)
174{
175 ++orig->refcount;
176 return orig;
177}
178
Radek Krejci19a96102018-11-15 13:38:09 +0100179static struct lysc_ext_instance *
180lysc_ext_instance_dup(struct ly_ctx *ctx, struct lysc_ext_instance *orig)
181{
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100182 /* TODO - extensions, increase refcount */
Radek Krejci19a96102018-11-15 13:38:09 +0100183 (void) ctx;
184 (void) orig;
185 return NULL;
186}
187
Michal Vasko7f45cf22020-10-01 12:49:44 +0200188/**
189 * @brief Add/replace a leaf default value in unres.
190 * Can also be used for a single leaf-list default value.
191 *
192 * @param[in] ctx Compile context.
193 * @param[in] leaf Leaf with the default value.
194 * @param[in] dflt Default value to use.
195 * @return LY_ERR value.
196 */
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200197static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +0200198lysc_unres_leaf_dflt_add(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, struct lysp_qname *dflt)
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200199{
Michal Vasko7f45cf22020-10-01 12:49:44 +0200200 struct lysc_unres_dflt *r = NULL;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200201 uint32_t i;
202
203 for (i = 0; i < ctx->dflts.count; ++i) {
Michal Vasko7f45cf22020-10-01 12:49:44 +0200204 if (((struct lysc_unres_dflt *)ctx->dflts.objs[i])->leaf == leaf) {
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200205 /* just replace the default */
Michal Vasko7f45cf22020-10-01 12:49:44 +0200206 r = ctx->dflts.objs[i];
207 lysp_qname_free(ctx->ctx, r->dflt);
208 free(r->dflt);
209 break;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200210 }
211 }
Michal Vasko7f45cf22020-10-01 12:49:44 +0200212 if (!r) {
213 /* add new unres item */
214 r = calloc(1, sizeof *r);
215 LY_CHECK_ERR_RET(!r, LOGMEM(ctx->ctx), LY_EMEM);
216 r->leaf = leaf;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200217
Radek Krejci3d92e442020-10-12 12:48:13 +0200218 LY_CHECK_RET(ly_set_add(&ctx->dflts, r, 1, NULL));
Michal Vasko7f45cf22020-10-01 12:49:44 +0200219 }
220
221 r->dflt = malloc(sizeof *r->dflt);
Michal Vaskoaf702452020-10-02 09:02:55 +0200222 LY_CHECK_GOTO(!r->dflt, error);
223 LY_CHECK_GOTO(lysp_qname_dup(ctx->ctx, r->dflt, dflt), error);
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200224
225 return LY_SUCCESS;
Michal Vaskoaf702452020-10-02 09:02:55 +0200226
227error:
228 free(r->dflt);
229 LOGMEM(ctx->ctx);
230 return LY_EMEM;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200231}
232
Radek Krejcib56c7502019-02-13 14:19:54 +0100233/**
Michal Vasko7f45cf22020-10-01 12:49:44 +0200234 * @brief Add/replace a leaf-list default value(s) in unres.
235 *
236 * @param[in] ctx Compile context.
237 * @param[in] llist Leaf-list with the default value.
238 * @param[in] dflts Sized array of the default values.
239 * @return LY_ERR value.
Radek Krejci474f9b82019-07-24 11:36:37 +0200240 */
241static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +0200242lysc_unres_llist_dflts_add(struct lysc_ctx *ctx, struct lysc_node_leaflist *llist, struct lysp_qname *dflts)
Radek Krejci474f9b82019-07-24 11:36:37 +0200243{
Michal Vasko7f45cf22020-10-01 12:49:44 +0200244 struct lysc_unres_dflt *r = NULL;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200245 uint32_t i;
246
247 for (i = 0; i < ctx->dflts.count; ++i) {
Michal Vasko7f45cf22020-10-01 12:49:44 +0200248 if (((struct lysc_unres_dflt *)ctx->dflts.objs[i])->llist == llist) {
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200249 /* just replace the defaults */
Michal Vasko7f45cf22020-10-01 12:49:44 +0200250 r = ctx->dflts.objs[i];
251 lysp_qname_free(ctx->ctx, r->dflt);
252 free(r->dflt);
253 r->dflt = NULL;
254 FREE_ARRAY(ctx->ctx, r->dflts, lysp_qname_free);
255 r->dflts = NULL;
256 break;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200257 }
258 }
Michal Vasko7f45cf22020-10-01 12:49:44 +0200259 if (!r) {
260 r = calloc(1, sizeof *r);
261 LY_CHECK_ERR_RET(!r, LOGMEM(ctx->ctx), LY_EMEM);
262 r->llist = llist;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200263
Radek Krejci3d92e442020-10-12 12:48:13 +0200264 LY_CHECK_RET(ly_set_add(&ctx->dflts, r, 1, NULL));
Michal Vasko7f45cf22020-10-01 12:49:44 +0200265 }
266
267 DUP_ARRAY(ctx->ctx, dflts, r->dflts, lysp_qname_dup);
Radek Krejci474f9b82019-07-24 11:36:37 +0200268
269 return LY_SUCCESS;
270}
271
Radek Krejci474f9b82019-07-24 11:36:37 +0200272static void
Michal Vasko7f45cf22020-10-01 12:49:44 +0200273lysc_unres_dflt_free(const struct ly_ctx *ctx, struct lysc_unres_dflt *r)
Radek Krejci474f9b82019-07-24 11:36:37 +0200274{
Michal Vasko7f45cf22020-10-01 12:49:44 +0200275 assert(!r->dflt || !r->dflts);
276 if (r->dflt) {
277 lysp_qname_free((struct ly_ctx *)ctx, r->dflt);
278 free(r->dflt);
279 } else {
280 FREE_ARRAY((struct ly_ctx *)ctx, r->dflts, lysp_qname_free);
Radek Krejci474f9b82019-07-24 11:36:37 +0200281 }
Michal Vasko7f45cf22020-10-01 12:49:44 +0200282 free(r);
Radek Krejci474f9b82019-07-24 11:36:37 +0200283}
284
Radek Krejci0e59c312019-08-15 15:34:15 +0200285void
Radek Krejci327de162019-06-14 12:52:07 +0200286lysc_update_path(struct lysc_ctx *ctx, struct lysc_node *parent, const char *name)
287{
288 int len;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200289 uint8_t nextlevel = 0; /* 0 - no starttag, 1 - '/' starttag, 2 - '=' starttag + '}' endtag */
Radek Krejci327de162019-06-14 12:52:07 +0200290
291 if (!name) {
292 /* removing last path segment */
293 if (ctx->path[ctx->path_len - 1] == '}') {
Michal Vaskod989ba02020-08-24 10:59:24 +0200294 for ( ; ctx->path[ctx->path_len] != '=' && ctx->path[ctx->path_len] != '{'; --ctx->path_len) {}
Radek Krejci327de162019-06-14 12:52:07 +0200295 if (ctx->path[ctx->path_len] == '=') {
296 ctx->path[ctx->path_len++] = '}';
297 } else {
298 /* not a top-level special tag, remove also preceiding '/' */
299 goto remove_nodelevel;
300 }
301 } else {
302remove_nodelevel:
Michal Vaskod989ba02020-08-24 10:59:24 +0200303 for ( ; ctx->path[ctx->path_len] != '/'; --ctx->path_len) {}
Radek Krejci327de162019-06-14 12:52:07 +0200304 if (ctx->path_len == 0) {
305 /* top-level (last segment) */
Radek Krejciacc79042019-07-25 14:14:57 +0200306 ctx->path_len = 1;
Radek Krejci327de162019-06-14 12:52:07 +0200307 }
308 }
309 /* set new terminating NULL-byte */
310 ctx->path[ctx->path_len] = '\0';
311 } else {
312 if (ctx->path_len > 1) {
Michal Vasko69730152020-10-09 16:30:07 +0200313 if (!parent && (ctx->path[ctx->path_len - 1] == '}') && (ctx->path[ctx->path_len - 2] != '\'')) {
Radek Krejci327de162019-06-14 12:52:07 +0200314 /* extension of the special tag */
315 nextlevel = 2;
316 --ctx->path_len;
317 } else {
318 /* there is already some path, so add next level */
319 nextlevel = 1;
320 }
321 } /* else the path is just initiated with '/', so do not add additional slash in case of top-level nodes */
322
323 if (nextlevel != 2) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200324 if ((parent && (parent->module == ctx->cur_mod)) || (!parent && (ctx->path_len > 1) && (name[0] == '{'))) {
Radek Krejci327de162019-06-14 12:52:07 +0200325 /* module not changed, print the name unprefixed */
Radek Krejci70ee9152019-07-25 11:27:27 +0200326 len = snprintf(&ctx->path[ctx->path_len], LYSC_CTX_BUFSIZE - ctx->path_len, "%s%s", nextlevel ? "/" : "", name);
Radek Krejci327de162019-06-14 12:52:07 +0200327 } else {
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200328 len = snprintf(&ctx->path[ctx->path_len], LYSC_CTX_BUFSIZE - ctx->path_len, "%s%s:%s", nextlevel ? "/" : "", ctx->cur_mod->name, name);
Radek Krejci327de162019-06-14 12:52:07 +0200329 }
330 } else {
Radek Krejci70ee9152019-07-25 11:27:27 +0200331 len = snprintf(&ctx->path[ctx->path_len], LYSC_CTX_BUFSIZE - ctx->path_len, "='%s'}", name);
Radek Krejci327de162019-06-14 12:52:07 +0200332 }
Radek Krejci1deb5be2020-08-26 16:43:36 +0200333 if (len >= LYSC_CTX_BUFSIZE - (int)ctx->path_len) {
Radek Krejciacc79042019-07-25 14:14:57 +0200334 /* output truncated */
335 ctx->path_len = LYSC_CTX_BUFSIZE - 1;
336 } else {
337 ctx->path_len += len;
338 }
Radek Krejci327de162019-06-14 12:52:07 +0200339 }
340}
341
342/**
Radek Krejcib56c7502019-02-13 14:19:54 +0100343 * @brief Duplicate the compiled pattern structure.
344 *
345 * Instead of duplicating memory, the reference counter in the @p orig is increased.
346 *
347 * @param[in] orig The pattern structure to duplicate.
348 * @return The duplicated structure to use.
349 */
Michal Vasko22df3f02020-08-24 13:29:22 +0200350static struct lysc_pattern *
Radek Krejci19a96102018-11-15 13:38:09 +0100351lysc_pattern_dup(struct lysc_pattern *orig)
352{
353 ++orig->refcount;
354 return orig;
355}
356
Radek Krejcib56c7502019-02-13 14:19:54 +0100357/**
358 * @brief Duplicate the array of compiled patterns.
359 *
360 * The sized array itself is duplicated, but the pattern structures are just shadowed by increasing their reference counter.
361 *
362 * @param[in] ctx Libyang context for logging.
363 * @param[in] orig The patterns sized array to duplicate.
364 * @return New sized array as a copy of @p orig.
365 * @return NULL in case of memory allocation error.
366 */
Michal Vasko22df3f02020-08-24 13:29:22 +0200367static struct lysc_pattern **
Radek Krejci19a96102018-11-15 13:38:09 +0100368lysc_patterns_dup(struct ly_ctx *ctx, struct lysc_pattern **orig)
369{
Radek Krejcid05cbd92018-12-05 14:26:40 +0100370 struct lysc_pattern **dup = NULL;
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200371 LY_ARRAY_COUNT_TYPE u;
Radek Krejci19a96102018-11-15 13:38:09 +0100372
Radek Krejcib56c7502019-02-13 14:19:54 +0100373 assert(orig);
374
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200375 LY_ARRAY_CREATE_RET(ctx, dup, LY_ARRAY_COUNT(orig), NULL);
Radek Krejci19a96102018-11-15 13:38:09 +0100376 LY_ARRAY_FOR(orig, u) {
377 dup[u] = lysc_pattern_dup(orig[u]);
378 LY_ARRAY_INCREMENT(dup);
379 }
380 return dup;
381}
382
Radek Krejcib56c7502019-02-13 14:19:54 +0100383/**
384 * @brief Duplicate compiled range structure.
385 *
386 * @param[in] ctx Libyang context for logging.
387 * @param[in] orig The range structure to be duplicated.
388 * @return New compiled range structure as a copy of @p orig.
389 * @return NULL in case of memory allocation error.
390 */
Michal Vasko22df3f02020-08-24 13:29:22 +0200391struct lysc_range *
Radek Krejci19a96102018-11-15 13:38:09 +0100392lysc_range_dup(struct ly_ctx *ctx, const struct lysc_range *orig)
393{
394 struct lysc_range *dup;
395 LY_ERR ret;
396
Radek Krejcib56c7502019-02-13 14:19:54 +0100397 assert(orig);
398
Radek Krejci19a96102018-11-15 13:38:09 +0100399 dup = calloc(1, sizeof *dup);
400 LY_CHECK_ERR_RET(!dup, LOGMEM(ctx), NULL);
401 if (orig->parts) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200402 LY_ARRAY_CREATE_GOTO(ctx, dup->parts, LY_ARRAY_COUNT(orig->parts), ret, cleanup);
403 LY_ARRAY_COUNT(dup->parts) = LY_ARRAY_COUNT(orig->parts);
404 memcpy(dup->parts, orig->parts, LY_ARRAY_COUNT(dup->parts) * sizeof *dup->parts);
Radek Krejci19a96102018-11-15 13:38:09 +0100405 }
Radek Krejci011e4aa2020-09-04 15:22:31 +0200406 DUP_STRING_GOTO(ctx, orig->eapptag, dup->eapptag, ret, cleanup);
407 DUP_STRING_GOTO(ctx, orig->emsg, dup->emsg, ret, cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +0100408 dup->exts = lysc_ext_instance_dup(ctx, orig->exts);
409
410 return dup;
411cleanup:
412 free(dup);
413 (void) ret; /* set but not used due to the return type */
414 return NULL;
415}
416
Radek Krejcib56c7502019-02-13 14:19:54 +0100417/**
418 * @brief Stack for processing if-feature expressions.
419 */
Radek Krejci19a96102018-11-15 13:38:09 +0100420struct iff_stack {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200421 size_t size; /**< number of items in the stack */
422 size_t index; /**< first empty item */
423 uint8_t *stack; /**< stack - array of @ref ifftokens to create the if-feature expression in prefix format */
Radek Krejci19a96102018-11-15 13:38:09 +0100424};
425
Radek Krejcib56c7502019-02-13 14:19:54 +0100426/**
427 * @brief Add @ref ifftokens into the stack.
428 * @param[in] stack The if-feature stack to use.
429 * @param[in] value One of the @ref ifftokens to store in the stack.
430 * @return LY_EMEM in case of memory allocation error
431 * @return LY_ESUCCESS if the value successfully stored.
432 */
Radek Krejci19a96102018-11-15 13:38:09 +0100433static LY_ERR
434iff_stack_push(struct iff_stack *stack, uint8_t value)
435{
436 if (stack->index == stack->size) {
437 stack->size += 4;
438 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
439 LY_CHECK_ERR_RET(!stack->stack, LOGMEM(NULL); stack->size = 0, LY_EMEM);
440 }
441 stack->stack[stack->index++] = value;
442 return LY_SUCCESS;
443}
444
Radek Krejcib56c7502019-02-13 14:19:54 +0100445/**
446 * @brief Get (and remove) the last item form the stack.
447 * @param[in] stack The if-feature stack to use.
448 * @return The value from the top of the stack.
449 */
Radek Krejci19a96102018-11-15 13:38:09 +0100450static uint8_t
451iff_stack_pop(struct iff_stack *stack)
452{
Radek Krejcib56c7502019-02-13 14:19:54 +0100453 assert(stack && stack->index);
454
Radek Krejci19a96102018-11-15 13:38:09 +0100455 stack->index--;
456 return stack->stack[stack->index];
457}
458
Radek Krejcib56c7502019-02-13 14:19:54 +0100459/**
460 * @brief Clean up the stack.
461 * @param[in] stack The if-feature stack to use.
462 */
Radek Krejci19a96102018-11-15 13:38:09 +0100463static void
464iff_stack_clean(struct iff_stack *stack)
465{
466 stack->size = 0;
467 free(stack->stack);
468}
469
Radek Krejcib56c7502019-02-13 14:19:54 +0100470/**
471 * @brief Store the @ref ifftokens (@p op) on the given position in the 2bits array
472 * (libyang format of the if-feature expression).
473 * @param[in,out] list The 2bits array to modify.
474 * @param[in] op The operand (@ref ifftokens) to store.
475 * @param[in] pos Position (0-based) where to store the given @p op.
476 */
Radek Krejci19a96102018-11-15 13:38:09 +0100477static void
Radek Krejci1deb5be2020-08-26 16:43:36 +0200478iff_setop(uint8_t *list, uint8_t op, size_t pos)
Radek Krejci19a96102018-11-15 13:38:09 +0100479{
480 uint8_t *item;
481 uint8_t mask = 3;
482
Radek Krejci19a96102018-11-15 13:38:09 +0100483 assert(op <= 3); /* max 2 bits */
484
485 item = &list[pos / 4];
486 mask = mask << 2 * (pos % 4);
487 *item = (*item) & ~mask;
488 *item = (*item) | (op << 2 * (pos % 4));
489}
490
Radek Krejcib56c7502019-02-13 14:19:54 +0100491#define LYS_IFF_LP 0x04 /**< Additional, temporary, value of @ref ifftokens: ( */
492#define LYS_IFF_RP 0x08 /**< Additional, temporary, value of @ref ifftokens: ) */
Radek Krejci19a96102018-11-15 13:38:09 +0100493
Radek Krejci0af46292019-01-11 16:02:31 +0100494/**
495 * @brief Find a feature of the given name and referenced in the given module.
496 *
497 * If the compiled schema is available (the schema is implemented), the feature from the compiled schema is
498 * returned. Otherwise, the special array of pre-compiled features is used to search for the feature. Such
499 * features are always disabled (feature from not implemented schema cannot be enabled), but in case the schema
500 * will be made implemented in future (no matter if implicitly via augmenting/deviating it or explicitly via
501 * ly_ctx_module_implement()), the compilation of these feature structure is finished, but the pointers
502 * assigned till that time will be still valid.
503 *
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200504 * @param[in] pmod Module where the feature was referenced (used to resolve prefix of the feature).
Radek Krejci0af46292019-01-11 16:02:31 +0100505 * @param[in] name Name of the feature including possible prefix.
506 * @param[in] len Length of the string representing the feature identifier in the name variable (mandatory!).
507 * @return Pointer to the feature structure if found, NULL otherwise.
508 */
Radek Krejci19a96102018-11-15 13:38:09 +0100509static struct lysc_feature *
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200510lys_feature_find(const struct lysp_module *pmod, const char *name, size_t len)
Radek Krejci19a96102018-11-15 13:38:09 +0100511{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200512 LY_ARRAY_COUNT_TYPE u;
Radek Krejci14915cc2020-09-14 17:28:13 +0200513 struct lysc_feature *f;
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200514 const struct lys_module *mod;
515 const char *ptr;
Radek Krejci19a96102018-11-15 13:38:09 +0100516
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200517 assert(pmod);
Radek Krejci120d8542020-08-12 09:29:16 +0200518
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200519 if ((ptr = ly_strnchr(name, ':', len))) {
520 /* we have a prefixed feature */
521 mod = lysp_module_find_prefix(pmod, name, ptr - name);
522 LY_CHECK_RET(!mod, NULL);
Radek Krejci19a96102018-11-15 13:38:09 +0100523
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200524 len = len - (ptr - name) - 1;
525 name = ptr + 1;
526 } else {
527 /* local feature */
528 mod = pmod->mod;
Radek Krejci19a96102018-11-15 13:38:09 +0100529 }
530
531 /* we have the correct module, get the feature */
Radek Krejci14915cc2020-09-14 17:28:13 +0200532 LY_ARRAY_FOR(mod->features, u) {
533 f = &mod->features[u];
Radek Krejci7f9b6512019-09-18 13:11:09 +0200534 if (!ly_strncmp(f->name, name, len)) {
Radek Krejci19a96102018-11-15 13:38:09 +0100535 return f;
536 }
537 }
538
539 return NULL;
540}
541
Michal Vasko8d544252020-03-02 10:19:52 +0100542/**
Michal Vasko5fe75f12020-03-02 13:52:37 +0100543 * @brief Fill in the prepared compiled extensions definition structure according to the parsed extension definition.
544 */
545static LY_ERR
546lys_compile_extension(struct lysc_ctx *ctx, const struct lys_module *ext_mod, struct lysp_ext *ext_p, struct lysc_ext **ext)
547{
548 LY_ERR ret = LY_SUCCESS;
549
550 if (!ext_p->compiled) {
551 lysc_update_path(ctx, NULL, "{extension}");
552 lysc_update_path(ctx, NULL, ext_p->name);
553
554 /* compile the extension definition */
555 ext_p->compiled = calloc(1, sizeof **ext);
556 ext_p->compiled->refcount = 1;
Radek Krejci011e4aa2020-09-04 15:22:31 +0200557 DUP_STRING_GOTO(ctx->ctx, ext_p->name, ext_p->compiled->name, ret, done);
558 DUP_STRING_GOTO(ctx->ctx, ext_p->argument, ext_p->compiled->argument, ret, done);
Michal Vasko5fe75f12020-03-02 13:52:37 +0100559 ext_p->compiled->module = (struct lys_module *)ext_mod;
560 COMPILE_EXTS_GOTO(ctx, ext_p->exts, ext_p->compiled->exts, *ext, LYEXT_PAR_EXT, ret, done);
561
562 lysc_update_path(ctx, NULL, NULL);
563 lysc_update_path(ctx, NULL, NULL);
564
565 /* find extension definition plugin */
566 ext_p->compiled->plugin = lyext_get_plugin(ext_p->compiled);
567 }
568
569 *ext = lysc_ext_dup(ext_p->compiled);
570
571done:
572 return ret;
573}
574
575/**
Michal Vasko8d544252020-03-02 10:19:52 +0100576 * @brief Fill in the prepared compiled extension instance structure according to the parsed extension instance.
577 *
578 * @param[in] ctx Compilation context.
579 * @param[in] ext_p Parsed extension instance.
580 * @param[in,out] ext Prepared compiled extension instance.
581 * @param[in] parent Extension instance parent.
582 * @param[in] parent_type Extension instance parent type.
583 * @param[in] ext_mod Optional module with the extension instance extension definition, set only for internal annotations.
584 */
Radek Krejci19a96102018-11-15 13:38:09 +0100585static LY_ERR
Michal Vasko8d544252020-03-02 10:19:52 +0100586lys_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 +0200587 LYEXT_PARENT parent_type, const struct lys_module *ext_mod)
Radek Krejci19a96102018-11-15 13:38:09 +0100588{
Radek Krejci011e4aa2020-09-04 15:22:31 +0200589 LY_ERR ret = LY_SUCCESS;
Radek Krejci19a96102018-11-15 13:38:09 +0100590 const char *name;
Radek Krejci7eb54ba2020-05-18 16:30:04 +0200591 size_t u;
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200592 LY_ARRAY_COUNT_TYPE v;
Radek Krejci7c960162019-09-18 14:16:12 +0200593 const char *prefixed_name = NULL;
Radek Krejci19a96102018-11-15 13:38:09 +0100594
Radek Krejci011e4aa2020-09-04 15:22:31 +0200595 DUP_STRING(ctx->ctx, ext_p->argument, ext->argument, ret);
596 LY_CHECK_RET(ret);
597
Radek Krejci19a96102018-11-15 13:38:09 +0100598 ext->insubstmt = ext_p->insubstmt;
599 ext->insubstmt_index = ext_p->insubstmt_index;
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200600 ext->module = ctx->cur_mod;
Radek Krejci0935f412019-08-20 16:15:18 +0200601 ext->parent = parent;
602 ext->parent_type = parent_type;
Radek Krejci19a96102018-11-15 13:38:09 +0100603
Michal Vasko22df3f02020-08-24 13:29:22 +0200604 lysc_update_path(ctx, ext->parent_type == LYEXT_PAR_NODE ? (struct lysc_node *)ext->parent : NULL, "{extension}");
Radek Krejcif56e2a42019-09-09 14:15:25 +0200605
Radek Krejci19a96102018-11-15 13:38:09 +0100606 /* get module where the extension definition should be placed */
Radek Krejci1e008d22020-08-17 11:37:37 +0200607 for (u = strlen(ext_p->name); u && ext_p->name[u - 1] != ':'; --u) {}
Radek Krejci7c960162019-09-18 14:16:12 +0200608 if (ext_p->yin) {
609 /* YIN parser has to replace prefixes by the namespace - XML namespace/prefix pairs may differs form the YANG schema's
610 * namespace/prefix pair. YIN parser does not have the imports available, so mapping from XML namespace to the
611 * YANG (import) prefix must be done here. */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200612 if (!ly_strncmp(ctx->pmod->mod->ns, ext_p->name, u - 1)) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200613 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, &ext_p->name[u], 0, &prefixed_name), cleanup);
Radek Krejci7c960162019-09-18 14:16:12 +0200614 u = 0;
Michal Vasko7c8439f2020-08-05 13:25:19 +0200615 } else {
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200616 LY_ARRAY_FOR(ctx->pmod->imports, v) {
617 if (!ly_strncmp(ctx->pmod->imports[v].module->ns, ext_p->name, u - 1)) {
Radek Krejci7c960162019-09-18 14:16:12 +0200618 char *s;
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200619 LY_CHECK_ERR_GOTO(asprintf(&s, "%s:%s", ctx->pmod->imports[v].prefix, &ext_p->name[u]) == -1,
Michal Vasko69730152020-10-09 16:30:07 +0200620 ret = LY_EMEM, cleanup);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200621 LY_CHECK_GOTO(ret = lydict_insert_zc(ctx->ctx, s, &prefixed_name), cleanup);
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200622 u = strlen(ctx->pmod->imports[v].prefix) + 1; /* add semicolon */
Radek Krejci7c960162019-09-18 14:16:12 +0200623 break;
624 }
625 }
626 }
627 if (!prefixed_name) {
628 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200629 "Invalid XML prefix of \"%.*s\" namespace used for extension instance identifier.", u, ext_p->name);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200630 ret = LY_EVALID;
Radek Krejci7c960162019-09-18 14:16:12 +0200631 goto cleanup;
632 }
633 } else {
634 prefixed_name = ext_p->name;
635 }
636 lysc_update_path(ctx, NULL, prefixed_name);
637
Michal Vasko8d544252020-03-02 10:19:52 +0100638 if (!ext_mod) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200639 ext_mod = u ? lysp_module_find_prefix(ctx->pmod, prefixed_name, u - 1) : ctx->pmod->mod;
Michal Vasko8d544252020-03-02 10:19:52 +0100640 if (!ext_mod) {
641 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200642 "Invalid prefix \"%.*s\" used for extension instance identifier.", u, prefixed_name);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200643 ret = LY_EVALID;
Michal Vasko8d544252020-03-02 10:19:52 +0100644 goto cleanup;
645 } else if (!ext_mod->parsed->extensions) {
646 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
647 "Extension instance \"%s\" refers \"%s\" module that does not contain extension definitions.",
648 prefixed_name, ext_mod->name);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200649 ret = LY_EVALID;
Michal Vasko8d544252020-03-02 10:19:52 +0100650 goto cleanup;
651 }
Radek Krejci7c960162019-09-18 14:16:12 +0200652 }
653 name = &prefixed_name[u];
Radek Krejci0935f412019-08-20 16:15:18 +0200654
Michal Vasko5fe75f12020-03-02 13:52:37 +0100655 /* find the parsed extension definition there */
Radek Krejci7eb54ba2020-05-18 16:30:04 +0200656 LY_ARRAY_FOR(ext_mod->parsed->extensions, v) {
657 if (!strcmp(name, ext_mod->parsed->extensions[v].name)) {
Michal Vasko5fe75f12020-03-02 13:52:37 +0100658 /* compile extension definition and assign it */
Radek Krejci011e4aa2020-09-04 15:22:31 +0200659 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 +0100660 break;
661 }
662 }
Radek Krejci7c960162019-09-18 14:16:12 +0200663 if (!ext->def) {
664 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200665 "Extension definition of extension instance \"%s\" not found.", prefixed_name);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200666 ret = LY_EVALID;
Radek Krejci7c960162019-09-18 14:16:12 +0200667 goto cleanup;
668 }
Radek Krejci0935f412019-08-20 16:15:18 +0200669
Radek Krejcif56e2a42019-09-09 14:15:25 +0200670 /* unify the parsed extension from YIN and YANG sources. Without extension definition, it is not possible
671 * to get extension's argument from YIN source, so it is stored as one of the substatements. Here we have
672 * to find it, mark it with LYS_YIN_ARGUMENT and store it in the compiled structure. */
Radek Krejci7c960162019-09-18 14:16:12 +0200673 if (ext_p->yin && ext->def->argument && !ext->argument) {
Radek Krejcif56e2a42019-09-09 14:15:25 +0200674 /* Schema was parsed from YIN and an argument is expected, ... */
675 struct lysp_stmt *stmt = NULL;
676
677 if (ext->def->flags & LYS_YINELEM_TRUE) {
678 /* ... argument was the first XML child element */
679 if (ext_p->child && !(ext_p->child->flags & LYS_YIN_ATTR)) {
680 /* TODO check namespace of the statement */
681 if (!strcmp(ext_p->child->stmt, ext->def->argument)) {
682 stmt = ext_p->child;
683 }
684 }
685 } else {
686 /* ... argument was one of the XML attributes which are represented as child stmt
687 * with LYS_YIN_ATTR flag */
688 for (stmt = ext_p->child; stmt && (stmt->flags & LYS_YIN_ATTR); stmt = stmt->next) {
689 if (!strcmp(stmt->stmt, ext->def->argument)) {
690 /* this is the extension's argument */
Radek Krejcif56e2a42019-09-09 14:15:25 +0200691 break;
692 }
693 }
694 }
695 if (!stmt) {
696 /* missing extension's argument */
697 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200698 "Extension instance \"%s\" misses argument \"%s\".", prefixed_name, ext->def->argument);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200699 ret = LY_EVALID;
Radek Krejci7c960162019-09-18 14:16:12 +0200700 goto cleanup;
Radek Krejcif56e2a42019-09-09 14:15:25 +0200701
702 }
Radek Krejci011e4aa2020-09-04 15:22:31 +0200703 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, stmt->arg, 0, &ext->argument), cleanup);
Radek Krejcif56e2a42019-09-09 14:15:25 +0200704 stmt->flags |= LYS_YIN_ARGUMENT;
705 }
Radek Krejci7c960162019-09-18 14:16:12 +0200706 if (prefixed_name != ext_p->name) {
707 lydict_remove(ctx->ctx, ext_p->name);
708 ext_p->name = prefixed_name;
709 if (!ext_p->argument && ext->argument) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200710 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, ext->argument, 0, &ext_p->argument), cleanup);
Radek Krejci7c960162019-09-18 14:16:12 +0200711 }
712 }
Radek Krejcif56e2a42019-09-09 14:15:25 +0200713
Radek Krejci0935f412019-08-20 16:15:18 +0200714 if (ext->def->plugin && ext->def->plugin->compile) {
Radek Krejciad5963b2019-09-06 16:03:05 +0200715 if (ext->argument) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200716 lysc_update_path(ctx, (struct lysc_node *)ext, ext->argument);
Radek Krejciad5963b2019-09-06 16:03:05 +0200717 }
Radek Krejci011e4aa2020-09-04 15:22:31 +0200718 LY_CHECK_GOTO(ret = ext->def->plugin->compile(ctx, ext_p, ext), cleanup);
Radek Krejciad5963b2019-09-06 16:03:05 +0200719 if (ext->argument) {
720 lysc_update_path(ctx, NULL, NULL);
721 }
Radek Krejci0935f412019-08-20 16:15:18 +0200722 }
Radek Krejcif56e2a42019-09-09 14:15:25 +0200723 ext_p->compiled = ext;
724
Radek Krejci7c960162019-09-18 14:16:12 +0200725cleanup:
Michal Vasko69730152020-10-09 16:30:07 +0200726 if (prefixed_name && (prefixed_name != ext_p->name)) {
Radek Krejci7c960162019-09-18 14:16:12 +0200727 lydict_remove(ctx->ctx, prefixed_name);
728 }
729
Radek Krejcif56e2a42019-09-09 14:15:25 +0200730 lysc_update_path(ctx, NULL, NULL);
731 lysc_update_path(ctx, NULL, NULL);
Radek Krejci0935f412019-08-20 16:15:18 +0200732
Radek Krejci7c960162019-09-18 14:16:12 +0200733 return ret;
Radek Krejci0935f412019-08-20 16:15:18 +0200734}
735
736/**
Radek Krejcib56c7502019-02-13 14:19:54 +0100737 * @brief Compile information from the if-feature statement
738 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +0200739 * @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 +0100740 * @param[in,out] iff Prepared (empty) compiled if-feature structure to fill.
741 * @return LY_ERR value.
742 */
Radek Krejci19a96102018-11-15 13:38:09 +0100743static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +0200744lys_compile_iffeature(struct lysc_ctx *ctx, struct lysp_qname *qname, struct lysc_iffeature *iff)
Radek Krejci19a96102018-11-15 13:38:09 +0100745{
Radek Krejci1deb5be2020-08-26 16:43:36 +0200746 LY_ERR rc = LY_SUCCESS;
Michal Vasko7f45cf22020-10-01 12:49:44 +0200747 const char *c = qname->str;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200748 int64_t i, j;
749 int8_t op_len, last_not = 0, checkversion = 0;
750 LY_ARRAY_COUNT_TYPE f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci19a96102018-11-15 13:38:09 +0100751 uint8_t op;
752 struct iff_stack stack = {0, 0, NULL};
753 struct lysc_feature *f;
754
755 assert(c);
756
757 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
Radek Krejci1deb5be2020-08-26 16:43:36 +0200758 for (i = j = 0; c[i]; i++) {
Radek Krejci19a96102018-11-15 13:38:09 +0100759 if (c[i] == '(') {
760 j++;
761 checkversion = 1;
762 continue;
763 } else if (c[i] == ')') {
764 j--;
765 continue;
766 } else if (isspace(c[i])) {
767 checkversion = 1;
768 continue;
769 }
770
Radek Krejci1deb5be2020-08-26 16:43:36 +0200771 if (!strncmp(&c[i], "not", op_len = 3) || !strncmp(&c[i], "and", op_len = 3) || !strncmp(&c[i], "or", op_len = 2)) {
772 uint64_t spaces;
Michal Vasko2b7e5582020-10-07 12:31:23 +0200773 for (spaces = 0; c[i + op_len + spaces] && isspace(c[i + op_len + spaces]); spaces++) {}
Radek Krejci1deb5be2020-08-26 16:43:36 +0200774 if (c[i + op_len + spaces] == '\0') {
Radek Krejci19a96102018-11-15 13:38:09 +0100775 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +0200776 "Invalid value \"%s\" of if-feature - unexpected end of expression.", qname->str);
Radek Krejci19a96102018-11-15 13:38:09 +0100777 return LY_EVALID;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200778 } else if (!isspace(c[i + op_len])) {
Radek Krejci19a96102018-11-15 13:38:09 +0100779 /* feature name starting with the not/and/or */
780 last_not = 0;
781 f_size++;
782 } else if (c[i] == 'n') { /* not operation */
783 if (last_not) {
784 /* double not */
785 expr_size = expr_size - 2;
786 last_not = 0;
787 } else {
788 last_not = 1;
789 }
790 } else { /* and, or */
Radek Krejci6788abc2019-06-14 13:56:49 +0200791 if (f_exp != f_size) {
792 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +0200793 "Invalid value \"%s\" of if-feature - missing feature/expression before \"%.*s\" operation.",
794 qname->str, op_len, &c[i]);
Radek Krejci6788abc2019-06-14 13:56:49 +0200795 return LY_EVALID;
796 }
Radek Krejci19a96102018-11-15 13:38:09 +0100797 f_exp++;
Radek Krejci6788abc2019-06-14 13:56:49 +0200798
Radek Krejci19a96102018-11-15 13:38:09 +0100799 /* not a not operation */
800 last_not = 0;
801 }
Radek Krejci1deb5be2020-08-26 16:43:36 +0200802 i += op_len;
Radek Krejci19a96102018-11-15 13:38:09 +0100803 } else {
804 f_size++;
805 last_not = 0;
806 }
807 expr_size++;
808
809 while (!isspace(c[i])) {
Michal Vasko69730152020-10-09 16:30:07 +0200810 if (!c[i] || (c[i] == ')') || (c[i] == '(')) {
Radek Krejci19a96102018-11-15 13:38:09 +0100811 i--;
812 break;
813 }
814 i++;
815 }
816 }
Radek Krejci6788abc2019-06-14 13:56:49 +0200817 if (j) {
Radek Krejci19a96102018-11-15 13:38:09 +0100818 /* not matching count of ( and ) */
819 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +0200820 "Invalid value \"%s\" of if-feature - non-matching opening and closing parentheses.", qname->str);
Radek Krejci19a96102018-11-15 13:38:09 +0100821 return LY_EVALID;
822 }
Radek Krejci6788abc2019-06-14 13:56:49 +0200823 if (f_exp != f_size) {
824 /* features do not match the needed arguments for the logical operations */
825 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +0200826 "Invalid value \"%s\" of if-feature - number of features in expression does not match "
827 "the required number of operands for the operations.", qname->str);
Radek Krejci6788abc2019-06-14 13:56:49 +0200828 return LY_EVALID;
829 }
Radek Krejci19a96102018-11-15 13:38:09 +0100830
Michal Vasko69730152020-10-09 16:30:07 +0200831 if (checkversion || (expr_size > 1)) {
Radek Krejci19a96102018-11-15 13:38:09 +0100832 /* check that we have 1.1 module */
Michal Vasko7f45cf22020-10-01 12:49:44 +0200833 if (qname->mod->version != LYS_VERSION_1_1) {
Radek Krejci19a96102018-11-15 13:38:09 +0100834 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +0200835 "Invalid value \"%s\" of if-feature - YANG 1.1 expression in YANG 1.0 module.", qname->str);
Radek Krejci19a96102018-11-15 13:38:09 +0100836 return LY_EVALID;
837 }
838 }
839
840 /* allocate the memory */
841 LY_ARRAY_CREATE_RET(ctx->ctx, iff->features, f_size, LY_EMEM);
842 iff->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iff->expr);
843 stack.stack = malloc(expr_size * sizeof *stack.stack);
Radek Krejci1deb5be2020-08-26 16:43:36 +0200844 LY_CHECK_ERR_GOTO(!stack.stack || !iff->expr, LOGMEM(ctx->ctx); rc = LY_EMEM, error);
Radek Krejci19a96102018-11-15 13:38:09 +0100845
846 stack.size = expr_size;
847 f_size--; expr_size--; /* used as indexes from now */
848
849 for (i--; i >= 0; i--) {
850 if (c[i] == ')') {
851 /* push it on stack */
852 iff_stack_push(&stack, LYS_IFF_RP);
853 continue;
854 } else if (c[i] == '(') {
855 /* pop from the stack into result all operators until ) */
Michal Vaskod989ba02020-08-24 10:59:24 +0200856 while ((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
Radek Krejci19a96102018-11-15 13:38:09 +0100857 iff_setop(iff->expr, op, expr_size--);
858 }
859 continue;
860 } else if (isspace(c[i])) {
861 continue;
862 }
863
864 /* end of operator or operand -> find beginning and get what is it */
865 j = i + 1;
866 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
867 i--;
868 }
869 i++; /* go back by one step */
870
871 if (!strncmp(&c[i], "not", 3) && isspace(c[i + 3])) {
Michal Vasko69730152020-10-09 16:30:07 +0200872 if (stack.index && (stack.stack[stack.index - 1] == LYS_IFF_NOT)) {
Radek Krejci19a96102018-11-15 13:38:09 +0100873 /* double not */
874 iff_stack_pop(&stack);
875 } else {
876 /* not has the highest priority, so do not pop from the stack
877 * as in case of AND and OR */
878 iff_stack_push(&stack, LYS_IFF_NOT);
879 }
880 } else if (!strncmp(&c[i], "and", 3) && isspace(c[i + 3])) {
881 /* as for OR - pop from the stack all operators with the same or higher
882 * priority and store them to the result, then push the AND to the stack */
883 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
884 op = iff_stack_pop(&stack);
885 iff_setop(iff->expr, op, expr_size--);
886 }
887 iff_stack_push(&stack, LYS_IFF_AND);
888 } else if (!strncmp(&c[i], "or", 2) && isspace(c[i + 2])) {
889 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
890 op = iff_stack_pop(&stack);
891 iff_setop(iff->expr, op, expr_size--);
892 }
893 iff_stack_push(&stack, LYS_IFF_OR);
894 } else {
895 /* feature name, length is j - i */
896
897 /* add it to the expression */
898 iff_setop(iff->expr, LYS_IFF_F, expr_size--);
899
900 /* now get the link to the feature definition */
Michal Vasko7f45cf22020-10-01 12:49:44 +0200901 f = lys_feature_find(qname->mod, &c[i], j - i);
Radek Krejci0af46292019-01-11 16:02:31 +0100902 LY_CHECK_ERR_GOTO(!f, LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko7f45cf22020-10-01 12:49:44 +0200903 "Invalid value \"%s\" of if-feature - unable to find feature \"%.*s\".", qname->str, j - i, &c[i]);
904 rc = LY_EVALID, error)
Radek Krejci19a96102018-11-15 13:38:09 +0100905 iff->features[f_size] = f;
906 LY_ARRAY_INCREMENT(iff->features);
907 f_size--;
908 }
909 }
910 while (stack.index) {
911 op = iff_stack_pop(&stack);
912 iff_setop(iff->expr, op, expr_size--);
913 }
914
915 if (++expr_size || ++f_size) {
916 /* not all expected operators and operands found */
917 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko7f45cf22020-10-01 12:49:44 +0200918 "Invalid value \"%s\" of if-feature - processing error.", qname->str);
Radek Krejci19a96102018-11-15 13:38:09 +0100919 rc = LY_EINT;
920 } else {
921 rc = LY_SUCCESS;
922 }
923
924error:
925 /* cleanup */
926 iff_stack_clean(&stack);
927
928 return rc;
929}
930
Radek Krejcib56c7502019-02-13 14:19:54 +0100931/**
Michal Vasko175012e2019-11-06 15:49:14 +0100932 * @brief Get the XPath context node for the given schema node.
933 * @param[in] start The schema node where the XPath expression appears.
934 * @return The context node to evaluate XPath expression in given schema node.
935 * @return NULL in case the context node is the root node.
936 */
937static struct lysc_node *
938lysc_xpath_context(struct lysc_node *start)
939{
Michal Vasko1bf09392020-03-27 12:38:10 +0100940 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 +0200941 start = start->parent) {}
Michal Vasko175012e2019-11-06 15:49:14 +0100942 return start;
943}
944
945/**
Radek Krejcib56c7502019-02-13 14:19:54 +0100946 * @brief Compile information from the when statement
Michal Vaskoceab6dd2020-10-09 16:53:36 +0200947 *
Radek Krejcib56c7502019-02-13 14:19:54 +0100948 * @param[in] ctx Compile context.
Michal Vaskoceab6dd2020-10-09 16:53:36 +0200949 * @param[in] when_p Parsed when structure.
950 * @param[in] flags Flags of the parsed node with the when statement.
951 * @param[in] ctx_node Context node for the when statement.
Radek Krejcib56c7502019-02-13 14:19:54 +0100952 * @param[out] when Pointer where to store pointer to the created compiled when structure.
953 * @return LY_ERR value.
954 */
Radek Krejci19a96102018-11-15 13:38:09 +0100955static LY_ERR
Michal Vaskoceab6dd2020-10-09 16:53:36 +0200956lys_compile_when_(struct lysc_ctx *ctx, struct lysp_when *when_p, uint16_t flags, const struct lysc_node *ctx_node,
957 struct lysc_when **when)
Radek Krejci19a96102018-11-15 13:38:09 +0100958{
Radek Krejci19a96102018-11-15 13:38:09 +0100959 LY_ERR ret = LY_SUCCESS;
960
Radek Krejci00b874b2019-02-12 10:54:50 +0100961 *when = calloc(1, sizeof **when);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200962 LY_CHECK_ERR_RET(!(*when), LOGMEM(ctx->ctx), LY_EMEM);
Radek Krejci00b874b2019-02-12 10:54:50 +0100963 (*when)->refcount = 1;
Radek Krejcif03a9e22020-09-18 20:09:31 +0200964 LY_CHECK_RET(lyxp_expr_parse(ctx->ctx, when_p->cond, 0, 1, &(*when)->cond));
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200965 LY_CHECK_RET(lysc_prefixes_compile(when_p->cond, strlen(when_p->cond), ctx->pmod, &(*when)->prefixes));
Michal Vaskoceab6dd2020-10-09 16:53:36 +0200966 (*when)->context = (struct lysc_node *)ctx_node;
Radek Krejci011e4aa2020-09-04 15:22:31 +0200967 DUP_STRING_GOTO(ctx->ctx, when_p->dsc, (*when)->dsc, ret, done);
968 DUP_STRING_GOTO(ctx->ctx, when_p->ref, (*when)->ref, ret, done);
Radek Krejci0935f412019-08-20 16:15:18 +0200969 COMPILE_EXTS_GOTO(ctx, when_p->exts, (*when)->exts, (*when), LYEXT_PAR_WHEN, ret, done);
Michal Vasko175012e2019-11-06 15:49:14 +0100970 (*when)->flags = flags & LYS_STATUS_MASK;
Radek Krejci19a96102018-11-15 13:38:09 +0100971
972done:
973 return ret;
974}
975
Radek Krejcib56c7502019-02-13 14:19:54 +0100976/**
Michal Vaskoceab6dd2020-10-09 16:53:36 +0200977 * @brief Compile information from the when statement by either standard compilation or by reusing
978 * another compiled when structure.
979 *
980 * @param[in] ctx Compile context.
981 * @param[in] when_p Parsed when structure.
982 * @param[in] flags Flags of the parsed node with the when statement.
983 * @param[in] ctx_node Context node for the when statement.
984 * @param[in] node Compiled node to which add the compiled when.
985 * @param[in,out] when_c Optional, pointer to the previously compiled @p when_p to be reused. Set to NULL
986 * for the first call.
987 * @return LY_ERR value.
988 */
989static LY_ERR
990lys_compile_when(struct lysc_ctx *ctx, struct lysp_when *when_p, uint16_t flags, const struct lysc_node *ctx_node,
991 struct lysc_node *node, struct lysc_when **when_c)
992{
993 struct lysc_when **new_when, ***node_when;
994
995 assert(when_p);
996
997 /* get the when array */
998 if (node->nodetype & LYS_ACTION) {
999 node_when = &((struct lysc_action *)node)->when;
1000 } else if (node->nodetype == LYS_NOTIF) {
1001 node_when = &((struct lysc_notif *)node)->when;
1002 } else {
1003 node_when = &node->when;
1004 }
1005
1006 /* create new when pointer */
1007 LY_ARRAY_NEW_RET(ctx->ctx, *node_when, new_when, LY_EMEM);
1008 if (!when_c || !(*when_c)) {
1009 /* compile when */
1010 LY_CHECK_RET(lys_compile_when_(ctx, when_p, flags, ctx_node, new_when));
1011
Radek Krejci90d4e922020-10-12 15:55:33 +02001012 if (!(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vaskoceab6dd2020-10-09 16:53:36 +02001013 /* do not check "when" semantics in a grouping */
1014 LY_CHECK_RET(ly_set_add(&ctx->xpath, node, 0, NULL));
1015 }
1016
1017 /* remember the compiled when for sharing */
1018 if (when_c) {
1019 *when_c = *new_when;
1020 }
1021 } else {
1022 /* use the previously compiled when */
1023 ++(*when_c)->refcount;
1024 *new_when = *when_c;
1025
Radek Krejci90d4e922020-10-12 15:55:33 +02001026 if (!(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vaskoceab6dd2020-10-09 16:53:36 +02001027 /* in this case check "when" again for all children because of dummy node check */
1028 LY_CHECK_RET(ly_set_add(&ctx->xpath, node, 0, NULL));
1029 }
1030 }
1031
1032 return LY_SUCCESS;
1033}
1034
1035/**
Radek Krejcib56c7502019-02-13 14:19:54 +01001036 * @brief Compile information from the must statement
1037 * @param[in] ctx Compile context.
1038 * @param[in] must_p The parsed must statement structure.
Radek Krejcib56c7502019-02-13 14:19:54 +01001039 * @param[in,out] must Prepared (empty) compiled must structure to fill.
1040 * @return LY_ERR value.
1041 */
Radek Krejci19a96102018-11-15 13:38:09 +01001042static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02001043lys_compile_must(struct lysc_ctx *ctx, struct lysp_restr *must_p, struct lysc_must *must)
Radek Krejci19a96102018-11-15 13:38:09 +01001044{
Radek Krejci19a96102018-11-15 13:38:09 +01001045 LY_ERR ret = LY_SUCCESS;
1046
Michal Vasko7f45cf22020-10-01 12:49:44 +02001047 LY_CHECK_RET(lyxp_expr_parse(ctx->ctx, must_p->arg.str, 0, 1, &must->cond));
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001048 LY_CHECK_RET(lysc_prefixes_compile(must_p->arg.str, strlen(must_p->arg.str), must_p->arg.mod, &must->prefixes));
Radek Krejci011e4aa2020-09-04 15:22:31 +02001049 DUP_STRING_GOTO(ctx->ctx, must_p->eapptag, must->eapptag, ret, done);
1050 DUP_STRING_GOTO(ctx->ctx, must_p->emsg, must->emsg, ret, done);
1051 DUP_STRING_GOTO(ctx->ctx, must_p->dsc, must->dsc, ret, done);
1052 DUP_STRING_GOTO(ctx->ctx, must_p->ref, must->ref, ret, done);
Radek Krejci0935f412019-08-20 16:15:18 +02001053 COMPILE_EXTS_GOTO(ctx, must_p->exts, must->exts, must, LYEXT_PAR_MUST, ret, done);
Radek Krejci19a96102018-11-15 13:38:09 +01001054
1055done:
1056 return ret;
1057}
1058
Radek Krejcib56c7502019-02-13 14:19:54 +01001059/**
Michal Vasko7c8439f2020-08-05 13:25:19 +02001060 * @brief Compile information in the import statement - make sure there is the target module
Radek Krejcib56c7502019-02-13 14:19:54 +01001061 * @param[in] ctx Compile context.
Michal Vasko7c8439f2020-08-05 13:25:19 +02001062 * @param[in] imp_p The parsed import statement structure to fill the module to.
Radek Krejcib56c7502019-02-13 14:19:54 +01001063 * @return LY_ERR value.
1064 */
Radek Krejci19a96102018-11-15 13:38:09 +01001065static LY_ERR
Michal Vasko7c8439f2020-08-05 13:25:19 +02001066lys_compile_import(struct lysc_ctx *ctx, struct lysp_import *imp_p)
Radek Krejci19a96102018-11-15 13:38:09 +01001067{
Michal Vasko3a41dff2020-07-15 14:30:28 +02001068 const struct lys_module *mod = NULL;
Radek Krejci19a96102018-11-15 13:38:09 +01001069 LY_ERR ret = LY_SUCCESS;
1070
Radek Krejci7f2a5362018-11-28 13:05:37 +01001071 /* make sure that we have the parsed version (lysp_) of the imported module to import groupings or typedefs.
1072 * The compiled version is needed only for augments, deviates and leafrefs, so they are checked (and added,
Radek Krejci0e5d8382018-11-28 16:37:53 +01001073 * if needed) when these nodes are finally being instantiated and validated at the end of schema compilation. */
Michal Vasko7c8439f2020-08-05 13:25:19 +02001074 if (!imp_p->module->parsed) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001075 /* try to use filepath if present */
Michal Vasko7c8439f2020-08-05 13:25:19 +02001076 if (imp_p->module->filepath) {
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001077 struct ly_in *in;
Michal Vasko7c8439f2020-08-05 13:25:19 +02001078 if (ly_in_new_filepath(imp_p->module->filepath, 0, &in)) {
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001079 LOGINT(ctx->ctx);
1080 } else {
Michal Vasko7c8439f2020-08-05 13:25:19 +02001081 LY_CHECK_RET(lys_parse(ctx->ctx, in, !strcmp(&imp_p->module->filepath[strlen(imp_p->module->filepath - 4)],
Michal Vasko69730152020-10-09 16:30:07 +02001082 ".yin") ? LYS_IN_YIN : LYS_IN_YANG, &mod));
Michal Vasko7c8439f2020-08-05 13:25:19 +02001083 if (mod != imp_p->module) {
Michal Vasko3a41dff2020-07-15 14:30:28 +02001084 LOGERR(ctx->ctx, LY_EINT, "Filepath \"%s\" of the module \"%s\" does not match.",
Michal Vasko69730152020-10-09 16:30:07 +02001085 imp_p->module->filepath, imp_p->module->name);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001086 mod = NULL;
1087 }
Radek Krejci19a96102018-11-15 13:38:09 +01001088 }
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001089 ly_in_free(in, 1);
Radek Krejci19a96102018-11-15 13:38:09 +01001090 }
1091 if (!mod) {
Michal Vasko7c8439f2020-08-05 13:25:19 +02001092 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 +01001093 LOGERR(ctx->ctx, LY_ENOTFOUND, "Unable to reload \"%s\" module to import it into \"%s\", source data not found.",
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001094 imp_p->module->name, ctx->cur_mod->name);
Radek Krejci19a96102018-11-15 13:38:09 +01001095 return LY_ENOTFOUND;
1096 }
1097 }
Radek Krejci19a96102018-11-15 13:38:09 +01001098 }
1099
Radek Krejci19a96102018-11-15 13:38:09 +01001100 return ret;
1101}
1102
Michal Vasko33ff9422020-07-03 09:50:39 +02001103LY_ERR
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001104lys_identity_precompile(struct lysc_ctx *ctx_sc, struct ly_ctx *ctx, struct lysp_module *parsed_mod,
Radek Krejci0f969882020-08-21 16:56:47 +02001105 struct lysp_ident *identities_p, struct lysc_ident **identities)
Radek Krejci19a96102018-11-15 13:38:09 +01001106{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001107 LY_ARRAY_COUNT_TYPE offset = 0, u, v;
Michal Vasko33ff9422020-07-03 09:50:39 +02001108 struct lysc_ctx context = {0};
Radek Krejci19a96102018-11-15 13:38:09 +01001109 LY_ERR ret = LY_SUCCESS;
1110
Michal Vasko33ff9422020-07-03 09:50:39 +02001111 assert(ctx_sc || ctx);
Radek Krejci327de162019-06-14 12:52:07 +02001112
Michal Vasko33ff9422020-07-03 09:50:39 +02001113 if (!ctx_sc) {
1114 context.ctx = ctx;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001115 context.cur_mod = parsed_mod->mod;
1116 context.pmod = parsed_mod;
Michal Vasko33ff9422020-07-03 09:50:39 +02001117 context.path_len = 1;
1118 context.path[0] = '/';
1119 ctx_sc = &context;
1120 }
Radek Krejci19a96102018-11-15 13:38:09 +01001121
Michal Vasko33ff9422020-07-03 09:50:39 +02001122 if (!identities_p) {
1123 return LY_SUCCESS;
1124 }
1125 if (*identities) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001126 offset = LY_ARRAY_COUNT(*identities);
Michal Vasko33ff9422020-07-03 09:50:39 +02001127 }
1128
1129 lysc_update_path(ctx_sc, NULL, "{identity}");
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001130 LY_ARRAY_CREATE_RET(ctx_sc->ctx, *identities, LY_ARRAY_COUNT(identities_p), LY_EMEM);
Michal Vasko33ff9422020-07-03 09:50:39 +02001131 LY_ARRAY_FOR(identities_p, u) {
1132 lysc_update_path(ctx_sc, NULL, identities_p[u].name);
1133
1134 LY_ARRAY_INCREMENT(*identities);
1135 COMPILE_CHECK_UNIQUENESS_ARRAY(ctx_sc, *identities, name, &(*identities)[offset + u], "identity", identities_p[u].name);
Radek Krejci011e4aa2020-09-04 15:22:31 +02001136 DUP_STRING_GOTO(ctx_sc->ctx, identities_p[u].name, (*identities)[offset + u].name, ret, done);
1137 DUP_STRING_GOTO(ctx_sc->ctx, identities_p[u].dsc, (*identities)[offset + u].dsc, ret, done);
1138 DUP_STRING_GOTO(ctx_sc->ctx, identities_p[u].ref, (*identities)[offset + u].ref, ret, done);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001139 (*identities)[offset + u].module = ctx_sc->cur_mod;
Michal Vasko33ff9422020-07-03 09:50:39 +02001140 COMPILE_ARRAY_GOTO(ctx_sc, identities_p[u].iffeatures, (*identities)[offset + u].iffeatures, v,
Michal Vasko69730152020-10-09 16:30:07 +02001141 lys_compile_iffeature, ret, done);
Michal Vasko33ff9422020-07-03 09:50:39 +02001142 /* backlinks (derived) can be added no sooner than when all the identities in the current module are present */
1143 COMPILE_EXTS_GOTO(ctx_sc, identities_p[u].exts, (*identities)[offset + u].exts, &(*identities)[offset + u],
Michal Vasko69730152020-10-09 16:30:07 +02001144 LYEXT_PAR_IDENT, ret, done);
Michal Vasko33ff9422020-07-03 09:50:39 +02001145 (*identities)[offset + u].flags = identities_p[u].flags;
1146
1147 lysc_update_path(ctx_sc, NULL, NULL);
1148 }
1149 lysc_update_path(ctx_sc, NULL, NULL);
Radek Krejci19a96102018-11-15 13:38:09 +01001150done:
1151 return ret;
1152}
1153
Radek Krejcib56c7502019-02-13 14:19:54 +01001154/**
1155 * @brief Check circular dependency of identities - identity MUST NOT reference itself (via their base statement).
1156 *
1157 * The function works in the same way as lys_compile_feature_circular_check() with different structures and error messages.
1158 *
1159 * @param[in] ctx Compile context for logging.
1160 * @param[in] ident The base identity (its derived list is being extended by the identity being currently processed).
1161 * @param[in] derived The list of derived identities of the identity being currently processed (not the one provided as @p ident)
1162 * @return LY_SUCCESS if everything is ok.
1163 * @return LY_EVALID if the identity is derived from itself.
1164 */
Radek Krejci38222632019-02-12 16:55:05 +01001165static LY_ERR
1166lys_compile_identity_circular_check(struct lysc_ctx *ctx, struct lysc_ident *ident, struct lysc_ident **derived)
1167{
Radek Krejciba03a5a2020-08-27 14:40:41 +02001168 LY_ERR ret = LY_SUCCESS;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001169 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci38222632019-02-12 16:55:05 +01001170 struct ly_set recursion = {0};
1171 struct lysc_ident *drv;
1172
1173 if (!derived) {
1174 return LY_SUCCESS;
1175 }
1176
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001177 for (u = 0; u < LY_ARRAY_COUNT(derived); ++u) {
Radek Krejci38222632019-02-12 16:55:05 +01001178 if (ident == derived[u]) {
1179 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02001180 "Identity \"%s\" is indirectly derived from itself.", ident->name);
Radek Krejciba03a5a2020-08-27 14:40:41 +02001181 ret = LY_EVALID;
Radek Krejci38222632019-02-12 16:55:05 +01001182 goto cleanup;
1183 }
Radek Krejciba03a5a2020-08-27 14:40:41 +02001184 ret = ly_set_add(&recursion, derived[u], 0, NULL);
1185 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci38222632019-02-12 16:55:05 +01001186 }
1187
1188 for (v = 0; v < recursion.count; ++v) {
1189 drv = recursion.objs[v];
1190 if (!drv->derived) {
1191 continue;
1192 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001193 for (u = 0; u < LY_ARRAY_COUNT(drv->derived); ++u) {
Radek Krejci38222632019-02-12 16:55:05 +01001194 if (ident == drv->derived[u]) {
1195 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02001196 "Identity \"%s\" is indirectly derived from itself.", ident->name);
Radek Krejciba03a5a2020-08-27 14:40:41 +02001197 ret = LY_EVALID;
Radek Krejci38222632019-02-12 16:55:05 +01001198 goto cleanup;
1199 }
Radek Krejciba03a5a2020-08-27 14:40:41 +02001200 ret = ly_set_add(&recursion, drv->derived[u], 0, NULL);
1201 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci38222632019-02-12 16:55:05 +01001202 }
1203 }
Radek Krejci38222632019-02-12 16:55:05 +01001204
1205cleanup:
1206 ly_set_erase(&recursion, NULL);
1207 return ret;
1208}
1209
Radek Krejcia3045382018-11-22 14:30:31 +01001210/**
1211 * @brief Find and process the referenced base identities from another identity or identityref
1212 *
Radek Krejciaca74032019-06-04 08:53:06 +02001213 * For bases in identity set backlinks to them from the base identities. For identityref, store
Radek Krejcia3045382018-11-22 14:30:31 +01001214 * the array of pointers to the base identities. So one of the ident or bases parameter must be set
1215 * to distinguish these two use cases.
1216 *
1217 * @param[in] ctx Compile context, not only for logging but also to get the current module to resolve prefixes.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001218 * @param[in] base_pmod Module where to resolve @p bases_p prefixes.
Radek Krejcia3045382018-11-22 14:30:31 +01001219 * @param[in] bases_p Array of names (including prefix if necessary) of base identities.
Michal Vasko33ff9422020-07-03 09:50:39 +02001220 * @param[in] ident Referencing identity to work with, NULL for identityref.
Radek Krejcia3045382018-11-22 14:30:31 +01001221 * @param[in] bases Array of bases of identityref to fill in.
1222 * @return LY_ERR value.
1223 */
Radek Krejci19a96102018-11-15 13:38:09 +01001224static LY_ERR
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001225lys_compile_identity_bases(struct lysc_ctx *ctx, const struct lysp_module *base_pmod, const char **bases_p,
Radek Krejci0f969882020-08-21 16:56:47 +02001226 struct lysc_ident *ident, struct lysc_ident ***bases)
Radek Krejci19a96102018-11-15 13:38:09 +01001227{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001228 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci19a96102018-11-15 13:38:09 +01001229 const char *s, *name;
Michal Vasko72619ce2020-10-06 14:05:32 +02001230 const struct lys_module *mod;
Radek Krejci80d281e2020-09-14 17:42:54 +02001231 struct lysc_ident **idref;
Radek Krejci555cb5b2018-11-16 14:54:33 +01001232
1233 assert(ident || bases);
1234
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001235 if ((LY_ARRAY_COUNT(bases_p) > 1) && (ctx->pmod->version < LYS_VERSION_1_1)) {
Radek Krejci555cb5b2018-11-16 14:54:33 +01001236 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001237 "Multiple bases in %s are allowed only in YANG 1.1 modules.", ident ? "identity" : "identityref type");
Radek Krejci555cb5b2018-11-16 14:54:33 +01001238 return LY_EVALID;
1239 }
1240
Michal Vasko33ff9422020-07-03 09:50:39 +02001241 LY_ARRAY_FOR(bases_p, u) {
Radek Krejci555cb5b2018-11-16 14:54:33 +01001242 s = strchr(bases_p[u], ':');
1243 if (s) {
1244 /* prefixed identity */
1245 name = &s[1];
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001246 mod = lysp_module_find_prefix(base_pmod, bases_p[u], s - bases_p[u]);
Radek Krejci555cb5b2018-11-16 14:54:33 +01001247 } else {
1248 name = bases_p[u];
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001249 mod = base_pmod->mod;
Radek Krejci555cb5b2018-11-16 14:54:33 +01001250 }
1251 if (!mod) {
1252 if (ident) {
1253 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001254 "Invalid prefix used for base (%s) of identity \"%s\".", bases_p[u], ident->name);
Radek Krejci555cb5b2018-11-16 14:54:33 +01001255 } else {
1256 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001257 "Invalid prefix used for base (%s) of identityref.", bases_p[u]);
Radek Krejci555cb5b2018-11-16 14:54:33 +01001258 }
1259 return LY_EVALID;
1260 }
Michal Vasko33ff9422020-07-03 09:50:39 +02001261
Radek Krejci555cb5b2018-11-16 14:54:33 +01001262 idref = NULL;
Radek Krejci80d281e2020-09-14 17:42:54 +02001263 LY_ARRAY_FOR(mod->identities, v) {
1264 if (!strcmp(name, mod->identities[v].name)) {
Michal Vasko33ff9422020-07-03 09:50:39 +02001265 if (ident) {
Radek Krejci80d281e2020-09-14 17:42:54 +02001266 if (ident == &mod->identities[v]) {
Michal Vasko33ff9422020-07-03 09:50:39 +02001267 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02001268 "Identity \"%s\" is derived from itself.", ident->name);
Michal Vasko33ff9422020-07-03 09:50:39 +02001269 return LY_EVALID;
Radek Krejci555cb5b2018-11-16 14:54:33 +01001270 }
Radek Krejci80d281e2020-09-14 17:42:54 +02001271 LY_CHECK_RET(lys_compile_identity_circular_check(ctx, &mod->identities[v], ident->derived));
Michal Vasko33ff9422020-07-03 09:50:39 +02001272 /* we have match! store the backlink */
Radek Krejci80d281e2020-09-14 17:42:54 +02001273 LY_ARRAY_NEW_RET(ctx->ctx, mod->identities[v].derived, idref, LY_EMEM);
Michal Vasko33ff9422020-07-03 09:50:39 +02001274 *idref = ident;
1275 } else {
1276 /* we have match! store the found identity */
1277 LY_ARRAY_NEW_RET(ctx->ctx, *bases, idref, LY_EMEM);
Radek Krejci80d281e2020-09-14 17:42:54 +02001278 *idref = &mod->identities[v];
Radek Krejci555cb5b2018-11-16 14:54:33 +01001279 }
Michal Vasko33ff9422020-07-03 09:50:39 +02001280 break;
Radek Krejci555cb5b2018-11-16 14:54:33 +01001281 }
1282 }
1283 if (!idref || !(*idref)) {
1284 if (ident) {
1285 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001286 "Unable to find base (%s) of identity \"%s\".", bases_p[u], ident->name);
Radek Krejci555cb5b2018-11-16 14:54:33 +01001287 } else {
1288 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001289 "Unable to find base (%s) of identityref.", bases_p[u]);
Radek Krejci555cb5b2018-11-16 14:54:33 +01001290 }
1291 return LY_EVALID;
1292 }
1293 }
1294 return LY_SUCCESS;
1295}
1296
Radek Krejcia3045382018-11-22 14:30:31 +01001297/**
1298 * @brief For the given array of identities, set the backlinks from all their base identities.
1299 * @param[in] ctx Compile context, not only for logging but also to get the current module to resolve prefixes.
1300 * @param[in] idents_p Array of identities definitions from the parsed schema structure.
1301 * @param[in] idents Array of referencing identities to which the backlinks are supposed to be set.
1302 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
1303 */
Radek Krejci555cb5b2018-11-16 14:54:33 +01001304static LY_ERR
1305lys_compile_identities_derived(struct lysc_ctx *ctx, struct lysp_ident *idents_p, struct lysc_ident *idents)
1306{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001307 LY_ARRAY_COUNT_TYPE u;
Radek Krejci19a96102018-11-15 13:38:09 +01001308
Michal Vasko33ff9422020-07-03 09:50:39 +02001309 lysc_update_path(ctx, NULL, "{identity}");
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001310 for (u = 0; u < LY_ARRAY_COUNT(idents_p); ++u) {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001311 if (!idents_p[u].bases) {
Radek Krejci19a96102018-11-15 13:38:09 +01001312 continue;
1313 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001314 lysc_update_path(ctx, NULL, idents[u].name);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001315 LY_CHECK_RET(lys_compile_identity_bases(ctx, idents[u].module->parsed, idents_p[u].bases, &idents[u], NULL));
Radek Krejci327de162019-06-14 12:52:07 +02001316 lysc_update_path(ctx, NULL, NULL);
Radek Krejci19a96102018-11-15 13:38:09 +01001317 }
Michal Vasko33ff9422020-07-03 09:50:39 +02001318 lysc_update_path(ctx, NULL, NULL);
Radek Krejci19a96102018-11-15 13:38:09 +01001319 return LY_SUCCESS;
1320}
1321
Radek Krejci0af46292019-01-11 16:02:31 +01001322LY_ERR
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001323lys_feature_precompile(struct lysc_ctx *ctx_sc, struct ly_ctx *ctx, struct lysp_module *parsed_mod,
Radek Krejci0f969882020-08-21 16:56:47 +02001324 struct lysp_feature *features_p, struct lysc_feature **features)
Radek Krejci0af46292019-01-11 16:02:31 +01001325{
Radek Krejci011e4aa2020-09-04 15:22:31 +02001326 LY_ERR ret = LY_SUCCESS;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001327 LY_ARRAY_COUNT_TYPE offset = 0, u;
Radek Krejci0af46292019-01-11 16:02:31 +01001328 struct lysc_ctx context = {0};
1329
Radek Krejci327de162019-06-14 12:52:07 +02001330 assert(ctx_sc || ctx);
1331
1332 if (!ctx_sc) {
1333 context.ctx = ctx;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001334 context.cur_mod = parsed_mod->mod;
1335 context.pmod = parsed_mod;
Radek Krejci327de162019-06-14 12:52:07 +02001336 context.path_len = 1;
1337 context.path[0] = '/';
1338 ctx_sc = &context;
1339 }
Radek Krejci0af46292019-01-11 16:02:31 +01001340
1341 if (!features_p) {
1342 return LY_SUCCESS;
1343 }
1344 if (*features) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001345 offset = LY_ARRAY_COUNT(*features);
Radek Krejci0af46292019-01-11 16:02:31 +01001346 }
1347
Radek Krejci327de162019-06-14 12:52:07 +02001348 lysc_update_path(ctx_sc, NULL, "{feature}");
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001349 LY_ARRAY_CREATE_RET(ctx_sc->ctx, *features, LY_ARRAY_COUNT(features_p), LY_EMEM);
Radek Krejci0af46292019-01-11 16:02:31 +01001350 LY_ARRAY_FOR(features_p, u) {
Radek Krejci327de162019-06-14 12:52:07 +02001351 lysc_update_path(ctx_sc, NULL, features_p[u].name);
1352
Radek Krejci0af46292019-01-11 16:02:31 +01001353 LY_ARRAY_INCREMENT(*features);
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001354 COMPILE_CHECK_UNIQUENESS_ARRAY(ctx_sc, *features, name, &(*features)[offset + u], "feature", features_p[u].name);
Radek Krejci011e4aa2020-09-04 15:22:31 +02001355 DUP_STRING_GOTO(ctx_sc->ctx, features_p[u].name, (*features)[offset + u].name, ret, done);
1356 DUP_STRING_GOTO(ctx_sc->ctx, features_p[u].dsc, (*features)[offset + u].dsc, ret, done);
1357 DUP_STRING_GOTO(ctx_sc->ctx, features_p[u].ref, (*features)[offset + u].ref, ret, done);
Radek Krejci0af46292019-01-11 16:02:31 +01001358 (*features)[offset + u].flags = features_p[u].flags;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001359 (*features)[offset + u].module = ctx_sc->cur_mod;
Radek Krejci327de162019-06-14 12:52:07 +02001360
1361 lysc_update_path(ctx_sc, NULL, NULL);
Radek Krejci0af46292019-01-11 16:02:31 +01001362 }
Radek Krejci327de162019-06-14 12:52:07 +02001363 lysc_update_path(ctx_sc, NULL, NULL);
Radek Krejci0af46292019-01-11 16:02:31 +01001364
Radek Krejci011e4aa2020-09-04 15:22:31 +02001365done:
1366 return ret;
Radek Krejci0af46292019-01-11 16:02:31 +01001367}
1368
Radek Krejcia3045382018-11-22 14:30:31 +01001369/**
Radek Krejci09a1fc52019-02-13 10:55:17 +01001370 * @brief Check circular dependency of features - feature MUST NOT reference itself (via their if-feature statement).
Radek Krejcib56c7502019-02-13 14:19:54 +01001371 *
1372 * The function works in the same way as lys_compile_identity_circular_check() with different structures and error messages.
1373 *
Radek Krejci09a1fc52019-02-13 10:55:17 +01001374 * @param[in] ctx Compile context for logging.
Radek Krejcib56c7502019-02-13 14:19:54 +01001375 * @param[in] feature The feature referenced in if-feature statement (its depfeatures list is being extended by the feature
1376 * being currently processed).
1377 * @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 +01001378 * @return LY_SUCCESS if everything is ok.
1379 * @return LY_EVALID if the feature references indirectly itself.
1380 */
1381static LY_ERR
1382lys_compile_feature_circular_check(struct lysc_ctx *ctx, struct lysc_feature *feature, struct lysc_feature **depfeatures)
1383{
Radek Krejciba03a5a2020-08-27 14:40:41 +02001384 LY_ERR ret = LY_SUCCESS;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001385 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci09a1fc52019-02-13 10:55:17 +01001386 struct ly_set recursion = {0};
1387 struct lysc_feature *drv;
1388
1389 if (!depfeatures) {
1390 return LY_SUCCESS;
1391 }
1392
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001393 for (u = 0; u < LY_ARRAY_COUNT(depfeatures); ++u) {
Radek Krejci09a1fc52019-02-13 10:55:17 +01001394 if (feature == depfeatures[u]) {
1395 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02001396 "Feature \"%s\" is indirectly referenced from itself.", feature->name);
Radek Krejciba03a5a2020-08-27 14:40:41 +02001397 ret = LY_EVALID;
Radek Krejci09a1fc52019-02-13 10:55:17 +01001398 goto cleanup;
1399 }
Radek Krejciba03a5a2020-08-27 14:40:41 +02001400 ret = ly_set_add(&recursion, depfeatures[u], 0, NULL);
1401 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci09a1fc52019-02-13 10:55:17 +01001402 }
1403
1404 for (v = 0; v < recursion.count; ++v) {
1405 drv = recursion.objs[v];
1406 if (!drv->depfeatures) {
1407 continue;
1408 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001409 for (u = 0; u < LY_ARRAY_COUNT(drv->depfeatures); ++u) {
Radek Krejci09a1fc52019-02-13 10:55:17 +01001410 if (feature == drv->depfeatures[u]) {
1411 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02001412 "Feature \"%s\" is indirectly referenced from itself.", feature->name);
Radek Krejciba03a5a2020-08-27 14:40:41 +02001413 ret = LY_EVALID;
Radek Krejci09a1fc52019-02-13 10:55:17 +01001414 goto cleanup;
1415 }
Radek Krejciba03a5a2020-08-27 14:40:41 +02001416 ly_set_add(&recursion, drv->depfeatures[u], 0, NULL);
1417 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci09a1fc52019-02-13 10:55:17 +01001418 }
1419 }
Radek Krejci09a1fc52019-02-13 10:55:17 +01001420
1421cleanup:
1422 ly_set_erase(&recursion, NULL);
1423 return ret;
1424}
1425
1426/**
Radek Krejci0af46292019-01-11 16:02:31 +01001427 * @brief Create pre-compiled features array.
1428 *
1429 * See lys_feature_precompile() for more details.
1430 *
Radek Krejcia3045382018-11-22 14:30:31 +01001431 * @param[in] ctx Compile context.
1432 * @param[in] feature_p Parsed feature definition to compile.
Radek Krejci0af46292019-01-11 16:02:31 +01001433 * @param[in,out] features List of already (pre)compiled features to find the corresponding precompiled feature structure.
Radek Krejcia3045382018-11-22 14:30:31 +01001434 * @return LY_ERR value.
1435 */
Radek Krejci19a96102018-11-15 13:38:09 +01001436static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02001437lys_feature_precompile_finish(struct lysc_ctx *ctx, struct lysp_feature *feature_p, struct lysc_feature *features)
Radek Krejci19a96102018-11-15 13:38:09 +01001438{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001439 LY_ARRAY_COUNT_TYPE u, v, x;
Radek Krejci0af46292019-01-11 16:02:31 +01001440 struct lysc_feature *feature, **df;
Radek Krejci19a96102018-11-15 13:38:09 +01001441 LY_ERR ret = LY_SUCCESS;
Radek Krejci19a96102018-11-15 13:38:09 +01001442
Radek Krejci0af46292019-01-11 16:02:31 +01001443 /* find the preprecompiled feature */
1444 LY_ARRAY_FOR(features, x) {
1445 if (strcmp(features[x].name, feature_p->name)) {
1446 continue;
1447 }
1448 feature = &features[x];
Radek Krejci327de162019-06-14 12:52:07 +02001449 lysc_update_path(ctx, NULL, "{feature}");
1450 lysc_update_path(ctx, NULL, feature_p->name);
Radek Krejci19a96102018-11-15 13:38:09 +01001451
Radek Krejci0af46292019-01-11 16:02:31 +01001452 /* finish compilation started in lys_feature_precompile() */
Radek Krejci0935f412019-08-20 16:15:18 +02001453 COMPILE_EXTS_GOTO(ctx, feature_p->exts, feature->exts, feature, LYEXT_PAR_FEATURE, ret, done);
Radek Krejciec4da802019-05-02 13:02:41 +02001454 COMPILE_ARRAY_GOTO(ctx, feature_p->iffeatures, feature->iffeatures, u, lys_compile_iffeature, ret, done);
Radek Krejci0af46292019-01-11 16:02:31 +01001455 if (feature->iffeatures) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001456 for (u = 0; u < LY_ARRAY_COUNT(feature->iffeatures); ++u) {
Radek Krejci0af46292019-01-11 16:02:31 +01001457 if (feature->iffeatures[u].features) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001458 for (v = 0; v < LY_ARRAY_COUNT(feature->iffeatures[u].features); ++v) {
Radek Krejci09a1fc52019-02-13 10:55:17 +01001459 /* check for circular dependency - direct reference first,... */
1460 if (feature == feature->iffeatures[u].features[v]) {
1461 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02001462 "Feature \"%s\" is referenced from itself.", feature->name);
Radek Krejci09a1fc52019-02-13 10:55:17 +01001463 return LY_EVALID;
1464 }
1465 /* ... and indirect circular reference */
1466 LY_CHECK_RET(lys_compile_feature_circular_check(ctx, feature->iffeatures[u].features[v], feature->depfeatures));
1467
Radek Krejci0af46292019-01-11 16:02:31 +01001468 /* add itself into the dependants list */
1469 LY_ARRAY_NEW_RET(ctx->ctx, feature->iffeatures[u].features[v]->depfeatures, df, LY_EMEM);
1470 *df = feature;
1471 }
Radek Krejci19a96102018-11-15 13:38:09 +01001472 }
Radek Krejci19a96102018-11-15 13:38:09 +01001473 }
1474 }
Radek Krejci327de162019-06-14 12:52:07 +02001475 lysc_update_path(ctx, NULL, NULL);
1476 lysc_update_path(ctx, NULL, NULL);
Michal Vasko69730152020-10-09 16:30:07 +02001477done:
Radek Krejci0af46292019-01-11 16:02:31 +01001478 return ret;
Radek Krejci19a96102018-11-15 13:38:09 +01001479 }
Radek Krejci0af46292019-01-11 16:02:31 +01001480
1481 LOGINT(ctx->ctx);
1482 return LY_EINT;
Radek Krejci19a96102018-11-15 13:38:09 +01001483}
1484
Radek Krejcib56c7502019-02-13 14:19:54 +01001485/**
1486 * @brief Revert compiled list of features back to the precompiled state.
1487 *
1488 * 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 +01001489 *
1490 * @param[in] ctx Compilation context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02001491 * @param[in] mod The module structure with the features to decompile.
Radek Krejcib56c7502019-02-13 14:19:54 +01001492 */
Radek Krejci95710c92019-02-11 15:49:55 +01001493static void
1494lys_feature_precompile_revert(struct lysc_ctx *ctx, struct lys_module *mod)
1495{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001496 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci95710c92019-02-11 15:49:55 +01001497
Michal Vasko33ff9422020-07-03 09:50:39 +02001498 /* in the dis_features list, remove all the parts (from finished compiling process)
Radek Krejci95710c92019-02-11 15:49:55 +01001499 * which may points into the data being freed here */
Radek Krejci14915cc2020-09-14 17:28:13 +02001500 LY_ARRAY_FOR(mod->features, u) {
1501 LY_ARRAY_FOR(mod->features[u].iffeatures, v) {
1502 lysc_iffeature_free(ctx->ctx, &mod->features[u].iffeatures[v]);
Radek Krejci95710c92019-02-11 15:49:55 +01001503 }
Radek Krejci14915cc2020-09-14 17:28:13 +02001504 LY_ARRAY_FREE(mod->features[u].iffeatures);
1505 mod->features[u].iffeatures = NULL;
Radek Krejci95710c92019-02-11 15:49:55 +01001506
Radek Krejci14915cc2020-09-14 17:28:13 +02001507 LY_ARRAY_FOR(mod->features[u].exts, v) {
1508 lysc_ext_instance_free(ctx->ctx, &(mod->features[u].exts)[v]);
Radek Krejci95710c92019-02-11 15:49:55 +01001509 }
Radek Krejci14915cc2020-09-14 17:28:13 +02001510 LY_ARRAY_FREE(mod->features[u].exts);
1511 mod->features[u].exts = NULL;
Radek Krejci95710c92019-02-11 15:49:55 +01001512 }
1513}
1514
Radek Krejcia3045382018-11-22 14:30:31 +01001515/**
1516 * @brief Validate and normalize numeric value from a range definition.
1517 * @param[in] ctx Compile context.
1518 * @param[in] basetype Base YANG built-in type of the node connected with the range restriction. Actually only LY_TYPE_DEC64 is important to
1519 * allow processing of the fractions. The fraction point is extracted from the value which is then normalize according to given frdigits into
1520 * valcopy to allow easy parsing and storing of the value. libyang stores decimal number without the decimal point which is always recovered from
1521 * the known fraction-digits value. So, with fraction-digits 2, number 3.14 is stored as 314 and number 1 is stored as 100.
1522 * @param[in] frdigits The fraction-digits of the type in case of LY_TYPE_DEC64.
1523 * @param[in] value String value of the range boundary.
1524 * @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.
1525 * @param[out] valcopy NULL-terminated string with the numeric value to parse and store.
1526 * @return LY_ERR value - LY_SUCCESS, LY_EMEM, LY_EVALID (no number) or LY_EINVAL (decimal64 not matching fraction-digits value).
1527 */
Radek Krejcie88beef2019-05-30 15:47:19 +02001528LY_ERR
Radek Krejci6cba4292018-11-15 17:33:29 +01001529range_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 +01001530{
Radek Krejci6cba4292018-11-15 17:33:29 +01001531 size_t fraction = 0, size;
1532
Radek Krejci19a96102018-11-15 13:38:09 +01001533 *len = 0;
1534
1535 assert(value);
1536 /* parse value */
1537 if (!isdigit(value[*len]) && (value[*len] != '-') && (value[*len] != '+')) {
1538 return LY_EVALID;
1539 }
1540
1541 if ((value[*len] == '-') || (value[*len] == '+')) {
1542 ++(*len);
1543 }
1544
1545 while (isdigit(value[*len])) {
1546 ++(*len);
1547 }
1548
1549 if ((basetype != LY_TYPE_DEC64) || (value[*len] != '.') || !isdigit(value[*len + 1])) {
Radek Krejci6cba4292018-11-15 17:33:29 +01001550 if (basetype == LY_TYPE_DEC64) {
1551 goto decimal;
1552 } else {
1553 *valcopy = strndup(value, *len);
1554 return LY_SUCCESS;
1555 }
Radek Krejci19a96102018-11-15 13:38:09 +01001556 }
1557 fraction = *len;
1558
1559 ++(*len);
1560 while (isdigit(value[*len])) {
1561 ++(*len);
1562 }
1563
Radek Krejci6cba4292018-11-15 17:33:29 +01001564 if (basetype == LY_TYPE_DEC64) {
1565decimal:
1566 assert(frdigits);
Radek Krejci943177f2019-06-14 16:32:43 +02001567 if (fraction && (*len - 1 - fraction > frdigits)) {
Radek Krejci6cba4292018-11-15 17:33:29 +01001568 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001569 "Range boundary \"%.*s\" of decimal64 type exceeds defined number (%u) of fraction digits.",
1570 *len, value, frdigits);
Radek Krejci6cba4292018-11-15 17:33:29 +01001571 return LY_EINVAL;
1572 }
1573 if (fraction) {
1574 size = (*len) + (frdigits - ((*len) - 1 - fraction));
1575 } else {
1576 size = (*len) + frdigits + 1;
1577 }
1578 *valcopy = malloc(size * sizeof **valcopy);
Radek Krejci19a96102018-11-15 13:38:09 +01001579 LY_CHECK_ERR_RET(!(*valcopy), LOGMEM(ctx->ctx), LY_EMEM);
1580
Radek Krejci6cba4292018-11-15 17:33:29 +01001581 (*valcopy)[size - 1] = '\0';
1582 if (fraction) {
1583 memcpy(&(*valcopy)[0], &value[0], fraction);
1584 memcpy(&(*valcopy)[fraction], &value[fraction + 1], (*len) - 1 - (fraction));
1585 memset(&(*valcopy)[(*len) - 1], '0', frdigits - ((*len) - 1 - fraction));
1586 } else {
1587 memcpy(&(*valcopy)[0], &value[0], *len);
1588 memset(&(*valcopy)[*len], '0', frdigits);
1589 }
Radek Krejci19a96102018-11-15 13:38:09 +01001590 }
1591 return LY_SUCCESS;
1592}
1593
Radek Krejcia3045382018-11-22 14:30:31 +01001594/**
1595 * @brief Check that values in range are in ascendant order.
1596 * @param[in] unsigned_value Flag to note that we are working with unsigned values.
Radek Krejci5969f272018-11-23 10:03:58 +01001597 * @param[in] max Flag to distinguish if checking min or max value. min value must be strictly higher than previous,
1598 * max can be also equal.
Radek Krejcia3045382018-11-22 14:30:31 +01001599 * @param[in] value Current value to check.
1600 * @param[in] prev_value The last seen value.
1601 * @return LY_SUCCESS or LY_EEXIST for invalid order.
1602 */
Radek Krejci19a96102018-11-15 13:38:09 +01001603static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02001604range_part_check_ascendancy(ly_bool unsigned_value, ly_bool max, int64_t value, int64_t prev_value)
Radek Krejci19a96102018-11-15 13:38:09 +01001605{
1606 if (unsigned_value) {
Michal Vasko69730152020-10-09 16:30:07 +02001607 if ((max && ((uint64_t)prev_value > (uint64_t)value)) || (!max && ((uint64_t)prev_value >= (uint64_t)value))) {
Radek Krejci19a96102018-11-15 13:38:09 +01001608 return LY_EEXIST;
1609 }
1610 } else {
Michal Vasko69730152020-10-09 16:30:07 +02001611 if ((max && (prev_value > value)) || (!max && (prev_value >= value))) {
Radek Krejci19a96102018-11-15 13:38:09 +01001612 return LY_EEXIST;
1613 }
1614 }
1615 return LY_SUCCESS;
1616}
1617
Radek Krejcia3045382018-11-22 14:30:31 +01001618/**
1619 * @brief Set min/max value of the range part.
1620 * @param[in] ctx Compile context.
1621 * @param[in] part Range part structure to fill.
1622 * @param[in] max Flag to distinguish if storing min or max value.
1623 * @param[in] prev The last seen value to check that all values in range are specified in ascendant order.
1624 * @param[in] basetype Type of the value to get know implicit min/max values and other checking rules.
1625 * @param[in] first Flag for the first value of the range to avoid ascendancy order.
1626 * @param[in] length_restr Flag to distinguish between range and length restrictions. Only for logging.
1627 * @param[in] frdigits The fraction-digits value in case of LY_TYPE_DEC64 basetype.
Radek Krejci5969f272018-11-23 10:03:58 +01001628 * @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 +01001629 * @param[in,out] value Numeric range value to be stored, if not provided the type's min/max value is set.
1630 * @return LY_ERR value - LY_SUCCESS, LY_EDENIED (value brokes type's boundaries), LY_EVALID (not a number),
1631 * LY_EEXIST (value is smaller than the previous one), LY_EINVAL (decimal64 value does not corresponds with the
1632 * frdigits value), LY_EMEM.
1633 */
Radek Krejci19a96102018-11-15 13:38:09 +01001634static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02001635range_part_minmax(struct lysc_ctx *ctx, struct lysc_range_part *part, ly_bool max, int64_t prev, LY_DATA_TYPE basetype,
1636 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 +01001637{
1638 LY_ERR ret = LY_SUCCESS;
1639 char *valcopy = NULL;
1640 size_t len;
1641
1642 if (value) {
Radek Krejci6cba4292018-11-15 17:33:29 +01001643 ret = range_part_check_value_syntax(ctx, basetype, frdigits, *value, &len, &valcopy);
Radek Krejci5969f272018-11-23 10:03:58 +01001644 LY_CHECK_GOTO(ret, finalize);
1645 }
1646 if (!valcopy && base_range) {
1647 if (max) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001648 part->max_64 = base_range->parts[LY_ARRAY_COUNT(base_range->parts) - 1].max_64;
Radek Krejci5969f272018-11-23 10:03:58 +01001649 } else {
1650 part->min_64 = base_range->parts[0].min_64;
1651 }
1652 if (!first) {
1653 ret = range_part_check_ascendancy(basetype <= LY_TYPE_STRING ? 1 : 0, max, max ? part->max_64 : part->min_64, prev);
1654 }
1655 goto finalize;
Radek Krejci19a96102018-11-15 13:38:09 +01001656 }
1657
1658 switch (basetype) {
Radek Krejci19a96102018-11-15 13:38:09 +01001659 case LY_TYPE_INT8: /* range */
1660 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001661 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 +01001662 } else if (max) {
1663 part->max_64 = INT64_C(127);
1664 } else {
1665 part->min_64 = INT64_C(-128);
1666 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001667 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001668 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001669 }
1670 break;
1671 case LY_TYPE_INT16: /* range */
1672 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001673 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 +01001674 } else if (max) {
1675 part->max_64 = INT64_C(32767);
1676 } else {
1677 part->min_64 = INT64_C(-32768);
1678 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001679 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001680 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001681 }
1682 break;
1683 case LY_TYPE_INT32: /* range */
1684 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001685 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 +01001686 } else if (max) {
1687 part->max_64 = INT64_C(2147483647);
1688 } else {
1689 part->min_64 = INT64_C(-2147483648);
1690 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001691 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001692 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001693 }
1694 break;
1695 case LY_TYPE_INT64: /* range */
Radek Krejci25cfef72018-11-23 14:15:52 +01001696 case LY_TYPE_DEC64: /* range */
Radek Krejci19a96102018-11-15 13:38:09 +01001697 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001698 ret = ly_parse_int(valcopy, strlen(valcopy), INT64_C(-9223372036854775807) - INT64_C(1), INT64_C(9223372036854775807), 10,
Michal Vasko69730152020-10-09 16:30:07 +02001699 max ? &part->max_64 : &part->min_64);
Radek Krejci19a96102018-11-15 13:38:09 +01001700 } else if (max) {
1701 part->max_64 = INT64_C(9223372036854775807);
1702 } else {
1703 part->min_64 = INT64_C(-9223372036854775807) - INT64_C(1);
1704 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001705 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001706 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001707 }
1708 break;
1709 case LY_TYPE_UINT8: /* range */
1710 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001711 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 +01001712 } else if (max) {
1713 part->max_u64 = UINT64_C(255);
1714 } else {
1715 part->min_u64 = UINT64_C(0);
1716 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001717 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001718 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001719 }
1720 break;
1721 case LY_TYPE_UINT16: /* range */
1722 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001723 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 +01001724 } else if (max) {
1725 part->max_u64 = UINT64_C(65535);
1726 } else {
1727 part->min_u64 = UINT64_C(0);
1728 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001729 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001730 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001731 }
1732 break;
1733 case LY_TYPE_UINT32: /* range */
1734 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001735 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 +01001736 } else if (max) {
1737 part->max_u64 = UINT64_C(4294967295);
1738 } else {
1739 part->min_u64 = UINT64_C(0);
1740 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001741 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001742 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001743 }
1744 break;
1745 case LY_TYPE_UINT64: /* range */
Radek Krejci19a96102018-11-15 13:38:09 +01001746 case LY_TYPE_STRING: /* length */
Radek Krejci25cfef72018-11-23 14:15:52 +01001747 case LY_TYPE_BINARY: /* length */
Radek Krejci19a96102018-11-15 13:38:09 +01001748 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001749 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 +01001750 } else if (max) {
1751 part->max_u64 = UINT64_C(18446744073709551615);
1752 } else {
1753 part->min_u64 = UINT64_C(0);
1754 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001755 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001756 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001757 }
1758 break;
1759 default:
1760 LOGINT(ctx->ctx);
1761 ret = LY_EINT;
1762 }
1763
Radek Krejci5969f272018-11-23 10:03:58 +01001764finalize:
Radek Krejci19a96102018-11-15 13:38:09 +01001765 if (ret == LY_EDENIED) {
1766 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001767 "Invalid %s restriction - value \"%s\" does not fit the type limitations.",
1768 length_restr ? "length" : "range", valcopy ? valcopy : *value);
Radek Krejci19a96102018-11-15 13:38:09 +01001769 } else if (ret == LY_EVALID) {
1770 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001771 "Invalid %s restriction - invalid value \"%s\".",
1772 length_restr ? "length" : "range", valcopy ? valcopy : *value);
Radek Krejci19a96102018-11-15 13:38:09 +01001773 } else if (ret == LY_EEXIST) {
1774 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001775 "Invalid %s restriction - values are not in ascending order (%s).",
1776 length_restr ? "length" : "range",
Radek Krejci0f969882020-08-21 16:56:47 +02001777 (valcopy && basetype != LY_TYPE_DEC64) ? valcopy : value ? *value : max ? "max" : "min");
Radek Krejci19a96102018-11-15 13:38:09 +01001778 } else if (!ret && value) {
1779 *value = *value + len;
1780 }
1781 free(valcopy);
1782 return ret;
1783}
1784
Radek Krejcia3045382018-11-22 14:30:31 +01001785/**
1786 * @brief Compile the parsed range restriction.
1787 * @param[in] ctx Compile context.
1788 * @param[in] range_p Parsed range structure to compile.
1789 * @param[in] basetype Base YANG built-in type of the node with the range restriction.
1790 * @param[in] length_restr Flag to distinguish between range and length restrictions. Only for logging.
1791 * @param[in] frdigits The fraction-digits value in case of LY_TYPE_DEC64 basetype.
1792 * @param[in] base_range Range restriction of the type from which the current type is derived. The current
1793 * range restriction must be more restrictive than the base_range.
1794 * @param[in,out] range Pointer to the created current range structure.
1795 * @return LY_ERR value.
1796 */
Radek Krejci19a96102018-11-15 13:38:09 +01001797static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02001798lys_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 +02001799 uint8_t frdigits, struct lysc_range *base_range, struct lysc_range **range)
Radek Krejci19a96102018-11-15 13:38:09 +01001800{
1801 LY_ERR ret = LY_EVALID;
1802 const char *expr;
1803 struct lysc_range_part *parts = NULL, *part;
Radek Krejci857189e2020-09-01 13:26:36 +02001804 ly_bool range_expected = 0, uns;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001805 LY_ARRAY_COUNT_TYPE parts_done = 0, u, v;
Radek Krejci19a96102018-11-15 13:38:09 +01001806
1807 assert(range);
1808 assert(range_p);
1809
Michal Vasko7f45cf22020-10-01 12:49:44 +02001810 expr = range_p->arg.str;
Michal Vaskod989ba02020-08-24 10:59:24 +02001811 while (1) {
Radek Krejci19a96102018-11-15 13:38:09 +01001812 if (isspace(*expr)) {
1813 ++expr;
1814 } else if (*expr == '\0') {
1815 if (range_expected) {
1816 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001817 "Invalid %s restriction - unexpected end of the expression after \"..\" (%s).",
1818 length_restr ? "length" : "range", range_p->arg);
Radek Krejci19a96102018-11-15 13:38:09 +01001819 goto cleanup;
Michal Vasko69730152020-10-09 16:30:07 +02001820 } else if (!parts || (parts_done == LY_ARRAY_COUNT(parts))) {
Radek Krejci19a96102018-11-15 13:38:09 +01001821 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001822 "Invalid %s restriction - unexpected end of the expression (%s).",
1823 length_restr ? "length" : "range", range_p->arg);
Radek Krejci19a96102018-11-15 13:38:09 +01001824 goto cleanup;
1825 }
1826 parts_done++;
1827 break;
1828 } else if (!strncmp(expr, "min", 3)) {
1829 if (parts) {
1830 /* min cannot be used elsewhere than in the first part */
1831 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001832 "Invalid %s restriction - unexpected data before min keyword (%.*s).", length_restr ? "length" : "range",
1833 expr - range_p->arg.str, range_p->arg.str);
Radek Krejci19a96102018-11-15 13:38:09 +01001834 goto cleanup;
1835 }
1836 expr += 3;
1837
1838 LY_ARRAY_NEW_GOTO(ctx->ctx, parts, part, ret, cleanup);
Radek Krejci5969f272018-11-23 10:03:58 +01001839 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 +01001840 part->max_64 = part->min_64;
1841 } else if (*expr == '|') {
1842 if (!parts || range_expected) {
1843 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001844 "Invalid %s restriction - unexpected beginning of the expression (%s).", length_restr ? "length" : "range", expr);
Radek Krejci19a96102018-11-15 13:38:09 +01001845 goto cleanup;
1846 }
1847 expr++;
1848 parts_done++;
1849 /* process next part of the expression */
1850 } else if (!strncmp(expr, "..", 2)) {
1851 expr += 2;
1852 while (isspace(*expr)) {
1853 expr++;
1854 }
Michal Vasko69730152020-10-09 16:30:07 +02001855 if (!parts || (LY_ARRAY_COUNT(parts) == parts_done)) {
Radek Krejci19a96102018-11-15 13:38:09 +01001856 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001857 "Invalid %s restriction - unexpected \"..\" without a lower bound.", length_restr ? "length" : "range");
Radek Krejci19a96102018-11-15 13:38:09 +01001858 goto cleanup;
1859 }
1860 /* continue expecting the upper boundary */
1861 range_expected = 1;
1862 } else if (isdigit(*expr) || (*expr == '-') || (*expr == '+')) {
1863 /* number */
1864 if (range_expected) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001865 part = &parts[LY_ARRAY_COUNT(parts) - 1];
Radek Krejci5969f272018-11-23 10:03:58 +01001866 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 +01001867 range_expected = 0;
1868 } else {
1869 LY_ARRAY_NEW_GOTO(ctx->ctx, parts, part, ret, cleanup);
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001870 LY_CHECK_GOTO(range_part_minmax(ctx, part, 0, parts_done ? parts[LY_ARRAY_COUNT(parts) - 2].max_64 : 0,
Michal Vasko69730152020-10-09 16:30:07 +02001871 basetype, parts_done ? 0 : 1, length_restr, frdigits, NULL, &expr), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01001872 part->max_64 = part->min_64;
1873 }
1874
1875 /* continue with possible another expression part */
1876 } else if (!strncmp(expr, "max", 3)) {
1877 expr += 3;
1878 while (isspace(*expr)) {
1879 expr++;
1880 }
1881 if (*expr != '\0') {
1882 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid %s restriction - unexpected data after max keyword (%s).",
Michal Vasko69730152020-10-09 16:30:07 +02001883 length_restr ? "length" : "range", expr);
Radek Krejci19a96102018-11-15 13:38:09 +01001884 goto cleanup;
1885 }
1886 if (range_expected) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001887 part = &parts[LY_ARRAY_COUNT(parts) - 1];
Radek Krejci5969f272018-11-23 10:03:58 +01001888 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 +01001889 range_expected = 0;
1890 } else {
1891 LY_ARRAY_NEW_GOTO(ctx->ctx, parts, part, ret, cleanup);
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001892 LY_CHECK_GOTO(range_part_minmax(ctx, part, 1, parts_done ? parts[LY_ARRAY_COUNT(parts) - 2].max_64 : 0,
Michal Vasko69730152020-10-09 16:30:07 +02001893 basetype, parts_done ? 0 : 1, length_restr, frdigits, base_range, NULL), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01001894 part->min_64 = part->max_64;
1895 }
1896 } else {
1897 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid %s restriction - unexpected data (%s).",
Michal Vasko69730152020-10-09 16:30:07 +02001898 length_restr ? "length" : "range", expr);
Radek Krejci19a96102018-11-15 13:38:09 +01001899 goto cleanup;
1900 }
1901 }
1902
1903 /* check with the previous range/length restriction */
1904 if (base_range) {
1905 switch (basetype) {
1906 case LY_TYPE_BINARY:
1907 case LY_TYPE_UINT8:
1908 case LY_TYPE_UINT16:
1909 case LY_TYPE_UINT32:
1910 case LY_TYPE_UINT64:
1911 case LY_TYPE_STRING:
1912 uns = 1;
1913 break;
1914 case LY_TYPE_DEC64:
1915 case LY_TYPE_INT8:
1916 case LY_TYPE_INT16:
1917 case LY_TYPE_INT32:
1918 case LY_TYPE_INT64:
1919 uns = 0;
1920 break;
1921 default:
1922 LOGINT(ctx->ctx);
1923 ret = LY_EINT;
1924 goto cleanup;
1925 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001926 for (u = v = 0; u < parts_done && v < LY_ARRAY_COUNT(base_range->parts); ++u) {
Michal Vasko69730152020-10-09 16:30:07 +02001927 if ((uns && (parts[u].min_u64 < base_range->parts[v].min_u64)) || (!uns && (parts[u].min_64 < base_range->parts[v].min_64))) {
Radek Krejci19a96102018-11-15 13:38:09 +01001928 goto baseerror;
1929 }
1930 /* current lower bound is not lower than the base */
1931 if (base_range->parts[v].min_64 == base_range->parts[v].max_64) {
1932 /* base has single value */
1933 if (base_range->parts[v].min_64 == parts[u].min_64) {
1934 /* both lower bounds are the same */
1935 if (parts[u].min_64 != parts[u].max_64) {
1936 /* current continues with a range */
1937 goto baseerror;
1938 } else {
1939 /* equal single values, move both forward */
1940 ++v;
1941 continue;
1942 }
1943 } else {
1944 /* base is single value lower than current range, so the
1945 * value from base range is removed in the current,
1946 * move only base and repeat checking */
1947 ++v;
1948 --u;
1949 continue;
1950 }
1951 } else {
1952 /* base is the range */
1953 if (parts[u].min_64 == parts[u].max_64) {
1954 /* current is a single value */
Michal Vasko69730152020-10-09 16:30:07 +02001955 if ((uns && (parts[u].max_u64 > base_range->parts[v].max_u64)) || (!uns && (parts[u].max_64 > base_range->parts[v].max_64))) {
Radek Krejci19a96102018-11-15 13:38:09 +01001956 /* current is behind the base range, so base range is omitted,
1957 * move the base and keep the current for further check */
1958 ++v;
1959 --u;
1960 } /* else it is within the base range, so move the current, but keep the base */
1961 continue;
1962 } else {
1963 /* both are ranges - check the higher bound, the lower was already checked */
Michal Vasko69730152020-10-09 16:30:07 +02001964 if ((uns && (parts[u].max_u64 > base_range->parts[v].max_u64)) || (!uns && (parts[u].max_64 > base_range->parts[v].max_64))) {
Radek Krejci19a96102018-11-15 13:38:09 +01001965 /* higher bound is higher than the current higher bound */
Michal Vasko69730152020-10-09 16:30:07 +02001966 if ((uns && (parts[u].min_u64 > base_range->parts[v].max_u64)) || (!uns && (parts[u].min_64 > base_range->parts[v].max_64))) {
Radek Krejci19a96102018-11-15 13:38:09 +01001967 /* but the current lower bound is also higher, so the base range is omitted,
1968 * continue with the same current, but move the base */
1969 --u;
1970 ++v;
1971 continue;
1972 }
1973 /* current range starts within the base range but end behind it */
1974 goto baseerror;
1975 } else {
1976 /* current range is smaller than the base,
1977 * move current, but stay with the base */
1978 continue;
1979 }
1980 }
1981 }
1982 }
1983 if (u != parts_done) {
1984baseerror:
1985 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001986 "Invalid %s restriction - the derived restriction (%s) is not equally or more limiting.",
1987 length_restr ? "length" : "range", range_p->arg);
Radek Krejci19a96102018-11-15 13:38:09 +01001988 goto cleanup;
1989 }
1990 }
1991
1992 if (!(*range)) {
1993 *range = calloc(1, sizeof **range);
1994 LY_CHECK_ERR_RET(!(*range), LOGMEM(ctx->ctx), LY_EMEM);
1995 }
1996
Radek Krejcic8b31002019-01-08 10:24:45 +01001997 /* we rewrite the following values as the types chain is being processed */
Radek Krejci19a96102018-11-15 13:38:09 +01001998 if (range_p->eapptag) {
1999 lydict_remove(ctx->ctx, (*range)->eapptag);
Radek Krejci011e4aa2020-09-04 15:22:31 +02002000 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->eapptag, 0, &(*range)->eapptag), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01002001 }
2002 if (range_p->emsg) {
2003 lydict_remove(ctx->ctx, (*range)->emsg);
Radek Krejci011e4aa2020-09-04 15:22:31 +02002004 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->emsg, 0, &(*range)->emsg), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01002005 }
Radek Krejcic8b31002019-01-08 10:24:45 +01002006 if (range_p->dsc) {
2007 lydict_remove(ctx->ctx, (*range)->dsc);
Radek Krejci011e4aa2020-09-04 15:22:31 +02002008 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->dsc, 0, &(*range)->dsc), cleanup);
Radek Krejcic8b31002019-01-08 10:24:45 +01002009 }
2010 if (range_p->ref) {
2011 lydict_remove(ctx->ctx, (*range)->ref);
Radek Krejci011e4aa2020-09-04 15:22:31 +02002012 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->ref, 0, &(*range)->ref), cleanup);
Radek Krejcic8b31002019-01-08 10:24:45 +01002013 }
Radek Krejci19a96102018-11-15 13:38:09 +01002014 /* extensions are taken only from the last range by the caller */
2015
2016 (*range)->parts = parts;
2017 parts = NULL;
2018 ret = LY_SUCCESS;
2019cleanup:
Radek Krejci19a96102018-11-15 13:38:09 +01002020 LY_ARRAY_FREE(parts);
2021
2022 return ret;
2023}
2024
2025/**
2026 * @brief Checks pattern syntax.
2027 *
Michal Vasko03ff5a72019-09-11 13:49:33 +02002028 * @param[in] ctx Context.
2029 * @param[in] log_path Path for logging errors.
Radek Krejci19a96102018-11-15 13:38:09 +01002030 * @param[in] pattern Pattern to check.
Radek Krejci54579462019-04-30 12:47:06 +02002031 * @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 +01002032 * @return LY_ERR value - LY_SUCCESS, LY_EMEM, LY_EVALID.
Radek Krejci19a96102018-11-15 13:38:09 +01002033 */
Michal Vasko03ff5a72019-09-11 13:49:33 +02002034LY_ERR
2035lys_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 +01002036{
Radek Krejci1deb5be2020-08-26 16:43:36 +02002037 size_t idx, idx2, start, end, size, brack;
Radek Krejci19a96102018-11-15 13:38:09 +01002038 char *perl_regex, *ptr;
Radek Krejci54579462019-04-30 12:47:06 +02002039 int err_code;
2040 const char *orig_ptr;
2041 PCRE2_SIZE err_offset;
2042 pcre2_code *code_local;
Michal Vasko69730152020-10-09 16:30:07 +02002043
Radek Krejci19a96102018-11-15 13:38:09 +01002044#define URANGE_LEN 19
2045 char *ublock2urange[][2] = {
2046 {"BasicLatin", "[\\x{0000}-\\x{007F}]"},
2047 {"Latin-1Supplement", "[\\x{0080}-\\x{00FF}]"},
2048 {"LatinExtended-A", "[\\x{0100}-\\x{017F}]"},
2049 {"LatinExtended-B", "[\\x{0180}-\\x{024F}]"},
2050 {"IPAExtensions", "[\\x{0250}-\\x{02AF}]"},
2051 {"SpacingModifierLetters", "[\\x{02B0}-\\x{02FF}]"},
2052 {"CombiningDiacriticalMarks", "[\\x{0300}-\\x{036F}]"},
2053 {"Greek", "[\\x{0370}-\\x{03FF}]"},
2054 {"Cyrillic", "[\\x{0400}-\\x{04FF}]"},
2055 {"Armenian", "[\\x{0530}-\\x{058F}]"},
2056 {"Hebrew", "[\\x{0590}-\\x{05FF}]"},
2057 {"Arabic", "[\\x{0600}-\\x{06FF}]"},
2058 {"Syriac", "[\\x{0700}-\\x{074F}]"},
2059 {"Thaana", "[\\x{0780}-\\x{07BF}]"},
2060 {"Devanagari", "[\\x{0900}-\\x{097F}]"},
2061 {"Bengali", "[\\x{0980}-\\x{09FF}]"},
2062 {"Gurmukhi", "[\\x{0A00}-\\x{0A7F}]"},
2063 {"Gujarati", "[\\x{0A80}-\\x{0AFF}]"},
2064 {"Oriya", "[\\x{0B00}-\\x{0B7F}]"},
2065 {"Tamil", "[\\x{0B80}-\\x{0BFF}]"},
2066 {"Telugu", "[\\x{0C00}-\\x{0C7F}]"},
2067 {"Kannada", "[\\x{0C80}-\\x{0CFF}]"},
2068 {"Malayalam", "[\\x{0D00}-\\x{0D7F}]"},
2069 {"Sinhala", "[\\x{0D80}-\\x{0DFF}]"},
2070 {"Thai", "[\\x{0E00}-\\x{0E7F}]"},
2071 {"Lao", "[\\x{0E80}-\\x{0EFF}]"},
2072 {"Tibetan", "[\\x{0F00}-\\x{0FFF}]"},
2073 {"Myanmar", "[\\x{1000}-\\x{109F}]"},
2074 {"Georgian", "[\\x{10A0}-\\x{10FF}]"},
2075 {"HangulJamo", "[\\x{1100}-\\x{11FF}]"},
2076 {"Ethiopic", "[\\x{1200}-\\x{137F}]"},
2077 {"Cherokee", "[\\x{13A0}-\\x{13FF}]"},
2078 {"UnifiedCanadianAboriginalSyllabics", "[\\x{1400}-\\x{167F}]"},
2079 {"Ogham", "[\\x{1680}-\\x{169F}]"},
2080 {"Runic", "[\\x{16A0}-\\x{16FF}]"},
2081 {"Khmer", "[\\x{1780}-\\x{17FF}]"},
2082 {"Mongolian", "[\\x{1800}-\\x{18AF}]"},
2083 {"LatinExtendedAdditional", "[\\x{1E00}-\\x{1EFF}]"},
2084 {"GreekExtended", "[\\x{1F00}-\\x{1FFF}]"},
2085 {"GeneralPunctuation", "[\\x{2000}-\\x{206F}]"},
2086 {"SuperscriptsandSubscripts", "[\\x{2070}-\\x{209F}]"},
2087 {"CurrencySymbols", "[\\x{20A0}-\\x{20CF}]"},
2088 {"CombiningMarksforSymbols", "[\\x{20D0}-\\x{20FF}]"},
2089 {"LetterlikeSymbols", "[\\x{2100}-\\x{214F}]"},
2090 {"NumberForms", "[\\x{2150}-\\x{218F}]"},
2091 {"Arrows", "[\\x{2190}-\\x{21FF}]"},
2092 {"MathematicalOperators", "[\\x{2200}-\\x{22FF}]"},
2093 {"MiscellaneousTechnical", "[\\x{2300}-\\x{23FF}]"},
2094 {"ControlPictures", "[\\x{2400}-\\x{243F}]"},
2095 {"OpticalCharacterRecognition", "[\\x{2440}-\\x{245F}]"},
2096 {"EnclosedAlphanumerics", "[\\x{2460}-\\x{24FF}]"},
2097 {"BoxDrawing", "[\\x{2500}-\\x{257F}]"},
2098 {"BlockElements", "[\\x{2580}-\\x{259F}]"},
2099 {"GeometricShapes", "[\\x{25A0}-\\x{25FF}]"},
2100 {"MiscellaneousSymbols", "[\\x{2600}-\\x{26FF}]"},
2101 {"Dingbats", "[\\x{2700}-\\x{27BF}]"},
2102 {"BraillePatterns", "[\\x{2800}-\\x{28FF}]"},
2103 {"CJKRadicalsSupplement", "[\\x{2E80}-\\x{2EFF}]"},
2104 {"KangxiRadicals", "[\\x{2F00}-\\x{2FDF}]"},
2105 {"IdeographicDescriptionCharacters", "[\\x{2FF0}-\\x{2FFF}]"},
2106 {"CJKSymbolsandPunctuation", "[\\x{3000}-\\x{303F}]"},
2107 {"Hiragana", "[\\x{3040}-\\x{309F}]"},
2108 {"Katakana", "[\\x{30A0}-\\x{30FF}]"},
2109 {"Bopomofo", "[\\x{3100}-\\x{312F}]"},
2110 {"HangulCompatibilityJamo", "[\\x{3130}-\\x{318F}]"},
2111 {"Kanbun", "[\\x{3190}-\\x{319F}]"},
2112 {"BopomofoExtended", "[\\x{31A0}-\\x{31BF}]"},
2113 {"EnclosedCJKLettersandMonths", "[\\x{3200}-\\x{32FF}]"},
2114 {"CJKCompatibility", "[\\x{3300}-\\x{33FF}]"},
2115 {"CJKUnifiedIdeographsExtensionA", "[\\x{3400}-\\x{4DB5}]"},
2116 {"CJKUnifiedIdeographs", "[\\x{4E00}-\\x{9FFF}]"},
2117 {"YiSyllables", "[\\x{A000}-\\x{A48F}]"},
2118 {"YiRadicals", "[\\x{A490}-\\x{A4CF}]"},
2119 {"HangulSyllables", "[\\x{AC00}-\\x{D7A3}]"},
2120 {"PrivateUse", "[\\x{E000}-\\x{F8FF}]"},
2121 {"CJKCompatibilityIdeographs", "[\\x{F900}-\\x{FAFF}]"},
2122 {"AlphabeticPresentationForms", "[\\x{FB00}-\\x{FB4F}]"},
2123 {"ArabicPresentationForms-A", "[\\x{FB50}-\\x{FDFF}]"},
2124 {"CombiningHalfMarks", "[\\x{FE20}-\\x{FE2F}]"},
2125 {"CJKCompatibilityForms", "[\\x{FE30}-\\x{FE4F}]"},
2126 {"SmallFormVariants", "[\\x{FE50}-\\x{FE6F}]"},
2127 {"ArabicPresentationForms-B", "[\\x{FE70}-\\x{FEFE}]"},
2128 {"HalfwidthandFullwidthForms", "[\\x{FF00}-\\x{FFEF}]"},
2129 {NULL, NULL}
2130 };
2131
2132 /* adjust the expression to a Perl equivalent
2133 * http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#regexs */
2134
Michal Vasko40a00082020-05-27 15:20:01 +02002135 /* allocate space for the transformed pattern */
2136 size = strlen(pattern) + 1;
2137 perl_regex = malloc(size);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002138 LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx), LY_EMEM);
Radek Krejci19a96102018-11-15 13:38:09 +01002139 perl_regex[0] = '\0';
2140
Michal Vasko40a00082020-05-27 15:20:01 +02002141 /* we need to replace all "$" and "^" (that are not in "[]") with "\$" and "\^" */
2142 brack = 0;
2143 idx = 0;
2144 orig_ptr = pattern;
2145 while (orig_ptr[0]) {
2146 switch (orig_ptr[0]) {
2147 case '$':
2148 case '^':
2149 if (!brack) {
2150 /* make space for the extra character */
2151 ++size;
2152 perl_regex = ly_realloc(perl_regex, size);
2153 LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx), LY_EMEM);
Radek Krejci19a96102018-11-15 13:38:09 +01002154
Michal Vasko40a00082020-05-27 15:20:01 +02002155 /* print escape slash */
2156 perl_regex[idx] = '\\';
2157 ++idx;
2158 }
2159 break;
2160 case '[':
2161 /* must not be escaped */
2162 if ((orig_ptr == pattern) || (orig_ptr[-1] != '\\')) {
2163 ++brack;
2164 }
2165 break;
2166 case ']':
2167 if ((orig_ptr == pattern) || (orig_ptr[-1] != '\\')) {
2168 /* pattern was checked and compiled already */
2169 assert(brack);
2170 --brack;
2171 }
2172 break;
2173 default:
2174 break;
Radek Krejci19a96102018-11-15 13:38:09 +01002175 }
Michal Vasko40a00082020-05-27 15:20:01 +02002176
2177 /* copy char */
2178 perl_regex[idx] = orig_ptr[0];
2179
2180 ++idx;
2181 ++orig_ptr;
Radek Krejci19a96102018-11-15 13:38:09 +01002182 }
Michal Vasko40a00082020-05-27 15:20:01 +02002183 perl_regex[idx] = '\0';
Radek Krejci19a96102018-11-15 13:38:09 +01002184
2185 /* substitute Unicode Character Blocks with exact Character Ranges */
2186 while ((ptr = strstr(perl_regex, "\\p{Is"))) {
2187 start = ptr - perl_regex;
2188
2189 ptr = strchr(ptr, '}');
2190 if (!ptr) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002191 LOGVAL(ctx, LY_VLOG_STR, log_path, LY_VCODE_INREGEXP,
Michal Vasko69730152020-10-09 16:30:07 +02002192 pattern, perl_regex + start + 2, "unterminated character property");
Radek Krejci19a96102018-11-15 13:38:09 +01002193 free(perl_regex);
2194 return LY_EVALID;
2195 }
2196 end = (ptr - perl_regex) + 1;
2197
2198 /* need more space */
2199 if (end - start < URANGE_LEN) {
2200 perl_regex = ly_realloc(perl_regex, strlen(perl_regex) + (URANGE_LEN - (end - start)) + 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002201 LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx); free(perl_regex), LY_EMEM);
Radek Krejci19a96102018-11-15 13:38:09 +01002202 }
2203
2204 /* find our range */
2205 for (idx = 0; ublock2urange[idx][0]; ++idx) {
2206 if (!strncmp(perl_regex + start + 5, ublock2urange[idx][0], strlen(ublock2urange[idx][0]))) {
2207 break;
2208 }
2209 }
2210 if (!ublock2urange[idx][0]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002211 LOGVAL(ctx, LY_VLOG_STR, log_path, LY_VCODE_INREGEXP,
Michal Vasko69730152020-10-09 16:30:07 +02002212 pattern, perl_regex + start + 5, "unknown block name");
Radek Krejci19a96102018-11-15 13:38:09 +01002213 free(perl_regex);
2214 return LY_EVALID;
2215 }
2216
2217 /* 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 +02002218 for (idx2 = 0, idx = 0; idx2 < start; ++idx2) {
Radek Krejci19a96102018-11-15 13:38:09 +01002219 if ((perl_regex[idx2] == '[') && (!idx2 || (perl_regex[idx2 - 1] != '\\'))) {
Michal Vasko40a00082020-05-27 15:20:01 +02002220 ++idx;
Radek Krejci19a96102018-11-15 13:38:09 +01002221 }
2222 if ((perl_regex[idx2] == ']') && (!idx2 || (perl_regex[idx2 - 1] != '\\'))) {
Michal Vasko40a00082020-05-27 15:20:01 +02002223 --idx;
Radek Krejci19a96102018-11-15 13:38:09 +01002224 }
2225 }
Michal Vasko40a00082020-05-27 15:20:01 +02002226 if (idx) {
Radek Krejci19a96102018-11-15 13:38:09 +01002227 /* skip brackets */
2228 memmove(perl_regex + start + (URANGE_LEN - 2), perl_regex + end, strlen(perl_regex + end) + 1);
2229 memcpy(perl_regex + start, ublock2urange[idx][1] + 1, URANGE_LEN - 2);
2230 } else {
2231 memmove(perl_regex + start + URANGE_LEN, perl_regex + end, strlen(perl_regex + end) + 1);
2232 memcpy(perl_regex + start, ublock2urange[idx][1], URANGE_LEN);
2233 }
2234 }
2235
2236 /* must return 0, already checked during parsing */
Radek Krejci5819f7c2019-05-31 14:53:29 +02002237 code_local = pcre2_compile((PCRE2_SPTR)perl_regex, PCRE2_ZERO_TERMINATED,
Michal Vasko69730152020-10-09 16:30:07 +02002238 PCRE2_UTF | PCRE2_ANCHORED | PCRE2_ENDANCHORED | PCRE2_DOLLAR_ENDONLY | PCRE2_NO_AUTO_CAPTURE,
2239 &err_code, &err_offset, NULL);
Radek Krejci54579462019-04-30 12:47:06 +02002240 if (!code_local) {
2241 PCRE2_UCHAR err_msg[256] = {0};
2242 pcre2_get_error_message(err_code, err_msg, 256);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002243 LOGVAL(ctx, LY_VLOG_STR, log_path, LY_VCODE_INREGEXP, pattern, perl_regex + err_offset, err_msg);
Radek Krejci19a96102018-11-15 13:38:09 +01002244 free(perl_regex);
2245 return LY_EVALID;
2246 }
2247 free(perl_regex);
2248
Radek Krejci54579462019-04-30 12:47:06 +02002249 if (code) {
2250 *code = code_local;
Radek Krejci19a96102018-11-15 13:38:09 +01002251 } else {
Radek Krejci54579462019-04-30 12:47:06 +02002252 free(code_local);
Radek Krejci19a96102018-11-15 13:38:09 +01002253 }
2254
2255 return LY_SUCCESS;
2256
2257#undef URANGE_LEN
2258}
2259
Radek Krejcia3045382018-11-22 14:30:31 +01002260/**
2261 * @brief Compile parsed pattern restriction in conjunction with the patterns from base type.
2262 * @param[in] ctx Compile context.
2263 * @param[in] patterns_p Array of parsed patterns from the current type to compile.
Radek Krejcia3045382018-11-22 14:30:31 +01002264 * @param[in] base_patterns Compiled patterns from the type from which the current type is derived.
2265 * Patterns from the base type are inherited to have all the patterns that have to match at one place.
2266 * @param[out] patterns Pointer to the storage for the patterns of the current type.
2267 * @return LY_ERR LY_SUCCESS, LY_EMEM, LY_EVALID.
2268 */
Radek Krejci19a96102018-11-15 13:38:09 +01002269static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02002270lys_compile_type_patterns(struct lysc_ctx *ctx, struct lysp_restr *patterns_p,
Radek Krejci0f969882020-08-21 16:56:47 +02002271 struct lysc_pattern **base_patterns, struct lysc_pattern ***patterns)
Radek Krejci19a96102018-11-15 13:38:09 +01002272{
2273 struct lysc_pattern **pattern;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002274 LY_ARRAY_COUNT_TYPE u;
Radek Krejci19a96102018-11-15 13:38:09 +01002275 LY_ERR ret = LY_SUCCESS;
2276
2277 /* first, copy the patterns from the base type */
2278 if (base_patterns) {
2279 *patterns = lysc_patterns_dup(ctx->ctx, base_patterns);
2280 LY_CHECK_ERR_RET(!(*patterns), LOGMEM(ctx->ctx), LY_EMEM);
2281 }
2282
2283 LY_ARRAY_FOR(patterns_p, u) {
2284 LY_ARRAY_NEW_RET(ctx->ctx, (*patterns), pattern, LY_EMEM);
2285 *pattern = calloc(1, sizeof **pattern);
2286 ++(*pattern)->refcount;
2287
Michal Vasko7f45cf22020-10-01 12:49:44 +02002288 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 +01002289 LY_CHECK_RET(ret);
Radek Krejci19a96102018-11-15 13:38:09 +01002290
Michal Vasko7f45cf22020-10-01 12:49:44 +02002291 if (patterns_p[u].arg.str[0] == 0x15) {
Radek Krejci19a96102018-11-15 13:38:09 +01002292 (*pattern)->inverted = 1;
2293 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02002294 DUP_STRING_GOTO(ctx->ctx, &patterns_p[u].arg.str[1], (*pattern)->expr, ret, done);
Radek Krejci011e4aa2020-09-04 15:22:31 +02002295 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].eapptag, (*pattern)->eapptag, ret, done);
2296 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].emsg, (*pattern)->emsg, ret, done);
2297 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].dsc, (*pattern)->dsc, ret, done);
2298 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].ref, (*pattern)->ref, ret, done);
Radek Krejci0935f412019-08-20 16:15:18 +02002299 COMPILE_EXTS_GOTO(ctx, patterns_p[u].exts, (*pattern)->exts, (*pattern), LYEXT_PAR_PATTERN, ret, done);
Radek Krejci19a96102018-11-15 13:38:09 +01002300 }
2301done:
2302 return ret;
2303}
2304
Radek Krejcia3045382018-11-22 14:30:31 +01002305/**
2306 * @brief map of the possible restrictions combination for the specific built-in type.
2307 */
Radek Krejci19a96102018-11-15 13:38:09 +01002308static uint16_t type_substmt_map[LY_DATA_TYPE_COUNT] = {
2309 0 /* LY_TYPE_UNKNOWN */,
2310 LYS_SET_LENGTH /* LY_TYPE_BINARY */,
Radek Krejci5969f272018-11-23 10:03:58 +01002311 LYS_SET_RANGE /* LY_TYPE_UINT8 */,
2312 LYS_SET_RANGE /* LY_TYPE_UINT16 */,
2313 LYS_SET_RANGE /* LY_TYPE_UINT32 */,
2314 LYS_SET_RANGE /* LY_TYPE_UINT64 */,
2315 LYS_SET_LENGTH | LYS_SET_PATTERN /* LY_TYPE_STRING */,
Radek Krejci19a96102018-11-15 13:38:09 +01002316 LYS_SET_BIT /* LY_TYPE_BITS */,
2317 0 /* LY_TYPE_BOOL */,
2318 LYS_SET_FRDIGITS | LYS_SET_RANGE /* LY_TYPE_DEC64 */,
2319 0 /* LY_TYPE_EMPTY */,
2320 LYS_SET_ENUM /* LY_TYPE_ENUM */,
2321 LYS_SET_BASE /* LY_TYPE_IDENT */,
2322 LYS_SET_REQINST /* LY_TYPE_INST */,
2323 LYS_SET_REQINST | LYS_SET_PATH /* LY_TYPE_LEAFREF */,
Radek Krejci19a96102018-11-15 13:38:09 +01002324 LYS_SET_TYPE /* LY_TYPE_UNION */,
2325 LYS_SET_RANGE /* LY_TYPE_INT8 */,
Radek Krejci19a96102018-11-15 13:38:09 +01002326 LYS_SET_RANGE /* LY_TYPE_INT16 */,
Radek Krejci19a96102018-11-15 13:38:09 +01002327 LYS_SET_RANGE /* LY_TYPE_INT32 */,
Radek Krejci5969f272018-11-23 10:03:58 +01002328 LYS_SET_RANGE /* LY_TYPE_INT64 */
2329};
2330
2331/**
2332 * @brief stringification of the YANG built-in data types
2333 */
Michal Vasko69730152020-10-09 16:30:07 +02002334const char *ly_data_type2str[LY_DATA_TYPE_COUNT] = {
2335 "unknown", "binary", "8bit unsigned integer", "16bit unsigned integer",
Radek Krejci5969f272018-11-23 10:03:58 +01002336 "32bit unsigned integer", "64bit unsigned integer", "string", "bits", "boolean", "decimal64", "empty", "enumeration",
Michal Vasko69730152020-10-09 16:30:07 +02002337 "identityref", "instance-identifier", "leafref", "union", "8bit integer", "16bit integer", "32bit integer", "64bit integer"
2338};
Radek Krejci19a96102018-11-15 13:38:09 +01002339
Radek Krejcia3045382018-11-22 14:30:31 +01002340/**
2341 * @brief Compile parsed type's enum structures (for enumeration and bits types).
2342 * @param[in] ctx Compile context.
2343 * @param[in] enums_p Array of the parsed enum structures to compile.
2344 * @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 +01002345 * @param[in] base_enums Array of the compiled enums information from the (latest) base type to check if the current enums are compatible.
2346 * @param[out] enums Newly created array of the compiled enums information for the current type.
2347 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
2348 */
Radek Krejci19a96102018-11-15 13:38:09 +01002349static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02002350lys_compile_type_enums(struct lysc_ctx *ctx, struct lysp_type_enum *enums_p, LY_DATA_TYPE basetype,
Radek Krejci0f969882020-08-21 16:56:47 +02002351 struct lysc_type_bitenum_item *base_enums, struct lysc_type_bitenum_item **enums)
Radek Krejci19a96102018-11-15 13:38:09 +01002352{
2353 LY_ERR ret = LY_SUCCESS;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002354 LY_ARRAY_COUNT_TYPE u, v, match = 0;
Radek Krejci19a96102018-11-15 13:38:09 +01002355 int32_t value = 0;
2356 uint32_t position = 0;
Radek Krejci693262f2019-04-29 15:23:20 +02002357 struct lysc_type_bitenum_item *e, storage;
Radek Krejci19a96102018-11-15 13:38:09 +01002358
Michal Vasko5d24f6c2020-10-13 13:49:06 +02002359 if (base_enums && (ctx->pmod->version < LYS_VERSION_1_1)) {
Radek Krejci19a96102018-11-15 13:38:09 +01002360 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "%s type can be subtyped only in YANG 1.1 modules.",
Michal Vasko69730152020-10-09 16:30:07 +02002361 basetype == LY_TYPE_ENUM ? "Enumeration" : "Bits");
Radek Krejci19a96102018-11-15 13:38:09 +01002362 return LY_EVALID;
2363 }
2364
2365 LY_ARRAY_FOR(enums_p, u) {
2366 LY_ARRAY_NEW_RET(ctx->ctx, *enums, e, LY_EMEM);
Radek Krejci011e4aa2020-09-04 15:22:31 +02002367 DUP_STRING_GOTO(ctx->ctx, enums_p[u].name, e->name, ret, done);
2368 DUP_STRING_GOTO(ctx->ctx, enums_p[u].ref, e->dsc, ret, done);
2369 DUP_STRING_GOTO(ctx->ctx, enums_p[u].ref, e->ref, ret, done);
Radek Krejci693262f2019-04-29 15:23:20 +02002370 e->flags = enums_p[u].flags & LYS_FLAGS_COMPILED_MASK;
Radek Krejci19a96102018-11-15 13:38:09 +01002371 if (base_enums) {
2372 /* check the enum/bit presence in the base type - the set of enums/bits in the derived type must be a subset */
2373 LY_ARRAY_FOR(base_enums, v) {
2374 if (!strcmp(e->name, base_enums[v].name)) {
2375 break;
2376 }
2377 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002378 if (v == LY_ARRAY_COUNT(base_enums)) {
Radek Krejci19a96102018-11-15 13:38:09 +01002379 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002380 "Invalid %s - derived type adds new item \"%s\".",
2381 basetype == LY_TYPE_ENUM ? "enumeration" : "bits", e->name);
Radek Krejci19a96102018-11-15 13:38:09 +01002382 return LY_EVALID;
2383 }
2384 match = v;
2385 }
2386
2387 if (basetype == LY_TYPE_ENUM) {
Radek Krejci693262f2019-04-29 15:23:20 +02002388 e->flags |= LYS_ISENUM;
Radek Krejci19a96102018-11-15 13:38:09 +01002389 if (enums_p[u].flags & LYS_SET_VALUE) {
2390 e->value = (int32_t)enums_p[u].value;
Michal Vasko69730152020-10-09 16:30:07 +02002391 if (!u || (e->value >= value)) {
Radek Krejci19a96102018-11-15 13:38:09 +01002392 value = e->value + 1;
2393 }
2394 /* check collision with other values */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002395 for (v = 0; v < LY_ARRAY_COUNT(*enums) - 1; ++v) {
Radek Krejci19a96102018-11-15 13:38:09 +01002396 if (e->value == (*enums)[v].value) {
2397 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002398 "Invalid enumeration - value %d collide in items \"%s\" and \"%s\".",
2399 e->value, e->name, (*enums)[v].name);
Radek Krejci19a96102018-11-15 13:38:09 +01002400 return LY_EVALID;
2401 }
2402 }
2403 } else if (base_enums) {
2404 /* inherit the assigned value */
2405 e->value = base_enums[match].value;
Michal Vasko69730152020-10-09 16:30:07 +02002406 if (!u || (e->value >= value)) {
Radek Krejci19a96102018-11-15 13:38:09 +01002407 value = e->value + 1;
2408 }
2409 } else {
2410 /* assign value automatically */
Michal Vasko69730152020-10-09 16:30:07 +02002411 if (u && (value == INT32_MIN)) {
Radek Krejci19a96102018-11-15 13:38:09 +01002412 /* counter overflow */
2413 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002414 "Invalid enumeration - it is not possible to auto-assign enum value for "
2415 "\"%s\" since the highest value is already 2147483647.", e->name);
Radek Krejci19a96102018-11-15 13:38:09 +01002416 return LY_EVALID;
2417 }
2418 e->value = value++;
2419 }
2420 } else { /* LY_TYPE_BITS */
2421 if (enums_p[u].flags & LYS_SET_VALUE) {
2422 e->value = (int32_t)enums_p[u].value;
Michal Vasko69730152020-10-09 16:30:07 +02002423 if (!u || ((uint32_t)e->value >= position)) {
Radek Krejci19a96102018-11-15 13:38:09 +01002424 position = (uint32_t)e->value + 1;
2425 }
2426 /* check collision with other values */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002427 for (v = 0; v < LY_ARRAY_COUNT(*enums) - 1; ++v) {
Radek Krejci19a96102018-11-15 13:38:09 +01002428 if (e->value == (*enums)[v].value) {
2429 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002430 "Invalid bits - position %u collide in items \"%s\" and \"%s\".",
Radek Krejci0f969882020-08-21 16:56:47 +02002431 (uint32_t)e->value, e->name, (*enums)[v].name);
Radek Krejci19a96102018-11-15 13:38:09 +01002432 return LY_EVALID;
2433 }
2434 }
2435 } else if (base_enums) {
2436 /* inherit the assigned value */
2437 e->value = base_enums[match].value;
Michal Vasko69730152020-10-09 16:30:07 +02002438 if (!u || ((uint32_t)e->value >= position)) {
Radek Krejci19a96102018-11-15 13:38:09 +01002439 position = (uint32_t)e->value + 1;
2440 }
2441 } else {
2442 /* assign value automatically */
Michal Vasko69730152020-10-09 16:30:07 +02002443 if (u && (position == 0)) {
Radek Krejci19a96102018-11-15 13:38:09 +01002444 /* counter overflow */
2445 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002446 "Invalid bits - it is not possible to auto-assign bit position for "
2447 "\"%s\" since the highest value is already 4294967295.", e->name);
Radek Krejci19a96102018-11-15 13:38:09 +01002448 return LY_EVALID;
2449 }
2450 e->value = position++;
2451 }
2452 }
2453
2454 if (base_enums) {
2455 /* the assigned values must not change from the derived type */
2456 if (e->value != base_enums[match].value) {
2457 if (basetype == LY_TYPE_ENUM) {
2458 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002459 "Invalid enumeration - value of the item \"%s\" has changed from %d to %d in the derived type.",
2460 e->name, base_enums[match].value, e->value);
Radek Krejci19a96102018-11-15 13:38:09 +01002461 } else {
2462 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002463 "Invalid bits - position of the item \"%s\" has changed from %u to %u in the derived type.",
2464 e->name, (uint32_t)base_enums[match].value, (uint32_t)e->value);
Radek Krejci19a96102018-11-15 13:38:09 +01002465 }
2466 return LY_EVALID;
2467 }
2468 }
2469
Radek Krejciec4da802019-05-02 13:02:41 +02002470 COMPILE_ARRAY_GOTO(ctx, enums_p[u].iffeatures, e->iffeatures, v, lys_compile_iffeature, ret, done);
Radek Krejci0935f412019-08-20 16:15:18 +02002471 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 +01002472
2473 if (basetype == LY_TYPE_BITS) {
2474 /* keep bits ordered by position */
Radek Krejci1e008d22020-08-17 11:37:37 +02002475 for (v = u; v && (*enums)[v - 1].value > e->value; --v) {}
Radek Krejci19a96102018-11-15 13:38:09 +01002476 if (v != u) {
2477 memcpy(&storage, e, sizeof *e);
2478 memmove(&(*enums)[v + 1], &(*enums)[v], (u - v) * sizeof **enums);
2479 memcpy(&(*enums)[v], &storage, sizeof storage);
2480 }
2481 }
2482 }
2483
2484done:
2485 return ret;
2486}
2487
Radek Krejcia3045382018-11-22 14:30:31 +01002488/**
2489 * @brief Parse path-arg (leafref). Get tokens of the path by repetitive calls of the function.
2490 *
2491 * path-arg = absolute-path / relative-path
2492 * absolute-path = 1*("/" (node-identifier *path-predicate))
2493 * relative-path = 1*(".." "/") descendant-path
2494 *
2495 * @param[in,out] path Path to parse.
2496 * @param[out] prefix Prefix of the token, NULL if there is not any.
2497 * @param[out] pref_len Length of the prefix, 0 if there is not any.
2498 * @param[out] name Name of the token.
2499 * @param[out] nam_len Length of the name.
2500 * @param[out] parent_times Number of leading ".." in the path. Must be 0 on the first call,
2501 * must not be changed between consecutive calls. -1 if the
2502 * path is absolute.
2503 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
2504 * @return LY_ERR value: LY_SUCCESS or LY_EINVAL in case of invalid character in the path.
2505 */
Radek Krejci2d7a47b2019-05-16 13:34:10 +02002506LY_ERR
Radek Krejcia3045382018-11-22 14:30:31 +01002507lys_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 +02002508 int32_t *parent_times, ly_bool *has_predicate)
Radek Krejcia3045382018-11-22 14:30:31 +01002509{
Radek Krejci1deb5be2020-08-26 16:43:36 +02002510 int32_t par_times = 0;
Radek Krejcia3045382018-11-22 14:30:31 +01002511
2512 assert(path && *path);
2513 assert(parent_times);
2514 assert(prefix);
2515 assert(prefix_len);
2516 assert(name);
2517 assert(name_len);
2518 assert(has_predicate);
2519
2520 *prefix = NULL;
2521 *prefix_len = 0;
2522 *name = NULL;
2523 *name_len = 0;
2524 *has_predicate = 0;
2525
2526 if (!*parent_times) {
2527 if (!strncmp(*path, "..", 2)) {
2528 *path += 2;
2529 ++par_times;
2530 while (!strncmp(*path, "/..", 3)) {
2531 *path += 3;
2532 ++par_times;
2533 }
2534 }
2535 if (par_times) {
2536 *parent_times = par_times;
2537 } else {
2538 *parent_times = -1;
2539 }
2540 }
2541
2542 if (**path != '/') {
2543 return LY_EINVAL;
2544 }
2545 /* skip '/' */
2546 ++(*path);
2547
2548 /* node-identifier ([prefix:]name) */
Radek Krejcib4a4a272019-06-10 12:44:52 +02002549 LY_CHECK_RET(ly_parse_nodeid(path, prefix, prefix_len, name, name_len));
Radek Krejcia3045382018-11-22 14:30:31 +01002550
Michal Vasko69730152020-10-09 16:30:07 +02002551 if (((**path == '/') && (*path)[1]) || !**path) {
Radek Krejcia3045382018-11-22 14:30:31 +01002552 /* path continues by another token or this is the last token */
2553 return LY_SUCCESS;
2554 } else if ((*path)[0] != '[') {
2555 /* unexpected character */
2556 return LY_EINVAL;
2557 } else {
2558 /* predicate starting with [ */
2559 *has_predicate = 1;
2560 return LY_SUCCESS;
2561 }
2562}
2563
2564/**
Radek Krejci58d171e2018-11-23 13:50:55 +01002565 * @brief Check the features used in if-feature statements applicable to the leafref and its target.
2566 *
2567 * The set of features used for target must be a subset of features used for the leafref.
2568 * This is not a perfect, we should compare the truth tables but it could require too much resources
2569 * and RFC 7950 does not require it explicitely, so we simplify that.
2570 *
2571 * @param[in] refnode The leafref node.
2572 * @param[in] target Tha target node of the leafref.
2573 * @return LY_SUCCESS or LY_EVALID;
2574 */
2575static LY_ERR
2576lys_compile_leafref_features_validate(const struct lysc_node *refnode, const struct lysc_node *target)
2577{
2578 LY_ERR ret = LY_EVALID;
2579 const struct lysc_node *iter;
Radek Krejci1deb5be2020-08-26 16:43:36 +02002580 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci58d171e2018-11-23 13:50:55 +01002581 struct ly_set features = {0};
2582
2583 for (iter = refnode; iter; iter = iter->parent) {
Radek Krejci056d0a82018-12-06 16:57:25 +01002584 if (iter->iffeatures) {
2585 LY_ARRAY_FOR(iter->iffeatures, u) {
2586 LY_ARRAY_FOR(iter->iffeatures[u].features, v) {
Radek Krejciba03a5a2020-08-27 14:40:41 +02002587 LY_CHECK_GOTO(ly_set_add(&features, iter->iffeatures[u].features[v], 0, NULL), cleanup);
Radek Krejci58d171e2018-11-23 13:50:55 +01002588 }
2589 }
2590 }
2591 }
2592
2593 /* we should have, in features set, a superset of features applicable to the target node.
Radek Krejciba03a5a2020-08-27 14:40:41 +02002594 * If the feature is not present, we don;t have a subset of features applicable
Radek Krejci58d171e2018-11-23 13:50:55 +01002595 * to the leafref itself. */
Radek Krejci58d171e2018-11-23 13:50:55 +01002596 for (iter = target; iter; iter = iter->parent) {
Radek Krejci056d0a82018-12-06 16:57:25 +01002597 if (iter->iffeatures) {
2598 LY_ARRAY_FOR(iter->iffeatures, u) {
2599 LY_ARRAY_FOR(iter->iffeatures[u].features, v) {
Radek Krejciba03a5a2020-08-27 14:40:41 +02002600 if (!ly_set_contains(&features, iter->iffeatures[u].features[v], NULL)) {
2601 /* feature not present */
Radek Krejci58d171e2018-11-23 13:50:55 +01002602 goto cleanup;
2603 }
2604 }
2605 }
2606 }
2607 }
2608 ret = LY_SUCCESS;
2609
2610cleanup:
2611 ly_set_erase(&features, NULL);
2612 return ret;
2613}
2614
Michal Vasko7f45cf22020-10-01 12:49:44 +02002615static 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 +02002616 struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p,
Michal Vasko7f45cf22020-10-01 12:49:44 +02002617 struct lysc_type **type, const char **units, struct lysp_qname **dflt);
Radek Krejcia3045382018-11-22 14:30:31 +01002618
Radek Krejcia3045382018-11-22 14:30:31 +01002619/**
2620 * @brief The core of the lys_compile_type() - compile information about the given type (from typedef or leaf/leaf-list).
2621 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02002622 * @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 +01002623 * @param[in] context_flags Flags of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
2624 * @param[in] context_mod Module of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
2625 * @param[in] context_name Name of the context node or referencing typedef for logging.
Radek Krejcia3045382018-11-22 14:30:31 +01002626 * @param[in] type_p Parsed type to compile.
2627 * @param[in] basetype Base YANG built-in type of the type to compile.
Radek Krejcia3045382018-11-22 14:30:31 +01002628 * @param[in] tpdfname Name of the type's typedef, serves as a flag - if it is leaf/leaf-list's type, it is NULL.
2629 * @param[in] base The latest base (compiled) type from which the current type is being derived.
2630 * @param[out] type Newly created type structure with the filled information about the type.
2631 * @return LY_ERR value.
2632 */
Radek Krejci19a96102018-11-15 13:38:09 +01002633static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02002634lys_compile_type_(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags,
Michal Vaskoe9c050f2020-10-06 14:01:23 +02002635 struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p, LY_DATA_TYPE basetype,
2636 const char *tpdfname, struct lysc_type *base, struct lysc_type **type)
Radek Krejcic5c27e52018-11-15 14:38:11 +01002637{
2638 LY_ERR ret = LY_SUCCESS;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002639 struct lysc_type_bin *bin;
2640 struct lysc_type_num *num;
2641 struct lysc_type_str *str;
2642 struct lysc_type_bits *bits;
2643 struct lysc_type_enum *enumeration;
Radek Krejci6cba4292018-11-15 17:33:29 +01002644 struct lysc_type_dec *dec;
Radek Krejci555cb5b2018-11-16 14:54:33 +01002645 struct lysc_type_identityref *idref;
Michal Vasko004d3152020-06-11 19:59:22 +02002646 struct lysc_type_leafref *lref;
Radek Krejcicdfecd92018-11-26 11:27:32 +01002647 struct lysc_type_union *un, *un_aux;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002648
2649 switch (basetype) {
2650 case LY_TYPE_BINARY:
Michal Vasko22df3f02020-08-24 13:29:22 +02002651 bin = (struct lysc_type_bin *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002652
2653 /* RFC 7950 9.8.1, 9.4.4 - length, number of octets it contains */
Radek Krejcic5c27e52018-11-15 14:38:11 +01002654 if (type_p->length) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002655 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->length, basetype, 1, 0,
Michal Vasko69730152020-10-09 16:30:07 +02002656 base ? ((struct lysc_type_bin *)base)->length : NULL, &bin->length));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002657 if (!tpdfname) {
Michal Vasko1734be92020-09-22 08:55:10 +02002658 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 +01002659 }
2660 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002661 break;
2662 case LY_TYPE_BITS:
2663 /* RFC 7950 9.7 - bits */
Michal Vasko22df3f02020-08-24 13:29:22 +02002664 bits = (struct lysc_type_bits *)(*type);
Radek Krejcic5c27e52018-11-15 14:38:11 +01002665 if (type_p->bits) {
Radek Krejciec4da802019-05-02 13:02:41 +02002666 LY_CHECK_RET(lys_compile_type_enums(ctx, type_p->bits, basetype,
Michal Vasko69730152020-10-09 16:30:07 +02002667 base ? (struct lysc_type_bitenum_item *)((struct lysc_type_bits *)base)->bits : NULL,
Michal Vasko22df3f02020-08-24 13:29:22 +02002668 (struct lysc_type_bitenum_item **)&bits->bits));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002669 }
2670
Radek Krejci555cb5b2018-11-16 14:54:33 +01002671 if (!base && !type_p->flags) {
Radek Krejcic5c27e52018-11-15 14:38:11 +01002672 /* type derived from bits built-in type must contain at least one bit */
Radek Krejci6cba4292018-11-15 17:33:29 +01002673 if (tpdfname) {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002674 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "bit", "bits type ", tpdfname);
Radek Krejci6cba4292018-11-15 17:33:29 +01002675 } else {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002676 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "bit", "bits type", "");
Radek Krejcic5c27e52018-11-15 14:38:11 +01002677 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002678 return LY_EVALID;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002679 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002680 break;
Radek Krejci6cba4292018-11-15 17:33:29 +01002681 case LY_TYPE_DEC64:
Radek Krejci115a74d2020-08-14 22:18:12 +02002682 dec = (struct lysc_type_dec *)(*type);
Radek Krejci6cba4292018-11-15 17:33:29 +01002683
2684 /* RFC 7950 9.3.4 - fraction-digits */
Radek Krejci555cb5b2018-11-16 14:54:33 +01002685 if (!base) {
Radek Krejci643c8242018-11-15 17:51:11 +01002686 if (!type_p->fraction_digits) {
2687 if (tpdfname) {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002688 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "fraction-digits", "decimal64 type ", tpdfname);
Radek Krejci643c8242018-11-15 17:51:11 +01002689 } else {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002690 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "fraction-digits", "decimal64 type", "");
Radek Krejci643c8242018-11-15 17:51:11 +01002691 }
2692 return LY_EVALID;
2693 }
Radek Krejci115a74d2020-08-14 22:18:12 +02002694 dec->fraction_digits = type_p->fraction_digits;
2695 } else {
2696 if (type_p->fraction_digits) {
2697 /* fraction digits is prohibited in types not directly derived from built-in decimal64 */
2698 if (tpdfname) {
2699 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002700 "Invalid fraction-digits substatement for type \"%s\" not directly derived from decimal64 built-in type.",
2701 tpdfname);
Radek Krejci115a74d2020-08-14 22:18:12 +02002702 } else {
2703 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002704 "Invalid fraction-digits substatement for type not directly derived from decimal64 built-in type.");
Radek Krejci115a74d2020-08-14 22:18:12 +02002705 }
2706 return LY_EVALID;
Radek Krejci6cba4292018-11-15 17:33:29 +01002707 }
Radek Krejci115a74d2020-08-14 22:18:12 +02002708 dec->fraction_digits = ((struct lysc_type_dec *)base)->fraction_digits;
Radek Krejci6cba4292018-11-15 17:33:29 +01002709 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002710
2711 /* RFC 7950 9.2.4 - range */
2712 if (type_p->range) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002713 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->range, basetype, 0, dec->fraction_digits,
Michal Vasko69730152020-10-09 16:30:07 +02002714 base ? ((struct lysc_type_dec *)base)->range : NULL, &dec->range));
Radek Krejci6cba4292018-11-15 17:33:29 +01002715 if (!tpdfname) {
Michal Vasko1734be92020-09-22 08:55:10 +02002716 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 +01002717 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002718 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002719 break;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002720 case LY_TYPE_STRING:
Michal Vasko22df3f02020-08-24 13:29:22 +02002721 str = (struct lysc_type_str *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002722
2723 /* RFC 7950 9.4.4 - length */
Radek Krejcic5c27e52018-11-15 14:38:11 +01002724 if (type_p->length) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002725 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->length, basetype, 1, 0,
Michal Vasko69730152020-10-09 16:30:07 +02002726 base ? ((struct lysc_type_str *)base)->length : NULL, &str->length));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002727 if (!tpdfname) {
Michal Vasko1734be92020-09-22 08:55:10 +02002728 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 +01002729 }
Michal Vasko22df3f02020-08-24 13:29:22 +02002730 } else if (base && ((struct lysc_type_str *)base)->length) {
2731 str->length = lysc_range_dup(ctx->ctx, ((struct lysc_type_str *)base)->length);
Radek Krejcic5c27e52018-11-15 14:38:11 +01002732 }
2733
2734 /* RFC 7950 9.4.5 - pattern */
2735 if (type_p->patterns) {
Radek Krejciec4da802019-05-02 13:02:41 +02002736 LY_CHECK_RET(lys_compile_type_patterns(ctx, type_p->patterns,
Michal Vasko69730152020-10-09 16:30:07 +02002737 base ? ((struct lysc_type_str *)base)->patterns : NULL, &str->patterns));
Michal Vasko22df3f02020-08-24 13:29:22 +02002738 } else if (base && ((struct lysc_type_str *)base)->patterns) {
2739 str->patterns = lysc_patterns_dup(ctx->ctx, ((struct lysc_type_str *)base)->patterns);
Radek Krejcic5c27e52018-11-15 14:38:11 +01002740 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002741 break;
2742 case LY_TYPE_ENUM:
Michal Vasko22df3f02020-08-24 13:29:22 +02002743 enumeration = (struct lysc_type_enum *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002744
2745 /* RFC 7950 9.6 - enum */
Radek Krejcic5c27e52018-11-15 14:38:11 +01002746 if (type_p->enums) {
Radek Krejciec4da802019-05-02 13:02:41 +02002747 LY_CHECK_RET(lys_compile_type_enums(ctx, type_p->enums, basetype,
Michal Vasko69730152020-10-09 16:30:07 +02002748 base ? ((struct lysc_type_enum *)base)->enums : NULL, &enumeration->enums));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002749 }
2750
Radek Krejci555cb5b2018-11-16 14:54:33 +01002751 if (!base && !type_p->flags) {
Radek Krejcic5c27e52018-11-15 14:38:11 +01002752 /* type derived from enumerations built-in type must contain at least one enum */
Radek Krejci6cba4292018-11-15 17:33:29 +01002753 if (tpdfname) {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002754 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "enum", "enumeration type ", tpdfname);
Radek Krejci6cba4292018-11-15 17:33:29 +01002755 } else {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002756 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "enum", "enumeration type", "");
Radek Krejcic5c27e52018-11-15 14:38:11 +01002757 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002758 return LY_EVALID;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002759 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002760 break;
2761 case LY_TYPE_INT8:
2762 case LY_TYPE_UINT8:
2763 case LY_TYPE_INT16:
2764 case LY_TYPE_UINT16:
2765 case LY_TYPE_INT32:
2766 case LY_TYPE_UINT32:
2767 case LY_TYPE_INT64:
2768 case LY_TYPE_UINT64:
Michal Vasko22df3f02020-08-24 13:29:22 +02002769 num = (struct lysc_type_num *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002770
2771 /* RFC 6020 9.2.4 - range */
Radek Krejcic5c27e52018-11-15 14:38:11 +01002772 if (type_p->range) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002773 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->range, basetype, 0, 0,
Michal Vasko69730152020-10-09 16:30:07 +02002774 base ? ((struct lysc_type_num *)base)->range : NULL, &num->range));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002775 if (!tpdfname) {
Michal Vasko1734be92020-09-22 08:55:10 +02002776 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 +01002777 }
2778 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002779 break;
Radek Krejci555cb5b2018-11-16 14:54:33 +01002780 case LY_TYPE_IDENT:
Michal Vasko22df3f02020-08-24 13:29:22 +02002781 idref = (struct lysc_type_identityref *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002782
2783 /* RFC 7950 9.10.2 - base */
2784 if (type_p->bases) {
2785 if (base) {
2786 /* only the directly derived identityrefs can contain base specification */
2787 if (tpdfname) {
2788 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002789 "Invalid base substatement for the type \"%s\" not directly derived from identityref built-in type.",
2790 tpdfname);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002791 } else {
2792 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002793 "Invalid base substatement for the type not directly derived from identityref built-in type.");
Radek Krejci555cb5b2018-11-16 14:54:33 +01002794 }
2795 return LY_EVALID;
2796 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +02002797 LY_CHECK_RET(lys_compile_identity_bases(ctx, type_p->pmod, type_p->bases, NULL, &idref->bases));
Radek Krejci555cb5b2018-11-16 14:54:33 +01002798 }
2799
2800 if (!base && !type_p->flags) {
2801 /* type derived from identityref built-in type must contain at least one base */
2802 if (tpdfname) {
2803 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "base", "identityref type ", tpdfname);
2804 } else {
2805 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "base", "identityref type", "");
Radek Krejci555cb5b2018-11-16 14:54:33 +01002806 }
2807 return LY_EVALID;
2808 }
Radek Krejci555cb5b2018-11-16 14:54:33 +01002809 break;
Radek Krejcia3045382018-11-22 14:30:31 +01002810 case LY_TYPE_LEAFREF:
Michal Vasko22df3f02020-08-24 13:29:22 +02002811 lref = (struct lysc_type_leafref *)*type;
Michal Vasko004d3152020-06-11 19:59:22 +02002812
Radek Krejcia3045382018-11-22 14:30:31 +01002813 /* RFC 7950 9.9.3 - require-instance */
2814 if (type_p->flags & LYS_SET_REQINST) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02002815 if (context_mod->version < LYS_VERSION_1_1) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01002816 if (tpdfname) {
2817 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02002818 "Leafref type \"%s\" can be restricted by require-instance statement only in YANG 1.1 modules.", tpdfname);
Radek Krejci9bb94eb2018-12-04 16:48:35 +01002819 } else {
2820 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02002821 "Leafref type can be restricted by require-instance statement only in YANG 1.1 modules.");
Radek Krejci9bb94eb2018-12-04 16:48:35 +01002822 }
2823 return LY_EVALID;
2824 }
Michal Vasko004d3152020-06-11 19:59:22 +02002825 lref->require_instance = type_p->require_instance;
Radek Krejci412ddfa2018-11-23 11:44:11 +01002826 } else if (base) {
2827 /* inherit */
Michal Vasko004d3152020-06-11 19:59:22 +02002828 lref->require_instance = ((struct lysc_type_leafref *)base)->require_instance;
Radek Krejcia3045382018-11-22 14:30:31 +01002829 } else {
2830 /* default is true */
Michal Vasko004d3152020-06-11 19:59:22 +02002831 lref->require_instance = 1;
Radek Krejcia3045382018-11-22 14:30:31 +01002832 }
2833 if (type_p->path) {
Michal Vasko1734be92020-09-22 08:55:10 +02002834 LY_CHECK_RET(lyxp_expr_dup(ctx->ctx, type_p->path, &lref->path));
Michal Vasko5d24f6c2020-10-13 13:49:06 +02002835 LY_CHECK_RET(lysc_prefixes_compile(type_p->path->expr, strlen(type_p->path->expr), type_p->pmod,
2836 &lref->prefixes));
Radek Krejcia3045382018-11-22 14:30:31 +01002837 } else if (base) {
Michal Vasko1734be92020-09-22 08:55:10 +02002838 LY_CHECK_RET(lyxp_expr_dup(ctx->ctx, ((struct lysc_type_leafref *)base)->path, &lref->path));
Michal Vasko5d24f6c2020-10-13 13:49:06 +02002839 LY_CHECK_RET(lysc_prefixes_dup(((struct lysc_type_leafref *)base)->prefixes, &lref->prefixes));
Radek Krejcia3045382018-11-22 14:30:31 +01002840 } else if (tpdfname) {
2841 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "path", "leafref type ", tpdfname);
2842 return LY_EVALID;
2843 } else {
2844 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "path", "leafref type", "");
Radek Krejcia3045382018-11-22 14:30:31 +01002845 return LY_EVALID;
2846 }
Radek Krejcia3045382018-11-22 14:30:31 +01002847 break;
Radek Krejci16c0f822018-11-16 10:46:10 +01002848 case LY_TYPE_INST:
2849 /* RFC 7950 9.9.3 - require-instance */
2850 if (type_p->flags & LYS_SET_REQINST) {
Michal Vasko22df3f02020-08-24 13:29:22 +02002851 ((struct lysc_type_instanceid *)(*type))->require_instance = type_p->require_instance;
Radek Krejci16c0f822018-11-16 10:46:10 +01002852 } else {
2853 /* default is true */
Michal Vasko22df3f02020-08-24 13:29:22 +02002854 ((struct lysc_type_instanceid *)(*type))->require_instance = 1;
Radek Krejci16c0f822018-11-16 10:46:10 +01002855 }
Radek Krejci16c0f822018-11-16 10:46:10 +01002856 break;
Radek Krejcicdfecd92018-11-26 11:27:32 +01002857 case LY_TYPE_UNION:
Michal Vasko22df3f02020-08-24 13:29:22 +02002858 un = (struct lysc_type_union *)(*type);
Radek Krejcicdfecd92018-11-26 11:27:32 +01002859
2860 /* RFC 7950 7.4 - type */
2861 if (type_p->types) {
2862 if (base) {
2863 /* only the directly derived union can contain types specification */
2864 if (tpdfname) {
2865 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002866 "Invalid type substatement for the type \"%s\" not directly derived from union built-in type.",
2867 tpdfname);
Radek Krejcicdfecd92018-11-26 11:27:32 +01002868 } else {
2869 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002870 "Invalid type substatement for the type not directly derived from union built-in type.");
Radek Krejcicdfecd92018-11-26 11:27:32 +01002871 }
2872 return LY_EVALID;
2873 }
2874 /* compile the type */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002875 LY_ARRAY_CREATE_RET(ctx->ctx, un->types, LY_ARRAY_COUNT(type_p->types), LY_EVALID);
2876 for (LY_ARRAY_COUNT_TYPE u = 0, additional = 0; u < LY_ARRAY_COUNT(type_p->types); ++u) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02002877 LY_CHECK_RET(lys_compile_type(ctx, context_pnode, context_flags, context_mod, context_name,
Michal Vasko69730152020-10-09 16:30:07 +02002878 &type_p->types[u], &un->types[u + additional], NULL, NULL));
Radek Krejcicdfecd92018-11-26 11:27:32 +01002879 if (un->types[u + additional]->basetype == LY_TYPE_UNION) {
2880 /* add space for additional types from the union subtype */
2881 un_aux = (struct lysc_type_union *)un->types[u + additional];
Michal Vasko22df3f02020-08-24 13:29:22 +02002882 LY_ARRAY_RESIZE_ERR_RET(ctx->ctx, un->types, (*((uint64_t *)(type_p->types) - 1)) + additional + LY_ARRAY_COUNT(un_aux->types) - 1,
Michal Vasko69730152020-10-09 16:30:07 +02002883 lysc_type_free(ctx->ctx, (struct lysc_type *)un_aux), LY_EMEM);
Radek Krejcicdfecd92018-11-26 11:27:32 +01002884
2885 /* copy subtypes of the subtype union */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002886 for (LY_ARRAY_COUNT_TYPE v = 0; v < LY_ARRAY_COUNT(un_aux->types); ++v) {
Radek Krejcicdfecd92018-11-26 11:27:32 +01002887 if (un_aux->types[v]->basetype == LY_TYPE_LEAFREF) {
2888 /* duplicate the whole structure because of the instance-specific path resolving for realtype */
2889 un->types[u + additional] = calloc(1, sizeof(struct lysc_type_leafref));
Michal Vasko22df3f02020-08-24 13:29:22 +02002890 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 +02002891 lref = (struct lysc_type_leafref *)un->types[u + additional];
2892
2893 lref->basetype = LY_TYPE_LEAFREF;
Michal Vasko1734be92020-09-22 08:55:10 +02002894 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 +02002895 lref->refcount = 1;
Michal Vasko22df3f02020-08-24 13:29:22 +02002896 lref->require_instance = ((struct lysc_type_leafref *)un_aux->types[v])->require_instance;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02002897 LY_CHECK_RET(lysc_prefixes_dup(((struct lysc_type_leafref *)un_aux->types[v])->prefixes,
2898 &lref->prefixes));
Radek Krejcicdfecd92018-11-26 11:27:32 +01002899 /* TODO extensions */
2900
2901 } else {
2902 un->types[u + additional] = un_aux->types[v];
2903 ++un_aux->types[v]->refcount;
2904 }
2905 ++additional;
2906 LY_ARRAY_INCREMENT(un->types);
2907 }
2908 /* compensate u increment in main loop */
2909 --additional;
2910
2911 /* free the replaced union subtype */
Michal Vasko22df3f02020-08-24 13:29:22 +02002912 lysc_type_free(ctx->ctx, (struct lysc_type *)un_aux);
Radek Krejcicdfecd92018-11-26 11:27:32 +01002913 } else {
2914 LY_ARRAY_INCREMENT(un->types);
2915 }
Radek Krejcicdfecd92018-11-26 11:27:32 +01002916 }
2917 }
2918
2919 if (!base && !type_p->flags) {
2920 /* type derived from union built-in type must contain at least one type */
2921 if (tpdfname) {
2922 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "type", "union type ", tpdfname);
2923 } else {
2924 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "type", "union type", "");
Radek Krejcicdfecd92018-11-26 11:27:32 +01002925 }
2926 return LY_EVALID;
2927 }
Radek Krejcicdfecd92018-11-26 11:27:32 +01002928 break;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002929 case LY_TYPE_BOOL:
2930 case LY_TYPE_EMPTY:
2931 case LY_TYPE_UNKNOWN: /* just to complete switch */
2932 break;
2933 }
Michal Vasko1734be92020-09-22 08:55:10 +02002934
2935 if (tpdfname) {
2936 switch (basetype) {
2937 case LY_TYPE_BINARY:
2938 type_p->compiled = *type;
2939 *type = calloc(1, sizeof(struct lysc_type_bin));
2940 break;
2941 case LY_TYPE_BITS:
2942 type_p->compiled = *type;
2943 *type = calloc(1, sizeof(struct lysc_type_bits));
2944 break;
2945 case LY_TYPE_DEC64:
2946 type_p->compiled = *type;
2947 *type = calloc(1, sizeof(struct lysc_type_dec));
2948 break;
2949 case LY_TYPE_STRING:
2950 type_p->compiled = *type;
2951 *type = calloc(1, sizeof(struct lysc_type_str));
2952 break;
2953 case LY_TYPE_ENUM:
2954 type_p->compiled = *type;
2955 *type = calloc(1, sizeof(struct lysc_type_enum));
2956 break;
2957 case LY_TYPE_INT8:
2958 case LY_TYPE_UINT8:
2959 case LY_TYPE_INT16:
2960 case LY_TYPE_UINT16:
2961 case LY_TYPE_INT32:
2962 case LY_TYPE_UINT32:
2963 case LY_TYPE_INT64:
2964 case LY_TYPE_UINT64:
2965 type_p->compiled = *type;
2966 *type = calloc(1, sizeof(struct lysc_type_num));
2967 break;
2968 case LY_TYPE_IDENT:
2969 type_p->compiled = *type;
2970 *type = calloc(1, sizeof(struct lysc_type_identityref));
2971 break;
2972 case LY_TYPE_LEAFREF:
2973 type_p->compiled = *type;
2974 *type = calloc(1, sizeof(struct lysc_type_leafref));
2975 break;
2976 case LY_TYPE_INST:
2977 type_p->compiled = *type;
2978 *type = calloc(1, sizeof(struct lysc_type_instanceid));
2979 break;
2980 case LY_TYPE_UNION:
2981 type_p->compiled = *type;
2982 *type = calloc(1, sizeof(struct lysc_type_union));
2983 break;
2984 case LY_TYPE_BOOL:
2985 case LY_TYPE_EMPTY:
2986 case LY_TYPE_UNKNOWN: /* just to complete switch */
2987 break;
2988 }
2989 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002990 LY_CHECK_ERR_RET(!(*type), LOGMEM(ctx->ctx), LY_EMEM);
Michal Vasko1734be92020-09-22 08:55:10 +02002991
2992cleanup:
Radek Krejcic5c27e52018-11-15 14:38:11 +01002993 return ret;
2994}
2995
Radek Krejcia3045382018-11-22 14:30:31 +01002996/**
2997 * @brief Compile information about the leaf/leaf-list's type.
2998 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02002999 * @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 +01003000 * @param[in] context_flags Flags of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
3001 * @param[in] context_mod Module of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
3002 * @param[in] context_name Name of the context node or referencing typedef for logging.
3003 * @param[in] type_p Parsed type to compile.
Radek Krejcia3045382018-11-22 14:30:31 +01003004 * @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 +01003005 * @param[out] units Storage for inheriting units value from the typedefs the current type derives from.
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003006 * @param[out] dflt Default value for the type.
Radek Krejcia3045382018-11-22 14:30:31 +01003007 * @return LY_ERR value.
3008 */
Radek Krejcic5c27e52018-11-15 14:38:11 +01003009static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02003010lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags,
Radek Krejci0f969882020-08-21 16:56:47 +02003011 struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p,
Michal Vasko7f45cf22020-10-01 12:49:44 +02003012 struct lysc_type **type, const char **units, struct lysp_qname **dflt)
Radek Krejci19a96102018-11-15 13:38:09 +01003013{
3014 LY_ERR ret = LY_SUCCESS;
Radek Krejci857189e2020-09-01 13:26:36 +02003015 ly_bool dummyloops = 0;
Radek Krejci19a96102018-11-15 13:38:09 +01003016 struct type_context {
3017 const struct lysp_tpdf *tpdf;
3018 struct lysp_node *node;
3019 struct lysp_module *mod;
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003020 } *tctx, *tctx_prev = NULL, *tctx_iter;
Radek Krejci19a96102018-11-15 13:38:09 +01003021 LY_DATA_TYPE basetype = LY_TYPE_UNKNOWN;
Radek Krejcic5c27e52018-11-15 14:38:11 +01003022 struct lysc_type *base = NULL, *prev_type;
Radek Krejci19a96102018-11-15 13:38:09 +01003023 struct ly_set tpdf_chain = {0};
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003024
Radek Krejci19a96102018-11-15 13:38:09 +01003025 (*type) = NULL;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003026 if (dflt) {
3027 *dflt = NULL;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003028 }
Radek Krejci19a96102018-11-15 13:38:09 +01003029
3030 tctx = calloc(1, sizeof *tctx);
3031 LY_CHECK_ERR_RET(!tctx, LOGMEM(ctx->ctx), LY_EMEM);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003032 for (ret = lysp_type_find(type_p->name, context_pnode, ctx->pmod, &basetype, &tctx->tpdf, &tctx->node, &tctx->mod);
Radek Krejci19a96102018-11-15 13:38:09 +01003033 ret == LY_SUCCESS;
3034 ret = lysp_type_find(tctx_prev->tpdf->type.name, tctx_prev->node, tctx_prev->mod,
Michal Vasko69730152020-10-09 16:30:07 +02003035 &basetype, &tctx->tpdf, &tctx->node, &tctx->mod)) {
Radek Krejci19a96102018-11-15 13:38:09 +01003036 if (basetype) {
3037 break;
3038 }
3039
3040 /* check status */
Radek Krejcicdfecd92018-11-26 11:27:32 +01003041 ret = lysc_check_status(ctx, context_flags, context_mod, context_name,
Michal Vasko69730152020-10-09 16:30:07 +02003042 tctx->tpdf->flags, tctx->mod, tctx->node ? tctx->node->name : tctx->tpdf->name);
Radek Krejci87e25252020-09-15 13:28:31 +02003043 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01003044
Radek Krejcicdfecd92018-11-26 11:27:32 +01003045 if (units && !*units) {
3046 /* inherit units */
Radek Krejci87e25252020-09-15 13:28:31 +02003047 DUP_STRING(ctx->ctx, tctx->tpdf->units, *units, ret);
3048 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
Radek Krejcicdfecd92018-11-26 11:27:32 +01003049 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02003050 if (dflt && !*dflt && tctx->tpdf->dflt.str) {
Radek Krejcicdfecd92018-11-26 11:27:32 +01003051 /* inherit default */
Michal Vasko7f45cf22020-10-01 12:49:44 +02003052 *dflt = (struct lysp_qname *)&tctx->tpdf->dflt;
Radek Krejcicdfecd92018-11-26 11:27:32 +01003053 }
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003054 if (dummyloops && (!units || *units) && dflt && *dflt) {
Michal Vasko22df3f02020-08-24 13:29:22 +02003055 basetype = ((struct type_context *)tpdf_chain.objs[tpdf_chain.count - 1])->tpdf->type.compiled->basetype;
Radek Krejcicdfecd92018-11-26 11:27:32 +01003056 break;
3057 }
3058
Radek Krejci19a96102018-11-15 13:38:09 +01003059 if (tctx->tpdf->type.compiled) {
Radek Krejcicdfecd92018-11-26 11:27:32 +01003060 /* it is not necessary to continue, the rest of the chain was already compiled,
3061 * but we still may need to inherit default and units values, so start dummy loops */
Radek Krejci19a96102018-11-15 13:38:09 +01003062 basetype = tctx->tpdf->type.compiled->basetype;
Radek Krejci3d92e442020-10-12 12:48:13 +02003063 ret = ly_set_add(&tpdf_chain, tctx, 1, NULL);
Radek Krejci87e25252020-09-15 13:28:31 +02003064 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003065
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003066 if ((units && !*units) || (dflt && !*dflt)) {
Radek Krejcicdfecd92018-11-26 11:27:32 +01003067 dummyloops = 1;
3068 goto preparenext;
3069 } else {
3070 tctx = NULL;
3071 break;
3072 }
Radek Krejci19a96102018-11-15 13:38:09 +01003073 }
3074
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003075 /* circular typedef reference detection */
Radek Krejci1deb5be2020-08-26 16:43:36 +02003076 for (uint32_t u = 0; u < tpdf_chain.count; u++) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003077 /* local part */
Michal Vasko22df3f02020-08-24 13:29:22 +02003078 tctx_iter = (struct type_context *)tpdf_chain.objs[u];
Michal Vasko69730152020-10-09 16:30:07 +02003079 if ((tctx_iter->mod == tctx->mod) && (tctx_iter->node == tctx->node) && (tctx_iter->tpdf == tctx->tpdf)) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003080 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02003081 "Invalid \"%s\" type reference - circular chain of types detected.", tctx->tpdf->name);
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003082 free(tctx);
3083 ret = LY_EVALID;
3084 goto cleanup;
3085 }
3086 }
Radek Krejci1deb5be2020-08-26 16:43:36 +02003087 for (uint32_t u = 0; u < ctx->tpdf_chain.count; u++) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003088 /* global part for unions corner case */
Michal Vasko22df3f02020-08-24 13:29:22 +02003089 tctx_iter = (struct type_context *)ctx->tpdf_chain.objs[u];
Michal Vasko69730152020-10-09 16:30:07 +02003090 if ((tctx_iter->mod == tctx->mod) && (tctx_iter->node == tctx->node) && (tctx_iter->tpdf == tctx->tpdf)) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003091 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02003092 "Invalid \"%s\" type reference - circular chain of types detected.", tctx->tpdf->name);
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003093 free(tctx);
3094 ret = LY_EVALID;
3095 goto cleanup;
3096 }
3097 }
3098
Radek Krejci19a96102018-11-15 13:38:09 +01003099 /* store information for the following processing */
Radek Krejci3d92e442020-10-12 12:48:13 +02003100 ret = ly_set_add(&tpdf_chain, tctx, 1, NULL);
Radek Krejci87e25252020-09-15 13:28:31 +02003101 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01003102
Radek Krejcicdfecd92018-11-26 11:27:32 +01003103preparenext:
Radek Krejci19a96102018-11-15 13:38:09 +01003104 /* prepare next loop */
3105 tctx_prev = tctx;
3106 tctx = calloc(1, sizeof *tctx);
3107 LY_CHECK_ERR_RET(!tctx, LOGMEM(ctx->ctx), LY_EMEM);
3108 }
3109 free(tctx);
3110
3111 /* allocate type according to the basetype */
3112 switch (basetype) {
3113 case LY_TYPE_BINARY:
3114 *type = calloc(1, sizeof(struct lysc_type_bin));
Radek Krejci19a96102018-11-15 13:38:09 +01003115 break;
3116 case LY_TYPE_BITS:
3117 *type = calloc(1, sizeof(struct lysc_type_bits));
Radek Krejci19a96102018-11-15 13:38:09 +01003118 break;
3119 case LY_TYPE_BOOL:
3120 case LY_TYPE_EMPTY:
3121 *type = calloc(1, sizeof(struct lysc_type));
3122 break;
3123 case LY_TYPE_DEC64:
3124 *type = calloc(1, sizeof(struct lysc_type_dec));
3125 break;
3126 case LY_TYPE_ENUM:
3127 *type = calloc(1, sizeof(struct lysc_type_enum));
Radek Krejci19a96102018-11-15 13:38:09 +01003128 break;
3129 case LY_TYPE_IDENT:
3130 *type = calloc(1, sizeof(struct lysc_type_identityref));
3131 break;
3132 case LY_TYPE_INST:
3133 *type = calloc(1, sizeof(struct lysc_type_instanceid));
3134 break;
3135 case LY_TYPE_LEAFREF:
3136 *type = calloc(1, sizeof(struct lysc_type_leafref));
3137 break;
3138 case LY_TYPE_STRING:
3139 *type = calloc(1, sizeof(struct lysc_type_str));
Radek Krejci19a96102018-11-15 13:38:09 +01003140 break;
3141 case LY_TYPE_UNION:
3142 *type = calloc(1, sizeof(struct lysc_type_union));
3143 break;
3144 case LY_TYPE_INT8:
3145 case LY_TYPE_UINT8:
3146 case LY_TYPE_INT16:
3147 case LY_TYPE_UINT16:
3148 case LY_TYPE_INT32:
3149 case LY_TYPE_UINT32:
3150 case LY_TYPE_INT64:
3151 case LY_TYPE_UINT64:
3152 *type = calloc(1, sizeof(struct lysc_type_num));
Radek Krejci19a96102018-11-15 13:38:09 +01003153 break;
3154 case LY_TYPE_UNKNOWN:
3155 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02003156 "Referenced type \"%s\" not found.", tctx_prev ? tctx_prev->tpdf->type.name : type_p->name);
Radek Krejci19a96102018-11-15 13:38:09 +01003157 ret = LY_EVALID;
3158 goto cleanup;
3159 }
3160 LY_CHECK_ERR_GOTO(!(*type), LOGMEM(ctx->ctx), cleanup);
Radek Krejcicdfecd92018-11-26 11:27:32 +01003161 if (~type_substmt_map[basetype] & type_p->flags) {
Radek Krejci19a96102018-11-15 13:38:09 +01003162 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid type restrictions for %s type.",
Michal Vasko69730152020-10-09 16:30:07 +02003163 ly_data_type2str[basetype]);
Radek Krejci19a96102018-11-15 13:38:09 +01003164 free(*type);
3165 (*type) = NULL;
3166 ret = LY_EVALID;
3167 goto cleanup;
3168 }
3169
3170 /* get restrictions from the referred typedefs */
Radek Krejci1deb5be2020-08-26 16:43:36 +02003171 for (uint32_t u = tpdf_chain.count - 1; u + 1 > 0; --u) {
Michal Vasko22df3f02020-08-24 13:29:22 +02003172 tctx = (struct type_context *)tpdf_chain.objs[u];
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003173
3174 /* remember the typedef context for circular check */
Radek Krejci3d92e442020-10-12 12:48:13 +02003175 ret = ly_set_add(&ctx->tpdf_chain, tctx, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003176 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003177
Radek Krejci43699232018-11-23 14:59:46 +01003178 if (tctx->tpdf->type.compiled) {
Radek Krejci19a96102018-11-15 13:38:09 +01003179 base = tctx->tpdf->type.compiled;
3180 continue;
Michal Vasko69730152020-10-09 16:30:07 +02003181 } else if ((basetype != LY_TYPE_LEAFREF) && (u != tpdf_chain.count - 1) && !(tctx->tpdf->type.flags)) {
Radek Krejci19a96102018-11-15 13:38:09 +01003182 /* no change, just use the type information from the base */
Michal Vasko22df3f02020-08-24 13:29:22 +02003183 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 +01003184 ++base->refcount;
3185 continue;
3186 }
3187
3188 ++(*type)->refcount;
Radek Krejci43699232018-11-23 14:59:46 +01003189 if (~type_substmt_map[basetype] & tctx->tpdf->type.flags) {
3190 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid type \"%s\" restriction(s) for %s type.",
Michal Vasko69730152020-10-09 16:30:07 +02003191 tctx->tpdf->name, ly_data_type2str[basetype]);
Radek Krejci43699232018-11-23 14:59:46 +01003192 ret = LY_EVALID;
3193 goto cleanup;
Michal Vasko69730152020-10-09 16:30:07 +02003194 } else if ((basetype == LY_TYPE_EMPTY) && tctx->tpdf->dflt.str) {
Radek Krejci43699232018-11-23 14:59:46 +01003195 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003196 "Invalid type \"%s\" - \"empty\" type must not have a default value (%s).",
3197 tctx->tpdf->name, tctx->tpdf->dflt.str);
Radek Krejci43699232018-11-23 14:59:46 +01003198 ret = LY_EVALID;
3199 goto cleanup;
3200 }
3201
Radek Krejci19a96102018-11-15 13:38:09 +01003202 (*type)->basetype = basetype;
Radek Krejcie7b95092019-05-15 11:03:07 +02003203 /* TODO user type plugins */
3204 (*type)->plugin = &ly_builtin_type_plugins[basetype];
Radek Krejcic5c27e52018-11-15 14:38:11 +01003205 prev_type = *type;
Michal Vaskoe9c050f2020-10-06 14:01:23 +02003206 ret = lys_compile_type_(ctx, tctx->node, tctx->tpdf->flags, tctx->mod, tctx->tpdf->name,
3207 &((struct lysp_tpdf *)tctx->tpdf)->type, basetype, tctx->tpdf->name, base, type);
Radek Krejcic5c27e52018-11-15 14:38:11 +01003208 LY_CHECK_GOTO(ret, cleanup);
3209 base = prev_type;
Radek Krejci19a96102018-11-15 13:38:09 +01003210 }
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003211 /* remove the processed typedef contexts from the stack for circular check */
3212 ctx->tpdf_chain.count = ctx->tpdf_chain.count - tpdf_chain.count;
Radek Krejci19a96102018-11-15 13:38:09 +01003213
Radek Krejcic5c27e52018-11-15 14:38:11 +01003214 /* process the type definition in leaf */
Michal Vasko69730152020-10-09 16:30:07 +02003215 if (type_p->flags || !base || (basetype == LY_TYPE_LEAFREF)) {
Radek Krejcia3045382018-11-22 14:30:31 +01003216 /* get restrictions from the node itself */
Radek Krejci19a96102018-11-15 13:38:09 +01003217 (*type)->basetype = basetype;
Radek Krejcie7b95092019-05-15 11:03:07 +02003218 /* TODO user type plugins */
3219 (*type)->plugin = &ly_builtin_type_plugins[basetype];
Radek Krejci19a96102018-11-15 13:38:09 +01003220 ++(*type)->refcount;
Michal Vaskoe9c050f2020-10-06 14:01:23 +02003221 ret = lys_compile_type_(ctx, context_pnode, context_flags, context_mod, context_name, type_p, basetype, NULL,
3222 base, type);
Radek Krejcic5c27e52018-11-15 14:38:11 +01003223 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko69730152020-10-09 16:30:07 +02003224 } else if ((basetype != LY_TYPE_BOOL) && (basetype != LY_TYPE_EMPTY)) {
Radek Krejci19a96102018-11-15 13:38:09 +01003225 /* no specific restriction in leaf's type definition, copy from the base */
3226 free(*type);
3227 (*type) = base;
3228 ++(*type)->refcount;
Radek Krejci19a96102018-11-15 13:38:09 +01003229 }
3230
Radek Krejci0935f412019-08-20 16:15:18 +02003231 COMPILE_EXTS_GOTO(ctx, type_p->exts, (*type)->exts, (*type), LYEXT_PAR_TYPE, ret, cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01003232
3233cleanup:
3234 ly_set_erase(&tpdf_chain, free);
3235 return ret;
3236}
3237
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003238/**
3239 * @brief Compile status information of the given node.
3240 *
3241 * To simplify getting status of the node, the flags are set following inheritance rules, so all the nodes
3242 * has the status correctly set during the compilation.
3243 *
3244 * @param[in] ctx Compile context
3245 * @param[in,out] node_flags Flags of the compiled node which status is supposed to be resolved.
3246 * If the status was set explicitly on the node, it is already set in the flags value and we just check
3247 * the compatibility with the parent's status value.
3248 * @param[in] parent_flags Flags of the parent node to check/inherit the status value.
3249 * @return LY_ERR value.
3250 */
3251static LY_ERR
3252lys_compile_status(struct lysc_ctx *ctx, uint16_t *node_flags, uint16_t parent_flags)
3253{
3254 /* status - it is not inherited by specification, but it does not make sense to have
3255 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
3256 if (!((*node_flags) & LYS_STATUS_MASK)) {
3257 if (parent_flags & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) {
3258 if ((parent_flags & 0x3) != 0x3) {
3259 /* do not print the warning when inheriting status from uses - the uses_status value has a special
3260 * combination of bits (0x3) which marks the uses_status value */
3261 LOGWRN(ctx->ctx, "Missing explicit \"%s\" status that was already specified in parent, inheriting.",
Radek Krejci0f969882020-08-21 16:56:47 +02003262 (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003263 }
3264 (*node_flags) |= parent_flags & LYS_STATUS_MASK;
3265 } else {
3266 (*node_flags) |= LYS_STATUS_CURR;
3267 }
3268 } else if (parent_flags & LYS_STATUS_MASK) {
3269 /* check status compatibility with the parent */
3270 if ((parent_flags & LYS_STATUS_MASK) > ((*node_flags) & LYS_STATUS_MASK)) {
3271 if ((*node_flags) & LYS_STATUS_CURR) {
3272 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003273 "A \"current\" status is in conflict with the parent's \"%s\" status.",
Radek Krejci0f969882020-08-21 16:56:47 +02003274 (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003275 } else { /* LYS_STATUS_DEPRC */
3276 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003277 "A \"deprecated\" status is in conflict with the parent's \"obsolete\" status.");
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003278 }
3279 return LY_EVALID;
3280 }
3281 }
3282 return LY_SUCCESS;
3283}
3284
Radek Krejci8cce8532019-03-05 11:27:45 +01003285/**
3286 * @brief Check uniqness of the node/action/notification name.
3287 *
3288 * Data nodes, actions/RPCs and Notifications are stored separately (in distinguish lists) in the schema
3289 * structures, but they share the namespace so we need to check their name collisions.
3290 *
3291 * @param[in] ctx Compile context.
Michal Vasko20424b42020-08-31 12:29:38 +02003292 * @param[in] parent Parent of the nodes to check, can be NULL.
Radek Krejci8cce8532019-03-05 11:27:45 +01003293 * @param[in] name Name of the item to find in the given lists.
Michal Vasko20424b42020-08-31 12:29:38 +02003294 * @param[in] exclude Node that was just added that should be excluded from the name checking.
Radek Krejci8cce8532019-03-05 11:27:45 +01003295 * @return LY_SUCCESS in case of unique name, LY_EEXIST otherwise.
3296 */
3297static LY_ERR
Michal Vasko20424b42020-08-31 12:29:38 +02003298lys_compile_node_uniqness(struct lysc_ctx *ctx, const struct lysc_node *parent, const char *name,
3299 const struct lysc_node *exclude)
Radek Krejci8cce8532019-03-05 11:27:45 +01003300{
Michal Vasko20424b42020-08-31 12:29:38 +02003301 const struct lysc_node *iter, *iter2;
3302 const struct lysc_action *actions;
3303 const struct lysc_notif *notifs;
3304 uint32_t getnext_flags;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003305 LY_ARRAY_COUNT_TYPE u;
Radek Krejci8cce8532019-03-05 11:27:45 +01003306
Michal Vasko20424b42020-08-31 12:29:38 +02003307#define CHECK_NODE(iter, exclude, name) (iter != (void *)exclude && (iter)->module == exclude->module && !strcmp(name, (iter)->name))
3308
3309 if (exclude->nodetype == LYS_CASE) {
3310 /* check restricted only to all the cases */
3311 assert(parent->nodetype == LYS_CHOICE);
3312 LY_LIST_FOR(lysc_node_children(parent, 0), iter) {
3313 if (CHECK_NODE(iter, exclude, name)) {
3314 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPIDENT, name, "case");
3315 return LY_EEXIST;
3316 }
3317 }
3318
3319 return LY_SUCCESS;
3320 }
3321
3322 /* no reason for our parent to be choice anymore */
3323 assert(!parent || (parent->nodetype != LYS_CHOICE));
3324
3325 if (parent && (parent->nodetype == LYS_CASE)) {
3326 /* move to the first data definition parent */
3327 parent = lysc_data_parent(parent);
3328 }
3329
3330 getnext_flags = LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE;
3331 if (parent && (parent->nodetype & (LYS_RPC | LYS_ACTION)) && (exclude->flags & LYS_CONFIG_R)) {
3332 getnext_flags |= LYS_GETNEXT_OUTPUT;
3333 }
3334
3335 iter = NULL;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003336 while ((iter = lys_getnext(iter, parent, ctx->cur_mod->compiled, getnext_flags))) {
Michal Vasko20424b42020-08-31 12:29:38 +02003337 if (CHECK_NODE(iter, exclude, name)) {
Radek Krejci8cce8532019-03-05 11:27:45 +01003338 goto error;
3339 }
Michal Vasko20424b42020-08-31 12:29:38 +02003340
3341 /* we must compare with both the choice and all its nested data-definiition nodes (but not recursively) */
3342 if (iter->nodetype == LYS_CHOICE) {
3343 iter2 = NULL;
3344 while ((iter2 = lys_getnext(iter2, iter, NULL, LYS_GETNEXT_NOSTATECHECK))) {
3345 if (CHECK_NODE(iter2, exclude, name)) {
3346 goto error;
3347 }
3348 }
3349 }
Radek Krejci8cce8532019-03-05 11:27:45 +01003350 }
Michal Vasko20424b42020-08-31 12:29:38 +02003351
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003352 actions = parent ? lysc_node_actions(parent) : ctx->cur_mod->compiled->rpcs;
Radek Krejci8cce8532019-03-05 11:27:45 +01003353 LY_ARRAY_FOR(actions, u) {
Michal Vasko20424b42020-08-31 12:29:38 +02003354 if (CHECK_NODE(&actions[u], exclude, name)) {
Radek Krejci8cce8532019-03-05 11:27:45 +01003355 goto error;
3356 }
3357 }
Michal Vasko20424b42020-08-31 12:29:38 +02003358
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003359 notifs = parent ? lysc_node_notifs(parent) : ctx->cur_mod->compiled->notifs;
Radek Krejci8cce8532019-03-05 11:27:45 +01003360 LY_ARRAY_FOR(notifs, u) {
Michal Vasko20424b42020-08-31 12:29:38 +02003361 if (CHECK_NODE(&notifs[u], exclude, name)) {
Radek Krejci8cce8532019-03-05 11:27:45 +01003362 goto error;
3363 }
3364 }
3365 return LY_SUCCESS;
Michal Vasko20424b42020-08-31 12:29:38 +02003366
Radek Krejci8cce8532019-03-05 11:27:45 +01003367error:
Michal Vaskoa3881362020-01-21 15:57:35 +01003368 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPIDENT, name, "data definition/RPC/action/notification");
Radek Krejci8cce8532019-03-05 11:27:45 +01003369 return LY_EEXIST;
Michal Vasko20424b42020-08-31 12:29:38 +02003370
3371#undef CHECK_NODE
Radek Krejci8cce8532019-03-05 11:27:45 +01003372}
3373
Michal Vasko7f45cf22020-10-01 12:49:44 +02003374static LY_ERR lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *parent,
3375 uint16_t uses_status, struct ly_set *child_set);
3376
3377static LY_ERR lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode,
3378 const struct lysc_node *parent, struct lysp_node **dev_pnode, ly_bool *not_supported);
3379
3380static LY_ERR lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node);
3381
3382static void lysp_dev_node_free(const struct ly_ctx *ctx, struct lysp_node *dev_pnode);
Radek Krejci19a96102018-11-15 13:38:09 +01003383
Radek Krejcia3045382018-11-22 14:30:31 +01003384/**
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003385 * @brief Compile parsed RPC/action schema node information.
3386 * @param[in] ctx Compile context
Radek Krejci43981a32019-04-12 09:44:11 +02003387 * @param[in] action_p Parsed RPC/action schema node.
Radek Krejci43981a32019-04-12 09:44:11 +02003388 * @param[in] parent Parent node of the action, NULL in case of RPC (top-level action)
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003389 * @param[in,out] action Prepared (empty) compiled action structure to fill.
3390 * @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).
3391 * Zero means no uses, non-zero value with no status bit set mean the default status.
Michal Vasko7f45cf22020-10-01 12:49:44 +02003392 * @return LY_SUCCESS on success,
3393 * @return LY_EVALID on validation error,
3394 * @return LY_EDENIED on not-supported deviation.
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003395 */
3396static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02003397lys_compile_action(struct lysc_ctx *ctx, struct lysp_action *action_p,
Radek Krejci0f969882020-08-21 16:56:47 +02003398 struct lysc_node *parent, struct lysc_action *action, uint16_t uses_status)
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003399{
3400 LY_ERR ret = LY_SUCCESS;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003401 struct lysp_node *child_p, *dev_pnode = NULL, *dev_input_p = NULL, *dev_output_p = NULL;
3402 struct lysp_action *orig_action_p = action_p;
3403 struct lysp_action_inout *inout_p;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003404 LY_ARRAY_COUNT_TYPE u;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003405 ly_bool not_supported;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003406 uint32_t opt_prev = ctx->options;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003407
Radek Krejci327de162019-06-14 12:52:07 +02003408 lysc_update_path(ctx, parent, action_p->name);
3409
Michal Vasko7f45cf22020-10-01 12:49:44 +02003410 /* apply deviation on the action/RPC */
3411 LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)action_p, parent, &dev_pnode, &not_supported));
3412 if (not_supported) {
3413 lysc_update_path(ctx, NULL, NULL);
3414 return LY_EDENIED;
3415 } else if (dev_pnode) {
3416 action_p = (struct lysp_action *)dev_pnode;
3417 }
3418
Michal Vasko20424b42020-08-31 12:29:38 +02003419 /* member needed for uniqueness check lys_getnext() */
3420 action->nodetype = parent ? LYS_ACTION : LYS_RPC;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003421 action->module = ctx->cur_mod;
Michal Vasko20424b42020-08-31 12:29:38 +02003422 action->parent = parent;
3423
3424 LY_CHECK_RET(lys_compile_node_uniqness(ctx, parent, action_p->name, (struct lysc_node *)action));
Radek Krejci8cce8532019-03-05 11:27:45 +01003425
Radek Krejci90d4e922020-10-12 15:55:33 +02003426 if (ctx->options & (LYS_COMPILE_RPC_MASK | LYS_COMPILE_NOTIFICATION)) {
Radek Krejci05b774b2019-02-25 13:26:18 +01003427 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003428 "Action \"%s\" is placed inside %s.", action_p->name,
Radek Krejci90d4e922020-10-12 15:55:33 +02003429 ctx->options & LYS_COMPILE_RPC_MASK ? "another RPC/action" : "notification");
Radek Krejci05b774b2019-02-25 13:26:18 +01003430 return LY_EVALID;
3431 }
3432
Radek Krejci90d4e922020-10-12 15:55:33 +02003433 action->sp = orig_action_p;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003434 action->flags = action_p->flags & LYS_FLAGS_COMPILED_MASK;
3435
3436 /* status - it is not inherited by specification, but it does not make sense to have
3437 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
Michal Vaskocc048b22020-03-27 15:52:38 +01003438 LY_CHECK_RET(lys_compile_status(ctx, &action->flags, uses_status ? uses_status : (parent ? parent->flags : 0)));
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003439
Radek Krejci011e4aa2020-09-04 15:22:31 +02003440 DUP_STRING_GOTO(ctx->ctx, action_p->name, action->name, ret, cleanup);
3441 DUP_STRING_GOTO(ctx->ctx, action_p->dsc, action->dsc, ret, cleanup);
3442 DUP_STRING_GOTO(ctx->ctx, action_p->ref, action->ref, ret, cleanup);
Radek Krejciec4da802019-05-02 13:02:41 +02003443 COMPILE_ARRAY_GOTO(ctx, action_p->iffeatures, action->iffeatures, u, lys_compile_iffeature, ret, cleanup);
Radek Krejci0935f412019-08-20 16:15:18 +02003444 COMPILE_EXTS_GOTO(ctx, action_p->exts, action->exts, action, LYEXT_PAR_NODE, ret, cleanup);
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003445
Michal Vasko7f45cf22020-10-01 12:49:44 +02003446 /* connect any action augments */
3447 LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)action));
3448
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003449 /* input */
Michal Vasko22df3f02020-08-24 13:29:22 +02003450 lysc_update_path(ctx, (struct lysc_node *)action, "input");
Michal Vasko7f45cf22020-10-01 12:49:44 +02003451
3452 /* apply deviations on input */
3453 LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)&action_p->input, (struct lysc_node *)action,
3454 &dev_input_p, &not_supported));
3455 if (not_supported) {
3456 inout_p = NULL;
3457 } else if (dev_input_p) {
3458 inout_p = (struct lysp_action_inout *)dev_input_p;
3459 } else {
3460 inout_p = &action_p->input;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003461 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02003462
3463 if (inout_p) {
3464 action->input.nodetype = LYS_INPUT;
3465 COMPILE_ARRAY_GOTO(ctx, inout_p->musts, action->input.musts, u, lys_compile_must, ret, cleanup);
3466 COMPILE_EXTS_GOTO(ctx, inout_p->exts, action->input_exts, &action->input, LYEXT_PAR_INPUT, ret, cleanup);
Radek Krejci90d4e922020-10-12 15:55:33 +02003467 ctx->options |= LYS_COMPILE_RPC_INPUT;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003468
3469 /* connect any input augments */
3470 LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)&action->input));
3471
3472 LY_LIST_FOR(inout_p->data, child_p) {
3473 LY_CHECK_RET(lys_compile_node(ctx, child_p, (struct lysc_node *)action, uses_status, NULL));
3474 }
3475 ctx->options = opt_prev;
3476 }
3477
Radek Krejci327de162019-06-14 12:52:07 +02003478 lysc_update_path(ctx, NULL, NULL);
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003479
3480 /* output */
Michal Vasko22df3f02020-08-24 13:29:22 +02003481 lysc_update_path(ctx, (struct lysc_node *)action, "output");
Michal Vasko7f45cf22020-10-01 12:49:44 +02003482
3483 /* apply deviations on output */
3484 LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)&action_p->output, (struct lysc_node *)action,
3485 &dev_output_p, &not_supported));
3486 if (not_supported) {
3487 inout_p = NULL;
3488 } else if (dev_output_p) {
3489 inout_p = (struct lysp_action_inout *)dev_output_p;
3490 } else {
3491 inout_p = &action_p->output;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003492 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02003493
3494 if (inout_p) {
3495 action->output.nodetype = LYS_OUTPUT;
3496 COMPILE_ARRAY_GOTO(ctx, inout_p->musts, action->output.musts, u, lys_compile_must, ret, cleanup);
3497 COMPILE_EXTS_GOTO(ctx, inout_p->exts, action->output_exts, &action->output, LYEXT_PAR_OUTPUT, ret, cleanup);
Radek Krejci90d4e922020-10-12 15:55:33 +02003498 ctx->options |= LYS_COMPILE_RPC_OUTPUT;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003499
3500 /* connect any output augments */
3501 LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)&action->output));
3502
3503 LY_LIST_FOR(inout_p->data, child_p) {
3504 LY_CHECK_RET(lys_compile_node(ctx, child_p, (struct lysc_node *)action, uses_status, NULL));
3505 }
3506 ctx->options = opt_prev;
3507 }
3508
Radek Krejci327de162019-06-14 12:52:07 +02003509 lysc_update_path(ctx, NULL, NULL);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003510
Radek Krejci90d4e922020-10-12 15:55:33 +02003511 if ((action->input.musts || action->output.musts) && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01003512 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003513 ret = ly_set_add(&ctx->xpath, action, 0, NULL);
3514 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003515 }
3516
Michal Vasko7f45cf22020-10-01 12:49:44 +02003517 lysc_update_path(ctx, NULL, NULL);
3518
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003519cleanup:
Michal Vasko7f45cf22020-10-01 12:49:44 +02003520 lysp_dev_node_free(ctx->ctx, dev_pnode);
3521 lysp_dev_node_free(ctx->ctx, dev_input_p);
3522 lysp_dev_node_free(ctx->ctx, dev_output_p);
Radek Krejciec4da802019-05-02 13:02:41 +02003523 ctx->options = opt_prev;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003524 return ret;
3525}
3526
3527/**
Radek Krejci43981a32019-04-12 09:44:11 +02003528 * @brief Compile parsed Notification schema node information.
Radek Krejcifc11bd72019-04-11 16:00:05 +02003529 * @param[in] ctx Compile context
Radek Krejci43981a32019-04-12 09:44:11 +02003530 * @param[in] notif_p Parsed Notification schema node.
Radek Krejci43981a32019-04-12 09:44:11 +02003531 * @param[in] parent Parent node of the Notification, NULL in case of top-level Notification
3532 * @param[in,out] notif Prepared (empty) compiled notification structure to fill.
3533 * @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 +02003534 * Zero means no uses, non-zero value with no status bit set mean the default status.
Michal Vasko7f45cf22020-10-01 12:49:44 +02003535 * @return LY_SUCCESS on success,
3536 * @return LY_EVALID on validation error,
3537 * @return LY_EDENIED on not-supported deviation.
Radek Krejcifc11bd72019-04-11 16:00:05 +02003538 */
3539static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02003540lys_compile_notif(struct lysc_ctx *ctx, struct lysp_notif *notif_p,
Radek Krejci0f969882020-08-21 16:56:47 +02003541 struct lysc_node *parent, struct lysc_notif *notif, uint16_t uses_status)
Radek Krejcifc11bd72019-04-11 16:00:05 +02003542{
3543 LY_ERR ret = LY_SUCCESS;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003544 struct lysp_node *child_p, *dev_pnode = NULL;
3545 struct lysp_notif *orig_notif_p = notif_p;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003546 LY_ARRAY_COUNT_TYPE u;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003547 ly_bool not_supported;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003548 uint32_t opt_prev = ctx->options;
Radek Krejcifc11bd72019-04-11 16:00:05 +02003549
Radek Krejci327de162019-06-14 12:52:07 +02003550 lysc_update_path(ctx, parent, notif_p->name);
3551
Michal Vasko7f45cf22020-10-01 12:49:44 +02003552 LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)notif_p, parent, &dev_pnode, &not_supported));
3553 if (not_supported) {
3554 lysc_update_path(ctx, NULL, NULL);
3555 return LY_EDENIED;
3556 } else if (dev_pnode) {
3557 notif_p = (struct lysp_notif *)dev_pnode;
3558 }
3559
Michal Vasko20424b42020-08-31 12:29:38 +02003560 /* member needed for uniqueness check lys_getnext() */
3561 notif->nodetype = LYS_NOTIF;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003562 notif->module = ctx->cur_mod;
Michal Vasko20424b42020-08-31 12:29:38 +02003563 notif->parent = parent;
3564
3565 LY_CHECK_RET(lys_compile_node_uniqness(ctx, parent, notif_p->name, (struct lysc_node *)notif));
Radek Krejcifc11bd72019-04-11 16:00:05 +02003566
Radek Krejci90d4e922020-10-12 15:55:33 +02003567 if (ctx->options & (LYS_COMPILE_RPC_MASK | LYS_COMPILE_NOTIFICATION)) {
Radek Krejcifc11bd72019-04-11 16:00:05 +02003568 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003569 "Notification \"%s\" is placed inside %s.", notif_p->name,
Radek Krejci90d4e922020-10-12 15:55:33 +02003570 ctx->options & LYS_COMPILE_RPC_MASK ? "RPC/action" : "another notification");
Radek Krejcifc11bd72019-04-11 16:00:05 +02003571 return LY_EVALID;
3572 }
3573
Radek Krejci90d4e922020-10-12 15:55:33 +02003574 notif->sp = orig_notif_p;
Radek Krejcifc11bd72019-04-11 16:00:05 +02003575 notif->flags = notif_p->flags & LYS_FLAGS_COMPILED_MASK;
3576
3577 /* status - it is not inherited by specification, but it does not make sense to have
3578 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003579 ret = lys_compile_status(ctx, &notif->flags, uses_status ? uses_status : (parent ? parent->flags : 0));
3580 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcifc11bd72019-04-11 16:00:05 +02003581
Radek Krejci011e4aa2020-09-04 15:22:31 +02003582 DUP_STRING_GOTO(ctx->ctx, notif_p->name, notif->name, ret, cleanup);
3583 DUP_STRING_GOTO(ctx->ctx, notif_p->dsc, notif->dsc, ret, cleanup);
3584 DUP_STRING_GOTO(ctx->ctx, notif_p->ref, notif->ref, ret, cleanup);
Radek Krejciec4da802019-05-02 13:02:41 +02003585 COMPILE_ARRAY_GOTO(ctx, notif_p->iffeatures, notif->iffeatures, u, lys_compile_iffeature, ret, cleanup);
Radek Krejcic71ac5b2019-09-10 15:34:22 +02003586 COMPILE_ARRAY_GOTO(ctx, notif_p->musts, notif->musts, u, lys_compile_must, ret, cleanup);
Radek Krejci90d4e922020-10-12 15:55:33 +02003587 if (notif_p->musts && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01003588 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003589 ret = ly_set_add(&ctx->xpath, notif, 0, NULL);
3590 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003591 }
Radek Krejci0935f412019-08-20 16:15:18 +02003592 COMPILE_EXTS_GOTO(ctx, notif_p->exts, notif->exts, notif, LYEXT_PAR_NODE, ret, cleanup);
Radek Krejcifc11bd72019-04-11 16:00:05 +02003593
Radek Krejci90d4e922020-10-12 15:55:33 +02003594 ctx->options |= LYS_COMPILE_NOTIFICATION;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003595
3596 /* connect any notification augments */
3597 LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)notif));
3598
Radek Krejcifc11bd72019-04-11 16:00:05 +02003599 LY_LIST_FOR(notif_p->data, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003600 ret = lys_compile_node(ctx, child_p, (struct lysc_node *)notif, uses_status, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003601 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcifc11bd72019-04-11 16:00:05 +02003602 }
3603
Radek Krejci327de162019-06-14 12:52:07 +02003604 lysc_update_path(ctx, NULL, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02003605
Radek Krejcifc11bd72019-04-11 16:00:05 +02003606cleanup:
Michal Vasko7f45cf22020-10-01 12:49:44 +02003607 lysp_dev_node_free(ctx->ctx, dev_pnode);
Radek Krejciec4da802019-05-02 13:02:41 +02003608 ctx->options = opt_prev;
Radek Krejcifc11bd72019-04-11 16:00:05 +02003609 return ret;
3610}
3611
3612/**
Radek Krejcia3045382018-11-22 14:30:31 +01003613 * @brief Compile parsed container node information.
3614 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02003615 * @param[in] pnode Parsed container node.
Radek Krejcia3045382018-11-22 14:30:31 +01003616 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
3617 * is enriched with the container-specific information.
3618 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3619 */
Radek Krejci19a96102018-11-15 13:38:09 +01003620static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02003621lys_compile_node_container(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci19a96102018-11-15 13:38:09 +01003622{
Michal Vasko7f45cf22020-10-01 12:49:44 +02003623 struct lysp_node_container *cont_p = (struct lysp_node_container *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02003624 struct lysc_node_container *cont = (struct lysc_node_container *)node;
Radek Krejci19a96102018-11-15 13:38:09 +01003625 struct lysp_node *child_p;
Michal Vaskoba417ac2020-08-06 14:48:20 +02003626 LY_ARRAY_COUNT_TYPE u;
Radek Krejci19a96102018-11-15 13:38:09 +01003627 LY_ERR ret = LY_SUCCESS;
3628
Radek Krejcife909632019-02-12 15:34:42 +01003629 if (cont_p->presence) {
Michal Vaskoba417ac2020-08-06 14:48:20 +02003630 /* explicit presence */
Radek Krejcife909632019-02-12 15:34:42 +01003631 cont->flags |= LYS_PRESENCE;
Michal Vaskoba417ac2020-08-06 14:48:20 +02003632 } else if (cont_p->musts) {
3633 /* container with a must condition */
Radek Krejci175f25b2020-08-13 12:02:36 +02003634 LOGWRN(ctx->ctx, "Container \"%s\" changed to presence because it has a meaning from its \"must\" condition.", cont_p->name);
3635 cont->flags |= LYS_PRESENCE;
3636 } else if (cont_p->when) {
3637 /* container with a when condition */
3638 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 +02003639 cont->flags |= LYS_PRESENCE;
3640 } else if (cont_p->parent) {
3641 if (cont_p->parent->nodetype == LYS_CHOICE) {
3642 /* container is an implicit case, so its existence decides the existence of the whole case */
Radek Krejci175f25b2020-08-13 12:02:36 +02003643 LOGWRN(ctx->ctx, "Container \"%s\" changed to presence because it has a meaning as a case of choice \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +02003644 cont_p->name, cont_p->parent->name);
Michal Vaskoba417ac2020-08-06 14:48:20 +02003645 cont->flags |= LYS_PRESENCE;
Michal Vasko69730152020-10-09 16:30:07 +02003646 } else if ((cont_p->parent->nodetype == LYS_CASE) &&
3647 (((struct lysp_node_case *)cont_p->parent)->child == pnode) && !cont_p->next) {
Michal Vaskoba417ac2020-08-06 14:48:20 +02003648 /* 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 +02003649 LOGWRN(ctx->ctx, "Container \"%s\" changed to presence because it has a meaning as a case of choice \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +02003650 cont_p->name, cont_p->parent->name);
Michal Vaskoba417ac2020-08-06 14:48:20 +02003651 cont->flags |= LYS_PRESENCE;
3652 }
Radek Krejcife909632019-02-12 15:34:42 +01003653 }
3654
Michal Vaskoba417ac2020-08-06 14:48:20 +02003655 /* more cases when the container has meaning but is kept NP for convenience:
3656 * - when condition
3657 * - direct child action/notification
3658 */
3659
Radek Krejci19a96102018-11-15 13:38:09 +01003660 LY_LIST_FOR(cont_p->child, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003661 ret = lys_compile_node(ctx, child_p, node, 0, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003662 LY_CHECK_GOTO(ret, done);
Radek Krejci19a96102018-11-15 13:38:09 +01003663 }
3664
Radek Krejcic71ac5b2019-09-10 15:34:22 +02003665 COMPILE_ARRAY_GOTO(ctx, cont_p->musts, cont->musts, u, lys_compile_must, ret, done);
Radek Krejci90d4e922020-10-12 15:55:33 +02003666 if (cont_p->musts && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01003667 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003668 ret = ly_set_add(&ctx->xpath, cont, 0, NULL);
3669 LY_CHECK_GOTO(ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003670 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02003671 COMPILE_OP_ARRAY_GOTO(ctx, cont_p->actions, cont->actions, node, u, lys_compile_action, 0, ret, done);
3672 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 +01003673
3674done:
3675 return ret;
3676}
3677
Radek Krejci33f72892019-02-21 10:36:58 +01003678/*
3679 * @brief Compile type in leaf/leaf-list node and do all the necessary checks.
3680 * @param[in] ctx Compile context.
3681 * @param[in] context_node Schema node where the type/typedef is placed to correctly find the base types.
3682 * @param[in] type_p Parsed type to compile.
Radek Krejci33f72892019-02-21 10:36:58 +01003683 * @param[in,out] leaf Compiled leaf structure (possibly cast leaf-list) to provide node information and to store the compiled type information.
3684 * @return LY_ERR value.
3685 */
3686static LY_ERR
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003687lys_compile_node_type(struct lysc_ctx *ctx, struct lysp_node *context_node, struct lysp_type *type_p,
Radek Krejci0f969882020-08-21 16:56:47 +02003688 struct lysc_node_leaf *leaf)
Radek Krejci33f72892019-02-21 10:36:58 +01003689{
Michal Vasko7f45cf22020-10-01 12:49:44 +02003690 struct lysp_qname *dflt;
Radek Krejci33f72892019-02-21 10:36:58 +01003691
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003692 LY_CHECK_RET(lys_compile_type(ctx, context_node, leaf->flags, ctx->pmod, leaf->name, type_p, &leaf->type,
Michal Vasko69730152020-10-09 16:30:07 +02003693 leaf->units ? NULL : &leaf->units, &dflt));
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003694
3695 /* store default value, if any */
3696 if (dflt && !(leaf->flags & LYS_SET_DFLT)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003697 LY_CHECK_RET(lysc_unres_leaf_dflt_add(ctx, leaf, dflt));
Radek Krejci33f72892019-02-21 10:36:58 +01003698 }
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003699
Radek Krejci33f72892019-02-21 10:36:58 +01003700 if (leaf->type->basetype == LY_TYPE_LEAFREF) {
3701 /* 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 +02003702 LY_CHECK_RET(ly_set_add(&ctx->leafrefs, leaf, 0, NULL));
Radek Krejci33f72892019-02-21 10:36:58 +01003703 } else if (leaf->type->basetype == LY_TYPE_UNION) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003704 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003705 LY_ARRAY_FOR(((struct lysc_type_union *)leaf->type)->types, u) {
3706 if (((struct lysc_type_union *)leaf->type)->types[u]->basetype == LY_TYPE_LEAFREF) {
Radek Krejci33f72892019-02-21 10:36:58 +01003707 /* 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 +02003708 LY_CHECK_RET(ly_set_add(&ctx->leafrefs, leaf, 0, NULL));
Radek Krejci33f72892019-02-21 10:36:58 +01003709 }
3710 }
3711 } else if (leaf->type->basetype == LY_TYPE_EMPTY) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003712 if ((leaf->nodetype == LYS_LEAFLIST) && (ctx->pmod->version < LYS_VERSION_1_1)) {
Radek Krejci33f72892019-02-21 10:36:58 +01003713 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003714 "Leaf-list of type \"empty\" is allowed only in YANG 1.1 modules.");
Radek Krejci33f72892019-02-21 10:36:58 +01003715 return LY_EVALID;
3716 }
3717 }
3718
Radek Krejci33f72892019-02-21 10:36:58 +01003719 return LY_SUCCESS;
3720}
3721
Radek Krejcia3045382018-11-22 14:30:31 +01003722/**
3723 * @brief Compile parsed leaf node information.
3724 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02003725 * @param[in] pnode Parsed leaf node.
Radek Krejcia3045382018-11-22 14:30:31 +01003726 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
3727 * is enriched with the leaf-specific information.
3728 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3729 */
Radek Krejci19a96102018-11-15 13:38:09 +01003730static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02003731lys_compile_node_leaf(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci19a96102018-11-15 13:38:09 +01003732{
Michal Vasko7f45cf22020-10-01 12:49:44 +02003733 struct lysp_node_leaf *leaf_p = (struct lysp_node_leaf *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02003734 struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)node;
Michal Vasko7c8439f2020-08-05 13:25:19 +02003735 LY_ARRAY_COUNT_TYPE u;
Radek Krejci19a96102018-11-15 13:38:09 +01003736 LY_ERR ret = LY_SUCCESS;
3737
Radek Krejcic71ac5b2019-09-10 15:34:22 +02003738 COMPILE_ARRAY_GOTO(ctx, leaf_p->musts, leaf->musts, u, lys_compile_must, ret, done);
Radek Krejci90d4e922020-10-12 15:55:33 +02003739 if (leaf_p->musts && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01003740 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003741 ret = ly_set_add(&ctx->xpath, leaf, 0, NULL);
3742 LY_CHECK_GOTO(ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003743 }
Radek Krejciccd20f12019-02-15 14:12:27 +01003744 if (leaf_p->units) {
Radek Krejci011e4aa2020-09-04 15:22:31 +02003745 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, leaf_p->units, 0, &leaf->units), done);
Radek Krejciccd20f12019-02-15 14:12:27 +01003746 leaf->flags |= LYS_SET_UNITS;
3747 }
Radek Krejcia1911222019-07-22 17:24:50 +02003748
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003749 /* compile type */
Michal Vasko7f45cf22020-10-01 12:49:44 +02003750 ret = lys_compile_node_type(ctx, pnode, &leaf_p->type, leaf);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003751 LY_CHECK_GOTO(ret, done);
Radek Krejcia1911222019-07-22 17:24:50 +02003752
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003753 /* store/update default value */
Michal Vasko7f45cf22020-10-01 12:49:44 +02003754 if (leaf_p->dflt.str) {
3755 LY_CHECK_RET(lysc_unres_leaf_dflt_add(ctx, leaf, &leaf_p->dflt));
Radek Krejci76b3e962018-12-14 17:01:25 +01003756 leaf->flags |= LYS_SET_DFLT;
3757 }
Radek Krejci43699232018-11-23 14:59:46 +01003758
Michal Vasko7f45cf22020-10-01 12:49:44 +02003759 /* checks */
3760 if ((leaf->flags & LYS_SET_DFLT) && (leaf->flags & LYS_MAND_TRUE)) {
3761 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
3762 "Invalid mandatory leaf with a default value.");
3763 return LY_EVALID;
3764 }
3765
Radek Krejci19a96102018-11-15 13:38:09 +01003766done:
3767 return ret;
3768}
3769
Radek Krejcia3045382018-11-22 14:30:31 +01003770/**
Radek Krejci0e5d8382018-11-28 16:37:53 +01003771 * @brief Compile parsed leaf-list node information.
3772 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02003773 * @param[in] pnode Parsed leaf-list node.
Radek Krejci0e5d8382018-11-28 16:37:53 +01003774 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
3775 * is enriched with the leaf-list-specific information.
3776 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3777 */
3778static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02003779lys_compile_node_leaflist(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci0e5d8382018-11-28 16:37:53 +01003780{
Michal Vasko7f45cf22020-10-01 12:49:44 +02003781 struct lysp_node_leaflist *llist_p = (struct lysp_node_leaflist *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02003782 struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)node;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003783 LY_ARRAY_COUNT_TYPE u;
Radek Krejci0e5d8382018-11-28 16:37:53 +01003784 LY_ERR ret = LY_SUCCESS;
3785
Radek Krejcic71ac5b2019-09-10 15:34:22 +02003786 COMPILE_ARRAY_GOTO(ctx, llist_p->musts, llist->musts, u, lys_compile_must, ret, done);
Radek Krejci90d4e922020-10-12 15:55:33 +02003787 if (llist_p->musts && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01003788 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003789 ret = ly_set_add(&ctx->xpath, llist, 0, NULL);
3790 LY_CHECK_GOTO(ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003791 }
Radek Krejciccd20f12019-02-15 14:12:27 +01003792 if (llist_p->units) {
Radek Krejci011e4aa2020-09-04 15:22:31 +02003793 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, llist_p->units, 0, &llist->units), done);
Radek Krejciccd20f12019-02-15 14:12:27 +01003794 llist->flags |= LYS_SET_UNITS;
3795 }
Radek Krejci0e5d8382018-11-28 16:37:53 +01003796
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003797 /* compile type */
Michal Vasko7f45cf22020-10-01 12:49:44 +02003798 ret = lys_compile_node_type(ctx, pnode, &llist_p->type, (struct lysc_node_leaf *)llist);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003799 LY_CHECK_GOTO(ret, done);
Michal Vasko6a044b22020-01-15 12:25:39 +01003800
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003801 /* store/update default values */
Radek Krejci0e5d8382018-11-28 16:37:53 +01003802 if (llist_p->dflts) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003803 if (ctx->pmod->version < LYS_VERSION_1_1) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003804 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003805 "Leaf-list default values are allowed only in YANG 1.1 modules.");
Michal Vasko7f45cf22020-10-01 12:49:44 +02003806 return LY_EVALID;
3807 }
3808
3809 LY_CHECK_GOTO(lysc_unres_llist_dflts_add(ctx, llist, llist_p->dflts), done);
Radek Krejciccd20f12019-02-15 14:12:27 +01003810 llist->flags |= LYS_SET_DFLT;
Radek Krejci0e5d8382018-11-28 16:37:53 +01003811 }
3812
3813 llist->min = llist_p->min;
Radek Krejcife909632019-02-12 15:34:42 +01003814 if (llist->min) {
3815 llist->flags |= LYS_MAND_TRUE;
3816 }
Radek Krejcib7408632018-11-28 17:12:11 +01003817 llist->max = llist_p->max ? llist_p->max : (uint32_t)-1;
Radek Krejci0e5d8382018-11-28 16:37:53 +01003818
Michal Vasko7f45cf22020-10-01 12:49:44 +02003819 /* checks */
3820 if ((llist->flags & LYS_SET_DFLT) && (llist->flags & LYS_MAND_TRUE)) {
3821 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
3822 "Invalid mandatory leaf-list with default value(s).");
3823 return LY_EVALID;
3824 }
3825
3826 if (llist->min > llist->max) {
3827 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Leaf-list min-elements %u is bigger than max-elements %u.",
Michal Vasko69730152020-10-09 16:30:07 +02003828 llist->min, llist->max);
Michal Vasko7f45cf22020-10-01 12:49:44 +02003829 return LY_EVALID;
3830 }
3831
Radek Krejci0e5d8382018-11-28 16:37:53 +01003832done:
3833 return ret;
3834}
3835
3836/**
Radek Krejci90d4e922020-10-12 15:55:33 +02003837 * @brief Find the node according to the given descendant/absolute schema nodeid.
3838 * Used in unique, refine and augment statements.
3839 *
3840 * @param[in] ctx Compile context
3841 * @param[in] nodeid Descendant-schema-nodeid (according to the YANG grammar)
3842 * @param[in] nodeid_len Length of the given nodeid, if it is not NULL-terminated string.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003843 * @param[in] ctx_node Context node for a relative nodeid.
3844 * @param[in] cur_mod Current module for the nodeid (where it was "instantiated").
3845 * @param[in] format Format of any prefixes.
3846 * @param[in] prefix_data Format-specific prefix data (see ::ly_resolve_prefix).
Radek Krejci90d4e922020-10-12 15:55:33 +02003847 * @param[in] nodetype Optional (can be 0) restriction for target's nodetype. If target exists, but does not match
3848 * the given nodetype, LY_EDENIED is returned (and target is provided), but no error message is printed.
3849 * The value can be even an ORed value to allow multiple nodetypes.
3850 * @param[out] target Found target node if any.
3851 * @param[out] result_flag Output parameter to announce if the schema nodeid goes through the action's input/output or a Notification.
3852 * The LYSC_OPT_RPC_INPUT, LYSC_OPT_RPC_OUTPUT and LYSC_OPT_NOTIFICATION are used as flags.
3853 * @return LY_ERR values - LY_ENOTFOUND, LY_EVALID, LY_EDENIED or LY_SUCCESS.
3854 */
3855static LY_ERR
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003856lysc_resolve_schema_nodeid(struct lysc_ctx *ctx, const char *nodeid, size_t nodeid_len, const struct lysc_node *ctx_node,
3857 const struct lys_module *cur_mod, LY_PREFIX_FORMAT format, void *prefix_data, uint16_t nodetype,
3858 const struct lysc_node **target, uint16_t *result_flag)
Radek Krejci90d4e922020-10-12 15:55:33 +02003859{
3860 LY_ERR ret = LY_EVALID;
3861 const char *name, *prefix, *id;
3862 size_t name_len, prefix_len;
3863 const struct lys_module *mod;
3864 const char *nodeid_type;
3865 uint32_t getnext_extra_flag = 0;
3866 uint16_t current_nodetype = 0;
3867
3868 assert(nodeid);
3869 assert(target);
3870 assert(result_flag);
3871 *target = NULL;
3872 *result_flag = 0;
3873
3874 id = nodeid;
3875
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003876 if (ctx_node) {
Radek Krejci90d4e922020-10-12 15:55:33 +02003877 /* descendant-schema-nodeid */
3878 nodeid_type = "descendant";
3879
3880 if (*id == '/') {
3881 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3882 "Invalid descendant-schema-nodeid value \"%.*s\" - absolute-schema-nodeid used.",
3883 nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
3884 return LY_EVALID;
3885 }
3886 } else {
3887 /* absolute-schema-nodeid */
3888 nodeid_type = "absolute";
3889
3890 if (*id != '/') {
3891 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3892 "Invalid absolute-schema-nodeid value \"%.*s\" - missing starting \"/\".",
3893 nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
3894 return LY_EVALID;
3895 }
3896 ++id;
3897 }
3898
3899 while (*id && (ret = ly_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len)) == LY_SUCCESS) {
3900 if (prefix) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003901 mod = ly_resolve_prefix(ctx->ctx, prefix, prefix_len, format, prefix_data);
Radek Krejci90d4e922020-10-12 15:55:33 +02003902 if (!mod) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003903 /* module must always be found */
3904 assert(prefix);
Radek Krejci90d4e922020-10-12 15:55:33 +02003905 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3906 "Invalid %s-schema-nodeid value \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003907 nodeid_type, id - nodeid, nodeid, prefix_len, prefix, LYSP_MODULE_NAME(ctx->pmod));
Radek Krejci90d4e922020-10-12 15:55:33 +02003908 return LY_ENOTFOUND;
3909 }
3910 } else {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003911 switch (format) {
3912 case LY_PREF_SCHEMA:
3913 case LY_PREF_SCHEMA_RESOLVED:
3914 /* use the current module */
3915 mod = cur_mod;
3916 break;
3917 case LY_PREF_JSON:
3918 if (!ctx_node) {
3919 LOGINT_RET(ctx->ctx);
3920 }
3921 /* inherit the module of the previous context node */
3922 mod = ctx_node->module;
3923 break;
3924 case LY_PREF_XML:
3925 /* not really defined */
3926 LOGINT_RET(ctx->ctx);
3927 }
Radek Krejci90d4e922020-10-12 15:55:33 +02003928 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003929
3930 if (ctx_node && (ctx_node->nodetype & (LYS_RPC | LYS_ACTION))) {
Radek Krejci90d4e922020-10-12 15:55:33 +02003931 /* move through input/output manually */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003932 if (mod != ctx_node->module) {
Radek Krejci90d4e922020-10-12 15:55:33 +02003933 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3934 "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.", nodeid_type, id - nodeid, nodeid);
3935 return LY_ENOTFOUND;
3936 }
3937 if (!ly_strncmp("input", name, name_len)) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003938 ctx_node = (struct lysc_node *)&((struct lysc_action *)ctx_node)->input;
Radek Krejci90d4e922020-10-12 15:55:33 +02003939 } else if (!ly_strncmp("output", name, name_len)) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003940 ctx_node = (struct lysc_node *)&((struct lysc_action *)ctx_node)->output;
Radek Krejci90d4e922020-10-12 15:55:33 +02003941 getnext_extra_flag = LYS_GETNEXT_OUTPUT;
3942 } else {
3943 /* only input or output is valid */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003944 ctx_node = NULL;
Radek Krejci90d4e922020-10-12 15:55:33 +02003945 }
3946 } else {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003947 ctx_node = lys_find_child(ctx_node, mod, name, name_len, 0,
Radek Krejci90d4e922020-10-12 15:55:33 +02003948 getnext_extra_flag | LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
3949 getnext_extra_flag = 0;
3950 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003951 if (!ctx_node) {
Radek Krejci90d4e922020-10-12 15:55:33 +02003952 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3953 "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.", nodeid_type, id - nodeid, nodeid);
3954 return LY_ENOTFOUND;
3955 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003956 current_nodetype = ctx_node->nodetype;
Radek Krejci90d4e922020-10-12 15:55:33 +02003957
3958 if (current_nodetype == LYS_NOTIF) {
3959 (*result_flag) |= LYS_COMPILE_NOTIFICATION;
3960 } else if (current_nodetype == LYS_INPUT) {
3961 (*result_flag) |= LYS_COMPILE_RPC_INPUT;
3962 } else if (current_nodetype == LYS_OUTPUT) {
3963 (*result_flag) |= LYS_COMPILE_RPC_OUTPUT;
3964 }
3965
3966 if (!*id || (nodeid_len && ((size_t)(id - nodeid) >= nodeid_len))) {
3967 break;
3968 }
3969 if (*id != '/') {
3970 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3971 "Invalid %s-schema-nodeid value \"%.*s\" - missing \"/\" as node-identifier separator.",
3972 nodeid_type, id - nodeid + 1, nodeid);
3973 return LY_EVALID;
3974 }
3975 ++id;
3976 }
3977
3978 if (ret == LY_SUCCESS) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003979 *target = ctx_node;
Radek Krejci90d4e922020-10-12 15:55:33 +02003980 if (nodetype && !(current_nodetype & nodetype)) {
3981 return LY_EDENIED;
3982 }
3983 } else {
3984 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3985 "Invalid %s-schema-nodeid value \"%.*s\" - unexpected end of expression.",
3986 nodeid_type, nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
3987 }
3988
3989 return ret;
3990}
3991
3992/**
Radek Krejci7af64242019-02-18 13:07:53 +01003993 * @brief Compile information about list's uniques.
3994 * @param[in] ctx Compile context.
Radek Krejci7af64242019-02-18 13:07:53 +01003995 * @param[in] uniques Sized array list of unique statements.
3996 * @param[in] list Compiled list where the uniques are supposed to be resolved and stored.
3997 * @return LY_ERR value.
3998 */
3999static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004000lys_compile_node_list_unique(struct lysc_ctx *ctx, struct lysp_qname *uniques, struct lysc_node_list *list)
Radek Krejci7af64242019-02-18 13:07:53 +01004001{
4002 LY_ERR ret = LY_SUCCESS;
4003 struct lysc_node_leaf **key, ***unique;
Michal Vasko14654712020-02-06 08:35:21 +01004004 struct lysc_node *parent;
Radek Krejci7af64242019-02-18 13:07:53 +01004005 const char *keystr, *delim;
4006 size_t len;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02004007 LY_ARRAY_COUNT_TYPE v;
Radek Krejci1deb5be2020-08-26 16:43:36 +02004008 int8_t config; /* -1 - not yet seen; 0 - LYS_CONFIG_R; 1 - LYS_CONFIG_W */
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004009 uint16_t flags;
Radek Krejci7af64242019-02-18 13:07:53 +01004010
Michal Vasko7f45cf22020-10-01 12:49:44 +02004011 LY_ARRAY_FOR(uniques, v) {
Radek Krejci7af64242019-02-18 13:07:53 +01004012 config = -1;
4013 LY_ARRAY_NEW_RET(ctx->ctx, list->uniques, unique, LY_EMEM);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004014 keystr = uniques[v].str;
Radek Krejci7af64242019-02-18 13:07:53 +01004015 while (keystr) {
4016 delim = strpbrk(keystr, " \t\n");
4017 if (delim) {
4018 len = delim - keystr;
4019 while (isspace(*delim)) {
4020 ++delim;
4021 }
4022 } else {
4023 len = strlen(keystr);
4024 }
4025
4026 /* unique node must be present */
4027 LY_ARRAY_NEW_RET(ctx->ctx, *unique, key, LY_EMEM);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004028 ret = lysc_resolve_schema_nodeid(ctx, keystr, len, (struct lysc_node *)list, uniques[v].mod->mod,
4029 LY_PREF_SCHEMA, (void *)uniques[v].mod, LYS_LEAF, (const struct lysc_node **)key, &flags);
Radek Krejci7af64242019-02-18 13:07:53 +01004030 if (ret != LY_SUCCESS) {
4031 if (ret == LY_EDENIED) {
4032 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02004033 "Unique's descendant-schema-nodeid \"%.*s\" refers to %s node instead of a leaf.",
4034 len, keystr, lys_nodetype2str((*key)->nodetype));
Radek Krejci7af64242019-02-18 13:07:53 +01004035 }
4036 return LY_EVALID;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004037 } else if (flags) {
4038 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02004039 "Unique's descendant-schema-nodeid \"%.*s\" refers into %s node.",
Radek Krejci90d4e922020-10-12 15:55:33 +02004040 len, keystr, flags & LYS_COMPILE_NOTIFICATION ? "notification" : "RPC/action");
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004041 return LY_EVALID;
Radek Krejci7af64242019-02-18 13:07:53 +01004042 }
4043
4044 /* all referenced leafs must be of the same config type */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004045 if ((config != -1) && ((((*key)->flags & LYS_CONFIG_W) && (config == 0)) ||
4046 (((*key)->flags & LYS_CONFIG_R) && (config == 1)))) {
Radek Krejci7af64242019-02-18 13:07:53 +01004047 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004048 "Unique statement \"%s\" refers to leaves with different config type.", uniques[v].str);
Radek Krejci7af64242019-02-18 13:07:53 +01004049 return LY_EVALID;
4050 } else if ((*key)->flags & LYS_CONFIG_W) {
4051 config = 1;
4052 } else { /* LYS_CONFIG_R */
4053 config = 0;
4054 }
4055
Michal Vasko14654712020-02-06 08:35:21 +01004056 /* we forbid referencing nested lists because it is unspecified what instance of such a list to use */
4057 for (parent = (*key)->parent; parent != (struct lysc_node *)list; parent = parent->parent) {
4058 if (parent->nodetype == LYS_LIST) {
4059 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004060 "Unique statement \"%s\" refers to a leaf in nested list \"%s\".", uniques[v].str, parent->name);
Michal Vasko14654712020-02-06 08:35:21 +01004061 return LY_EVALID;
4062 }
4063 }
4064
Radek Krejci7af64242019-02-18 13:07:53 +01004065 /* check status */
4066 LY_CHECK_RET(lysc_check_status(ctx, list->flags, list->module, list->name,
Radek Krejci0f969882020-08-21 16:56:47 +02004067 (*key)->flags, (*key)->module, (*key)->name));
Radek Krejci7af64242019-02-18 13:07:53 +01004068
4069 /* mark leaf as unique */
4070 (*key)->flags |= LYS_UNIQUE;
4071
4072 /* next unique value in line */
4073 keystr = delim;
4074 }
4075 /* next unique definition */
4076 }
4077
4078 return LY_SUCCESS;
4079}
4080
4081/**
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004082 * @brief Compile parsed list node information.
4083 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02004084 * @param[in] pnode Parsed list node.
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004085 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
4086 * is enriched with the list-specific information.
4087 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
4088 */
4089static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004090lys_compile_node_list(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004091{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004092 struct lysp_node_list *list_p = (struct lysp_node_list *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02004093 struct lysc_node_list *list = (struct lysc_node_list *)node;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004094 struct lysp_node *child_p;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004095 struct lysc_node_leaf *key, *prev_key = NULL;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004096 size_t len;
Radek Krejci1deb5be2020-08-26 16:43:36 +02004097 LY_ARRAY_COUNT_TYPE u;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004098 const char *keystr, *delim;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004099 LY_ERR ret = LY_SUCCESS;
4100
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004101 list->min = list_p->min;
Radek Krejcife909632019-02-12 15:34:42 +01004102 if (list->min) {
4103 list->flags |= LYS_MAND_TRUE;
4104 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004105 list->max = list_p->max ? list_p->max : (uint32_t)-1;
4106
4107 LY_LIST_FOR(list_p->child, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004108 LY_CHECK_RET(lys_compile_node(ctx, child_p, node, 0, NULL));
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004109 }
4110
Radek Krejcic71ac5b2019-09-10 15:34:22 +02004111 COMPILE_ARRAY_GOTO(ctx, list_p->musts, list->musts, u, lys_compile_must, ret, done);
Radek Krejci90d4e922020-10-12 15:55:33 +02004112 if (list_p->musts && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01004113 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02004114 LY_CHECK_RET(ly_set_add(&ctx->xpath, list, 0, NULL));
Michal Vasko5d8756a2019-11-07 15:21:00 +01004115 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004116
4117 /* keys */
4118 if ((list->flags & LYS_CONFIG_W) && (!list_p->key || !list_p->key[0])) {
4119 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Missing key in list representing configuration data.");
4120 return LY_EVALID;
4121 }
4122
4123 /* find all the keys (must be direct children) */
4124 keystr = list_p->key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004125 if (!keystr) {
4126 /* keyless list */
4127 list->flags |= LYS_KEYLESS;
4128 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004129 while (keystr) {
4130 delim = strpbrk(keystr, " \t\n");
4131 if (delim) {
4132 len = delim - keystr;
4133 while (isspace(*delim)) {
4134 ++delim;
4135 }
4136 } else {
4137 len = strlen(keystr);
4138 }
4139
4140 /* key node must be present */
Michal Vasko22df3f02020-08-24 13:29:22 +02004141 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 +02004142 if (!(key)) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004143 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02004144 "The list's key \"%.*s\" not found.", len, keystr);
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004145 return LY_EVALID;
4146 }
4147 /* keys must be unique */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004148 if (key->flags & LYS_KEY) {
4149 /* the node was already marked as a key */
4150 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004151 "Duplicated key identifier \"%.*s\".", len, keystr);
Radek Krejci0fe9b512019-07-26 17:51:05 +02004152 return LY_EVALID;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004153 }
Radek Krejci0fe9b512019-07-26 17:51:05 +02004154
Michal Vasko22df3f02020-08-24 13:29:22 +02004155 lysc_update_path(ctx, (struct lysc_node *)list, key->name);
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004156 /* key must have the same config flag as the list itself */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004157 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004158 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Key of the configuration list must not be status leaf.");
4159 return LY_EVALID;
4160 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004161 if (ctx->pmod->version < LYS_VERSION_1_1) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004162 /* YANG 1.0 denies key to be of empty type */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004163 if (key->type->basetype == LY_TYPE_EMPTY) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004164 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004165 "List's key cannot be of \"empty\" type until it is in YANG 1.1 module.");
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004166 return LY_EVALID;
4167 }
4168 } else {
4169 /* when and if-feature are illegal on list keys */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004170 if (key->when) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004171 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004172 "List's key must not have any \"when\" statement.");
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004173 return LY_EVALID;
4174 }
Radek Krejci0fe9b512019-07-26 17:51:05 +02004175 if (key->iffeatures) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004176 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004177 "List's key must not have any \"if-feature\" statement.");
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004178 return LY_EVALID;
4179 }
4180 }
Radek Krejci76b3e962018-12-14 17:01:25 +01004181
4182 /* check status */
4183 LY_CHECK_RET(lysc_check_status(ctx, list->flags, list->module, list->name,
Michal Vasko69730152020-10-09 16:30:07 +02004184 key->flags, key->module, key->name));
Radek Krejci76b3e962018-12-14 17:01:25 +01004185
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004186 /* ignore default values of the key */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004187 if (key->dflt) {
4188 key->dflt->realtype->plugin->free(ctx->ctx, key->dflt);
Michal Vaskofeca4fb2020-10-05 08:58:40 +02004189 lysc_type_free(ctx->ctx, (struct lysc_type *)key->dflt->realtype);
Radek Krejci0fe9b512019-07-26 17:51:05 +02004190 free(key->dflt);
4191 key->dflt = NULL;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004192 }
4193 /* mark leaf as key */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004194 key->flags |= LYS_KEY;
4195
4196 /* move it to the correct position */
Michal Vasko69730152020-10-09 16:30:07 +02004197 if ((prev_key && ((struct lysc_node *)prev_key != key->prev)) || (!prev_key && key->prev->next)) {
Radek Krejci0fe9b512019-07-26 17:51:05 +02004198 /* fix links in closest previous siblings of the key */
4199 if (key->next) {
4200 key->next->prev = key->prev;
4201 } else {
4202 /* last child */
4203 list->child->prev = key->prev;
4204 }
4205 if (key->prev->next) {
4206 key->prev->next = key->next;
4207 }
4208 /* fix links in the key */
4209 if (prev_key) {
Michal Vasko22df3f02020-08-24 13:29:22 +02004210 key->prev = (struct lysc_node *)prev_key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004211 key->next = prev_key->next;
4212 } else {
4213 key->prev = list->child->prev;
4214 key->next = list->child;
4215 }
4216 /* fix links in closes future siblings of the key */
4217 if (prev_key) {
4218 if (prev_key->next) {
Michal Vasko22df3f02020-08-24 13:29:22 +02004219 prev_key->next->prev = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004220 } else {
Michal Vasko22df3f02020-08-24 13:29:22 +02004221 list->child->prev = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004222 }
Michal Vasko22df3f02020-08-24 13:29:22 +02004223 prev_key->next = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004224 } else {
Michal Vasko22df3f02020-08-24 13:29:22 +02004225 list->child->prev = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004226 }
4227 /* fix links in parent */
4228 if (!key->prev->next) {
Michal Vasko22df3f02020-08-24 13:29:22 +02004229 list->child = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004230 }
4231 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004232
4233 /* next key value */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004234 prev_key = key;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004235 keystr = delim;
Radek Krejci327de162019-06-14 12:52:07 +02004236 lysc_update_path(ctx, NULL, NULL);
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004237 }
4238
4239 /* uniques */
4240 if (list_p->uniques) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004241 LY_CHECK_RET(lys_compile_node_list_unique(ctx, list_p->uniques, list));
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004242 }
4243
Michal Vasko7f45cf22020-10-01 12:49:44 +02004244 COMPILE_OP_ARRAY_GOTO(ctx, list_p->actions, list->actions, node, u, lys_compile_action, 0, ret, done);
4245 COMPILE_OP_ARRAY_GOTO(ctx, list_p->notifs, list->notifs, node, u, lys_compile_notif, 0, ret, done);
4246
4247 /* checks */
4248 if (list->min > list->max) {
4249 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "List min-elements %u is bigger than max-elements %u.",
Michal Vasko69730152020-10-09 16:30:07 +02004250 list->min, list->max);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004251 return LY_EVALID;
4252 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004253
4254done:
4255 return ret;
4256}
4257
Radek Krejcib56c7502019-02-13 14:19:54 +01004258/**
4259 * @brief Do some checks and set the default choice's case.
4260 *
4261 * Selects (and stores into ::lysc_node_choice#dflt) the default case and set LYS_SET_DFLT flag on it.
4262 *
4263 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02004264 * @param[in] dflt Name of the default branch. Can even contain a prefix.
Radek Krejcib56c7502019-02-13 14:19:54 +01004265 * @param[in,out] ch The compiled choice node, its dflt member is filled to point to the default case node of the choice.
4266 * @return LY_ERR value.
4267 */
Radek Krejci76b3e962018-12-14 17:01:25 +01004268static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004269lys_compile_node_choice_dflt(struct lysc_ctx *ctx, struct lysp_qname *dflt, struct lysc_node_choice *ch)
Radek Krejci76b3e962018-12-14 17:01:25 +01004270{
Michal Vasko22df3f02020-08-24 13:29:22 +02004271 struct lysc_node *iter, *node = (struct lysc_node *)ch;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004272 const struct lys_module *mod;
Radek Krejci76b3e962018-12-14 17:01:25 +01004273 const char *prefix = NULL, *name;
4274 size_t prefix_len = 0;
4275
4276 /* 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 +02004277 name = strchr(dflt->str, ':');
Radek Krejci76b3e962018-12-14 17:01:25 +01004278 if (name) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004279 prefix = dflt->str;
Radek Krejci76b3e962018-12-14 17:01:25 +01004280 prefix_len = name - prefix;
4281 ++name;
4282 } else {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004283 name = dflt->str;
Radek Krejci76b3e962018-12-14 17:01:25 +01004284 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004285 if (prefix) {
4286 mod = ly_resolve_prefix(ctx->ctx, prefix, prefix_len, LY_PREF_SCHEMA, (void *)dflt->mod);
4287 if (!mod) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004288 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Default case prefix \"%.*s\" not found "
4289 "in imports of \"%s\".", prefix_len, prefix, LYSP_MODULE_NAME(dflt->mod));
Michal Vasko7f45cf22020-10-01 12:49:44 +02004290 return LY_EVALID;
4291 }
4292 } else {
4293 mod = node->module;
Radek Krejci76b3e962018-12-14 17:01:25 +01004294 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004295
4296 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 +01004297 if (!ch->dflt) {
4298 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004299 "Default case \"%s\" not found.", dflt->str);
Radek Krejci76b3e962018-12-14 17:01:25 +01004300 return LY_EVALID;
4301 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004302
Radek Krejci76b3e962018-12-14 17:01:25 +01004303 /* no mandatory nodes directly under the default case */
4304 LY_LIST_FOR(ch->dflt->child, iter) {
Michal Vasko22df3f02020-08-24 13:29:22 +02004305 if (iter->parent != (struct lysc_node *)ch->dflt) {
Radek Krejcife13da42019-02-15 14:51:01 +01004306 break;
4307 }
Radek Krejci76b3e962018-12-14 17:01:25 +01004308 if (iter->flags & LYS_MAND_TRUE) {
4309 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004310 "Mandatory node \"%s\" under the default case \"%s\".", iter->name, dflt->str);
Radek Krejci76b3e962018-12-14 17:01:25 +01004311 return LY_EVALID;
4312 }
4313 }
Radek Krejci76b3e962018-12-14 17:01:25 +01004314
Michal Vasko7f45cf22020-10-01 12:49:44 +02004315 if (ch->flags & LYS_MAND_TRUE) {
4316 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid mandatory choice with a default case.");
Radek Krejciccd20f12019-02-15 14:12:27 +01004317 return LY_EVALID;
4318 }
4319
Michal Vasko7f45cf22020-10-01 12:49:44 +02004320 ch->dflt->flags |= LYS_SET_DFLT;
Radek Krejciccd20f12019-02-15 14:12:27 +01004321 return LY_SUCCESS;
4322}
4323
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004324/**
Michal Vasko20424b42020-08-31 12:29:38 +02004325 * @brief Compile choice children.
4326 *
4327 * @param[in] ctx Compile context
4328 * @param[in] child_p Parsed choice children nodes.
4329 * @param[in] node Compiled choice node to compile and add children to.
4330 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
4331 */
4332static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004333lys_compile_node_choice_child(struct lysc_ctx *ctx, struct lysp_node *child_p, struct lysc_node *node,
4334 struct ly_set *child_set)
Michal Vasko20424b42020-08-31 12:29:38 +02004335{
4336 LY_ERR ret = LY_SUCCESS;
Radek Krejci8f5fad22020-09-15 16:50:54 +02004337 struct lysp_node *child_p_next = child_p->next;
Michal Vasko20424b42020-08-31 12:29:38 +02004338 struct lysp_node_case *cs_p;
4339
4340 if (child_p->nodetype == LYS_CASE) {
4341 /* standard case under choice */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004342 ret = lys_compile_node(ctx, child_p, node, 0, child_set);
Michal Vasko20424b42020-08-31 12:29:38 +02004343 } else {
4344 /* we need the implicit case first, so create a fake parsed case */
4345 cs_p = calloc(1, sizeof *cs_p);
4346 cs_p->nodetype = LYS_CASE;
Radek Krejci87e25252020-09-15 13:28:31 +02004347 DUP_STRING_GOTO(ctx->ctx, child_p->name, cs_p->name, ret, free_fake_node);
Michal Vasko20424b42020-08-31 12:29:38 +02004348 cs_p->child = child_p;
4349
4350 /* make the child the only case child */
Michal Vasko20424b42020-08-31 12:29:38 +02004351 child_p->next = NULL;
4352
4353 /* compile it normally */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004354 ret = lys_compile_node(ctx, (struct lysp_node *)cs_p, node, 0, child_set);
Michal Vasko20424b42020-08-31 12:29:38 +02004355
Radek Krejci87e25252020-09-15 13:28:31 +02004356free_fake_node:
Michal Vasko20424b42020-08-31 12:29:38 +02004357 /* free the fake parsed node and correct pointers back */
4358 cs_p->child = NULL;
4359 lysp_node_free(ctx->ctx, (struct lysp_node *)cs_p);
Radek Krejci8f5fad22020-09-15 16:50:54 +02004360 child_p->next = child_p_next;
Michal Vasko20424b42020-08-31 12:29:38 +02004361 }
4362
4363 return ret;
4364}
4365
4366/**
Radek Krejci056d0a82018-12-06 16:57:25 +01004367 * @brief Compile parsed choice node information.
Michal Vasko20424b42020-08-31 12:29:38 +02004368 *
Radek Krejci056d0a82018-12-06 16:57:25 +01004369 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02004370 * @param[in] pnode Parsed choice node.
Radek Krejci056d0a82018-12-06 16:57:25 +01004371 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
Radek Krejci76b3e962018-12-14 17:01:25 +01004372 * is enriched with the choice-specific information.
Radek Krejci056d0a82018-12-06 16:57:25 +01004373 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
4374 */
4375static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004376lys_compile_node_choice(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci056d0a82018-12-06 16:57:25 +01004377{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004378 struct lysp_node_choice *ch_p = (struct lysp_node_choice *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02004379 struct lysc_node_choice *ch = (struct lysc_node_choice *)node;
Michal Vasko20424b42020-08-31 12:29:38 +02004380 struct lysp_node *child_p;
Radek Krejci056d0a82018-12-06 16:57:25 +01004381 LY_ERR ret = LY_SUCCESS;
4382
Michal Vasko20424b42020-08-31 12:29:38 +02004383 assert(node->nodetype == LYS_CHOICE);
4384
Radek Krejci056d0a82018-12-06 16:57:25 +01004385 LY_LIST_FOR(ch_p->child, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004386 LY_CHECK_RET(lys_compile_node_choice_child(ctx, child_p, node, NULL));
Radek Krejci056d0a82018-12-06 16:57:25 +01004387 }
4388
4389 /* default branch */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004390 if (ch_p->dflt.str) {
4391 LY_CHECK_RET(lys_compile_node_choice_dflt(ctx, &ch_p->dflt, ch));
Radek Krejcia9026eb2018-12-12 16:04:47 +01004392 }
Radek Krejci056d0a82018-12-06 16:57:25 +01004393
Radek Krejci9800fb82018-12-13 14:26:23 +01004394 return ret;
4395}
4396
4397/**
4398 * @brief Compile parsed anydata or anyxml node information.
4399 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02004400 * @param[in] pnode Parsed anydata or anyxml node.
Radek Krejci9800fb82018-12-13 14:26:23 +01004401 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
4402 * is enriched with the any-specific information.
4403 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
4404 */
4405static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004406lys_compile_node_any(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci9800fb82018-12-13 14:26:23 +01004407{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004408 struct lysp_node_anydata *any_p = (struct lysp_node_anydata *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02004409 struct lysc_node_anydata *any = (struct lysc_node_anydata *)node;
Radek Krejci1deb5be2020-08-26 16:43:36 +02004410 LY_ARRAY_COUNT_TYPE u;
Radek Krejci9800fb82018-12-13 14:26:23 +01004411 LY_ERR ret = LY_SUCCESS;
4412
Radek Krejcic71ac5b2019-09-10 15:34:22 +02004413 COMPILE_ARRAY_GOTO(ctx, any_p->musts, any->musts, u, lys_compile_must, ret, done);
Radek Krejci90d4e922020-10-12 15:55:33 +02004414 if (any_p->musts && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01004415 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02004416 ret = ly_set_add(&ctx->xpath, any, 0, NULL);
4417 LY_CHECK_GOTO(ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01004418 }
Radek Krejci9800fb82018-12-13 14:26:23 +01004419
4420 if (any->flags & LYS_CONFIG_W) {
Radek Krejci5c4ed7b2020-08-12 11:29:44 +02004421 LOGWRN(ctx->ctx, "Use of %s to define configuration data is not recommended. %s",
Michal Vasko69730152020-10-09 16:30:07 +02004422 ly_stmt2str(any->nodetype == LYS_ANYDATA ? LY_STMT_ANYDATA : LY_STMT_ANYXML), ctx->path);
Radek Krejci9800fb82018-12-13 14:26:23 +01004423 }
Radek Krejci056d0a82018-12-06 16:57:25 +01004424done:
4425 return ret;
4426}
4427
Radek Krejcib56c7502019-02-13 14:19:54 +01004428/**
Michal Vasko795b3752020-07-13 15:24:27 +02004429 * @brief Connect the node into the siblings list and check its name uniqueness. Also,
4430 * keep specific order of augments targetting the same node.
Radek Krejci056d0a82018-12-06 16:57:25 +01004431 *
4432 * @param[in] ctx Compile context
4433 * @param[in] parent Parent node holding the children list, in case of node from a choice's case,
4434 * the choice itself is expected instead of a specific case node.
4435 * @param[in] node Schema node to connect into the list.
4436 * @return LY_ERR value - LY_SUCCESS or LY_EEXIST.
Radek Krejci1c54f462020-05-12 17:25:34 +02004437 * 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 +01004438 */
4439static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02004440lys_compile_node_connect(struct lysc_ctx *ctx, struct lysc_node *parent, struct lysc_node *node)
Radek Krejci056d0a82018-12-06 16:57:25 +01004441{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004442 struct lysc_node **children, *anchor = NULL;
4443 int insert_after = 0;
Radek Krejci056d0a82018-12-06 16:57:25 +01004444
Michal Vasko20424b42020-08-31 12:29:38 +02004445 node->parent = parent;
4446
4447 if (parent) {
4448 if (parent->nodetype == LYS_CHOICE) {
4449 assert(node->nodetype == LYS_CASE);
4450 children = (struct lysc_node **)&((struct lysc_node_choice *)parent)->cases;
4451 } else {
4452 children = lysc_node_children_p(parent, ctx->options);
4453 }
4454 assert(children);
4455
Radek Krejci056d0a82018-12-06 16:57:25 +01004456 if (!(*children)) {
4457 /* first child */
4458 *children = node;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004459 } else if (node->flags & LYS_KEY) {
4460 /* special handling of adding keys */
4461 assert(node->module == parent->module);
4462 anchor = *children;
4463 if (anchor->flags & LYS_KEY) {
4464 while ((anchor->flags & LYS_KEY) && anchor->next) {
4465 anchor = anchor->next;
4466 }
4467 /* insert after the last key */
4468 insert_after = 1;
4469 } /* else insert before anchor (at the beginning) */
4470 } else if ((*children)->prev->module == node->module) {
4471 /* last child is from the same module, keep the order and insert at the end */
4472 anchor = (*children)->prev;
4473 insert_after = 1;
4474 } else if (parent->module == node->module) {
4475 /* adding module child after some augments were connected */
4476 for (anchor = *children; anchor->module == node->module; anchor = anchor->next) {}
4477 } else {
4478 /* some augments are already connected and we are connecting new ones,
4479 * keep module name order and insert the node into the children list */
4480 anchor = *children;
4481 do {
4482 anchor = anchor->prev;
Michal Vasko795b3752020-07-13 15:24:27 +02004483
Michal Vasko7f45cf22020-10-01 12:49:44 +02004484 /* check that we have not found the last augment node from our module or
4485 * the first augment node from a "smaller" module or
4486 * the first node from a local module */
Michal Vasko69730152020-10-09 16:30:07 +02004487 if ((anchor->module == node->module) || (strcmp(anchor->module->name, node->module->name) < 0) ||
4488 (anchor->module == parent->module)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004489 /* insert after */
4490 insert_after = 1;
4491 break;
4492 }
4493
4494 /* we have traversed all the nodes, insert before anchor (as the first node) */
4495 } while (anchor->prev->next);
4496 }
4497
4498 /* insert */
4499 if (anchor) {
4500 if (insert_after) {
4501 node->next = anchor->next;
4502 node->prev = anchor;
4503 anchor->next = node;
4504 if (node->next) {
4505 /* middle node */
4506 node->next->prev = node;
4507 } else {
4508 /* last node */
4509 (*children)->prev = node;
4510 }
Michal Vasko795b3752020-07-13 15:24:27 +02004511 } else {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004512 node->next = anchor;
4513 node->prev = anchor->prev;
4514 anchor->prev = node;
4515 if (anchor == *children) {
4516 /* first node */
4517 *children = node;
4518 } else {
4519 /* middle node */
4520 node->prev->next = node;
4521 }
Michal Vasko795b3752020-07-13 15:24:27 +02004522 }
Michal Vasko20424b42020-08-31 12:29:38 +02004523 }
Radek Krejci056d0a82018-12-06 16:57:25 +01004524
Michal Vasko20424b42020-08-31 12:29:38 +02004525 /* check the name uniqueness (even for an only child, it may be in case) */
4526 if (lys_compile_node_uniqness(ctx, parent, node->name, node)) {
4527 return LY_EEXIST;
4528 }
4529 } else {
4530 /* top-level element */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004531 if (!ctx->cur_mod->compiled->data) {
4532 ctx->cur_mod->compiled->data = node;
Michal Vasko20424b42020-08-31 12:29:38 +02004533 } else {
4534 /* insert at the end of the module's top-level nodes list */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004535 ctx->cur_mod->compiled->data->prev->next = node;
4536 node->prev = ctx->cur_mod->compiled->data->prev;
4537 ctx->cur_mod->compiled->data->prev = node;
Michal Vasko20424b42020-08-31 12:29:38 +02004538 }
4539
4540 /* check the name uniqueness on top-level */
4541 if (lys_compile_node_uniqness(ctx, NULL, node->name, node)) {
4542 return LY_EEXIST;
Radek Krejci056d0a82018-12-06 16:57:25 +01004543 }
4544 }
Michal Vasko20424b42020-08-31 12:29:38 +02004545
Radek Krejci056d0a82018-12-06 16:57:25 +01004546 return LY_SUCCESS;
4547}
4548
Radek Krejci95710c92019-02-11 15:49:55 +01004549/**
Radek Krejcib56c7502019-02-13 14:19:54 +01004550 * @brief Prepare the case structure in choice node for the new data node.
4551 *
4552 * 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
4553 * created in the choice when the first child was processed.
4554 *
4555 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02004556 * @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 +02004557 * it is the LYS_CHOICE, LYS_AUGMENT or LYS_GROUPING node.
Radek Krejcib56c7502019-02-13 14:19:54 +01004558 * @param[in] ch The compiled choice structure where the new case structures are created (if needed).
4559 * @param[in] child The new data node being part of a case (no matter if explicit or implicit).
4560 * @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,
4561 * it is linked from the case structure only in case it is its first child.
Radek Krejci95710c92019-02-11 15:49:55 +01004562 */
Michal Vasko20424b42020-08-31 12:29:38 +02004563static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004564lys_compile_node_case(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci056d0a82018-12-06 16:57:25 +01004565{
Michal Vasko20424b42020-08-31 12:29:38 +02004566 struct lysp_node *child_p;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004567 struct lysp_node_case *cs_p = (struct lysp_node_case *)pnode;
Radek Krejci056d0a82018-12-06 16:57:25 +01004568
Michal Vasko7f45cf22020-10-01 12:49:44 +02004569 if (pnode->nodetype & (LYS_CHOICE | LYS_AUGMENT | LYS_GROUPING)) {
Radek Krejci056d0a82018-12-06 16:57:25 +01004570 /* we have to add an implicit case node into the parent choice */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004571 } else if (pnode->nodetype == LYS_CASE) {
Michal Vasko20424b42020-08-31 12:29:38 +02004572 /* explicit parent case */
4573 LY_LIST_FOR(cs_p->child, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004574 LY_CHECK_RET(lys_compile_node(ctx, child_p, node, 0, NULL));
Radek Krejci056d0a82018-12-06 16:57:25 +01004575 }
Radek Krejci95710c92019-02-11 15:49:55 +01004576 } else {
Michal Vasko20424b42020-08-31 12:29:38 +02004577 LOGINT_RET(ctx->ctx);
Radek Krejci056d0a82018-12-06 16:57:25 +01004578 }
Radek Krejci056d0a82018-12-06 16:57:25 +01004579
Michal Vasko20424b42020-08-31 12:29:38 +02004580 return LY_SUCCESS;
Radek Krejci056d0a82018-12-06 16:57:25 +01004581}
4582
Radek Krejcib56c7502019-02-13 14:19:54 +01004583/**
Radek Krejcib56c7502019-02-13 14:19:54 +01004584 * @brief Set LYS_MAND_TRUE flag for the non-presence container parents.
4585 *
4586 * A non-presence container is mandatory in case it has at least one mandatory children. This function propagate
4587 * the flag to such parents from a mandatory children.
4588 *
4589 * @param[in] parent A schema node to be examined if the mandatory child make it also mandatory.
4590 * @param[in] add Flag to distinguish adding the mandatory flag (new mandatory children appeared) or removing the flag
4591 * (mandatory children was removed).
4592 */
Radek Krejci1deb5be2020-08-26 16:43:36 +02004593static void
Radek Krejci857189e2020-09-01 13:26:36 +02004594lys_compile_mandatory_parents(struct lysc_node *parent, ly_bool add)
Radek Krejcife909632019-02-12 15:34:42 +01004595{
4596 struct lysc_node *iter;
4597
4598 if (add) { /* set flag */
Michal Vaskod989ba02020-08-24 10:59:24 +02004599 for ( ; parent && parent->nodetype == LYS_CONTAINER && !(parent->flags & LYS_MAND_TRUE) && !(parent->flags & LYS_PRESENCE);
Radek Krejcife909632019-02-12 15:34:42 +01004600 parent = parent->parent) {
4601 parent->flags |= LYS_MAND_TRUE;
4602 }
4603 } else { /* unset flag */
Michal Vaskod989ba02020-08-24 10:59:24 +02004604 for ( ; parent && parent->nodetype == LYS_CONTAINER && (parent->flags & LYS_MAND_TRUE); parent = parent->parent) {
Michal Vasko22df3f02020-08-24 13:29:22 +02004605 for (iter = (struct lysc_node *)lysc_node_children(parent, 0); iter; iter = iter->next) {
Radek Krejcif1421c22019-02-19 13:05:20 +01004606 if (iter->flags & LYS_MAND_TRUE) {
Radek Krejcife909632019-02-12 15:34:42 +01004607 /* there is another mandatory node */
4608 return;
4609 }
4610 }
4611 /* unset mandatory flag - there is no mandatory children in the non-presence container */
4612 parent->flags &= ~LYS_MAND_TRUE;
4613 }
4614 }
4615}
4616
Radek Krejci056d0a82018-12-06 16:57:25 +01004617/**
Radek Krejci3641f562019-02-13 15:38:40 +01004618 * @brief Compile the parsed augment connecting it into its target.
4619 *
4620 * It is expected that all the data referenced in path are present - augments are ordered so that augment B
4621 * targeting data from augment A is being compiled after augment A. Also the modules referenced in the path
4622 * are already implemented and compiled.
4623 *
4624 * @param[in] ctx Compile context.
4625 * @param[in] aug_p Parsed augment to compile.
Michal Vasko7f45cf22020-10-01 12:49:44 +02004626 * @param[in] target Target node of the augment.
Radek Krejci3641f562019-02-13 15:38:40 +01004627 * @return LY_SUCCESS on success.
4628 * @return LY_EVALID on failure.
4629 */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004630static LY_ERR
4631lys_compile_augment(struct lysc_ctx *ctx, struct lysp_augment *aug_p, struct lysc_node *target)
Radek Krejci3641f562019-02-13 15:38:40 +01004632{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004633 LY_ERR ret = LY_SUCCESS;
4634 struct lysp_node *pnode;
Radek Krejci3641f562019-02-13 15:38:40 +01004635 struct lysc_node *node;
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004636 struct lysc_when *when_shared = NULL;
4637 struct lysc_action **actions;
4638 struct lysc_notif **notifs;
Radek Krejci857189e2020-09-01 13:26:36 +02004639 ly_bool allow_mandatory = 0;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004640 LY_ARRAY_COUNT_TYPE u;
4641 struct ly_set child_set = {0};
4642 uint32_t i;
Radek Krejci3641f562019-02-13 15:38:40 +01004643
Michal Vasko7f45cf22020-10-01 12:49:44 +02004644 if (!(target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF))) {
4645 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
4646 "Augment's %s-schema-nodeid \"%s\" refers to a %s node which is not an allowed augment's target.",
4647 aug_p->nodeid[0] == '/' ? "absolute" : "descendant", aug_p->nodeid, lys_nodetype2str(target->nodetype));
4648 ret = LY_EVALID;
4649 goto cleanup;
Radek Krejci3641f562019-02-13 15:38:40 +01004650 }
4651
4652 /* check for mandatory nodes
4653 * - new cases augmenting some choice can have mandatory nodes
4654 * - mandatory nodes are allowed only in case the augmentation is made conditional with a when statement
4655 */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004656 if (aug_p->when || (target->nodetype == LYS_CHOICE) || (ctx->cur_mod == target->module)) {
Radek Krejci3641f562019-02-13 15:38:40 +01004657 allow_mandatory = 1;
4658 }
4659
Michal Vasko7f45cf22020-10-01 12:49:44 +02004660 LY_LIST_FOR(aug_p->child, pnode) {
Radek Krejci3641f562019-02-13 15:38:40 +01004661 /* check if the subnode can be connected to the found target (e.g. case cannot be inserted into container) */
Michal Vasko69730152020-10-09 16:30:07 +02004662 if (((pnode->nodetype == LYS_CASE) && (target->nodetype != LYS_CHOICE)) ||
4663 ((pnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && !(target->nodetype & (LYS_CONTAINER | LYS_LIST))) ||
4664 ((pnode->nodetype == LYS_USES) && (target->nodetype == LYS_CHOICE))) {
Radek Krejci3641f562019-02-13 15:38:40 +01004665 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02004666 "Invalid augment of %s node which is not allowed to contain %s node \"%s\".",
4667 lys_nodetype2str(target->nodetype), lys_nodetype2str(pnode->nodetype), pnode->name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004668 ret = LY_EVALID;
4669 goto cleanup;
Radek Krejci3641f562019-02-13 15:38:40 +01004670 }
4671
4672 /* compile the children */
Michal Vasko20424b42020-08-31 12:29:38 +02004673 if (target->nodetype == LYS_CHOICE) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004674 LY_CHECK_GOTO(ret = lys_compile_node_choice_child(ctx, pnode, target, &child_set), cleanup);
Radek Krejci3641f562019-02-13 15:38:40 +01004675 } else {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004676 LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
Radek Krejci3641f562019-02-13 15:38:40 +01004677 }
4678
Michal Vasko7f45cf22020-10-01 12:49:44 +02004679 /* since the augment node is not present in the compiled tree, we need to pass some of its
4680 * statements to all its children */
4681 for (i = 0; i < child_set.count; ++i) {
4682 node = child_set.snodes[i];
4683 if (!allow_mandatory && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
4684 node->flags &= ~LYS_MAND_TRUE;
4685 lys_compile_mandatory_parents(target, 0);
4686 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004687 "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.", node->name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004688 ret = LY_EVALID;
4689 goto cleanup;
Radek Krejci7c7783d2020-04-08 15:34:39 +02004690 }
Radek Krejci3641f562019-02-13 15:38:40 +01004691
Michal Vasko7f45cf22020-10-01 12:49:44 +02004692 if (aug_p->when) {
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004693 /* pass augment's when to all the children */
4694 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_xpath_context(target), node, &when_shared);
4695 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci3641f562019-02-13 15:38:40 +01004696 }
4697 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004698 ly_set_erase(&child_set, NULL);
Radek Krejci3641f562019-02-13 15:38:40 +01004699 }
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004700
4701 switch (target->nodetype) {
4702 case LYS_CONTAINER:
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004703 actions = &((struct lysc_node_container *)target)->actions;
4704 notifs = &((struct lysc_node_container *)target)->notifs;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004705 break;
4706 case LYS_LIST:
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004707 actions = &((struct lysc_node_list *)target)->actions;
4708 notifs = &((struct lysc_node_list *)target)->notifs;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004709 break;
4710 default:
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004711 actions = NULL;
4712 notifs = NULL;
4713 break;
4714 }
4715
4716 if (aug_p->actions) {
4717 if (!actions) {
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004718 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02004719 "Invalid augment of %s node which is not allowed to contain RPC/action node \"%s\".",
4720 lys_nodetype2str(target->nodetype), aug_p->actions[0].name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004721 ret = LY_EVALID;
4722 goto cleanup;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004723 }
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004724
4725 /* compile actions into the target */
4726 COMPILE_OP_ARRAY_GOTO(ctx, aug_p->actions, *actions, target, u, lys_compile_action, 0, ret, cleanup);
4727
4728 if (aug_p->when) {
4729 /* inherit when */
4730 LY_ARRAY_FOR(*actions, u) {
4731 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_xpath_context(target),
4732 (struct lysc_node *)&(*actions)[u], &when_shared);
4733 LY_CHECK_GOTO(ret, cleanup);
4734 }
4735 }
4736 }
4737 if (aug_p->notifs) {
4738 if (!notifs) {
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004739 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02004740 "Invalid augment of %s node which is not allowed to contain notification node \"%s\".",
4741 lys_nodetype2str(target->nodetype), aug_p->notifs[0].name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004742 ret = LY_EVALID;
4743 goto cleanup;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004744 }
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004745
4746 /* compile notifications into the target */
4747 COMPILE_OP_ARRAY_GOTO(ctx, aug_p->notifs, *notifs, target, u, lys_compile_notif, 0, ret, cleanup);
4748
4749 if (aug_p->when) {
4750 /* inherit when */
4751 LY_ARRAY_FOR(*notifs, u) {
4752 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_xpath_context(target),
4753 (struct lysc_node *)&(*notifs)[u], &when_shared);
4754 LY_CHECK_GOTO(ret, cleanup);
4755 }
4756 }
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004757 }
Radek Krejci3641f562019-02-13 15:38:40 +01004758
Michal Vasko7f45cf22020-10-01 12:49:44 +02004759cleanup:
4760 ly_set_erase(&child_set, NULL);
Radek Krejci3641f562019-02-13 15:38:40 +01004761 return ret;
4762}
4763
4764/**
Michal Vasko601ddb32020-08-31 16:25:35 +02004765 * @brief Find grouping for a uses.
Radek Krejcie86bf772018-12-14 11:39:53 +01004766 *
Michal Vasko601ddb32020-08-31 16:25:35 +02004767 * @param[in] ctx Compile context.
4768 * @param[in] uses_p Parsed uses node.
4769 * @param[out] gpr_p Found grouping on success.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004770 * @param[out] grp_pmod Module of @p grp_p on success.
Michal Vasko601ddb32020-08-31 16:25:35 +02004771 * @return LY_ERR value.
Radek Krejcie86bf772018-12-14 11:39:53 +01004772 */
4773static LY_ERR
Michal Vasko601ddb32020-08-31 16:25:35 +02004774lys_compile_uses_find_grouping(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, struct lysp_grp **grp_p,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004775 struct lysp_module **grp_pmod)
Radek Krejcie86bf772018-12-14 11:39:53 +01004776{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004777 struct lysp_node *pnode;
Michal Vasko601ddb32020-08-31 16:25:35 +02004778 struct lysp_grp *grp;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02004779 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004780 const char *id, *name, *prefix, *local_pref;
Radek Krejcie86bf772018-12-14 11:39:53 +01004781 size_t prefix_len, name_len;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004782 struct lysp_module *pmod, *found = NULL;
Michal Vasko601ddb32020-08-31 16:25:35 +02004783 struct lys_module *mod;
4784
4785 *grp_p = NULL;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004786 *grp_pmod = NULL;
Radek Krejcie86bf772018-12-14 11:39:53 +01004787
4788 /* search for the grouping definition */
Radek Krejcie86bf772018-12-14 11:39:53 +01004789 id = uses_p->name;
Radek Krejcib4a4a272019-06-10 12:44:52 +02004790 LY_CHECK_RET(ly_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len), LY_EVALID);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004791 local_pref = ctx->pmod->is_submod ? ((struct lysp_submodule *)ctx->pmod)->prefix : ctx->pmod->mod->prefix;
4792 if (!prefix || !ly_strncmp(local_pref, prefix, prefix_len)) {
4793 /* current module, search local groupings first */
4794 pmod = ctx->pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004795 for (pnode = uses_p->parent; !found && pnode; pnode = pnode->parent) {
4796 grp = (struct lysp_grp *)lysp_node_groupings(pnode);
Radek Krejcie86bf772018-12-14 11:39:53 +01004797 LY_ARRAY_FOR(grp, u) {
4798 if (!strcmp(grp[u].name, name)) {
4799 grp = &grp[u];
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004800 found = ctx->pmod;
Radek Krejcie86bf772018-12-14 11:39:53 +01004801 break;
4802 }
4803 }
4804 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004805 } else {
4806 /* foreign module, find it first */
4807 mod = lysp_module_find_prefix(ctx->pmod, prefix, prefix_len);
4808 if (!mod) {
4809 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
4810 "Invalid prefix used for grouping reference.", uses_p->name);
4811 return LY_EVALID;
4812 }
4813 pmod = mod->parsed;
Radek Krejcie86bf772018-12-14 11:39:53 +01004814 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004815
Radek Krejcie86bf772018-12-14 11:39:53 +01004816 if (!found) {
Radek Krejci76b3e962018-12-14 17:01:25 +01004817 /* search in top-level groupings of the main module ... */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004818 grp = pmod->groupings;
Michal Vasko601ddb32020-08-31 16:25:35 +02004819 LY_ARRAY_FOR(grp, u) {
4820 if (!strcmp(grp[u].name, name)) {
4821 grp = &grp[u];
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004822 found = pmod;
Michal Vasko601ddb32020-08-31 16:25:35 +02004823 break;
Radek Krejci76b3e962018-12-14 17:01:25 +01004824 }
4825 }
Michal Vasko601ddb32020-08-31 16:25:35 +02004826 if (!found) {
Radek Krejci76b3e962018-12-14 17:01:25 +01004827 /* ... and all the submodules */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004828 LY_ARRAY_FOR(pmod->includes, u) {
4829 grp = pmod->includes[u].submodule->groupings;
Michal Vasko601ddb32020-08-31 16:25:35 +02004830 LY_ARRAY_FOR(grp, v) {
4831 if (!strcmp(grp[v].name, name)) {
4832 grp = &grp[v];
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004833 found = (struct lysp_module *)pmod->includes[u].submodule;
Michal Vasko601ddb32020-08-31 16:25:35 +02004834 break;
Radek Krejci76b3e962018-12-14 17:01:25 +01004835 }
4836 }
Michal Vasko601ddb32020-08-31 16:25:35 +02004837 if (found) {
4838 break;
4839 }
Radek Krejcie86bf772018-12-14 11:39:53 +01004840 }
4841 }
4842 }
4843 if (!found) {
4844 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004845 "Grouping \"%s\" referenced by a uses statement not found.", uses_p->name);
Radek Krejcie86bf772018-12-14 11:39:53 +01004846 return LY_EVALID;
4847 }
4848
Radek Krejci90d4e922020-10-12 15:55:33 +02004849 if (!(ctx->options & LYS_COMPILE_GROUPING)) {
Radek Krejcif2de0ed2019-05-02 14:13:18 +02004850 /* remember that the grouping is instantiated to avoid its standalone validation */
4851 grp->flags |= LYS_USED_GRP;
4852 }
Radek Krejcie86bf772018-12-14 11:39:53 +01004853
Michal Vasko601ddb32020-08-31 16:25:35 +02004854 *grp_p = grp;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004855 *grp_pmod = found;
Michal Vasko601ddb32020-08-31 16:25:35 +02004856 return LY_SUCCESS;
4857}
Radek Krejcie86bf772018-12-14 11:39:53 +01004858
Michal Vasko7f45cf22020-10-01 12:49:44 +02004859static const struct lys_module *lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004860 size_t nametest_len, const struct lysp_module *mod, const char **name, size_t *name_len);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004861
Michal Vasko601ddb32020-08-31 16:25:35 +02004862static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004863lys_nodeid_check(struct lysc_ctx *ctx, const char *nodeid, ly_bool abs, struct lys_module **target_mod,
4864 struct lyxp_expr **expr)
Michal Vasko601ddb32020-08-31 16:25:35 +02004865{
Michal Vasko601ddb32020-08-31 16:25:35 +02004866 LY_ERR ret = LY_SUCCESS;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004867 struct lyxp_expr *e = NULL;
4868 struct lys_module *tmod = NULL, *mod;
4869 const char *nodeid_type = abs ? "absolute-schema-nodeid" : "descendant-schema-nodeid";
4870 uint32_t i;
Radek Krejcie86bf772018-12-14 11:39:53 +01004871
Michal Vasko7f45cf22020-10-01 12:49:44 +02004872 /* parse */
4873 ret = lyxp_expr_parse(ctx->ctx, nodeid, strlen(nodeid), 0, &e);
4874 if (ret) {
4875 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid %s value \"%s\" - invalid syntax.",
4876 nodeid_type, nodeid);
4877 ret = LY_EVALID;
4878 goto cleanup;
Radek Krejci01342af2019-01-03 15:18:08 +01004879 }
Radek Krejcie86bf772018-12-14 11:39:53 +01004880
Michal Vasko7f45cf22020-10-01 12:49:44 +02004881 if (abs) {
4882 /* absolute schema nodeid */
4883 i = 0;
4884 } else {
4885 /* descendant schema nodeid */
4886 if (e->tokens[0] != LYXP_TOKEN_NAMETEST) {
4887 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
4888 nodeid_type, nodeid, e->tok_len[0], e->expr + e->tok_pos[0]);
Michal Vasko20424b42020-08-31 12:29:38 +02004889 ret = LY_EVALID;
Radek Krejcifc11bd72019-04-11 16:00:05 +02004890 goto cleanup;
Radek Krejcif2271f12019-01-07 16:42:23 +01004891 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004892 i = 1;
4893 }
Radek Krejcif2271f12019-01-07 16:42:23 +01004894
Michal Vasko7f45cf22020-10-01 12:49:44 +02004895 /* check all the tokens */
4896 for ( ; i < e->used; i += 2) {
4897 if (e->tokens[i] != LYXP_TOKEN_OPER_PATH) {
4898 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s value \"%s\" - \"/\" expected instead of \"%.*s\".",
4899 nodeid_type, nodeid, e->tok_len[i], e->expr + e->tok_pos[i]);
4900 ret = LY_EVALID;
4901 goto cleanup;
4902 } else if (e->used == i + 1) {
4903 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
4904 "Invalid %s value \"%s\" - unexpected end of expression.", nodeid_type, e->expr);
4905 ret = LY_EVALID;
4906 goto cleanup;
4907 } else if (e->tokens[i + 1] != LYXP_TOKEN_NAMETEST) {
4908 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
4909 nodeid_type, nodeid, e->tok_len[i + 1], e->expr + e->tok_pos[i + 1]);
4910 ret = LY_EVALID;
4911 goto cleanup;
4912 } else if (abs) {
4913 mod = (struct lys_module *)lys_schema_node_get_module(ctx->ctx, e->expr + e->tok_pos[i + 1],
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004914 e->tok_len[i + 1], ctx->pmod, NULL, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004915 LY_CHECK_ERR_GOTO(!mod, ret = LY_EVALID, cleanup);
4916
4917 /* only keep the first module */
4918 if (!tmod) {
4919 tmod = mod;
Radek Krejcif2271f12019-01-07 16:42:23 +01004920 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004921
4922 /* all the modules must be implemented */
4923 if (!mod->implemented) {
Michal Vasko89b5c072020-10-06 13:52:44 +02004924 ret = lys_set_implemented(mod);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004925 LY_CHECK_GOTO(ret, cleanup);
4926 }
4927 }
4928 }
4929
4930cleanup:
4931 if (ret || !expr) {
4932 lyxp_expr_free(ctx->ctx, e);
4933 e = NULL;
4934 }
4935 if (expr) {
4936 *expr = ret ? NULL : e;
4937 }
4938 if (target_mod) {
4939 *target_mod = ret ? NULL : tmod;
4940 }
4941 return ret;
4942}
4943
4944/**
4945 * @brief Check whether 2 schema nodeids match.
4946 *
4947 * @param[in] ctx libyang context.
4948 * @param[in] exp1 First schema nodeid.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004949 * @param[in] exp1p_mod Module of @p exp1 nodes without any prefix.
Michal Vasko7f45cf22020-10-01 12:49:44 +02004950 * @param[in] exp2 Second schema nodeid.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004951 * @param[in] exp2_pmod Module of @p exp2 nodes without any prefix.
Michal Vasko7f45cf22020-10-01 12:49:44 +02004952 * @return Whether the schema nodeids match or not.
4953 */
4954static ly_bool
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004955lys_abs_schema_nodeid_match(const struct ly_ctx *ctx, const struct lyxp_expr *exp1, const struct lysp_module *exp1_pmod,
4956 const struct lyxp_expr *exp2, const struct lysp_module *exp2_pmod)
Michal Vasko7f45cf22020-10-01 12:49:44 +02004957{
4958 uint32_t i;
4959 const struct lys_module *mod1, *mod2;
4960 const char *name1, *name2;
4961 size_t name1_len, name2_len;
4962
4963 if (exp1->used != exp2->used) {
4964 return 0;
4965 }
4966
4967 for (i = 0; i < exp1->used; ++i) {
4968 assert(exp1->tokens[i] == exp2->tokens[i]);
4969
4970 if (exp1->tokens[i] == LYXP_TOKEN_NAMETEST) {
4971 /* check modules of all the nodes in the node ID */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004972 mod1 = lys_schema_node_get_module(ctx, exp1->expr + exp1->tok_pos[i], exp1->tok_len[i], exp1_pmod,
Michal Vasko7f45cf22020-10-01 12:49:44 +02004973 &name1, &name1_len);
4974 assert(mod1);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004975 mod2 = lys_schema_node_get_module(ctx, exp2->expr + exp2->tok_pos[i], exp2->tok_len[i], exp2_pmod,
Michal Vasko7f45cf22020-10-01 12:49:44 +02004976 &name2, &name2_len);
4977 assert(mod2);
4978
4979 /* compare modules */
4980 if (mod1 != mod2) {
4981 return 0;
4982 }
4983
4984 /* compare names */
4985 if ((name1_len != name2_len) || strncmp(name1, name2, name1_len)) {
4986 return 0;
4987 }
4988 }
4989 }
4990
4991 return 1;
4992}
4993
4994/**
4995 * @brief Prepare any uses augments and refines in the context to be applied during uses descendant node compilation.
4996 *
4997 * @param[in] ctx Compile context.
4998 * @param[in] uses_p Parsed uses structure with augments and refines.
4999 * @param[in] ctx_node Context node of @p uses_p meaning its first data definiition parent.
5000 * @return LY_ERR value.
5001 */
5002static LY_ERR
5003lys_precompile_uses_augments_refines(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, const struct lysc_node *ctx_node)
5004{
5005 LY_ERR ret = LY_SUCCESS;
5006 LY_ARRAY_COUNT_TYPE u;
5007 struct lyxp_expr *exp = NULL;
5008 struct lysc_augment *aug;
5009 struct lysc_refine *rfn;
5010 struct lysp_refine **new_rfn;
5011 uint32_t i;
5012
5013 LY_ARRAY_FOR(uses_p->augments, u) {
5014 lysc_update_path(ctx, NULL, "{augment}");
5015 lysc_update_path(ctx, NULL, uses_p->augments[u].nodeid);
5016
5017 /* parse the nodeid */
5018 LY_CHECK_GOTO(ret = lys_nodeid_check(ctx, uses_p->augments[u].nodeid, 0, NULL, &exp), cleanup);
5019
5020 /* allocate new compiled augment and store it in the set */
5021 aug = calloc(1, sizeof *aug);
5022 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci3d92e442020-10-12 12:48:13 +02005023 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_augs, aug, 1, NULL), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005024
5025 aug->nodeid = exp;
5026 exp = NULL;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005027 aug->nodeid_pmod = ctx->pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005028 aug->nodeid_ctx_node = ctx_node;
5029 aug->aug_p = &uses_p->augments[u];
5030
5031 lysc_update_path(ctx, NULL, NULL);
5032 lysc_update_path(ctx, NULL, NULL);
5033 }
5034
5035 LY_ARRAY_FOR(uses_p->refines, u) {
5036 lysc_update_path(ctx, NULL, "{refine}");
5037 lysc_update_path(ctx, NULL, uses_p->refines[u].nodeid);
5038
5039 /* parse the nodeid */
5040 LY_CHECK_GOTO(ret = lys_nodeid_check(ctx, uses_p->refines[u].nodeid, 0, NULL, &exp), cleanup);
5041
5042 /* try to find the node in already compiled refines */
5043 rfn = NULL;
5044 for (i = 0; i < ctx->uses_rfns.count; ++i) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005045 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, ctx->pmod, ((struct lysc_refine *)ctx->uses_rfns.objs[i])->nodeid,
5046 ctx->pmod)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02005047 rfn = ctx->uses_rfns.objs[i];
5048 break;
Radek Krejcif2271f12019-01-07 16:42:23 +01005049 }
5050 }
Michal Vasko601ddb32020-08-31 16:25:35 +02005051
Michal Vasko7f45cf22020-10-01 12:49:44 +02005052 if (!rfn) {
5053 /* allocate new compiled refine */
5054 rfn = calloc(1, sizeof *rfn);
5055 LY_CHECK_ERR_GOTO(!rfn, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci3d92e442020-10-12 12:48:13 +02005056 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_rfns, rfn, 1, NULL), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005057
5058 rfn->nodeid = exp;
5059 exp = NULL;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005060 rfn->nodeid_pmod = ctx->pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005061 rfn->nodeid_ctx_node = ctx_node;
5062 } else {
5063 /* just free exp */
5064 lyxp_expr_free(ctx->ctx, exp);
5065 exp = NULL;
5066 }
5067
5068 /* add new parsed refine structure */
5069 LY_ARRAY_NEW_GOTO(ctx->ctx, rfn->rfns, new_rfn, ret, cleanup);
5070 *new_rfn = &uses_p->refines[u];
5071
5072 lysc_update_path(ctx, NULL, NULL);
Michal Vasko601ddb32020-08-31 16:25:35 +02005073 lysc_update_path(ctx, NULL, NULL);
Radek Krejcif2271f12019-01-07 16:42:23 +01005074 }
5075
Michal Vasko601ddb32020-08-31 16:25:35 +02005076cleanup:
Michal Vasko7f45cf22020-10-01 12:49:44 +02005077 lyxp_expr_free(ctx->ctx, exp);
Michal Vasko601ddb32020-08-31 16:25:35 +02005078 return ret;
5079}
5080
5081/**
5082 * @brief Compile parsed uses statement - resolve target grouping and connect its content into parent.
5083 * If present, also apply uses's modificators.
5084 *
5085 * @param[in] ctx Compile context
5086 * @param[in] uses_p Parsed uses schema node.
5087 * @param[in] parent Compiled parent node where the content of the referenced grouping is supposed to be connected. It is
5088 * NULL for top-level nodes, in such a case the module where the node will be connected is taken from
5089 * the compile context.
5090 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
5091 */
5092static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02005093lys_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 +02005094{
Michal Vasko7f45cf22020-10-01 12:49:44 +02005095 struct lysp_node *pnode;
5096 struct lysc_node *child;
Michal Vasko601ddb32020-08-31 16:25:35 +02005097 struct lysp_grp *grp = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005098 uint32_t i, grp_stack_count;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005099 struct lysp_module *grp_mod, *mod_old = ctx->pmod;
Michal Vasko601ddb32020-08-31 16:25:35 +02005100 LY_ERR ret = LY_SUCCESS;
Michal Vaskoceab6dd2020-10-09 16:53:36 +02005101 struct lysc_when *when_shared = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005102 LY_ARRAY_COUNT_TYPE u;
Michal Vasko601ddb32020-08-31 16:25:35 +02005103 struct lysc_notif **notifs = NULL;
5104 struct lysc_action **actions = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005105 struct ly_set uses_child_set = {0};
Michal Vasko601ddb32020-08-31 16:25:35 +02005106
5107 /* find the referenced grouping */
5108 LY_CHECK_RET(lys_compile_uses_find_grouping(ctx, uses_p, &grp, &grp_mod));
5109
5110 /* grouping must not reference themselves - stack in ctx maintains list of groupings currently being applied */
5111 grp_stack_count = ctx->groupings.count;
5112 LY_CHECK_RET(ly_set_add(&ctx->groupings, (void *)grp, 0, NULL));
5113 if (grp_stack_count == ctx->groupings.count) {
5114 /* the target grouping is already in the stack, so we are already inside it -> circular dependency */
5115 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02005116 "Grouping \"%s\" references itself through a uses statement.", grp->name);
Michal Vasko601ddb32020-08-31 16:25:35 +02005117 return LY_EVALID;
5118 }
5119
Michal Vasko7f45cf22020-10-01 12:49:44 +02005120 /* check status */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005121 ret = lysc_check_status(ctx, uses_p->flags, ctx->pmod, uses_p->name, grp->flags, grp_mod, grp->name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005122 LY_CHECK_GOTO(ret, cleanup);
5123
5124 /* compile any augments and refines so they can be applied during the grouping nodes compilation */
5125 ret = lys_precompile_uses_augments_refines(ctx, uses_p, parent);
5126 LY_CHECK_GOTO(ret, cleanup);
5127
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005128 /* switch context's parsed module being processed */
5129 ctx->pmod = grp_mod;
Michal Vasko601ddb32020-08-31 16:25:35 +02005130
Michal Vasko601ddb32020-08-31 16:25:35 +02005131 /* compile data nodes */
Michal Vasko7f45cf22020-10-01 12:49:44 +02005132 LY_LIST_FOR(grp->data, pnode) {
Michal Vasko601ddb32020-08-31 16:25:35 +02005133 /* 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 +02005134 ret = lys_compile_node(ctx, pnode, parent, (uses_p->flags & LYS_STATUS_MASK) | 0x3, &uses_child_set);
Michal Vasko601ddb32020-08-31 16:25:35 +02005135 LY_CHECK_GOTO(ret, cleanup);
5136 }
5137
Michal Vasko7f45cf22020-10-01 12:49:44 +02005138 if (child_set) {
5139 /* add these children to our compiled child_set as well since uses is a schema-only node */
Radek Krejci3d92e442020-10-12 12:48:13 +02005140 LY_CHECK_GOTO(ret = ly_set_merge(child_set, &uses_child_set, 1, NULL), cleanup);
Michal Vasko601ddb32020-08-31 16:25:35 +02005141 }
5142
Michal Vasko7f45cf22020-10-01 12:49:44 +02005143 if (uses_p->when) {
Michal Vaskoceab6dd2020-10-09 16:53:36 +02005144 /* pass uses's when to all the data children */
Michal Vasko7f45cf22020-10-01 12:49:44 +02005145 for (i = 0; i < uses_child_set.count; ++i) {
5146 child = uses_child_set.snodes[i];
5147
Michal Vaskoceab6dd2020-10-09 16:53:36 +02005148 ret = lys_compile_when(ctx, uses_p->when, uses_p->flags, lysc_xpath_context(parent), child, &when_shared);
5149 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko601ddb32020-08-31 16:25:35 +02005150 }
5151 }
5152
5153 /* compile actions */
Michal Vasko7f45cf22020-10-01 12:49:44 +02005154 if (grp->actions) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005155 actions = parent ? lysc_node_actions_p(parent) : &ctx->cur_mod->compiled->rpcs;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005156 if (!actions) {
5157 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid child %s \"%s\" of uses parent %s \"%s\" node.",
Michal Vasko69730152020-10-09 16:30:07 +02005158 grp->actions[0].name, lys_nodetype2str(grp->actions[0].nodetype), parent->name,
5159 lys_nodetype2str(parent->nodetype));
Michal Vasko7f45cf22020-10-01 12:49:44 +02005160 ret = LY_EVALID;
5161 goto cleanup;
Michal Vasko601ddb32020-08-31 16:25:35 +02005162 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02005163 COMPILE_OP_ARRAY_GOTO(ctx, grp->actions, *actions, parent, u, lys_compile_action, 0, ret, cleanup);
Michal Vaskoceab6dd2020-10-09 16:53:36 +02005164
5165 if (uses_p->when) {
5166 /* inherit when */
5167 LY_ARRAY_FOR(*actions, u) {
5168 ret = lys_compile_when(ctx, uses_p->when, uses_p->flags, lysc_xpath_context(parent),
5169 (struct lysc_node *)&(*actions)[u], &when_shared);
5170 LY_CHECK_GOTO(ret, cleanup);
5171 }
5172 }
Michal Vasko601ddb32020-08-31 16:25:35 +02005173 }
5174
5175 /* compile notifications */
Michal Vasko7f45cf22020-10-01 12:49:44 +02005176 if (grp->notifs) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005177 notifs = parent ? lysc_node_notifs_p(parent) : &ctx->cur_mod->compiled->notifs;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005178 if (!notifs) {
5179 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid child %s \"%s\" of uses parent %s \"%s\" node.",
Michal Vasko69730152020-10-09 16:30:07 +02005180 grp->notifs[0].name, lys_nodetype2str(grp->notifs[0].nodetype), parent->name,
5181 lys_nodetype2str(parent->nodetype));
Michal Vasko7f45cf22020-10-01 12:49:44 +02005182 ret = LY_EVALID;
5183 goto cleanup;
Michal Vasko601ddb32020-08-31 16:25:35 +02005184 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02005185 COMPILE_OP_ARRAY_GOTO(ctx, grp->notifs, *notifs, parent, u, lys_compile_notif, 0, ret, cleanup);
Michal Vaskoceab6dd2020-10-09 16:53:36 +02005186
5187 if (uses_p->when) {
5188 /* inherit when */
5189 LY_ARRAY_FOR(*notifs, u) {
5190 ret = lys_compile_when(ctx, uses_p->when, uses_p->flags, lysc_xpath_context(parent),
5191 (struct lysc_node *)&(*notifs)[u], &when_shared);
5192 LY_CHECK_GOTO(ret, cleanup);
5193 }
5194 }
Michal Vasko601ddb32020-08-31 16:25:35 +02005195 }
5196
Michal Vasko7f45cf22020-10-01 12:49:44 +02005197 /* check that all augments were applied */
5198 for (i = 0; i < ctx->uses_augs.count; ++i) {
5199 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02005200 "Augment target node \"%s\" in grouping \"%s\" was not found.",
Michal Vasko891d7532020-10-07 09:41:38 +02005201 ((struct lysc_augment *)ctx->uses_augs.objs[i])->nodeid->expr, grp->name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005202 ret = LY_ENOTFOUND;
Michal Vasko601ddb32020-08-31 16:25:35 +02005203 }
Michal Vasko601ddb32020-08-31 16:25:35 +02005204 LY_CHECK_GOTO(ret, cleanup);
5205
Michal Vasko7f45cf22020-10-01 12:49:44 +02005206 /* check that all refines were applied */
5207 for (i = 0; i < ctx->uses_rfns.count; ++i) {
5208 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02005209 "Refine(s) target node \"%s\" in grouping \"%s\" was not found.",
Michal Vasko891d7532020-10-07 09:41:38 +02005210 ((struct lysc_refine *)ctx->uses_rfns.objs[i])->nodeid->expr, grp->name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005211 ret = LY_ENOTFOUND;
Radek Krejcic6b4f442020-08-12 14:45:18 +02005212 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02005213 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcifc11bd72019-04-11 16:00:05 +02005214
5215cleanup:
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005216 /* reload previous context's parsed module being processed */
5217 ctx->pmod = mod_old;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005218
Radek Krejcie86bf772018-12-14 11:39:53 +01005219 /* remove the grouping from the stack for circular groupings dependency check */
5220 ly_set_rm_index(&ctx->groupings, ctx->groupings.count - 1, NULL);
5221 assert(ctx->groupings.count == grp_stack_count);
5222
Michal Vasko7f45cf22020-10-01 12:49:44 +02005223 ly_set_erase(&uses_child_set, NULL);
Radek Krejcie86bf772018-12-14 11:39:53 +01005224 return ret;
5225}
5226
Radek Krejci327de162019-06-14 12:52:07 +02005227static int
5228lys_compile_grouping_pathlog(struct lysc_ctx *ctx, struct lysp_node *node, char **path)
5229{
5230 struct lysp_node *iter;
5231 int len = 0;
5232
5233 *path = NULL;
5234 for (iter = node; iter && len >= 0; iter = iter->parent) {
5235 char *s = *path;
5236 char *id;
5237
5238 switch (iter->nodetype) {
5239 case LYS_USES:
Radek Krejci200f1062020-07-11 22:51:03 +02005240 LY_CHECK_RET(asprintf(&id, "{uses='%s'}", iter->name) == -1, -1);
Radek Krejci327de162019-06-14 12:52:07 +02005241 break;
5242 case LYS_GROUPING:
Radek Krejci200f1062020-07-11 22:51:03 +02005243 LY_CHECK_RET(asprintf(&id, "{grouping='%s'}", iter->name) == -1, -1);
Radek Krejci327de162019-06-14 12:52:07 +02005244 break;
5245 case LYS_AUGMENT:
Radek Krejci200f1062020-07-11 22:51:03 +02005246 LY_CHECK_RET(asprintf(&id, "{augment='%s'}", iter->name) == -1, -1);
Radek Krejci327de162019-06-14 12:52:07 +02005247 break;
5248 default:
5249 id = strdup(iter->name);
5250 break;
5251 }
5252
5253 if (!iter->parent) {
5254 /* print prefix */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005255 len = asprintf(path, "/%s:%s%s", ctx->cur_mod->name, id, s ? s : "");
Radek Krejci327de162019-06-14 12:52:07 +02005256 } else {
5257 /* prefix is the same as in parent */
5258 len = asprintf(path, "/%s%s", id, s ? s : "");
5259 }
5260 free(s);
5261 free(id);
5262 }
5263
5264 if (len < 0) {
5265 free(*path);
5266 *path = NULL;
5267 } else if (len == 0) {
5268 *path = strdup("/");
5269 len = 1;
5270 }
5271 return len;
5272}
5273
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005274/**
5275 * @brief Validate groupings that were defined but not directly used in the schema itself.
5276 *
5277 * The grouping does not need to be compiled (and it is compiled here, but the result is forgotten immediately),
5278 * but to have the complete result of the schema validity, even such groupings are supposed to be checked.
5279 */
5280static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02005281lys_compile_grouping(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysp_grp *grp)
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005282{
5283 LY_ERR ret;
Radek Krejci327de162019-06-14 12:52:07 +02005284 char *path;
5285 int len;
5286
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005287 struct lysp_node_uses fake_uses = {
Michal Vasko7f45cf22020-10-01 12:49:44 +02005288 .parent = pnode,
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005289 .nodetype = LYS_USES,
5290 .flags = 0, .next = NULL,
5291 .name = grp->name,
5292 .dsc = NULL, .ref = NULL, .when = NULL, .iffeatures = NULL, .exts = NULL,
5293 .refines = NULL, .augments = NULL
5294 };
5295 struct lysc_node_container fake_container = {
5296 .nodetype = LYS_CONTAINER,
Michal Vasko7f45cf22020-10-01 12:49:44 +02005297 .flags = pnode ? (pnode->flags & LYS_FLAGS_COMPILED_MASK) : 0,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005298 .module = ctx->cur_mod,
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005299 .sp = NULL, .parent = NULL, .next = NULL,
Michal Vasko22df3f02020-08-24 13:29:22 +02005300 .prev = (struct lysc_node *)&fake_container,
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005301 .name = "fake",
5302 .dsc = NULL, .ref = NULL, .exts = NULL, .iffeatures = NULL, .when = NULL,
5303 .child = NULL, .musts = NULL, .actions = NULL, .notifs = NULL
5304 };
5305
5306 if (grp->parent) {
5307 LOGWRN(ctx->ctx, "Locally scoped grouping \"%s\" not used.", grp->name);
5308 }
Radek Krejci327de162019-06-14 12:52:07 +02005309
5310 len = lys_compile_grouping_pathlog(ctx, grp->parent, &path);
5311 if (len < 0) {
5312 LOGMEM(ctx->ctx);
5313 return LY_EMEM;
5314 }
5315 strncpy(ctx->path, path, LYSC_CTX_BUFSIZE - 1);
Radek Krejci1deb5be2020-08-26 16:43:36 +02005316 ctx->path_len = (uint32_t)len;
Radek Krejci327de162019-06-14 12:52:07 +02005317 free(path);
5318
5319 lysc_update_path(ctx, NULL, "{grouping}");
5320 lysc_update_path(ctx, NULL, grp->name);
Michal Vasko22df3f02020-08-24 13:29:22 +02005321 ret = lys_compile_uses(ctx, &fake_uses, (struct lysc_node *)&fake_container, NULL);
Radek Krejci327de162019-06-14 12:52:07 +02005322 lysc_update_path(ctx, NULL, NULL);
5323 lysc_update_path(ctx, NULL, NULL);
5324
5325 ctx->path_len = 1;
5326 ctx->path[1] = '\0';
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005327
5328 /* cleanup */
5329 lysc_node_container_free(ctx->ctx, &fake_container);
5330
5331 return ret;
5332}
Radek Krejcife909632019-02-12 15:34:42 +01005333
Radek Krejcie86bf772018-12-14 11:39:53 +01005334/**
Michal Vasko20424b42020-08-31 12:29:38 +02005335 * @brief Set config flags for a node.
5336 *
5337 * @param[in] ctx Compile context.
5338 * @param[in] node Compiled node config to set.
5339 * @param[in] parent Parent of @p node.
5340 * @return LY_ERR value.
5341 */
5342static LY_ERR
5343lys_compile_config(struct lysc_ctx *ctx, struct lysc_node *node, struct lysc_node *parent)
5344{
5345 if (node->nodetype == LYS_CASE) {
5346 /* case never has any config */
5347 assert(!(node->flags & LYS_CONFIG_MASK));
5348 return LY_SUCCESS;
5349 }
5350
5351 /* adjust parent to always get the ancestor with config */
5352 if (parent && (parent->nodetype == LYS_CASE)) {
5353 parent = parent->parent;
5354 assert(parent);
5355 }
5356
Radek Krejci90d4e922020-10-12 15:55:33 +02005357 if (ctx->options & (LYS_COMPILE_RPC_INPUT | LYS_COMPILE_RPC_OUTPUT)) {
Michal Vasko20424b42020-08-31 12:29:38 +02005358 /* ignore config statements inside RPC/action data */
5359 node->flags &= ~LYS_CONFIG_MASK;
Radek Krejci90d4e922020-10-12 15:55:33 +02005360 node->flags |= (ctx->options & LYS_COMPILE_RPC_INPUT) ? LYS_CONFIG_W : LYS_CONFIG_R;
5361 } else if (ctx->options & LYS_COMPILE_NOTIFICATION) {
Michal Vasko20424b42020-08-31 12:29:38 +02005362 /* ignore config statements inside Notification data */
5363 node->flags &= ~LYS_CONFIG_MASK;
5364 node->flags |= LYS_CONFIG_R;
5365 } else if (!(node->flags & LYS_CONFIG_MASK)) {
5366 /* config not explicitely set, inherit it from parent */
5367 if (parent) {
5368 node->flags |= parent->flags & LYS_CONFIG_MASK;
5369 } else {
5370 /* default is config true */
5371 node->flags |= LYS_CONFIG_W;
5372 }
5373 } else {
5374 /* config set explicitely */
5375 node->flags |= LYS_SET_CONFIG;
5376 }
5377
5378 if (parent && (parent->flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
5379 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02005380 "Configuration node cannot be child of any state data node.");
Michal Vasko20424b42020-08-31 12:29:38 +02005381 return LY_EVALID;
5382 }
5383
5384 return LY_SUCCESS;
5385}
5386
Michal Vasko7f45cf22020-10-01 12:49:44 +02005387static LY_ERR
5388lysp_ext_dup(const struct ly_ctx *ctx, struct lysp_ext_instance *ext, const struct lysp_ext_instance *orig_ext)
5389{
5390 LY_ERR ret = LY_SUCCESS;
5391
5392 *ext = *orig_ext;
5393 DUP_STRING(ctx, orig_ext->name, ext->name, ret);
5394 DUP_STRING(ctx, orig_ext->argument, ext->argument, ret);
5395
5396 return ret;
5397}
5398
5399static LY_ERR
5400lysp_restr_dup(const struct ly_ctx *ctx, struct lysp_restr *restr, const struct lysp_restr *orig_restr)
5401{
5402 LY_ERR ret = LY_SUCCESS;
5403
5404 if (orig_restr) {
5405 DUP_STRING(ctx, orig_restr->arg.str, restr->arg.str, ret);
5406 restr->arg.mod = orig_restr->arg.mod;
5407 DUP_STRING(ctx, orig_restr->emsg, restr->emsg, ret);
5408 DUP_STRING(ctx, orig_restr->eapptag, restr->eapptag, ret);
5409 DUP_STRING(ctx, orig_restr->dsc, restr->dsc, ret);
5410 DUP_STRING(ctx, orig_restr->ref, restr->ref, ret);
5411 DUP_ARRAY(ctx, orig_restr->exts, restr->exts, lysp_ext_dup);
5412 }
5413
5414 return ret;
5415}
5416
5417static LY_ERR
5418lysp_string_dup(const struct ly_ctx *ctx, const char **str, const char **orig_str)
5419{
5420 LY_ERR ret = LY_SUCCESS;
5421
5422 DUP_STRING(ctx, *orig_str, *str, ret);
5423
5424 return ret;
5425}
5426
5427static LY_ERR
5428lysp_qname_dup(const struct ly_ctx *ctx, struct lysp_qname *qname, const struct lysp_qname *orig_qname)
5429{
5430 LY_ERR ret = LY_SUCCESS;
5431
Michal Vaskoe9c050f2020-10-06 14:01:23 +02005432 if (!orig_qname->str) {
5433 return LY_SUCCESS;
5434 }
5435
Michal Vasko7f45cf22020-10-01 12:49:44 +02005436 DUP_STRING(ctx, orig_qname->str, qname->str, ret);
Michal Vaskoe9c050f2020-10-06 14:01:23 +02005437 assert(orig_qname->mod);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005438 qname->mod = orig_qname->mod;
5439
5440 return ret;
5441}
5442
5443static LY_ERR
5444lysp_type_enum_dup(const struct ly_ctx *ctx, struct lysp_type_enum *enm, const struct lysp_type_enum *orig_enm)
5445{
5446 LY_ERR ret = LY_SUCCESS;
5447
5448 DUP_STRING(ctx, orig_enm->name, enm->name, ret);
5449 DUP_STRING(ctx, orig_enm->dsc, enm->dsc, ret);
5450 DUP_STRING(ctx, orig_enm->ref, enm->ref, ret);
5451 enm->value = orig_enm->value;
5452 DUP_ARRAY(ctx, orig_enm->iffeatures, enm->iffeatures, lysp_qname_dup);
5453 DUP_ARRAY(ctx, orig_enm->exts, enm->exts, lysp_ext_dup);
5454 enm->flags = orig_enm->flags;
5455
5456 return ret;
5457}
5458
5459static LY_ERR
5460lysp_type_dup(const struct ly_ctx *ctx, struct lysp_type *type, const struct lysp_type *orig_type)
5461{
5462 LY_ERR ret = LY_SUCCESS;
5463
5464 DUP_STRING_GOTO(ctx, orig_type->name, type->name, ret, done);
5465
5466 if (orig_type->range) {
5467 type->range = calloc(1, sizeof *type->range);
5468 LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx), LY_EMEM);
5469 LY_CHECK_RET(lysp_restr_dup(ctx, type->range, orig_type->range));
5470 }
5471
5472 if (orig_type->length) {
5473 type->length = calloc(1, sizeof *type->length);
5474 LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx), LY_EMEM);
5475 LY_CHECK_RET(lysp_restr_dup(ctx, type->length, orig_type->length));
5476 }
5477
5478 DUP_ARRAY(ctx, orig_type->patterns, type->patterns, lysp_restr_dup);
5479 DUP_ARRAY(ctx, orig_type->enums, type->enums, lysp_type_enum_dup);
5480 DUP_ARRAY(ctx, orig_type->bits, type->bits, lysp_type_enum_dup);
5481 LY_CHECK_GOTO(ret = lyxp_expr_dup(ctx, orig_type->path, &type->path), done);
5482 DUP_ARRAY(ctx, orig_type->bases, type->bases, lysp_string_dup);
5483 DUP_ARRAY(ctx, orig_type->types, type->types, lysp_type_dup);
5484 DUP_ARRAY(ctx, orig_type->exts, type->exts, lysp_ext_dup);
5485
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005486 type->pmod = orig_type->pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005487 type->compiled = orig_type->compiled;
5488
5489 type->fraction_digits = orig_type->fraction_digits;
5490 type->require_instance = orig_type->require_instance;
5491 type->flags = orig_type->flags;
5492
5493done:
5494 return ret;
5495}
5496
5497static LY_ERR
5498lysp_when_dup(const struct ly_ctx *ctx, struct lysp_when *when, const struct lysp_when *orig_when)
5499{
5500 LY_ERR ret = LY_SUCCESS;
5501
5502 DUP_STRING(ctx, orig_when->cond, when->cond, ret);
5503 DUP_STRING(ctx, orig_when->dsc, when->dsc, ret);
5504 DUP_STRING(ctx, orig_when->ref, when->ref, ret);
5505 DUP_ARRAY(ctx, orig_when->exts, when->exts, lysp_ext_dup);
5506
5507 return ret;
5508}
5509
5510static LY_ERR
5511lysp_node_common_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
5512{
5513 LY_ERR ret = LY_SUCCESS;
5514
5515 node->parent = NULL;
5516 node->nodetype = orig->nodetype;
5517 node->flags = orig->flags;
5518 node->next = NULL;
5519 DUP_STRING(ctx, orig->name, node->name, ret);
5520 DUP_STRING(ctx, orig->dsc, node->dsc, ret);
5521 DUP_STRING(ctx, orig->ref, node->ref, ret);
5522
5523 if (orig->when) {
5524 node->when = calloc(1, sizeof *node->when);
5525 LY_CHECK_ERR_RET(!node->when, LOGMEM(ctx), LY_EMEM);
5526 LY_CHECK_RET(lysp_when_dup(ctx, node->when, orig->when));
5527 }
5528
5529 DUP_ARRAY(ctx, orig->iffeatures, node->iffeatures, lysp_qname_dup);
5530 DUP_ARRAY(ctx, orig->exts, node->exts, lysp_ext_dup);
5531
5532 return ret;
5533}
5534
5535static LY_ERR
5536lysp_node_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
5537{
5538 LY_ERR ret = LY_SUCCESS;
5539 struct lysp_node_container *cont;
5540 const struct lysp_node_container *orig_cont;
5541 struct lysp_node_leaf *leaf;
5542 const struct lysp_node_leaf *orig_leaf;
5543 struct lysp_node_leaflist *llist;
5544 const struct lysp_node_leaflist *orig_llist;
5545 struct lysp_node_list *list;
5546 const struct lysp_node_list *orig_list;
5547 struct lysp_node_choice *choice;
5548 const struct lysp_node_choice *orig_choice;
5549 struct lysp_node_case *cas;
5550 const struct lysp_node_case *orig_cas;
5551 struct lysp_node_anydata *any;
5552 const struct lysp_node_anydata *orig_any;
5553
5554 assert(orig->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_ANYDATA));
5555
5556 /* common part */
5557 LY_CHECK_RET(lysp_node_common_dup(ctx, node, orig));
5558
5559 /* specific part */
5560 switch (node->nodetype) {
5561 case LYS_CONTAINER:
5562 cont = (struct lysp_node_container *)node;
5563 orig_cont = (const struct lysp_node_container *)orig;
5564
5565 DUP_ARRAY(ctx, orig_cont->musts, cont->musts, lysp_restr_dup);
5566 DUP_STRING(ctx, orig_cont->presence, cont->presence, ret);
5567 /* we do not need the rest */
5568 break;
5569 case LYS_LEAF:
5570 leaf = (struct lysp_node_leaf *)node;
5571 orig_leaf = (const struct lysp_node_leaf *)orig;
5572
5573 DUP_ARRAY(ctx, orig_leaf->musts, leaf->musts, lysp_restr_dup);
5574 LY_CHECK_RET(lysp_type_dup(ctx, &leaf->type, &orig_leaf->type));
5575 DUP_STRING(ctx, orig_leaf->units, leaf->units, ret);
Michal Vaskoe9c050f2020-10-06 14:01:23 +02005576 LY_CHECK_RET(lysp_qname_dup(ctx, &leaf->dflt, &orig_leaf->dflt));
Michal Vasko7f45cf22020-10-01 12:49:44 +02005577 break;
5578 case LYS_LEAFLIST:
5579 llist = (struct lysp_node_leaflist *)node;
5580 orig_llist = (const struct lysp_node_leaflist *)orig;
5581
5582 DUP_ARRAY(ctx, orig_llist->musts, llist->musts, lysp_restr_dup);
5583 LY_CHECK_RET(lysp_type_dup(ctx, &llist->type, &orig_llist->type));
5584 DUP_STRING(ctx, orig_llist->units, llist->units, ret);
5585 DUP_ARRAY(ctx, orig_llist->dflts, llist->dflts, lysp_qname_dup);
5586 llist->min = orig_llist->min;
5587 llist->max = orig_llist->max;
5588 break;
5589 case LYS_LIST:
5590 list = (struct lysp_node_list *)node;
5591 orig_list = (const struct lysp_node_list *)orig;
5592
5593 DUP_ARRAY(ctx, orig_list->musts, list->musts, lysp_restr_dup);
5594 DUP_STRING(ctx, orig_list->key, list->key, ret);
5595 /* we do not need these arrays */
5596 DUP_ARRAY(ctx, orig_list->uniques, list->uniques, lysp_qname_dup);
5597 list->min = orig_list->min;
5598 list->max = orig_list->max;
5599 break;
5600 case LYS_CHOICE:
5601 choice = (struct lysp_node_choice *)node;
5602 orig_choice = (const struct lysp_node_choice *)orig;
5603
5604 /* we do not need children */
5605 LY_CHECK_RET(lysp_qname_dup(ctx, &choice->dflt, &orig_choice->dflt));
5606 break;
5607 case LYS_CASE:
5608 cas = (struct lysp_node_case *)node;
5609 orig_cas = (const struct lysp_node_case *)orig;
5610
5611 /* we do not need children */
5612 (void)cas;
5613 (void)orig_cas;
5614 break;
5615 case LYS_ANYDATA:
5616 case LYS_ANYXML:
5617 any = (struct lysp_node_anydata *)node;
5618 orig_any = (const struct lysp_node_anydata *)orig;
5619
5620 DUP_ARRAY(ctx, orig_any->musts, any->musts, lysp_restr_dup);
5621 break;
5622 default:
5623 LOGINT_RET(ctx);
5624 }
5625
5626 return ret;
5627}
5628
5629static LY_ERR
5630lysp_action_inout_dup(const struct ly_ctx *ctx, struct lysp_action_inout *inout, const struct lysp_action_inout *orig)
5631{
5632 inout->parent = NULL;
5633 inout->nodetype = orig->nodetype;
5634 DUP_ARRAY(ctx, orig->musts, inout->musts, lysp_restr_dup);
5635 /* we dot need these arrays */
5636 DUP_ARRAY(ctx, orig->exts, inout->exts, lysp_ext_dup);
5637
5638 return LY_SUCCESS;
5639}
5640
5641static LY_ERR
5642lysp_action_dup(const struct ly_ctx *ctx, struct lysp_action *act, const struct lysp_action *orig)
5643{
5644 LY_ERR ret = LY_SUCCESS;
5645
5646 act->parent = NULL;
5647 act->nodetype = orig->nodetype;
5648 act->flags = orig->flags;
5649 DUP_STRING(ctx, orig->name, act->name, ret);
5650 DUP_STRING(ctx, orig->dsc, act->dsc, ret);
5651 DUP_STRING(ctx, orig->ref, act->ref, ret);
5652 DUP_ARRAY(ctx, orig->iffeatures, act->iffeatures, lysp_qname_dup);
5653
5654 act->input.nodetype = orig->input.nodetype;
5655 act->output.nodetype = orig->output.nodetype;
5656 /* we do not need choldren of in/out */
5657 DUP_ARRAY(ctx, orig->exts, act->exts, lysp_ext_dup);
5658
5659 return ret;
5660}
5661
5662static LY_ERR
5663lysp_notif_dup(const struct ly_ctx *ctx, struct lysp_notif *notif, const struct lysp_notif *orig)
5664{
5665 LY_ERR ret = LY_SUCCESS;
5666
5667 notif->parent = NULL;
5668 notif->nodetype = orig->nodetype;
5669 notif->flags = orig->flags;
5670 DUP_STRING(ctx, orig->name, notif->name, ret);
5671 DUP_STRING(ctx, orig->dsc, notif->dsc, ret);
5672 DUP_STRING(ctx, orig->ref, notif->ref, ret);
5673 DUP_ARRAY(ctx, orig->iffeatures, notif->iffeatures, lysp_qname_dup);
5674 DUP_ARRAY(ctx, orig->musts, notif->musts, lysp_restr_dup);
5675 /* we do not need these arrays */
5676 DUP_ARRAY(ctx, orig->exts, notif->exts, lysp_ext_dup);
5677
5678 return ret;
5679}
5680
5681/**
5682 * @brief Duplicate a single parsed node. Only attributes that are used in compilation are copied.
5683 *
5684 * @param[in] ctx libyang context.
5685 * @param[in] pnode Node to duplicate.
5686 * @param[in] with_links Whether to also copy any links (child, parent pointers).
5687 * @param[out] dup_p Duplicated parsed node.
5688 * @return LY_ERR value.
5689 */
5690static LY_ERR
5691lysp_dup_single(const struct ly_ctx *ctx, const struct lysp_node *pnode, ly_bool with_links, struct lysp_node **dup_p)
5692{
Michal Vaskoaf702452020-10-02 09:02:55 +02005693 LY_ERR ret = LY_SUCCESS;
5694 void *mem = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005695
5696 if (!pnode) {
5697 *dup_p = NULL;
5698 return LY_SUCCESS;
5699 }
5700
5701 switch (pnode->nodetype) {
5702 case LYS_CONTAINER:
5703 mem = calloc(1, sizeof(struct lysp_node_container));
Michal Vaskoaf702452020-10-02 09:02:55 +02005704 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5705 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005706 break;
5707 case LYS_LEAF:
5708 mem = calloc(1, sizeof(struct lysp_node_leaf));
Michal Vaskoaf702452020-10-02 09:02:55 +02005709 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5710 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005711 break;
5712 case LYS_LEAFLIST:
5713 mem = calloc(1, sizeof(struct lysp_node_leaflist));
Michal Vaskoaf702452020-10-02 09:02:55 +02005714 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5715 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005716 break;
5717 case LYS_LIST:
5718 mem = calloc(1, sizeof(struct lysp_node_list));
Michal Vaskoaf702452020-10-02 09:02:55 +02005719 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5720 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005721 break;
5722 case LYS_CHOICE:
5723 mem = calloc(1, sizeof(struct lysp_node_choice));
Michal Vaskoaf702452020-10-02 09:02:55 +02005724 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5725 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005726 break;
5727 case LYS_CASE:
5728 mem = calloc(1, sizeof(struct lysp_node_case));
Michal Vaskoaf702452020-10-02 09:02:55 +02005729 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5730 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005731 break;
5732 case LYS_ANYDATA:
5733 case LYS_ANYXML:
5734 mem = calloc(1, sizeof(struct lysp_node_anydata));
Michal Vaskoaf702452020-10-02 09:02:55 +02005735 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5736 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005737 break;
5738 case LYS_INPUT:
5739 case LYS_OUTPUT:
5740 mem = calloc(1, sizeof(struct lysp_action_inout));
Michal Vaskoaf702452020-10-02 09:02:55 +02005741 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5742 LY_CHECK_GOTO(ret = lysp_action_inout_dup(ctx, mem, (struct lysp_action_inout *)pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005743 break;
5744 case LYS_ACTION:
5745 case LYS_RPC:
5746 mem = calloc(1, sizeof(struct lysp_action));
Michal Vaskoaf702452020-10-02 09:02:55 +02005747 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5748 LY_CHECK_GOTO(ret = lysp_action_dup(ctx, mem, (struct lysp_action *)pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005749 break;
5750 case LYS_NOTIF:
5751 mem = calloc(1, sizeof(struct lysp_notif));
Michal Vaskoaf702452020-10-02 09:02:55 +02005752 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5753 LY_CHECK_GOTO(ret = lysp_notif_dup(ctx, mem, (struct lysp_notif *)pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005754 break;
5755 default:
5756 LOGINT_RET(ctx);
5757 }
5758
5759 if (with_links) {
5760 /* copy also parent and child pointers */
5761 ((struct lysp_node *)mem)->parent = pnode->parent;
5762 switch (pnode->nodetype) {
5763 case LYS_CONTAINER:
5764 ((struct lysp_node_container *)mem)->child = ((struct lysp_node_container *)pnode)->child;
5765 break;
5766 case LYS_LIST:
5767 ((struct lysp_node_list *)mem)->child = ((struct lysp_node_list *)pnode)->child;
5768 break;
5769 case LYS_CHOICE:
5770 ((struct lysp_node_choice *)mem)->child = ((struct lysp_node_choice *)pnode)->child;
5771 break;
5772 case LYS_CASE:
5773 ((struct lysp_node_case *)mem)->child = ((struct lysp_node_case *)pnode)->child;
5774 break;
5775 default:
5776 break;
5777 }
5778 }
5779
Michal Vaskoaf702452020-10-02 09:02:55 +02005780cleanup:
5781 if (ret) {
5782 free(mem);
5783 } else {
5784 *dup_p = mem;
5785 }
5786 return ret;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005787}
5788
5789#define AMEND_WRONG_NODETYPE(AMEND_STR, OP_STR, PROPERTY) \
5790 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s of %s node - it is not possible to %s \"%s\" property.", \
5791 AMEND_STR, lys_nodetype2str(target->nodetype), OP_STR, PROPERTY);\
5792 ret = LY_EVALID; \
5793 goto cleanup;
5794
5795#define AMEND_CHECK_CARDINALITY(ARRAY, MAX, AMEND_STR, PROPERTY) \
5796 if (LY_ARRAY_COUNT(ARRAY) > MAX) { \
5797 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid %s of %s with too many (%"LY_PRI_ARRAY_COUNT_TYPE") %s properties.", \
5798 AMEND_STR, lys_nodetype2str(target->nodetype), LY_ARRAY_COUNT(ARRAY), PROPERTY); \
5799 ret = LY_EVALID; \
5800 goto cleanup; \
5801 }
5802
5803/**
5804 * @brief Apply refine.
5805 *
5806 * @param[in] ctx Compile context.
5807 * @param[in] rfn Refine to apply.
5808 * @param[in,out] target Refine target.
5809 * @return LY_ERR value.
5810 */
5811static LY_ERR
5812lys_apply_refine(struct lysc_ctx *ctx, struct lysp_refine *rfn, struct lysp_node *target)
5813{
5814 LY_ERR ret = LY_SUCCESS;
5815 LY_ARRAY_COUNT_TYPE u;
5816 struct lysp_qname *qname;
5817 struct lysp_restr **musts, *must;
5818 uint32_t *num;
5819
5820 /* default value */
5821 if (rfn->dflts) {
5822 switch (target->nodetype) {
5823 case LYS_LEAF:
5824 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
5825
5826 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005827 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &rfn->dflts[0]), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005828 break;
5829 case LYS_LEAFLIST:
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005830 if (rfn->dflts[0].mod->version < LYS_VERSION_1_1) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02005831 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
5832 "Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.");
5833 ret = LY_EVALID;
5834 goto cleanup;
5835 }
5836
5837 FREE_ARRAY(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, lysp_qname_free);
5838 ((struct lysp_node_leaflist *)target)->dflts = NULL;
5839 LY_ARRAY_FOR(rfn->dflts, u) {
5840 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005841 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &rfn->dflts[u]), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005842 }
5843 break;
5844 case LYS_CHOICE:
5845 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
5846
5847 FREE_STRING(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005848 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &rfn->dflts[0]), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005849 break;
5850 default:
5851 AMEND_WRONG_NODETYPE("refine", "replace", "default");
5852 }
5853 }
5854
5855 /* description */
5856 if (rfn->dsc) {
5857 FREE_STRING(ctx->ctx, target->dsc);
5858 DUP_STRING_GOTO(ctx->ctx, rfn->dsc, target->dsc, ret, cleanup);
5859 }
5860
5861 /* reference */
5862 if (rfn->ref) {
5863 FREE_STRING(ctx->ctx, target->ref);
5864 DUP_STRING_GOTO(ctx->ctx, rfn->ref, target->ref, ret, cleanup);
5865 }
5866
5867 /* config */
5868 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci90d4e922020-10-12 15:55:33 +02005869 if (ctx->options & (LYS_COMPILE_NOTIFICATION | LYS_COMPILE_RPC_INPUT | LYS_COMPILE_RPC_OUTPUT)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02005870 LOGWRN(ctx->ctx, "Refining config inside %s has no effect (%s).",
Radek Krejci90d4e922020-10-12 15:55:33 +02005871 ctx->options & LYS_COMPILE_NOTIFICATION ? "notification" : "RPC/action", ctx->path);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005872 } else {
5873 target->flags &= ~LYS_CONFIG_MASK;
5874 target->flags |= rfn->flags & LYS_CONFIG_MASK;
5875 }
5876 }
5877
5878 /* mandatory */
5879 if (rfn->flags & LYS_MAND_MASK) {
5880 switch (target->nodetype) {
5881 case LYS_LEAF:
5882 case LYS_CHOICE:
5883 case LYS_ANYDATA:
5884 case LYS_ANYXML:
5885 break;
5886 default:
5887 AMEND_WRONG_NODETYPE("refine", "replace", "mandatory");
5888 }
5889
5890 target->flags &= ~LYS_MAND_MASK;
5891 target->flags |= rfn->flags & LYS_MAND_MASK;
5892 }
5893
5894 /* presence */
5895 if (rfn->presence) {
5896 switch (target->nodetype) {
5897 case LYS_CONTAINER:
5898 break;
5899 default:
5900 AMEND_WRONG_NODETYPE("refine", "replace", "presence");
5901 }
5902
5903 FREE_STRING(ctx->ctx, ((struct lysp_node_container *)target)->presence);
5904 DUP_STRING_GOTO(ctx->ctx, rfn->presence, ((struct lysp_node_container *)target)->presence, ret, cleanup);
5905 }
5906
5907 /* must */
5908 if (rfn->musts) {
5909 switch (target->nodetype) {
5910 case LYS_CONTAINER:
5911 case LYS_LIST:
5912 case LYS_LEAF:
5913 case LYS_LEAFLIST:
5914 case LYS_ANYDATA:
5915 case LYS_ANYXML:
5916 musts = &((struct lysp_node_container *)target)->musts;
5917 break;
5918 default:
5919 AMEND_WRONG_NODETYPE("refine", "add", "must");
5920 }
5921
5922 LY_ARRAY_FOR(rfn->musts, u) {
5923 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
5924 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &rfn->musts[u]), cleanup);
5925 }
5926 }
5927
5928 /* min-elements */
5929 if (rfn->flags & LYS_SET_MIN) {
5930 switch (target->nodetype) {
5931 case LYS_LEAFLIST:
5932 num = &((struct lysp_node_leaflist *)target)->min;
5933 break;
5934 case LYS_LIST:
5935 num = &((struct lysp_node_list *)target)->min;
5936 break;
5937 default:
5938 AMEND_WRONG_NODETYPE("refine", "replace", "min-elements");
5939 }
5940
5941 *num = rfn->min;
5942 }
5943
5944 /* max-elements */
5945 if (rfn->flags & LYS_SET_MAX) {
5946 switch (target->nodetype) {
5947 case LYS_LEAFLIST:
5948 num = &((struct lysp_node_leaflist *)target)->max;
5949 break;
5950 case LYS_LIST:
5951 num = &((struct lysp_node_list *)target)->max;
5952 break;
5953 default:
5954 AMEND_WRONG_NODETYPE("refine", "replace", "max-elements");
5955 }
5956
5957 *num = rfn->max;
5958 }
5959
5960 /* if-feature */
5961 if (rfn->iffeatures) {
5962 switch (target->nodetype) {
5963 case LYS_LEAF:
5964 case LYS_LEAFLIST:
5965 case LYS_LIST:
5966 case LYS_CONTAINER:
5967 case LYS_CHOICE:
5968 case LYS_CASE:
5969 case LYS_ANYDATA:
5970 case LYS_ANYXML:
5971 break;
5972 default:
5973 AMEND_WRONG_NODETYPE("refine", "add", "if-feature");
5974 }
5975
5976 LY_ARRAY_FOR(rfn->iffeatures, u) {
5977 LY_ARRAY_NEW_GOTO(ctx->ctx, target->iffeatures, qname, ret, cleanup);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005978 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &rfn->iffeatures[u]), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005979 }
5980 }
5981
5982 /* extension */
5983 /* TODO refine extensions */
5984
5985cleanup:
5986 return ret;
5987}
5988
5989/**
5990 * @brief Apply deviate add.
5991 *
5992 * @param[in] ctx Compile context.
5993 * @param[in] d Deviate add to apply.
5994 * @param[in,out] target Deviation target.
5995 * @return LY_ERR value.
5996 */
5997static LY_ERR
5998lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysp_deviate_add *d, struct lysp_node *target)
5999{
6000 LY_ERR ret = LY_SUCCESS;
6001 LY_ARRAY_COUNT_TYPE u;
6002 struct lysp_qname *qname;
6003 uint32_t *num;
6004 struct lysp_restr **musts, *must;
6005
6006#define DEV_CHECK_NONPRESENCE(TYPE, MEMBER, PROPERTY, VALUEMEMBER) \
6007 if (((TYPE)target)->MEMBER) { \
6008 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
6009 "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", \
6010 PROPERTY, ((TYPE)target)->VALUEMEMBER); \
6011 ret = LY_EVALID; \
6012 goto cleanup; \
6013 }
6014
6015 /* [units-stmt] */
6016 if (d->units) {
6017 switch (target->nodetype) {
6018 case LYS_LEAF:
6019 case LYS_LEAFLIST:
6020 break;
6021 default:
6022 AMEND_WRONG_NODETYPE("deviation", "add", "units");
6023 }
6024
6025 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, units, "units", units);
6026 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
6027 }
6028
6029 /* *must-stmt */
6030 if (d->musts) {
6031 switch (target->nodetype) {
6032 case LYS_CONTAINER:
6033 case LYS_LIST:
6034 case LYS_LEAF:
6035 case LYS_LEAFLIST:
6036 case LYS_ANYDATA:
6037 case LYS_ANYXML:
6038 musts = &((struct lysp_node_container *)target)->musts;
6039 break;
6040 case LYS_NOTIF:
6041 musts = &((struct lysp_notif *)target)->musts;
6042 break;
6043 case LYS_INPUT:
6044 case LYS_OUTPUT:
6045 musts = &((struct lysp_action_inout *)target)->musts;
6046 break;
6047 default:
6048 AMEND_WRONG_NODETYPE("deviation", "add", "must");
6049 }
6050
6051 LY_ARRAY_FOR(d->musts, u) {
6052 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
6053 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &d->musts[u]), cleanup);
6054 }
6055 }
6056
6057 /* *unique-stmt */
6058 if (d->uniques) {
6059 switch (target->nodetype) {
6060 case LYS_LIST:
6061 break;
6062 default:
6063 AMEND_WRONG_NODETYPE("deviation", "add", "unique");
6064 }
6065
6066 LY_ARRAY_FOR(d->uniques, u) {
6067 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_list *)target)->uniques, qname, ret, cleanup);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006068 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &d->uniques[u]), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006069 }
6070 }
6071
6072 /* *default-stmt */
6073 if (d->dflts) {
6074 switch (target->nodetype) {
6075 case LYS_LEAF:
6076 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
6077 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, dflt.str, "default", dflt.str);
6078
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006079 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &d->dflts[0]), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006080 break;
6081 case LYS_LEAFLIST:
6082 LY_ARRAY_FOR(d->dflts, u) {
6083 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006084 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &d->dflts[u]), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006085 }
6086 break;
6087 case LYS_CHOICE:
6088 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
6089 DEV_CHECK_NONPRESENCE(struct lysp_node_choice *, dflt.str, "default", dflt.str);
6090
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006091 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &d->dflts[0]), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006092 break;
6093 default:
6094 AMEND_WRONG_NODETYPE("deviation", "add", "default");
6095 }
6096 }
6097
6098 /* [config-stmt] */
6099 if (d->flags & LYS_CONFIG_MASK) {
6100 switch (target->nodetype) {
6101 case LYS_CONTAINER:
6102 case LYS_LEAF:
6103 case LYS_LEAFLIST:
6104 case LYS_LIST:
6105 case LYS_CHOICE:
6106 case LYS_ANYDATA:
6107 case LYS_ANYXML:
6108 break;
6109 default:
6110 AMEND_WRONG_NODETYPE("deviation", "add", "config");
6111 }
6112
6113 if (target->flags & LYS_CONFIG_MASK) {
6114 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6115 "Invalid deviation adding \"config\" property which already exists (with value \"config %s\").",
6116 target->flags & LYS_CONFIG_W ? "true" : "false");
6117 ret = LY_EVALID;
6118 goto cleanup;
6119 }
6120
6121 target->flags |= d->flags & LYS_CONFIG_MASK;
6122 }
6123
6124 /* [mandatory-stmt] */
6125 if (d->flags & LYS_MAND_MASK) {
6126 switch (target->nodetype) {
6127 case LYS_LEAF:
6128 case LYS_CHOICE:
6129 case LYS_ANYDATA:
6130 case LYS_ANYXML:
6131 break;
6132 default:
6133 AMEND_WRONG_NODETYPE("deviation", "add", "mandatory");
6134 }
6135
6136 if (target->flags & LYS_MAND_MASK) {
6137 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6138 "Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory %s\").",
6139 target->flags & LYS_MAND_TRUE ? "true" : "false");
6140 ret = LY_EVALID;
6141 goto cleanup;
6142 }
6143
6144 target->flags |= d->flags & LYS_MAND_MASK;
6145 }
6146
6147 /* [min-elements-stmt] */
6148 if (d->flags & LYS_SET_MIN) {
6149 switch (target->nodetype) {
6150 case LYS_LEAFLIST:
6151 num = &((struct lysp_node_leaflist *)target)->min;
6152 break;
6153 case LYS_LIST:
6154 num = &((struct lysp_node_list *)target)->min;
6155 break;
6156 default:
6157 AMEND_WRONG_NODETYPE("deviation", "add", "min-elements");
6158 }
6159
6160 if (target->flags & LYS_SET_MIN) {
6161 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6162 "Invalid deviation adding \"min-elements\" property which already exists (with value \"%u\").", *num);
6163 ret = LY_EVALID;
6164 goto cleanup;
6165 }
6166
6167 *num = d->min;
6168 }
6169
6170 /* [max-elements-stmt] */
6171 if (d->flags & LYS_SET_MAX) {
6172 switch (target->nodetype) {
6173 case LYS_LEAFLIST:
6174 num = &((struct lysp_node_leaflist *)target)->max;
6175 break;
6176 case LYS_LIST:
6177 num = &((struct lysp_node_list *)target)->max;
6178 break;
6179 default:
6180 AMEND_WRONG_NODETYPE("deviation", "add", "max-elements");
6181 }
6182
6183 if (target->flags & LYS_SET_MAX) {
6184 if (*num) {
6185 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6186 "Invalid deviation adding \"max-elements\" property which already exists (with value \"%u\").",
6187 *num);
6188 } else {
6189 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6190 "Invalid deviation adding \"max-elements\" property which already exists (with value \"unbounded\").");
6191 }
6192 ret = LY_EVALID;
6193 goto cleanup;
6194 }
6195
6196 *num = d->max;
6197 }
6198
6199cleanup:
6200 return ret;
6201}
6202
6203/**
6204 * @brief Apply deviate delete.
6205 *
6206 * @param[in] ctx Compile context.
6207 * @param[in] d Deviate delete to apply.
6208 * @param[in,out] target Deviation target.
6209 * @return LY_ERR value.
6210 */
6211static LY_ERR
6212lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysp_deviate_del *d, struct lysp_node *target)
6213{
6214 LY_ERR ret = LY_SUCCESS;
6215 struct lysp_restr **musts;
6216 LY_ARRAY_COUNT_TYPE u, v;
6217 struct lysp_qname **uniques, **dflts;
6218
6219#define DEV_DEL_ARRAY(DEV_ARRAY, ORIG_ARRAY, DEV_MEMBER, ORIG_MEMBER, FREE_FUNC, PROPERTY) \
6220 LY_ARRAY_FOR(d->DEV_ARRAY, u) { \
6221 int found = 0; \
6222 LY_ARRAY_FOR(ORIG_ARRAY, v) { \
6223 if (!strcmp(d->DEV_ARRAY[u]DEV_MEMBER, (ORIG_ARRAY)[v]ORIG_MEMBER)) { \
6224 found = 1; \
6225 break; \
6226 } \
6227 } \
6228 if (!found) { \
6229 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
6230 "Invalid deviation deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
6231 PROPERTY, d->DEV_ARRAY[u]DEV_MEMBER); \
6232 ret = LY_EVALID; \
6233 goto cleanup; \
6234 } \
6235 LY_ARRAY_DECREMENT(ORIG_ARRAY); \
6236 FREE_FUNC(ctx->ctx, &(ORIG_ARRAY)[v]); \
6237 memmove(&(ORIG_ARRAY)[v], &(ORIG_ARRAY)[v + 1], (LY_ARRAY_COUNT(ORIG_ARRAY) - v) * sizeof *(ORIG_ARRAY)); \
6238 } \
6239 if (!LY_ARRAY_COUNT(ORIG_ARRAY)) { \
6240 LY_ARRAY_FREE(ORIG_ARRAY); \
6241 ORIG_ARRAY = NULL; \
6242 }
6243
6244#define DEV_CHECK_PRESENCE_VALUE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
6245 if (!((TYPE)target)->MEMBER) { \
6246 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
6247 ret = LY_EVALID; \
6248 goto cleanup; \
6249 } else if (strcmp(((TYPE)target)->MEMBER, VALUE)) { \
6250 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
6251 "Invalid deviation deleting \"%s\" property \"%s\" which does not match the target's property value \"%s\".", \
6252 PROPERTY, VALUE, ((TYPE)target)->MEMBER); \
6253 ret = LY_EVALID; \
6254 goto cleanup; \
6255 }
6256
6257 /* [units-stmt] */
6258 if (d->units) {
6259 switch (target->nodetype) {
6260 case LYS_LEAF:
6261 case LYS_LEAFLIST:
6262 break;
6263 default:
6264 AMEND_WRONG_NODETYPE("deviation", "delete", "units");
6265 }
6266
6267 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, units, "deleting", "units", d->units);
6268 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
6269 ((struct lysp_node_leaf *)target)->units = NULL;
6270 }
6271
6272 /* *must-stmt */
6273 if (d->musts) {
6274 switch (target->nodetype) {
6275 case LYS_CONTAINER:
6276 case LYS_LIST:
6277 case LYS_LEAF:
6278 case LYS_LEAFLIST:
6279 case LYS_ANYDATA:
6280 case LYS_ANYXML:
6281 musts = &((struct lysp_node_container *)target)->musts;
6282 break;
6283 case LYS_NOTIF:
6284 musts = &((struct lysp_notif *)target)->musts;
6285 break;
6286 case LYS_INPUT:
6287 case LYS_OUTPUT:
6288 musts = &((struct lysp_action_inout *)target)->musts;
6289 break;
6290 default:
6291 AMEND_WRONG_NODETYPE("deviation", "delete", "must");
6292 }
6293
6294 DEV_DEL_ARRAY(musts, *musts, .arg.str, .arg.str, lysp_restr_free, "must");
6295 }
6296
6297 /* *unique-stmt */
6298 if (d->uniques) {
6299 switch (target->nodetype) {
6300 case LYS_LIST:
6301 break;
6302 default:
6303 AMEND_WRONG_NODETYPE("deviation", "delete", "unique");
6304 }
6305
6306 uniques = &((struct lysp_node_list *)target)->uniques;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006307 DEV_DEL_ARRAY(uniques, *uniques, .str, .str, lysp_qname_free, "unique");
Michal Vasko7f45cf22020-10-01 12:49:44 +02006308 }
6309
6310 /* *default-stmt */
6311 if (d->dflts) {
6312 switch (target->nodetype) {
6313 case LYS_LEAF:
6314 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006315 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, dflt.str, "deleting", "default", d->dflts[0].str);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006316
6317 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
6318 ((struct lysp_node_leaf *)target)->dflt.str = NULL;
6319 break;
6320 case LYS_LEAFLIST:
6321 dflts = &((struct lysp_node_leaflist *)target)->dflts;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006322 DEV_DEL_ARRAY(dflts, *dflts, .str, .str, lysp_qname_free, "default");
Michal Vasko7f45cf22020-10-01 12:49:44 +02006323 break;
6324 case LYS_CHOICE:
6325 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006326 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_choice *, dflt.str, "deleting", "default", d->dflts[0].str);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006327
6328 FREE_STRING(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
6329 ((struct lysp_node_choice *)target)->dflt.str = NULL;
6330 break;
6331 default:
6332 AMEND_WRONG_NODETYPE("deviation", "delete", "default");
6333 }
6334 }
6335
6336cleanup:
6337 return ret;
6338}
6339
6340/**
6341 * @brief Apply deviate replace.
6342 *
6343 * @param[in] ctx Compile context.
6344 * @param[in] d Deviate replace to apply.
6345 * @param[in,out] target Deviation target.
6346 * @return LY_ERR value.
6347 */
6348static LY_ERR
6349lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysp_deviate_rpl *d, struct lysp_node *target)
6350{
6351 LY_ERR ret = LY_SUCCESS;
6352 uint32_t *num;
6353
6354#define DEV_CHECK_PRESENCE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
6355 if (!((TYPE)target)->MEMBER) { \
6356 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
6357 ret = LY_EVALID; \
6358 goto cleanup; \
6359 }
6360
6361 /* [type-stmt] */
6362 if (d->type) {
6363 switch (target->nodetype) {
6364 case LYS_LEAF:
6365 case LYS_LEAFLIST:
6366 break;
6367 default:
6368 AMEND_WRONG_NODETYPE("deviation", "replace", "type");
6369 }
6370
6371 lysp_type_free(ctx->ctx, &((struct lysp_node_leaf *)target)->type);
6372 lysp_type_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->type, d->type);
6373 }
6374
6375 /* [units-stmt] */
6376 if (d->units) {
6377 switch (target->nodetype) {
6378 case LYS_LEAF:
6379 case LYS_LEAFLIST:
6380 break;
6381 default:
6382 AMEND_WRONG_NODETYPE("deviation", "replace", "units");
6383 }
6384
6385 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, units, "replacing", "units", d->units);
6386 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
6387 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
6388 }
6389
6390 /* [default-stmt] */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006391 if (d->dflt.str) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02006392 switch (target->nodetype) {
6393 case LYS_LEAF:
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006394 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, dflt.str, "replacing", "default", d->dflt.str);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006395
6396 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006397 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &d->dflt), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006398 break;
6399 case LYS_CHOICE:
6400 DEV_CHECK_PRESENCE(struct lysp_node_choice *, dflt.str, "replacing", "default", d->dflt);
6401
6402 FREE_STRING(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006403 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &d->dflt), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006404 break;
6405 default:
6406 AMEND_WRONG_NODETYPE("deviation", "replace", "default");
6407 }
6408 }
6409
6410 /* [config-stmt] */
6411 if (d->flags & LYS_CONFIG_MASK) {
6412 switch (target->nodetype) {
6413 case LYS_CONTAINER:
6414 case LYS_LEAF:
6415 case LYS_LEAFLIST:
6416 case LYS_LIST:
6417 case LYS_CHOICE:
6418 case LYS_ANYDATA:
6419 case LYS_ANYXML:
6420 break;
6421 default:
6422 AMEND_WRONG_NODETYPE("deviation", "replace", "config");
6423 }
6424
6425 if (!(target->flags & LYS_CONFIG_MASK)) {
6426 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT,
6427 "replacing", "config", d->flags & LYS_CONFIG_W ? "config true" : "config false");
6428 ret = LY_EVALID;
6429 goto cleanup;
6430 }
6431
6432 target->flags &= ~LYS_CONFIG_MASK;
6433 target->flags |= d->flags & LYS_CONFIG_MASK;
6434 }
6435
6436 /* [mandatory-stmt] */
6437 if (d->flags & LYS_MAND_MASK) {
6438 switch (target->nodetype) {
6439 case LYS_LEAF:
6440 case LYS_CHOICE:
6441 case LYS_ANYDATA:
6442 case LYS_ANYXML:
6443 break;
6444 default:
6445 AMEND_WRONG_NODETYPE("deviation", "replace", "mandatory");
6446 }
6447
6448 if (!(target->flags & LYS_MAND_MASK)) {
6449 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT,
6450 "replacing", "mandatory", d->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
6451 ret = LY_EVALID;
6452 goto cleanup;
6453 }
6454
6455 target->flags &= ~LYS_MAND_MASK;
6456 target->flags |= d->flags & LYS_MAND_MASK;
6457 }
6458
6459 /* [min-elements-stmt] */
6460 if (d->flags & LYS_SET_MIN) {
6461 switch (target->nodetype) {
6462 case LYS_LEAFLIST:
6463 num = &((struct lysp_node_leaflist *)target)->min;
6464 break;
6465 case LYS_LIST:
6466 num = &((struct lysp_node_list *)target)->min;
6467 break;
6468 default:
6469 AMEND_WRONG_NODETYPE("deviation", "replace", "min-elements");
6470 }
6471
6472 if (!(target->flags & LYS_SET_MIN)) {
6473 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6474 "Invalid deviation replacing \"min-elements\" property which is not present.");
6475 ret = LY_EVALID;
6476 goto cleanup;
6477 }
6478
6479 *num = d->min;
6480 }
6481
6482 /* [max-elements-stmt] */
6483 if (d->flags & LYS_SET_MAX) {
6484 switch (target->nodetype) {
6485 case LYS_LEAFLIST:
6486 num = &((struct lysp_node_leaflist *)target)->max;
6487 break;
6488 case LYS_LIST:
6489 num = &((struct lysp_node_list *)target)->max;
6490 break;
6491 default:
6492 AMEND_WRONG_NODETYPE("deviation", "replace", "max-elements");
6493 }
6494
6495 if (!(target->flags & LYS_SET_MAX)) {
6496 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6497 "Invalid deviation replacing \"max-elements\" property which is not present.");
6498 ret = LY_EVALID;
6499 goto cleanup;
6500 }
6501
6502 *num = d->max;
6503 }
6504
6505cleanup:
6506 return ret;
6507}
6508
6509/**
6510 * @brief Get module of a single nodeid node name test.
6511 *
6512 * @param[in] ctx libyang context.
6513 * @param[in] nametest Nametest with an optional prefix.
6514 * @param[in] nametest_len Length of @p nametest.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006515 * @param[in] mod Both current and prefix module for resolving prefixes and to return in case of no prefix.
Michal Vasko7f45cf22020-10-01 12:49:44 +02006516 * @param[out] name Optional pointer to the name test without the prefix.
6517 * @param[out] name_len Length of @p name.
6518 * @return Resolved module.
6519 */
6520static const struct lys_module *
6521lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest, size_t nametest_len,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006522 const struct lysp_module *mod, const char **name, size_t *name_len)
Michal Vasko7f45cf22020-10-01 12:49:44 +02006523{
6524 const struct lys_module *target_mod;
6525 const char *ptr;
6526
6527 ptr = ly_strnchr(nametest, ':', nametest_len);
6528 if (ptr) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006529 target_mod = ly_resolve_prefix(ctx, nametest, ptr - nametest, LY_PREF_SCHEMA, (void *)mod);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006530 if (!target_mod) {
6531 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
6532 "Invalid absolute-schema-nodeid nametest \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006533 nametest_len, nametest, ptr - nametest, nametest, LYSP_MODULE_NAME(mod));
Michal Vasko7f45cf22020-10-01 12:49:44 +02006534 return NULL;
6535 }
6536
6537 if (name) {
6538 *name = ptr + 1;
6539 *name_len = nametest_len - ((ptr - nametest) + 1);
6540 }
6541 } else {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006542 target_mod = mod->mod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02006543 if (name) {
6544 *name = nametest;
6545 *name_len = nametest_len;
6546 }
6547 }
6548
6549 return target_mod;
6550}
6551
6552/**
6553 * @brief Check whether a parsed node matches a single schema nodeid name test.
6554 *
6555 * @param[in] pnode Parsed node to consider.
6556 * @param[in] pnode_mod Compiled @p pnode to-be module.
6557 * @param[in] mod Expected module.
6558 * @param[in] name Expected name.
6559 * @param[in] name_len Length of @p name.
6560 * @return Whether it is a match or not.
6561 */
6562static ly_bool
6563lysp_schema_nodeid_match_pnode(const struct lysp_node *pnode, const struct lys_module *pnode_mod,
6564 const struct lys_module *mod, const char *name, size_t name_len)
6565{
6566 const char *pname;
6567
6568 /* compare with the module of the node */
6569 if (pnode_mod != mod) {
6570 return 0;
6571 }
6572
6573 /* compare names */
6574 if (pnode->nodetype & (LYS_ACTION | LYS_RPC)) {
6575 pname = ((struct lysp_action *)pnode)->name;
6576 } else if (pnode->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6577 pname = (pnode->nodetype & LYS_INPUT) ? "input" : "output";
6578 } else {
6579 pname = pnode->name;
6580 }
6581 if (ly_strncmp(pname, name, name_len)) {
6582 return 0;
6583 }
6584
6585 return 1;
6586}
6587
6588/**
6589 * @brief Check whether a compiled node matches a single schema nodeid name test.
6590 *
6591 * @param[in,out] node Compiled node to consider. On a match it is moved to its parent.
6592 * @param[in] mod Expected module.
6593 * @param[in] name Expected name.
6594 * @param[in] name_len Length of @p name.
6595 * @return Whether it is a match or not.
6596 */
6597static ly_bool
6598lysp_schema_nodeid_match_node(const struct lysc_node **node, const struct lys_module *mod, const char *name,
6599 size_t name_len)
6600{
6601 const struct lys_module *node_mod;
6602 const char *node_name;
6603
6604 /* compare with the module of the node */
6605 if ((*node)->nodetype == LYS_INPUT) {
6606 node_mod = ((struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, input)))->module;
6607 } else if ((*node)->nodetype == LYS_OUTPUT) {
6608 node_mod = ((struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, output)))->module;
6609 } else {
6610 node_mod = (*node)->module;
6611 }
6612 if (node_mod != mod) {
6613 return 0;
6614 }
6615
6616 /* compare names */
6617 if ((*node)->nodetype == LYS_INPUT) {
6618 node_name = "input";
6619 } else if ((*node)->nodetype == LYS_OUTPUT) {
6620 node_name = "output";
6621 } else {
6622 node_name = (*node)->name;
6623 }
6624 if (ly_strncmp(node_name, name, name_len)) {
6625 return 0;
6626 }
6627
6628 if ((*node)->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6629 /* move up from input/output */
6630 if ((*node)->nodetype == LYS_INPUT) {
6631 (*node) = (struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, input));
6632 } else {
6633 (*node) = (struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, output));
6634 }
6635 } else if ((*node)->parent && ((*node)->parent->nodetype & (LYS_RPC | LYS_ACTION))) {
6636 /* move to the input/output */
6637 if ((*node)->flags & LYS_CONFIG_W) {
6638 *node = (struct lysc_node *)&((struct lysc_action *)(*node)->parent)->input;
6639 } else {
6640 *node = (struct lysc_node *)&((struct lysc_action *)(*node)->parent)->output;
6641 }
6642 } else {
6643 /* move to next parent */
6644 *node = (*node)->parent;
6645 }
6646
6647 return 1;
6648}
6649
6650/**
6651 * @brief Check whether a node matches specific schema nodeid.
6652 *
6653 * @param[in] exp Parsed nodeid to match.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006654 * @param[in] exp_pmod Module to use for nodes in @p exp without a prefix.
Michal Vasko7f45cf22020-10-01 12:49:44 +02006655 * @param[in] ctx_node Initial context node that should match, only for descendant paths.
6656 * @param[in] parent First compiled parent to consider. If @p pnode is NULL, it is condered the node to be matched.
6657 * @param[in] pnode Parsed node to be matched. May be NULL if the target node was already compiled.
6658 * @param[in] pnode_mod Compiled @p pnode to-be module.
6659 * @return Whether it is a match or not.
6660 */
6661static ly_bool
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006662lysp_schema_nodeid_match(const struct lyxp_expr *exp, const struct lysp_module *exp_pmod, const struct lysc_node *ctx_node,
Michal Vasko7f45cf22020-10-01 12:49:44 +02006663 const struct lysc_node *parent, const struct lysp_node *pnode, const struct lys_module *pnode_mod)
6664{
6665 uint32_t i;
6666 const struct lys_module *mod;
6667 const char *name;
6668 size_t name_len;
6669
6670 /* compare last node in the node ID */
6671 i = exp->used - 1;
6672
6673 /* get exp node ID module */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006674 mod = lys_schema_node_get_module(exp_pmod->mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_pmod, &name, &name_len);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006675 assert(mod);
6676
6677 if (pnode) {
6678 /* compare on the last parsed-only node */
6679 if (!lysp_schema_nodeid_match_pnode(pnode, pnode_mod, mod, name, name_len)) {
6680 return 0;
6681 }
6682 } else {
6683 /* using parent directly */
6684 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
6685 return 0;
6686 }
6687 }
6688
6689 /* now compare all the compiled parents */
6690 while (i > 1) {
6691 i -= 2;
6692 assert(exp->tokens[i] == LYXP_TOKEN_NAMETEST);
6693
6694 if (!parent) {
6695 /* no more parents but path continues */
6696 return 0;
6697 }
6698
6699 /* get exp node ID module */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006700 mod = lys_schema_node_get_module(exp_pmod->mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_pmod, &name,
Michal Vasko7f45cf22020-10-01 12:49:44 +02006701 &name_len);
6702 assert(mod);
6703
6704 /* compare with the parent */
6705 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
6706 return 0;
6707 }
6708 }
6709
6710 if (ctx_node && (ctx_node != parent)) {
6711 /* descendant path has not finished in the context node */
6712 return 0;
6713 } else if (!ctx_node && parent) {
6714 /* some parent was not matched */
6715 return 0;
6716 }
6717
6718 return 1;
6719}
6720
6721static void
6722lysc_augment_free(const struct ly_ctx *ctx, struct lysc_augment *aug)
6723{
6724 if (aug) {
6725 lyxp_expr_free(ctx, aug->nodeid);
6726
6727 free(aug);
6728 }
6729}
6730
6731static void
6732lysc_deviation_free(const struct ly_ctx *ctx, struct lysc_deviation *dev)
6733{
6734 if (dev) {
6735 lyxp_expr_free(ctx, dev->nodeid);
6736 LY_ARRAY_FREE(dev->devs);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006737 LY_ARRAY_FREE(dev->dev_pmods);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006738
6739 free(dev);
6740 }
6741}
6742
6743static void
6744lysc_refine_free(const struct ly_ctx *ctx, struct lysc_refine *rfn)
6745{
6746 if (rfn) {
6747 lyxp_expr_free(ctx, rfn->nodeid);
6748 LY_ARRAY_FREE(rfn->rfns);
6749
6750 free(rfn);
6751 }
6752}
6753
6754static void
6755lysp_dev_node_free(const struct ly_ctx *ctx, struct lysp_node *dev_pnode)
6756{
6757 if (!dev_pnode) {
6758 return;
6759 }
6760
6761 switch (dev_pnode->nodetype) {
6762 case LYS_CONTAINER:
6763 ((struct lysp_node_container *)dev_pnode)->child = NULL;
6764 break;
6765 case LYS_LIST:
6766 ((struct lysp_node_list *)dev_pnode)->child = NULL;
6767 break;
6768 case LYS_CHOICE:
6769 ((struct lysp_node_choice *)dev_pnode)->child = NULL;
6770 break;
6771 case LYS_CASE:
6772 ((struct lysp_node_case *)dev_pnode)->child = NULL;
6773 break;
6774 case LYS_LEAF:
6775 case LYS_LEAFLIST:
6776 case LYS_ANYXML:
6777 case LYS_ANYDATA:
6778 /* no children */
6779 break;
6780 case LYS_NOTIF:
6781 ((struct lysp_notif *)dev_pnode)->data = NULL;
6782 lysp_notif_free((struct ly_ctx *)ctx, (struct lysp_notif *)dev_pnode);
6783 free(dev_pnode);
6784 return;
6785 case LYS_RPC:
6786 case LYS_ACTION:
6787 ((struct lysp_action *)dev_pnode)->input.data = NULL;
6788 ((struct lysp_action *)dev_pnode)->output.data = NULL;
6789 lysp_action_free((struct ly_ctx *)ctx, (struct lysp_action *)dev_pnode);
6790 free(dev_pnode);
6791 return;
6792 case LYS_INPUT:
6793 case LYS_OUTPUT:
6794 ((struct lysp_action_inout *)dev_pnode)->data = NULL;
6795 lysp_action_inout_free((struct ly_ctx *)ctx, (struct lysp_action_inout *)dev_pnode);
6796 free(dev_pnode);
6797 return;
6798 default:
6799 LOGINT(ctx);
6800 return;
6801 }
6802
6803 lysp_node_free((struct ly_ctx *)ctx, dev_pnode);
6804}
6805
6806/**
6807 * @brief Compile and apply any precompiled deviations and refines targetting a node.
6808 *
6809 * @param[in] ctx Compile context.
6810 * @param[in] pnode Parsed node to consider.
6811 * @param[in] parent First compiled parent of @p pnode.
6812 * @param[out] dev_pnode Copy of parsed node @p pnode with deviations and refines, if any. NULL if there are none.
6813 * @param[out] no_supported Whether a not-supported deviation is defined for the node.
6814 * @return LY_ERR value.
6815 */
6816static LY_ERR
6817lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode, const struct lysc_node *parent,
6818 struct lysp_node **dev_pnode, ly_bool *not_supported)
6819{
6820 LY_ERR ret = LY_SUCCESS;
6821 uint32_t i;
6822 LY_ARRAY_COUNT_TYPE u;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006823 struct lys_module *orig_mod = ctx->cur_mod;
6824 struct lysp_module *orig_pmod = ctx->pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02006825 char orig_path[LYSC_CTX_BUFSIZE];
6826 struct lysc_refine *rfn;
6827 struct lysc_deviation *dev;
6828 struct lysp_deviation *dev_p;
6829 struct lysp_deviate *d;
6830
6831 *dev_pnode = NULL;
6832 *not_supported = 0;
6833
6834 for (i = 0; i < ctx->uses_rfns.count; ++i) {
6835 rfn = ctx->uses_rfns.objs[i];
6836
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006837 if (!lysp_schema_nodeid_match(rfn->nodeid, rfn->nodeid_pmod, rfn->nodeid_ctx_node, parent, pnode, ctx->cur_mod)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02006838 /* not our target node */
6839 continue;
6840 }
6841
6842 if (!*dev_pnode) {
6843 /* first refine on this node, create a copy first */
6844 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
6845 }
6846
6847 /* apply all the refines by changing (the copy of) the parsed node */
6848 LY_ARRAY_FOR(rfn->rfns, u) {
6849 /* apply refine, keep the current path and add to it */
6850 lysc_update_path(ctx, NULL, "{refine}");
6851 lysc_update_path(ctx, NULL, rfn->rfns[u]->nodeid);
6852 ret = lys_apply_refine(ctx, rfn->rfns[u], *dev_pnode);
6853 lysc_update_path(ctx, NULL, NULL);
6854 lysc_update_path(ctx, NULL, NULL);
6855 LY_CHECK_GOTO(ret, cleanup);
6856 }
6857
6858 /* refine was applied, remove it */
6859 lysc_refine_free(ctx->ctx, rfn);
6860 ly_set_rm_index(&ctx->uses_rfns, i, NULL);
6861
6862 /* all the refines for one target node are in one structure, we are done */
6863 break;
6864 }
6865
6866 for (i = 0; i < ctx->devs.count; ++i) {
6867 dev = ctx->devs.objs[i];
6868
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006869 if (!lysp_schema_nodeid_match(dev->nodeid, dev->dev_pmods[0], NULL, parent, pnode, ctx->cur_mod)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02006870 /* not our target node */
6871 continue;
6872 }
6873
6874 if (dev->not_supported) {
6875 /* it is not supported, no more deviations */
6876 *not_supported = 1;
6877 goto dev_applied;
6878 }
6879
6880 if (!*dev_pnode) {
6881 /* first deviation on this node, create a copy first */
6882 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
6883 }
6884
6885 /* apply all the deviates by changing (the copy of) the parsed node */
6886 LY_ARRAY_FOR(dev->devs, u) {
6887 dev_p = dev->devs[u];
6888 LY_LIST_FOR(dev_p->deviates, d) {
6889 /* generate correct path */
6890 strcpy(orig_path, ctx->path);
6891 ctx->path_len = 1;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006892 ctx->cur_mod = dev->dev_pmods[u]->mod;
6893 ctx->pmod = (struct lysp_module *)dev->dev_pmods[u];
Michal Vasko7f45cf22020-10-01 12:49:44 +02006894 lysc_update_path(ctx, NULL, "{deviation}");
6895 lysc_update_path(ctx, NULL, dev_p->nodeid);
6896
6897 switch (d->mod) {
6898 case LYS_DEV_ADD:
6899 ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, *dev_pnode);
6900 break;
6901 case LYS_DEV_DELETE:
6902 ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, *dev_pnode);
6903 break;
6904 case LYS_DEV_REPLACE:
6905 ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, *dev_pnode);
6906 break;
6907 default:
6908 LOGINT(ctx->ctx);
6909 ret = LY_EINT;
6910 }
6911
6912 /* restore previous path */
6913 strcpy(ctx->path, orig_path);
6914 ctx->path_len = strlen(ctx->path);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006915 ctx->cur_mod = orig_mod;
6916 ctx->pmod = orig_pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02006917
6918 LY_CHECK_GOTO(ret, cleanup);
6919 }
6920 }
6921
6922dev_applied:
6923 /* deviation was applied, remove it */
6924 lysc_deviation_free(ctx->ctx, dev);
6925 ly_set_rm_index(&ctx->devs, i, NULL);
6926
6927 /* all the deviations for one target node are in one structure, we are done */
6928 break;
6929 }
6930
6931cleanup:
6932 if (ret) {
6933 lysp_dev_node_free(ctx->ctx, *dev_pnode);
6934 *dev_pnode = NULL;
6935 *not_supported = 0;
6936 }
6937 return ret;
6938}
6939
6940/**
6941 * @brief Compile and apply any precompiled top-level or uses augments targetting a node.
6942 *
6943 * @param[in] ctx Compile context.
6944 * @param[in] node Compiled node to consider.
6945 * @return LY_ERR value.
6946 */
6947static LY_ERR
6948lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
6949{
6950 LY_ERR ret = LY_SUCCESS;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006951 struct lys_module *orig_mod = ctx->cur_mod;
6952 struct lysp_module *orig_pmod = ctx->pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02006953 uint32_t i;
6954 char orig_path[LYSC_CTX_BUFSIZE];
6955 struct lysc_augment *aug;
6956
6957 /* uses augments */
6958 for (i = 0; i < ctx->uses_augs.count; ) {
6959 aug = ctx->uses_augs.objs[i];
6960
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006961 if (!lysp_schema_nodeid_match(aug->nodeid, aug->nodeid_pmod, aug->nodeid_ctx_node, node, NULL, NULL)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02006962 /* not our target node */
6963 ++i;
6964 continue;
6965 }
6966
6967 /* apply augment, keep the current path and add to it */
6968 lysc_update_path(ctx, NULL, "{augment}");
6969 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
6970 ret = lys_compile_augment(ctx, aug->aug_p, node);
6971 lysc_update_path(ctx, NULL, NULL);
6972 lysc_update_path(ctx, NULL, NULL);
6973 LY_CHECK_GOTO(ret, cleanup);
6974
6975 /* augment was applied, remove it (index may have changed because other augments could have been applied) */
Michal Vasko7f45cf22020-10-01 12:49:44 +02006976 ly_set_rm(&ctx->uses_augs, aug, NULL);
Michal Vaskoaf702452020-10-02 09:02:55 +02006977 lysc_augment_free(ctx->ctx, aug);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006978 }
6979
6980 /* top-level augments */
6981 for (i = 0; i < ctx->augs.count; ) {
6982 aug = ctx->augs.objs[i];
6983
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006984 if (!lysp_schema_nodeid_match(aug->nodeid, aug->nodeid_pmod, NULL, node, NULL, NULL)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02006985 /* not our target node */
6986 ++i;
6987 continue;
6988 }
6989
6990 /* apply augment, use the path and modules from the augment */
6991 strcpy(orig_path, ctx->path);
6992 ctx->path_len = 1;
6993 lysc_update_path(ctx, NULL, "{augment}");
6994 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006995 ctx->cur_mod = aug->nodeid_pmod->mod;
6996 ctx->pmod = (struct lysp_module *)aug->nodeid_pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02006997 ret = lys_compile_augment(ctx, aug->aug_p, node);
6998 strcpy(ctx->path, orig_path);
6999 ctx->path_len = strlen(ctx->path);
7000 LY_CHECK_GOTO(ret, cleanup);
7001
7002 /* augment was applied, remove it */
Michal Vasko7f45cf22020-10-01 12:49:44 +02007003 ly_set_rm(&ctx->augs, aug, NULL);
Michal Vaskoaf702452020-10-02 09:02:55 +02007004 lysc_augment_free(ctx->ctx, aug);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007005 }
7006
7007cleanup:
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007008 ctx->cur_mod = orig_mod;
7009 ctx->pmod = orig_pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007010 return ret;
7011}
7012
7013/**
7014 * @brief Prepare a top-level augment to be applied during data nodes compilation.
7015 *
7016 * @param[in] ctx Compile context.
7017 * @param[in] aug_p Parsed augment to be applied.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007018 * @param[in] pmod Both current and prefix module for @p aug_p.
Michal Vasko7f45cf22020-10-01 12:49:44 +02007019 * @return LY_ERR value.
7020 */
7021static LY_ERR
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007022lys_precompile_own_augment(struct lysc_ctx *ctx, struct lysp_augment *aug_p, const struct lysp_module *pmod)
Michal Vasko7f45cf22020-10-01 12:49:44 +02007023{
7024 LY_ERR ret = LY_SUCCESS;
7025 struct lyxp_expr *exp = NULL;
7026 struct lysc_augment *aug;
7027 const struct lys_module *mod;
7028
7029 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
7030 ret = lyxp_expr_parse(ctx->ctx, aug_p->nodeid, strlen(aug_p->nodeid), 0, &exp);
7031 LY_CHECK_GOTO(ret, cleanup);
7032
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007033 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007034 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007035 if (mod != ctx->cur_mod) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02007036 /* augment for another module, ignore */
7037 goto cleanup;
7038 }
7039
7040 /* allocate new compiled augment and store it in the set */
7041 aug = calloc(1, sizeof *aug);
7042 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci3d92e442020-10-12 12:48:13 +02007043 LY_CHECK_GOTO(ret = ly_set_add(&ctx->augs, aug, 1, NULL), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007044
7045 aug->nodeid = exp;
7046 exp = NULL;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007047 aug->nodeid_pmod = pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007048 aug->aug_p = aug_p;
7049
7050cleanup:
7051 lyxp_expr_free(ctx->ctx, exp);
7052 return ret;
7053}
7054
7055/**
7056 * @brief Prepare all top-level augments for the current module to be applied during data nodes compilation.
7057 *
7058 * @param[in] ctx Compile context.
7059 * @return LY_ERR value.
7060 */
7061static LY_ERR
7062lys_precompile_own_augments(struct lysc_ctx *ctx)
7063{
7064 LY_ARRAY_COUNT_TYPE u, v, w;
7065 const struct lys_module *aug_mod;
7066
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007067 LY_ARRAY_FOR(ctx->cur_mod->augmented_by, u) {
7068 aug_mod = ctx->cur_mod->augmented_by[u];
Michal Vasko7f45cf22020-10-01 12:49:44 +02007069
7070 /* collect all module augments */
7071 LY_ARRAY_FOR(aug_mod->parsed->augments, v) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007072 LY_CHECK_RET(lys_precompile_own_augment(ctx, &aug_mod->parsed->augments[v], aug_mod->parsed));
Michal Vasko7f45cf22020-10-01 12:49:44 +02007073 }
7074
7075 /* collect all submodules augments */
7076 LY_ARRAY_FOR(aug_mod->parsed->includes, v) {
7077 LY_ARRAY_FOR(aug_mod->parsed->includes[v].submodule->augments, w) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007078 LY_CHECK_RET(lys_precompile_own_augment(ctx, &aug_mod->parsed->includes[v].submodule->augments[w],
7079 (struct lysp_module *)aug_mod->parsed->includes[v].submodule));
Michal Vasko7f45cf22020-10-01 12:49:44 +02007080 }
7081 }
7082 }
7083
7084 return LY_SUCCESS;
7085}
7086
7087/**
7088 * @brief Prepare a deviation to be applied during data nodes compilation.
7089 *
7090 * @param[in] ctx Compile context.
7091 * @param[in] dev_p Parsed deviation to be applied.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007092 * @param[in] pmod Both current and prefix module for @p dev_p.
Michal Vasko7f45cf22020-10-01 12:49:44 +02007093 * @return LY_ERR value.
7094 */
7095static LY_ERR
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007096lys_precompile_own_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev_p, const struct lysp_module *pmod)
Michal Vasko7f45cf22020-10-01 12:49:44 +02007097{
7098 LY_ERR ret = LY_SUCCESS;
7099 struct lysc_deviation *dev = NULL;
7100 struct lyxp_expr *exp = NULL;
7101 struct lysp_deviation **new_dev;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007102 const struct lys_module *mod;
7103 const struct lysp_module **new_dev_pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007104 uint32_t i;
7105
7106 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
7107 ret = lyxp_expr_parse(ctx->ctx, dev_p->nodeid, strlen(dev_p->nodeid), 0, &exp);
7108 LY_CHECK_GOTO(ret, cleanup);
7109
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007110 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007111 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007112 if (mod != ctx->cur_mod) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02007113 /* deviation for another module, ignore */
7114 goto cleanup;
7115 }
7116
7117 /* try to find the node in already compiled deviations */
7118 for (i = 0; i < ctx->devs.count; ++i) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007119 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, pmod, ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid,
7120 ((struct lysc_deviation *)ctx->devs.objs[i])->dev_pmods[0])) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02007121 dev = ctx->devs.objs[i];
7122 break;
7123 }
7124 }
7125
7126 if (!dev) {
7127 /* allocate new compiled deviation */
7128 dev = calloc(1, sizeof *dev);
7129 LY_CHECK_ERR_GOTO(!dev, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci3d92e442020-10-12 12:48:13 +02007130 LY_CHECK_GOTO(ret = ly_set_add(&ctx->devs, dev, 1, NULL), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007131
7132 dev->nodeid = exp;
7133 exp = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007134 }
7135
7136 /* add new parsed deviation structure */
7137 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->devs, new_dev, ret, cleanup);
7138 *new_dev = dev_p;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007139 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->dev_pmods, new_dev_pmod, ret, cleanup);
7140 *new_dev_pmod = pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007141
7142cleanup:
7143 lyxp_expr_free(ctx->ctx, exp);
7144 return ret;
7145}
7146
7147/**
7148 * @brief Prepare all deviations for the current module to be applied during data nodes compilation.
7149 *
7150 * @param[in] ctx Compile context.
7151 * @return LY_ERR value.
7152 */
7153static LY_ERR
7154lys_precompile_own_deviations(struct lysc_ctx *ctx)
7155{
7156 LY_ARRAY_COUNT_TYPE u, v, w;
7157 const struct lys_module *dev_mod;
7158 struct lysc_deviation *dev;
7159 struct lysp_deviate *d;
7160 int not_supported;
7161 uint32_t i;
7162
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007163 LY_ARRAY_FOR(ctx->cur_mod->deviated_by, u) {
7164 dev_mod = ctx->cur_mod->deviated_by[u];
Michal Vasko7f45cf22020-10-01 12:49:44 +02007165
7166 /* compile all module deviations */
7167 LY_ARRAY_FOR(dev_mod->parsed->deviations, v) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007168 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->deviations[v], dev_mod->parsed));
Michal Vasko7f45cf22020-10-01 12:49:44 +02007169 }
7170
7171 /* compile all submodules deviations */
7172 LY_ARRAY_FOR(dev_mod->parsed->includes, v) {
7173 LY_ARRAY_FOR(dev_mod->parsed->includes[v].submodule->deviations, w) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007174 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->includes[v].submodule->deviations[w],
7175 (struct lysp_module *)dev_mod->parsed->includes[v].submodule));
Michal Vasko7f45cf22020-10-01 12:49:44 +02007176 }
7177 }
7178 }
7179
7180 /* set not-supported flags for all the deviations */
7181 for (i = 0; i < ctx->devs.count; ++i) {
7182 dev = ctx->devs.objs[i];
7183 not_supported = 0;
7184
7185 LY_ARRAY_FOR(dev->devs, u) {
7186 LY_LIST_FOR(dev->devs[u]->deviates, d) {
7187 if (d->mod == LYS_DEV_NOT_SUPPORTED) {
7188 not_supported = 1;
7189 break;
7190 }
7191 }
7192 if (not_supported) {
7193 break;
7194 }
7195 }
7196 if (not_supported && (LY_ARRAY_COUNT(dev->devs) > 1)) {
7197 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
7198 "Multiple deviations of \"%s\" with one of them being \"not-supported\".", dev->nodeid->expr);
7199 return LY_EVALID;
7200 }
7201
7202 dev->not_supported = not_supported;
7203 }
7204
7205 return LY_SUCCESS;
7206}
7207
Michal Vasko20424b42020-08-31 12:29:38 +02007208/**
Radek Krejcia3045382018-11-22 14:30:31 +01007209 * @brief Compile parsed schema node information.
7210 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02007211 * @param[in] pnode Parsed schema node.
Radek Krejcia3045382018-11-22 14:30:31 +01007212 * @param[in] parent Compiled parent node where the current node is supposed to be connected. It is
7213 * NULL for top-level nodes, in such a case the module where the node will be connected is taken from
7214 * the compile context.
Radek Krejcib1b59152019-01-07 13:21:56 +01007215 * @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).
7216 * Zero means no uses, non-zero value with no status bit set mean the default status.
Radek Krejcia3045382018-11-22 14:30:31 +01007217 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
7218 */
Radek Krejci19a96102018-11-15 13:38:09 +01007219static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02007220lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *parent, uint16_t uses_status,
7221 struct ly_set *child_set)
Radek Krejci19a96102018-11-15 13:38:09 +01007222{
Radek Krejci1c54f462020-05-12 17:25:34 +02007223 LY_ERR ret = LY_SUCCESS;
Radek Krejcic6b4f442020-08-12 14:45:18 +02007224 struct lysc_node *node = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007225 struct lysp_node *dev_pnode = NULL, *orig_pnode = pnode;
Radek Krejci1deb5be2020-08-26 16:43:36 +02007226 LY_ARRAY_COUNT_TYPE u;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007227 ly_bool not_supported;
Michal Vasko69730152020-10-09 16:30:07 +02007228
Michal Vasko22df3f02020-08-24 13:29:22 +02007229 LY_ERR (*node_compile_spec)(struct lysc_ctx *, struct lysp_node *, struct lysc_node *);
Radek Krejci19a96102018-11-15 13:38:09 +01007230
Michal Vasko7f45cf22020-10-01 12:49:44 +02007231 if (pnode->nodetype != LYS_USES) {
7232 lysc_update_path(ctx, parent, pnode->name);
Radek Krejci327de162019-06-14 12:52:07 +02007233 } else {
7234 lysc_update_path(ctx, NULL, "{uses}");
Michal Vasko7f45cf22020-10-01 12:49:44 +02007235 lysc_update_path(ctx, NULL, pnode->name);
Radek Krejci327de162019-06-14 12:52:07 +02007236 }
7237
Michal Vasko7f45cf22020-10-01 12:49:44 +02007238 switch (pnode->nodetype) {
Radek Krejci19a96102018-11-15 13:38:09 +01007239 case LYS_CONTAINER:
Michal Vasko22df3f02020-08-24 13:29:22 +02007240 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_container));
Radek Krejci19a96102018-11-15 13:38:09 +01007241 node_compile_spec = lys_compile_node_container;
7242 break;
7243 case LYS_LEAF:
Michal Vasko22df3f02020-08-24 13:29:22 +02007244 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_leaf));
Radek Krejci19a96102018-11-15 13:38:09 +01007245 node_compile_spec = lys_compile_node_leaf;
7246 break;
7247 case LYS_LIST:
Michal Vasko22df3f02020-08-24 13:29:22 +02007248 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_list));
Radek Krejci9bb94eb2018-12-04 16:48:35 +01007249 node_compile_spec = lys_compile_node_list;
Radek Krejci19a96102018-11-15 13:38:09 +01007250 break;
7251 case LYS_LEAFLIST:
Michal Vasko22df3f02020-08-24 13:29:22 +02007252 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_leaflist));
Radek Krejci0e5d8382018-11-28 16:37:53 +01007253 node_compile_spec = lys_compile_node_leaflist;
Radek Krejci19a96102018-11-15 13:38:09 +01007254 break;
Radek Krejci19a96102018-11-15 13:38:09 +01007255 case LYS_CHOICE:
Michal Vasko22df3f02020-08-24 13:29:22 +02007256 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_choice));
Radek Krejci056d0a82018-12-06 16:57:25 +01007257 node_compile_spec = lys_compile_node_choice;
Radek Krejci19a96102018-11-15 13:38:09 +01007258 break;
Michal Vasko891d7532020-10-07 09:41:38 +02007259 case LYS_CASE:
Michal Vasko20424b42020-08-31 12:29:38 +02007260 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_case));
7261 node_compile_spec = lys_compile_node_case;
7262 break;
Radek Krejci19a96102018-11-15 13:38:09 +01007263 case LYS_ANYXML:
7264 case LYS_ANYDATA:
Michal Vasko22df3f02020-08-24 13:29:22 +02007265 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_anydata));
Radek Krejci9800fb82018-12-13 14:26:23 +01007266 node_compile_spec = lys_compile_node_any;
Radek Krejci19a96102018-11-15 13:38:09 +01007267 break;
Radek Krejcie86bf772018-12-14 11:39:53 +01007268 case LYS_USES:
Michal Vasko7f45cf22020-10-01 12:49:44 +02007269 ret = lys_compile_uses(ctx, (struct lysp_node_uses *)pnode, parent, child_set);
Radek Krejci327de162019-06-14 12:52:07 +02007270 lysc_update_path(ctx, NULL, NULL);
7271 lysc_update_path(ctx, NULL, NULL);
7272 return ret;
Radek Krejci19a96102018-11-15 13:38:09 +01007273 default:
7274 LOGINT(ctx->ctx);
7275 return LY_EINT;
7276 }
7277 LY_CHECK_ERR_RET(!node, LOGMEM(ctx->ctx), LY_EMEM);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007278
7279 /* compile any deviations for this node */
7280 LY_CHECK_ERR_RET(ret = lys_compile_node_deviations_refines(ctx, pnode, parent, &dev_pnode, &not_supported),
7281 free(node), ret);
7282 if (not_supported) {
7283 free(node);
7284 lysc_update_path(ctx, NULL, NULL);
7285 return LY_SUCCESS;
7286 } else if (dev_pnode) {
7287 pnode = dev_pnode;
7288 }
7289
7290 node->nodetype = pnode->nodetype;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007291 node->module = ctx->cur_mod;
Radek Krejci19a96102018-11-15 13:38:09 +01007292 node->prev = node;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007293 node->flags = pnode->flags & LYS_FLAGS_COMPILED_MASK;
Radek Krejci19a96102018-11-15 13:38:09 +01007294
7295 /* config */
Michal Vasko20424b42020-08-31 12:29:38 +02007296 ret = lys_compile_config(ctx, node, parent);
7297 LY_CHECK_GOTO(ret, error);
Radek Krejci19a96102018-11-15 13:38:09 +01007298
Michal Vasko20424b42020-08-31 12:29:38 +02007299 /* list ordering */
Radek Krejcia6d57732018-11-29 13:40:37 +01007300 if (node->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
7301 if ((node->flags & LYS_CONFIG_R) && (node->flags & LYS_ORDBY_MASK)) {
Radek Krejcifc11bd72019-04-11 16:00:05 +02007302 LOGWRN(ctx->ctx, "The ordered-by statement is ignored in lists representing %s (%s).",
Radek Krejci90d4e922020-10-12 15:55:33 +02007303 (ctx->options & LYS_COMPILE_RPC_OUTPUT) ? "RPC/action output parameters" :
7304 (ctx->options & LYS_COMPILE_NOTIFICATION) ? "notification content" : "state data", ctx->path);
Radek Krejcia6d57732018-11-29 13:40:37 +01007305 node->flags &= ~LYS_ORDBY_MASK;
7306 node->flags |= LYS_ORDBY_SYSTEM;
7307 } else if (!(node->flags & LYS_ORDBY_MASK)) {
7308 /* default ordering is system */
7309 node->flags |= LYS_ORDBY_SYSTEM;
7310 }
7311 }
7312
Radek Krejci19a96102018-11-15 13:38:09 +01007313 /* status - it is not inherited by specification, but it does not make sense to have
7314 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
Michal Vasko20424b42020-08-31 12:29:38 +02007315 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 +01007316
Radek Krejci90d4e922020-10-12 15:55:33 +02007317 node->sp = orig_pnode;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007318 DUP_STRING_GOTO(ctx->ctx, pnode->name, node->name, ret, error);
7319 DUP_STRING_GOTO(ctx->ctx, pnode->dsc, node->dsc, ret, error);
7320 DUP_STRING_GOTO(ctx->ctx, pnode->ref, node->ref, ret, error);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007321 COMPILE_ARRAY_GOTO(ctx, pnode->iffeatures, node->iffeatures, u, lys_compile_iffeature, ret, error);
Radek Krejci19a96102018-11-15 13:38:09 +01007322
Michal Vasko20424b42020-08-31 12:29:38 +02007323 /* insert into parent's children/compiled module (we can no longer free the node separately on error) */
Michal Vasko7f45cf22020-10-01 12:49:44 +02007324 LY_CHECK_GOTO(ret = lys_compile_node_connect(ctx, parent, node), cleanup);
7325
Michal Vasko4865ac42020-10-12 16:31:06 +02007326 if (pnode->when) {
7327 /* compile when */
7328 ret = lys_compile_when(ctx, pnode->when, pnode->flags, lysc_xpath_context(node), node, NULL);
7329 LY_CHECK_GOTO(ret, cleanup);
7330 }
7331
Michal Vasko7f45cf22020-10-01 12:49:44 +02007332 /* connect any augments */
7333 LY_CHECK_GOTO(ret = lys_compile_node_augments(ctx, node), cleanup);
Michal Vasko20424b42020-08-31 12:29:38 +02007334
Radek Krejci19a96102018-11-15 13:38:09 +01007335 /* nodetype-specific part */
Michal Vasko7f45cf22020-10-01 12:49:44 +02007336 LY_CHECK_GOTO(ret = node_compile_spec(ctx, pnode, node), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01007337
Michal Vasko20424b42020-08-31 12:29:38 +02007338 /* final compilation tasks that require the node to be connected */
Michal Vasko7f45cf22020-10-01 12:49:44 +02007339 COMPILE_EXTS_GOTO(ctx, pnode->exts, node->exts, node, LYEXT_PAR_NODE, ret, cleanup);
Radek Krejcife909632019-02-12 15:34:42 +01007340 if (node->flags & LYS_MAND_TRUE) {
Michal Vasko20424b42020-08-31 12:29:38 +02007341 /* inherit LYS_MAND_TRUE in parent containers */
Radek Krejcife909632019-02-12 15:34:42 +01007342 lys_compile_mandatory_parents(parent, 1);
7343 }
7344
Michal Vasko7f45cf22020-10-01 12:49:44 +02007345 if (child_set) {
7346 /* add the new node into set */
Radek Krejci3d92e442020-10-12 12:48:13 +02007347 LY_CHECK_GOTO(ret = ly_set_add(child_set, node, 1, NULL), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007348 }
7349
Radek Krejci327de162019-06-14 12:52:07 +02007350 lysc_update_path(ctx, NULL, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007351 lysp_dev_node_free(ctx->ctx, dev_pnode);
Radek Krejci19a96102018-11-15 13:38:09 +01007352 return LY_SUCCESS;
7353
7354error:
7355 lysc_node_free(ctx->ctx, node);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007356cleanup:
7357 if (dev_pnode) {
7358 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_OTHER, "Compilation of a deviated and/or refined node failed.");
7359 lysp_dev_node_free(ctx->ctx, dev_pnode);
7360 }
Radek Krejci19a96102018-11-15 13:38:09 +01007361 return ret;
7362}
7363
Michal Vaskoccc062a2020-08-13 08:34:50 +02007364/**
Michal Vasko7f45cf22020-10-01 12:49:44 +02007365 * @brief Add a module reference into an array, checks for duplicities.
Michal Vaskoccc062a2020-08-13 08:34:50 +02007366 *
7367 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02007368 * @param[in] mod Module reference to add.
7369 * @param[in,out] mod_array Module sized array to add to.
Michal Vaskoccc062a2020-08-13 08:34:50 +02007370 * @return LY_ERR value.
7371 */
7372static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02007373lys_array_add_mod_ref(struct lysc_ctx *ctx, struct lys_module *mod, struct lys_module ***mod_array)
Michal Vaskoccc062a2020-08-13 08:34:50 +02007374{
Michal Vasko7f45cf22020-10-01 12:49:44 +02007375 LY_ARRAY_COUNT_TYPE u;
7376 struct lys_module **new_mod;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007377
Michal Vasko7f45cf22020-10-01 12:49:44 +02007378 LY_ARRAY_FOR(*mod_array, u) {
7379 if ((*mod_array)[u] == mod) {
7380 /* already there */
7381 return LY_EEXIST;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007382 }
7383 }
7384
Michal Vasko7f45cf22020-10-01 12:49:44 +02007385 /* add the new module ref */
7386 LY_ARRAY_NEW_RET(ctx->ctx, *mod_array, new_mod, LY_EMEM);
7387 *new_mod = mod;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007388
7389 return LY_SUCCESS;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007390}
7391
Michal Vaskoccc062a2020-08-13 08:34:50 +02007392/**
Michal Vasko7f45cf22020-10-01 12:49:44 +02007393 * @brief Compile top-level augments and deviations defined in the current module.
Michal Vasko89b5c072020-10-06 13:52:44 +02007394 * Generally, just add the module refence to the target modules. But in case
7395 * of foreign augments, they are directly applied.
Michal Vaskoccc062a2020-08-13 08:34:50 +02007396 *
7397 * @param[in] ctx Compile context.
Michal Vaskoccc062a2020-08-13 08:34:50 +02007398 * @return LY_ERR value.
7399 */
7400static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02007401lys_precompile_augments_deviations(struct lysc_ctx *ctx)
Michal Vaskoccc062a2020-08-13 08:34:50 +02007402{
Michal Vasko7f45cf22020-10-01 12:49:44 +02007403 LY_ERR ret = LY_SUCCESS;
7404 LY_ARRAY_COUNT_TYPE u, v;
7405 const struct lysp_module *mod_p;
7406 const struct lysc_node *target;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007407 struct lys_module *mod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007408 struct lysp_submodule *submod;
7409 ly_bool has_dev = 0;
7410 uint16_t flags;
7411 uint32_t idx, opt_prev = ctx->options;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007412
Michal Vasko89b5c072020-10-06 13:52:44 +02007413 for (idx = 0; idx < ctx->ctx->implementing.count; ++idx) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007414 if (ctx->cur_mod == ctx->ctx->implementing.objs[idx]) {
Michal Vasko89b5c072020-10-06 13:52:44 +02007415 break;
7416 }
7417 }
7418 if (idx == ctx->ctx->implementing.count) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02007419 /* it was already implemented and all the augments and deviations fully applied */
7420 return LY_SUCCESS;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007421 }
7422
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007423 mod_p = ctx->cur_mod->parsed;
Michal Vasko89b5c072020-10-06 13:52:44 +02007424
Michal Vasko7f45cf22020-10-01 12:49:44 +02007425 LY_ARRAY_FOR(mod_p->augments, u) {
7426 lysc_update_path(ctx, NULL, "{augment}");
7427 lysc_update_path(ctx, NULL, mod_p->augments[u].nodeid);
Michal Vaskoccc062a2020-08-13 08:34:50 +02007428
Michal Vasko7f45cf22020-10-01 12:49:44 +02007429 /* get target module */
7430 ret = lys_nodeid_check(ctx, mod_p->augments[u].nodeid, 1, &mod, NULL);
7431 LY_CHECK_RET(ret);
Michal Vaskoccc062a2020-08-13 08:34:50 +02007432
Michal Vasko7f45cf22020-10-01 12:49:44 +02007433 /* add this module into the target module augmented_by, if not there already from previous augments */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007434 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->augmented_by);
Michal Vaskoccc062a2020-08-13 08:34:50 +02007435
Michal Vasko7f45cf22020-10-01 12:49:44 +02007436 /* if we are compiling this module, we cannot add augments to it yet */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007437 if (mod != ctx->cur_mod) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02007438 /* apply the augment, find the target node first */
7439 flags = 0;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007440 ret = lysc_resolve_schema_nodeid(ctx, mod_p->augments[u].nodeid, 0, NULL, ctx->cur_mod, LY_PREF_SCHEMA,
7441 (void *)mod_p, 0, &target, &flags);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007442 LY_CHECK_RET(ret);
7443
Michal Vasko7f45cf22020-10-01 12:49:44 +02007444 /* apply the augment */
7445 ctx->options |= flags;
7446 ret = lys_compile_augment(ctx, &mod_p->augments[u], (struct lysc_node *)target);
7447 ctx->options = opt_prev;
7448 LY_CHECK_RET(ret);
Radek Krejciccd20f12019-02-15 14:12:27 +01007449 }
Radek Krejci327de162019-06-14 12:52:07 +02007450
7451 lysc_update_path(ctx, NULL, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007452 lysc_update_path(ctx, NULL, NULL);
Radek Krejciccd20f12019-02-15 14:12:27 +01007453 }
7454
Michal Vasko7f45cf22020-10-01 12:49:44 +02007455 LY_ARRAY_FOR(mod_p->deviations, u) {
7456 /* get target module */
7457 lysc_update_path(ctx, NULL, "{deviation}");
7458 lysc_update_path(ctx, NULL, mod_p->deviations[u].nodeid);
7459 ret = lys_nodeid_check(ctx, mod_p->deviations[u].nodeid, 1, &mod, NULL);
7460 lysc_update_path(ctx, NULL, NULL);
7461 lysc_update_path(ctx, NULL, NULL);
7462 LY_CHECK_RET(ret);
Radek Krejciba03a5a2020-08-27 14:40:41 +02007463
Michal Vasko7f45cf22020-10-01 12:49:44 +02007464 /* add this module into the target module deviated_by, if not there already from previous deviations */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007465 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->deviated_by);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007466
7467 /* new deviation added to the target module */
7468 has_dev = 1;
7469 }
7470
7471 /* the same for augments and deviations in submodules */
7472 LY_ARRAY_FOR(mod_p->includes, v) {
7473 submod = mod_p->includes[v].submodule;
7474 LY_ARRAY_FOR(submod->augments, u) {
7475 lysc_update_path(ctx, NULL, "{augment}");
7476 lysc_update_path(ctx, NULL, submod->augments[u].nodeid);
7477
7478 ret = lys_nodeid_check(ctx, submod->augments[u].nodeid, 1, &mod, NULL);
7479 LY_CHECK_RET(ret);
7480
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007481 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->augmented_by);
7482 if (mod != ctx->cur_mod) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02007483 flags = 0;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007484 ret = lysc_resolve_schema_nodeid(ctx, mod_p->augments[u].nodeid, 0, NULL, ctx->cur_mod, LY_PREF_SCHEMA,
7485 submod, 0, &target, &flags);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007486 LY_CHECK_RET(ret);
7487
7488 ctx->options |= flags;
7489 ret = lys_compile_augment(ctx, &submod->augments[u], (struct lysc_node *)target);
7490 ctx->options = opt_prev;
7491 LY_CHECK_RET(ret);
Radek Krejcif538ce52019-03-05 10:46:14 +01007492 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02007493
7494 lysc_update_path(ctx, NULL, NULL);
7495 lysc_update_path(ctx, NULL, NULL);
Radek Krejcif538ce52019-03-05 10:46:14 +01007496 }
7497
Michal Vasko7f45cf22020-10-01 12:49:44 +02007498 LY_ARRAY_FOR(submod->deviations, u) {
7499 lysc_update_path(ctx, NULL, "{deviation}");
7500 lysc_update_path(ctx, NULL, submod->deviations[u].nodeid);
7501 ret = lys_nodeid_check(ctx, submod->deviations[u].nodeid, 1, &mod, NULL);
7502 lysc_update_path(ctx, NULL, NULL);
7503 lysc_update_path(ctx, NULL, NULL);
7504 LY_CHECK_RET(ret);
Radek Krejcifc11bd72019-04-11 16:00:05 +02007505
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007506 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->deviated_by);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007507 has_dev = 1;
Michal Vaskoe6143202020-07-03 13:02:08 +02007508 }
Radek Krejciccd20f12019-02-15 14:12:27 +01007509 }
7510
Michal Vasko7f45cf22020-10-01 12:49:44 +02007511 if (!has_dev) {
7512 /* no need to recompile any modules */
7513 return LY_SUCCESS;
7514 }
7515
7516 /* free all the modules in descending order */
7517 idx = ctx->ctx->list.count;
7518 do {
7519 --idx;
7520 mod = ctx->ctx->list.objs[idx];
7521 /* skip this module */
7522 if (mod == mod_p->mod) {
7523 continue;
7524 }
7525
7526 if (mod->implemented && mod->compiled) {
7527 /* keep information about features state in the module */
7528 lys_feature_precompile_revert(ctx, mod);
7529
7530 /* free the module */
7531 lysc_module_free(mod->compiled, NULL);
7532 mod->compiled = NULL;
7533 }
7534 } while (idx);
7535
7536 /* recompile all the modules in ascending order */
7537 for (idx = 0; idx < ctx->ctx->list.count; ++idx) {
7538 mod = ctx->ctx->list.objs[idx];
7539
7540 /* skip this module */
7541 if (mod == mod_p->mod) {
7542 continue;
7543 }
7544
7545 if (mod->implemented) {
7546 /* compile */
Michal Vasko89b5c072020-10-06 13:52:44 +02007547 LY_CHECK_GOTO(ret = lys_compile(mod, 0), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007548 }
7549 }
Radek Krejciccd20f12019-02-15 14:12:27 +01007550
7551cleanup:
Radek Krejcid05cbd92018-12-05 14:26:40 +01007552 return ret;
7553}
7554
Radek Krejci335332a2019-09-05 13:03:35 +02007555static void *
7556lys_compile_extension_instance_storage(enum ly_stmt stmt, struct lysc_ext_substmt *substmts)
7557{
Radek Krejci1deb5be2020-08-26 16:43:36 +02007558 for (LY_ARRAY_COUNT_TYPE u = 0; substmts[u].stmt; ++u) {
Radek Krejci335332a2019-09-05 13:03:35 +02007559 if (substmts[u].stmt == stmt) {
7560 return substmts[u].storage;
7561 }
7562 }
7563 return NULL;
7564}
7565
7566LY_ERR
7567lys_compile_extension_instance(struct lysc_ctx *ctx, const struct lysp_ext_instance *ext, struct lysc_ext_substmt *substmts)
7568{
7569 LY_ERR ret = LY_EVALID, r;
Radek Krejci1deb5be2020-08-26 16:43:36 +02007570 LY_ARRAY_COUNT_TYPE u;
Radek Krejci335332a2019-09-05 13:03:35 +02007571 struct lysp_stmt *stmt;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007572 struct lysp_qname qname;
Radek Krejci335332a2019-09-05 13:03:35 +02007573 void *parsed = NULL, **compiled = NULL;
Radek Krejci335332a2019-09-05 13:03:35 +02007574
7575 /* check for invalid substatements */
7576 for (stmt = ext->child; stmt; stmt = stmt->next) {
Radek Krejcif56e2a42019-09-09 14:15:25 +02007577 if (stmt->flags & (LYS_YIN_ATTR | LYS_YIN_ARGUMENT)) {
7578 continue;
7579 }
Radek Krejci335332a2019-09-05 13:03:35 +02007580 for (u = 0; substmts[u].stmt; ++u) {
7581 if (substmts[u].stmt == stmt->kw) {
7582 break;
7583 }
7584 }
7585 if (!substmts[u].stmt) {
Radek Krejciad5963b2019-09-06 16:03:05 +02007586 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s%s%s\" extension instance.",
Michal Vasko69730152020-10-09 16:30:07 +02007587 stmt->stmt, ext->name, ext->argument ? " " : "", ext->argument ? ext->argument : "");
Radek Krejci335332a2019-09-05 13:03:35 +02007588 goto cleanup;
7589 }
Radek Krejci335332a2019-09-05 13:03:35 +02007590 }
7591
Radek Krejciad5963b2019-09-06 16:03:05 +02007592 /* TODO store inherited data, e.g. status first, but mark them somehow to allow to overwrite them and not detect duplicity */
7593
Radek Krejci335332a2019-09-05 13:03:35 +02007594 /* keep order of the processing the same as the order in the defined substmts,
7595 * the order is important for some of the statements depending on others (e.g. type needs status and units) */
7596 for (u = 0; substmts[u].stmt; ++u) {
Radek Krejci857189e2020-09-01 13:26:36 +02007597 ly_bool stmt_present = 0;
Radek Krejciad5963b2019-09-06 16:03:05 +02007598
Radek Krejci335332a2019-09-05 13:03:35 +02007599 for (stmt = ext->child; stmt; stmt = stmt->next) {
7600 if (substmts[u].stmt != stmt->kw) {
7601 continue;
7602 }
7603
Radek Krejciad5963b2019-09-06 16:03:05 +02007604 stmt_present = 1;
Radek Krejci335332a2019-09-05 13:03:35 +02007605 if (substmts[u].storage) {
7606 switch (stmt->kw) {
Radek Krejciad5963b2019-09-06 16:03:05 +02007607 case LY_STMT_STATUS:
7608 assert(substmts[u].cardinality < LY_STMT_CARD_SOME);
7609 LY_CHECK_ERR_GOTO(r = lysp_stmt_parse(ctx, stmt, stmt->kw, &substmts[u].storage, /* TODO */ NULL), ret = r, cleanup);
7610 break;
7611 case LY_STMT_UNITS: {
7612 const char **units;
7613
7614 if (substmts[u].cardinality < LY_STMT_CARD_SOME) {
7615 /* single item */
7616 if (*((const char **)substmts[u].storage)) {
7617 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPSTMT, stmt->stmt);
7618 goto cleanup;
7619 }
7620 units = (const char **)substmts[u].storage;
7621 } else {
7622 /* sized array */
7623 const char ***units_array = (const char ***)substmts[u].storage;
7624 LY_ARRAY_NEW_GOTO(ctx->ctx, *units_array, units, ret, cleanup);
7625 }
Radek Krejci011e4aa2020-09-04 15:22:31 +02007626 r = lydict_insert(ctx->ctx, stmt->arg, 0, units);
7627 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
Radek Krejciad5963b2019-09-06 16:03:05 +02007628 break;
7629 }
Radek Krejci335332a2019-09-05 13:03:35 +02007630 case LY_STMT_TYPE: {
7631 uint16_t *flags = lys_compile_extension_instance_storage(LY_STMT_STATUS, substmts);
7632 const char **units = lys_compile_extension_instance_storage(LY_STMT_UNITS, substmts);
7633
7634 if (substmts[u].cardinality < LY_STMT_CARD_SOME) {
7635 /* single item */
Michal Vasko22df3f02020-08-24 13:29:22 +02007636 if (*(struct lysc_type **)substmts[u].storage) {
Radek Krejci335332a2019-09-05 13:03:35 +02007637 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPSTMT, stmt->stmt);
7638 goto cleanup;
7639 }
7640 compiled = substmts[u].storage;
7641 } else {
7642 /* sized array */
Michal Vasko22df3f02020-08-24 13:29:22 +02007643 struct lysc_type ***types = (struct lysc_type ***)substmts[u].storage, **type = NULL;
Radek Krejci335332a2019-09-05 13:03:35 +02007644 LY_ARRAY_NEW_GOTO(ctx->ctx, *types, type, ret, cleanup);
Michal Vasko22df3f02020-08-24 13:29:22 +02007645 compiled = (void *)type;
Radek Krejci335332a2019-09-05 13:03:35 +02007646 }
7647
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007648 r = lysp_stmt_parse(ctx, stmt, stmt->kw, &parsed, NULL);
7649 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
7650 r = lys_compile_type(ctx, ext->parent_type == LYEXT_PAR_NODE ? ((struct lysc_node *)ext->parent)->sp : NULL,
7651 flags ? *flags : 0, ctx->pmod, ext->name, parsed, (struct lysc_type **)compiled,
7652 units && !*units ? units : NULL, NULL);
Radek Krejci38d85362019-09-05 16:26:38 +02007653 lysp_type_free(ctx->ctx, parsed);
7654 free(parsed);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007655 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
Radek Krejci335332a2019-09-05 13:03:35 +02007656 break;
7657 }
Radek Krejciad5963b2019-09-06 16:03:05 +02007658 case LY_STMT_IF_FEATURE: {
7659 struct lysc_iffeature *iff = NULL;
7660
7661 if (substmts[u].cardinality < LY_STMT_CARD_SOME) {
7662 /* single item */
Michal Vasko22df3f02020-08-24 13:29:22 +02007663 if (((struct lysc_iffeature *)substmts[u].storage)->features) {
Radek Krejciad5963b2019-09-06 16:03:05 +02007664 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPSTMT, stmt->stmt);
7665 goto cleanup;
7666 }
Michal Vasko22df3f02020-08-24 13:29:22 +02007667 iff = (struct lysc_iffeature *)substmts[u].storage;
Radek Krejciad5963b2019-09-06 16:03:05 +02007668 } else {
7669 /* sized array */
Michal Vasko22df3f02020-08-24 13:29:22 +02007670 struct lysc_iffeature **iffs = (struct lysc_iffeature **)substmts[u].storage;
Radek Krejciad5963b2019-09-06 16:03:05 +02007671 LY_ARRAY_NEW_GOTO(ctx->ctx, *iffs, iff, ret, cleanup);
7672 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02007673 qname.str = stmt->arg;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007674 qname.mod = ctx->pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007675 LY_CHECK_ERR_GOTO(r = lys_compile_iffeature(ctx, &qname, iff), ret = r, cleanup);
Radek Krejciad5963b2019-09-06 16:03:05 +02007676 break;
7677 }
7678 /* TODO support other substatements (parse stmt to lysp and then compile lysp to lysc),
7679 * also note that in many statements their extensions are not taken into account */
Radek Krejci335332a2019-09-05 13:03:35 +02007680 default:
Radek Krejciad5963b2019-09-06 16:03:05 +02007681 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.",
Michal Vasko69730152020-10-09 16:30:07 +02007682 stmt->stmt, ext->name, ext->argument ? " " : "", ext->argument ? ext->argument : "");
Radek Krejci335332a2019-09-05 13:03:35 +02007683 goto cleanup;
7684 }
7685 }
Radek Krejci335332a2019-09-05 13:03:35 +02007686 }
Radek Krejci335332a2019-09-05 13:03:35 +02007687
Michal Vasko69730152020-10-09 16:30:07 +02007688 if (((substmts[u].cardinality == LY_STMT_CARD_MAND) || (substmts[u].cardinality == LY_STMT_CARD_SOME)) && !stmt_present) {
Radek Krejciad5963b2019-09-06 16:03:05 +02007689 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Missing mandatory keyword \"%s\" as a child of \"%s%s%s\".",
Michal Vasko69730152020-10-09 16:30:07 +02007690 ly_stmt2str(substmts[u].stmt), ext->name, ext->argument ? " " : "", ext->argument ? ext->argument : "");
Radek Krejciad5963b2019-09-06 16:03:05 +02007691 goto cleanup;
7692 }
Radek Krejci335332a2019-09-05 13:03:35 +02007693 }
7694
7695 ret = LY_SUCCESS;
7696
7697cleanup:
Radek Krejci335332a2019-09-05 13:03:35 +02007698 return ret;
7699}
7700
Michal Vasko175012e2019-11-06 15:49:14 +01007701/**
Michal Vaskoecd62de2019-11-13 12:35:11 +01007702 * @brief Check when for cyclic dependencies.
Michal Vasko7f45cf22020-10-01 12:49:44 +02007703 *
Michal Vaskoecd62de2019-11-13 12:35:11 +01007704 * @param[in] set Set with all the referenced nodes.
7705 * @param[in] node Node whose "when" referenced nodes are in @p set.
7706 * @return LY_ERR value
7707 */
7708static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02007709lys_compile_unres_when_cyclic(struct lyxp_set *set, const struct lysc_node *node)
Michal Vaskoecd62de2019-11-13 12:35:11 +01007710{
7711 struct lyxp_set tmp_set;
7712 struct lyxp_set_scnode *xp_scnode;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007713 uint32_t i, j;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02007714 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoecd62de2019-11-13 12:35:11 +01007715 struct lysc_when *when;
7716 LY_ERR ret = LY_SUCCESS;
7717
7718 memset(&tmp_set, 0, sizeof tmp_set);
7719
7720 /* prepare in_ctx of the set */
Michal Vaskod989ba02020-08-24 10:59:24 +02007721 for (i = 0; i < set->used; ++i) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007722 xp_scnode = &set->val.scnodes[i];
7723
Michal Vasko5c4e5892019-11-14 12:31:38 +01007724 if (xp_scnode->in_ctx != -1) {
7725 /* check node when, skip the context node (it was just checked) */
Michal Vaskoecd62de2019-11-13 12:35:11 +01007726 xp_scnode->in_ctx = 1;
7727 }
7728 }
7729
7730 for (i = 0; i < set->used; ++i) {
7731 xp_scnode = &set->val.scnodes[i];
7732 if (xp_scnode->in_ctx != 1) {
7733 /* already checked */
7734 continue;
7735 }
7736
Michal Vasko69730152020-10-09 16:30:07 +02007737 if ((xp_scnode->type != LYXP_NODE_ELEM) || (xp_scnode->scnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) ||
7738 !xp_scnode->scnode->when) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007739 /* no when to check */
7740 xp_scnode->in_ctx = 0;
7741 continue;
7742 }
7743
7744 node = xp_scnode->scnode;
7745 do {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007746 LY_ARRAY_FOR(node->when, u) {
7747 when = node->when[u];
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007748 ret = lyxp_atomize(when->cond, node->module, LY_PREF_SCHEMA_RESOLVED, when->prefixes, when->context,
7749 &tmp_set, LYXP_SCNODE_SCHEMA);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007750 if (ret != LY_SUCCESS) {
Michal Vaskof6e51882019-12-16 09:59:45 +01007751 LOGVAL(set->ctx, LY_VLOG_LYSC, node, LYVE_SEMANTICS, "Invalid when condition \"%s\".", when->cond->expr);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007752 goto cleanup;
7753 }
7754
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007755 for (j = 0; j < tmp_set.used; ++j) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007756 /* skip roots'n'stuff */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007757 if (tmp_set.val.scnodes[j].type == LYXP_NODE_ELEM) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007758 /* try to find this node in our set */
Radek Krejciaa6b53f2020-08-27 15:19:03 +02007759 uint32_t idx;
7760 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 +01007761 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 +01007762 ret = LY_EVALID;
7763 goto cleanup;
7764 }
7765
7766 /* needs to be checked, if in both sets, will be ignored */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007767 tmp_set.val.scnodes[j].in_ctx = 1;
Michal Vaskoecd62de2019-11-13 12:35:11 +01007768 } else {
7769 /* no when, nothing to check */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007770 tmp_set.val.scnodes[j].in_ctx = 0;
Michal Vaskoecd62de2019-11-13 12:35:11 +01007771 }
7772 }
7773
7774 /* merge this set into the global when set */
7775 lyxp_set_scnode_merge(set, &tmp_set);
7776 }
7777
7778 /* check when of non-data parents as well */
7779 node = node->parent;
7780 } while (node && (node->nodetype & (LYS_CASE | LYS_CHOICE)));
7781
Michal Vasko251f56e2019-11-14 16:06:47 +01007782 /* this node when was checked (xp_scnode could have been reallocd) */
7783 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoecd62de2019-11-13 12:35:11 +01007784 }
7785
7786cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02007787 lyxp_set_free_content(&tmp_set);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007788 return ret;
7789}
7790
7791/**
Michal Vasko7f45cf22020-10-01 12:49:44 +02007792 * @brief Check when/must expressions of a node on a complete compiled schema tree.
7793 *
Michal Vasko175012e2019-11-06 15:49:14 +01007794 * @param[in] ctx Compile context.
7795 * @param[in] node Node to check.
7796 * @return LY_ERR value
7797 */
7798static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02007799lys_compile_unres_xpath(struct lysc_ctx *ctx, const struct lysc_node *node)
Michal Vasko175012e2019-11-06 15:49:14 +01007800{
Michal Vasko175012e2019-11-06 15:49:14 +01007801 struct lyxp_set tmp_set;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007802 uint32_t i, opts;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02007803 LY_ARRAY_COUNT_TYPE u;
Radek Krejci857189e2020-09-01 13:26:36 +02007804 ly_bool input_done = 0;
Michal Vasko175012e2019-11-06 15:49:14 +01007805 struct lysc_when **when = NULL;
7806 struct lysc_must *musts = NULL;
7807 LY_ERR ret = LY_SUCCESS;
Michal Vasko6b26e742020-07-17 15:02:10 +02007808 const struct lysc_node *op;
Michal Vasko175012e2019-11-06 15:49:14 +01007809
7810 memset(&tmp_set, 0, sizeof tmp_set);
Michal Vasko5d8756a2019-11-07 15:21:00 +01007811 opts = LYXP_SCNODE_SCHEMA;
Michal Vasko6b26e742020-07-17 15:02:10 +02007812 if (node->flags & LYS_CONFIG_R) {
Michal Vasko2b7e5582020-10-07 12:31:23 +02007813 for (op = node->parent; op && !(op->nodetype & (LYS_RPC | LYS_ACTION)); op = op->parent) {}
Michal Vasko6b26e742020-07-17 15:02:10 +02007814 if (op) {
7815 /* we are actually in output */
7816 opts = LYXP_SCNODE_OUTPUT;
7817 }
7818 }
Michal Vasko175012e2019-11-06 15:49:14 +01007819
7820 switch (node->nodetype) {
7821 case LYS_CONTAINER:
7822 when = ((struct lysc_node_container *)node)->when;
7823 musts = ((struct lysc_node_container *)node)->musts;
7824 break;
7825 case LYS_CHOICE:
7826 when = ((struct lysc_node_choice *)node)->when;
7827 break;
7828 case LYS_LEAF:
7829 when = ((struct lysc_node_leaf *)node)->when;
7830 musts = ((struct lysc_node_leaf *)node)->musts;
7831 break;
7832 case LYS_LEAFLIST:
7833 when = ((struct lysc_node_leaflist *)node)->when;
7834 musts = ((struct lysc_node_leaflist *)node)->musts;
7835 break;
7836 case LYS_LIST:
7837 when = ((struct lysc_node_list *)node)->when;
7838 musts = ((struct lysc_node_list *)node)->musts;
7839 break;
7840 case LYS_ANYXML:
7841 case LYS_ANYDATA:
7842 when = ((struct lysc_node_anydata *)node)->when;
7843 musts = ((struct lysc_node_anydata *)node)->musts;
7844 break;
7845 case LYS_CASE:
7846 when = ((struct lysc_node_case *)node)->when;
7847 break;
7848 case LYS_NOTIF:
Michal Vaskoceab6dd2020-10-09 16:53:36 +02007849 when = ((struct lysc_notif *)node)->when;
Michal Vasko175012e2019-11-06 15:49:14 +01007850 musts = ((struct lysc_notif *)node)->musts;
7851 break;
Michal Vasko1bf09392020-03-27 12:38:10 +01007852 case LYS_RPC:
Michal Vasko5d8756a2019-11-07 15:21:00 +01007853 case LYS_ACTION:
Michal Vaskoceab6dd2020-10-09 16:53:36 +02007854 /* first process when and input musts */
7855 when = ((struct lysc_action *)node)->when;
Michal Vasko5d8756a2019-11-07 15:21:00 +01007856 musts = ((struct lysc_action *)node)->input.musts;
7857 break;
Michal Vasko175012e2019-11-06 15:49:14 +01007858 default:
7859 /* nothing to check */
7860 break;
7861 }
7862
Michal Vasko175012e2019-11-06 15:49:14 +01007863 /* check "when" */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007864 LY_ARRAY_FOR(when, u) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007865 ret = lyxp_atomize(when[u]->cond, node->module, LY_PREF_SCHEMA_RESOLVED, when[u]->prefixes, when[u]->context,
7866 &tmp_set, opts);
Michal Vasko175012e2019-11-06 15:49:14 +01007867 if (ret != LY_SUCCESS) {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007868 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_SEMANTICS, "Invalid when condition \"%s\".", when[u]->cond->expr);
Michal Vasko175012e2019-11-06 15:49:14 +01007869 goto cleanup;
7870 }
7871
Michal Vaskodc052f32019-11-07 11:11:38 +01007872 ctx->path[0] = '\0';
7873 lysc_path((struct lysc_node *)node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007874 for (i = 0; i < tmp_set.used; ++i) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01007875 /* skip roots'n'stuff */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007876 if ((tmp_set.val.scnodes[i].type == LYXP_NODE_ELEM) && (tmp_set.val.scnodes[i].in_ctx != -1)) {
7877 struct lysc_node *schema = tmp_set.val.scnodes[i].scnode;
Michal Vasko175012e2019-11-06 15:49:14 +01007878
Michal Vaskoecd62de2019-11-13 12:35:11 +01007879 /* XPath expression cannot reference "lower" status than the node that has the definition */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007880 ret = lysc_check_status(ctx, when[u]->flags, node->module, node->name, schema->flags, schema->module,
Michal Vasko69730152020-10-09 16:30:07 +02007881 schema->name);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007882 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko5c4e5892019-11-14 12:31:38 +01007883
7884 /* check dummy node accessing */
7885 if (schema == node) {
Michal Vaskof6e51882019-12-16 09:59:45 +01007886 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LY_VCODE_DUMMY_WHEN, node->name);
Michal Vasko5c4e5892019-11-14 12:31:38 +01007887 ret = LY_EVALID;
7888 goto cleanup;
7889 }
Michal Vasko175012e2019-11-06 15:49:14 +01007890 }
7891 }
7892
Michal Vaskoecd62de2019-11-13 12:35:11 +01007893 /* check cyclic dependencies */
Michal Vasko004d3152020-06-11 19:59:22 +02007894 ret = lys_compile_unres_when_cyclic(&tmp_set, node);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007895 LY_CHECK_GOTO(ret, cleanup);
7896
Michal Vaskod3678892020-05-21 10:06:58 +02007897 lyxp_set_free_content(&tmp_set);
Michal Vasko175012e2019-11-06 15:49:14 +01007898 }
7899
Michal Vasko5d8756a2019-11-07 15:21:00 +01007900check_musts:
Michal Vasko175012e2019-11-06 15:49:14 +01007901 /* check "must" */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007902 LY_ARRAY_FOR(musts, u) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007903 ret = lyxp_atomize(musts[u].cond, node->module, LY_PREF_SCHEMA_RESOLVED, musts[u].prefixes, node, &tmp_set, opts);
Michal Vasko175012e2019-11-06 15:49:14 +01007904 if (ret != LY_SUCCESS) {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007905 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_SEMANTICS, "Invalid must restriction \"%s\".", musts[u].cond->expr);
Michal Vasko175012e2019-11-06 15:49:14 +01007906 goto cleanup;
7907 }
7908
Michal Vaskodc052f32019-11-07 11:11:38 +01007909 ctx->path[0] = '\0';
7910 lysc_path((struct lysc_node *)node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007911 for (i = 0; i < tmp_set.used; ++i) {
Michal Vasko175012e2019-11-06 15:49:14 +01007912 /* skip roots'n'stuff */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007913 if (tmp_set.val.scnodes[i].type == LYXP_NODE_ELEM) {
Michal Vasko175012e2019-11-06 15:49:14 +01007914 /* XPath expression cannot reference "lower" status than the node that has the definition */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007915 ret = lysc_check_status(ctx, node->flags, node->module, node->name, tmp_set.val.scnodes[i].scnode->flags,
Michal Vasko69730152020-10-09 16:30:07 +02007916 tmp_set.val.scnodes[i].scnode->module, tmp_set.val.scnodes[i].scnode->name);
Michal Vasko175012e2019-11-06 15:49:14 +01007917 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko175012e2019-11-06 15:49:14 +01007918 }
7919 }
7920
Michal Vaskod3678892020-05-21 10:06:58 +02007921 lyxp_set_free_content(&tmp_set);
Michal Vasko175012e2019-11-06 15:49:14 +01007922 }
7923
Michal Vasko1bf09392020-03-27 12:38:10 +01007924 if ((node->nodetype & (LYS_RPC | LYS_ACTION)) && !input_done) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01007925 /* now check output musts */
7926 input_done = 1;
Michal Vaskoceab6dd2020-10-09 16:53:36 +02007927 when = NULL;
Michal Vasko5d8756a2019-11-07 15:21:00 +01007928 musts = ((struct lysc_action *)node)->output.musts;
7929 opts = LYXP_SCNODE_OUTPUT;
7930 goto check_musts;
7931 }
7932
Michal Vasko175012e2019-11-06 15:49:14 +01007933cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02007934 lyxp_set_free_content(&tmp_set);
Michal Vasko175012e2019-11-06 15:49:14 +01007935 return ret;
7936}
7937
Michal Vasko7f45cf22020-10-01 12:49:44 +02007938/**
7939 * @brief Check leafref for its target existence on a complete compiled schema tree.
7940 *
7941 * @param[in] ctx Compile context.
7942 * @param[in] node Context node for the leafref.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007943 * @param[in] lref Leafref to check/resolve.
Michal Vasko7f45cf22020-10-01 12:49:44 +02007944 * @return LY_ERR value.
7945 */
Michal Vasko8d544252020-03-02 10:19:52 +01007946static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02007947lys_compile_unres_leafref(struct lysc_ctx *ctx, const struct lysc_node *node, struct lysc_type_leafref *lref)
7948{
Michal Vasko6b26e742020-07-17 15:02:10 +02007949 const struct lysc_node *target = NULL, *siter;
Michal Vasko004d3152020-06-11 19:59:22 +02007950 struct ly_path *p;
7951 struct lysc_type *type;
7952
7953 assert(node->nodetype & (LYS_LEAF | LYS_LEAFLIST));
7954
7955 /* try to find the target */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007956 LY_CHECK_RET(ly_path_compile(ctx->ctx, node->module, node, lref->path, LY_PATH_LREF_TRUE, lysc_is_output(node) ?
7957 LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_MANY, LY_PREF_SCHEMA_RESOLVED, lref->prefixes, &p));
Michal Vasko004d3152020-06-11 19:59:22 +02007958
7959 /* get the target node */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02007960 target = p[LY_ARRAY_COUNT(p) - 1].node;
Michal Vasko004d3152020-06-11 19:59:22 +02007961 ly_path_free(node->module->ctx, p);
7962
7963 if (!(target->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
7964 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02007965 "Invalid leafref path \"%s\" - target node is %s instead of leaf or leaf-list.",
7966 lref->path->expr, lys_nodetype2str(target->nodetype));
Michal Vasko004d3152020-06-11 19:59:22 +02007967 return LY_EVALID;
7968 }
7969
7970 /* check status */
7971 ctx->path[0] = '\0';
7972 lysc_path(node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
7973 ctx->path_len = strlen(ctx->path);
7974 if (lysc_check_status(ctx, node->flags, node->module, node->name, target->flags, target->module, target->name)) {
7975 return LY_EVALID;
7976 }
7977 ctx->path_len = 1;
7978 ctx->path[1] = '\0';
7979
7980 /* check config */
Michal Vasko6b26e742020-07-17 15:02:10 +02007981 if (lref->require_instance) {
Radek Krejci1e008d22020-08-17 11:37:37 +02007982 for (siter = node->parent; siter && !(siter->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); siter = siter->parent) {}
Michal Vasko6b26e742020-07-17 15:02:10 +02007983 if (!siter && (node->flags & LYS_CONFIG_W) && (target->flags & LYS_CONFIG_R)) {
Michal Vasko004d3152020-06-11 19:59:22 +02007984 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE, "Invalid leafref path \"%s\" - target is supposed"
Michal Vasko69730152020-10-09 16:30:07 +02007985 " to represent configuration data (as the leafref does), but it does not.", lref->path->expr);
Michal Vasko004d3152020-06-11 19:59:22 +02007986 return LY_EVALID;
7987 }
7988 }
7989
7990 /* store the target's type and check for circular chain of leafrefs */
7991 lref->realtype = ((struct lysc_node_leaf *)target)->type;
7992 for (type = lref->realtype; type && type->basetype == LY_TYPE_LEAFREF; type = ((struct lysc_type_leafref *)type)->realtype) {
7993 if (type == (struct lysc_type *)lref) {
7994 /* circular chain detected */
7995 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02007996 "Invalid leafref path \"%s\" - circular chain of leafrefs detected.", lref->path->expr);
Michal Vasko004d3152020-06-11 19:59:22 +02007997 return LY_EVALID;
7998 }
7999 }
8000
8001 /* check if leafref and its target are under common if-features */
8002 if (lys_compile_leafref_features_validate(node, target)) {
8003 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02008004 "Invalid leafref path \"%s\" - set of features applicable to the leafref target is not a subset of"
8005 " features applicable to the leafref itself.", lref->path->expr);
Michal Vasko004d3152020-06-11 19:59:22 +02008006 return LY_EVALID;
8007 }
8008
8009 return LY_SUCCESS;
8010}
8011
8012static LY_ERR
Michal Vasko8d544252020-03-02 10:19:52 +01008013lys_compile_ietf_netconf_wd_annotation(struct lysc_ctx *ctx, struct lys_module *mod)
8014{
8015 struct lysc_ext_instance *ext;
8016 struct lysp_ext_instance *ext_p = NULL;
8017 struct lysp_stmt *stmt;
8018 const struct lys_module *ext_mod;
8019 LY_ERR ret = LY_SUCCESS;
8020
8021 /* create the parsed extension instance manually */
8022 ext_p = calloc(1, sizeof *ext_p);
8023 LY_CHECK_ERR_GOTO(!ext_p, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci011e4aa2020-09-04 15:22:31 +02008024 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "md:annotation", 0, &ext_p->name), cleanup);
8025 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "default", 0, &ext_p->argument), cleanup);
Michal Vasko8d544252020-03-02 10:19:52 +01008026 ext_p->insubstmt = LYEXT_SUBSTMT_SELF;
8027 ext_p->insubstmt_index = 0;
8028
Radek Krejci87e25252020-09-15 13:28:31 +02008029 ext_p->child = stmt = calloc(1, sizeof *ext_p->child);
8030 LY_CHECK_ERR_GOTO(!stmt, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci011e4aa2020-09-04 15:22:31 +02008031 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "type", 0, &stmt->stmt), cleanup);
8032 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "boolean", 0, &stmt->arg), cleanup);
Michal Vasko8d544252020-03-02 10:19:52 +01008033 stmt->kw = LY_STMT_TYPE;
Michal Vasko8d544252020-03-02 10:19:52 +01008034
8035 /* allocate new extension instance */
8036 LY_ARRAY_NEW_GOTO(mod->ctx, mod->compiled->exts, ext, ret, cleanup);
8037
8038 /* manually get extension definition module */
8039 ext_mod = ly_ctx_get_module_latest(ctx->ctx, "ietf-yang-metadata");
8040
8041 /* compile the extension instance */
8042 LY_CHECK_GOTO(ret = lys_compile_ext(ctx, ext_p, ext, mod->compiled, LYEXT_PAR_MODULE, ext_mod), cleanup);
8043
8044cleanup:
8045 lysp_ext_instance_free(ctx->ctx, ext_p);
8046 free(ext_p);
8047 return ret;
8048}
8049
Michal Vasko7f45cf22020-10-01 12:49:44 +02008050/**
8051 * @brief Compile default value(s) for leaf or leaf-list expecting a complete compiled schema tree.
8052 *
8053 * @param[in] ctx Compile context.
8054 * @param[in] node Leaf or leaf-list to compile the default value(s) for.
8055 * @param[in] type Type of the default value.
8056 * @param[in] dflt Default value.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008057 * @param[in] dflt_pmod Parsed module of the @p dflt to resolve possible prefixes.
Michal Vasko7f45cf22020-10-01 12:49:44 +02008058 * @param[in,out] storage Storage for the compiled default value.
8059 * @return LY_ERR value.
8060 */
Michal Vasko004d3152020-06-11 19:59:22 +02008061static LY_ERR
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008062lys_compile_unres_dflt(struct lysc_ctx *ctx, struct lysc_node *node, struct lysc_type *type, const char *dflt,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008063 const struct lysp_module *dflt_pmod, struct lyd_value *storage)
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008064{
8065 LY_ERR ret;
8066 struct ly_err_item *err = NULL;
8067
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008068 ret = type->plugin->store(ctx->ctx, type, dflt, strlen(dflt), 0, LY_PREF_SCHEMA, (void *)dflt_pmod,
8069 LYD_HINT_SCHEMA, node, storage, &err);
Michal Vaskofeca4fb2020-10-05 08:58:40 +02008070 if (ret == LY_EINCOMPLETE) {
8071 /* we have no data so we will not be resolving it */
8072 ret = LY_SUCCESS;
8073 }
8074
8075 if (ret) {
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008076 ctx->path[0] = '\0';
8077 lysc_path(node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
Michal Vaskofeca4fb2020-10-05 08:58:40 +02008078 if (err) {
8079 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02008080 "Invalid default - value does not fit the type (%s).", err->msg);
Michal Vaskofeca4fb2020-10-05 08:58:40 +02008081 ly_err_free(err);
8082 } else {
8083 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02008084 "Invalid default - value does not fit the type.");
Michal Vaskofeca4fb2020-10-05 08:58:40 +02008085 }
8086 return ret;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008087 }
Michal Vaskofeca4fb2020-10-05 08:58:40 +02008088
8089 ++((struct lysc_type *)storage->realtype)->refcount;
8090 return LY_SUCCESS;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008091}
8092
Michal Vasko7f45cf22020-10-01 12:49:44 +02008093/**
8094 * @brief Compile default value of a leaf expecting a complete compiled schema tree.
8095 *
8096 * @param[in] ctx Compile context.
8097 * @param[in] leaf Leaf that the default value is for.
8098 * @param[in] dflt Default value to compile.
8099 * @return LY_ERR value.
8100 */
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008101static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02008102lys_compile_unres_leaf_dlft(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, struct lysp_qname *dflt)
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008103{
8104 LY_ERR ret;
8105
8106 assert(!leaf->dflt);
8107
8108 if (leaf->flags & (LYS_MAND_TRUE | LYS_KEY)) {
8109 /* ignore default values for keys and mandatory leaves */
8110 return LY_SUCCESS;
8111 }
8112
8113 /* allocate the default value */
8114 leaf->dflt = calloc(1, sizeof *leaf->dflt);
8115 LY_CHECK_ERR_RET(!leaf->dflt, LOGMEM(ctx->ctx), LY_EMEM);
8116
8117 /* store the default value */
Michal Vasko7f45cf22020-10-01 12:49:44 +02008118 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 +02008119 if (ret) {
8120 free(leaf->dflt);
8121 leaf->dflt = NULL;
8122 }
8123
8124 return ret;
8125}
8126
Michal Vasko7f45cf22020-10-01 12:49:44 +02008127/**
8128 * @brief Compile default values of a leaf-list expecting a complete compiled schema tree.
8129 *
8130 * @param[in] ctx Compile context.
8131 * @param[in] llist Leaf-list that the default value(s) are for.
8132 * @param[in] dflt Default value to compile, in case of a single value.
8133 * @param[in] dflts Sized array of default values, in case of more values.
8134 * @return LY_ERR value.
8135 */
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008136static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02008137lys_compile_unres_llist_dflts(struct lysc_ctx *ctx, struct lysc_node_leaflist *llist, struct lysp_qname *dflt,
8138 struct lysp_qname *dflts)
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008139{
8140 LY_ERR ret;
8141 LY_ARRAY_COUNT_TYPE orig_count, u, v;
8142
8143 assert(dflt || dflts);
8144
8145 if (llist->dflts) {
8146 /* there were already some defaults and we are adding new by deviations */
8147 assert(dflts);
8148 orig_count = LY_ARRAY_COUNT(llist->dflts);
8149 } else {
8150 orig_count = 0;
8151 }
8152
8153 /* allocate new items */
8154 if (dflts) {
8155 LY_ARRAY_CREATE_RET(ctx->ctx, llist->dflts, orig_count + LY_ARRAY_COUNT(dflts), LY_EMEM);
8156 } else {
8157 LY_ARRAY_CREATE_RET(ctx->ctx, llist->dflts, orig_count + 1, LY_EMEM);
8158 }
8159
8160 /* fill each new default value */
8161 if (dflts) {
8162 LY_ARRAY_FOR(dflts, u) {
8163 llist->dflts[orig_count + u] = calloc(1, sizeof **llist->dflts);
Michal Vasko7f45cf22020-10-01 12:49:44 +02008164 ret = lys_compile_unres_dflt(ctx, (struct lysc_node *)llist, llist->type, dflts[u].str, dflts[u].mod,
8165 llist->dflts[orig_count + u]);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008166 LY_CHECK_ERR_RET(ret, free(llist->dflts[orig_count + u]), ret);
8167 LY_ARRAY_INCREMENT(llist->dflts);
8168 }
8169 } else {
8170 llist->dflts[orig_count] = calloc(1, sizeof **llist->dflts);
Michal Vasko7f45cf22020-10-01 12:49:44 +02008171 ret = lys_compile_unres_dflt(ctx, (struct lysc_node *)llist, llist->type, dflt->str, dflt->mod,
8172 llist->dflts[orig_count]);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008173 LY_CHECK_ERR_RET(ret, free(llist->dflts[orig_count]), ret);
8174 LY_ARRAY_INCREMENT(llist->dflts);
8175 }
8176
8177 /* check default value uniqueness */
8178 if (llist->flags & LYS_CONFIG_W) {
8179 /* configuration data values must be unique - so check the default values */
8180 for (u = orig_count; u < LY_ARRAY_COUNT(llist->dflts); ++u) {
8181 for (v = 0; v < u; ++v) {
8182 if (!llist->dflts[u]->realtype->plugin->compare(llist->dflts[u], llist->dflts[v])) {
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008183 lysc_update_path(ctx, llist->parent, llist->name);
8184 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko7f45cf22020-10-01 12:49:44 +02008185 "Configuration leaf-list has multiple defaults of the same value \"%s\".",
8186 llist->dflts[u]->canonical);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008187 lysc_update_path(ctx, NULL, NULL);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008188 return LY_EVALID;
8189 }
8190 }
8191 }
8192 }
8193
8194 return LY_SUCCESS;
8195}
8196
Michal Vasko7f45cf22020-10-01 12:49:44 +02008197/**
8198 * @brief Finish compilation of all the unres sets of a compile context.
8199 *
8200 * @param[in] ctx Compile context with unres sets.
8201 * @return LY_ERR value.
8202 */
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008203static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02008204lys_compile_unres(struct lysc_ctx *ctx)
8205{
8206 struct lysc_node *node;
8207 struct lysc_type *type, *typeiter;
8208 struct lysc_type_leafref *lref;
Michal Vasko7f45cf22020-10-01 12:49:44 +02008209 struct lysc_augment *aug;
8210 struct lysc_deviation *dev;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02008211 LY_ARRAY_COUNT_TYPE v;
Michal Vasko004d3152020-06-11 19:59:22 +02008212 uint32_t i;
8213
8214 /* for leafref, we need 2 rounds - first detects circular chain by storing the first referred type (which
8215 * can be also leafref, in case it is already resolved, go through the chain and check that it does not
8216 * point to the starting leafref type). The second round stores the first non-leafref type for later data validation. */
8217 for (i = 0; i < ctx->leafrefs.count; ++i) {
8218 node = ctx->leafrefs.objs[i];
8219 assert(node->nodetype & (LYS_LEAF | LYS_LEAFLIST));
8220 type = ((struct lysc_node_leaf *)node)->type;
8221 if (type->basetype == LY_TYPE_LEAFREF) {
8222 LY_CHECK_RET(lys_compile_unres_leafref(ctx, node, (struct lysc_type_leafref *)type));
8223 } else if (type->basetype == LY_TYPE_UNION) {
8224 LY_ARRAY_FOR(((struct lysc_type_union *)type)->types, v) {
8225 if (((struct lysc_type_union *)type)->types[v]->basetype == LY_TYPE_LEAFREF) {
8226 lref = (struct lysc_type_leafref *)((struct lysc_type_union *)type)->types[v];
8227 LY_CHECK_RET(lys_compile_unres_leafref(ctx, node, lref));
8228 }
8229 }
8230 }
8231 }
8232 for (i = 0; i < ctx->leafrefs.count; ++i) {
8233 /* store pointer to the real type */
8234 type = ((struct lysc_node_leaf *)ctx->leafrefs.objs[i])->type;
8235 if (type->basetype == LY_TYPE_LEAFREF) {
Michal Vasko22df3f02020-08-24 13:29:22 +02008236 for (typeiter = ((struct lysc_type_leafref *)type)->realtype;
Michal Vasko004d3152020-06-11 19:59:22 +02008237 typeiter->basetype == LY_TYPE_LEAFREF;
Michal Vasko22df3f02020-08-24 13:29:22 +02008238 typeiter = ((struct lysc_type_leafref *)typeiter)->realtype) {}
8239 ((struct lysc_type_leafref *)type)->realtype = typeiter;
Michal Vasko004d3152020-06-11 19:59:22 +02008240 } else if (type->basetype == LY_TYPE_UNION) {
Michal Vasko22df3f02020-08-24 13:29:22 +02008241 LY_ARRAY_FOR(((struct lysc_type_union *)type)->types, v) {
8242 if (((struct lysc_type_union *)type)->types[v]->basetype == LY_TYPE_LEAFREF) {
8243 for (typeiter = ((struct lysc_type_leafref *)((struct lysc_type_union *)type)->types[v])->realtype;
Michal Vasko004d3152020-06-11 19:59:22 +02008244 typeiter->basetype == LY_TYPE_LEAFREF;
Michal Vasko22df3f02020-08-24 13:29:22 +02008245 typeiter = ((struct lysc_type_leafref *)typeiter)->realtype) {}
8246 ((struct lysc_type_leafref *)((struct lysc_type_union *)type)->types[v])->realtype = typeiter;
Michal Vasko004d3152020-06-11 19:59:22 +02008247 }
8248 }
8249 }
8250 }
8251
8252 /* check xpath */
8253 for (i = 0; i < ctx->xpath.count; ++i) {
8254 LY_CHECK_RET(lys_compile_unres_xpath(ctx, ctx->xpath.objs[i]));
8255 }
8256
8257 /* finish incomplete default values compilation */
8258 for (i = 0; i < ctx->dflts.count; ++i) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008259 struct lysc_unres_dflt *r = ctx->dflts.objs[i];
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008260 if (r->leaf->nodetype == LYS_LEAF) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008261 LY_CHECK_RET(lys_compile_unres_leaf_dlft(ctx, r->leaf, r->dflt));
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008262 } else {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008263 LY_CHECK_RET(lys_compile_unres_llist_dflts(ctx, r->llist, r->dflt, r->dflts));
Michal Vasko004d3152020-06-11 19:59:22 +02008264 }
Michal Vasko004d3152020-06-11 19:59:22 +02008265 }
8266
Michal Vasko7f45cf22020-10-01 12:49:44 +02008267 /* check that all augments were applied */
8268 for (i = 0; i < ctx->augs.count; ++i) {
8269 aug = ctx->augs.objs[i];
8270 LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
8271 "Augment target node \"%s\" from module \"%s\" was not found.", aug->nodeid->expr,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008272 LYSP_MODULE_NAME(aug->nodeid_pmod));
Michal Vasko7f45cf22020-10-01 12:49:44 +02008273 }
8274 if (ctx->augs.count) {
8275 return LY_ENOTFOUND;
8276 }
8277
8278 /* check that all deviations were applied */
8279 for (i = 0; i < ctx->devs.count; ++i) {
8280 dev = ctx->devs.objs[i];
8281 LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
8282 "Deviation(s) target node \"%s\" from module \"%s\" was not found.", dev->nodeid->expr,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008283 LYSP_MODULE_NAME(dev->dev_pmods[0]));
Michal Vasko7f45cf22020-10-01 12:49:44 +02008284 }
8285 if (ctx->devs.count) {
8286 return LY_ENOTFOUND;
8287 }
8288
8289 return LY_SUCCESS;
8290}
8291
Michal Vasko89b5c072020-10-06 13:52:44 +02008292void
8293lys_precompile_augments_deviations_revert(struct ly_ctx *ctx, const struct lys_module *mod)
Michal Vasko7f45cf22020-10-01 12:49:44 +02008294{
8295 uint32_t i;
8296 LY_ARRAY_COUNT_TYPE u, count;
8297 struct lys_module *m;
8298
Michal Vasko89b5c072020-10-06 13:52:44 +02008299 for (i = 0; i < ctx->list.count; ++i) {
8300 m = ctx->list.objs[i];
Michal Vasko7f45cf22020-10-01 12:49:44 +02008301
8302 if (m->augmented_by) {
8303 count = LY_ARRAY_COUNT(m->augmented_by);
8304 for (u = 0; u < count; ++u) {
8305 if (m->augmented_by[u] == mod) {
8306 /* keep the order */
8307 if (u < count - 1) {
8308 memmove(m->augmented_by + u, m->augmented_by + u + 1, (count - u) * sizeof *m->augmented_by);
8309 }
8310 LY_ARRAY_DECREMENT(m->augmented_by);
8311 break;
8312 }
8313 }
8314 if (!LY_ARRAY_COUNT(m->augmented_by)) {
8315 LY_ARRAY_FREE(m->augmented_by);
8316 m->augmented_by = NULL;
8317 }
8318 }
8319
8320 if (m->deviated_by) {
8321 count = LY_ARRAY_COUNT(m->deviated_by);
8322 for (u = 0; u < count; ++u) {
8323 if (m->deviated_by[u] == mod) {
8324 /* keep the order */
8325 if (u < count - 1) {
8326 memmove(m->deviated_by + u, m->deviated_by + u + 1, (count - u) * sizeof *m->deviated_by);
8327 }
8328 LY_ARRAY_DECREMENT(m->deviated_by);
8329 break;
8330 }
8331 }
8332 if (!LY_ARRAY_COUNT(m->deviated_by)) {
8333 LY_ARRAY_FREE(m->deviated_by);
8334 m->deviated_by = NULL;
8335 }
8336 }
8337 }
8338}
8339
8340/**
8341 * @brief Compile features in the current module and all its submodules.
8342 *
8343 * @param[in] ctx Compile context.
8344 * @return LY_ERR value.
8345 */
8346static LY_ERR
8347lys_compile_features(struct lysc_ctx *ctx)
8348{
8349 struct lysp_submodule *submod;
8350 LY_ARRAY_COUNT_TYPE u, v;
8351
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008352 if (!ctx->cur_mod->features) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008353 /* features are compiled directly into the module structure,
8354 * but it must be done in two steps to allow forward references (via if-feature) between the features themselves */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008355 LY_CHECK_RET(lys_feature_precompile(ctx, NULL, NULL, ctx->cur_mod->parsed->features, &ctx->cur_mod->features));
8356 LY_ARRAY_FOR(ctx->cur_mod->parsed->includes, v) {
8357 submod = ctx->cur_mod->parsed->includes[v].submodule;
8358 LY_CHECK_RET(lys_feature_precompile(ctx, NULL, NULL, submod->features, &ctx->cur_mod->features));
Michal Vasko7f45cf22020-10-01 12:49:44 +02008359 }
8360 }
8361
8362 /* finish feature compilation, not only for the main module, but also for the submodules.
8363 * Due to possible forward references, it must be done when all the features (including submodules)
8364 * are present. */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008365 LY_ARRAY_FOR(ctx->cur_mod->parsed->features, u) {
8366 LY_CHECK_RET(lys_feature_precompile_finish(ctx, &ctx->cur_mod->parsed->features[u], ctx->cur_mod->features));
Michal Vasko7f45cf22020-10-01 12:49:44 +02008367 }
8368
8369 lysc_update_path(ctx, NULL, "{submodule}");
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008370 LY_ARRAY_FOR(ctx->cur_mod->parsed->includes, v) {
8371 submod = ctx->cur_mod->parsed->includes[v].submodule;
Michal Vasko7f45cf22020-10-01 12:49:44 +02008372
8373 lysc_update_path(ctx, NULL, submod->name);
8374 LY_ARRAY_FOR(submod->features, u) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008375 LY_CHECK_RET(lys_feature_precompile_finish(ctx, &submod->features[u], ctx->cur_mod->features));
Michal Vasko7f45cf22020-10-01 12:49:44 +02008376 }
8377 lysc_update_path(ctx, NULL, NULL);
8378 }
8379 lysc_update_path(ctx, NULL, NULL);
8380
8381 return LY_SUCCESS;
8382}
8383
8384/**
8385 * @brief Compile identites in the current module and all its submodules.
8386 *
8387 * @param[in] ctx Compile context.
8388 * @return LY_ERR value.
8389 */
8390static LY_ERR
8391lys_compile_identities(struct lysc_ctx *ctx)
8392{
8393 struct lysp_submodule *submod;
8394 LY_ARRAY_COUNT_TYPE u;
8395
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008396 if (!ctx->cur_mod->identities) {
8397 LY_CHECK_RET(lys_identity_precompile(ctx, NULL, NULL, ctx->cur_mod->parsed->identities, &ctx->cur_mod->identities));
8398 LY_ARRAY_FOR(ctx->cur_mod->parsed->includes, u) {
8399 submod = ctx->cur_mod->parsed->includes[u].submodule;
8400 LY_CHECK_RET(lys_identity_precompile(ctx, NULL, NULL, submod->identities, &ctx->cur_mod->identities));
Michal Vasko7f45cf22020-10-01 12:49:44 +02008401 }
8402 }
8403
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008404 if (ctx->cur_mod->parsed->identities) {
8405 LY_CHECK_RET(lys_compile_identities_derived(ctx, ctx->cur_mod->parsed->identities, ctx->cur_mod->identities));
Michal Vasko7f45cf22020-10-01 12:49:44 +02008406 }
8407 lysc_update_path(ctx, NULL, "{submodule}");
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008408 LY_ARRAY_FOR(ctx->cur_mod->parsed->includes, u) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008409
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008410 submod = ctx->cur_mod->parsed->includes[u].submodule;
Michal Vasko7f45cf22020-10-01 12:49:44 +02008411 if (submod->identities) {
8412 lysc_update_path(ctx, NULL, submod->name);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008413 LY_CHECK_RET(lys_compile_identities_derived(ctx, submod->identities, ctx->cur_mod->identities));
Michal Vasko7f45cf22020-10-01 12:49:44 +02008414 lysc_update_path(ctx, NULL, NULL);
8415 }
8416 }
8417 lysc_update_path(ctx, NULL, NULL);
8418
Michal Vasko004d3152020-06-11 19:59:22 +02008419 return LY_SUCCESS;
8420}
8421
Radek Krejci19a96102018-11-15 13:38:09 +01008422LY_ERR
Michal Vasko7a0b0762020-09-02 16:37:01 +02008423lys_compile(struct lys_module *mod, uint32_t options)
Radek Krejci19a96102018-11-15 13:38:09 +01008424{
8425 struct lysc_ctx ctx = {0};
8426 struct lysc_module *mod_c;
8427 struct lysp_module *sp;
Michal Vasko7f45cf22020-10-01 12:49:44 +02008428 struct lysp_submodule *submod;
8429 struct lysp_node *pnode;
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008430 struct lysp_grp *grps;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02008431 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02008432 uint32_t i;
Radek Krejcid05cbd92018-12-05 14:26:40 +01008433 LY_ERR ret = LY_SUCCESS;
Radek Krejci19a96102018-11-15 13:38:09 +01008434
Michal Vasko7a0b0762020-09-02 16:37:01 +02008435 LY_CHECK_ARG_RET(NULL, mod, mod->parsed, !mod->compiled, mod->ctx, LY_EINVAL);
Radek Krejci096235c2019-01-11 11:12:19 +01008436
Michal Vasko7a0b0762020-09-02 16:37:01 +02008437 if (!mod->implemented) {
Radek Krejci096235c2019-01-11 11:12:19 +01008438 /* just imported modules are not compiled */
8439 return LY_SUCCESS;
8440 }
8441
Michal Vasko7f45cf22020-10-01 12:49:44 +02008442 /* context will be changed */
8443 ++mod->ctx->module_set_id;
8444
Michal Vasko7a0b0762020-09-02 16:37:01 +02008445 sp = mod->parsed;
Radek Krejci19a96102018-11-15 13:38:09 +01008446
Michal Vasko7a0b0762020-09-02 16:37:01 +02008447 ctx.ctx = mod->ctx;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008448 ctx.cur_mod = mod;
8449 ctx.pmod = sp;
Radek Krejciec4da802019-05-02 13:02:41 +02008450 ctx.options = options;
Radek Krejci327de162019-06-14 12:52:07 +02008451 ctx.path_len = 1;
8452 ctx.path[0] = '/';
Radek Krejci19a96102018-11-15 13:38:09 +01008453
Michal Vasko7a0b0762020-09-02 16:37:01 +02008454 mod->compiled = mod_c = calloc(1, sizeof *mod_c);
8455 LY_CHECK_ERR_RET(!mod_c, LOGMEM(mod->ctx), LY_EMEM);
8456 mod_c->mod = mod;
Radek Krejci19a96102018-11-15 13:38:09 +01008457
Michal Vasko7f45cf22020-10-01 12:49:44 +02008458 /* process imports */
Michal Vasko7c8439f2020-08-05 13:25:19 +02008459 LY_ARRAY_FOR(sp->imports, u) {
8460 LY_CHECK_GOTO(ret = lys_compile_import(&ctx, &sp->imports[u]), error);
8461 }
Radek Krejci0935f412019-08-20 16:15:18 +02008462
Michal Vasko7f45cf22020-10-01 12:49:44 +02008463 /* features */
8464 LY_CHECK_GOTO(ret = lys_compile_features(&ctx), error);
Radek Krejci14915cc2020-09-14 17:28:13 +02008465
8466 /* identities, work similarly to features with the precompilation */
Michal Vasko7f45cf22020-10-01 12:49:44 +02008467 LY_CHECK_GOTO(ret = lys_compile_identities(&ctx), error);
8468
8469 /* augments and deviations */
8470 LY_CHECK_GOTO(ret = lys_precompile_augments_deviations(&ctx), error);
8471
8472 /* compile augments and deviations of our module from other modules so they can be applied during compilation */
8473 LY_CHECK_GOTO(ret = lys_precompile_own_augments(&ctx), error);
8474 LY_CHECK_GOTO(ret = lys_precompile_own_deviations(&ctx), error);
Radek Krejci19a96102018-11-15 13:38:09 +01008475
Radek Krejci95710c92019-02-11 15:49:55 +01008476 /* data nodes */
Michal Vasko7f45cf22020-10-01 12:49:44 +02008477 LY_LIST_FOR(sp->data, pnode) {
8478 LY_CHECK_GOTO(ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL), error);
Radek Krejci19a96102018-11-15 13:38:09 +01008479 }
Radek Krejci95710c92019-02-11 15:49:55 +01008480
Michal Vasko7f45cf22020-10-01 12:49:44 +02008481 /* top-level RPCs and notifications */
8482 COMPILE_OP_ARRAY_GOTO(&ctx, sp->rpcs, mod_c->rpcs, NULL, u, lys_compile_action, 0, ret, error);
8483 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 +01008484
Michal Vasko7f45cf22020-10-01 12:49:44 +02008485 /* extension instances */
Radek Krejci0935f412019-08-20 16:15:18 +02008486 COMPILE_EXTS_GOTO(&ctx, sp->exts, mod_c->exts, mod_c, LYEXT_PAR_MODULE, ret, error);
Radek Krejci19a96102018-11-15 13:38:09 +01008487
Michal Vasko7f45cf22020-10-01 12:49:44 +02008488 /* the same for submodules */
8489 LY_ARRAY_FOR(sp->includes, u) {
8490 submod = sp->includes[u].submodule;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008491 ctx.pmod = (struct lysp_module *)submod;
8492
Michal Vasko7f45cf22020-10-01 12:49:44 +02008493 LY_LIST_FOR(submod->data, pnode) {
8494 ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL);
8495 LY_CHECK_GOTO(ret, error);
8496 }
8497
8498 COMPILE_OP_ARRAY_GOTO(&ctx, submod->rpcs, mod_c->rpcs, NULL, v, lys_compile_action, 0, ret, error);
8499 COMPILE_OP_ARRAY_GOTO(&ctx, submod->notifs, mod_c->notifs, NULL, v, lys_compile_notif, 0, ret, error);
8500
8501 COMPILE_EXTS_GOTO(&ctx, submod->exts, mod_c->exts, mod_c, LYEXT_PAR_MODULE, ret, error);
8502 }
8503
Michal Vasko004d3152020-06-11 19:59:22 +02008504 /* finish compilation for all unresolved items in the context */
8505 LY_CHECK_GOTO(ret = lys_compile_unres(&ctx), error);
Radek Krejci474f9b82019-07-24 11:36:37 +02008506
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008507 /* validate non-instantiated groupings from the parsed schema,
8508 * without it we would accept even the schemas with invalid grouping specification */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008509 ctx.pmod = sp;
Radek Krejci90d4e922020-10-12 15:55:33 +02008510 ctx.options |= LYS_COMPILE_GROUPING;
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008511 LY_ARRAY_FOR(sp->groupings, u) {
8512 if (!(sp->groupings[u].flags & LYS_USED_GRP)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008513 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &sp->groupings[u]), error);
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008514 }
8515 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02008516 LY_LIST_FOR(sp->data, pnode) {
8517 grps = (struct lysp_grp *)lysp_node_groupings(pnode);
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008518 LY_ARRAY_FOR(grps, u) {
8519 if (!(grps[u].flags & LYS_USED_GRP)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008520 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &grps[u]), error);
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008521 }
8522 }
8523 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02008524 LY_ARRAY_FOR(sp->includes, u) {
8525 submod = sp->includes[u].submodule;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008526 ctx.pmod = (struct lysp_module *)submod;
8527
Michal Vasko7f45cf22020-10-01 12:49:44 +02008528 LY_ARRAY_FOR(submod->groupings, u) {
8529 if (!(submod->groupings[u].flags & LYS_USED_GRP)) {
8530 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &submod->groupings[u]), error);
8531 }
8532 }
8533 LY_LIST_FOR(submod->data, pnode) {
8534 grps = (struct lysp_grp *)lysp_node_groupings(pnode);
8535 LY_ARRAY_FOR(grps, u) {
8536 if (!(grps[u].flags & LYS_USED_GRP)) {
8537 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &grps[u]), error);
8538 }
8539 }
8540 }
Radek Krejci474f9b82019-07-24 11:36:37 +02008541 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008542 ctx.pmod = sp;
Radek Krejci474f9b82019-07-24 11:36:37 +02008543
Michal Vasko8d544252020-03-02 10:19:52 +01008544#if 0
8545 /* hack for NETCONF's edit-config's operation attribute. It is not defined in the schema, but since libyang
8546 * implements YANG metadata (annotations), we need its definition. Because the ietf-netconf schema is not the
8547 * internal part of libyang, we cannot add the annotation into the schema source, but we do it here to have
8548 * the anotation definitions available in the internal schema structure. */
8549 if (ly_strequal(mod->name, "ietf-netconf", 0)) {
8550 if (lyp_add_ietf_netconf_annotations(mod)) {
8551 lys_free(mod, NULL, 1, 1);
8552 return NULL;
8553 }
8554 }
8555#endif
8556
8557 /* add ietf-netconf-with-defaults "default" metadata to the compiled module */
Michal Vasko7a0b0762020-09-02 16:37:01 +02008558 if (!strcmp(mod->name, "ietf-netconf-with-defaults")) {
8559 LY_CHECK_GOTO(ret = lys_compile_ietf_netconf_wd_annotation(&ctx, mod), error);
Michal Vasko8d544252020-03-02 10:19:52 +01008560 }
8561
Michal Vasko7f45cf22020-10-01 12:49:44 +02008562 /* there can be no leftover deviations */
8563 LY_CHECK_ERR_GOTO(ctx.devs.count, LOGINT(ctx.ctx); ret = LY_EINT, error);
8564
8565 for (i = 0; i < ctx.dflts.count; ++i) {
8566 lysc_unres_dflt_free(ctx.ctx, ctx.dflts.objs[i]);
8567 }
8568 ly_set_erase(&ctx.dflts, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +02008569 ly_set_erase(&ctx.xpath, NULL);
8570 ly_set_erase(&ctx.leafrefs, NULL);
Radek Krejcie86bf772018-12-14 11:39:53 +01008571 ly_set_erase(&ctx.groupings, NULL);
Radek Krejci99b5b2a2019-04-30 16:57:04 +02008572 ly_set_erase(&ctx.tpdf_chain, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02008573 ly_set_erase(&ctx.augs, NULL);
8574 ly_set_erase(&ctx.devs, NULL);
8575 ly_set_erase(&ctx.uses_augs, NULL);
8576 ly_set_erase(&ctx.uses_rfns, NULL);
Radek Krejcia3045382018-11-22 14:30:31 +01008577
Radek Krejci19a96102018-11-15 13:38:09 +01008578 return LY_SUCCESS;
8579
8580error:
Michal Vasko89b5c072020-10-06 13:52:44 +02008581 lys_precompile_augments_deviations_revert(ctx.ctx, mod);
Michal Vasko7a0b0762020-09-02 16:37:01 +02008582 lys_feature_precompile_revert(&ctx, mod);
Michal Vasko7f45cf22020-10-01 12:49:44 +02008583 for (i = 0; i < ctx.dflts.count; ++i) {
8584 lysc_unres_dflt_free(ctx.ctx, ctx.dflts.objs[i]);
8585 }
8586 ly_set_erase(&ctx.dflts, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +02008587 ly_set_erase(&ctx.xpath, NULL);
8588 ly_set_erase(&ctx.leafrefs, NULL);
Radek Krejcie86bf772018-12-14 11:39:53 +01008589 ly_set_erase(&ctx.groupings, NULL);
Radek Krejci99b5b2a2019-04-30 16:57:04 +02008590 ly_set_erase(&ctx.tpdf_chain, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02008591 for (i = 0; i < ctx.augs.count; ++i) {
8592 lysc_augment_free(ctx.ctx, ctx.augs.objs[i]);
8593 }
8594 ly_set_erase(&ctx.augs, NULL);
8595 for (i = 0; i < ctx.devs.count; ++i) {
8596 lysc_deviation_free(ctx.ctx, ctx.devs.objs[i]);
8597 }
8598 ly_set_erase(&ctx.devs, NULL);
8599 for (i = 0; i < ctx.uses_augs.count; ++i) {
8600 lysc_augment_free(ctx.ctx, ctx.uses_augs.objs[i]);
8601 }
8602 ly_set_erase(&ctx.uses_augs, NULL);
8603 for (i = 0; i < ctx.uses_rfns.count; ++i) {
8604 lysc_refine_free(ctx.ctx, ctx.uses_rfns.objs[i]);
8605 }
8606 ly_set_erase(&ctx.uses_rfns, NULL);
Radek Krejci19a96102018-11-15 13:38:09 +01008607 lysc_module_free(mod_c, NULL);
Michal Vasko7a0b0762020-09-02 16:37:01 +02008608 mod->compiled = NULL;
Radek Krejci95710c92019-02-11 15:49:55 +01008609
Radek Krejci19a96102018-11-15 13:38:09 +01008610 return ret;
8611}