To: vim_dev@googlegroups.com Subject: Patch 8.2.1047 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.1047 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. Files: src/vim.h, src/structs.h, src/globals.h, src/ex_eval.c, src/eval.c, src/proto/eval.pro, src/dict.c, src/evalfunc.c, src/evalvars.c, src/list.c, src/userfunc.c, src/scriptfile.c, src/proto/scriptfile.pro, src/testdir/test_vim9_expr.vim *** ../vim-8.2.1046/src/vim.h 2020-06-16 20:03:38.747351038 +0200 --- src/vim.h 2020-06-24 14:30:33.494935506 +0200 *************** *** 2665,2674 **** #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 --- 2665,2670 ---- *** ../vim-8.2.1046/src/structs.h 2020-06-20 22:50:44.171608245 +0200 --- src/structs.h 2020-06-24 15:30:16.345482478 +0200 *************** *** 1746,1751 **** --- 1746,1764 ---- # 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. *** ../vim-8.2.1046/src/globals.h 2020-06-22 23:02:14.773942551 +0200 --- src/globals.h 2020-06-24 15:16:42.863873556 +0200 *************** *** 1880,1885 **** --- 1880,1888 ---- // 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 *** ../vim-8.2.1046/src/ex_eval.c 2020-06-12 22:59:07.262097216 +0200 --- src/ex_eval.c 2020-06-24 17:47:15.224988598 +0200 *************** *** 895,903 **** ex_eval(exarg_T *eap) { typval_T tv; ! if (eval0(eap->arg, &tv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE) ! == OK) clear_tv(&tv); } --- 895,906 ---- ex_eval(exarg_T *eap) { typval_T tv; + evalarg_T evalarg; ! 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); } *** ../vim-8.2.1046/src/eval.c 2020-06-20 18:19:05.920877872 +0200 --- src/eval.c 2020-06-24 18:26:27.453643950 +0200 *************** *** 45,56 **** } 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 eval7_leader(typval_T *rettv, char_u *start_leader, char_u **end_leaderp); static int free_unref_items(int copyID); --- 45,56 ---- } forinfo_T; static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op); ! 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,175 **** if (skip) ++emsg_skip; ! if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL) *error = TRUE; else { --- 169,175 ---- if (skip) ++emsg_skip; ! if (eval0(arg, &tv, nextcmd, skip ? NULL : &EVALARG_EVALUATE) == FAIL) *error = TRUE; else { *************** *** 197,203 **** int did_emsg_before = did_emsg; int called_emsg_before = called_emsg; ! ret = eval1(arg, rettv, evaluate ? EVAL_EVALUATE : 0); if (ret == FAIL) { // Report the invalid expression unless the expression evaluation has --- 197,203 ---- int did_emsg_before = did_emsg; int called_emsg_before = called_emsg; ! ret = eval1(arg, rettv, evaluate ? &EVALARG_EVALUATE : NULL); if (ret == FAIL) { // Report the invalid expression unless the expression evaluation has *************** *** 325,331 **** if (skip) ++emsg_skip; ! if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL || skip) retval = NULL; else { --- 325,332 ---- if (skip) ++emsg_skip; ! if (eval0(arg, &tv, nextcmd, skip ? NULL : &EVALARG_EVALUATE) ! == FAIL || skip) retval = NULL; else { *************** *** 348,354 **** typval_T rettv; *pp = skipwhite(*pp); ! return eval1(pp, &rettv, 0); } /* --- 349,355 ---- typval_T rettv; *pp = skipwhite(*pp); ! return eval1(pp, &rettv, NULL); } /* *************** *** 370,376 **** char_u numbuf[NUMBUFLEN]; #endif ! if (eval0(arg, &tv, nextcmd, EVAL_EVALUATE) == FAIL) retval = NULL; else { --- 371,377 ---- char_u numbuf[NUMBUFLEN]; #endif ! if (eval0(arg, &tv, nextcmd, &EVALARG_EVALUATE) == FAIL) retval = NULL; else { *************** *** 440,446 **** ++emsg_off; ! if (eval1(&p, &rettv, EVAL_EVALUATE) == FAIL) retval = -1; else { --- 441,447 ---- ++emsg_off; ! if (eval1(&p, &rettv, &EVALARG_EVALUATE) == FAIL) retval = -1; else { *************** *** 463,469 **** typval_T *tv; tv = ALLOC_ONE(typval_T); ! if (tv != NULL && eval0(arg, tv, nextcmd, EVAL_EVALUATE) == FAIL) VIM_CLEAR(tv); return tv; --- 464,470 ---- typval_T *tv; tv = ALLOC_ONE(typval_T); ! if (tv != NULL && eval0(arg, tv, nextcmd, &EVALARG_EVALUATE) == FAIL) VIM_CLEAR(tv); return tv; *************** *** 588,594 **** ++sandbox; ++textwinlock; *cp = NUL; ! if (eval0(arg, &tv, NULL, EVAL_EVALUATE) == FAIL) retval = 0; else { --- 589,595 ---- ++sandbox; ++textwinlock; *cp = NUL; ! if (eval0(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) retval = 0; else { *************** *** 776,782 **** else { empty1 = FALSE; ! if (eval1(&p, &var1, EVAL_EVALUATE) == FAIL) // recursive! return NULL; if (tv_get_string_chk(&var1) == NULL) { --- 777,783 ---- else { empty1 = FALSE; ! if (eval1(&p, &var1, &EVALARG_EVALUATE) == FAIL) // recursive! return NULL; if (tv_get_string_chk(&var1) == NULL) { *************** *** 814,820 **** { lp->ll_empty2 = FALSE; // recursive! ! if (eval1(&p, &var2, EVAL_EVALUATE) == FAIL) { clear_tv(&var1); return NULL; --- 815,821 ---- { lp->ll_empty2 = FALSE; // recursive! ! if (eval1(&p, &var2, &EVALARG_EVALUATE) == FAIL) { clear_tv(&var1); return NULL; *************** *** 1424,1430 **** --- 1425,1434 ---- 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,1451 **** if (skip) ++emsg_skip; ! if (eval0(skipwhite(expr + 2), &tv, nextcmdp, skip ? 0 : EVAL_EVALUATE) ! == OK) { *errp = FALSE; if (!skip) --- 1448,1454 ---- if (skip) ++emsg_skip; ! if (eval0(skipwhite(expr + 2), &tv, nextcmdp, &evalarg) == OK) { *errp = FALSE; if (!skip) *************** *** 1764,1769 **** --- 1767,1801 ---- } /* + * 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,1780 **** * 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. * Return OK or FAIL. */ int --- 1806,1812 ---- * 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. ! * "evalarg" can be NULL, EVALARG_EVALUATE or a pointer. * Return OK or FAIL. */ int *************** *** 1782,1796 **** char_u *arg, typval_T *rettv, char_u **nextcmd, ! int flags) { int ret; char_u *p; int did_emsg_before = did_emsg; int called_emsg_before = called_emsg; p = skipwhite(arg); ! ret = eval1(&p, rettv, flags); if (ret == FAIL || !ends_excmd2(arg, p)) { if (ret != FAIL) --- 1814,1829 ---- char_u *arg, typval_T *rettv, char_u **nextcmd, ! 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, evalarg); if (ret == FAIL || !ends_excmd2(arg, p)) { if (ret != FAIL) *************** *** 1826,1848 **** * Return OK or FAIL. */ int ! eval1(char_u **arg, typval_T *rettv, int flags) { - int result; - typval_T var2; - /* * Get the first variable. */ ! if (eval2(arg, rettv, flags) == FAIL) return FAIL; if ((*arg)[0] == '?') { ! int evaluate = flags & EVAL_EVALUATE; result = FALSE; ! if (flags & EVAL_EVALUATE) { int error = FALSE; --- 1859,1894 ---- * Return OK or FAIL. */ int ! eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg) { /* * Get the first variable. */ ! if (eval2(arg, rettv, evalarg) == FAIL) return FAIL; if ((*arg)[0] == '?') { ! 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 (evaluate) { int error = FALSE; *************** *** 1857,1863 **** * Get the second variable. Recursive! */ *arg = skipwhite(*arg + 1); ! if (eval1(arg, rettv, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) return FAIL; /* --- 1903,1911 ---- * Get the second variable. Recursive! */ *arg = skipwhite(*arg + 1); ! nested_evalarg.eval_flags = result ? orig_flags ! : orig_flags & ~EVAL_EVALUATE; ! if (eval1(arg, rettv, &nested_evalarg) == FAIL) return FAIL; /* *************** *** 1875,1881 **** * Get the third variable. Recursive! */ *arg = skipwhite(*arg + 1); ! if (eval1(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) == FAIL) { if (evaluate && result) clear_tv(rettv); --- 1923,1931 ---- * Get the third variable. Recursive! */ *arg = skipwhite(*arg + 1); ! 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,1904 **** * Return OK or FAIL. */ static int ! eval2(char_u **arg, typval_T *rettv, int flags) { typval_T var2; long result; --- 1948,1954 ---- * Return OK or FAIL. */ static int ! eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg) { typval_T var2; long result; *************** *** 1908,1914 **** /* * Get the first variable. */ ! if (eval3(arg, rettv, flags) == FAIL) return FAIL; /* --- 1958,1964 ---- /* * Get the first variable. */ ! if (eval3(arg, rettv, evalarg) == FAIL) return FAIL; /* *************** *** 1918,1924 **** result = FALSE; while ((*arg)[0] == '|' && (*arg)[1] == '|') { ! int evaluate = flags & EVAL_EVALUATE; if (evaluate && first) { --- 1968,1989 ---- result = FALSE; while ((*arg)[0] == '|' && (*arg)[1] == '|') { ! 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,1941 **** * Get the second variable. */ *arg = skipwhite(*arg + 2); ! if (eval3(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) ! == FAIL) return FAIL; /* --- 1999,2007 ---- * Get the second variable. */ *arg = skipwhite(*arg + 2); ! nested_evalarg.eval_flags = !result ? orig_flags ! : orig_flags & ~EVAL_EVALUATE; ! if (eval3(arg, &var2, &nested_evalarg) == FAIL) return FAIL; /* *************** *** 1969,1975 **** * Return OK or FAIL. */ static int ! eval3(char_u **arg, typval_T *rettv, int flags) { typval_T var2; long result; --- 2035,2041 ---- * Return OK or FAIL. */ static int ! eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg) { typval_T var2; long result; *************** *** 1979,1985 **** /* * Get the first variable. */ ! if (eval4(arg, rettv, flags) == FAIL) return FAIL; /* --- 2045,2051 ---- /* * Get the first variable. */ ! if (eval4(arg, rettv, evalarg) == FAIL) return FAIL; /* *************** *** 1989,1996 **** result = TRUE; while ((*arg)[0] == '&' && (*arg)[1] == '&') { ! int evaluate = flags & EVAL_EVALUATE; ! if (evaluate && first) { if (tv_get_number_chk(rettv, &error) == 0) --- 2055,2076 ---- result = TRUE; while ((*arg)[0] == '&' && (*arg)[1] == '&') { ! 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,2011 **** * Get the second variable. */ *arg = skipwhite(*arg + 2); ! if (eval4(arg, &var2, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) return FAIL; /* --- 2085,2093 ---- * Get the second variable. */ *arg = skipwhite(*arg + 2); ! nested_evalarg.eval_flags = result ? orig_flags ! : orig_flags & ~EVAL_EVALUATE; ! if (eval4(arg, &var2, &nested_evalarg) == FAIL) return FAIL; /* *************** *** 2048,2054 **** * Return OK or FAIL. */ static int ! eval4(char_u **arg, typval_T *rettv, int flags) { typval_T var2; char_u *p; --- 2130,2136 ---- * Return OK or FAIL. */ static int ! eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg) { typval_T var2; char_u *p; *************** *** 2060,2066 **** /* * Get the first variable. */ ! if (eval5(arg, rettv, flags) == FAIL) return FAIL; p = *arg; --- 2142,2148 ---- /* * Get the first variable. */ ! if (eval5(arg, rettv, evalarg) == FAIL) return FAIL; p = *arg; *************** *** 2128,2139 **** * Get the second variable. */ *arg = skipwhite(p + len); ! if (eval5(arg, &var2, flags) == FAIL) { clear_tv(rettv); return FAIL; } ! if (flags & EVAL_EVALUATE) { int ret = typval_compare(rettv, &var2, type, ic); --- 2210,2221 ---- * Get the second variable. */ *arg = skipwhite(p + len); ! if (eval5(arg, &var2, evalarg) == FAIL) { clear_tv(rettv); return FAIL; } ! if (evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE)) { int ret = typval_compare(rettv, &var2, type, ic); *************** *** 2195,2217 **** * Return OK or FAIL. */ static int ! eval5(char_u **arg, typval_T *rettv, int flags) { ! 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; /* * Get the first variable. */ ! if (eval6(arg, rettv, flags, FALSE) == FAIL) return FAIL; /* --- 2277,2290 ---- * Return OK or FAIL. */ static int ! eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg) { ! int evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE); /* * Get the first variable. */ ! if (eval6(arg, rettv, evalarg, FALSE) == FAIL) return FAIL; /* *************** *** 2219,2230 **** */ for (;;) { // "." is only string concatenation when scriptversion is 1 ! op = **arg; ! concat = op == '.' ! && (*(*arg + 1) == '.' || current_sctx.sc_version < 2); if (op != '+' && op != '-' && !concat) break; if ((op != '+' || (rettv->v_type != VAR_LIST && rettv->v_type != VAR_BLOB)) --- 2292,2311 ---- */ for (;;) { + int getnext; + char_u *p; + int op; + int concat; + typval_T var2; + // "." is only string concatenation when scriptversion is 1 ! 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,2246 **** // 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) { clear_tv(rettv); return FAIL; --- 2321,2327 ---- // 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 (evaluate && tv_get_string_chk(rettv) == NULL) { clear_tv(rettv); return FAIL; *************** *** 2253,2273 **** if (op == '.' && *(*arg + 1) == '.') // .. string concatenation ++*arg; *arg = skipwhite(*arg + 1); ! if (eval6(arg, &var2, flags, op == '.') == FAIL) { clear_tv(rettv); return FAIL; } ! if (flags & EVAL_EVALUATE) { /* * Compute the result. */ if (op == '.') { ! s1 = tv_get_string_buf(rettv, buf1); // already checked ! s2 = tv_get_string_buf_chk(&var2, buf2); if (s2 == NULL) // type error ? { clear_tv(rettv); --- 2334,2356 ---- if (op == '.' && *(*arg + 1) == '.') // .. string concatenation ++*arg; *arg = skipwhite(*arg + 1); ! if (eval6(arg, &var2, evalarg, op == '.') == FAIL) { clear_tv(rettv); return FAIL; } ! if (evaluate) { /* * Compute the result. */ if (op == '.') { ! 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,2298 **** } else { ! int error = FALSE; ! #ifdef FEAT_FLOAT if (rettv->v_type == VAR_FLOAT) { f1 = rettv->vval.v_float; --- 2373,2383 ---- } else { ! 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,2387 **** eval6( char_u **arg, typval_T *rettv, ! int flags, int want_string) // after "." operator { typval_T var2; --- 2466,2472 ---- eval6( char_u **arg, typval_T *rettv, ! evalarg_T *evalarg, int want_string) // after "." operator { typval_T var2; *************** *** 2396,2402 **** /* * Get the first variable. */ ! if (eval7(arg, rettv, flags, want_string) == FAIL) return FAIL; /* --- 2481,2487 ---- /* * Get the first variable. */ ! if (eval7(arg, rettv, evalarg, want_string) == FAIL) return FAIL; /* *************** *** 2404,2414 **** */ for (;;) { ! op = **arg; if (op != '*' && op != '/' && op != '%') break; ! if (flags & EVAL_EVALUATE) { #ifdef FEAT_FLOAT if (rettv->v_type == VAR_FLOAT) --- 2489,2505 ---- */ for (;;) { ! 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 (getnext) + *arg = skipwhite(getsourceline(0, evalarg->eval_cookie, 0, TRUE)); ! if (evaluate) { #ifdef FEAT_FLOAT if (rettv->v_type == VAR_FLOAT) *************** *** 2431,2440 **** * Get the second variable. */ *arg = skipwhite(*arg + 1); ! if (eval7(arg, &var2, flags, FALSE) == FAIL) return FAIL; ! if (flags & EVAL_EVALUATE) { #ifdef FEAT_FLOAT if (var2.v_type == VAR_FLOAT) --- 2522,2531 ---- * Get the second variable. */ *arg = skipwhite(*arg + 1); ! if (eval7(arg, &var2, evalarg, FALSE) == FAIL) return FAIL; ! if (evaluate) { #ifdef FEAT_FLOAT if (var2.v_type == VAR_FLOAT) *************** *** 2551,2560 **** eval7( char_u **arg, typval_T *rettv, ! int flags, int want_string) // after "." operator { ! int evaluate = flags & EVAL_EVALUATE; int len; char_u *s; char_u *start_leader, *end_leader; --- 2642,2653 ---- eval7( char_u **arg, typval_T *rettv, ! evalarg_T *evalarg, int want_string) // after "." operator { ! 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,2686 **** /* * 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; } break; --- 2765,2781 ---- /* * nested expression: (expression). */ ! 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,3035 **** --- 3125,3135 ---- } else { + evalarg_T evalarg; + + CLEAR_FIELD(evalarg); + evalarg.eval_flags = flags; + /* * something[idx] * *************** *** 3038,3044 **** *arg = skipwhite(*arg + 1); if (**arg == ':') empty1 = TRUE; ! else if (eval1(arg, &var1, flags) == FAIL) // recursive! return FAIL; else if (evaluate && tv_get_string_chk(&var1) == NULL) { --- 3138,3144 ---- *arg = skipwhite(*arg + 1); if (**arg == ':') empty1 = TRUE; ! else if (eval1(arg, &var1, &evalarg) == FAIL) // recursive! return FAIL; else if (evaluate && tv_get_string_chk(&var1) == NULL) { *************** *** 3056,3062 **** *arg = skipwhite(*arg + 1); if (**arg == ']') empty2 = TRUE; ! else if (eval1(arg, &var2, flags) == FAIL) // recursive! { if (!empty1) clear_tv(&var1); --- 3156,3162 ---- *arg = skipwhite(*arg + 1); if (**arg == ']') empty2 = TRUE; ! else if (eval1(arg, &var2, &evalarg) == FAIL) // recursive! { if (!empty1) clear_tv(&var1); *************** *** 4947,4952 **** --- 5047,5056 ---- 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,4963 **** need_clr_eos = needclr; p = arg; ! if (eval1(&arg, &rettv, eap->skip ? 0 : EVAL_EVALUATE) == FAIL) { /* * Report the invalid expression unless the expression evaluation --- 5061,5067 ---- need_clr_eos = needclr; p = arg; ! if (eval1(&arg, &rettv, &evalarg) == FAIL) { /* * Report the invalid expression unless the expression evaluation *** ../vim-8.2.1046/src/proto/eval.pro 2020-06-07 14:50:47.271846855 +0200 --- src/proto/eval.pro 2020-06-24 15:29:48.293576760 +0200 *************** *** 26,33 **** 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); 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); --- 26,33 ---- 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, 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); *** ../vim-8.2.1046/src/dict.c 2020-06-07 20:49:02.073891895 +0200 --- src/dict.c 2020-06-24 15:17:09.663805921 +0200 *************** *** 788,799 **** --- 788,801 ---- /* * 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,808 **** --- 805,813 ---- 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,818 **** */ if (!vim9script && *start != '}') { ! if (eval1(&start, &tv, 0) == FAIL) // recursive! return FAIL; if (*start == '}') return NOTDONE; --- 817,823 ---- */ if (!vim9script && *start != '}') { ! if (eval1(&start, &tv, NULL) == FAIL) // recursive! return FAIL; if (*start == '}') return NOTDONE; *************** *** 832,838 **** { if ((literal ? get_literal_key(arg, &tvkey) ! : eval1(arg, &tvkey, flags)) == FAIL) // recursive! goto failret; if (**arg != ':') --- 837,843 ---- { if ((literal ? get_literal_key(arg, &tvkey) ! : eval1(arg, &tvkey, &evalarg)) == FAIL) // recursive! goto failret; if (**arg != ':') *************** *** 854,860 **** } *arg = skipwhite(*arg + 1); ! if (eval1(arg, &tv, flags) == FAIL) // recursive! { if (evaluate) clear_tv(&tvkey); --- 859,865 ---- } *arg = skipwhite(*arg + 1); ! if (eval1(arg, &tv, &evalarg) == FAIL) // recursive! { if (evaluate) clear_tv(&tvkey); *** ../vim-8.2.1046/src/evalfunc.c 2020-06-22 19:10:51.685755111 +0200 --- src/evalfunc.c 2020-06-24 15:10:58.576743921 +0200 *************** *** 2084,2090 **** s = skipwhite(s); p = s; ! if (s == NULL || eval1(&s, rettv, EVAL_EVALUATE) == FAIL) { if (p != NULL && !aborting()) semsg(_(e_invexpr2), p); --- 2084,2090 ---- s = skipwhite(s); p = s; ! if (s == NULL || eval1(&s, rettv, &EVALARG_EVALUATE) == FAIL) { if (p != NULL && !aborting()) semsg(_(e_invexpr2), p); *** ../vim-8.2.1046/src/evalvars.c 2020-06-21 15:52:55.810451610 +0200 --- src/evalvars.c 2020-06-24 17:48:46.152783688 +0200 *************** *** 435,441 **** if (p_verbose == 0) ++emsg_off; ! if (eval1(&p, &rettv, EVAL_EVALUATE) == OK) { if (rettv.v_type != VAR_LIST) clear_tv(&rettv); --- 435,441 ---- if (p_verbose == 0) ++emsg_off; ! if (eval1(&p, &rettv, &EVALARG_EVALUATE) == OK) { if (rettv.v_type != VAR_LIST) clear_tv(&rettv); *************** *** 774,780 **** } else { ! int eval_flags; rettv.v_type = VAR_UNKNOWN; i = FAIL; --- 774,780 ---- } else { ! evalarg_T evalarg; rettv.v_type = VAR_UNKNOWN; i = FAIL; *************** *** 797,810 **** if (eap->skip) ++emsg_skip; ! eval_flags = eap->skip ? 0 : EVAL_EVALUATE; ! i = eval0(expr, &rettv, &eap->nextcmd, eval_flags); } if (eap->skip) { if (i != FAIL) clear_tv(&rettv); - --emsg_skip; } else if (i != FAIL) { --- 797,813 ---- if (eap->skip) ++emsg_skip; ! 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); } else if (i != FAIL) { *** ../vim-8.2.1046/src/list.c 2020-06-16 11:34:38.314223444 +0200 --- src/list.c 2020-06-24 15:12:29.432513898 +0200 *************** *** 1165,1170 **** --- 1165,1174 ---- list_T *l = NULL; typval_T tv; listitem_T *item; + evalarg_T evalarg; + + CLEAR_FIELD(evalarg); + evalarg.eval_flags = flags; if (evaluate) { *************** *** 1176,1182 **** *arg = skipwhite(*arg + 1); while (**arg != ']' && **arg != NUL) { ! if (eval1(arg, &tv, flags) == FAIL) // recursive! goto failret; if (evaluate) { --- 1180,1186 ---- *arg = skipwhite(*arg + 1); while (**arg != ']' && **arg != NUL) { ! if (eval1(arg, &tv, &evalarg) == FAIL) // recursive! goto failret; if (evaluate) { *** ../vim-8.2.1046/src/userfunc.c 2020-06-20 22:50:44.175608236 +0200 --- src/userfunc.c 2020-06-24 18:12:28.057560263 +0200 *************** *** 239,245 **** whitep = p; p = skipwhite(p); expr = p; ! if (eval1(&p, &rettv, 0) != FAIL) { if (ga_grow(default_args, 1) == FAIL) goto err_ret; --- 239,245 ---- whitep = p; p = skipwhite(p); expr = p; ! if (eval1(&p, &rettv, NULL) != FAIL) { if (ga_grow(default_args, 1) == FAIL) goto err_ret; *************** *** 561,566 **** --- 561,570 ---- 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,579 **** argp = skipwhite(argp + 1); // skip the '(' or ',' if (*argp == ')' || *argp == ',' || *argp == NUL) break; ! if (eval1(&argp, &argvars[argcount], ! funcexe->evaluate ? EVAL_EVALUATE : 0) == FAIL) { ret = FAIL; break; --- 576,582 ---- argp = skipwhite(argp + 1); // skip the '(' or ',' if (*argp == ')' || *argp == ',' || *argp == NUL) break; ! if (eval1(&argp, &argvars[argcount], &evalarg) == FAIL) { ret = FAIL; break; *************** *** 1249,1255 **** 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) { default_arg_err = 1; break; --- 1252,1258 ---- default_expr = ((char_u **)(fp->uf_def_args.ga_data)) [ai + fp->uf_def_args.ga_len]; ! if (eval1(&default_expr, &def_rettv, &EVALARG_EVALUATE) == FAIL) { default_arg_err = 1; break; *************** *** 1394,1400 **** // 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); --ex_nesting_level; } else --- 1397,1403 ---- // A Lambda always has the command "return {expr}". It is much faster // to evaluate {expr} directly. ++ex_nesting_level; ! (void)eval1(&p, rettv, &EVALARG_EVALUATE); --ex_nesting_level; } else *************** *** 3697,3702 **** --- 3700,3706 ---- char_u *arg = eap->arg; typval_T rettv; int returning = FALSE; + evalarg_T evalarg; if (current_funccal == NULL) { *************** *** 3704,3716 **** return; } 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) { if (!eap->skip) returning = do_return(eap, FALSE, TRUE, &rettv); --- 3708,3722 ---- 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, &evalarg) != FAIL) { if (!eap->skip) returning = do_return(eap, FALSE, TRUE, &rettv); *************** *** 3767,3773 **** // 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) clear_tv(&rettv); --emsg_skip; return; --- 3773,3779 ---- // 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, NULL) != FAIL) clear_tv(&rettv); --emsg_skip; return; *** ../vim-8.2.1046/src/scriptfile.c 2020-06-20 22:50:44.175608236 +0200 --- src/scriptfile.c 2020-06-24 14:35:18.694204892 +0200 *************** *** 1050,1055 **** --- 1050,1064 ---- { 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) *** ../vim-8.2.1046/src/proto/scriptfile.pro 2020-05-25 22:36:46.629735032 +0200 --- src/proto/scriptfile.pro 2020-06-24 15:16:55.911840634 +0200 *************** *** 22,27 **** --- 22,28 ---- 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); *** ../vim-8.2.1046/src/testdir/test_vim9_expr.vim 2020-06-23 22:26:01.893386768 +0200 --- src/testdir/test_vim9_expr.vim 2020-06-24 17:23:25.596076339 +0200 *************** *** 570,575 **** --- 570,595 ---- 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,666 **** --- 681,706 ---- 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' *** ../vim-8.2.1046/src/version.c 2020-06-24 13:37:03.162425194 +0200 --- src/version.c 2020-06-24 17:07:37.269316749 +0200 *************** *** 756,757 **** --- 756,759 ---- { /* Add new patch number below this line */ + /**/ + 1047, /**/ -- Q: Why does /dev/null accept only integers? A: You can't sink a float. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///