patch 8.2.2219: Vim9: method call with expression not supported
Problem: Vim9: method call with expression not supported.
Solution: Implement expr->(expr)().
diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim
index 73fdb98..e4f7f2d 100644
--- a/src/testdir/test_vim9_expr.vim
+++ b/src/testdir/test_vim9_expr.vim
@@ -2560,6 +2560,39 @@
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 @@
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)
diff --git a/src/version.c b/src/version.c
index 90ef966..6178cae 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2219,
+/**/
2218,
/**/
2217,
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 2b1f651..e515f2b 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -2817,9 +2817,8 @@
&& 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;
}
@@ -3430,6 +3429,19 @@
}
/*
+ * 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 '!'.
*/
@@ -3488,6 +3500,38 @@
}
/*
+ * 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 @@
}
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 @@
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 @@
* 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 @@
// 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;
}