diff options
author | zeertzjq <zeertzjq@outlook.com> | 2023-04-14 07:11:59 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-14 07:11:59 +0800 |
commit | 8f69c5ed450337b9f77c50f9ee0d3eb32f649ca6 (patch) | |
tree | 20ce18a0515f58ae6aa955cf40ac3d73bc96603f /src | |
parent | 0adb9f75c52424c8839708f51294ca5f58a3c18f (diff) | |
download | rneovim-8f69c5ed450337b9f77c50f9ee0d3eb32f649ca6.tar.gz rneovim-8f69c5ed450337b9f77c50f9ee0d3eb32f649ca6.tar.bz2 rneovim-8f69c5ed450337b9f77c50f9ee0d3eb32f649ca6.zip |
vim-patch:8.2.{0695,0725,0734,0753,0818,0819,0822} (#23075)
vim-patch:8.2.0695: Vim9: cannot define a function inside a function
Problem: Vim9: cannot define a function inside a function.
Solution: Initial support for :def inside :def.
https://github.com/vim/vim/commit/04b12697838b232b8b17c553ccc74cf1f1bdb81c
vim-patch:8.2.0725: Vim9: cannot call a function declared later in Vim9 script
Problem: Vim9: cannot call a function declared later in Vim9 script.
Solution: Make two passes through the script file.
https://github.com/vim/vim/commit/09689a02840be40fa7bb10b1921fb5bc5b2908f1
vim-patch:8.2.0734: Vim9: leaking memory when using :finish
Problem: Vim9: leaking memory when using :finish.
Solution: Do not check for next line in third pass.
https://github.com/vim/vim/commit/04816717dfea6e2469ff4c9d40f68b59aaf03724
vim-patch:8.2.0753: Vim9: expressions are evaluated in the discovery phase
Problem: Vim9: expressions are evaluated in the discovery phase.
Solution: Bail out if an expression is not a constant. Require a type for
declared constants.
https://github.com/vim/vim/commit/32e351179eacfc84f64cd5029e221582d400bb38
vim-patch:8.2.0818: Vim9: using a discovery phase doesn't work well
Problem: Vim9: using a discovery phase doesn't work well.
Solution: Remove the discovery phase, instead compile a function only when
it is used. Add :defcompile to compile def functions earlier.
https://github.com/vim/vim/commit/822ba24743af9ee1b5e7f656a7a61a38f3638bca
vim-patch:8.2.0819: compiler warning for unused variable
Problem: Compiler warning for unused variable.
Solution: Remove the variable.
https://github.com/vim/vim/commit/f40e51a880a95f94dbbbecc9476559506c2cc345
vim-patch:8.2.0822: Vim9: code left over from discovery phase
Problem: Vim9: code left over from discovery phase.
Solution: Remove the dead code.
https://github.com/vim/vim/commit/2eec37926db6d31beb36f162ac00357a30c093c8
Co-authored-by: Bram Moolenaar <Bram@vim.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/vimscript.c | 4 | ||||
-rw-r--r-- | src/nvim/eval.c | 144 | ||||
-rw-r--r-- | src/nvim/eval.h | 5 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 2 | ||||
-rw-r--r-- | src/nvim/eval/userfunc.c | 15 | ||||
-rw-r--r-- | src/nvim/eval/vars.c | 29 | ||||
-rw-r--r-- | src/nvim/ex_cmds.lua | 2 | ||||
-rw-r--r-- | src/nvim/ex_eval.c | 2 | ||||
-rw-r--r-- | src/nvim/quickfix.c | 2 |
9 files changed, 111 insertions, 94 deletions
diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index 2438a5cf1d..1740429ef6 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -172,7 +172,7 @@ Object nvim_eval(String expr, Error *err) int ok; TRY_WRAP(err, { - ok = eval0(expr.data, &rettv, NULL, true); + ok = eval0(expr.data, &rettv, NULL, EVAL_EVALUATE); }); if (!ERROR_SET(err)) { @@ -290,7 +290,7 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err) switch (dict.type) { case kObjectTypeString: try_start(); - if (eval0(dict.data.string.data, &rettv, NULL, true) == FAIL) { + if (eval0(dict.data.string.data, &rettv, NULL, EVAL_EVALUATE) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to evaluate dict expression"); } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index ff33fdeccb..796c010f74 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -706,7 +706,7 @@ int eval_to_bool(char *arg, bool *error, char **nextcmd, int skip) if (skip) { emsg_skip++; } - if (eval0(arg, &tv, nextcmd, !skip) == FAIL) { + if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL) { *error = true; } else { *error = false; @@ -730,7 +730,7 @@ static int eval1_emsg(char **arg, typval_T *rettv, bool evaluate) const int did_emsg_before = did_emsg; const int called_emsg_before = called_emsg; - const int ret = eval1(arg, rettv, evaluate); + const int ret = eval1(arg, rettv, evaluate ? EVAL_EVALUATE : 0); if (ret == FAIL) { // Report the invalid expression unless the expression evaluation has // been cancelled due to an aborting error, an interrupt, or an @@ -832,7 +832,7 @@ char *eval_to_string_skip(const char *arg, const char **nextcmd, const bool skip if (skip) { emsg_skip++; } - if (eval0((char *)arg, &tv, (char **)nextcmd, !skip) == FAIL || skip) { + if (eval0((char *)arg, &tv, (char **)nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL || skip) { retval = NULL; } else { retval = xstrdup(tv_get_string(&tv)); @@ -853,7 +853,7 @@ int skip_expr(char **pp) typval_T rettv; *pp = skipwhite(*pp); - return eval1(pp, &rettv, false); + return eval1(pp, &rettv, 0); } /// Top level evaluation function, returning a string. @@ -868,7 +868,7 @@ char *eval_to_string(char *arg, char **nextcmd, bool convert) char *retval; garray_T ga; - if (eval0(arg, &tv, nextcmd, true) == FAIL) { + if (eval0(arg, &tv, nextcmd, EVAL_EVALUATE) == FAIL) { retval = NULL; } else { if (convert && tv.v_type == VAR_LIST) { @@ -929,7 +929,7 @@ varnumber_T eval_to_number(char *expr) emsg_off++; - if (eval1(&p, &rettv, true) == FAIL) { + if (eval1(&p, &rettv, EVAL_EVALUATE) == FAIL) { retval = -1; } else { retval = tv_get_number_chk(&rettv, NULL); @@ -947,7 +947,7 @@ varnumber_T eval_to_number(char *expr) typval_T *eval_expr(char *arg) { typval_T *tv = xmalloc(sizeof(*tv)); - if (eval0(arg, tv, NULL, true) == FAIL) { + if (eval0(arg, tv, NULL, EVAL_EVALUATE) == FAIL) { XFREE_CLEAR(tv); } return tv; @@ -1024,7 +1024,7 @@ list_T *eval_spell_expr(char *badword, char *expr) emsg_off++; } - if (eval1(&p, &rettv, true) == OK) { + if (eval1(&p, &rettv, EVAL_EVALUATE) == OK) { if (rettv.v_type != VAR_LIST) { tv_clear(&rettv); } else { @@ -1171,7 +1171,7 @@ int eval_foldexpr(char *arg, int *cp) } textlock++; *cp = NUL; - if (eval0(arg, &tv, NULL, true) == FAIL) { + if (eval0(arg, &tv, NULL, EVAL_EVALUATE) == FAIL) { retval = 0; } else { // If the result is a number, just return the number. @@ -1346,7 +1346,7 @@ char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const empty1 = true; } else { empty1 = false; - if (eval1(&p, &var1, true) == FAIL) { // Recursive! + if (eval1(&p, &var1, EVAL_EVALUATE) == FAIL) { // Recursive! return NULL; } if (!tv_check_str(&var1)) { @@ -1380,7 +1380,8 @@ char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const lp->ll_empty2 = true; } else { lp->ll_empty2 = false; - if (eval1(&p, &var2, true) == FAIL) { // Recursive! + // Recursive! + if (eval1(&p, &var2, EVAL_EVALUATE) == FAIL) { tv_clear(&var1); return NULL; } @@ -1799,7 +1800,7 @@ void *eval_for_line(const char *arg, bool *errp, char **nextcmdp, int skip) if (skip) { emsg_skip++; } - if (eval0(skipwhite(expr + 2), &tv, nextcmdp, !skip) == OK) { + if (eval0(skipwhite(expr + 2), &tv, nextcmdp, skip ? 0 : EVAL_EVALUATE) == OK) { *errp = false; if (!skip) { if (tv.v_type == VAR_LIST) { @@ -2164,9 +2165,10 @@ int pattern_match(const char *pat, const char *text, bool ic) /// /// @return OK or FAIL. static int eval_func(char **const arg, char *const name, const int name_len, typval_T *const rettv, - const bool evaluate, typval_T *const basetv) + const int flags, typval_T *const basetv) FUNC_ATTR_NONNULL_ARG(1, 2, 4) { + const bool evaluate = flags & EVAL_EVALUATE; char *s = name; int len = name_len; @@ -2223,8 +2225,10 @@ static int eval_func(char **const arg, char *const name, const int name_len, typ /// Put the result in "rettv" when returning OK and "evaluate" is true. /// Note: "rettv.v_lock" is not set. /// +/// @param flags has EVAL_EVALUATE and similar flags. +/// /// @return OK or FAIL. -int eval0(char *arg, typval_T *rettv, char **nextcmd, int evaluate) +int eval0(char *arg, typval_T *rettv, char **nextcmd, const int flags) { int ret; char *p; @@ -2233,7 +2237,7 @@ int eval0(char *arg, typval_T *rettv, char **nextcmd, int evaluate) bool end_error = false; p = skipwhite(arg); - ret = eval1(&p, rettv, evaluate); + ret = eval1(&p, rettv, flags); if (ret != FAIL) { end_error = !ends_excmd(*p); @@ -2246,7 +2250,8 @@ int eval0(char *arg, typval_T *rettv, char **nextcmd, int evaluate) // been cancelled due to an aborting error, an interrupt, or an // exception, or we already gave a more specific error. // Also check called_emsg for when using assert_fails(). - if (!aborting() && did_emsg == did_emsg_before + if (!aborting() + && did_emsg == did_emsg_before && called_emsg == called_emsg_before) { if (end_error) { semsg(_(e_trailing_arg), p); @@ -2272,18 +2277,20 @@ int eval0(char *arg, typval_T *rettv, char **nextcmd, int evaluate) /// Note: "rettv.v_lock" is not set. /// /// @return OK or FAIL. -int eval1(char **arg, typval_T *rettv, int evaluate) +int eval1(char **arg, typval_T *rettv, const int flags) { typval_T var2; // Get the first variable. - if (eval2(arg, rettv, evaluate) == FAIL) { + if (eval2(arg, rettv, flags) == FAIL) { return FAIL; } if ((*arg)[0] == '?') { + const bool evaluate = flags & EVAL_EVALUATE; + bool result = false; - if (evaluate) { + if (flags & EVAL_EVALUATE) { bool error = false; if (tv_get_number_chk(rettv, &error) != 0) { @@ -2295,9 +2302,9 @@ int eval1(char **arg, typval_T *rettv, int evaluate) } } - // Get the second variable. + // Get the second variable. Recursive! *arg = skipwhite(*arg + 1); - if (eval1(arg, rettv, evaluate && result) == FAIL) { // recursive! + if (eval1(arg, rettv, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) { return FAIL; } @@ -2310,9 +2317,9 @@ int eval1(char **arg, typval_T *rettv, int evaluate) return FAIL; } - // Get the third variable. + // Get the third variable. Recursive! *arg = skipwhite(*arg + 1); - if (eval1(arg, &var2, evaluate && !result) == FAIL) { // Recursive! + if (eval1(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) == FAIL) { if (evaluate && result) { tv_clear(rettv); } @@ -2333,13 +2340,13 @@ int eval1(char **arg, typval_T *rettv, int evaluate) /// "arg" is advanced to the next non-white after the recognized expression. /// /// @return OK or FAIL. -static int eval2(char **arg, typval_T *rettv, int evaluate) +static int eval2(char **arg, typval_T *rettv, const int flags) { typval_T var2; bool error = false; // Get the first variable. - if (eval3(arg, rettv, evaluate) == FAIL) { + if (eval3(arg, rettv, flags) == FAIL) { return FAIL; } @@ -2347,6 +2354,8 @@ static int eval2(char **arg, typval_T *rettv, int evaluate) bool first = true; bool result = false; while ((*arg)[0] == '|' && (*arg)[1] == '|') { + const bool evaluate = flags & EVAL_EVALUATE; + if (evaluate && first) { if (tv_get_number_chk(rettv, &error) != 0) { result = true; @@ -2360,7 +2369,7 @@ static int eval2(char **arg, typval_T *rettv, int evaluate) // Get the second variable. *arg = skipwhite(*arg + 2); - if (eval3(arg, &var2, evaluate && !result) == FAIL) { + if (eval3(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) == FAIL) { return FAIL; } @@ -2390,13 +2399,13 @@ static int eval2(char **arg, typval_T *rettv, int evaluate) /// `arg` is advanced to the next non-white after the recognized expression. /// /// @return OK or FAIL. -static int eval3(char **arg, typval_T *rettv, int evaluate) +static int eval3(char **arg, typval_T *rettv, const int flags) { typval_T var2; bool error = false; // Get the first variable. - if (eval4(arg, rettv, evaluate) == FAIL) { + if (eval4(arg, rettv, flags) == FAIL) { return FAIL; } @@ -2404,6 +2413,8 @@ static int eval3(char **arg, typval_T *rettv, int evaluate) bool first = true; bool result = true; while ((*arg)[0] == '&' && (*arg)[1] == '&') { + const bool evaluate = flags & EVAL_EVALUATE; + if (evaluate && first) { if (tv_get_number_chk(rettv, &error) == 0) { result = false; @@ -2417,7 +2428,7 @@ static int eval3(char **arg, typval_T *rettv, int evaluate) // Get the second variable. *arg = skipwhite(*arg + 2); - if (eval4(arg, &var2, evaluate && result) == FAIL) { + if (eval4(arg, &var2, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) { return FAIL; } @@ -2456,7 +2467,7 @@ static int eval3(char **arg, typval_T *rettv, int evaluate) /// "arg" is advanced to the next non-white after the recognized expression. /// /// @return OK or FAIL. -static int eval4(char **arg, typval_T *rettv, int evaluate) +static int eval4(char **arg, typval_T *rettv, const int flags) { typval_T var2; char *p; @@ -2464,7 +2475,7 @@ static int eval4(char **arg, typval_T *rettv, int evaluate) int len = 2; // Get the first variable. - if (eval5(arg, rettv, evaluate) == FAIL) { + if (eval5(arg, rettv, flags) == FAIL) { return FAIL; } @@ -2528,11 +2539,11 @@ static int eval4(char **arg, typval_T *rettv, int evaluate) // Get the second variable. *arg = skipwhite(p + len); - if (eval5(arg, &var2, evaluate) == FAIL) { + if (eval5(arg, &var2, flags) == FAIL) { tv_clear(rettv); return FAIL; } - if (evaluate) { + if (flags & EVAL_EVALUATE) { const int ret = typval_compare(rettv, &var2, type, ic); tv_clear(&var2); @@ -2586,7 +2597,7 @@ static int eval_addlist(typval_T *tv1, typval_T *tv2) /// `arg` is advanced to the next non-white after the recognized expression. /// /// @return OK or FAIL. -static int eval5(char **arg, typval_T *rettv, int evaluate) +static int eval5(char **arg, typval_T *rettv, const int flags) { typval_T var2; varnumber_T n1, n2; @@ -2594,7 +2605,7 @@ static int eval5(char **arg, typval_T *rettv, int evaluate) char *p; // Get the first variable. - if (eval6(arg, rettv, evaluate, false) == FAIL) { + if (eval6(arg, rettv, flags, false) == FAIL) { return FAIL; } @@ -2606,7 +2617,7 @@ static int eval5(char **arg, typval_T *rettv, int evaluate) } if ((op != '+' || (rettv->v_type != VAR_LIST && rettv->v_type != VAR_BLOB)) - && (op == '.' || rettv->v_type != VAR_FLOAT) && evaluate) { + && (op == '.' || rettv->v_type != VAR_FLOAT) && (flags & EVAL_EVALUATE)) { // For "list + ...", an illegal use of the first operand as // a number cannot be determined before evaluating the 2nd // operand: if this is also a list, all is ok. @@ -2625,12 +2636,12 @@ static int eval5(char **arg, typval_T *rettv, int evaluate) (*arg)++; } *arg = skipwhite(*arg + 1); - if (eval6(arg, &var2, evaluate, op == '.') == FAIL) { + if (eval6(arg, &var2, flags, op == '.') == FAIL) { tv_clear(rettv); return FAIL; } - if (evaluate) { + if (flags & EVAL_EVALUATE) { // Compute the result. if (op == '.') { char buf1[NUMBUFLEN]; @@ -2724,11 +2735,10 @@ static int eval5(char **arg, typval_T *rettv, int evaluate) /// expression. Is advanced to the next non-whitespace /// character after the recognized expression. /// @param[out] rettv Location where result is saved. -/// @param[in] evaluate If not true, rettv is not populated. /// @param[in] want_string True if "." is string_concatenation, otherwise /// float /// @return OK or FAIL. -static int eval6(char **arg, typval_T *rettv, int evaluate, int want_string) +static int eval6(char **arg, typval_T *rettv, const int flags, bool want_string) FUNC_ATTR_NO_SANITIZE_UNDEFINED { typval_T var2; @@ -2739,7 +2749,7 @@ static int eval6(char **arg, typval_T *rettv, int evaluate, int want_string) bool error = false; // Get the first variable. - if (eval7(arg, rettv, evaluate, want_string) == FAIL) { + if (eval7(arg, rettv, flags, want_string) == FAIL) { return FAIL; } @@ -2750,7 +2760,7 @@ static int eval6(char **arg, typval_T *rettv, int evaluate, int want_string) break; } - if (evaluate) { + if (flags & EVAL_EVALUATE) { if (rettv->v_type == VAR_FLOAT) { f1 = rettv->vval.v_float; use_float = true; @@ -2768,11 +2778,11 @@ static int eval6(char **arg, typval_T *rettv, int evaluate, int want_string) // Get the second variable. *arg = skipwhite(*arg + 1); - if (eval7(arg, &var2, evaluate, false) == FAIL) { + if (eval7(arg, &var2, flags, false) == FAIL) { return FAIL; } - if (evaluate) { + if (flags & EVAL_EVALUATE) { if (var2.v_type == VAR_FLOAT) { if (!use_float) { f1 = (float_T)n1; @@ -2859,8 +2869,9 @@ static int eval6(char **arg, typval_T *rettv, int evaluate, int want_string) /// @param want_string after "." operator /// /// @return OK or FAIL. -static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string) +static int eval7(char **arg, typval_T *rettv, const int flags, bool want_string) { + const bool evaluate = flags & EVAL_EVALUATE; int ret = OK; static int recurse = 0; @@ -2922,14 +2933,14 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string) // List: [expr, expr] case '[': - ret = get_list_tv(arg, rettv, evaluate); + ret = get_list_tv(arg, rettv, flags); break; // Dictionary: #{key: val, key: val} case '#': if ((*arg)[1] == '{') { (*arg)++; - ret = eval_dict(arg, rettv, evaluate, true); + ret = eval_dict(arg, rettv, flags, true); } else { ret = NOTDONE; } @@ -2940,7 +2951,7 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string) case '{': ret = get_lambda_tv(arg, rettv, evaluate); if (ret == NOTDONE) { - ret = eval_dict(arg, rettv, evaluate, false); + ret = eval_dict(arg, rettv, flags, false); } break; @@ -2968,7 +2979,7 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string) // nested expression: (expression). case '(': *arg = skipwhite(*arg + 1); - ret = eval1(arg, rettv, evaluate); // recursive! + ret = eval1(arg, rettv, flags); // recursive! if (**arg == ')') { (*arg)++; } else if (ret == OK) { @@ -2997,7 +3008,7 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string) ret = FAIL; } else { if (**arg == '(') { // recursive! - ret = eval_func(arg, s, len, rettv, evaluate, NULL); + ret = eval_func(arg, s, len, rettv, flags, NULL); } else if (evaluate) { ret = get_var_tv(s, len, rettv, NULL, true, false); } else { @@ -3013,7 +3024,7 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string) // Handle following '[', '(' and '.' for expr[expr], expr.name, // expr(expr), expr->name(expr) if (ret == OK) { - ret = handle_subscript((const char **)arg, rettv, evaluate, true); + ret = handle_subscript((const char **)arg, rettv, flags, true); } // Apply logical NOT and unary '-', from right to left, ignore '+'. @@ -3238,7 +3249,7 @@ static int eval_method(char **const arg, typval_T *const rettv, const bool evalu } ret = call_func_rettv(arg, rettv, evaluate, NULL, &base, lua_funcname); } else { - ret = eval_func(arg, name, len, rettv, evaluate, &base); + ret = eval_func(arg, name, len, rettv, evaluate ? EVAL_EVALUATE : 0, &base); } } @@ -3257,8 +3268,9 @@ static int eval_method(char **const arg, typval_T *const rettv, const bool evalu /// @param verbose give error messages /// /// @returns FAIL or OK. "*arg" is advanced to after the ']'. -static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose) +static int eval_index(char **arg, typval_T *rettv, const int flags, bool verbose) { + const bool evaluate = flags & EVAL_EVALUATE; bool empty1 = false; bool empty2 = false; ptrdiff_t len = -1; @@ -3313,7 +3325,7 @@ static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose) *arg = skipwhite(*arg + 1); if (**arg == ':') { empty1 = true; - } else if (eval1(arg, &var1, evaluate) == FAIL) { // Recursive! + } else if (eval1(arg, &var1, flags) == FAIL) { // Recursive! return FAIL; } else if (evaluate && !tv_check_str(&var1)) { // Not a number or string. @@ -3327,7 +3339,7 @@ static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose) *arg = skipwhite(*arg + 1); if (**arg == ']') { empty2 = true; - } else if (eval1(arg, &var2, evaluate) == FAIL) { // Recursive! + } else if (eval1(arg, &var2, flags) == FAIL) { // Recursive! if (!empty1) { tv_clear(&var1); } @@ -3930,8 +3942,9 @@ void partial_unref(partial_T *pt) /// Allocate a variable for a List and fill it from "*arg". /// /// @return OK or FAIL. -static int get_list_tv(char **arg, typval_T *rettv, int evaluate) +static int get_list_tv(char **arg, typval_T *rettv, const int flags) { + const bool evaluate = flags & EVAL_EVALUATE; list_T *l = NULL; if (evaluate) { @@ -3941,7 +3954,7 @@ static int get_list_tv(char **arg, typval_T *rettv, int evaluate) *arg = skipwhite(*arg + 1); while (**arg != ']' && **arg != NUL) { typval_T tv; - if (eval1(arg, &tv, evaluate) == FAIL) { // Recursive! + if (eval1(arg, &tv, flags) == FAIL) { // Recursive! goto failret; } if (evaluate) { @@ -4576,8 +4589,9 @@ static int get_literal_key(char **arg, typval_T *tv) /// "literal" is true for #{key: val} /// /// @return OK or FAIL. Returns NOTDONE for {expr}. -static int eval_dict(char **arg, typval_T *rettv, int evaluate, bool literal) +static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal) { + const bool evaluate = flags & EVAL_EVALUATE; typval_T tv; char *key = NULL; char *curly_expr = skipwhite(*arg + 1); @@ -4591,7 +4605,7 @@ static int eval_dict(char **arg, typval_T *rettv, int evaluate, bool literal) // "#{abc}" is never a curly-braces expression. if (*curly_expr != '}' && !literal - && eval1(&curly_expr, &tv, false) == OK + && eval1(&curly_expr, &tv, 0) == OK && *skipwhite(curly_expr) == '}') { return NOTDONE; } @@ -4608,7 +4622,7 @@ static int eval_dict(char **arg, typval_T *rettv, int evaluate, bool literal) while (**arg != '}' && **arg != NUL) { if ((literal ? get_literal_key(arg, &tvkey) - : eval1(arg, &tvkey, evaluate)) == FAIL) { // recursive! + : eval1(arg, &tvkey, flags)) == FAIL) { // recursive! goto failret; } if (**arg != ':') { @@ -4626,7 +4640,7 @@ static int eval_dict(char **arg, typval_T *rettv, int evaluate, bool literal) } *arg = skipwhite(*arg + 1); - if (eval1(arg, &tv, evaluate) == FAIL) { // Recursive! + if (eval1(arg, &tv, flags) == FAIL) { // Recursive! if (evaluate) { tv_clear(&tvkey); } @@ -6937,12 +6951,12 @@ int check_luafunc_name(const char *const str, const bool paren) /// /// Can all be combined in any order: dict.func(expr)[idx]['func'](expr)->len() /// -/// @param evaluate do more than finding the end /// @param verbose give error messages /// @param start_leader start of '!' and '-' prefixes /// @param end_leaderp end of '!' and '-' prefixes -int handle_subscript(const char **const arg, typval_T *rettv, int evaluate, int verbose) +int handle_subscript(const char **const arg, typval_T *rettv, const int flags, bool verbose) { + const bool evaluate = flags & EVAL_EVALUATE; int ret = OK; dict_T *selfdict = NULL; const char *lua_funcname = NULL; @@ -7002,7 +7016,7 @@ int handle_subscript(const char **const arg, typval_T *rettv, int evaluate, int } else { selfdict = NULL; } - if (eval_index((char **)arg, rettv, evaluate, verbose) == FAIL) { + if (eval_index((char **)arg, rettv, flags, verbose) == FAIL) { tv_clear(rettv); ret = FAIL; } @@ -7385,7 +7399,7 @@ void ex_echo(exarg_T *eap) { char *p = arg; - if (eval1(&arg, &rettv, !eap->skip) == FAIL) { + if (eval1(&arg, &rettv, eap->skip ? 0 : EVAL_EVALUATE) == FAIL) { // Report the invalid expression unless the expression evaluation // has been cancelled due to an aborting error, an interrupt, or an // exception. diff --git a/src/nvim/eval.h b/src/nvim/eval.h index aa034cb2b3..973a4a1fc3 100644 --- a/src/nvim/eval.h +++ b/src/nvim/eval.h @@ -266,6 +266,11 @@ typedef int (*ex_unletlock_callback)(lval_T *, char *, exarg_T *, int); // Used for checking if local variables or arguments used in a lambda. extern bool *eval_lavars_used; +/// Flag for expression evaluation. +enum { + EVAL_EVALUATE = 1, ///< when missing don't actually evaluate +}; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "eval.h.generated.h" #endif diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 7f224f371c..52e38b73ba 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1550,7 +1550,7 @@ static void f_eval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } const char *const expr_start = s; - if (s == NULL || eval1((char **)&s, rettv, true) == FAIL) { + if (s == NULL || eval1((char **)&s, rettv, EVAL_EVALUATE) == FAIL) { if (expr_start != NULL && !aborting()) { semsg(_(e_invexpr2), expr_start); } diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index f09da6b79b..f82ab08d2d 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -152,7 +152,7 @@ static int get_function_args(char **argp, char endchar, garray_T *newargs, int * p = skipwhite(p) + 1; p = skipwhite(p); char *expr = p; - if (eval1(&p, &rettv, false) != FAIL) { + if (eval1(&p, &rettv, 0) != FAIL) { ga_grow(default_args, 1); // trim trailing whitespace @@ -463,7 +463,8 @@ int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, funcexe_ if (*argp == ')' || *argp == ',' || *argp == NUL) { break; } - if (eval1(&argp, &argvars[argcount], funcexe->fe_evaluate) == FAIL) { + if (eval1(&argp, &argvars[argcount], + funcexe->fe_evaluate ? EVAL_EVALUATE : 0) == FAIL) { ret = FAIL; break; } @@ -972,7 +973,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett default_expr = ((char **)(fp->uf_def_args.ga_data)) [ai + fp->uf_def_args.ga_len]; - if (eval1(&default_expr, &def_rettv, true) == FAIL) { + if (eval1(&default_expr, &def_rettv, EVAL_EVALUATE) == FAIL) { default_arg_err = true; break; } @@ -1109,7 +1110,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett // A Lambda always has the command "return {expr}". It is much faster // to evaluate {expr} directly. ex_nesting_level++; - (void)eval1(&p, rettv, true); + (void)eval1(&p, rettv, EVAL_EVALUATE); ex_nesting_level--; } else { // call do_cmdline() to execute the lines @@ -2953,7 +2954,7 @@ void ex_return(exarg_T *eap) eap->nextcmd = NULL; if ((*arg != NUL && *arg != '|' && *arg != '\n') - && eval0(arg, &rettv, &eap->nextcmd, !eap->skip) != FAIL) { + && eval0(arg, &rettv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE) != FAIL) { if (!eap->skip) { returning = do_return(eap, false, true, &rettv); } else { @@ -3004,7 +3005,7 @@ void ex_call(exarg_T *eap) // instead to skip to any following command, e.g. for: // :if 0 | call dict.foo().bar() | endif. emsg_skip++; - if (eval0(eap->arg, &rettv, &eap->nextcmd, false) != FAIL) { + if (eval0(eap->arg, &rettv, &eap->nextcmd, 0) != FAIL) { tv_clear(&rettv); } emsg_skip--; @@ -3071,7 +3072,7 @@ void ex_call(exarg_T *eap) } // Handle a function returning a Funcref, Dictionary or List. - if (handle_subscript((const char **)&arg, &rettv, true, true) + if (handle_subscript((const char **)&arg, &rettv, EVAL_EVALUATE, true) == FAIL) { failed = true; break; diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index 9120cc4471..a3dc0cfc04 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -175,21 +175,13 @@ static list_T *heredoc_get(exarg_T *eap, char *cmd) /// ":let var ..= expr" assignment command. /// ":let [var1, var2] = expr" unpack list. /// ":let [name, ..., ; lastname] = expr" unpack list. -void ex_let(exarg_T *eap) -{ - ex_let_const(eap, false); -} - +/// /// ":cons[t] var = expr1" define constant /// ":cons[t] [name1, name2, ...] = expr1" define constants unpacking list /// ":cons[t] [name, ..., ; lastname] = expr" define constants unpacking list -void ex_const(exarg_T *eap) -{ - ex_let_const(eap, true); -} - -static void ex_let_const(exarg_T *eap, const bool is_const) +void ex_let(exarg_T *eap) { + const bool is_const = eap->cmdidx == CMD_const; char *arg = eap->arg; char *expr = NULL; typval_T rettv; @@ -208,8 +200,10 @@ static void ex_let_const(exarg_T *eap, const bool is_const) argend--; } expr = skipwhite(argend); - if (*expr != '=' && !((vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL - && expr[1] == '=') || strncmp(expr, "..=", 3) == 0)) { + bool concat = strncmp(expr, "..=", 3) == 0; + bool has_assign = *expr == '=' || (vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL + && expr[1] == '='); + if (!has_assign && !concat) { // ":let" without "=": list variables if (*arg == '[') { emsg(_(e_invarg)); @@ -240,6 +234,8 @@ static void ex_let_const(exarg_T *eap, const bool is_const) tv_clear(&rettv); } } else { + rettv.v_type = VAR_UNKNOWN; + op[0] = '='; op[1] = NUL; if (*expr != '=') { @@ -259,7 +255,8 @@ static void ex_let_const(exarg_T *eap, const bool is_const) if (eap->skip) { emsg_skip++; } - i = eval0(expr, &rettv, &eap->nextcmd, !eap->skip); + int eval_flags = eap->skip ? 0 : EVAL_EVALUATE; + i = eval0(expr, &rettv, &eap->nextcmd, eval_flags); if (eap->skip) { if (i != FAIL) { tv_clear(&rettv); @@ -506,7 +503,7 @@ static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first) } else { // handle d.key, l[idx], f(expr) const char *const arg_subsc = arg; - if (handle_subscript(&arg, &tv, true, true) == FAIL) { + if (handle_subscript(&arg, &tv, EVAL_EVALUATE, true) == FAIL) { error = true; } else { if (arg == arg_subsc && len == 2 && name[1] == ':') { @@ -1713,7 +1710,7 @@ bool var_exists(const char *var) n = get_var_tv(name, len, &tv, NULL, false, true) == OK; if (n) { // Handle d.key, l[idx], f(expr). - n = handle_subscript(&var, &tv, true, false) == OK; + n = handle_subscript(&var, &tv, EVAL_EVALUATE, false) == OK; if (n) { tv_clear(&tv); } diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index bdc1174de3..be6299db0e 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -634,7 +634,7 @@ module.cmds = { command='const', flags=bit.bor(EXTRA, NOTRLCOM, SBOXOK, CMDWIN, LOCK_OK), addr_type='ADDR_NONE', - func='ex_const', + func='ex_let', }, { command='copen', diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index fed8f549e6..6772b78c33 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -793,7 +793,7 @@ void ex_eval(exarg_T *eap) { typval_T tv; - if (eval0(eap->arg, &tv, &eap->nextcmd, !eap->skip) == OK) { + if (eval0(eap->arg, &tv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE) == OK) { tv_clear(&tv); } } diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 262d87ba61..cfaa3b5781 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -6958,7 +6958,7 @@ void ex_cexpr(exarg_T *eap) // Evaluate the expression. When the result is a string or a list we can // use it to fill the errorlist. typval_T tv; - if (eval0(eap->arg, &tv, &eap->nextcmd, true) == FAIL) { + if (eval0(eap->arg, &tv, &eap->nextcmd, EVAL_EVALUATE) == FAIL) { return; } |