forked from aniani/vim
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:
parent
ab19d495fd
commit
e40fbc2ca9
137
src/eval.c
137
src/eval.c
@ -325,8 +325,7 @@ eval_to_string_skip(
|
|||||||
|
|
||||||
if (skip)
|
if (skip)
|
||||||
++emsg_skip;
|
++emsg_skip;
|
||||||
if (eval0(arg, &tv, eap, skip ? NULL : &EVALARG_EVALUATE)
|
if (eval0(arg, &tv, eap, skip ? NULL : &EVALARG_EVALUATE) == FAIL || skip)
|
||||||
== FAIL || skip)
|
|
||||||
retval = NULL;
|
retval = NULL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -352,6 +351,61 @@ skip_expr(char_u **pp)
|
|||||||
return eval1(pp, &rettv, NULL);
|
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.
|
* Top level evaluation function, returning a string.
|
||||||
* When "convert" is TRUE convert a List into a sequence of lines and convert
|
* 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 *
|
char_u *
|
||||||
eval_next_line(evalarg_T *evalarg)
|
eval_next_line(evalarg_T *evalarg)
|
||||||
{
|
{
|
||||||
vim_free(evalarg->eval_tofree);
|
garray_T *gap = &evalarg->eval_ga;
|
||||||
evalarg->eval_tofree = getsourceline(0, evalarg->eval_cookie, 0, TRUE);
|
char_u *line;
|
||||||
return skipwhite(evalarg->eval_tofree);
|
|
||||||
|
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 called_emsg_before = called_emsg;
|
||||||
int flags = evalarg == NULL ? 0 : evalarg->eval_flags;
|
int flags = evalarg == NULL ? 0 : evalarg->eval_flags;
|
||||||
|
|
||||||
if (evalarg != NULL)
|
|
||||||
evalarg->eval_tofree = NULL;
|
|
||||||
p = skipwhite(arg);
|
p = skipwhite(arg);
|
||||||
ret = eval1(&p, rettv, evalarg);
|
ret = eval1(&p, rettv, evalarg);
|
||||||
|
|
||||||
@ -1857,22 +1922,15 @@ eval0(
|
|||||||
if (eap != NULL)
|
if (eap != NULL)
|
||||||
eap->nextcmd = check_nextcmd(p);
|
eap->nextcmd = check_nextcmd(p);
|
||||||
|
|
||||||
if (evalarg != NULL)
|
if (evalarg != NULL && eap != 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
|
||||||
if (evalarg->eval_tofree != NULL)
|
// new one, "nextcmd" points into it. Keep both.
|
||||||
{
|
vim_free(eap->cmdline_tofree);
|
||||||
// We may need to keep the original command line, e.g. for
|
eap->cmdline_tofree = *eap->cmdlinep;
|
||||||
// ":let" it has the variable names. But we may also need the
|
*eap->cmdlinep = evalarg->eval_tofree;
|
||||||
// new one, "nextcmd" points into it. Keep both.
|
evalarg->eval_tofree = NULL;
|
||||||
vim_free(eap->cmdline_tofree);
|
|
||||||
eap->cmdline_tofree = *eap->cmdlinep;
|
|
||||||
*eap->cmdlinep = evalarg->eval_tofree;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
vim_free(evalarg->eval_tofree);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -2797,7 +2855,7 @@ eval7(
|
|||||||
* Lambda: {arg, arg -> expr}
|
* Lambda: {arg, arg -> expr}
|
||||||
* Dictionary: {'key': val, 'key': val}
|
* Dictionary: {'key': val, 'key': val}
|
||||||
*/
|
*/
|
||||||
case '{': ret = get_lambda_tv(arg, rettv, evaluate);
|
case '{': ret = get_lambda_tv(arg, rettv, evalarg);
|
||||||
if (ret == NOTDONE)
|
if (ret == NOTDONE)
|
||||||
ret = eval_dict(arg, rettv, evalarg, FALSE);
|
ret = eval_dict(arg, rettv, evalarg, FALSE);
|
||||||
break;
|
break;
|
||||||
@ -2884,7 +2942,7 @@ eval7(
|
|||||||
// Handle following '[', '(' and '.' for expr[expr], expr.name,
|
// Handle following '[', '(' and '.' for expr[expr], expr.name,
|
||||||
// expr(expr), expr->name(expr)
|
// expr(expr), expr->name(expr)
|
||||||
if (ret == OK)
|
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 '+'.
|
* Apply logical NOT and unary '-', from right to left, ignore '+'.
|
||||||
@ -3031,9 +3089,11 @@ call_func_rettv(
|
|||||||
eval_lambda(
|
eval_lambda(
|
||||||
char_u **arg,
|
char_u **arg,
|
||||||
typval_T *rettv,
|
typval_T *rettv,
|
||||||
int evaluate,
|
evalarg_T *evalarg,
|
||||||
int verbose) // give error messages
|
int verbose) // give error messages
|
||||||
{
|
{
|
||||||
|
int evaluate = evalarg != NULL
|
||||||
|
&& (evalarg->eval_flags & EVAL_EVALUATE);
|
||||||
typval_T base = *rettv;
|
typval_T base = *rettv;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -3041,7 +3101,7 @@ eval_lambda(
|
|||||||
*arg += 2;
|
*arg += 2;
|
||||||
rettv->v_type = VAR_UNKNOWN;
|
rettv->v_type = VAR_UNKNOWN;
|
||||||
|
|
||||||
ret = get_lambda_tv(arg, rettv, evaluate);
|
ret = get_lambda_tv(arg, rettv, evalarg);
|
||||||
if (ret != OK)
|
if (ret != OK)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
else if (**arg != '(')
|
else if (**arg != '(')
|
||||||
@ -3136,10 +3196,11 @@ eval_method(
|
|||||||
eval_index(
|
eval_index(
|
||||||
char_u **arg,
|
char_u **arg,
|
||||||
typval_T *rettv,
|
typval_T *rettv,
|
||||||
int flags,
|
evalarg_T *evalarg,
|
||||||
int verbose) // give error messages
|
int verbose) // give error messages
|
||||||
{
|
{
|
||||||
int evaluate = flags & EVAL_EVALUATE;
|
int evaluate = evalarg != NULL
|
||||||
|
&& (evalarg->eval_flags & EVAL_EVALUATE);
|
||||||
int empty1 = FALSE, empty2 = FALSE;
|
int empty1 = FALSE, empty2 = FALSE;
|
||||||
typval_T var1, var2;
|
typval_T var1, var2;
|
||||||
long i;
|
long i;
|
||||||
@ -3200,11 +3261,6 @@ eval_index(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
evalarg_T evalarg;
|
|
||||||
|
|
||||||
CLEAR_FIELD(evalarg);
|
|
||||||
evalarg.eval_flags = flags;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* something[idx]
|
* something[idx]
|
||||||
*
|
*
|
||||||
@ -3213,7 +3269,7 @@ eval_index(
|
|||||||
*arg = skipwhite(*arg + 1);
|
*arg = skipwhite(*arg + 1);
|
||||||
if (**arg == ':')
|
if (**arg == ':')
|
||||||
empty1 = TRUE;
|
empty1 = TRUE;
|
||||||
else if (eval1(arg, &var1, &evalarg) == FAIL) // recursive!
|
else if (eval1(arg, &var1, evalarg) == FAIL) // recursive!
|
||||||
return FAIL;
|
return FAIL;
|
||||||
else if (evaluate && tv_get_string_chk(&var1) == NULL)
|
else if (evaluate && tv_get_string_chk(&var1) == NULL)
|
||||||
{
|
{
|
||||||
@ -3231,7 +3287,7 @@ eval_index(
|
|||||||
*arg = skipwhite(*arg + 1);
|
*arg = skipwhite(*arg + 1);
|
||||||
if (**arg == ']')
|
if (**arg == ']')
|
||||||
empty2 = TRUE;
|
empty2 = TRUE;
|
||||||
else if (eval1(arg, &var2, &evalarg) == FAIL) // recursive!
|
else if (eval1(arg, &var2, evalarg) == FAIL) // recursive!
|
||||||
{
|
{
|
||||||
if (!empty1)
|
if (!empty1)
|
||||||
clear_tv(&var1);
|
clear_tv(&var1);
|
||||||
@ -4884,10 +4940,11 @@ eval_isnamec1(int c)
|
|||||||
handle_subscript(
|
handle_subscript(
|
||||||
char_u **arg,
|
char_u **arg,
|
||||||
typval_T *rettv,
|
typval_T *rettv,
|
||||||
int flags, // do more than finding the end
|
evalarg_T *evalarg,
|
||||||
int verbose) // give error messages
|
int verbose) // give error messages
|
||||||
{
|
{
|
||||||
int evaluate = flags & EVAL_EVALUATE;
|
int evaluate = evalarg != NULL
|
||||||
|
&& (evalarg->eval_flags & EVAL_EVALUATE);
|
||||||
int ret = OK;
|
int ret = OK;
|
||||||
dict_T *selfdict = NULL;
|
dict_T *selfdict = NULL;
|
||||||
|
|
||||||
@ -4926,7 +4983,7 @@ handle_subscript(
|
|||||||
{
|
{
|
||||||
if ((*arg)[2] == '{')
|
if ((*arg)[2] == '{')
|
||||||
// expr->{lambda}()
|
// expr->{lambda}()
|
||||||
ret = eval_lambda(arg, rettv, evaluate, verbose);
|
ret = eval_lambda(arg, rettv, evalarg, verbose);
|
||||||
else
|
else
|
||||||
// expr->name()
|
// expr->name()
|
||||||
ret = eval_method(arg, rettv, evaluate, verbose);
|
ret = eval_method(arg, rettv, evaluate, verbose);
|
||||||
@ -4943,7 +5000,7 @@ handle_subscript(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
selfdict = NULL;
|
selfdict = NULL;
|
||||||
if (eval_index(arg, rettv, flags, verbose) == FAIL)
|
if (eval_index(arg, rettv, evalarg, verbose) == FAIL)
|
||||||
{
|
{
|
||||||
clear_tv(rettv);
|
clear_tv(rettv);
|
||||||
ret = FAIL;
|
ret = FAIL;
|
||||||
|
@ -797,12 +797,14 @@ ex_let(exarg_T *eap)
|
|||||||
|
|
||||||
if (eap->skip)
|
if (eap->skip)
|
||||||
++emsg_skip;
|
++emsg_skip;
|
||||||
|
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
|
evalarg.eval_cookie = eap->getline == getsourceline
|
||||||
? eap->cookie : NULL;
|
? eap->cookie : NULL;
|
||||||
i = eval0(expr, &rettv, eap, &evalarg);
|
i = eval0(expr, &rettv, eap, &evalarg);
|
||||||
if (eap->skip)
|
if (eap->skip)
|
||||||
--emsg_skip;
|
--emsg_skip;
|
||||||
|
vim_free(evalarg.eval_tofree);
|
||||||
}
|
}
|
||||||
if (eap->skip)
|
if (eap->skip)
|
||||||
{
|
{
|
||||||
@ -1125,7 +1127,7 @@ list_arg_vars(exarg_T *eap, char_u *arg, int *first)
|
|||||||
{
|
{
|
||||||
// handle d.key, l[idx], f(expr)
|
// handle d.key, l[idx], f(expr)
|
||||||
arg_subsc = arg;
|
arg_subsc = arg;
|
||||||
if (handle_subscript(&arg, &tv, EVAL_EVALUATE, TRUE)
|
if (handle_subscript(&arg, &tv, &EVALARG_EVALUATE, TRUE)
|
||||||
== FAIL)
|
== FAIL)
|
||||||
error = TRUE;
|
error = TRUE;
|
||||||
else
|
else
|
||||||
@ -3341,7 +3343,7 @@ var_exists(char_u *var)
|
|||||||
if (n)
|
if (n)
|
||||||
{
|
{
|
||||||
// handle d.key, l[idx], f(expr)
|
// handle d.key, l[idx], f(expr)
|
||||||
n = (handle_subscript(&var, &tv, EVAL_EVALUATE, FALSE) == OK);
|
n = (handle_subscript(&var, &tv, &EVALARG_EVALUATE, FALSE) == OK);
|
||||||
if (n)
|
if (n)
|
||||||
clear_tv(&tv);
|
clear_tv(&tv);
|
||||||
}
|
}
|
||||||
|
@ -897,6 +897,7 @@ ex_eval(exarg_T *eap)
|
|||||||
typval_T tv;
|
typval_T tv;
|
||||||
evalarg_T evalarg;
|
evalarg_T 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;
|
evalarg.eval_cookie = eap->getline == getsourceline ? eap->cookie : NULL;
|
||||||
|
|
||||||
|
@ -1883,7 +1883,11 @@ EXTERN char windowsVersion[20] INIT(= {0});
|
|||||||
EXTERN listitem_T range_list_item;
|
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 INIT3(EVAL_EVALUATE, NULL, NULL);
|
EXTERN evalarg_T EVALARG_EVALUATE
|
||||||
|
# ifdef DO_INIT
|
||||||
|
= {EVAL_EVALUATE, NULL, {0, 0, 0, 0, NULL}, NULL}
|
||||||
|
# endif
|
||||||
|
;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MSWIN
|
#ifdef MSWIN
|
||||||
|
@ -384,7 +384,7 @@ popup_add_timeout(win_T *wp, int time)
|
|||||||
|
|
||||||
vim_snprintf((char *)cbbuf, sizeof(cbbuf),
|
vim_snprintf((char *)cbbuf, sizeof(cbbuf),
|
||||||
"{_ -> popup_close(%d)}", wp->w_id);
|
"{_ -> popup_close(%d)}", wp->w_id);
|
||||||
if (get_lambda_tv(&ptr, &tv, TRUE) == OK)
|
if (get_lambda_tv(&ptr, &tv, &EVALARG_EVALUATE) == OK)
|
||||||
{
|
{
|
||||||
wp->w_popup_timer = create_timer(time, 0);
|
wp->w_popup_timer = create_timer(time, 0);
|
||||||
wp->w_popup_timer->tr_callback = get_callback(&tv);
|
wp->w_popup_timer->tr_callback = get_callback(&tv);
|
||||||
|
@ -9,6 +9,7 @@ int eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv);
|
|||||||
int eval_expr_to_bool(typval_T *expr, int *error);
|
int eval_expr_to_bool(typval_T *expr, int *error);
|
||||||
char_u *eval_to_string_skip(char_u *arg, exarg_T *eap, int skip);
|
char_u *eval_to_string_skip(char_u *arg, exarg_T *eap, int skip);
|
||||||
int skip_expr(char_u **pp);
|
int skip_expr(char_u **pp);
|
||||||
|
int skip_expr_concatenate(char_u **start, char_u **end, evalarg_T *evalarg);
|
||||||
char_u *eval_to_string(char_u *arg, int convert);
|
char_u *eval_to_string(char_u *arg, int convert);
|
||||||
char_u *eval_to_string_safe(char_u *arg, int use_sandbox);
|
char_u *eval_to_string_safe(char_u *arg, int use_sandbox);
|
||||||
varnumber_T eval_to_number(char_u *expr);
|
varnumber_T eval_to_number(char_u *expr);
|
||||||
@ -53,7 +54,7 @@ int get_name_len(char_u **arg, char_u **alias, int evaluate, int verbose);
|
|||||||
char_u *find_name_end(char_u *arg, char_u **expr_start, char_u **expr_end, int flags);
|
char_u *find_name_end(char_u *arg, char_u **expr_start, char_u **expr_end, int flags);
|
||||||
int eval_isnamec(int c);
|
int eval_isnamec(int c);
|
||||||
int eval_isnamec1(int c);
|
int eval_isnamec1(int c);
|
||||||
int handle_subscript(char_u **arg, typval_T *rettv, int flags, int verbose);
|
int handle_subscript(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int verbose);
|
||||||
int item_copy(typval_T *from, typval_T *to, int deep, int copyID);
|
int item_copy(typval_T *from, typval_T *to, int deep, int copyID);
|
||||||
void echo_one(typval_T *rettv, int with_space, int *atstart, int *needclr);
|
void echo_one(typval_T *rettv, int with_space, int *atstart, int *needclr);
|
||||||
void ex_echo(exarg_T *eap);
|
void ex_echo(exarg_T *eap);
|
||||||
|
@ -3,8 +3,8 @@ void func_init(void);
|
|||||||
hashtab_T *func_tbl_get(void);
|
hashtab_T *func_tbl_get(void);
|
||||||
int get_function_args(char_u **argp, char_u endchar, garray_T *newargs, garray_T *argtypes, int *varargs, garray_T *default_args, int skip, exarg_T *eap, char_u **line_to_free);
|
int get_function_args(char_u **argp, char_u endchar, garray_T *newargs, garray_T *argtypes, int *varargs, garray_T *default_args, int skip, exarg_T *eap, char_u **line_to_free);
|
||||||
char_u *get_lambda_name(void);
|
char_u *get_lambda_name(void);
|
||||||
int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate);
|
char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state);
|
||||||
char_u *register_cfunc(cfunc_T cb, cfunc_free_T free_cb, void *state);
|
int get_lambda_tv(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
|
||||||
char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload);
|
char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload);
|
||||||
void emsg_funcname(char *ermsg, char_u *name);
|
void emsg_funcname(char *ermsg, char_u *name);
|
||||||
int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, funcexe_T *funcexe);
|
int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, funcexe_T *funcexe);
|
||||||
|
@ -1763,6 +1763,11 @@ typedef struct {
|
|||||||
// copied from exarg_T when "getline" is "getsourceline". Can be NULL.
|
// copied from exarg_T when "getline" is "getsourceline". Can be NULL.
|
||||||
void *eval_cookie; // argument for getline()
|
void *eval_cookie; // argument for getline()
|
||||||
|
|
||||||
|
// Used to collect lines while parsing them, so that they can be
|
||||||
|
// concatenated later. Used when "eval_ga.ga_itemsize" is not zero.
|
||||||
|
// "eval_ga.ga_data" is a list of pointers to lines.
|
||||||
|
garray_T eval_ga;
|
||||||
|
|
||||||
// pointer to the line obtained with getsourceline()
|
// pointer to the line obtained with getsourceline()
|
||||||
char_u *eval_tofree;
|
char_u *eval_tofree;
|
||||||
} evalarg_T;
|
} evalarg_T;
|
||||||
|
@ -1017,6 +1017,18 @@ def Test_expr7_lambda()
|
|||||||
assert_equal([1, 3, 5], [1, 2, 3]->map({key, val -> key + val}))
|
assert_equal([1, 3, 5], [1, 2, 3]->map({key, val -> key + val}))
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_expr7_lambda_vim9script()
|
||||||
|
let lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
let v = 10->{a ->
|
||||||
|
a
|
||||||
|
+ 2
|
||||||
|
}()
|
||||||
|
assert_equal(12, v)
|
||||||
|
END
|
||||||
|
CheckScriptSuccess(lines)
|
||||||
|
enddef
|
||||||
|
|
||||||
def Test_expr7_dict()
|
def Test_expr7_dict()
|
||||||
" dictionary
|
" dictionary
|
||||||
assert_equal(g:dict_empty, {})
|
assert_equal(g:dict_empty, {})
|
||||||
|
@ -391,8 +391,10 @@ errret:
|
|||||||
* Return OK or FAIL. Returns NOTDONE for dict or {expr}.
|
* Return OK or FAIL. Returns NOTDONE for dict or {expr}.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
|
get_lambda_tv(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
||||||
{
|
{
|
||||||
|
int evaluate = evalarg != NULL
|
||||||
|
&& (evalarg->eval_flags & EVAL_EVALUATE);
|
||||||
garray_T newargs;
|
garray_T newargs;
|
||||||
garray_T newlines;
|
garray_T newlines;
|
||||||
garray_T *pnewargs;
|
garray_T *pnewargs;
|
||||||
@ -404,6 +406,8 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
|
|||||||
char_u *s, *e;
|
char_u *s, *e;
|
||||||
int *old_eval_lavars = eval_lavars_used;
|
int *old_eval_lavars = eval_lavars_used;
|
||||||
int eval_lavars = FALSE;
|
int eval_lavars = FALSE;
|
||||||
|
int getnext;
|
||||||
|
char_u *tofree = NULL;
|
||||||
|
|
||||||
ga_init(&newargs);
|
ga_init(&newargs);
|
||||||
ga_init(&newlines);
|
ga_init(&newlines);
|
||||||
@ -432,12 +436,25 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
|
|||||||
|
|
||||||
// Get the start and the end of the expression.
|
// Get the start and the end of the expression.
|
||||||
*arg = skipwhite(*arg + 1);
|
*arg = skipwhite(*arg + 1);
|
||||||
|
eval_next_non_blank(*arg, evalarg, &getnext);
|
||||||
|
if (getnext)
|
||||||
|
*arg = eval_next_line(evalarg);
|
||||||
s = *arg;
|
s = *arg;
|
||||||
ret = skip_expr(arg);
|
ret = skip_expr_concatenate(&s, arg, evalarg);
|
||||||
if (ret == FAIL)
|
if (ret == FAIL)
|
||||||
goto errret;
|
goto errret;
|
||||||
|
if (evalarg != NULL)
|
||||||
|
{
|
||||||
|
// avoid that the expression gets freed when another line break follows
|
||||||
|
tofree = evalarg->eval_tofree;
|
||||||
|
evalarg->eval_tofree = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
e = *arg;
|
e = *arg;
|
||||||
*arg = skipwhite(*arg);
|
*arg = skipwhite(*arg);
|
||||||
|
eval_next_non_blank(*arg, evalarg, &getnext);
|
||||||
|
if (getnext)
|
||||||
|
*arg = eval_next_line(evalarg);
|
||||||
if (**arg != '}')
|
if (**arg != '}')
|
||||||
{
|
{
|
||||||
semsg(_("E451: Expected }: %s"), *arg);
|
semsg(_("E451: Expected }: %s"), *arg);
|
||||||
@ -447,7 +464,8 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
|
|||||||
|
|
||||||
if (evaluate)
|
if (evaluate)
|
||||||
{
|
{
|
||||||
int len, flags = 0;
|
int len;
|
||||||
|
int flags = 0;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
char_u *name = get_lambda_name();
|
char_u *name = get_lambda_name();
|
||||||
|
|
||||||
@ -464,7 +482,7 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
|
|||||||
goto errret;
|
goto errret;
|
||||||
|
|
||||||
// Add "return " before the expression.
|
// Add "return " before the expression.
|
||||||
len = 7 + e - s + 1;
|
len = 7 + (int)(e - s) + 1;
|
||||||
p = alloc(len);
|
p = alloc(len);
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
goto errret;
|
goto errret;
|
||||||
@ -510,6 +528,7 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
|
|||||||
}
|
}
|
||||||
|
|
||||||
eval_lavars_used = old_eval_lavars;
|
eval_lavars_used = old_eval_lavars;
|
||||||
|
vim_free(tofree);
|
||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
errret:
|
errret:
|
||||||
@ -517,6 +536,7 @@ errret:
|
|||||||
ga_clear_strings(&newlines);
|
ga_clear_strings(&newlines);
|
||||||
vim_free(fp);
|
vim_free(fp);
|
||||||
vim_free(pt);
|
vim_free(pt);
|
||||||
|
vim_free(tofree);
|
||||||
eval_lavars_used = old_eval_lavars;
|
eval_lavars_used = old_eval_lavars;
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
@ -3925,8 +3945,8 @@ ex_call(exarg_T *eap)
|
|||||||
dbg_check_breakpoint(eap);
|
dbg_check_breakpoint(eap);
|
||||||
|
|
||||||
// Handle a function returning a Funcref, Dictionary or List.
|
// Handle a function returning a Funcref, Dictionary or List.
|
||||||
if (handle_subscript(&arg, &rettv, eap->skip ? 0 : EVAL_EVALUATE,
|
if (handle_subscript(&arg, &rettv,
|
||||||
TRUE) == FAIL)
|
eap->skip ? NULL : &EVALARG_EVALUATE, TRUE) == FAIL)
|
||||||
{
|
{
|
||||||
failed = TRUE;
|
failed = TRUE;
|
||||||
break;
|
break;
|
||||||
|
@ -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 */
|
||||||
|
/**/
|
||||||
|
1071,
|
||||||
/**/
|
/**/
|
||||||
1070,
|
1070,
|
||||||
/**/
|
/**/
|
||||||
|
@ -3001,7 +3001,7 @@ to_name_const_end(char_u *arg)
|
|||||||
}
|
}
|
||||||
else if (p == arg && *arg == '{')
|
else if (p == arg && *arg == '{')
|
||||||
{
|
{
|
||||||
int ret = get_lambda_tv(&p, &rettv, FALSE);
|
int ret = get_lambda_tv(&p, &rettv, NULL);
|
||||||
|
|
||||||
// Can be "{x -> ret}()".
|
// Can be "{x -> ret}()".
|
||||||
// Can be "{'a': 1}->Func()".
|
// Can be "{'a': 1}->Func()".
|
||||||
@ -3065,7 +3065,7 @@ compile_lambda(char_u **arg, cctx_T *cctx)
|
|||||||
ufunc_T *ufunc;
|
ufunc_T *ufunc;
|
||||||
|
|
||||||
// Get the funcref in "rettv".
|
// Get the funcref in "rettv".
|
||||||
if (get_lambda_tv(arg, &rettv, TRUE) != OK)
|
if (get_lambda_tv(arg, &rettv, &EVALARG_EVALUATE) != OK)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
ufunc = rettv.vval.v_partial->pt_func;
|
ufunc = rettv.vval.v_partial->pt_func;
|
||||||
@ -3095,7 +3095,7 @@ compile_lambda_call(char_u **arg, cctx_T *cctx)
|
|||||||
int ret = FAIL;
|
int ret = FAIL;
|
||||||
|
|
||||||
// Get the funcref in "rettv".
|
// Get the funcref in "rettv".
|
||||||
if (get_lambda_tv(arg, &rettv, TRUE) == FAIL)
|
if (get_lambda_tv(arg, &rettv, &EVALARG_EVALUATE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
if (**arg != '(')
|
if (**arg != '(')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user