summaryrefslogtreecommitdiffstats
path: root/src/vim9class.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vim9class.c')
-rw-r--r--src/vim9class.c115
1 files changed, 95 insertions, 20 deletions
diff --git a/src/vim9class.c b/src/vim9class.c
index 5dda700fa3..bfa6149602 100644
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -2167,15 +2167,35 @@ call_oc_method(
ufunc_T *fp;
typval_T argvars[MAX_FUNC_ARGS + 1];
int argcount = 0;
+ ocmember_T *ocm = NULL;
+ int m_idx;
fp = method_lookup(cl, rettv->v_type, name, len, NULL);
if (fp == NULL)
{
- method_not_found_msg(cl, rettv->v_type, name, len);
- return FAIL;
+ // could be an object or class funcref variable
+ ocm = member_lookup(cl, rettv->v_type, name, len, &m_idx);
+ if (ocm == NULL || ocm->ocm_type->tt_type != VAR_FUNC)
+ {
+ method_not_found_msg(cl, rettv->v_type, name, len);
+ return FAIL;
+ }
+
+ if (rettv->v_type == VAR_OBJECT)
+ {
+ // funcref object variable
+ object_T *obj = rettv->vval.v_object;
+ typval_T *tv = (typval_T *)(obj + 1) + m_idx;
+ copy_tv(tv, rettv);
+ }
+ else
+ // funcref class variable
+ copy_tv(&cl->class_members_tv[m_idx], rettv);
+ *arg = name_end;
+ return OK;
}
- if (*fp->uf_name == '_')
+ if (ocm == NULL && *fp->uf_name == '_')
{
// Cannot access a private method outside of a class
semsg(_(e_cannot_access_private_method_str), fp->uf_name);
@@ -2288,6 +2308,37 @@ class_object_index(
return OK;
}
+ // could be a class method or an object method
+ int fidx;
+ ufunc_T *fp = method_lookup(cl, rettv->v_type, name, len, &fidx);
+ if (fp != NULL)
+ {
+ // Private methods are not accessible outside the class
+ if (*name == '_')
+ {
+ semsg(_(e_cannot_access_private_method_str), fp->uf_name);
+ return FAIL;
+ }
+
+ partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
+ if (pt == NULL)
+ return FAIL;
+
+ pt->pt_refcount = 1;
+ if (is_object)
+ {
+ pt->pt_obj = rettv->vval.v_object;
+ ++pt->pt_obj->obj_refcount;
+ }
+ pt->pt_auto = TRUE;
+ pt->pt_func = fp;
+ func_ptr_ref(pt->pt_func);
+ rettv->v_type = VAR_PARTIAL;
+ rettv->vval.v_partial = pt;
+ *arg = name_end;
+ return OK;
+ }
+
if (did_emsg == did_emsg_save)
member_not_found_msg(cl, is_object, name, len);
}
@@ -2774,8 +2825,6 @@ object_created(object_T *obj)
first_object = obj;
}
-static object_T *next_nonref_obj = NULL;
-
/*
* Call this function when an object has been cleared and is about to be freed.
* It is removed from the list headed by "first_object".
@@ -2789,30 +2838,35 @@ object_cleared(object_T *obj)
obj->obj_prev_used->obj_next_used = obj->obj_next_used;
else if (first_object == obj)
first_object = obj->obj_next_used;
-
- // update the next object to check if needed
- if (obj == next_nonref_obj)
- next_nonref_obj = obj->obj_next_used;
}
/*
- * Free an object.
+ * Free the contents of an object ignoring the reference count.
*/
static void
-object_clear(object_T *obj)
+object_free_contents(object_T *obj)
{
- // Avoid a recursive call, it can happen if "obj" has a circular reference.
- obj->obj_refcount = INT_MAX;
-
class_T *cl = obj->obj_class;
if (!cl)
return;
+ // Avoid a recursive call, it can happen if "obj" has a circular reference.
+ obj->obj_refcount = INT_MAX;
+
// the member values are just after the object structure
typval_T *tv = (typval_T *)(obj + 1);
for (int i = 0; i < cl->class_obj_member_count; ++i)
clear_tv(tv + i);
+}
+
+ static void
+object_free_object(object_T *obj)
+{
+ class_T *cl = obj->obj_class;
+
+ if (!cl)
+ return;
// Remove from the list headed by "first_object".
object_cleared(obj);
@@ -2821,6 +2875,16 @@ object_clear(object_T *obj)
class_unref(cl);
}
+ static void
+object_free(object_T *obj)
+{
+ if (in_free_unref_items)
+ return;
+
+ object_free_contents(obj);
+ object_free_object(obj);
+}
+
/*
* Unreference an object.
*/
@@ -2828,7 +2892,7 @@ object_clear(object_T *obj)
object_unref(object_T *obj)
{
if (obj != NULL && --obj->obj_refcount <= 0)
- object_clear(obj);
+ object_free(obj);
}
/*
@@ -2839,21 +2903,32 @@ object_free_nonref(int copyID)
{
int did_free = FALSE;
- for (object_T *obj = first_object; obj != NULL; obj = next_nonref_obj)
+ for (object_T *obj = first_object; obj != NULL; obj = obj->obj_next_used)
{
- next_nonref_obj = obj->obj_next_used;
if ((obj->obj_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
{
- // Free the object and items it contains.
- object_clear(obj);
+ // Free the object contents. Object itself will be freed later.
+ object_free_contents(obj);
did_free = TRUE;
}
}
- next_nonref_obj = NULL;
return did_free;
}
+ void
+object_free_items(int copyID)
+{
+ object_T *obj_next;
+
+ for (object_T *obj = first_object; obj != NULL; obj = obj_next)
+ {
+ obj_next = obj->obj_next_used;
+ if ((obj->obj_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
+ object_free_object(obj);
+ }
+}
+
/*
* Output message which takes a variable name and the class that defines it.
* "cl" is that class where the name was found. Search "cl"'s hierarchy to