]> granicus.if.org Git - vim/commitdiff
patch 8.2.2219: Vim9: method call with expression not supported v8.2.2219
authorBram Moolenaar <Bram@vim.org>
Fri, 25 Dec 2020 20:56:57 +0000 (21:56 +0100)
committerBram Moolenaar <Bram@vim.org>
Fri, 25 Dec 2020 20:56:57 +0000 (21:56 +0100)
Problem:    Vim9: method call with expression not supported.
Solution:   Implement expr->(expr)().

src/testdir/test_vim9_expr.vim
src/version.c
src/vim9compile.c

index 73fdb98fceb1c57860be36bf07dacbe71c3fdb47..e4f7f2d10d1b6de80e2a1929ba46387949be982e 100644 (file)
@@ -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)
index 90ef966cca0927d2bdf30cf675392c2304ccb6b9..6178cae1b2a90d500479e4cd9b1fe7a23aceda47 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2219,
 /**/
     2218,
 /**/
index 2b1f65114da51d7978781d3007ae5db73b8df702..e515f2bc33650de71a0322a2f2e40a5379a986c4 100644 (file)
@@ -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_T      *type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
 
-       type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
        res = generate_PCALL(cctx, argcount, namebuf, type, FALSE);
        goto theend;
     }
@@ -3429,6 +3428,19 @@ get_compare_type(char_u *p, int *len, int *type_is)
     return type;
 }
 
+/*
+ * 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 '!'.
@@ -3487,6 +3499,38 @@ compile_leader(cctx_T *cctx, int numeric_only, char_u *start, char_u **end)
     return OK;
 }
 
+/*
+ * 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, ppconst_T *ppconst)
  * 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 *cctx, ppconst_T *ppconst)
     // 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;
     }