patch 9.0.1123: class function not implemented yet
Problem: Class function not implemented yet.
Solution: Implement defining and calling a class function.
diff --git a/src/vim9class.c b/src/vim9class.c
index 2e1cac0..b1de90b 100644
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -223,9 +223,9 @@
garray_T classmembers;
ga_init2(&classmembers, sizeof(ocmember_T), 10);
- // Growarray with object methods declared in the class.
- garray_T classmethods;
- ga_init2(&classmethods, sizeof(ufunc_T *), 10);
+ // Growarray with functions declared in the class.
+ garray_T classfunctions;
+ ga_init2(&classfunctions, sizeof(ufunc_T *), 10);
// Growarray with object members declared in the class.
garray_T objmembers;
@@ -288,6 +288,19 @@
}
}
+ int has_static = FALSE;
+ char_u *ps = p;
+ if (checkforcmd(&p, "static", 4))
+ {
+ if (STRNCMP(ps, "static", 6) != 0)
+ {
+ semsg(_(e_command_cannot_be_shortened_str), ps);
+ break;
+ }
+ has_static = TRUE;
+ p = skipwhite(ps + 6);
+ }
+
// object members (public, read access, private):
// "this._varname"
// "this.varname"
@@ -314,47 +327,15 @@
}
}
- // class members and methods
- else if (checkforcmd(&p, "static", 6))
- {
- p = skipwhite(p);
- if (checkforcmd(&p, "def", 3))
- {
- // TODO: class method
- // static def someMethod()
- // enddef
- // static def <Tval> someMethod()
- // enddef
- }
- else
- {
- // class members (public, read access, private):
- // "static _varname"
- // "static varname"
- // "public static varname"
- char_u *varname = p;
- char_u *varname_end = NULL;
- type_T *type = NULL;
- char_u *init_expr = NULL;
- if (parse_member(eap, line, varname, has_public,
- &varname_end, &type_list, &type, &init_expr) == FAIL)
- break;
- if (add_member(&classmembers, varname, varname_end,
- has_public, type, init_expr) == FAIL)
- {
- vim_free(init_expr);
- break;
- }
- }
- }
-
// constructors:
// def new()
// enddef
// def newOther()
// enddef
- // methods:
- // def someMethod()
+ // object methods and class functions:
+ // def SomeMethod()
+ // enddef
+ // static def ClassFunction()
// enddef
// TODO:
// def <Tval> someMethod()
@@ -364,6 +345,8 @@
exarg_T ea;
garray_T lines_to_free;
+ // TODO: error for "public static def Func()"?
+
CLEAR_FIELD(ea);
ea.cmd = line;
ea.arg = p;
@@ -376,13 +359,38 @@
ga_clear_strings(&lines_to_free);
// TODO: how about errors?
- if (uf != NULL && ga_grow(&objmethods, 1) == OK)
+ int is_new = STRNCMP(uf->uf_name, "new", 3) == 0;
+ garray_T *fgap = has_static || is_new
+ ? &classfunctions : &objmethods;
+ if (uf != NULL && ga_grow(fgap, 1) == OK)
{
- if (STRNCMP(uf->uf_name, "new", 3) == 0)
+ if (is_new)
uf->uf_flags |= FC_NEW;
- ((ufunc_T **)objmethods.ga_data)[objmethods.ga_len] = uf;
- ++objmethods.ga_len;
+ ((ufunc_T **)fgap->ga_data)[fgap->ga_len] = uf;
+ ++fgap->ga_len;
+ }
+ }
+
+ // class members
+ else if (has_static)
+ {
+ // class members (public, read access, private):
+ // "static _varname"
+ // "static varname"
+ // "public static varname"
+ char_u *varname = p;
+ char_u *varname_end = NULL;
+ type_T *type = NULL;
+ char_u *init_expr = NULL;
+ if (parse_member(eap, line, varname, has_public,
+ &varname_end, &type_list, &type, &init_expr) == FAIL)
+ break;
+ if (add_member(&classmembers, varname, varname_end,
+ has_public, type, init_expr) == FAIL)
+ {
+ vim_free(init_expr);
+ break;
}
}
@@ -445,8 +453,8 @@
}
int have_new = FALSE;
- for (int i = 0; i < objmethods.ga_len; ++i)
- if (STRCMP(((ufunc_T **)objmethods.ga_data)[i]->uf_name,
+ for (int i = 0; i < classfunctions.ga_len; ++i)
+ if (STRCMP(((ufunc_T **)classfunctions.ga_data)[i]->uf_name,
"new") == 0)
{
have_new = TRUE;
@@ -483,10 +491,10 @@
ga_clear_strings(&lines_to_free);
vim_free(fga.ga_data);
- if (nf != NULL && ga_grow(&objmethods, 1) == OK)
+ if (nf != NULL && ga_grow(&classfunctions, 1) == OK)
{
- ((ufunc_T **)objmethods.ga_data)[objmethods.ga_len] = nf;
- ++objmethods.ga_len;
+ ((ufunc_T **)classfunctions.ga_data)[classfunctions.ga_len] = nf;
+ ++classfunctions.ga_len;
nf->uf_flags |= FC_NEW;
nf->uf_ret_type = get_type_ptr(&type_list);
@@ -500,21 +508,35 @@
}
}
- // TODO: class methods
- cl->class_obj_method_count = objmethods.ga_len;
- cl->class_obj_methods = ALLOC_MULT(ufunc_T *, objmethods.ga_len);
- if (cl->class_obj_methods == NULL)
- goto cleanup;
- mch_memmove(cl->class_obj_methods, objmethods.ga_data,
- sizeof(ufunc_T *) * objmethods.ga_len);
- vim_free(objmethods.ga_data);
-
- // Set the class pointer on all the object methods.
- for (int i = 0; i < objmethods.ga_len; ++i)
+ // loop 1: class functions, loop 2: object methods
+ for (int loop = 1; loop <= 2; ++loop)
{
- ufunc_T *fp = cl->class_obj_methods[i];
- fp->uf_class = cl;
- fp->uf_flags |= FC_OBJECT; // TODO: not for class method
+ garray_T *gap = loop == 1 ? &classfunctions : &objmethods;
+ int *fcount = loop == 1 ? &cl->class_class_function_count
+ : &cl->class_obj_method_count;
+ ufunc_T ***fup = loop == 1 ? &cl->class_class_functions
+ : &cl->class_obj_methods;
+
+ *fcount = gap->ga_len;
+ if (gap->ga_len == 0)
+ {
+ *fup = NULL;
+ continue;
+ }
+ *fup = ALLOC_MULT(ufunc_T *, gap->ga_len);
+ if (*fup == NULL)
+ goto cleanup;
+ mch_memmove(*fup, gap->ga_data, sizeof(ufunc_T *) * gap->ga_len);
+ vim_free(gap->ga_data);
+
+ // Set the class pointer on all the object methods.
+ for (int i = 0; i < gap->ga_len; ++i)
+ {
+ ufunc_T *fp = (*fup)[i];
+ fp->uf_class = cl;
+ if (loop == 2)
+ fp->uf_flags |= FC_OBJECT;
+ }
}
cl->class_type.tt_type = VAR_CLASS;
@@ -539,6 +561,7 @@
if (cl != NULL)
{
vim_free(cl->class_name);
+ vim_free(cl->class_class_functions);
vim_free(cl->class_obj_members);
vim_free(cl->class_obj_methods);
vim_free(cl);
@@ -565,6 +588,14 @@
func_clear_free(uf, FALSE);
}
ga_clear(&objmethods);
+
+ for (int i = 0; i < classfunctions.ga_len; ++i)
+ {
+ ufunc_T *uf = ((ufunc_T **)classfunctions.ga_data)[i];
+ func_clear_free(uf, FALSE);
+ }
+ ga_clear(&classfunctions);
+
clear_type_list(&type_list);
}
@@ -627,7 +658,7 @@
/*
* Evaluate what comes after a class:
* - class member: SomeClass.varname
- * - class method: SomeClass.SomeMethod()
+ * - class function: SomeClass.SomeMethod()
* - class constructor: SomeClass.new()
* - object member: someObject.varname
* - object method: someObject.SomeMethod()
@@ -664,9 +695,13 @@
: rettv->vval.v_object->obj_class;
if (*name_end == '(')
{
- for (int i = 0; i < cl->class_obj_method_count; ++i)
+ 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 = cl->class_obj_methods[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;
@@ -805,9 +840,13 @@
goto fail_after_eval;
len = fname_end - fname;
- for (int i = 0; i < cl->class_obj_method_count; ++i)
+ 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 = cl->class_obj_methods[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;
@@ -824,6 +863,35 @@
}
/*
+ * If "cctx->ctx_ufunc" indicates we are in a class, check if "name" is a class
+ * member. If it is then return TRUE and set "cl_ret" and "idx_ret".
+ */
+ int
+class_member_exists(
+ char_u *name,
+ class_T **cl_ret,
+ int *idx_ret,
+ cctx_T *cctx)
+{
+ if (cctx->ctx_ufunc == NULL || cctx->ctx_ufunc->uf_class == NULL)
+ return FALSE;
+ class_T *cl = cctx->ctx_ufunc->uf_class;
+
+ for (int idx = 0; idx < cl->class_class_member_count; ++idx)
+ {
+ ocmember_T *m = &cl->class_class_members[idx];
+ if (STRCMP(m->ocm_name, name) == 0)
+ {
+ *cl_ret = cl;
+ *idx_ret = idx;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*
* Make a copy of an object.
*/
void