path FEATURE variables instead of values

Supported now for node-instance-identifier.
diff --git a/src/path.c b/src/path.c
index e455b75..4ee9832 100644
--- a/src/path.c
+++ b/src/path.c
@@ -3,7 +3,7 @@
  * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief Path functions
  *
- * Copyright (c) 2020 CESNET, z.s.p.o.
+ * Copyright (c) 2020 - 2023 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
@@ -11,6 +11,9 @@
  *
  *     https://opensource.org/licenses/BSD-3-Clause
  */
+
+#define _GNU_SOURCE
+
 #include "path.h"
 
 #include <assert.h>
@@ -106,8 +109,14 @@
                 /* '=' */
                 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
 
-                /* Literal or Number */
-                LY_CHECK_GOTO(lyxp_next_token2(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL, LYXP_TOKEN_NUMBER), token_error);
+                /* Literal, Number, or VariableReference */
+                if (lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_LITERAL) &&
+                        lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER) &&
+                        lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_VARREF)) {
+                    /* error */
+                    lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL);
+                    goto token_error;
+                }
 
                 /* ']' */
                 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
@@ -528,7 +537,7 @@
 LY_ERR
 ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
         const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint32_t *tok_idx, LY_VALUE_FORMAT format,
-        void *prefix_data, struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type)
+        void *prefix_data, struct ly_path_predicate **predicates)
 {
     LY_ERR ret = LY_SUCCESS;
     struct ly_path_predicate *p;
@@ -540,7 +549,7 @@
 
     LOG_LOCSET(cur_node, NULL, NULL, NULL);
 
-    *pred_type = 0;
+    *predicates = NULL;
 
     if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
         /* '[', no predicate */
@@ -572,11 +581,7 @@
             }
             ++(*tok_idx);
 
-            if (!*pred_type) {
-                /* new predicate */
-                *pred_type = LY_PATH_PREDTYPE_LIST;
-            }
-            assert(*pred_type == LY_PATH_PREDTYPE_LIST);
+            /* new predicate */
             LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
             p->key = key;
 
@@ -584,28 +589,39 @@
             assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
             ++(*tok_idx);
 
-            /* Literal or Number */
-            assert((expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) || (expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER));
-            if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
-                /* skip quotes */
-                val = expr->expr + expr->tok_pos[*tok_idx] + 1;
-                val_len = expr->tok_len[*tok_idx] - 2;
+            /* Literal, Number, or VariableReference */
+            if (expr->tokens[*tok_idx] == LYXP_TOKEN_VARREF) {
+                /* store the variable name */
+                p->variable = strndup(expr->expr + expr->tok_pos[*tok_idx], expr->tok_len[*tok_idx]);
+                LY_CHECK_ERR_GOTO(!p->variable, LOGMEM(ctx); ret = LY_EMEM, cleanup);
+
+                p->type = LY_PATH_PREDTYPE_LIST_VAR;
+                ++(*tok_idx);
             } else {
-                val = expr->expr + expr->tok_pos[*tok_idx];
-                val_len = expr->tok_len[*tok_idx];
+                if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
+                    /* skip quotes */
+                    val = expr->expr + expr->tok_pos[*tok_idx] + 1;
+                    val_len = expr->tok_len[*tok_idx] - 2;
+                } else {
+                    assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
+                    val = expr->expr + expr->tok_pos[*tok_idx];
+                    val_len = expr->tok_len[*tok_idx];
+                }
+
+                /* store the value */
+                LOG_LOCSET(key, NULL, NULL, NULL);
+                ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, NULL, format,
+                        prefix_data, LYD_HINT_DATA, key, NULL);
+                LOG_LOCBACK(key ? 1 : 0, 0, 0, 0);
+                LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
+
+                /* "allocate" the type to avoid problems when freeing the value after the type was freed */
+                LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount);
+
+                p->type = LY_PATH_PREDTYPE_LIST;
+                ++(*tok_idx);
             }
 
-            /* store the value */
-            LOG_LOCSET(key, NULL, NULL, NULL);
-            ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, NULL, format,
-                    prefix_data, LYD_HINT_DATA, key, NULL);
-            LOG_LOCBACK(key ? 1 : 0, 0, 0, 0);
-            LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
-            ++(*tok_idx);
-
-            /* "allocate" the type to avoid problems when freeing the value after the type was freed */
-            LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount);
-
             /* ']' */
             assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
             ++(*tok_idx);
@@ -622,7 +638,7 @@
             /* names (keys) are unique - it was checked when parsing */
             LOGVAL(ctx, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
                     lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
-            ly_path_predicates_free(ctx, LY_PATH_PREDTYPE_LIST, *predicates);
+            ly_path_predicates_free(ctx, *predicates);
             *predicates = NULL;
             ret = LY_EVALID;
             goto cleanup;
@@ -638,8 +654,8 @@
         ++(*tok_idx);
 
         /* new predicate */
-        *pred_type = LY_PATH_PREDTYPE_LEAFLIST;
         LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
+        p->type = LY_PATH_PREDTYPE_LEAFLIST;
 
         /* '=' */
         assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
@@ -685,8 +701,8 @@
         }
 
         /* new predicate */
-        *pred_type = LY_PATH_PREDTYPE_POSITION;
         LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
+        p->type = LY_PATH_PREDTYPE_POSITION;
 
         /* syntax was already checked */
         p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&val, LY_BASE_DEC);
@@ -947,7 +963,7 @@
             ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data);
         } else {
             ret = ly_path_compile_predicate(ctx, cur_node, cur_mod, ctx_node, expr, &tok_idx, format, prefix_data,
-                    &p->predicates, &p->pred_type);
+                    &p->predicates);
         }
         LY_CHECK_GOTO(ret, cleanup);
     } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
@@ -994,8 +1010,8 @@
 }
 
 LY_ERR
-ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, LY_ARRAY_COUNT_TYPE *path_idx,
-        struct lyd_node **match)
+ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, const struct lyxp_var *vars,
+        LY_ARRAY_COUNT_TYPE *path_idx, struct lyd_node **match)
 {
     LY_ARRAY_COUNT_TYPE u;
     struct lyd_node *prev_node = NULL, *elem, *node = NULL, *target;
@@ -1017,35 +1033,37 @@
     }
 
     LY_ARRAY_FOR(path, u) {
-        switch (path[u].pred_type) {
-        case LY_PATH_PREDTYPE_POSITION:
-            /* we cannot use hashes and want an instance on a specific position */
-            pos = 1;
-            node = NULL;
-            LYD_LIST_FOR_INST(start, path[u].node, elem) {
-                if (pos == path[u].predicates[0].position) {
-                    node = elem;
-                    break;
+        if (path[u].predicates) {
+            switch (path[u].predicates[0].type) {
+            case LY_PATH_PREDTYPE_POSITION:
+                /* we cannot use hashes and want an instance on a specific position */
+                pos = 1;
+                node = NULL;
+                LYD_LIST_FOR_INST(start, path[u].node, elem) {
+                    if (pos == path[u].predicates[0].position) {
+                        node = elem;
+                        break;
+                    }
+                    ++pos;
                 }
-                ++pos;
+                break;
+            case LY_PATH_PREDTYPE_LEAFLIST:
+                /* we will use hashes to find one leaf-list instance */
+                LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
+                lyd_find_sibling_first(start, target, &node);
+                lyd_free_tree(target);
+                break;
+            case LY_PATH_PREDTYPE_LIST_VAR:
+            case LY_PATH_PREDTYPE_LIST:
+                /* we will use hashes to find one list instance */
+                LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, vars, &target));
+                lyd_find_sibling_first(start, target, &node);
+                lyd_free_tree(target);
+                break;
             }
-            break;
-        case LY_PATH_PREDTYPE_LEAFLIST:
-            /* we will use hashes to find one leaf-list instance */
-            LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
-            lyd_find_sibling_first(start, target, &node);
-            lyd_free_tree(target);
-            break;
-        case LY_PATH_PREDTYPE_LIST:
-            /* we will use hashes to find one list instance */
-            LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, &target));
-            lyd_find_sibling_first(start, target, &node);
-            lyd_free_tree(target);
-            break;
-        case LY_PATH_PREDTYPE_NONE:
+        } else {
             /* we will use hashes to find one any/container/leaf instance */
             lyd_find_sibling_val(start, path[u].node, NULL, 0, &node);
-            break;
         }
 
         if (!node) {
@@ -1092,12 +1110,12 @@
 }
 
 LY_ERR
-ly_path_eval(const struct ly_path *path, const struct lyd_node *start, struct lyd_node **match)
+ly_path_eval(const struct ly_path *path, const struct lyd_node *start, const struct lyxp_var *vars, struct lyd_node **match)
 {
     LY_ERR ret;
     struct lyd_node *m;
 
-    ret = ly_path_eval_partial(path, start, NULL, &m);
+    ret = ly_path_eval_partial(path, start, vars, NULL, &m);
 
     if (ret == LY_SUCCESS) {
         /* last node was found */
@@ -1129,12 +1147,13 @@
         (*dup)[u].node = path[u].node;
         if (path[u].predicates) {
             LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_COUNT(path[u].predicates), LY_EMEM);
-            (*dup)[u].pred_type = path[u].pred_type;
             LY_ARRAY_FOR(path[u].predicates, v) {
                 struct ly_path_predicate *pred = &path[u].predicates[v];
 
                 LY_ARRAY_INCREMENT((*dup)[u].predicates);
-                switch (path[u].pred_type) {
+                (*dup)[u].predicates[v].type = pred->type;
+
+                switch (pred->type) {
                 case LY_PATH_PREDTYPE_POSITION:
                     /* position-predicate */
                     (*dup)[u].predicates[v].position = pred->position;
@@ -1146,7 +1165,10 @@
                     pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
                     LY_ATOMIC_INC_BARRIER(((struct lysc_type *)pred->value.realtype)->refcount);
                     break;
-                case LY_PATH_PREDTYPE_NONE:
+                case LY_PATH_PREDTYPE_LIST_VAR:
+                    /* key-predicate with a variable */
+                    (*dup)[u].predicates[v].key = pred->key;
+                    (*dup)[u].predicates[v].variable = strdup(pred->variable);
                     break;
                 }
             }
@@ -1157,7 +1179,7 @@
 }
 
 void
-ly_path_predicates_free(const struct ly_ctx *ctx, enum ly_path_pred_type pred_type, struct ly_path_predicate *predicates)
+ly_path_predicates_free(const struct ly_ctx *ctx, struct ly_path_predicate *predicates)
 {
     LY_ARRAY_COUNT_TYPE u;
     struct lysf_ctx fctx = {.ctx = (struct ly_ctx *)ctx};
@@ -1167,9 +1189,8 @@
     }
 
     LY_ARRAY_FOR(predicates, u) {
-        switch (pred_type) {
+        switch (predicates[u].type) {
         case LY_PATH_PREDTYPE_POSITION:
-        case LY_PATH_PREDTYPE_NONE:
             /* nothing to free */
             break;
         case LY_PATH_PREDTYPE_LIST:
@@ -1179,6 +1200,9 @@
                 lysc_type_free(&fctx, (struct lysc_type *)predicates[u].value.realtype);
             }
             break;
+        case LY_PATH_PREDTYPE_LIST_VAR:
+            free(predicates[u].variable);
+            break;
         }
     }
     LY_ARRAY_FREE(predicates);
@@ -1194,7 +1218,7 @@
     }
 
     LY_ARRAY_FOR(path, u) {
-        ly_path_predicates_free(ctx, path[u].pred_type, path[u].predicates);
+        ly_path_predicates_free(ctx, path[u].predicates);
     }
     LY_ARRAY_FREE(path);
 }