0
0
mirror of https://github.com/vim/vim.git synced 2025-07-04 23:07:33 -04:00

patch 9.0.2002: Vim9: need cleanup of class related interface code

Problem:  Vim9: need cleanup of class related interface code
Solution: Remove the unused class variable and class method related code
          for interfaces.

Remove unused class variable and class method related code for
interfaces.

Refactor the code.

Optimize the object/class member double lookup in compile_lhs().

Change unused global functions to static functions.

closes: #13302

Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
Yegappan Lakshmanan 2023-10-08 19:07:39 +02:00 committed by Christian Brabandt
parent 75b277d35c
commit b852305dbf
No known key found for this signature in database
GPG Key ID: F3F92DA383FDDE09
6 changed files with 266 additions and 256 deletions

View File

@ -10,11 +10,8 @@ ufunc_T *find_class_func(char_u **arg);
int class_member_idx(class_T *cl, char_u *name, size_t namelen);
ocmember_T *class_member_lookup(class_T *cl, char_u *name, size_t namelen, int *idx);
int class_method_idx(class_T *cl, char_u *name, size_t namelen);
ufunc_T *class_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx);
int object_member_idx(class_T *cl, char_u *name, size_t namelen);
ocmember_T *object_member_lookup(class_T *cl, char_u *name, size_t namelen, int *idx);
int object_method_idx(class_T *cl, char_u *name, size_t namelen);
ufunc_T *object_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx);
ocmember_T *member_lookup(class_T *cl, vartype_T v_type, char_u *name, size_t namelen, int *idx);
void emsg_var_cl_define(char *msg, char_u *name, size_t len, class_T *cl);
ufunc_T *method_lookup(class_T *cl, vartype_T v_type, char_u *name, size_t namelen, int *idx);
@ -26,7 +23,6 @@ void class_unref(class_T *cl);
int class_free_nonref(int copyID);
int set_ref_in_classes(int copyID);
void object_created(object_T *obj);
void object_cleared(object_T *obj);
int object_free_nonref(int copyID);
void method_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len);
void member_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len);

View File

@ -975,6 +975,28 @@ def Test_class_new_with_object_member()
Check()
END
v9.CheckSourceSuccess(lines)
# Try using "this." argument in a class method
lines =<< trim END
vim9script
class A
this.val = 10
static def Foo(this.val: number)
enddef
endclass
END
v9.CheckSourceFailure(lines, 'E1390: Cannot use an object variable "this.val" except with the "new" method', 4)
# Try using "this." argument in an object method
lines =<< trim END
vim9script
class A
this.val = 10
def Foo(this.val: number)
enddef
endclass
END
v9.CheckSourceFailure(lines, 'E1390: Cannot use an object variable "this.val" except with the "new" method', 4)
enddef
def Test_class_object_member_inits()
@ -1722,7 +1744,7 @@ def Test_class_member()
var a = A.new()
var v = a.bar
END
v9.CheckSourceFailure(lines, 'E1326: Variable not found on object "A": bar', 5)
v9.CheckSourceFailure(lines, 'E1337: Class variable "bar" not found in class "A"', 5)
enddef
" These messages should show the defining class of the variable (base class),
@ -4255,7 +4277,7 @@ def Test_private_object_method()
var a = A.new()
a._Foo()
END
v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()', 9)
v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo', 9)
# Try calling a private method using an object (from a def function)
lines =<< trim END
@ -4468,7 +4490,7 @@ def Test_private_object_method()
var c = C.new()
assert_equal(1234, c._Foo())
END
v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()', 16)
v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo', 16)
# Using "_" prefix in a method name should fail outside of a class
lines =<< trim END
@ -4494,7 +4516,7 @@ def Test_private_class_method()
endclass
A._Foo()
END
v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()', 8)
v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo', 8)
# Try calling a class private method (from a def function)
lines =<< trim END
@ -5122,7 +5144,7 @@ def Test_class_variable_access_using_object()
var a = A.new()
echo a.svar2
END
v9.CheckSourceFailure(lines, 'E1375: Class variable "svar2" accessible only using class "A"', 8)
v9.CheckSourceFailure(lines, 'E1337: Class variable "svar2" not found in class "A"', 8)
# Cannot write to a class variable using an object in script context
lines =<< trim END
@ -5597,7 +5619,7 @@ def Test_class_variable()
var a = A.new()
var i = a.val
END
v9.CheckSourceFailure(lines, 'E1375: Class variable "val" accessible only using class "A"', 7)
v9.CheckSourceFailure(lines, 'E1337: Class variable "val" not found in class "A"', 7)
# Modifying a class variable using an object at function level
lines =<< trim END
@ -5969,6 +5991,18 @@ def Test_extend_interface()
END
v9.CheckSourceSuccess(lines)
# extending empty interface
lines =<< trim END
vim9script
interface A
endinterface
interface B extends A
endinterface
class C implements B
endclass
END
v9.CheckSourceSuccess(lines)
lines =<< trim END
vim9script
interface A
@ -6567,6 +6601,17 @@ def Test_reserved_varname()
o.F()
END
v9.CheckSourceFailure(lines, $'E1034: Cannot use reserved name {kword}', 3)
# class variable name
if kword != 'this'
lines =<< trim eval END
vim9script
class C
public static {kword}: list<number> = [1, 2, 3]
endclass
END
v9.CheckSourceFailure(lines, $'E1034: Cannot use reserved name {kword}', 3)
endif
endfor
enddef

View File

@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
2002,
/**/
2001,
/**/

View File

@ -555,7 +555,6 @@ validate_abstract_class_methods(
intf_variable_present(
char_u *intf_class_name,
ocmember_T *if_var,
int is_class_var,
ocmember_T *cl_mt,
int cl_member_count,
class_T *extends_cl)
@ -600,15 +599,10 @@ intf_variable_present(
if (!variable_present && extends_cl != NULL)
{
int ext_cl_count = is_class_var
? extends_cl->class_class_member_count
: extends_cl->class_obj_member_count;
ocmember_T *ext_cl_mt = is_class_var
? extends_cl->class_class_members
: extends_cl->class_obj_members;
int ext_cl_count = extends_cl->class_obj_member_count;
ocmember_T *ext_cl_mt = extends_cl->class_obj_members;
return intf_variable_present(intf_class_name, if_var,
is_class_var, ext_cl_mt,
ext_cl_count,
ext_cl_mt, ext_cl_count,
extends_cl->class_extends);
}
@ -616,43 +610,32 @@ intf_variable_present(
}
/*
* Check the variables of the interface class "ifcl" match the class variables
* ("classmembers_gap") and object variables ("objmembers_gap") of a class.
* Returns TRUE if the class and object variables names are valid.
* Check the variables of the interface class "ifcl" match object variables
* ("objmembers_gap") of a class.
* Returns TRUE if the object variables names are valid.
*/
static int
validate_interface_variables(
char_u *intf_class_name,
class_T *ifcl,
garray_T *classmembers_gap,
garray_T *objmembers_gap,
class_T *extends_cl)
{
for (int loop = 1; loop <= 2; ++loop)
int if_count = ifcl->class_obj_member_count;
if (if_count == 0)
return TRUE;
ocmember_T *if_ms = ifcl->class_obj_members;
ocmember_T *cl_ms = (ocmember_T *)(objmembers_gap->ga_data);
int cl_count = objmembers_gap->ga_len;
for (int if_i = 0; if_i < if_count; ++if_i)
{
// loop == 1: check class variables
// loop == 2: check object variables
int is_class_var = (loop == 1);
int if_count = is_class_var ? ifcl->class_class_member_count
: ifcl->class_obj_member_count;
if (if_count == 0)
continue;
ocmember_T *if_ms = is_class_var ? ifcl->class_class_members
: ifcl->class_obj_members;
ocmember_T *cl_ms = (ocmember_T *)(is_class_var
? classmembers_gap->ga_data
: objmembers_gap->ga_data);
int cl_count = is_class_var ? classmembers_gap->ga_len
: objmembers_gap->ga_len;
for (int if_i = 0; if_i < if_count; ++if_i)
if (!intf_variable_present(intf_class_name, &if_ms[if_i], cl_ms,
cl_count, extends_cl))
{
if (!intf_variable_present(intf_class_name, &if_ms[if_i],
is_class_var, cl_ms, cl_count, extends_cl))
{
semsg(_(e_variable_str_of_interface_str_not_implemented),
if_ms[if_i].ocm_name, intf_class_name);
return FALSE;
}
semsg(_(e_variable_str_of_interface_str_not_implemented),
if_ms[if_i].ocm_name, intf_class_name);
return FALSE;
}
}
@ -685,7 +668,6 @@ intf_method_type_matches(ufunc_T *if_method, ufunc_T *cl_method)
static int
intf_method_present(
ufunc_T *if_ufunc,
int is_class_method,
ufunc_T **cl_fp,
int cl_count,
class_T *extends_cl)
@ -707,15 +689,10 @@ intf_method_present(
if (!method_present && extends_cl != NULL)
{
ufunc_T **ext_cl_fp = (ufunc_T **)(is_class_method
? extends_cl->class_class_functions
: extends_cl->class_obj_methods);
int ext_cl_count = is_class_method
? extends_cl->class_class_function_count
: extends_cl->class_obj_method_count;
return intf_method_present(if_ufunc, is_class_method, ext_cl_fp,
ext_cl_count,
extends_cl->class_extends);
ufunc_T **ext_cl_fp = (ufunc_T **)(extends_cl->class_obj_methods);
int ext_cl_count = extends_cl->class_obj_method_count;
return intf_method_present(if_ufunc, ext_cl_fp, ext_cl_count,
extends_cl->class_extends);
}
return method_present;
@ -733,37 +710,25 @@ intf_method_present(
validate_interface_methods(
char_u *intf_class_name,
class_T *ifcl,
garray_T *classfunctions_gap,
garray_T *objmethods_gap,
class_T *extends_cl)
{
for (int loop = 1; loop <= 2; ++loop)
{
// loop == 1: check class methods
// loop == 2: check object methods
int is_class_method = (loop == 1);
int if_count = is_class_method ? ifcl->class_class_function_count
: ifcl->class_obj_method_count;
if (if_count == 0)
continue;
ufunc_T **if_fp = is_class_method ? ifcl->class_class_functions
: ifcl->class_obj_methods;
ufunc_T **cl_fp = (ufunc_T **)(is_class_method
? classfunctions_gap->ga_data
: objmethods_gap->ga_data);
int cl_count = is_class_method ? classfunctions_gap->ga_len
: objmethods_gap->ga_len;
for (int if_i = 0; if_i < if_count; ++if_i)
{
char_u *if_name = if_fp[if_i]->uf_name;
int if_count = ifcl->class_obj_method_count;
if (if_count == 0)
return TRUE;
if (!intf_method_present(if_fp[if_i], is_class_method, cl_fp,
cl_count, extends_cl))
{
semsg(_(e_method_str_of_interface_str_not_implemented),
if_name, intf_class_name);
return FALSE;
}
ufunc_T **if_fp = ifcl->class_obj_methods;
ufunc_T **cl_fp = (ufunc_T **)(objmethods_gap->ga_data);
int cl_count = objmethods_gap->ga_len;
for (int if_i = 0; if_i < if_count; ++if_i)
{
char_u *if_name = if_fp[if_i]->uf_name;
if (!intf_method_present(if_fp[if_i], cl_fp, cl_count, extends_cl))
{
semsg(_(e_method_str_of_interface_str_not_implemented),
if_name, intf_class_name);
return FALSE;
}
}
@ -781,8 +746,6 @@ validate_interface_methods(
validate_implements_classes(
garray_T *impl_gap,
class_T **intf_classes,
garray_T *classfunctions_gap,
garray_T *classmembers_gap,
garray_T *objmethods_gap,
garray_T *objmembers_gap,
class_T *extends_cl)
@ -816,15 +779,14 @@ validate_implements_classes(
++ifcl->class_refcount;
// check the variables of the interface match the members of the class
success = validate_interface_variables(impl, ifcl, classmembers_gap,
objmembers_gap, extends_cl);
success = validate_interface_variables(impl, ifcl, objmembers_gap,
extends_cl);
// check the functions/methods of the interface match the
// functions/methods of the class
if (success)
success = validate_interface_methods(impl, ifcl,
classfunctions_gap, objmethods_gap,
extends_cl);
success = validate_interface_methods(impl, ifcl, objmethods_gap,
extends_cl);
clear_tv(&tv);
}
@ -1873,9 +1835,7 @@ early_ret:
intf_classes = ALLOC_CLEAR_MULT(class_T *, ga_impl.ga_len);
success = validate_implements_classes(&ga_impl, intf_classes,
&classfunctions, &classmembers,
&objmethods, &objmembers,
extends_cl);
&objmethods, &objmembers, extends_cl);
}
// Check no function argument name is used as a class member.
@ -2172,18 +2132,90 @@ get_member_tv(
return FAIL;
}
// The object only contains a pointer to the class, the member
// values array follows right after that.
object_T *obj = rettv->vval.v_object;
if (is_object)
{
// The object only contains a pointer to the class, the member values
// array follows right after that.
object_T *obj = rettv->vval.v_object;
typval_T *tv = (typval_T *)(obj + 1) + m_idx;
copy_tv(tv, rettv);
object_unref(obj);
}
else
{
copy_tv(&cl->class_members_tv[m_idx], rettv);
class_unref(cl);
}
object_unref(obj);
return OK;
}
/*
* Call an object or class method "name" in class "cl". The method return
* value is returned in "rettv".
*/
static int
call_oc_method(
class_T *cl,
char_u *name,
size_t len,
char_u *name_end,
evalarg_T *evalarg,
char_u **arg,
typval_T *rettv)
{
ufunc_T *fp;
typval_T argvars[MAX_FUNC_ARGS + 1];
int argcount = 0;
fp = method_lookup(cl, rettv->v_type, name, len, NULL);
if (fp == NULL)
{
method_not_found_msg(cl, rettv->v_type, name, len);
return FAIL;
}
if (*fp->uf_name == '_')
{
// Cannot access a private method outside of a class
semsg(_(e_cannot_access_private_method_str), fp->uf_name);
return FAIL;
}
char_u *argp = name_end;
int ret = get_func_arguments(&argp, evalarg, 0, argvars, &argcount);
if (ret == FAIL)
return FAIL;
funcexe_T funcexe;
CLEAR_FIELD(funcexe);
funcexe.fe_evaluate = TRUE;
if (rettv->v_type == VAR_OBJECT)
{
funcexe.fe_object = rettv->vval.v_object;
++funcexe.fe_object->obj_refcount;
}
// Clear the class or object after calling the function, in
// case the refcount is one.
typval_T tv_tofree = *rettv;
rettv->v_type = VAR_UNKNOWN;
// Call the user function. Result goes into rettv;
int error = call_user_func_check(fp, argcount, argvars, rettv, &funcexe,
NULL);
// Clear the previous rettv and the arguments.
clear_tv(&tv_tofree);
for (int idx = 0; idx < argcount; ++idx)
clear_tv(&argvars[idx]);
if (error != FCERR_NONE)
{
user_func_error(error, printable_func_name(fp), funcexe.fe_found_var);
return FAIL;
}
*arg = argp;
return OK;
}
@ -2242,104 +2274,22 @@ class_object_index(
}
if (*name_end == '(')
{
ufunc_T *fp;
// Invoke the class or object method
return call_oc_method(cl, name, len, name_end, evalarg, arg, rettv);
fp = method_lookup(cl, rettv->v_type, name, len, NULL);
if (fp == NULL)
{
method_not_found_msg(cl, rettv->v_type, name, len);
return FAIL;
}
typval_T argvars[MAX_FUNC_ARGS + 1];
int argcount = 0;
if (*fp->uf_name == '_')
{
// Cannot access a private method outside of a class
semsg(_(e_cannot_access_private_method_str), name);
return FAIL;
}
char_u *argp = name_end;
int ret = get_func_arguments(&argp, evalarg, 0,
argvars, &argcount);
if (ret == FAIL)
return FAIL;
funcexe_T funcexe;
CLEAR_FIELD(funcexe);
funcexe.fe_evaluate = TRUE;
if (rettv->v_type == VAR_OBJECT)
{
funcexe.fe_object = rettv->vval.v_object;
++funcexe.fe_object->obj_refcount;
}
// Clear the class or object after calling the function, in
// case the refcount is one.
typval_T tv_tofree = *rettv;
rettv->v_type = VAR_UNKNOWN;
// Call the user function. Result goes into rettv;
int error = call_user_func_check(fp, argcount, argvars,
rettv, &funcexe, NULL);
// Clear the previous rettv and the arguments.
clear_tv(&tv_tofree);
for (int idx = 0; idx < argcount; ++idx)
clear_tv(&argvars[idx]);
if (error != FCERR_NONE)
{
user_func_error(error, printable_func_name(fp),
funcexe.fe_found_var);
return FAIL;
}
*arg = argp;
return OK;
}
else if (rettv->v_type == VAR_OBJECT)
else if (rettv->v_type == VAR_OBJECT || rettv->v_type == VAR_CLASS)
{
// Search in the object member variable table and the class member
// variable table.
if (get_member_tv(cl, TRUE, name, len, rettv) == OK)
int is_object = rettv->v_type == VAR_OBJECT;
if (get_member_tv(cl, is_object, name, len, rettv) == OK)
{
*arg = name_end;
return OK;
}
if (did_emsg == did_emsg_save)
member_not_found_msg(cl, VAR_OBJECT, name, len);
}
else if (rettv->v_type == VAR_CLASS)
{
int m_idx;
// class member
ocmember_T *m = class_member_lookup(cl, name, len, &m_idx);
if (m == NULL)
{
member_not_found_msg(cl, VAR_CLASS, name, len);
return FAIL;
}
if (*name == '_')
{
emsg_var_cl_define(e_cannot_access_private_variable_str,
m->ocm_name, 0, cl);
return FAIL;
}
typval_T *tv = &cl->class_members_tv[m_idx];
copy_tv(tv, rettv);
class_unref(cl);
*arg = name_end;
return OK;
member_not_found_msg(cl, is_object, name, len);
}
return FAIL;
@ -2432,24 +2382,12 @@ class_member_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
return ret_m;
}
/*
* Returns the index of class method "name" in the class "cl".
* Returns -1, if the method is not found.
*/
int
class_method_idx(class_T *cl, char_u *name, size_t namelen)
{
int idx;
class_method_lookup(cl, name, namelen, &idx);
return idx;
}
/*
* Returns a pointer to the class method "name" in class "cl".
* Returns NULL if the method is not found.
* The method index is set in "idx".
*/
ufunc_T *
static ufunc_T *
class_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
{
ufunc_T *ret_fp = NULL;
@ -2470,12 +2408,24 @@ class_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
return ret_fp;
}
/*
* Returns the index of class method "name" in the class "cl".
* Returns -1, if the method is not found.
*/
int
class_method_idx(class_T *cl, char_u *name, size_t namelen)
{
int idx;
class_method_lookup(cl, name, namelen, &idx);
return idx;
}
/*
* Returns the index of object member variable "name" in the class "cl".
* Returns -1, if the variable is not found.
* If "namelen" is zero, then it is assumed that "name" is NUL terminated.
*/
int
static int
object_member_idx(class_T *cl, char_u *name, size_t namelen)
{
int idx;
@ -2518,24 +2468,12 @@ object_member_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
return ret_m;
}
/*
* Returns the index of object method "name" in the class "cl".
* Returns -1, if the method is not found.
*/
int
object_method_idx(class_T *cl, char_u *name, size_t namelen)
{
int idx;
object_method_lookup(cl, name, namelen, &idx);
return idx;
}
/*
* Returns a pointer to the object method "name" in class "cl".
* Returns NULL if the method is not found.
* The object method index is set in "idx".
*/
ufunc_T *
static ufunc_T *
object_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
{
ufunc_T *ret_fp = NULL;
@ -2558,6 +2496,18 @@ object_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
return ret_fp;
}
/*
* Returns the index of object method "name" in the class "cl".
* Returns -1, if the method is not found.
*/
int
object_method_idx(class_T *cl, char_u *name, size_t namelen)
{
int idx;
object_method_lookup(cl, name, namelen, &idx);
return idx;
}
/*
* Lookup a class or object member variable by name. If v_type is VAR_CLASS,
* then lookup a class member variable and if it is VAR_OBJECT, then lookup a
@ -2681,42 +2631,6 @@ copy_object(typval_T *from, typval_T *to)
}
}
/*
* Free an object.
*/
static void
object_clear(object_T *obj)
{
// Avoid a recursive call, it can happen if "obj" has a circular reference.
obj->obj_refcount = INT_MAX;
class_T *cl = obj->obj_class;
if (!cl)
return;
// the member values are just after the object structure
typval_T *tv = (typval_T *)(obj + 1);
for (int i = 0; i < cl->class_obj_member_count; ++i)
clear_tv(tv + i);
// Remove from the list headed by "first_object".
object_cleared(obj);
vim_free(obj);
class_unref(cl);
}
/*
* Unreference an object.
*/
void
object_unref(object_T *obj)
{
if (obj != NULL && --obj->obj_refcount <= 0)
object_clear(obj);
}
/*
* Make a copy of a class.
*/
@ -2866,7 +2780,7 @@ static object_T *next_nonref_obj = NULL;
* Call this function when an object has been cleared and is about to be freed.
* It is removed from the list headed by "first_object".
*/
void
static void
object_cleared(object_T *obj)
{
if (obj->obj_next_used != NULL)
@ -2881,6 +2795,42 @@ object_cleared(object_T *obj)
next_nonref_obj = obj->obj_next_used;
}
/*
* Free an object.
*/
static void
object_clear(object_T *obj)
{
// Avoid a recursive call, it can happen if "obj" has a circular reference.
obj->obj_refcount = INT_MAX;
class_T *cl = obj->obj_class;
if (!cl)
return;
// the member values are just after the object structure
typval_T *tv = (typval_T *)(obj + 1);
for (int i = 0; i < cl->class_obj_member_count; ++i)
clear_tv(tv + i);
// Remove from the list headed by "first_object".
object_cleared(obj);
vim_free(obj);
class_unref(cl);
}
/*
* Unreference an object.
*/
void
object_unref(object_T *obj)
{
if (obj != NULL && --obj->obj_refcount <= 0)
object_clear(obj);
}
/*
* Go through the list of all objects and free items without "copyID".
*/

View File

@ -254,7 +254,7 @@ compile_lock_unlock(
{
// Push the class of the bare class variable name
name = cl->class_name;
len = STRLEN(name);
len = (int)STRLEN(name);
#ifdef LOG_LOCKVAR
ch_log(NULL, "LKVAR: ... cctx_class_member: name %s",
name);

View File

@ -2011,16 +2011,33 @@ compile_lhs(
// for an object or class member get the type of the member
class_T *cl = lhs->lhs_type->tt_class;
int is_object = lhs->lhs_type->tt_type == VAR_OBJECT;
char_u *name = var_start + lhs->lhs_varlen + 1;
size_t namelen = lhs->lhs_end - var_start - lhs->lhs_varlen - 1;
if (!lhs_class_member_modifiable(lhs, var_start, cctx))
ocmember_T *m = member_lookup(cl, lhs->lhs_type->tt_type,
name, namelen, &lhs->lhs_member_idx);
if (m == NULL)
{
member_not_found_msg(cl, lhs->lhs_type->tt_type, name, namelen);
return FAIL;
}
lhs->lhs_member_type = class_member_type(cl,
is_object,
after + 1, lhs->lhs_end,
&lhs->lhs_member_idx);
if (lhs->lhs_member_idx < 0)
// If it is private member variable, then accessing it outside the
// class is not allowed.
// If it is a read only class variable, then it can be modified
// only inside the class where it is defined.
if ((m->ocm_access != VIM_ACCESS_ALL) &&
((is_object && !inside_class(cctx, cl))
|| (!is_object && cctx->ctx_ufunc->uf_class != cl)))
{
char *msg = (m->ocm_access == VIM_ACCESS_PRIVATE)
? e_cannot_access_private_variable_str
: e_variable_is_not_writable_str;
emsg_var_cl_define(msg, m->ocm_name, 0, cl);
return FAIL;
}
lhs->lhs_member_type = m->ocm_type;
}
else
{