To: vim_dev@googlegroups.com Subject: Patch 8.2.1080 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 -- Bram@Moolenaar.net -- 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 ///