mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 9.0.1838: Vim9: Cannot modify class member vars from def function
Problem: Vim9: Cannot modify class member vars from def function Solution: Add support for modifying class member variables from a def function closes: #12995 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
committed by
Christian Brabandt
parent
b147d31489
commit
3775f777a6
@@ -1,7 +1,7 @@
|
|||||||
/* vim9class.c */
|
/* vim9class.c */
|
||||||
int object_index_from_itf_index(class_T *itf, int is_method, int idx, class_T *cl);
|
int object_index_from_itf_index(class_T *itf, int is_method, int idx, class_T *cl);
|
||||||
void ex_class(exarg_T *eap);
|
void ex_class(exarg_T *eap);
|
||||||
type_T *class_member_type(class_T *cl, char_u *name, char_u *name_end, int *member_idx, ocmember_T **m);
|
type_T *class_member_type(class_T *cl, int is_object, char_u *name, char_u *name_end, int *member_idx, ocmember_T **m);
|
||||||
void ex_enum(exarg_T *eap);
|
void ex_enum(exarg_T *eap);
|
||||||
void ex_type(exarg_T *eap);
|
void ex_type(exarg_T *eap);
|
||||||
int class_object_index(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int verbose);
|
int class_object_index(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int verbose);
|
||||||
|
@@ -3783,4 +3783,28 @@ def Test_readonly_member_change_in_def_func()
|
|||||||
v9.CheckScriptFailure(lines, 'E46: Cannot change read-only variable "val"')
|
v9.CheckScriptFailure(lines, 'E46: Cannot change read-only variable "val"')
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
" Test for reading and writing a class member from a def function
|
||||||
|
def Test_modify_class_member_from_def_function()
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class A
|
||||||
|
this.var1: number = 10
|
||||||
|
public static var2 = 20
|
||||||
|
public static var3 = 30
|
||||||
|
static _priv_var4: number = 40
|
||||||
|
endclass
|
||||||
|
def T()
|
||||||
|
assert_equal(20, A.var2)
|
||||||
|
assert_equal(30, A.var3)
|
||||||
|
A.var2 = 50
|
||||||
|
A.var3 = 60
|
||||||
|
assert_equal(50, A.var2)
|
||||||
|
assert_equal(60, A.var3)
|
||||||
|
assert_fails('echo A._priv_var4', 'E1333: Cannot access private member: _priv_var4')
|
||||||
|
enddef
|
||||||
|
T()
|
||||||
|
END
|
||||||
|
v9.CheckScriptSuccess(lines)
|
||||||
|
enddef
|
||||||
|
|
||||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||||
|
@@ -699,6 +699,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 */
|
||||||
|
/**/
|
||||||
|
1838,
|
||||||
/**/
|
/**/
|
||||||
1837,
|
1837,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -33,9 +33,9 @@ parse_member(
|
|||||||
exarg_T *eap,
|
exarg_T *eap,
|
||||||
char_u *line,
|
char_u *line,
|
||||||
char_u *varname,
|
char_u *varname,
|
||||||
int has_public, // TRUE if "public" seen before "varname"
|
int has_public, // TRUE if "public" seen before "varname"
|
||||||
char_u **varname_end,
|
char_u **varname_end,
|
||||||
garray_T *type_list,
|
garray_T *type_list,
|
||||||
type_T **type_ret,
|
type_T **type_ret,
|
||||||
char_u **init_expr)
|
char_u **init_expr)
|
||||||
{
|
{
|
||||||
@@ -119,12 +119,12 @@ parse_member(
|
|||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
add_member(
|
add_member(
|
||||||
garray_T *gap,
|
garray_T *gap,
|
||||||
char_u *varname,
|
char_u *varname,
|
||||||
char_u *varname_end,
|
char_u *varname_end,
|
||||||
int has_public,
|
int has_public,
|
||||||
type_T *type,
|
type_T *type,
|
||||||
char_u *init_expr)
|
char_u *init_expr)
|
||||||
{
|
{
|
||||||
if (ga_grow(gap, 1) == FAIL)
|
if (ga_grow(gap, 1) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@@ -629,8 +629,8 @@ is_valid_constructor(ufunc_T *uf, int is_abstract, int has_static)
|
|||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
update_member_method_lookup_table(
|
update_member_method_lookup_table(
|
||||||
class_T *ifcl,
|
class_T *ifcl,
|
||||||
class_T *cl,
|
class_T *cl,
|
||||||
garray_T *objmethods,
|
garray_T *objmethods,
|
||||||
int pobj_method_offset,
|
int pobj_method_offset,
|
||||||
int is_interface)
|
int is_interface)
|
||||||
@@ -1553,12 +1553,15 @@ cleanup:
|
|||||||
/*
|
/*
|
||||||
* Find member "name" in class "cl", set "member_idx" to the member index and
|
* Find member "name" in class "cl", set "member_idx" to the member index and
|
||||||
* return its type.
|
* return its type.
|
||||||
|
* When "is_object" is TRUE, then look for object members. Otherwise look for
|
||||||
|
* class members.
|
||||||
* When not found "member_idx" is set to -1 and t_any is returned.
|
* When not found "member_idx" is set to -1 and t_any is returned.
|
||||||
* Set *p_m ocmmember_T if not NULL
|
* Set *p_m ocmmember_T if not NULL
|
||||||
*/
|
*/
|
||||||
type_T *
|
type_T *
|
||||||
class_member_type(
|
class_member_type(
|
||||||
class_T *cl,
|
class_T *cl,
|
||||||
|
int is_object,
|
||||||
char_u *name,
|
char_u *name,
|
||||||
char_u *name_end,
|
char_u *name_end,
|
||||||
int *member_idx,
|
int *member_idx,
|
||||||
@@ -1566,10 +1569,14 @@ class_member_type(
|
|||||||
{
|
{
|
||||||
*member_idx = -1; // not found (yet)
|
*member_idx = -1; // not found (yet)
|
||||||
size_t len = name_end - name;
|
size_t len = name_end - name;
|
||||||
|
int member_count = is_object ? cl->class_obj_member_count
|
||||||
|
: cl->class_class_member_count;
|
||||||
|
ocmember_T *members = is_object ? cl->class_obj_members
|
||||||
|
: cl->class_class_members;
|
||||||
|
|
||||||
for (int i = 0; i < cl->class_obj_member_count; ++i)
|
for (int i = 0; i < member_count; ++i)
|
||||||
{
|
{
|
||||||
ocmember_T *m = cl->class_obj_members + i;
|
ocmember_T *m = members + i;
|
||||||
if (STRNCMP(m->ocm_name, name, len) == 0 && m->ocm_name[len] == NUL)
|
if (STRNCMP(m->ocm_name, name, len) == 0 && m->ocm_name[len] == NUL)
|
||||||
{
|
{
|
||||||
*member_idx = i;
|
*member_idx = i;
|
||||||
|
@@ -1868,8 +1868,10 @@ compile_lhs(
|
|||||||
class_T *cl = lhs->lhs_type->tt_class;
|
class_T *cl = lhs->lhs_type->tt_class;
|
||||||
ocmember_T *m;
|
ocmember_T *m;
|
||||||
|
|
||||||
lhs->lhs_member_type = class_member_type(cl, after + 1,
|
lhs->lhs_member_type = class_member_type(cl,
|
||||||
lhs->lhs_end, &lhs->lhs_member_idx, &m);
|
lhs->lhs_type->tt_type == VAR_OBJECT,
|
||||||
|
after + 1, lhs->lhs_end,
|
||||||
|
&lhs->lhs_member_idx, &m);
|
||||||
if (lhs->lhs_member_idx < 0)
|
if (lhs->lhs_member_idx < 0)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
@@ -2091,7 +2093,7 @@ compile_load_lhs_with_index(lhs_T *lhs, char_u *var_start, cctx_T *cctx)
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
class_T *cl = lhs->lhs_type->tt_class;
|
class_T *cl = lhs->lhs_type->tt_class;
|
||||||
type_T *type = class_member_type(cl, dot + 1,
|
type_T *type = class_member_type(cl, TRUE, dot + 1,
|
||||||
lhs->lhs_end, &lhs->lhs_member_idx,
|
lhs->lhs_end, &lhs->lhs_member_idx,
|
||||||
NULL);
|
NULL);
|
||||||
if (lhs->lhs_member_idx < 0)
|
if (lhs->lhs_member_idx < 0)
|
||||||
|
@@ -2144,7 +2144,7 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx)
|
|||||||
// Stack contains:
|
// Stack contains:
|
||||||
// -3 value to be stored
|
// -3 value to be stored
|
||||||
// -2 index
|
// -2 index
|
||||||
// -1 dict, list, blob or object
|
// -1 dict, list, blob, object or class
|
||||||
tv = STACK_TV_BOT(-3);
|
tv = STACK_TV_BOT(-3);
|
||||||
SOURCING_LNUM = iptr->isn_lnum;
|
SOURCING_LNUM = iptr->isn_lnum;
|
||||||
|
|
||||||
@@ -2306,14 +2306,25 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx)
|
|||||||
}
|
}
|
||||||
else if (dest_type == VAR_CLASS || dest_type == VAR_OBJECT)
|
else if (dest_type == VAR_CLASS || dest_type == VAR_OBJECT)
|
||||||
{
|
{
|
||||||
object_T *obj = tv_dest->vval.v_object;
|
typval_T *otv;
|
||||||
typval_T *otv = (typval_T *)(obj + 1);
|
|
||||||
|
|
||||||
class_T *itf = iptr->isn_arg.storeindex.si_class;
|
if (dest_type == VAR_OBJECT)
|
||||||
if (itf != NULL)
|
{
|
||||||
// convert interface member index to class member index
|
object_T *obj = tv_dest->vval.v_object;
|
||||||
lidx = object_index_from_itf_index(itf, FALSE,
|
|
||||||
lidx, obj->obj_class);
|
otv = (typval_T *)(obj + 1);
|
||||||
|
class_T *itf = iptr->isn_arg.storeindex.si_class;
|
||||||
|
if (itf != NULL)
|
||||||
|
// convert interface member index to class member index
|
||||||
|
lidx = object_index_from_itf_index(itf, FALSE,
|
||||||
|
lidx, obj->obj_class);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// VAR_CLASS
|
||||||
|
class_T *class = tv_dest->vval.v_class;
|
||||||
|
otv = class->class_members_tv;
|
||||||
|
}
|
||||||
|
|
||||||
clear_tv(&otv[lidx]);
|
clear_tv(&otv[lidx]);
|
||||||
otv[lidx] = *tv;
|
otv[lidx] = *tv;
|
||||||
|
@@ -438,7 +438,14 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type)
|
|||||||
{
|
{
|
||||||
ocmember_T *m = &cl->class_class_members[idx];
|
ocmember_T *m = &cl->class_class_members[idx];
|
||||||
if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
|
if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
|
||||||
|
{
|
||||||
|
if (*name == '_' && !inside_class(cctx, cl))
|
||||||
|
{
|
||||||
|
semsg(_(e_cannot_access_private_member_str), m->ocm_name);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (idx < cl->class_class_member_count)
|
if (idx < cl->class_class_member_count)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user