Patch 8.2.1071

3 views
Skip to first unread message

Bram Moolenaar

unread,
Jun 27, 2020, 12:07:19 PM6/27/20
to vim...@googlegroups.com

Patch 8.2.1071
Problem: Vim9: no line break allowed inside a lambda.
Solution: Handle line break inside a lambda in Vim9 script.
Files: src/eval.c, src/proto/eval.pro, src/evalvars.c, src/userfunc.c,
src/proto/userfunc.pro, src/popupwin.c, src/vim9compile.c,
src/ex_eval.c, src/globals.h, src/structs.h,
src/testdir/test_vim9_expr.vim


*** ../vim-8.2.1070/src/eval.c 2020-06-27 14:11:50.494644105 +0200
--- src/eval.c 2020-06-27 18:02:08.197832760 +0200
***************
*** 325,332 ****

if (skip)
++emsg_skip;
! if (eval0(arg, &tv, eap, skip ? NULL : &EVALARG_EVALUATE)
! == FAIL || skip)
retval = NULL;
else
{
--- 325,331 ----

if (skip)
++emsg_skip;
! if (eval0(arg, &tv, eap, skip ? NULL : &EVALARG_EVALUATE) == FAIL || skip)
retval = NULL;
else
{
***************
*** 353,358 ****
--- 352,412 ----
}

/*
+ * 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
* a Float to a String.
***************
*** 1794,1807 ****
}

/*
! * To be called when 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);
}

/*
--- 1848,1874 ----
}

/*
! * To be called after eval_next_non_blank() sets "getnext" to TRUE.
*/
char_u *
eval_next_line(evalarg_T *evalarg)
{
! 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,1838 ****
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);

--- 1898,1903 ----
***************
*** 1857,1878 ****
if (eap != NULL)
eap->nextcmd = check_nextcmd(p);

! if (evalarg != 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);
}

return ret;
--- 1922,1936 ----
if (eap != NULL)
eap->nextcmd = check_nextcmd(p);

! 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;
}

return ret;
***************
*** 2797,2803 ****
* Lambda: {arg, arg -> expr}
* Dictionary: {'key': val, 'key': val}
*/
! case '{': ret = get_lambda_tv(arg, rettv, evaluate);
if (ret == NOTDONE)
ret = eval_dict(arg, rettv, evalarg, FALSE);
break;
--- 2855,2861 ----
* Lambda: {arg, arg -> expr}
* Dictionary: {'key': val, 'key': val}
*/
! case '{': ret = get_lambda_tv(arg, rettv, evalarg);
if (ret == NOTDONE)
ret = eval_dict(arg, rettv, evalarg, FALSE);
break;
***************
*** 2884,2890 ****
// Handle following '[', '(' and '.' for expr[expr], expr.name,
// expr(expr), expr->name(expr)
if (ret == OK)
! ret = handle_subscript(arg, rettv, flags, TRUE);

/*
* Apply logical NOT and unary '-', from right to left, ignore '+'.
--- 2942,2948 ----
// Handle following '[', '(' and '.' for expr[expr], expr.name,
// expr(expr), expr->name(expr)
if (ret == OK)
! ret = handle_subscript(arg, rettv, evalarg, TRUE);

/*
* Apply logical NOT and unary '-', from right to left, ignore '+'.
***************
*** 3031,3039 ****
eval_lambda(
char_u **arg,
typval_T *rettv,
! int evaluate,
int verbose) // give error messages
{
typval_T base = *rettv;
int ret;

--- 3089,3099 ----
eval_lambda(
char_u **arg,
typval_T *rettv,
! evalarg_T *evalarg,
int verbose) // give error messages
{
+ int evaluate = evalarg != NULL
+ && (evalarg->eval_flags & EVAL_EVALUATE);
typval_T base = *rettv;
int ret;

***************
*** 3041,3047 ****
*arg += 2;
rettv->v_type = VAR_UNKNOWN;

! ret = get_lambda_tv(arg, rettv, evaluate);
if (ret != OK)
return FAIL;
else if (**arg != '(')
--- 3101,3107 ----
*arg += 2;
rettv->v_type = VAR_UNKNOWN;

! ret = get_lambda_tv(arg, rettv, evalarg);
if (ret != OK)
return FAIL;
else if (**arg != '(')
***************
*** 3136,3145 ****
eval_index(
char_u **arg,
typval_T *rettv,
! int flags,
int verbose) // give error messages
{
! int evaluate = flags & EVAL_EVALUATE;
int empty1 = FALSE, empty2 = FALSE;
typval_T var1, var2;
long i;
--- 3196,3206 ----
eval_index(
char_u **arg,
typval_T *rettv,
! evalarg_T *evalarg,
int verbose) // give error messages
{
! int evaluate = evalarg != NULL
! && (evalarg->eval_flags & EVAL_EVALUATE);
int empty1 = FALSE, empty2 = FALSE;
typval_T var1, var2;
long i;
***************
*** 3200,3210 ****
}
else
{
- evalarg_T evalarg;
-
- CLEAR_FIELD(evalarg);
- evalarg.eval_flags = flags;
-
/*
* something[idx]
*
--- 3261,3266 ----
***************
*** 3213,3219 ****
*arg = skipwhite(*arg + 1);
if (**arg == ':')
empty1 = TRUE;
! else if (eval1(arg, &var1, &evalarg) == FAIL) // recursive!
return FAIL;
else if (evaluate && tv_get_string_chk(&var1) == NULL)
{
--- 3269,3275 ----
*arg = skipwhite(*arg + 1);
if (**arg == ':')
empty1 = TRUE;
! else if (eval1(arg, &var1, evalarg) == FAIL) // recursive!
return FAIL;
else if (evaluate && tv_get_string_chk(&var1) == NULL)
{
***************
*** 3231,3237 ****
*arg = skipwhite(*arg + 1);
if (**arg == ']')
empty2 = TRUE;
! else if (eval1(arg, &var2, &evalarg) == FAIL) // recursive!
{
if (!empty1)
clear_tv(&var1);
--- 3287,3293 ----
*arg = skipwhite(*arg + 1);
if (**arg == ']')
empty2 = TRUE;
! else if (eval1(arg, &var2, evalarg) == FAIL) // recursive!
{
if (!empty1)
clear_tv(&var1);
***************
*** 4884,4893 ****
handle_subscript(
char_u **arg,
typval_T *rettv,
! int flags, // do more than finding the end
int verbose) // give error messages
{
! int evaluate = flags & EVAL_EVALUATE;
int ret = OK;
dict_T *selfdict = NULL;

--- 4940,4950 ----
handle_subscript(
char_u **arg,
typval_T *rettv,
! evalarg_T *evalarg,
int verbose) // give error messages
{
! int evaluate = evalarg != NULL
! && (evalarg->eval_flags & EVAL_EVALUATE);
int ret = OK;
dict_T *selfdict = NULL;

***************
*** 4926,4932 ****
{
if ((*arg)[2] == '{')
// expr->{lambda}()
! ret = eval_lambda(arg, rettv, evaluate, verbose);
else
// expr->name()
ret = eval_method(arg, rettv, evaluate, verbose);
--- 4983,4989 ----
{
if ((*arg)[2] == '{')
// expr->{lambda}()
! ret = eval_lambda(arg, rettv, evalarg, verbose);
else
// expr->name()
ret = eval_method(arg, rettv, evaluate, verbose);
***************
*** 4943,4949 ****
}
else
selfdict = NULL;
! if (eval_index(arg, rettv, flags, verbose) == FAIL)
{
clear_tv(rettv);
ret = FAIL;
--- 5000,5006 ----
}
else
selfdict = NULL;
! if (eval_index(arg, rettv, evalarg, verbose) == FAIL)
{
clear_tv(rettv);
ret = FAIL;
*** ../vim-8.2.1070/src/proto/eval.pro 2020-06-27 13:11:46.863462713 +0200
--- src/proto/eval.pro 2020-06-27 15:27:38.043790985 +0200
***************
*** 9,14 ****
--- 9,15 ----
int eval_expr_to_bool(typval_T *expr, int *error);
char_u *eval_to_string_skip(char_u *arg, exarg_T *eap, int skip);
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_safe(char_u *arg, int use_sandbox);
varnumber_T eval_to_number(char_u *expr);
***************
*** 53,59 ****
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_isnamec1(int c);
! int handle_subscript(char_u **arg, typval_T *rettv, int flags, int verbose);
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 ex_echo(exarg_T *eap);
--- 54,60 ----
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_isnamec1(int c);
! 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);
void echo_one(typval_T *rettv, int with_space, int *atstart, int *needclr);
void ex_echo(exarg_T *eap);
*** ../vim-8.2.1070/src/evalvars.c 2020-06-27 13:11:46.863462713 +0200
--- src/evalvars.c 2020-06-27 17:15:36.878996132 +0200
***************
*** 797,808 ****
--- 797,810 ----

if (eap->skip)
++emsg_skip;
+ CLEAR_FIELD(evalarg);
evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE;
evalarg.eval_cookie = eap->getline == getsourceline
? eap->cookie : NULL;
i = eval0(expr, &rettv, eap, &evalarg);
if (eap->skip)
--emsg_skip;
+ vim_free(evalarg.eval_tofree);
}
if (eap->skip)
{
***************
*** 1125,1131 ****
{
// handle d.key, l[idx], f(expr)
arg_subsc = arg;
! if (handle_subscript(&arg, &tv, EVAL_EVALUATE, TRUE)
== FAIL)
error = TRUE;
else
--- 1127,1133 ----
{
// handle d.key, l[idx], f(expr)
arg_subsc = arg;
! if (handle_subscript(&arg, &tv, &EVALARG_EVALUATE, TRUE)
== FAIL)
error = TRUE;
else
***************
*** 3341,3347 ****
if (n)
{
// handle d.key, l[idx], f(expr)
! n = (handle_subscript(&var, &tv, EVAL_EVALUATE, FALSE) == OK);
if (n)
clear_tv(&tv);
}
--- 3343,3349 ----
if (n)
{
// handle d.key, l[idx], f(expr)
! n = (handle_subscript(&var, &tv, &EVALARG_EVALUATE, FALSE) == OK);
if (n)
clear_tv(&tv);
}
*** ../vim-8.2.1070/src/userfunc.c 2020-06-27 13:11:46.863462713 +0200
--- src/userfunc.c 2020-06-27 17:55:25.163278860 +0200
***************
*** 391,398 ****
* Return OK or FAIL. Returns NOTDONE for dict or {expr}.
*/
int
! get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
{
garray_T newargs;
garray_T newlines;
garray_T *pnewargs;
--- 391,400 ----
* Return OK or FAIL. Returns NOTDONE for dict or {expr}.
*/
int
! 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 newlines;
garray_T *pnewargs;
***************
*** 404,409 ****
--- 406,413 ----
char_u *s, *e;
int *old_eval_lavars = eval_lavars_used;
int eval_lavars = FALSE;
+ int getnext;
+ char_u *tofree = NULL;

ga_init(&newargs);
ga_init(&newlines);
***************
*** 432,443 ****

// Get the start and the end of the expression.
*arg = skipwhite(*arg + 1);
s = *arg;
! ret = skip_expr(arg);
if (ret == FAIL)
goto errret;
e = *arg;
*arg = skipwhite(*arg);
if (**arg != '}')
{
semsg(_("E451: Expected }: %s"), *arg);
--- 436,460 ----

// Get the start and the end of the expression.
*arg = skipwhite(*arg + 1);
+ eval_next_non_blank(*arg, evalarg, &getnext);
+ if (getnext)
+ *arg = eval_next_line(evalarg);
s = *arg;
! ret = skip_expr_concatenate(&s, arg, evalarg);
if (ret == FAIL)
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;
*arg = skipwhite(*arg);
+ eval_next_non_blank(*arg, evalarg, &getnext);
+ if (getnext)
+ *arg = eval_next_line(evalarg);
if (**arg != '}')
{
semsg(_("E451: Expected }: %s"), *arg);
***************
*** 447,453 ****

if (evaluate)
{
! int len, flags = 0;
char_u *p;
char_u *name = get_lambda_name();

--- 464,471 ----

if (evaluate)
{
! int len;
! int flags = 0;
char_u *p;
char_u *name = get_lambda_name();

***************
*** 464,470 ****
goto errret;

// Add "return " before the expression.
! len = 7 + e - s + 1;
p = alloc(len);
if (p == NULL)
goto errret;
--- 482,488 ----
goto errret;

// Add "return " before the expression.
! len = 7 + (int)(e - s) + 1;
p = alloc(len);
if (p == NULL)
goto errret;
***************
*** 510,515 ****
--- 528,534 ----
}

eval_lavars_used = old_eval_lavars;
+ vim_free(tofree);
return OK;

errret:
***************
*** 517,522 ****
--- 536,542 ----
ga_clear_strings(&newlines);
vim_free(fp);
vim_free(pt);
+ vim_free(tofree);
eval_lavars_used = old_eval_lavars;
return FAIL;
}
***************
*** 3925,3932 ****
dbg_check_breakpoint(eap);

// Handle a function returning a Funcref, Dictionary or List.
! if (handle_subscript(&arg, &rettv, eap->skip ? 0 : EVAL_EVALUATE,
! TRUE) == FAIL)
{
failed = TRUE;
break;
--- 3945,3952 ----
dbg_check_breakpoint(eap);

// Handle a function returning a Funcref, Dictionary or List.
! if (handle_subscript(&arg, &rettv,
! eap->skip ? NULL : &EVALARG_EVALUATE, TRUE) == FAIL)
{
failed = TRUE;
break;
*** ../vim-8.2.1070/src/proto/userfunc.pro 2020-06-25 19:27:53.036387595 +0200
--- src/proto/userfunc.pro 2020-06-27 14:42:50.009378168 +0200
***************
*** 3,10 ****
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);
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 free_cb, void *state);
char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload);
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);
--- 3,10 ----
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);
char_u *get_lambda_name(void);
! char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, 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);
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);
*** ../vim-8.2.1070/src/popupwin.c 2020-06-15 21:19:04.017590497 +0200
--- src/popupwin.c 2020-06-27 14:41:58.969728917 +0200
***************
*** 384,390 ****

vim_snprintf((char *)cbbuf, sizeof(cbbuf),
"{_ -> popup_close(%d)}", wp->w_id);
! if (get_lambda_tv(&ptr, &tv, TRUE) == OK)
{
wp->w_popup_timer = create_timer(time, 0);
wp->w_popup_timer->tr_callback = get_callback(&tv);
--- 384,390 ----

vim_snprintf((char *)cbbuf, sizeof(cbbuf),
"{_ -> popup_close(%d)}", wp->w_id);
! if (get_lambda_tv(&ptr, &tv, &EVALARG_EVALUATE) == OK)
{
wp->w_popup_timer = create_timer(time, 0);
wp->w_popup_timer->tr_callback = get_callback(&tv);
*** ../vim-8.2.1070/src/vim9compile.c 2020-06-27 14:11:50.494644105 +0200
--- src/vim9compile.c 2020-06-27 14:42:42.725427502 +0200
***************
*** 3001,3007 ****
}
else if (p == arg && *arg == '{')
{
! int ret = get_lambda_tv(&p, &rettv, FALSE);

// Can be "{x -> ret}()".
// Can be "{'a': 1}->Func()".
--- 3001,3007 ----
}
else if (p == arg && *arg == '{')
{
! int ret = get_lambda_tv(&p, &rettv, NULL);

// Can be "{x -> ret}()".
// Can be "{'a': 1}->Func()".
***************
*** 3065,3071 ****
ufunc_T *ufunc;

// Get the funcref in "rettv".
! if (get_lambda_tv(arg, &rettv, TRUE) != OK)
return FAIL;

ufunc = rettv.vval.v_partial->pt_func;
--- 3065,3071 ----
ufunc_T *ufunc;

// Get the funcref in "rettv".
! if (get_lambda_tv(arg, &rettv, &EVALARG_EVALUATE) != OK)
return FAIL;

ufunc = rettv.vval.v_partial->pt_func;
***************
*** 3095,3101 ****
int ret = FAIL;

// Get the funcref in "rettv".
! if (get_lambda_tv(arg, &rettv, TRUE) == FAIL)
return FAIL;

if (**arg != '(')
--- 3095,3101 ----
int ret = FAIL;

// Get the funcref in "rettv".
! if (get_lambda_tv(arg, &rettv, &EVALARG_EVALUATE) == FAIL)
return FAIL;

if (**arg != '(')
*** ../vim-8.2.1070/src/ex_eval.c 2020-06-24 20:33:59.565106319 +0200
--- src/ex_eval.c 2020-06-27 15:47:09.489105718 +0200
***************
*** 897,902 ****
--- 897,903 ----
typval_T tv;
evalarg_T evalarg;

+ CLEAR_FIELD(evalarg);
evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE;
evalarg.eval_cookie = eap->getline == getsourceline ? eap->cookie : NULL;

*** ../vim-8.2.1070/src/globals.h 2020-06-26 19:44:02.972305916 +0200
--- src/globals.h 2020-06-27 16:14:49.255935319 +0200
***************
*** 1883,1889 ****
EXTERN listitem_T range_list_item;

// Passed to an eval() function to enable evaluation.
! EXTERN evalarg_T EVALARG_EVALUATE INIT3(EVAL_EVALUATE, NULL, NULL);
#endif

#ifdef MSWIN
--- 1883,1893 ----
EXTERN listitem_T range_list_item;

// Passed to an eval() function to enable evaluation.
! EXTERN evalarg_T EVALARG_EVALUATE
! # ifdef DO_INIT
! = {EVAL_EVALUATE, NULL, {0, 0, 0, 0, NULL}, NULL}
! # endif
! ;
#endif

#ifdef MSWIN
*** ../vim-8.2.1070/src/structs.h 2020-06-25 19:27:53.036387595 +0200
--- src/structs.h 2020-06-27 15:09:17.951377551 +0200
***************
*** 1763,1768 ****
--- 1763,1773 ----
// copied from exarg_T when "getline" is "getsourceline". Can be NULL.
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()
char_u *eval_tofree;
} evalarg_T;
*** ../vim-8.2.1070/src/testdir/test_vim9_expr.vim 2020-06-27 14:11:50.494644105 +0200
--- src/testdir/test_vim9_expr.vim 2020-06-27 16:06:06.482819706 +0200
***************
*** 1017,1022 ****
--- 1017,1034 ----
assert_equal([1, 3, 5], [1, 2, 3]->map({key, val -> key + val}))
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()
" dictionary
assert_equal(g:dict_empty, {})
*** ../vim-8.2.1070/src/version.c 2020-06-27 17:04:01.298972727 +0200
--- src/version.c 2020-06-27 18:06:03.032763405 +0200
***************
*** 756,757 ****
--- 756,759 ----
{ /* Add new patch number below this line */
+ /**/
+ 1071,
/**/

--
FROG: How you English say: I one more time, mac, I unclog my nose towards
you, sons of a window-dresser, so, you think you could out-clever us
French fellows with your silly knees-bent creeping about advancing
behaviour. (blows a raspberry) I wave my private parts at your aunties,
you brightly-coloured, mealy-templed, cranberry-smelling, electric
donkey-bottom biters.
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

/// Bram Moolenaar -- Br...@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 ///
Reply all
Reply to author
Forward
0 new messages