changeset 23368:a7cbdb9294c4 v8.2.2227

patch 8.2.2227: Vim9: recognizing lambda is too complicated Commit: https://github.com/vim/vim/commit/e462f52db3cab656485a71e4322b6cb18d564a06 Author: Bram Moolenaar <Bram@vim.org> 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.
author Bram Moolenaar <Bram@vim.org>
date Sun, 27 Dec 2020 14:45:03 +0100
parents 91b6cc84c6b7
children a547793a18c1
files src/testdir/test_vim9_expr.vim src/userfunc.c src/version.c src/vim9compile.c
diffstat 4 files changed, 25 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- 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
 
--- 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);
--- 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,
--- 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;