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.
diff --git a/src/eval.c b/src/eval.c
index 0c8ab49..e1a33df 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -325,8 +325,7 @@
 
     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
     {
@@ -353,6 +352,61 @@
 }
 
 /*
+ * 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,14 +1848,27 @@
 }
 
 /*
- * 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 @@
     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 @@
     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 @@
      * 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 @@
     // 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 @@
 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 @@
     *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_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 @@
     }
     else
     {
-	evalarg_T	evalarg;
-
-	CLEAR_FIELD(evalarg);
-	evalarg.eval_flags = flags;
-
 	/*
 	 * something[idx]
 	 *
@@ -3213,7 +3269,7 @@
 	*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 @@
 	    *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 @@
 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 @@
 	    {
 		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 @@
 	    }
 	    else
 		selfdict = NULL;
-	    if (eval_index(arg, rettv, flags, verbose) == FAIL)
+	    if (eval_index(arg, rettv, evalarg, verbose) == FAIL)
 	    {
 		clear_tv(rettv);
 		ret = FAIL;