To: vim_dev@googlegroups.com Subject: Patch 8.2.1110 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.1110 Problem: Vim9: line continuation does not work in function arguments. Solution: Pass "evalarg" to get_func_tv(). Fix seeing double quoted string as comment. Files: src/userfunc.c, src/proto/userfunc.pro, src/eval.c, src/ex_eval.c, src/list.c, src/dict.c, src/proto/eval.pro, src/testdir/test_vim9_expr.vim, src/testdir/test_vim9_func.vim *** ../vim-8.2.1109/src/userfunc.c 2020-06-29 20:20:28.047899632 +0200 --- src/userfunc.c 2020-07-01 16:17:08.795558275 +0200 *************** *** 601,616 **** int len, // length of "name" or -1 to use strlen() typval_T *rettv, char_u **arg, // argument, pointing to the '(' 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. --- 601,613 ---- 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 /* * Get the arguments. *************** *** 619,628 **** while (argcount < MAX_FUNC_ARGS - (funcexe->partial == NULL ? 0 : funcexe->partial->pt_argc)) { ! argp = skipwhite(argp + 1); // skip the '(' or ',' if (*argp == ')' || *argp == ',' || *argp == NUL) break; ! if (eval1(&argp, &argvars[argcount], &evalarg) == FAIL) { ret = FAIL; break; --- 616,627 ---- while (argcount < MAX_FUNC_ARGS - (funcexe->partial == NULL ? 0 : funcexe->partial->pt_argc)) { ! // 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) { ret = FAIL; break; *************** *** 631,636 **** --- 630,636 ---- if (*argp != ',') break; } + argp = skipwhite_and_linebreak(argp, evalarg); if (*argp == ')') ++argp; else *************** *** 3832,3847 **** int failed = FALSE; funcdict_T fudi; partial_T *partial = NULL; 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) clear_tv(&rettv); --emsg_skip; return; } --- 3832,3850 ---- 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, &evalarg) != FAIL) clear_tv(&rettv); --emsg_skip; + clear_evalarg(&evalarg, eap); return; } *************** *** 3918,3924 **** funcexe.evaluate = !eap->skip; funcexe.partial = partial; funcexe.selfdict = fudi.fd_dict; ! if (get_func_tv(name, -1, &rettv, &arg, &funcexe) == FAIL) { failed = TRUE; break; --- 3921,3927 ---- funcexe.evaluate = !eap->skip; funcexe.partial = partial; funcexe.selfdict = fudi.fd_dict; ! if (get_func_tv(name, -1, &rettv, &arg, &evalarg, &funcexe) == FAIL) { failed = TRUE; break; *************** *** 3947,3952 **** --- 3950,3956 ---- } 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) *** ../vim-8.2.1109/src/proto/userfunc.pro 2020-06-27 18:06:42.152575113 +0200 --- src/proto/userfunc.pro 2020-07-01 16:15:05.368237127 +0200 *************** *** 7,13 **** 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); 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); --- 7,13 ---- 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, 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); *** ../vim-8.2.1109/src/eval.c 2020-07-01 13:07:34.261146025 +0200 --- src/eval.c 2020-07-01 17:07:29.031461006 +0200 *************** *** 153,159 **** } #endif ! static void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip) { CLEAR_FIELD(*evalarg); --- 153,159 ---- } #endif ! void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip) { CLEAR_FIELD(*evalarg); *************** *** 1804,1809 **** --- 1804,1810 ---- 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,1845 **** funcexe.evaluate = evaluate; funcexe.partial = partial; funcexe.basetv = basetv; ! ret = get_func_tv(s, len, rettv, arg, &funcexe); } vim_free(s); --- 1840,1846 ---- funcexe.evaluate = evaluate; funcexe.partial = partial; funcexe.basetv = basetv; ! ret = get_func_tv(s, len, rettv, arg, evalarg, &funcexe); } vim_free(s); *************** *** 1917,1922 **** --- 1918,1926 ---- 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,1935 **** --- 1934,1953 ---- } /* + * 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,3001 **** else { if (**arg == '(') // recursive! ! ret = eval_func(arg, s, len, rettv, flags, NULL); else if (flags & EVAL_CONSTANT) ret = FAIL; else if (evaluate) --- 3013,3019 ---- else { if (**arg == '(') // recursive! ! ret = eval_func(arg, evalarg, s, len, rettv, flags, NULL); else if (flags & EVAL_CONSTANT) ret = FAIL; else if (evaluate) *************** *** 3106,3111 **** --- 3124,3130 ---- static int call_func_rettv( char_u **arg, + evalarg_T *evalarg, typval_T *rettv, int evaluate, dict_T *selfdict, *************** *** 3142,3148 **** funcexe.partial = pt; funcexe.selfdict = selfdict; funcexe.basetv = basetv; ! ret = get_func_tv(s, -1, rettv, arg, &funcexe); // Clear the funcref afterwards, so that deleting it while // evaluating the arguments is possible (see test55). --- 3161,3167 ---- funcexe.partial = pt; funcexe.selfdict = selfdict; funcexe.basetv = basetv; ! 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,3195 **** ret = FAIL; } else ! ret = call_func_rettv(arg, rettv, evaluate, NULL, &base); // Clear the funcref afterwards, so that deleting it while // evaluating the arguments is possible (see test55). --- 3208,3214 ---- ret = FAIL; } else ! 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,3214 **** eval_method( char_u **arg, typval_T *rettv, ! int evaluate, int verbose) // give error messages { char_u *name; --- 3227,3233 ---- eval_method( char_u **arg, typval_T *rettv, ! evalarg_T *evalarg, int verbose) // give error messages { char_u *name; *************** *** 3216,3221 **** --- 3235,3242 ---- char_u *alias; typval_T base = *rettv; int ret; + int evaluate = evalarg != NULL + && (evalarg->eval_flags & EVAL_EVALUATE); // Skip over the ->. *arg += 2; *************** *** 3247,3253 **** ret = FAIL; } else ! ret = eval_func(arg, name, len, rettv, evaluate ? EVAL_EVALUATE : 0, &base); } --- 3268,3274 ---- ret = FAIL; } else ! ret = eval_func(arg, evalarg, name, len, rettv, evaluate ? EVAL_EVALUATE : 0, &base); } *************** *** 5035,5041 **** { if (**arg == '(') { ! ret = call_func_rettv(arg, rettv, evaluate, selfdict, NULL); // Stop the expression evaluation when immediately aborting on // error, or when an interrupt occurred or an exception was thrown --- 5056,5063 ---- { if (**arg == '(') { ! 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,5064 **** ret = eval_lambda(arg, rettv, evalarg, verbose); else // expr->name() ! ret = eval_method(arg, rettv, evaluate, verbose); } } else // **arg == '[' || **arg == '.' --- 5080,5086 ---- ret = eval_lambda(arg, rettv, evalarg, verbose); else // expr->name() ! ret = eval_method(arg, rettv, evalarg, verbose); } } else // **arg == '[' || **arg == '.' *** ../vim-8.2.1109/src/ex_eval.c 2020-06-28 18:43:36.296992324 +0200 --- src/ex_eval.c 2020-07-01 16:37:14.715189132 +0200 *************** *** 897,909 **** 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; ! } if (eval0(eap->arg, &tv, eap, &evalarg) == OK) clear_tv(&tv); --- 897,903 ---- typval_T tv; evalarg_T evalarg; ! fill_evalarg_from_eap(&evalarg, eap, eap->skip); if (eval0(eap->arg, &tv, eap, &evalarg) == OK) clear_tv(&tv); *** ../vim-8.2.1109/src/list.c 2020-06-29 20:09:33.266762870 +0200 --- src/list.c 2020-07-01 17:19:20.750886757 +0200 *************** *** 1177,1183 **** return FAIL; } ! *arg = skipwhite_and_linebreak(*arg + 1, evalarg); while (**arg != ']' && **arg != NUL) { if (eval1(arg, &tv, evalarg) == FAIL) // recursive! --- 1177,1183 ---- return FAIL; } ! *arg = skipwhite_and_linebreak_keep_string(*arg + 1, evalarg); while (**arg != ']' && **arg != NUL) { if (eval1(arg, &tv, evalarg) == FAIL) // recursive! *************** *** 1207,1214 **** *arg = skipwhite(*arg + 1); } ! // the "]" can be on the next line ! *arg = skipwhite_and_linebreak(*arg, evalarg); if (**arg == ']') break; --- 1207,1215 ---- *arg = skipwhite(*arg + 1); } ! // 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,2362 **** } if (l != NULL) { ! list_insert_tv(l, &argvars[1], item); copy_tv(&argvars[0], rettv); } } --- 2357,2363 ---- } if (l != NULL) { ! (void)list_insert_tv(l, &argvars[1], item); copy_tv(&argvars[0], rettv); } } *** ../vim-8.2.1109/src/dict.c 2020-06-27 21:17:55.359214424 +0200 --- src/dict.c 2020-07-01 17:21:16.610157312 +0200 *************** *** 830,836 **** tvkey.v_type = VAR_UNKNOWN; tv.v_type = VAR_UNKNOWN; ! *arg = skipwhite_and_linebreak(*arg + 1, evalarg); while (**arg != '}' && **arg != NUL) { if ((literal --- 830,836 ---- tvkey.v_type = VAR_UNKNOWN; tv.v_type = VAR_UNKNOWN; ! *arg = skipwhite_and_linebreak_keep_string(*arg + 1, evalarg); while (**arg != '}' && **arg != NUL) { if ((literal *************** *** 862,868 **** goto failret; } ! *arg = skipwhite_and_linebreak(*arg + 1, evalarg); if (eval1(arg, &tv, evalarg) == FAIL) // recursive! { if (evaluate) --- 862,868 ---- goto failret; } ! *arg = skipwhite_and_linebreak_keep_string(*arg + 1, evalarg); if (eval1(arg, &tv, evalarg) == FAIL) // recursive! { if (evaluate) *************** *** 904,910 **** } // the "}" can be on the next line ! *arg = skipwhite_and_linebreak(*arg, evalarg); if (**arg == '}') break; if (!had_comma) --- 904,910 ---- } // the "}" can be on the next line ! *arg = skipwhite_and_linebreak_keep_string(*arg, evalarg); if (**arg == '}') break; if (!had_comma) *** ../vim-8.2.1109/src/proto/eval.pro 2020-06-28 18:43:36.296992324 +0200 --- src/proto/eval.pro 2020-07-01 17:12:53.277350109 +0200 *************** *** 3,8 **** --- 3,9 ---- 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,36 **** --- 32,38 ---- 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); *** ../vim-8.2.1109/src/testdir/test_vim9_expr.vim 2020-06-27 21:17:55.359214424 +0200 --- src/testdir/test_vim9_expr.vim 2020-07-01 17:11:54.829726236 +0200 *************** *** 1101,1106 **** --- 1101,1113 ---- 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, } *** ../vim-8.2.1109/src/testdir/test_vim9_func.vim 2020-06-30 13:37:57.931017122 +0200 --- src/testdir/test_vim9_func.vim 2020-07-01 16:29:48.046272595 +0200 *************** *** 353,358 **** --- 353,374 ---- 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 *** ../vim-8.2.1109/src/version.c 2020-07-01 16:00:39.936953109 +0200 --- src/version.c 2020-07-01 17:27:14.211918264 +0200 *************** *** 756,757 **** --- 756,759 ---- { /* Add new patch number below this line */ + /**/ + 1110, /**/ -- I used to wonder about the meaning of life. But I looked it up in the dictionary under "L" and there it was - the meaning of life. It was less than I expected. - Dogbert /// 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 ///