]> granicus.if.org Git - vim/commitdiff
patch 8.2.1080: Vim9: no line break allowed in a for loop v8.2.1080
authorBram Moolenaar <Bram@vim.org>
Sun, 28 Jun 2020 16:43:40 +0000 (18:43 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 28 Jun 2020 16:43:40 +0000 (18:43 +0200)
Problem:    Vim9: no line break allowed in a for loop.
Solution:   Skip line breaks in for command.

src/eval.c
src/ex_eval.c
src/globals.h
src/proto/eval.pro
src/structs.h
src/testdir/test_vim9_cmd.vim
src/userfunc.c
src/version.c

index 82045675d01b66634072492cae7c34f11fec291e..141a97315bd27fb34d0e3c12424b0453b4e91117 100644 (file)
@@ -38,6 +38,7 @@ typedef struct
 {
     int                fi_semicolon;   // TRUE if ending in '; var]'
     int                fi_varcount;    // nr of variables in the list
+    int                fi_break_count; // nr of line breaks encountered
     listwatch_T        fi_lw;          // keep an eye on the item used.
     list_T     *fi_list;       // list being used
     int                fi_bi;          // index of blob
@@ -344,6 +345,7 @@ eval_to_string_skip(
     }
     if (skip)
        --emsg_skip;
+    clear_evalarg(&EVALARG_EVALUATE, eap);
 
     return retval;
 }
@@ -461,6 +463,7 @@ eval_to_string(
            retval = vim_strsave(tv_get_string(&tv));
        clear_tv(&tv);
     }
+    clear_evalarg(&EVALARG_EVALUATE, NULL);
 
     return retval;
 }
@@ -528,6 +531,7 @@ eval_expr(char_u *arg, exarg_T *eap)
     tv = ALLOC_ONE(typval_T);
     if (tv != NULL && eval0(arg, tv, eap, &EVALARG_EVALUATE) == FAIL)
        VIM_CLEAR(tv);
+    clear_evalarg(&EVALARG_EVALUATE, eap);
 
     return tv;
 }
@@ -675,6 +679,7 @@ eval_foldexpr(char_u *arg, int *cp)
     if (use_sandbox)
        --sandbox;
     --textwinlock;
+    clear_evalarg(&EVALARG_EVALUATE, NULL);
 
     return (int)retval;
 }
@@ -1481,16 +1486,14 @@ eval_for_line(
     char_u     *arg,
     int                *errp,
     exarg_T    *eap,
-    int                skip)
+    evalarg_T  *evalarg)
 {
     forinfo_T  *fi;
     char_u     *expr;
     typval_T   tv;
     list_T     *l;
-    evalarg_T  evalarg;
+    int                skip = !(evalarg->eval_flags & EVAL_EVALUATE);
 
-    CLEAR_FIELD(evalarg);
-    evalarg.eval_flags = skip ? 0 : EVAL_EVALUATE;
     *errp = TRUE;      // default: there is an error
 
     fi = ALLOC_CLEAR_ONE(forinfo_T);
@@ -1501,8 +1504,9 @@ eval_for_line(
     if (expr == NULL)
        return fi;
 
-    expr = skipwhite(expr);
-    if (expr[0] != 'i' || expr[1] != 'n' || !VIM_ISWHITE(expr[2]))
+    expr = skipwhite_and_linebreak(expr, evalarg);
+    if (expr[0] != 'i' || expr[1] != 'n'
+                                 || !(expr[2] == NUL || VIM_ISWHITE(expr[2])))
     {
        emsg(_(e_missing_in));
        return fi;
@@ -1510,7 +1514,8 @@ eval_for_line(
 
     if (skip)
        ++emsg_skip;
-    if (eval0(skipwhite(expr + 2), &tv, eap, &evalarg) == OK)
+    expr = skipwhite_and_linebreak(expr + 2, evalarg);
+    if (eval0(expr, &tv, eap, evalarg) == OK)
     {
        *errp = FALSE;
        if (!skip)
@@ -1558,10 +1563,24 @@ eval_for_line(
     }
     if (skip)
        --emsg_skip;
+    fi->fi_break_count = evalarg->eval_break_count;
 
     return fi;
 }
 
+/*
+ * Used when looping over a :for line, skip the "in expr" part.
+ */
+    void
+skip_for_lines(void *fi_void, evalarg_T *evalarg)
+{
+    forinfo_T  *fi = (forinfo_T *)fi_void;
+    int                i;
+
+    for (i = 0; i < fi->fi_break_count; ++i)
+       eval_next_line(evalarg);
+}
+
 /*
  * Use the first item in a ":for" list.  Advance to the next.
  * Assign the values to the variable (list).  "arg" points to the first one.
@@ -1866,6 +1885,7 @@ eval_next_line(evalarg_T *evalarg)
     char_u     *line;
 
     line = evalarg->eval_getline(0, evalarg->eval_cookie, 0, TRUE);
+    ++evalarg->eval_break_count;
     if (gap->ga_itemsize > 0 && ga_grow(gap, 1) == OK)
     {
        // Going to concatenate the lines after parsing.
@@ -1898,14 +1918,19 @@ skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg)
     void
 clear_evalarg(evalarg_T *evalarg, exarg_T *eap)
 {
-    if (evalarg != NULL && eap != NULL && evalarg->eval_tofree != NULL)
+    if (evalarg != NULL && evalarg->eval_tofree != NULL)
     {
-       // We may need to keep the original command line, e.g. for
-       // ":let" it has the variable names.  But we may also need the
-       // new one, "nextcmd" points into it.  Keep both.
-       vim_free(eap->cmdline_tofree);
-       eap->cmdline_tofree = *eap->cmdlinep;
-       *eap->cmdlinep = evalarg->eval_tofree;
+       if (eap != NULL)
+       {
+           // We may need to keep the original command line, e.g. for
+           // ":let" it has the variable names.  But we may also need the
+           // new one, "nextcmd" points into it.  Keep both.
+           vim_free(eap->cmdline_tofree);
+           eap->cmdline_tofree = *eap->cmdlinep;
+           *eap->cmdlinep = evalarg->eval_tofree;
+       }
+       else
+           vim_free(evalarg->eval_tofree);
        evalarg->eval_tofree = NULL;
     }
 }
@@ -1961,8 +1986,6 @@ eval0(
     if (eap != NULL)
        eap->nextcmd = check_nextcmd(p);
 
-    clear_evalarg(evalarg, eap);
-
     return ret;
 }
 
index 6f6b8c21894ddb866411d2dda027323cb909885a..fea8c7fd6bd9fd8a39280750d8bd054d76d9ad6d 100644 (file)
@@ -899,10 +899,16 @@ ex_eval(exarg_T *eap)
 
     CLEAR_FIELD(evalarg);
     evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE;
-    evalarg.eval_cookie = eap->getline == getsourceline ? eap->cookie : NULL;
+    if (getline_equal(eap->getline, eap->cookie, getsourceline))
+    {
+       evalarg.eval_getline = eap->getline;
+       evalarg.eval_cookie = eap->cookie;
+    }
 
     if (eval0(eap->arg, &tv, eap, &evalarg) == OK)
        clear_tv(&tv);
+
+    clear_evalarg(&evalarg, eap);
 }
 
 /*
@@ -1108,7 +1114,16 @@ ex_while(exarg_T *eap)
        }
        else
        {
-           void *fi;
+           void        *fi;
+           evalarg_T   evalarg;
+
+           CLEAR_FIELD(evalarg);
+           evalarg.eval_flags = skip ? 0 : EVAL_EVALUATE;
+           if (getline_equal(eap->getline, eap->cookie, getsourceline))
+           {
+               evalarg.eval_getline = eap->getline;
+               evalarg.eval_cookie = eap->cookie;
+           }
 
            /*
             * ":for var in list-expr"
@@ -1119,11 +1134,14 @@ ex_while(exarg_T *eap)
                // previously evaluated list.
                fi = cstack->cs_forinfo[cstack->cs_idx];
                error = FALSE;
+
+               // the "in expr" is not used, skip over it
+               skip_for_lines(fi, &evalarg);
            }
            else
            {
                // Evaluate the argument and get the info in a structure.
-               fi = eval_for_line(eap->arg, &error, eap, skip);
+               fi = eval_for_line(eap->arg, &error, eap, &evalarg);
                cstack->cs_forinfo[cstack->cs_idx] = fi;
            }
 
@@ -1138,6 +1156,7 @@ ex_while(exarg_T *eap)
                free_for_info(fi);
                cstack->cs_forinfo[cstack->cs_idx] = NULL;
            }
+           clear_evalarg(&evalarg, eap);
        }
 
        /*
index 19c6837ce282befaf58240765a38450e3052ab6c..41f9781c10606619e24d7411f7a68b92f7697872 100644 (file)
@@ -1885,7 +1885,7 @@ EXTERN listitem_T range_list_item;
 // Passed to an eval() function to enable evaluation.
 EXTERN evalarg_T EVALARG_EVALUATE
 # ifdef DO_INIT
-       = {EVAL_EVALUATE, NULL, NULL, {0, 0, 0, 0, NULL}, NULL}
+       = {EVAL_EVALUATE, 0, NULL, NULL, {0, 0, 0, 0, NULL}, NULL}
 # endif
        ;
 #endif
index 88dd8a7538dfcc9e8bea3dc5779732b992acc339..0e9ffeb80843f0523096f93229fa498bb07cb3f8 100644 (file)
@@ -22,7 +22,8 @@ int eval_foldexpr(char_u *arg, int *cp);
 char_u *get_lval(char_u *name, typval_T *rettv, lval_T *lp, int unlet, int skip, int flags, int fne_flags);
 void clear_lval(lval_T *lp);
 void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, int flags, char_u *op);
-void *eval_for_line(char_u *arg, int *errp, exarg_T *eap, int skip);
+void *eval_for_line(char_u *arg, int *errp, exarg_T *eap, evalarg_T *evalarg);
+void skip_for_lines(void *fi_void, evalarg_T *evalarg);
 int next_for_item(void *fi_void, char_u *arg);
 void free_for_info(void *fi_void);
 void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx);
index fd5ae2aa211ab86c84251d65ff73d1dbc3d3cc2c..cab6885e41b267e81d77943fba57bee5514e1053 100644 (file)
@@ -1758,11 +1758,12 @@ typedef struct
 // Struct passed through eval() functions.
 // See EVALARG_EVALUATE for a fixed value with eval_flags set to EVAL_EVALUATE.
 typedef struct {
-    int                eval_flags;     // EVAL_ flag values below
+    int                eval_flags;         // EVAL_ flag values below
+    int                eval_break_count;   // nr of line breaks consumed
 
     // copied from exarg_T when "getline" is "getsourceline". Can be NULL.
     char_u     *(*eval_getline)(int, void *, int, int);
-    void       *eval_cookie;   // argument for eval_getline()
+    void       *eval_cookie;       // argument for eval_getline()
 
     // Used to collect lines while parsing them, so that they can be
     // concatenated later.  Used when "eval_ga.ga_itemsize" is not zero.
index c0a4358d8dfd26f784f4134270e7fb815ad568f3..6fedf1fe9ceaf3a0b19e150bf3e9f8fe0e2e573a 100644 (file)
@@ -160,4 +160,35 @@ def Test_while_linebreak()
   CheckScriptSuccess(lines)
 enddef
 
+def Test_for_linebreak()
+  let lines =<< trim END
+      vim9script
+      let nr = 0
+      for x
+            in
+              [1, 2, 3, 4]
+          nr = nr + x
+      endfor
+      assert_equal(10, nr)
+  END
+  CheckScriptSuccess(lines)
+
+  lines =<< trim END
+      vim9script
+      let nr = 0
+      for x
+            in
+              [1, 2,
+                  3, 4
+                  ]
+          nr = nr
+                 +
+                  x
+      endfor
+      assert_equal(10, nr)
+  END
+  CheckScriptSuccess(lines)
+enddef
+
+
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
index 51c437f208132b69810d582e2d4e906d1c5f6869..05d3fda34c7f05082d0ff09d70497e797d498041 100644 (file)
@@ -3825,6 +3825,7 @@ ex_return(exarg_T *eap)
 
     if (eap->skip)
        --emsg_skip;
+    clear_evalarg(&evalarg, eap);
 }
 
 /*
index 8047cbe68a346bd4636ca2c1ab89f7ba6150b090..0c24515bc802e172ca9ef79ed28ac1fb5afb3bf9 100644 (file)
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1080,
 /**/
     1079,
 /**/