]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.4116: Vim9: cannot use a method with a complex expression in :def v8.2.4116
authorBram Moolenaar <Bram@vim.org>
Sun, 16 Jan 2022 20:59:39 +0000 (20:59 +0000)
committerBram Moolenaar <Bram@vim.org>
Sun, 16 Jan 2022 20:59:39 +0000 (20:59 +0000)
Problem:    Vim9: cannot use a method with a complex expression in a :def
            function.
Solution:   Implement compiling the expression.

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

index 263b6d31052a26effcd608ba9394ad25b0e62a45..3ea3a0b6bcfd9f8772c74d50e61150785288d68c 100644 (file)
@@ -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()
index 83b979f6cd0f2f8217e06eedfa3a89f02bdccfd2..feedd8f6e99be3a18b8d2c7b70bfff4fa340635e 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4116,
 /**/
     4115,
 /**/
index 39ce9fe72e4651627466e171c53e9ee8251c2f44..4c395785f4c6c17ddbf490d4843a9c35674f0dff 100644 (file)
@@ -1583,6 +1583,8 @@ compile_parenthesis(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
     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;