]> granicus.if.org Git - vim/commitdiff
patch 8.2.1189: Vim9: line continuation in lambda doesn't always work v8.2.1189
authorBram Moolenaar <Bram@vim.org>
Sun, 12 Jul 2020 14:32:19 +0000 (16:32 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 12 Jul 2020 14:32:19 +0000 (16:32 +0200)
Problem:    Vim9: line continuation in lambda doesn't always work.
Solution:   Do not use a local evalarg unless there isn't one. (closes #6439)

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

index 595cd06663946b9f7e535642cee903ace69cf811..9f2c503d3b4d3ea88b687fd81b8ae0bbcfa6fdbe 100644 (file)
@@ -2088,25 +2088,22 @@ eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
     {
        int             result;
        typval_T        var2;
-       evalarg_T       nested_evalarg;
+       evalarg_T       *evalarg_used = evalarg;
+       evalarg_T       local_evalarg;
        int             orig_flags;
        int             evaluate;
 
-       if (getnext)
-           *arg = eval_next_line(evalarg);
-
        if (evalarg == NULL)
        {
-           CLEAR_FIELD(nested_evalarg);
-           orig_flags = 0;
-       }
-       else
-       {
-           nested_evalarg = *evalarg;
-           orig_flags = evalarg->eval_flags;
+           CLEAR_FIELD(local_evalarg);
+           evalarg_used = &local_evalarg;
        }
+       orig_flags = evalarg_used->eval_flags;
+       evaluate = evalarg_used->eval_flags & EVAL_EVALUATE;
+
+       if (getnext)
+           *arg = eval_next_line(evalarg_used);
 
-       evaluate = nested_evalarg.eval_flags & EVAL_EVALUATE;
        result = FALSE;
        if (evaluate)
        {
@@ -2122,16 +2119,16 @@ eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
        /*
         * Get the second variable.  Recursive!
         */
-       *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
-       nested_evalarg.eval_flags = result ? orig_flags
+       *arg = skipwhite_and_linebreak(*arg + 1, evalarg_used);
+       evalarg_used->eval_flags = result ? orig_flags
                                                 : orig_flags & ~EVAL_EVALUATE;
-       if (eval1(arg, rettv, &nested_evalarg) == FAIL)
+       if (eval1(arg, rettv, evalarg_used) == FAIL)
            return FAIL;
 
        /*
         * Check for the ":".
         */
-       p = eval_next_non_blank(*arg, evalarg, &getnext);
+       p = eval_next_non_blank(*arg, evalarg_used, &getnext);
        if (*p != ':')
        {
            emsg(_(e_missing_colon));
@@ -2140,15 +2137,15 @@ eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
            return FAIL;
        }
        if (getnext)
-           *arg = eval_next_line(evalarg);
+           *arg = eval_next_line(evalarg_used);
 
        /*
         * Get the third variable.  Recursive!
         */
-       *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
-       nested_evalarg.eval_flags = !result ? orig_flags
+       *arg = skipwhite_and_linebreak(*arg + 1, evalarg_used);
+       evalarg_used->eval_flags = !result ? orig_flags
                                                 : orig_flags & ~EVAL_EVALUATE;
-       if (eval1(arg, &var2, &nested_evalarg) == FAIL)
+       if (eval1(arg, &var2, evalarg_used) == FAIL)
        {
            if (evaluate && result)
                clear_tv(rettv);
@@ -2156,6 +2153,11 @@ eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
        }
        if (evaluate && !result)
            *rettv = var2;
+
+       if (evalarg == NULL)
+           clear_evalarg(&local_evalarg, NULL);
+       else
+           evalarg->eval_flags = orig_flags;
     }
 
     return OK;
@@ -2175,10 +2177,6 @@ eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
 {
     char_u     *p;
     int                getnext;
-    typval_T   var2;
-    long       result;
-    int                first;
-    int                error = FALSE;
 
     /*
      * Get the first variable.
@@ -2187,70 +2185,77 @@ eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
        return FAIL;
 
     /*
-     * Repeat until there is no following "||".
+     * Handle the  "||" operator.
      */
-    first = TRUE;
-    result = FALSE;
     p = eval_next_non_blank(*arg, evalarg, &getnext);
-    while (p[0] == '|' && p[1] == '|')
+    if (p[0] == '|' && p[1] == '|')
     {
-       evalarg_T   nested_evalarg;
+       evalarg_T   *evalarg_used = evalarg;
+       evalarg_T   local_evalarg;
        int         evaluate;
        int         orig_flags;
-
-       if (getnext)
-           *arg = eval_next_line(evalarg);
+       long        result = FALSE;
+       typval_T    var2;
+       int         error;
 
        if (evalarg == NULL)
        {
-           CLEAR_FIELD(nested_evalarg);
-           orig_flags = 0;
-           evaluate = FALSE;
+           CLEAR_FIELD(local_evalarg);
+           evalarg_used = &local_evalarg;
        }
-       else
-       {
-           nested_evalarg = *evalarg;
-           orig_flags = evalarg->eval_flags;
-           evaluate = orig_flags & EVAL_EVALUATE;
-       }
-
-       if (evaluate && first)
+       orig_flags = evalarg_used->eval_flags;
+       evaluate = orig_flags & EVAL_EVALUATE;
+       if (evaluate)
        {
+           error = FALSE;
            if (tv_get_number_chk(rettv, &error) != 0)
                result = TRUE;
            clear_tv(rettv);
            if (error)
                return FAIL;
-           first = FALSE;
        }
 
        /*
-        * Get the second variable.
+        * Repeat until there is no following "||".
         */
-       *arg = skipwhite_and_linebreak(*arg + 2, evalarg);
-       nested_evalarg.eval_flags = !result ? orig_flags
-                                                : orig_flags & ~EVAL_EVALUATE;
-       if (eval3(arg, &var2, &nested_evalarg) == FAIL)
-           return FAIL;
-
-       /*
-        * Compute the result.
-        */
-       if (evaluate && !result)
+       while (p[0] == '|' && p[1] == '|')
        {
-           if (tv_get_number_chk(&var2, &error) != 0)
-               result = TRUE;
-           clear_tv(&var2);
-           if (error)
+           if (getnext)
+               *arg = eval_next_line(evalarg_used);
+
+           /*
+            * Get the second variable.
+            */
+           *arg = skipwhite_and_linebreak(*arg + 2, evalarg_used);
+           evalarg_used->eval_flags = !result ? orig_flags
+                                                : orig_flags & ~EVAL_EVALUATE;
+           if (eval3(arg, &var2, evalarg_used) == FAIL)
                return FAIL;
-       }
-       if (evaluate)
-       {
-           rettv->v_type = VAR_NUMBER;
-           rettv->vval.v_number = result;
+
+           /*
+            * Compute the result.
+            */
+           if (evaluate && !result)
+           {
+               if (tv_get_number_chk(&var2, &error) != 0)
+                   result = TRUE;
+               clear_tv(&var2);
+               if (error)
+                   return FAIL;
+           }
+           if (evaluate)
+           {
+               rettv->v_type = VAR_NUMBER;
+               rettv->vval.v_number = result;
+           }
+
+           p = eval_next_non_blank(*arg, evalarg_used, &getnext);
        }
 
-       p = eval_next_non_blank(*arg, evalarg, &getnext);
+       if (evalarg == NULL)
+           clear_evalarg(&local_evalarg, NULL);
+       else
+           evalarg->eval_flags = orig_flags;
     }
 
     return OK;
@@ -2270,10 +2275,6 @@ eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
 {
     char_u     *p;
     int                getnext;
-    typval_T   var2;
-    long       result;
-    int                first;
-    int                error = FALSE;
 
     /*
      * Get the first variable.
@@ -2282,69 +2283,77 @@ eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
        return FAIL;
 
     /*
-     * Repeat until there is no following "&&".
+     * Handle the "&&" operator.
      */
-    first = TRUE;
-    result = TRUE;
     p = eval_next_non_blank(*arg, evalarg, &getnext);
-    while (p[0] == '&' && p[1] == '&')
+    if (p[0] == '&' && p[1] == '&')
     {
-       evalarg_T   nested_evalarg;
+       evalarg_T   *evalarg_used = evalarg;
+       evalarg_T   local_evalarg;
        int         orig_flags;
        int         evaluate;
-
-       if (getnext)
-           *arg = eval_next_line(evalarg);
+       long        result = TRUE;
+       typval_T    var2;
+       int         error;
 
        if (evalarg == NULL)
        {
-           CLEAR_FIELD(nested_evalarg);
-           orig_flags = 0;
-           evaluate = FALSE;
+           CLEAR_FIELD(local_evalarg);
+           evalarg_used = &local_evalarg;
        }
-       else
-       {
-           nested_evalarg = *evalarg;
-           orig_flags = evalarg->eval_flags;
-           evaluate = orig_flags & EVAL_EVALUATE;
-       }
-       if (evaluate && first)
+       orig_flags = evalarg_used->eval_flags;
+       evaluate = orig_flags & EVAL_EVALUATE;
+       if (evaluate)
        {
+           error = FALSE;
            if (tv_get_number_chk(rettv, &error) == 0)
                result = FALSE;
            clear_tv(rettv);
            if (error)
                return FAIL;
-           first = FALSE;
        }
 
        /*
-        * Get the second variable.
+        * Repeat until there is no following "&&".
         */
-       *arg = skipwhite_and_linebreak(*arg + 2, evalarg);
-       nested_evalarg.eval_flags = result ? orig_flags
-                                                : orig_flags & ~EVAL_EVALUATE;
-       if (eval4(arg, &var2, &nested_evalarg) == FAIL)
-           return FAIL;
-
-       /*
-        * Compute the result.
-        */
-       if (evaluate && result)
+       while (p[0] == '&' && p[1] == '&')
        {
-           if (tv_get_number_chk(&var2, &error) == 0)
-               result = FALSE;
-           clear_tv(&var2);
-           if (error)
+           if (getnext)
+               *arg = eval_next_line(evalarg_used);
+
+           /*
+            * Get the second variable.
+            */
+           *arg = skipwhite_and_linebreak(*arg + 2, evalarg_used);
+           evalarg_used->eval_flags = result ? orig_flags
+                                                : orig_flags & ~EVAL_EVALUATE;
+           if (eval4(arg, &var2, evalarg_used) == FAIL)
                return FAIL;
-       }
-       if (evaluate)
-       {
-           rettv->v_type = VAR_NUMBER;
-           rettv->vval.v_number = result;
+
+           /*
+            * Compute the result.
+            */
+           if (evaluate && result)
+           {
+               if (tv_get_number_chk(&var2, &error) == 0)
+                   result = FALSE;
+               clear_tv(&var2);
+               if (error)
+                   return FAIL;
+           }
+           if (evaluate)
+           {
+               rettv->v_type = VAR_NUMBER;
+               rettv->vval.v_number = result;
+           }
+
+           p = eval_next_non_blank(*arg, evalarg_used, &getnext);
        }
 
-       p = eval_next_non_blank(*arg, evalarg, &getnext);
+       if (evalarg == NULL)
+           clear_evalarg(&local_evalarg, NULL);
+       else
+           evalarg->eval_flags = orig_flags;
     }
 
     return OK;
index edc655aeac4095e149823da7296b2c0979fcce42..ede464e519e75817f3b3e25d3a3d66c30b51d628 100644 (file)
@@ -1071,6 +1071,27 @@ def Test_expr7_lambda()
   assert_equal('result', La())
   assert_equal([1, 3, 5], [1, 2, 3]->map({key, val -> key + val}))
 
+  " line continuation inside lambda with "cond ? expr : expr" works
+  let ll = range(3)
+  map(ll, {k, v -> v % 2 ? {
+           '111': 111 } : {}
+       })
+  assert_equal([{}, {'111': 111}, {}], ll)
+
+  ll = range(3)
+  map(ll, {k, v -> v == 8 || v
+               == 9
+               || v % 2 ? 111 : 222
+       })
+  assert_equal([222, 111, 222], ll)
+
+  ll = range(3)
+  map(ll, {k, v -> v != 8 && v
+               != 9
+               && v % 2 == 0 ? 111 : 222
+       })
+  assert_equal([111, 222, 111], ll)
+
   call CheckDefFailure(["filter([1, 2], {k,v -> 1})"], 'E1069:')
 enddef
 
index eaca91f2c95155240090042091d6262c20cd1ab9..449d402a83c95385563b9c18e86c0db134630ea0 100644 (file)
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1189,
 /**/
     1188,
 /**/