Mercurial > vim
diff src/vim9class.c @ 31416:f088f1d97eee v9.0.1041
patch 9.0.1041: cannot define a method in a class
Commit: https://github.com/vim/vim/commit/ffdaca9e6f3d39af6857ac52ced9385df203a152
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri Dec 9 21:41:48 2022 +0000
patch 9.0.1041: cannot define a method in a class
Problem: Cannot define a method in a class.
Solution: Implement defining an object method. Make calling an object
method work.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Fri, 09 Dec 2022 22:45:03 +0100 |
parents | c82cb53474ee |
children | 462508d04341 |
line wrap: on
line diff
--- a/src/vim9class.c +++ b/src/vim9class.c @@ -77,7 +77,7 @@ ex_class(exarg_T *eap) // Growarray with object methods declared in the class. garray_T objmethods; - ga_init2(&objmethods, sizeof(ufunc_T), 10); + ga_init2(&objmethods, sizeof(ufunc_T *), 10); /* * Go over the body of the class until "endclass" is found. @@ -97,22 +97,6 @@ ex_class(exarg_T *eap) // static varname // public static varname // static _varname - // - // constructors: - // def new() - // enddef - // def newOther() - // enddef - // - // methods (object, class, generics): - // def someMethod() - // enddef - // static def someMethod() - // enddef - // def <Tval> someMethod() - // enddef - // static def <Tval> someMethod() - // enddef char_u *p = line; if (checkforcmd(&p, "endclass", 4)) @@ -172,6 +156,45 @@ ex_class(exarg_T *eap) ++objmembers.ga_len; } + // constructors: + // def new() + // enddef + // def newOther() + // enddef + // methods: + // def someMethod() + // enddef + // TODO: + // static def someMethod() + // enddef + // def <Tval> someMethod() + // enddef + // static def <Tval> someMethod() + // enddef + else if (checkforcmd(&p, "def", 3)) + { + exarg_T ea; + garray_T lines_to_free; + + CLEAR_FIELD(ea); + ea.cmd = line; + ea.arg = p; + ea.cmdidx = CMD_def; + ea.getline = eap->getline; + ea.cookie = eap->cookie; + + ga_init2(&lines_to_free, sizeof(char_u *), 50); + ufunc_T *uf = define_function(&ea, NULL, &lines_to_free, TRUE); + ga_clear_strings(&lines_to_free); + + // TODO: how about errors? + if (uf != NULL && ga_grow(&objmethods, 1) == OK) + { + ((ufunc_T **)objmethods.ga_data)[objmethods.ga_len] = uf; + ++objmethods.ga_len; + } + } + else { semsg(_(e_not_valid_command_in_class_str), line); @@ -206,7 +229,7 @@ ex_class(exarg_T *eap) int have_new = FALSE; for (int i = 0; i < objmethods.ga_len; ++i) - if (STRCMP((((ufunc_T *)objmethods.ga_data) + i)->uf_name, + if (STRCMP(((ufunc_T **)objmethods.ga_data)[i]->uf_name, "new") == 0) { have_new = TRUE; @@ -237,7 +260,7 @@ ex_class(exarg_T *eap) garray_T lines_to_free; ga_init2(&lines_to_free, sizeof(char_u *), 50); - ufunc_T *nf = define_function(&fea, NULL, &lines_to_free, cl); + ufunc_T *nf = define_function(&fea, NULL, &lines_to_free, TRUE); ga_clear_strings(&lines_to_free); vim_free(fga.ga_data); @@ -248,7 +271,6 @@ ex_class(exarg_T *eap) ++objmethods.ga_len; nf->uf_flags |= FC_NEW; - nf->uf_class = cl; nf->uf_ret_type = get_type_ptr(&type_list); if (nf->uf_ret_type != NULL) { @@ -257,7 +279,6 @@ ex_class(exarg_T *eap) nf->uf_ret_type->tt_argcount = 0; nf->uf_ret_type->tt_args = NULL; } - cl->class_new_func = nf; } } @@ -275,8 +296,18 @@ ex_class(exarg_T *eap) 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) + { + ufunc_T *fp = cl->class_obj_methods[i]; + fp->uf_class = cl; + fp->uf_flags |= FC_OBJECT; // TODO: not for class method + } + cl->class_type.tt_type = VAR_CLASS; cl->class_type.tt_member = (type_T *)cl; + cl->class_object_type.tt_type = VAR_OBJECT; + cl->class_object_type.tt_member = (type_T *)cl; cl->class_type_list = type_list; // TODO: @@ -305,6 +336,11 @@ cleanup: } ga_clear(&objmembers); + for (int i = 0; i < objmethods.ga_len; ++i) + { + ufunc_T *uf = ((ufunc_T **)objmethods.ga_data)[i]; + func_clear_free(uf, FALSE); + } ga_clear(&objmethods); clear_type_list(&type_list); } @@ -419,6 +455,11 @@ class_object_index( 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. @@ -426,7 +467,6 @@ class_object_index( rettv->v_type = VAR_UNKNOWN; // Call the user function. Result goes into rettv; - // TODO: pass the object int error = call_user_func_check(fp, argcount, argvars, rettv, &funcexe, NULL); @@ -545,11 +585,13 @@ class_unref(class_T *cl) } vim_free(cl->class_obj_members); + for (int i = 0; i < cl->class_obj_method_count; ++i) + { + ufunc_T *uf = cl->class_obj_methods[i]; + func_clear_free(uf, FALSE); + } vim_free(cl->class_obj_methods); - if (cl->class_new_func != NULL) - func_ptr_unref(cl->class_new_func); - clear_type_list(&cl->class_type_list); vim_free(cl);