0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

patch 8.2.1080: Vim9: no line break allowed in a for loop

Problem:    Vim9: no line break allowed in a for loop.
Solution:   Skip line breaks in for command.
This commit is contained in:
Bram Moolenaar 2020-06-28 18:43:40 +02:00
parent d5053d015a
commit b7a78f7a67
8 changed files with 101 additions and 23 deletions

View File

@ -38,6 +38,7 @@ typedef struct
{ {
int fi_semicolon; // TRUE if ending in '; var]' int fi_semicolon; // TRUE if ending in '; var]'
int fi_varcount; // nr of variables in the list 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. listwatch_T fi_lw; // keep an eye on the item used.
list_T *fi_list; // list being used list_T *fi_list; // list being used
int fi_bi; // index of blob int fi_bi; // index of blob
@ -344,6 +345,7 @@ eval_to_string_skip(
} }
if (skip) if (skip)
--emsg_skip; --emsg_skip;
clear_evalarg(&EVALARG_EVALUATE, eap);
return retval; return retval;
} }
@ -461,6 +463,7 @@ eval_to_string(
retval = vim_strsave(tv_get_string(&tv)); retval = vim_strsave(tv_get_string(&tv));
clear_tv(&tv); clear_tv(&tv);
} }
clear_evalarg(&EVALARG_EVALUATE, NULL);
return retval; return retval;
} }
@ -528,6 +531,7 @@ eval_expr(char_u *arg, exarg_T *eap)
tv = ALLOC_ONE(typval_T); tv = ALLOC_ONE(typval_T);
if (tv != NULL && eval0(arg, tv, eap, &EVALARG_EVALUATE) == FAIL) if (tv != NULL && eval0(arg, tv, eap, &EVALARG_EVALUATE) == FAIL)
VIM_CLEAR(tv); VIM_CLEAR(tv);
clear_evalarg(&EVALARG_EVALUATE, eap);
return tv; return tv;
} }
@ -675,6 +679,7 @@ eval_foldexpr(char_u *arg, int *cp)
if (use_sandbox) if (use_sandbox)
--sandbox; --sandbox;
--textwinlock; --textwinlock;
clear_evalarg(&EVALARG_EVALUATE, NULL);
return (int)retval; return (int)retval;
} }
@ -1481,16 +1486,14 @@ eval_for_line(
char_u *arg, char_u *arg,
int *errp, int *errp,
exarg_T *eap, exarg_T *eap,
int skip) evalarg_T *evalarg)
{ {
forinfo_T *fi; forinfo_T *fi;
char_u *expr; char_u *expr;
typval_T tv; typval_T tv;
list_T *l; 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 *errp = TRUE; // default: there is an error
fi = ALLOC_CLEAR_ONE(forinfo_T); fi = ALLOC_CLEAR_ONE(forinfo_T);
@ -1501,8 +1504,9 @@ eval_for_line(
if (expr == NULL) if (expr == NULL)
return fi; return fi;
expr = skipwhite(expr); expr = skipwhite_and_linebreak(expr, evalarg);
if (expr[0] != 'i' || expr[1] != 'n' || !VIM_ISWHITE(expr[2])) if (expr[0] != 'i' || expr[1] != 'n'
|| !(expr[2] == NUL || VIM_ISWHITE(expr[2])))
{ {
emsg(_(e_missing_in)); emsg(_(e_missing_in));
return fi; return fi;
@ -1510,7 +1514,8 @@ eval_for_line(
if (skip) if (skip)
++emsg_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; *errp = FALSE;
if (!skip) if (!skip)
@ -1558,10 +1563,24 @@ eval_for_line(
} }
if (skip) if (skip)
--emsg_skip; --emsg_skip;
fi->fi_break_count = evalarg->eval_break_count;
return fi; 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. * 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. * 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; char_u *line;
line = evalarg->eval_getline(0, evalarg->eval_cookie, 0, TRUE); line = evalarg->eval_getline(0, evalarg->eval_cookie, 0, TRUE);
++evalarg->eval_break_count;
if (gap->ga_itemsize > 0 && ga_grow(gap, 1) == OK) if (gap->ga_itemsize > 0 && ga_grow(gap, 1) == OK)
{ {
// Going to concatenate the lines after parsing. // Going to concatenate the lines after parsing.
@ -1898,7 +1918,9 @@ skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg)
void void
clear_evalarg(evalarg_T *evalarg, exarg_T *eap) clear_evalarg(evalarg_T *evalarg, exarg_T *eap)
{ {
if (evalarg != NULL && eap != NULL && evalarg->eval_tofree != NULL) if (evalarg != NULL && evalarg->eval_tofree != NULL)
{
if (eap != NULL)
{ {
// We may need to keep the original command line, e.g. for // We may need to keep the original command line, e.g. for
// ":let" it has the variable names. But we may also need the // ":let" it has the variable names. But we may also need the
@ -1906,6 +1928,9 @@ clear_evalarg(evalarg_T *evalarg, exarg_T *eap)
vim_free(eap->cmdline_tofree); vim_free(eap->cmdline_tofree);
eap->cmdline_tofree = *eap->cmdlinep; eap->cmdline_tofree = *eap->cmdlinep;
*eap->cmdlinep = evalarg->eval_tofree; *eap->cmdlinep = evalarg->eval_tofree;
}
else
vim_free(evalarg->eval_tofree);
evalarg->eval_tofree = NULL; evalarg->eval_tofree = NULL;
} }
} }
@ -1961,8 +1986,6 @@ eval0(
if (eap != NULL) if (eap != NULL)
eap->nextcmd = check_nextcmd(p); eap->nextcmd = check_nextcmd(p);
clear_evalarg(evalarg, eap);
return ret; return ret;
} }

View File

@ -899,10 +899,16 @@ ex_eval(exarg_T *eap)
CLEAR_FIELD(evalarg); CLEAR_FIELD(evalarg);
evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE; 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) if (eval0(eap->arg, &tv, eap, &evalarg) == OK)
clear_tv(&tv); clear_tv(&tv);
clear_evalarg(&evalarg, eap);
} }
/* /*
@ -1109,6 +1115,15 @@ ex_while(exarg_T *eap)
else 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" * ":for var in list-expr"
@ -1119,11 +1134,14 @@ ex_while(exarg_T *eap)
// previously evaluated list. // previously evaluated list.
fi = cstack->cs_forinfo[cstack->cs_idx]; fi = cstack->cs_forinfo[cstack->cs_idx];
error = FALSE; error = FALSE;
// the "in expr" is not used, skip over it
skip_for_lines(fi, &evalarg);
} }
else else
{ {
// Evaluate the argument and get the info in a structure. // 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; cstack->cs_forinfo[cstack->cs_idx] = fi;
} }
@ -1138,6 +1156,7 @@ ex_while(exarg_T *eap)
free_for_info(fi); free_for_info(fi);
cstack->cs_forinfo[cstack->cs_idx] = NULL; cstack->cs_forinfo[cstack->cs_idx] = NULL;
} }
clear_evalarg(&evalarg, eap);
} }
/* /*

View File

@ -1885,7 +1885,7 @@ EXTERN listitem_T range_list_item;
// Passed to an eval() function to enable evaluation. // Passed to an eval() function to enable evaluation.
EXTERN evalarg_T EVALARG_EVALUATE EXTERN evalarg_T EVALARG_EVALUATE
# ifdef DO_INIT # 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
; ;
#endif #endif

View 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); 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 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 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); int next_for_item(void *fi_void, char_u *arg);
void free_for_info(void *fi_void); void free_for_info(void *fi_void);
void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx); void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx);

View File

@ -1759,6 +1759,7 @@ typedef struct
// See EVALARG_EVALUATE for a fixed value with eval_flags set to EVAL_EVALUATE. // See EVALARG_EVALUATE for a fixed value with eval_flags set to EVAL_EVALUATE.
typedef struct { 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. // copied from exarg_T when "getline" is "getsourceline". Can be NULL.
char_u *(*eval_getline)(int, void *, int, int); char_u *(*eval_getline)(int, void *, int, int);

View File

@ -160,4 +160,35 @@ def Test_while_linebreak()
CheckScriptSuccess(lines) CheckScriptSuccess(lines)
enddef 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: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker

View File

@ -3825,6 +3825,7 @@ ex_return(exarg_T *eap)
if (eap->skip) if (eap->skip)
--emsg_skip; --emsg_skip;
clear_evalarg(&evalarg, eap);
} }
/* /*

View File

@ -754,6 +754,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1080,
/**/ /**/
1079, 1079,
/**/ /**/