garray_T *gap = &evalarg->eval_ga;
int save_flags = evalarg == NULL ? 0 : evalarg->eval_flags;
- if (vim9script && evalarg->eval_cookie != NULL)
+ if (vim9script
+ && (evalarg->eval_cookie != NULL || evalarg->eval_cctx != NULL))
{
ga_init2(gap, sizeof(char_u *), 10);
+ // leave room for "start"
if (ga_grow(gap, 1) == OK)
- // leave room for "start"
++gap->ga_len;
}
if (evalarg != NULL)
evalarg->eval_flags = save_flags;
- if (vim9script && evalarg->eval_cookie != NULL
- && evalarg->eval_ga.ga_len > 1)
+ if (vim9script
+ && (evalarg->eval_cookie != NULL || evalarg->eval_cctx != NULL))
{
- 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;
+ if (evalarg->eval_ga.ga_len == 1)
+ {
+ // just one line, no need to concatenate
+ ga_clear(gap);
+ gap->ga_itemsize = 0;
+ }
+ else
+ {
+ 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, "");
+
+ // free the lines only when using getsourceline()
+ if (evalarg->eval_cookie != NULL)
+ {
+ *((char_u **)gap->ga_data) = NULL;
+ ga_clear_strings(gap);
+ }
+ else
+ ga_clear(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. Does not handle line
+ * breaks.
* When "convert" is TRUE convert a List into a sequence of lines and convert
* a Float to a String.
* Return pointer to allocated memory, or NULL for failure.
*getnext = FALSE;
if (current_sctx.sc_version == SCRIPT_VERSION_VIM9
&& evalarg != NULL
- && evalarg->eval_cookie != NULL
+ && (evalarg->eval_cookie != NULL || evalarg->eval_cctx != NULL)
&& (*arg == NUL || (VIM_ISWHITE(arg[-1])
&& *arg == '#' && arg[1] != '{')))
{
- char_u *p = getline_peek(evalarg->eval_getline, evalarg->eval_cookie);
+ char_u *p;
+
+ if (evalarg->eval_cookie != NULL)
+ p = getline_peek(evalarg->eval_getline, evalarg->eval_cookie);
+ else
+ p = peek_next_line_from_context(evalarg->eval_cctx);
if (p != NULL)
{
garray_T *gap = &evalarg->eval_ga;
char_u *line;
- line = evalarg->eval_getline(0, evalarg->eval_cookie, 0, TRUE);
+ if (evalarg->eval_cookie != NULL)
+ line = evalarg->eval_getline(0, evalarg->eval_cookie, 0, TRUE);
+ else
+ line = next_line_from_context(evalarg->eval_cctx, TRUE);
++evalarg->eval_break_count;
if (gap->ga_itemsize > 0 && ga_grow(gap, 1) == OK)
{
int ret = OK;
dict_T *selfdict = NULL;
int check_white = TRUE;
+ int getnext;
+ char_u *p;
- // When at the end of the line and ".name" follows in the next line then
- // consume the line break. Only when rettv is a dict.
- if (rettv->v_type == VAR_DICT)
+ while (ret == OK)
{
- int getnext;
- char_u *p = eval_next_non_blank(*arg, evalarg, &getnext);
-
- if (getnext && *p == '.' && ASCII_ISALPHA(p[1]))
+ // When at the end of the line and ".name" or "->{" or "->X" follows in
+ // the next line then consume the line break.
+ p = eval_next_non_blank(*arg, evalarg, &getnext);
+ if (getnext
+ && ((rettv->v_type == VAR_DICT && *p == '.'
+ && ASCII_ISALPHA(p[1]))
+ || (*p == '-' && p[1] == '>'
+ && (p[2] == '{' || ASCII_ISALPHA(p[2])))))
{
*arg = eval_next_line(evalarg);
check_white = FALSE;
}
- }
- // "." is ".name" lookup when we found a dict or when evaluating and
- // scriptversion is at least 2, where string concatenation is "..".
- while (ret == OK
- && (((**arg == '['
- || (**arg == '.' && (rettv->v_type == VAR_DICT
- || (!evaluate
- && (*arg)[1] != '.'
- && current_sctx.sc_version >= 2)))
- || (**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC
- || rettv->v_type == VAR_PARTIAL)))
- && (!check_white || !VIM_ISWHITE(*(*arg - 1))))
- || (**arg == '-' && (*arg)[1] == '>')))
- {
- if (**arg == '(')
+ if ((**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC
+ || rettv->v_type == VAR_PARTIAL))
+ && (!check_white || !VIM_ISWHITE(*(*arg - 1))))
{
ret = call_func_rettv(arg, evalarg, rettv, evaluate,
selfdict, NULL);
dict_unref(selfdict);
selfdict = NULL;
}
- else if (**arg == '-')
+ else if (**arg == '-' && (*arg)[1] == '>')
{
if (ret == OK)
{
ret = eval_method(arg, rettv, evalarg, verbose);
}
}
- else // **arg == '[' || **arg == '.'
+ // "." is ".name" lookup when we found a dict or when evaluating and
+ // scriptversion is at least 2, where string concatenation is "..".
+ else if (**arg == '['
+ || (**arg == '.' && (rettv->v_type == VAR_DICT
+ || (!evaluate
+ && (*arg)[1] != '.'
+ && current_sctx.sc_version >= 2))))
{
dict_unref(selfdict);
if (rettv->v_type == VAR_DICT)
ret = FAIL;
}
}
+ else
+ break;
}
// Turn "dict.Func" into a partial for "Func" bound to "dict".
* comment. Skips over white space.
* Returns NULL if there is none.
*/
- static char_u *
-peek_next_line(cctx_T *cctx)
+ char_u *
+peek_next_line_from_context(cctx_T *cctx)
{
int lnum = cctx->ctx_lnum;
*nextp = NULL;
if (*p == NUL || (VIM_ISWHITE(*arg) && comment_start(p)))
{
- *nextp = peek_next_line(cctx);
+ *nextp = peek_next_line_from_context(cctx);
if (*nextp != NULL)
return *nextp;
}
* Skips over empty lines. Skips over comment lines if "skip_comment" is TRUE.
* Returns NULL when at the end.
*/
- static char_u *
+ char_u *
next_line_from_context(cctx_T *cctx, int skip_comment)
{
char_u *line;
{
typval_T rettv;
ufunc_T *ufunc;
+ evalarg_T evalarg;
+
+ CLEAR_FIELD(evalarg);
+ evalarg.eval_flags = EVAL_EVALUATE;
+ evalarg.eval_cctx = cctx;
// Get the funcref in "rettv".
- if (get_lambda_tv(arg, &rettv, &EVALARG_EVALUATE) != OK)
+ if (get_lambda_tv(arg, &rettv, &evalarg) != OK)
return FAIL;
ufunc = rettv.vval.v_partial->pt_func;
/*
* Compile whatever comes after "name" or "name()".
+ * Advances "*arg" only when something was recognized.
*/
static int
compile_subscript(
if (*p == NUL || (VIM_ISWHITE(**arg) && comment_start(p)))
{
- char_u *next = peek_next_line(cctx);
+ char_u *next = peek_next_line_from_context(cctx);
// If a following line starts with "->{" or "->X" advance to that
// line, so that a line break before "->" is allowed.
next = next_line_from_context(cctx, TRUE);
if (next == NULL)
return FAIL;
- *arg = skipwhite(next);
+ *arg = next;
+ p = skipwhite(*arg);
}
}
- if (**arg == '(')
+ if (*p == '(')
{
garray_T *stack = &cctx->ctx_type_stack;
type_T *type;
// funcref(arg)
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
- *arg = skipwhite(*arg + 1);
+ *arg = skipwhite(p + 1);
if (compile_arguments(arg, cctx, &argcount) == FAIL)
return FAIL;
if (generate_PCALL(cctx, argcount, end_leader, type, TRUE) == FAIL)
return FAIL;
}
- else if (**arg == '-' && (*arg)[1] == '>')
+ else if (*p == '-' && p[1] == '>')
{
if (generate_ppconst(cctx, ppconst) == FAIL)
return FAIL;
return FAIL;
*start_leader = end_leader; // don't apply again later
- p = *arg + 2;
+ p += 2;
*arg = skipwhite(p);
if (may_get_next_line(p, arg, cctx) == FAIL)
return FAIL;
return FAIL;
}
}
- else if (**arg == '[')
+ else if (*p == '[')
{
garray_T *stack = &cctx->ctx_type_stack;
type_T **typep;
if (generate_ppconst(cctx, ppconst) == FAIL)
return FAIL;
- p = *arg + 1;
+ ++p;
*arg = skipwhite(p);
if (may_get_next_line(p, arg, cctx) == FAIL)
return FAIL;
return FAIL;
}
}
- else if (**arg == '.' && (*arg)[1] != '.')
+ else if (*p == '.' && p[1] != '.')
{
if (generate_ppconst(cctx, ppconst) == FAIL)
return FAIL;
- ++*arg;
+ *arg = p + 1;
if (may_get_next_line(*arg, arg, cctx) == FAIL)
return FAIL;
// dictionary member: dict.name