Patch 8.2.1080
Problem:    Vim9: no line break allowed in a for loop.
Solution:   Skip line breaks in for command.
Files:      src/eval.c, src/ex_eval.c, src/proto/eval.pro, src/userfunc.c,
            src/structs.h, src/globals.h, src/testdir/test_vim9_cmd.vim


*** ../vim-8.2.1079/src/eval.c  2020-06-28 15:51:12.145674365 +0200
--- src/eval.c  2020-06-28 18:13:11.781536397 +0200
***************
*** 38,43 ****
--- 38,44 ----
  {
      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,349 ****
--- 345,351 ----
      }
      if (skip)
        --emsg_skip;
+     clear_evalarg(&EVALARG_EVALUATE, eap);
  
      return retval;
  }
***************
*** 461,466 ****
--- 463,469 ----
            retval = vim_strsave(tv_get_string(&tv));
        clear_tv(&tv);
      }
+     clear_evalarg(&EVALARG_EVALUATE, NULL);
  
      return retval;
  }
***************
*** 528,533 ****
--- 531,537 ----
      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,680 ****
--- 679,685 ----
      if (use_sandbox)
        --sandbox;
      --textwinlock;
+     clear_evalarg(&EVALARG_EVALUATE, NULL);
  
      return (int)retval;
  }
***************
*** 1481,1496 ****
      char_u    *arg,
      int               *errp,
      exarg_T   *eap,
!     int               skip)
  {
      forinfo_T *fi;
      char_u    *expr;
      typval_T  tv;
      list_T    *l;
!     evalarg_T evalarg;
  
-     CLEAR_FIELD(evalarg);
-     evalarg.eval_flags = skip ? 0 : EVAL_EVALUATE;
      *errp = TRUE;     // default: there is an error
  
      fi = ALLOC_CLEAR_ONE(forinfo_T);
--- 1486,1499 ----
      char_u    *arg,
      int               *errp,
      exarg_T   *eap,
!     evalarg_T *evalarg)
  {
      forinfo_T *fi;
      char_u    *expr;
      typval_T  tv;
      list_T    *l;
!     int               skip = !(evalarg->eval_flags & EVAL_EVALUATE);
  
      *errp = TRUE;     // default: there is an error
  
      fi = ALLOC_CLEAR_ONE(forinfo_T);
***************
*** 1501,1508 ****
      if (expr == NULL)
        return fi;
  
!     expr = skipwhite(expr);
!     if (expr[0] != 'i' || expr[1] != 'n' || !VIM_ISWHITE(expr[2]))
      {
        emsg(_(e_missing_in));
        return fi;
--- 1504,1512 ----
      if (expr == NULL)
        return fi;
  
!     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,1516 ****
  
      if (skip)
        ++emsg_skip;
!     if (eval0(skipwhite(expr + 2), &tv, eap, &evalarg) == OK)
      {
        *errp = FALSE;
        if (!skip)
--- 1514,1521 ----
  
      if (skip)
        ++emsg_skip;
!     expr = skipwhite_and_linebreak(expr + 2, evalarg);
!     if (eval0(expr, &tv, eap, evalarg) == OK)
      {
        *errp = FALSE;
        if (!skip)
***************
*** 1558,1568 ****
--- 1563,1587 ----
      }
      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.
   * Return TRUE when a valid item was found, FALSE when at end of list or
***************
*** 1866,1871 ****
--- 1885,1891 ----
      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,1911 ****
      void
  clear_evalarg(evalarg_T *evalarg, exarg_T *eap)
  {
!     if (evalarg != NULL && eap != 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;
        evalarg->eval_tofree = NULL;
      }
  }
--- 1918,1936 ----
      void
  clear_evalarg(evalarg_T *evalarg, exarg_T *eap)
  {
!     if (evalarg != NULL && evalarg->eval_tofree != NULL)
      {
!       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,1968 ****
      if (eap != NULL)
        eap->nextcmd = check_nextcmd(p);
  
-     clear_evalarg(evalarg, eap);
- 
      return ret;
  }
  
--- 1986,1991 ----
*** ../vim-8.2.1079/src/ex_eval.c       2020-06-27 18:06:42.152575113 +0200
--- src/ex_eval.c       2020-06-28 17:44:22.647831198 +0200
***************
*** 899,908 ****
  
      CLEAR_FIELD(evalarg);
      evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE;
!     evalarg.eval_cookie = eap->getline == getsourceline ? eap->cookie : NULL;
  
      if (eval0(eap->arg, &tv, eap, &evalarg) == OK)
        clear_tv(&tv);
  }
  
  /*
--- 899,914 ----
  
      CLEAR_FIELD(evalarg);
      evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE;
!     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,1114 ****
        }
        else
        {
!           void *fi;
  
            /*
             * ":for var in list-expr"
--- 1114,1129 ----
        }
        else
        {
!           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,1129 ****
                // previously evaluated list.
                fi = cstack->cs_forinfo[cstack->cs_idx];
                error = FALSE;
            }
            else
            {
                // Evaluate the argument and get the info in a structure.
!               fi = eval_for_line(eap->arg, &error, eap, skip);
                cstack->cs_forinfo[cstack->cs_idx] = fi;
            }
  
--- 1134,1147 ----
                // 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, &evalarg);
                cstack->cs_forinfo[cstack->cs_idx] = fi;
            }
  
***************
*** 1138,1143 ****
--- 1156,1162 ----
                free_for_info(fi);
                cstack->cs_forinfo[cstack->cs_idx] = NULL;
            }
+           clear_evalarg(&evalarg, eap);
        }
  
        /*
*** ../vim-8.2.1079/src/proto/eval.pro  2020-06-27 23:07:31.959995377 +0200
--- src/proto/eval.pro  2020-06-28 17:44:27.595803900 +0200
***************
*** 22,28 ****
  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);
  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);
--- 22,29 ----
  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, 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);
*** ../vim-8.2.1079/src/userfunc.c      2020-06-27 21:17:55.359214424 +0200
--- src/userfunc.c      2020-06-28 17:11:10.624308131 +0200
***************
*** 3825,3830 ****
--- 3825,3831 ----
  
      if (eap->skip)
        --emsg_skip;
+     clear_evalarg(&evalarg, eap);
  }
  
  /*
*** ../vim-8.2.1079/src/structs.h       2020-06-28 15:51:12.145674365 +0200
--- src/structs.h       2020-06-28 17:34:58.438997932 +0200
***************
*** 1758,1768 ****
  // 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
  
      // 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()
  
      // Used to collect lines while parsing them, so that they can be
      // concatenated later.  Used when "eval_ga.ga_itemsize" is not zero.
--- 1758,1769 ----
  // 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_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()
  
      // Used to collect lines while parsing them, so that they can be
      // concatenated later.  Used when "eval_ga.ga_itemsize" is not zero.
*** ../vim-8.2.1079/src/globals.h       2020-06-28 15:51:12.145674365 +0200
--- src/globals.h       2020-06-28 17:35:33.170798595 +0200
***************
*** 1885,1891 ****
  // 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}
  # endif
        ;
  #endif
--- 1885,1891 ----
  // Passed to an eval() function to enable evaluation.
  EXTERN evalarg_T EVALARG_EVALUATE
  # ifdef DO_INIT
!       = {EVAL_EVALUATE, 0, NULL, NULL, {0, 0, 0, 0, NULL}, NULL}
  # endif
        ;
  #endif
*** ../vim-8.2.1079/src/testdir/test_vim9_cmd.vim       2020-06-28 
15:51:12.149674344 +0200
--- src/testdir/test_vim9_cmd.vim       2020-06-28 18:14:35.689151772 +0200
***************
*** 160,163 ****
--- 160,194 ----
    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
*** ../vim-8.2.1079/src/version.c       2020-06-28 15:51:12.149674344 +0200
--- src/version.c       2020-06-28 17:01:23.466966315 +0200
***************
*** 756,757 ****
--- 756,759 ----
  {   /* Add new patch number below this line */
+ /**/
+     1080,
  /**/

-- 
NEIL INNES PLAYED: THE FIRST SELF-DESTRUCTIVE MONK, ROBIN'S LEAST FAVORITE
                   MINSTREL, THE PAGE CRUSHED BY A RABBIT, THE OWNER OF A DUCK
                 "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202006281644.05SGiHxl399283%40masaka.moolenaar.net.

Raspunde prin e-mail lui