xpath CHANGE refactor lyxp_expr_parse() to return LY_ERR

To correctly inherit LY_ERR value and detect errors, it is necessary to
refactor lyxp_expr_parse() to return LY_ERR value and return the
processed expression via an output parameter.
diff --git a/src/xpath.c b/src/xpath.c
index bc23eae..4691984 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -2653,146 +2653,150 @@
     free(expr);
 }
 
-struct lyxp_expr *
-lyxp_expr_parse(const struct ly_ctx *ctx, const char *expr, size_t expr_len, ly_bool reparse)
+LY_ERR
+lyxp_expr_parse(const struct ly_ctx *ctx, const char *expr_str, size_t expr_len, ly_bool reparse, struct lyxp_expr **expr_p)
 {
-    struct lyxp_expr *ret;
+    LY_ERR ret = LY_SUCCESS;
+    struct lyxp_expr *expr;
     size_t parsed = 0, tok_len;
     enum lyxp_token tok_type;
     ly_bool prev_function_check = 0;
     uint16_t tok_idx = 0;
 
-    if (!expr[0]) {
+    assert(expr_p);
+
+    if (!expr_str[0]) {
         LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOF);
-        return NULL;
+        return LY_EVALID;
     }
 
     if (!expr_len) {
-        expr_len = strlen(expr);
+        expr_len = strlen(expr_str);
     }
     if (expr_len > UINT16_MAX) {
-        LOGERR(ctx, LY_EINVAL, "XPath expression cannot be longer than %ud characters.", UINT16_MAX);
-        return NULL;
+        LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "XPath expression cannot be longer than %ud characters.", UINT16_MAX);
+        return LY_EVALID;
     }
 
     /* init lyxp_expr structure */
-    ret = calloc(1, sizeof *ret);
-    LY_CHECK_ERR_GOTO(!ret, LOGMEM(ctx), error);
-    LY_CHECK_GOTO(lydict_insert(ctx, expr, expr_len, &ret->expr), error);
-    LY_CHECK_ERR_GOTO(!ret->expr, LOGMEM(ctx), error);
-    ret->used = 0;
-    ret->size = LYXP_EXPR_SIZE_START;
-    ret->tokens = malloc(ret->size * sizeof *ret->tokens);
-    LY_CHECK_ERR_GOTO(!ret->tokens, LOGMEM(ctx), error);
+    expr = calloc(1, sizeof *expr);
+    LY_CHECK_ERR_GOTO(!expr, LOGMEM(ctx); ret = LY_EMEM, error);
+    LY_CHECK_GOTO(ret = lydict_insert(ctx, expr_str, expr_len, &expr->expr), error);
+    expr->used = 0;
+    expr->size = LYXP_EXPR_SIZE_START;
+    expr->tokens = malloc(expr->size * sizeof *expr->tokens);
+    LY_CHECK_ERR_GOTO(!expr->tokens, LOGMEM(ctx); ret = LY_EMEM, error);
 
-    ret->tok_pos = malloc(ret->size * sizeof *ret->tok_pos);
-    LY_CHECK_ERR_GOTO(!ret->tok_pos, LOGMEM(ctx), error);
+    expr->tok_pos = malloc(expr->size * sizeof *expr->tok_pos);
+    LY_CHECK_ERR_GOTO(!expr->tok_pos, LOGMEM(ctx); ret = LY_EMEM, error);
 
-    ret->tok_len = malloc(ret->size * sizeof *ret->tok_len);
-    LY_CHECK_ERR_GOTO(!ret->tok_len, LOGMEM(ctx), error);
+    expr->tok_len = malloc(expr->size * sizeof *expr->tok_len);
+    LY_CHECK_ERR_GOTO(!expr->tok_len, LOGMEM(ctx); ret = LY_EMEM, error);
 
     /* make expr 0-terminated */
-    expr = ret->expr;
+    expr_str = expr->expr;
 
-    while (is_xmlws(expr[parsed])) {
+    while (is_xmlws(expr_str[parsed])) {
         ++parsed;
     }
 
     do {
-        if (expr[parsed] == '(') {
+        if (expr_str[parsed] == '(') {
 
             /* '(' */
             tok_len = 1;
             tok_type = LYXP_TOKEN_PAR1;
 
-            if (prev_function_check && ret->used && (ret->tokens[ret->used - 1] == LYXP_TOKEN_NAMETEST)) {
+            if (prev_function_check && expr->used && (expr->tokens[expr->used - 1] == LYXP_TOKEN_NAMETEST)) {
                 /* it is a NodeType/FunctionName after all */
-                if (((ret->tok_len[ret->used - 1] == 4)
-                        && (!strncmp(&expr[ret->tok_pos[ret->used - 1]], "node", 4)
-                        || !strncmp(&expr[ret->tok_pos[ret->used - 1]], "text", 4))) ||
-                        ((ret->tok_len[ret->used - 1] == 7)
-                        && !strncmp(&expr[ret->tok_pos[ret->used - 1]], "comment", 7))) {
-                    ret->tokens[ret->used - 1] = LYXP_TOKEN_NODETYPE;
+                if (((expr->tok_len[expr->used - 1] == 4)
+                        && (!strncmp(&expr_str[expr->tok_pos[expr->used - 1]], "node", 4)
+                        || !strncmp(&expr_str[expr->tok_pos[expr->used - 1]], "text", 4))) ||
+                        ((expr->tok_len[expr->used - 1] == 7)
+                        && !strncmp(&expr_str[expr->tok_pos[expr->used - 1]], "comment", 7))) {
+                    expr->tokens[expr->used - 1] = LYXP_TOKEN_NODETYPE;
                 } else {
-                    ret->tokens[ret->used - 1] = LYXP_TOKEN_FUNCNAME;
+                    expr->tokens[expr->used - 1] = LYXP_TOKEN_FUNCNAME;
                 }
                 prev_function_check = 0;
             }
 
-        } else if (expr[parsed] == ')') {
+        } else if (expr_str[parsed] == ')') {
 
             /* ')' */
             tok_len = 1;
             tok_type = LYXP_TOKEN_PAR2;
 
-        } else if (expr[parsed] == '[') {
+        } else if (expr_str[parsed] == '[') {
 
             /* '[' */
             tok_len = 1;
             tok_type = LYXP_TOKEN_BRACK1;
 
-        } else if (expr[parsed] == ']') {
+        } else if (expr_str[parsed] == ']') {
 
             /* ']' */
             tok_len = 1;
             tok_type = LYXP_TOKEN_BRACK2;
 
-        } else if (!strncmp(&expr[parsed], "..", 2)) {
+        } else if (!strncmp(&expr_str[parsed], "..", 2)) {
 
             /* '..' */
             tok_len = 2;
             tok_type = LYXP_TOKEN_DDOT;
 
-        } else if ((expr[parsed] == '.') && (!isdigit(expr[parsed + 1]))) {
+        } else if ((expr_str[parsed] == '.') && (!isdigit(expr_str[parsed + 1]))) {
 
             /* '.' */
             tok_len = 1;
             tok_type = LYXP_TOKEN_DOT;
 
-        } else if (expr[parsed] == '@') {
+        } else if (expr_str[parsed] == '@') {
 
             /* '@' */
             tok_len = 1;
             tok_type = LYXP_TOKEN_AT;
 
-        } else if (expr[parsed] == ',') {
+        } else if (expr_str[parsed] == ',') {
 
             /* ',' */
             tok_len = 1;
             tok_type = LYXP_TOKEN_COMMA;
 
-        } else if (expr[parsed] == '\'') {
+        } else if (expr_str[parsed] == '\'') {
 
             /* Literal with ' */
-            for (tok_len = 1; (expr[parsed + tok_len] != '\0') && (expr[parsed + tok_len] != '\''); ++tok_len) {}
-            LY_CHECK_ERR_GOTO(expr[parsed + tok_len] == '\0',
-                              LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr[parsed], &expr[parsed]), error);
+            for (tok_len = 1; (expr_str[parsed + tok_len] != '\0') && (expr_str[parsed + tok_len] != '\''); ++tok_len) {}
+            LY_CHECK_ERR_GOTO(expr_str[parsed + tok_len] == '\0',
+                              LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr_str[parsed], &expr_str[parsed]); ret = LY_EVALID,
+                              error);
             ++tok_len;
             tok_type = LYXP_TOKEN_LITERAL;
 
-        } else if (expr[parsed] == '\"') {
+        } else if (expr_str[parsed] == '\"') {
 
             /* Literal with " */
-            for (tok_len = 1; (expr[parsed + tok_len] != '\0') && (expr[parsed + tok_len] != '\"'); ++tok_len) {}
-            LY_CHECK_ERR_GOTO(expr[parsed + tok_len] == '\0',
-                              LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr[parsed], &expr[parsed]), error);
+            for (tok_len = 1; (expr_str[parsed + tok_len] != '\0') && (expr_str[parsed + tok_len] != '\"'); ++tok_len) {}
+            LY_CHECK_ERR_GOTO(expr_str[parsed + tok_len] == '\0',
+                              LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr_str[parsed], &expr_str[parsed]); ret = LY_EVALID,
+                              error);
             ++tok_len;
             tok_type = LYXP_TOKEN_LITERAL;
 
-        } else if ((expr[parsed] == '.') || (isdigit(expr[parsed]))) {
+        } else if ((expr_str[parsed] == '.') || (isdigit(expr_str[parsed]))) {
 
             /* Number */
-            for (tok_len = 0; isdigit(expr[parsed + tok_len]); ++tok_len) {}
-            if (expr[parsed + tok_len] == '.') {
+            for (tok_len = 0; isdigit(expr_str[parsed + tok_len]); ++tok_len) {}
+            if (expr_str[parsed + tok_len] == '.') {
                 ++tok_len;
-                for ( ; isdigit(expr[parsed + tok_len]); ++tok_len) {}
+                for ( ; isdigit(expr_str[parsed + tok_len]); ++tok_len) {}
             }
             tok_type = LYXP_TOKEN_NUMBER;
 
-        } else if (expr[parsed] == '/') {
+        } else if (expr_str[parsed] == '/') {
 
             /* Operator '/', '//' */
-            if (!strncmp(&expr[parsed], "//", 2)) {
+            if (!strncmp(&expr_str[parsed], "//", 2)) {
                 tok_len = 2;
                 tok_type = LYXP_TOKEN_OPER_RPATH;
             } else {
@@ -2800,81 +2804,83 @@
                 tok_type = LYXP_TOKEN_OPER_PATH;
             }
 
-        } else if (!strncmp(&expr[parsed], "!=", 2)) {
+        } else if (!strncmp(&expr_str[parsed], "!=", 2)) {
 
             /* Operator '!=' */
             tok_len = 2;
             tok_type = LYXP_TOKEN_OPER_NEQUAL;
 
-        } else if (!strncmp(&expr[parsed], "<=", 2) || !strncmp(&expr[parsed], ">=", 2)) {
+        } else if (!strncmp(&expr_str[parsed], "<=", 2) || !strncmp(&expr_str[parsed], ">=", 2)) {
 
             /* Operator '<=', '>=' */
             tok_len = 2;
             tok_type = LYXP_TOKEN_OPER_COMP;
 
-        } else if (expr[parsed] == '|') {
+        } else if (expr_str[parsed] == '|') {
 
             /* Operator '|' */
             tok_len = 1;
             tok_type = LYXP_TOKEN_OPER_UNI;
 
-        } else if ((expr[parsed] == '+') || (expr[parsed] == '-')) {
+        } else if ((expr_str[parsed] == '+') || (expr_str[parsed] == '-')) {
 
             /* Operator '+', '-' */
             tok_len = 1;
             tok_type = LYXP_TOKEN_OPER_MATH;
 
-        } else if (expr[parsed] == '=') {
+        } else if (expr_str[parsed] == '=') {
 
             /* Operator '=' */
             tok_len = 1;
             tok_type = LYXP_TOKEN_OPER_EQUAL;
 
-        } else if ((expr[parsed] == '<') || (expr[parsed] == '>')) {
+        } else if ((expr_str[parsed] == '<') || (expr_str[parsed] == '>')) {
 
             /* Operator '<', '>' */
             tok_len = 1;
             tok_type = LYXP_TOKEN_OPER_COMP;
 
-        } else if (ret->used && (ret->tokens[ret->used - 1] != LYXP_TOKEN_AT)
-                && (ret->tokens[ret->used - 1] != LYXP_TOKEN_PAR1)
-                && (ret->tokens[ret->used - 1] != LYXP_TOKEN_BRACK1)
-                && (ret->tokens[ret->used - 1] != LYXP_TOKEN_COMMA)
-                && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPER_LOG)
-                && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPER_EQUAL)
-                && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPER_NEQUAL)
-                && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPER_COMP)
-                && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPER_MATH)
-                && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPER_UNI)
-                && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPER_PATH)
-                && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPER_RPATH)) {
+        } else if (expr->used && (expr->tokens[expr->used - 1] != LYXP_TOKEN_AT)
+                && (expr->tokens[expr->used - 1] != LYXP_TOKEN_PAR1)
+                && (expr->tokens[expr->used - 1] != LYXP_TOKEN_BRACK1)
+                && (expr->tokens[expr->used - 1] != LYXP_TOKEN_COMMA)
+                && (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_LOG)
+                && (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_EQUAL)
+                && (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_NEQUAL)
+                && (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_COMP)
+                && (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_MATH)
+                && (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_UNI)
+                && (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_PATH)
+                && (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_RPATH)) {
 
             /* Operator '*', 'or', 'and', 'mod', or 'div' */
-            if (expr[parsed] == '*') {
+            if (expr_str[parsed] == '*') {
                 tok_len = 1;
                 tok_type = LYXP_TOKEN_OPER_MATH;
 
-            } else if (!strncmp(&expr[parsed], "or", 2)) {
+            } else if (!strncmp(&expr_str[parsed], "or", 2)) {
                 tok_len = 2;
                 tok_type = LYXP_TOKEN_OPER_LOG;
 
-            } else if (!strncmp(&expr[parsed], "and", 3)) {
+            } else if (!strncmp(&expr_str[parsed], "and", 3)) {
                 tok_len = 3;
                 tok_type = LYXP_TOKEN_OPER_LOG;
 
-            } else if (!strncmp(&expr[parsed], "mod", 3) || !strncmp(&expr[parsed], "div", 3)) {
+            } else if (!strncmp(&expr_str[parsed], "mod", 3) || !strncmp(&expr_str[parsed], "div", 3)) {
                 tok_len = 3;
                 tok_type = LYXP_TOKEN_OPER_MATH;
 
             } else if (prev_function_check) {
                 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Invalid character 0x%x ('%c'), perhaps \"%.*s\" is supposed to be a function call.",
-                       expr[parsed], expr[parsed], ret->tok_len[ret->used - 1], &ret->expr[ret->tok_pos[ret->used - 1]]);
+                       expr_str[parsed], expr_str[parsed], expr->tok_len[expr->used - 1], &expr->expr[expr->tok_pos[expr->used - 1]]);
+                ret = LY_EVALID;
                 goto error;
             } else {
-                LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed + 1, expr);
+                LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed + 1, expr_str);
+                ret = LY_EVALID;
                 goto error;
             }
-        } else if (expr[parsed] == '*') {
+        } else if (expr_str[parsed] == '*') {
 
             /* NameTest '*' */
             tok_len = 1;
@@ -2883,17 +2889,21 @@
         } else {
 
             /* NameTest (NCName ':' '*' | QName) or NodeType/FunctionName */
-            long int ncname_len = parse_ncname(&expr[parsed]);
-            LY_CHECK_ERR_GOTO(ncname_len < 0, LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed - ncname_len + 1, expr), error);
+            long int ncname_len = parse_ncname(&expr_str[parsed]);
+            LY_CHECK_ERR_GOTO(ncname_len < 0,
+                              LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed - ncname_len + 1, expr_str); ret = LY_EVALID,
+                              error);
             tok_len = ncname_len;
 
-            if (expr[parsed + tok_len] == ':') {
+            if (expr_str[parsed + tok_len] == ':') {
                 ++tok_len;
-                if (expr[parsed + tok_len] == '*') {
+                if (expr_str[parsed + tok_len] == '*') {
                     ++tok_len;
                 } else {
-                    ncname_len = parse_ncname(&expr[parsed + tok_len]);
-                    LY_CHECK_ERR_GOTO(ncname_len < 0, LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed - ncname_len + 1, expr), error);
+                    ncname_len = parse_ncname(&expr_str[parsed + tok_len]);
+                    LY_CHECK_ERR_GOTO(ncname_len < 0,
+                                      LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed - ncname_len + 1, expr_str); ret = LY_EVALID,
+                                      error);
                     tok_len += ncname_len;
                 }
                 /* remove old flag to prevent ambiguities */
@@ -2907,35 +2917,36 @@
         }
 
         /* store the token, move on to the next one */
-        LY_CHECK_GOTO(exp_add_token(ctx, ret, tok_type, parsed, tok_len), error);
+        LY_CHECK_GOTO(ret = exp_add_token(ctx, expr, tok_type, parsed, tok_len), error);
         parsed += tok_len;
-        while (is_xmlws(expr[parsed])) {
+        while (is_xmlws(expr_str[parsed])) {
             ++parsed;
         }
 
-    } while (expr[parsed]);
+    } while (expr_str[parsed]);
 
     if (reparse) {
         /* prealloc repeat */
-        ret->repeat = calloc(ret->size, sizeof *ret->repeat);
-        LY_CHECK_ERR_GOTO(!ret->repeat, LOGMEM(ctx), error);
+        expr->repeat = calloc(expr->size, sizeof *expr->repeat);
+        LY_CHECK_ERR_GOTO(!expr->repeat, LOGMEM(ctx); ret = LY_EMEM, error);
 
         /* fill repeat */
-        LY_CHECK_GOTO(reparse_or_expr(ctx, ret, &tok_idx), error);
-        if (ret->used > tok_idx) {
+        LY_CHECK_ERR_GOTO(reparse_or_expr(ctx, expr, &tok_idx), ret = LY_EVALID, error);
+        if (expr->used > tok_idx) {
             LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of an XPath expression.",
-                &ret->expr[ret->tok_pos[tok_idx]]);
+                &expr->expr[expr->tok_pos[tok_idx]]);
+            ret = LY_EVALID;
             goto error;
         }
     }
 
-    print_expr_struct_debug(ret);
-
-    return ret;
+    print_expr_struct_debug(expr);
+    *expr_p = expr;
+    return LY_SUCCESS;
 
 error:
-    lyxp_expr_free(ctx, ret);
-    return NULL;
+    lyxp_expr_free(ctx, expr);
+    return ret;
 }
 
 struct lyxp_expr *