1
0
forked from aniani/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.
This commit is contained in:
Bram Moolenaar 2020-07-01 17:28:33 +02:00
parent 086eb18ba1
commit e6b5324e3a
10 changed files with 80 additions and 32 deletions

View File

@ -830,7 +830,7 @@ eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal)
tvkey.v_type = VAR_UNKNOWN; tvkey.v_type = VAR_UNKNOWN;
tv.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) while (**arg != '}' && **arg != NUL)
{ {
if ((literal if ((literal
@ -862,7 +862,7 @@ eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal)
goto failret; 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 (eval1(arg, &tv, evalarg) == FAIL) // recursive!
{ {
if (evaluate) if (evaluate)
@ -904,7 +904,7 @@ eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal)
} }
// the "}" can be on the next line // the "}" can be on the next line
*arg = skipwhite_and_linebreak(*arg, evalarg); *arg = skipwhite_and_linebreak_keep_string(*arg, evalarg);
if (**arg == '}') if (**arg == '}')
break; break;
if (!had_comma) if (!had_comma)

View File

@ -153,7 +153,7 @@ eval_clear(void)
} }
#endif #endif
static void void
fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip) fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip)
{ {
CLEAR_FIELD(*evalarg); CLEAR_FIELD(*evalarg);
@ -1804,6 +1804,7 @@ pattern_match(char_u *pat, char_u *text, int ic)
static int static int
eval_func( eval_func(
char_u **arg, // points to "(", will be advanced char_u **arg, // points to "(", will be advanced
evalarg_T *evalarg,
char_u *name, char_u *name,
int name_len, int name_len,
typval_T *rettv, typval_T *rettv,
@ -1839,7 +1840,7 @@ eval_func(
funcexe.evaluate = evaluate; funcexe.evaluate = evaluate;
funcexe.partial = partial; funcexe.partial = partial;
funcexe.basetv = basetv; 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); vim_free(s);
@ -1917,6 +1918,9 @@ eval_next_line(evalarg_T *evalarg)
return skipwhite(line); return skipwhite(line);
} }
/*
* Call eval_next_non_blank() and get the next line if needed.
*/
char_u * char_u *
skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg) skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg)
{ {
@ -1929,6 +1933,20 @@ skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg)
return p; return p;
} }
/*
* 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. * After using "evalarg" filled from "eap" free the memory.
*/ */
@ -2995,7 +3013,7 @@ eval7(
else else
{ {
if (**arg == '(') // recursive! 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) else if (flags & EVAL_CONSTANT)
ret = FAIL; ret = FAIL;
else if (evaluate) else if (evaluate)
@ -3106,6 +3124,7 @@ eval7_leader(
static int static int
call_func_rettv( call_func_rettv(
char_u **arg, char_u **arg,
evalarg_T *evalarg,
typval_T *rettv, typval_T *rettv,
int evaluate, int evaluate,
dict_T *selfdict, dict_T *selfdict,
@ -3142,7 +3161,7 @@ call_func_rettv(
funcexe.partial = pt; funcexe.partial = pt;
funcexe.selfdict = selfdict; funcexe.selfdict = selfdict;
funcexe.basetv = basetv; 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 // Clear the funcref afterwards, so that deleting it while
// evaluating the arguments is possible (see test55). // evaluating the arguments is possible (see test55).
@ -3189,7 +3208,7 @@ eval_lambda(
ret = FAIL; ret = FAIL;
} }
else 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 // Clear the funcref afterwards, so that deleting it while
// evaluating the arguments is possible (see test55). // evaluating the arguments is possible (see test55).
@ -3208,7 +3227,7 @@ eval_lambda(
eval_method( eval_method(
char_u **arg, char_u **arg,
typval_T *rettv, typval_T *rettv,
int evaluate, evalarg_T *evalarg,
int verbose) // give error messages int verbose) // give error messages
{ {
char_u *name; char_u *name;
@ -3216,6 +3235,8 @@ eval_method(
char_u *alias; char_u *alias;
typval_T base = *rettv; typval_T base = *rettv;
int ret; int ret;
int evaluate = evalarg != NULL
&& (evalarg->eval_flags & EVAL_EVALUATE);
// Skip over the ->. // Skip over the ->.
*arg += 2; *arg += 2;
@ -3247,7 +3268,7 @@ eval_method(
ret = FAIL; ret = FAIL;
} }
else else
ret = eval_func(arg, name, len, rettv, ret = eval_func(arg, evalarg, name, len, rettv,
evaluate ? EVAL_EVALUATE : 0, &base); evaluate ? EVAL_EVALUATE : 0, &base);
} }
@ -5035,7 +5056,8 @@ handle_subscript(
{ {
if (**arg == '(') 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 // Stop the expression evaluation when immediately aborting on
// error, or when an interrupt occurred or an exception was thrown // error, or when an interrupt occurred or an exception was thrown
@ -5058,7 +5080,7 @@ handle_subscript(
ret = eval_lambda(arg, rettv, evalarg, verbose); ret = eval_lambda(arg, rettv, evalarg, verbose);
else else
// expr->name() // expr->name()
ret = eval_method(arg, rettv, evaluate, verbose); ret = eval_method(arg, rettv, evalarg, verbose);
} }
} }
else // **arg == '[' || **arg == '.' else // **arg == '[' || **arg == '.'

View File

@ -897,13 +897,7 @@ ex_eval(exarg_T *eap)
typval_T tv; typval_T tv;
evalarg_T evalarg; evalarg_T evalarg;
CLEAR_FIELD(evalarg); fill_evalarg_from_eap(&evalarg, eap, eap->skip);
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) if (eval0(eap->arg, &tv, eap, &evalarg) == OK)
clear_tv(&tv); clear_tv(&tv);

View File

@ -1177,7 +1177,7 @@ get_list_tv(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int do_error)
return FAIL; return FAIL;
} }
*arg = skipwhite_and_linebreak(*arg + 1, evalarg); *arg = skipwhite_and_linebreak_keep_string(*arg + 1, evalarg);
while (**arg != ']' && **arg != NUL) while (**arg != ']' && **arg != NUL)
{ {
if (eval1(arg, &tv, evalarg) == FAIL) // recursive! if (eval1(arg, &tv, evalarg) == FAIL) // recursive!
@ -1207,8 +1207,9 @@ get_list_tv(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int do_error)
*arg = skipwhite(*arg + 1); *arg = skipwhite(*arg + 1);
} }
// the "]" can be on the next line // The "]" can be on the next line. But a double quoted string may
*arg = skipwhite_and_linebreak(*arg, evalarg); // follow, not a comment.
*arg = skipwhite_and_linebreak_keep_string(*arg, evalarg);
if (**arg == ']') if (**arg == ']')
break; break;
@ -2356,7 +2357,7 @@ f_insert(typval_T *argvars, typval_T *rettv)
} }
if (l != NULL) if (l != NULL)
{ {
list_insert_tv(l, &argvars[1], item); (void)list_insert_tv(l, &argvars[1], item);
copy_tv(&argvars[0], rettv); copy_tv(&argvars[0], rettv);
} }
} }

View File

@ -3,6 +3,7 @@ varnumber_T num_divide(varnumber_T n1, varnumber_T n2);
varnumber_T num_modulus(varnumber_T n1, varnumber_T n2); varnumber_T num_modulus(varnumber_T n1, varnumber_T n2);
void eval_init(void); void eval_init(void);
void eval_clear(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_to_bool(char_u *arg, int *error, exarg_T *eap, int skip);
int eval_expr_valid_arg(typval_T *tv); int eval_expr_valid_arg(typval_T *tv);
int eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv); 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 *text, int ic);
char_u *eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext); char_u *eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext);
char_u *eval_next_line(evalarg_T *evalarg); char_u *eval_next_line(evalarg_T *evalarg);
char_u *skipwhite_and_linebreak(char_u *arg, 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); void clear_evalarg(evalarg_T *evalarg, exarg_T *eap);
int eval0(char_u *arg, typval_T *rettv, exarg_T *eap, evalarg_T *evalarg); 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); int eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg);

View File

@ -7,7 +7,7 @@ char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state);
int get_lambda_tv(char_u **arg, typval_T *rettv, evalarg_T *evalarg); 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); char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload);
void emsg_funcname(char *ermsg, char_u *name); 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); 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); 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); int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict);

View File

@ -1099,6 +1099,13 @@ def Test_expr7_dict_vim9script()
END END
CheckScriptSuccess(lines) CheckScriptSuccess(lines)
lines =<< trim END
vim9script
let d = { "one": "one", "two": "two", }
assert_equal({'one': 'one', 'two': 'two'}, d)
END
CheckScriptSuccess(lines)
lines =<< trim END lines =<< trim END
vim9script vim9script
let d = #{one: 1, let d = #{one: 1,

View File

@ -353,6 +353,22 @@ def Test_vim9script_call()
assert_equal('text', var) assert_equal('text', var)
("some")->MyFunc() ("some")->MyFunc()
assert_equal('some', var) assert_equal('some', var)
MyFunc(
'continued'
)
assert_equal('continued',
var
)
call MyFunc(
'more'
..
'lines'
)
assert_equal(
'morelines',
var)
END END
writefile(lines, 'Xcall.vim') writefile(lines, 'Xcall.vim')
source Xcall.vim source Xcall.vim

View File

@ -601,16 +601,13 @@ get_func_tv(
int len, // length of "name" or -1 to use strlen() int len, // length of "name" or -1 to use strlen()
typval_T *rettv, typval_T *rettv,
char_u **arg, // argument, pointing to the '(' char_u **arg, // argument, pointing to the '('
evalarg_T *evalarg, // for line continuation
funcexe_T *funcexe) // various values funcexe_T *funcexe) // various values
{ {
char_u *argp; char_u *argp;
int ret = OK; int ret = OK;
typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments
int argcount = 0; // number of arguments found int argcount = 0; // number of arguments found
evalarg_T evalarg;
CLEAR_FIELD(evalarg);
evalarg.eval_flags = funcexe->evaluate ? EVAL_EVALUATE : 0;
/* /*
* Get the arguments. * Get the arguments.
@ -619,10 +616,12 @@ get_func_tv(
while (argcount < MAX_FUNC_ARGS - (funcexe->partial == NULL ? 0 while (argcount < MAX_FUNC_ARGS - (funcexe->partial == NULL ? 0
: funcexe->partial->pt_argc)) : 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) if (*argp == ')' || *argp == ',' || *argp == NUL)
break; break;
if (eval1(&argp, &argvars[argcount], &evalarg) == FAIL) if (eval1(&argp, &argvars[argcount], evalarg) == FAIL)
{ {
ret = FAIL; ret = FAIL;
break; break;
@ -631,6 +630,7 @@ get_func_tv(
if (*argp != ',') if (*argp != ',')
break; break;
} }
argp = skipwhite_and_linebreak(argp, evalarg);
if (*argp == ')') if (*argp == ')')
++argp; ++argp;
else else
@ -3832,16 +3832,19 @@ ex_call(exarg_T *eap)
int failed = FALSE; int failed = FALSE;
funcdict_T fudi; funcdict_T fudi;
partial_T *partial = NULL; partial_T *partial = NULL;
evalarg_T evalarg;
fill_evalarg_from_eap(&evalarg, eap, eap->skip);
if (eap->skip) if (eap->skip)
{ {
// trans_function_name() doesn't work well when skipping, use eval0() // trans_function_name() doesn't work well when skipping, use eval0()
// instead to skip to any following command, e.g. for: // instead to skip to any following command, e.g. for:
// :if 0 | call dict.foo().bar() | endif // :if 0 | call dict.foo().bar() | endif
++emsg_skip; ++emsg_skip;
if (eval0(eap->arg, &rettv, eap, NULL) != FAIL) if (eval0(eap->arg, &rettv, eap, &evalarg) != FAIL)
clear_tv(&rettv); clear_tv(&rettv);
--emsg_skip; --emsg_skip;
clear_evalarg(&evalarg, eap);
return; return;
} }
@ -3918,7 +3921,7 @@ ex_call(exarg_T *eap)
funcexe.evaluate = !eap->skip; funcexe.evaluate = !eap->skip;
funcexe.partial = partial; funcexe.partial = partial;
funcexe.selfdict = fudi.fd_dict; 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; failed = TRUE;
break; break;
@ -3947,6 +3950,7 @@ ex_call(exarg_T *eap)
} }
if (eap->skip) if (eap->skip)
--emsg_skip; --emsg_skip;
clear_evalarg(&evalarg, eap);
// When inside :try we need to check for following "| catch". // When inside :try we need to check for following "| catch".
if (!failed || eap->cstack->cs_trylevel > 0) if (!failed || eap->cstack->cs_trylevel > 0)

View File

@ -754,6 +754,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1110,
/**/ /**/
1109, 1109,
/**/ /**/