Mercurial > vim
comparison 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 |
comparison
equal
deleted
inserted
replaced
31415:4fd33db887f2 | 31416:f088f1d97eee |
---|---|
75 garray_T objmembers; | 75 garray_T objmembers; |
76 ga_init2(&objmembers, sizeof(objmember_T), 10); | 76 ga_init2(&objmembers, sizeof(objmember_T), 10); |
77 | 77 |
78 // Growarray with object methods declared in the class. | 78 // Growarray with object methods declared in the class. |
79 garray_T objmethods; | 79 garray_T objmethods; |
80 ga_init2(&objmethods, sizeof(ufunc_T), 10); | 80 ga_init2(&objmethods, sizeof(ufunc_T *), 10); |
81 | 81 |
82 /* | 82 /* |
83 * Go over the body of the class until "endclass" is found. | 83 * Go over the body of the class until "endclass" is found. |
84 */ | 84 */ |
85 char_u *theline = NULL; | 85 char_u *theline = NULL; |
95 // TODO: | 95 // TODO: |
96 // class members (public, read access, private): | 96 // class members (public, read access, private): |
97 // static varname | 97 // static varname |
98 // public static varname | 98 // public static varname |
99 // static _varname | 99 // static _varname |
100 // | |
101 // constructors: | |
102 // def new() | |
103 // enddef | |
104 // def newOther() | |
105 // enddef | |
106 // | |
107 // methods (object, class, generics): | |
108 // def someMethod() | |
109 // enddef | |
110 // static def someMethod() | |
111 // enddef | |
112 // def <Tval> someMethod() | |
113 // enddef | |
114 // static def <Tval> someMethod() | |
115 // enddef | |
116 | 100 |
117 char_u *p = line; | 101 char_u *p = line; |
118 if (checkforcmd(&p, "endclass", 4)) | 102 if (checkforcmd(&p, "endclass", 4)) |
119 { | 103 { |
120 if (STRNCMP(line, "endclass", 8) != 0) | 104 if (STRNCMP(line, "endclass", 8) != 0) |
170 m->om_name = vim_strnsave(varname, varname_end - varname); | 154 m->om_name = vim_strnsave(varname, varname_end - varname); |
171 m->om_type = type; | 155 m->om_type = type; |
172 ++objmembers.ga_len; | 156 ++objmembers.ga_len; |
173 } | 157 } |
174 | 158 |
159 // constructors: | |
160 // def new() | |
161 // enddef | |
162 // def newOther() | |
163 // enddef | |
164 // methods: | |
165 // def someMethod() | |
166 // enddef | |
167 // TODO: | |
168 // static def someMethod() | |
169 // enddef | |
170 // def <Tval> someMethod() | |
171 // enddef | |
172 // static def <Tval> someMethod() | |
173 // enddef | |
174 else if (checkforcmd(&p, "def", 3)) | |
175 { | |
176 exarg_T ea; | |
177 garray_T lines_to_free; | |
178 | |
179 CLEAR_FIELD(ea); | |
180 ea.cmd = line; | |
181 ea.arg = p; | |
182 ea.cmdidx = CMD_def; | |
183 ea.getline = eap->getline; | |
184 ea.cookie = eap->cookie; | |
185 | |
186 ga_init2(&lines_to_free, sizeof(char_u *), 50); | |
187 ufunc_T *uf = define_function(&ea, NULL, &lines_to_free, TRUE); | |
188 ga_clear_strings(&lines_to_free); | |
189 | |
190 // TODO: how about errors? | |
191 if (uf != NULL && ga_grow(&objmethods, 1) == OK) | |
192 { | |
193 ((ufunc_T **)objmethods.ga_data)[objmethods.ga_len] = uf; | |
194 ++objmethods.ga_len; | |
195 } | |
196 } | |
197 | |
175 else | 198 else |
176 { | 199 { |
177 semsg(_(e_not_valid_command_in_class_str), line); | 200 semsg(_(e_not_valid_command_in_class_str), line); |
178 break; | 201 break; |
179 } | 202 } |
204 sizeof(objmember_T) * objmembers.ga_len); | 227 sizeof(objmember_T) * objmembers.ga_len); |
205 vim_free(objmembers.ga_data); | 228 vim_free(objmembers.ga_data); |
206 | 229 |
207 int have_new = FALSE; | 230 int have_new = FALSE; |
208 for (int i = 0; i < objmethods.ga_len; ++i) | 231 for (int i = 0; i < objmethods.ga_len; ++i) |
209 if (STRCMP((((ufunc_T *)objmethods.ga_data) + i)->uf_name, | 232 if (STRCMP(((ufunc_T **)objmethods.ga_data)[i]->uf_name, |
210 "new") == 0) | 233 "new") == 0) |
211 { | 234 { |
212 have_new = TRUE; | 235 have_new = TRUE; |
213 break; | 236 break; |
214 } | 237 } |
235 fea.cmd = fea.arg = fga.ga_data; | 258 fea.cmd = fea.arg = fga.ga_data; |
236 | 259 |
237 garray_T lines_to_free; | 260 garray_T lines_to_free; |
238 ga_init2(&lines_to_free, sizeof(char_u *), 50); | 261 ga_init2(&lines_to_free, sizeof(char_u *), 50); |
239 | 262 |
240 ufunc_T *nf = define_function(&fea, NULL, &lines_to_free, cl); | 263 ufunc_T *nf = define_function(&fea, NULL, &lines_to_free, TRUE); |
241 | 264 |
242 ga_clear_strings(&lines_to_free); | 265 ga_clear_strings(&lines_to_free); |
243 vim_free(fga.ga_data); | 266 vim_free(fga.ga_data); |
244 | 267 |
245 if (nf != NULL && ga_grow(&objmethods, 1) == OK) | 268 if (nf != NULL && ga_grow(&objmethods, 1) == OK) |
246 { | 269 { |
247 ((ufunc_T **)objmethods.ga_data)[objmethods.ga_len] = nf; | 270 ((ufunc_T **)objmethods.ga_data)[objmethods.ga_len] = nf; |
248 ++objmethods.ga_len; | 271 ++objmethods.ga_len; |
249 | 272 |
250 nf->uf_flags |= FC_NEW; | 273 nf->uf_flags |= FC_NEW; |
251 nf->uf_class = cl; | |
252 nf->uf_ret_type = get_type_ptr(&type_list); | 274 nf->uf_ret_type = get_type_ptr(&type_list); |
253 if (nf->uf_ret_type != NULL) | 275 if (nf->uf_ret_type != NULL) |
254 { | 276 { |
255 nf->uf_ret_type->tt_type = VAR_OBJECT; | 277 nf->uf_ret_type->tt_type = VAR_OBJECT; |
256 nf->uf_ret_type->tt_member = (type_T *)cl; | 278 nf->uf_ret_type->tt_member = (type_T *)cl; |
257 nf->uf_ret_type->tt_argcount = 0; | 279 nf->uf_ret_type->tt_argcount = 0; |
258 nf->uf_ret_type->tt_args = NULL; | 280 nf->uf_ret_type->tt_args = NULL; |
259 } | 281 } |
260 cl->class_new_func = nf; | |
261 } | 282 } |
262 } | 283 } |
263 | 284 |
264 cl->class_obj_method_count = objmethods.ga_len; | 285 cl->class_obj_method_count = objmethods.ga_len; |
265 cl->class_obj_methods = ALLOC_MULT(ufunc_T *, objmethods.ga_len); | 286 cl->class_obj_methods = ALLOC_MULT(ufunc_T *, objmethods.ga_len); |
273 } | 294 } |
274 mch_memmove(cl->class_obj_methods, objmethods.ga_data, | 295 mch_memmove(cl->class_obj_methods, objmethods.ga_data, |
275 sizeof(ufunc_T *) * objmethods.ga_len); | 296 sizeof(ufunc_T *) * objmethods.ga_len); |
276 vim_free(objmethods.ga_data); | 297 vim_free(objmethods.ga_data); |
277 | 298 |
299 // Set the class pointer on all the object methods. | |
300 for (int i = 0; i < objmethods.ga_len; ++i) | |
301 { | |
302 ufunc_T *fp = cl->class_obj_methods[i]; | |
303 fp->uf_class = cl; | |
304 fp->uf_flags |= FC_OBJECT; // TODO: not for class method | |
305 } | |
306 | |
278 cl->class_type.tt_type = VAR_CLASS; | 307 cl->class_type.tt_type = VAR_CLASS; |
279 cl->class_type.tt_member = (type_T *)cl; | 308 cl->class_type.tt_member = (type_T *)cl; |
309 cl->class_object_type.tt_type = VAR_OBJECT; | |
310 cl->class_object_type.tt_member = (type_T *)cl; | |
280 cl->class_type_list = type_list; | 311 cl->class_type_list = type_list; |
281 | 312 |
282 // TODO: | 313 // TODO: |
283 // - Add the methods to the class | 314 // - Add the methods to the class |
284 // - array with ufunc_T pointers | 315 // - array with ufunc_T pointers |
303 objmember_T *m = ((objmember_T *)objmembers.ga_data) + i; | 334 objmember_T *m = ((objmember_T *)objmembers.ga_data) + i; |
304 vim_free(m->om_name); | 335 vim_free(m->om_name); |
305 } | 336 } |
306 ga_clear(&objmembers); | 337 ga_clear(&objmembers); |
307 | 338 |
339 for (int i = 0; i < objmethods.ga_len; ++i) | |
340 { | |
341 ufunc_T *uf = ((ufunc_T **)objmethods.ga_data)[i]; | |
342 func_clear_free(uf, FALSE); | |
343 } | |
308 ga_clear(&objmethods); | 344 ga_clear(&objmethods); |
309 clear_type_list(&type_list); | 345 clear_type_list(&type_list); |
310 } | 346 } |
311 | 347 |
312 /* | 348 /* |
417 return FAIL; | 453 return FAIL; |
418 | 454 |
419 funcexe_T funcexe; | 455 funcexe_T funcexe; |
420 CLEAR_FIELD(funcexe); | 456 CLEAR_FIELD(funcexe); |
421 funcexe.fe_evaluate = TRUE; | 457 funcexe.fe_evaluate = TRUE; |
458 if (rettv->v_type == VAR_OBJECT) | |
459 { | |
460 funcexe.fe_object = rettv->vval.v_object; | |
461 ++funcexe.fe_object->obj_refcount; | |
462 } | |
422 | 463 |
423 // Clear the class or object after calling the function, in | 464 // Clear the class or object after calling the function, in |
424 // case the refcount is one. | 465 // case the refcount is one. |
425 typval_T tv_tofree = *rettv; | 466 typval_T tv_tofree = *rettv; |
426 rettv->v_type = VAR_UNKNOWN; | 467 rettv->v_type = VAR_UNKNOWN; |
427 | 468 |
428 // Call the user function. Result goes into rettv; | 469 // Call the user function. Result goes into rettv; |
429 // TODO: pass the object | |
430 int error = call_user_func_check(fp, argcount, argvars, | 470 int error = call_user_func_check(fp, argcount, argvars, |
431 rettv, &funcexe, NULL); | 471 rettv, &funcexe, NULL); |
432 | 472 |
433 // Clear the previous rettv and the arguments. | 473 // Clear the previous rettv and the arguments. |
434 clear_tv(&tv_tofree); | 474 clear_tv(&tv_tofree); |
543 objmember_T *m = &cl->class_obj_members[i]; | 583 objmember_T *m = &cl->class_obj_members[i]; |
544 vim_free(m->om_name); | 584 vim_free(m->om_name); |
545 } | 585 } |
546 vim_free(cl->class_obj_members); | 586 vim_free(cl->class_obj_members); |
547 | 587 |
588 for (int i = 0; i < cl->class_obj_method_count; ++i) | |
589 { | |
590 ufunc_T *uf = cl->class_obj_methods[i]; | |
591 func_clear_free(uf, FALSE); | |
592 } | |
548 vim_free(cl->class_obj_methods); | 593 vim_free(cl->class_obj_methods); |
549 | |
550 if (cl->class_new_func != NULL) | |
551 func_ptr_unref(cl->class_new_func); | |
552 | 594 |
553 clear_type_list(&cl->class_type_list); | 595 clear_type_list(&cl->class_type_list); |
554 | 596 |
555 vim_free(cl); | 597 vim_free(cl); |
556 } | 598 } |