patch 9.0.1890: Vim9: lookup code for class/object repaeated

Commit: 
https://github.com/vim/vim/commit/f36bbcd402c6ee5a27bcab3b20b6362ab93b8898
Author: Yegappan Lakshmanan <yegap...@yahoo.com>
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 <c...@256bit.org>
    Co-authored-by: Yegappan Lakshmanan <yegap...@yahoo.com>

diff --git a/src/eval.c b/src/eval.c
index ec8d3baf9..dd7b8d8f3 100644
--- 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
index 8413a81dd..a61c40f23 100644
--- 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
index 9f2263a6e..080a2ffaa 100644
--- a/src/proto/vim9compile.pro
+++ b/src/proto/vim9compile.pro
@@ -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);
diff --git a/src/version.c b/src/version.c
index 11bf957d5..7f1d69d86 100644
--- a/src/version.c
+++ b/src/version.c
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1890,
 /**/
     1889,
 /**/
diff --git a/src/vim9class.c b/src/vim9class.c
index 90cdb8ec1..15d2b0913 100644
--- a/src/vim9class.c
+++ b/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;
-
-    for (int i = 0; i < member_count; ++i)
-    {
-       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;
-           }
+    ocmember_T *m;
+    int                m_idx;
 
-           // 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);
+    m = member_lookup(cl, is_object ? VAR_OBJECT : VAR_CLASS, name, namelen,
+                                                               &m_idx);
+    if (m == NULL)
+       return FAIL;
 
-           object_unref(obj);
+    if (*name == '_')
+    {
+       semsg(_(e_cannot_access_private_member_str), m->ocm_name);
+       return FAIL;
+    }
 
-           return OK;
-       }
+    // 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);
 
-    return FAIL;
+    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;
+           semsg(_(e_method_not_found_on_class_str_str), cl->class_name,
+                   name);
+           return FAIL;
+       }
 
-               if (*ufname == '_')
-               {
-                   // Cannot access a private method outside of a class
-                   semsg(_(e_cannot_access_private_method_str), name);
-                   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;
+       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;
-               }
+       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;
+       // 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);
+       // 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]);
+       // 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;
-           }
+       if (error != FCERR_NONE)
+       {
+           user_func_error(error, printable_func_name(fp),
+                   funcexe.fe_found_var);
+           return FAIL;
        }
-
-       semsg(_(e_method_not_found_on_class_str_str), cl->class_name, name);
+       *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);
+           semsg(_(e_member_not_found_on_class_str_str), cl->class_name, name);
+           return FAIL;
+       }
 
-               *arg = name_end;
-               return OK;
-           }
+       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);
 
-       semsg(_(e_member_not_found_on_class_str_str), cl->class_name, name);
+       *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".
  */
-    int
-class_method_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx)
+    ocmember_T *
+class_member_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
 {
-    if (cctx == NULL || cctx->ctx_ufunc == NULL
-                                         || cctx->ctx_ufunc->uf_class == NULL)
-       return -1;
-    class_T *cl = cctx->ctx_ufunc->uf_class;
+    *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];
-       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.
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 5778be6e2..7d24f21c8 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -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)
                {
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 4a1dd1ce2..f8e267641 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -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);
diff --git a/src/vim9expr.c b/src/vim9expr.c
index 883219ef5..0315f4f7b 100644
--- a/src/vim9expr.c
+++ b/src/vim9expr.c
@@ -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;
-               }
+               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,
+           *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, 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
diff --git a/src/vim9instr.c b/src/vim9instr.c
index 68fad25d5..dcbe897cd 100644
--- 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

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1qfNK0-006Kc0-JU%40256bit.org.

Raspunde prin e-mail lui