# HG changeset patch # User Christian Brabandt # Date 1694363404 -7200 # Node ID 108d890d887f0ef7424693204156b57de785ebf9 # Parent d72f150af9f1ce959c312c92f02985cbec040640 patch 9.0.1890: Vim9: lookup code for class/object repaeated Commit: https://github.com/vim/vim/commit/f36bbcd402c6ee5a27bcab3b20b6362ab93b8898 Author: Yegappan Lakshmanan Date: Sun Sep 10 18:19:06 2023 +0200 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 Co-authored-by: Yegappan Lakshmanan diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/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; } } diff --git a/src/proto/vim9class.pro b/src/proto/vim9class.pro --- a/src/proto/vim9class.pro +++ b/src/proto/vim9class.pro @@ -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); diff --git a/src/proto/vim9compile.pro b/src/proto/vim9compile.pro --- a/src/proto/vim9compile.pro +++ b/src/proto/vim9compile.pro @@ -4,6 +4,8 @@ int arg_exists(char_u *name, size_t len, 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); diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -700,6 +700,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1890, +/**/ 1889, /**/ 1888, diff --git a/src/vim9class.c b/src/vim9class.c --- a/src/vim9class.c +++ b/src/vim9class.c @@ -269,14 +269,10 @@ object_index_from_itf_index(class_T *itf { // 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) { + size_t len = name_end - name; + ocmember_T *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; - for (int i = 0; i < member_count; ++i) + 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 = 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; + ufunc_T *fp; + int m_idx; - 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; + fp = method_lookup(cl, rettv->v_type, name, len, &m_idx); + if (fp == NULL) + { + semsg(_(e_method_not_found_on_class_str_str), cl->class_name, + name); + return FAIL; + } - // 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]); + typval_T argvars[MAX_FUNC_ARGS + 1]; + int argcount = 0; - if (error != FCERR_NONE) - { - user_func_error(error, printable_func_name(fp), - funcexe.fe_found_var); - return FAIL; - } - *arg = argp; - return OK; - } + if (*fp->uf_name == '_') + { + // Cannot access a private method outside of a class + semsg(_(e_cannot_access_private_method_str), name); + return FAIL; } - semsg(_(e_method_not_found_on_class_str_str), cl->class_name, name); + 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,83 +2022,192 @@ 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; + 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 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_idx(class_T *cl, char_u *name, size_t namelen) +{ + for (int i = 0; i < cl->class_class_function_count; ++i) + { + ufunc_T *fp = cl->class_class_functions[i]; + char_u *ufname = (char_u *)fp->uf_name; + if (STRNCMP(name, ufname, namelen) == 0 && ufname[namelen] == NUL) + 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 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 (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 -class_method_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx) +object_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) + for (int i = 0; i < cl->class_obj_method_count; ++i) { - ufunc_T *fp = cl->class_class_functions[i]; - if (STRNCMP(name, fp->uf_name, len) == 0 && fp->uf_name[len] == NUL) - { - if (cl_ret != NULL) - *cl_ret = cl; + 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. */ diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -332,6 +332,62 @@ script_var_exists(char_u *name, size_t l } /* + * 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->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) { diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -2166,26 +2166,20 @@ execute_storeindex(isn_T *iptr, ectx_T * 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; + + lidx = m_idx; } - - if (m == NULL) + else { semsg(_(e_member_not_found_on_object_str_str), cl->class_name, member); diff --git a/src/vim9expr.c b/src/vim9expr.c --- a/src/vim9expr.c +++ b/src/vim9expr.c @@ -394,39 +394,32 @@ compile_class_object_index(cctx_T *cctx, 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, + 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, i, 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, { // 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 diff --git a/src/vim9instr.c b/src/vim9instr.c --- a/src/vim9instr.c +++ b/src/vim9instr.c @@ -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