@@ -379,59 +379,93 @@ skip_expr(char_u **pp)
379379 * Skip over an expression at "*pp".
380380 * If in Vim9 script and line breaks are encountered, the lines are
381381 * concatenated. "evalarg->eval_tofree" will be set accordingly.
382+ * "arg" is advanced to just after the expression.
383+ * "start" is set to the start of the expression, "end" to just after the end.
384+ * Also when the expression is copied to allocated memory.
382385 * Return FAIL for an error, OK otherwise.
383386 */
384387 int
385- skip_expr_concatenate (char_u * * start , char_u * * end , evalarg_T * evalarg )
388+ skip_expr_concatenate (
389+ char_u * * arg ,
390+ char_u * * start ,
391+ char_u * * end ,
392+ evalarg_T * evalarg )
386393{
387394 typval_T rettv ;
388395 int res ;
389396 int vim9script = current_sctx .sc_version == SCRIPT_VERSION_VIM9 ;
390397 garray_T * gap = & evalarg -> eval_ga ;
391398 int save_flags = evalarg == NULL ? 0 : evalarg -> eval_flags ;
392399
393- if (vim9script && evalarg -> eval_cookie != NULL )
400+ if (vim9script
401+ && (evalarg -> eval_cookie != NULL || evalarg -> eval_cctx != NULL ))
394402 {
395403 ga_init2 (gap , sizeof (char_u * ), 10 );
404+ // leave room for "start"
396405 if (ga_grow (gap , 1 ) == OK )
397- // leave room for "start"
398406 ++ gap -> ga_len ;
399407 }
408+ * start = * arg ;
400409
401410 // Don't evaluate the expression.
402411 if (evalarg != NULL )
403412 evalarg -> eval_flags &= ~EVAL_EVALUATE ;
404- * end = skipwhite (* end );
405- res = eval1 (end , & rettv , evalarg );
413+ * arg = skipwhite (* arg );
414+ res = eval1 (arg , & rettv , evalarg );
415+ * end = * arg ;
406416 if (evalarg != NULL )
407417 evalarg -> eval_flags = save_flags ;
408418
409- if (vim9script && evalarg -> eval_cookie != NULL
410- && evalarg -> eval_ga . ga_len > 1 )
419+ if (vim9script
420+ && ( evalarg -> eval_cookie != NULL || evalarg -> eval_cctx != NULL ) )
411421 {
412- char_u * p ;
413- size_t endoff = STRLEN (* end );
414-
415- // Line breaks encountered, concatenate all the lines.
416- * ((char_u * * )gap -> ga_data ) = * start ;
417- p = ga_concat_strings (gap , "" );
418- * ((char_u * * )gap -> ga_data ) = NULL ;
419- ga_clear_strings (gap );
420- gap -> ga_itemsize = 0 ;
421- if (p == NULL )
422- return FAIL ;
423- * start = p ;
424- vim_free (evalarg -> eval_tofree );
425- evalarg -> eval_tofree = p ;
426- // Compute "end" relative to the end.
427- * end = * start + STRLEN (* start ) - endoff ;
422+ if (evalarg -> eval_ga .ga_len == 1 )
423+ {
424+ // just one line, no need to concatenate
425+ ga_clear (gap );
426+ gap -> ga_itemsize = 0 ;
427+ }
428+ else
429+ {
430+ char_u * p ;
431+ size_t endoff = STRLEN (* arg );
432+
433+ // Line breaks encountered, concatenate all the lines.
434+ * ((char_u * * )gap -> ga_data ) = * start ;
435+ p = ga_concat_strings (gap , "" );
436+
437+ // free the lines only when using getsourceline()
438+ if (evalarg -> eval_cookie != NULL )
439+ {
440+ // Do not free the first line, the caller can still use it.
441+ * ((char_u * * )gap -> ga_data ) = NULL ;
442+ // Do not free the last line, "arg" points into it, free it
443+ // later.
444+ vim_free (evalarg -> eval_tofree );
445+ evalarg -> eval_tofree =
446+ ((char_u * * )gap -> ga_data )[gap -> ga_len - 1 ];
447+ ((char_u * * )gap -> ga_data )[gap -> ga_len - 1 ] = NULL ;
448+ ga_clear_strings (gap );
449+ }
450+ else
451+ ga_clear (gap );
452+ gap -> ga_itemsize = 0 ;
453+ if (p == NULL )
454+ return FAIL ;
455+ * start = p ;
456+ vim_free (evalarg -> eval_tofree_lambda );
457+ evalarg -> eval_tofree_lambda = p ;
458+ // Compute "end" relative to the end.
459+ * end = * start + STRLEN (* start ) - endoff ;
460+ }
428461 }
429462
430463 return res ;
431464}
432465
433466/*
434- * Top level evaluation function, returning a string.
467+ * Top level evaluation function, returning a string. Does not handle line
468+ * breaks.
435469 * When "convert" is TRUE convert a List into a sequence of lines and convert
436470 * a Float to a String.
437471 * Return pointer to allocated memory, or NULL for failure.
@@ -1878,11 +1912,16 @@ eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext)
18781912 * getnext = FALSE;
18791913 if (current_sctx .sc_version == SCRIPT_VERSION_VIM9
18801914 && evalarg != NULL
1881- && evalarg -> eval_cookie != NULL
1915+ && ( evalarg -> eval_cookie != NULL || evalarg -> eval_cctx != NULL )
18821916 && (* arg == NUL || (VIM_ISWHITE (arg [-1 ])
18831917 && * arg == '#' && arg [1 ] != '{' )))
18841918 {
1885- char_u * p = getline_peek (evalarg -> eval_getline , evalarg -> eval_cookie );
1919+ char_u * p ;
1920+
1921+ if (evalarg -> eval_cookie != NULL )
1922+ p = getline_peek (evalarg -> eval_getline , evalarg -> eval_cookie );
1923+ else
1924+ p = peek_next_line_from_context (evalarg -> eval_cctx );
18861925
18871926 if (p != NULL )
18881927 {
@@ -1902,15 +1941,18 @@ eval_next_line(evalarg_T *evalarg)
19021941 garray_T * gap = & evalarg -> eval_ga ;
19031942 char_u * line ;
19041943
1905- line = evalarg -> eval_getline (0 , evalarg -> eval_cookie , 0 , TRUE);
1944+ if (evalarg -> eval_cookie != NULL )
1945+ line = evalarg -> eval_getline (0 , evalarg -> eval_cookie , 0 , TRUE);
1946+ else
1947+ line = next_line_from_context (evalarg -> eval_cctx , TRUE);
19061948 ++ evalarg -> eval_break_count ;
19071949 if (gap -> ga_itemsize > 0 && ga_grow (gap , 1 ) == OK )
19081950 {
19091951 // Going to concatenate the lines after parsing.
19101952 ((char_u * * )gap -> ga_data )[gap -> ga_len ] = line ;
19111953 ++ gap -> ga_len ;
19121954 }
1913- else
1955+ else if ( evalarg -> eval_cookie != NULL )
19141956 {
19151957 vim_free (evalarg -> eval_tofree );
19161958 evalarg -> eval_tofree = line ;
@@ -1936,25 +1978,31 @@ skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg)
19361978}
19371979
19381980/*
1939- * After using "evalarg" filled from "eap" free the memory.
1981+ * After using "evalarg" filled from "eap": free the memory.
19401982 */
19411983 void
19421984clear_evalarg (evalarg_T * evalarg , exarg_T * eap )
19431985{
1944- if (evalarg != NULL && evalarg -> eval_tofree != NULL )
1986+ if (evalarg != NULL )
19451987 {
1946- if (eap != NULL )
1988+ if (evalarg -> eval_tofree != NULL )
19471989 {
1948- // We may need to keep the original command line, e.g. for
1949- // ":let" it has the variable names. But we may also need the
1950- // new one, "nextcmd" points into it. Keep both.
1951- vim_free (eap -> cmdline_tofree );
1952- eap -> cmdline_tofree = * eap -> cmdlinep ;
1953- * eap -> cmdlinep = evalarg -> eval_tofree ;
1990+ if (eap != NULL )
1991+ {
1992+ // We may need to keep the original command line, e.g. for
1993+ // ":let" it has the variable names. But we may also need the
1994+ // new one, "nextcmd" points into it. Keep both.
1995+ vim_free (eap -> cmdline_tofree );
1996+ eap -> cmdline_tofree = * eap -> cmdlinep ;
1997+ * eap -> cmdlinep = evalarg -> eval_tofree ;
1998+ }
1999+ else
2000+ vim_free (evalarg -> eval_tofree );
2001+ evalarg -> eval_tofree = NULL ;
19542002 }
1955- else
1956- vim_free (evalarg -> eval_tofree );
1957- evalarg -> eval_tofree = NULL ;
2003+
2004+ vim_free (evalarg -> eval_tofree_lambda );
2005+ evalarg -> eval_tofree_lambda = NULL ;
19582006 }
19592007}
19602008
@@ -5034,35 +5082,27 @@ handle_subscript(
50345082 int ret = OK ;
50355083 dict_T * selfdict = NULL ;
50365084 int check_white = TRUE;
5085+ int getnext ;
5086+ char_u * p ;
50375087
5038- // When at the end of the line and ".name" follows in the next line then
5039- // consume the line break. Only when rettv is a dict.
5040- if (rettv -> v_type == VAR_DICT )
5088+ while (ret == OK )
50415089 {
5042- int getnext ;
5043- char_u * p = eval_next_non_blank (* arg , evalarg , & getnext );
5044-
5045- if (getnext && * p == '.' && ASCII_ISALPHA (p [1 ]))
5090+ // When at the end of the line and ".name" or "->{" or "->X" follows in
5091+ // the next line then consume the line break.
5092+ p = eval_next_non_blank (* arg , evalarg , & getnext );
5093+ if (getnext
5094+ && ((rettv -> v_type == VAR_DICT && * p == '.'
5095+ && ASCII_ISALPHA (p [1 ]))
5096+ || (* p == '-' && p [1 ] == '>'
5097+ && (p [2 ] == '{' || ASCII_ISALPHA (p [2 ])))))
50465098 {
50475099 * arg = eval_next_line (evalarg );
50485100 check_white = FALSE;
50495101 }
5050- }
50515102
5052- // "." is ".name" lookup when we found a dict or when evaluating and
5053- // scriptversion is at least 2, where string concatenation is "..".
5054- while (ret == OK
5055- && (((* * arg == '['
5056- || (* * arg == '.' && (rettv -> v_type == VAR_DICT
5057- || (!evaluate
5058- && (* arg )[1 ] != '.'
5059- && current_sctx .sc_version >= 2 )))
5060- || (* * arg == '(' && (!evaluate || rettv -> v_type == VAR_FUNC
5061- || rettv -> v_type == VAR_PARTIAL )))
5062- && (!check_white || !VIM_ISWHITE (* (* arg - 1 ))))
5063- || (* * arg == '-' && (* arg )[1 ] == '>' )))
5064- {
5065- if (* * arg == '(' )
5103+ if ((* * arg == '(' && (!evaluate || rettv -> v_type == VAR_FUNC
5104+ || rettv -> v_type == VAR_PARTIAL ))
5105+ && (!check_white || !VIM_ISWHITE (* (* arg - 1 ))))
50665106 {
50675107 ret = call_func_rettv (arg , evalarg , rettv , evaluate ,
50685108 selfdict , NULL );
@@ -5079,7 +5119,7 @@ handle_subscript(
50795119 dict_unref (selfdict );
50805120 selfdict = NULL ;
50815121 }
5082- else if (* * arg == '-' )
5122+ else if (* * arg == '-' && ( * arg )[ 1 ] == '>' )
50835123 {
50845124 if (ret == OK )
50855125 {
@@ -5091,7 +5131,13 @@ handle_subscript(
50915131 ret = eval_method (arg , rettv , evalarg , verbose );
50925132 }
50935133 }
5094- else // **arg == '[' || **arg == '.'
5134+ // "." is ".name" lookup when we found a dict or when evaluating and
5135+ // scriptversion is at least 2, where string concatenation is "..".
5136+ else if (* * arg == '['
5137+ || (* * arg == '.' && (rettv -> v_type == VAR_DICT
5138+ || (!evaluate
5139+ && (* arg )[1 ] != '.'
5140+ && current_sctx .sc_version >= 2 ))))
50955141 {
50965142 dict_unref (selfdict );
50975143 if (rettv -> v_type == VAR_DICT )
@@ -5108,6 +5154,8 @@ handle_subscript(
51085154 ret = FAIL ;
51095155 }
51105156 }
5157+ else
5158+ break ;
51115159 }
51125160
51135161 // Turn "dict.Func" into a partial for "Func" bound to "dict".
0 commit comments