changeset 23352:37118deff718 v8.2.2219

patch 8.2.2219: Vim9: method call with expression not supported Commit: https://github.com/vim/vim/commit/7e3682068bebc53a5d1e9eaaba61bb4fa9c612da Author: Bram Moolenaar <Bram@vim.org> 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)().
author Bram Moolenaar <Bram@vim.org>
date Fri, 25 Dec 2020 22:00:04 +0100
parents ae0e6f75e315
children 8643a226458d
files src/testdir/test_vim9_expr.vim src/version.c src/vim9compile.c
diffstat 3 files changed, 121 insertions(+), 62 deletions(-) [+]
line wrap: on
line diff
--- 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)
--- 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,
--- 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;
     }