0
0
mirror of https://github.com/vim/vim.git synced 2025-09-24 03:44:06 -04:00

patch 9.0.1045: in a class object members cannot be initialized

Problem:    In a class object members cannot be initialized.
Solution:   Support initializing object members. Make "dissassemble" work on
            an object method.
This commit is contained in:
Bram Moolenaar
2022-12-10 18:42:12 +00:00
parent 6c87bbb4e4
commit 7ce7daf6cd
13 changed files with 280 additions and 74 deletions

View File

@@ -2117,6 +2117,71 @@ compile_assign_unlet(
return OK;
}
/*
* Generate an instruction to push the default value for "vartype".
* if "dest_local" is TRUE then for some types no instruction is generated.
* "skip_store" is set to TRUE if no PUSH instruction is generated.
* Returns OK or FAIL.
*/
static int
push_default_value(
cctx_T *cctx,
vartype_T vartype,
int dest_is_local,
int *skip_store)
{
int r = OK;
switch (vartype)
{
case VAR_BOOL:
r = generate_PUSHBOOL(cctx, VVAL_FALSE);
break;
case VAR_FLOAT:
r = generate_PUSHF(cctx, 0.0);
break;
case VAR_STRING:
r = generate_PUSHS(cctx, NULL);
break;
case VAR_BLOB:
r = generate_PUSHBLOB(cctx, blob_alloc());
break;
case VAR_FUNC:
r = generate_PUSHFUNC(cctx, NULL, &t_func_void, TRUE);
break;
case VAR_LIST:
r = generate_NEWLIST(cctx, 0, FALSE);
break;
case VAR_DICT:
r = generate_NEWDICT(cctx, 0, FALSE);
break;
case VAR_JOB:
r = generate_PUSHJOB(cctx);
break;
case VAR_CHANNEL:
r = generate_PUSHCHANNEL(cctx);
break;
case VAR_NUMBER:
case VAR_UNKNOWN:
case VAR_ANY:
case VAR_PARTIAL:
case VAR_VOID:
case VAR_INSTR:
case VAR_CLASS:
case VAR_OBJECT:
case VAR_SPECIAL: // cannot happen
// This is skipped for local variables, they are always
// initialized to zero. But in a "for" or "while" loop
// the value may have been changed.
if (dest_is_local && !inside_loop_scope(cctx))
*skip_store = TRUE;
else
r = generate_PUSHNR(cctx, 0);
break;
}
return r;
}
/*
* Compile declaration and assignment:
* "let name"
@@ -2462,62 +2527,12 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
}
else
{
int r = OK;
// variables are always initialized
if (GA_GROW_FAILS(instr, 1))
goto theend;
switch (lhs.lhs_member_type->tt_type)
{
case VAR_BOOL:
r = generate_PUSHBOOL(cctx, VVAL_FALSE);
break;
case VAR_FLOAT:
r = generate_PUSHF(cctx, 0.0);
break;
case VAR_STRING:
r = generate_PUSHS(cctx, NULL);
break;
case VAR_BLOB:
r = generate_PUSHBLOB(cctx, blob_alloc());
break;
case VAR_FUNC:
r = generate_PUSHFUNC(cctx, NULL, &t_func_void, TRUE);
break;
case VAR_LIST:
r = generate_NEWLIST(cctx, 0, FALSE);
break;
case VAR_DICT:
r = generate_NEWDICT(cctx, 0, FALSE);
break;
case VAR_JOB:
r = generate_PUSHJOB(cctx);
break;
case VAR_CHANNEL:
r = generate_PUSHCHANNEL(cctx);
break;
case VAR_NUMBER:
case VAR_UNKNOWN:
case VAR_ANY:
case VAR_PARTIAL:
case VAR_VOID:
case VAR_INSTR:
case VAR_CLASS:
case VAR_OBJECT:
case VAR_SPECIAL: // cannot happen
// This is skipped for local variables, they are always
// initialized to zero. But in a "for" or "while" loop
// the value may have been changed.
if (lhs.lhs_dest == dest_local
&& !inside_loop_scope(cctx))
skip_store = TRUE;
else
{
instr_count = instr->ga_len;
r = generate_PUSHNR(cctx, 0);
}
break;
}
instr_count = instr->ga_len;
int r = push_default_value(cctx, lhs.lhs_member_type->tt_type,
lhs.lhs_dest == dest_local, &skip_store);
if (r == FAIL)
goto theend;
}
@@ -2946,9 +2961,32 @@ compile_def_function(
vim_strsave((char_u *)"this");
++dfunc->df_var_names.ga_len;
// In the constructor allocate memory for the object.
// In the constructor allocate memory for the object and initialize the
// object members.
if ((ufunc->uf_flags & FC_NEW) == FC_NEW)
{
generate_CONSTRUCT(&cctx, ufunc->uf_class);
for (int i = 0; i < ufunc->uf_class->class_obj_member_count; ++i)
{
objmember_T *m = &ufunc->uf_class->class_obj_members[i];
if (m->om_init != NULL)
{
char_u *expr = m->om_init;
if (compile_expr0(&expr, &cctx) == FAIL)
goto erret;
if (!ends_excmd2(m->om_init, expr))
{
semsg(_(e_trailing_characters_str), expr);
goto erret;
}
}
else
push_default_value(&cctx, m->om_type->tt_type,
FALSE, NULL);
generate_STORE_THIS(&cctx, i);
}
}
}
if (ufunc->uf_def_args.ga_len > 0)
@@ -3564,7 +3602,10 @@ nextline:
// Return void if there is no return at the end.
// For a constructor return the object.
if ((ufunc->uf_flags & FC_NEW) == FC_NEW)
{
generate_instr(&cctx, ISN_RETURN_OBJECT);
ufunc->uf_ret_type = &ufunc->uf_class->class_object_type;
}
else
generate_instr(&cctx, ISN_RETURN_VOID);
}