From 9ecfb42ec0b8959c291c5c1d28710fe12d3d070f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 12:48:08 +0800 Subject: vim-patch:8.2.1062: Vim9: no line break allowed inside "cond ? val1 : val2" Problem: Vim9: no line break allowed inside "cond ? val1 : val2". Solution: Check for operator after line break. https://github.com/vim/vim/commit/793648fb563359396a23740c72a6e04cb64df3a9 Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a9c5ca46f3..29c294c754 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -2303,7 +2303,8 @@ int eval1(char **arg, typval_T *rettv, evalarg_T *const evalarg) return FAIL; } - if ((*arg)[0] == '?') { + char *p = *arg; + if (*p == '?') { 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; @@ -2329,7 +2330,8 @@ int eval1(char **arg, typval_T *rettv, evalarg_T *const evalarg) } // Check for the ":". - if ((*arg)[0] != ':') { + p = *arg; + if (*p != ':') { emsg(_("E109: Missing ':' after '?'")); if (evaluate && result) { tv_clear(rettv); -- cgit From 9781a21133238060a8b58b9c84d3960d830fa3e9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 12:49:19 +0800 Subject: vim-patch:8.2.1063: Vim9: no line break allowed before || or && Problem: Vim9: no line break allowed before || or &&. Solution: Check for operator after line break. https://github.com/vim/vim/commit/be7ee488761a5582a5605197c3951a17f20d072e Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 29c294c754..bb756fa324 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -2377,7 +2377,8 @@ static int eval2(char **arg, typval_T *rettv, evalarg_T *const evalarg) // Repeat until there is no following "||". bool first = true; bool result = false; - while ((*arg)[0] == '|' && (*arg)[1] == '|') { + char *p = *arg; + while (p[0] == '|' && p[1] == '|') { 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; @@ -2414,6 +2415,8 @@ static int eval2(char **arg, typval_T *rettv, evalarg_T *const evalarg) rettv->v_type = VAR_NUMBER; rettv->vval.v_number = result; } + + p = *arg; } return OK; @@ -2439,7 +2442,8 @@ static int eval3(char **arg, typval_T *rettv, evalarg_T *const evalarg) // Repeat until there is no following "&&". bool first = true; bool result = true; - while ((*arg)[0] == '&' && (*arg)[1] == '&') { + char *p = *arg; + while (p[0] == '&' && p[1] == '&') { 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; @@ -2476,6 +2480,8 @@ static int eval3(char **arg, typval_T *rettv, evalarg_T *const evalarg) rettv->v_type = VAR_NUMBER; rettv->vval.v_number = result; } + + p = *arg; } return OK; -- cgit From 51f99a347d181e16ccd80604f553b4b985991817 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 12:50:56 +0800 Subject: vim-patch:8.2.1064: Vim9: no line break allowed before comperators Problem: Vim9: no line break allowed before comperators. Solution: Check for comperator after line break. https://github.com/vim/vim/commit/e6536aa766e95b6c64489678eb029e6909ee6a35 Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index bb756fa324..0396b01771 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -2506,7 +2506,6 @@ static int eval3(char **arg, typval_T *rettv, evalarg_T *const evalarg) static int eval4(char **arg, typval_T *rettv, evalarg_T *const evalarg) { typval_T var2; - char *p; exprtype_T type = EXPR_UNKNOWN; int len = 2; @@ -2515,7 +2514,7 @@ static int eval4(char **arg, typval_T *rettv, evalarg_T *const evalarg) return FAIL; } - p = *arg; + char *p = *arg; switch (p[0]) { case '=': if (p[1] == '=') { -- cgit From 2af6bbcfa70863df7b6068059f9d504c7894e154 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 12:55:09 +0800 Subject: vim-patch:8.2.1065: Vim9: no line break allowed inside a list Problem: Vim9: no line break allowed inside a list. Solution: Handle line break inside a list in Vim9 script. https://github.com/vim/vim/commit/7147820cb978f5b179cfec2f9d8b7774e28d43e0 Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 0396b01771..8ea78cb5d4 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -2971,7 +2971,7 @@ static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan // List: [expr, expr] case '[': - ret = get_list_tv(arg, rettv, flags); + ret = get_list_tv(arg, rettv, evalarg); break; // Dictionary: #{key: val, key: val} @@ -3981,14 +3981,13 @@ void partial_unref(partial_T *pt) /// Allocate a variable for a List and fill it from "*arg". /// +/// @param arg "*arg" points to the "[". /// @return OK or FAIL. -static int get_list_tv(char **arg, typval_T *rettv, const int flags) +static int get_list_tv(char **arg, typval_T *rettv, evalarg_T *const evalarg) { - const bool evaluate = flags & EVAL_EVALUATE; + const bool evaluate = evalarg == NULL ? false : evalarg->eval_flags & EVAL_EVALUATE; list_T *l = NULL; - evalarg_T evalarg = { .eval_flags = flags }; - if (evaluate) { l = tv_list_alloc(kListLenShouldKnow); } @@ -3996,7 +3995,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, &evalarg) == FAIL) { // Recursive! + if (eval1(arg, &tv, evalarg) == FAIL) { // Recursive! goto failret; } if (evaluate) { @@ -4004,14 +4003,20 @@ static int get_list_tv(char **arg, typval_T *rettv, const int flags) tv_list_append_owned_tv(l, tv); } + // the comma must comma after the value + bool had_comma = **arg == ','; + if (had_comma) { + *arg = skipwhite(*arg + 1); + } + if (**arg == ']') { break; } - if (**arg != ',') { + + if (!had_comma) { semsg(_("E696: Missing comma in List: %s"), *arg); goto failret; } - *arg = skipwhite(*arg + 1); } if (**arg != ']') { -- cgit From 4ce20f722943708ae16a80442e62edf58717901b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 12:59:06 +0800 Subject: vim-patch:8.2.1068: Vim9: no line break allowed inside a dict Problem: Vim9: no line break allowed inside a dict. Solution: Handle line break inside a dict in Vim9 script. https://github.com/vim/vim/commit/8ea9390b78da9e34a20e7418712921397c0c1989 Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 8ea78cb5d4..1bc343f7de 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -2978,7 +2978,7 @@ static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan case '#': if ((*arg)[1] == '{') { (*arg)++; - ret = eval_dict(arg, rettv, flags, true); + ret = eval_dict(arg, rettv, evalarg, true); } else { ret = NOTDONE; } @@ -2989,7 +2989,7 @@ static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan case '{': ret = get_lambda_tv(arg, rettv, evaluate); if (ret == NOTDONE) { - ret = eval_dict(arg, rettv, flags, false); + ret = eval_dict(arg, rettv, evalarg, false); } break; @@ -4638,16 +4638,14 @@ static int get_literal_key(char **arg, typval_T *tv) /// @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) +static int eval_dict(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool literal) { - const bool evaluate = flags & EVAL_EVALUATE; + const bool evaluate = evalarg == NULL ? false : evalarg->eval_flags & EVAL_EVALUATE; typval_T tv; char *key = NULL; 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 @@ -4673,7 +4671,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, &evalarg)) == FAIL) { // recursive! + : eval1(arg, &tvkey, evalarg)) == FAIL) { // recursive! goto failret; } if (**arg != ':') { @@ -4691,7 +4689,7 @@ static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal) } *arg = skipwhite(*arg + 1); - if (eval1(arg, &tv, &evalarg) == FAIL) { // Recursive! + if (eval1(arg, &tv, evalarg) == FAIL) { // Recursive! if (evaluate) { tv_clear(&tvkey); } @@ -4714,14 +4712,19 @@ static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal) } tv_clear(&tvkey); + // the comma must come after the value + bool had_comma = **arg == ','; + if (had_comma) { + *arg = skipwhite(*arg + 1); + } + if (**arg == '}') { break; } - if (**arg != ',') { + if (!had_comma) { semsg(_("E722: Missing comma in Dictionary: %s"), *arg); goto failret; } - *arg = skipwhite(*arg + 1); } if (**arg != '}') { -- cgit From 89ff05b258f9d5663b4659e9023ff83004021ce6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 13:01:50 +0800 Subject: vim-patch:8.2.1069: Vim9: fail to check for white space in list Problem: Vim9: fail to check for white space in list. Solution: Add check for white space. https://github.com/vim/vim/commit/e6e031739c9d0c4140e371031b58a249db0eb572 N/A patches for version.c: vim-patch:8.2.1070: Vim9: leaking memory when lacking white space in dict Problem: Vim9: leaking memory when lacking white space in dict. Solution: Clear the typval. https://github.com/vim/vim/commit/ab19d495fd880b25a38d58cbeb5b21e4d0ee5835 Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 1bc343f7de..39ca70ae93 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -4003,7 +4003,7 @@ static int get_list_tv(char **arg, typval_T *rettv, evalarg_T *const evalarg) tv_list_append_owned_tv(l, tv); } - // the comma must comma after the value + // the comma must come after the value bool had_comma = **arg == ','; if (had_comma) { *arg = skipwhite(*arg + 1); -- cgit From d927128fccad1c234e4b87321ff0d6392b9d69d5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 13:03:04 +0800 Subject: vim-patch:8.2.1071: Vim9: no line break allowed inside a lambda Problem: Vim9: no line break allowed inside a lambda. Solution: Handle line break inside a lambda in Vim9 script. https://github.com/vim/vim/commit/e40fbc2ca9fda07332a4da5af1fcaba91bed865b Omit skip_expr_concatenate(). Apply the change to skip_expr() instead. Omit eval_ga: Vim9 script only. Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 72 +++++++++++++++++++++++++----------------------- src/nvim/eval/userfunc.c | 17 +++++++++--- src/nvim/eval/userfunc.h | 1 + src/nvim/eval/vars.c | 5 ++-- src/nvim/ex_docmd.c | 4 +-- src/nvim/os/env.c | 2 +- 6 files changed, 58 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 39ca70ae93..d5dd8407a1 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -847,12 +847,24 @@ char *eval_to_string_skip(char *arg, exarg_T *eap, const bool skip) /// Skip over an expression at "*pp". /// /// @return FAIL for an error, OK otherwise. -int skip_expr(char **pp) +int skip_expr(char **pp, evalarg_T *const evalarg) { - typval_T rettv; + const int save_flags = evalarg == NULL ? 0 : evalarg->eval_flags; + + // Don't evaluate the expression. + if (evalarg != NULL) { + evalarg->eval_flags &= ~EVAL_EVALUATE; + } *pp = skipwhite(*pp); - return eval1(pp, &rettv, NULL); + typval_T rettv; + int res = eval1(pp, &rettv, NULL); + + if (evalarg != NULL) { + evalarg->eval_flags = save_flags; + } + + return res; } /// Top level evaluation function, returning a string. @@ -2236,9 +2248,6 @@ int eval0(char *arg, typval_T *rettv, exarg_T *eap, evalarg_T *const evalarg) 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, evalarg); @@ -2269,19 +2278,14 @@ int eval0(char *arg, typval_T *rettv, exarg_T *eap, evalarg_T *const evalarg) 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); - } + if (evalarg != NULL && eap != NULL && 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; + evalarg->eval_tofree = NULL; } return ret; @@ -2987,7 +2991,7 @@ static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan // Lambda: {arg, arg -> expr} // Dictionary: {'key': val, 'key': val} case '{': - ret = get_lambda_tv(arg, rettv, evaluate); + ret = get_lambda_tv(arg, rettv, evalarg); if (ret == NOTDONE) { ret = eval_dict(arg, rettv, evalarg, false); } @@ -3062,7 +3066,7 @@ static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan // Handle following '[', '(' and '.' for expr[expr], expr.name, // expr(expr), expr->name(expr) if (ret == OK) { - ret = handle_subscript((const char **)arg, rettv, flags, true); + ret = handle_subscript((const char **)arg, rettv, evalarg, true); } // Apply logical NOT and unary '-', from right to left, ignore '+'. @@ -3192,16 +3196,17 @@ static int call_func_rettv(char **const arg, typval_T *const rettv, const bool e /// @return FAIL or OK. /// /// @note "*arg" is advanced to after the ')'. -static int eval_lambda(char **const arg, typval_T *const rettv, const bool evaluate, +static int eval_lambda(char **const arg, typval_T *const rettv, evalarg_T *const evalarg, const bool verbose) - FUNC_ATTR_NONNULL_ALL + FUNC_ATTR_NONNULL_ARG(1, 2) { + const bool evaluate = evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE); // Skip over the ->. *arg += 2; typval_T base = *rettv; rettv->v_type = VAR_UNKNOWN; - int ret = get_lambda_tv(arg, rettv, evaluate); + int ret = get_lambda_tv(arg, rettv, evalarg); if (ret != OK) { return FAIL; } else if (**arg != '(') { @@ -3306,9 +3311,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, const int flags, bool verbose) +static int eval_index(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool verbose) { - const bool evaluate = flags & EVAL_EVALUATE; + const bool evaluate = evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE); bool empty1 = false; bool empty2 = false; ptrdiff_t len = -1; @@ -3357,15 +3362,13 @@ 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, &evalarg) == FAIL) { // Recursive! + } else if (eval1(arg, &var1, evalarg) == FAIL) { // Recursive! return FAIL; } else if (evaluate && !tv_check_str(&var1)) { // Not a number or string. @@ -3379,7 +3382,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, &evalarg) == FAIL) { // Recursive! + } else if (eval1(arg, &var2, evalarg) == FAIL) { // Recursive! if (!empty1) { tv_clear(&var1); } @@ -7007,9 +7010,10 @@ int check_luafunc_name(const char *const str, const bool paren) /// @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, const int flags, bool verbose) +int handle_subscript(const char **const arg, typval_T *rettv, evalarg_T *const evalarg, + bool verbose) { - const bool evaluate = flags & EVAL_EVALUATE; + const bool evaluate = evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE); int ret = OK; dict_T *selfdict = NULL; const char *lua_funcname = NULL; @@ -7054,7 +7058,7 @@ int handle_subscript(const char **const arg, typval_T *rettv, const int flags, b } else if (**arg == '-') { if ((*arg)[2] == '{') { // expr->{lambda}() - ret = eval_lambda((char **)arg, rettv, evaluate, verbose); + ret = eval_lambda((char **)arg, rettv, evalarg, verbose); } else { // expr->name() ret = eval_method((char **)arg, rettv, evaluate, verbose); @@ -7069,7 +7073,7 @@ int handle_subscript(const char **const arg, typval_T *rettv, const int flags, b } else { selfdict = NULL; } - if (eval_index((char **)arg, rettv, flags, verbose) == FAIL) { + if (eval_index((char **)arg, rettv, evalarg, verbose) == FAIL) { tv_clear(rettv); ret = FAIL; } diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index fe0249ea3a..b1cb53fec2 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -252,8 +252,9 @@ static void set_ufunc_name(ufunc_T *fp, char *name) /// Parse a lambda expression and get a Funcref from "*arg". /// /// @return OK or FAIL. Returns NOTDONE for dict or {expr}. -int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate) +int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg) { + const bool evaluate = evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE); garray_T newargs = GA_EMPTY_INIT_VALUE; garray_T *pnewargs; ufunc_T *fp = NULL; @@ -264,6 +265,7 @@ int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate) char *s, *e; bool *old_eval_lavars = eval_lavars_used; bool eval_lavars = false; + char *tofree = NULL; // First, check if this is a lambda expression. "->" must exists. ret = get_function_args(&start, '-', NULL, NULL, NULL, true); @@ -291,10 +293,16 @@ int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate) // Get the start and the end of the expression. *arg = skipwhite((*arg) + 1); s = *arg; - ret = skip_expr(arg); + ret = skip_expr(arg, evalarg); if (ret == FAIL) { goto errret; } + if (evalarg != NULL) { + // avoid that the expression gets freed when another line break follows + tofree = evalarg->eval_tofree; + evalarg->eval_tofree = NULL; + } + e = *arg; *arg = skipwhite(*arg); if (**arg != '}') { @@ -359,12 +367,14 @@ int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate) } eval_lavars_used = old_eval_lavars; + xfree(tofree); return OK; errret: ga_clear_strings(&newargs); xfree(fp); xfree(pt); + xfree(tofree); eval_lavars_used = old_eval_lavars; return FAIL; } @@ -3075,8 +3085,7 @@ void ex_call(exarg_T *eap) } // Handle a function returning a Funcref, Dictionary or List. - if (handle_subscript((const char **)&arg, &rettv, EVAL_EVALUATE, true) - == FAIL) { + if (handle_subscript((const char **)&arg, &rettv, &EVALARG_EVALUATE, true) == FAIL) { failed = true; break; } diff --git a/src/nvim/eval/userfunc.h b/src/nvim/eval/userfunc.h index c8583f232c..f0e1f5dca0 100644 --- a/src/nvim/eval/userfunc.h +++ b/src/nvim/eval/userfunc.h @@ -4,6 +4,7 @@ #include #include +#include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds_defs.h" diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index 79414acac9..c566129202 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -267,6 +267,7 @@ void ex_let(exarg_T *eap) if (eap->skip) { emsg_skip--; } + xfree(evalarg.eval_tofree); if (!eap->skip && eval_res != FAIL) { (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, is_const, op); @@ -510,7 +511,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, EVAL_EVALUATE, true) == FAIL) { + if (handle_subscript(&arg, &tv, &EVALARG_EVALUATE, true) == FAIL) { error = true; } else { if (arg == arg_subsc && len == 2 && name[1] == ':') { @@ -1717,7 +1718,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, EVAL_EVALUATE, false) == OK; + n = handle_subscript(&var, &tv, &EVALARG_EVALUATE, false) == OK; if (n) { tv_clear(&tv); } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index e8ad472da8..f9f4a2514f 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -3751,7 +3751,7 @@ int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp) // Skip over `=expr`, wildcards in it are not expanded. if (p[0] == '`' && p[1] == '=') { p += 2; - (void)skip_expr(&p); + (void)skip_expr(&p, NULL); if (*p == '`') { p++; } @@ -3970,7 +3970,7 @@ void separate_nextcmd(exarg_T *eap) } else if (p[0] == '`' && p[1] == '=' && (eap->argt & EX_XFILE)) { // Skip over `=expr` when wildcards are expanded. p += 2; - (void)skip_expr(&p); + (void)skip_expr(&p, NULL); if (*p == NUL) { // stop at NUL after CTRL-V break; } diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 0b06877f3c..26707fd6ca 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -603,7 +603,7 @@ void expand_env_esc(char *restrict srcp, char *restrict dst, int dstlen, bool es if (src[0] == '`' && src[1] == '=') { var = src; src += 2; - (void)skip_expr(&src); + (void)skip_expr(&src, NULL); if (*src == '`') { src++; } -- cgit From 9c29c07705101b0117ea23e22ac3e5bb24e8c6c5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 13:24:05 +0800 Subject: vim-patch:8.2.1073: Vim9: no line break allowed in () expression Problem: Vim9: no line break allowed in () expression. Solution: Skip a line break. https://github.com/vim/vim/commit/7a4981b93642b5b62018cd8150b3fb0dfa2417d4 Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index d5dd8407a1..5c0083bf7d 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -3021,7 +3021,9 @@ static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan // nested expression: (expression). case '(': *arg = skipwhite(*arg + 1); + ret = eval1(arg, rettv, evalarg); // recursive! + if (**arg == ')') { (*arg)++; } else if (ret == OK) { -- cgit From 10b8c6481fdf1f6a5d16ac89462c806b12114d1f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 13:25:34 +0800 Subject: vim-patch:8.2.1074: Vim9: no line break allowed after some operators Problem: Vim9: no line break allowed after some operators. Solution: Skip a line break after the operator. Add eval_may_get_next_line() to simplify checking for a line break. https://github.com/vim/vim/commit/9215f01218b2ed2cfe49c1f43fcf342bd9ffdded Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 5c0083bf7d..b07ff2972e 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -3023,7 +3023,6 @@ static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan *arg = skipwhite(*arg + 1); ret = eval1(arg, rettv, evalarg); // recursive! - if (**arg == ')') { (*arg)++; } else if (ret == OK) { -- cgit From 64a91f5ea2424674b0f2550e33f3f8512af75231 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 13:31:41 +0800 Subject: vim-patch:8.2.1075: Vim9: no line break allowed in :echo expression Problem: Vim9: no line break allowed in :echo expression. Solution: Skip linebreak. https://github.com/vim/vim/commit/7e8967fdcdf45caf08753bb791dc3779e78b34c8 Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index b07ff2972e..16db4e791b 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -7447,7 +7447,10 @@ 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 }; + evalarg_T evalarg = { + .eval_flags = eap->skip ? 0 : EVAL_EVALUATE, + .eval_cookie = eap->getline == getsourceline ? eap->cookie : NULL, + }; if (eap->skip) { emsg_skip++; -- cgit From e99f28e57d69cfa1bd38ab531a0954f4f875ca47 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 13:32:47 +0800 Subject: vim-patch:8.2.1076: Vim9: no line break allowed in :if expression Problem: Vim9: no line break allowed in :if expression. Solution: Skip linebreak. https://github.com/vim/vim/commit/faf8626b79e380fe81e7ae2439a535ed7619d27b Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 33 +++++++++++++++++++++++---------- src/nvim/eval/vars.c | 2 +- 2 files changed, 24 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 16db4e791b..a79a464860 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -703,10 +703,15 @@ int eval_to_bool(char *arg, bool *error, exarg_T *eap, int skip) typval_T tv; bool retval = false; + evalarg_T evalarg = { + .eval_flags = skip ? 0 : EVAL_EVALUATE, + .eval_cookie = eap != NULL && eap->getline == getsourceline ? eap->cookie : NULL, + }; + if (skip) { emsg_skip++; } - if (eval0(arg, &tv, eap, skip ? NULL : &EVALARG_EVALUATE) == FAIL) { + if (eval0(arg, &tv, eap, &evalarg) == FAIL) { *error = true; } else { *error = false; @@ -718,6 +723,7 @@ int eval_to_bool(char *arg, bool *error, exarg_T *eap, int skip) if (skip) { emsg_skip--; } + clear_evalarg(&evalarg, eap); return retval; } @@ -2228,6 +2234,20 @@ static int eval_func(char **const arg, char *const name, const int name_len, typ return ret; } +/// After using "evalarg" filled from "eap" free the memory. +void clear_evalarg(evalarg_T *evalarg, exarg_T *eap) +{ + if (evalarg != NULL && eap != NULL && 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; + evalarg->eval_tofree = NULL; + } +} + /// The "evaluate" argument: When false, the argument is only parsed but not /// executed. The function may return OK, but the rettv will be of type /// VAR_UNKNOWN. The function still returns FAIL for a syntax error. @@ -2278,15 +2298,7 @@ int eval0(char *arg, typval_T *rettv, exarg_T *eap, evalarg_T *const evalarg) eap->nextcmd = check_nextcmd(p); } - if (evalarg != NULL && eap != NULL && 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; - evalarg->eval_tofree = NULL; - } + clear_evalarg(evalarg, eap); return ret; } @@ -7502,6 +7514,7 @@ void ex_echo(exarg_T *eap) arg = skipwhite(arg); } eap->nextcmd = check_nextcmd(arg); + clear_evalarg(&evalarg, eap); if (eap->skip) { emsg_skip--; diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index c566129202..868d03a115 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -267,7 +267,7 @@ void ex_let(exarg_T *eap) if (eap->skip) { emsg_skip--; } - xfree(evalarg.eval_tofree); + clear_evalarg(&evalarg, eap); if (!eap->skip && eval_res != FAIL) { (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, is_const, op); -- cgit From 4b84b2e2aa3d7ab6a4e346c7439826700682f5f1 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 13:38:14 +0800 Subject: vim-patch:8.2.1079: Vim9: no line break allowed in a while loop Problem: Vim9: no line break allowed in a while loop. Solution: Update stored loop lines when finding line breaks. https://github.com/vim/vim/commit/d5053d015a957b343ad9c9e45e0abd2978f10cf0 Omit getline_peek(): Vim9 script only. Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 10 ++++++++-- src/nvim/eval.h | 5 +++-- src/nvim/eval/vars.c | 5 ++++- src/nvim/ex_docmd.c | 56 ++++++++++++++++++++++++++++------------------------ 4 files changed, 45 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a79a464860..e5193cdfb8 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -705,8 +705,11 @@ int eval_to_bool(char *arg, bool *error, exarg_T *eap, int skip) evalarg_T evalarg = { .eval_flags = skip ? 0 : EVAL_EVALUATE, - .eval_cookie = eap != NULL && eap->getline == getsourceline ? eap->cookie : NULL, }; + if (eap != NULL && getline_equal(eap->getline, eap->cookie, getsourceline)) { + evalarg.eval_getline = eap->getline; + evalarg.eval_cookie = eap->cookie; + } if (skip) { emsg_skip++; @@ -7461,8 +7464,11 @@ void ex_echo(exarg_T *eap) evalarg_T evalarg = { .eval_flags = eap->skip ? 0 : EVAL_EVALUATE, - .eval_cookie = eap->getline == getsourceline ? eap->cookie : NULL, }; + if (getline_equal(eap->getline, eap->cookie, getsourceline)) { + evalarg.eval_getline = eap->getline; + evalarg.eval_cookie = eap->cookie; + } if (eap->skip) { emsg_skip++; diff --git a/src/nvim/eval.h b/src/nvim/eval.h index 4f517551c6..4e0eb6ebb8 100644 --- a/src/nvim/eval.h +++ b/src/nvim/eval.h @@ -272,7 +272,8 @@ 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() + LineGetter eval_getline; + void *eval_cookie; ///< argument for eval_getline() /// pointer to the line obtained with getsourceline() char *eval_tofree; @@ -284,7 +285,7 @@ enum { }; /// Passed to an eval() function to enable evaluation. -EXTERN evalarg_T EVALARG_EVALUATE INIT(= { EVAL_EVALUATE, NULL, NULL }); +EXTERN evalarg_T EVALARG_EVALUATE INIT(= { EVAL_EVALUATE, NULL, NULL, NULL }); #ifdef INCLUDE_GENERATED_DECLARATIONS # include "eval.h.generated.h" diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index 868d03a115..4bce555d75 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -261,8 +261,11 @@ void ex_let(exarg_T *eap) } evalarg_T evalarg = { .eval_flags = eap->skip ? 0 : EVAL_EVALUATE, - .eval_cookie = eap->getline == getsourceline ? eap->cookie : NULL, }; + if (getline_equal(eap->getline, eap->cookie, getsourceline)) { + evalarg.eval_getline = eap->getline; + evalarg.eval_cookie = eap->cookie; + } int eval_res = eval0(expr, &rettv, eap, &evalarg); if (eap->skip) { emsg_skip--; diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index f9f4a2514f..8e55672615 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -484,24 +484,6 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) } } - if (cstack.cs_looplevel > 0) { - // Inside a while/for loop we need to store the lines and use them - // again. Pass a different "fgetline" function to do_one_cmd() - // below, so that it stores lines in or reads them from - // "lines_ga". Makes it possible to define a function inside a - // while/for loop. - cmd_getline = get_loop_line; - cmd_cookie = (void *)&cmd_loop_cookie; - cmd_loop_cookie.lines_gap = &lines_ga; - cmd_loop_cookie.current_line = current_line; - cmd_loop_cookie.getline = fgetline; - cmd_loop_cookie.cookie = cookie; - cmd_loop_cookie.repeating = (current_line < lines_ga.ga_len); - } else { - cmd_getline = fgetline; - cmd_cookie = cookie; - } - // 2. If no line given, get an allocated line with fgetline(). if (next_cmdline == NULL) { // Need to set msg_didout for the first line after an ":if", @@ -540,15 +522,37 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) } cmdline_copy = next_cmdline; - // Save the current line when inside a ":while" or ":for", and when - // the command looks like a ":while" or ":for", because we may need it - // later. When there is a '|' and another command, it is stored - // separately, because we need to be able to jump back to it from an + int current_line_before = 0; + // Inside a while/for loop, and when the command looks like a ":while" + // or ":for", the line is stored, because we may need it later when + // looping. + // + // When there is a '|' and another command, it is stored separately, + // because we need to be able to jump back to it from an // :endwhile/:endfor. - if (current_line == lines_ga.ga_len - && (cstack.cs_looplevel || has_loop_cmd(next_cmdline))) { - store_loop_line(&lines_ga, next_cmdline); + // + // Pass a different "fgetline" function to do_one_cmd() below, + // that it stores lines in or reads them from "lines_ga". Makes it + // possible to define a function inside a while/for loop. + if ((cstack.cs_looplevel > 0 || has_loop_cmd(next_cmdline))) { + cmd_getline = get_loop_line; + cmd_cookie = (void *)&cmd_loop_cookie; + cmd_loop_cookie.lines_gap = &lines_ga; + cmd_loop_cookie.current_line = current_line; + cmd_loop_cookie.getline = fgetline; + cmd_loop_cookie.cookie = cookie; + cmd_loop_cookie.repeating = (current_line < lines_ga.ga_len); + + // Save the current line when encountering it the first time. + if (current_line == lines_ga.ga_len) { + store_loop_line(&lines_ga, next_cmdline); + } + current_line_before = current_line; + } else { + cmd_getline = fgetline; + cmd_cookie = cookie; } + did_endif = false; if (count++ == 0) { @@ -651,7 +655,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) } else if (cstack.cs_lflags & CSL_HAD_LOOP) { // For a ":while" or ":for" we need to remember the line number. cstack.cs_lflags &= ~CSL_HAD_LOOP; - cstack.cs_line[cstack.cs_idx] = current_line - 1; + cstack.cs_line[cstack.cs_idx] = current_line_before; } } -- cgit From 8729c41f44de3b164ad8d01bb3558c6400e27952 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 13:49:28 +0800 Subject: vim-patch:8.2.1080: Vim9: no line break allowed in a for loop Problem: Vim9: no line break allowed in a for loop. Solution: Skip line breaks in for command. https://github.com/vim/vim/commit/b7a78f7a6713f07d2fcad0b27dea22925c7b1cdf Omit *_break_count and skip_for_lines(): Vim9 script only. Co-authored-by: Bram Moolenaar --- src/nvim/api/vimscript.c | 2 ++ src/nvim/debugger.c | 2 +- src/nvim/eval.c | 38 +++++++++++++++++++++++--------------- src/nvim/eval/userfunc.c | 1 + src/nvim/ex_eval.c | 19 +++++++++++++++++-- src/nvim/option.c | 2 +- src/nvim/quickfix.c | 12 ++++++------ 7 files changed, 51 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index d2e18f08f3..208aa165c9 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -173,6 +173,7 @@ Object nvim_eval(String expr, Error *err) TRY_WRAP(err, { ok = eval0(expr.data, &rettv, NULL, &EVALARG_EVALUATE); + clear_evalarg(&EVALARG_EVALUATE, NULL); }); if (!ERROR_SET(err)) { @@ -294,6 +295,7 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err) api_set_error(err, kErrorTypeException, "Failed to evaluate dict expression"); } + clear_evalarg(&EVALARG_EVALUATE, NULL); if (try_end(err)) { return rv; } diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c index 3c9a63f5a3..90723372a9 100644 --- a/src/nvim/debugger.c +++ b/src/nvim/debugger.c @@ -494,7 +494,7 @@ static typval_T *eval_expr_no_emsg(struct debuggy *const bp) { // Disable error messages, a bad expression would make Vim unusable. emsg_off++; - typval_T *const tv = eval_expr(bp->dbg_name); + typval_T *const tv = eval_expr(bp->dbg_name, NULL); emsg_off--; return tv; } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index e5193cdfb8..0880fed71e 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -849,6 +849,7 @@ char *eval_to_string_skip(char *arg, exarg_T *eap, const bool skip) if (skip) { emsg_skip--; } + clear_evalarg(&EVALARG_EVALUATE, eap); return retval; } @@ -910,6 +911,7 @@ char *eval_to_string(char *arg, bool convert) } tv_clear(&tv); } + clear_evalarg(&EVALARG_EVALUATE, NULL); return retval; } @@ -964,12 +966,13 @@ varnumber_T eval_to_number(char *expr) /// /// @return an allocated typval_T with the result or /// NULL when there is an error. -typval_T *eval_expr(char *arg) +typval_T *eval_expr(char *arg, exarg_T *eap) { typval_T *tv = xmalloc(sizeof(*tv)); - if (eval0(arg, tv, NULL, &EVALARG_EVALUATE) == FAIL) { + if (eval0(arg, tv, eap, &EVALARG_EVALUATE) == FAIL) { XFREE_CLEAR(tv); } + clear_evalarg(&EVALARG_EVALUATE, eap); return tv; } @@ -1215,6 +1218,7 @@ int eval_foldexpr(char *arg, int *cp) sandbox--; } textlock--; + clear_evalarg(&EVALARG_EVALUATE, NULL); return (int)retval; } @@ -1797,14 +1801,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, exarg_T *eap, int skip) +void *eval_for_line(const char *arg, bool *errp, exarg_T *eap, evalarg_T *const evalarg) { forinfo_T *fi = xcalloc(1, sizeof(forinfo_T)); const char *expr; typval_T tv; list_T *l; + const bool skip = !(evalarg->eval_flags & EVAL_EVALUATE); - 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); @@ -1813,7 +1817,8 @@ void *eval_for_line(const char *arg, bool *errp, exarg_T *eap, int skip) } expr = skipwhite(expr); - if (expr[0] != 'i' || expr[1] != 'n' || !ascii_iswhite(expr[2])) { + if (expr[0] != 'i' || expr[1] != 'n' + || !(expr[2] == NUL || ascii_iswhite(expr[2]))) { emsg(_("E690: Missing \"in\" after :for")); return fi; } @@ -1821,7 +1826,8 @@ void *eval_for_line(const char *arg, bool *errp, exarg_T *eap, int skip) if (skip) { emsg_skip++; } - if (eval0(skipwhite(expr + 2), &tv, eap, &evalarg) == OK) { + expr = skipwhite(expr + 2); + if (eval0((char *)expr, &tv, eap, evalarg) == OK) { *errp = false; if (!skip) { if (tv.v_type == VAR_LIST) { @@ -2240,13 +2246,17 @@ static int eval_func(char **const arg, char *const name, const int name_len, typ /// After using "evalarg" filled from "eap" free the memory. void clear_evalarg(evalarg_T *evalarg, exarg_T *eap) { - if (evalarg != NULL && eap != NULL && 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; + if (evalarg != NULL && evalarg->eval_tofree != NULL) { + if (eap != 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); + } evalarg->eval_tofree = NULL; } } @@ -2301,8 +2311,6 @@ int eval0(char *arg, typval_T *rettv, exarg_T *eap, evalarg_T *const evalarg) eap->nextcmd = check_nextcmd(p); } - clear_evalarg(evalarg, eap); - return ret; } diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index b1cb53fec2..1f25b7fb36 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -2996,6 +2996,7 @@ void ex_return(exarg_T *eap) if (eap->skip) { emsg_skip--; } + clear_evalarg(&evalarg, eap); } /// ":1,25call func(arg1, arg2)" function call. diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index 27f012a4ab..34015728b0 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -794,11 +794,17 @@ void ex_eval(exarg_T *eap) typval_T tv; evalarg_T evalarg = { .eval_flags = eap->skip ? 0 : EVAL_EVALUATE, - .eval_cookie = eap->getline == getsourceline ? eap->cookie : NULL, }; + if (getline_equal(eap->getline, eap->cookie, getsourceline)) { + evalarg.eval_getline = eap->getline; + evalarg.eval_cookie = eap->cookie; + } + if (eval0(eap->arg, &tv, eap, &evalarg) == OK) { tv_clear(&tv); } + + clear_evalarg(&evalarg, eap); } /// Handle ":if". @@ -961,6 +967,14 @@ void ex_while(exarg_T *eap) } else { void *fi; + evalarg_T evalarg = { + .eval_flags = eap->skip ? 0 : EVAL_EVALUATE, + }; + if (getline_equal(eap->getline, eap->cookie, getsourceline)) { + evalarg.eval_getline = eap->getline; + evalarg.eval_cookie = eap->cookie; + } + // ":for var in list-expr" if ((cstack->cs_lflags & CSL_HAD_LOOP) != 0) { // Jumping here from a ":continue" or ":endfor": use the @@ -969,7 +983,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, skip); + fi = eval_for_line(eap->arg, &error, eap, &evalarg); cstack->cs_forinfo[cstack->cs_idx] = fi; } @@ -984,6 +998,7 @@ void ex_while(exarg_T *eap) free_for_info(fi); cstack->cs_forinfo[cstack->cs_idx] = NULL; } + clear_evalarg(&evalarg, eap); } // If this cstack entry was just initialised and is active, set the diff --git a/src/nvim/option.c b/src/nvim/option.c index 386c6d88d9..6d4e7de1a3 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -5266,7 +5266,7 @@ int option_set_callback_func(char *optval, Callback *optcb) || (strncmp(optval, "function(", 9) == 0) || (strncmp(optval, "funcref(", 8) == 0)) { // Lambda expression or a funcref - tv = eval_expr(optval); + tv = eval_expr(optval, NULL); if (tv == NULL) { return FAIL; } diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index fdcdd71ceb..62eb14342c 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -6957,15 +6957,15 @@ 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, &EVALARG_EVALUATE) == FAIL) { + typval_T *tv = eval_expr(eap->arg, eap); + if (tv == NULL) { return; } - if ((tv.v_type == VAR_STRING && tv.vval.v_string != NULL) - || tv.v_type == VAR_LIST) { + if ((tv->v_type == VAR_STRING && tv->vval.v_string != NULL) + || tv->v_type == VAR_LIST) { incr_quickfix_busy(); - int res = qf_init_ext(qi, qi->qf_curlist, NULL, NULL, &tv, p_efm, + int res = qf_init_ext(qi, qi->qf_curlist, NULL, NULL, tv, p_efm, (eap->cmdidx != CMD_caddexpr && eap->cmdidx != CMD_laddexpr), (linenr_T)0, (linenr_T)0, @@ -6996,7 +6996,7 @@ void ex_cexpr(exarg_T *eap) emsg(_("E777: String or List expected")); } cleanup: - tv_clear(&tv); + tv_free(tv); } // Get the location list for ":lhelpgrep" -- cgit From ff963d699bd8113913d3511c7b4ea1621eae8a06 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 14:11:24 +0800 Subject: vim-patch:8.2.1098: Vim9: cannot use line break in :throw argument Problem: Vim9: cannot use line break in :throw argument. Solution: Check for line break. https://github.com/vim/vim/commit/006ad48b8a15c3bace741d8caaf3195e592fbe78 Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 0880fed71e..1a2268504c 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -837,10 +837,17 @@ char *eval_to_string_skip(char *arg, exarg_T *eap, const bool skip) typval_T tv; char *retval; + evalarg_T evalarg = { + .eval_flags = skip ? 0 : EVAL_EVALUATE, + }; + if (eap != NULL && getline_equal(eap->getline, eap->cookie, getsourceline)) { + evalarg.eval_getline = eap->getline; + evalarg.eval_cookie = eap->cookie; + } if (skip) { emsg_skip++; } - if (eval0(arg, &tv, eap, skip ? NULL : &EVALARG_EVALUATE) == FAIL || skip) { + if (eval0(arg, &tv, eap, &evalarg) == FAIL || skip) { retval = NULL; } else { retval = xstrdup(tv_get_string(&tv)); @@ -849,7 +856,7 @@ char *eval_to_string_skip(char *arg, exarg_T *eap, const bool skip) if (skip) { emsg_skip--; } - clear_evalarg(&EVALARG_EVALUATE, eap); + clear_evalarg(&evalarg, eap); return retval; } -- cgit From 78dd6100b1b00e4a30d389fccc3c7770132e91a4 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 14:13:12 +0800 Subject: vim-patch:8.2.1099: Vim9: cannot use line break in :cexpr argument Problem: Vim9: cannot use line break in :cexpr argument. Solution: Check for line break. https://github.com/vim/vim/commit/37c837119579ff70b005a4e54c2e26ca42b74022 Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 1a2268504c..5944cebf4c 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -692,6 +692,15 @@ void eval_patch(const char *const origfile, const char *const difffile, const ch set_vim_var_string(VV_FNAME_OUT, NULL, -1); } +static void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, bool skip) +{ + *evalarg = (evalarg_T){ .eval_flags = skip ? 0 : EVAL_EVALUATE }; + if (eap != NULL && getline_equal(eap->getline, eap->cookie, getsourceline)) { + evalarg->eval_getline = eap->getline; + evalarg->eval_cookie = eap->cookie; + } +} + /// Top level evaluation function, returning a boolean. /// Sets "error" to true if there was an error. /// @@ -702,14 +711,9 @@ int eval_to_bool(char *arg, bool *error, exarg_T *eap, int skip) { typval_T tv; bool retval = false; + evalarg_T evalarg; - evalarg_T evalarg = { - .eval_flags = skip ? 0 : EVAL_EVALUATE, - }; - if (eap != NULL && getline_equal(eap->getline, eap->cookie, getsourceline)) { - evalarg.eval_getline = eap->getline; - evalarg.eval_cookie = eap->cookie; - } + fill_evalarg_from_eap(&evalarg, eap, skip); if (skip) { emsg_skip++; @@ -836,14 +840,9 @@ char *eval_to_string_skip(char *arg, exarg_T *eap, const bool skip) { typval_T tv; char *retval; + evalarg_T evalarg; - evalarg_T evalarg = { - .eval_flags = skip ? 0 : EVAL_EVALUATE, - }; - if (eap != NULL && getline_equal(eap->getline, eap->cookie, getsourceline)) { - evalarg.eval_getline = eap->getline; - evalarg.eval_cookie = eap->cookie; - } + fill_evalarg_from_eap(&evalarg, eap, skip); if (skip) { emsg_skip++; } @@ -976,10 +975,15 @@ varnumber_T eval_to_number(char *expr) typval_T *eval_expr(char *arg, exarg_T *eap) { typval_T *tv = xmalloc(sizeof(*tv)); - if (eval0(arg, tv, eap, &EVALARG_EVALUATE) == FAIL) { + evalarg_T evalarg; + + fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip); + + if (eval0(arg, tv, eap, &evalarg) == FAIL) { XFREE_CLEAR(tv); } - clear_evalarg(&EVALARG_EVALUATE, eap); + + clear_evalarg(&evalarg, eap); return tv; } @@ -7476,14 +7480,9 @@ void ex_echo(exarg_T *eap) bool need_clear = true; const int did_emsg_before = did_emsg; const int called_emsg_before = called_emsg; + evalarg_T evalarg; - evalarg_T evalarg = { - .eval_flags = eap->skip ? 0 : EVAL_EVALUATE, - }; - if (getline_equal(eap->getline, eap->cookie, getsourceline)) { - evalarg.eval_getline = eap->getline; - evalarg.eval_cookie = eap->cookie; - } + fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip); if (eap->skip) { emsg_skip++; -- cgit From 04b58cec86e24aaa395b27b2a9587b5cb329ea04 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 14:18:23 +0800 Subject: vim-patch:8.2.1100: Vim9: cannot use line break in :execute argument Problem: Vim9: cannot use line break in :execute, :echomsg and :echoerr argument. Solution: Check for line break. https://github.com/vim/vim/commit/47e880d6c13c3ec2888398fd9ba1f5a7180d791a Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 5944cebf4c..ba5c615ffd 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -736,14 +736,17 @@ int eval_to_bool(char *arg, bool *error, exarg_T *eap, int skip) } /// Call eval1() and give an error message if not done at a lower level. -static int eval1_emsg(char **arg, typval_T *rettv, bool evaluate) +static int eval1_emsg(char **arg, typval_T *rettv, exarg_T *eap) FUNC_ATTR_NONNULL_ARG(1, 2) { const char *const start = *arg; const int did_emsg_before = did_emsg; const int called_emsg_before = called_emsg; + evalarg_T evalarg; + + fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip); - const int ret = eval1(arg, rettv, evaluate ? &EVALARG_EVALUATE : NULL); + const int ret = eval1(arg, rettv, &evalarg); if (ret == FAIL) { // Report the invalid expression unless the expression evaluation has // been cancelled due to an aborting error, an interrupt, or an @@ -755,6 +758,7 @@ static int eval1_emsg(char **arg, typval_T *rettv, bool evaluate) semsg(_(e_invexpr2), start); } } + clear_evalarg(&evalarg, eap); return ret; } @@ -799,7 +803,7 @@ int eval_expr_typval(const typval_T *expr, typval_T *argv, int argc, typval_T *r return FAIL; } s = skipwhite(s); - if (eval1_emsg(&s, rettv, true) == FAIL) { + if (eval1_emsg(&s, rettv, NULL) == FAIL) { return FAIL; } if (*skipwhite(s) != NUL) { // check for trailing chars after expr @@ -7573,7 +7577,7 @@ void ex_execute(exarg_T *eap) emsg_skip++; } while (*arg != NUL && *arg != '|' && *arg != '\n') { - ret = eval1_emsg(&arg, &rettv, !eap->skip); + ret = eval1_emsg(&arg, &rettv, eap); if (ret == FAIL) { break; } -- cgit From 9c65a18753404ec0419bac45969be6c9e5a2fbb6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 14:24:08 +0800 Subject: vim-patch:8.2.1103: Coverity reports an unnecessary NULL check Problem: Coverity reports an unnecessary NULL check. Solution: Remove the check for NULL. https://github.com/vim/vim/commit/e707c882b23a53d2c1f0d1f7fc3a7be247aca614 Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index ba5c615ffd..ed1a49f08d 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -7486,7 +7486,7 @@ void ex_echo(exarg_T *eap) const int called_emsg_before = called_emsg; evalarg_T evalarg; - fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip); + fill_evalarg_from_eap(&evalarg, eap, eap->skip); if (eap->skip) { emsg_skip++; -- cgit From cf37630d1b1443427c13e0a35e0a12b39e1415db Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 14:24:50 +0800 Subject: vim-patch:8.2.1110: Vim9: line continuation does not work in function arguments Problem: Vim9: line continuation does not work in function arguments. Solution: Pass "evalarg" to get_func_tv(). Fix seeing double quoted string as comment. https://github.com/vim/vim/commit/e6b5324e3a3d354363f3c48e784c42ce3e77453f Omit skipwhite_and_linebreak_keep_string(): Vim9 script only. Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 37 ++++++++++++++++++++----------------- src/nvim/eval/userfunc.c | 15 +++++++++------ src/nvim/ex_eval.c | 10 +++------- 3 files changed, 32 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index ed1a49f08d..907e380b85 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -692,7 +692,7 @@ void eval_patch(const char *const origfile, const char *const difffile, const ch set_vim_var_string(VV_FNAME_OUT, NULL, -1); } -static void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, bool skip) +void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, bool skip) { *evalarg = (evalarg_T){ .eval_flags = skip ? 0 : EVAL_EVALUATE }; if (eap != NULL && getline_equal(eap->getline, eap->cookie, getsourceline)) { @@ -2206,9 +2206,10 @@ int pattern_match(const char *pat, const char *text, bool ic) /// @param basetv "expr" for "expr->name(arg)" /// /// @return OK or FAIL. -static int eval_func(char **const arg, char *const name, const int name_len, typval_T *const rettv, - const int flags, typval_T *const basetv) - FUNC_ATTR_NONNULL_ARG(1, 2, 4) +static int eval_func(char **const arg, evalarg_T *const evalarg, char *const name, + const int name_len, typval_T *const rettv, const int flags, + typval_T *const basetv) + FUNC_ATTR_NONNULL_ARG(1, 3, 5) { const bool evaluate = flags & EVAL_EVALUATE; char *s = name; @@ -2234,7 +2235,7 @@ static int eval_func(char **const arg, char *const name, const int name_len, typ funcexe.fe_evaluate = evaluate; funcexe.fe_partial = partial; funcexe.fe_basetv = basetv; - int ret = get_func_tv(s, len, rettv, arg, &funcexe); + int ret = get_func_tv(s, len, rettv, arg, evalarg, &funcexe); xfree(s); @@ -3089,7 +3090,7 @@ static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan ret = FAIL; } else { if (**arg == '(') { // recursive! - ret = eval_func(arg, s, len, rettv, flags, NULL); + ret = eval_func(arg, evalarg, s, len, rettv, flags, NULL); } else if (evaluate) { ret = get_var_tv(s, len, rettv, NULL, true, false); } else { @@ -3181,10 +3182,10 @@ static int eval7_leader(typval_T *const rettv, const bool numeric_only, /// to the name of the Lua function to call (after the /// "v:lua." prefix). /// @return OK on success, FAIL on failure. -static int call_func_rettv(char **const arg, typval_T *const rettv, const bool evaluate, - dict_T *const selfdict, typval_T *const basetv, +static int call_func_rettv(char **const arg, evalarg_T *const evalarg, typval_T *const rettv, + const bool evaluate, dict_T *const selfdict, typval_T *const basetv, const char *const lua_funcname) - FUNC_ATTR_NONNULL_ARG(1, 2) + FUNC_ATTR_NONNULL_ARG(1, 3) { partial_T *pt = NULL; typval_T functv; @@ -3216,7 +3217,7 @@ static int call_func_rettv(char **const arg, typval_T *const rettv, const bool e funcexe.fe_selfdict = selfdict; funcexe.fe_basetv = basetv; const int ret = get_func_tv(funcname, is_lua ? (int)(*arg - funcname) : -1, rettv, - arg, &funcexe); + arg, evalarg, &funcexe); // Clear the funcref afterwards, so that deleting it while // evaluating the arguments is possible (see test55). @@ -3259,7 +3260,7 @@ static int eval_lambda(char **const arg, typval_T *const rettv, evalarg_T *const tv_clear(rettv); ret = FAIL; } else { - ret = call_func_rettv(arg, rettv, evaluate, NULL, &base, NULL); + ret = call_func_rettv(arg, evalarg, rettv, evaluate, NULL, &base, NULL); } // Clear the funcref afterwards, so that deleting it while @@ -3276,10 +3277,12 @@ static int eval_lambda(char **const arg, typval_T *const rettv, evalarg_T *const /// @param *arg points to the '-'. /// /// @return FAIL or OK. "*arg" is advanced to after the ')'. -static int eval_method(char **const arg, typval_T *const rettv, const bool evaluate, +static int eval_method(char **const arg, typval_T *const rettv, evalarg_T *const evalarg, const bool verbose) - FUNC_ATTR_NONNULL_ALL + FUNC_ATTR_NONNULL_ARG(1, 2) { + const bool evaluate = evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE); + // Skip over the ->. *arg += 2; typval_T base = *rettv; @@ -3329,9 +3332,9 @@ static int eval_method(char **const arg, typval_T *const rettv, const bool evalu rettv->vval.v_partial = vvlua_partial; rettv->vval.v_partial->pt_refcount++; } - ret = call_func_rettv(arg, rettv, evaluate, NULL, &base, lua_funcname); + ret = call_func_rettv(arg, evalarg, rettv, evaluate, NULL, &base, lua_funcname); } else { - ret = eval_func(arg, name, len, rettv, evaluate ? EVAL_EVALUATE : 0, &base); + ret = eval_func(arg, evalarg, name, len, rettv, evaluate ? EVAL_EVALUATE : 0, &base); } } @@ -7081,7 +7084,7 @@ int handle_subscript(const char **const arg, typval_T *rettv, evalarg_T *const e && !ascii_iswhite(*(*arg - 1))) || (**arg == '-' && (*arg)[1] == '>'))) { if (**arg == '(') { - ret = call_func_rettv((char **)arg, rettv, evaluate, selfdict, NULL, lua_funcname); + ret = call_func_rettv((char **)arg, evalarg, rettv, evaluate, selfdict, NULL, lua_funcname); // Stop the expression evaluation when immediately aborting on // error, or when an interrupt occurred or an exception was thrown @@ -7100,7 +7103,7 @@ int handle_subscript(const char **const arg, typval_T *rettv, evalarg_T *const e ret = eval_lambda((char **)arg, rettv, evalarg, verbose); } else { // expr->name() - ret = eval_method((char **)arg, rettv, evaluate, verbose); + ret = eval_method((char **)arg, rettv, evalarg, verbose); } } else { // **arg == '[' || **arg == '.' tv_dict_unref(selfdict); diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 1f25b7fb36..3fc34471bf 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -458,15 +458,14 @@ void emsg_funcname(const char *errmsg, const char *name) /// @param funcexe various values /// /// @return OK or FAIL. -int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, funcexe_T *funcexe) +int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, evalarg_T *const evalarg, + funcexe_T *funcexe) { char *argp; int ret = OK; 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 @@ -475,7 +474,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], &evalarg) == FAIL) { + if (eval1(&argp, &argvars[argcount], evalarg) == FAIL) { ret = FAIL; break; } @@ -3013,16 +3012,19 @@ void ex_call(exarg_T *eap) bool failed = false; funcdict_T fudi; partial_T *partial = NULL; + evalarg_T evalarg; + fill_evalarg_from_eap(&evalarg, eap, eap->skip); if (eap->skip) { // trans_function_name() doesn't work well when skipping, use eval0() // 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, NULL) != FAIL) { + if (eval0(eap->arg, &rettv, eap, &evalarg) != FAIL) { tv_clear(&rettv); } emsg_skip--; + clear_evalarg(&evalarg, eap); return; } @@ -3080,7 +3082,7 @@ void ex_call(exarg_T *eap) funcexe.fe_evaluate = true; funcexe.fe_partial = partial; funcexe.fe_selfdict = fudi.fd_dict; - if (get_func_tv(name, -1, &rettv, &arg, &funcexe) == FAIL) { + if (get_func_tv(name, -1, &rettv, &arg, &evalarg, &funcexe) == FAIL) { failed = true; break; } @@ -3118,6 +3120,7 @@ void ex_call(exarg_T *eap) eap->nextcmd = check_nextcmd(arg); } } + clear_evalarg(&evalarg, eap); end: tv_dict_unref(fudi.fd_dict); diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index 34015728b0..63ead3550f 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -792,13 +792,9 @@ void report_discard_pending(int pending, void *value) void ex_eval(exarg_T *eap) { typval_T tv; - evalarg_T evalarg = { - .eval_flags = eap->skip ? 0 : EVAL_EVALUATE, - }; - if (getline_equal(eap->getline, eap->cookie, getsourceline)) { - evalarg.eval_getline = eap->getline; - evalarg.eval_cookie = eap->cookie; - } + evalarg_T evalarg; + + fill_evalarg_from_eap(&evalarg, eap, eap->skip); if (eval0(eap->arg, &tv, eap, &evalarg) == OK) { tv_clear(&tv); -- cgit From 562840a2a16b4532f6d216c137506a7432c2e0e3 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 14:40:42 +0800 Subject: vim-patch:8.2.1125: Vim9: double quote can be a string or a comment Problem: Vim9: double quote can be a string or a comment. Solution: Only support comments starting with # to avoid confusion. https://github.com/vim/vim/commit/962d7213194647e90f9bdc608f693d39dd07cbd5 Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 907e380b85..ec3c2b5e85 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -4679,8 +4679,8 @@ static int get_literal_key(char **arg, typval_T *tv) /// Allocate a variable for a Dictionary and fill it from "*arg". /// +/// @param arg "*arg" points to the "{". /// @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, evalarg_T *const evalarg, bool literal) -- cgit From cc7a50a9ae9384167bd0fc2ee2eb7f1b31842f27 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 15:05:12 +0800 Subject: vim-patch:8.2.1161: Vim9: using freed memory Problem: Vim9: using freed memory. Solution: Put pointer back in evalarg instead of freeing it. https://github.com/vim/vim/commit/8e2730a315b8b06192f5fc822dc218dbb3cff7ae Omit eval_tofree_lambda: Vim9 script only. N/A patches for version.c: vim-patch:8.2.1163: build error Problem: Build error. Solution: Add missing change to globals. https://github.com/vim/vim/commit/6e13530ca03dd9cad245221177dd65f712211448 Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 26 ++++++++++++++------------ src/nvim/eval.h | 2 +- src/nvim/eval/userfunc.c | 27 +++++++++++++++++---------- 3 files changed, 32 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index ec3c2b5e85..9660157592 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -2259,21 +2259,23 @@ static int eval_func(char **const arg, evalarg_T *const evalarg, char *const nam return ret; } -/// After using "evalarg" filled from "eap" free the memory. +/// After using "evalarg" filled from "eap": free the memory. void clear_evalarg(evalarg_T *evalarg, exarg_T *eap) { - if (evalarg != NULL && evalarg->eval_tofree != NULL) { - if (eap != 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); + if (evalarg != NULL) { + if (evalarg->eval_tofree != NULL) { + if (eap != 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); + } + evalarg->eval_tofree = NULL; } - evalarg->eval_tofree = NULL; } } diff --git a/src/nvim/eval.h b/src/nvim/eval.h index 4e0eb6ebb8..e9cdb108a8 100644 --- a/src/nvim/eval.h +++ b/src/nvim/eval.h @@ -275,7 +275,7 @@ typedef struct { LineGetter eval_getline; void *eval_cookie; ///< argument for eval_getline() - /// pointer to the line obtained with getsourceline() + /// pointer to the last line obtained with getsourceline() char *eval_tofree; } evalarg_T; diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 3fc34471bf..9440ceb36e 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -261,15 +261,14 @@ int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg) partial_T *pt = NULL; int varargs; int ret; - char *start = skipwhite(*arg + 1); - char *s, *e; bool *old_eval_lavars = eval_lavars_used; bool eval_lavars = false; char *tofree = NULL; // First, check if this is a lambda expression. "->" must exists. - ret = get_function_args(&start, '-', NULL, NULL, NULL, true); - if (ret == FAIL || *start != '>') { + char *s = skipwhite(*arg + 1); + ret = get_function_args(&s, '-', NULL, NULL, NULL, true); + if (ret == FAIL || *s != '>') { return NOTDONE; } @@ -292,8 +291,9 @@ int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg) // Get the start and the end of the expression. *arg = skipwhite((*arg) + 1); - s = *arg; + char *start = *arg; ret = skip_expr(arg, evalarg); + char *end = *arg; if (ret == FAIL) { goto errret; } @@ -303,7 +303,6 @@ int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg) evalarg->eval_tofree = NULL; } - e = *arg; *arg = skipwhite(*arg); if (**arg != '}') { semsg(_("E451: Expected }: %s"), *arg); @@ -325,11 +324,11 @@ int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg) ga_grow(&newlines, 1); // Add "return " before the expression. - size_t len = (size_t)(7 + e - s + 1); + size_t len = (size_t)(7 + end - start + 1); p = xmalloc(len); ((char **)(newlines.ga_data))[newlines.ga_len++] = p; STRCPY(p, "return "); - xstrlcpy(p + 7, s, (size_t)(e - s) + 1); + xstrlcpy(p + 7, start, (size_t)(end - start) + 1); if (strstr(p + 7, "a:") == NULL) { // No a: variables are used for sure. flags |= FC_NOARGS; @@ -367,14 +366,22 @@ int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg) } eval_lavars_used = old_eval_lavars; - xfree(tofree); + if (evalarg->eval_tofree == NULL) { + evalarg->eval_tofree = tofree; + } else { + xfree(tofree); + } return OK; errret: ga_clear_strings(&newargs); xfree(fp); xfree(pt); - xfree(tofree); + if (evalarg->eval_tofree == NULL) { + evalarg->eval_tofree = tofree; + } else { + xfree(tofree); + } eval_lavars_used = old_eval_lavars; return FAIL; } -- cgit From c804c7df0cf3259b4ee3e286293b43529c9e42d6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 15:24:57 +0800 Subject: vim-patch:8.2.1162: crash when using a lambda Problem: Crash when using a lambda. Solution: Check for evalarg to be NULL. https://github.com/vim/vim/commit/efaaaa683b7b0cebc128be5c0c257b9d6578ac96 Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 9440ceb36e..f73d22243d 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -366,7 +366,7 @@ int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg) } eval_lavars_used = old_eval_lavars; - if (evalarg->eval_tofree == NULL) { + if (evalarg != NULL && evalarg->eval_tofree == NULL) { evalarg->eval_tofree = tofree; } else { xfree(tofree); @@ -377,7 +377,7 @@ errret: ga_clear_strings(&newargs); xfree(fp); xfree(pt); - if (evalarg->eval_tofree == NULL) { + if (evalarg != NULL && evalarg->eval_tofree == NULL) { evalarg->eval_tofree = tofree; } else { xfree(tofree); -- cgit From 56cfecdd59b4a8e4fa5c23adce858371ade5620f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 14:50:17 +0800 Subject: vim-patch:8.2.1203: unused assignments in expression evaluation Problem: Unused assignments in expression evaluation. Solution: Move declarations and assignments to inner blocks where possible. https://github.com/vim/vim/commit/3ac9c4701a5f1e39303ca2885956db92215966db Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 9660157592..a088e6d253 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -2679,8 +2679,6 @@ static int eval_addlist(typval_T *tv1, typval_T *tv2) /// @return OK or FAIL. static int eval5(char **arg, typval_T *rettv, evalarg_T *const evalarg) { - const bool evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE); - // Get the first variable. if (eval6(arg, rettv, evalarg, false) == FAIL) { return FAIL; @@ -2694,6 +2692,7 @@ static int eval5(char **arg, typval_T *rettv, evalarg_T *const evalarg) break; } + const bool evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE); if ((op != '+' || (rettv->v_type != VAR_LIST && rettv->v_type != VAR_BLOB)) && (op == '.' || rettv->v_type != VAR_FLOAT) && evaluate) { // For "list + ...", an illegal use of the first operand as @@ -2822,12 +2821,7 @@ static int eval5(char **arg, typval_T *rettv, evalarg_T *const evalarg) static int eval6(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool want_string) FUNC_ATTR_NO_SANITIZE_UNDEFINED { - typval_T var2; - int op; - varnumber_T n1, n2; bool use_float = false; - float_T f1 = 0, f2 = 0; - bool error = false; // Get the first variable. if (eval7(arg, rettv, evalarg, want_string) == FAIL) { @@ -2836,12 +2830,15 @@ static int eval6(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan // Repeat computing, until no '*', '/' or '%' is following. for (;;) { - const bool evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE); - op = (uint8_t)(**arg); + int op = (uint8_t)(**arg); if (op != '*' && op != '/' && op != '%') { break; } + varnumber_T n1, n2; + float_T f1 = 0, f2 = 0; + bool error = false; + const bool evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE); if (evaluate) { if (rettv->v_type == VAR_FLOAT) { f1 = rettv->vval.v_float; @@ -2860,6 +2857,7 @@ static int eval6(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan // Get the second variable. *arg = skipwhite(*arg + 1); + typval_T var2; if (eval7(arg, &var2, evalarg, false) == FAIL) { return FAIL; } @@ -2953,7 +2951,6 @@ static int eval6(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan /// @return OK or FAIL. static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool want_string) { - 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; @@ -3091,6 +3088,7 @@ static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan if (len <= 0) { ret = FAIL; } else { + const int flags = evalarg == NULL ? 0 : evalarg->eval_flags; if (**arg == '(') { // recursive! ret = eval_func(arg, evalarg, s, len, rettv, flags, NULL); } else if (evaluate) { -- cgit From 9c66b48316d85d24ee92d917765700713862aa2d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 14:57:22 +0800 Subject: vim-patch:8.2.3216: Vim9: crash when using variable in a loop at script level Problem: Vim9: crash when using variable in a loop at script level. Solution: Do not clear the variable if a function was defined. Do not create a new entry in sn_var_vals every time. (closes vim/vim#8628) https://github.com/vim/vim/commit/2eb6fc3b52148f961e804ec2be361d531ff770d8 Omit eval_cstack: Vim9 script only. Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 8 +++++--- src/nvim/eval/vars.c | 9 ++------- src/nvim/ex_eval.c | 17 ++++------------- 3 files changed, 11 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a088e6d253..ad2d854e1e 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -695,9 +695,11 @@ void eval_patch(const char *const origfile, const char *const difffile, const ch void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, bool skip) { *evalarg = (evalarg_T){ .eval_flags = skip ? 0 : EVAL_EVALUATE }; - if (eap != NULL && getline_equal(eap->getline, eap->cookie, getsourceline)) { - evalarg->eval_getline = eap->getline; - evalarg->eval_cookie = eap->cookie; + if (eap != NULL) { + if (getline_equal(eap->getline, eap->cookie, getsourceline)) { + evalarg->eval_getline = eap->getline; + evalarg->eval_cookie = eap->cookie; + } } } diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index 4bce555d75..c4a9823c0a 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -259,13 +259,8 @@ void ex_let(exarg_T *eap) if (eap->skip) { emsg_skip++; } - evalarg_T evalarg = { - .eval_flags = eap->skip ? 0 : EVAL_EVALUATE, - }; - if (getline_equal(eap->getline, eap->cookie, getsourceline)) { - evalarg.eval_getline = eap->getline; - evalarg.eval_cookie = eap->cookie; - } + evalarg_T evalarg; + fill_evalarg_from_eap(&evalarg, eap, eap->skip); int eval_res = eval0(expr, &rettv, eap, &evalarg); if (eap->skip) { emsg_skip--; diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index 63ead3550f..5404ae6731 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -957,21 +957,12 @@ void ex_while(exarg_T *eap) eap->cmdidx == CMD_while ? CSF_WHILE : CSF_FOR; int skip = CHECK_SKIP; - if (eap->cmdidx == CMD_while) { - // ":while bool-expr" + if (eap->cmdidx == CMD_while) { // ":while bool-expr" result = eval_to_bool(eap->arg, &error, eap, skip); - } else { + } else { // ":for var in list-expr" + evalarg_T evalarg; + fill_evalarg_from_eap(&evalarg, eap, skip); void *fi; - - evalarg_T evalarg = { - .eval_flags = eap->skip ? 0 : EVAL_EVALUATE, - }; - if (getline_equal(eap->getline, eap->cookie, getsourceline)) { - evalarg.eval_getline = eap->getline; - evalarg.eval_cookie = eap->cookie; - } - - // ":for var in list-expr" if ((cstack->cs_lflags & CSL_HAD_LOOP) != 0) { // Jumping here from a ":continue" or ":endfor": use the // previously evaluated list. -- cgit