mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 8.2.1071: Vim9: no line break allowed inside a lambda
Problem: Vim9: no line break allowed inside a lambda. Solution: Handle line break inside a lambda in Vim9 script.
This commit is contained in:
137
src/eval.c
137
src/eval.c
@@ -325,8 +325,7 @@ eval_to_string_skip(
|
||||
|
||||
if (skip)
|
||||
++emsg_skip;
|
||||
if (eval0(arg, &tv, eap, skip ? NULL : &EVALARG_EVALUATE)
|
||||
== FAIL || skip)
|
||||
if (eval0(arg, &tv, eap, skip ? NULL : &EVALARG_EVALUATE) == FAIL || skip)
|
||||
retval = NULL;
|
||||
else
|
||||
{
|
||||
@@ -352,6 +351,61 @@ skip_expr(char_u **pp)
|
||||
return eval1(pp, &rettv, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip over an expression at "*pp".
|
||||
* If in Vim9 script and line breaks are encountered, the lines are
|
||||
* concatenated. "evalarg->eval_tofree" will be set accordingly.
|
||||
* Return FAIL for an error, OK otherwise.
|
||||
*/
|
||||
int
|
||||
skip_expr_concatenate(char_u **start, char_u **end, evalarg_T *evalarg)
|
||||
{
|
||||
typval_T rettv;
|
||||
int res;
|
||||
int vim9script = current_sctx.sc_version == SCRIPT_VERSION_VIM9;
|
||||
garray_T *gap = &evalarg->eval_ga;
|
||||
int save_flags = evalarg == NULL ? 0 : evalarg->eval_flags;
|
||||
|
||||
if (vim9script && evalarg->eval_cookie != NULL)
|
||||
{
|
||||
ga_init2(gap, sizeof(char_u *), 10);
|
||||
if (ga_grow(gap, 1) == OK)
|
||||
// leave room for "start"
|
||||
++gap->ga_len;
|
||||
}
|
||||
|
||||
// Don't evaluate the expression.
|
||||
if (evalarg != NULL)
|
||||
evalarg->eval_flags &= ~EVAL_EVALUATE;
|
||||
*end = skipwhite(*end);
|
||||
res = eval1(end, &rettv, evalarg);
|
||||
if (evalarg != NULL)
|
||||
evalarg->eval_flags = save_flags;
|
||||
|
||||
if (vim9script && evalarg->eval_cookie != NULL
|
||||
&& evalarg->eval_ga.ga_len > 1)
|
||||
{
|
||||
char_u *p;
|
||||
size_t endoff = STRLEN(*end);
|
||||
|
||||
// Line breaks encountered, concatenate all the lines.
|
||||
*((char_u **)gap->ga_data) = *start;
|
||||
p = ga_concat_strings(gap, "");
|
||||
*((char_u **)gap->ga_data) = NULL;
|
||||
ga_clear_strings(gap);
|
||||
gap->ga_itemsize = 0;
|
||||
if (p == NULL)
|
||||
return FAIL;
|
||||
*start = p;
|
||||
vim_free(evalarg->eval_tofree);
|
||||
evalarg->eval_tofree = p;
|
||||
// Compute "end" relative to the end.
|
||||
*end = *start + STRLEN(*start) - endoff;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Top level evaluation function, returning a string.
|
||||
* When "convert" is TRUE convert a List into a sequence of lines and convert
|
||||
@@ -1794,14 +1848,27 @@ eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext)
|
||||
}
|
||||
|
||||
/*
|
||||
* To be called when eval_next_non_blank() sets "getnext" to TRUE.
|
||||
* To be called after eval_next_non_blank() sets "getnext" to TRUE.
|
||||
*/
|
||||
char_u *
|
||||
eval_next_line(evalarg_T *evalarg)
|
||||
{
|
||||
vim_free(evalarg->eval_tofree);
|
||||
evalarg->eval_tofree = getsourceline(0, evalarg->eval_cookie, 0, TRUE);
|
||||
return skipwhite(evalarg->eval_tofree);
|
||||
garray_T *gap = &evalarg->eval_ga;
|
||||
char_u *line;
|
||||
|
||||
line = getsourceline(0, evalarg->eval_cookie, 0, TRUE);
|
||||
if (gap->ga_itemsize > 0 && ga_grow(gap, 1) == OK)
|
||||
{
|
||||
// Going to concatenate the lines after parsing.
|
||||
((char_u **)gap->ga_data)[gap->ga_len] = line;
|
||||
++gap->ga_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
vim_free(evalarg->eval_tofree);
|
||||
evalarg->eval_tofree = line;
|
||||
}
|
||||
return skipwhite(line);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1831,8 +1898,6 @@ eval0(
|
||||
int called_emsg_before = called_emsg;
|
||||
int flags = evalarg == NULL ? 0 : evalarg->eval_flags;
|
||||
|
||||
if (evalarg != NULL)
|
||||
evalarg->eval_tofree = NULL;
|
||||
p = skipwhite(arg);
|
||||
ret = eval1(&p, rettv, evalarg);
|
||||
|
||||
@@ -1857,22 +1922,15 @@ eval0(
|
||||
if (eap != NULL)
|
||||
eap->nextcmd = check_nextcmd(p);
|
||||
|
||||
if (evalarg != NULL)
|
||||
if (evalarg != NULL && eap != NULL && evalarg->eval_tofree != NULL)
|
||||
{
|
||||
if (eap != NULL)
|
||||
{
|
||||
if (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;
|
||||
}
|
||||
}
|
||||
else
|
||||
vim_free(evalarg->eval_tofree);
|
||||
// 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;
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -2797,7 +2855,7 @@ eval7(
|
||||
* Lambda: {arg, arg -> expr}
|
||||
* Dictionary: {'key': val, 'key': val}
|
||||
*/
|
||||
case '{': ret = get_lambda_tv(arg, rettv, evaluate);
|
||||
case '{': ret = get_lambda_tv(arg, rettv, evalarg);
|
||||
if (ret == NOTDONE)
|
||||
ret = eval_dict(arg, rettv, evalarg, FALSE);
|
||||
break;
|
||||
@@ -2884,7 +2942,7 @@ eval7(
|
||||
// Handle following '[', '(' and '.' for expr[expr], expr.name,
|
||||
// expr(expr), expr->name(expr)
|
||||
if (ret == OK)
|
||||
ret = handle_subscript(arg, rettv, flags, TRUE);
|
||||
ret = handle_subscript(arg, rettv, evalarg, TRUE);
|
||||
|
||||
/*
|
||||
* Apply logical NOT and unary '-', from right to left, ignore '+'.
|
||||
@@ -3031,9 +3089,11 @@ call_func_rettv(
|
||||
eval_lambda(
|
||||
char_u **arg,
|
||||
typval_T *rettv,
|
||||
int evaluate,
|
||||
evalarg_T *evalarg,
|
||||
int verbose) // give error messages
|
||||
{
|
||||
int evaluate = evalarg != NULL
|
||||
&& (evalarg->eval_flags & EVAL_EVALUATE);
|
||||
typval_T base = *rettv;
|
||||
int ret;
|
||||
|
||||
@@ -3041,7 +3101,7 @@ eval_lambda(
|
||||
*arg += 2;
|
||||
rettv->v_type = VAR_UNKNOWN;
|
||||
|
||||
ret = get_lambda_tv(arg, rettv, evaluate);
|
||||
ret = get_lambda_tv(arg, rettv, evalarg);
|
||||
if (ret != OK)
|
||||
return FAIL;
|
||||
else if (**arg != '(')
|
||||
@@ -3136,10 +3196,11 @@ eval_method(
|
||||
eval_index(
|
||||
char_u **arg,
|
||||
typval_T *rettv,
|
||||
int flags,
|
||||
evalarg_T *evalarg,
|
||||
int verbose) // give error messages
|
||||
{
|
||||
int evaluate = flags & EVAL_EVALUATE;
|
||||
int evaluate = evalarg != NULL
|
||||
&& (evalarg->eval_flags & EVAL_EVALUATE);
|
||||
int empty1 = FALSE, empty2 = FALSE;
|
||||
typval_T var1, var2;
|
||||
long i;
|
||||
@@ -3200,11 +3261,6 @@ eval_index(
|
||||
}
|
||||
else
|
||||
{
|
||||
evalarg_T evalarg;
|
||||
|
||||
CLEAR_FIELD(evalarg);
|
||||
evalarg.eval_flags = flags;
|
||||
|
||||
/*
|
||||
* something[idx]
|
||||
*
|
||||
@@ -3213,7 +3269,7 @@ eval_index(
|
||||
*arg = skipwhite(*arg + 1);
|
||||
if (**arg == ':')
|
||||
empty1 = TRUE;
|
||||
else if (eval1(arg, &var1, &evalarg) == FAIL) // recursive!
|
||||
else if (eval1(arg, &var1, evalarg) == FAIL) // recursive!
|
||||
return FAIL;
|
||||
else if (evaluate && tv_get_string_chk(&var1) == NULL)
|
||||
{
|
||||
@@ -3231,7 +3287,7 @@ eval_index(
|
||||
*arg = skipwhite(*arg + 1);
|
||||
if (**arg == ']')
|
||||
empty2 = TRUE;
|
||||
else if (eval1(arg, &var2, &evalarg) == FAIL) // recursive!
|
||||
else if (eval1(arg, &var2, evalarg) == FAIL) // recursive!
|
||||
{
|
||||
if (!empty1)
|
||||
clear_tv(&var1);
|
||||
@@ -4884,10 +4940,11 @@ eval_isnamec1(int c)
|
||||
handle_subscript(
|
||||
char_u **arg,
|
||||
typval_T *rettv,
|
||||
int flags, // do more than finding the end
|
||||
evalarg_T *evalarg,
|
||||
int verbose) // give error messages
|
||||
{
|
||||
int evaluate = flags & EVAL_EVALUATE;
|
||||
int evaluate = evalarg != NULL
|
||||
&& (evalarg->eval_flags & EVAL_EVALUATE);
|
||||
int ret = OK;
|
||||
dict_T *selfdict = NULL;
|
||||
|
||||
@@ -4926,7 +4983,7 @@ handle_subscript(
|
||||
{
|
||||
if ((*arg)[2] == '{')
|
||||
// expr->{lambda}()
|
||||
ret = eval_lambda(arg, rettv, evaluate, verbose);
|
||||
ret = eval_lambda(arg, rettv, evalarg, verbose);
|
||||
else
|
||||
// expr->name()
|
||||
ret = eval_method(arg, rettv, evaluate, verbose);
|
||||
@@ -4943,7 +5000,7 @@ handle_subscript(
|
||||
}
|
||||
else
|
||||
selfdict = NULL;
|
||||
if (eval_index(arg, rettv, flags, verbose) == FAIL)
|
||||
if (eval_index(arg, rettv, evalarg, verbose) == FAIL)
|
||||
{
|
||||
clear_tv(rettv);
|
||||
ret = FAIL;
|
||||
|
Reference in New Issue
Block a user