Patch 9.0.1045

5 views
Skip to first unread message

Bram Moolenaar

unread,
Dec 10, 2022, 1:42:52 PM12/10/22
to vim...@googlegroups.com

Patch 9.0.1045
Problem: In a class object members cannot be initialized.
Solution: Support initializing object members. Make "dissassemble" work on
an object method.
Files: src/vim9class.c, src/proto/vim9class.pro, src/vim9compile.c,
src/vim9execute.c, src/vim9expr.c, src/vim9instr.c,
src/proto/vim9instr.pro, src/structs.h, src/userfunc.c,
src/eval.c, src/vim9.h, src/testdir/test_vim9_class.vim


*** ../vim-9.0.1044/src/vim9class.c 2022-12-09 22:49:19.447580421 +0000
--- src/vim9class.c 2022-12-10 18:09:29.470008096 +0000
***************
*** 147,158 ****
--- 147,176 ----
if (type == NULL)
break;

+ char_u *expr_start = skipwhite(type_arg);
+ if (*expr_start == '=' && (!VIM_ISWHITE(expr_start[-1])
+ || !VIM_ISWHITE(expr_start[1])))
+ {
+ semsg(_(e_white_space_required_before_and_after_str_at_str),
+ "=", type_arg);
+ break;
+ }
+ expr_start = skipwhite(expr_start + 1);
+
+ char_u *expr_end = expr_start;
+ evalarg_T evalarg;
+ init_evalarg(&evalarg);
+ skip_expr(&expr_end, &evalarg);
+ clear_evalarg(&evalarg, NULL);
+
if (ga_grow(&objmembers, 1) == FAIL)
break;
objmember_T *m = ((objmember_T *)objmembers.ga_data)
+ objmembers.ga_len;
m->om_name = vim_strnsave(varname, varname_end - varname);
m->om_type = type;
+ if (expr_end > expr_start)
+ m->om_init = vim_strnsave(expr_start, expr_end - expr_start);
++objmembers.ga_len;
}

***************
*** 190,195 ****
--- 208,216 ----
// TODO: how about errors?
if (uf != NULL && ga_grow(&objmethods, 1) == OK)
{
+ if (STRNCMP(uf->uf_name, "new", 3) == 0)
+ uf->uf_flags |= FC_NEW;
+
((ufunc_T **)objmethods.ga_data)[objmethods.ga_len] = uf;
++objmethods.ga_len;
}
***************
*** 333,338 ****
--- 354,360 ----
{
objmember_T *m = ((objmember_T *)objmembers.ga_data) + i;
vim_free(m->om_name);
+ vim_free(m->om_init);
}
ga_clear(&objmembers);

***************
*** 520,525 ****
--- 542,593 ----
}

/*
+ * If "arg" points to a class or object method, return it.
+ * Otherwise return NULL.
+ */
+ ufunc_T *
+ find_class_func(char_u **arg)
+ {
+ char_u *name = *arg;
+ char_u *name_end = find_name_end(name, NULL, NULL, FNE_CHECK_START);
+ if (name_end == name || *name_end != '.')
+ return NULL;
+
+ size_t len = name_end - name;
+ typval_T tv;
+ tv.v_type = VAR_UNKNOWN;
+ if (eval_variable(name, len, 0, &tv, NULL, EVAL_VAR_NOAUTOLOAD) == FAIL)
+ return NULL;
+ if (tv.v_type != VAR_CLASS && tv.v_type != VAR_OBJECT)
+ {
+ clear_tv(&tv);
+ return NULL;
+ }
+
+ class_T *cl = tv.v_type == VAR_CLASS ? tv.vval.v_class
+ : tv.vval.v_object->obj_class;
+ if (cl == NULL)
+ return NULL;
+ char_u *fname = name_end + 1;
+ char_u *fname_end = find_name_end(fname, NULL, NULL, FNE_CHECK_START);
+ if (fname_end == fname)
+ return NULL;
+ len = fname_end - fname;
+
+ for (int i = 0; i < cl->class_obj_method_count; ++i)
+ {
+ ufunc_T *fp = cl->class_obj_methods[i];
+ // Use a separate pointer to avoid that ASAN complains about
+ // uf_name[] only being 4 characters.
+ char_u *ufname = (char_u *)fp->uf_name;
+ if (STRNCMP(fname, ufname, len) == 0 && ufname[len] == NUL)
+ return fp;
+ }
+
+ return NULL;
+ }
+
+ /*
* Make a copy of an object.
*/
void
***************
*** 585,590 ****
--- 653,659 ----
{
objmember_T *m = &cl->class_obj_members[i];
vim_free(m->om_name);
+ vim_free(m->om_init);
}
vim_free(cl->class_obj_members);

*** ../vim-9.0.1044/src/proto/vim9class.pro 2022-12-08 20:41:55.433288306 +0000
--- src/proto/vim9class.pro 2022-12-10 17:38:19.147340414 +0000
***************
*** 5,10 ****
--- 5,11 ----
void ex_enum(exarg_T *eap);
void ex_type(exarg_T *eap);
int class_object_index(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int verbose);
+ ufunc_T *find_class_func(char_u **arg);
void copy_object(typval_T *from, typval_T *to);
void object_unref(object_T *obj);
void copy_class(typval_T *from, typval_T *to);
*** ../vim-9.0.1044/src/vim9compile.c 2022-12-09 21:41:43.908327271 +0000
--- src/vim9compile.c 2022-12-10 16:24:08.356778584 +0000
***************
*** 2118,2123 ****
--- 2118,2188 ----
}

/*
+ * 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"
* "var name = expr"
***************
*** 2462,2523 ****
}
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;
! }
if (r == FAIL)
goto theend;
}
--- 2527,2538 ----
}
else
{
// variables are always initialized
if (GA_GROW_FAILS(instr, 1))
goto theend;
! 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,2954 ****
vim_strsave((char_u *)"this");
++dfunc->df_var_names.ga_len;

! // In the constructor allocate memory for the object.
if ((ufunc->uf_flags & FC_NEW) == FC_NEW)
generate_CONSTRUCT(&cctx, ufunc->uf_class);
}

if (ufunc->uf_def_args.ga_len > 0)
--- 2961,2992 ----
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 ((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,3570 ****
--- 3602,3611 ----
// 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);
}
*** ../vim-9.0.1044/src/vim9execute.c 2022-12-09 21:41:43.908327271 +0000
--- src/vim9execute.c 2022-12-10 17:25:04.637876026 +0000
***************
*** 3009,3015 ****
iptr = &ectx->ec_instr[ectx->ec_iidx++];
switch (iptr->isn_type)
{
! // Constructor, new() method.
case ISN_CONSTRUCT:
// "this" is always the local variable at index zero
tv = STACK_TV_VAR(0);
--- 3009,3015 ----
iptr = &ectx->ec_instr[ectx->ec_iidx++];
switch (iptr->isn_type)
{
! // Constructor, first instruction in a new() method.
case ISN_CONSTRUCT:
// "this" is always the local variable at index zero
tv = STACK_TV_VAR(0);
***************
*** 5114,5120 ****
}
break;

! case ISN_OBJ_MEMBER:
{
tv = STACK_TV_BOT(-1);
if (tv->v_type != VAR_OBJECT)
--- 5114,5120 ----
}
break;

! case ISN_GET_OBJ_MEMBER:
{
tv = STACK_TV_BOT(-1);
if (tv->v_type != VAR_OBJECT)
***************
*** 5143,5148 ****
--- 5143,5160 ----
}
break;

+ case ISN_STORE_THIS:
+ {
+ int idx = iptr->isn_arg.number;
+ object_T *obj = STACK_TV_VAR(0)->vval.v_object;
+ // the members are located right after the object struct
+ typval_T *mtv = ((typval_T *)(obj + 1)) + idx;
+ clear_tv(mtv);
+ *mtv = *STACK_TV_BOT(-1);
+ --ectx->ec_stack.ga_len;
+ }
+ break;
+
case ISN_CLEARDICT:
dict_stack_drop();
break;
***************
*** 6805,6811 ****
case ISN_MEMBER: smsg("%s%4d MEMBER", pfx, current); break;
case ISN_STRINGMEMBER: smsg("%s%4d MEMBER %s", pfx, current,
iptr->isn_arg.string); break;
! case ISN_OBJ_MEMBER: smsg("%s%4d OBJ_MEMBER %d", pfx, current,
(int)iptr->isn_arg.number); break;
case ISN_CLEARDICT: smsg("%s%4d CLEARDICT", pfx, current); break;
case ISN_USEDICT: smsg("%s%4d USEDICT", pfx, current); break;
--- 6817,6825 ----
case ISN_MEMBER: smsg("%s%4d MEMBER", pfx, current); break;
case ISN_STRINGMEMBER: smsg("%s%4d MEMBER %s", pfx, current,
iptr->isn_arg.string); break;
! case ISN_GET_OBJ_MEMBER: smsg("%s%4d OBJ_MEMBER %d", pfx, current,
! (int)iptr->isn_arg.number); break;
! case ISN_STORE_THIS: smsg("%s%4d STORE_THIS %d", pfx, current,
(int)iptr->isn_arg.number); break;
case ISN_CLEARDICT: smsg("%s%4d CLEARDICT", pfx, current); break;
case ISN_USEDICT: smsg("%s%4d USEDICT", pfx, current); break;
*** ../vim-9.0.1044/src/vim9expr.c 2022-12-09 21:41:43.908327271 +0000
--- src/vim9expr.c 2022-12-10 15:58:26.540459771 +0000
***************
*** 253,259 ****
/*
* Compile ".member" coming after an object or class.
*/
-
static int
compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type)
{
--- 253,258 ----
***************
*** 282,288 ****
objmember_T *m = &cl->class_obj_members[i];
if (STRNCMP(name, m->om_name, len) == 0 && m->om_name[len] == NUL)
{
! generate_OBJ_MEMBER(cctx, i, m->om_type);

*arg = name_end;
return OK;
--- 281,287 ----
objmember_T *m = &cl->class_obj_members[i];
if (STRNCMP(name, m->om_name, len) == 0 && m->om_name[len] == NUL)
{
! generate_GET_OBJ_MEMBER(cctx, i, m->om_type);

*arg = name_end;
return OK;
*** ../vim-9.0.1044/src/vim9instr.c 2022-12-09 21:41:43.908327271 +0000
--- src/vim9instr.c 2022-12-10 16:02:18.204571906 +0000
***************
*** 132,146 ****
}

/*
! * Generate ISN_OBJ_MEMBER - access object member by indes.
*/
int
! generate_OBJ_MEMBER(cctx_T *cctx, int idx, type_T *type)
{
RETURN_OK_IF_SKIP(cctx);

// drop the object type
! isn_T *isn = generate_instr_drop(cctx, ISN_OBJ_MEMBER, 1);
if (isn == NULL)
return FAIL;

--- 132,147 ----
}

/*
! * Generate ISN_GET_OBJ_MEMBER - access member of object at bottom of stack by
! * index.
*/
int
! generate_GET_OBJ_MEMBER(cctx_T *cctx, int idx, type_T *type)
{
RETURN_OK_IF_SKIP(cctx);

// drop the object type
! isn_T *isn = generate_instr_drop(cctx, ISN_GET_OBJ_MEMBER, 1);
if (isn == NULL)
return FAIL;

***************
*** 149,154 ****
--- 150,173 ----
}

/*
+ * Generate ISN_STORE_THIS - store value in member of "this" object with member
+ * index "idx".
+ */
+ int
+ generate_STORE_THIS(cctx_T *cctx, int idx)
+ {
+ RETURN_OK_IF_SKIP(cctx);
+
+ // drop the value type
+ isn_T *isn = generate_instr_drop(cctx, ISN_STORE_THIS, 1);
+ if (isn == NULL)
+ return FAIL;
+
+ isn->isn_arg.number = idx;
+ return OK;
+ }
+
+ /*
* If type at "offset" isn't already VAR_STRING then generate ISN_2STRING.
* But only for simple types.
* When "tolerant" is TRUE convert most types to string, e.g. a List.
***************
*** 2458,2463 ****
--- 2477,2483 ----
case ISN_FINISH:
case ISN_FOR:
case ISN_GETITEM:
+ case ISN_GET_OBJ_MEMBER:
case ISN_JUMP:
case ISN_JUMP_IF_ARG_SET:
case ISN_LISTAPPEND:
***************
*** 2477,2483 ****
case ISN_NEWDICT:
case ISN_NEWLIST:
case ISN_NEWPARTIAL:
- case ISN_OBJ_MEMBER:
case ISN_OPANY:
case ISN_OPFLOAT:
case ISN_OPNR:
--- 2497,2502 ----
***************
*** 2495,2502 ****
case ISN_REDIREND:
case ISN_REDIRSTART:
case ISN_RETURN:
- case ISN_RETURN_VOID:
case ISN_RETURN_OBJECT:
case ISN_SHUFFLE:
case ISN_SLICE:
case ISN_SOURCE:
--- 2514,2521 ----
case ISN_REDIREND:
case ISN_REDIRSTART:
case ISN_RETURN:
case ISN_RETURN_OBJECT:
+ case ISN_RETURN_VOID:
case ISN_SHUFFLE:
case ISN_SLICE:
case ISN_SOURCE:
***************
*** 2504,2509 ****
--- 2523,2529 ----
case ISN_STOREINDEX:
case ISN_STORENR:
case ISN_STOREOUTER:
+ case ISN_STORE_THIS:
case ISN_STORERANGE:
case ISN_STOREREG:
case ISN_STOREV:
*** ../vim-9.0.1044/src/proto/vim9instr.pro 2022-12-09 21:41:43.908327271 +0000
--- src/proto/vim9instr.pro 2022-12-10 15:58:24.476458533 +0000
***************
*** 4,10 ****
isn_T *generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type);
isn_T *generate_instr_debug(cctx_T *cctx);
int generate_CONSTRUCT(cctx_T *cctx, class_T *cl);
! int generate_OBJ_MEMBER(cctx_T *cctx, int idx, type_T *type);
int may_generate_2STRING(int offset, int tolerant, cctx_T *cctx);
int generate_add_instr(cctx_T *cctx, vartype_T vartype, type_T *type1, type_T *type2, exprtype_T expr_type);
vartype_T operator_type(type_T *type1, type_T *type2);
--- 4,11 ----
isn_T *generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type);
isn_T *generate_instr_debug(cctx_T *cctx);
int generate_CONSTRUCT(cctx_T *cctx, class_T *cl);
! int generate_GET_OBJ_MEMBER(cctx_T *cctx, int idx, type_T *type);
! int generate_STORE_THIS(cctx_T *cctx, int idx);
int may_generate_2STRING(int offset, int tolerant, cctx_T *cctx);
int generate_add_instr(cctx_T *cctx, vartype_T vartype, type_T *type1, type_T *type2, exprtype_T expr_type);
vartype_T operator_type(type_T *type1, type_T *type2);
*** ../vim-9.0.1044/src/structs.h 2022-12-09 21:41:43.904327284 +0000
--- src/structs.h 2022-12-10 16:15:29.192738979 +0000
***************
*** 1463,1470 ****
* Entry for an object member variable.
*/
typedef struct {
! char_u *om_name; // allocated
type_T *om_type;
} objmember_T;

// "class_T": used for v_class of typval of VAR_CLASS
--- 1463,1471 ----
* Entry for an object member variable.
*/
typedef struct {
! char_u *om_name; // allocated
type_T *om_type;
+ char_u *om_init; // allocated
} objmember_T;

// "class_T": used for v_class of typval of VAR_CLASS
*** ../vim-9.0.1044/src/userfunc.c 2022-12-09 21:41:43.904327284 +0000
--- src/userfunc.c 2022-12-10 17:27:31.237805351 +0000
***************
*** 4047,4052 ****
--- 4047,4058 ----
name = vim_strsave(lv.ll_tv->vval.v_string);
*pp = end;
}
+ else if (lv.ll_tv->v_type == VAR_CLASS
+ && lv.ll_tv->vval.v_class != NULL)
+ {
+ name = vim_strsave(lv.ll_tv->vval.v_class->class_name);
+ *pp = end;
+ }
else if (lv.ll_tv->v_type == VAR_PARTIAL
&& lv.ll_tv->vval.v_partial != NULL)
{
***************
*** 5240,5247 ****
fname = vim_strnsave(name, arg - name);
}
else
fname = trans_function_name(&arg, &is_global, FALSE,
! TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD, NULL, NULL, NULL);
if (fname == NULL)
{
semsg(_(e_invalid_argument_str), name);
--- 5246,5262 ----
fname = vim_strnsave(name, arg - name);
}
else
+ {
+ // First try finding a method in a class, find_func_by_name() will give
+ // an error if the function is not found.
+ ufunc = find_class_func(&arg);
+ if (ufunc != NULL)
+ return ufunc;
+
fname = trans_function_name(&arg, &is_global, FALSE,
! TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DECL,
! NULL, NULL, NULL);
! }
if (fname == NULL)
{
semsg(_(e_invalid_argument_str), name);
*** ../vim-9.0.1044/src/eval.c 2022-12-09 21:41:43.904327284 +0000
--- src/eval.c 2022-12-10 16:53:00.408481439 +0000
***************
*** 1193,1201 ****
var2.v_type = VAR_UNKNOWN;
while (*p == '[' || (*p == '.' && p[1] != '=' && p[1] != '.'))
{
! int r = OK;
!
! if (*p == '.' && lp->ll_tv->v_type != VAR_DICT)
{
if (!quiet)
semsg(_(e_dot_can_only_be_used_on_dictionary_str), name);
--- 1193,1200 ----
var2.v_type = VAR_UNKNOWN;
while (*p == '[' || (*p == '.' && p[1] != '=' && p[1] != '.'))
{
! if (*p == '.' && lp->ll_tv->v_type != VAR_DICT
! && lp->ll_tv->v_type != VAR_CLASS)
{
if (!quiet)
semsg(_(e_dot_can_only_be_used_on_dictionary_str), name);
***************
*** 1203,1209 ****
}
if (lp->ll_tv->v_type != VAR_LIST
&& lp->ll_tv->v_type != VAR_DICT
! && lp->ll_tv->v_type != VAR_BLOB)
{
if (!quiet)
emsg(_(e_can_only_index_list_dictionary_or_blob));
--- 1202,1209 ----
}
if (lp->ll_tv->v_type != VAR_LIST
&& lp->ll_tv->v_type != VAR_DICT
! && lp->ll_tv->v_type != VAR_BLOB
! && lp->ll_tv->v_type != VAR_CLASS)
{
if (!quiet)
emsg(_(e_can_only_index_list_dictionary_or_blob));
***************
*** 1211,1216 ****
--- 1211,1217 ----
}

// A NULL list/blob works like an empty list/blob, allocate one now.
+ int r = OK;
if (lp->ll_tv->v_type == VAR_LIST && lp->ll_tv->vval.v_list == NULL)
r = rettv_list_alloc(lp->ll_tv);
else if (lp->ll_tv->v_type == VAR_BLOB
***************
*** 1463,1469 ****
lp->ll_tv = NULL;
break;
}
! else
{
/*
* Get the number and item for the only or first index of the List.
--- 1464,1470 ----
lp->ll_tv = NULL;
break;
}
! else if (lp->ll_tv->v_type == VAR_LIST)
{
/*
* Get the number and item for the only or first index of the List.
***************
*** 1508,1513 ****
--- 1509,1519 ----

lp->ll_tv = &lp->ll_li->li_tv;
}
+ else // v_type == VAR_CLASS
+ {
+ // TODO: check object members and methods if
+ // "key" points name start, "p" to the end
+ }
}

clear_tv(&var1);
*** ../vim-9.0.1044/src/vim9.h 2022-12-09 21:41:43.908327271 +0000
--- src/vim9.h 2022-12-10 13:59:30.716854085 +0000
***************
*** 33,39 ****
ISN_SOURCE, // source autoload script, isn_arg.number is the script ID
ISN_INSTR, // instructions compiled from expression
ISN_CONSTRUCT, // construct an object, using contstruct_T
! ISN_OBJ_MEMBER, // object member, index is isn_arg.number

// get and set variables
ISN_LOAD, // push local variable isn_arg.number
--- 33,41 ----
ISN_SOURCE, // source autoload script, isn_arg.number is the script ID
ISN_INSTR, // instructions compiled from expression
ISN_CONSTRUCT, // construct an object, using contstruct_T
! ISN_GET_OBJ_MEMBER, // object member, index is isn_arg.number
! ISN_STORE_THIS, // store value in "this" object member, index is
! // isn_arg.number

// get and set variables
ISN_LOAD, // push local variable isn_arg.number
*** ../vim-9.0.1044/src/testdir/test_vim9_class.vim 2022-12-09 21:41:43.908327271 +0000
--- src/testdir/test_vim9_class.vim 2022-12-10 18:29:25.714260061 +0000
***************
*** 129,135 ****

class TextPosition
this.lnum: number
! this.col: number

def ToString(): string
return $'({this.lnum}, {this.col})'
--- 129,135 ----

class TextPosition
this.lnum: number
! this.col: number

def ToString(): string
return $'({this.lnum}, {this.col})'
***************
*** 146,151 ****
--- 146,186 ----
END
v9.CheckScriptSuccess(lines)
enddef
+
+ def Test_class_member_initializer()
+ var lines =<< trim END
+ vim9script
+
+ class TextPosition
+ this.lnum: number = 1
+ this.col: number = 1
+
+ def new(lnum: number)
+ this.lnum = lnum
+ enddef
+ endclass
+
+ var pos = TextPosition.new(3)
+ assert_equal(3, pos.lnum)
+ assert_equal(1, pos.col)
+
+ var instr = execute('disassemble TextPosition.new')
+ assert_match('new\_s*' ..
+ '0 NEW TextPosition size 72\_s*' ..
+ '\d PUSHNR 1\_s*' ..
+ '\d STORE_THIS 0\_s*' ..
+ '\d PUSHNR 1\_s*' ..
+ '\d STORE_THIS 1\_s*' ..
+ 'this.lnum = lnum\_s*' ..
+ '\d LOAD arg\[-1]\_s*' ..
+ '\d PUSHNR 0\_s*' ..
+ '\d LOAD $0\_s*' ..
+ '\d\+ STOREINDEX object\_s*' ..
+ '\d\+ RETURN object.*',
+ instr)
+ END
+ v9.CheckScriptSuccess(lines)
+ enddef


" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
*** ../vim-9.0.1044/src/version.c 2022-12-10 11:17:07.426230828 +0000
--- src/version.c 2022-12-10 18:32:33.466334006 +0000
***************
*** 697,698 ****
--- 697,700 ----
{ /* Add new patch number below this line */
+ /**/
+ 1045,
/**/

--
Microsoft: "Windows NT 4.0 now has the same user-interface as Windows 95"
Windows 95: "Press CTRL-ALT-DEL to reboot"
Windows NT 4.0: "Press CTRL-ALT-DEL to login"

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
Reply all
Reply to author
Forward
0 new messages