xpath FEATURE get atoms from parsed expr and path
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 1937de1..5f033f3 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -34,6 +34,7 @@
 #include "in_internal.h"
 #include "parser_internal.h"
 #include "parser_schema.h"
+#include "path.h"
 #include "schema_compile.h"
 #include "schema_compile_amend.h"
 #include "set.h"
@@ -273,10 +274,82 @@
 }
 
 API LY_ERR
+lys_find_path_atoms(const struct ly_path *path, struct ly_set **set)
+{
+    LY_ERR ret = LY_SUCCESS;
+    LY_ARRAY_COUNT_TYPE u, v;
+
+    LY_CHECK_ARG_RET(NULL, path, set, LY_EINVAL);
+
+    /* allocate return set */
+    LY_CHECK_RET(ly_set_new(set));
+
+    LY_ARRAY_FOR(path, u) {
+        /* add nodes from the path */
+        LY_CHECK_GOTO(ret = ly_set_add(*set, (void *)path[u].node, 0, NULL), cleanup);
+        if (path[u].pred_type == LY_PATH_PREDTYPE_LIST) {
+            LY_ARRAY_FOR(path[u].predicates, v) {
+                /* add all the keys in a predicate */
+                LY_CHECK_GOTO(ret = ly_set_add(*set, (void *)path[u].predicates[v].key, 0, NULL), cleanup);
+            }
+        }
+    }
+
+cleanup:
+    if (ret) {
+        ly_set_free(*set, NULL);
+        *set = NULL;
+    }
+    return ret;
+}
+
+API LY_ERR
+lys_find_expr_atoms(const struct lysc_node *ctx_node, const struct lys_module *cur_mod, const struct lyxp_expr *expr,
+        const struct lysc_prefix *prefixes, uint32_t options, struct ly_set **set)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct lyxp_set xp_set = {0};
+    uint32_t i;
+
+    LY_CHECK_ARG_RET(NULL, cur_mod, expr, prefixes, set, LY_EINVAL);
+    if (!(options & LYXP_SCNODE_ALL)) {
+        options = LYXP_SCNODE;
+    }
+
+    /* atomize expression */
+    ret = lyxp_atomize(expr, cur_mod, LY_PREF_SCHEMA_RESOLVED, (void *)prefixes, ctx_node, &xp_set, options);
+    LY_CHECK_GOTO(ret, cleanup);
+
+    /* allocate return set */
+    ret = ly_set_new(set);
+    LY_CHECK_GOTO(ret, cleanup);
+
+    /* transform into ly_set */
+    (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
+    LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(cur_mod->ctx); ret = LY_EMEM, cleanup);
+    (*set)->size = xp_set.used;
+
+    for (i = 0; i < xp_set.used; ++i) {
+        if ((xp_set.val.scnodes[i].type == LYXP_NODE_ELEM) && (xp_set.val.scnodes[i].in_ctx == 1)) {
+            ret = ly_set_add(*set, xp_set.val.scnodes[i].scnode, 1, NULL);
+            LY_CHECK_GOTO(ret, cleanup);
+        }
+    }
+
+cleanup:
+    lyxp_set_free_content(&xp_set);
+    if (ret) {
+        ly_set_free(*set, NULL);
+        *set = NULL;
+    }
+    return ret;
+}
+
+API LY_ERR
 lys_find_xpath(const struct lysc_node *ctx_node, const char *xpath, uint32_t options, struct ly_set **set)
 {
     LY_ERR ret = LY_SUCCESS;
-    struct lyxp_set xp_set;
+    struct lyxp_set xp_set = {0};
     struct lyxp_expr *exp = NULL;
     uint32_t i;
 
@@ -285,8 +358,6 @@
         options = LYXP_SCNODE;
     }
 
-    memset(&xp_set, 0, sizeof xp_set);
-
     /* compile expression */
     ret = lyxp_expr_parse(ctx_node->module->ctx, xpath, 0, 1, &exp);
     LY_CHECK_GOTO(ret, cleanup);
@@ -314,6 +385,10 @@
 cleanup:
     lyxp_set_free_content(&xp_set);
     lyxp_expr_free(ctx_node->module->ctx, exp);
+     if (ret) {
+        ly_set_free(*set, NULL);
+        *set = NULL;
+    }
     return ret;
 }
 
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 28301e3..aa10ef6 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -1910,22 +1910,47 @@
  */
 
 /**
- * @brief Get all the schema nodes (atoms) that are required for \p xpath to be evaluated.
+ * @brief Get all the schema nodes that are required for @p xpath to be evaluated (atoms).
  *
  * @param[in] ctx_node XPath schema context node.
- * @param[in] xpath Data XPath expression filtering the matching nodes. ::LYD_JSON format is expected.
+ * @param[in] xpath Data XPath expression filtering the matching nodes. ::LY_PREF_JSON prefix format is expected.
  * @param[in] options Whether to apply some node access restrictions, see @ref findxpathoptions.
  * @param[out] set Set of found atoms (schema nodes).
  * @return LY_SUCCESS on success, @p set is returned.
- * @return LY_ERR value if an error occurred.
+ * @return LY_ERR value on error.
  */
 LY_ERR lys_find_xpath_atoms(const struct lysc_node *ctx_node, const char *xpath, uint32_t options, struct ly_set **set);
 
 /**
- * @brief Evaluate an \p xpath expression on schema nodes.
+ * @brief Get all the schema nodes that are required for @p path to be evaluated (atoms).
+ *
+ * @param[in] path Compiled path to use.
+ * @param[out] set Set of found atoms (schema nodes).
+ * @return LY_SUCCESS on success, @p set is returned.
+ * @return LY_ERR value on error.
+ */
+LY_ERR lys_find_path_atoms(const struct ly_path *path, struct ly_set **set);
+
+/**
+ * @brief Get all the schema nodes that are required for @p expr to be evaluated (atoms).
  *
  * @param[in] ctx_node XPath schema context node.
- * @param[in] xpath Data XPath expression filtering the matching nodes. ::LYD_JSON format is expected.
+ * @param[in] cur_mod Current module for the expression (where it was "instantiated").
+ * @param[in] expr Parsed expression to use.
+ * @param[in] prefixes Sized array of compiled prefixes.
+ * @param[in] options Whether to apply some node access restrictions, see @ref findxpathoptions.
+ * @param[out] set Set of found atoms (schema nodes).
+ * @return LY_SUCCESS on success, @p set is returned.
+ * @return LY_ERR value on error.
+ */
+LY_ERR lys_find_expr_atoms(const struct lysc_node *ctx_node, const struct lys_module *cur_mod,
+        const struct lyxp_expr *expr, const struct lysc_prefix *prefixes, uint32_t options, struct ly_set **set);
+
+/**
+ * @brief Evaluate an @p xpath expression on schema nodes.
+ *
+ * @param[in] ctx_node XPath schema context node.
+ * @param[in] xpath Data XPath expression filtering the matching nodes. ::LY_PREF_JSON prefix format is expected.
  * @param[in] options Whether to apply some node access restrictions, see @ref findxpathoptions.
  * @param[out] set Set of found schema nodes.
  * @return LY_SUCCESS on success, @p set is returned.
diff --git a/src/xpath.c b/src/xpath.c
index d3c0b4c..1e5cf39 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -45,7 +45,8 @@
 #include "xml.h"
 
 static LY_ERR reparse_or_expr(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx);
-static LY_ERR eval_expr_select(struct lyxp_expr *exp, uint16_t *tok_idx, enum lyxp_expr_type etype, struct lyxp_set *set, uint32_t options);
+static LY_ERR eval_expr_select(const struct lyxp_expr *exp, uint16_t *tok_idx, enum lyxp_expr_type etype,
+        struct lyxp_set *set, uint32_t options);
 
 /**
  * @brief Print the type of an XPath \p set.
@@ -130,7 +131,7 @@
  * @param[in] exp Expression to use.
  */
 static void
-print_expr_struct_debug(struct lyxp_expr *exp)
+print_expr_struct_debug(const struct lyxp_expr *exp)
 {
     uint16_t i, j;
     char tmp[128];
@@ -1871,7 +1872,7 @@
 
 /* just like lyxp_check_token() but tests for 2 tokens */
 static LY_ERR
-exp_check_token2(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t tok_idx, enum lyxp_token want_tok1,
+exp_check_token2(const struct ly_ctx *ctx, const struct lyxp_expr *exp, uint16_t tok_idx, enum lyxp_token want_tok1,
         enum lyxp_token want_tok2)
 {
     if (exp->used == tok_idx) {
@@ -3303,7 +3304,8 @@
  * @param[in] last_equal_exp Index of the end of the equality expression in @p exp.
  */
 static void
-warn_equality_value(struct lyxp_expr *exp, struct lyxp_set *set, uint16_t val_exp, uint16_t equal_exp, uint16_t last_equal_exp)
+warn_equality_value(const struct lyxp_expr *exp, struct lyxp_set *set, uint16_t val_exp, uint16_t equal_exp,
+        uint16_t last_equal_exp)
 {
     struct lysc_node *scnode;
     struct lysc_type *type;
@@ -6726,7 +6728,7 @@
  * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
  */
 static LY_ERR
-eval_predicate(struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set, uint32_t options, ly_bool parent_pos_pred)
+eval_predicate(const struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set, uint32_t options, ly_bool parent_pos_pred)
 {
     LY_ERR rc;
     uint16_t i, orig_exp;
@@ -6872,7 +6874,7 @@
  * @param[in,out] set Context and result set. On NULL the rule is only parsed.
  */
 static void
-eval_literal(struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set)
+eval_literal(const struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set)
 {
     if (set) {
         if (exp->tok_len[*tok_idx] == 2) {
@@ -6902,7 +6904,7 @@
  * @return LY_ERR on any error.
  */
 static LY_ERR
-eval_name_test_try_compile_predicates(struct lyxp_expr *exp, uint16_t *tok_idx, const struct lysc_node *ctx_node,
+eval_name_test_try_compile_predicates(const struct lyxp_expr *exp, uint16_t *tok_idx, const struct lysc_node *ctx_node,
         const struct lys_module *cur_mod, const struct lysc_node *cur_node, LY_PREFIX_FORMAT format, void *prefix_data,
         struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type)
 {
@@ -7077,7 +7079,7 @@
  * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
  */
 static LY_ERR
-eval_name_test_with_predicate(struct lyxp_expr *exp, uint16_t *tok_idx, ly_bool attr_axis, ly_bool all_desc,
+eval_name_test_with_predicate(const struct lyxp_expr *exp, uint16_t *tok_idx, ly_bool attr_axis, ly_bool all_desc,
         struct lyxp_set *set, uint32_t options)
 {
     char *path;
@@ -7231,7 +7233,7 @@
  * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
  */
 static LY_ERR
-eval_node_type_with_predicate(struct lyxp_expr *exp, uint16_t *tok_idx, ly_bool attr_axis, ly_bool all_desc,
+eval_node_type_with_predicate(const struct lyxp_expr *exp, uint16_t *tok_idx, ly_bool attr_axis, ly_bool all_desc,
         struct lyxp_set *set, uint32_t options)
 {
     LY_ERR rc;
@@ -7296,7 +7298,8 @@
  * @return LY_ERR (YL_EINCOMPLETE on unresolved when)
  */
 static LY_ERR
-eval_relative_location_path(struct lyxp_expr *exp, uint16_t *tok_idx, ly_bool all_desc, struct lyxp_set *set, uint32_t options)
+eval_relative_location_path(const struct lyxp_expr *exp, uint16_t *tok_idx, ly_bool all_desc, struct lyxp_set *set,
+        uint32_t options)
 {
     ly_bool attr_axis;
     LY_ERR rc;
@@ -7386,7 +7389,7 @@
  * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
  */
 static LY_ERR
-eval_absolute_location_path(struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set, uint32_t options)
+eval_absolute_location_path(const struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set, uint32_t options)
 {
     ly_bool all_desc;
 
@@ -7444,7 +7447,7 @@
  * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
  */
 static LY_ERR
-eval_function_call(struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set, uint32_t options)
+eval_function_call(const struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set, uint32_t options)
 {
     LY_ERR rc;
 
@@ -7664,7 +7667,7 @@
  * @return LY_ERR
  */
 static LY_ERR
-eval_number(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set)
+eval_number(struct ly_ctx *ctx, const struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set)
 {
     long double num;
     char *endptr;
@@ -7709,7 +7712,7 @@
  * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
  */
 static LY_ERR
-eval_path_expr(struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set, uint32_t options)
+eval_path_expr(const struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set, uint32_t options)
 {
     ly_bool all_desc, parent_pos_pred;
     LY_ERR rc;
@@ -7843,7 +7846,7 @@
  * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
  */
 static LY_ERR
-eval_union_expr(struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
+eval_union_expr(const struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
 {
     LY_ERR rc = LY_SUCCESS;
     struct lyxp_set orig_set, set2;
@@ -7904,7 +7907,7 @@
  * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
  */
 static LY_ERR
-eval_unary_expr(struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
+eval_unary_expr(const struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
 {
     LY_ERR rc;
     uint16_t this_op, i;
@@ -7952,7 +7955,8 @@
  * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
  */
 static LY_ERR
-eval_multiplicative_expr(struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
+eval_multiplicative_expr(const struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set,
+        uint32_t options)
 {
     LY_ERR rc;
     uint16_t this_op;
@@ -8020,7 +8024,7 @@
  * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
  */
 static LY_ERR
-eval_additive_expr(struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
+eval_additive_expr(const struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
 {
     LY_ERR rc;
     uint16_t this_op;
@@ -8090,7 +8094,7 @@
  * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
  */
 static LY_ERR
-eval_relational_expr(struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
+eval_relational_expr(const struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
 {
     LY_ERR rc;
     uint16_t this_op;
@@ -8157,7 +8161,7 @@
  * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
  */
 static LY_ERR
-eval_equality_expr(struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
+eval_equality_expr(const struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
 {
     LY_ERR rc;
     uint16_t this_op;
@@ -8225,7 +8229,7 @@
  * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
  */
 static LY_ERR
-eval_and_expr(struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
+eval_and_expr(const struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
 {
     LY_ERR rc;
     struct lyxp_set orig_set, set2;
@@ -8295,7 +8299,7 @@
  * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
  */
 static LY_ERR
-eval_or_expr(struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
+eval_or_expr(const struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
 {
     LY_ERR rc;
     struct lyxp_set orig_set, set2;
@@ -8365,7 +8369,8 @@
  * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
  */
 static LY_ERR
-eval_expr_select(struct lyxp_expr *exp, uint16_t *tok_idx, enum lyxp_expr_type etype, struct lyxp_set *set, uint32_t options)
+eval_expr_select(const struct lyxp_expr *exp, uint16_t *tok_idx, enum lyxp_expr_type etype, struct lyxp_set *set,
+        uint32_t options)
 {
     uint16_t i, count;
     enum lyxp_expr_type next_etype;
@@ -8466,7 +8471,7 @@
 }
 
 LY_ERR
-lyxp_eval(struct lyxp_expr *exp, const struct lys_module *cur_mod, LY_PREFIX_FORMAT format, void *prefix_data,
+lyxp_eval(const struct lyxp_expr *exp, const struct lys_module *cur_mod, LY_PREFIX_FORMAT format, void *prefix_data,
         const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lyxp_set *set, uint32_t options)
 {
     uint16_t tok_idx = 0;
@@ -8732,7 +8737,7 @@
 }
 
 LY_ERR
-lyxp_atomize(struct lyxp_expr *exp, const struct lys_module *cur_mod, LY_PREFIX_FORMAT format, void *prefix_data,
+lyxp_atomize(const struct lyxp_expr *exp, const struct lys_module *cur_mod, LY_PREFIX_FORMAT format, void *prefix_data,
         const struct lysc_node *ctx_scnode, struct lyxp_set *set, uint32_t options)
 {
     uint16_t tok_idx = 0;
diff --git a/src/xpath.h b/src/xpath.h
index 05a059a..ae75320 100644
--- a/src/xpath.h
+++ b/src/xpath.h
@@ -289,7 +289,7 @@
  * @return LY_EINCOMPLETE for unresolved when,
  * @return LY_EINVAL, LY_EMEM, LY_EINT for other errors.
  */
-LY_ERR lyxp_eval(struct lyxp_expr *exp, const struct lys_module *cur_mod, LY_PREFIX_FORMAT format, void *prefix_data,
+LY_ERR lyxp_eval(const struct lyxp_expr *exp, const struct lys_module *cur_mod, LY_PREFIX_FORMAT format, void *prefix_data,
         const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lyxp_set *set, uint32_t options);
 
 
@@ -305,7 +305,7 @@
  * @param[in] options Whether to apply some evaluation restrictions, one flag must always be used.
  * @return LY_ERR (same as ::lyxp_eval()).
  */
-LY_ERR lyxp_atomize(struct lyxp_expr *exp, const struct lys_module *cur_mod, LY_PREFIX_FORMAT format, void *prefix_data,
+LY_ERR lyxp_atomize(const struct lyxp_expr *exp, const struct lys_module *cur_mod, LY_PREFIX_FORMAT format, void *prefix_data,
         const struct lysc_node *ctx_scnode, struct lyxp_set *set, uint32_t options);
 
 /* used only internally, maps with @ref findxpathoptions */