diff options
author | zeertzjq <zeertzjq@outlook.com> | 2023-04-14 10:58:29 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-14 10:58:29 +0800 |
commit | 37bb40701d672d5213ec1be4e21d7808aee968e7 (patch) | |
tree | 8f2c7db06448099e9ee768e2dbd718514e5ef9ca /src | |
parent | f64f6706e58061f0a3de530edd1f10e331cd1525 (diff) | |
parent | e8c25aac8d864e7033bcfe4640ee44054035f61d (diff) | |
download | rneovim-37bb40701d672d5213ec1be4e21d7808aee968e7.tar.gz rneovim-37bb40701d672d5213ec1be4e21d7808aee968e7.tar.bz2 rneovim-37bb40701d672d5213ec1be4e21d7808aee968e7.zip |
Merge pull request #23078 from zeertzjq/vim-8.2.1047
vim-patch:8.2.{1047,1048,1049,1050,1052},9.0.1447
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/vimscript.c | 4 | ||||
-rw-r--r-- | src/nvim/digraph.c | 2 | ||||
-rw-r--r-- | src/nvim/eval.c | 188 | ||||
-rw-r--r-- | src/nvim/eval.h | 15 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 2 | ||||
-rw-r--r-- | src/nvim/eval/userfunc.c | 17 | ||||
-rw-r--r-- | src/nvim/eval/vars.c | 69 | ||||
-rw-r--r-- | src/nvim/ex_cmds_defs.h | 1 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 3 | ||||
-rw-r--r-- | src/nvim/ex_eval.c | 20 | ||||
-rw-r--r-- | src/nvim/fold.c | 3 | ||||
-rw-r--r-- | src/nvim/mapping.c | 2 | ||||
-rw-r--r-- | src/nvim/ops.c | 2 | ||||
-rw-r--r-- | src/nvim/path.c | 4 | ||||
-rw-r--r-- | src/nvim/quickfix.c | 2 | ||||
-rw-r--r-- | src/nvim/regexp.c | 2 | ||||
-rw-r--r-- | src/nvim/statusline.c | 4 |
17 files changed, 205 insertions, 135 deletions
diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index 1740429ef6..d2e18f08f3 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, EVAL_EVALUATE); + ok = eval0(expr.data, &rettv, NULL, &EVALARG_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, EVAL_EVALUATE) == FAIL) { + if (eval0(dict.data.string.data, &rettv, NULL, &EVALARG_EVALUATE) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to evaluate dict expression"); } diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c index 7d6349e552..de3808e4f5 100644 --- a/src/nvim/digraph.c +++ b/src/nvim/digraph.c @@ -2203,7 +2203,7 @@ bool get_keymap_str(win_T *wp, char *fmt, char *buf, int len) curwin = wp; STRCPY(buf, "b:keymap_name"); // must be writable emsg_skip++; - s = p = eval_to_string(buf, NULL, false); + s = p = eval_to_string(buf, false); emsg_skip--; curbuf = old_curbuf; curwin = old_curwin; diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 796c010f74..a9c5ca46f3 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -698,7 +698,7 @@ void eval_patch(const char *const origfile, const char *const difffile, const ch /// @param skip only parse, don't execute /// /// @return true or false. -int eval_to_bool(char *arg, bool *error, char **nextcmd, int skip) +int eval_to_bool(char *arg, bool *error, exarg_T *eap, int skip) { typval_T tv; bool retval = false; @@ -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 ? 0 : EVAL_EVALUATE) == FAIL) { + if (eval0(arg, &tv, eap, skip ? NULL : &EVALARG_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 ? EVAL_EVALUATE : 0); + const int ret = eval1(arg, rettv, evaluate ? &EVALARG_EVALUATE : NULL); if (ret == FAIL) { // Report the invalid expression unless the expression evaluation has // been cancelled due to an aborting error, an interrupt, or an @@ -817,13 +817,12 @@ bool eval_expr_to_bool(const typval_T *expr, bool *error) /// Top level evaluation function, returning a string /// /// @param[in] arg String to evaluate. -/// @param nextcmd Pointer to the start of the next Ex command. /// @param[in] skip If true, only do parsing to nextcmd without reporting /// errors or actually evaluating anything. /// /// @return [allocated] string result of evaluation or NULL in case of error or /// when skipping. -char *eval_to_string_skip(const char *arg, const char **nextcmd, const bool skip) +char *eval_to_string_skip(char *arg, exarg_T *eap, const bool skip) FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT { typval_T tv; @@ -832,7 +831,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 ? 0 : EVAL_EVALUATE) == FAIL || skip) { + if (eval0(arg, &tv, eap, skip ? NULL : &EVALARG_EVALUATE) == FAIL || skip) { retval = NULL; } else { retval = xstrdup(tv_get_string(&tv)); @@ -853,7 +852,7 @@ int skip_expr(char **pp) typval_T rettv; *pp = skipwhite(*pp); - return eval1(pp, &rettv, 0); + return eval1(pp, &rettv, NULL); } /// Top level evaluation function, returning a string. @@ -862,13 +861,13 @@ int skip_expr(char **pp) /// a Float to a String. /// /// @return pointer to allocated memory, or NULL for failure. -char *eval_to_string(char *arg, char **nextcmd, bool convert) +char *eval_to_string(char *arg, bool convert) { typval_T tv; char *retval; garray_T ga; - if (eval0(arg, &tv, nextcmd, EVAL_EVALUATE) == FAIL) { + if (eval0(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) { retval = NULL; } else { if (convert && tv.v_type == VAR_LIST) { @@ -898,7 +897,7 @@ char *eval_to_string(char *arg, char **nextcmd, bool convert) /// textlock. /// /// @param use_sandbox when true, use the sandbox. -char *eval_to_string_safe(char *arg, char **nextcmd, int use_sandbox) +char *eval_to_string_safe(char *arg, int use_sandbox) { char *retval; funccal_entry_T funccal_entry; @@ -908,7 +907,7 @@ char *eval_to_string_safe(char *arg, char **nextcmd, int use_sandbox) sandbox++; } textlock++; - retval = eval_to_string(arg, nextcmd, false); + retval = eval_to_string(arg, false); if (use_sandbox) { sandbox--; } @@ -929,7 +928,7 @@ varnumber_T eval_to_number(char *expr) emsg_off++; - if (eval1(&p, &rettv, EVAL_EVALUATE) == FAIL) { + if (eval1(&p, &rettv, &EVALARG_EVALUATE) == FAIL) { retval = -1; } else { retval = tv_get_number_chk(&rettv, NULL); @@ -947,7 +946,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, EVAL_EVALUATE) == FAIL) { + if (eval0(arg, tv, NULL, &EVALARG_EVALUATE) == FAIL) { XFREE_CLEAR(tv); } return tv; @@ -1024,7 +1023,7 @@ list_T *eval_spell_expr(char *badword, char *expr) emsg_off++; } - if (eval1(&p, &rettv, EVAL_EVALUATE) == OK) { + if (eval1(&p, &rettv, &EVALARG_EVALUATE) == OK) { if (rettv.v_type != VAR_LIST) { tv_clear(&rettv); } else { @@ -1171,7 +1170,7 @@ int eval_foldexpr(char *arg, int *cp) } textlock++; *cp = NUL; - if (eval0(arg, &tv, NULL, EVAL_EVALUATE) == FAIL) { + if (eval0(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) { retval = 0; } else { // If the result is a number, just return the number. @@ -1346,7 +1345,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, EVAL_EVALUATE) == FAIL) { // Recursive! + if (eval1(&p, &var1, &EVALARG_EVALUATE) == FAIL) { // Recursive! return NULL; } if (!tv_check_str(&var1)) { @@ -1381,7 +1380,7 @@ char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const } else { lp->ll_empty2 = false; // Recursive! - if (eval1(&p, &var2, EVAL_EVALUATE) == FAIL) { + if (eval1(&p, &var2, &EVALARG_EVALUATE) == FAIL) { tv_clear(&var1); return NULL; } @@ -1777,13 +1776,14 @@ notify: /// @param[out] *errp set to true for an error, false otherwise; /// /// @return a pointer that holds the info. Null when there is an error. -void *eval_for_line(const char *arg, bool *errp, char **nextcmdp, int skip) +void *eval_for_line(const char *arg, bool *errp, exarg_T *eap, int skip) { forinfo_T *fi = xcalloc(1, sizeof(forinfo_T)); const char *expr; typval_T tv; list_T *l; + evalarg_T evalarg = { .eval_flags = skip ? 0 : EVAL_EVALUATE }; *errp = true; // Default: there is an error. expr = skip_var_list(arg, &fi->fi_varcount, &fi->fi_semicolon); @@ -1800,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 ? 0 : EVAL_EVALUATE) == OK) { + if (eval0(skipwhite(expr + 2), &tv, eap, &evalarg) == OK) { *errp = false; if (!skip) { if (tv.v_type == VAR_LIST) { @@ -2225,10 +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. +/// @param evalarg can be NULL, &EVALARG_EVALUATE or a pointer. /// /// @return OK or FAIL. -int eval0(char *arg, typval_T *rettv, char **nextcmd, const int flags) +int eval0(char *arg, typval_T *rettv, exarg_T *eap, evalarg_T *const evalarg) { int ret; char *p; @@ -2236,8 +2236,11 @@ int eval0(char *arg, typval_T *rettv, char **nextcmd, const int flags) const int called_emsg_before = called_emsg; bool end_error = false; + if (evalarg != NULL) { + evalarg->eval_tofree = NULL; + } p = skipwhite(arg); - ret = eval1(&p, rettv, flags); + ret = eval1(&p, rettv, evalarg); if (ret != FAIL) { end_error = !ends_excmd(*p); @@ -2261,8 +2264,24 @@ int eval0(char *arg, typval_T *rettv, char **nextcmd, const int flags) } ret = FAIL; } - if (nextcmd != NULL) { - *nextcmd = check_nextcmd(p); + + if (eap != NULL) { + eap->nextcmd = check_nextcmd(p); + } + + if (evalarg != NULL) { + if (eap != NULL) { + if (evalarg->eval_tofree != NULL) { + // We may need to keep the original command line, e.g. for + // ":let" it has the variable names. But we may also need the + // new one, "nextcmd" points into it. Keep both. + xfree(eap->cmdline_tofree); + eap->cmdline_tofree = *eap->cmdlinep; + *eap->cmdlinep = evalarg->eval_tofree; + } + } else { + xfree(evalarg->eval_tofree); + } } return ret; @@ -2277,20 +2296,20 @@ int eval0(char *arg, typval_T *rettv, char **nextcmd, const int flags) /// Note: "rettv.v_lock" is not set. /// /// @return OK or FAIL. -int eval1(char **arg, typval_T *rettv, const int flags) +int eval1(char **arg, typval_T *rettv, evalarg_T *const evalarg) { - typval_T var2; - // Get the first variable. - if (eval2(arg, rettv, flags) == FAIL) { + if (eval2(arg, rettv, evalarg) == FAIL) { return FAIL; } if ((*arg)[0] == '?') { - const bool evaluate = flags & EVAL_EVALUATE; + evalarg_T nested_evalarg = evalarg == NULL ? (evalarg_T){ 0 } : *evalarg; + const int orig_flags = evalarg == NULL ? 0 : evalarg->eval_flags; + const bool evaluate = nested_evalarg.eval_flags & EVAL_EVALUATE; bool result = false; - if (flags & EVAL_EVALUATE) { + if (evaluate) { bool error = false; if (tv_get_number_chk(rettv, &error) != 0) { @@ -2304,7 +2323,8 @@ int eval1(char **arg, typval_T *rettv, const int flags) // Get the second variable. Recursive! *arg = skipwhite(*arg + 1); - if (eval1(arg, rettv, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) { + nested_evalarg.eval_flags = result ? orig_flags : orig_flags & ~EVAL_EVALUATE; + if (eval1(arg, rettv, &nested_evalarg) == FAIL) { return FAIL; } @@ -2319,7 +2339,9 @@ int eval1(char **arg, typval_T *rettv, const int flags) // Get the third variable. Recursive! *arg = skipwhite(*arg + 1); - if (eval1(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) == FAIL) { + typval_T var2; + nested_evalarg.eval_flags = !result ? orig_flags : orig_flags & ~EVAL_EVALUATE; + if (eval1(arg, &var2, &nested_evalarg) == FAIL) { if (evaluate && result) { tv_clear(rettv); } @@ -2340,13 +2362,13 @@ int eval1(char **arg, typval_T *rettv, const int flags) /// "arg" is advanced to the next non-white after the recognized expression. /// /// @return OK or FAIL. -static int eval2(char **arg, typval_T *rettv, const int flags) +static int eval2(char **arg, typval_T *rettv, evalarg_T *const evalarg) { typval_T var2; bool error = false; // Get the first variable. - if (eval3(arg, rettv, flags) == FAIL) { + if (eval3(arg, rettv, evalarg) == FAIL) { return FAIL; } @@ -2354,7 +2376,9 @@ static int eval2(char **arg, typval_T *rettv, const int flags) bool first = true; bool result = false; while ((*arg)[0] == '|' && (*arg)[1] == '|') { - const bool evaluate = flags & EVAL_EVALUATE; + evalarg_T nested_evalarg = evalarg == NULL ? (evalarg_T){ 0 } : *evalarg; + const int orig_flags = evalarg == NULL ? 0 : evalarg->eval_flags; + const bool evaluate = orig_flags & EVAL_EVALUATE; if (evaluate && first) { if (tv_get_number_chk(rettv, &error) != 0) { @@ -2369,7 +2393,8 @@ static int eval2(char **arg, typval_T *rettv, const int flags) // Get the second variable. *arg = skipwhite(*arg + 2); - if (eval3(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) == FAIL) { + nested_evalarg.eval_flags = !result ? orig_flags : orig_flags & ~EVAL_EVALUATE; + if (eval3(arg, &var2, &nested_evalarg) == FAIL) { return FAIL; } @@ -2399,13 +2424,13 @@ static int eval2(char **arg, typval_T *rettv, const int flags) /// `arg` is advanced to the next non-white after the recognized expression. /// /// @return OK or FAIL. -static int eval3(char **arg, typval_T *rettv, const int flags) +static int eval3(char **arg, typval_T *rettv, evalarg_T *const evalarg) { typval_T var2; bool error = false; // Get the first variable. - if (eval4(arg, rettv, flags) == FAIL) { + if (eval4(arg, rettv, evalarg) == FAIL) { return FAIL; } @@ -2413,7 +2438,9 @@ static int eval3(char **arg, typval_T *rettv, const int flags) bool first = true; bool result = true; while ((*arg)[0] == '&' && (*arg)[1] == '&') { - const bool evaluate = flags & EVAL_EVALUATE; + evalarg_T nested_evalarg = evalarg == NULL ? (evalarg_T){ 0 } : *evalarg; + const int orig_flags = evalarg == NULL ? 0 : evalarg->eval_flags; + const bool evaluate = orig_flags & EVAL_EVALUATE; if (evaluate && first) { if (tv_get_number_chk(rettv, &error) == 0) { @@ -2428,7 +2455,8 @@ static int eval3(char **arg, typval_T *rettv, const int flags) // Get the second variable. *arg = skipwhite(*arg + 2); - if (eval4(arg, &var2, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) { + nested_evalarg.eval_flags = result ? orig_flags : orig_flags & ~EVAL_EVALUATE; + if (eval4(arg, &var2, &nested_evalarg) == FAIL) { return FAIL; } @@ -2467,7 +2495,7 @@ static int eval3(char **arg, typval_T *rettv, const int flags) /// "arg" is advanced to the next non-white after the recognized expression. /// /// @return OK or FAIL. -static int eval4(char **arg, typval_T *rettv, const int flags) +static int eval4(char **arg, typval_T *rettv, evalarg_T *const evalarg) { typval_T var2; char *p; @@ -2475,7 +2503,7 @@ static int eval4(char **arg, typval_T *rettv, const int flags) int len = 2; // Get the first variable. - if (eval5(arg, rettv, flags) == FAIL) { + if (eval5(arg, rettv, evalarg) == FAIL) { return FAIL; } @@ -2539,11 +2567,11 @@ static int eval4(char **arg, typval_T *rettv, const int flags) // Get the second variable. *arg = skipwhite(p + len); - if (eval5(arg, &var2, flags) == FAIL) { + if (eval5(arg, &var2, evalarg) == FAIL) { tv_clear(rettv); return FAIL; } - if (flags & EVAL_EVALUATE) { + if (evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE)) { const int ret = typval_compare(rettv, &var2, type, ic); tv_clear(&var2); @@ -2597,27 +2625,25 @@ 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, const int flags) +static int eval5(char **arg, typval_T *rettv, evalarg_T *const evalarg) { - typval_T var2; - varnumber_T n1, n2; - float_T f1 = 0, f2 = 0; - char *p; + const bool evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE); // Get the first variable. - if (eval6(arg, rettv, flags, false) == FAIL) { + if (eval6(arg, rettv, evalarg, false) == FAIL) { return FAIL; } // Repeat computing, until no '+', '-' or '.' is following. for (;;) { int op = (uint8_t)(**arg); - if (op != '+' && op != '-' && op != '.') { + bool concat = op == '.'; + if (op != '+' && op != '-' && !concat) { break; } if ((op != '+' || (rettv->v_type != VAR_LIST && rettv->v_type != VAR_BLOB)) - && (op == '.' || rettv->v_type != VAR_FLOAT) && (flags & EVAL_EVALUATE)) { + && (op == '.' || rettv->v_type != VAR_FLOAT) && 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. @@ -2636,12 +2662,13 @@ static int eval5(char **arg, typval_T *rettv, const int flags) (*arg)++; } *arg = skipwhite(*arg + 1); - if (eval6(arg, &var2, flags, op == '.') == FAIL) { + typval_T var2; + if (eval6(arg, &var2, evalarg, op == '.') == FAIL) { tv_clear(rettv); return FAIL; } - if (flags & EVAL_EVALUATE) { + if (evaluate) { // Compute the result. if (op == '.') { char buf1[NUMBUFLEN]; @@ -2654,7 +2681,7 @@ static int eval5(char **arg, typval_T *rettv, const int flags) tv_clear(&var2); return FAIL; } - p = concat_str(s1, s2); + char *p = concat_str(s1, s2); tv_clear(rettv); rettv->v_type = VAR_STRING; rettv->vval.v_string = p; @@ -2666,6 +2693,8 @@ static int eval5(char **arg, typval_T *rettv, const int flags) } } else { bool error = false; + varnumber_T n1, n2; + float_T f1 = 0, f2 = 0; if (rettv->v_type == VAR_FLOAT) { f1 = rettv->vval.v_float; @@ -2738,7 +2767,7 @@ static int eval5(char **arg, typval_T *rettv, const int flags) /// @param[in] want_string True if "." is string_concatenation, otherwise /// float /// @return OK or FAIL. -static int eval6(char **arg, typval_T *rettv, const int flags, bool want_string) +static int eval6(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool want_string) FUNC_ATTR_NO_SANITIZE_UNDEFINED { typval_T var2; @@ -2749,18 +2778,19 @@ static int eval6(char **arg, typval_T *rettv, const int flags, bool want_string) bool error = false; // Get the first variable. - if (eval7(arg, rettv, flags, want_string) == FAIL) { + if (eval7(arg, rettv, evalarg, want_string) == FAIL) { return FAIL; } // Repeat computing, until no '*', '/' or '%' is following. for (;;) { + const bool evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE); op = (uint8_t)(**arg); if (op != '*' && op != '/' && op != '%') { break; } - if (flags & EVAL_EVALUATE) { + if (evaluate) { if (rettv->v_type == VAR_FLOAT) { f1 = rettv->vval.v_float; use_float = true; @@ -2778,11 +2808,11 @@ static int eval6(char **arg, typval_T *rettv, const int flags, bool want_string) // Get the second variable. *arg = skipwhite(*arg + 1); - if (eval7(arg, &var2, flags, false) == FAIL) { + if (eval7(arg, &var2, evalarg, false) == FAIL) { return FAIL; } - if (flags & EVAL_EVALUATE) { + if (evaluate) { if (var2.v_type == VAR_FLOAT) { if (!use_float) { f1 = (float_T)n1; @@ -2869,9 +2899,10 @@ static int eval6(char **arg, typval_T *rettv, const int flags, bool want_string) /// @param want_string after "." operator /// /// @return OK or FAIL. -static int eval7(char **arg, typval_T *rettv, const int flags, bool want_string) +static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool want_string) { - const bool evaluate = flags & EVAL_EVALUATE; + const int flags = evalarg == NULL ? 0 : evalarg->eval_flags; + const bool evaluate = evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE); int ret = OK; static int recurse = 0; @@ -2979,7 +3010,7 @@ static int eval7(char **arg, typval_T *rettv, const int flags, bool want_string) // nested expression: (expression). case '(': *arg = skipwhite(*arg + 1); - ret = eval1(arg, rettv, flags); // recursive! + ret = eval1(arg, rettv, evalarg); // recursive! if (**arg == ')') { (*arg)++; } else if (ret == OK) { @@ -3319,13 +3350,15 @@ static int eval_index(char **arg, typval_T *rettv, const int flags, bool verbose } *arg = skipwhite(key + len); } else { + evalarg_T evalarg = { .eval_flags = flags }; + // something[idx] // // Get the (first) variable from inside the []. *arg = skipwhite(*arg + 1); if (**arg == ':') { empty1 = true; - } else if (eval1(arg, &var1, flags) == FAIL) { // Recursive! + } else if (eval1(arg, &var1, &evalarg) == FAIL) { // Recursive! return FAIL; } else if (evaluate && !tv_check_str(&var1)) { // Not a number or string. @@ -3339,7 +3372,7 @@ static int eval_index(char **arg, typval_T *rettv, const int flags, bool verbose *arg = skipwhite(*arg + 1); if (**arg == ']') { empty2 = true; - } else if (eval1(arg, &var2, flags) == FAIL) { // Recursive! + } else if (eval1(arg, &var2, &evalarg) == FAIL) { // Recursive! if (!empty1) { tv_clear(&var1); } @@ -3947,6 +3980,8 @@ static int get_list_tv(char **arg, typval_T *rettv, const int flags) const bool evaluate = flags & EVAL_EVALUATE; list_T *l = NULL; + evalarg_T evalarg = { .eval_flags = flags }; + if (evaluate) { l = tv_list_alloc(kListLenShouldKnow); } @@ -3954,7 +3989,7 @@ static int get_list_tv(char **arg, typval_T *rettv, const int flags) *arg = skipwhite(*arg + 1); while (**arg != ']' && **arg != NUL) { typval_T tv; - if (eval1(arg, &tv, flags) == FAIL) { // Recursive! + if (eval1(arg, &tv, &evalarg) == FAIL) { // Recursive! goto failret; } if (evaluate) { @@ -4586,7 +4621,9 @@ static int get_literal_key(char **arg, typval_T *tv) } /// Allocate a variable for a Dictionary and fill it from "*arg". -/// "literal" is true for #{key: val} +/// +/// @param literal true for #{key: val} +/// @param flags can have EVAL_EVALUATE and other EVAL_ flags. /// /// @return OK or FAIL. Returns NOTDONE for {expr}. static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal) @@ -4597,6 +4634,8 @@ static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal) char *curly_expr = skipwhite(*arg + 1); char buf[NUMBUFLEN]; + evalarg_T evalarg = { .eval_flags = flags }; + // First check if it's not a curly-braces expression: {expr}. // Must do this without evaluating, otherwise a function may be called // twice. Unfortunately this means we need to call eval1() twice for the @@ -4605,7 +4644,7 @@ static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal) // "#{abc}" is never a curly-braces expression. if (*curly_expr != '}' && !literal - && eval1(&curly_expr, &tv, 0) == OK + && eval1(&curly_expr, &tv, NULL) == OK && *skipwhite(curly_expr) == '}') { return NOTDONE; } @@ -4622,7 +4661,7 @@ static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal) while (**arg != '}' && **arg != NUL) { if ((literal ? get_literal_key(arg, &tvkey) - : eval1(arg, &tvkey, flags)) == FAIL) { // recursive! + : eval1(arg, &tvkey, &evalarg)) == FAIL) { // recursive! goto failret; } if (**arg != ':') { @@ -4640,7 +4679,7 @@ static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal) } *arg = skipwhite(*arg + 1); - if (eval1(arg, &tv, flags) == FAIL) { // Recursive! + if (eval1(arg, &tv, &evalarg) == FAIL) { // Recursive! if (evaluate) { tv_clear(&tvkey); } @@ -6515,15 +6554,14 @@ static char *make_expanded_name(const char *in_start, char *expr_start, char *ex } char *retval = NULL; - char *nextcmd = NULL; *expr_start = NUL; *expr_end = NUL; char c1 = *in_end; *in_end = NUL; - char *temp_result = eval_to_string(expr_start + 1, &nextcmd, false); - if (temp_result != NULL && nextcmd == NULL) { + char *temp_result = eval_to_string(expr_start + 1, false); + if (temp_result != NULL) { retval = xmalloc(strlen(temp_result) + (size_t)(expr_start - in_start) + (size_t)(in_end - expr_end) + 1); STRCPY(retval, in_start); @@ -7389,6 +7427,8 @@ void ex_echo(exarg_T *eap) const int did_emsg_before = did_emsg; const int called_emsg_before = called_emsg; + evalarg_T evalarg = { .eval_flags = eap->skip ? 0 : EVAL_EVALUATE }; + if (eap->skip) { emsg_skip++; } @@ -7399,7 +7439,7 @@ void ex_echo(exarg_T *eap) { char *p = arg; - if (eval1(&arg, &rettv, eap->skip ? 0 : EVAL_EVALUATE) == FAIL) { + if (eval1(&arg, &rettv, &evalarg) == 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 973a4a1fc3..4f517551c6 100644 --- a/src/nvim/eval.h +++ b/src/nvim/eval.h @@ -266,11 +266,26 @@ 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; +/// Struct passed through eval() functions. +/// See EVALARG_EVALUATE for a fixed value with eval_flags set to EVAL_EVALUATE. +typedef struct { + int eval_flags; ///< EVAL_ flag values below + + /// copied from exarg_T when "getline" is "getsourceline". Can be NULL. + void *eval_cookie; // argument for getline() + + /// pointer to the line obtained with getsourceline() + char *eval_tofree; +} evalarg_T; + /// Flag for expression evaluation. enum { EVAL_EVALUATE = 1, ///< when missing don't actually evaluate }; +/// Passed to an eval() function to enable evaluation. +EXTERN evalarg_T EVALARG_EVALUATE INIT(= { EVAL_EVALUATE, NULL, NULL }); + #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 52e38b73ba..887a4857f6 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, EVAL_EVALUATE) == FAIL) { + if (s == NULL || eval1((char **)&s, rettv, &EVALARG_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 f82ab08d2d..fe0249ea3a 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, 0) != FAIL) { + if (eval1(&p, &rettv, NULL) != FAIL) { ga_grow(default_args, 1); // trim trailing whitespace @@ -455,6 +455,8 @@ int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, funcexe_ typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments int argcount = 0; // number of arguments found + evalarg_T evalarg = { .eval_flags = funcexe->fe_evaluate ? EVAL_EVALUATE : 0 }; + // Get the arguments. argp = *arg; while (argcount < MAX_FUNC_ARGS @@ -463,8 +465,7 @@ 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 ? EVAL_EVALUATE : 0) == FAIL) { + if (eval1(&argp, &argvars[argcount], &evalarg) == FAIL) { ret = FAIL; break; } @@ -973,7 +974,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, EVAL_EVALUATE) == FAIL) { + if (eval1(&default_expr, &def_rettv, &EVALARG_EVALUATE) == FAIL) { default_arg_err = true; break; } @@ -1110,7 +1111,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, EVAL_EVALUATE); + (void)eval1(&p, rettv, &EVALARG_EVALUATE); ex_nesting_level--; } else { // call do_cmdline() to execute the lines @@ -2948,13 +2949,15 @@ void ex_return(exarg_T *eap) return; } + evalarg_T evalarg = { .eval_flags = eap->skip ? 0 : EVAL_EVALUATE }; + if (eap->skip) { emsg_skip++; } eap->nextcmd = NULL; if ((*arg != NUL && *arg != '|' && *arg != '\n') - && eval0(arg, &rettv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE) != FAIL) { + && eval0(arg, &rettv, eap, &evalarg) != FAIL) { if (!eap->skip) { returning = do_return(eap, false, true, &rettv); } else { @@ -3005,7 +3008,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, 0) != FAIL) { + if (eval0(eap->arg, &rettv, eap, NULL) != FAIL) { tv_clear(&rettv); } emsg_skip--; diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index a3dc0cfc04..79414acac9 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -185,7 +185,6 @@ void ex_let(exarg_T *eap) char *arg = eap->arg; char *expr = NULL; typval_T rettv; - int i; int var_count = 0; int semicolon = 0; char op[2]; @@ -221,7 +220,10 @@ void ex_let(exarg_T *eap) list_vim_vars(&first); } eap->nextcmd = check_nextcmd(arg); - } else if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<') { + return; + } + + if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<') { // HERE document list_T *l = heredoc_get(eap, expr + 3); if (l != NULL) { @@ -233,39 +235,44 @@ void ex_let(exarg_T *eap) } tv_clear(&rettv); } - } else { - rettv.v_type = VAR_UNKNOWN; - - op[0] = '='; - op[1] = NUL; - if (*expr != '=') { - if (vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL) { - op[0] = *expr; // +=, -=, *=, /=, %= or .= - if (expr[0] == '.' && expr[1] == '.') { // ..= - expr++; - } - } - expr += 2; - } else { - expr += 1; - } + return; + } - expr = skipwhite(expr); + rettv.v_type = VAR_UNKNOWN; - if (eap->skip) { - emsg_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); + op[0] = '='; + op[1] = NUL; + if (*expr != '=') { + if (vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL) { + op[0] = *expr; // +=, -=, *=, /=, %= or .= + if (expr[0] == '.' && expr[1] == '.') { // ..= + expr++; } - emsg_skip--; - } else if (i != FAIL) { - (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, is_const, op); - tv_clear(&rettv); } + expr += 2; + } else { + expr += 1; + } + + expr = skipwhite(expr); + + if (eap->skip) { + emsg_skip++; + } + evalarg_T evalarg = { + .eval_flags = eap->skip ? 0 : EVAL_EVALUATE, + .eval_cookie = eap->getline == getsourceline ? eap->cookie : NULL, + }; + int eval_res = eval0(expr, &rettv, eap, &evalarg); + if (eap->skip) { + emsg_skip--; + } + + if (!eap->skip && eval_res != FAIL) { + (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, is_const, op); + } + if (eval_res != FAIL) { + tv_clear(&rettv); } } diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h index 629aaf14cf..7932649114 100644 --- a/src/nvim/ex_cmds_defs.h +++ b/src/nvim/ex_cmds_defs.h @@ -185,6 +185,7 @@ struct exarg { char *nextcmd; ///< next command (NULL if none) char *cmd; ///< the name of the command (except for :make) char **cmdlinep; ///< pointer to pointer of allocated cmdline + char *cmdline_tofree; ///< free later cmdidx_T cmdidx; ///< the index for the command uint32_t argt; ///< flags for the command int skip; ///< don't execute the command, only parse it diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index fbdb1bc2d7..e8ad472da8 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2328,6 +2328,7 @@ doend: } ex_nesting_level--; + xfree(ea.cmdline_tofree); return ea.nextcmd; } @@ -4432,7 +4433,7 @@ static void ex_colorscheme(exarg_T *eap) char *expr = xstrdup("g:colors_name"); emsg_off++; - char *p = eval_to_string(expr, NULL, false); + char *p = eval_to_string(expr, false); emsg_off--; xfree(expr); diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index 6772b78c33..27f012a4ab 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -792,8 +792,11 @@ void report_discard_pending(int pending, void *value) void ex_eval(exarg_T *eap) { typval_T tv; - - if (eval0(eap->arg, &tv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE) == OK) { + evalarg_T evalarg = { + .eval_flags = eap->skip ? 0 : EVAL_EVALUATE, + .eval_cookie = eap->getline == getsourceline ? eap->cookie : NULL, + }; + if (eval0(eap->arg, &tv, eap, &evalarg) == OK) { tv_clear(&tv); } } @@ -812,7 +815,7 @@ void ex_if(exarg_T *eap) int skip = CHECK_SKIP; bool error; - int result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip); + int result = eval_to_bool(eap->arg, &error, eap, skip); if (!skip && !error) { if (result) { @@ -907,7 +910,7 @@ void ex_else(exarg_T *eap) if (skip && *eap->arg != '"' && ends_excmd(*eap->arg)) { semsg(_(e_invexpr2), eap->arg); } else { - result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip); + result = eval_to_bool(eap->arg, &error, eap, skip); } // When throwing error exceptions, we want to throw always the first @@ -954,7 +957,7 @@ void ex_while(exarg_T *eap) int skip = CHECK_SKIP; if (eap->cmdidx == CMD_while) { // ":while bool-expr" - result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip); + result = eval_to_bool(eap->arg, &error, eap, skip); } else { void *fi; @@ -966,7 +969,7 @@ void ex_while(exarg_T *eap) error = false; } else { // Evaluate the argument and get the info in a structure. - fi = eval_for_line(eap->arg, &error, &eap->nextcmd, skip); + fi = eval_for_line(eap->arg, &error, eap, skip); cstack->cs_forinfo[cstack->cs_idx] = fi; } @@ -1125,12 +1128,11 @@ void ex_endwhile(exarg_T *eap) /// Handle ":throw expr" void ex_throw(exarg_T *eap) { - const char *arg = eap->arg; + char *arg = eap->arg; char *value; if (*arg != NUL && *arg != '|' && *arg != '\n') { - value = eval_to_string_skip(arg, (const char **)&eap->nextcmd, - (bool)eap->skip); + value = eval_to_string_skip(arg, eap, eap->skip); } else { emsg(_(e_argreq)); value = NULL; diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 71984e806d..a0869b54c9 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -1749,7 +1749,8 @@ char *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldinfo curbuf = wp->w_buffer; emsg_silent++; // handle exceptions, but don't display errors - text = eval_to_string_safe(wp->w_p_fdt, NULL, was_set_insecurely(wp, "foldtext", OPT_LOCAL)); + text = eval_to_string_safe(wp->w_p_fdt, + was_set_insecurely(wp, "foldtext", OPT_LOCAL)); emsg_silent--; if (text == NULL || did_emsg) { diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c index 19a2aca75e..c1565a84f5 100644 --- a/src/nvim/mapping.c +++ b/src/nvim/mapping.c @@ -1632,7 +1632,7 @@ char *eval_map_expr(mapblock_T *mp, int c) api_clear_error(&err); } } else { - p = eval_to_string(expr, NULL, false); + p = eval_to_string(expr, false); xfree(expr); } expr_map_lock--; diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 9aacfcad30..b2c0dd6c01 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -763,7 +763,7 @@ char *get_expr_line(void) } nested++; - rv = eval_to_string(expr_copy, NULL, true); + rv = eval_to_string(expr_copy, true); nested--; xfree(expr_copy); return rv; diff --git a/src/nvim/path.c b/src/nvim/path.c index 368f3feb27..8bd3303166 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -1371,7 +1371,7 @@ static int expand_backtick(garray_T *gap, char *pat, int flags) char *cmd = xstrnsave(pat + 1, strlen(pat) - 2); if (*cmd == '=') { // `={expr}`: Expand expression - buffer = eval_to_string(cmd + 1, &p, true); + buffer = eval_to_string(cmd + 1, true); } else { buffer = get_cmd_output(cmd, NULL, (flags & EW_SILENT) ? kShellOptSilent : 0, NULL); } @@ -1662,7 +1662,7 @@ void simplify_filename(char *filename) static char *eval_includeexpr(const char *const ptr, const size_t len) { set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len); - char *res = eval_to_string_safe(curbuf->b_p_inex, NULL, + char *res = eval_to_string_safe(curbuf->b_p_inex, was_set_insecurely(curwin, "includeexpr", OPT_LOCAL)); set_vim_var_string(VV_FNAME, NULL, 0); return res; diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index cfaa3b5781..fdcdd71ceb 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, EVAL_EVALUATE) == FAIL) { + if (eval0(eap->arg, &tv, eap, &EVALARG_EVALUATE) == FAIL) { return; } diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index 94796f0ed3..3ed32bf8af 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -1812,7 +1812,7 @@ static int vim_regsub_both(char *source, typval_T *expr, char *dest, int destlen } tv_clear(&rettv); } else { - eval_result[nested] = eval_to_string(source + 2, NULL, true); + eval_result[nested] = eval_to_string(source + 2, true); } nesting--; diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c index 6c698f45be..05649e9b7f 100644 --- a/src/nvim/statusline.c +++ b/src/nvim/statusline.c @@ -985,7 +985,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n }; set_var(S_LEN("g:statusline_winid"), &tv, false); - usefmt = eval_to_string_safe(fmt + 2, NULL, use_sandbox); + usefmt = eval_to_string_safe(fmt + 2, use_sandbox); if (usefmt == NULL) { usefmt = fmt; } @@ -1457,7 +1457,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n } // Note: The result stored in `t` is unused. - str = eval_to_string_safe(out_p, &t, use_sandbox); + str = eval_to_string_safe(out_p, use_sandbox); curwin = save_curwin; curbuf = save_curbuf; |