# HG changeset patch # User Bram Moolenaar # Date 1593017104 -7200 # Node ID 7ee565134d4a8be259ae566095e1efeba8e98a6b # Parent cf7644c0a7914c0cc828daa102eada11e5a3a1c7 patch 8.2.1047: Vim9: script cannot use line continuation like :def function Commit: https://github.com/vim/vim/commit/5409f5d8c95007216ae1190565a7a8ee9ebd7100 Author: Bram Moolenaar Date: Wed Jun 24 18:37:35 2020 +0200 patch 8.2.1047: Vim9: script cannot use line continuation like :def function Problem: Vim9: script cannot use line continuation like in a :def function. Solution: Pass the getline function pointer to the eval() functions. Use it for addition and multiplication operators. diff --git a/src/dict.c b/src/dict.c --- a/src/dict.c +++ b/src/dict.c @@ -788,12 +788,14 @@ get_literal_key(char_u **arg, typval_T * /* * Allocate a variable for a Dictionary and fill it from "*arg". * "literal" is TRUE for #{key: val} + * "flags" can have EVAL_EVALUATE and other EVAL_ flags. * Return OK or FAIL. Returns NOTDONE for {expr}. */ int eval_dict(char_u **arg, typval_T *rettv, int flags, int literal) { int evaluate = flags & EVAL_EVALUATE; + evalarg_T evalarg; dict_T *d = NULL; typval_T tvkey; typval_T tv; @@ -803,6 +805,9 @@ eval_dict(char_u **arg, typval_T *rettv, char_u buf[NUMBUFLEN]; int vim9script = current_sctx.sc_version == SCRIPT_VERSION_VIM9; + CLEAR_FIELD(evalarg); + evalarg.eval_flags = flags; + /* * First check if it's not a curly-braces thing: {expr}. * Must do this without evaluating, otherwise a function may be called @@ -812,7 +817,7 @@ eval_dict(char_u **arg, typval_T *rettv, */ if (!vim9script && *start != '}') { - if (eval1(&start, &tv, 0) == FAIL) // recursive! + if (eval1(&start, &tv, NULL) == FAIL) // recursive! return FAIL; if (*start == '}') return NOTDONE; @@ -832,7 +837,7 @@ eval_dict(char_u **arg, typval_T *rettv, { if ((literal ? get_literal_key(arg, &tvkey) - : eval1(arg, &tvkey, flags)) == FAIL) // recursive! + : eval1(arg, &tvkey, &evalarg)) == FAIL) // recursive! goto failret; if (**arg != ':') @@ -854,7 +859,7 @@ eval_dict(char_u **arg, typval_T *rettv, } *arg = skipwhite(*arg + 1); - if (eval1(arg, &tv, flags) == FAIL) // recursive! + if (eval1(arg, &tv, &evalarg) == FAIL) // recursive! { if (evaluate) clear_tv(&tvkey); diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -45,12 +45,12 @@ typedef struct } forinfo_T; static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op); -static int eval2(char_u **arg, typval_T *rettv, int flags); -static int eval3(char_u **arg, typval_T *rettv, int flags); -static int eval4(char_u **arg, typval_T *rettv, int flags); -static int eval5(char_u **arg, typval_T *rettv, int flags); -static int eval6(char_u **arg, typval_T *rettv, int flags, int want_string); -static int eval7(char_u **arg, typval_T *rettv, int flags, int want_string); +static int eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg); +static int eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg); +static int eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg); +static int eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg); +static int eval6(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string); +static int eval7(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string); static int eval7_leader(typval_T *rettv, char_u *start_leader, char_u **end_leaderp); static int free_unref_items(int copyID); @@ -169,7 +169,7 @@ eval_to_bool( if (skip) ++emsg_skip; - if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL) + if (eval0(arg, &tv, nextcmd, skip ? NULL : &EVALARG_EVALUATE) == FAIL) *error = TRUE; else { @@ -197,7 +197,7 @@ eval1_emsg(char_u **arg, typval_T *rettv int did_emsg_before = did_emsg; int called_emsg_before = called_emsg; - ret = eval1(arg, rettv, evaluate ? EVAL_EVALUATE : 0); + ret = eval1(arg, rettv, evaluate ? &EVALARG_EVALUATE : NULL); if (ret == FAIL) { // Report the invalid expression unless the expression evaluation has @@ -325,7 +325,8 @@ eval_to_string_skip( if (skip) ++emsg_skip; - if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL || skip) + if (eval0(arg, &tv, nextcmd, skip ? NULL : &EVALARG_EVALUATE) + == FAIL || skip) retval = NULL; else { @@ -348,7 +349,7 @@ skip_expr(char_u **pp) typval_T rettv; *pp = skipwhite(*pp); - return eval1(pp, &rettv, 0); + return eval1(pp, &rettv, NULL); } /* @@ -370,7 +371,7 @@ eval_to_string( char_u numbuf[NUMBUFLEN]; #endif - if (eval0(arg, &tv, nextcmd, EVAL_EVALUATE) == FAIL) + if (eval0(arg, &tv, nextcmd, &EVALARG_EVALUATE) == FAIL) retval = NULL; else { @@ -440,7 +441,7 @@ eval_to_number(char_u *expr) ++emsg_off; - if (eval1(&p, &rettv, EVAL_EVALUATE) == FAIL) + if (eval1(&p, &rettv, &EVALARG_EVALUATE) == FAIL) retval = -1; else { @@ -463,7 +464,7 @@ eval_expr(char_u *arg, char_u **nextcmd) typval_T *tv; tv = ALLOC_ONE(typval_T); - if (tv != NULL && eval0(arg, tv, nextcmd, EVAL_EVALUATE) == FAIL) + if (tv != NULL && eval0(arg, tv, nextcmd, &EVALARG_EVALUATE) == FAIL) VIM_CLEAR(tv); return tv; @@ -588,7 +589,7 @@ eval_foldexpr(char_u *arg, int *cp) ++sandbox; ++textwinlock; *cp = NUL; - if (eval0(arg, &tv, NULL, EVAL_EVALUATE) == FAIL) + if (eval0(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) retval = 0; else { @@ -776,7 +777,7 @@ get_lval( else { empty1 = FALSE; - if (eval1(&p, &var1, EVAL_EVALUATE) == FAIL) // recursive! + if (eval1(&p, &var1, &EVALARG_EVALUATE) == FAIL) // recursive! return NULL; if (tv_get_string_chk(&var1) == NULL) { @@ -814,7 +815,7 @@ get_lval( { lp->ll_empty2 = FALSE; // recursive! - if (eval1(&p, &var2, EVAL_EVALUATE) == FAIL) + if (eval1(&p, &var2, &EVALARG_EVALUATE) == FAIL) { clear_tv(&var1); return NULL; @@ -1424,7 +1425,10 @@ eval_for_line( char_u *expr; typval_T tv; list_T *l; - + evalarg_T evalarg; + + CLEAR_FIELD(evalarg); + evalarg.eval_flags = skip ? 0 : EVAL_EVALUATE; *errp = TRUE; // default: there is an error fi = ALLOC_CLEAR_ONE(forinfo_T); @@ -1444,8 +1448,7 @@ eval_for_line( if (skip) ++emsg_skip; - if (eval0(skipwhite(expr + 2), &tv, nextcmdp, skip ? 0 : EVAL_EVALUATE) - == OK) + if (eval0(skipwhite(expr + 2), &tv, nextcmdp, &evalarg) == OK) { *errp = FALSE; if (!skip) @@ -1764,6 +1767,35 @@ eval_func( } /* + * If inside Vim9 script, "arg" points to the end of a line (ignoring comments) + * and there is a next line, return the next line (skipping blanks) and set + * "getnext". + * Otherwise just return "arg" unmodified and set "getnext" to FALSE. + * "arg" must point somewhere inside a line, not at the start. + */ + static char_u * +eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext) +{ + *getnext = FALSE; + if (current_sctx.sc_version == SCRIPT_VERSION_VIM9 + && evalarg != NULL + && evalarg->eval_cookie != NULL + && (*arg == NUL || (VIM_ISWHITE(arg[-1]) + && (*arg == '"' || *arg == '#'))) + && source_nextline(evalarg->eval_cookie) != NULL) + { + char_u *p = source_nextline(evalarg->eval_cookie); + + if (p != NULL) + { + *getnext = TRUE; + return skipwhite(p); + } + } + return arg; +} + +/* * 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. @@ -1774,7 +1806,7 @@ eval_func( * This calls eval1() and handles error message and nextcmd. * Put the result in "rettv" when returning OK and "evaluate" is TRUE. * Note: "rettv.v_lock" is not set. - * "flags" has EVAL_EVALUATE and similar flags. + * "evalarg" can be NULL, EVALARG_EVALUATE or a pointer. * Return OK or FAIL. */ int @@ -1782,15 +1814,16 @@ eval0( char_u *arg, typval_T *rettv, char_u **nextcmd, - int flags) + evalarg_T *evalarg) { int ret; char_u *p; int did_emsg_before = did_emsg; int called_emsg_before = called_emsg; + int flags = evalarg == NULL ? 0 : evalarg->eval_flags; p = skipwhite(arg); - ret = eval1(&p, rettv, flags); + ret = eval1(&p, rettv, evalarg); if (ret == FAIL || !ends_excmd2(arg, p)) { if (ret != FAIL) @@ -1826,23 +1859,36 @@ eval0( * Return OK or FAIL. */ int -eval1(char_u **arg, typval_T *rettv, int flags) +eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg) { - int result; - typval_T var2; - /* * Get the first variable. */ - if (eval2(arg, rettv, flags) == FAIL) + if (eval2(arg, rettv, evalarg) == FAIL) return FAIL; if ((*arg)[0] == '?') { - int evaluate = flags & EVAL_EVALUATE; + int result; + typval_T var2; + evalarg_T nested_evalarg; + int orig_flags; + + if (evalarg == NULL) + { + CLEAR_FIELD(nested_evalarg); + orig_flags = 0; + } + else + { + nested_evalarg = *evalarg; + orig_flags = evalarg->eval_flags; + } + + int evaluate = nested_evalarg.eval_flags & EVAL_EVALUATE; result = FALSE; - if (flags & EVAL_EVALUATE) + if (evaluate) { int error = FALSE; @@ -1857,7 +1903,9 @@ eval1(char_u **arg, typval_T *rettv, int * 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; /* @@ -1875,7 +1923,9 @@ eval1(char_u **arg, typval_T *rettv, int * Get the third variable. Recursive! */ *arg = skipwhite(*arg + 1); - if (eval1(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) == FAIL) + nested_evalarg.eval_flags = !result ? orig_flags + : orig_flags & ~EVAL_EVALUATE; + if (eval1(arg, &var2, &nested_evalarg) == FAIL) { if (evaluate && result) clear_tv(rettv); @@ -1898,7 +1948,7 @@ eval1(char_u **arg, typval_T *rettv, int * Return OK or FAIL. */ static int -eval2(char_u **arg, typval_T *rettv, int flags) +eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg) { typval_T var2; long result; @@ -1908,7 +1958,7 @@ eval2(char_u **arg, typval_T *rettv, int /* * Get the first variable. */ - if (eval3(arg, rettv, flags) == FAIL) + if (eval3(arg, rettv, evalarg) == FAIL) return FAIL; /* @@ -1918,7 +1968,22 @@ eval2(char_u **arg, typval_T *rettv, int result = FALSE; while ((*arg)[0] == '|' && (*arg)[1] == '|') { - int evaluate = flags & EVAL_EVALUATE; + evalarg_T nested_evalarg; + int evaluate; + int orig_flags; + + if (evalarg == NULL) + { + CLEAR_FIELD(nested_evalarg); + orig_flags = 0; + evaluate = FALSE; + } + else + { + nested_evalarg = *evalarg; + orig_flags = evalarg->eval_flags; + evaluate = orig_flags & EVAL_EVALUATE; + } if (evaluate && first) { @@ -1934,8 +1999,9 @@ eval2(char_u **arg, typval_T *rettv, int * 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; /* @@ -1969,7 +2035,7 @@ eval2(char_u **arg, typval_T *rettv, int * Return OK or FAIL. */ static int -eval3(char_u **arg, typval_T *rettv, int flags) +eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg) { typval_T var2; long result; @@ -1979,7 +2045,7 @@ eval3(char_u **arg, typval_T *rettv, int /* * Get the first variable. */ - if (eval4(arg, rettv, flags) == FAIL) + if (eval4(arg, rettv, evalarg) == FAIL) return FAIL; /* @@ -1989,8 +2055,22 @@ eval3(char_u **arg, typval_T *rettv, int result = TRUE; while ((*arg)[0] == '&' && (*arg)[1] == '&') { - int evaluate = flags & EVAL_EVALUATE; - + evalarg_T nested_evalarg; + int orig_flags; + int evaluate; + + if (evalarg == NULL) + { + CLEAR_FIELD(nested_evalarg); + orig_flags = 0; + evaluate = FALSE; + } + else + { + nested_evalarg = *evalarg; + orig_flags = evalarg->eval_flags; + evaluate = orig_flags & EVAL_EVALUATE; + } if (evaluate && first) { if (tv_get_number_chk(rettv, &error) == 0) @@ -2005,7 +2085,9 @@ eval3(char_u **arg, typval_T *rettv, int * 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; /* @@ -2048,7 +2130,7 @@ eval3(char_u **arg, typval_T *rettv, int * Return OK or FAIL. */ static int -eval4(char_u **arg, typval_T *rettv, int flags) +eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg) { typval_T var2; char_u *p; @@ -2060,7 +2142,7 @@ eval4(char_u **arg, typval_T *rettv, int /* * Get the first variable. */ - if (eval5(arg, rettv, flags) == FAIL) + if (eval5(arg, rettv, evalarg) == FAIL) return FAIL; p = *arg; @@ -2128,12 +2210,12 @@ eval4(char_u **arg, typval_T *rettv, int * Get the second variable. */ *arg = skipwhite(p + len); - if (eval5(arg, &var2, flags) == FAIL) + if (eval5(arg, &var2, evalarg) == FAIL) { clear_tv(rettv); return FAIL; } - if (flags & EVAL_EVALUATE) + if (evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE)) { int ret = typval_compare(rettv, &var2, type, ic); @@ -2195,23 +2277,14 @@ eval_addlist(typval_T *tv1, typval_T *tv * Return OK or FAIL. */ static int -eval5(char_u **arg, typval_T *rettv, int flags) +eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg) { - typval_T var2; - int op; - varnumber_T n1, n2; -#ifdef FEAT_FLOAT - float_T f1 = 0, f2 = 0; -#endif - char_u *s1, *s2; - char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN]; - char_u *p; - int concat; + int 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; /* @@ -2219,12 +2292,20 @@ eval5(char_u **arg, typval_T *rettv, int */ for (;;) { + int getnext; + char_u *p; + int op; + int concat; + typval_T var2; + // "." is only string concatenation when scriptversion is 1 - op = **arg; - concat = op == '.' - && (*(*arg + 1) == '.' || current_sctx.sc_version < 2); + p = eval_next_non_blank(*arg, evalarg, &getnext); + op = *p; + concat = op == '.' && (*(p + 1) == '.' || current_sctx.sc_version < 2); if (op != '+' && op != '-' && !concat) break; + if (getnext) + *arg = skipwhite(getsourceline(0, evalarg->eval_cookie, 0, TRUE)); if ((op != '+' || (rettv->v_type != VAR_LIST && rettv->v_type != VAR_BLOB)) @@ -2240,7 +2321,7 @@ eval5(char_u **arg, typval_T *rettv, int // we know that the first operand needs to be a string or number // without evaluating the 2nd operand. So check before to avoid // side effects after an error. - if ((flags & EVAL_EVALUATE) && tv_get_string_chk(rettv) == NULL) + if (evaluate && tv_get_string_chk(rettv) == NULL) { clear_tv(rettv); return FAIL; @@ -2253,21 +2334,23 @@ eval5(char_u **arg, typval_T *rettv, int if (op == '.' && *(*arg + 1) == '.') // .. string concatenation ++*arg; *arg = skipwhite(*arg + 1); - if (eval6(arg, &var2, flags, op == '.') == FAIL) + if (eval6(arg, &var2, evalarg, op == '.') == FAIL) { clear_tv(rettv); return FAIL; } - if (flags & EVAL_EVALUATE) + if (evaluate) { /* * Compute the result. */ if (op == '.') { - s1 = tv_get_string_buf(rettv, buf1); // already checked - s2 = tv_get_string_buf_chk(&var2, buf2); + char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN]; + char_u *s1 = tv_get_string_buf(rettv, buf1); + char_u *s2 = tv_get_string_buf_chk(&var2, buf2); + if (s2 == NULL) // type error ? { clear_tv(rettv); @@ -2290,9 +2373,11 @@ eval5(char_u **arg, typval_T *rettv, int } else { - int error = FALSE; - + int error = FALSE; + varnumber_T n1, n2; #ifdef FEAT_FLOAT + float_T f1 = 0, f2 = 0; + if (rettv->v_type == VAR_FLOAT) { f1 = rettv->vval.v_float; @@ -2381,7 +2466,7 @@ eval5(char_u **arg, typval_T *rettv, int eval6( char_u **arg, typval_T *rettv, - int flags, + evalarg_T *evalarg, int want_string) // after "." operator { typval_T var2; @@ -2396,7 +2481,7 @@ eval6( /* * Get the first variable. */ - if (eval7(arg, rettv, flags, want_string) == FAIL) + if (eval7(arg, rettv, evalarg, want_string) == FAIL) return FAIL; /* @@ -2404,11 +2489,17 @@ eval6( */ for (;;) { - op = **arg; + int evaluate = evalarg == NULL ? 0 + : (evalarg->eval_flags & EVAL_EVALUATE); + int getnext; + + op = *eval_next_non_blank(*arg, evalarg, &getnext); if (op != '*' && op != '/' && op != '%') break; - - if (flags & EVAL_EVALUATE) + if (getnext) + *arg = skipwhite(getsourceline(0, evalarg->eval_cookie, 0, TRUE)); + + if (evaluate) { #ifdef FEAT_FLOAT if (rettv->v_type == VAR_FLOAT) @@ -2431,10 +2522,10 @@ eval6( * 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) { #ifdef FEAT_FLOAT if (var2.v_type == VAR_FLOAT) @@ -2551,10 +2642,12 @@ eval6( eval7( char_u **arg, typval_T *rettv, - int flags, + evalarg_T *evalarg, int want_string) // after "." operator { - int evaluate = flags & EVAL_EVALUATE; + int flags = evalarg == NULL ? 0 : evalarg->eval_flags; + int evaluate = evalarg != NULL + && (evalarg->eval_flags & EVAL_EVALUATE); int len; char_u *s; char_u *start_leader, *end_leader; @@ -2672,15 +2765,17 @@ eval7( /* * nested expression: (expression). */ - case '(': *arg = skipwhite(*arg + 1); - ret = eval1(arg, rettv, flags); // recursive! - if (**arg == ')') - ++*arg; - else if (ret == OK) - { - emsg(_(e_missing_close)); - clear_tv(rettv); - ret = FAIL; + case '(': { + *arg = skipwhite(*arg + 1); + ret = eval1(arg, rettv, evalarg); // recursive! + if (**arg == ')') + ++*arg; + else if (ret == OK) + { + emsg(_(e_missing_close)); + clear_tv(rettv); + ret = FAIL; + } } break; @@ -3030,6 +3125,11 @@ eval_index( } else { + evalarg_T evalarg; + + CLEAR_FIELD(evalarg); + evalarg.eval_flags = flags; + /* * something[idx] * @@ -3038,7 +3138,7 @@ eval_index( *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_get_string_chk(&var1) == NULL) { @@ -3056,7 +3156,7 @@ eval_index( *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) clear_tv(&var1); @@ -4947,6 +5047,10 @@ ex_echo(exarg_T *eap) int atstart = TRUE; int did_emsg_before = did_emsg; int called_emsg_before = called_emsg; + evalarg_T evalarg; + + CLEAR_FIELD(evalarg); + evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE; if (eap->skip) ++emsg_skip; @@ -4957,7 +5061,7 @@ ex_echo(exarg_T *eap) need_clr_eos = needclr; 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 diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -2084,7 +2084,7 @@ f_eval(typval_T *argvars, typval_T *rett s = skipwhite(s); p = s; - if (s == NULL || eval1(&s, rettv, EVAL_EVALUATE) == FAIL) + if (s == NULL || eval1(&s, rettv, &EVALARG_EVALUATE) == FAIL) { if (p != NULL && !aborting()) semsg(_(e_invexpr2), p); diff --git a/src/evalvars.c b/src/evalvars.c --- a/src/evalvars.c +++ b/src/evalvars.c @@ -435,7 +435,7 @@ eval_spell_expr(char_u *badword, char_u if (p_verbose == 0) ++emsg_off; - if (eval1(&p, &rettv, EVAL_EVALUATE) == OK) + if (eval1(&p, &rettv, &EVALARG_EVALUATE) == OK) { if (rettv.v_type != VAR_LIST) clear_tv(&rettv); @@ -774,7 +774,7 @@ ex_let(exarg_T *eap) } else { - int eval_flags; + evalarg_T evalarg; rettv.v_type = VAR_UNKNOWN; i = FAIL; @@ -797,14 +797,17 @@ ex_let(exarg_T *eap) if (eap->skip) ++emsg_skip; - eval_flags = eap->skip ? 0 : EVAL_EVALUATE; - i = eval0(expr, &rettv, &eap->nextcmd, eval_flags); + evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE; + evalarg.eval_cookie = eap->getline == getsourceline + ? eap->cookie : NULL; + i = eval0(expr, &rettv, &eap->nextcmd, &evalarg); + if (eap->skip) + --emsg_skip; } if (eap->skip) { if (i != FAIL) clear_tv(&rettv); - --emsg_skip; } else if (i != FAIL) { diff --git a/src/ex_eval.c b/src/ex_eval.c --- a/src/ex_eval.c +++ b/src/ex_eval.c @@ -895,9 +895,12 @@ report_discard_pending(int pending, void ex_eval(exarg_T *eap) { typval_T tv; + evalarg_T evalarg; - if (eval0(eap->arg, &tv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE) - == OK) + evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE; + evalarg.eval_cookie = eap->getline == getsourceline ? eap->cookie : NULL; + + if (eval0(eap->arg, &tv, &eap->nextcmd, &evalarg) == OK) clear_tv(&tv); } diff --git a/src/globals.h b/src/globals.h --- a/src/globals.h +++ b/src/globals.h @@ -1880,6 +1880,9 @@ EXTERN char windowsVersion[20] INIT(= {0 // Used for lv_first in a non-materialized range() list. EXTERN listitem_T range_list_item; + +// Passed to an eval() function to enable evaluation. +EXTERN evalarg_T EVALARG_EVALUATE INIT2(EVAL_EVALUATE, NULL); #endif #ifdef MSWIN diff --git a/src/list.c b/src/list.c --- a/src/list.c +++ b/src/list.c @@ -1165,6 +1165,10 @@ get_list_tv(char_u **arg, typval_T *rett list_T *l = NULL; typval_T tv; listitem_T *item; + evalarg_T evalarg; + + CLEAR_FIELD(evalarg); + evalarg.eval_flags = flags; if (evaluate) { @@ -1176,7 +1180,7 @@ get_list_tv(char_u **arg, typval_T *rett *arg = skipwhite(*arg + 1); while (**arg != ']' && **arg != NUL) { - if (eval1(arg, &tv, flags) == FAIL) // recursive! + if (eval1(arg, &tv, &evalarg) == FAIL) // recursive! goto failret; if (evaluate) { diff --git a/src/proto/eval.pro b/src/proto/eval.pro --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -26,8 +26,8 @@ int next_for_item(void *fi_void, char_u void free_for_info(void *fi_void); void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx); int pattern_match(char_u *pat, char_u *text, int ic); -int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int flags); -int eval1(char_u **arg, typval_T *rettv, int flags); +int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, evalarg_T *evalarg); +int eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg_in); void eval_addblob(typval_T *tv1, typval_T *tv2); int eval_addlist(typval_T *tv1, typval_T *tv2); char_u *partial_name(partial_T *pt); diff --git a/src/proto/scriptfile.pro b/src/proto/scriptfile.pro --- a/src/proto/scriptfile.pro +++ b/src/proto/scriptfile.pro @@ -22,6 +22,7 @@ void ex_options(exarg_T *eap); linenr_T *source_breakpoint(void *cookie); int *source_dbg_tick(void *cookie); int source_level(void *cookie); +char_u *source_nextline(void *cookie); int do_source(char_u *fname, int check_other, int is_vimrc, int *ret_sid); void ex_scriptnames(exarg_T *eap); void scriptnames_slash_adjust(void); diff --git a/src/scriptfile.c b/src/scriptfile.c --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -1050,6 +1050,15 @@ source_level(void *cookie) { return ((struct source_cookie *)cookie)->level; } + +/* + * Return the readahead line. + */ + char_u * +source_nextline(void *cookie) +{ + return ((struct source_cookie *)cookie)->nextline; +} #endif #if (defined(MSWIN) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC) diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -1746,6 +1746,19 @@ typedef struct # endif } scriptitem_T; +// 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() +} evalarg_T; + +// Flags for expression evaluation. +#define EVAL_EVALUATE 1 // when missing don't actually evaluate +#define EVAL_CONSTANT 2 // when not a constant return FAIL + # ifdef FEAT_PROFILE /* * Struct used in sn_prl_ga for every line of a script. diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -570,6 +570,26 @@ def Test_expr5() assert_equal(0z01ab01ab, g:ablob + g:ablob) enddef +def Test_expr5_vim9script() + " only checks line continuation + let lines =<< trim END + vim9script + let var = 11 + + 77 + - 22 + assert_equal(66, var) + END + CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + let var = 'one' + .. 'two' + assert_equal('onetwo', var) + END + CheckScriptSuccess(lines) +enddef + def Test_expr5_float() if !has('float') MissingFeature 'float' @@ -661,6 +681,26 @@ def Test_expr6() call CheckDefFailure(["let x = 6 * xxx"], 'E1001') enddef +def Test_expr6_vim9script() + " only checks line continuation + let lines =<< trim END + vim9script + let var = 11 + * 22 + / 3 + assert_equal(80, var) + END + CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + let var = 25 + % 10 + assert_equal(5, var) + END + CheckScriptSuccess(lines) +enddef + def Test_expr6_float() if !has('float') MissingFeature 'float' diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -239,7 +239,7 @@ get_function_args( whitep = p; p = skipwhite(p); expr = p; - if (eval1(&p, &rettv, 0) != FAIL) + if (eval1(&p, &rettv, NULL) != FAIL) { if (ga_grow(default_args, 1) == FAIL) goto err_ret; @@ -561,6 +561,10 @@ get_func_tv( int ret = OK; typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments int argcount = 0; // number of arguments found + evalarg_T evalarg; + + CLEAR_FIELD(evalarg); + evalarg.eval_flags = funcexe->evaluate ? EVAL_EVALUATE : 0; /* * Get the arguments. @@ -572,8 +576,7 @@ get_func_tv( argp = skipwhite(argp + 1); // skip the '(' or ',' if (*argp == ')' || *argp == ',' || *argp == NUL) break; - if (eval1(&argp, &argvars[argcount], - funcexe->evaluate ? EVAL_EVALUATE : 0) == FAIL) + if (eval1(&argp, &argvars[argcount], &evalarg) == FAIL) { ret = FAIL; break; @@ -1249,7 +1252,7 @@ call_user_func( default_expr = ((char_u **)(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 = 1; break; @@ -1394,7 +1397,7 @@ call_user_func( // 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 @@ -3697,6 +3700,7 @@ ex_return(exarg_T *eap) char_u *arg = eap->arg; typval_T rettv; int returning = FALSE; + evalarg_T evalarg; if (current_funccal == NULL) { @@ -3704,13 +3708,15 @@ ex_return(exarg_T *eap) return; } + CLEAR_FIELD(evalarg); + 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->nextcmd, &evalarg) != FAIL) { if (!eap->skip) returning = do_return(eap, FALSE, TRUE, &rettv); @@ -3767,7 +3773,7 @@ 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->nextcmd, NULL) != FAIL) clear_tv(&rettv); --emsg_skip; return; diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1047, +/**/ 1046, /**/ 1045, diff --git a/src/vim.h b/src/vim.h --- a/src/vim.h +++ b/src/vim.h @@ -2665,10 +2665,6 @@ long elapsed(DWORD start_tick); #define REPTERM_SPECIAL 4 #define REPTERM_NO_SIMPLIFY 8 -// Flags for expression evaluation. -#define EVAL_EVALUATE 1 // when missing don't actually evaluate -#define EVAL_CONSTANT 2 // when not a constant return FAIL - // Flags for find_special_key() #define FSK_KEYCODE 0x01 // prefer key code, e.g. K_DEL instead of DEL #define FSK_KEEP_X_KEY 0x02 // don't translate xHome to Home key