Skip to content

Commit 7e36820

Browse files
committed
patch 8.2.2219: Vim9: method call with expression not supported
Problem: Vim9: method call with expression not supported. Solution: Implement expr->(expr)().
1 parent fc0e8f5 commit 7e36820

3 files changed

Lines changed: 120 additions & 61 deletions

File tree

src/testdir/test_vim9_expr.vim

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2560,6 +2560,39 @@ def Test_expr7_call()
25602560
delete('Xruntime', 'rf')
25612561
enddef
25622562

2563+
def Test_expr7_method_call()
2564+
new
2565+
setline(1, ['first', 'last'])
2566+
'second'->append(1)
2567+
"third"->append(2)
2568+
assert_equal(['first', 'second', 'third', 'last'], getline(1, '$'))
2569+
bwipe!
2570+
2571+
var bufnr = bufnr()
2572+
var loclist = [{bufnr: bufnr, lnum: 42, col: 17, text: 'wrong'}]
2573+
loclist->setloclist(0)
2574+
assert_equal([{bufnr: bufnr,
2575+
lnum: 42,
2576+
col: 17,
2577+
text: 'wrong',
2578+
pattern: '',
2579+
valid: 1,
2580+
vcol: 0,
2581+
nr: 0,
2582+
type: '',
2583+
module: ''}
2584+
], getloclist(0))
2585+
2586+
var result: bool = get({n: 0}, 'n', 0)
2587+
assert_equal(false, result)
2588+
2589+
assert_equal('+string+', 'string'->((s) => '+' .. s .. '+')())
2590+
assert_equal('-text-', 'text'->((s, c) => c .. s .. c)('-'))
2591+
2592+
var Join = (l) => join(l, 'x')
2593+
assert_equal('axb', ['a', 'b']->(Join)())
2594+
enddef
2595+
25632596

25642597
def Test_expr7_not()
25652598
var lines =<< trim END
@@ -2852,33 +2885,6 @@ def Test_expr7_subscript_linebreak()
28522885
one)
28532886
enddef
28542887

2855-
def Test_expr7_method_call()
2856-
new
2857-
setline(1, ['first', 'last'])
2858-
'second'->append(1)
2859-
"third"->append(2)
2860-
assert_equal(['first', 'second', 'third', 'last'], getline(1, '$'))
2861-
bwipe!
2862-
2863-
var bufnr = bufnr()
2864-
var loclist = [{bufnr: bufnr, lnum: 42, col: 17, text: 'wrong'}]
2865-
loclist->setloclist(0)
2866-
assert_equal([{bufnr: bufnr,
2867-
lnum: 42,
2868-
col: 17,
2869-
text: 'wrong',
2870-
pattern: '',
2871-
valid: 1,
2872-
vcol: 0,
2873-
nr: 0,
2874-
type: '',
2875-
module: ''}
2876-
], getloclist(0))
2877-
2878-
var result: bool = get({n: 0}, 'n', 0)
2879-
assert_equal(false, result)
2880-
enddef
2881-
28822888
func Test_expr7_trailing_fails()
28832889
call CheckDefFailure(['var l = [2]', 'l->{l -> add(l, 8)}'], 'E107:', 2)
28842890
call CheckDefFailure(['var l = [2]', 'l->{l -> add(l, 8)} ()'], 'E274:', 2)

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ static char *(features[]) =
750750

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
2219,
753755
/**/
754756
2218,
755757
/**/

src/vim9compile.c

Lines changed: 85 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2817,9 +2817,8 @@ compile_call(
28172817
&& compile_load(&p, namebuf + varlen, cctx, FALSE, FALSE) == OK)
28182818
{
28192819
garray_T *stack = &cctx->ctx_type_stack;
2820-
type_T *type;
2820+
type_T *type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
28212821

2822-
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
28232822
res = generate_PCALL(cctx, argcount, namebuf, type, FALSE);
28242823
goto theend;
28252824
}
@@ -3429,6 +3428,19 @@ get_compare_type(char_u *p, int *len, int *type_is)
34293428
return type;
34303429
}
34313430

3431+
/*
3432+
* Skip over an expression, ignoring most errors.
3433+
*/
3434+
static void
3435+
skip_expr_cctx(char_u **arg, cctx_T *cctx)
3436+
{
3437+
evalarg_T evalarg;
3438+
3439+
CLEAR_FIELD(evalarg);
3440+
evalarg.eval_cctx = cctx;
3441+
skip_expr(arg, &evalarg);
3442+
}
3443+
34323444
/*
34333445
* Compile code to apply '-', '+' and '!'.
34343446
* 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)
34873499
return OK;
34883500
}
34893501

3502+
/*
3503+
* Compile "(expression)": recursive!
3504+
* Return FAIL/OK.
3505+
*/
3506+
static int
3507+
compile_parenthesis(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
3508+
{
3509+
int ret;
3510+
3511+
*arg = skipwhite(*arg + 1);
3512+
if (ppconst->pp_used <= PPSIZE - 10)
3513+
{
3514+
ret = compile_expr1(arg, cctx, ppconst);
3515+
}
3516+
else
3517+
{
3518+
// Not enough space in ppconst, flush constants.
3519+
if (generate_ppconst(cctx, ppconst) == FAIL)
3520+
return FAIL;
3521+
ret = compile_expr0(arg, cctx);
3522+
}
3523+
*arg = skipwhite(*arg);
3524+
if (**arg == ')')
3525+
++*arg;
3526+
else if (ret == OK)
3527+
{
3528+
emsg(_(e_missing_close));
3529+
ret = FAIL;
3530+
}
3531+
return ret;
3532+
}
3533+
34903534
/*
34913535
* Compile whatever comes after "name" or "name()".
34923536
* Advances "*arg" only when something was recognized.
@@ -3572,10 +3616,42 @@ compile_subscript(
35723616
}
35733617
else if (**arg == '(')
35743618
{
3575-
// Funcref call: list->(Refs[2])()
3576-
// or lambda: list->((arg) => expr)()
3577-
// TODO: make this work
3578-
if (compile_lambda_call(arg, cctx) == FAIL)
3619+
int argcount = 1;
3620+
char_u *expr;
3621+
garray_T *stack;
3622+
type_T *type;
3623+
3624+
// Funcref call: list->(Refs[2])(arg)
3625+
// or lambda: list->((arg) => expr)(arg)
3626+
// Fist compile the arguments.
3627+
expr = *arg;
3628+
*arg = skipwhite(*arg + 1);
3629+
skip_expr_cctx(arg, cctx);
3630+
*arg = skipwhite(*arg);
3631+
if (**arg != ')')
3632+
{
3633+
semsg(_(e_missing_paren), *arg);
3634+
return FAIL;
3635+
}
3636+
++*arg;
3637+
if (**arg != '(')
3638+
{
3639+
semsg(_(e_missing_paren), *arg);
3640+
return FAIL;
3641+
}
3642+
3643+
*arg = skipwhite(*arg + 1);
3644+
if (compile_arguments(arg, cctx, &argcount) == FAIL)
3645+
return FAIL;
3646+
3647+
// Compile the function expression.
3648+
if (compile_parenthesis(&expr, cctx, ppconst) == FAIL)
3649+
return FAIL;
3650+
3651+
stack = &cctx->ctx_type_stack;
3652+
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
3653+
if (generate_PCALL(cctx, argcount,
3654+
(char_u *)"[expression]", type, FALSE) == FAIL)
35793655
return FAIL;
35803656
}
35813657
else
@@ -3998,28 +4074,7 @@ compile_expr7(
39984074
break;
39994075
}
40004076
}
4001-
4002-
// (expression): recursive!
4003-
*arg = skipwhite(*arg + 1);
4004-
if (ppconst->pp_used <= PPSIZE - 10)
4005-
{
4006-
ret = compile_expr1(arg, cctx, ppconst);
4007-
}
4008-
else
4009-
{
4010-
// Not enough space in ppconst, flush constants.
4011-
if (generate_ppconst(cctx, ppconst) == FAIL)
4012-
return FAIL;
4013-
ret = compile_expr0(arg, cctx);
4014-
}
4015-
*arg = skipwhite(*arg);
4016-
if (**arg == ')')
4017-
++*arg;
4018-
else if (ret == OK)
4019-
{
4020-
emsg(_(e_missing_close));
4021-
ret = FAIL;
4022-
}
4077+
ret = compile_parenthesis(arg, cctx, ppconst);
40234078
}
40244079
break;
40254080

@@ -4597,7 +4652,7 @@ compile_expr2(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
45974652
* end:
45984653
*/
45994654
static int
4600-
compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
4655+
compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
46014656
{
46024657
char_u *p;
46034658
int ppconst_used = ppconst->pp_used;
@@ -4606,11 +4661,7 @@ compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
46064661
// Ignore all kinds of errors when not producing code.
46074662
if (cctx->ctx_skip == SKIP_YES)
46084663
{
4609-
evalarg_T evalarg;
4610-
4611-
CLEAR_FIELD(evalarg);
4612-
evalarg.eval_cctx = cctx;
4613-
skip_expr(arg, &evalarg);
4664+
skip_expr_cctx(arg, cctx);
46144665
return OK;
46154666
}
46164667

0 commit comments

Comments
 (0)