# HG changeset patch # User Bram Moolenaar # Date 1593617406 -7200 # Node ID b0baa80cb53f2d68d03944680d5ac6c04847825c # Parent 0aa8873aa305bbe3c00b1ad5ff1c704880876692 patch 8.2.1110: Vim9: line continuation does not work in function arguments Commit: https://github.com/vim/vim/commit/e6b5324e3a3d354363f3c48e784c42ce3e77453f Author: Bram Moolenaar Date: Wed Jul 1 17:28:33 2020 +0200 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. diff --git a/src/dict.c b/src/dict.c --- a/src/dict.c +++ b/src/dict.c @@ -830,7 +830,7 @@ eval_dict(char_u **arg, typval_T *rettv, tvkey.v_type = VAR_UNKNOWN; tv.v_type = VAR_UNKNOWN; - *arg = skipwhite_and_linebreak(*arg + 1, evalarg); + *arg = skipwhite_and_linebreak_keep_string(*arg + 1, evalarg); while (**arg != '}' && **arg != NUL) { if ((literal @@ -862,7 +862,7 @@ eval_dict(char_u **arg, typval_T *rettv, goto failret; } - *arg = skipwhite_and_linebreak(*arg + 1, evalarg); + *arg = skipwhite_and_linebreak_keep_string(*arg + 1, evalarg); if (eval1(arg, &tv, evalarg) == FAIL) // recursive! { if (evaluate) @@ -904,7 +904,7 @@ eval_dict(char_u **arg, typval_T *rettv, } // the "}" can be on the next line - *arg = skipwhite_and_linebreak(*arg, evalarg); + *arg = skipwhite_and_linebreak_keep_string(*arg, evalarg); if (**arg == '}') break; if (!had_comma) diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -153,7 +153,7 @@ eval_clear(void) } #endif - static void + void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip) { CLEAR_FIELD(*evalarg); @@ -1804,6 +1804,7 @@ pattern_match(char_u *pat, char_u *text, static int eval_func( char_u **arg, // points to "(", will be advanced + evalarg_T *evalarg, char_u *name, int name_len, typval_T *rettv, @@ -1839,7 +1840,7 @@ eval_func( funcexe.evaluate = evaluate; funcexe.partial = partial; funcexe.basetv = basetv; - ret = get_func_tv(s, len, rettv, arg, &funcexe); + ret = get_func_tv(s, len, rettv, arg, evalarg, &funcexe); } vim_free(s); @@ -1917,6 +1918,9 @@ eval_next_line(evalarg_T *evalarg) return skipwhite(line); } +/* + * Call eval_next_non_blank() and get the next line if needed. + */ char_u * skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg) { @@ -1930,6 +1934,20 @@ skipwhite_and_linebreak(char_u *arg, eva } /* + * Call eval_next_non_blank() and get the next line if needed, but not when a + * double quote follows. Used inside an expression. + */ + char_u * +skipwhite_and_linebreak_keep_string(char_u *arg, evalarg_T *evalarg) +{ + char_u *p = skipwhite(arg); + + if (*p == '"') + return p; + return skipwhite_and_linebreak(arg, evalarg); +} + +/* * After using "evalarg" filled from "eap" free the memory. */ void @@ -2995,7 +3013,7 @@ eval7( 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 (flags & EVAL_CONSTANT) ret = FAIL; else if (evaluate) @@ -3106,6 +3124,7 @@ eval7_leader( static int call_func_rettv( char_u **arg, + evalarg_T *evalarg, typval_T *rettv, int evaluate, dict_T *selfdict, @@ -3142,7 +3161,7 @@ call_func_rettv( funcexe.partial = pt; funcexe.selfdict = selfdict; funcexe.basetv = basetv; - ret = get_func_tv(s, -1, rettv, arg, &funcexe); + ret = get_func_tv(s, -1, rettv, arg, evalarg, &funcexe); // Clear the funcref afterwards, so that deleting it while // evaluating the arguments is possible (see test55). @@ -3189,7 +3208,7 @@ eval_lambda( ret = FAIL; } else - ret = call_func_rettv(arg, rettv, evaluate, NULL, &base); + ret = call_func_rettv(arg, evalarg, rettv, evaluate, NULL, &base); // Clear the funcref afterwards, so that deleting it while // evaluating the arguments is possible (see test55). @@ -3208,7 +3227,7 @@ eval_lambda( eval_method( char_u **arg, typval_T *rettv, - int evaluate, + evalarg_T *evalarg, int verbose) // give error messages { char_u *name; @@ -3216,6 +3235,8 @@ eval_method( char_u *alias; typval_T base = *rettv; int ret; + int evaluate = evalarg != NULL + && (evalarg->eval_flags & EVAL_EVALUATE); // Skip over the ->. *arg += 2; @@ -3247,7 +3268,7 @@ eval_method( ret = FAIL; } else - ret = eval_func(arg, name, len, rettv, + ret = eval_func(arg, evalarg, name, len, rettv, evaluate ? EVAL_EVALUATE : 0, &base); } @@ -5035,7 +5056,8 @@ handle_subscript( { if (**arg == '(') { - ret = call_func_rettv(arg, rettv, evaluate, selfdict, NULL); + ret = call_func_rettv(arg, evalarg, rettv, evaluate, + selfdict, NULL); // Stop the expression evaluation when immediately aborting on // error, or when an interrupt occurred or an exception was thrown @@ -5058,7 +5080,7 @@ handle_subscript( ret = eval_lambda(arg, rettv, evalarg, verbose); else // expr->name() - ret = eval_method(arg, rettv, evaluate, verbose); + ret = eval_method(arg, rettv, evalarg, verbose); } } else // **arg == '[' || **arg == '.' diff --git a/src/ex_eval.c b/src/ex_eval.c --- a/src/ex_eval.c +++ b/src/ex_eval.c @@ -897,13 +897,7 @@ ex_eval(exarg_T *eap) typval_T tv; evalarg_T evalarg; - CLEAR_FIELD(evalarg); - 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->skip); if (eval0(eap->arg, &tv, eap, &evalarg) == OK) clear_tv(&tv); diff --git a/src/list.c b/src/list.c --- a/src/list.c +++ b/src/list.c @@ -1177,7 +1177,7 @@ get_list_tv(char_u **arg, typval_T *rett return FAIL; } - *arg = skipwhite_and_linebreak(*arg + 1, evalarg); + *arg = skipwhite_and_linebreak_keep_string(*arg + 1, evalarg); while (**arg != ']' && **arg != NUL) { if (eval1(arg, &tv, evalarg) == FAIL) // recursive! @@ -1207,8 +1207,9 @@ get_list_tv(char_u **arg, typval_T *rett *arg = skipwhite(*arg + 1); } - // the "]" can be on the next line - *arg = skipwhite_and_linebreak(*arg, evalarg); + // The "]" can be on the next line. But a double quoted string may + // follow, not a comment. + *arg = skipwhite_and_linebreak_keep_string(*arg, evalarg); if (**arg == ']') break; @@ -2356,7 +2357,7 @@ f_insert(typval_T *argvars, typval_T *re } if (l != NULL) { - list_insert_tv(l, &argvars[1], item); + (void)list_insert_tv(l, &argvars[1], item); copy_tv(&argvars[0], rettv); } } diff --git a/src/proto/eval.pro b/src/proto/eval.pro --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -3,6 +3,7 @@ varnumber_T num_divide(varnumber_T n1, v varnumber_T num_modulus(varnumber_T n1, varnumber_T n2); void eval_init(void); void eval_clear(void); +void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip); int eval_to_bool(char_u *arg, int *error, exarg_T *eap, int skip); int eval_expr_valid_arg(typval_T *tv); int eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv); @@ -31,6 +32,7 @@ int pattern_match(char_u *pat, char_u *t char_u *eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext); char_u *eval_next_line(evalarg_T *evalarg); char_u *skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg); +char_u *skipwhite_and_linebreak_keep_string(char_u *arg, evalarg_T *evalarg); void clear_evalarg(evalarg_T *evalarg, exarg_T *eap); int eval0(char_u *arg, typval_T *rettv, exarg_T *eap, evalarg_T *evalarg); int eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg); diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro --- a/src/proto/userfunc.pro +++ b/src/proto/userfunc.pro @@ -7,7 +7,7 @@ char_u *register_cfunc(cfunc_T cb, cfunc int get_lambda_tv(char_u **arg, typval_T *rettv, evalarg_T *evalarg); char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload); void emsg_funcname(char *ermsg, char_u *name); -int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, funcexe_T *funcexe); +int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, evalarg_T *evalarg, funcexe_T *funcexe); char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error); ufunc_T *find_func(char_u *name, int is_global, cctx_T *cctx); int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict); 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 @@ -1101,6 +1101,13 @@ def Test_expr7_dict_vim9script() lines =<< trim END vim9script + let d = { "one": "one", "two": "two", } + assert_equal({'one': 'one', 'two': 'two'}, d) + END + CheckScriptSuccess(lines) + + lines =<< trim END + vim9script let d = #{one: 1, two: 2, } diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -353,6 +353,22 @@ def Test_vim9script_call() assert_equal('text', var) ("some")->MyFunc() assert_equal('some', var) + + MyFunc( + 'continued' + ) + assert_equal('continued', + var + ) + + call MyFunc( + 'more' + .. + 'lines' + ) + assert_equal( + 'morelines', + var) END writefile(lines, 'Xcall.vim') source Xcall.vim diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -601,16 +601,13 @@ get_func_tv( int len, // length of "name" or -1 to use strlen() typval_T *rettv, char_u **arg, // argument, pointing to the '(' + evalarg_T *evalarg, // for line continuation funcexe_T *funcexe) // various values { char_u *argp; 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. @@ -619,10 +616,12 @@ get_func_tv( while (argcount < MAX_FUNC_ARGS - (funcexe->partial == NULL ? 0 : funcexe->partial->pt_argc)) { - argp = skipwhite(argp + 1); // skip the '(' or ',' + // skip the '(' or ',' and possibly line breaks + argp = skipwhite_and_linebreak(argp + 1, evalarg); + if (*argp == ')' || *argp == ',' || *argp == NUL) break; - if (eval1(&argp, &argvars[argcount], &evalarg) == FAIL) + if (eval1(&argp, &argvars[argcount], evalarg) == FAIL) { ret = FAIL; break; @@ -631,6 +630,7 @@ get_func_tv( if (*argp != ',') break; } + argp = skipwhite_and_linebreak(argp, evalarg); if (*argp == ')') ++argp; else @@ -3832,16 +3832,19 @@ ex_call(exarg_T *eap) int 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) clear_tv(&rettv); --emsg_skip; + clear_evalarg(&evalarg, eap); return; } @@ -3918,7 +3921,7 @@ ex_call(exarg_T *eap) funcexe.evaluate = !eap->skip; funcexe.partial = partial; funcexe.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; @@ -3947,6 +3950,7 @@ ex_call(exarg_T *eap) } if (eap->skip) --emsg_skip; + clear_evalarg(&evalarg, eap); // When inside :try we need to check for following "| catch". if (!failed || eap->cstack->cs_trylevel > 0) 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 */ /**/ + 1110, +/**/ 1109, /**/ 1108,