# HG changeset patch # User Bram Moolenaar # Date 1642366804 -3600 # Node ID 6af18c69c59d61ce6bd7bfc0fba5a57d8fce700f # Parent 10acb26022533fefb6c8a6c84e6aa788a5f7e607 patch 8.2.4116: Vim9: cannot use a method with a complex expression in :def Commit: https://github.com/vim/vim/commit/c73499351aef8b611b13c70ef8706a7e98df67a8 Author: Bram Moolenaar Date: Sun Jan 16 20:59:39 2022 +0000 patch 8.2.4116: Vim9: cannot use a method with a complex expression in :def Problem: Vim9: cannot use a method with a complex expression in a :def function. Solution: Implement compiling the expression. 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 @@ -3140,7 +3140,6 @@ def Test_expr7_method_call() CheckDefAndScriptSuccess(lines) lines =<< trim END - vim9script def SetNumber(n: number) g:number = n enddef @@ -3166,7 +3165,7 @@ def Test_expr7_method_call() unlet g:number END - CheckScriptSuccess(lines) # TODO: CheckDefAndScriptSuccess() + CheckDefAndScriptSuccess(lines) lines =<< trim END def RetVoid() 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 */ /**/ + 4116, +/**/ 4115, /**/ 4114, diff --git a/src/vim9expr.c b/src/vim9expr.c --- a/src/vim9expr.c +++ b/src/vim9expr.c @@ -1583,6 +1583,8 @@ compile_parenthesis(char_u **arg, cctx_T return ret; } +static int compile_expr8(char_u **arg, cctx_T *cctx, ppconst_T *ppconst); + /* * Compile whatever comes after "name" or "name()". * Advances "*arg" only when something was recognized. @@ -1651,13 +1653,15 @@ compile_subscript( } else if (*p == '-' && p[1] == '>') { - char_u *pstart = p; + char_u *pstart = p; + int alt; + char_u *paren; + // something->method() if (generate_ppconst(cctx, ppconst) == FAIL) return FAIL; ppconst->pp_is_const = FALSE; - // something->method() // Apply the '!', '-' and '+' first: // -1.0->func() works like (-1.0)->func() if (compile_leader(cctx, TRUE, start_leader, end_leader) == FAIL) @@ -1666,7 +1670,48 @@ compile_subscript( p += 2; *arg = skipwhite(p); // No line break supported right after "->". + + // Three alternatives handled here: + // 1. "base->name(" only a name, use compile_call() + // 2. "base->(expr)(" evaluate "expr", then use PCALL + // 3. "base->expr(" Same, find the end of "expr" by "(" if (**arg == '(') + alt = 2; + else + { + // alternative 1 or 3 + p = *arg; + if (!eval_isnamec1(*p)) + { + semsg(_(e_trailing_characters_str), pstart); + return FAIL; + } + if (ASCII_ISALPHA(*p) && p[1] == ':') + p += 2; + for ( ; eval_isnamec(*p); ++p) + ; + if (*p == '(') + { + // alternative 1 + alt = 1; + if (compile_call(arg, p - *arg, cctx, ppconst, 1) == FAIL) + return FAIL; + } + else + { + // Must be alternative 3, find the "(". Only works within + // one line. + alt = 3; + paren = vim_strchr(p, '('); + if (paren == NULL) + { + semsg(_(e_missing_parenthesis_str), *arg); + return FAIL; + } + } + } + + if (alt != 1) { int argcount = 1; garray_T *stack = &cctx->ctx_type_stack; @@ -1676,12 +1721,27 @@ compile_subscript( int expr_isn_end; int arg_isn_count; - // Funcref call: list->(Refs[2])(arg) - // or lambda: list->((arg) => expr)(arg) - // - // Fist compile the function expression. - if (compile_parenthesis(arg, cctx, ppconst) == FAIL) - return FAIL; + if (alt == 2) + { + // Funcref call: list->(Refs[2])(arg) + // or lambda: list->((arg) => expr)(arg) + // + // Fist compile the function expression. + if (compile_parenthesis(arg, cctx, ppconst) == FAIL) + return FAIL; + } + else + { + *paren = NUL; + if (compile_expr8(arg, cctx, ppconst) == FAIL + || *skipwhite(*arg) != NUL) + { + *paren = '('; + semsg(_(e_invalid_expression_str), pstart); + return FAIL; + } + *paren = '('; + } // Remember the next instruction index, where the instructions // for arguments are being written. @@ -1742,27 +1802,7 @@ compile_subscript( if (generate_PCALL(cctx, argcount, p - 2, type, FALSE) == FAIL) return FAIL; } - else - { - // method call: list->method() - p = *arg; - if (!eval_isnamec1(*p)) - { - semsg(_(e_trailing_characters_str), pstart); - return FAIL; - } - if (ASCII_ISALPHA(*p) && p[1] == ':') - p += 2; - for ( ; eval_isnamec(*p); ++p) - ; - if (*p != '(') - { - semsg(_(e_missing_parenthesis_str), *arg); - return FAIL; - } - if (compile_call(arg, p - *arg, cctx, ppconst, 1) == FAIL) - return FAIL; - } + if (keeping_dict) { keeping_dict = FALSE;