0
0
mirror of https://github.com/vim/vim.git synced 2025-09-27 04:14:06 -04:00

patch 9.1.0933: Vim9: vim9compile.c can be further improved

Problem:  Vim9: vim9compile.c can be further improved
Solution: further refactor the compile assignment code
          (Yegappan Lakshmanan)

closes: #16230

Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Yegappan Lakshmanan
2024-12-16 20:56:56 +01:00
committed by Christian Brabandt
parent 3f7d584e96
commit 468db1f8af
2 changed files with 302 additions and 213 deletions

View File

@@ -704,6 +704,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 */
/**/
933,
/**/ /**/
932, 932,
/**/ /**/

View File

@@ -2583,43 +2583,6 @@ push_default_value(
return r; return r;
} }
/*
* Compile an object member variable assignment in the argument passed to a
* class new() method.
*
* Instruction format:
*
* ifargisset <n> this.<varname> = <value>
*
* where <n> is the object member variable index.
*
* Generates the ISN_JUMP_IF_ARG_NOT_SET instruction to skip the assignment if
* the value is passed as an argument to the new() method call.
*
* Returns OK on success.
*/
static int
compile_assign_obj_new_arg(char_u **argp, cctx_T *cctx)
{
char_u *arg = *argp;
arg += 11; // skip "ifargisset"
int def_idx = getdigits(&arg);
arg = skipwhite(arg);
// Use a JUMP_IF_ARG_NOT_SET instruction to skip if the value was not
// given and the default value is "v:none".
int off = STACK_FRAME_SIZE + (cctx->ctx_ufunc->uf_va_name != NULL
? 1 : 0);
int count = cctx->ctx_ufunc->uf_def_args.ga_len;
if (generate_JUMP_IF_ARG(cctx, ISN_JUMP_IF_ARG_NOT_SET,
def_idx - count - off) == FAIL)
return FAIL;
*argp = arg;
return OK;
}
/* /*
* Compile assignment context. Used when compiling an assignment statement. * Compile assignment context. Used when compiling an assignment statement.
*/ */
@@ -2664,6 +2627,45 @@ compile_assign_context_init(cac_T *cac, cctx_T *cctx, int cmdidx, char_u *arg)
cac->cac_var_end = arg; cac->cac_var_end = arg;
} }
/*
* Compile an object member variable assignment in the arguments passed to a
* class new() method.
*
* Instruction format:
*
* ifargisset <n> this.<varname> = <value>
*
* where <n> is the index of the default argument.
*
* Generates the ISN_JUMP_IF_ARG_NOT_SET instruction to skip the assignment if
* the value is passed as an argument to the new() method call.
*
* Returns OK on success.
*/
static int
compile_assign_obj_new_arg(char_u **argp, cctx_T *cctx)
{
char_u *arg = *argp;
arg += 11; // skip "ifargisset"
int def_arg_idx = getdigits(&arg);
arg = skipwhite(arg);
// Use a JUMP_IF_ARG_NOT_SET instruction to skip if the value was not
// given and the default value is "v:none".
int stack_offset = STACK_FRAME_SIZE +
(cctx->ctx_ufunc->uf_va_name != NULL ? 1 : 0);
int def_arg_count = cctx->ctx_ufunc->uf_def_args.ga_len;
int arg_offset = def_arg_idx - def_arg_count - stack_offset;
if (generate_JUMP_IF_ARG(cctx, ISN_JUMP_IF_ARG_NOT_SET,
arg_offset) == FAIL)
return FAIL;
*argp = arg;
return OK;
}
/* /*
* Translate the increment (++) and decrement (--) operators to the * Translate the increment (++) and decrement (--) operators to the
* corresponding compound operators (+= or -=). * corresponding compound operators (+= or -=).
@@ -2700,39 +2702,46 @@ compile_assign_process_operator(
*retstr = NULL; *retstr = NULL;
if (eap->cmdidx == CMD_increment || eap->cmdidx == CMD_decrement) if (eap->cmdidx == CMD_increment || eap->cmdidx == CMD_decrement)
{
// Change an unary operator to a compound operator // Change an unary operator to a compound operator
if (translate_incdec_op(eap, cac) == FAIL) return translate_incdec_op(eap, cac);
return FAIL;
} char_u *sp = cac->cac_nextc;
else cac->cac_nextc = skipwhite(cac->cac_nextc);
cac->cac_op = cac->cac_nextc;
cac->cac_oplen = assignment_len(cac->cac_nextc, heredoc);
if (cac->cac_var_count > 0 && cac->cac_oplen == 0)
{ {
char_u *sp; // can be something like "[1, 2]->func()"
*retstr = arg;
return FAIL;
}
sp = cac->cac_nextc; // need white space before and after the operator
cac->cac_nextc = skipwhite(cac->cac_nextc); if (cac->cac_oplen > 0 && (!VIM_ISWHITE(*sp)
cac->cac_op = cac->cac_nextc; || !IS_WHITE_OR_NUL(cac->cac_op[cac->cac_oplen])))
cac->cac_oplen = assignment_len(cac->cac_nextc, heredoc); {
error_white_both(cac->cac_op, cac->cac_oplen);
if (cac->cac_var_count > 0 && cac->cac_oplen == 0) return FAIL;
{
// can be something like "[1, 2]->func()"
*retstr = arg;
return FAIL;
}
// need white space before and after the operator
if (cac->cac_oplen > 0 && (!VIM_ISWHITE(*sp)
|| !IS_WHITE_OR_NUL(cac->cac_op[cac->cac_oplen])))
{
error_white_both(cac->cac_op, cac->cac_oplen);
return FAIL;
}
} }
return OK; return OK;
} }
/*
* Find the start of an assignment statement.
*/
static char_u *
compile_assign_compute_start(char_u *arg, int var_count)
{
if (var_count > 0)
// [var1, var2] = [val1, val2]
// skip over the "["
return skipwhite(arg + 1);
return arg;
}
/* /*
* Parse a heredoc assignment starting at "p". Returns a pointer to the * Parse a heredoc assignment starting at "p". Returns a pointer to the
* beginning of the heredoc content. * beginning of the heredoc content.
@@ -2755,61 +2764,60 @@ parse_heredoc_assignment(exarg_T *eap, cctx_T *cctx, cac_T *cac)
} }
/* /*
* Evaluate the expression for "[var, var] = expr" assignment. * Check the type of a RHS expression in a list assignment statement.
* A line break may follow the assignment operator "=". * The RHS expression is already compiled. So the type is on the stack.
*/ */
static char_u * static int
compile_list_assignment_expr(cctx_T *cctx, cac_T *cac) compile_assign_list_check_rhs_type(cctx_T *cctx, cac_T *cac)
{ {
char_u *wp;
wp = cac->cac_op + cac->cac_oplen;
if (may_get_next_line_error(wp, &cac->cac_nextc, cctx) == FAIL)
return NULL;
if (compile_expr0(&cac->cac_nextc, cctx) == FAIL)
return NULL;
if (cctx->ctx_skip == SKIP_YES)
// no need to parse more when skipping
return cac->cac_nextc;
type_T *stacktype; type_T *stacktype;
int needed_list_len;
int did_check = FALSE;
stacktype = cctx->ctx_type_stack.ga_len == 0 ? &t_void stacktype = cctx->ctx_type_stack.ga_len == 0 ? &t_void
: get_type_on_stack(cctx, 0); : get_type_on_stack(cctx, 0);
if (stacktype->tt_type == VAR_VOID) if (stacktype->tt_type == VAR_VOID)
{ {
emsg(_(e_cannot_use_void_value)); emsg(_(e_cannot_use_void_value));
return NULL; return FAIL;
} }
if (need_type(stacktype, &t_list_any, FALSE, -1, 0, cctx, if (need_type(stacktype, &t_list_any, FALSE, -1, 0, cctx,
FALSE, FALSE) == FAIL) FALSE, FALSE) == FAIL)
return NULL; return FAIL;
if (stacktype->tt_member != NULL)
cac->cac_rhs_type = stacktype->tt_member;
return OK;
}
/*
* In a list assignment statement, if a constant list was used, check the
* length. Returns OK if the length check succeeds. Returns FAIL otherwise.
*/
static int
compile_assign_list_check_length(cctx_T *cctx, cac_T *cac)
{
int needed_list_len;
int did_check = FALSE;
// If a constant list was used we can check the length right here.
needed_list_len = cac->cac_semicolon needed_list_len = cac->cac_semicolon
? cac->cac_var_count - 1 ? cac->cac_var_count - 1
: cac->cac_var_count; : cac->cac_var_count;
if (cac->cac_instr->ga_len > 0) if (cac->cac_instr->ga_len > 0)
{ {
isn_T *isn = ((isn_T *)cac->cac_instr->ga_data) + isn_T *isn = ((isn_T *)cac->cac_instr->ga_data) +
cac->cac_instr->ga_len - 1; cac->cac_instr->ga_len - 1;
if (isn->isn_type == ISN_NEWLIST) if (isn->isn_type == ISN_NEWLIST)
{ {
did_check = TRUE; did_check = TRUE;
if (cac->cac_semicolon ? isn->isn_arg.number < if (cac->cac_semicolon ?
needed_list_len isn->isn_arg.number < needed_list_len
: isn->isn_arg.number != needed_list_len) : isn->isn_arg.number != needed_list_len)
{ {
semsg(_(e_expected_nr_items_but_got_nr), semsg(_(e_expected_nr_items_but_got_nr),
needed_list_len, (int)isn->isn_arg.number); needed_list_len, (int)isn->isn_arg.number);
return NULL; return FAIL;
} }
} }
} }
@@ -2817,8 +2825,37 @@ compile_list_assignment_expr(cctx_T *cctx, cac_T *cac)
if (!did_check) if (!did_check)
generate_CHECKLEN(cctx, needed_list_len, cac->cac_semicolon); generate_CHECKLEN(cctx, needed_list_len, cac->cac_semicolon);
if (stacktype->tt_member != NULL) return OK;
cac->cac_rhs_type = stacktype->tt_member; }
/*
* Evaluate the expression for "[var, var] = expr" assignment.
* A line break may follow the assignment operator "=".
*/
static char_u *
compile_assign_list_expr(cctx_T *cctx, cac_T *cac)
{
char_u *whitep;
whitep = cac->cac_op + cac->cac_oplen;
if (may_get_next_line_error(whitep, &cac->cac_nextc, cctx) == FAIL)
return NULL;
// compile RHS expression
if (compile_expr0(&cac->cac_nextc, cctx) == FAIL)
return NULL;
if (cctx->ctx_skip == SKIP_YES)
// no need to parse more when skipping
return cac->cac_nextc;
if (compile_assign_list_check_rhs_type(cctx, cac) == FAIL)
return NULL;
// If a constant list was used we can check the length right here.
if (compile_assign_list_check_length(cctx, cac) == FAIL)
return FAIL;
return cac->cac_nextc; return cac->cac_nextc;
} }
@@ -2841,12 +2878,13 @@ compile_assign_compute_end(
cac->cac_nextc = parse_heredoc_assignment(eap, cctx, cac); cac->cac_nextc = parse_heredoc_assignment(eap, cctx, cac);
return cac->cac_nextc; return cac->cac_nextc;
} }
else if (cac->cac_var_count > 0)
if (cac->cac_var_count > 0)
{ {
// for "[var, var] = expr" evaluate the expression. The list of // for "[var, var] = expr" evaluate the expression. The list of
// variables are processed later. // variables are processed later.
// A line break may follow the "=". // A line break may follow the "=".
cac->cac_nextc = compile_list_assignment_expr(cctx, cac); cac->cac_nextc = compile_assign_list_expr(cctx, cac);
return cac->cac_nextc; return cac->cac_nextc;
} }
@@ -2860,7 +2898,7 @@ compile_assign_compute_end(
compile_assign_single_eval_expr(cctx_T *cctx, cac_T *cac) compile_assign_single_eval_expr(cctx_T *cctx, cac_T *cac)
{ {
int ret = OK; int ret = OK;
char_u *wp; char_u *whitep;
lhs_T *lhs = &cac->cac_lhs; lhs_T *lhs = &cac->cac_lhs;
// Compile the expression. // Compile the expression.
@@ -2871,9 +2909,9 @@ compile_assign_single_eval_expr(cctx_T *cctx, cac_T *cac)
// not available to this expression. // not available to this expression.
if (lhs->lhs_new_local) if (lhs->lhs_new_local)
--cctx->ctx_locals.ga_len; --cctx->ctx_locals.ga_len;
wp = cac->cac_op + cac->cac_oplen; whitep = cac->cac_op + cac->cac_oplen;
if (may_get_next_line_error(wp, &cac->cac_nextc, cctx) == FAIL) if (may_get_next_line_error(whitep, &cac->cac_nextc, cctx) == FAIL)
{ {
if (lhs->lhs_new_local) if (lhs->lhs_new_local)
++cctx->ctx_locals.ga_len; ++cctx->ctx_locals.ga_len;
@@ -2887,6 +2925,79 @@ compile_assign_single_eval_expr(cctx_T *cctx, cac_T *cac)
return ret; return ret;
} }
/*
* When compiling an assignment, set the LHS type to the RHS type.
*/
static int
compile_assign_set_lhs_type_from_rhs(
cctx_T *cctx,
cac_T *cac,
lhs_T *lhs,
type_T *rhs_type)
{
if (rhs_type->tt_type == VAR_VOID)
{
emsg(_(e_cannot_use_void_value));
return FAIL;
}
type_T *type;
// An empty list or dict has a &t_unknown member, for a variable that
// implies &t_any.
if (rhs_type == &t_list_empty)
type = &t_list_any;
else if (rhs_type == &t_dict_empty)
type = &t_dict_any;
else if (rhs_type == &t_unknown)
type = &t_any;
else
{
type = rhs_type;
cac->cac_inferred_type = rhs_type;
}
set_var_type(lhs->lhs_lvar, type, cctx);
return OK;
}
/*
* Returns TRUE if the "rhs_type" can be assigned to the "lhs" variable.
* Used when compiling an assignment statement.
*/
static int
compile_assign_valid_rhs_type(
cctx_T *cctx,
cac_T *cac,
lhs_T *lhs,
type_T *rhs_type)
{
type_T *use_type = lhs->lhs_lvar->lv_type;
where_T where = WHERE_INIT;
// Without operator check type here, otherwise below.
// Use the line number of the assignment.
SOURCING_LNUM = cac->cac_start_lnum;
if (cac->cac_var_count > 0)
{
where.wt_index = cac->cac_var_idx + 1;
where.wt_kind = WT_VARIABLE;
}
// If assigning to a list or dict member, use the member type.
// Not for "list[:] =".
if (lhs->lhs_has_index &&
!has_list_index(cac->cac_var_start + lhs->lhs_varlen, cctx))
use_type = lhs->lhs_member_type;
if (need_type_where(rhs_type, use_type, FALSE, -1, where, cctx, FALSE,
cac->cac_is_const) == FAIL)
return FALSE;
return TRUE;
}
/* /*
* Compare the LHS type with the RHS type in an assignment. * Compare the LHS type with the RHS type in an assignment.
*/ */
@@ -2896,8 +3007,9 @@ compile_assign_check_type(cctx_T *cctx, cac_T *cac)
lhs_T *lhs = &cac->cac_lhs; lhs_T *lhs = &cac->cac_lhs;
type_T *rhs_type; type_T *rhs_type;
rhs_type = cctx->ctx_type_stack.ga_len == 0 ? rhs_type = cctx->ctx_type_stack.ga_len == 0
&t_void : get_type_on_stack(cctx, 0); ? &t_void
: get_type_on_stack(cctx, 0);
cac->cac_rhs_type = rhs_type; cac->cac_rhs_type = rhs_type;
if (check_type_is_value(rhs_type) == FAIL) if (check_type_is_value(rhs_type) == FAIL)
@@ -2905,77 +3017,95 @@ compile_assign_check_type(cctx_T *cctx, cac_T *cac)
if (lhs->lhs_lvar != NULL && (cac->cac_is_decl || !lhs->lhs_has_type)) if (lhs->lhs_lvar != NULL && (cac->cac_is_decl || !lhs->lhs_has_type))
{ {
if ((rhs_type->tt_type == VAR_FUNC if (rhs_type->tt_type == VAR_FUNC
|| rhs_type->tt_type == VAR_PARTIAL) || rhs_type->tt_type == VAR_PARTIAL)
&& !lhs->lhs_has_index {
&& var_wrong_func_name(lhs->lhs_name, TRUE)) // Make sure the variable name can be used as a funcref
return FAIL; if (!lhs->lhs_has_index
&& var_wrong_func_name(lhs->lhs_name, TRUE))
return FAIL;
}
if (lhs->lhs_new_local && !lhs->lhs_has_type) if (lhs->lhs_new_local && !lhs->lhs_has_type)
{ {
if (rhs_type->tt_type == VAR_VOID) // The LHS variable doesn't have a type. Set it to the RHS type.
{ if (compile_assign_set_lhs_type_from_rhs(cctx, cac, lhs, rhs_type)
emsg(_(e_cannot_use_void_value)); == FAIL)
return FAIL; return FAIL;
}
else
{
type_T *type;
// An empty list or dict has a &t_unknown member,
// for a variable that implies &t_any.
if (rhs_type == &t_list_empty)
type = &t_list_any;
else if (rhs_type == &t_dict_empty)
type = &t_dict_any;
else if (rhs_type == &t_unknown)
type = &t_any;
else
{
type = rhs_type;
cac->cac_inferred_type = rhs_type;
}
set_var_type(lhs->lhs_lvar, type, cctx);
}
} }
else if (*cac->cac_op == '=') else if (*cac->cac_op == '=')
{ {
type_T *use_type = lhs->lhs_lvar->lv_type; if (!compile_assign_valid_rhs_type(cctx, cac, lhs, rhs_type))
where_T where = WHERE_INIT;
// Without operator check type here, otherwise below.
// Use the line number of the assignment.
SOURCING_LNUM = cac->cac_start_lnum;
if (cac->cac_var_count > 0)
{
where.wt_index = cac->cac_var_idx + 1;
where.wt_kind = WT_VARIABLE;
}
// If assigning to a list or dict member, use the
// member type. Not for "list[:] =".
if (lhs->lhs_has_index &&
!has_list_index(cac->cac_var_start +
lhs->lhs_varlen, cctx))
use_type = lhs->lhs_member_type;
if (need_type_where(rhs_type, use_type, FALSE, -1,
where, cctx, FALSE, cac->cac_is_const) == FAIL)
return FAIL; return FAIL;
} }
} }
else else
{ {
// Assigning to a register using @r = "abc"
type_T *lhs_type = lhs->lhs_member_type; type_T *lhs_type = lhs->lhs_member_type;
// Special case: assigning to @# can use a number or a // Special case: assigning to @# can use a number or a string.
// string.
// Also: can assign a number to a float. // Also: can assign a number to a float.
if ((lhs_type == &t_number_or_string || lhs_type == &t_float) if ((lhs_type == &t_number_or_string || lhs_type == &t_float)
&& rhs_type->tt_type == VAR_NUMBER) && rhs_type->tt_type == VAR_NUMBER)
lhs_type = &t_number; lhs_type = &t_number;
if (*cac->cac_nextc != '=' && need_type(rhs_type,
lhs_type, FALSE, -1, 0, cctx, FALSE, FALSE) == FAIL) if (*cac->cac_nextc != '=')
{
if (need_type(rhs_type, lhs_type, FALSE, -1, 0, cctx, FALSE,
FALSE) == FAIL)
return FAIL;
}
}
return OK;
}
/*
* Compile the RHS expression in an assignment statement and generate the
* instructions.
*/
static int
compile_assign_rhs_expr(cctx_T *cctx, cac_T *cac)
{
cac->cac_is_const = FALSE;
// for "+=", "*=", "..=" etc. first load the current value
if (*cac->cac_op != '='
&& compile_load_lhs_with_index(&cac->cac_lhs, cac->cac_var_start,
cctx) == FAIL)
return FAIL;
// For "var = expr" evaluate the expression.
if (cac->cac_var_count == 0)
{
int ret;
// Compile the expression.
cac->cac_instr_count = cac->cac_instr->ga_len;
ret = compile_assign_single_eval_expr(cctx, cac);
if (ret == FAIL)
return FAIL; return FAIL;
} }
else if (cac->cac_semicolon && cac->cac_var_idx == cac->cac_var_count - 1)
{
// For "[var; var] = expr" get the rest of the list
cac->cac_did_generate_slice = TRUE;
if (generate_SLICE(cctx, cac->cac_var_count - 1) == FAIL)
return FAIL;
}
else
{
// For "[var, var] = expr" get the "var_idx" item from the
// list.
int with_op = *cac->cac_op != '=';
if (generate_GETITEM(cctx, cac->cac_var_idx, with_op) == FAIL)
return FAIL;
}
if (compile_assign_check_type(cctx, cac) == FAIL)
return FAIL;
return OK; return OK;
} }
@@ -2999,50 +3129,9 @@ compile_assign_rhs(cctx_T *cctx, cac_T *cac)
return OK; return OK;
} }
// If RHS is specified, then generate instructions for RHS expression
if (cac->cac_oplen > 0) if (cac->cac_oplen > 0)
{ return compile_assign_rhs_expr(cctx, cac);
cac->cac_is_const = FALSE;
// for "+=", "*=", "..=" etc. first load the current value
if (*cac->cac_op != '='
&& compile_load_lhs_with_index(&cac->cac_lhs,
cac->cac_var_start,
cctx) == FAIL)
return FAIL;
// For "var = expr" evaluate the expression.
if (cac->cac_var_count == 0)
{
int ret;
// Compile the expression.
cac->cac_instr_count = cac->cac_instr->ga_len;
ret = compile_assign_single_eval_expr(cctx, cac);
if (ret == FAIL)
return FAIL;
}
else if (cac->cac_semicolon &&
cac->cac_var_idx == cac->cac_var_count - 1)
{
// For "[var; var] = expr" get the rest of the list
cac->cac_did_generate_slice = TRUE;
if (generate_SLICE(cctx, cac->cac_var_count - 1) == FAIL)
return FAIL;
}
else
{
// For "[var, var] = expr" get the "var_idx" item from the
// list.
if (generate_GETITEM(cctx, cac->cac_var_idx,
*cac->cac_op != '=') == FAIL)
return FAIL;
}
if (compile_assign_check_type(cctx, cac) == FAIL)
return FAIL;
return OK;
}
if (cac->cac_cmdidx == CMD_final) if (cac->cac_cmdidx == CMD_final)
{ {
@@ -3186,6 +3275,7 @@ compile_assign_generate_store(cctx_T *cctx, cac_T *cac)
} }
cctx->ctx_lnum = save_lnum; cctx->ctx_lnum = save_lnum;
return OK; return OK;
} }
@@ -3202,6 +3292,10 @@ compile_assign_process_variables(
int has_argisset_prefix, int has_argisset_prefix,
int jump_instr_idx) int jump_instr_idx)
{ {
/*
* Loop over variables in "[var, var] = expr".
* For "name = expr" and "var name: type" this is done only once.
*/
for (cac->cac_var_idx = 0; cac->cac_var_idx == 0 || for (cac->cac_var_idx = 0; cac->cac_var_idx == 0 ||
cac->cac_var_idx < cac->cac_var_count; cac->cac_var_idx++) cac->cac_var_idx < cac->cac_var_count; cac->cac_var_idx++)
{ {
@@ -3286,14 +3380,14 @@ compile_assign_process_variables(
*/ */
static char_u * static char_u *
compile_assignment( compile_assignment(
char_u *arg_start, char_u *arg_start,
exarg_T *eap, exarg_T *eap,
cmdidx_T cmdidx, cmdidx_T cmdidx,
cctx_T *cctx) cctx_T *cctx)
{ {
cac_T cac; cac_T cac;
char_u *arg = arg_start; char_u *arg = arg_start;
char_u *ret = NULL; char_u *retstr = NULL;
int heredoc = FALSE; int heredoc = FALSE;
int jump_instr_idx; int jump_instr_idx;
@@ -3313,25 +3407,18 @@ compile_assignment(
if (cac.cac_nextc == NULL) if (cac.cac_nextc == NULL)
return *arg == '[' ? arg : NULL; return *arg == '[' ? arg : NULL;
char_u *retstr;
if (compile_assign_process_operator(eap, arg, &cac, &heredoc, if (compile_assign_process_operator(eap, arg, &cac, &heredoc,
&retstr) == FAIL) &retstr) == FAIL)
return retstr; return retstr;
// Compute the start of the assignment
cac.cac_var_start = compile_assign_compute_start(arg, cac.cac_var_count);
// Compute the end of the assignment // Compute the end of the assignment
cac.cac_var_end = compile_assign_compute_end(eap, cctx, &cac, heredoc); cac.cac_var_end = compile_assign_compute_end(eap, cctx, &cac, heredoc);
if (cac.cac_var_end == NULL) if (cac.cac_var_end == NULL)
return NULL; return NULL;
/*
* Loop over variables in "[var, var] = expr".
* For "name = expr" and "var name: type" this is done only once.
*/
if (cac.cac_var_count > 0)
cac.cac_var_start = skipwhite(arg + 1); // skip over the "["
else
cac.cac_var_start = arg;
int has_cmd = cac.cac_var_start > eap->cmd; int has_cmd = cac.cac_var_start > eap->cmd;
/* process the variable(s) */ /* process the variable(s) */
@@ -3349,11 +3436,11 @@ compile_assignment(
goto theend; goto theend;
} }
ret = skipwhite(cac.cac_var_end); retstr = skipwhite(cac.cac_var_end);
theend: theend:
vim_free(cac.cac_lhs.lhs_name); vim_free(cac.cac_lhs.lhs_name);
return ret; return retstr;
} }
/* /*