Patch 8.2.2219
Problem: Vim9: method call with expression not supported.
Solution: Implement expr->(expr)().
Files: src/vim9compile.c, src/testdir/test_vim9_expr.vim
*** ../vim-8.2.2218/src/vim9compile.c 2020-12-25 19:25:41.742706213 +0100
--- src/vim9compile.c 2020-12-25 21:46:03.877525095 +0100
***************
*** 2817,2825 ****
&& compile_load(&p, namebuf + varlen, cctx, FALSE, FALSE) == OK)
{
garray_T *stack = &cctx->ctx_type_stack;
! type_T *type;
- type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
res = generate_PCALL(cctx, argcount, namebuf, type, FALSE);
goto theend;
}
--- 2817,2824 ----
&& compile_load(&p, namebuf + varlen, cctx, FALSE, FALSE) == OK)
{
garray_T *stack = &cctx->ctx_type_stack;
! type_T *type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
res = generate_PCALL(cctx, argcount, namebuf, type, FALSE);
goto theend;
}
***************
*** 3430,3435 ****
--- 3429,3447 ----
}
/*
+ * 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,3493 ****
--- 3500,3537 ----
}
/*
+ * 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,3581 ****
}
else if (**arg == '(')
{
! // Funcref call: list->(Refs[2])()
! // or lambda: list->((arg) => expr)()
! // TODO: make this work
! if (compile_lambda_call(arg, cctx) == FAIL)
return FAIL;
}
else
--- 3616,3657 ----
}
else if (**arg == '(')
{
! 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,4025 ****
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;
! }
}
break;
--- 4074,4080 ----
break;
}
}
! ret = compile_parenthesis(arg, cctx, ppconst);
}
break;
***************
*** 4597,4603 ****
* end:
*/
static int
! compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
{
char_u *p;
int ppconst_used = ppconst->pp_used;
--- 4652,4658 ----
* end:
*/
static int
! compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
{
char_u *p;
int ppconst_used = ppconst->pp_used;
***************
*** 4606,4616 ****
// 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);
return OK;
}
--- 4661,4667 ----
// Ignore all kinds of errors when not producing code.
if (cctx->ctx_skip == SKIP_YES)
{
! skip_expr_cctx(arg, cctx);
return OK;
}
*** ../vim-8.2.2218/src/testdir/test_vim9_expr.vim 2020-12-25 15:24:19.902942195 +0100
--- src/testdir/test_vim9_expr.vim 2020-12-25 21:53:38.330148915 +0100
***************
*** 2560,2565 ****
--- 2560,2598 ----
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,2884 ****
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)
--- 2885,2890 ----
*** ../vim-8.2.2218/src/version.c 2020-12-25 20:24:48.172245018 +0100
--- src/version.c 2020-12-25 21:52:17.594679993 +0100
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 2219,
/**/
--
How To Keep A Healthy Level Of Insanity:
14. Put mosquito netting around your work area. Play a tape of jungle
sounds all day.
/// Bram Moolenaar -- Br...@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 ///