# HG changeset patch # User Bram Moolenaar # Date 1609076703 -3600 # Node ID a7cbdb9294c442ebb06f9930cc108f59c16fd0bc # Parent 91b6cc84c6b71a4e9530d267d6e277830b7c2bfa patch 8.2.2227: Vim9: recognizing lambda is too complicated Commit: https://github.com/vim/vim/commit/e462f52db3cab656485a71e4322b6cb18d564a06 Author: Bram Moolenaar Date: Sun Dec 27 14:43:30 2020 +0100 patch 8.2.2227: Vim9: recognizing lambda is too complicated Problem: Vim9: recognizing lambda is too complicated. Solution: Call compile_lambda() and check for NOTDONE. 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 @@ -1863,9 +1863,9 @@ def Test_expr7_lambda() END CheckDefAndScriptSuccess(lines) - CheckDefFailure(["var Ref = {a->a + 1}"], 'E720:') - CheckDefFailure(["var Ref = {a-> a + 1}"], 'E720:') - CheckDefFailure(["var Ref = {a ->a + 1}"], 'E720:') + CheckDefFailure(["var Ref = {a->a + 1}"], 'E1004:') + CheckDefFailure(["var Ref = {a-> a + 1}"], 'E1004:') + CheckDefFailure(["var Ref = {a ->a + 1}"], 'E1004:') CheckDefFailure(["filter([1, 2], {k,v -> 1})"], 'E1069:', 1) # error is in first line of the lambda @@ -1964,13 +1964,9 @@ def Test_expr7_new_lambda() END CheckDefAndScriptSuccess(lines) - CheckDefFailure(["var Ref = (a)=>a + 1"], 'E1001:') - CheckDefFailure(["var Ref = (a)=> a + 1"], 'E1001:') - CheckDefFailure(["var Ref = (a) =>a + 1"], 'E1001:') - - CheckScriptFailure(["vim9script", "var Ref = (a)=>a + 1"], 'E1004:') - CheckScriptFailure(["vim9script", "var Ref = (a)=> a + 1"], 'E1004:') - CheckScriptFailure(["vim9script", "var Ref = (a) =>a + 1"], 'E1004:') + CheckDefAndScriptFailure(["var Ref = (a)=>a + 1"], 'E1004:') + CheckDefAndScriptFailure(["var Ref = (a)=> a + 1"], 'E1004:') + CheckDefAndScriptFailure(["var Ref = (a) =>a + 1"], 'E1004:') CheckDefFailure(["var Ref: func(number): number = (a: number): string => 'x'"], 'E1012:') CheckDefFailure(["var Ref: func(number): string = (a: number): string => 99"], 'E1012:') @@ -2682,7 +2678,7 @@ func Test_expr7_fails() call CheckDefFailure(["'yes'->", "Echo()"], 'E488: Trailing characters: ->', 1) call CheckDefExecFailure(["[1, 2->len()"], 'E697:', 2) - call CheckDefExecFailure(["{a: 1->len()"], 'E723:', 2) + call CheckDefExecFailure(["{a: 1->len()"], 'E1004:', 1) call CheckDefExecFailure(["{['a']: 1->len()"], 'E723:', 2) endfunc diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -570,7 +570,7 @@ get_lambda_tv( &varargs, NULL, FALSE, NULL, NULL); if (ret == FAIL || (s = skip_arrow(*arg, equal_arrow, &ret_type, - equal_arrow ? &white_error : NULL)) == NULL) + equal_arrow || in_vim9script() ? &white_error : NULL)) == NULL) { if (types_optional) ga_clear_strings(&argtypes); 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 */ /**/ + 2227, +/**/ 2226, /**/ 2225, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -2949,10 +2949,12 @@ compile_list(char_u **arg, cctx_T *cctx, /* * parse a lambda: "{arg, arg -> expr}" or "(arg, arg) => expr" * "*arg" points to the '{'. + * Returns OK/FAIL when a lambda is recognized, NOTDONE if it's not a lambda. */ static int compile_lambda(char_u **arg, cctx_T *cctx) { + int r; typval_T rettv; ufunc_T *ufunc; evalarg_T evalarg; @@ -2962,10 +2964,11 @@ compile_lambda(char_u **arg, cctx_T *cct evalarg.eval_cctx = cctx; // Get the funcref in "rettv". - if (get_lambda_tv(arg, &rettv, TRUE, &evalarg) != OK) + r = get_lambda_tv(arg, &rettv, TRUE, &evalarg); + if (r != OK) { clear_evalarg(&evalarg, NULL); - return FAIL; + return r; } // "rettv" will now be a partial referencing the function. @@ -4001,26 +4004,13 @@ compile_expr7( * Lambda: {arg, arg -> expr} * Dictionary: {'key': val, 'key': val} */ - case '{': { - char_u *start = skipwhite(*arg + 1); - char_u *after = start; - garray_T ga_arg; - - // Find out what comes after the arguments. - ret = get_function_args(&after, '-', NULL, - &ga_arg, TRUE, NULL, NULL, - TRUE, NULL, NULL); - if (ret != FAIL && after[0] == '>' - && ((after > start + 2 - && VIM_ISWHITE(after[-2])) - || after == start + 1) - && IS_WHITE_OR_NUL(after[1])) - // TODO: if we go with the "(arg) => expr" syntax - // remove this - ret = compile_lambda(arg, cctx); - else - ret = compile_dict(arg, cctx, ppconst); - } + case '{': // Try parsing as a lambda, if NOTDONE is returned it + // must be a dict. + // TODO: if we go with the "(arg) => expr" syntax remove + // this + ret = compile_lambda(arg, cctx); + if (ret == NOTDONE) + ret = compile_dict(arg, cctx, ppconst); break; /* @@ -4051,32 +4041,10 @@ compile_expr7( * lambda: (arg, arg) => expr * funcref: (arg, arg) => { statement } */ - case '(': { - char_u *start = skipwhite(*arg + 1); - char_u *after = start; - garray_T ga_arg; - - // Find out if "=>" comes after the (). - ret = get_function_args(&after, ')', NULL, - &ga_arg, TRUE, NULL, NULL, - TRUE, NULL, NULL); - if (ret == OK && VIM_ISWHITE( - *after == ':' ? after[1] : *after)) - { - if (*after == ':') - // Skip over type in "(arg): type". - after = skip_type(skipwhite(after + 1), TRUE); - - after = skipwhite(after); - if (after[0] == '=' && after[1] == '>' - && IS_WHITE_OR_NUL(after[2])) - { - ret = compile_lambda(arg, cctx); - break; - } - } + case '(': // if compile_lambda returns NOTDONE then it must be (expr) + ret = compile_lambda(arg, cctx); + if (ret == NOTDONE) ret = compile_parenthesis(arg, cctx, ppconst); - } break; default: ret = NOTDONE;