mirror of
https://github.com/vim/vim.git
synced 2025-07-04 23:07:33 -04:00
patch 9.0.1890: Vim9: lookup code for class/object repaeated
Problem: Vim9: lookup code for class/object repaeated Solution: Refactor and make use of lookup functions closes: #13067 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
parent
0661033075
commit
f36bbcd402
94
src/eval.c
94
src/eval.c
@ -1540,71 +1540,57 @@ get_lval(
|
||||
// round 1: class functions (skipped for an object)
|
||||
// round 2: object methods
|
||||
for (int round = v_type == VAR_OBJECT ? 2 : 1;
|
||||
round <= 2; ++round)
|
||||
round <= 2; ++round)
|
||||
{
|
||||
int count = round == 1
|
||||
? cl->class_class_function_count
|
||||
: cl->class_obj_method_count;
|
||||
ufunc_T **funcs = round == 1
|
||||
? cl->class_class_functions
|
||||
: cl->class_obj_methods;
|
||||
for (int i = 0; i < count; ++i)
|
||||
int m_idx;
|
||||
ufunc_T *fp;
|
||||
|
||||
fp = method_lookup(cl,
|
||||
round == 1 ? VAR_CLASS : VAR_OBJECT,
|
||||
key, p - key, &m_idx);
|
||||
if (fp != NULL)
|
||||
{
|
||||
ufunc_T *fp = funcs[i];
|
||||
char_u *ufname = (char_u *)fp->uf_name;
|
||||
if (STRNCMP(ufname, key, p - key) == 0
|
||||
&& ufname[p - key] == NUL)
|
||||
{
|
||||
lp->ll_ufunc = fp;
|
||||
lp->ll_valtype = fp->uf_func_type;
|
||||
round = 3;
|
||||
break;
|
||||
}
|
||||
lp->ll_ufunc = fp;
|
||||
lp->ll_valtype = fp->uf_func_type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lp->ll_valtype == NULL)
|
||||
{
|
||||
int count = v_type == VAR_OBJECT
|
||||
? cl->class_obj_member_count
|
||||
: cl->class_class_member_count;
|
||||
ocmember_T *members = v_type == VAR_OBJECT
|
||||
? cl->class_obj_members
|
||||
: cl->class_class_members;
|
||||
for (int i = 0; i < count; ++i)
|
||||
int m_idx;
|
||||
ocmember_T *om;
|
||||
|
||||
om = member_lookup(cl, v_type, key, p - key, &m_idx);
|
||||
if (om != NULL)
|
||||
{
|
||||
ocmember_T *om = members + i;
|
||||
if (STRNCMP(om->ocm_name, key, p - key) == 0
|
||||
&& om->ocm_name[p - key] == NUL)
|
||||
switch (om->ocm_access)
|
||||
{
|
||||
switch (om->ocm_access)
|
||||
{
|
||||
case VIM_ACCESS_PRIVATE:
|
||||
semsg(_(e_cannot_access_private_member_str),
|
||||
om->ocm_name);
|
||||
return NULL;
|
||||
case VIM_ACCESS_READ:
|
||||
if ((flags & GLV_READ_ONLY) == 0)
|
||||
{
|
||||
semsg(_(e_member_is_not_writable_str),
|
||||
om->ocm_name);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case VIM_ACCESS_ALL:
|
||||
break;
|
||||
}
|
||||
|
||||
lp->ll_valtype = om->ocm_type;
|
||||
|
||||
if (v_type == VAR_OBJECT)
|
||||
lp->ll_tv = ((typval_T *)(
|
||||
lp->ll_tv->vval.v_object + 1)) + i;
|
||||
else
|
||||
lp->ll_tv = &cl->class_members_tv[i];
|
||||
break;
|
||||
case VIM_ACCESS_PRIVATE:
|
||||
semsg(_(e_cannot_access_private_member_str),
|
||||
om->ocm_name);
|
||||
return NULL;
|
||||
case VIM_ACCESS_READ:
|
||||
if ((flags & GLV_READ_ONLY) == 0)
|
||||
{
|
||||
semsg(_(e_member_is_not_writable_str),
|
||||
om->ocm_name);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case VIM_ACCESS_ALL:
|
||||
break;
|
||||
}
|
||||
|
||||
lp->ll_valtype = om->ocm_type;
|
||||
|
||||
if (v_type == VAR_OBJECT)
|
||||
lp->ll_tv = ((typval_T *)(
|
||||
lp->ll_tv->vval.v_object + 1)) + m_idx;
|
||||
else
|
||||
lp->ll_tv = &cl->class_members_tv[m_idx];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,16 @@ 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);
|
||||
int class_member_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx);
|
||||
int class_method_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx);
|
||||
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);
|
||||
ufunc_T *method_lookup(class_T *cl, vartype_T v_type, char_u *name, size_t namelen, int *idx);
|
||||
int inside_class(cctx_T *cctx_arg, class_T *cl);
|
||||
void copy_object(typval_T *from, typval_T *to);
|
||||
void object_unref(object_T *obj);
|
||||
|
@ -4,6 +4,8 @@ int arg_exists(char_u *name, size_t len, int *idxp, type_T **type, int *gen_load
|
||||
void update_script_var_block_id(char_u *name, int block_id);
|
||||
int script_is_vim9(void);
|
||||
int script_var_exists(char_u *name, size_t len, cctx_T *cctx, cstack_T *cstack);
|
||||
int cctx_class_method_idx(cctx_T *cctx, char_u *name, size_t len, class_T **cl_ret);
|
||||
int cctx_class_member_idx(cctx_T *cctx, char_u *name, size_t len, class_T **cl_ret);
|
||||
int check_defined(char_u *p, size_t len, cctx_T *cctx, cstack_T *cstack, int is_arg);
|
||||
int need_type_where(type_T *actual, type_T *expected, int number_ok, int offset, where_T where, cctx_T *cctx, int silent, int actual_is_const);
|
||||
int need_type(type_T *actual, type_T *expected, int number_ok, int offset, int arg_idx, cctx_T *cctx, int silent, int actual_is_const);
|
||||
|
@ -699,6 +699,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1890,
|
||||
/**/
|
||||
1889,
|
||||
/**/
|
||||
|
456
src/vim9class.c
456
src/vim9class.c
@ -269,14 +269,10 @@ object_index_from_itf_index(class_T *itf, int is_method, int idx, class_T *cl,
|
||||
{
|
||||
// TODO: Need a table for fast lookup?
|
||||
char_u *name = itf->class_class_members[idx].ocm_name;
|
||||
for (int i = 0; i < i2c->i2c_class->class_class_member_count; ++i)
|
||||
{
|
||||
ocmember_T *m = &i2c->i2c_class->class_class_members[i];
|
||||
if (STRCMP(name, m->ocm_name) == 0)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
int m_idx = class_member_idx(i2c->i2c_class, name, 0);
|
||||
if (m_idx >= 0)
|
||||
return m_idx;
|
||||
|
||||
siemsg("class %s, interface %s, static %s not found",
|
||||
cl->class_name, itf->class_name, name);
|
||||
return 0;
|
||||
@ -1751,27 +1747,23 @@ class_member_type(
|
||||
int *member_idx,
|
||||
ocmember_T **p_m)
|
||||
{
|
||||
*member_idx = -1; // not found (yet)
|
||||
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;
|
||||
ocmember_T *m;
|
||||
|
||||
for (int i = 0; i < member_count; ++i)
|
||||
*member_idx = -1; // not found (yet)
|
||||
|
||||
m = member_lookup(cl, is_object ? VAR_OBJECT : VAR_CLASS, name, len,
|
||||
member_idx);
|
||||
if (m == NULL)
|
||||
{
|
||||
ocmember_T *m = members + i;
|
||||
if (STRNCMP(m->ocm_name, name, len) == 0 && m->ocm_name[len] == NUL)
|
||||
{
|
||||
*member_idx = i;
|
||||
if (p_m != NULL)
|
||||
*p_m = m;
|
||||
return m->ocm_type;
|
||||
}
|
||||
semsg(_(e_unknown_variable_str), name);
|
||||
return &t_any;
|
||||
}
|
||||
|
||||
semsg(_(e_unknown_variable_str), name);
|
||||
return &t_any;
|
||||
if (p_m != NULL)
|
||||
*p_m = m;
|
||||
|
||||
return m->ocm_type;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1806,41 +1798,34 @@ get_member_tv(
|
||||
size_t namelen,
|
||||
typval_T *rettv)
|
||||
{
|
||||
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;
|
||||
ocmember_T *m;
|
||||
int m_idx;
|
||||
|
||||
for (int i = 0; i < member_count; ++i)
|
||||
m = member_lookup(cl, is_object ? VAR_OBJECT : VAR_CLASS, name, namelen,
|
||||
&m_idx);
|
||||
if (m == NULL)
|
||||
return FAIL;
|
||||
|
||||
if (*name == '_')
|
||||
{
|
||||
ocmember_T *m = &members[i];
|
||||
if (STRNCMP(name, m->ocm_name, namelen) == 0
|
||||
&& m->ocm_name[namelen] == NUL)
|
||||
{
|
||||
if (*name == '_')
|
||||
{
|
||||
semsg(_(e_cannot_access_private_member_str), m->ocm_name);
|
||||
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)
|
||||
{
|
||||
typval_T *tv = (typval_T *)(obj + 1) + i;
|
||||
copy_tv(tv, rettv);
|
||||
}
|
||||
else
|
||||
copy_tv(&cl->class_members_tv[i], rettv);
|
||||
|
||||
object_unref(obj);
|
||||
|
||||
return OK;
|
||||
}
|
||||
semsg(_(e_cannot_access_private_member_str), m->ocm_name);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
typval_T *tv = (typval_T *)(obj + 1) + m_idx;
|
||||
copy_tv(tv, rettv);
|
||||
}
|
||||
else
|
||||
copy_tv(&cl->class_members_tv[m_idx], rettv);
|
||||
|
||||
object_unref(obj);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1897,69 +1882,64 @@ class_object_index(
|
||||
|
||||
if (*name_end == '(')
|
||||
{
|
||||
int on_class = rettv->v_type == VAR_CLASS;
|
||||
int count = on_class ? cl->class_class_function_count
|
||||
: cl->class_obj_method_count;
|
||||
for (int i = 0; i < count; ++i)
|
||||
ufunc_T *fp;
|
||||
int m_idx;
|
||||
|
||||
fp = method_lookup(cl, rettv->v_type, name, len, &m_idx);
|
||||
if (fp == NULL)
|
||||
{
|
||||
ufunc_T *fp = on_class ? cl->class_class_functions[i]
|
||||
: 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(name, ufname, len) == 0 && ufname[len] == NUL)
|
||||
{
|
||||
typval_T argvars[MAX_FUNC_ARGS + 1];
|
||||
int argcount = 0;
|
||||
|
||||
if (*ufname == '_')
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
semsg(_(e_method_not_found_on_class_str_str), cl->class_name,
|
||||
name);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
semsg(_(e_method_not_found_on_class_str_str), cl->class_name, name);
|
||||
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)
|
||||
@ -1977,34 +1957,34 @@ class_object_index(
|
||||
|
||||
else if (rettv->v_type == VAR_CLASS)
|
||||
{
|
||||
int m_idx;
|
||||
|
||||
// class member
|
||||
for (int i = 0; i < cl->class_class_member_count; ++i)
|
||||
ocmember_T *m = class_member_lookup(cl, name, len, &m_idx);
|
||||
if (m == NULL)
|
||||
{
|
||||
ocmember_T *m = &cl->class_class_members[i];
|
||||
if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
|
||||
{
|
||||
if (*name == '_')
|
||||
{
|
||||
semsg(_(e_cannot_access_private_member_str), m->ocm_name);
|
||||
return FAIL;
|
||||
}
|
||||
if ((cl->class_flags & CLASS_INTERFACE) != 0)
|
||||
{
|
||||
semsg(_(e_interface_static_direct_access_str),
|
||||
cl->class_name, m->ocm_name);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
typval_T *tv = &cl->class_members_tv[i];
|
||||
copy_tv(tv, rettv);
|
||||
class_unref(cl);
|
||||
|
||||
*arg = name_end;
|
||||
return OK;
|
||||
}
|
||||
semsg(_(e_member_not_found_on_class_str_str), cl->class_name, name);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
semsg(_(e_member_not_found_on_class_str_str), cl->class_name, name);
|
||||
if (*name == '_')
|
||||
{
|
||||
semsg(_(e_cannot_access_private_member_str), m->ocm_name);
|
||||
return FAIL;
|
||||
}
|
||||
if ((cl->class_flags & CLASS_INTERFACE) != 0)
|
||||
{
|
||||
semsg(_(e_interface_static_direct_access_str),
|
||||
cl->class_name, m->ocm_name);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
typval_T *tv = &cl->class_members_tv[m_idx];
|
||||
copy_tv(tv, rettv);
|
||||
class_unref(cl);
|
||||
|
||||
*arg = name_end;
|
||||
return OK;
|
||||
}
|
||||
|
||||
return FAIL;
|
||||
@ -2022,6 +2002,7 @@ find_class_func(char_u **arg)
|
||||
if (name_end == name || *name_end != '.')
|
||||
return NULL;
|
||||
|
||||
ufunc_T *fp = NULL;
|
||||
size_t len = name_end - name;
|
||||
typval_T tv;
|
||||
tv.v_type = VAR_UNKNOWN;
|
||||
@ -2041,82 +2022,191 @@ find_class_func(char_u **arg)
|
||||
goto fail_after_eval;
|
||||
len = fname_end - fname;
|
||||
|
||||
int count = tv.v_type == VAR_CLASS ? cl->class_class_function_count
|
||||
: cl->class_obj_method_count;
|
||||
ufunc_T **funcs = tv.v_type == VAR_CLASS ? cl->class_class_functions
|
||||
: cl->class_obj_methods;
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
ufunc_T *fp = funcs[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)
|
||||
{
|
||||
clear_tv(&tv);
|
||||
return fp;
|
||||
}
|
||||
}
|
||||
int m_idx;
|
||||
fp = method_lookup(cl, tv.v_type, fname, len, &m_idx);
|
||||
|
||||
fail_after_eval:
|
||||
clear_tv(&tv);
|
||||
return NULL;
|
||||
return fp;
|
||||
}
|
||||
|
||||
/*
|
||||
* If "name[len]" is a class member in cctx->ctx_ufunc->uf_class return the
|
||||
* index in class.class_class_members[].
|
||||
* If "cl_ret" is not NULL set it to the class.
|
||||
* Otherwise return -1;
|
||||
* Returns the index of class 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
|
||||
class_member_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx)
|
||||
class_member_idx(class_T *cl, char_u *name, size_t namelen)
|
||||
{
|
||||
if (cctx == NULL || cctx->ctx_ufunc == NULL
|
||||
|| cctx->ctx_ufunc->uf_class == NULL)
|
||||
return -1;
|
||||
class_T *cl = cctx->ctx_ufunc->uf_class;
|
||||
|
||||
for (int i = 0; i < cl->class_class_member_count; ++i)
|
||||
{
|
||||
ocmember_T *m = &cl->class_class_members[i];
|
||||
if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
|
||||
if (namelen)
|
||||
{
|
||||
if (cl_ret != NULL)
|
||||
*cl_ret = cl;
|
||||
return i;
|
||||
if (STRNCMP(name, m->ocm_name, namelen) == 0
|
||||
&& m->ocm_name[namelen] == NUL)
|
||||
return i;
|
||||
}
|
||||
else if (STRCMP(name, m->ocm_name) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If "name[len]" is a class method in cctx->ctx_ufunc->uf_class return the
|
||||
* index in class.class_class_functions[].
|
||||
* If "cl_ret" is not NULL set it to the class.
|
||||
* Otherwise return -1.
|
||||
* Returns a pointer to the class member variable "name" in the class "cl".
|
||||
* Returns NULL if the variable is not found.
|
||||
* The member variable index is set in "idx".
|
||||
*/
|
||||
ocmember_T *
|
||||
class_member_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
|
||||
{
|
||||
*idx = class_member_idx(cl, name, namelen);
|
||||
return *idx >= 0 ? &cl->class_class_members[*idx] : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the index of class method "name" in the class "cl".
|
||||
* Returns -1, if the method is not found.
|
||||
*/
|
||||
int
|
||||
class_method_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx)
|
||||
class_method_idx(class_T *cl, char_u *name, size_t namelen)
|
||||
{
|
||||
if (cctx == NULL || cctx->ctx_ufunc == NULL
|
||||
|| cctx->ctx_ufunc->uf_class == NULL)
|
||||
return -1;
|
||||
class_T *cl = cctx->ctx_ufunc->uf_class;
|
||||
|
||||
for (int i = 0; i < cl->class_class_function_count; ++i)
|
||||
{
|
||||
ufunc_T *fp = cl->class_class_functions[i];
|
||||
if (STRNCMP(name, fp->uf_name, len) == 0 && fp->uf_name[len] == NUL)
|
||||
char_u *ufname = (char_u *)fp->uf_name;
|
||||
if (STRNCMP(name, ufname, namelen) == 0 && ufname[namelen] == NUL)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 *
|
||||
class_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
|
||||
{
|
||||
*idx = class_method_idx(cl, name, namelen);
|
||||
return *idx >= 0 ? cl->class_class_functions[*idx] : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
object_member_idx(class_T *cl, char_u *name, size_t namelen)
|
||||
{
|
||||
for (int i = 0; i < cl->class_obj_member_count; ++i)
|
||||
{
|
||||
ocmember_T *m = &cl->class_obj_members[i];
|
||||
if (namelen)
|
||||
{
|
||||
if (cl_ret != NULL)
|
||||
*cl_ret = cl;
|
||||
if (STRNCMP(name, m->ocm_name, namelen) == 0
|
||||
&& m->ocm_name[namelen] == NUL)
|
||||
return i;
|
||||
}
|
||||
else if (STRCMP(name, m->ocm_name) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a pointer to the object member variable "name" in the class "cl".
|
||||
* Returns NULL if the variable is not found.
|
||||
* The object member variable index is set in "idx".
|
||||
*/
|
||||
ocmember_T *
|
||||
object_member_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
|
||||
{
|
||||
*idx = object_member_idx(cl, name, namelen);
|
||||
return *idx >= 0 ? &cl->class_obj_members[*idx] : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
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(name, ufname, namelen) == 0 && ufname[namelen] == NUL)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 *
|
||||
object_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
|
||||
{
|
||||
*idx = object_method_idx(cl, name, namelen);
|
||||
return *idx >= 0 ? cl->class_obj_methods[*idx] : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* object member variable.
|
||||
*
|
||||
* Returns a pointer to the member variable structure if variable is found.
|
||||
* Otherwise returns NULL. The member variable index is set in "*idx".
|
||||
*/
|
||||
ocmember_T *
|
||||
member_lookup(
|
||||
class_T *cl,
|
||||
vartype_T v_type,
|
||||
char_u *name,
|
||||
size_t namelen,
|
||||
int *idx)
|
||||
{
|
||||
if (v_type == VAR_CLASS)
|
||||
return class_member_lookup(cl, name, namelen, idx);
|
||||
else
|
||||
return object_member_lookup(cl, name, namelen, idx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup a class or object method by name. If v_type is VAR_CLASS, then
|
||||
* lookup a class method and if it is VAR_OBJECT, then lookup a object method.
|
||||
*
|
||||
* Returns a pointer to the method structure if variable is found.
|
||||
* Otherwise returns NULL. The method variable index is set in "*idx".
|
||||
*/
|
||||
ufunc_T *
|
||||
method_lookup(
|
||||
class_T *cl,
|
||||
vartype_T v_type,
|
||||
char_u *name,
|
||||
size_t namelen,
|
||||
int *idx)
|
||||
{
|
||||
if (v_type == VAR_CLASS)
|
||||
return class_method_lookup(cl, name, namelen, idx);
|
||||
else
|
||||
return object_method_lookup(cl, name, namelen, idx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if current context "cctx_arg" is inside class "cl".
|
||||
* Return FALSE if not.
|
||||
|
@ -331,6 +331,62 @@ script_var_exists(char_u *name, size_t len, cctx_T *cctx, cstack_T *cstack)
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If "name[len]" is a class method in cctx->ctx_ufunc->uf_class return the
|
||||
* class method index.
|
||||
* If "cl_ret" is not NULL set it to the class.
|
||||
* Otherwise return -1.
|
||||
*/
|
||||
int
|
||||
cctx_class_method_idx(
|
||||
cctx_T *cctx,
|
||||
char_u *name,
|
||||
size_t len,
|
||||
class_T **cl_ret)
|
||||
{
|
||||
if (cctx == NULL || cctx->ctx_ufunc == NULL
|
||||
|| cctx->ctx_ufunc->uf_class == NULL)
|
||||
return -1;
|
||||
|
||||
class_T *cl = cctx->ctx_ufunc->uf_class;
|
||||
int m_idx = class_method_idx(cl, name, len);
|
||||
if (m_idx >= 0)
|
||||
{
|
||||
if (cl_ret != NULL)
|
||||
*cl_ret = cl;
|
||||
}
|
||||
|
||||
return m_idx;
|
||||
}
|
||||
|
||||
/*
|
||||
* If "name[len]" is a class member in cctx->ctx_ufunc->uf_class return the
|
||||
* class member variable index.
|
||||
* If "cl_ret" is not NULL set it to the class.
|
||||
* Otherwise return -1;
|
||||
*/
|
||||
int
|
||||
cctx_class_member_idx(
|
||||
cctx_T *cctx,
|
||||
char_u *name,
|
||||
size_t len,
|
||||
class_T **cl_ret)
|
||||
{
|
||||
if (cctx == NULL || cctx->ctx_ufunc == NULL
|
||||
|| cctx->ctx_ufunc->uf_class == NULL)
|
||||
return -1;
|
||||
|
||||
class_T *cl = cctx->ctx_ufunc->uf_class;
|
||||
int m_idx = class_member_idx(cl, name, len);
|
||||
if (m_idx >= 0)
|
||||
{
|
||||
if (cl_ret != NULL)
|
||||
*cl_ret = cl;
|
||||
}
|
||||
|
||||
return m_idx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if "name" is a local variable, argument, script variable or
|
||||
* imported. Also if "name" is "this" and in a class method.
|
||||
@ -346,7 +402,7 @@ variable_exists(char_u *name, size_t len, cctx_T *cctx)
|
||||
&& (cctx->ctx_ufunc->uf_flags & (FC_OBJECT|FC_NEW))
|
||||
&& STRNCMP(name, "this", 4) == 0)))
|
||||
|| script_var_exists(name, len, cctx, NULL) == OK
|
||||
|| class_member_index(name, len, NULL, cctx) >= 0
|
||||
|| cctx_class_member_idx(cctx, name, len, NULL) >= 0
|
||||
|| find_imported(name, len, FALSE) != NULL;
|
||||
}
|
||||
|
||||
@ -393,7 +449,7 @@ check_defined(
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if (class_member_index(p, len, NULL, cctx) >= 0)
|
||||
if (cctx_class_member_idx(cctx, p, len, NULL) >= 0)
|
||||
{
|
||||
if (is_arg)
|
||||
semsg(_(e_argument_already_declared_in_class_str), p);
|
||||
@ -1617,8 +1673,8 @@ compile_lhs(
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
else if ((lhs->lhs_classmember_idx = class_member_index(
|
||||
var_start, lhs->lhs_varlen, NULL, cctx)) >= 0)
|
||||
else if ((lhs->lhs_classmember_idx = cctx_class_member_idx(
|
||||
cctx, var_start, lhs->lhs_varlen, NULL)) >= 0)
|
||||
{
|
||||
if (is_decl)
|
||||
{
|
||||
|
@ -2166,26 +2166,20 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx)
|
||||
class_T *cl = obj->obj_class;
|
||||
char_u *member = tv_idx->vval.v_string;
|
||||
|
||||
ocmember_T *m = NULL;
|
||||
for (int i = 0; i < cl->class_obj_member_count; ++i)
|
||||
int m_idx;
|
||||
ocmember_T *m = object_member_lookup(cl, member, 0, &m_idx);
|
||||
if (m != NULL)
|
||||
{
|
||||
m = &cl->class_obj_members[i];
|
||||
if (STRCMP(member, m->ocm_name) == 0)
|
||||
if (*member == '_')
|
||||
{
|
||||
if (*member == '_')
|
||||
{
|
||||
semsg(_(e_cannot_access_private_member_str),
|
||||
m->ocm_name);
|
||||
status = FAIL;
|
||||
}
|
||||
|
||||
lidx = i;
|
||||
break;
|
||||
semsg(_(e_cannot_access_private_member_str),
|
||||
m->ocm_name);
|
||||
status = FAIL;
|
||||
}
|
||||
m = NULL;
|
||||
}
|
||||
|
||||
if (m == NULL)
|
||||
lidx = m_idx;
|
||||
}
|
||||
else
|
||||
{
|
||||
semsg(_(e_member_not_found_on_object_str_str),
|
||||
cl->class_name, member);
|
||||
|
@ -394,39 +394,32 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type)
|
||||
|
||||
if (type->tt_type == VAR_OBJECT)
|
||||
{
|
||||
for (int i = 0; i < cl->class_obj_member_count; ++i)
|
||||
int m_idx = object_member_idx(cl, name, len);
|
||||
if (m_idx >= 0)
|
||||
{
|
||||
ocmember_T *m = &cl->class_obj_members[i];
|
||||
if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
|
||||
ocmember_T *m = &cl->class_obj_members[m_idx];
|
||||
if (*name == '_' && !inside_class(cctx, cl))
|
||||
{
|
||||
if (*name == '_' && !inside_class(cctx, cl))
|
||||
{
|
||||
semsg(_(e_cannot_access_private_member_str), m->ocm_name);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
*arg = name_end;
|
||||
if (cl->class_flags & (CLASS_INTERFACE | CLASS_EXTENDED))
|
||||
return generate_GET_ITF_MEMBER(cctx, cl, i, m->ocm_type,
|
||||
FALSE);
|
||||
return generate_GET_OBJ_MEMBER(cctx, i, m->ocm_type, FALSE);
|
||||
semsg(_(e_cannot_access_private_member_str), m->ocm_name);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
*arg = name_end;
|
||||
if (cl->class_flags & (CLASS_INTERFACE | CLASS_EXTENDED))
|
||||
return generate_GET_ITF_MEMBER(cctx, cl, m_idx, m->ocm_type,
|
||||
FALSE);
|
||||
return generate_GET_OBJ_MEMBER(cctx, m_idx, m->ocm_type, FALSE);
|
||||
}
|
||||
|
||||
// Could be a function reference: "obj.Func".
|
||||
for (int i = 0; i < cl->class_obj_method_count; ++i)
|
||||
m_idx = object_method_idx(cl, name, len);
|
||||
if (m_idx >= 0)
|
||||
{
|
||||
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(name, ufname, len) == 0 && ufname[len] == NUL)
|
||||
{
|
||||
if (type->tt_type == VAR_OBJECT
|
||||
&& (cl->class_flags & (CLASS_INTERFACE | CLASS_EXTENDED)))
|
||||
return generate_FUNCREF(cctx, fp, cl, i, NULL);
|
||||
return generate_FUNCREF(cctx, fp, NULL, 0, NULL);
|
||||
}
|
||||
ufunc_T *fp = cl->class_obj_methods[m_idx];
|
||||
if (type->tt_type == VAR_OBJECT
|
||||
&& (cl->class_flags & (CLASS_INTERFACE | CLASS_EXTENDED)))
|
||||
return generate_FUNCREF(cctx, fp, cl, m_idx, NULL);
|
||||
return generate_FUNCREF(cctx, fp, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
semsg(_(e_member_not_found_on_object_str_str), cl->class_name, name);
|
||||
@ -435,28 +428,22 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type)
|
||||
{
|
||||
// load class member
|
||||
int idx;
|
||||
for (idx = 0; idx < cl->class_class_member_count; ++idx)
|
||||
ocmember_T *m = class_member_lookup(cl, name, len, &idx);
|
||||
if (m != NULL)
|
||||
{
|
||||
ocmember_T *m = &cl->class_class_members[idx];
|
||||
if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
|
||||
// Note: type->tt_type = VAR_CLASS
|
||||
if ((cl->class_flags & CLASS_INTERFACE) != 0)
|
||||
{
|
||||
// Note: type->tt_type = VAR_CLASS
|
||||
if ((cl->class_flags & CLASS_INTERFACE) != 0)
|
||||
{
|
||||
semsg(_(e_interface_static_direct_access_str),
|
||||
cl->class_name, m->ocm_name);
|
||||
return FAIL;
|
||||
}
|
||||
if (*name == '_' && !inside_class(cctx, cl))
|
||||
{
|
||||
semsg(_(e_cannot_access_private_member_str), m->ocm_name);
|
||||
return FAIL;
|
||||
}
|
||||
break;
|
||||
semsg(_(e_interface_static_direct_access_str),
|
||||
cl->class_name, m->ocm_name);
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
if (idx < cl->class_class_member_count)
|
||||
{
|
||||
if (*name == '_' && !inside_class(cctx, cl))
|
||||
{
|
||||
semsg(_(e_cannot_access_private_member_str), m->ocm_name);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
*arg = name_end;
|
||||
return generate_CLASSMEMBER(cctx, TRUE, cl, idx);
|
||||
}
|
||||
@ -773,7 +760,7 @@ compile_load(
|
||||
else
|
||||
gen_load = TRUE;
|
||||
}
|
||||
else if ((idx = class_member_index(*arg, len, &cl, cctx)) >= 0)
|
||||
else if ((idx = cctx_class_member_idx(cctx, *arg, len, &cl)) >= 0)
|
||||
{
|
||||
// Referencing a class member without the class name. Infer
|
||||
// the class from the def function context.
|
||||
@ -1141,7 +1128,7 @@ compile_call(
|
||||
goto theend;
|
||||
}
|
||||
}
|
||||
else if ((mi = class_method_index(name, varlen, &cl, cctx)) >= 0)
|
||||
else if ((mi = cctx_class_method_idx(cctx, name, varlen, &cl)) >= 0)
|
||||
{
|
||||
// Class method invocation without the class name. The
|
||||
// generate_CALL() function expects the class type at the top of
|
||||
|
@ -1837,17 +1837,12 @@ generate_CALL(
|
||||
if (class_constructor && expected->tt_type == VAR_ANY)
|
||||
{
|
||||
class_T *clp = mtype->tt_class;
|
||||
char_u *aname = ((char_u **)ufunc->uf_args.ga_data)[i];
|
||||
for (int om = 0; om < clp->class_obj_member_count; ++om)
|
||||
{
|
||||
if (STRCMP(aname, clp->class_obj_members[om].ocm_name)
|
||||
== 0)
|
||||
{
|
||||
expected = clp->class_obj_members[om].ocm_type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char_u *aname = ((char_u **)ufunc->uf_args.ga_data)[i];
|
||||
int m_idx;
|
||||
ocmember_T *m = object_member_lookup(clp, aname, 0,
|
||||
&m_idx);
|
||||
if (m != NULL)
|
||||
expected = m->ocm_type;
|
||||
}
|
||||
}
|
||||
else if (ufunc->uf_va_type == NULL
|
||||
|
Loading…
x
Reference in New Issue
Block a user