mirror of
https://github.com/vim/vim.git
synced 2025-09-25 03:54:15 -04:00
patch 9.1.0371: Vim9: compile_def_function() still too long
Problem: Vim9: compile_def_function() still too long Solution: Refactor the code into separate functions (Yegappan Lakshmanan) closes: #14632 Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
e679a37e17
commit
f6c1fb20e3
@@ -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 */
|
||||||
|
/**/
|
||||||
|
371,
|
||||||
/**/
|
/**/
|
||||||
370,
|
370,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -3273,6 +3273,166 @@ add_def_function(ufunc_T *ufunc)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For an object constructor, generate instruction to setup "this" (the first
|
||||||
|
* local variable) and to initialize the object variables.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
obj_constructor_prologue(ufunc_T *ufunc, cctx_T *cctx)
|
||||||
|
{
|
||||||
|
generate_CONSTRUCT(cctx, ufunc->uf_class);
|
||||||
|
|
||||||
|
for (int i = 0; i < ufunc->uf_class->class_obj_member_count; ++i)
|
||||||
|
{
|
||||||
|
ocmember_T *m = &ufunc->uf_class->class_obj_members[i];
|
||||||
|
|
||||||
|
if (i < 2 && IS_ENUM(ufunc->uf_class))
|
||||||
|
// The first two object variables in an enum are the name
|
||||||
|
// and the ordinal. These are set by the ISN_CONSTRUCT
|
||||||
|
// instruction. So don't generate instructions to set
|
||||||
|
// these variables.
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (m->ocm_init != NULL)
|
||||||
|
{
|
||||||
|
char_u *expr = m->ocm_init;
|
||||||
|
|
||||||
|
if (compile_expr0(&expr, cctx) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
|
if (!ends_excmd2(m->ocm_init, expr))
|
||||||
|
{
|
||||||
|
semsg(_(e_trailing_characters_str), expr);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
type_T *type = get_type_on_stack(cctx, 0);
|
||||||
|
if (m->ocm_type->tt_type == VAR_ANY
|
||||||
|
&& !(m->ocm_flags & OCMFLAG_HAS_TYPE)
|
||||||
|
&& type->tt_type != VAR_SPECIAL)
|
||||||
|
{
|
||||||
|
// If the member variable type is not yet set, then use
|
||||||
|
// the initialization expression type.
|
||||||
|
m->ocm_type = type;
|
||||||
|
}
|
||||||
|
else if (m->ocm_type->tt_type != type->tt_type)
|
||||||
|
{
|
||||||
|
// The type of the member initialization expression is
|
||||||
|
// determined at run time. Add a runtime type check.
|
||||||
|
where_T where = WHERE_INIT;
|
||||||
|
where.wt_kind = WT_MEMBER;
|
||||||
|
where.wt_func_name = (char *)m->ocm_name;
|
||||||
|
if (need_type_where(type, m->ocm_type, FALSE, -1,
|
||||||
|
where, cctx, FALSE, FALSE) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
push_default_value(cctx, m->ocm_type->tt_type, FALSE, NULL);
|
||||||
|
|
||||||
|
generate_STORE_THIS(cctx, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For an object method and an constructor, generate instruction to setup
|
||||||
|
* "this" (the first local variable). For a constructor, generate instructions
|
||||||
|
* to initialize the object variables.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
obj_method_prologue(ufunc_T *ufunc, cctx_T *cctx)
|
||||||
|
{
|
||||||
|
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
|
||||||
|
|
||||||
|
if (GA_GROW_FAILS(&dfunc->df_var_names, 1))
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
|
((char_u **)dfunc->df_var_names.ga_data)[0] =
|
||||||
|
vim_strsave((char_u *)"this");
|
||||||
|
++dfunc->df_var_names.ga_len;
|
||||||
|
|
||||||
|
// In the constructor allocate memory for the object and initialize the
|
||||||
|
// object members.
|
||||||
|
if (IS_CONSTRUCTOR_METHOD(ufunc))
|
||||||
|
return obj_constructor_prologue(ufunc, cctx);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Produce instructions for the default values of optional arguments.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
compile_def_function_default_args(
|
||||||
|
ufunc_T *ufunc,
|
||||||
|
cctx_T *cctx,
|
||||||
|
garray_T *instr)
|
||||||
|
{
|
||||||
|
int count = ufunc->uf_def_args.ga_len;
|
||||||
|
int first_def_arg = ufunc->uf_args.ga_len - count;
|
||||||
|
int i;
|
||||||
|
int off = STACK_FRAME_SIZE + (ufunc->uf_va_name != NULL ? 1 : 0);
|
||||||
|
int did_set_arg_type = FALSE;
|
||||||
|
|
||||||
|
// Produce instructions for the default values of optional arguments.
|
||||||
|
SOURCING_LNUM = 0; // line number unknown
|
||||||
|
for (i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
char_u *arg = ((char_u **)(ufunc->uf_def_args.ga_data))[i];
|
||||||
|
if (STRCMP(arg, "v:none") == 0)
|
||||||
|
// "arg = v:none" means the argument is optional without
|
||||||
|
// setting a value when the argument is missing.
|
||||||
|
continue;
|
||||||
|
|
||||||
|
type_T *val_type;
|
||||||
|
int arg_idx = first_def_arg + i;
|
||||||
|
where_T where = WHERE_INIT;
|
||||||
|
int jump_instr_idx = instr->ga_len;
|
||||||
|
isn_T *isn;
|
||||||
|
|
||||||
|
// Use a JUMP_IF_ARG_SET instruction to skip if the value was given.
|
||||||
|
if (generate_JUMP_IF_ARG(cctx, ISN_JUMP_IF_ARG_SET,
|
||||||
|
i - count - off) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
|
// Make sure later arguments are not found.
|
||||||
|
ufunc->uf_args_visible = arg_idx;
|
||||||
|
|
||||||
|
int r = compile_expr0(&arg, cctx);
|
||||||
|
if (r == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
|
// If no type specified use the type of the default value.
|
||||||
|
// Otherwise check that the default value type matches the
|
||||||
|
// specified type.
|
||||||
|
val_type = get_type_on_stack(cctx, 0);
|
||||||
|
where.wt_index = arg_idx + 1;
|
||||||
|
where.wt_kind = WT_ARGUMENT;
|
||||||
|
if (ufunc->uf_arg_types[arg_idx] == &t_unknown)
|
||||||
|
{
|
||||||
|
did_set_arg_type = TRUE;
|
||||||
|
ufunc->uf_arg_types[arg_idx] = val_type;
|
||||||
|
}
|
||||||
|
else if (need_type_where(val_type, ufunc->uf_arg_types[arg_idx],
|
||||||
|
FALSE, -1, where, cctx, FALSE, FALSE) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
|
if (generate_STORE(cctx, ISN_STORE, i - count - off, NULL) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
|
// set instruction index in JUMP_IF_ARG_SET to here
|
||||||
|
isn = ((isn_T *)instr->ga_data) + jump_instr_idx;
|
||||||
|
isn->isn_arg.jumparg.jump_where = instr->ga_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (did_set_arg_type)
|
||||||
|
set_function_type(ufunc);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compile def function body. Loop over all the lines in the function and
|
* Compile def function body. Loop over all the lines in the function and
|
||||||
* generate instructions.
|
* generate instructions.
|
||||||
@@ -3937,136 +4097,15 @@ compile_def_function(
|
|||||||
if (check_args_shadowing(ufunc, &cctx) == FAIL)
|
if (check_args_shadowing(ufunc, &cctx) == FAIL)
|
||||||
goto erret;
|
goto erret;
|
||||||
|
|
||||||
// For an object method and constructor "this" is the first local variable.
|
// For an object method and a constructor generate instructions to
|
||||||
|
// initialize "this" and the object variables.
|
||||||
if (ufunc->uf_flags & (FC_OBJECT|FC_NEW))
|
if (ufunc->uf_flags & (FC_OBJECT|FC_NEW))
|
||||||
{
|
if (obj_method_prologue(ufunc, &cctx) == FAIL)
|
||||||
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
|
||||||
+ ufunc->uf_dfunc_idx;
|
|
||||||
if (GA_GROW_FAILS(&dfunc->df_var_names, 1))
|
|
||||||
goto erret;
|
goto erret;
|
||||||
((char_u **)dfunc->df_var_names.ga_data)[0] =
|
|
||||||
vim_strsave((char_u *)"this");
|
|
||||||
++dfunc->df_var_names.ga_len;
|
|
||||||
|
|
||||||
// In the constructor allocate memory for the object and initialize the
|
|
||||||
// object members.
|
|
||||||
if (IS_CONSTRUCTOR_METHOD(ufunc))
|
|
||||||
{
|
|
||||||
generate_CONSTRUCT(&cctx, ufunc->uf_class);
|
|
||||||
|
|
||||||
for (int i = 0; i < ufunc->uf_class->class_obj_member_count; ++i)
|
|
||||||
{
|
|
||||||
ocmember_T *m = &ufunc->uf_class->class_obj_members[i];
|
|
||||||
|
|
||||||
if (i < 2 && IS_ENUM(ufunc->uf_class))
|
|
||||||
// The first two object variables in an enum are the name
|
|
||||||
// and the ordinal. These are set by the ISN_CONSTRUCT
|
|
||||||
// instruction. So don't generate instructions to set
|
|
||||||
// these variables.
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (m->ocm_init != NULL)
|
|
||||||
{
|
|
||||||
char_u *expr = m->ocm_init;
|
|
||||||
if (compile_expr0(&expr, &cctx) == FAIL)
|
|
||||||
goto erret;
|
|
||||||
if (!ends_excmd2(m->ocm_init, expr))
|
|
||||||
{
|
|
||||||
semsg(_(e_trailing_characters_str), expr);
|
|
||||||
goto erret;
|
|
||||||
}
|
|
||||||
|
|
||||||
type_T *type = get_type_on_stack(&cctx, 0);
|
|
||||||
if (m->ocm_type->tt_type == VAR_ANY
|
|
||||||
&& !(m->ocm_flags & OCMFLAG_HAS_TYPE)
|
|
||||||
&& type->tt_type != VAR_SPECIAL)
|
|
||||||
{
|
|
||||||
// If the member variable type is not yet set, then use
|
|
||||||
// the initialization expression type.
|
|
||||||
m->ocm_type = type;
|
|
||||||
}
|
|
||||||
else if (m->ocm_type->tt_type != type->tt_type)
|
|
||||||
{
|
|
||||||
// The type of the member initialization expression is
|
|
||||||
// determined at run time. Add a runtime type check.
|
|
||||||
where_T where = WHERE_INIT;
|
|
||||||
where.wt_kind = WT_MEMBER;
|
|
||||||
where.wt_func_name = (char *)m->ocm_name;
|
|
||||||
if (need_type_where(type, m->ocm_type, FALSE, -1,
|
|
||||||
where, &cctx, FALSE, FALSE) == FAIL)
|
|
||||||
goto erret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
push_default_value(&cctx, m->ocm_type->tt_type,
|
|
||||||
FALSE, NULL);
|
|
||||||
generate_STORE_THIS(&cctx, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ufunc->uf_def_args.ga_len > 0)
|
if (ufunc->uf_def_args.ga_len > 0)
|
||||||
{
|
if (compile_def_function_default_args(ufunc, &cctx, instr) == FAIL)
|
||||||
int count = ufunc->uf_def_args.ga_len;
|
goto erret;
|
||||||
int first_def_arg = ufunc->uf_args.ga_len - count;
|
|
||||||
int i;
|
|
||||||
int off = STACK_FRAME_SIZE + (ufunc->uf_va_name != NULL ? 1 : 0);
|
|
||||||
int did_set_arg_type = FALSE;
|
|
||||||
|
|
||||||
// Produce instructions for the default values of optional arguments.
|
|
||||||
SOURCING_LNUM = 0; // line number unknown
|
|
||||||
for (i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
char_u *arg = ((char_u **)(ufunc->uf_def_args.ga_data))[i];
|
|
||||||
if (STRCMP(arg, "v:none") == 0)
|
|
||||||
// "arg = v:none" means the argument is optional without
|
|
||||||
// setting a value when the argument is missing.
|
|
||||||
continue;
|
|
||||||
|
|
||||||
type_T *val_type;
|
|
||||||
int arg_idx = first_def_arg + i;
|
|
||||||
where_T where = WHERE_INIT;
|
|
||||||
int jump_instr_idx = instr->ga_len;
|
|
||||||
isn_T *isn;
|
|
||||||
|
|
||||||
// Use a JUMP_IF_ARG_SET instruction to skip if the value was given.
|
|
||||||
if (generate_JUMP_IF_ARG(&cctx, ISN_JUMP_IF_ARG_SET,
|
|
||||||
i - count - off) == FAIL)
|
|
||||||
goto erret;
|
|
||||||
|
|
||||||
// Make sure later arguments are not found.
|
|
||||||
ufunc->uf_args_visible = arg_idx;
|
|
||||||
|
|
||||||
int r = compile_expr0(&arg, &cctx);
|
|
||||||
if (r == FAIL)
|
|
||||||
goto erret;
|
|
||||||
|
|
||||||
// If no type specified use the type of the default value.
|
|
||||||
// Otherwise check that the default value type matches the
|
|
||||||
// specified type.
|
|
||||||
val_type = get_type_on_stack(&cctx, 0);
|
|
||||||
where.wt_index = arg_idx + 1;
|
|
||||||
where.wt_kind = WT_ARGUMENT;
|
|
||||||
if (ufunc->uf_arg_types[arg_idx] == &t_unknown)
|
|
||||||
{
|
|
||||||
did_set_arg_type = TRUE;
|
|
||||||
ufunc->uf_arg_types[arg_idx] = val_type;
|
|
||||||
}
|
|
||||||
else if (need_type_where(val_type, ufunc->uf_arg_types[arg_idx],
|
|
||||||
FALSE, -1, where, &cctx, FALSE, FALSE) == FAIL)
|
|
||||||
goto erret;
|
|
||||||
|
|
||||||
if (generate_STORE(&cctx, ISN_STORE, i - count - off, NULL) == FAIL)
|
|
||||||
goto erret;
|
|
||||||
|
|
||||||
// set instruction index in JUMP_IF_ARG_SET to here
|
|
||||||
isn = ((isn_T *)instr->ga_data) + jump_instr_idx;
|
|
||||||
isn->isn_arg.jumparg.jump_where = instr->ga_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (did_set_arg_type)
|
|
||||||
set_function_type(ufunc);
|
|
||||||
}
|
|
||||||
ufunc->uf_args_visible = ufunc->uf_args.ga_len;
|
ufunc->uf_args_visible = ufunc->uf_args.ga_len;
|
||||||
|
|
||||||
// Compiling a function in an interface is done to get the function type.
|
// Compiling a function in an interface is done to get the function type.
|
||||||
@@ -4078,6 +4117,7 @@ compile_def_function(
|
|||||||
goto erret;
|
goto erret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// compile the function body
|
||||||
if (compile_def_function_body(&cctx, ufunc->uf_lines.ga_len,
|
if (compile_def_function_body(&cctx, ufunc->uf_lines.ga_len,
|
||||||
check_return_type, &lines_to_free, &errormsg) == FAIL)
|
check_return_type, &lines_to_free, &errormsg) == FAIL)
|
||||||
goto erret;
|
goto erret;
|
||||||
|
Reference in New Issue
Block a user