# HG changeset patch # User Bram Moolenaar # Date 1608930004 -3600 # Node ID 37118deff718c04228d291d8f4555d4255551173 # Parent ae0e6f75e31536f40fd994c69c3daf41accfdc94 patch 8.2.2219: Vim9: method call with expression not supported Commit: https://github.com/vim/vim/commit/7e3682068bebc53a5d1e9eaaba61bb4fa9c612da Author: Bram Moolenaar Date: Fri Dec 25 21:56:57 2020 +0100 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 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -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) diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2219, +/**/ 2218, /**/ 2217, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -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 = ((type_T **)stack->ga_data)[stack->ga_len - 1]; + type_T *type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; + res = generate_PCALL(cctx, argcount, namebuf, type, FALSE); goto theend; } @@ -3430,6 +3429,19 @@ get_compare_type(char_u *p, int *len, in } /* + * 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_leader(cctx_T *cctx, int numeric } /* + * 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 * 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 *cct // 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; }