mirror of
https://github.com/vim/vim
synced 2025-03-26 11:45:22 +01:00
patch 9.1.0914: Vim9: compile_assignment() is too long
Problem: Vim9: compile_assignment() is too long Solution: refactor compile_assignment() into smaller functions (Yegappan Lakshmanan) closes: #16186 Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
parent
65be834c30
commit
85ee742f1e
2 changed files with 164 additions and 84 deletions
|
@ -704,6 +704,8 @@ static char *(features[]) =
|
|||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
914,
|
||||
/**/
|
||||
913,
|
||||
/**/
|
||||
|
|
|
@ -2583,6 +2583,156 @@ push_default_value(
|
|||
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_assignment_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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the increment (++) or decrement (--) operator to the corresponding
|
||||
* compound operator.
|
||||
*
|
||||
* Returns OK on success and FAIL on syntax error.
|
||||
*/
|
||||
static int
|
||||
incdec_op_translate(
|
||||
exarg_T *eap,
|
||||
char_u **op,
|
||||
int *oplen,
|
||||
int *incdec)
|
||||
{
|
||||
if (VIM_ISWHITE(eap->cmd[2]))
|
||||
{
|
||||
semsg(_(e_no_white_space_allowed_after_str_str),
|
||||
eap->cmdidx == CMD_increment ? "++" : "--", eap->cmd);
|
||||
return FAIL;
|
||||
}
|
||||
*op = (char_u *)(eap->cmdidx == CMD_increment ? "+=" : "-=");
|
||||
*oplen = 2;
|
||||
*incdec = TRUE;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a heredoc assignment starting at "p". Returns a pointer to the
|
||||
* beginning of the heredoc content.
|
||||
*/
|
||||
static char_u *
|
||||
heredoc_assign_stmt_end_get(char_u *p, exarg_T *eap, cctx_T *cctx)
|
||||
{
|
||||
// [let] varname =<< [trim] {end}
|
||||
eap->ea_getline = exarg_getline;
|
||||
eap->cookie = cctx;
|
||||
|
||||
list_T *l = heredoc_get(eap, p + 3, FALSE, TRUE);
|
||||
if (l == NULL)
|
||||
return NULL;
|
||||
|
||||
list_free(l);
|
||||
p += STRLEN(p);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static char_u *
|
||||
compile_list_assignment(
|
||||
char_u *p,
|
||||
char_u *op,
|
||||
int oplen,
|
||||
int var_count,
|
||||
int semicolon,
|
||||
garray_T *instr,
|
||||
type_T **rhs_type,
|
||||
cctx_T *cctx)
|
||||
{
|
||||
char_u *wp;
|
||||
|
||||
// for "[var, var] = expr" evaluate the expression here, loop over the
|
||||
// list of variables below.
|
||||
// A line break may follow the "=".
|
||||
|
||||
wp = op + oplen;
|
||||
if (may_get_next_line_error(wp, &p, cctx) == FAIL)
|
||||
return NULL;
|
||||
if (compile_expr0(&p, cctx) == FAIL)
|
||||
return NULL;
|
||||
|
||||
if (cctx->ctx_skip != SKIP_YES)
|
||||
{
|
||||
type_T *stacktype;
|
||||
int needed_list_len;
|
||||
int did_check = FALSE;
|
||||
|
||||
stacktype = cctx->ctx_type_stack.ga_len == 0 ? &t_void
|
||||
: get_type_on_stack(cctx, 0);
|
||||
if (stacktype->tt_type == VAR_VOID)
|
||||
{
|
||||
emsg(_(e_cannot_use_void_value));
|
||||
return NULL;
|
||||
}
|
||||
if (need_type(stacktype, &t_list_any, FALSE, -1, 0, cctx, FALSE,
|
||||
FALSE) == FAIL)
|
||||
return NULL;
|
||||
// If a constant list was used we can check the length right here.
|
||||
needed_list_len = semicolon ? var_count - 1 : var_count;
|
||||
if (instr->ga_len > 0)
|
||||
{
|
||||
isn_T *isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1;
|
||||
|
||||
if (isn->isn_type == ISN_NEWLIST)
|
||||
{
|
||||
did_check = TRUE;
|
||||
if (semicolon ? isn->isn_arg.number < needed_list_len
|
||||
: isn->isn_arg.number != needed_list_len)
|
||||
{
|
||||
semsg(_(e_expected_nr_items_but_got_nr),
|
||||
needed_list_len, (int)isn->isn_arg.number);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!did_check)
|
||||
generate_CHECKLEN(cctx, needed_list_len, semicolon);
|
||||
if (stacktype->tt_member != NULL)
|
||||
*rhs_type = stacktype->tt_member;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compile declaration and assignment:
|
||||
* "let name"
|
||||
|
@ -2625,38 +2775,20 @@ compile_assignment(
|
|||
long start_lnum = SOURCING_LNUM;
|
||||
|
||||
int has_arg_is_set_prefix = STRNCMP(arg, "ifargisset ", 11) == 0;
|
||||
if (has_arg_is_set_prefix)
|
||||
{
|
||||
arg += 11;
|
||||
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)
|
||||
goto theend;
|
||||
}
|
||||
if (has_arg_is_set_prefix &&
|
||||
compile_assignment_obj_new_arg(&arg, cctx) == FAIL)
|
||||
goto theend;
|
||||
|
||||
// Skip over the "varname" or "[varname, varname]" to get to any "=".
|
||||
p = skip_var_list(arg, TRUE, &var_count, &semicolon, TRUE);
|
||||
if (p == NULL)
|
||||
return *arg == '[' ? arg : NULL;
|
||||
|
||||
|
||||
if (eap->cmdidx == CMD_increment || eap->cmdidx == CMD_decrement)
|
||||
{
|
||||
if (VIM_ISWHITE(eap->cmd[2]))
|
||||
{
|
||||
semsg(_(e_no_white_space_allowed_after_str_str),
|
||||
eap->cmdidx == CMD_increment ? "++" : "--", eap->cmd);
|
||||
if (incdec_op_translate(eap, &op, &oplen, &incdec) == FAIL)
|
||||
return NULL;
|
||||
}
|
||||
op = (char_u *)(eap->cmdidx == CMD_increment ? "+=" : "-=");
|
||||
oplen = 2;
|
||||
incdec = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2678,73 +2810,19 @@ compile_assignment(
|
|||
|
||||
if (heredoc)
|
||||
{
|
||||
list_T *l;
|
||||
|
||||
// [let] varname =<< [trim] {end}
|
||||
eap->ea_getline = exarg_getline;
|
||||
eap->cookie = cctx;
|
||||
l = heredoc_get(eap, op + 3, FALSE, TRUE);
|
||||
if (l == NULL)
|
||||
p = heredoc_assign_stmt_end_get(p, eap, cctx);
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
|
||||
list_free(l);
|
||||
p += STRLEN(p);
|
||||
end = p;
|
||||
}
|
||||
else if (var_count > 0)
|
||||
{
|
||||
char_u *wp;
|
||||
|
||||
// for "[var, var] = expr" evaluate the expression here, loop over the
|
||||
// list of variables below.
|
||||
// A line break may follow the "=".
|
||||
|
||||
wp = op + oplen;
|
||||
if (may_get_next_line_error(wp, &p, cctx) == FAIL)
|
||||
return FAIL;
|
||||
if (compile_expr0(&p, cctx) == FAIL)
|
||||
return NULL;
|
||||
// "[var, var] = expr"
|
||||
p = compile_list_assignment(p, op, oplen, var_count, semicolon,
|
||||
instr, &rhs_type, cctx);
|
||||
if (p == NULL)
|
||||
goto theend;
|
||||
end = p;
|
||||
|
||||
if (cctx->ctx_skip != SKIP_YES)
|
||||
{
|
||||
type_T *stacktype;
|
||||
int needed_list_len;
|
||||
int did_check = FALSE;
|
||||
|
||||
stacktype = cctx->ctx_type_stack.ga_len == 0 ? &t_void
|
||||
: get_type_on_stack(cctx, 0);
|
||||
if (stacktype->tt_type == VAR_VOID)
|
||||
{
|
||||
emsg(_(e_cannot_use_void_value));
|
||||
goto theend;
|
||||
}
|
||||
if (need_type(stacktype, &t_list_any, FALSE, -1, 0, cctx,
|
||||
FALSE, FALSE) == FAIL)
|
||||
goto theend;
|
||||
// If a constant list was used we can check the length right here.
|
||||
needed_list_len = semicolon ? var_count - 1 : var_count;
|
||||
if (instr->ga_len > 0)
|
||||
{
|
||||
isn_T *isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1;
|
||||
|
||||
if (isn->isn_type == ISN_NEWLIST)
|
||||
{
|
||||
did_check = TRUE;
|
||||
if (semicolon ? isn->isn_arg.number < needed_list_len
|
||||
: isn->isn_arg.number != needed_list_len)
|
||||
{
|
||||
semsg(_(e_expected_nr_items_but_got_nr),
|
||||
needed_list_len, (int)isn->isn_arg.number);
|
||||
goto theend;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!did_check)
|
||||
generate_CHECKLEN(cctx, needed_list_len, semicolon);
|
||||
if (stacktype->tt_member != NULL)
|
||||
rhs_type = stacktype->tt_member;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Add table
Reference in a new issue