blob: 5016286ecd5114a4b54f929828c4e42f87a3d5cc [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/**
Radek Krejci58d171e2018-11-23 13:50:55 +01002489 * @brief Check the features used in if-feature statements applicable to the leafref and its target.
2490 *
2491 * The set of features used for target must be a subset of features used for the leafref.
2492 * This is not a perfect, we should compare the truth tables but it could require too much resources
2493 * and RFC 7950 does not require it explicitely, so we simplify that.
2494 *
2495 * @param[in] refnode The leafref node.
2496 * @param[in] target Tha target node of the leafref.
2497 * @return LY_SUCCESS or LY_EVALID;
2498 */
2499static LY_ERR
2500lys_compile_leafref_features_validate(const struct lysc_node *refnode, const struct lysc_node *target)
2501{
2502 LY_ERR ret = LY_EVALID;
2503 const struct lysc_node *iter;
Radek Krejci1deb5be2020-08-26 16:43:36 +02002504 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci58d171e2018-11-23 13:50:55 +01002505 struct ly_set features = {0};
2506
2507 for (iter = refnode; iter; iter = iter->parent) {
Radek Krejci056d0a82018-12-06 16:57:25 +01002508 if (iter->iffeatures) {
2509 LY_ARRAY_FOR(iter->iffeatures, u) {
2510 LY_ARRAY_FOR(iter->iffeatures[u].features, v) {
Radek Krejciba03a5a2020-08-27 14:40:41 +02002511 LY_CHECK_GOTO(ly_set_add(&features, iter->iffeatures[u].features[v], 0, NULL), cleanup);
Radek Krejci58d171e2018-11-23 13:50:55 +01002512 }
2513 }
2514 }
2515 }
2516
2517 /* we should have, in features set, a superset of features applicable to the target node.
Radek Krejciba03a5a2020-08-27 14:40:41 +02002518 * If the feature is not present, we don;t have a subset of features applicable
Radek Krejci58d171e2018-11-23 13:50:55 +01002519 * to the leafref itself. */
Radek Krejci58d171e2018-11-23 13:50:55 +01002520 for (iter = target; iter; iter = iter->parent) {
Radek Krejci056d0a82018-12-06 16:57:25 +01002521 if (iter->iffeatures) {
2522 LY_ARRAY_FOR(iter->iffeatures, u) {
2523 LY_ARRAY_FOR(iter->iffeatures[u].features, v) {
Radek Krejciba03a5a2020-08-27 14:40:41 +02002524 if (!ly_set_contains(&features, iter->iffeatures[u].features[v], NULL)) {
2525 /* feature not present */
Radek Krejci58d171e2018-11-23 13:50:55 +01002526 goto cleanup;
2527 }
2528 }
2529 }
2530 }
2531 }
2532 ret = LY_SUCCESS;
2533
2534cleanup:
2535 ly_set_erase(&features, NULL);
2536 return ret;
2537}
2538
Michal Vasko7f45cf22020-10-01 12:49:44 +02002539static 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 +02002540 struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p,
Michal Vasko7f45cf22020-10-01 12:49:44 +02002541 struct lysc_type **type, const char **units, struct lysp_qname **dflt);
Radek Krejcia3045382018-11-22 14:30:31 +01002542
Radek Krejcia3045382018-11-22 14:30:31 +01002543/**
2544 * @brief The core of the lys_compile_type() - compile information about the given type (from typedef or leaf/leaf-list).
2545 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02002546 * @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 +01002547 * @param[in] context_flags Flags of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
2548 * @param[in] context_mod Module of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
2549 * @param[in] context_name Name of the context node or referencing typedef for logging.
Radek Krejcia3045382018-11-22 14:30:31 +01002550 * @param[in] type_p Parsed type to compile.
2551 * @param[in] basetype Base YANG built-in type of the type to compile.
Radek Krejcia3045382018-11-22 14:30:31 +01002552 * @param[in] tpdfname Name of the type's typedef, serves as a flag - if it is leaf/leaf-list's type, it is NULL.
2553 * @param[in] base The latest base (compiled) type from which the current type is being derived.
2554 * @param[out] type Newly created type structure with the filled information about the type.
2555 * @return LY_ERR value.
2556 */
Radek Krejci19a96102018-11-15 13:38:09 +01002557static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02002558lys_compile_type_(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags,
Michal Vaskoe9c050f2020-10-06 14:01:23 +02002559 struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p, LY_DATA_TYPE basetype,
2560 const char *tpdfname, struct lysc_type *base, struct lysc_type **type)
Radek Krejcic5c27e52018-11-15 14:38:11 +01002561{
2562 LY_ERR ret = LY_SUCCESS;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002563 struct lysc_type_bin *bin;
2564 struct lysc_type_num *num;
2565 struct lysc_type_str *str;
2566 struct lysc_type_bits *bits;
2567 struct lysc_type_enum *enumeration;
Radek Krejci6cba4292018-11-15 17:33:29 +01002568 struct lysc_type_dec *dec;
Radek Krejci555cb5b2018-11-16 14:54:33 +01002569 struct lysc_type_identityref *idref;
Michal Vasko004d3152020-06-11 19:59:22 +02002570 struct lysc_type_leafref *lref;
Radek Krejcicdfecd92018-11-26 11:27:32 +01002571 struct lysc_type_union *un, *un_aux;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002572
2573 switch (basetype) {
2574 case LY_TYPE_BINARY:
Michal Vasko22df3f02020-08-24 13:29:22 +02002575 bin = (struct lysc_type_bin *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002576
2577 /* RFC 7950 9.8.1, 9.4.4 - length, number of octets it contains */
Radek Krejcic5c27e52018-11-15 14:38:11 +01002578 if (type_p->length) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002579 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->length, basetype, 1, 0,
Michal Vasko69730152020-10-09 16:30:07 +02002580 base ? ((struct lysc_type_bin *)base)->length : NULL, &bin->length));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002581 if (!tpdfname) {
Michal Vasko1734be92020-09-22 08:55:10 +02002582 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 +01002583 }
2584 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002585 break;
2586 case LY_TYPE_BITS:
2587 /* RFC 7950 9.7 - bits */
Michal Vasko22df3f02020-08-24 13:29:22 +02002588 bits = (struct lysc_type_bits *)(*type);
Radek Krejcic5c27e52018-11-15 14:38:11 +01002589 if (type_p->bits) {
Radek Krejciec4da802019-05-02 13:02:41 +02002590 LY_CHECK_RET(lys_compile_type_enums(ctx, type_p->bits, basetype,
Michal Vasko69730152020-10-09 16:30:07 +02002591 base ? (struct lysc_type_bitenum_item *)((struct lysc_type_bits *)base)->bits : NULL,
Michal Vasko22df3f02020-08-24 13:29:22 +02002592 (struct lysc_type_bitenum_item **)&bits->bits));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002593 }
2594
Radek Krejci555cb5b2018-11-16 14:54:33 +01002595 if (!base && !type_p->flags) {
Radek Krejcic5c27e52018-11-15 14:38:11 +01002596 /* type derived from bits built-in type must contain at least one bit */
Radek Krejci6cba4292018-11-15 17:33:29 +01002597 if (tpdfname) {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002598 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "bit", "bits type ", tpdfname);
Radek Krejci6cba4292018-11-15 17:33:29 +01002599 } else {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002600 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "bit", "bits type", "");
Radek Krejcic5c27e52018-11-15 14:38:11 +01002601 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002602 return LY_EVALID;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002603 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002604 break;
Radek Krejci6cba4292018-11-15 17:33:29 +01002605 case LY_TYPE_DEC64:
Radek Krejci115a74d2020-08-14 22:18:12 +02002606 dec = (struct lysc_type_dec *)(*type);
Radek Krejci6cba4292018-11-15 17:33:29 +01002607
2608 /* RFC 7950 9.3.4 - fraction-digits */
Radek Krejci555cb5b2018-11-16 14:54:33 +01002609 if (!base) {
Radek Krejci643c8242018-11-15 17:51:11 +01002610 if (!type_p->fraction_digits) {
2611 if (tpdfname) {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002612 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "fraction-digits", "decimal64 type ", tpdfname);
Radek Krejci643c8242018-11-15 17:51:11 +01002613 } else {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002614 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "fraction-digits", "decimal64 type", "");
Radek Krejci643c8242018-11-15 17:51:11 +01002615 }
2616 return LY_EVALID;
2617 }
Radek Krejci115a74d2020-08-14 22:18:12 +02002618 dec->fraction_digits = type_p->fraction_digits;
2619 } else {
2620 if (type_p->fraction_digits) {
2621 /* fraction digits is prohibited in types not directly derived from built-in decimal64 */
2622 if (tpdfname) {
2623 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002624 "Invalid fraction-digits substatement for type \"%s\" not directly derived from decimal64 built-in type.",
2625 tpdfname);
Radek Krejci115a74d2020-08-14 22:18:12 +02002626 } else {
2627 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002628 "Invalid fraction-digits substatement for type not directly derived from decimal64 built-in type.");
Radek Krejci115a74d2020-08-14 22:18:12 +02002629 }
2630 return LY_EVALID;
Radek Krejci6cba4292018-11-15 17:33:29 +01002631 }
Radek Krejci115a74d2020-08-14 22:18:12 +02002632 dec->fraction_digits = ((struct lysc_type_dec *)base)->fraction_digits;
Radek Krejci6cba4292018-11-15 17:33:29 +01002633 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002634
2635 /* RFC 7950 9.2.4 - range */
2636 if (type_p->range) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002637 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->range, basetype, 0, dec->fraction_digits,
Michal Vasko69730152020-10-09 16:30:07 +02002638 base ? ((struct lysc_type_dec *)base)->range : NULL, &dec->range));
Radek Krejci6cba4292018-11-15 17:33:29 +01002639 if (!tpdfname) {
Michal Vasko1734be92020-09-22 08:55:10 +02002640 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 +01002641 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002642 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002643 break;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002644 case LY_TYPE_STRING:
Michal Vasko22df3f02020-08-24 13:29:22 +02002645 str = (struct lysc_type_str *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002646
2647 /* RFC 7950 9.4.4 - length */
Radek Krejcic5c27e52018-11-15 14:38:11 +01002648 if (type_p->length) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002649 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->length, basetype, 1, 0,
Michal Vasko69730152020-10-09 16:30:07 +02002650 base ? ((struct lysc_type_str *)base)->length : NULL, &str->length));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002651 if (!tpdfname) {
Michal Vasko1734be92020-09-22 08:55:10 +02002652 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 +01002653 }
Michal Vasko22df3f02020-08-24 13:29:22 +02002654 } else if (base && ((struct lysc_type_str *)base)->length) {
2655 str->length = lysc_range_dup(ctx->ctx, ((struct lysc_type_str *)base)->length);
Radek Krejcic5c27e52018-11-15 14:38:11 +01002656 }
2657
2658 /* RFC 7950 9.4.5 - pattern */
2659 if (type_p->patterns) {
Radek Krejciec4da802019-05-02 13:02:41 +02002660 LY_CHECK_RET(lys_compile_type_patterns(ctx, type_p->patterns,
Michal Vasko69730152020-10-09 16:30:07 +02002661 base ? ((struct lysc_type_str *)base)->patterns : NULL, &str->patterns));
Michal Vasko22df3f02020-08-24 13:29:22 +02002662 } else if (base && ((struct lysc_type_str *)base)->patterns) {
2663 str->patterns = lysc_patterns_dup(ctx->ctx, ((struct lysc_type_str *)base)->patterns);
Radek Krejcic5c27e52018-11-15 14:38:11 +01002664 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002665 break;
2666 case LY_TYPE_ENUM:
Michal Vasko22df3f02020-08-24 13:29:22 +02002667 enumeration = (struct lysc_type_enum *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002668
2669 /* RFC 7950 9.6 - enum */
Radek Krejcic5c27e52018-11-15 14:38:11 +01002670 if (type_p->enums) {
Radek Krejciec4da802019-05-02 13:02:41 +02002671 LY_CHECK_RET(lys_compile_type_enums(ctx, type_p->enums, basetype,
Michal Vasko69730152020-10-09 16:30:07 +02002672 base ? ((struct lysc_type_enum *)base)->enums : NULL, &enumeration->enums));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002673 }
2674
Radek Krejci555cb5b2018-11-16 14:54:33 +01002675 if (!base && !type_p->flags) {
Radek Krejcic5c27e52018-11-15 14:38:11 +01002676 /* type derived from enumerations built-in type must contain at least one enum */
Radek Krejci6cba4292018-11-15 17:33:29 +01002677 if (tpdfname) {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002678 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "enum", "enumeration type ", tpdfname);
Radek Krejci6cba4292018-11-15 17:33:29 +01002679 } else {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002680 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "enum", "enumeration type", "");
Radek Krejcic5c27e52018-11-15 14:38:11 +01002681 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002682 return LY_EVALID;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002683 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002684 break;
2685 case LY_TYPE_INT8:
2686 case LY_TYPE_UINT8:
2687 case LY_TYPE_INT16:
2688 case LY_TYPE_UINT16:
2689 case LY_TYPE_INT32:
2690 case LY_TYPE_UINT32:
2691 case LY_TYPE_INT64:
2692 case LY_TYPE_UINT64:
Michal Vasko22df3f02020-08-24 13:29:22 +02002693 num = (struct lysc_type_num *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002694
2695 /* RFC 6020 9.2.4 - range */
Radek Krejcic5c27e52018-11-15 14:38:11 +01002696 if (type_p->range) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002697 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->range, basetype, 0, 0,
Michal Vasko69730152020-10-09 16:30:07 +02002698 base ? ((struct lysc_type_num *)base)->range : NULL, &num->range));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002699 if (!tpdfname) {
Michal Vasko1734be92020-09-22 08:55:10 +02002700 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 +01002701 }
2702 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002703 break;
Radek Krejci555cb5b2018-11-16 14:54:33 +01002704 case LY_TYPE_IDENT:
Michal Vasko22df3f02020-08-24 13:29:22 +02002705 idref = (struct lysc_type_identityref *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002706
2707 /* RFC 7950 9.10.2 - base */
2708 if (type_p->bases) {
2709 if (base) {
2710 /* only the directly derived identityrefs can contain base specification */
2711 if (tpdfname) {
2712 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002713 "Invalid base substatement for the type \"%s\" not directly derived from identityref built-in type.",
2714 tpdfname);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002715 } else {
2716 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002717 "Invalid base substatement for the type not directly derived from identityref built-in type.");
Radek Krejci555cb5b2018-11-16 14:54:33 +01002718 }
2719 return LY_EVALID;
2720 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +02002721 LY_CHECK_RET(lys_compile_identity_bases(ctx, type_p->pmod, type_p->bases, NULL, &idref->bases));
Radek Krejci555cb5b2018-11-16 14:54:33 +01002722 }
2723
2724 if (!base && !type_p->flags) {
2725 /* type derived from identityref built-in type must contain at least one base */
2726 if (tpdfname) {
2727 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "base", "identityref type ", tpdfname);
2728 } else {
2729 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "base", "identityref type", "");
Radek Krejci555cb5b2018-11-16 14:54:33 +01002730 }
2731 return LY_EVALID;
2732 }
Radek Krejci555cb5b2018-11-16 14:54:33 +01002733 break;
Radek Krejcia3045382018-11-22 14:30:31 +01002734 case LY_TYPE_LEAFREF:
Michal Vasko22df3f02020-08-24 13:29:22 +02002735 lref = (struct lysc_type_leafref *)*type;
Michal Vasko004d3152020-06-11 19:59:22 +02002736
Radek Krejcia3045382018-11-22 14:30:31 +01002737 /* RFC 7950 9.9.3 - require-instance */
2738 if (type_p->flags & LYS_SET_REQINST) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02002739 if (context_mod->version < LYS_VERSION_1_1) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01002740 if (tpdfname) {
2741 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02002742 "Leafref type \"%s\" can be restricted by require-instance statement only in YANG 1.1 modules.", tpdfname);
Radek Krejci9bb94eb2018-12-04 16:48:35 +01002743 } else {
2744 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02002745 "Leafref type can be restricted by require-instance statement only in YANG 1.1 modules.");
Radek Krejci9bb94eb2018-12-04 16:48:35 +01002746 }
2747 return LY_EVALID;
2748 }
Michal Vasko004d3152020-06-11 19:59:22 +02002749 lref->require_instance = type_p->require_instance;
Radek Krejci412ddfa2018-11-23 11:44:11 +01002750 } else if (base) {
2751 /* inherit */
Michal Vasko004d3152020-06-11 19:59:22 +02002752 lref->require_instance = ((struct lysc_type_leafref *)base)->require_instance;
Radek Krejcia3045382018-11-22 14:30:31 +01002753 } else {
2754 /* default is true */
Michal Vasko004d3152020-06-11 19:59:22 +02002755 lref->require_instance = 1;
Radek Krejcia3045382018-11-22 14:30:31 +01002756 }
2757 if (type_p->path) {
Michal Vasko1734be92020-09-22 08:55:10 +02002758 LY_CHECK_RET(lyxp_expr_dup(ctx->ctx, type_p->path, &lref->path));
Michal Vasko5d24f6c2020-10-13 13:49:06 +02002759 LY_CHECK_RET(lysc_prefixes_compile(type_p->path->expr, strlen(type_p->path->expr), type_p->pmod,
2760 &lref->prefixes));
Radek Krejcia3045382018-11-22 14:30:31 +01002761 } else if (base) {
Michal Vasko1734be92020-09-22 08:55:10 +02002762 LY_CHECK_RET(lyxp_expr_dup(ctx->ctx, ((struct lysc_type_leafref *)base)->path, &lref->path));
Michal Vasko5d24f6c2020-10-13 13:49:06 +02002763 LY_CHECK_RET(lysc_prefixes_dup(((struct lysc_type_leafref *)base)->prefixes, &lref->prefixes));
Radek Krejcia3045382018-11-22 14:30:31 +01002764 } else if (tpdfname) {
2765 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "path", "leafref type ", tpdfname);
2766 return LY_EVALID;
2767 } else {
2768 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "path", "leafref type", "");
Radek Krejcia3045382018-11-22 14:30:31 +01002769 return LY_EVALID;
2770 }
Radek Krejcia3045382018-11-22 14:30:31 +01002771 break;
Radek Krejci16c0f822018-11-16 10:46:10 +01002772 case LY_TYPE_INST:
2773 /* RFC 7950 9.9.3 - require-instance */
2774 if (type_p->flags & LYS_SET_REQINST) {
Michal Vasko22df3f02020-08-24 13:29:22 +02002775 ((struct lysc_type_instanceid *)(*type))->require_instance = type_p->require_instance;
Radek Krejci16c0f822018-11-16 10:46:10 +01002776 } else {
2777 /* default is true */
Michal Vasko22df3f02020-08-24 13:29:22 +02002778 ((struct lysc_type_instanceid *)(*type))->require_instance = 1;
Radek Krejci16c0f822018-11-16 10:46:10 +01002779 }
Radek Krejci16c0f822018-11-16 10:46:10 +01002780 break;
Radek Krejcicdfecd92018-11-26 11:27:32 +01002781 case LY_TYPE_UNION:
Michal Vasko22df3f02020-08-24 13:29:22 +02002782 un = (struct lysc_type_union *)(*type);
Radek Krejcicdfecd92018-11-26 11:27:32 +01002783
2784 /* RFC 7950 7.4 - type */
2785 if (type_p->types) {
2786 if (base) {
2787 /* only the directly derived union can contain types specification */
2788 if (tpdfname) {
2789 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002790 "Invalid type substatement for the type \"%s\" not directly derived from union built-in type.",
2791 tpdfname);
Radek Krejcicdfecd92018-11-26 11:27:32 +01002792 } else {
2793 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002794 "Invalid type substatement for the type not directly derived from union built-in type.");
Radek Krejcicdfecd92018-11-26 11:27:32 +01002795 }
2796 return LY_EVALID;
2797 }
2798 /* compile the type */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002799 LY_ARRAY_CREATE_RET(ctx->ctx, un->types, LY_ARRAY_COUNT(type_p->types), LY_EVALID);
2800 for (LY_ARRAY_COUNT_TYPE u = 0, additional = 0; u < LY_ARRAY_COUNT(type_p->types); ++u) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02002801 LY_CHECK_RET(lys_compile_type(ctx, context_pnode, context_flags, context_mod, context_name,
Michal Vasko69730152020-10-09 16:30:07 +02002802 &type_p->types[u], &un->types[u + additional], NULL, NULL));
Radek Krejcicdfecd92018-11-26 11:27:32 +01002803 if (un->types[u + additional]->basetype == LY_TYPE_UNION) {
2804 /* add space for additional types from the union subtype */
2805 un_aux = (struct lysc_type_union *)un->types[u + additional];
Michal Vasko22df3f02020-08-24 13:29:22 +02002806 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 +02002807 lysc_type_free(ctx->ctx, (struct lysc_type *)un_aux), LY_EMEM);
Radek Krejcicdfecd92018-11-26 11:27:32 +01002808
2809 /* copy subtypes of the subtype union */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002810 for (LY_ARRAY_COUNT_TYPE v = 0; v < LY_ARRAY_COUNT(un_aux->types); ++v) {
Radek Krejcicdfecd92018-11-26 11:27:32 +01002811 if (un_aux->types[v]->basetype == LY_TYPE_LEAFREF) {
2812 /* duplicate the whole structure because of the instance-specific path resolving for realtype */
2813 un->types[u + additional] = calloc(1, sizeof(struct lysc_type_leafref));
Michal Vasko22df3f02020-08-24 13:29:22 +02002814 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 +02002815 lref = (struct lysc_type_leafref *)un->types[u + additional];
2816
2817 lref->basetype = LY_TYPE_LEAFREF;
Michal Vasko1734be92020-09-22 08:55:10 +02002818 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 +02002819 lref->refcount = 1;
Michal Vasko22df3f02020-08-24 13:29:22 +02002820 lref->require_instance = ((struct lysc_type_leafref *)un_aux->types[v])->require_instance;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02002821 LY_CHECK_RET(lysc_prefixes_dup(((struct lysc_type_leafref *)un_aux->types[v])->prefixes,
2822 &lref->prefixes));
Radek Krejcicdfecd92018-11-26 11:27:32 +01002823 /* TODO extensions */
2824
2825 } else {
2826 un->types[u + additional] = un_aux->types[v];
2827 ++un_aux->types[v]->refcount;
2828 }
2829 ++additional;
2830 LY_ARRAY_INCREMENT(un->types);
2831 }
2832 /* compensate u increment in main loop */
2833 --additional;
2834
2835 /* free the replaced union subtype */
Michal Vasko22df3f02020-08-24 13:29:22 +02002836 lysc_type_free(ctx->ctx, (struct lysc_type *)un_aux);
Radek Krejcicdfecd92018-11-26 11:27:32 +01002837 } else {
2838 LY_ARRAY_INCREMENT(un->types);
2839 }
Radek Krejcicdfecd92018-11-26 11:27:32 +01002840 }
2841 }
2842
2843 if (!base && !type_p->flags) {
2844 /* type derived from union built-in type must contain at least one type */
2845 if (tpdfname) {
2846 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "type", "union type ", tpdfname);
2847 } else {
2848 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "type", "union type", "");
Radek Krejcicdfecd92018-11-26 11:27:32 +01002849 }
2850 return LY_EVALID;
2851 }
Radek Krejcicdfecd92018-11-26 11:27:32 +01002852 break;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002853 case LY_TYPE_BOOL:
2854 case LY_TYPE_EMPTY:
2855 case LY_TYPE_UNKNOWN: /* just to complete switch */
2856 break;
2857 }
Michal Vasko1734be92020-09-22 08:55:10 +02002858
2859 if (tpdfname) {
2860 switch (basetype) {
2861 case LY_TYPE_BINARY:
2862 type_p->compiled = *type;
2863 *type = calloc(1, sizeof(struct lysc_type_bin));
2864 break;
2865 case LY_TYPE_BITS:
2866 type_p->compiled = *type;
2867 *type = calloc(1, sizeof(struct lysc_type_bits));
2868 break;
2869 case LY_TYPE_DEC64:
2870 type_p->compiled = *type;
2871 *type = calloc(1, sizeof(struct lysc_type_dec));
2872 break;
2873 case LY_TYPE_STRING:
2874 type_p->compiled = *type;
2875 *type = calloc(1, sizeof(struct lysc_type_str));
2876 break;
2877 case LY_TYPE_ENUM:
2878 type_p->compiled = *type;
2879 *type = calloc(1, sizeof(struct lysc_type_enum));
2880 break;
2881 case LY_TYPE_INT8:
2882 case LY_TYPE_UINT8:
2883 case LY_TYPE_INT16:
2884 case LY_TYPE_UINT16:
2885 case LY_TYPE_INT32:
2886 case LY_TYPE_UINT32:
2887 case LY_TYPE_INT64:
2888 case LY_TYPE_UINT64:
2889 type_p->compiled = *type;
2890 *type = calloc(1, sizeof(struct lysc_type_num));
2891 break;
2892 case LY_TYPE_IDENT:
2893 type_p->compiled = *type;
2894 *type = calloc(1, sizeof(struct lysc_type_identityref));
2895 break;
2896 case LY_TYPE_LEAFREF:
2897 type_p->compiled = *type;
2898 *type = calloc(1, sizeof(struct lysc_type_leafref));
2899 break;
2900 case LY_TYPE_INST:
2901 type_p->compiled = *type;
2902 *type = calloc(1, sizeof(struct lysc_type_instanceid));
2903 break;
2904 case LY_TYPE_UNION:
2905 type_p->compiled = *type;
2906 *type = calloc(1, sizeof(struct lysc_type_union));
2907 break;
2908 case LY_TYPE_BOOL:
2909 case LY_TYPE_EMPTY:
2910 case LY_TYPE_UNKNOWN: /* just to complete switch */
2911 break;
2912 }
2913 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002914 LY_CHECK_ERR_RET(!(*type), LOGMEM(ctx->ctx), LY_EMEM);
Michal Vasko1734be92020-09-22 08:55:10 +02002915
2916cleanup:
Radek Krejcic5c27e52018-11-15 14:38:11 +01002917 return ret;
2918}
2919
Radek Krejcia3045382018-11-22 14:30:31 +01002920/**
2921 * @brief Compile information about the leaf/leaf-list's type.
2922 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02002923 * @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 +01002924 * @param[in] context_flags Flags of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
2925 * @param[in] context_mod Module of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
2926 * @param[in] context_name Name of the context node or referencing typedef for logging.
2927 * @param[in] type_p Parsed type to compile.
Radek Krejcia3045382018-11-22 14:30:31 +01002928 * @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 +01002929 * @param[out] units Storage for inheriting units value from the typedefs the current type derives from.
Michal Vaskoba99a3e2020-08-18 15:50:05 +02002930 * @param[out] dflt Default value for the type.
Radek Krejcia3045382018-11-22 14:30:31 +01002931 * @return LY_ERR value.
2932 */
Radek Krejcic5c27e52018-11-15 14:38:11 +01002933static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02002934lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags,
Radek Krejci0f969882020-08-21 16:56:47 +02002935 struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p,
Michal Vasko7f45cf22020-10-01 12:49:44 +02002936 struct lysc_type **type, const char **units, struct lysp_qname **dflt)
Radek Krejci19a96102018-11-15 13:38:09 +01002937{
2938 LY_ERR ret = LY_SUCCESS;
Radek Krejci857189e2020-09-01 13:26:36 +02002939 ly_bool dummyloops = 0;
Radek Krejci19a96102018-11-15 13:38:09 +01002940 struct type_context {
2941 const struct lysp_tpdf *tpdf;
2942 struct lysp_node *node;
2943 struct lysp_module *mod;
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002944 } *tctx, *tctx_prev = NULL, *tctx_iter;
Radek Krejci19a96102018-11-15 13:38:09 +01002945 LY_DATA_TYPE basetype = LY_TYPE_UNKNOWN;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002946 struct lysc_type *base = NULL, *prev_type;
Radek Krejci19a96102018-11-15 13:38:09 +01002947 struct ly_set tpdf_chain = {0};
Michal Vaskoba99a3e2020-08-18 15:50:05 +02002948
Radek Krejci19a96102018-11-15 13:38:09 +01002949 (*type) = NULL;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02002950 if (dflt) {
2951 *dflt = NULL;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02002952 }
Radek Krejci19a96102018-11-15 13:38:09 +01002953
2954 tctx = calloc(1, sizeof *tctx);
2955 LY_CHECK_ERR_RET(!tctx, LOGMEM(ctx->ctx), LY_EMEM);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02002956 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 +01002957 ret == LY_SUCCESS;
2958 ret = lysp_type_find(tctx_prev->tpdf->type.name, tctx_prev->node, tctx_prev->mod,
Michal Vasko69730152020-10-09 16:30:07 +02002959 &basetype, &tctx->tpdf, &tctx->node, &tctx->mod)) {
Radek Krejci19a96102018-11-15 13:38:09 +01002960 if (basetype) {
2961 break;
2962 }
2963
2964 /* check status */
Radek Krejcicdfecd92018-11-26 11:27:32 +01002965 ret = lysc_check_status(ctx, context_flags, context_mod, context_name,
Michal Vasko69730152020-10-09 16:30:07 +02002966 tctx->tpdf->flags, tctx->mod, tctx->node ? tctx->node->name : tctx->tpdf->name);
Radek Krejci87e25252020-09-15 13:28:31 +02002967 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01002968
Radek Krejcicdfecd92018-11-26 11:27:32 +01002969 if (units && !*units) {
2970 /* inherit units */
Radek Krejci87e25252020-09-15 13:28:31 +02002971 DUP_STRING(ctx->ctx, tctx->tpdf->units, *units, ret);
2972 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
Radek Krejcicdfecd92018-11-26 11:27:32 +01002973 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02002974 if (dflt && !*dflt && tctx->tpdf->dflt.str) {
Radek Krejcicdfecd92018-11-26 11:27:32 +01002975 /* inherit default */
Michal Vasko7f45cf22020-10-01 12:49:44 +02002976 *dflt = (struct lysp_qname *)&tctx->tpdf->dflt;
Radek Krejcicdfecd92018-11-26 11:27:32 +01002977 }
Michal Vaskoba99a3e2020-08-18 15:50:05 +02002978 if (dummyloops && (!units || *units) && dflt && *dflt) {
Michal Vasko22df3f02020-08-24 13:29:22 +02002979 basetype = ((struct type_context *)tpdf_chain.objs[tpdf_chain.count - 1])->tpdf->type.compiled->basetype;
Radek Krejcicdfecd92018-11-26 11:27:32 +01002980 break;
2981 }
2982
Radek Krejci19a96102018-11-15 13:38:09 +01002983 if (tctx->tpdf->type.compiled) {
Radek Krejcicdfecd92018-11-26 11:27:32 +01002984 /* it is not necessary to continue, the rest of the chain was already compiled,
2985 * but we still may need to inherit default and units values, so start dummy loops */
Radek Krejci19a96102018-11-15 13:38:09 +01002986 basetype = tctx->tpdf->type.compiled->basetype;
Radek Krejci3d92e442020-10-12 12:48:13 +02002987 ret = ly_set_add(&tpdf_chain, tctx, 1, NULL);
Radek Krejci87e25252020-09-15 13:28:31 +02002988 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
Radek Krejciba03a5a2020-08-27 14:40:41 +02002989
Michal Vaskoba99a3e2020-08-18 15:50:05 +02002990 if ((units && !*units) || (dflt && !*dflt)) {
Radek Krejcicdfecd92018-11-26 11:27:32 +01002991 dummyloops = 1;
2992 goto preparenext;
2993 } else {
2994 tctx = NULL;
2995 break;
2996 }
Radek Krejci19a96102018-11-15 13:38:09 +01002997 }
2998
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002999 /* circular typedef reference detection */
Radek Krejci1deb5be2020-08-26 16:43:36 +02003000 for (uint32_t u = 0; u < tpdf_chain.count; u++) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003001 /* local part */
Michal Vasko22df3f02020-08-24 13:29:22 +02003002 tctx_iter = (struct type_context *)tpdf_chain.objs[u];
Michal Vasko69730152020-10-09 16:30:07 +02003003 if ((tctx_iter->mod == tctx->mod) && (tctx_iter->node == tctx->node) && (tctx_iter->tpdf == tctx->tpdf)) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003004 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02003005 "Invalid \"%s\" type reference - circular chain of types detected.", tctx->tpdf->name);
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003006 free(tctx);
3007 ret = LY_EVALID;
3008 goto cleanup;
3009 }
3010 }
Radek Krejci1deb5be2020-08-26 16:43:36 +02003011 for (uint32_t u = 0; u < ctx->tpdf_chain.count; u++) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003012 /* global part for unions corner case */
Michal Vasko22df3f02020-08-24 13:29:22 +02003013 tctx_iter = (struct type_context *)ctx->tpdf_chain.objs[u];
Michal Vasko69730152020-10-09 16:30:07 +02003014 if ((tctx_iter->mod == tctx->mod) && (tctx_iter->node == tctx->node) && (tctx_iter->tpdf == tctx->tpdf)) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003015 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02003016 "Invalid \"%s\" type reference - circular chain of types detected.", tctx->tpdf->name);
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003017 free(tctx);
3018 ret = LY_EVALID;
3019 goto cleanup;
3020 }
3021 }
3022
Radek Krejci19a96102018-11-15 13:38:09 +01003023 /* store information for the following processing */
Radek Krejci3d92e442020-10-12 12:48:13 +02003024 ret = ly_set_add(&tpdf_chain, tctx, 1, NULL);
Radek Krejci87e25252020-09-15 13:28:31 +02003025 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01003026
Radek Krejcicdfecd92018-11-26 11:27:32 +01003027preparenext:
Radek Krejci19a96102018-11-15 13:38:09 +01003028 /* prepare next loop */
3029 tctx_prev = tctx;
3030 tctx = calloc(1, sizeof *tctx);
3031 LY_CHECK_ERR_RET(!tctx, LOGMEM(ctx->ctx), LY_EMEM);
3032 }
3033 free(tctx);
3034
3035 /* allocate type according to the basetype */
3036 switch (basetype) {
3037 case LY_TYPE_BINARY:
3038 *type = calloc(1, sizeof(struct lysc_type_bin));
Radek Krejci19a96102018-11-15 13:38:09 +01003039 break;
3040 case LY_TYPE_BITS:
3041 *type = calloc(1, sizeof(struct lysc_type_bits));
Radek Krejci19a96102018-11-15 13:38:09 +01003042 break;
3043 case LY_TYPE_BOOL:
3044 case LY_TYPE_EMPTY:
3045 *type = calloc(1, sizeof(struct lysc_type));
3046 break;
3047 case LY_TYPE_DEC64:
3048 *type = calloc(1, sizeof(struct lysc_type_dec));
3049 break;
3050 case LY_TYPE_ENUM:
3051 *type = calloc(1, sizeof(struct lysc_type_enum));
Radek Krejci19a96102018-11-15 13:38:09 +01003052 break;
3053 case LY_TYPE_IDENT:
3054 *type = calloc(1, sizeof(struct lysc_type_identityref));
3055 break;
3056 case LY_TYPE_INST:
3057 *type = calloc(1, sizeof(struct lysc_type_instanceid));
3058 break;
3059 case LY_TYPE_LEAFREF:
3060 *type = calloc(1, sizeof(struct lysc_type_leafref));
3061 break;
3062 case LY_TYPE_STRING:
3063 *type = calloc(1, sizeof(struct lysc_type_str));
Radek Krejci19a96102018-11-15 13:38:09 +01003064 break;
3065 case LY_TYPE_UNION:
3066 *type = calloc(1, sizeof(struct lysc_type_union));
3067 break;
3068 case LY_TYPE_INT8:
3069 case LY_TYPE_UINT8:
3070 case LY_TYPE_INT16:
3071 case LY_TYPE_UINT16:
3072 case LY_TYPE_INT32:
3073 case LY_TYPE_UINT32:
3074 case LY_TYPE_INT64:
3075 case LY_TYPE_UINT64:
3076 *type = calloc(1, sizeof(struct lysc_type_num));
Radek Krejci19a96102018-11-15 13:38:09 +01003077 break;
3078 case LY_TYPE_UNKNOWN:
3079 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02003080 "Referenced type \"%s\" not found.", tctx_prev ? tctx_prev->tpdf->type.name : type_p->name);
Radek Krejci19a96102018-11-15 13:38:09 +01003081 ret = LY_EVALID;
3082 goto cleanup;
3083 }
3084 LY_CHECK_ERR_GOTO(!(*type), LOGMEM(ctx->ctx), cleanup);
Radek Krejcicdfecd92018-11-26 11:27:32 +01003085 if (~type_substmt_map[basetype] & type_p->flags) {
Radek Krejci19a96102018-11-15 13:38:09 +01003086 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid type restrictions for %s type.",
Michal Vasko69730152020-10-09 16:30:07 +02003087 ly_data_type2str[basetype]);
Radek Krejci19a96102018-11-15 13:38:09 +01003088 free(*type);
3089 (*type) = NULL;
3090 ret = LY_EVALID;
3091 goto cleanup;
3092 }
3093
3094 /* get restrictions from the referred typedefs */
Radek Krejci1deb5be2020-08-26 16:43:36 +02003095 for (uint32_t u = tpdf_chain.count - 1; u + 1 > 0; --u) {
Michal Vasko22df3f02020-08-24 13:29:22 +02003096 tctx = (struct type_context *)tpdf_chain.objs[u];
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003097
3098 /* remember the typedef context for circular check */
Radek Krejci3d92e442020-10-12 12:48:13 +02003099 ret = ly_set_add(&ctx->tpdf_chain, tctx, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003100 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003101
Radek Krejci43699232018-11-23 14:59:46 +01003102 if (tctx->tpdf->type.compiled) {
Radek Krejci19a96102018-11-15 13:38:09 +01003103 base = tctx->tpdf->type.compiled;
3104 continue;
Michal Vasko69730152020-10-09 16:30:07 +02003105 } else if ((basetype != LY_TYPE_LEAFREF) && (u != tpdf_chain.count - 1) && !(tctx->tpdf->type.flags)) {
Radek Krejci19a96102018-11-15 13:38:09 +01003106 /* no change, just use the type information from the base */
Michal Vasko22df3f02020-08-24 13:29:22 +02003107 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 +01003108 ++base->refcount;
3109 continue;
3110 }
3111
3112 ++(*type)->refcount;
Radek Krejci43699232018-11-23 14:59:46 +01003113 if (~type_substmt_map[basetype] & tctx->tpdf->type.flags) {
3114 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 +02003115 tctx->tpdf->name, ly_data_type2str[basetype]);
Radek Krejci43699232018-11-23 14:59:46 +01003116 ret = LY_EVALID;
3117 goto cleanup;
Michal Vasko69730152020-10-09 16:30:07 +02003118 } else if ((basetype == LY_TYPE_EMPTY) && tctx->tpdf->dflt.str) {
Radek Krejci43699232018-11-23 14:59:46 +01003119 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003120 "Invalid type \"%s\" - \"empty\" type must not have a default value (%s).",
3121 tctx->tpdf->name, tctx->tpdf->dflt.str);
Radek Krejci43699232018-11-23 14:59:46 +01003122 ret = LY_EVALID;
3123 goto cleanup;
3124 }
3125
Radek Krejci19a96102018-11-15 13:38:09 +01003126 (*type)->basetype = basetype;
Radek Krejcie7b95092019-05-15 11:03:07 +02003127 /* TODO user type plugins */
3128 (*type)->plugin = &ly_builtin_type_plugins[basetype];
Radek Krejcic5c27e52018-11-15 14:38:11 +01003129 prev_type = *type;
Michal Vaskoe9c050f2020-10-06 14:01:23 +02003130 ret = lys_compile_type_(ctx, tctx->node, tctx->tpdf->flags, tctx->mod, tctx->tpdf->name,
3131 &((struct lysp_tpdf *)tctx->tpdf)->type, basetype, tctx->tpdf->name, base, type);
Radek Krejcic5c27e52018-11-15 14:38:11 +01003132 LY_CHECK_GOTO(ret, cleanup);
3133 base = prev_type;
Radek Krejci19a96102018-11-15 13:38:09 +01003134 }
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003135 /* remove the processed typedef contexts from the stack for circular check */
3136 ctx->tpdf_chain.count = ctx->tpdf_chain.count - tpdf_chain.count;
Radek Krejci19a96102018-11-15 13:38:09 +01003137
Radek Krejcic5c27e52018-11-15 14:38:11 +01003138 /* process the type definition in leaf */
Michal Vasko69730152020-10-09 16:30:07 +02003139 if (type_p->flags || !base || (basetype == LY_TYPE_LEAFREF)) {
Radek Krejcia3045382018-11-22 14:30:31 +01003140 /* get restrictions from the node itself */
Radek Krejci19a96102018-11-15 13:38:09 +01003141 (*type)->basetype = basetype;
Radek Krejcie7b95092019-05-15 11:03:07 +02003142 /* TODO user type plugins */
3143 (*type)->plugin = &ly_builtin_type_plugins[basetype];
Radek Krejci19a96102018-11-15 13:38:09 +01003144 ++(*type)->refcount;
Michal Vaskoe9c050f2020-10-06 14:01:23 +02003145 ret = lys_compile_type_(ctx, context_pnode, context_flags, context_mod, context_name, type_p, basetype, NULL,
3146 base, type);
Radek Krejcic5c27e52018-11-15 14:38:11 +01003147 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko69730152020-10-09 16:30:07 +02003148 } else if ((basetype != LY_TYPE_BOOL) && (basetype != LY_TYPE_EMPTY)) {
Radek Krejci19a96102018-11-15 13:38:09 +01003149 /* no specific restriction in leaf's type definition, copy from the base */
3150 free(*type);
3151 (*type) = base;
3152 ++(*type)->refcount;
Radek Krejci19a96102018-11-15 13:38:09 +01003153 }
3154
Radek Krejci0935f412019-08-20 16:15:18 +02003155 COMPILE_EXTS_GOTO(ctx, type_p->exts, (*type)->exts, (*type), LYEXT_PAR_TYPE, ret, cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01003156
3157cleanup:
3158 ly_set_erase(&tpdf_chain, free);
3159 return ret;
3160}
3161
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003162/**
3163 * @brief Compile status information of the given node.
3164 *
3165 * To simplify getting status of the node, the flags are set following inheritance rules, so all the nodes
3166 * has the status correctly set during the compilation.
3167 *
3168 * @param[in] ctx Compile context
3169 * @param[in,out] node_flags Flags of the compiled node which status is supposed to be resolved.
3170 * If the status was set explicitly on the node, it is already set in the flags value and we just check
3171 * the compatibility with the parent's status value.
3172 * @param[in] parent_flags Flags of the parent node to check/inherit the status value.
3173 * @return LY_ERR value.
3174 */
3175static LY_ERR
3176lys_compile_status(struct lysc_ctx *ctx, uint16_t *node_flags, uint16_t parent_flags)
3177{
3178 /* status - it is not inherited by specification, but it does not make sense to have
3179 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
3180 if (!((*node_flags) & LYS_STATUS_MASK)) {
3181 if (parent_flags & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) {
3182 if ((parent_flags & 0x3) != 0x3) {
3183 /* do not print the warning when inheriting status from uses - the uses_status value has a special
3184 * combination of bits (0x3) which marks the uses_status value */
3185 LOGWRN(ctx->ctx, "Missing explicit \"%s\" status that was already specified in parent, inheriting.",
Radek Krejci0f969882020-08-21 16:56:47 +02003186 (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003187 }
3188 (*node_flags) |= parent_flags & LYS_STATUS_MASK;
3189 } else {
3190 (*node_flags) |= LYS_STATUS_CURR;
3191 }
3192 } else if (parent_flags & LYS_STATUS_MASK) {
3193 /* check status compatibility with the parent */
3194 if ((parent_flags & LYS_STATUS_MASK) > ((*node_flags) & LYS_STATUS_MASK)) {
3195 if ((*node_flags) & LYS_STATUS_CURR) {
3196 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003197 "A \"current\" status is in conflict with the parent's \"%s\" status.",
Radek Krejci0f969882020-08-21 16:56:47 +02003198 (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003199 } else { /* LYS_STATUS_DEPRC */
3200 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003201 "A \"deprecated\" status is in conflict with the parent's \"obsolete\" status.");
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003202 }
3203 return LY_EVALID;
3204 }
3205 }
3206 return LY_SUCCESS;
3207}
3208
Radek Krejci8cce8532019-03-05 11:27:45 +01003209/**
3210 * @brief Check uniqness of the node/action/notification name.
3211 *
3212 * Data nodes, actions/RPCs and Notifications are stored separately (in distinguish lists) in the schema
3213 * structures, but they share the namespace so we need to check their name collisions.
3214 *
3215 * @param[in] ctx Compile context.
Michal Vasko20424b42020-08-31 12:29:38 +02003216 * @param[in] parent Parent of the nodes to check, can be NULL.
Radek Krejci8cce8532019-03-05 11:27:45 +01003217 * @param[in] name Name of the item to find in the given lists.
Michal Vasko20424b42020-08-31 12:29:38 +02003218 * @param[in] exclude Node that was just added that should be excluded from the name checking.
Radek Krejci8cce8532019-03-05 11:27:45 +01003219 * @return LY_SUCCESS in case of unique name, LY_EEXIST otherwise.
3220 */
3221static LY_ERR
Michal Vasko20424b42020-08-31 12:29:38 +02003222lys_compile_node_uniqness(struct lysc_ctx *ctx, const struct lysc_node *parent, const char *name,
3223 const struct lysc_node *exclude)
Radek Krejci8cce8532019-03-05 11:27:45 +01003224{
Michal Vasko20424b42020-08-31 12:29:38 +02003225 const struct lysc_node *iter, *iter2;
3226 const struct lysc_action *actions;
3227 const struct lysc_notif *notifs;
3228 uint32_t getnext_flags;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003229 LY_ARRAY_COUNT_TYPE u;
Radek Krejci8cce8532019-03-05 11:27:45 +01003230
Michal Vasko20424b42020-08-31 12:29:38 +02003231#define CHECK_NODE(iter, exclude, name) (iter != (void *)exclude && (iter)->module == exclude->module && !strcmp(name, (iter)->name))
3232
3233 if (exclude->nodetype == LYS_CASE) {
3234 /* check restricted only to all the cases */
3235 assert(parent->nodetype == LYS_CHOICE);
3236 LY_LIST_FOR(lysc_node_children(parent, 0), iter) {
3237 if (CHECK_NODE(iter, exclude, name)) {
3238 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPIDENT, name, "case");
3239 return LY_EEXIST;
3240 }
3241 }
3242
3243 return LY_SUCCESS;
3244 }
3245
3246 /* no reason for our parent to be choice anymore */
3247 assert(!parent || (parent->nodetype != LYS_CHOICE));
3248
3249 if (parent && (parent->nodetype == LYS_CASE)) {
3250 /* move to the first data definition parent */
3251 parent = lysc_data_parent(parent);
3252 }
3253
3254 getnext_flags = LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE;
3255 if (parent && (parent->nodetype & (LYS_RPC | LYS_ACTION)) && (exclude->flags & LYS_CONFIG_R)) {
3256 getnext_flags |= LYS_GETNEXT_OUTPUT;
3257 }
3258
3259 iter = NULL;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003260 while ((iter = lys_getnext(iter, parent, ctx->cur_mod->compiled, getnext_flags))) {
Michal Vasko20424b42020-08-31 12:29:38 +02003261 if (CHECK_NODE(iter, exclude, name)) {
Radek Krejci8cce8532019-03-05 11:27:45 +01003262 goto error;
3263 }
Michal Vasko20424b42020-08-31 12:29:38 +02003264
3265 /* we must compare with both the choice and all its nested data-definiition nodes (but not recursively) */
3266 if (iter->nodetype == LYS_CHOICE) {
3267 iter2 = NULL;
3268 while ((iter2 = lys_getnext(iter2, iter, NULL, LYS_GETNEXT_NOSTATECHECK))) {
3269 if (CHECK_NODE(iter2, exclude, name)) {
3270 goto error;
3271 }
3272 }
3273 }
Radek Krejci8cce8532019-03-05 11:27:45 +01003274 }
Michal Vasko20424b42020-08-31 12:29:38 +02003275
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003276 actions = parent ? lysc_node_actions(parent) : ctx->cur_mod->compiled->rpcs;
Radek Krejci8cce8532019-03-05 11:27:45 +01003277 LY_ARRAY_FOR(actions, u) {
Michal Vasko20424b42020-08-31 12:29:38 +02003278 if (CHECK_NODE(&actions[u], exclude, name)) {
Radek Krejci8cce8532019-03-05 11:27:45 +01003279 goto error;
3280 }
3281 }
Michal Vasko20424b42020-08-31 12:29:38 +02003282
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003283 notifs = parent ? lysc_node_notifs(parent) : ctx->cur_mod->compiled->notifs;
Radek Krejci8cce8532019-03-05 11:27:45 +01003284 LY_ARRAY_FOR(notifs, u) {
Michal Vasko20424b42020-08-31 12:29:38 +02003285 if (CHECK_NODE(&notifs[u], exclude, name)) {
Radek Krejci8cce8532019-03-05 11:27:45 +01003286 goto error;
3287 }
3288 }
3289 return LY_SUCCESS;
Michal Vasko20424b42020-08-31 12:29:38 +02003290
Radek Krejci8cce8532019-03-05 11:27:45 +01003291error:
Michal Vaskoa3881362020-01-21 15:57:35 +01003292 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPIDENT, name, "data definition/RPC/action/notification");
Radek Krejci8cce8532019-03-05 11:27:45 +01003293 return LY_EEXIST;
Michal Vasko20424b42020-08-31 12:29:38 +02003294
3295#undef CHECK_NODE
Radek Krejci8cce8532019-03-05 11:27:45 +01003296}
3297
Michal Vasko7f45cf22020-10-01 12:49:44 +02003298static LY_ERR lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *parent,
3299 uint16_t uses_status, struct ly_set *child_set);
3300
3301static LY_ERR lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode,
3302 const struct lysc_node *parent, struct lysp_node **dev_pnode, ly_bool *not_supported);
3303
3304static LY_ERR lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node);
3305
3306static void lysp_dev_node_free(const struct ly_ctx *ctx, struct lysp_node *dev_pnode);
Radek Krejci19a96102018-11-15 13:38:09 +01003307
Radek Krejcia3045382018-11-22 14:30:31 +01003308/**
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003309 * @brief Compile parsed RPC/action schema node information.
3310 * @param[in] ctx Compile context
Radek Krejci43981a32019-04-12 09:44:11 +02003311 * @param[in] action_p Parsed RPC/action schema node.
Radek Krejci43981a32019-04-12 09:44:11 +02003312 * @param[in] parent Parent node of the action, NULL in case of RPC (top-level action)
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003313 * @param[in,out] action Prepared (empty) compiled action structure to fill.
3314 * @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).
3315 * Zero means no uses, non-zero value with no status bit set mean the default status.
Michal Vasko7f45cf22020-10-01 12:49:44 +02003316 * @return LY_SUCCESS on success,
3317 * @return LY_EVALID on validation error,
3318 * @return LY_EDENIED on not-supported deviation.
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003319 */
3320static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02003321lys_compile_action(struct lysc_ctx *ctx, struct lysp_action *action_p,
Radek Krejci0f969882020-08-21 16:56:47 +02003322 struct lysc_node *parent, struct lysc_action *action, uint16_t uses_status)
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003323{
3324 LY_ERR ret = LY_SUCCESS;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003325 struct lysp_node *child_p, *dev_pnode = NULL, *dev_input_p = NULL, *dev_output_p = NULL;
3326 struct lysp_action *orig_action_p = action_p;
3327 struct lysp_action_inout *inout_p;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003328 LY_ARRAY_COUNT_TYPE u;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003329 ly_bool not_supported;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003330 uint32_t opt_prev = ctx->options;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003331
Radek Krejci327de162019-06-14 12:52:07 +02003332 lysc_update_path(ctx, parent, action_p->name);
3333
Michal Vasko7f45cf22020-10-01 12:49:44 +02003334 /* apply deviation on the action/RPC */
3335 LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)action_p, parent, &dev_pnode, &not_supported));
3336 if (not_supported) {
3337 lysc_update_path(ctx, NULL, NULL);
3338 return LY_EDENIED;
3339 } else if (dev_pnode) {
3340 action_p = (struct lysp_action *)dev_pnode;
3341 }
3342
Michal Vasko20424b42020-08-31 12:29:38 +02003343 /* member needed for uniqueness check lys_getnext() */
3344 action->nodetype = parent ? LYS_ACTION : LYS_RPC;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003345 action->module = ctx->cur_mod;
Michal Vasko20424b42020-08-31 12:29:38 +02003346 action->parent = parent;
3347
3348 LY_CHECK_RET(lys_compile_node_uniqness(ctx, parent, action_p->name, (struct lysc_node *)action));
Radek Krejci8cce8532019-03-05 11:27:45 +01003349
Radek Krejci90d4e922020-10-12 15:55:33 +02003350 if (ctx->options & (LYS_COMPILE_RPC_MASK | LYS_COMPILE_NOTIFICATION)) {
Radek Krejci05b774b2019-02-25 13:26:18 +01003351 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003352 "Action \"%s\" is placed inside %s.", action_p->name,
Radek Krejci90d4e922020-10-12 15:55:33 +02003353 ctx->options & LYS_COMPILE_RPC_MASK ? "another RPC/action" : "notification");
Radek Krejci05b774b2019-02-25 13:26:18 +01003354 return LY_EVALID;
3355 }
3356
Radek Krejci90d4e922020-10-12 15:55:33 +02003357 action->sp = orig_action_p;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003358 action->flags = action_p->flags & LYS_FLAGS_COMPILED_MASK;
3359
3360 /* status - it is not inherited by specification, but it does not make sense to have
3361 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
Michal Vaskocc048b22020-03-27 15:52:38 +01003362 LY_CHECK_RET(lys_compile_status(ctx, &action->flags, uses_status ? uses_status : (parent ? parent->flags : 0)));
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003363
Radek Krejci011e4aa2020-09-04 15:22:31 +02003364 DUP_STRING_GOTO(ctx->ctx, action_p->name, action->name, ret, cleanup);
3365 DUP_STRING_GOTO(ctx->ctx, action_p->dsc, action->dsc, ret, cleanup);
3366 DUP_STRING_GOTO(ctx->ctx, action_p->ref, action->ref, ret, cleanup);
Radek Krejciec4da802019-05-02 13:02:41 +02003367 COMPILE_ARRAY_GOTO(ctx, action_p->iffeatures, action->iffeatures, u, lys_compile_iffeature, ret, cleanup);
Radek Krejci0935f412019-08-20 16:15:18 +02003368 COMPILE_EXTS_GOTO(ctx, action_p->exts, action->exts, action, LYEXT_PAR_NODE, ret, cleanup);
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003369
Michal Vasko7f45cf22020-10-01 12:49:44 +02003370 /* connect any action augments */
3371 LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)action));
3372
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003373 /* input */
Michal Vasko22df3f02020-08-24 13:29:22 +02003374 lysc_update_path(ctx, (struct lysc_node *)action, "input");
Michal Vasko7f45cf22020-10-01 12:49:44 +02003375
3376 /* apply deviations on input */
3377 LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)&action_p->input, (struct lysc_node *)action,
3378 &dev_input_p, &not_supported));
3379 if (not_supported) {
3380 inout_p = NULL;
3381 } else if (dev_input_p) {
3382 inout_p = (struct lysp_action_inout *)dev_input_p;
3383 } else {
3384 inout_p = &action_p->input;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003385 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02003386
3387 if (inout_p) {
3388 action->input.nodetype = LYS_INPUT;
3389 COMPILE_ARRAY_GOTO(ctx, inout_p->musts, action->input.musts, u, lys_compile_must, ret, cleanup);
3390 COMPILE_EXTS_GOTO(ctx, inout_p->exts, action->input_exts, &action->input, LYEXT_PAR_INPUT, ret, cleanup);
Radek Krejci90d4e922020-10-12 15:55:33 +02003391 ctx->options |= LYS_COMPILE_RPC_INPUT;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003392
3393 /* connect any input augments */
3394 LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)&action->input));
3395
3396 LY_LIST_FOR(inout_p->data, child_p) {
3397 LY_CHECK_RET(lys_compile_node(ctx, child_p, (struct lysc_node *)action, uses_status, NULL));
3398 }
3399 ctx->options = opt_prev;
3400 }
3401
Radek Krejci327de162019-06-14 12:52:07 +02003402 lysc_update_path(ctx, NULL, NULL);
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003403
3404 /* output */
Michal Vasko22df3f02020-08-24 13:29:22 +02003405 lysc_update_path(ctx, (struct lysc_node *)action, "output");
Michal Vasko7f45cf22020-10-01 12:49:44 +02003406
3407 /* apply deviations on output */
3408 LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)&action_p->output, (struct lysc_node *)action,
3409 &dev_output_p, &not_supported));
3410 if (not_supported) {
3411 inout_p = NULL;
3412 } else if (dev_output_p) {
3413 inout_p = (struct lysp_action_inout *)dev_output_p;
3414 } else {
3415 inout_p = &action_p->output;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003416 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02003417
3418 if (inout_p) {
3419 action->output.nodetype = LYS_OUTPUT;
3420 COMPILE_ARRAY_GOTO(ctx, inout_p->musts, action->output.musts, u, lys_compile_must, ret, cleanup);
3421 COMPILE_EXTS_GOTO(ctx, inout_p->exts, action->output_exts, &action->output, LYEXT_PAR_OUTPUT, ret, cleanup);
Radek Krejci90d4e922020-10-12 15:55:33 +02003422 ctx->options |= LYS_COMPILE_RPC_OUTPUT;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003423
3424 /* connect any output augments */
3425 LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)&action->output));
3426
3427 LY_LIST_FOR(inout_p->data, child_p) {
3428 LY_CHECK_RET(lys_compile_node(ctx, child_p, (struct lysc_node *)action, uses_status, NULL));
3429 }
3430 ctx->options = opt_prev;
3431 }
3432
Radek Krejci327de162019-06-14 12:52:07 +02003433 lysc_update_path(ctx, NULL, NULL);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003434
Radek Krejci90d4e922020-10-12 15:55:33 +02003435 if ((action->input.musts || action->output.musts) && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01003436 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003437 ret = ly_set_add(&ctx->xpath, action, 0, NULL);
3438 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003439 }
3440
Michal Vasko7f45cf22020-10-01 12:49:44 +02003441 lysc_update_path(ctx, NULL, NULL);
3442
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003443cleanup:
Michal Vasko7f45cf22020-10-01 12:49:44 +02003444 lysp_dev_node_free(ctx->ctx, dev_pnode);
3445 lysp_dev_node_free(ctx->ctx, dev_input_p);
3446 lysp_dev_node_free(ctx->ctx, dev_output_p);
Radek Krejciec4da802019-05-02 13:02:41 +02003447 ctx->options = opt_prev;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003448 return ret;
3449}
3450
3451/**
Radek Krejci43981a32019-04-12 09:44:11 +02003452 * @brief Compile parsed Notification schema node information.
Radek Krejcifc11bd72019-04-11 16:00:05 +02003453 * @param[in] ctx Compile context
Radek Krejci43981a32019-04-12 09:44:11 +02003454 * @param[in] notif_p Parsed Notification schema node.
Radek Krejci43981a32019-04-12 09:44:11 +02003455 * @param[in] parent Parent node of the Notification, NULL in case of top-level Notification
3456 * @param[in,out] notif Prepared (empty) compiled notification structure to fill.
3457 * @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 +02003458 * Zero means no uses, non-zero value with no status bit set mean the default status.
Michal Vasko7f45cf22020-10-01 12:49:44 +02003459 * @return LY_SUCCESS on success,
3460 * @return LY_EVALID on validation error,
3461 * @return LY_EDENIED on not-supported deviation.
Radek Krejcifc11bd72019-04-11 16:00:05 +02003462 */
3463static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02003464lys_compile_notif(struct lysc_ctx *ctx, struct lysp_notif *notif_p,
Radek Krejci0f969882020-08-21 16:56:47 +02003465 struct lysc_node *parent, struct lysc_notif *notif, uint16_t uses_status)
Radek Krejcifc11bd72019-04-11 16:00:05 +02003466{
3467 LY_ERR ret = LY_SUCCESS;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003468 struct lysp_node *child_p, *dev_pnode = NULL;
3469 struct lysp_notif *orig_notif_p = notif_p;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003470 LY_ARRAY_COUNT_TYPE u;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003471 ly_bool not_supported;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003472 uint32_t opt_prev = ctx->options;
Radek Krejcifc11bd72019-04-11 16:00:05 +02003473
Radek Krejci327de162019-06-14 12:52:07 +02003474 lysc_update_path(ctx, parent, notif_p->name);
3475
Michal Vasko7f45cf22020-10-01 12:49:44 +02003476 LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)notif_p, parent, &dev_pnode, &not_supported));
3477 if (not_supported) {
3478 lysc_update_path(ctx, NULL, NULL);
3479 return LY_EDENIED;
3480 } else if (dev_pnode) {
3481 notif_p = (struct lysp_notif *)dev_pnode;
3482 }
3483
Michal Vasko20424b42020-08-31 12:29:38 +02003484 /* member needed for uniqueness check lys_getnext() */
3485 notif->nodetype = LYS_NOTIF;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003486 notif->module = ctx->cur_mod;
Michal Vasko20424b42020-08-31 12:29:38 +02003487 notif->parent = parent;
3488
3489 LY_CHECK_RET(lys_compile_node_uniqness(ctx, parent, notif_p->name, (struct lysc_node *)notif));
Radek Krejcifc11bd72019-04-11 16:00:05 +02003490
Radek Krejci90d4e922020-10-12 15:55:33 +02003491 if (ctx->options & (LYS_COMPILE_RPC_MASK | LYS_COMPILE_NOTIFICATION)) {
Radek Krejcifc11bd72019-04-11 16:00:05 +02003492 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003493 "Notification \"%s\" is placed inside %s.", notif_p->name,
Radek Krejci90d4e922020-10-12 15:55:33 +02003494 ctx->options & LYS_COMPILE_RPC_MASK ? "RPC/action" : "another notification");
Radek Krejcifc11bd72019-04-11 16:00:05 +02003495 return LY_EVALID;
3496 }
3497
Radek Krejci90d4e922020-10-12 15:55:33 +02003498 notif->sp = orig_notif_p;
Radek Krejcifc11bd72019-04-11 16:00:05 +02003499 notif->flags = notif_p->flags & LYS_FLAGS_COMPILED_MASK;
3500
3501 /* status - it is not inherited by specification, but it does not make sense to have
3502 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003503 ret = lys_compile_status(ctx, &notif->flags, uses_status ? uses_status : (parent ? parent->flags : 0));
3504 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcifc11bd72019-04-11 16:00:05 +02003505
Radek Krejci011e4aa2020-09-04 15:22:31 +02003506 DUP_STRING_GOTO(ctx->ctx, notif_p->name, notif->name, ret, cleanup);
3507 DUP_STRING_GOTO(ctx->ctx, notif_p->dsc, notif->dsc, ret, cleanup);
3508 DUP_STRING_GOTO(ctx->ctx, notif_p->ref, notif->ref, ret, cleanup);
Radek Krejciec4da802019-05-02 13:02:41 +02003509 COMPILE_ARRAY_GOTO(ctx, notif_p->iffeatures, notif->iffeatures, u, lys_compile_iffeature, ret, cleanup);
Radek Krejcic71ac5b2019-09-10 15:34:22 +02003510 COMPILE_ARRAY_GOTO(ctx, notif_p->musts, notif->musts, u, lys_compile_must, ret, cleanup);
Radek Krejci90d4e922020-10-12 15:55:33 +02003511 if (notif_p->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, notif, 0, NULL);
3514 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003515 }
Radek Krejci0935f412019-08-20 16:15:18 +02003516 COMPILE_EXTS_GOTO(ctx, notif_p->exts, notif->exts, notif, LYEXT_PAR_NODE, ret, cleanup);
Radek Krejcifc11bd72019-04-11 16:00:05 +02003517
Radek Krejci90d4e922020-10-12 15:55:33 +02003518 ctx->options |= LYS_COMPILE_NOTIFICATION;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003519
3520 /* connect any notification augments */
3521 LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)notif));
3522
Radek Krejcifc11bd72019-04-11 16:00:05 +02003523 LY_LIST_FOR(notif_p->data, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003524 ret = lys_compile_node(ctx, child_p, (struct lysc_node *)notif, uses_status, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003525 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcifc11bd72019-04-11 16:00:05 +02003526 }
3527
Radek Krejci327de162019-06-14 12:52:07 +02003528 lysc_update_path(ctx, NULL, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02003529
Radek Krejcifc11bd72019-04-11 16:00:05 +02003530cleanup:
Michal Vasko7f45cf22020-10-01 12:49:44 +02003531 lysp_dev_node_free(ctx->ctx, dev_pnode);
Radek Krejciec4da802019-05-02 13:02:41 +02003532 ctx->options = opt_prev;
Radek Krejcifc11bd72019-04-11 16:00:05 +02003533 return ret;
3534}
3535
3536/**
Radek Krejcia3045382018-11-22 14:30:31 +01003537 * @brief Compile parsed container node information.
3538 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02003539 * @param[in] pnode Parsed container node.
Radek Krejcia3045382018-11-22 14:30:31 +01003540 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
3541 * is enriched with the container-specific information.
3542 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3543 */
Radek Krejci19a96102018-11-15 13:38:09 +01003544static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02003545lys_compile_node_container(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci19a96102018-11-15 13:38:09 +01003546{
Michal Vasko7f45cf22020-10-01 12:49:44 +02003547 struct lysp_node_container *cont_p = (struct lysp_node_container *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02003548 struct lysc_node_container *cont = (struct lysc_node_container *)node;
Radek Krejci19a96102018-11-15 13:38:09 +01003549 struct lysp_node *child_p;
Michal Vaskoba417ac2020-08-06 14:48:20 +02003550 LY_ARRAY_COUNT_TYPE u;
Radek Krejci19a96102018-11-15 13:38:09 +01003551 LY_ERR ret = LY_SUCCESS;
3552
Radek Krejcife909632019-02-12 15:34:42 +01003553 if (cont_p->presence) {
Michal Vaskoba417ac2020-08-06 14:48:20 +02003554 /* explicit presence */
Radek Krejcife909632019-02-12 15:34:42 +01003555 cont->flags |= LYS_PRESENCE;
Michal Vaskoba417ac2020-08-06 14:48:20 +02003556 } else if (cont_p->musts) {
3557 /* container with a must condition */
Radek Krejci175f25b2020-08-13 12:02:36 +02003558 LOGWRN(ctx->ctx, "Container \"%s\" changed to presence because it has a meaning from its \"must\" condition.", cont_p->name);
3559 cont->flags |= LYS_PRESENCE;
3560 } else if (cont_p->when) {
3561 /* container with a when condition */
3562 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 +02003563 cont->flags |= LYS_PRESENCE;
3564 } else if (cont_p->parent) {
3565 if (cont_p->parent->nodetype == LYS_CHOICE) {
3566 /* container is an implicit case, so its existence decides the existence of the whole case */
Radek Krejci175f25b2020-08-13 12:02:36 +02003567 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 +02003568 cont_p->name, cont_p->parent->name);
Michal Vaskoba417ac2020-08-06 14:48:20 +02003569 cont->flags |= LYS_PRESENCE;
Michal Vasko69730152020-10-09 16:30:07 +02003570 } else if ((cont_p->parent->nodetype == LYS_CASE) &&
3571 (((struct lysp_node_case *)cont_p->parent)->child == pnode) && !cont_p->next) {
Michal Vaskoba417ac2020-08-06 14:48:20 +02003572 /* 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 +02003573 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 +02003574 cont_p->name, cont_p->parent->name);
Michal Vaskoba417ac2020-08-06 14:48:20 +02003575 cont->flags |= LYS_PRESENCE;
3576 }
Radek Krejcife909632019-02-12 15:34:42 +01003577 }
3578
Michal Vaskoba417ac2020-08-06 14:48:20 +02003579 /* more cases when the container has meaning but is kept NP for convenience:
3580 * - when condition
3581 * - direct child action/notification
3582 */
3583
Radek Krejci19a96102018-11-15 13:38:09 +01003584 LY_LIST_FOR(cont_p->child, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003585 ret = lys_compile_node(ctx, child_p, node, 0, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003586 LY_CHECK_GOTO(ret, done);
Radek Krejci19a96102018-11-15 13:38:09 +01003587 }
3588
Radek Krejcic71ac5b2019-09-10 15:34:22 +02003589 COMPILE_ARRAY_GOTO(ctx, cont_p->musts, cont->musts, u, lys_compile_must, ret, done);
Radek Krejci90d4e922020-10-12 15:55:33 +02003590 if (cont_p->musts && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01003591 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003592 ret = ly_set_add(&ctx->xpath, cont, 0, NULL);
3593 LY_CHECK_GOTO(ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003594 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02003595 COMPILE_OP_ARRAY_GOTO(ctx, cont_p->actions, cont->actions, node, u, lys_compile_action, 0, ret, done);
3596 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 +01003597
3598done:
3599 return ret;
3600}
3601
Radek Krejci33f72892019-02-21 10:36:58 +01003602/*
3603 * @brief Compile type in leaf/leaf-list node and do all the necessary checks.
3604 * @param[in] ctx Compile context.
3605 * @param[in] context_node Schema node where the type/typedef is placed to correctly find the base types.
3606 * @param[in] type_p Parsed type to compile.
Radek Krejci33f72892019-02-21 10:36:58 +01003607 * @param[in,out] leaf Compiled leaf structure (possibly cast leaf-list) to provide node information and to store the compiled type information.
3608 * @return LY_ERR value.
3609 */
3610static LY_ERR
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003611lys_compile_node_type(struct lysc_ctx *ctx, struct lysp_node *context_node, struct lysp_type *type_p,
Radek Krejci0f969882020-08-21 16:56:47 +02003612 struct lysc_node_leaf *leaf)
Radek Krejci33f72892019-02-21 10:36:58 +01003613{
Michal Vasko7f45cf22020-10-01 12:49:44 +02003614 struct lysp_qname *dflt;
Radek Krejci33f72892019-02-21 10:36:58 +01003615
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003616 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 +02003617 leaf->units ? NULL : &leaf->units, &dflt));
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003618
3619 /* store default value, if any */
3620 if (dflt && !(leaf->flags & LYS_SET_DFLT)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003621 LY_CHECK_RET(lysc_unres_leaf_dflt_add(ctx, leaf, dflt));
Radek Krejci33f72892019-02-21 10:36:58 +01003622 }
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003623
Radek Krejci33f72892019-02-21 10:36:58 +01003624 if (leaf->type->basetype == LY_TYPE_LEAFREF) {
3625 /* 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 +02003626 LY_CHECK_RET(ly_set_add(&ctx->leafrefs, leaf, 0, NULL));
Radek Krejci33f72892019-02-21 10:36:58 +01003627 } else if (leaf->type->basetype == LY_TYPE_UNION) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003628 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003629 LY_ARRAY_FOR(((struct lysc_type_union *)leaf->type)->types, u) {
3630 if (((struct lysc_type_union *)leaf->type)->types[u]->basetype == LY_TYPE_LEAFREF) {
Radek Krejci33f72892019-02-21 10:36:58 +01003631 /* 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 +02003632 LY_CHECK_RET(ly_set_add(&ctx->leafrefs, leaf, 0, NULL));
Radek Krejci33f72892019-02-21 10:36:58 +01003633 }
3634 }
3635 } else if (leaf->type->basetype == LY_TYPE_EMPTY) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003636 if ((leaf->nodetype == LYS_LEAFLIST) && (ctx->pmod->version < LYS_VERSION_1_1)) {
Radek Krejci33f72892019-02-21 10:36:58 +01003637 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003638 "Leaf-list of type \"empty\" is allowed only in YANG 1.1 modules.");
Radek Krejci33f72892019-02-21 10:36:58 +01003639 return LY_EVALID;
3640 }
3641 }
3642
Radek Krejci33f72892019-02-21 10:36:58 +01003643 return LY_SUCCESS;
3644}
3645
Radek Krejcia3045382018-11-22 14:30:31 +01003646/**
3647 * @brief Compile parsed leaf node information.
3648 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02003649 * @param[in] pnode Parsed leaf node.
Radek Krejcia3045382018-11-22 14:30:31 +01003650 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
3651 * is enriched with the leaf-specific information.
3652 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3653 */
Radek Krejci19a96102018-11-15 13:38:09 +01003654static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02003655lys_compile_node_leaf(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci19a96102018-11-15 13:38:09 +01003656{
Michal Vasko7f45cf22020-10-01 12:49:44 +02003657 struct lysp_node_leaf *leaf_p = (struct lysp_node_leaf *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02003658 struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)node;
Michal Vasko7c8439f2020-08-05 13:25:19 +02003659 LY_ARRAY_COUNT_TYPE u;
Radek Krejci19a96102018-11-15 13:38:09 +01003660 LY_ERR ret = LY_SUCCESS;
3661
Radek Krejcic71ac5b2019-09-10 15:34:22 +02003662 COMPILE_ARRAY_GOTO(ctx, leaf_p->musts, leaf->musts, u, lys_compile_must, ret, done);
Radek Krejci90d4e922020-10-12 15:55:33 +02003663 if (leaf_p->musts && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01003664 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003665 ret = ly_set_add(&ctx->xpath, leaf, 0, NULL);
3666 LY_CHECK_GOTO(ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003667 }
Radek Krejciccd20f12019-02-15 14:12:27 +01003668 if (leaf_p->units) {
Radek Krejci011e4aa2020-09-04 15:22:31 +02003669 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, leaf_p->units, 0, &leaf->units), done);
Radek Krejciccd20f12019-02-15 14:12:27 +01003670 leaf->flags |= LYS_SET_UNITS;
3671 }
Radek Krejcia1911222019-07-22 17:24:50 +02003672
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003673 /* compile type */
Michal Vasko7f45cf22020-10-01 12:49:44 +02003674 ret = lys_compile_node_type(ctx, pnode, &leaf_p->type, leaf);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003675 LY_CHECK_GOTO(ret, done);
Radek Krejcia1911222019-07-22 17:24:50 +02003676
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003677 /* store/update default value */
Michal Vasko7f45cf22020-10-01 12:49:44 +02003678 if (leaf_p->dflt.str) {
3679 LY_CHECK_RET(lysc_unres_leaf_dflt_add(ctx, leaf, &leaf_p->dflt));
Radek Krejci76b3e962018-12-14 17:01:25 +01003680 leaf->flags |= LYS_SET_DFLT;
3681 }
Radek Krejci43699232018-11-23 14:59:46 +01003682
Michal Vasko7f45cf22020-10-01 12:49:44 +02003683 /* checks */
3684 if ((leaf->flags & LYS_SET_DFLT) && (leaf->flags & LYS_MAND_TRUE)) {
3685 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
3686 "Invalid mandatory leaf with a default value.");
3687 return LY_EVALID;
3688 }
3689
Radek Krejci19a96102018-11-15 13:38:09 +01003690done:
3691 return ret;
3692}
3693
Radek Krejcia3045382018-11-22 14:30:31 +01003694/**
Radek Krejci0e5d8382018-11-28 16:37:53 +01003695 * @brief Compile parsed leaf-list node information.
3696 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02003697 * @param[in] pnode Parsed leaf-list node.
Radek Krejci0e5d8382018-11-28 16:37:53 +01003698 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
3699 * is enriched with the leaf-list-specific information.
3700 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3701 */
3702static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02003703lys_compile_node_leaflist(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci0e5d8382018-11-28 16:37:53 +01003704{
Michal Vasko7f45cf22020-10-01 12:49:44 +02003705 struct lysp_node_leaflist *llist_p = (struct lysp_node_leaflist *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02003706 struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)node;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003707 LY_ARRAY_COUNT_TYPE u;
Radek Krejci0e5d8382018-11-28 16:37:53 +01003708 LY_ERR ret = LY_SUCCESS;
3709
Radek Krejcic71ac5b2019-09-10 15:34:22 +02003710 COMPILE_ARRAY_GOTO(ctx, llist_p->musts, llist->musts, u, lys_compile_must, ret, done);
Radek Krejci90d4e922020-10-12 15:55:33 +02003711 if (llist_p->musts && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01003712 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003713 ret = ly_set_add(&ctx->xpath, llist, 0, NULL);
3714 LY_CHECK_GOTO(ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003715 }
Radek Krejciccd20f12019-02-15 14:12:27 +01003716 if (llist_p->units) {
Radek Krejci011e4aa2020-09-04 15:22:31 +02003717 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, llist_p->units, 0, &llist->units), done);
Radek Krejciccd20f12019-02-15 14:12:27 +01003718 llist->flags |= LYS_SET_UNITS;
3719 }
Radek Krejci0e5d8382018-11-28 16:37:53 +01003720
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003721 /* compile type */
Michal Vasko7f45cf22020-10-01 12:49:44 +02003722 ret = lys_compile_node_type(ctx, pnode, &llist_p->type, (struct lysc_node_leaf *)llist);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003723 LY_CHECK_GOTO(ret, done);
Michal Vasko6a044b22020-01-15 12:25:39 +01003724
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003725 /* store/update default values */
Radek Krejci0e5d8382018-11-28 16:37:53 +01003726 if (llist_p->dflts) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003727 if (ctx->pmod->version < LYS_VERSION_1_1) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003728 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003729 "Leaf-list default values are allowed only in YANG 1.1 modules.");
Michal Vasko7f45cf22020-10-01 12:49:44 +02003730 return LY_EVALID;
3731 }
3732
3733 LY_CHECK_GOTO(lysc_unres_llist_dflts_add(ctx, llist, llist_p->dflts), done);
Radek Krejciccd20f12019-02-15 14:12:27 +01003734 llist->flags |= LYS_SET_DFLT;
Radek Krejci0e5d8382018-11-28 16:37:53 +01003735 }
3736
3737 llist->min = llist_p->min;
Radek Krejcife909632019-02-12 15:34:42 +01003738 if (llist->min) {
3739 llist->flags |= LYS_MAND_TRUE;
3740 }
Radek Krejcib7408632018-11-28 17:12:11 +01003741 llist->max = llist_p->max ? llist_p->max : (uint32_t)-1;
Radek Krejci0e5d8382018-11-28 16:37:53 +01003742
Michal Vasko7f45cf22020-10-01 12:49:44 +02003743 /* checks */
3744 if ((llist->flags & LYS_SET_DFLT) && (llist->flags & LYS_MAND_TRUE)) {
3745 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
3746 "Invalid mandatory leaf-list with default value(s).");
3747 return LY_EVALID;
3748 }
3749
3750 if (llist->min > llist->max) {
3751 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 +02003752 llist->min, llist->max);
Michal Vasko7f45cf22020-10-01 12:49:44 +02003753 return LY_EVALID;
3754 }
3755
Radek Krejci0e5d8382018-11-28 16:37:53 +01003756done:
3757 return ret;
3758}
3759
3760/**
Radek Krejci90d4e922020-10-12 15:55:33 +02003761 * @brief Find the node according to the given descendant/absolute schema nodeid.
3762 * Used in unique, refine and augment statements.
3763 *
3764 * @param[in] ctx Compile context
3765 * @param[in] nodeid Descendant-schema-nodeid (according to the YANG grammar)
3766 * @param[in] nodeid_len Length of the given nodeid, if it is not NULL-terminated string.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003767 * @param[in] ctx_node Context node for a relative nodeid.
3768 * @param[in] cur_mod Current module for the nodeid (where it was "instantiated").
3769 * @param[in] format Format of any prefixes.
3770 * @param[in] prefix_data Format-specific prefix data (see ::ly_resolve_prefix).
Radek Krejci90d4e922020-10-12 15:55:33 +02003771 * @param[in] nodetype Optional (can be 0) restriction for target's nodetype. If target exists, but does not match
3772 * the given nodetype, LY_EDENIED is returned (and target is provided), but no error message is printed.
3773 * The value can be even an ORed value to allow multiple nodetypes.
3774 * @param[out] target Found target node if any.
3775 * @param[out] result_flag Output parameter to announce if the schema nodeid goes through the action's input/output or a Notification.
3776 * The LYSC_OPT_RPC_INPUT, LYSC_OPT_RPC_OUTPUT and LYSC_OPT_NOTIFICATION are used as flags.
3777 * @return LY_ERR values - LY_ENOTFOUND, LY_EVALID, LY_EDENIED or LY_SUCCESS.
3778 */
3779static LY_ERR
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003780lysc_resolve_schema_nodeid(struct lysc_ctx *ctx, const char *nodeid, size_t nodeid_len, const struct lysc_node *ctx_node,
3781 const struct lys_module *cur_mod, LY_PREFIX_FORMAT format, void *prefix_data, uint16_t nodetype,
3782 const struct lysc_node **target, uint16_t *result_flag)
Radek Krejci90d4e922020-10-12 15:55:33 +02003783{
3784 LY_ERR ret = LY_EVALID;
3785 const char *name, *prefix, *id;
3786 size_t name_len, prefix_len;
3787 const struct lys_module *mod;
3788 const char *nodeid_type;
3789 uint32_t getnext_extra_flag = 0;
3790 uint16_t current_nodetype = 0;
3791
3792 assert(nodeid);
3793 assert(target);
3794 assert(result_flag);
3795 *target = NULL;
3796 *result_flag = 0;
3797
3798 id = nodeid;
3799
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003800 if (ctx_node) {
Radek Krejci90d4e922020-10-12 15:55:33 +02003801 /* descendant-schema-nodeid */
3802 nodeid_type = "descendant";
3803
3804 if (*id == '/') {
3805 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3806 "Invalid descendant-schema-nodeid value \"%.*s\" - absolute-schema-nodeid used.",
3807 nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
3808 return LY_EVALID;
3809 }
3810 } else {
3811 /* absolute-schema-nodeid */
3812 nodeid_type = "absolute";
3813
3814 if (*id != '/') {
3815 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3816 "Invalid absolute-schema-nodeid value \"%.*s\" - missing starting \"/\".",
3817 nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
3818 return LY_EVALID;
3819 }
3820 ++id;
3821 }
3822
3823 while (*id && (ret = ly_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len)) == LY_SUCCESS) {
3824 if (prefix) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003825 mod = ly_resolve_prefix(ctx->ctx, prefix, prefix_len, format, prefix_data);
Radek Krejci90d4e922020-10-12 15:55:33 +02003826 if (!mod) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003827 /* module must always be found */
3828 assert(prefix);
Radek Krejci90d4e922020-10-12 15:55:33 +02003829 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3830 "Invalid %s-schema-nodeid value \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003831 nodeid_type, id - nodeid, nodeid, prefix_len, prefix, LYSP_MODULE_NAME(ctx->pmod));
Radek Krejci90d4e922020-10-12 15:55:33 +02003832 return LY_ENOTFOUND;
3833 }
3834 } else {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003835 switch (format) {
3836 case LY_PREF_SCHEMA:
3837 case LY_PREF_SCHEMA_RESOLVED:
3838 /* use the current module */
3839 mod = cur_mod;
3840 break;
3841 case LY_PREF_JSON:
3842 if (!ctx_node) {
3843 LOGINT_RET(ctx->ctx);
3844 }
3845 /* inherit the module of the previous context node */
3846 mod = ctx_node->module;
3847 break;
3848 case LY_PREF_XML:
3849 /* not really defined */
3850 LOGINT_RET(ctx->ctx);
3851 }
Radek Krejci90d4e922020-10-12 15:55:33 +02003852 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003853
3854 if (ctx_node && (ctx_node->nodetype & (LYS_RPC | LYS_ACTION))) {
Radek Krejci90d4e922020-10-12 15:55:33 +02003855 /* move through input/output manually */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003856 if (mod != ctx_node->module) {
Radek Krejci90d4e922020-10-12 15:55:33 +02003857 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3858 "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.", nodeid_type, id - nodeid, nodeid);
3859 return LY_ENOTFOUND;
3860 }
3861 if (!ly_strncmp("input", name, name_len)) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003862 ctx_node = (struct lysc_node *)&((struct lysc_action *)ctx_node)->input;
Radek Krejci90d4e922020-10-12 15:55:33 +02003863 } else if (!ly_strncmp("output", name, name_len)) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003864 ctx_node = (struct lysc_node *)&((struct lysc_action *)ctx_node)->output;
Radek Krejci90d4e922020-10-12 15:55:33 +02003865 getnext_extra_flag = LYS_GETNEXT_OUTPUT;
3866 } else {
3867 /* only input or output is valid */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003868 ctx_node = NULL;
Radek Krejci90d4e922020-10-12 15:55:33 +02003869 }
3870 } else {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003871 ctx_node = lys_find_child(ctx_node, mod, name, name_len, 0,
Radek Krejci90d4e922020-10-12 15:55:33 +02003872 getnext_extra_flag | LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
3873 getnext_extra_flag = 0;
3874 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003875 if (!ctx_node) {
Radek Krejci90d4e922020-10-12 15:55:33 +02003876 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3877 "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.", nodeid_type, id - nodeid, nodeid);
3878 return LY_ENOTFOUND;
3879 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003880 current_nodetype = ctx_node->nodetype;
Radek Krejci90d4e922020-10-12 15:55:33 +02003881
3882 if (current_nodetype == LYS_NOTIF) {
3883 (*result_flag) |= LYS_COMPILE_NOTIFICATION;
3884 } else if (current_nodetype == LYS_INPUT) {
3885 (*result_flag) |= LYS_COMPILE_RPC_INPUT;
3886 } else if (current_nodetype == LYS_OUTPUT) {
3887 (*result_flag) |= LYS_COMPILE_RPC_OUTPUT;
3888 }
3889
3890 if (!*id || (nodeid_len && ((size_t)(id - nodeid) >= nodeid_len))) {
3891 break;
3892 }
3893 if (*id != '/') {
3894 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3895 "Invalid %s-schema-nodeid value \"%.*s\" - missing \"/\" as node-identifier separator.",
3896 nodeid_type, id - nodeid + 1, nodeid);
3897 return LY_EVALID;
3898 }
3899 ++id;
3900 }
3901
3902 if (ret == LY_SUCCESS) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003903 *target = ctx_node;
Radek Krejci90d4e922020-10-12 15:55:33 +02003904 if (nodetype && !(current_nodetype & nodetype)) {
3905 return LY_EDENIED;
3906 }
3907 } else {
3908 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3909 "Invalid %s-schema-nodeid value \"%.*s\" - unexpected end of expression.",
3910 nodeid_type, nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
3911 }
3912
3913 return ret;
3914}
3915
3916/**
Radek Krejci7af64242019-02-18 13:07:53 +01003917 * @brief Compile information about list's uniques.
3918 * @param[in] ctx Compile context.
Radek Krejci7af64242019-02-18 13:07:53 +01003919 * @param[in] uniques Sized array list of unique statements.
3920 * @param[in] list Compiled list where the uniques are supposed to be resolved and stored.
3921 * @return LY_ERR value.
3922 */
3923static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02003924lys_compile_node_list_unique(struct lysc_ctx *ctx, struct lysp_qname *uniques, struct lysc_node_list *list)
Radek Krejci7af64242019-02-18 13:07:53 +01003925{
3926 LY_ERR ret = LY_SUCCESS;
3927 struct lysc_node_leaf **key, ***unique;
Michal Vasko14654712020-02-06 08:35:21 +01003928 struct lysc_node *parent;
Radek Krejci7af64242019-02-18 13:07:53 +01003929 const char *keystr, *delim;
3930 size_t len;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003931 LY_ARRAY_COUNT_TYPE v;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003932 int8_t config; /* -1 - not yet seen; 0 - LYS_CONFIG_R; 1 - LYS_CONFIG_W */
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003933 uint16_t flags;
Radek Krejci7af64242019-02-18 13:07:53 +01003934
Michal Vasko7f45cf22020-10-01 12:49:44 +02003935 LY_ARRAY_FOR(uniques, v) {
Radek Krejci7af64242019-02-18 13:07:53 +01003936 config = -1;
3937 LY_ARRAY_NEW_RET(ctx->ctx, list->uniques, unique, LY_EMEM);
Michal Vasko7f45cf22020-10-01 12:49:44 +02003938 keystr = uniques[v].str;
Radek Krejci7af64242019-02-18 13:07:53 +01003939 while (keystr) {
3940 delim = strpbrk(keystr, " \t\n");
3941 if (delim) {
3942 len = delim - keystr;
3943 while (isspace(*delim)) {
3944 ++delim;
3945 }
3946 } else {
3947 len = strlen(keystr);
3948 }
3949
3950 /* unique node must be present */
3951 LY_ARRAY_NEW_RET(ctx->ctx, *unique, key, LY_EMEM);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003952 ret = lysc_resolve_schema_nodeid(ctx, keystr, len, (struct lysc_node *)list, uniques[v].mod->mod,
3953 LY_PREF_SCHEMA, (void *)uniques[v].mod, LYS_LEAF, (const struct lysc_node **)key, &flags);
Radek Krejci7af64242019-02-18 13:07:53 +01003954 if (ret != LY_SUCCESS) {
3955 if (ret == LY_EDENIED) {
3956 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02003957 "Unique's descendant-schema-nodeid \"%.*s\" refers to %s node instead of a leaf.",
3958 len, keystr, lys_nodetype2str((*key)->nodetype));
Radek Krejci7af64242019-02-18 13:07:53 +01003959 }
3960 return LY_EVALID;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003961 } else if (flags) {
3962 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02003963 "Unique's descendant-schema-nodeid \"%.*s\" refers into %s node.",
Radek Krejci90d4e922020-10-12 15:55:33 +02003964 len, keystr, flags & LYS_COMPILE_NOTIFICATION ? "notification" : "RPC/action");
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003965 return LY_EVALID;
Radek Krejci7af64242019-02-18 13:07:53 +01003966 }
3967
3968 /* all referenced leafs must be of the same config type */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003969 if ((config != -1) && ((((*key)->flags & LYS_CONFIG_W) && (config == 0)) ||
3970 (((*key)->flags & LYS_CONFIG_R) && (config == 1)))) {
Radek Krejci7af64242019-02-18 13:07:53 +01003971 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003972 "Unique statement \"%s\" refers to leaves with different config type.", uniques[v].str);
Radek Krejci7af64242019-02-18 13:07:53 +01003973 return LY_EVALID;
3974 } else if ((*key)->flags & LYS_CONFIG_W) {
3975 config = 1;
3976 } else { /* LYS_CONFIG_R */
3977 config = 0;
3978 }
3979
Michal Vasko14654712020-02-06 08:35:21 +01003980 /* we forbid referencing nested lists because it is unspecified what instance of such a list to use */
3981 for (parent = (*key)->parent; parent != (struct lysc_node *)list; parent = parent->parent) {
3982 if (parent->nodetype == LYS_LIST) {
3983 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003984 "Unique statement \"%s\" refers to a leaf in nested list \"%s\".", uniques[v].str, parent->name);
Michal Vasko14654712020-02-06 08:35:21 +01003985 return LY_EVALID;
3986 }
3987 }
3988
Radek Krejci7af64242019-02-18 13:07:53 +01003989 /* check status */
3990 LY_CHECK_RET(lysc_check_status(ctx, list->flags, list->module, list->name,
Radek Krejci0f969882020-08-21 16:56:47 +02003991 (*key)->flags, (*key)->module, (*key)->name));
Radek Krejci7af64242019-02-18 13:07:53 +01003992
3993 /* mark leaf as unique */
3994 (*key)->flags |= LYS_UNIQUE;
3995
3996 /* next unique value in line */
3997 keystr = delim;
3998 }
3999 /* next unique definition */
4000 }
4001
4002 return LY_SUCCESS;
4003}
4004
4005/**
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004006 * @brief Compile parsed list node information.
4007 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02004008 * @param[in] pnode Parsed list node.
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004009 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
4010 * is enriched with the list-specific information.
4011 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
4012 */
4013static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004014lys_compile_node_list(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004015{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004016 struct lysp_node_list *list_p = (struct lysp_node_list *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02004017 struct lysc_node_list *list = (struct lysc_node_list *)node;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004018 struct lysp_node *child_p;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004019 struct lysc_node_leaf *key, *prev_key = NULL;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004020 size_t len;
Radek Krejci1deb5be2020-08-26 16:43:36 +02004021 LY_ARRAY_COUNT_TYPE u;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004022 const char *keystr, *delim;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004023 LY_ERR ret = LY_SUCCESS;
4024
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004025 list->min = list_p->min;
Radek Krejcife909632019-02-12 15:34:42 +01004026 if (list->min) {
4027 list->flags |= LYS_MAND_TRUE;
4028 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004029 list->max = list_p->max ? list_p->max : (uint32_t)-1;
4030
4031 LY_LIST_FOR(list_p->child, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004032 LY_CHECK_RET(lys_compile_node(ctx, child_p, node, 0, NULL));
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004033 }
4034
Radek Krejcic71ac5b2019-09-10 15:34:22 +02004035 COMPILE_ARRAY_GOTO(ctx, list_p->musts, list->musts, u, lys_compile_must, ret, done);
Radek Krejci90d4e922020-10-12 15:55:33 +02004036 if (list_p->musts && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01004037 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02004038 LY_CHECK_RET(ly_set_add(&ctx->xpath, list, 0, NULL));
Michal Vasko5d8756a2019-11-07 15:21:00 +01004039 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004040
4041 /* keys */
4042 if ((list->flags & LYS_CONFIG_W) && (!list_p->key || !list_p->key[0])) {
4043 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Missing key in list representing configuration data.");
4044 return LY_EVALID;
4045 }
4046
4047 /* find all the keys (must be direct children) */
4048 keystr = list_p->key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004049 if (!keystr) {
4050 /* keyless list */
4051 list->flags |= LYS_KEYLESS;
4052 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004053 while (keystr) {
4054 delim = strpbrk(keystr, " \t\n");
4055 if (delim) {
4056 len = delim - keystr;
4057 while (isspace(*delim)) {
4058 ++delim;
4059 }
4060 } else {
4061 len = strlen(keystr);
4062 }
4063
4064 /* key node must be present */
Michal Vasko22df3f02020-08-24 13:29:22 +02004065 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 +02004066 if (!(key)) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004067 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02004068 "The list's key \"%.*s\" not found.", len, keystr);
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004069 return LY_EVALID;
4070 }
4071 /* keys must be unique */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004072 if (key->flags & LYS_KEY) {
4073 /* the node was already marked as a key */
4074 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004075 "Duplicated key identifier \"%.*s\".", len, keystr);
Radek Krejci0fe9b512019-07-26 17:51:05 +02004076 return LY_EVALID;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004077 }
Radek Krejci0fe9b512019-07-26 17:51:05 +02004078
Michal Vasko22df3f02020-08-24 13:29:22 +02004079 lysc_update_path(ctx, (struct lysc_node *)list, key->name);
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004080 /* key must have the same config flag as the list itself */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004081 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004082 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Key of the configuration list must not be status leaf.");
4083 return LY_EVALID;
4084 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004085 if (ctx->pmod->version < LYS_VERSION_1_1) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004086 /* YANG 1.0 denies key to be of empty type */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004087 if (key->type->basetype == LY_TYPE_EMPTY) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004088 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004089 "List's key cannot be of \"empty\" type until it is in YANG 1.1 module.");
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004090 return LY_EVALID;
4091 }
4092 } else {
4093 /* when and if-feature are illegal on list keys */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004094 if (key->when) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004095 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004096 "List's key must not have any \"when\" statement.");
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004097 return LY_EVALID;
4098 }
Radek Krejci0fe9b512019-07-26 17:51:05 +02004099 if (key->iffeatures) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004100 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004101 "List's key must not have any \"if-feature\" statement.");
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004102 return LY_EVALID;
4103 }
4104 }
Radek Krejci76b3e962018-12-14 17:01:25 +01004105
4106 /* check status */
4107 LY_CHECK_RET(lysc_check_status(ctx, list->flags, list->module, list->name,
Michal Vasko69730152020-10-09 16:30:07 +02004108 key->flags, key->module, key->name));
Radek Krejci76b3e962018-12-14 17:01:25 +01004109
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004110 /* ignore default values of the key */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004111 if (key->dflt) {
4112 key->dflt->realtype->plugin->free(ctx->ctx, key->dflt);
Michal Vaskofeca4fb2020-10-05 08:58:40 +02004113 lysc_type_free(ctx->ctx, (struct lysc_type *)key->dflt->realtype);
Radek Krejci0fe9b512019-07-26 17:51:05 +02004114 free(key->dflt);
4115 key->dflt = NULL;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004116 }
4117 /* mark leaf as key */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004118 key->flags |= LYS_KEY;
4119
4120 /* move it to the correct position */
Michal Vasko69730152020-10-09 16:30:07 +02004121 if ((prev_key && ((struct lysc_node *)prev_key != key->prev)) || (!prev_key && key->prev->next)) {
Radek Krejci0fe9b512019-07-26 17:51:05 +02004122 /* fix links in closest previous siblings of the key */
4123 if (key->next) {
4124 key->next->prev = key->prev;
4125 } else {
4126 /* last child */
4127 list->child->prev = key->prev;
4128 }
4129 if (key->prev->next) {
4130 key->prev->next = key->next;
4131 }
4132 /* fix links in the key */
4133 if (prev_key) {
Michal Vasko22df3f02020-08-24 13:29:22 +02004134 key->prev = (struct lysc_node *)prev_key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004135 key->next = prev_key->next;
4136 } else {
4137 key->prev = list->child->prev;
4138 key->next = list->child;
4139 }
4140 /* fix links in closes future siblings of the key */
4141 if (prev_key) {
4142 if (prev_key->next) {
Michal Vasko22df3f02020-08-24 13:29:22 +02004143 prev_key->next->prev = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004144 } else {
Michal Vasko22df3f02020-08-24 13:29:22 +02004145 list->child->prev = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004146 }
Michal Vasko22df3f02020-08-24 13:29:22 +02004147 prev_key->next = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004148 } else {
Michal Vasko22df3f02020-08-24 13:29:22 +02004149 list->child->prev = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004150 }
4151 /* fix links in parent */
4152 if (!key->prev->next) {
Michal Vasko22df3f02020-08-24 13:29:22 +02004153 list->child = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004154 }
4155 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004156
4157 /* next key value */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004158 prev_key = key;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004159 keystr = delim;
Radek Krejci327de162019-06-14 12:52:07 +02004160 lysc_update_path(ctx, NULL, NULL);
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004161 }
4162
4163 /* uniques */
4164 if (list_p->uniques) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004165 LY_CHECK_RET(lys_compile_node_list_unique(ctx, list_p->uniques, list));
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004166 }
4167
Michal Vasko7f45cf22020-10-01 12:49:44 +02004168 COMPILE_OP_ARRAY_GOTO(ctx, list_p->actions, list->actions, node, u, lys_compile_action, 0, ret, done);
4169 COMPILE_OP_ARRAY_GOTO(ctx, list_p->notifs, list->notifs, node, u, lys_compile_notif, 0, ret, done);
4170
4171 /* checks */
4172 if (list->min > list->max) {
4173 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 +02004174 list->min, list->max);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004175 return LY_EVALID;
4176 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004177
4178done:
4179 return ret;
4180}
4181
Radek Krejcib56c7502019-02-13 14:19:54 +01004182/**
4183 * @brief Do some checks and set the default choice's case.
4184 *
4185 * Selects (and stores into ::lysc_node_choice#dflt) the default case and set LYS_SET_DFLT flag on it.
4186 *
4187 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02004188 * @param[in] dflt Name of the default branch. Can even contain a prefix.
Radek Krejcib56c7502019-02-13 14:19:54 +01004189 * @param[in,out] ch The compiled choice node, its dflt member is filled to point to the default case node of the choice.
4190 * @return LY_ERR value.
4191 */
Radek Krejci76b3e962018-12-14 17:01:25 +01004192static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004193lys_compile_node_choice_dflt(struct lysc_ctx *ctx, struct lysp_qname *dflt, struct lysc_node_choice *ch)
Radek Krejci76b3e962018-12-14 17:01:25 +01004194{
Michal Vasko22df3f02020-08-24 13:29:22 +02004195 struct lysc_node *iter, *node = (struct lysc_node *)ch;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004196 const struct lys_module *mod;
Radek Krejci76b3e962018-12-14 17:01:25 +01004197 const char *prefix = NULL, *name;
4198 size_t prefix_len = 0;
4199
4200 /* 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 +02004201 name = strchr(dflt->str, ':');
Radek Krejci76b3e962018-12-14 17:01:25 +01004202 if (name) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004203 prefix = dflt->str;
Radek Krejci76b3e962018-12-14 17:01:25 +01004204 prefix_len = name - prefix;
4205 ++name;
4206 } else {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004207 name = dflt->str;
Radek Krejci76b3e962018-12-14 17:01:25 +01004208 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004209 if (prefix) {
4210 mod = ly_resolve_prefix(ctx->ctx, prefix, prefix_len, LY_PREF_SCHEMA, (void *)dflt->mod);
4211 if (!mod) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004212 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Default case prefix \"%.*s\" not found "
4213 "in imports of \"%s\".", prefix_len, prefix, LYSP_MODULE_NAME(dflt->mod));
Michal Vasko7f45cf22020-10-01 12:49:44 +02004214 return LY_EVALID;
4215 }
4216 } else {
4217 mod = node->module;
Radek Krejci76b3e962018-12-14 17:01:25 +01004218 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004219
4220 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 +01004221 if (!ch->dflt) {
4222 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004223 "Default case \"%s\" not found.", dflt->str);
Radek Krejci76b3e962018-12-14 17:01:25 +01004224 return LY_EVALID;
4225 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004226
Radek Krejci76b3e962018-12-14 17:01:25 +01004227 /* no mandatory nodes directly under the default case */
4228 LY_LIST_FOR(ch->dflt->child, iter) {
Michal Vasko22df3f02020-08-24 13:29:22 +02004229 if (iter->parent != (struct lysc_node *)ch->dflt) {
Radek Krejcife13da42019-02-15 14:51:01 +01004230 break;
4231 }
Radek Krejci76b3e962018-12-14 17:01:25 +01004232 if (iter->flags & LYS_MAND_TRUE) {
4233 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004234 "Mandatory node \"%s\" under the default case \"%s\".", iter->name, dflt->str);
Radek Krejci76b3e962018-12-14 17:01:25 +01004235 return LY_EVALID;
4236 }
4237 }
Radek Krejci76b3e962018-12-14 17:01:25 +01004238
Michal Vasko7f45cf22020-10-01 12:49:44 +02004239 if (ch->flags & LYS_MAND_TRUE) {
4240 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid mandatory choice with a default case.");
Radek Krejciccd20f12019-02-15 14:12:27 +01004241 return LY_EVALID;
4242 }
4243
Michal Vasko7f45cf22020-10-01 12:49:44 +02004244 ch->dflt->flags |= LYS_SET_DFLT;
Radek Krejciccd20f12019-02-15 14:12:27 +01004245 return LY_SUCCESS;
4246}
4247
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004248/**
Michal Vasko20424b42020-08-31 12:29:38 +02004249 * @brief Compile choice children.
4250 *
4251 * @param[in] ctx Compile context
4252 * @param[in] child_p Parsed choice children nodes.
4253 * @param[in] node Compiled choice node to compile and add children to.
4254 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
4255 */
4256static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004257lys_compile_node_choice_child(struct lysc_ctx *ctx, struct lysp_node *child_p, struct lysc_node *node,
4258 struct ly_set *child_set)
Michal Vasko20424b42020-08-31 12:29:38 +02004259{
4260 LY_ERR ret = LY_SUCCESS;
Radek Krejci8f5fad22020-09-15 16:50:54 +02004261 struct lysp_node *child_p_next = child_p->next;
Michal Vasko20424b42020-08-31 12:29:38 +02004262 struct lysp_node_case *cs_p;
4263
4264 if (child_p->nodetype == LYS_CASE) {
4265 /* standard case under choice */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004266 ret = lys_compile_node(ctx, child_p, node, 0, child_set);
Michal Vasko20424b42020-08-31 12:29:38 +02004267 } else {
4268 /* we need the implicit case first, so create a fake parsed case */
4269 cs_p = calloc(1, sizeof *cs_p);
4270 cs_p->nodetype = LYS_CASE;
Radek Krejci87e25252020-09-15 13:28:31 +02004271 DUP_STRING_GOTO(ctx->ctx, child_p->name, cs_p->name, ret, free_fake_node);
Michal Vasko20424b42020-08-31 12:29:38 +02004272 cs_p->child = child_p;
4273
4274 /* make the child the only case child */
Michal Vasko20424b42020-08-31 12:29:38 +02004275 child_p->next = NULL;
4276
4277 /* compile it normally */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004278 ret = lys_compile_node(ctx, (struct lysp_node *)cs_p, node, 0, child_set);
Michal Vasko20424b42020-08-31 12:29:38 +02004279
Radek Krejci87e25252020-09-15 13:28:31 +02004280free_fake_node:
Michal Vasko20424b42020-08-31 12:29:38 +02004281 /* free the fake parsed node and correct pointers back */
4282 cs_p->child = NULL;
4283 lysp_node_free(ctx->ctx, (struct lysp_node *)cs_p);
Radek Krejci8f5fad22020-09-15 16:50:54 +02004284 child_p->next = child_p_next;
Michal Vasko20424b42020-08-31 12:29:38 +02004285 }
4286
4287 return ret;
4288}
4289
4290/**
Radek Krejci056d0a82018-12-06 16:57:25 +01004291 * @brief Compile parsed choice node information.
Michal Vasko20424b42020-08-31 12:29:38 +02004292 *
Radek Krejci056d0a82018-12-06 16:57:25 +01004293 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02004294 * @param[in] pnode Parsed choice node.
Radek Krejci056d0a82018-12-06 16:57:25 +01004295 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
Radek Krejci76b3e962018-12-14 17:01:25 +01004296 * is enriched with the choice-specific information.
Radek Krejci056d0a82018-12-06 16:57:25 +01004297 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
4298 */
4299static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004300lys_compile_node_choice(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci056d0a82018-12-06 16:57:25 +01004301{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004302 struct lysp_node_choice *ch_p = (struct lysp_node_choice *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02004303 struct lysc_node_choice *ch = (struct lysc_node_choice *)node;
Michal Vasko20424b42020-08-31 12:29:38 +02004304 struct lysp_node *child_p;
Radek Krejci056d0a82018-12-06 16:57:25 +01004305 LY_ERR ret = LY_SUCCESS;
4306
Michal Vasko20424b42020-08-31 12:29:38 +02004307 assert(node->nodetype == LYS_CHOICE);
4308
Radek Krejci056d0a82018-12-06 16:57:25 +01004309 LY_LIST_FOR(ch_p->child, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004310 LY_CHECK_RET(lys_compile_node_choice_child(ctx, child_p, node, NULL));
Radek Krejci056d0a82018-12-06 16:57:25 +01004311 }
4312
4313 /* default branch */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004314 if (ch_p->dflt.str) {
4315 LY_CHECK_RET(lys_compile_node_choice_dflt(ctx, &ch_p->dflt, ch));
Radek Krejcia9026eb2018-12-12 16:04:47 +01004316 }
Radek Krejci056d0a82018-12-06 16:57:25 +01004317
Radek Krejci9800fb82018-12-13 14:26:23 +01004318 return ret;
4319}
4320
4321/**
4322 * @brief Compile parsed anydata or anyxml node information.
4323 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02004324 * @param[in] pnode Parsed anydata or anyxml node.
Radek Krejci9800fb82018-12-13 14:26:23 +01004325 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
4326 * is enriched with the any-specific information.
4327 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
4328 */
4329static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004330lys_compile_node_any(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci9800fb82018-12-13 14:26:23 +01004331{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004332 struct lysp_node_anydata *any_p = (struct lysp_node_anydata *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02004333 struct lysc_node_anydata *any = (struct lysc_node_anydata *)node;
Radek Krejci1deb5be2020-08-26 16:43:36 +02004334 LY_ARRAY_COUNT_TYPE u;
Radek Krejci9800fb82018-12-13 14:26:23 +01004335 LY_ERR ret = LY_SUCCESS;
4336
Radek Krejcic71ac5b2019-09-10 15:34:22 +02004337 COMPILE_ARRAY_GOTO(ctx, any_p->musts, any->musts, u, lys_compile_must, ret, done);
Radek Krejci90d4e922020-10-12 15:55:33 +02004338 if (any_p->musts && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01004339 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02004340 ret = ly_set_add(&ctx->xpath, any, 0, NULL);
4341 LY_CHECK_GOTO(ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01004342 }
Radek Krejci9800fb82018-12-13 14:26:23 +01004343
4344 if (any->flags & LYS_CONFIG_W) {
Radek Krejci5c4ed7b2020-08-12 11:29:44 +02004345 LOGWRN(ctx->ctx, "Use of %s to define configuration data is not recommended. %s",
Michal Vasko69730152020-10-09 16:30:07 +02004346 ly_stmt2str(any->nodetype == LYS_ANYDATA ? LY_STMT_ANYDATA : LY_STMT_ANYXML), ctx->path);
Radek Krejci9800fb82018-12-13 14:26:23 +01004347 }
Radek Krejci056d0a82018-12-06 16:57:25 +01004348done:
4349 return ret;
4350}
4351
Radek Krejcib56c7502019-02-13 14:19:54 +01004352/**
Michal Vasko795b3752020-07-13 15:24:27 +02004353 * @brief Connect the node into the siblings list and check its name uniqueness. Also,
4354 * keep specific order of augments targetting the same node.
Radek Krejci056d0a82018-12-06 16:57:25 +01004355 *
4356 * @param[in] ctx Compile context
4357 * @param[in] parent Parent node holding the children list, in case of node from a choice's case,
4358 * the choice itself is expected instead of a specific case node.
4359 * @param[in] node Schema node to connect into the list.
4360 * @return LY_ERR value - LY_SUCCESS or LY_EEXIST.
Radek Krejci1c54f462020-05-12 17:25:34 +02004361 * 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 +01004362 */
4363static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02004364lys_compile_node_connect(struct lysc_ctx *ctx, struct lysc_node *parent, struct lysc_node *node)
Radek Krejci056d0a82018-12-06 16:57:25 +01004365{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004366 struct lysc_node **children, *anchor = NULL;
4367 int insert_after = 0;
Radek Krejci056d0a82018-12-06 16:57:25 +01004368
Michal Vasko20424b42020-08-31 12:29:38 +02004369 node->parent = parent;
4370
4371 if (parent) {
4372 if (parent->nodetype == LYS_CHOICE) {
4373 assert(node->nodetype == LYS_CASE);
4374 children = (struct lysc_node **)&((struct lysc_node_choice *)parent)->cases;
4375 } else {
4376 children = lysc_node_children_p(parent, ctx->options);
4377 }
4378 assert(children);
4379
Radek Krejci056d0a82018-12-06 16:57:25 +01004380 if (!(*children)) {
4381 /* first child */
4382 *children = node;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004383 } else if (node->flags & LYS_KEY) {
4384 /* special handling of adding keys */
4385 assert(node->module == parent->module);
4386 anchor = *children;
4387 if (anchor->flags & LYS_KEY) {
4388 while ((anchor->flags & LYS_KEY) && anchor->next) {
4389 anchor = anchor->next;
4390 }
4391 /* insert after the last key */
4392 insert_after = 1;
4393 } /* else insert before anchor (at the beginning) */
4394 } else if ((*children)->prev->module == node->module) {
4395 /* last child is from the same module, keep the order and insert at the end */
4396 anchor = (*children)->prev;
4397 insert_after = 1;
4398 } else if (parent->module == node->module) {
4399 /* adding module child after some augments were connected */
4400 for (anchor = *children; anchor->module == node->module; anchor = anchor->next) {}
4401 } else {
4402 /* some augments are already connected and we are connecting new ones,
4403 * keep module name order and insert the node into the children list */
4404 anchor = *children;
4405 do {
4406 anchor = anchor->prev;
Michal Vasko795b3752020-07-13 15:24:27 +02004407
Michal Vasko7f45cf22020-10-01 12:49:44 +02004408 /* check that we have not found the last augment node from our module or
4409 * the first augment node from a "smaller" module or
4410 * the first node from a local module */
Michal Vasko69730152020-10-09 16:30:07 +02004411 if ((anchor->module == node->module) || (strcmp(anchor->module->name, node->module->name) < 0) ||
4412 (anchor->module == parent->module)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004413 /* insert after */
4414 insert_after = 1;
4415 break;
4416 }
4417
4418 /* we have traversed all the nodes, insert before anchor (as the first node) */
4419 } while (anchor->prev->next);
4420 }
4421
4422 /* insert */
4423 if (anchor) {
4424 if (insert_after) {
4425 node->next = anchor->next;
4426 node->prev = anchor;
4427 anchor->next = node;
4428 if (node->next) {
4429 /* middle node */
4430 node->next->prev = node;
4431 } else {
4432 /* last node */
4433 (*children)->prev = node;
4434 }
Michal Vasko795b3752020-07-13 15:24:27 +02004435 } else {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004436 node->next = anchor;
4437 node->prev = anchor->prev;
4438 anchor->prev = node;
4439 if (anchor == *children) {
4440 /* first node */
4441 *children = node;
4442 } else {
4443 /* middle node */
4444 node->prev->next = node;
4445 }
Michal Vasko795b3752020-07-13 15:24:27 +02004446 }
Michal Vasko20424b42020-08-31 12:29:38 +02004447 }
Radek Krejci056d0a82018-12-06 16:57:25 +01004448
Michal Vasko20424b42020-08-31 12:29:38 +02004449 /* check the name uniqueness (even for an only child, it may be in case) */
4450 if (lys_compile_node_uniqness(ctx, parent, node->name, node)) {
4451 return LY_EEXIST;
4452 }
4453 } else {
4454 /* top-level element */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004455 if (!ctx->cur_mod->compiled->data) {
4456 ctx->cur_mod->compiled->data = node;
Michal Vasko20424b42020-08-31 12:29:38 +02004457 } else {
4458 /* insert at the end of the module's top-level nodes list */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004459 ctx->cur_mod->compiled->data->prev->next = node;
4460 node->prev = ctx->cur_mod->compiled->data->prev;
4461 ctx->cur_mod->compiled->data->prev = node;
Michal Vasko20424b42020-08-31 12:29:38 +02004462 }
4463
4464 /* check the name uniqueness on top-level */
4465 if (lys_compile_node_uniqness(ctx, NULL, node->name, node)) {
4466 return LY_EEXIST;
Radek Krejci056d0a82018-12-06 16:57:25 +01004467 }
4468 }
Michal Vasko20424b42020-08-31 12:29:38 +02004469
Radek Krejci056d0a82018-12-06 16:57:25 +01004470 return LY_SUCCESS;
4471}
4472
Radek Krejci95710c92019-02-11 15:49:55 +01004473/**
Radek Krejcib56c7502019-02-13 14:19:54 +01004474 * @brief Prepare the case structure in choice node for the new data node.
4475 *
4476 * 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
4477 * created in the choice when the first child was processed.
4478 *
4479 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02004480 * @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 +02004481 * it is the LYS_CHOICE, LYS_AUGMENT or LYS_GROUPING node.
Radek Krejcib56c7502019-02-13 14:19:54 +01004482 * @param[in] ch The compiled choice structure where the new case structures are created (if needed).
4483 * @param[in] child The new data node being part of a case (no matter if explicit or implicit).
4484 * @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,
4485 * it is linked from the case structure only in case it is its first child.
Radek Krejci95710c92019-02-11 15:49:55 +01004486 */
Michal Vasko20424b42020-08-31 12:29:38 +02004487static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004488lys_compile_node_case(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci056d0a82018-12-06 16:57:25 +01004489{
Michal Vasko20424b42020-08-31 12:29:38 +02004490 struct lysp_node *child_p;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004491 struct lysp_node_case *cs_p = (struct lysp_node_case *)pnode;
Radek Krejci056d0a82018-12-06 16:57:25 +01004492
Michal Vasko7f45cf22020-10-01 12:49:44 +02004493 if (pnode->nodetype & (LYS_CHOICE | LYS_AUGMENT | LYS_GROUPING)) {
Radek Krejci056d0a82018-12-06 16:57:25 +01004494 /* we have to add an implicit case node into the parent choice */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004495 } else if (pnode->nodetype == LYS_CASE) {
Michal Vasko20424b42020-08-31 12:29:38 +02004496 /* explicit parent case */
4497 LY_LIST_FOR(cs_p->child, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004498 LY_CHECK_RET(lys_compile_node(ctx, child_p, node, 0, NULL));
Radek Krejci056d0a82018-12-06 16:57:25 +01004499 }
Radek Krejci95710c92019-02-11 15:49:55 +01004500 } else {
Michal Vasko20424b42020-08-31 12:29:38 +02004501 LOGINT_RET(ctx->ctx);
Radek Krejci056d0a82018-12-06 16:57:25 +01004502 }
Radek Krejci056d0a82018-12-06 16:57:25 +01004503
Michal Vasko20424b42020-08-31 12:29:38 +02004504 return LY_SUCCESS;
Radek Krejci056d0a82018-12-06 16:57:25 +01004505}
4506
Radek Krejcib56c7502019-02-13 14:19:54 +01004507/**
Radek Krejcib56c7502019-02-13 14:19:54 +01004508 * @brief Set LYS_MAND_TRUE flag for the non-presence container parents.
4509 *
4510 * A non-presence container is mandatory in case it has at least one mandatory children. This function propagate
4511 * the flag to such parents from a mandatory children.
4512 *
4513 * @param[in] parent A schema node to be examined if the mandatory child make it also mandatory.
4514 * @param[in] add Flag to distinguish adding the mandatory flag (new mandatory children appeared) or removing the flag
4515 * (mandatory children was removed).
4516 */
Radek Krejci1deb5be2020-08-26 16:43:36 +02004517static void
Radek Krejci857189e2020-09-01 13:26:36 +02004518lys_compile_mandatory_parents(struct lysc_node *parent, ly_bool add)
Radek Krejcife909632019-02-12 15:34:42 +01004519{
4520 struct lysc_node *iter;
4521
4522 if (add) { /* set flag */
Michal Vaskod989ba02020-08-24 10:59:24 +02004523 for ( ; parent && parent->nodetype == LYS_CONTAINER && !(parent->flags & LYS_MAND_TRUE) && !(parent->flags & LYS_PRESENCE);
Radek Krejcife909632019-02-12 15:34:42 +01004524 parent = parent->parent) {
4525 parent->flags |= LYS_MAND_TRUE;
4526 }
4527 } else { /* unset flag */
Michal Vaskod989ba02020-08-24 10:59:24 +02004528 for ( ; parent && parent->nodetype == LYS_CONTAINER && (parent->flags & LYS_MAND_TRUE); parent = parent->parent) {
Michal Vasko22df3f02020-08-24 13:29:22 +02004529 for (iter = (struct lysc_node *)lysc_node_children(parent, 0); iter; iter = iter->next) {
Radek Krejcif1421c22019-02-19 13:05:20 +01004530 if (iter->flags & LYS_MAND_TRUE) {
Radek Krejcife909632019-02-12 15:34:42 +01004531 /* there is another mandatory node */
4532 return;
4533 }
4534 }
4535 /* unset mandatory flag - there is no mandatory children in the non-presence container */
4536 parent->flags &= ~LYS_MAND_TRUE;
4537 }
4538 }
4539}
4540
Radek Krejci056d0a82018-12-06 16:57:25 +01004541/**
Radek Krejci3641f562019-02-13 15:38:40 +01004542 * @brief Compile the parsed augment connecting it into its target.
4543 *
4544 * It is expected that all the data referenced in path are present - augments are ordered so that augment B
4545 * targeting data from augment A is being compiled after augment A. Also the modules referenced in the path
4546 * are already implemented and compiled.
4547 *
4548 * @param[in] ctx Compile context.
4549 * @param[in] aug_p Parsed augment to compile.
Michal Vasko7f45cf22020-10-01 12:49:44 +02004550 * @param[in] target Target node of the augment.
Radek Krejci3641f562019-02-13 15:38:40 +01004551 * @return LY_SUCCESS on success.
4552 * @return LY_EVALID on failure.
4553 */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004554static LY_ERR
4555lys_compile_augment(struct lysc_ctx *ctx, struct lysp_augment *aug_p, struct lysc_node *target)
Radek Krejci3641f562019-02-13 15:38:40 +01004556{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004557 LY_ERR ret = LY_SUCCESS;
4558 struct lysp_node *pnode;
Radek Krejci3641f562019-02-13 15:38:40 +01004559 struct lysc_node *node;
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004560 struct lysc_when *when_shared = NULL;
4561 struct lysc_action **actions;
4562 struct lysc_notif **notifs;
Radek Krejci857189e2020-09-01 13:26:36 +02004563 ly_bool allow_mandatory = 0;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004564 LY_ARRAY_COUNT_TYPE u;
4565 struct ly_set child_set = {0};
4566 uint32_t i;
Radek Krejci3641f562019-02-13 15:38:40 +01004567
Michal Vasko7f45cf22020-10-01 12:49:44 +02004568 if (!(target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF))) {
4569 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
4570 "Augment's %s-schema-nodeid \"%s\" refers to a %s node which is not an allowed augment's target.",
4571 aug_p->nodeid[0] == '/' ? "absolute" : "descendant", aug_p->nodeid, lys_nodetype2str(target->nodetype));
4572 ret = LY_EVALID;
4573 goto cleanup;
Radek Krejci3641f562019-02-13 15:38:40 +01004574 }
4575
4576 /* check for mandatory nodes
4577 * - new cases augmenting some choice can have mandatory nodes
4578 * - mandatory nodes are allowed only in case the augmentation is made conditional with a when statement
4579 */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004580 if (aug_p->when || (target->nodetype == LYS_CHOICE) || (ctx->cur_mod == target->module)) {
Radek Krejci3641f562019-02-13 15:38:40 +01004581 allow_mandatory = 1;
4582 }
4583
Michal Vasko7f45cf22020-10-01 12:49:44 +02004584 LY_LIST_FOR(aug_p->child, pnode) {
Radek Krejci3641f562019-02-13 15:38:40 +01004585 /* 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 +02004586 if (((pnode->nodetype == LYS_CASE) && (target->nodetype != LYS_CHOICE)) ||
4587 ((pnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && !(target->nodetype & (LYS_CONTAINER | LYS_LIST))) ||
4588 ((pnode->nodetype == LYS_USES) && (target->nodetype == LYS_CHOICE))) {
Radek Krejci3641f562019-02-13 15:38:40 +01004589 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02004590 "Invalid augment of %s node which is not allowed to contain %s node \"%s\".",
4591 lys_nodetype2str(target->nodetype), lys_nodetype2str(pnode->nodetype), pnode->name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004592 ret = LY_EVALID;
4593 goto cleanup;
Radek Krejci3641f562019-02-13 15:38:40 +01004594 }
4595
4596 /* compile the children */
Michal Vasko20424b42020-08-31 12:29:38 +02004597 if (target->nodetype == LYS_CHOICE) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004598 LY_CHECK_GOTO(ret = lys_compile_node_choice_child(ctx, pnode, target, &child_set), cleanup);
Radek Krejci3641f562019-02-13 15:38:40 +01004599 } else {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004600 LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
Radek Krejci3641f562019-02-13 15:38:40 +01004601 }
4602
Michal Vasko7f45cf22020-10-01 12:49:44 +02004603 /* since the augment node is not present in the compiled tree, we need to pass some of its
4604 * statements to all its children */
4605 for (i = 0; i < child_set.count; ++i) {
4606 node = child_set.snodes[i];
4607 if (!allow_mandatory && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
4608 node->flags &= ~LYS_MAND_TRUE;
4609 lys_compile_mandatory_parents(target, 0);
4610 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004611 "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.", node->name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004612 ret = LY_EVALID;
4613 goto cleanup;
Radek Krejci7c7783d2020-04-08 15:34:39 +02004614 }
Radek Krejci3641f562019-02-13 15:38:40 +01004615
Michal Vasko7f45cf22020-10-01 12:49:44 +02004616 if (aug_p->when) {
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004617 /* pass augment's when to all the children */
4618 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_xpath_context(target), node, &when_shared);
4619 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci3641f562019-02-13 15:38:40 +01004620 }
4621 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004622 ly_set_erase(&child_set, NULL);
Radek Krejci3641f562019-02-13 15:38:40 +01004623 }
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004624
4625 switch (target->nodetype) {
4626 case LYS_CONTAINER:
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004627 actions = &((struct lysc_node_container *)target)->actions;
4628 notifs = &((struct lysc_node_container *)target)->notifs;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004629 break;
4630 case LYS_LIST:
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004631 actions = &((struct lysc_node_list *)target)->actions;
4632 notifs = &((struct lysc_node_list *)target)->notifs;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004633 break;
4634 default:
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004635 actions = NULL;
4636 notifs = NULL;
4637 break;
4638 }
4639
4640 if (aug_p->actions) {
4641 if (!actions) {
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004642 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02004643 "Invalid augment of %s node which is not allowed to contain RPC/action node \"%s\".",
4644 lys_nodetype2str(target->nodetype), aug_p->actions[0].name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004645 ret = LY_EVALID;
4646 goto cleanup;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004647 }
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004648
4649 /* compile actions into the target */
4650 COMPILE_OP_ARRAY_GOTO(ctx, aug_p->actions, *actions, target, u, lys_compile_action, 0, ret, cleanup);
4651
4652 if (aug_p->when) {
4653 /* inherit when */
4654 LY_ARRAY_FOR(*actions, u) {
4655 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_xpath_context(target),
4656 (struct lysc_node *)&(*actions)[u], &when_shared);
4657 LY_CHECK_GOTO(ret, cleanup);
4658 }
4659 }
4660 }
4661 if (aug_p->notifs) {
4662 if (!notifs) {
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004663 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02004664 "Invalid augment of %s node which is not allowed to contain notification node \"%s\".",
4665 lys_nodetype2str(target->nodetype), aug_p->notifs[0].name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004666 ret = LY_EVALID;
4667 goto cleanup;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004668 }
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004669
4670 /* compile notifications into the target */
4671 COMPILE_OP_ARRAY_GOTO(ctx, aug_p->notifs, *notifs, target, u, lys_compile_notif, 0, ret, cleanup);
4672
4673 if (aug_p->when) {
4674 /* inherit when */
4675 LY_ARRAY_FOR(*notifs, u) {
4676 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_xpath_context(target),
4677 (struct lysc_node *)&(*notifs)[u], &when_shared);
4678 LY_CHECK_GOTO(ret, cleanup);
4679 }
4680 }
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004681 }
Radek Krejci3641f562019-02-13 15:38:40 +01004682
Michal Vasko7f45cf22020-10-01 12:49:44 +02004683cleanup:
4684 ly_set_erase(&child_set, NULL);
Radek Krejci3641f562019-02-13 15:38:40 +01004685 return ret;
4686}
4687
4688/**
Michal Vasko601ddb32020-08-31 16:25:35 +02004689 * @brief Find grouping for a uses.
Radek Krejcie86bf772018-12-14 11:39:53 +01004690 *
Michal Vasko601ddb32020-08-31 16:25:35 +02004691 * @param[in] ctx Compile context.
4692 * @param[in] uses_p Parsed uses node.
4693 * @param[out] gpr_p Found grouping on success.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004694 * @param[out] grp_pmod Module of @p grp_p on success.
Michal Vasko601ddb32020-08-31 16:25:35 +02004695 * @return LY_ERR value.
Radek Krejcie86bf772018-12-14 11:39:53 +01004696 */
4697static LY_ERR
Michal Vasko601ddb32020-08-31 16:25:35 +02004698lys_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 +02004699 struct lysp_module **grp_pmod)
Radek Krejcie86bf772018-12-14 11:39:53 +01004700{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004701 struct lysp_node *pnode;
Michal Vasko601ddb32020-08-31 16:25:35 +02004702 struct lysp_grp *grp;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02004703 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004704 const char *id, *name, *prefix, *local_pref;
Radek Krejcie86bf772018-12-14 11:39:53 +01004705 size_t prefix_len, name_len;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004706 struct lysp_module *pmod, *found = NULL;
Michal Vasko601ddb32020-08-31 16:25:35 +02004707 struct lys_module *mod;
4708
4709 *grp_p = NULL;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004710 *grp_pmod = NULL;
Radek Krejcie86bf772018-12-14 11:39:53 +01004711
4712 /* search for the grouping definition */
Radek Krejcie86bf772018-12-14 11:39:53 +01004713 id = uses_p->name;
Radek Krejcib4a4a272019-06-10 12:44:52 +02004714 LY_CHECK_RET(ly_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len), LY_EVALID);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004715 local_pref = ctx->pmod->is_submod ? ((struct lysp_submodule *)ctx->pmod)->prefix : ctx->pmod->mod->prefix;
4716 if (!prefix || !ly_strncmp(local_pref, prefix, prefix_len)) {
4717 /* current module, search local groupings first */
4718 pmod = ctx->pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004719 for (pnode = uses_p->parent; !found && pnode; pnode = pnode->parent) {
4720 grp = (struct lysp_grp *)lysp_node_groupings(pnode);
Radek Krejcie86bf772018-12-14 11:39:53 +01004721 LY_ARRAY_FOR(grp, u) {
4722 if (!strcmp(grp[u].name, name)) {
4723 grp = &grp[u];
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004724 found = ctx->pmod;
Radek Krejcie86bf772018-12-14 11:39:53 +01004725 break;
4726 }
4727 }
4728 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004729 } else {
4730 /* foreign module, find it first */
4731 mod = lysp_module_find_prefix(ctx->pmod, prefix, prefix_len);
4732 if (!mod) {
4733 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
4734 "Invalid prefix used for grouping reference.", uses_p->name);
4735 return LY_EVALID;
4736 }
4737 pmod = mod->parsed;
Radek Krejcie86bf772018-12-14 11:39:53 +01004738 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004739
Radek Krejcie86bf772018-12-14 11:39:53 +01004740 if (!found) {
Radek Krejci76b3e962018-12-14 17:01:25 +01004741 /* search in top-level groupings of the main module ... */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004742 grp = pmod->groupings;
Michal Vasko601ddb32020-08-31 16:25:35 +02004743 LY_ARRAY_FOR(grp, u) {
4744 if (!strcmp(grp[u].name, name)) {
4745 grp = &grp[u];
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004746 found = pmod;
Michal Vasko601ddb32020-08-31 16:25:35 +02004747 break;
Radek Krejci76b3e962018-12-14 17:01:25 +01004748 }
4749 }
Michal Vasko601ddb32020-08-31 16:25:35 +02004750 if (!found) {
Radek Krejci76b3e962018-12-14 17:01:25 +01004751 /* ... and all the submodules */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004752 LY_ARRAY_FOR(pmod->includes, u) {
4753 grp = pmod->includes[u].submodule->groupings;
Michal Vasko601ddb32020-08-31 16:25:35 +02004754 LY_ARRAY_FOR(grp, v) {
4755 if (!strcmp(grp[v].name, name)) {
4756 grp = &grp[v];
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004757 found = (struct lysp_module *)pmod->includes[u].submodule;
Michal Vasko601ddb32020-08-31 16:25:35 +02004758 break;
Radek Krejci76b3e962018-12-14 17:01:25 +01004759 }
4760 }
Michal Vasko601ddb32020-08-31 16:25:35 +02004761 if (found) {
4762 break;
4763 }
Radek Krejcie86bf772018-12-14 11:39:53 +01004764 }
4765 }
4766 }
4767 if (!found) {
4768 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004769 "Grouping \"%s\" referenced by a uses statement not found.", uses_p->name);
Radek Krejcie86bf772018-12-14 11:39:53 +01004770 return LY_EVALID;
4771 }
4772
Radek Krejci90d4e922020-10-12 15:55:33 +02004773 if (!(ctx->options & LYS_COMPILE_GROUPING)) {
Radek Krejcif2de0ed2019-05-02 14:13:18 +02004774 /* remember that the grouping is instantiated to avoid its standalone validation */
4775 grp->flags |= LYS_USED_GRP;
4776 }
Radek Krejcie86bf772018-12-14 11:39:53 +01004777
Michal Vasko601ddb32020-08-31 16:25:35 +02004778 *grp_p = grp;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004779 *grp_pmod = found;
Michal Vasko601ddb32020-08-31 16:25:35 +02004780 return LY_SUCCESS;
4781}
Radek Krejcie86bf772018-12-14 11:39:53 +01004782
Michal Vasko7f45cf22020-10-01 12:49:44 +02004783static const struct lys_module *lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004784 size_t nametest_len, const struct lysp_module *mod, const char **name, size_t *name_len);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004785
Michal Vasko601ddb32020-08-31 16:25:35 +02004786static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004787lys_nodeid_check(struct lysc_ctx *ctx, const char *nodeid, ly_bool abs, struct lys_module **target_mod,
4788 struct lyxp_expr **expr)
Michal Vasko601ddb32020-08-31 16:25:35 +02004789{
Michal Vasko601ddb32020-08-31 16:25:35 +02004790 LY_ERR ret = LY_SUCCESS;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004791 struct lyxp_expr *e = NULL;
4792 struct lys_module *tmod = NULL, *mod;
4793 const char *nodeid_type = abs ? "absolute-schema-nodeid" : "descendant-schema-nodeid";
4794 uint32_t i;
Radek Krejcie86bf772018-12-14 11:39:53 +01004795
Michal Vasko7f45cf22020-10-01 12:49:44 +02004796 /* parse */
4797 ret = lyxp_expr_parse(ctx->ctx, nodeid, strlen(nodeid), 0, &e);
4798 if (ret) {
4799 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid %s value \"%s\" - invalid syntax.",
4800 nodeid_type, nodeid);
4801 ret = LY_EVALID;
4802 goto cleanup;
Radek Krejci01342af2019-01-03 15:18:08 +01004803 }
Radek Krejcie86bf772018-12-14 11:39:53 +01004804
Michal Vasko7f45cf22020-10-01 12:49:44 +02004805 if (abs) {
4806 /* absolute schema nodeid */
4807 i = 0;
4808 } else {
4809 /* descendant schema nodeid */
4810 if (e->tokens[0] != LYXP_TOKEN_NAMETEST) {
4811 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
4812 nodeid_type, nodeid, e->tok_len[0], e->expr + e->tok_pos[0]);
Michal Vasko20424b42020-08-31 12:29:38 +02004813 ret = LY_EVALID;
Radek Krejcifc11bd72019-04-11 16:00:05 +02004814 goto cleanup;
Radek Krejcif2271f12019-01-07 16:42:23 +01004815 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004816 i = 1;
4817 }
Radek Krejcif2271f12019-01-07 16:42:23 +01004818
Michal Vasko7f45cf22020-10-01 12:49:44 +02004819 /* check all the tokens */
4820 for ( ; i < e->used; i += 2) {
4821 if (e->tokens[i] != LYXP_TOKEN_OPER_PATH) {
4822 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s value \"%s\" - \"/\" expected instead of \"%.*s\".",
4823 nodeid_type, nodeid, e->tok_len[i], e->expr + e->tok_pos[i]);
4824 ret = LY_EVALID;
4825 goto cleanup;
4826 } else if (e->used == i + 1) {
4827 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
4828 "Invalid %s value \"%s\" - unexpected end of expression.", nodeid_type, e->expr);
4829 ret = LY_EVALID;
4830 goto cleanup;
4831 } else if (e->tokens[i + 1] != LYXP_TOKEN_NAMETEST) {
4832 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
4833 nodeid_type, nodeid, e->tok_len[i + 1], e->expr + e->tok_pos[i + 1]);
4834 ret = LY_EVALID;
4835 goto cleanup;
4836 } else if (abs) {
4837 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 +02004838 e->tok_len[i + 1], ctx->pmod, NULL, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004839 LY_CHECK_ERR_GOTO(!mod, ret = LY_EVALID, cleanup);
4840
4841 /* only keep the first module */
4842 if (!tmod) {
4843 tmod = mod;
Radek Krejcif2271f12019-01-07 16:42:23 +01004844 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004845
4846 /* all the modules must be implemented */
4847 if (!mod->implemented) {
Michal Vasko89b5c072020-10-06 13:52:44 +02004848 ret = lys_set_implemented(mod);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004849 LY_CHECK_GOTO(ret, cleanup);
4850 }
4851 }
4852 }
4853
4854cleanup:
4855 if (ret || !expr) {
4856 lyxp_expr_free(ctx->ctx, e);
4857 e = NULL;
4858 }
4859 if (expr) {
4860 *expr = ret ? NULL : e;
4861 }
4862 if (target_mod) {
4863 *target_mod = ret ? NULL : tmod;
4864 }
4865 return ret;
4866}
4867
4868/**
4869 * @brief Check whether 2 schema nodeids match.
4870 *
4871 * @param[in] ctx libyang context.
4872 * @param[in] exp1 First schema nodeid.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004873 * @param[in] exp1p_mod Module of @p exp1 nodes without any prefix.
Michal Vasko7f45cf22020-10-01 12:49:44 +02004874 * @param[in] exp2 Second schema nodeid.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004875 * @param[in] exp2_pmod Module of @p exp2 nodes without any prefix.
Michal Vasko7f45cf22020-10-01 12:49:44 +02004876 * @return Whether the schema nodeids match or not.
4877 */
4878static ly_bool
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004879lys_abs_schema_nodeid_match(const struct ly_ctx *ctx, const struct lyxp_expr *exp1, const struct lysp_module *exp1_pmod,
4880 const struct lyxp_expr *exp2, const struct lysp_module *exp2_pmod)
Michal Vasko7f45cf22020-10-01 12:49:44 +02004881{
4882 uint32_t i;
4883 const struct lys_module *mod1, *mod2;
4884 const char *name1, *name2;
4885 size_t name1_len, name2_len;
4886
4887 if (exp1->used != exp2->used) {
4888 return 0;
4889 }
4890
4891 for (i = 0; i < exp1->used; ++i) {
4892 assert(exp1->tokens[i] == exp2->tokens[i]);
4893
4894 if (exp1->tokens[i] == LYXP_TOKEN_NAMETEST) {
4895 /* check modules of all the nodes in the node ID */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004896 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 +02004897 &name1, &name1_len);
4898 assert(mod1);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004899 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 +02004900 &name2, &name2_len);
4901 assert(mod2);
4902
4903 /* compare modules */
4904 if (mod1 != mod2) {
4905 return 0;
4906 }
4907
4908 /* compare names */
4909 if ((name1_len != name2_len) || strncmp(name1, name2, name1_len)) {
4910 return 0;
4911 }
4912 }
4913 }
4914
4915 return 1;
4916}
4917
4918/**
4919 * @brief Prepare any uses augments and refines in the context to be applied during uses descendant node compilation.
4920 *
4921 * @param[in] ctx Compile context.
4922 * @param[in] uses_p Parsed uses structure with augments and refines.
4923 * @param[in] ctx_node Context node of @p uses_p meaning its first data definiition parent.
4924 * @return LY_ERR value.
4925 */
4926static LY_ERR
4927lys_precompile_uses_augments_refines(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, const struct lysc_node *ctx_node)
4928{
4929 LY_ERR ret = LY_SUCCESS;
4930 LY_ARRAY_COUNT_TYPE u;
4931 struct lyxp_expr *exp = NULL;
4932 struct lysc_augment *aug;
4933 struct lysc_refine *rfn;
4934 struct lysp_refine **new_rfn;
4935 uint32_t i;
4936
4937 LY_ARRAY_FOR(uses_p->augments, u) {
4938 lysc_update_path(ctx, NULL, "{augment}");
4939 lysc_update_path(ctx, NULL, uses_p->augments[u].nodeid);
4940
4941 /* parse the nodeid */
4942 LY_CHECK_GOTO(ret = lys_nodeid_check(ctx, uses_p->augments[u].nodeid, 0, NULL, &exp), cleanup);
4943
4944 /* allocate new compiled augment and store it in the set */
4945 aug = calloc(1, sizeof *aug);
4946 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci3d92e442020-10-12 12:48:13 +02004947 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_augs, aug, 1, NULL), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004948
4949 aug->nodeid = exp;
4950 exp = NULL;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004951 aug->nodeid_pmod = ctx->pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004952 aug->nodeid_ctx_node = ctx_node;
4953 aug->aug_p = &uses_p->augments[u];
4954
4955 lysc_update_path(ctx, NULL, NULL);
4956 lysc_update_path(ctx, NULL, NULL);
4957 }
4958
4959 LY_ARRAY_FOR(uses_p->refines, u) {
4960 lysc_update_path(ctx, NULL, "{refine}");
4961 lysc_update_path(ctx, NULL, uses_p->refines[u].nodeid);
4962
4963 /* parse the nodeid */
4964 LY_CHECK_GOTO(ret = lys_nodeid_check(ctx, uses_p->refines[u].nodeid, 0, NULL, &exp), cleanup);
4965
4966 /* try to find the node in already compiled refines */
4967 rfn = NULL;
4968 for (i = 0; i < ctx->uses_rfns.count; ++i) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004969 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, ctx->pmod, ((struct lysc_refine *)ctx->uses_rfns.objs[i])->nodeid,
4970 ctx->pmod)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004971 rfn = ctx->uses_rfns.objs[i];
4972 break;
Radek Krejcif2271f12019-01-07 16:42:23 +01004973 }
4974 }
Michal Vasko601ddb32020-08-31 16:25:35 +02004975
Michal Vasko7f45cf22020-10-01 12:49:44 +02004976 if (!rfn) {
4977 /* allocate new compiled refine */
4978 rfn = calloc(1, sizeof *rfn);
4979 LY_CHECK_ERR_GOTO(!rfn, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci3d92e442020-10-12 12:48:13 +02004980 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_rfns, rfn, 1, NULL), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004981
4982 rfn->nodeid = exp;
4983 exp = NULL;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004984 rfn->nodeid_pmod = ctx->pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004985 rfn->nodeid_ctx_node = ctx_node;
4986 } else {
4987 /* just free exp */
4988 lyxp_expr_free(ctx->ctx, exp);
4989 exp = NULL;
4990 }
4991
4992 /* add new parsed refine structure */
4993 LY_ARRAY_NEW_GOTO(ctx->ctx, rfn->rfns, new_rfn, ret, cleanup);
4994 *new_rfn = &uses_p->refines[u];
4995
4996 lysc_update_path(ctx, NULL, NULL);
Michal Vasko601ddb32020-08-31 16:25:35 +02004997 lysc_update_path(ctx, NULL, NULL);
Radek Krejcif2271f12019-01-07 16:42:23 +01004998 }
4999
Michal Vasko601ddb32020-08-31 16:25:35 +02005000cleanup:
Michal Vasko7f45cf22020-10-01 12:49:44 +02005001 lyxp_expr_free(ctx->ctx, exp);
Michal Vasko601ddb32020-08-31 16:25:35 +02005002 return ret;
5003}
5004
5005/**
5006 * @brief Compile parsed uses statement - resolve target grouping and connect its content into parent.
5007 * If present, also apply uses's modificators.
5008 *
5009 * @param[in] ctx Compile context
5010 * @param[in] uses_p Parsed uses schema node.
5011 * @param[in] parent Compiled parent node where the content of the referenced grouping is supposed to be connected. It is
5012 * NULL for top-level nodes, in such a case the module where the node will be connected is taken from
5013 * the compile context.
5014 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
5015 */
5016static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02005017lys_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 +02005018{
Michal Vasko7f45cf22020-10-01 12:49:44 +02005019 struct lysp_node *pnode;
5020 struct lysc_node *child;
Michal Vasko601ddb32020-08-31 16:25:35 +02005021 struct lysp_grp *grp = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005022 uint32_t i, grp_stack_count;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005023 struct lysp_module *grp_mod, *mod_old = ctx->pmod;
Michal Vasko601ddb32020-08-31 16:25:35 +02005024 LY_ERR ret = LY_SUCCESS;
Michal Vaskoceab6dd2020-10-09 16:53:36 +02005025 struct lysc_when *when_shared = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005026 LY_ARRAY_COUNT_TYPE u;
Michal Vasko601ddb32020-08-31 16:25:35 +02005027 struct lysc_notif **notifs = NULL;
5028 struct lysc_action **actions = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005029 struct ly_set uses_child_set = {0};
Michal Vasko601ddb32020-08-31 16:25:35 +02005030
5031 /* find the referenced grouping */
5032 LY_CHECK_RET(lys_compile_uses_find_grouping(ctx, uses_p, &grp, &grp_mod));
5033
5034 /* grouping must not reference themselves - stack in ctx maintains list of groupings currently being applied */
5035 grp_stack_count = ctx->groupings.count;
5036 LY_CHECK_RET(ly_set_add(&ctx->groupings, (void *)grp, 0, NULL));
5037 if (grp_stack_count == ctx->groupings.count) {
5038 /* the target grouping is already in the stack, so we are already inside it -> circular dependency */
5039 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02005040 "Grouping \"%s\" references itself through a uses statement.", grp->name);
Michal Vasko601ddb32020-08-31 16:25:35 +02005041 return LY_EVALID;
5042 }
5043
Michal Vasko7f45cf22020-10-01 12:49:44 +02005044 /* check status */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005045 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 +02005046 LY_CHECK_GOTO(ret, cleanup);
5047
5048 /* compile any augments and refines so they can be applied during the grouping nodes compilation */
5049 ret = lys_precompile_uses_augments_refines(ctx, uses_p, parent);
5050 LY_CHECK_GOTO(ret, cleanup);
5051
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005052 /* switch context's parsed module being processed */
5053 ctx->pmod = grp_mod;
Michal Vasko601ddb32020-08-31 16:25:35 +02005054
Michal Vasko601ddb32020-08-31 16:25:35 +02005055 /* compile data nodes */
Michal Vasko7f45cf22020-10-01 12:49:44 +02005056 LY_LIST_FOR(grp->data, pnode) {
Michal Vasko601ddb32020-08-31 16:25:35 +02005057 /* 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 +02005058 ret = lys_compile_node(ctx, pnode, parent, (uses_p->flags & LYS_STATUS_MASK) | 0x3, &uses_child_set);
Michal Vasko601ddb32020-08-31 16:25:35 +02005059 LY_CHECK_GOTO(ret, cleanup);
5060 }
5061
Michal Vasko7f45cf22020-10-01 12:49:44 +02005062 if (child_set) {
5063 /* add these children to our compiled child_set as well since uses is a schema-only node */
Radek Krejci3d92e442020-10-12 12:48:13 +02005064 LY_CHECK_GOTO(ret = ly_set_merge(child_set, &uses_child_set, 1, NULL), cleanup);
Michal Vasko601ddb32020-08-31 16:25:35 +02005065 }
5066
Michal Vasko7f45cf22020-10-01 12:49:44 +02005067 if (uses_p->when) {
Michal Vaskoceab6dd2020-10-09 16:53:36 +02005068 /* pass uses's when to all the data children */
Michal Vasko7f45cf22020-10-01 12:49:44 +02005069 for (i = 0; i < uses_child_set.count; ++i) {
5070 child = uses_child_set.snodes[i];
5071
Michal Vaskoceab6dd2020-10-09 16:53:36 +02005072 ret = lys_compile_when(ctx, uses_p->when, uses_p->flags, lysc_xpath_context(parent), child, &when_shared);
5073 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko601ddb32020-08-31 16:25:35 +02005074 }
5075 }
5076
5077 /* compile actions */
Michal Vasko7f45cf22020-10-01 12:49:44 +02005078 if (grp->actions) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005079 actions = parent ? lysc_node_actions_p(parent) : &ctx->cur_mod->compiled->rpcs;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005080 if (!actions) {
5081 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 +02005082 grp->actions[0].name, lys_nodetype2str(grp->actions[0].nodetype), parent->name,
5083 lys_nodetype2str(parent->nodetype));
Michal Vasko7f45cf22020-10-01 12:49:44 +02005084 ret = LY_EVALID;
5085 goto cleanup;
Michal Vasko601ddb32020-08-31 16:25:35 +02005086 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02005087 COMPILE_OP_ARRAY_GOTO(ctx, grp->actions, *actions, parent, u, lys_compile_action, 0, ret, cleanup);
Michal Vaskoceab6dd2020-10-09 16:53:36 +02005088
5089 if (uses_p->when) {
5090 /* inherit when */
5091 LY_ARRAY_FOR(*actions, u) {
5092 ret = lys_compile_when(ctx, uses_p->when, uses_p->flags, lysc_xpath_context(parent),
5093 (struct lysc_node *)&(*actions)[u], &when_shared);
5094 LY_CHECK_GOTO(ret, cleanup);
5095 }
5096 }
Michal Vasko601ddb32020-08-31 16:25:35 +02005097 }
5098
5099 /* compile notifications */
Michal Vasko7f45cf22020-10-01 12:49:44 +02005100 if (grp->notifs) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005101 notifs = parent ? lysc_node_notifs_p(parent) : &ctx->cur_mod->compiled->notifs;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005102 if (!notifs) {
5103 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 +02005104 grp->notifs[0].name, lys_nodetype2str(grp->notifs[0].nodetype), parent->name,
5105 lys_nodetype2str(parent->nodetype));
Michal Vasko7f45cf22020-10-01 12:49:44 +02005106 ret = LY_EVALID;
5107 goto cleanup;
Michal Vasko601ddb32020-08-31 16:25:35 +02005108 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02005109 COMPILE_OP_ARRAY_GOTO(ctx, grp->notifs, *notifs, parent, u, lys_compile_notif, 0, ret, cleanup);
Michal Vaskoceab6dd2020-10-09 16:53:36 +02005110
5111 if (uses_p->when) {
5112 /* inherit when */
5113 LY_ARRAY_FOR(*notifs, u) {
5114 ret = lys_compile_when(ctx, uses_p->when, uses_p->flags, lysc_xpath_context(parent),
5115 (struct lysc_node *)&(*notifs)[u], &when_shared);
5116 LY_CHECK_GOTO(ret, cleanup);
5117 }
5118 }
Michal Vasko601ddb32020-08-31 16:25:35 +02005119 }
5120
Michal Vasko7f45cf22020-10-01 12:49:44 +02005121 /* check that all augments were applied */
5122 for (i = 0; i < ctx->uses_augs.count; ++i) {
5123 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02005124 "Augment target node \"%s\" in grouping \"%s\" was not found.",
Michal Vasko891d7532020-10-07 09:41:38 +02005125 ((struct lysc_augment *)ctx->uses_augs.objs[i])->nodeid->expr, grp->name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005126 ret = LY_ENOTFOUND;
Michal Vasko601ddb32020-08-31 16:25:35 +02005127 }
Michal Vasko601ddb32020-08-31 16:25:35 +02005128 LY_CHECK_GOTO(ret, cleanup);
5129
Michal Vasko7f45cf22020-10-01 12:49:44 +02005130 /* check that all refines were applied */
5131 for (i = 0; i < ctx->uses_rfns.count; ++i) {
5132 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02005133 "Refine(s) target node \"%s\" in grouping \"%s\" was not found.",
Michal Vasko891d7532020-10-07 09:41:38 +02005134 ((struct lysc_refine *)ctx->uses_rfns.objs[i])->nodeid->expr, grp->name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005135 ret = LY_ENOTFOUND;
Radek Krejcic6b4f442020-08-12 14:45:18 +02005136 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02005137 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcifc11bd72019-04-11 16:00:05 +02005138
5139cleanup:
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005140 /* reload previous context's parsed module being processed */
5141 ctx->pmod = mod_old;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005142
Radek Krejcie86bf772018-12-14 11:39:53 +01005143 /* remove the grouping from the stack for circular groupings dependency check */
5144 ly_set_rm_index(&ctx->groupings, ctx->groupings.count - 1, NULL);
5145 assert(ctx->groupings.count == grp_stack_count);
5146
Michal Vasko7f45cf22020-10-01 12:49:44 +02005147 ly_set_erase(&uses_child_set, NULL);
Radek Krejcie86bf772018-12-14 11:39:53 +01005148 return ret;
5149}
5150
Radek Krejci327de162019-06-14 12:52:07 +02005151static int
5152lys_compile_grouping_pathlog(struct lysc_ctx *ctx, struct lysp_node *node, char **path)
5153{
5154 struct lysp_node *iter;
5155 int len = 0;
5156
5157 *path = NULL;
5158 for (iter = node; iter && len >= 0; iter = iter->parent) {
5159 char *s = *path;
5160 char *id;
5161
5162 switch (iter->nodetype) {
5163 case LYS_USES:
Radek Krejci200f1062020-07-11 22:51:03 +02005164 LY_CHECK_RET(asprintf(&id, "{uses='%s'}", iter->name) == -1, -1);
Radek Krejci327de162019-06-14 12:52:07 +02005165 break;
5166 case LYS_GROUPING:
Radek Krejci200f1062020-07-11 22:51:03 +02005167 LY_CHECK_RET(asprintf(&id, "{grouping='%s'}", iter->name) == -1, -1);
Radek Krejci327de162019-06-14 12:52:07 +02005168 break;
5169 case LYS_AUGMENT:
Radek Krejci200f1062020-07-11 22:51:03 +02005170 LY_CHECK_RET(asprintf(&id, "{augment='%s'}", iter->name) == -1, -1);
Radek Krejci327de162019-06-14 12:52:07 +02005171 break;
5172 default:
5173 id = strdup(iter->name);
5174 break;
5175 }
5176
5177 if (!iter->parent) {
5178 /* print prefix */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005179 len = asprintf(path, "/%s:%s%s", ctx->cur_mod->name, id, s ? s : "");
Radek Krejci327de162019-06-14 12:52:07 +02005180 } else {
5181 /* prefix is the same as in parent */
5182 len = asprintf(path, "/%s%s", id, s ? s : "");
5183 }
5184 free(s);
5185 free(id);
5186 }
5187
5188 if (len < 0) {
5189 free(*path);
5190 *path = NULL;
5191 } else if (len == 0) {
5192 *path = strdup("/");
5193 len = 1;
5194 }
5195 return len;
5196}
5197
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005198/**
5199 * @brief Validate groupings that were defined but not directly used in the schema itself.
5200 *
5201 * The grouping does not need to be compiled (and it is compiled here, but the result is forgotten immediately),
5202 * but to have the complete result of the schema validity, even such groupings are supposed to be checked.
5203 */
5204static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02005205lys_compile_grouping(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysp_grp *grp)
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005206{
5207 LY_ERR ret;
Radek Krejci327de162019-06-14 12:52:07 +02005208 char *path;
5209 int len;
5210
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005211 struct lysp_node_uses fake_uses = {
Michal Vasko7f45cf22020-10-01 12:49:44 +02005212 .parent = pnode,
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005213 .nodetype = LYS_USES,
5214 .flags = 0, .next = NULL,
5215 .name = grp->name,
5216 .dsc = NULL, .ref = NULL, .when = NULL, .iffeatures = NULL, .exts = NULL,
5217 .refines = NULL, .augments = NULL
5218 };
5219 struct lysc_node_container fake_container = {
5220 .nodetype = LYS_CONTAINER,
Michal Vasko7f45cf22020-10-01 12:49:44 +02005221 .flags = pnode ? (pnode->flags & LYS_FLAGS_COMPILED_MASK) : 0,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005222 .module = ctx->cur_mod,
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005223 .sp = NULL, .parent = NULL, .next = NULL,
Michal Vasko22df3f02020-08-24 13:29:22 +02005224 .prev = (struct lysc_node *)&fake_container,
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005225 .name = "fake",
5226 .dsc = NULL, .ref = NULL, .exts = NULL, .iffeatures = NULL, .when = NULL,
5227 .child = NULL, .musts = NULL, .actions = NULL, .notifs = NULL
5228 };
5229
5230 if (grp->parent) {
5231 LOGWRN(ctx->ctx, "Locally scoped grouping \"%s\" not used.", grp->name);
5232 }
Radek Krejci327de162019-06-14 12:52:07 +02005233
5234 len = lys_compile_grouping_pathlog(ctx, grp->parent, &path);
5235 if (len < 0) {
5236 LOGMEM(ctx->ctx);
5237 return LY_EMEM;
5238 }
5239 strncpy(ctx->path, path, LYSC_CTX_BUFSIZE - 1);
Radek Krejci1deb5be2020-08-26 16:43:36 +02005240 ctx->path_len = (uint32_t)len;
Radek Krejci327de162019-06-14 12:52:07 +02005241 free(path);
5242
5243 lysc_update_path(ctx, NULL, "{grouping}");
5244 lysc_update_path(ctx, NULL, grp->name);
Michal Vasko22df3f02020-08-24 13:29:22 +02005245 ret = lys_compile_uses(ctx, &fake_uses, (struct lysc_node *)&fake_container, NULL);
Radek Krejci327de162019-06-14 12:52:07 +02005246 lysc_update_path(ctx, NULL, NULL);
5247 lysc_update_path(ctx, NULL, NULL);
5248
5249 ctx->path_len = 1;
5250 ctx->path[1] = '\0';
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005251
5252 /* cleanup */
5253 lysc_node_container_free(ctx->ctx, &fake_container);
5254
5255 return ret;
5256}
Radek Krejcife909632019-02-12 15:34:42 +01005257
Radek Krejcie86bf772018-12-14 11:39:53 +01005258/**
Michal Vasko20424b42020-08-31 12:29:38 +02005259 * @brief Set config flags for a node.
5260 *
5261 * @param[in] ctx Compile context.
5262 * @param[in] node Compiled node config to set.
5263 * @param[in] parent Parent of @p node.
5264 * @return LY_ERR value.
5265 */
5266static LY_ERR
5267lys_compile_config(struct lysc_ctx *ctx, struct lysc_node *node, struct lysc_node *parent)
5268{
5269 if (node->nodetype == LYS_CASE) {
5270 /* case never has any config */
5271 assert(!(node->flags & LYS_CONFIG_MASK));
5272 return LY_SUCCESS;
5273 }
5274
5275 /* adjust parent to always get the ancestor with config */
5276 if (parent && (parent->nodetype == LYS_CASE)) {
5277 parent = parent->parent;
5278 assert(parent);
5279 }
5280
Radek Krejci90d4e922020-10-12 15:55:33 +02005281 if (ctx->options & (LYS_COMPILE_RPC_INPUT | LYS_COMPILE_RPC_OUTPUT)) {
Michal Vasko20424b42020-08-31 12:29:38 +02005282 /* ignore config statements inside RPC/action data */
5283 node->flags &= ~LYS_CONFIG_MASK;
Radek Krejci90d4e922020-10-12 15:55:33 +02005284 node->flags |= (ctx->options & LYS_COMPILE_RPC_INPUT) ? LYS_CONFIG_W : LYS_CONFIG_R;
5285 } else if (ctx->options & LYS_COMPILE_NOTIFICATION) {
Michal Vasko20424b42020-08-31 12:29:38 +02005286 /* ignore config statements inside Notification data */
5287 node->flags &= ~LYS_CONFIG_MASK;
5288 node->flags |= LYS_CONFIG_R;
5289 } else if (!(node->flags & LYS_CONFIG_MASK)) {
5290 /* config not explicitely set, inherit it from parent */
5291 if (parent) {
5292 node->flags |= parent->flags & LYS_CONFIG_MASK;
5293 } else {
5294 /* default is config true */
5295 node->flags |= LYS_CONFIG_W;
5296 }
5297 } else {
5298 /* config set explicitely */
5299 node->flags |= LYS_SET_CONFIG;
5300 }
5301
5302 if (parent && (parent->flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
5303 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02005304 "Configuration node cannot be child of any state data node.");
Michal Vasko20424b42020-08-31 12:29:38 +02005305 return LY_EVALID;
5306 }
5307
5308 return LY_SUCCESS;
5309}
5310
Michal Vasko7f45cf22020-10-01 12:49:44 +02005311static LY_ERR
5312lysp_ext_dup(const struct ly_ctx *ctx, struct lysp_ext_instance *ext, const struct lysp_ext_instance *orig_ext)
5313{
5314 LY_ERR ret = LY_SUCCESS;
5315
5316 *ext = *orig_ext;
5317 DUP_STRING(ctx, orig_ext->name, ext->name, ret);
5318 DUP_STRING(ctx, orig_ext->argument, ext->argument, ret);
5319
5320 return ret;
5321}
5322
5323static LY_ERR
5324lysp_restr_dup(const struct ly_ctx *ctx, struct lysp_restr *restr, const struct lysp_restr *orig_restr)
5325{
5326 LY_ERR ret = LY_SUCCESS;
5327
5328 if (orig_restr) {
5329 DUP_STRING(ctx, orig_restr->arg.str, restr->arg.str, ret);
5330 restr->arg.mod = orig_restr->arg.mod;
5331 DUP_STRING(ctx, orig_restr->emsg, restr->emsg, ret);
5332 DUP_STRING(ctx, orig_restr->eapptag, restr->eapptag, ret);
5333 DUP_STRING(ctx, orig_restr->dsc, restr->dsc, ret);
5334 DUP_STRING(ctx, orig_restr->ref, restr->ref, ret);
5335 DUP_ARRAY(ctx, orig_restr->exts, restr->exts, lysp_ext_dup);
5336 }
5337
5338 return ret;
5339}
5340
5341static LY_ERR
5342lysp_string_dup(const struct ly_ctx *ctx, const char **str, const char **orig_str)
5343{
5344 LY_ERR ret = LY_SUCCESS;
5345
5346 DUP_STRING(ctx, *orig_str, *str, ret);
5347
5348 return ret;
5349}
5350
5351static LY_ERR
5352lysp_qname_dup(const struct ly_ctx *ctx, struct lysp_qname *qname, const struct lysp_qname *orig_qname)
5353{
5354 LY_ERR ret = LY_SUCCESS;
5355
Michal Vaskoe9c050f2020-10-06 14:01:23 +02005356 if (!orig_qname->str) {
5357 return LY_SUCCESS;
5358 }
5359
Michal Vasko7f45cf22020-10-01 12:49:44 +02005360 DUP_STRING(ctx, orig_qname->str, qname->str, ret);
Michal Vaskoe9c050f2020-10-06 14:01:23 +02005361 assert(orig_qname->mod);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005362 qname->mod = orig_qname->mod;
5363
5364 return ret;
5365}
5366
5367static LY_ERR
5368lysp_type_enum_dup(const struct ly_ctx *ctx, struct lysp_type_enum *enm, const struct lysp_type_enum *orig_enm)
5369{
5370 LY_ERR ret = LY_SUCCESS;
5371
5372 DUP_STRING(ctx, orig_enm->name, enm->name, ret);
5373 DUP_STRING(ctx, orig_enm->dsc, enm->dsc, ret);
5374 DUP_STRING(ctx, orig_enm->ref, enm->ref, ret);
5375 enm->value = orig_enm->value;
5376 DUP_ARRAY(ctx, orig_enm->iffeatures, enm->iffeatures, lysp_qname_dup);
5377 DUP_ARRAY(ctx, orig_enm->exts, enm->exts, lysp_ext_dup);
5378 enm->flags = orig_enm->flags;
5379
5380 return ret;
5381}
5382
5383static LY_ERR
5384lysp_type_dup(const struct ly_ctx *ctx, struct lysp_type *type, const struct lysp_type *orig_type)
5385{
5386 LY_ERR ret = LY_SUCCESS;
5387
5388 DUP_STRING_GOTO(ctx, orig_type->name, type->name, ret, done);
5389
5390 if (orig_type->range) {
5391 type->range = calloc(1, sizeof *type->range);
5392 LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx), LY_EMEM);
5393 LY_CHECK_RET(lysp_restr_dup(ctx, type->range, orig_type->range));
5394 }
5395
5396 if (orig_type->length) {
5397 type->length = calloc(1, sizeof *type->length);
5398 LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx), LY_EMEM);
5399 LY_CHECK_RET(lysp_restr_dup(ctx, type->length, orig_type->length));
5400 }
5401
5402 DUP_ARRAY(ctx, orig_type->patterns, type->patterns, lysp_restr_dup);
5403 DUP_ARRAY(ctx, orig_type->enums, type->enums, lysp_type_enum_dup);
5404 DUP_ARRAY(ctx, orig_type->bits, type->bits, lysp_type_enum_dup);
5405 LY_CHECK_GOTO(ret = lyxp_expr_dup(ctx, orig_type->path, &type->path), done);
5406 DUP_ARRAY(ctx, orig_type->bases, type->bases, lysp_string_dup);
5407 DUP_ARRAY(ctx, orig_type->types, type->types, lysp_type_dup);
5408 DUP_ARRAY(ctx, orig_type->exts, type->exts, lysp_ext_dup);
5409
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005410 type->pmod = orig_type->pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005411 type->compiled = orig_type->compiled;
5412
5413 type->fraction_digits = orig_type->fraction_digits;
5414 type->require_instance = orig_type->require_instance;
5415 type->flags = orig_type->flags;
5416
5417done:
5418 return ret;
5419}
5420
5421static LY_ERR
5422lysp_when_dup(const struct ly_ctx *ctx, struct lysp_when *when, const struct lysp_when *orig_when)
5423{
5424 LY_ERR ret = LY_SUCCESS;
5425
5426 DUP_STRING(ctx, orig_when->cond, when->cond, ret);
5427 DUP_STRING(ctx, orig_when->dsc, when->dsc, ret);
5428 DUP_STRING(ctx, orig_when->ref, when->ref, ret);
5429 DUP_ARRAY(ctx, orig_when->exts, when->exts, lysp_ext_dup);
5430
5431 return ret;
5432}
5433
5434static LY_ERR
5435lysp_node_common_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
5436{
5437 LY_ERR ret = LY_SUCCESS;
5438
5439 node->parent = NULL;
5440 node->nodetype = orig->nodetype;
5441 node->flags = orig->flags;
5442 node->next = NULL;
5443 DUP_STRING(ctx, orig->name, node->name, ret);
5444 DUP_STRING(ctx, orig->dsc, node->dsc, ret);
5445 DUP_STRING(ctx, orig->ref, node->ref, ret);
5446
5447 if (orig->when) {
5448 node->when = calloc(1, sizeof *node->when);
5449 LY_CHECK_ERR_RET(!node->when, LOGMEM(ctx), LY_EMEM);
5450 LY_CHECK_RET(lysp_when_dup(ctx, node->when, orig->when));
5451 }
5452
5453 DUP_ARRAY(ctx, orig->iffeatures, node->iffeatures, lysp_qname_dup);
5454 DUP_ARRAY(ctx, orig->exts, node->exts, lysp_ext_dup);
5455
5456 return ret;
5457}
5458
5459static LY_ERR
5460lysp_node_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
5461{
5462 LY_ERR ret = LY_SUCCESS;
5463 struct lysp_node_container *cont;
5464 const struct lysp_node_container *orig_cont;
5465 struct lysp_node_leaf *leaf;
5466 const struct lysp_node_leaf *orig_leaf;
5467 struct lysp_node_leaflist *llist;
5468 const struct lysp_node_leaflist *orig_llist;
5469 struct lysp_node_list *list;
5470 const struct lysp_node_list *orig_list;
5471 struct lysp_node_choice *choice;
5472 const struct lysp_node_choice *orig_choice;
5473 struct lysp_node_case *cas;
5474 const struct lysp_node_case *orig_cas;
5475 struct lysp_node_anydata *any;
5476 const struct lysp_node_anydata *orig_any;
5477
5478 assert(orig->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_ANYDATA));
5479
5480 /* common part */
5481 LY_CHECK_RET(lysp_node_common_dup(ctx, node, orig));
5482
5483 /* specific part */
5484 switch (node->nodetype) {
5485 case LYS_CONTAINER:
5486 cont = (struct lysp_node_container *)node;
5487 orig_cont = (const struct lysp_node_container *)orig;
5488
5489 DUP_ARRAY(ctx, orig_cont->musts, cont->musts, lysp_restr_dup);
5490 DUP_STRING(ctx, orig_cont->presence, cont->presence, ret);
5491 /* we do not need the rest */
5492 break;
5493 case LYS_LEAF:
5494 leaf = (struct lysp_node_leaf *)node;
5495 orig_leaf = (const struct lysp_node_leaf *)orig;
5496
5497 DUP_ARRAY(ctx, orig_leaf->musts, leaf->musts, lysp_restr_dup);
5498 LY_CHECK_RET(lysp_type_dup(ctx, &leaf->type, &orig_leaf->type));
5499 DUP_STRING(ctx, orig_leaf->units, leaf->units, ret);
Michal Vaskoe9c050f2020-10-06 14:01:23 +02005500 LY_CHECK_RET(lysp_qname_dup(ctx, &leaf->dflt, &orig_leaf->dflt));
Michal Vasko7f45cf22020-10-01 12:49:44 +02005501 break;
5502 case LYS_LEAFLIST:
5503 llist = (struct lysp_node_leaflist *)node;
5504 orig_llist = (const struct lysp_node_leaflist *)orig;
5505
5506 DUP_ARRAY(ctx, orig_llist->musts, llist->musts, lysp_restr_dup);
5507 LY_CHECK_RET(lysp_type_dup(ctx, &llist->type, &orig_llist->type));
5508 DUP_STRING(ctx, orig_llist->units, llist->units, ret);
5509 DUP_ARRAY(ctx, orig_llist->dflts, llist->dflts, lysp_qname_dup);
5510 llist->min = orig_llist->min;
5511 llist->max = orig_llist->max;
5512 break;
5513 case LYS_LIST:
5514 list = (struct lysp_node_list *)node;
5515 orig_list = (const struct lysp_node_list *)orig;
5516
5517 DUP_ARRAY(ctx, orig_list->musts, list->musts, lysp_restr_dup);
5518 DUP_STRING(ctx, orig_list->key, list->key, ret);
5519 /* we do not need these arrays */
5520 DUP_ARRAY(ctx, orig_list->uniques, list->uniques, lysp_qname_dup);
5521 list->min = orig_list->min;
5522 list->max = orig_list->max;
5523 break;
5524 case LYS_CHOICE:
5525 choice = (struct lysp_node_choice *)node;
5526 orig_choice = (const struct lysp_node_choice *)orig;
5527
5528 /* we do not need children */
5529 LY_CHECK_RET(lysp_qname_dup(ctx, &choice->dflt, &orig_choice->dflt));
5530 break;
5531 case LYS_CASE:
5532 cas = (struct lysp_node_case *)node;
5533 orig_cas = (const struct lysp_node_case *)orig;
5534
5535 /* we do not need children */
5536 (void)cas;
5537 (void)orig_cas;
5538 break;
5539 case LYS_ANYDATA:
5540 case LYS_ANYXML:
5541 any = (struct lysp_node_anydata *)node;
5542 orig_any = (const struct lysp_node_anydata *)orig;
5543
5544 DUP_ARRAY(ctx, orig_any->musts, any->musts, lysp_restr_dup);
5545 break;
5546 default:
5547 LOGINT_RET(ctx);
5548 }
5549
5550 return ret;
5551}
5552
5553static LY_ERR
5554lysp_action_inout_dup(const struct ly_ctx *ctx, struct lysp_action_inout *inout, const struct lysp_action_inout *orig)
5555{
5556 inout->parent = NULL;
5557 inout->nodetype = orig->nodetype;
5558 DUP_ARRAY(ctx, orig->musts, inout->musts, lysp_restr_dup);
5559 /* we dot need these arrays */
5560 DUP_ARRAY(ctx, orig->exts, inout->exts, lysp_ext_dup);
5561
5562 return LY_SUCCESS;
5563}
5564
5565static LY_ERR
5566lysp_action_dup(const struct ly_ctx *ctx, struct lysp_action *act, const struct lysp_action *orig)
5567{
5568 LY_ERR ret = LY_SUCCESS;
5569
5570 act->parent = NULL;
5571 act->nodetype = orig->nodetype;
5572 act->flags = orig->flags;
5573 DUP_STRING(ctx, orig->name, act->name, ret);
5574 DUP_STRING(ctx, orig->dsc, act->dsc, ret);
5575 DUP_STRING(ctx, orig->ref, act->ref, ret);
5576 DUP_ARRAY(ctx, orig->iffeatures, act->iffeatures, lysp_qname_dup);
5577
5578 act->input.nodetype = orig->input.nodetype;
5579 act->output.nodetype = orig->output.nodetype;
5580 /* we do not need choldren of in/out */
5581 DUP_ARRAY(ctx, orig->exts, act->exts, lysp_ext_dup);
5582
5583 return ret;
5584}
5585
5586static LY_ERR
5587lysp_notif_dup(const struct ly_ctx *ctx, struct lysp_notif *notif, const struct lysp_notif *orig)
5588{
5589 LY_ERR ret = LY_SUCCESS;
5590
5591 notif->parent = NULL;
5592 notif->nodetype = orig->nodetype;
5593 notif->flags = orig->flags;
5594 DUP_STRING(ctx, orig->name, notif->name, ret);
5595 DUP_STRING(ctx, orig->dsc, notif->dsc, ret);
5596 DUP_STRING(ctx, orig->ref, notif->ref, ret);
5597 DUP_ARRAY(ctx, orig->iffeatures, notif->iffeatures, lysp_qname_dup);
5598 DUP_ARRAY(ctx, orig->musts, notif->musts, lysp_restr_dup);
5599 /* we do not need these arrays */
5600 DUP_ARRAY(ctx, orig->exts, notif->exts, lysp_ext_dup);
5601
5602 return ret;
5603}
5604
5605/**
5606 * @brief Duplicate a single parsed node. Only attributes that are used in compilation are copied.
5607 *
5608 * @param[in] ctx libyang context.
5609 * @param[in] pnode Node to duplicate.
5610 * @param[in] with_links Whether to also copy any links (child, parent pointers).
5611 * @param[out] dup_p Duplicated parsed node.
5612 * @return LY_ERR value.
5613 */
5614static LY_ERR
5615lysp_dup_single(const struct ly_ctx *ctx, const struct lysp_node *pnode, ly_bool with_links, struct lysp_node **dup_p)
5616{
Michal Vaskoaf702452020-10-02 09:02:55 +02005617 LY_ERR ret = LY_SUCCESS;
5618 void *mem = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005619
5620 if (!pnode) {
5621 *dup_p = NULL;
5622 return LY_SUCCESS;
5623 }
5624
5625 switch (pnode->nodetype) {
5626 case LYS_CONTAINER:
5627 mem = calloc(1, sizeof(struct lysp_node_container));
Michal Vaskoaf702452020-10-02 09:02:55 +02005628 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5629 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005630 break;
5631 case LYS_LEAF:
5632 mem = calloc(1, sizeof(struct lysp_node_leaf));
Michal Vaskoaf702452020-10-02 09:02:55 +02005633 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5634 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005635 break;
5636 case LYS_LEAFLIST:
5637 mem = calloc(1, sizeof(struct lysp_node_leaflist));
Michal Vaskoaf702452020-10-02 09:02:55 +02005638 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5639 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005640 break;
5641 case LYS_LIST:
5642 mem = calloc(1, sizeof(struct lysp_node_list));
Michal Vaskoaf702452020-10-02 09:02:55 +02005643 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5644 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005645 break;
5646 case LYS_CHOICE:
5647 mem = calloc(1, sizeof(struct lysp_node_choice));
Michal Vaskoaf702452020-10-02 09:02:55 +02005648 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5649 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005650 break;
5651 case LYS_CASE:
5652 mem = calloc(1, sizeof(struct lysp_node_case));
Michal Vaskoaf702452020-10-02 09:02:55 +02005653 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5654 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005655 break;
5656 case LYS_ANYDATA:
5657 case LYS_ANYXML:
5658 mem = calloc(1, sizeof(struct lysp_node_anydata));
Michal Vaskoaf702452020-10-02 09:02:55 +02005659 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5660 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005661 break;
5662 case LYS_INPUT:
5663 case LYS_OUTPUT:
5664 mem = calloc(1, sizeof(struct lysp_action_inout));
Michal Vaskoaf702452020-10-02 09:02:55 +02005665 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5666 LY_CHECK_GOTO(ret = lysp_action_inout_dup(ctx, mem, (struct lysp_action_inout *)pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005667 break;
5668 case LYS_ACTION:
5669 case LYS_RPC:
5670 mem = calloc(1, sizeof(struct lysp_action));
Michal Vaskoaf702452020-10-02 09:02:55 +02005671 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5672 LY_CHECK_GOTO(ret = lysp_action_dup(ctx, mem, (struct lysp_action *)pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005673 break;
5674 case LYS_NOTIF:
5675 mem = calloc(1, sizeof(struct lysp_notif));
Michal Vaskoaf702452020-10-02 09:02:55 +02005676 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5677 LY_CHECK_GOTO(ret = lysp_notif_dup(ctx, mem, (struct lysp_notif *)pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005678 break;
5679 default:
5680 LOGINT_RET(ctx);
5681 }
5682
5683 if (with_links) {
5684 /* copy also parent and child pointers */
5685 ((struct lysp_node *)mem)->parent = pnode->parent;
5686 switch (pnode->nodetype) {
5687 case LYS_CONTAINER:
5688 ((struct lysp_node_container *)mem)->child = ((struct lysp_node_container *)pnode)->child;
5689 break;
5690 case LYS_LIST:
5691 ((struct lysp_node_list *)mem)->child = ((struct lysp_node_list *)pnode)->child;
5692 break;
5693 case LYS_CHOICE:
5694 ((struct lysp_node_choice *)mem)->child = ((struct lysp_node_choice *)pnode)->child;
5695 break;
5696 case LYS_CASE:
5697 ((struct lysp_node_case *)mem)->child = ((struct lysp_node_case *)pnode)->child;
5698 break;
5699 default:
5700 break;
5701 }
5702 }
5703
Michal Vaskoaf702452020-10-02 09:02:55 +02005704cleanup:
5705 if (ret) {
5706 free(mem);
5707 } else {
5708 *dup_p = mem;
5709 }
5710 return ret;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005711}
5712
5713#define AMEND_WRONG_NODETYPE(AMEND_STR, OP_STR, PROPERTY) \
5714 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s of %s node - it is not possible to %s \"%s\" property.", \
5715 AMEND_STR, lys_nodetype2str(target->nodetype), OP_STR, PROPERTY);\
5716 ret = LY_EVALID; \
5717 goto cleanup;
5718
5719#define AMEND_CHECK_CARDINALITY(ARRAY, MAX, AMEND_STR, PROPERTY) \
5720 if (LY_ARRAY_COUNT(ARRAY) > MAX) { \
5721 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid %s of %s with too many (%"LY_PRI_ARRAY_COUNT_TYPE") %s properties.", \
5722 AMEND_STR, lys_nodetype2str(target->nodetype), LY_ARRAY_COUNT(ARRAY), PROPERTY); \
5723 ret = LY_EVALID; \
5724 goto cleanup; \
5725 }
5726
5727/**
5728 * @brief Apply refine.
5729 *
5730 * @param[in] ctx Compile context.
5731 * @param[in] rfn Refine to apply.
5732 * @param[in,out] target Refine target.
5733 * @return LY_ERR value.
5734 */
5735static LY_ERR
5736lys_apply_refine(struct lysc_ctx *ctx, struct lysp_refine *rfn, struct lysp_node *target)
5737{
5738 LY_ERR ret = LY_SUCCESS;
5739 LY_ARRAY_COUNT_TYPE u;
5740 struct lysp_qname *qname;
5741 struct lysp_restr **musts, *must;
5742 uint32_t *num;
5743
5744 /* default value */
5745 if (rfn->dflts) {
5746 switch (target->nodetype) {
5747 case LYS_LEAF:
5748 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
5749
5750 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005751 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 +02005752 break;
5753 case LYS_LEAFLIST:
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005754 if (rfn->dflts[0].mod->version < LYS_VERSION_1_1) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02005755 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
5756 "Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.");
5757 ret = LY_EVALID;
5758 goto cleanup;
5759 }
5760
5761 FREE_ARRAY(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, lysp_qname_free);
5762 ((struct lysp_node_leaflist *)target)->dflts = NULL;
5763 LY_ARRAY_FOR(rfn->dflts, u) {
5764 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005765 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &rfn->dflts[u]), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005766 }
5767 break;
5768 case LYS_CHOICE:
5769 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
5770
5771 FREE_STRING(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005772 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 +02005773 break;
5774 default:
5775 AMEND_WRONG_NODETYPE("refine", "replace", "default");
5776 }
5777 }
5778
5779 /* description */
5780 if (rfn->dsc) {
5781 FREE_STRING(ctx->ctx, target->dsc);
5782 DUP_STRING_GOTO(ctx->ctx, rfn->dsc, target->dsc, ret, cleanup);
5783 }
5784
5785 /* reference */
5786 if (rfn->ref) {
5787 FREE_STRING(ctx->ctx, target->ref);
5788 DUP_STRING_GOTO(ctx->ctx, rfn->ref, target->ref, ret, cleanup);
5789 }
5790
5791 /* config */
5792 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci90d4e922020-10-12 15:55:33 +02005793 if (ctx->options & (LYS_COMPILE_NOTIFICATION | LYS_COMPILE_RPC_INPUT | LYS_COMPILE_RPC_OUTPUT)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02005794 LOGWRN(ctx->ctx, "Refining config inside %s has no effect (%s).",
Radek Krejci90d4e922020-10-12 15:55:33 +02005795 ctx->options & LYS_COMPILE_NOTIFICATION ? "notification" : "RPC/action", ctx->path);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005796 } else {
5797 target->flags &= ~LYS_CONFIG_MASK;
5798 target->flags |= rfn->flags & LYS_CONFIG_MASK;
5799 }
5800 }
5801
5802 /* mandatory */
5803 if (rfn->flags & LYS_MAND_MASK) {
5804 switch (target->nodetype) {
5805 case LYS_LEAF:
5806 case LYS_CHOICE:
5807 case LYS_ANYDATA:
5808 case LYS_ANYXML:
5809 break;
5810 default:
5811 AMEND_WRONG_NODETYPE("refine", "replace", "mandatory");
5812 }
5813
5814 target->flags &= ~LYS_MAND_MASK;
5815 target->flags |= rfn->flags & LYS_MAND_MASK;
5816 }
5817
5818 /* presence */
5819 if (rfn->presence) {
5820 switch (target->nodetype) {
5821 case LYS_CONTAINER:
5822 break;
5823 default:
5824 AMEND_WRONG_NODETYPE("refine", "replace", "presence");
5825 }
5826
5827 FREE_STRING(ctx->ctx, ((struct lysp_node_container *)target)->presence);
5828 DUP_STRING_GOTO(ctx->ctx, rfn->presence, ((struct lysp_node_container *)target)->presence, ret, cleanup);
5829 }
5830
5831 /* must */
5832 if (rfn->musts) {
5833 switch (target->nodetype) {
5834 case LYS_CONTAINER:
5835 case LYS_LIST:
5836 case LYS_LEAF:
5837 case LYS_LEAFLIST:
5838 case LYS_ANYDATA:
5839 case LYS_ANYXML:
5840 musts = &((struct lysp_node_container *)target)->musts;
5841 break;
5842 default:
5843 AMEND_WRONG_NODETYPE("refine", "add", "must");
5844 }
5845
5846 LY_ARRAY_FOR(rfn->musts, u) {
5847 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
5848 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &rfn->musts[u]), cleanup);
5849 }
5850 }
5851
5852 /* min-elements */
5853 if (rfn->flags & LYS_SET_MIN) {
5854 switch (target->nodetype) {
5855 case LYS_LEAFLIST:
5856 num = &((struct lysp_node_leaflist *)target)->min;
5857 break;
5858 case LYS_LIST:
5859 num = &((struct lysp_node_list *)target)->min;
5860 break;
5861 default:
5862 AMEND_WRONG_NODETYPE("refine", "replace", "min-elements");
5863 }
5864
5865 *num = rfn->min;
5866 }
5867
5868 /* max-elements */
5869 if (rfn->flags & LYS_SET_MAX) {
5870 switch (target->nodetype) {
5871 case LYS_LEAFLIST:
5872 num = &((struct lysp_node_leaflist *)target)->max;
5873 break;
5874 case LYS_LIST:
5875 num = &((struct lysp_node_list *)target)->max;
5876 break;
5877 default:
5878 AMEND_WRONG_NODETYPE("refine", "replace", "max-elements");
5879 }
5880
5881 *num = rfn->max;
5882 }
5883
5884 /* if-feature */
5885 if (rfn->iffeatures) {
5886 switch (target->nodetype) {
5887 case LYS_LEAF:
5888 case LYS_LEAFLIST:
5889 case LYS_LIST:
5890 case LYS_CONTAINER:
5891 case LYS_CHOICE:
5892 case LYS_CASE:
5893 case LYS_ANYDATA:
5894 case LYS_ANYXML:
5895 break;
5896 default:
5897 AMEND_WRONG_NODETYPE("refine", "add", "if-feature");
5898 }
5899
5900 LY_ARRAY_FOR(rfn->iffeatures, u) {
5901 LY_ARRAY_NEW_GOTO(ctx->ctx, target->iffeatures, qname, ret, cleanup);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005902 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &rfn->iffeatures[u]), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005903 }
5904 }
5905
5906 /* extension */
5907 /* TODO refine extensions */
5908
5909cleanup:
5910 return ret;
5911}
5912
5913/**
5914 * @brief Apply deviate add.
5915 *
5916 * @param[in] ctx Compile context.
5917 * @param[in] d Deviate add to apply.
5918 * @param[in,out] target Deviation target.
5919 * @return LY_ERR value.
5920 */
5921static LY_ERR
5922lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysp_deviate_add *d, struct lysp_node *target)
5923{
5924 LY_ERR ret = LY_SUCCESS;
5925 LY_ARRAY_COUNT_TYPE u;
5926 struct lysp_qname *qname;
5927 uint32_t *num;
5928 struct lysp_restr **musts, *must;
5929
5930#define DEV_CHECK_NONPRESENCE(TYPE, MEMBER, PROPERTY, VALUEMEMBER) \
5931 if (((TYPE)target)->MEMBER) { \
5932 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
5933 "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", \
5934 PROPERTY, ((TYPE)target)->VALUEMEMBER); \
5935 ret = LY_EVALID; \
5936 goto cleanup; \
5937 }
5938
5939 /* [units-stmt] */
5940 if (d->units) {
5941 switch (target->nodetype) {
5942 case LYS_LEAF:
5943 case LYS_LEAFLIST:
5944 break;
5945 default:
5946 AMEND_WRONG_NODETYPE("deviation", "add", "units");
5947 }
5948
5949 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, units, "units", units);
5950 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
5951 }
5952
5953 /* *must-stmt */
5954 if (d->musts) {
5955 switch (target->nodetype) {
5956 case LYS_CONTAINER:
5957 case LYS_LIST:
5958 case LYS_LEAF:
5959 case LYS_LEAFLIST:
5960 case LYS_ANYDATA:
5961 case LYS_ANYXML:
5962 musts = &((struct lysp_node_container *)target)->musts;
5963 break;
5964 case LYS_NOTIF:
5965 musts = &((struct lysp_notif *)target)->musts;
5966 break;
5967 case LYS_INPUT:
5968 case LYS_OUTPUT:
5969 musts = &((struct lysp_action_inout *)target)->musts;
5970 break;
5971 default:
5972 AMEND_WRONG_NODETYPE("deviation", "add", "must");
5973 }
5974
5975 LY_ARRAY_FOR(d->musts, u) {
5976 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
5977 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &d->musts[u]), cleanup);
5978 }
5979 }
5980
5981 /* *unique-stmt */
5982 if (d->uniques) {
5983 switch (target->nodetype) {
5984 case LYS_LIST:
5985 break;
5986 default:
5987 AMEND_WRONG_NODETYPE("deviation", "add", "unique");
5988 }
5989
5990 LY_ARRAY_FOR(d->uniques, u) {
5991 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_list *)target)->uniques, qname, ret, cleanup);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005992 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &d->uniques[u]), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005993 }
5994 }
5995
5996 /* *default-stmt */
5997 if (d->dflts) {
5998 switch (target->nodetype) {
5999 case LYS_LEAF:
6000 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
6001 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, dflt.str, "default", dflt.str);
6002
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006003 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 +02006004 break;
6005 case LYS_LEAFLIST:
6006 LY_ARRAY_FOR(d->dflts, u) {
6007 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006008 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &d->dflts[u]), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006009 }
6010 break;
6011 case LYS_CHOICE:
6012 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
6013 DEV_CHECK_NONPRESENCE(struct lysp_node_choice *, dflt.str, "default", dflt.str);
6014
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006015 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 +02006016 break;
6017 default:
6018 AMEND_WRONG_NODETYPE("deviation", "add", "default");
6019 }
6020 }
6021
6022 /* [config-stmt] */
6023 if (d->flags & LYS_CONFIG_MASK) {
6024 switch (target->nodetype) {
6025 case LYS_CONTAINER:
6026 case LYS_LEAF:
6027 case LYS_LEAFLIST:
6028 case LYS_LIST:
6029 case LYS_CHOICE:
6030 case LYS_ANYDATA:
6031 case LYS_ANYXML:
6032 break;
6033 default:
6034 AMEND_WRONG_NODETYPE("deviation", "add", "config");
6035 }
6036
6037 if (target->flags & LYS_CONFIG_MASK) {
6038 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6039 "Invalid deviation adding \"config\" property which already exists (with value \"config %s\").",
6040 target->flags & LYS_CONFIG_W ? "true" : "false");
6041 ret = LY_EVALID;
6042 goto cleanup;
6043 }
6044
6045 target->flags |= d->flags & LYS_CONFIG_MASK;
6046 }
6047
6048 /* [mandatory-stmt] */
6049 if (d->flags & LYS_MAND_MASK) {
6050 switch (target->nodetype) {
6051 case LYS_LEAF:
6052 case LYS_CHOICE:
6053 case LYS_ANYDATA:
6054 case LYS_ANYXML:
6055 break;
6056 default:
6057 AMEND_WRONG_NODETYPE("deviation", "add", "mandatory");
6058 }
6059
6060 if (target->flags & LYS_MAND_MASK) {
6061 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6062 "Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory %s\").",
6063 target->flags & LYS_MAND_TRUE ? "true" : "false");
6064 ret = LY_EVALID;
6065 goto cleanup;
6066 }
6067
6068 target->flags |= d->flags & LYS_MAND_MASK;
6069 }
6070
6071 /* [min-elements-stmt] */
6072 if (d->flags & LYS_SET_MIN) {
6073 switch (target->nodetype) {
6074 case LYS_LEAFLIST:
6075 num = &((struct lysp_node_leaflist *)target)->min;
6076 break;
6077 case LYS_LIST:
6078 num = &((struct lysp_node_list *)target)->min;
6079 break;
6080 default:
6081 AMEND_WRONG_NODETYPE("deviation", "add", "min-elements");
6082 }
6083
6084 if (target->flags & LYS_SET_MIN) {
6085 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6086 "Invalid deviation adding \"min-elements\" property which already exists (with value \"%u\").", *num);
6087 ret = LY_EVALID;
6088 goto cleanup;
6089 }
6090
6091 *num = d->min;
6092 }
6093
6094 /* [max-elements-stmt] */
6095 if (d->flags & LYS_SET_MAX) {
6096 switch (target->nodetype) {
6097 case LYS_LEAFLIST:
6098 num = &((struct lysp_node_leaflist *)target)->max;
6099 break;
6100 case LYS_LIST:
6101 num = &((struct lysp_node_list *)target)->max;
6102 break;
6103 default:
6104 AMEND_WRONG_NODETYPE("deviation", "add", "max-elements");
6105 }
6106
6107 if (target->flags & LYS_SET_MAX) {
6108 if (*num) {
6109 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6110 "Invalid deviation adding \"max-elements\" property which already exists (with value \"%u\").",
6111 *num);
6112 } else {
6113 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6114 "Invalid deviation adding \"max-elements\" property which already exists (with value \"unbounded\").");
6115 }
6116 ret = LY_EVALID;
6117 goto cleanup;
6118 }
6119
6120 *num = d->max;
6121 }
6122
6123cleanup:
6124 return ret;
6125}
6126
6127/**
6128 * @brief Apply deviate delete.
6129 *
6130 * @param[in] ctx Compile context.
6131 * @param[in] d Deviate delete to apply.
6132 * @param[in,out] target Deviation target.
6133 * @return LY_ERR value.
6134 */
6135static LY_ERR
6136lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysp_deviate_del *d, struct lysp_node *target)
6137{
6138 LY_ERR ret = LY_SUCCESS;
6139 struct lysp_restr **musts;
6140 LY_ARRAY_COUNT_TYPE u, v;
6141 struct lysp_qname **uniques, **dflts;
6142
6143#define DEV_DEL_ARRAY(DEV_ARRAY, ORIG_ARRAY, DEV_MEMBER, ORIG_MEMBER, FREE_FUNC, PROPERTY) \
6144 LY_ARRAY_FOR(d->DEV_ARRAY, u) { \
6145 int found = 0; \
6146 LY_ARRAY_FOR(ORIG_ARRAY, v) { \
6147 if (!strcmp(d->DEV_ARRAY[u]DEV_MEMBER, (ORIG_ARRAY)[v]ORIG_MEMBER)) { \
6148 found = 1; \
6149 break; \
6150 } \
6151 } \
6152 if (!found) { \
6153 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
6154 "Invalid deviation deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
6155 PROPERTY, d->DEV_ARRAY[u]DEV_MEMBER); \
6156 ret = LY_EVALID; \
6157 goto cleanup; \
6158 } \
6159 LY_ARRAY_DECREMENT(ORIG_ARRAY); \
6160 FREE_FUNC(ctx->ctx, &(ORIG_ARRAY)[v]); \
6161 memmove(&(ORIG_ARRAY)[v], &(ORIG_ARRAY)[v + 1], (LY_ARRAY_COUNT(ORIG_ARRAY) - v) * sizeof *(ORIG_ARRAY)); \
6162 } \
6163 if (!LY_ARRAY_COUNT(ORIG_ARRAY)) { \
6164 LY_ARRAY_FREE(ORIG_ARRAY); \
6165 ORIG_ARRAY = NULL; \
6166 }
6167
6168#define DEV_CHECK_PRESENCE_VALUE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
6169 if (!((TYPE)target)->MEMBER) { \
6170 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
6171 ret = LY_EVALID; \
6172 goto cleanup; \
6173 } else if (strcmp(((TYPE)target)->MEMBER, VALUE)) { \
6174 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
6175 "Invalid deviation deleting \"%s\" property \"%s\" which does not match the target's property value \"%s\".", \
6176 PROPERTY, VALUE, ((TYPE)target)->MEMBER); \
6177 ret = LY_EVALID; \
6178 goto cleanup; \
6179 }
6180
6181 /* [units-stmt] */
6182 if (d->units) {
6183 switch (target->nodetype) {
6184 case LYS_LEAF:
6185 case LYS_LEAFLIST:
6186 break;
6187 default:
6188 AMEND_WRONG_NODETYPE("deviation", "delete", "units");
6189 }
6190
6191 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, units, "deleting", "units", d->units);
6192 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
6193 ((struct lysp_node_leaf *)target)->units = NULL;
6194 }
6195
6196 /* *must-stmt */
6197 if (d->musts) {
6198 switch (target->nodetype) {
6199 case LYS_CONTAINER:
6200 case LYS_LIST:
6201 case LYS_LEAF:
6202 case LYS_LEAFLIST:
6203 case LYS_ANYDATA:
6204 case LYS_ANYXML:
6205 musts = &((struct lysp_node_container *)target)->musts;
6206 break;
6207 case LYS_NOTIF:
6208 musts = &((struct lysp_notif *)target)->musts;
6209 break;
6210 case LYS_INPUT:
6211 case LYS_OUTPUT:
6212 musts = &((struct lysp_action_inout *)target)->musts;
6213 break;
6214 default:
6215 AMEND_WRONG_NODETYPE("deviation", "delete", "must");
6216 }
6217
6218 DEV_DEL_ARRAY(musts, *musts, .arg.str, .arg.str, lysp_restr_free, "must");
6219 }
6220
6221 /* *unique-stmt */
6222 if (d->uniques) {
6223 switch (target->nodetype) {
6224 case LYS_LIST:
6225 break;
6226 default:
6227 AMEND_WRONG_NODETYPE("deviation", "delete", "unique");
6228 }
6229
6230 uniques = &((struct lysp_node_list *)target)->uniques;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006231 DEV_DEL_ARRAY(uniques, *uniques, .str, .str, lysp_qname_free, "unique");
Michal Vasko7f45cf22020-10-01 12:49:44 +02006232 }
6233
6234 /* *default-stmt */
6235 if (d->dflts) {
6236 switch (target->nodetype) {
6237 case LYS_LEAF:
6238 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006239 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, dflt.str, "deleting", "default", d->dflts[0].str);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006240
6241 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
6242 ((struct lysp_node_leaf *)target)->dflt.str = NULL;
6243 break;
6244 case LYS_LEAFLIST:
6245 dflts = &((struct lysp_node_leaflist *)target)->dflts;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006246 DEV_DEL_ARRAY(dflts, *dflts, .str, .str, lysp_qname_free, "default");
Michal Vasko7f45cf22020-10-01 12:49:44 +02006247 break;
6248 case LYS_CHOICE:
6249 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006250 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_choice *, dflt.str, "deleting", "default", d->dflts[0].str);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006251
6252 FREE_STRING(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
6253 ((struct lysp_node_choice *)target)->dflt.str = NULL;
6254 break;
6255 default:
6256 AMEND_WRONG_NODETYPE("deviation", "delete", "default");
6257 }
6258 }
6259
6260cleanup:
6261 return ret;
6262}
6263
6264/**
6265 * @brief Apply deviate replace.
6266 *
6267 * @param[in] ctx Compile context.
6268 * @param[in] d Deviate replace to apply.
6269 * @param[in,out] target Deviation target.
6270 * @return LY_ERR value.
6271 */
6272static LY_ERR
6273lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysp_deviate_rpl *d, struct lysp_node *target)
6274{
6275 LY_ERR ret = LY_SUCCESS;
6276 uint32_t *num;
6277
6278#define DEV_CHECK_PRESENCE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
6279 if (!((TYPE)target)->MEMBER) { \
6280 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
6281 ret = LY_EVALID; \
6282 goto cleanup; \
6283 }
6284
6285 /* [type-stmt] */
6286 if (d->type) {
6287 switch (target->nodetype) {
6288 case LYS_LEAF:
6289 case LYS_LEAFLIST:
6290 break;
6291 default:
6292 AMEND_WRONG_NODETYPE("deviation", "replace", "type");
6293 }
6294
6295 lysp_type_free(ctx->ctx, &((struct lysp_node_leaf *)target)->type);
6296 lysp_type_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->type, d->type);
6297 }
6298
6299 /* [units-stmt] */
6300 if (d->units) {
6301 switch (target->nodetype) {
6302 case LYS_LEAF:
6303 case LYS_LEAFLIST:
6304 break;
6305 default:
6306 AMEND_WRONG_NODETYPE("deviation", "replace", "units");
6307 }
6308
6309 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, units, "replacing", "units", d->units);
6310 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
6311 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
6312 }
6313
6314 /* [default-stmt] */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006315 if (d->dflt.str) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02006316 switch (target->nodetype) {
6317 case LYS_LEAF:
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006318 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, dflt.str, "replacing", "default", d->dflt.str);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006319
6320 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006321 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 +02006322 break;
6323 case LYS_CHOICE:
6324 DEV_CHECK_PRESENCE(struct lysp_node_choice *, dflt.str, "replacing", "default", d->dflt);
6325
6326 FREE_STRING(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006327 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 +02006328 break;
6329 default:
6330 AMEND_WRONG_NODETYPE("deviation", "replace", "default");
6331 }
6332 }
6333
6334 /* [config-stmt] */
6335 if (d->flags & LYS_CONFIG_MASK) {
6336 switch (target->nodetype) {
6337 case LYS_CONTAINER:
6338 case LYS_LEAF:
6339 case LYS_LEAFLIST:
6340 case LYS_LIST:
6341 case LYS_CHOICE:
6342 case LYS_ANYDATA:
6343 case LYS_ANYXML:
6344 break;
6345 default:
6346 AMEND_WRONG_NODETYPE("deviation", "replace", "config");
6347 }
6348
6349 if (!(target->flags & LYS_CONFIG_MASK)) {
6350 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT,
6351 "replacing", "config", d->flags & LYS_CONFIG_W ? "config true" : "config false");
6352 ret = LY_EVALID;
6353 goto cleanup;
6354 }
6355
6356 target->flags &= ~LYS_CONFIG_MASK;
6357 target->flags |= d->flags & LYS_CONFIG_MASK;
6358 }
6359
6360 /* [mandatory-stmt] */
6361 if (d->flags & LYS_MAND_MASK) {
6362 switch (target->nodetype) {
6363 case LYS_LEAF:
6364 case LYS_CHOICE:
6365 case LYS_ANYDATA:
6366 case LYS_ANYXML:
6367 break;
6368 default:
6369 AMEND_WRONG_NODETYPE("deviation", "replace", "mandatory");
6370 }
6371
6372 if (!(target->flags & LYS_MAND_MASK)) {
6373 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT,
6374 "replacing", "mandatory", d->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
6375 ret = LY_EVALID;
6376 goto cleanup;
6377 }
6378
6379 target->flags &= ~LYS_MAND_MASK;
6380 target->flags |= d->flags & LYS_MAND_MASK;
6381 }
6382
6383 /* [min-elements-stmt] */
6384 if (d->flags & LYS_SET_MIN) {
6385 switch (target->nodetype) {
6386 case LYS_LEAFLIST:
6387 num = &((struct lysp_node_leaflist *)target)->min;
6388 break;
6389 case LYS_LIST:
6390 num = &((struct lysp_node_list *)target)->min;
6391 break;
6392 default:
6393 AMEND_WRONG_NODETYPE("deviation", "replace", "min-elements");
6394 }
6395
6396 if (!(target->flags & LYS_SET_MIN)) {
6397 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6398 "Invalid deviation replacing \"min-elements\" property which is not present.");
6399 ret = LY_EVALID;
6400 goto cleanup;
6401 }
6402
6403 *num = d->min;
6404 }
6405
6406 /* [max-elements-stmt] */
6407 if (d->flags & LYS_SET_MAX) {
6408 switch (target->nodetype) {
6409 case LYS_LEAFLIST:
6410 num = &((struct lysp_node_leaflist *)target)->max;
6411 break;
6412 case LYS_LIST:
6413 num = &((struct lysp_node_list *)target)->max;
6414 break;
6415 default:
6416 AMEND_WRONG_NODETYPE("deviation", "replace", "max-elements");
6417 }
6418
6419 if (!(target->flags & LYS_SET_MAX)) {
6420 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6421 "Invalid deviation replacing \"max-elements\" property which is not present.");
6422 ret = LY_EVALID;
6423 goto cleanup;
6424 }
6425
6426 *num = d->max;
6427 }
6428
6429cleanup:
6430 return ret;
6431}
6432
6433/**
6434 * @brief Get module of a single nodeid node name test.
6435 *
6436 * @param[in] ctx libyang context.
6437 * @param[in] nametest Nametest with an optional prefix.
6438 * @param[in] nametest_len Length of @p nametest.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006439 * @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 +02006440 * @param[out] name Optional pointer to the name test without the prefix.
6441 * @param[out] name_len Length of @p name.
6442 * @return Resolved module.
6443 */
6444static const struct lys_module *
6445lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest, size_t nametest_len,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006446 const struct lysp_module *mod, const char **name, size_t *name_len)
Michal Vasko7f45cf22020-10-01 12:49:44 +02006447{
6448 const struct lys_module *target_mod;
6449 const char *ptr;
6450
6451 ptr = ly_strnchr(nametest, ':', nametest_len);
6452 if (ptr) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006453 target_mod = ly_resolve_prefix(ctx, nametest, ptr - nametest, LY_PREF_SCHEMA, (void *)mod);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006454 if (!target_mod) {
6455 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
6456 "Invalid absolute-schema-nodeid nametest \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006457 nametest_len, nametest, ptr - nametest, nametest, LYSP_MODULE_NAME(mod));
Michal Vasko7f45cf22020-10-01 12:49:44 +02006458 return NULL;
6459 }
6460
6461 if (name) {
6462 *name = ptr + 1;
6463 *name_len = nametest_len - ((ptr - nametest) + 1);
6464 }
6465 } else {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006466 target_mod = mod->mod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02006467 if (name) {
6468 *name = nametest;
6469 *name_len = nametest_len;
6470 }
6471 }
6472
6473 return target_mod;
6474}
6475
6476/**
6477 * @brief Check whether a parsed node matches a single schema nodeid name test.
6478 *
6479 * @param[in] pnode Parsed node to consider.
6480 * @param[in] pnode_mod Compiled @p pnode to-be module.
6481 * @param[in] mod Expected module.
6482 * @param[in] name Expected name.
6483 * @param[in] name_len Length of @p name.
6484 * @return Whether it is a match or not.
6485 */
6486static ly_bool
6487lysp_schema_nodeid_match_pnode(const struct lysp_node *pnode, const struct lys_module *pnode_mod,
6488 const struct lys_module *mod, const char *name, size_t name_len)
6489{
6490 const char *pname;
6491
6492 /* compare with the module of the node */
6493 if (pnode_mod != mod) {
6494 return 0;
6495 }
6496
6497 /* compare names */
6498 if (pnode->nodetype & (LYS_ACTION | LYS_RPC)) {
6499 pname = ((struct lysp_action *)pnode)->name;
6500 } else if (pnode->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6501 pname = (pnode->nodetype & LYS_INPUT) ? "input" : "output";
6502 } else {
6503 pname = pnode->name;
6504 }
6505 if (ly_strncmp(pname, name, name_len)) {
6506 return 0;
6507 }
6508
6509 return 1;
6510}
6511
6512/**
6513 * @brief Check whether a compiled node matches a single schema nodeid name test.
6514 *
6515 * @param[in,out] node Compiled node to consider. On a match it is moved to its parent.
6516 * @param[in] mod Expected module.
6517 * @param[in] name Expected name.
6518 * @param[in] name_len Length of @p name.
6519 * @return Whether it is a match or not.
6520 */
6521static ly_bool
6522lysp_schema_nodeid_match_node(const struct lysc_node **node, const struct lys_module *mod, const char *name,
6523 size_t name_len)
6524{
6525 const struct lys_module *node_mod;
6526 const char *node_name;
6527
6528 /* compare with the module of the node */
6529 if ((*node)->nodetype == LYS_INPUT) {
6530 node_mod = ((struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, input)))->module;
6531 } else if ((*node)->nodetype == LYS_OUTPUT) {
6532 node_mod = ((struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, output)))->module;
6533 } else {
6534 node_mod = (*node)->module;
6535 }
6536 if (node_mod != mod) {
6537 return 0;
6538 }
6539
6540 /* compare names */
6541 if ((*node)->nodetype == LYS_INPUT) {
6542 node_name = "input";
6543 } else if ((*node)->nodetype == LYS_OUTPUT) {
6544 node_name = "output";
6545 } else {
6546 node_name = (*node)->name;
6547 }
6548 if (ly_strncmp(node_name, name, name_len)) {
6549 return 0;
6550 }
6551
6552 if ((*node)->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6553 /* move up from input/output */
6554 if ((*node)->nodetype == LYS_INPUT) {
6555 (*node) = (struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, input));
6556 } else {
6557 (*node) = (struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, output));
6558 }
6559 } else if ((*node)->parent && ((*node)->parent->nodetype & (LYS_RPC | LYS_ACTION))) {
6560 /* move to the input/output */
6561 if ((*node)->flags & LYS_CONFIG_W) {
6562 *node = (struct lysc_node *)&((struct lysc_action *)(*node)->parent)->input;
6563 } else {
6564 *node = (struct lysc_node *)&((struct lysc_action *)(*node)->parent)->output;
6565 }
6566 } else {
6567 /* move to next parent */
6568 *node = (*node)->parent;
6569 }
6570
6571 return 1;
6572}
6573
6574/**
6575 * @brief Check whether a node matches specific schema nodeid.
6576 *
6577 * @param[in] exp Parsed nodeid to match.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006578 * @param[in] exp_pmod Module to use for nodes in @p exp without a prefix.
Michal Vasko7f45cf22020-10-01 12:49:44 +02006579 * @param[in] ctx_node Initial context node that should match, only for descendant paths.
6580 * @param[in] parent First compiled parent to consider. If @p pnode is NULL, it is condered the node to be matched.
6581 * @param[in] pnode Parsed node to be matched. May be NULL if the target node was already compiled.
6582 * @param[in] pnode_mod Compiled @p pnode to-be module.
6583 * @return Whether it is a match or not.
6584 */
6585static ly_bool
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006586lysp_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 +02006587 const struct lysc_node *parent, const struct lysp_node *pnode, const struct lys_module *pnode_mod)
6588{
6589 uint32_t i;
6590 const struct lys_module *mod;
6591 const char *name;
6592 size_t name_len;
6593
6594 /* compare last node in the node ID */
6595 i = exp->used - 1;
6596
6597 /* get exp node ID module */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006598 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 +02006599 assert(mod);
6600
6601 if (pnode) {
6602 /* compare on the last parsed-only node */
6603 if (!lysp_schema_nodeid_match_pnode(pnode, pnode_mod, mod, name, name_len)) {
6604 return 0;
6605 }
6606 } else {
6607 /* using parent directly */
6608 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
6609 return 0;
6610 }
6611 }
6612
6613 /* now compare all the compiled parents */
6614 while (i > 1) {
6615 i -= 2;
6616 assert(exp->tokens[i] == LYXP_TOKEN_NAMETEST);
6617
6618 if (!parent) {
6619 /* no more parents but path continues */
6620 return 0;
6621 }
6622
6623 /* get exp node ID module */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006624 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 +02006625 &name_len);
6626 assert(mod);
6627
6628 /* compare with the parent */
6629 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
6630 return 0;
6631 }
6632 }
6633
6634 if (ctx_node && (ctx_node != parent)) {
6635 /* descendant path has not finished in the context node */
6636 return 0;
6637 } else if (!ctx_node && parent) {
6638 /* some parent was not matched */
6639 return 0;
6640 }
6641
6642 return 1;
6643}
6644
6645static void
6646lysc_augment_free(const struct ly_ctx *ctx, struct lysc_augment *aug)
6647{
6648 if (aug) {
6649 lyxp_expr_free(ctx, aug->nodeid);
6650
6651 free(aug);
6652 }
6653}
6654
6655static void
6656lysc_deviation_free(const struct ly_ctx *ctx, struct lysc_deviation *dev)
6657{
6658 if (dev) {
6659 lyxp_expr_free(ctx, dev->nodeid);
6660 LY_ARRAY_FREE(dev->devs);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006661 LY_ARRAY_FREE(dev->dev_pmods);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006662
6663 free(dev);
6664 }
6665}
6666
6667static void
6668lysc_refine_free(const struct ly_ctx *ctx, struct lysc_refine *rfn)
6669{
6670 if (rfn) {
6671 lyxp_expr_free(ctx, rfn->nodeid);
6672 LY_ARRAY_FREE(rfn->rfns);
6673
6674 free(rfn);
6675 }
6676}
6677
6678static void
6679lysp_dev_node_free(const struct ly_ctx *ctx, struct lysp_node *dev_pnode)
6680{
6681 if (!dev_pnode) {
6682 return;
6683 }
6684
6685 switch (dev_pnode->nodetype) {
6686 case LYS_CONTAINER:
6687 ((struct lysp_node_container *)dev_pnode)->child = NULL;
6688 break;
6689 case LYS_LIST:
6690 ((struct lysp_node_list *)dev_pnode)->child = NULL;
6691 break;
6692 case LYS_CHOICE:
6693 ((struct lysp_node_choice *)dev_pnode)->child = NULL;
6694 break;
6695 case LYS_CASE:
6696 ((struct lysp_node_case *)dev_pnode)->child = NULL;
6697 break;
6698 case LYS_LEAF:
6699 case LYS_LEAFLIST:
6700 case LYS_ANYXML:
6701 case LYS_ANYDATA:
6702 /* no children */
6703 break;
6704 case LYS_NOTIF:
6705 ((struct lysp_notif *)dev_pnode)->data = NULL;
6706 lysp_notif_free((struct ly_ctx *)ctx, (struct lysp_notif *)dev_pnode);
6707 free(dev_pnode);
6708 return;
6709 case LYS_RPC:
6710 case LYS_ACTION:
6711 ((struct lysp_action *)dev_pnode)->input.data = NULL;
6712 ((struct lysp_action *)dev_pnode)->output.data = NULL;
6713 lysp_action_free((struct ly_ctx *)ctx, (struct lysp_action *)dev_pnode);
6714 free(dev_pnode);
6715 return;
6716 case LYS_INPUT:
6717 case LYS_OUTPUT:
6718 ((struct lysp_action_inout *)dev_pnode)->data = NULL;
6719 lysp_action_inout_free((struct ly_ctx *)ctx, (struct lysp_action_inout *)dev_pnode);
6720 free(dev_pnode);
6721 return;
6722 default:
6723 LOGINT(ctx);
6724 return;
6725 }
6726
6727 lysp_node_free((struct ly_ctx *)ctx, dev_pnode);
6728}
6729
6730/**
6731 * @brief Compile and apply any precompiled deviations and refines targetting a node.
6732 *
6733 * @param[in] ctx Compile context.
6734 * @param[in] pnode Parsed node to consider.
6735 * @param[in] parent First compiled parent of @p pnode.
6736 * @param[out] dev_pnode Copy of parsed node @p pnode with deviations and refines, if any. NULL if there are none.
6737 * @param[out] no_supported Whether a not-supported deviation is defined for the node.
6738 * @return LY_ERR value.
6739 */
6740static LY_ERR
6741lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode, const struct lysc_node *parent,
6742 struct lysp_node **dev_pnode, ly_bool *not_supported)
6743{
6744 LY_ERR ret = LY_SUCCESS;
6745 uint32_t i;
6746 LY_ARRAY_COUNT_TYPE u;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006747 struct lys_module *orig_mod = ctx->cur_mod;
6748 struct lysp_module *orig_pmod = ctx->pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02006749 char orig_path[LYSC_CTX_BUFSIZE];
6750 struct lysc_refine *rfn;
6751 struct lysc_deviation *dev;
6752 struct lysp_deviation *dev_p;
6753 struct lysp_deviate *d;
6754
6755 *dev_pnode = NULL;
6756 *not_supported = 0;
6757
6758 for (i = 0; i < ctx->uses_rfns.count; ++i) {
6759 rfn = ctx->uses_rfns.objs[i];
6760
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006761 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 +02006762 /* not our target node */
6763 continue;
6764 }
6765
6766 if (!*dev_pnode) {
6767 /* first refine on this node, create a copy first */
6768 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
6769 }
6770
6771 /* apply all the refines by changing (the copy of) the parsed node */
6772 LY_ARRAY_FOR(rfn->rfns, u) {
6773 /* apply refine, keep the current path and add to it */
6774 lysc_update_path(ctx, NULL, "{refine}");
6775 lysc_update_path(ctx, NULL, rfn->rfns[u]->nodeid);
6776 ret = lys_apply_refine(ctx, rfn->rfns[u], *dev_pnode);
6777 lysc_update_path(ctx, NULL, NULL);
6778 lysc_update_path(ctx, NULL, NULL);
6779 LY_CHECK_GOTO(ret, cleanup);
6780 }
6781
6782 /* refine was applied, remove it */
6783 lysc_refine_free(ctx->ctx, rfn);
6784 ly_set_rm_index(&ctx->uses_rfns, i, NULL);
6785
6786 /* all the refines for one target node are in one structure, we are done */
6787 break;
6788 }
6789
6790 for (i = 0; i < ctx->devs.count; ++i) {
6791 dev = ctx->devs.objs[i];
6792
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006793 if (!lysp_schema_nodeid_match(dev->nodeid, dev->dev_pmods[0], NULL, parent, pnode, ctx->cur_mod)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02006794 /* not our target node */
6795 continue;
6796 }
6797
6798 if (dev->not_supported) {
6799 /* it is not supported, no more deviations */
6800 *not_supported = 1;
6801 goto dev_applied;
6802 }
6803
6804 if (!*dev_pnode) {
6805 /* first deviation on this node, create a copy first */
6806 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
6807 }
6808
6809 /* apply all the deviates by changing (the copy of) the parsed node */
6810 LY_ARRAY_FOR(dev->devs, u) {
6811 dev_p = dev->devs[u];
6812 LY_LIST_FOR(dev_p->deviates, d) {
6813 /* generate correct path */
6814 strcpy(orig_path, ctx->path);
6815 ctx->path_len = 1;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006816 ctx->cur_mod = dev->dev_pmods[u]->mod;
6817 ctx->pmod = (struct lysp_module *)dev->dev_pmods[u];
Michal Vasko7f45cf22020-10-01 12:49:44 +02006818 lysc_update_path(ctx, NULL, "{deviation}");
6819 lysc_update_path(ctx, NULL, dev_p->nodeid);
6820
6821 switch (d->mod) {
6822 case LYS_DEV_ADD:
6823 ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, *dev_pnode);
6824 break;
6825 case LYS_DEV_DELETE:
6826 ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, *dev_pnode);
6827 break;
6828 case LYS_DEV_REPLACE:
6829 ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, *dev_pnode);
6830 break;
6831 default:
6832 LOGINT(ctx->ctx);
6833 ret = LY_EINT;
6834 }
6835
6836 /* restore previous path */
6837 strcpy(ctx->path, orig_path);
6838 ctx->path_len = strlen(ctx->path);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006839 ctx->cur_mod = orig_mod;
6840 ctx->pmod = orig_pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02006841
6842 LY_CHECK_GOTO(ret, cleanup);
6843 }
6844 }
6845
6846dev_applied:
6847 /* deviation was applied, remove it */
6848 lysc_deviation_free(ctx->ctx, dev);
6849 ly_set_rm_index(&ctx->devs, i, NULL);
6850
6851 /* all the deviations for one target node are in one structure, we are done */
6852 break;
6853 }
6854
6855cleanup:
6856 if (ret) {
6857 lysp_dev_node_free(ctx->ctx, *dev_pnode);
6858 *dev_pnode = NULL;
6859 *not_supported = 0;
6860 }
6861 return ret;
6862}
6863
6864/**
6865 * @brief Compile and apply any precompiled top-level or uses augments targetting a node.
6866 *
6867 * @param[in] ctx Compile context.
6868 * @param[in] node Compiled node to consider.
6869 * @return LY_ERR value.
6870 */
6871static LY_ERR
6872lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
6873{
6874 LY_ERR ret = LY_SUCCESS;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006875 struct lys_module *orig_mod = ctx->cur_mod;
6876 struct lysp_module *orig_pmod = ctx->pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02006877 uint32_t i;
6878 char orig_path[LYSC_CTX_BUFSIZE];
6879 struct lysc_augment *aug;
6880
6881 /* uses augments */
6882 for (i = 0; i < ctx->uses_augs.count; ) {
6883 aug = ctx->uses_augs.objs[i];
6884
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006885 if (!lysp_schema_nodeid_match(aug->nodeid, aug->nodeid_pmod, aug->nodeid_ctx_node, node, NULL, NULL)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02006886 /* not our target node */
6887 ++i;
6888 continue;
6889 }
6890
6891 /* apply augment, keep the current path and add to it */
6892 lysc_update_path(ctx, NULL, "{augment}");
6893 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
6894 ret = lys_compile_augment(ctx, aug->aug_p, node);
6895 lysc_update_path(ctx, NULL, NULL);
6896 lysc_update_path(ctx, NULL, NULL);
6897 LY_CHECK_GOTO(ret, cleanup);
6898
6899 /* augment was applied, remove it (index may have changed because other augments could have been applied) */
Michal Vasko7f45cf22020-10-01 12:49:44 +02006900 ly_set_rm(&ctx->uses_augs, aug, NULL);
Michal Vaskoaf702452020-10-02 09:02:55 +02006901 lysc_augment_free(ctx->ctx, aug);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006902 }
6903
6904 /* top-level augments */
6905 for (i = 0; i < ctx->augs.count; ) {
6906 aug = ctx->augs.objs[i];
6907
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006908 if (!lysp_schema_nodeid_match(aug->nodeid, aug->nodeid_pmod, NULL, node, NULL, NULL)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02006909 /* not our target node */
6910 ++i;
6911 continue;
6912 }
6913
6914 /* apply augment, use the path and modules from the augment */
6915 strcpy(orig_path, ctx->path);
6916 ctx->path_len = 1;
6917 lysc_update_path(ctx, NULL, "{augment}");
6918 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006919 ctx->cur_mod = aug->nodeid_pmod->mod;
6920 ctx->pmod = (struct lysp_module *)aug->nodeid_pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02006921 ret = lys_compile_augment(ctx, aug->aug_p, node);
6922 strcpy(ctx->path, orig_path);
6923 ctx->path_len = strlen(ctx->path);
6924 LY_CHECK_GOTO(ret, cleanup);
6925
6926 /* augment was applied, remove it */
Michal Vasko7f45cf22020-10-01 12:49:44 +02006927 ly_set_rm(&ctx->augs, aug, NULL);
Michal Vaskoaf702452020-10-02 09:02:55 +02006928 lysc_augment_free(ctx->ctx, aug);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006929 }
6930
6931cleanup:
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006932 ctx->cur_mod = orig_mod;
6933 ctx->pmod = orig_pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02006934 return ret;
6935}
6936
6937/**
6938 * @brief Prepare a top-level augment to be applied during data nodes compilation.
6939 *
6940 * @param[in] ctx Compile context.
6941 * @param[in] aug_p Parsed augment to be applied.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006942 * @param[in] pmod Both current and prefix module for @p aug_p.
Michal Vasko7f45cf22020-10-01 12:49:44 +02006943 * @return LY_ERR value.
6944 */
6945static LY_ERR
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006946lys_precompile_own_augment(struct lysc_ctx *ctx, struct lysp_augment *aug_p, const struct lysp_module *pmod)
Michal Vasko7f45cf22020-10-01 12:49:44 +02006947{
6948 LY_ERR ret = LY_SUCCESS;
6949 struct lyxp_expr *exp = NULL;
6950 struct lysc_augment *aug;
6951 const struct lys_module *mod;
6952
6953 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
6954 ret = lyxp_expr_parse(ctx->ctx, aug_p->nodeid, strlen(aug_p->nodeid), 0, &exp);
6955 LY_CHECK_GOTO(ret, cleanup);
6956
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006957 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 +02006958 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006959 if (mod != ctx->cur_mod) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02006960 /* augment for another module, ignore */
6961 goto cleanup;
6962 }
6963
6964 /* allocate new compiled augment and store it in the set */
6965 aug = calloc(1, sizeof *aug);
6966 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci3d92e442020-10-12 12:48:13 +02006967 LY_CHECK_GOTO(ret = ly_set_add(&ctx->augs, aug, 1, NULL), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006968
6969 aug->nodeid = exp;
6970 exp = NULL;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006971 aug->nodeid_pmod = pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02006972 aug->aug_p = aug_p;
6973
6974cleanup:
6975 lyxp_expr_free(ctx->ctx, exp);
6976 return ret;
6977}
6978
6979/**
6980 * @brief Prepare all top-level augments for the current module to be applied during data nodes compilation.
6981 *
6982 * @param[in] ctx Compile context.
6983 * @return LY_ERR value.
6984 */
6985static LY_ERR
6986lys_precompile_own_augments(struct lysc_ctx *ctx)
6987{
6988 LY_ARRAY_COUNT_TYPE u, v, w;
6989 const struct lys_module *aug_mod;
6990
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006991 LY_ARRAY_FOR(ctx->cur_mod->augmented_by, u) {
6992 aug_mod = ctx->cur_mod->augmented_by[u];
Michal Vasko7f45cf22020-10-01 12:49:44 +02006993
6994 /* collect all module augments */
6995 LY_ARRAY_FOR(aug_mod->parsed->augments, v) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006996 LY_CHECK_RET(lys_precompile_own_augment(ctx, &aug_mod->parsed->augments[v], aug_mod->parsed));
Michal Vasko7f45cf22020-10-01 12:49:44 +02006997 }
6998
6999 /* collect all submodules augments */
7000 LY_ARRAY_FOR(aug_mod->parsed->includes, v) {
7001 LY_ARRAY_FOR(aug_mod->parsed->includes[v].submodule->augments, w) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007002 LY_CHECK_RET(lys_precompile_own_augment(ctx, &aug_mod->parsed->includes[v].submodule->augments[w],
7003 (struct lysp_module *)aug_mod->parsed->includes[v].submodule));
Michal Vasko7f45cf22020-10-01 12:49:44 +02007004 }
7005 }
7006 }
7007
7008 return LY_SUCCESS;
7009}
7010
7011/**
7012 * @brief Prepare a deviation to be applied during data nodes compilation.
7013 *
7014 * @param[in] ctx Compile context.
7015 * @param[in] dev_p Parsed deviation to be applied.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007016 * @param[in] pmod Both current and prefix module for @p dev_p.
Michal Vasko7f45cf22020-10-01 12:49:44 +02007017 * @return LY_ERR value.
7018 */
7019static LY_ERR
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007020lys_precompile_own_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev_p, const struct lysp_module *pmod)
Michal Vasko7f45cf22020-10-01 12:49:44 +02007021{
7022 LY_ERR ret = LY_SUCCESS;
7023 struct lysc_deviation *dev = NULL;
7024 struct lyxp_expr *exp = NULL;
7025 struct lysp_deviation **new_dev;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007026 const struct lys_module *mod;
7027 const struct lysp_module **new_dev_pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007028 uint32_t i;
7029
7030 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
7031 ret = lyxp_expr_parse(ctx->ctx, dev_p->nodeid, strlen(dev_p->nodeid), 0, &exp);
7032 LY_CHECK_GOTO(ret, cleanup);
7033
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007034 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 +02007035 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007036 if (mod != ctx->cur_mod) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02007037 /* deviation for another module, ignore */
7038 goto cleanup;
7039 }
7040
7041 /* try to find the node in already compiled deviations */
7042 for (i = 0; i < ctx->devs.count; ++i) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007043 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, pmod, ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid,
7044 ((struct lysc_deviation *)ctx->devs.objs[i])->dev_pmods[0])) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02007045 dev = ctx->devs.objs[i];
7046 break;
7047 }
7048 }
7049
7050 if (!dev) {
7051 /* allocate new compiled deviation */
7052 dev = calloc(1, sizeof *dev);
7053 LY_CHECK_ERR_GOTO(!dev, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci3d92e442020-10-12 12:48:13 +02007054 LY_CHECK_GOTO(ret = ly_set_add(&ctx->devs, dev, 1, NULL), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007055
7056 dev->nodeid = exp;
7057 exp = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007058 }
7059
7060 /* add new parsed deviation structure */
7061 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->devs, new_dev, ret, cleanup);
7062 *new_dev = dev_p;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007063 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->dev_pmods, new_dev_pmod, ret, cleanup);
7064 *new_dev_pmod = pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007065
7066cleanup:
7067 lyxp_expr_free(ctx->ctx, exp);
7068 return ret;
7069}
7070
7071/**
7072 * @brief Prepare all deviations for the current module to be applied during data nodes compilation.
7073 *
7074 * @param[in] ctx Compile context.
7075 * @return LY_ERR value.
7076 */
7077static LY_ERR
7078lys_precompile_own_deviations(struct lysc_ctx *ctx)
7079{
7080 LY_ARRAY_COUNT_TYPE u, v, w;
7081 const struct lys_module *dev_mod;
7082 struct lysc_deviation *dev;
7083 struct lysp_deviate *d;
7084 int not_supported;
7085 uint32_t i;
7086
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007087 LY_ARRAY_FOR(ctx->cur_mod->deviated_by, u) {
7088 dev_mod = ctx->cur_mod->deviated_by[u];
Michal Vasko7f45cf22020-10-01 12:49:44 +02007089
7090 /* compile all module deviations */
7091 LY_ARRAY_FOR(dev_mod->parsed->deviations, v) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007092 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->deviations[v], dev_mod->parsed));
Michal Vasko7f45cf22020-10-01 12:49:44 +02007093 }
7094
7095 /* compile all submodules deviations */
7096 LY_ARRAY_FOR(dev_mod->parsed->includes, v) {
7097 LY_ARRAY_FOR(dev_mod->parsed->includes[v].submodule->deviations, w) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007098 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->includes[v].submodule->deviations[w],
7099 (struct lysp_module *)dev_mod->parsed->includes[v].submodule));
Michal Vasko7f45cf22020-10-01 12:49:44 +02007100 }
7101 }
7102 }
7103
7104 /* set not-supported flags for all the deviations */
7105 for (i = 0; i < ctx->devs.count; ++i) {
7106 dev = ctx->devs.objs[i];
7107 not_supported = 0;
7108
7109 LY_ARRAY_FOR(dev->devs, u) {
7110 LY_LIST_FOR(dev->devs[u]->deviates, d) {
7111 if (d->mod == LYS_DEV_NOT_SUPPORTED) {
7112 not_supported = 1;
7113 break;
7114 }
7115 }
7116 if (not_supported) {
7117 break;
7118 }
7119 }
7120 if (not_supported && (LY_ARRAY_COUNT(dev->devs) > 1)) {
7121 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
7122 "Multiple deviations of \"%s\" with one of them being \"not-supported\".", dev->nodeid->expr);
7123 return LY_EVALID;
7124 }
7125
7126 dev->not_supported = not_supported;
7127 }
7128
7129 return LY_SUCCESS;
7130}
7131
Michal Vasko20424b42020-08-31 12:29:38 +02007132/**
Radek Krejcia3045382018-11-22 14:30:31 +01007133 * @brief Compile parsed schema node information.
7134 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02007135 * @param[in] pnode Parsed schema node.
Radek Krejcia3045382018-11-22 14:30:31 +01007136 * @param[in] parent Compiled parent node where the current node is supposed to be connected. It is
7137 * NULL for top-level nodes, in such a case the module where the node will be connected is taken from
7138 * the compile context.
Radek Krejcib1b59152019-01-07 13:21:56 +01007139 * @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).
7140 * Zero means no uses, non-zero value with no status bit set mean the default status.
Radek Krejcia3045382018-11-22 14:30:31 +01007141 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
7142 */
Radek Krejci19a96102018-11-15 13:38:09 +01007143static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02007144lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *parent, uint16_t uses_status,
7145 struct ly_set *child_set)
Radek Krejci19a96102018-11-15 13:38:09 +01007146{
Radek Krejci1c54f462020-05-12 17:25:34 +02007147 LY_ERR ret = LY_SUCCESS;
Radek Krejcic6b4f442020-08-12 14:45:18 +02007148 struct lysc_node *node = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007149 struct lysp_node *dev_pnode = NULL, *orig_pnode = pnode;
Radek Krejci1deb5be2020-08-26 16:43:36 +02007150 LY_ARRAY_COUNT_TYPE u;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007151 ly_bool not_supported;
Michal Vasko69730152020-10-09 16:30:07 +02007152
Michal Vasko22df3f02020-08-24 13:29:22 +02007153 LY_ERR (*node_compile_spec)(struct lysc_ctx *, struct lysp_node *, struct lysc_node *);
Radek Krejci19a96102018-11-15 13:38:09 +01007154
Michal Vasko7f45cf22020-10-01 12:49:44 +02007155 if (pnode->nodetype != LYS_USES) {
7156 lysc_update_path(ctx, parent, pnode->name);
Radek Krejci327de162019-06-14 12:52:07 +02007157 } else {
7158 lysc_update_path(ctx, NULL, "{uses}");
Michal Vasko7f45cf22020-10-01 12:49:44 +02007159 lysc_update_path(ctx, NULL, pnode->name);
Radek Krejci327de162019-06-14 12:52:07 +02007160 }
7161
Michal Vasko7f45cf22020-10-01 12:49:44 +02007162 switch (pnode->nodetype) {
Radek Krejci19a96102018-11-15 13:38:09 +01007163 case LYS_CONTAINER:
Michal Vasko22df3f02020-08-24 13:29:22 +02007164 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_container));
Radek Krejci19a96102018-11-15 13:38:09 +01007165 node_compile_spec = lys_compile_node_container;
7166 break;
7167 case LYS_LEAF:
Michal Vasko22df3f02020-08-24 13:29:22 +02007168 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_leaf));
Radek Krejci19a96102018-11-15 13:38:09 +01007169 node_compile_spec = lys_compile_node_leaf;
7170 break;
7171 case LYS_LIST:
Michal Vasko22df3f02020-08-24 13:29:22 +02007172 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_list));
Radek Krejci9bb94eb2018-12-04 16:48:35 +01007173 node_compile_spec = lys_compile_node_list;
Radek Krejci19a96102018-11-15 13:38:09 +01007174 break;
7175 case LYS_LEAFLIST:
Michal Vasko22df3f02020-08-24 13:29:22 +02007176 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_leaflist));
Radek Krejci0e5d8382018-11-28 16:37:53 +01007177 node_compile_spec = lys_compile_node_leaflist;
Radek Krejci19a96102018-11-15 13:38:09 +01007178 break;
Radek Krejci19a96102018-11-15 13:38:09 +01007179 case LYS_CHOICE:
Michal Vasko22df3f02020-08-24 13:29:22 +02007180 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_choice));
Radek Krejci056d0a82018-12-06 16:57:25 +01007181 node_compile_spec = lys_compile_node_choice;
Radek Krejci19a96102018-11-15 13:38:09 +01007182 break;
Michal Vasko891d7532020-10-07 09:41:38 +02007183 case LYS_CASE:
Michal Vasko20424b42020-08-31 12:29:38 +02007184 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_case));
7185 node_compile_spec = lys_compile_node_case;
7186 break;
Radek Krejci19a96102018-11-15 13:38:09 +01007187 case LYS_ANYXML:
7188 case LYS_ANYDATA:
Michal Vasko22df3f02020-08-24 13:29:22 +02007189 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_anydata));
Radek Krejci9800fb82018-12-13 14:26:23 +01007190 node_compile_spec = lys_compile_node_any;
Radek Krejci19a96102018-11-15 13:38:09 +01007191 break;
Radek Krejcie86bf772018-12-14 11:39:53 +01007192 case LYS_USES:
Michal Vasko7f45cf22020-10-01 12:49:44 +02007193 ret = lys_compile_uses(ctx, (struct lysp_node_uses *)pnode, parent, child_set);
Radek Krejci327de162019-06-14 12:52:07 +02007194 lysc_update_path(ctx, NULL, NULL);
7195 lysc_update_path(ctx, NULL, NULL);
7196 return ret;
Radek Krejci19a96102018-11-15 13:38:09 +01007197 default:
7198 LOGINT(ctx->ctx);
7199 return LY_EINT;
7200 }
7201 LY_CHECK_ERR_RET(!node, LOGMEM(ctx->ctx), LY_EMEM);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007202
7203 /* compile any deviations for this node */
7204 LY_CHECK_ERR_RET(ret = lys_compile_node_deviations_refines(ctx, pnode, parent, &dev_pnode, &not_supported),
7205 free(node), ret);
7206 if (not_supported) {
7207 free(node);
7208 lysc_update_path(ctx, NULL, NULL);
7209 return LY_SUCCESS;
7210 } else if (dev_pnode) {
7211 pnode = dev_pnode;
7212 }
7213
7214 node->nodetype = pnode->nodetype;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007215 node->module = ctx->cur_mod;
Radek Krejci19a96102018-11-15 13:38:09 +01007216 node->prev = node;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007217 node->flags = pnode->flags & LYS_FLAGS_COMPILED_MASK;
Radek Krejci19a96102018-11-15 13:38:09 +01007218
7219 /* config */
Michal Vasko20424b42020-08-31 12:29:38 +02007220 ret = lys_compile_config(ctx, node, parent);
7221 LY_CHECK_GOTO(ret, error);
Radek Krejci19a96102018-11-15 13:38:09 +01007222
Michal Vasko20424b42020-08-31 12:29:38 +02007223 /* list ordering */
Radek Krejcia6d57732018-11-29 13:40:37 +01007224 if (node->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
7225 if ((node->flags & LYS_CONFIG_R) && (node->flags & LYS_ORDBY_MASK)) {
Radek Krejcifc11bd72019-04-11 16:00:05 +02007226 LOGWRN(ctx->ctx, "The ordered-by statement is ignored in lists representing %s (%s).",
Radek Krejci90d4e922020-10-12 15:55:33 +02007227 (ctx->options & LYS_COMPILE_RPC_OUTPUT) ? "RPC/action output parameters" :
7228 (ctx->options & LYS_COMPILE_NOTIFICATION) ? "notification content" : "state data", ctx->path);
Radek Krejcia6d57732018-11-29 13:40:37 +01007229 node->flags &= ~LYS_ORDBY_MASK;
7230 node->flags |= LYS_ORDBY_SYSTEM;
7231 } else if (!(node->flags & LYS_ORDBY_MASK)) {
7232 /* default ordering is system */
7233 node->flags |= LYS_ORDBY_SYSTEM;
7234 }
7235 }
7236
Radek Krejci19a96102018-11-15 13:38:09 +01007237 /* status - it is not inherited by specification, but it does not make sense to have
7238 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
Michal Vasko20424b42020-08-31 12:29:38 +02007239 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 +01007240
Radek Krejci90d4e922020-10-12 15:55:33 +02007241 node->sp = orig_pnode;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007242 DUP_STRING_GOTO(ctx->ctx, pnode->name, node->name, ret, error);
7243 DUP_STRING_GOTO(ctx->ctx, pnode->dsc, node->dsc, ret, error);
7244 DUP_STRING_GOTO(ctx->ctx, pnode->ref, node->ref, ret, error);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007245 COMPILE_ARRAY_GOTO(ctx, pnode->iffeatures, node->iffeatures, u, lys_compile_iffeature, ret, error);
Radek Krejci19a96102018-11-15 13:38:09 +01007246
Michal Vasko20424b42020-08-31 12:29:38 +02007247 /* insert into parent's children/compiled module (we can no longer free the node separately on error) */
Michal Vasko7f45cf22020-10-01 12:49:44 +02007248 LY_CHECK_GOTO(ret = lys_compile_node_connect(ctx, parent, node), cleanup);
7249
Michal Vasko4865ac42020-10-12 16:31:06 +02007250 if (pnode->when) {
7251 /* compile when */
7252 ret = lys_compile_when(ctx, pnode->when, pnode->flags, lysc_xpath_context(node), node, NULL);
7253 LY_CHECK_GOTO(ret, cleanup);
7254 }
7255
Michal Vasko7f45cf22020-10-01 12:49:44 +02007256 /* connect any augments */
7257 LY_CHECK_GOTO(ret = lys_compile_node_augments(ctx, node), cleanup);
Michal Vasko20424b42020-08-31 12:29:38 +02007258
Radek Krejci19a96102018-11-15 13:38:09 +01007259 /* nodetype-specific part */
Michal Vasko7f45cf22020-10-01 12:49:44 +02007260 LY_CHECK_GOTO(ret = node_compile_spec(ctx, pnode, node), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01007261
Michal Vasko20424b42020-08-31 12:29:38 +02007262 /* final compilation tasks that require the node to be connected */
Michal Vasko7f45cf22020-10-01 12:49:44 +02007263 COMPILE_EXTS_GOTO(ctx, pnode->exts, node->exts, node, LYEXT_PAR_NODE, ret, cleanup);
Radek Krejcife909632019-02-12 15:34:42 +01007264 if (node->flags & LYS_MAND_TRUE) {
Michal Vasko20424b42020-08-31 12:29:38 +02007265 /* inherit LYS_MAND_TRUE in parent containers */
Radek Krejcife909632019-02-12 15:34:42 +01007266 lys_compile_mandatory_parents(parent, 1);
7267 }
7268
Michal Vasko7f45cf22020-10-01 12:49:44 +02007269 if (child_set) {
7270 /* add the new node into set */
Radek Krejci3d92e442020-10-12 12:48:13 +02007271 LY_CHECK_GOTO(ret = ly_set_add(child_set, node, 1, NULL), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007272 }
7273
Radek Krejci327de162019-06-14 12:52:07 +02007274 lysc_update_path(ctx, NULL, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007275 lysp_dev_node_free(ctx->ctx, dev_pnode);
Radek Krejci19a96102018-11-15 13:38:09 +01007276 return LY_SUCCESS;
7277
7278error:
7279 lysc_node_free(ctx->ctx, node);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007280cleanup:
7281 if (dev_pnode) {
7282 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_OTHER, "Compilation of a deviated and/or refined node failed.");
7283 lysp_dev_node_free(ctx->ctx, dev_pnode);
7284 }
Radek Krejci19a96102018-11-15 13:38:09 +01007285 return ret;
7286}
7287
Michal Vaskoccc062a2020-08-13 08:34:50 +02007288/**
Michal Vasko7f45cf22020-10-01 12:49:44 +02007289 * @brief Add a module reference into an array, checks for duplicities.
Michal Vaskoccc062a2020-08-13 08:34:50 +02007290 *
7291 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02007292 * @param[in] mod Module reference to add.
7293 * @param[in,out] mod_array Module sized array to add to.
Michal Vaskoccc062a2020-08-13 08:34:50 +02007294 * @return LY_ERR value.
7295 */
7296static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02007297lys_array_add_mod_ref(struct lysc_ctx *ctx, struct lys_module *mod, struct lys_module ***mod_array)
Michal Vaskoccc062a2020-08-13 08:34:50 +02007298{
Michal Vasko7f45cf22020-10-01 12:49:44 +02007299 LY_ARRAY_COUNT_TYPE u;
7300 struct lys_module **new_mod;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007301
Michal Vasko7f45cf22020-10-01 12:49:44 +02007302 LY_ARRAY_FOR(*mod_array, u) {
7303 if ((*mod_array)[u] == mod) {
7304 /* already there */
7305 return LY_EEXIST;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007306 }
7307 }
7308
Michal Vasko7f45cf22020-10-01 12:49:44 +02007309 /* add the new module ref */
7310 LY_ARRAY_NEW_RET(ctx->ctx, *mod_array, new_mod, LY_EMEM);
7311 *new_mod = mod;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007312
7313 return LY_SUCCESS;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007314}
7315
Michal Vaskoccc062a2020-08-13 08:34:50 +02007316/**
Michal Vasko7f45cf22020-10-01 12:49:44 +02007317 * @brief Compile top-level augments and deviations defined in the current module.
Michal Vasko89b5c072020-10-06 13:52:44 +02007318 * Generally, just add the module refence to the target modules. But in case
7319 * of foreign augments, they are directly applied.
Michal Vaskoccc062a2020-08-13 08:34:50 +02007320 *
7321 * @param[in] ctx Compile context.
Michal Vaskoccc062a2020-08-13 08:34:50 +02007322 * @return LY_ERR value.
7323 */
7324static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02007325lys_precompile_augments_deviations(struct lysc_ctx *ctx)
Michal Vaskoccc062a2020-08-13 08:34:50 +02007326{
Michal Vasko7f45cf22020-10-01 12:49:44 +02007327 LY_ERR ret = LY_SUCCESS;
7328 LY_ARRAY_COUNT_TYPE u, v;
7329 const struct lysp_module *mod_p;
7330 const struct lysc_node *target;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007331 struct lys_module *mod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007332 struct lysp_submodule *submod;
7333 ly_bool has_dev = 0;
7334 uint16_t flags;
7335 uint32_t idx, opt_prev = ctx->options;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007336
Michal Vasko89b5c072020-10-06 13:52:44 +02007337 for (idx = 0; idx < ctx->ctx->implementing.count; ++idx) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007338 if (ctx->cur_mod == ctx->ctx->implementing.objs[idx]) {
Michal Vasko89b5c072020-10-06 13:52:44 +02007339 break;
7340 }
7341 }
7342 if (idx == ctx->ctx->implementing.count) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02007343 /* it was already implemented and all the augments and deviations fully applied */
7344 return LY_SUCCESS;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007345 }
7346
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007347 mod_p = ctx->cur_mod->parsed;
Michal Vasko89b5c072020-10-06 13:52:44 +02007348
Michal Vasko7f45cf22020-10-01 12:49:44 +02007349 LY_ARRAY_FOR(mod_p->augments, u) {
7350 lysc_update_path(ctx, NULL, "{augment}");
7351 lysc_update_path(ctx, NULL, mod_p->augments[u].nodeid);
Michal Vaskoccc062a2020-08-13 08:34:50 +02007352
Michal Vasko7f45cf22020-10-01 12:49:44 +02007353 /* get target module */
7354 ret = lys_nodeid_check(ctx, mod_p->augments[u].nodeid, 1, &mod, NULL);
7355 LY_CHECK_RET(ret);
Michal Vaskoccc062a2020-08-13 08:34:50 +02007356
Michal Vasko7f45cf22020-10-01 12:49:44 +02007357 /* add this module into the target module augmented_by, if not there already from previous augments */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007358 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->augmented_by);
Michal Vaskoccc062a2020-08-13 08:34:50 +02007359
Michal Vasko7f45cf22020-10-01 12:49:44 +02007360 /* if we are compiling this module, we cannot add augments to it yet */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007361 if (mod != ctx->cur_mod) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02007362 /* apply the augment, find the target node first */
7363 flags = 0;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007364 ret = lysc_resolve_schema_nodeid(ctx, mod_p->augments[u].nodeid, 0, NULL, ctx->cur_mod, LY_PREF_SCHEMA,
7365 (void *)mod_p, 0, &target, &flags);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007366 LY_CHECK_RET(ret);
7367
Michal Vasko7f45cf22020-10-01 12:49:44 +02007368 /* apply the augment */
7369 ctx->options |= flags;
7370 ret = lys_compile_augment(ctx, &mod_p->augments[u], (struct lysc_node *)target);
7371 ctx->options = opt_prev;
7372 LY_CHECK_RET(ret);
Radek Krejciccd20f12019-02-15 14:12:27 +01007373 }
Radek Krejci327de162019-06-14 12:52:07 +02007374
7375 lysc_update_path(ctx, NULL, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007376 lysc_update_path(ctx, NULL, NULL);
Radek Krejciccd20f12019-02-15 14:12:27 +01007377 }
7378
Michal Vasko7f45cf22020-10-01 12:49:44 +02007379 LY_ARRAY_FOR(mod_p->deviations, u) {
7380 /* get target module */
7381 lysc_update_path(ctx, NULL, "{deviation}");
7382 lysc_update_path(ctx, NULL, mod_p->deviations[u].nodeid);
7383 ret = lys_nodeid_check(ctx, mod_p->deviations[u].nodeid, 1, &mod, NULL);
7384 lysc_update_path(ctx, NULL, NULL);
7385 lysc_update_path(ctx, NULL, NULL);
7386 LY_CHECK_RET(ret);
Radek Krejciba03a5a2020-08-27 14:40:41 +02007387
Michal Vasko7f45cf22020-10-01 12:49:44 +02007388 /* add this module into the target module deviated_by, if not there already from previous deviations */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007389 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->deviated_by);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007390
7391 /* new deviation added to the target module */
7392 has_dev = 1;
7393 }
7394
7395 /* the same for augments and deviations in submodules */
7396 LY_ARRAY_FOR(mod_p->includes, v) {
7397 submod = mod_p->includes[v].submodule;
7398 LY_ARRAY_FOR(submod->augments, u) {
7399 lysc_update_path(ctx, NULL, "{augment}");
7400 lysc_update_path(ctx, NULL, submod->augments[u].nodeid);
7401
7402 ret = lys_nodeid_check(ctx, submod->augments[u].nodeid, 1, &mod, NULL);
7403 LY_CHECK_RET(ret);
7404
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007405 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->augmented_by);
7406 if (mod != ctx->cur_mod) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02007407 flags = 0;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007408 ret = lysc_resolve_schema_nodeid(ctx, mod_p->augments[u].nodeid, 0, NULL, ctx->cur_mod, LY_PREF_SCHEMA,
7409 submod, 0, &target, &flags);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007410 LY_CHECK_RET(ret);
7411
7412 ctx->options |= flags;
7413 ret = lys_compile_augment(ctx, &submod->augments[u], (struct lysc_node *)target);
7414 ctx->options = opt_prev;
7415 LY_CHECK_RET(ret);
Radek Krejcif538ce52019-03-05 10:46:14 +01007416 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02007417
7418 lysc_update_path(ctx, NULL, NULL);
7419 lysc_update_path(ctx, NULL, NULL);
Radek Krejcif538ce52019-03-05 10:46:14 +01007420 }
7421
Michal Vasko7f45cf22020-10-01 12:49:44 +02007422 LY_ARRAY_FOR(submod->deviations, u) {
7423 lysc_update_path(ctx, NULL, "{deviation}");
7424 lysc_update_path(ctx, NULL, submod->deviations[u].nodeid);
7425 ret = lys_nodeid_check(ctx, submod->deviations[u].nodeid, 1, &mod, NULL);
7426 lysc_update_path(ctx, NULL, NULL);
7427 lysc_update_path(ctx, NULL, NULL);
7428 LY_CHECK_RET(ret);
Radek Krejcifc11bd72019-04-11 16:00:05 +02007429
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007430 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->deviated_by);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007431 has_dev = 1;
Michal Vaskoe6143202020-07-03 13:02:08 +02007432 }
Radek Krejciccd20f12019-02-15 14:12:27 +01007433 }
7434
Michal Vasko7f45cf22020-10-01 12:49:44 +02007435 if (!has_dev) {
7436 /* no need to recompile any modules */
7437 return LY_SUCCESS;
7438 }
7439
7440 /* free all the modules in descending order */
7441 idx = ctx->ctx->list.count;
7442 do {
7443 --idx;
7444 mod = ctx->ctx->list.objs[idx];
7445 /* skip this module */
7446 if (mod == mod_p->mod) {
7447 continue;
7448 }
7449
7450 if (mod->implemented && mod->compiled) {
7451 /* keep information about features state in the module */
7452 lys_feature_precompile_revert(ctx, mod);
7453
7454 /* free the module */
7455 lysc_module_free(mod->compiled, NULL);
7456 mod->compiled = NULL;
7457 }
7458 } while (idx);
7459
7460 /* recompile all the modules in ascending order */
7461 for (idx = 0; idx < ctx->ctx->list.count; ++idx) {
7462 mod = ctx->ctx->list.objs[idx];
7463
7464 /* skip this module */
7465 if (mod == mod_p->mod) {
7466 continue;
7467 }
7468
7469 if (mod->implemented) {
7470 /* compile */
Michal Vasko89b5c072020-10-06 13:52:44 +02007471 LY_CHECK_GOTO(ret = lys_compile(mod, 0), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007472 }
7473 }
Radek Krejciccd20f12019-02-15 14:12:27 +01007474
7475cleanup:
Radek Krejcid05cbd92018-12-05 14:26:40 +01007476 return ret;
7477}
7478
Radek Krejci335332a2019-09-05 13:03:35 +02007479static void *
7480lys_compile_extension_instance_storage(enum ly_stmt stmt, struct lysc_ext_substmt *substmts)
7481{
Radek Krejci1deb5be2020-08-26 16:43:36 +02007482 for (LY_ARRAY_COUNT_TYPE u = 0; substmts[u].stmt; ++u) {
Radek Krejci335332a2019-09-05 13:03:35 +02007483 if (substmts[u].stmt == stmt) {
7484 return substmts[u].storage;
7485 }
7486 }
7487 return NULL;
7488}
7489
7490LY_ERR
7491lys_compile_extension_instance(struct lysc_ctx *ctx, const struct lysp_ext_instance *ext, struct lysc_ext_substmt *substmts)
7492{
7493 LY_ERR ret = LY_EVALID, r;
Radek Krejci1deb5be2020-08-26 16:43:36 +02007494 LY_ARRAY_COUNT_TYPE u;
Radek Krejci335332a2019-09-05 13:03:35 +02007495 struct lysp_stmt *stmt;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007496 struct lysp_qname qname;
Radek Krejci335332a2019-09-05 13:03:35 +02007497 void *parsed = NULL, **compiled = NULL;
Radek Krejci335332a2019-09-05 13:03:35 +02007498
7499 /* check for invalid substatements */
7500 for (stmt = ext->child; stmt; stmt = stmt->next) {
Radek Krejcif56e2a42019-09-09 14:15:25 +02007501 if (stmt->flags & (LYS_YIN_ATTR | LYS_YIN_ARGUMENT)) {
7502 continue;
7503 }
Radek Krejci335332a2019-09-05 13:03:35 +02007504 for (u = 0; substmts[u].stmt; ++u) {
7505 if (substmts[u].stmt == stmt->kw) {
7506 break;
7507 }
7508 }
7509 if (!substmts[u].stmt) {
Radek Krejciad5963b2019-09-06 16:03:05 +02007510 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 +02007511 stmt->stmt, ext->name, ext->argument ? " " : "", ext->argument ? ext->argument : "");
Radek Krejci335332a2019-09-05 13:03:35 +02007512 goto cleanup;
7513 }
Radek Krejci335332a2019-09-05 13:03:35 +02007514 }
7515
Radek Krejciad5963b2019-09-06 16:03:05 +02007516 /* TODO store inherited data, e.g. status first, but mark them somehow to allow to overwrite them and not detect duplicity */
7517
Radek Krejci335332a2019-09-05 13:03:35 +02007518 /* keep order of the processing the same as the order in the defined substmts,
7519 * the order is important for some of the statements depending on others (e.g. type needs status and units) */
7520 for (u = 0; substmts[u].stmt; ++u) {
Radek Krejci857189e2020-09-01 13:26:36 +02007521 ly_bool stmt_present = 0;
Radek Krejciad5963b2019-09-06 16:03:05 +02007522
Radek Krejci335332a2019-09-05 13:03:35 +02007523 for (stmt = ext->child; stmt; stmt = stmt->next) {
7524 if (substmts[u].stmt != stmt->kw) {
7525 continue;
7526 }
7527
Radek Krejciad5963b2019-09-06 16:03:05 +02007528 stmt_present = 1;
Radek Krejci335332a2019-09-05 13:03:35 +02007529 if (substmts[u].storage) {
7530 switch (stmt->kw) {
Radek Krejciad5963b2019-09-06 16:03:05 +02007531 case LY_STMT_STATUS:
7532 assert(substmts[u].cardinality < LY_STMT_CARD_SOME);
7533 LY_CHECK_ERR_GOTO(r = lysp_stmt_parse(ctx, stmt, stmt->kw, &substmts[u].storage, /* TODO */ NULL), ret = r, cleanup);
7534 break;
7535 case LY_STMT_UNITS: {
7536 const char **units;
7537
7538 if (substmts[u].cardinality < LY_STMT_CARD_SOME) {
7539 /* single item */
7540 if (*((const char **)substmts[u].storage)) {
7541 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPSTMT, stmt->stmt);
7542 goto cleanup;
7543 }
7544 units = (const char **)substmts[u].storage;
7545 } else {
7546 /* sized array */
7547 const char ***units_array = (const char ***)substmts[u].storage;
7548 LY_ARRAY_NEW_GOTO(ctx->ctx, *units_array, units, ret, cleanup);
7549 }
Radek Krejci011e4aa2020-09-04 15:22:31 +02007550 r = lydict_insert(ctx->ctx, stmt->arg, 0, units);
7551 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
Radek Krejciad5963b2019-09-06 16:03:05 +02007552 break;
7553 }
Radek Krejci335332a2019-09-05 13:03:35 +02007554 case LY_STMT_TYPE: {
7555 uint16_t *flags = lys_compile_extension_instance_storage(LY_STMT_STATUS, substmts);
7556 const char **units = lys_compile_extension_instance_storage(LY_STMT_UNITS, substmts);
7557
7558 if (substmts[u].cardinality < LY_STMT_CARD_SOME) {
7559 /* single item */
Michal Vasko22df3f02020-08-24 13:29:22 +02007560 if (*(struct lysc_type **)substmts[u].storage) {
Radek Krejci335332a2019-09-05 13:03:35 +02007561 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPSTMT, stmt->stmt);
7562 goto cleanup;
7563 }
7564 compiled = substmts[u].storage;
7565 } else {
7566 /* sized array */
Michal Vasko22df3f02020-08-24 13:29:22 +02007567 struct lysc_type ***types = (struct lysc_type ***)substmts[u].storage, **type = NULL;
Radek Krejci335332a2019-09-05 13:03:35 +02007568 LY_ARRAY_NEW_GOTO(ctx->ctx, *types, type, ret, cleanup);
Michal Vasko22df3f02020-08-24 13:29:22 +02007569 compiled = (void *)type;
Radek Krejci335332a2019-09-05 13:03:35 +02007570 }
7571
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007572 r = lysp_stmt_parse(ctx, stmt, stmt->kw, &parsed, NULL);
7573 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
7574 r = lys_compile_type(ctx, ext->parent_type == LYEXT_PAR_NODE ? ((struct lysc_node *)ext->parent)->sp : NULL,
7575 flags ? *flags : 0, ctx->pmod, ext->name, parsed, (struct lysc_type **)compiled,
7576 units && !*units ? units : NULL, NULL);
Radek Krejci38d85362019-09-05 16:26:38 +02007577 lysp_type_free(ctx->ctx, parsed);
7578 free(parsed);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007579 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
Radek Krejci335332a2019-09-05 13:03:35 +02007580 break;
7581 }
Radek Krejciad5963b2019-09-06 16:03:05 +02007582 case LY_STMT_IF_FEATURE: {
7583 struct lysc_iffeature *iff = NULL;
7584
7585 if (substmts[u].cardinality < LY_STMT_CARD_SOME) {
7586 /* single item */
Michal Vasko22df3f02020-08-24 13:29:22 +02007587 if (((struct lysc_iffeature *)substmts[u].storage)->features) {
Radek Krejciad5963b2019-09-06 16:03:05 +02007588 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPSTMT, stmt->stmt);
7589 goto cleanup;
7590 }
Michal Vasko22df3f02020-08-24 13:29:22 +02007591 iff = (struct lysc_iffeature *)substmts[u].storage;
Radek Krejciad5963b2019-09-06 16:03:05 +02007592 } else {
7593 /* sized array */
Michal Vasko22df3f02020-08-24 13:29:22 +02007594 struct lysc_iffeature **iffs = (struct lysc_iffeature **)substmts[u].storage;
Radek Krejciad5963b2019-09-06 16:03:05 +02007595 LY_ARRAY_NEW_GOTO(ctx->ctx, *iffs, iff, ret, cleanup);
7596 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02007597 qname.str = stmt->arg;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007598 qname.mod = ctx->pmod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007599 LY_CHECK_ERR_GOTO(r = lys_compile_iffeature(ctx, &qname, iff), ret = r, cleanup);
Radek Krejciad5963b2019-09-06 16:03:05 +02007600 break;
7601 }
7602 /* TODO support other substatements (parse stmt to lysp and then compile lysp to lysc),
7603 * also note that in many statements their extensions are not taken into account */
Radek Krejci335332a2019-09-05 13:03:35 +02007604 default:
Radek Krejciad5963b2019-09-06 16:03:05 +02007605 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 +02007606 stmt->stmt, ext->name, ext->argument ? " " : "", ext->argument ? ext->argument : "");
Radek Krejci335332a2019-09-05 13:03:35 +02007607 goto cleanup;
7608 }
7609 }
Radek Krejci335332a2019-09-05 13:03:35 +02007610 }
Radek Krejci335332a2019-09-05 13:03:35 +02007611
Michal Vasko69730152020-10-09 16:30:07 +02007612 if (((substmts[u].cardinality == LY_STMT_CARD_MAND) || (substmts[u].cardinality == LY_STMT_CARD_SOME)) && !stmt_present) {
Radek Krejciad5963b2019-09-06 16:03:05 +02007613 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 +02007614 ly_stmt2str(substmts[u].stmt), ext->name, ext->argument ? " " : "", ext->argument ? ext->argument : "");
Radek Krejciad5963b2019-09-06 16:03:05 +02007615 goto cleanup;
7616 }
Radek Krejci335332a2019-09-05 13:03:35 +02007617 }
7618
7619 ret = LY_SUCCESS;
7620
7621cleanup:
Radek Krejci335332a2019-09-05 13:03:35 +02007622 return ret;
7623}
7624
Michal Vasko175012e2019-11-06 15:49:14 +01007625/**
Michal Vaskoecd62de2019-11-13 12:35:11 +01007626 * @brief Check when for cyclic dependencies.
Michal Vasko7f45cf22020-10-01 12:49:44 +02007627 *
Michal Vaskoecd62de2019-11-13 12:35:11 +01007628 * @param[in] set Set with all the referenced nodes.
7629 * @param[in] node Node whose "when" referenced nodes are in @p set.
7630 * @return LY_ERR value
7631 */
7632static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02007633lys_compile_unres_when_cyclic(struct lyxp_set *set, const struct lysc_node *node)
Michal Vaskoecd62de2019-11-13 12:35:11 +01007634{
7635 struct lyxp_set tmp_set;
7636 struct lyxp_set_scnode *xp_scnode;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007637 uint32_t i, j;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02007638 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoecd62de2019-11-13 12:35:11 +01007639 struct lysc_when *when;
7640 LY_ERR ret = LY_SUCCESS;
7641
7642 memset(&tmp_set, 0, sizeof tmp_set);
7643
7644 /* prepare in_ctx of the set */
Michal Vaskod989ba02020-08-24 10:59:24 +02007645 for (i = 0; i < set->used; ++i) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007646 xp_scnode = &set->val.scnodes[i];
7647
Michal Vasko5c4e5892019-11-14 12:31:38 +01007648 if (xp_scnode->in_ctx != -1) {
7649 /* check node when, skip the context node (it was just checked) */
Michal Vaskoecd62de2019-11-13 12:35:11 +01007650 xp_scnode->in_ctx = 1;
7651 }
7652 }
7653
7654 for (i = 0; i < set->used; ++i) {
7655 xp_scnode = &set->val.scnodes[i];
7656 if (xp_scnode->in_ctx != 1) {
7657 /* already checked */
7658 continue;
7659 }
7660
Michal Vasko69730152020-10-09 16:30:07 +02007661 if ((xp_scnode->type != LYXP_NODE_ELEM) || (xp_scnode->scnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) ||
7662 !xp_scnode->scnode->when) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007663 /* no when to check */
7664 xp_scnode->in_ctx = 0;
7665 continue;
7666 }
7667
7668 node = xp_scnode->scnode;
7669 do {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007670 LY_ARRAY_FOR(node->when, u) {
7671 when = node->when[u];
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007672 ret = lyxp_atomize(when->cond, node->module, LY_PREF_SCHEMA_RESOLVED, when->prefixes, when->context,
7673 &tmp_set, LYXP_SCNODE_SCHEMA);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007674 if (ret != LY_SUCCESS) {
Michal Vaskof6e51882019-12-16 09:59:45 +01007675 LOGVAL(set->ctx, LY_VLOG_LYSC, node, LYVE_SEMANTICS, "Invalid when condition \"%s\".", when->cond->expr);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007676 goto cleanup;
7677 }
7678
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007679 for (j = 0; j < tmp_set.used; ++j) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007680 /* skip roots'n'stuff */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007681 if (tmp_set.val.scnodes[j].type == LYXP_NODE_ELEM) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007682 /* try to find this node in our set */
Radek Krejciaa6b53f2020-08-27 15:19:03 +02007683 uint32_t idx;
7684 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 +01007685 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 +01007686 ret = LY_EVALID;
7687 goto cleanup;
7688 }
7689
7690 /* needs to be checked, if in both sets, will be ignored */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007691 tmp_set.val.scnodes[j].in_ctx = 1;
Michal Vaskoecd62de2019-11-13 12:35:11 +01007692 } else {
7693 /* no when, nothing to check */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007694 tmp_set.val.scnodes[j].in_ctx = 0;
Michal Vaskoecd62de2019-11-13 12:35:11 +01007695 }
7696 }
7697
7698 /* merge this set into the global when set */
7699 lyxp_set_scnode_merge(set, &tmp_set);
7700 }
7701
7702 /* check when of non-data parents as well */
7703 node = node->parent;
7704 } while (node && (node->nodetype & (LYS_CASE | LYS_CHOICE)));
7705
Michal Vasko251f56e2019-11-14 16:06:47 +01007706 /* this node when was checked (xp_scnode could have been reallocd) */
7707 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoecd62de2019-11-13 12:35:11 +01007708 }
7709
7710cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02007711 lyxp_set_free_content(&tmp_set);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007712 return ret;
7713}
7714
7715/**
Michal Vasko7f45cf22020-10-01 12:49:44 +02007716 * @brief Check when/must expressions of a node on a complete compiled schema tree.
7717 *
Michal Vasko175012e2019-11-06 15:49:14 +01007718 * @param[in] ctx Compile context.
7719 * @param[in] node Node to check.
7720 * @return LY_ERR value
7721 */
7722static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02007723lys_compile_unres_xpath(struct lysc_ctx *ctx, const struct lysc_node *node)
Michal Vasko175012e2019-11-06 15:49:14 +01007724{
Michal Vasko175012e2019-11-06 15:49:14 +01007725 struct lyxp_set tmp_set;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007726 uint32_t i, opts;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02007727 LY_ARRAY_COUNT_TYPE u;
Radek Krejci857189e2020-09-01 13:26:36 +02007728 ly_bool input_done = 0;
Michal Vasko175012e2019-11-06 15:49:14 +01007729 struct lysc_when **when = NULL;
7730 struct lysc_must *musts = NULL;
7731 LY_ERR ret = LY_SUCCESS;
Michal Vasko6b26e742020-07-17 15:02:10 +02007732 const struct lysc_node *op;
Michal Vasko175012e2019-11-06 15:49:14 +01007733
7734 memset(&tmp_set, 0, sizeof tmp_set);
Michal Vasko5d8756a2019-11-07 15:21:00 +01007735 opts = LYXP_SCNODE_SCHEMA;
Michal Vasko6b26e742020-07-17 15:02:10 +02007736 if (node->flags & LYS_CONFIG_R) {
Michal Vasko2b7e5582020-10-07 12:31:23 +02007737 for (op = node->parent; op && !(op->nodetype & (LYS_RPC | LYS_ACTION)); op = op->parent) {}
Michal Vasko6b26e742020-07-17 15:02:10 +02007738 if (op) {
7739 /* we are actually in output */
7740 opts = LYXP_SCNODE_OUTPUT;
7741 }
7742 }
Michal Vasko175012e2019-11-06 15:49:14 +01007743
7744 switch (node->nodetype) {
7745 case LYS_CONTAINER:
7746 when = ((struct lysc_node_container *)node)->when;
7747 musts = ((struct lysc_node_container *)node)->musts;
7748 break;
7749 case LYS_CHOICE:
7750 when = ((struct lysc_node_choice *)node)->when;
7751 break;
7752 case LYS_LEAF:
7753 when = ((struct lysc_node_leaf *)node)->when;
7754 musts = ((struct lysc_node_leaf *)node)->musts;
7755 break;
7756 case LYS_LEAFLIST:
7757 when = ((struct lysc_node_leaflist *)node)->when;
7758 musts = ((struct lysc_node_leaflist *)node)->musts;
7759 break;
7760 case LYS_LIST:
7761 when = ((struct lysc_node_list *)node)->when;
7762 musts = ((struct lysc_node_list *)node)->musts;
7763 break;
7764 case LYS_ANYXML:
7765 case LYS_ANYDATA:
7766 when = ((struct lysc_node_anydata *)node)->when;
7767 musts = ((struct lysc_node_anydata *)node)->musts;
7768 break;
7769 case LYS_CASE:
7770 when = ((struct lysc_node_case *)node)->when;
7771 break;
7772 case LYS_NOTIF:
Michal Vaskoceab6dd2020-10-09 16:53:36 +02007773 when = ((struct lysc_notif *)node)->when;
Michal Vasko175012e2019-11-06 15:49:14 +01007774 musts = ((struct lysc_notif *)node)->musts;
7775 break;
Michal Vasko1bf09392020-03-27 12:38:10 +01007776 case LYS_RPC:
Michal Vasko5d8756a2019-11-07 15:21:00 +01007777 case LYS_ACTION:
Michal Vaskoceab6dd2020-10-09 16:53:36 +02007778 /* first process when and input musts */
7779 when = ((struct lysc_action *)node)->when;
Michal Vasko5d8756a2019-11-07 15:21:00 +01007780 musts = ((struct lysc_action *)node)->input.musts;
7781 break;
Michal Vasko175012e2019-11-06 15:49:14 +01007782 default:
7783 /* nothing to check */
7784 break;
7785 }
7786
Michal Vasko175012e2019-11-06 15:49:14 +01007787 /* check "when" */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007788 LY_ARRAY_FOR(when, u) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007789 ret = lyxp_atomize(when[u]->cond, node->module, LY_PREF_SCHEMA_RESOLVED, when[u]->prefixes, when[u]->context,
7790 &tmp_set, opts);
Michal Vasko175012e2019-11-06 15:49:14 +01007791 if (ret != LY_SUCCESS) {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007792 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_SEMANTICS, "Invalid when condition \"%s\".", when[u]->cond->expr);
Michal Vasko175012e2019-11-06 15:49:14 +01007793 goto cleanup;
7794 }
7795
Michal Vaskodc052f32019-11-07 11:11:38 +01007796 ctx->path[0] = '\0';
7797 lysc_path((struct lysc_node *)node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007798 for (i = 0; i < tmp_set.used; ++i) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01007799 /* skip roots'n'stuff */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007800 if ((tmp_set.val.scnodes[i].type == LYXP_NODE_ELEM) && (tmp_set.val.scnodes[i].in_ctx != -1)) {
7801 struct lysc_node *schema = tmp_set.val.scnodes[i].scnode;
Michal Vasko175012e2019-11-06 15:49:14 +01007802
Michal Vaskoecd62de2019-11-13 12:35:11 +01007803 /* XPath expression cannot reference "lower" status than the node that has the definition */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007804 ret = lysc_check_status(ctx, when[u]->flags, node->module, node->name, schema->flags, schema->module,
Michal Vasko69730152020-10-09 16:30:07 +02007805 schema->name);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007806 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko5c4e5892019-11-14 12:31:38 +01007807
7808 /* check dummy node accessing */
7809 if (schema == node) {
Michal Vaskof6e51882019-12-16 09:59:45 +01007810 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LY_VCODE_DUMMY_WHEN, node->name);
Michal Vasko5c4e5892019-11-14 12:31:38 +01007811 ret = LY_EVALID;
7812 goto cleanup;
7813 }
Michal Vasko175012e2019-11-06 15:49:14 +01007814 }
7815 }
7816
Michal Vaskoecd62de2019-11-13 12:35:11 +01007817 /* check cyclic dependencies */
Michal Vasko004d3152020-06-11 19:59:22 +02007818 ret = lys_compile_unres_when_cyclic(&tmp_set, node);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007819 LY_CHECK_GOTO(ret, cleanup);
7820
Michal Vaskod3678892020-05-21 10:06:58 +02007821 lyxp_set_free_content(&tmp_set);
Michal Vasko175012e2019-11-06 15:49:14 +01007822 }
7823
Michal Vasko5d8756a2019-11-07 15:21:00 +01007824check_musts:
Michal Vasko175012e2019-11-06 15:49:14 +01007825 /* check "must" */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007826 LY_ARRAY_FOR(musts, u) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007827 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 +01007828 if (ret != LY_SUCCESS) {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007829 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_SEMANTICS, "Invalid must restriction \"%s\".", musts[u].cond->expr);
Michal Vasko175012e2019-11-06 15:49:14 +01007830 goto cleanup;
7831 }
7832
Michal Vaskodc052f32019-11-07 11:11:38 +01007833 ctx->path[0] = '\0';
7834 lysc_path((struct lysc_node *)node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007835 for (i = 0; i < tmp_set.used; ++i) {
Michal Vasko175012e2019-11-06 15:49:14 +01007836 /* skip roots'n'stuff */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007837 if (tmp_set.val.scnodes[i].type == LYXP_NODE_ELEM) {
Michal Vasko175012e2019-11-06 15:49:14 +01007838 /* XPath expression cannot reference "lower" status than the node that has the definition */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007839 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 +02007840 tmp_set.val.scnodes[i].scnode->module, tmp_set.val.scnodes[i].scnode->name);
Michal Vasko175012e2019-11-06 15:49:14 +01007841 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko175012e2019-11-06 15:49:14 +01007842 }
7843 }
7844
Michal Vaskod3678892020-05-21 10:06:58 +02007845 lyxp_set_free_content(&tmp_set);
Michal Vasko175012e2019-11-06 15:49:14 +01007846 }
7847
Michal Vasko1bf09392020-03-27 12:38:10 +01007848 if ((node->nodetype & (LYS_RPC | LYS_ACTION)) && !input_done) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01007849 /* now check output musts */
7850 input_done = 1;
Michal Vaskoceab6dd2020-10-09 16:53:36 +02007851 when = NULL;
Michal Vasko5d8756a2019-11-07 15:21:00 +01007852 musts = ((struct lysc_action *)node)->output.musts;
7853 opts = LYXP_SCNODE_OUTPUT;
7854 goto check_musts;
7855 }
7856
Michal Vasko175012e2019-11-06 15:49:14 +01007857cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02007858 lyxp_set_free_content(&tmp_set);
Michal Vasko175012e2019-11-06 15:49:14 +01007859 return ret;
7860}
7861
Michal Vasko7f45cf22020-10-01 12:49:44 +02007862/**
7863 * @brief Check leafref for its target existence on a complete compiled schema tree.
7864 *
7865 * @param[in] ctx Compile context.
7866 * @param[in] node Context node for the leafref.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007867 * @param[in] lref Leafref to check/resolve.
Michal Vasko7f45cf22020-10-01 12:49:44 +02007868 * @return LY_ERR value.
7869 */
Michal Vasko8d544252020-03-02 10:19:52 +01007870static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02007871lys_compile_unres_leafref(struct lysc_ctx *ctx, const struct lysc_node *node, struct lysc_type_leafref *lref)
7872{
Michal Vasko6b26e742020-07-17 15:02:10 +02007873 const struct lysc_node *target = NULL, *siter;
Michal Vasko004d3152020-06-11 19:59:22 +02007874 struct ly_path *p;
7875 struct lysc_type *type;
7876
7877 assert(node->nodetype & (LYS_LEAF | LYS_LEAFLIST));
7878
7879 /* try to find the target */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007880 LY_CHECK_RET(ly_path_compile(ctx->ctx, node->module, node, lref->path, LY_PATH_LREF_TRUE, lysc_is_output(node) ?
7881 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 +02007882
7883 /* get the target node */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02007884 target = p[LY_ARRAY_COUNT(p) - 1].node;
Michal Vasko004d3152020-06-11 19:59:22 +02007885 ly_path_free(node->module->ctx, p);
7886
7887 if (!(target->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
7888 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02007889 "Invalid leafref path \"%s\" - target node is %s instead of leaf or leaf-list.",
7890 lref->path->expr, lys_nodetype2str(target->nodetype));
Michal Vasko004d3152020-06-11 19:59:22 +02007891 return LY_EVALID;
7892 }
7893
7894 /* check status */
7895 ctx->path[0] = '\0';
7896 lysc_path(node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
7897 ctx->path_len = strlen(ctx->path);
7898 if (lysc_check_status(ctx, node->flags, node->module, node->name, target->flags, target->module, target->name)) {
7899 return LY_EVALID;
7900 }
7901 ctx->path_len = 1;
7902 ctx->path[1] = '\0';
7903
7904 /* check config */
Michal Vasko6b26e742020-07-17 15:02:10 +02007905 if (lref->require_instance) {
Radek Krejci1e008d22020-08-17 11:37:37 +02007906 for (siter = node->parent; siter && !(siter->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); siter = siter->parent) {}
Michal Vasko6b26e742020-07-17 15:02:10 +02007907 if (!siter && (node->flags & LYS_CONFIG_W) && (target->flags & LYS_CONFIG_R)) {
Michal Vasko004d3152020-06-11 19:59:22 +02007908 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE, "Invalid leafref path \"%s\" - target is supposed"
Michal Vasko69730152020-10-09 16:30:07 +02007909 " to represent configuration data (as the leafref does), but it does not.", lref->path->expr);
Michal Vasko004d3152020-06-11 19:59:22 +02007910 return LY_EVALID;
7911 }
7912 }
7913
7914 /* store the target's type and check for circular chain of leafrefs */
7915 lref->realtype = ((struct lysc_node_leaf *)target)->type;
7916 for (type = lref->realtype; type && type->basetype == LY_TYPE_LEAFREF; type = ((struct lysc_type_leafref *)type)->realtype) {
7917 if (type == (struct lysc_type *)lref) {
7918 /* circular chain detected */
7919 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02007920 "Invalid leafref path \"%s\" - circular chain of leafrefs detected.", lref->path->expr);
Michal Vasko004d3152020-06-11 19:59:22 +02007921 return LY_EVALID;
7922 }
7923 }
7924
7925 /* check if leafref and its target are under common if-features */
7926 if (lys_compile_leafref_features_validate(node, target)) {
7927 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02007928 "Invalid leafref path \"%s\" - set of features applicable to the leafref target is not a subset of"
7929 " features applicable to the leafref itself.", lref->path->expr);
Michal Vasko004d3152020-06-11 19:59:22 +02007930 return LY_EVALID;
7931 }
7932
7933 return LY_SUCCESS;
7934}
7935
7936static LY_ERR
Michal Vasko8d544252020-03-02 10:19:52 +01007937lys_compile_ietf_netconf_wd_annotation(struct lysc_ctx *ctx, struct lys_module *mod)
7938{
7939 struct lysc_ext_instance *ext;
7940 struct lysp_ext_instance *ext_p = NULL;
7941 struct lysp_stmt *stmt;
7942 const struct lys_module *ext_mod;
7943 LY_ERR ret = LY_SUCCESS;
7944
7945 /* create the parsed extension instance manually */
7946 ext_p = calloc(1, sizeof *ext_p);
7947 LY_CHECK_ERR_GOTO(!ext_p, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci011e4aa2020-09-04 15:22:31 +02007948 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "md:annotation", 0, &ext_p->name), cleanup);
7949 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "default", 0, &ext_p->argument), cleanup);
Michal Vasko8d544252020-03-02 10:19:52 +01007950 ext_p->insubstmt = LYEXT_SUBSTMT_SELF;
7951 ext_p->insubstmt_index = 0;
7952
Radek Krejci87e25252020-09-15 13:28:31 +02007953 ext_p->child = stmt = calloc(1, sizeof *ext_p->child);
7954 LY_CHECK_ERR_GOTO(!stmt, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci011e4aa2020-09-04 15:22:31 +02007955 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "type", 0, &stmt->stmt), cleanup);
7956 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "boolean", 0, &stmt->arg), cleanup);
Michal Vasko8d544252020-03-02 10:19:52 +01007957 stmt->kw = LY_STMT_TYPE;
Michal Vasko8d544252020-03-02 10:19:52 +01007958
7959 /* allocate new extension instance */
7960 LY_ARRAY_NEW_GOTO(mod->ctx, mod->compiled->exts, ext, ret, cleanup);
7961
7962 /* manually get extension definition module */
7963 ext_mod = ly_ctx_get_module_latest(ctx->ctx, "ietf-yang-metadata");
7964
7965 /* compile the extension instance */
7966 LY_CHECK_GOTO(ret = lys_compile_ext(ctx, ext_p, ext, mod->compiled, LYEXT_PAR_MODULE, ext_mod), cleanup);
7967
7968cleanup:
7969 lysp_ext_instance_free(ctx->ctx, ext_p);
7970 free(ext_p);
7971 return ret;
7972}
7973
Michal Vasko7f45cf22020-10-01 12:49:44 +02007974/**
7975 * @brief Compile default value(s) for leaf or leaf-list expecting a complete compiled schema tree.
7976 *
7977 * @param[in] ctx Compile context.
7978 * @param[in] node Leaf or leaf-list to compile the default value(s) for.
7979 * @param[in] type Type of the default value.
7980 * @param[in] dflt Default value.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007981 * @param[in] dflt_pmod Parsed module of the @p dflt to resolve possible prefixes.
Michal Vasko7f45cf22020-10-01 12:49:44 +02007982 * @param[in,out] storage Storage for the compiled default value.
7983 * @return LY_ERR value.
7984 */
Michal Vasko004d3152020-06-11 19:59:22 +02007985static LY_ERR
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007986lys_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 +02007987 const struct lysp_module *dflt_pmod, struct lyd_value *storage)
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007988{
7989 LY_ERR ret;
7990 struct ly_err_item *err = NULL;
7991
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007992 ret = type->plugin->store(ctx->ctx, type, dflt, strlen(dflt), 0, LY_PREF_SCHEMA, (void *)dflt_pmod,
7993 LYD_HINT_SCHEMA, node, storage, &err);
Michal Vaskofeca4fb2020-10-05 08:58:40 +02007994 if (ret == LY_EINCOMPLETE) {
7995 /* we have no data so we will not be resolving it */
7996 ret = LY_SUCCESS;
7997 }
7998
7999 if (ret) {
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008000 ctx->path[0] = '\0';
8001 lysc_path(node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
Michal Vaskofeca4fb2020-10-05 08:58:40 +02008002 if (err) {
8003 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02008004 "Invalid default - value does not fit the type (%s).", err->msg);
Michal Vaskofeca4fb2020-10-05 08:58:40 +02008005 ly_err_free(err);
8006 } else {
8007 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02008008 "Invalid default - value does not fit the type.");
Michal Vaskofeca4fb2020-10-05 08:58:40 +02008009 }
8010 return ret;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008011 }
Michal Vaskofeca4fb2020-10-05 08:58:40 +02008012
8013 ++((struct lysc_type *)storage->realtype)->refcount;
8014 return LY_SUCCESS;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008015}
8016
Michal Vasko7f45cf22020-10-01 12:49:44 +02008017/**
8018 * @brief Compile default value of a leaf expecting a complete compiled schema tree.
8019 *
8020 * @param[in] ctx Compile context.
8021 * @param[in] leaf Leaf that the default value is for.
8022 * @param[in] dflt Default value to compile.
8023 * @return LY_ERR value.
8024 */
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008025static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02008026lys_compile_unres_leaf_dlft(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, struct lysp_qname *dflt)
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008027{
8028 LY_ERR ret;
8029
8030 assert(!leaf->dflt);
8031
8032 if (leaf->flags & (LYS_MAND_TRUE | LYS_KEY)) {
8033 /* ignore default values for keys and mandatory leaves */
8034 return LY_SUCCESS;
8035 }
8036
8037 /* allocate the default value */
8038 leaf->dflt = calloc(1, sizeof *leaf->dflt);
8039 LY_CHECK_ERR_RET(!leaf->dflt, LOGMEM(ctx->ctx), LY_EMEM);
8040
8041 /* store the default value */
Michal Vasko7f45cf22020-10-01 12:49:44 +02008042 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 +02008043 if (ret) {
8044 free(leaf->dflt);
8045 leaf->dflt = NULL;
8046 }
8047
8048 return ret;
8049}
8050
Michal Vasko7f45cf22020-10-01 12:49:44 +02008051/**
8052 * @brief Compile default values of a leaf-list expecting a complete compiled schema tree.
8053 *
8054 * @param[in] ctx Compile context.
8055 * @param[in] llist Leaf-list that the default value(s) are for.
8056 * @param[in] dflt Default value to compile, in case of a single value.
8057 * @param[in] dflts Sized array of default values, in case of more values.
8058 * @return LY_ERR value.
8059 */
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008060static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02008061lys_compile_unres_llist_dflts(struct lysc_ctx *ctx, struct lysc_node_leaflist *llist, struct lysp_qname *dflt,
8062 struct lysp_qname *dflts)
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008063{
8064 LY_ERR ret;
8065 LY_ARRAY_COUNT_TYPE orig_count, u, v;
8066
8067 assert(dflt || dflts);
8068
8069 if (llist->dflts) {
8070 /* there were already some defaults and we are adding new by deviations */
8071 assert(dflts);
8072 orig_count = LY_ARRAY_COUNT(llist->dflts);
8073 } else {
8074 orig_count = 0;
8075 }
8076
8077 /* allocate new items */
8078 if (dflts) {
8079 LY_ARRAY_CREATE_RET(ctx->ctx, llist->dflts, orig_count + LY_ARRAY_COUNT(dflts), LY_EMEM);
8080 } else {
8081 LY_ARRAY_CREATE_RET(ctx->ctx, llist->dflts, orig_count + 1, LY_EMEM);
8082 }
8083
8084 /* fill each new default value */
8085 if (dflts) {
8086 LY_ARRAY_FOR(dflts, u) {
8087 llist->dflts[orig_count + u] = calloc(1, sizeof **llist->dflts);
Michal Vasko7f45cf22020-10-01 12:49:44 +02008088 ret = lys_compile_unres_dflt(ctx, (struct lysc_node *)llist, llist->type, dflts[u].str, dflts[u].mod,
8089 llist->dflts[orig_count + u]);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008090 LY_CHECK_ERR_RET(ret, free(llist->dflts[orig_count + u]), ret);
8091 LY_ARRAY_INCREMENT(llist->dflts);
8092 }
8093 } else {
8094 llist->dflts[orig_count] = calloc(1, sizeof **llist->dflts);
Michal Vasko7f45cf22020-10-01 12:49:44 +02008095 ret = lys_compile_unres_dflt(ctx, (struct lysc_node *)llist, llist->type, dflt->str, dflt->mod,
8096 llist->dflts[orig_count]);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008097 LY_CHECK_ERR_RET(ret, free(llist->dflts[orig_count]), ret);
8098 LY_ARRAY_INCREMENT(llist->dflts);
8099 }
8100
8101 /* check default value uniqueness */
8102 if (llist->flags & LYS_CONFIG_W) {
8103 /* configuration data values must be unique - so check the default values */
8104 for (u = orig_count; u < LY_ARRAY_COUNT(llist->dflts); ++u) {
8105 for (v = 0; v < u; ++v) {
8106 if (!llist->dflts[u]->realtype->plugin->compare(llist->dflts[u], llist->dflts[v])) {
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008107 lysc_update_path(ctx, llist->parent, llist->name);
8108 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko7f45cf22020-10-01 12:49:44 +02008109 "Configuration leaf-list has multiple defaults of the same value \"%s\".",
8110 llist->dflts[u]->canonical);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008111 lysc_update_path(ctx, NULL, NULL);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008112 return LY_EVALID;
8113 }
8114 }
8115 }
8116 }
8117
8118 return LY_SUCCESS;
8119}
8120
Michal Vasko7f45cf22020-10-01 12:49:44 +02008121/**
8122 * @brief Finish compilation of all the unres sets of a compile context.
8123 *
8124 * @param[in] ctx Compile context with unres sets.
8125 * @return LY_ERR value.
8126 */
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008127static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02008128lys_compile_unres(struct lysc_ctx *ctx)
8129{
8130 struct lysc_node *node;
8131 struct lysc_type *type, *typeiter;
8132 struct lysc_type_leafref *lref;
Michal Vasko7f45cf22020-10-01 12:49:44 +02008133 struct lysc_augment *aug;
8134 struct lysc_deviation *dev;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02008135 LY_ARRAY_COUNT_TYPE v;
Michal Vasko004d3152020-06-11 19:59:22 +02008136 uint32_t i;
8137
8138 /* for leafref, we need 2 rounds - first detects circular chain by storing the first referred type (which
8139 * can be also leafref, in case it is already resolved, go through the chain and check that it does not
8140 * point to the starting leafref type). The second round stores the first non-leafref type for later data validation. */
8141 for (i = 0; i < ctx->leafrefs.count; ++i) {
8142 node = ctx->leafrefs.objs[i];
8143 assert(node->nodetype & (LYS_LEAF | LYS_LEAFLIST));
8144 type = ((struct lysc_node_leaf *)node)->type;
8145 if (type->basetype == LY_TYPE_LEAFREF) {
8146 LY_CHECK_RET(lys_compile_unres_leafref(ctx, node, (struct lysc_type_leafref *)type));
8147 } else if (type->basetype == LY_TYPE_UNION) {
8148 LY_ARRAY_FOR(((struct lysc_type_union *)type)->types, v) {
8149 if (((struct lysc_type_union *)type)->types[v]->basetype == LY_TYPE_LEAFREF) {
8150 lref = (struct lysc_type_leafref *)((struct lysc_type_union *)type)->types[v];
8151 LY_CHECK_RET(lys_compile_unres_leafref(ctx, node, lref));
8152 }
8153 }
8154 }
8155 }
8156 for (i = 0; i < ctx->leafrefs.count; ++i) {
8157 /* store pointer to the real type */
8158 type = ((struct lysc_node_leaf *)ctx->leafrefs.objs[i])->type;
8159 if (type->basetype == LY_TYPE_LEAFREF) {
Michal Vasko22df3f02020-08-24 13:29:22 +02008160 for (typeiter = ((struct lysc_type_leafref *)type)->realtype;
Michal Vasko004d3152020-06-11 19:59:22 +02008161 typeiter->basetype == LY_TYPE_LEAFREF;
Michal Vasko22df3f02020-08-24 13:29:22 +02008162 typeiter = ((struct lysc_type_leafref *)typeiter)->realtype) {}
8163 ((struct lysc_type_leafref *)type)->realtype = typeiter;
Michal Vasko004d3152020-06-11 19:59:22 +02008164 } else if (type->basetype == LY_TYPE_UNION) {
Michal Vasko22df3f02020-08-24 13:29:22 +02008165 LY_ARRAY_FOR(((struct lysc_type_union *)type)->types, v) {
8166 if (((struct lysc_type_union *)type)->types[v]->basetype == LY_TYPE_LEAFREF) {
8167 for (typeiter = ((struct lysc_type_leafref *)((struct lysc_type_union *)type)->types[v])->realtype;
Michal Vasko004d3152020-06-11 19:59:22 +02008168 typeiter->basetype == LY_TYPE_LEAFREF;
Michal Vasko22df3f02020-08-24 13:29:22 +02008169 typeiter = ((struct lysc_type_leafref *)typeiter)->realtype) {}
8170 ((struct lysc_type_leafref *)((struct lysc_type_union *)type)->types[v])->realtype = typeiter;
Michal Vasko004d3152020-06-11 19:59:22 +02008171 }
8172 }
8173 }
8174 }
8175
8176 /* check xpath */
8177 for (i = 0; i < ctx->xpath.count; ++i) {
8178 LY_CHECK_RET(lys_compile_unres_xpath(ctx, ctx->xpath.objs[i]));
8179 }
8180
8181 /* finish incomplete default values compilation */
8182 for (i = 0; i < ctx->dflts.count; ++i) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008183 struct lysc_unres_dflt *r = ctx->dflts.objs[i];
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008184 if (r->leaf->nodetype == LYS_LEAF) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008185 LY_CHECK_RET(lys_compile_unres_leaf_dlft(ctx, r->leaf, r->dflt));
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008186 } else {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008187 LY_CHECK_RET(lys_compile_unres_llist_dflts(ctx, r->llist, r->dflt, r->dflts));
Michal Vasko004d3152020-06-11 19:59:22 +02008188 }
Michal Vasko004d3152020-06-11 19:59:22 +02008189 }
8190
Michal Vasko7f45cf22020-10-01 12:49:44 +02008191 /* check that all augments were applied */
8192 for (i = 0; i < ctx->augs.count; ++i) {
8193 aug = ctx->augs.objs[i];
8194 LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
8195 "Augment target node \"%s\" from module \"%s\" was not found.", aug->nodeid->expr,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008196 LYSP_MODULE_NAME(aug->nodeid_pmod));
Michal Vasko7f45cf22020-10-01 12:49:44 +02008197 }
8198 if (ctx->augs.count) {
8199 return LY_ENOTFOUND;
8200 }
8201
8202 /* check that all deviations were applied */
8203 for (i = 0; i < ctx->devs.count; ++i) {
8204 dev = ctx->devs.objs[i];
8205 LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
8206 "Deviation(s) target node \"%s\" from module \"%s\" was not found.", dev->nodeid->expr,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008207 LYSP_MODULE_NAME(dev->dev_pmods[0]));
Michal Vasko7f45cf22020-10-01 12:49:44 +02008208 }
8209 if (ctx->devs.count) {
8210 return LY_ENOTFOUND;
8211 }
8212
8213 return LY_SUCCESS;
8214}
8215
Michal Vasko89b5c072020-10-06 13:52:44 +02008216void
8217lys_precompile_augments_deviations_revert(struct ly_ctx *ctx, const struct lys_module *mod)
Michal Vasko7f45cf22020-10-01 12:49:44 +02008218{
8219 uint32_t i;
8220 LY_ARRAY_COUNT_TYPE u, count;
8221 struct lys_module *m;
8222
Michal Vasko89b5c072020-10-06 13:52:44 +02008223 for (i = 0; i < ctx->list.count; ++i) {
8224 m = ctx->list.objs[i];
Michal Vasko7f45cf22020-10-01 12:49:44 +02008225
8226 if (m->augmented_by) {
8227 count = LY_ARRAY_COUNT(m->augmented_by);
8228 for (u = 0; u < count; ++u) {
8229 if (m->augmented_by[u] == mod) {
8230 /* keep the order */
8231 if (u < count - 1) {
8232 memmove(m->augmented_by + u, m->augmented_by + u + 1, (count - u) * sizeof *m->augmented_by);
8233 }
8234 LY_ARRAY_DECREMENT(m->augmented_by);
8235 break;
8236 }
8237 }
8238 if (!LY_ARRAY_COUNT(m->augmented_by)) {
8239 LY_ARRAY_FREE(m->augmented_by);
8240 m->augmented_by = NULL;
8241 }
8242 }
8243
8244 if (m->deviated_by) {
8245 count = LY_ARRAY_COUNT(m->deviated_by);
8246 for (u = 0; u < count; ++u) {
8247 if (m->deviated_by[u] == mod) {
8248 /* keep the order */
8249 if (u < count - 1) {
8250 memmove(m->deviated_by + u, m->deviated_by + u + 1, (count - u) * sizeof *m->deviated_by);
8251 }
8252 LY_ARRAY_DECREMENT(m->deviated_by);
8253 break;
8254 }
8255 }
8256 if (!LY_ARRAY_COUNT(m->deviated_by)) {
8257 LY_ARRAY_FREE(m->deviated_by);
8258 m->deviated_by = NULL;
8259 }
8260 }
8261 }
8262}
8263
8264/**
8265 * @brief Compile features in the current module and all its submodules.
8266 *
8267 * @param[in] ctx Compile context.
8268 * @return LY_ERR value.
8269 */
8270static LY_ERR
8271lys_compile_features(struct lysc_ctx *ctx)
8272{
8273 struct lysp_submodule *submod;
8274 LY_ARRAY_COUNT_TYPE u, v;
8275
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008276 if (!ctx->cur_mod->features) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008277 /* features are compiled directly into the module structure,
8278 * 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 +02008279 LY_CHECK_RET(lys_feature_precompile(ctx, NULL, NULL, ctx->cur_mod->parsed->features, &ctx->cur_mod->features));
8280 LY_ARRAY_FOR(ctx->cur_mod->parsed->includes, v) {
8281 submod = ctx->cur_mod->parsed->includes[v].submodule;
8282 LY_CHECK_RET(lys_feature_precompile(ctx, NULL, NULL, submod->features, &ctx->cur_mod->features));
Michal Vasko7f45cf22020-10-01 12:49:44 +02008283 }
8284 }
8285
8286 /* finish feature compilation, not only for the main module, but also for the submodules.
8287 * Due to possible forward references, it must be done when all the features (including submodules)
8288 * are present. */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008289 LY_ARRAY_FOR(ctx->cur_mod->parsed->features, u) {
8290 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 +02008291 }
8292
8293 lysc_update_path(ctx, NULL, "{submodule}");
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008294 LY_ARRAY_FOR(ctx->cur_mod->parsed->includes, v) {
8295 submod = ctx->cur_mod->parsed->includes[v].submodule;
Michal Vasko7f45cf22020-10-01 12:49:44 +02008296
8297 lysc_update_path(ctx, NULL, submod->name);
8298 LY_ARRAY_FOR(submod->features, u) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008299 LY_CHECK_RET(lys_feature_precompile_finish(ctx, &submod->features[u], ctx->cur_mod->features));
Michal Vasko7f45cf22020-10-01 12:49:44 +02008300 }
8301 lysc_update_path(ctx, NULL, NULL);
8302 }
8303 lysc_update_path(ctx, NULL, NULL);
8304
8305 return LY_SUCCESS;
8306}
8307
8308/**
8309 * @brief Compile identites in the current module and all its submodules.
8310 *
8311 * @param[in] ctx Compile context.
8312 * @return LY_ERR value.
8313 */
8314static LY_ERR
8315lys_compile_identities(struct lysc_ctx *ctx)
8316{
8317 struct lysp_submodule *submod;
8318 LY_ARRAY_COUNT_TYPE u;
8319
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008320 if (!ctx->cur_mod->identities) {
8321 LY_CHECK_RET(lys_identity_precompile(ctx, NULL, NULL, ctx->cur_mod->parsed->identities, &ctx->cur_mod->identities));
8322 LY_ARRAY_FOR(ctx->cur_mod->parsed->includes, u) {
8323 submod = ctx->cur_mod->parsed->includes[u].submodule;
8324 LY_CHECK_RET(lys_identity_precompile(ctx, NULL, NULL, submod->identities, &ctx->cur_mod->identities));
Michal Vasko7f45cf22020-10-01 12:49:44 +02008325 }
8326 }
8327
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008328 if (ctx->cur_mod->parsed->identities) {
8329 LY_CHECK_RET(lys_compile_identities_derived(ctx, ctx->cur_mod->parsed->identities, ctx->cur_mod->identities));
Michal Vasko7f45cf22020-10-01 12:49:44 +02008330 }
8331 lysc_update_path(ctx, NULL, "{submodule}");
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008332 LY_ARRAY_FOR(ctx->cur_mod->parsed->includes, u) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008333
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008334 submod = ctx->cur_mod->parsed->includes[u].submodule;
Michal Vasko7f45cf22020-10-01 12:49:44 +02008335 if (submod->identities) {
8336 lysc_update_path(ctx, NULL, submod->name);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008337 LY_CHECK_RET(lys_compile_identities_derived(ctx, submod->identities, ctx->cur_mod->identities));
Michal Vasko7f45cf22020-10-01 12:49:44 +02008338 lysc_update_path(ctx, NULL, NULL);
8339 }
8340 }
8341 lysc_update_path(ctx, NULL, NULL);
8342
Michal Vasko004d3152020-06-11 19:59:22 +02008343 return LY_SUCCESS;
8344}
8345
Radek Krejci19a96102018-11-15 13:38:09 +01008346LY_ERR
Michal Vasko7a0b0762020-09-02 16:37:01 +02008347lys_compile(struct lys_module *mod, uint32_t options)
Radek Krejci19a96102018-11-15 13:38:09 +01008348{
8349 struct lysc_ctx ctx = {0};
8350 struct lysc_module *mod_c;
8351 struct lysp_module *sp;
Michal Vasko7f45cf22020-10-01 12:49:44 +02008352 struct lysp_submodule *submod;
8353 struct lysp_node *pnode;
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008354 struct lysp_grp *grps;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02008355 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02008356 uint32_t i;
Radek Krejcid05cbd92018-12-05 14:26:40 +01008357 LY_ERR ret = LY_SUCCESS;
Radek Krejci19a96102018-11-15 13:38:09 +01008358
Michal Vasko7a0b0762020-09-02 16:37:01 +02008359 LY_CHECK_ARG_RET(NULL, mod, mod->parsed, !mod->compiled, mod->ctx, LY_EINVAL);
Radek Krejci096235c2019-01-11 11:12:19 +01008360
Michal Vasko7a0b0762020-09-02 16:37:01 +02008361 if (!mod->implemented) {
Radek Krejci096235c2019-01-11 11:12:19 +01008362 /* just imported modules are not compiled */
8363 return LY_SUCCESS;
8364 }
8365
Michal Vasko7f45cf22020-10-01 12:49:44 +02008366 /* context will be changed */
8367 ++mod->ctx->module_set_id;
8368
Michal Vasko7a0b0762020-09-02 16:37:01 +02008369 sp = mod->parsed;
Radek Krejci19a96102018-11-15 13:38:09 +01008370
Michal Vasko7a0b0762020-09-02 16:37:01 +02008371 ctx.ctx = mod->ctx;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008372 ctx.cur_mod = mod;
8373 ctx.pmod = sp;
Radek Krejciec4da802019-05-02 13:02:41 +02008374 ctx.options = options;
Radek Krejci327de162019-06-14 12:52:07 +02008375 ctx.path_len = 1;
8376 ctx.path[0] = '/';
Radek Krejci19a96102018-11-15 13:38:09 +01008377
Michal Vasko7a0b0762020-09-02 16:37:01 +02008378 mod->compiled = mod_c = calloc(1, sizeof *mod_c);
8379 LY_CHECK_ERR_RET(!mod_c, LOGMEM(mod->ctx), LY_EMEM);
8380 mod_c->mod = mod;
Radek Krejci19a96102018-11-15 13:38:09 +01008381
Michal Vasko7f45cf22020-10-01 12:49:44 +02008382 /* process imports */
Michal Vasko7c8439f2020-08-05 13:25:19 +02008383 LY_ARRAY_FOR(sp->imports, u) {
8384 LY_CHECK_GOTO(ret = lys_compile_import(&ctx, &sp->imports[u]), error);
8385 }
Radek Krejci0935f412019-08-20 16:15:18 +02008386
Michal Vasko7f45cf22020-10-01 12:49:44 +02008387 /* features */
8388 LY_CHECK_GOTO(ret = lys_compile_features(&ctx), error);
Radek Krejci14915cc2020-09-14 17:28:13 +02008389
8390 /* identities, work similarly to features with the precompilation */
Michal Vasko7f45cf22020-10-01 12:49:44 +02008391 LY_CHECK_GOTO(ret = lys_compile_identities(&ctx), error);
8392
8393 /* augments and deviations */
8394 LY_CHECK_GOTO(ret = lys_precompile_augments_deviations(&ctx), error);
8395
8396 /* compile augments and deviations of our module from other modules so they can be applied during compilation */
8397 LY_CHECK_GOTO(ret = lys_precompile_own_augments(&ctx), error);
8398 LY_CHECK_GOTO(ret = lys_precompile_own_deviations(&ctx), error);
Radek Krejci19a96102018-11-15 13:38:09 +01008399
Radek Krejci95710c92019-02-11 15:49:55 +01008400 /* data nodes */
Michal Vasko7f45cf22020-10-01 12:49:44 +02008401 LY_LIST_FOR(sp->data, pnode) {
8402 LY_CHECK_GOTO(ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL), error);
Radek Krejci19a96102018-11-15 13:38:09 +01008403 }
Radek Krejci95710c92019-02-11 15:49:55 +01008404
Michal Vasko7f45cf22020-10-01 12:49:44 +02008405 /* top-level RPCs and notifications */
8406 COMPILE_OP_ARRAY_GOTO(&ctx, sp->rpcs, mod_c->rpcs, NULL, u, lys_compile_action, 0, ret, error);
8407 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 +01008408
Michal Vasko7f45cf22020-10-01 12:49:44 +02008409 /* extension instances */
Radek Krejci0935f412019-08-20 16:15:18 +02008410 COMPILE_EXTS_GOTO(&ctx, sp->exts, mod_c->exts, mod_c, LYEXT_PAR_MODULE, ret, error);
Radek Krejci19a96102018-11-15 13:38:09 +01008411
Michal Vasko7f45cf22020-10-01 12:49:44 +02008412 /* the same for submodules */
8413 LY_ARRAY_FOR(sp->includes, u) {
8414 submod = sp->includes[u].submodule;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008415 ctx.pmod = (struct lysp_module *)submod;
8416
Michal Vasko7f45cf22020-10-01 12:49:44 +02008417 LY_LIST_FOR(submod->data, pnode) {
8418 ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL);
8419 LY_CHECK_GOTO(ret, error);
8420 }
8421
8422 COMPILE_OP_ARRAY_GOTO(&ctx, submod->rpcs, mod_c->rpcs, NULL, v, lys_compile_action, 0, ret, error);
8423 COMPILE_OP_ARRAY_GOTO(&ctx, submod->notifs, mod_c->notifs, NULL, v, lys_compile_notif, 0, ret, error);
8424
8425 COMPILE_EXTS_GOTO(&ctx, submod->exts, mod_c->exts, mod_c, LYEXT_PAR_MODULE, ret, error);
8426 }
8427
Michal Vasko004d3152020-06-11 19:59:22 +02008428 /* finish compilation for all unresolved items in the context */
8429 LY_CHECK_GOTO(ret = lys_compile_unres(&ctx), error);
Radek Krejci474f9b82019-07-24 11:36:37 +02008430
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008431 /* validate non-instantiated groupings from the parsed schema,
8432 * without it we would accept even the schemas with invalid grouping specification */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008433 ctx.pmod = sp;
Radek Krejci90d4e922020-10-12 15:55:33 +02008434 ctx.options |= LYS_COMPILE_GROUPING;
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008435 LY_ARRAY_FOR(sp->groupings, u) {
8436 if (!(sp->groupings[u].flags & LYS_USED_GRP)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008437 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &sp->groupings[u]), error);
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008438 }
8439 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02008440 LY_LIST_FOR(sp->data, pnode) {
8441 grps = (struct lysp_grp *)lysp_node_groupings(pnode);
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008442 LY_ARRAY_FOR(grps, u) {
8443 if (!(grps[u].flags & LYS_USED_GRP)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008444 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &grps[u]), error);
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008445 }
8446 }
8447 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02008448 LY_ARRAY_FOR(sp->includes, u) {
8449 submod = sp->includes[u].submodule;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008450 ctx.pmod = (struct lysp_module *)submod;
8451
Michal Vasko7f45cf22020-10-01 12:49:44 +02008452 LY_ARRAY_FOR(submod->groupings, u) {
8453 if (!(submod->groupings[u].flags & LYS_USED_GRP)) {
8454 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &submod->groupings[u]), error);
8455 }
8456 }
8457 LY_LIST_FOR(submod->data, pnode) {
8458 grps = (struct lysp_grp *)lysp_node_groupings(pnode);
8459 LY_ARRAY_FOR(grps, u) {
8460 if (!(grps[u].flags & LYS_USED_GRP)) {
8461 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &grps[u]), error);
8462 }
8463 }
8464 }
Radek Krejci474f9b82019-07-24 11:36:37 +02008465 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008466 ctx.pmod = sp;
Radek Krejci474f9b82019-07-24 11:36:37 +02008467
Michal Vasko8d544252020-03-02 10:19:52 +01008468#if 0
8469 /* hack for NETCONF's edit-config's operation attribute. It is not defined in the schema, but since libyang
8470 * implements YANG metadata (annotations), we need its definition. Because the ietf-netconf schema is not the
8471 * internal part of libyang, we cannot add the annotation into the schema source, but we do it here to have
8472 * the anotation definitions available in the internal schema structure. */
8473 if (ly_strequal(mod->name, "ietf-netconf", 0)) {
8474 if (lyp_add_ietf_netconf_annotations(mod)) {
8475 lys_free(mod, NULL, 1, 1);
8476 return NULL;
8477 }
8478 }
8479#endif
8480
8481 /* add ietf-netconf-with-defaults "default" metadata to the compiled module */
Michal Vasko7a0b0762020-09-02 16:37:01 +02008482 if (!strcmp(mod->name, "ietf-netconf-with-defaults")) {
8483 LY_CHECK_GOTO(ret = lys_compile_ietf_netconf_wd_annotation(&ctx, mod), error);
Michal Vasko8d544252020-03-02 10:19:52 +01008484 }
8485
Michal Vasko7f45cf22020-10-01 12:49:44 +02008486 /* there can be no leftover deviations */
8487 LY_CHECK_ERR_GOTO(ctx.devs.count, LOGINT(ctx.ctx); ret = LY_EINT, error);
8488
8489 for (i = 0; i < ctx.dflts.count; ++i) {
8490 lysc_unres_dflt_free(ctx.ctx, ctx.dflts.objs[i]);
8491 }
8492 ly_set_erase(&ctx.dflts, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +02008493 ly_set_erase(&ctx.xpath, NULL);
8494 ly_set_erase(&ctx.leafrefs, NULL);
Radek Krejcie86bf772018-12-14 11:39:53 +01008495 ly_set_erase(&ctx.groupings, NULL);
Radek Krejci99b5b2a2019-04-30 16:57:04 +02008496 ly_set_erase(&ctx.tpdf_chain, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02008497 ly_set_erase(&ctx.augs, NULL);
8498 ly_set_erase(&ctx.devs, NULL);
8499 ly_set_erase(&ctx.uses_augs, NULL);
8500 ly_set_erase(&ctx.uses_rfns, NULL);
Radek Krejcia3045382018-11-22 14:30:31 +01008501
Radek Krejci19a96102018-11-15 13:38:09 +01008502 return LY_SUCCESS;
8503
8504error:
Michal Vasko89b5c072020-10-06 13:52:44 +02008505 lys_precompile_augments_deviations_revert(ctx.ctx, mod);
Michal Vasko7a0b0762020-09-02 16:37:01 +02008506 lys_feature_precompile_revert(&ctx, mod);
Michal Vasko7f45cf22020-10-01 12:49:44 +02008507 for (i = 0; i < ctx.dflts.count; ++i) {
8508 lysc_unres_dflt_free(ctx.ctx, ctx.dflts.objs[i]);
8509 }
8510 ly_set_erase(&ctx.dflts, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +02008511 ly_set_erase(&ctx.xpath, NULL);
8512 ly_set_erase(&ctx.leafrefs, NULL);
Radek Krejcie86bf772018-12-14 11:39:53 +01008513 ly_set_erase(&ctx.groupings, NULL);
Radek Krejci99b5b2a2019-04-30 16:57:04 +02008514 ly_set_erase(&ctx.tpdf_chain, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02008515 for (i = 0; i < ctx.augs.count; ++i) {
8516 lysc_augment_free(ctx.ctx, ctx.augs.objs[i]);
8517 }
8518 ly_set_erase(&ctx.augs, NULL);
8519 for (i = 0; i < ctx.devs.count; ++i) {
8520 lysc_deviation_free(ctx.ctx, ctx.devs.objs[i]);
8521 }
8522 ly_set_erase(&ctx.devs, NULL);
8523 for (i = 0; i < ctx.uses_augs.count; ++i) {
8524 lysc_augment_free(ctx.ctx, ctx.uses_augs.objs[i]);
8525 }
8526 ly_set_erase(&ctx.uses_augs, NULL);
8527 for (i = 0; i < ctx.uses_rfns.count; ++i) {
8528 lysc_refine_free(ctx.ctx, ctx.uses_rfns.objs[i]);
8529 }
8530 ly_set_erase(&ctx.uses_rfns, NULL);
Radek Krejci19a96102018-11-15 13:38:09 +01008531 lysc_module_free(mod_c, NULL);
Michal Vasko7a0b0762020-09-02 16:37:01 +02008532 mod->compiled = NULL;
Radek Krejci95710c92019-02-11 15:49:55 +01008533
Radek Krejci19a96102018-11-15 13:38:09 +01008534 return ret;
8535}