1
0
forked from aniani/vim

patch 8.2.2219: Vim9: method call with expression not supported

Problem:    Vim9: method call with expression not supported.
Solution:   Implement expr->(expr)().
This commit is contained in:
Bram Moolenaar 2020-12-25 21:56:57 +01:00
parent fc0e8f5c3e
commit 7e3682068b
3 changed files with 120 additions and 61 deletions

View File

@ -2560,6 +2560,39 @@ def Test_expr7_call()
delete('Xruntime', 'rf')
enddef
def Test_expr7_method_call()
new
setline(1, ['first', 'last'])
'second'->append(1)
"third"->append(2)
assert_equal(['first', 'second', 'third', 'last'], getline(1, '$'))
bwipe!
var bufnr = bufnr()
var loclist = [{bufnr: bufnr, lnum: 42, col: 17, text: 'wrong'}]
loclist->setloclist(0)
assert_equal([{bufnr: bufnr,
lnum: 42,
col: 17,
text: 'wrong',
pattern: '',
valid: 1,
vcol: 0,
nr: 0,
type: '',
module: ''}
], getloclist(0))
var result: bool = get({n: 0}, 'n', 0)
assert_equal(false, result)
assert_equal('+string+', 'string'->((s) => '+' .. s .. '+')())
assert_equal('-text-', 'text'->((s, c) => c .. s .. c)('-'))
var Join = (l) => join(l, 'x')
assert_equal('axb', ['a', 'b']->(Join)())
enddef
def Test_expr7_not()
var lines =<< trim END
@ -2852,33 +2885,6 @@ def Test_expr7_subscript_linebreak()
one)
enddef
def Test_expr7_method_call()
new
setline(1, ['first', 'last'])
'second'->append(1)
"third"->append(2)
assert_equal(['first', 'second', 'third', 'last'], getline(1, '$'))
bwipe!
var bufnr = bufnr()
var loclist = [{bufnr: bufnr, lnum: 42, col: 17, text: 'wrong'}]
loclist->setloclist(0)
assert_equal([{bufnr: bufnr,
lnum: 42,
col: 17,
text: 'wrong',
pattern: '',
valid: 1,
vcol: 0,
nr: 0,
type: '',
module: ''}
], getloclist(0))
var result: bool = get({n: 0}, 'n', 0)
assert_equal(false, result)
enddef
func Test_expr7_trailing_fails()
call CheckDefFailure(['var l = [2]', 'l->{l -> add(l, 8)}'], 'E107:', 2)
call CheckDefFailure(['var l = [2]', 'l->{l -> add(l, 8)} ()'], 'E274:', 2)

View File

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

View File

@ -2817,9 +2817,8 @@ compile_call(
&& compile_load(&p, namebuf + varlen, cctx, FALSE, FALSE) == OK)
{
garray_T *stack = &cctx->ctx_type_stack;
type_T *type;
type_T *type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
res = generate_PCALL(cctx, argcount, namebuf, type, FALSE);
goto theend;
}
@ -3429,6 +3428,19 @@ get_compare_type(char_u *p, int *len, int *type_is)
return type;
}
/*
* Skip over an expression, ignoring most errors.
*/
static void
skip_expr_cctx(char_u **arg, cctx_T *cctx)
{
evalarg_T evalarg;
CLEAR_FIELD(evalarg);
evalarg.eval_cctx = cctx;
skip_expr(arg, &evalarg);
}
/*
* Compile code to apply '-', '+' and '!'.
* When "numeric_only" is TRUE do not apply '!'.
@ -3487,6 +3499,38 @@ compile_leader(cctx_T *cctx, int numeric_only, char_u *start, char_u **end)
return OK;
}
/*
* Compile "(expression)": recursive!
* Return FAIL/OK.
*/
static int
compile_parenthesis(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
{
int ret;
*arg = skipwhite(*arg + 1);
if (ppconst->pp_used <= PPSIZE - 10)
{
ret = compile_expr1(arg, cctx, ppconst);
}
else
{
// Not enough space in ppconst, flush constants.
if (generate_ppconst(cctx, ppconst) == FAIL)
return FAIL;
ret = compile_expr0(arg, cctx);
}
*arg = skipwhite(*arg);
if (**arg == ')')
++*arg;
else if (ret == OK)
{
emsg(_(e_missing_close));
ret = FAIL;
}
return ret;
}
/*
* Compile whatever comes after "name" or "name()".
* Advances "*arg" only when something was recognized.
@ -3572,10 +3616,42 @@ compile_subscript(
}
else if (**arg == '(')
{
// Funcref call: list->(Refs[2])()
// or lambda: list->((arg) => expr)()
// TODO: make this work
if (compile_lambda_call(arg, cctx) == FAIL)
int argcount = 1;
char_u *expr;
garray_T *stack;
type_T *type;
// Funcref call: list->(Refs[2])(arg)
// or lambda: list->((arg) => expr)(arg)
// Fist compile the arguments.
expr = *arg;
*arg = skipwhite(*arg + 1);
skip_expr_cctx(arg, cctx);
*arg = skipwhite(*arg);
if (**arg != ')')
{
semsg(_(e_missing_paren), *arg);
return FAIL;
}
++*arg;
if (**arg != '(')
{
semsg(_(e_missing_paren), *arg);
return FAIL;
}
*arg = skipwhite(*arg + 1);
if (compile_arguments(arg, cctx, &argcount) == FAIL)
return FAIL;
// Compile the function expression.
if (compile_parenthesis(&expr, cctx, ppconst) == FAIL)
return FAIL;
stack = &cctx->ctx_type_stack;
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
if (generate_PCALL(cctx, argcount,
(char_u *)"[expression]", type, FALSE) == FAIL)
return FAIL;
}
else
@ -3998,28 +4074,7 @@ compile_expr7(
break;
}
}
// (expression): recursive!
*arg = skipwhite(*arg + 1);
if (ppconst->pp_used <= PPSIZE - 10)
{
ret = compile_expr1(arg, cctx, ppconst);
}
else
{
// Not enough space in ppconst, flush constants.
if (generate_ppconst(cctx, ppconst) == FAIL)
return FAIL;
ret = compile_expr0(arg, cctx);
}
*arg = skipwhite(*arg);
if (**arg == ')')
++*arg;
else if (ret == OK)
{
emsg(_(e_missing_close));
ret = FAIL;
}
ret = compile_parenthesis(arg, cctx, ppconst);
}
break;
@ -4597,7 +4652,7 @@ compile_expr2(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
* end:
*/
static int
compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
{
char_u *p;
int ppconst_used = ppconst->pp_used;
@ -4606,11 +4661,7 @@ compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
// Ignore all kinds of errors when not producing code.
if (cctx->ctx_skip == SKIP_YES)
{
evalarg_T evalarg;
CLEAR_FIELD(evalarg);
evalarg.eval_cctx = cctx;
skip_expr(arg, &evalarg);
skip_expr_cctx(arg, cctx);
return OK;
}