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:
parent
75b277d35c
commit
b852305dbf
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -704,6 +704,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
2002,
|
||||
/**/
|
||||
2001,
|
||||
/**/
|
||||
|
428
src/vim9class.c
428
src/vim9class.c
@ -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".
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user