blob: 74a9bf370203418ac5770bcc5bb512969247bf0c [file] [log] [blame]
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * vim9class.c: Vim9 script class support
12 */
13
14#define USING_FLOAT_STUFF
15#include "vim.h"
16
17#if defined(FEAT_EVAL) || defined(PROTO)
18
19// When not generating protos this is included in proto.h
20#ifdef PROTO
21# include "vim9.h"
22#endif
23
24/*
25 * Handle ":class" and ":abstract class" up to ":endclass".
26 */
27 void
28ex_class(exarg_T *eap)
29{
Bram Moolenaar00b28d62022-12-08 15:32:33 +000030 if (!current_script_is_vim9()
31 || (cmdmod.cmod_flags & CMOD_LEGACY)
32 || !getline_equal(eap->getline, eap->cookie, getsourceline))
33 {
34 emsg(_(e_class_can_only_be_defined_in_vim9_script));
35 return;
36 }
Bram Moolenaarc1c365c2022-12-04 20:13:24 +000037
38 char_u *arg = eap->arg;
Bram Moolenaar00b28d62022-12-08 15:32:33 +000039 int is_abstract = eap->cmdidx == CMD_abstract;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +000040 if (is_abstract)
41 {
42 if (STRNCMP(arg, "class", 5) != 0 || !VIM_ISWHITE(arg[5]))
43 {
44 semsg(_(e_invalid_argument_str), arg);
45 return;
46 }
47 arg = skipwhite(arg + 5);
48 }
49
50 if (!ASCII_ISUPPER(*arg))
51 {
52 semsg(_(e_class_name_must_start_with_uppercase_letter_str), arg);
53 return;
54 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +000055 char_u *name_end = find_name_end(arg, NULL, NULL, FNE_CHECK_START);
56 if (!IS_WHITE_OR_NUL(*name_end))
57 {
58 semsg(_(e_white_space_required_after_class_name_str), arg);
59 return;
60 }
Bram Moolenaarc1c365c2022-12-04 20:13:24 +000061
62 // TODO:
Bram Moolenaar00b28d62022-12-08 15:32:33 +000063 // generics: <Tkey, Tentry>
Bram Moolenaarc1c365c2022-12-04 20:13:24 +000064 // extends SomeClass
65 // implements SomeInterface
66 // specifies SomeInterface
Bram Moolenaar00b28d62022-12-08 15:32:33 +000067 // check nothing follows
Bram Moolenaarc1c365c2022-12-04 20:13:24 +000068
Bram Moolenaar00b28d62022-12-08 15:32:33 +000069 // TODO: handle "is_export" if it is set
Bram Moolenaarc1c365c2022-12-04 20:13:24 +000070
Bram Moolenaar00b28d62022-12-08 15:32:33 +000071 garray_T type_list; // list of pointers to allocated types
72 ga_init2(&type_list, sizeof(type_T *), 10);
73
74 // Growarray with object members declared in the class.
75 garray_T objmembers;
76 ga_init2(&objmembers, sizeof(objmember_T), 10);
77
78 // Growarray with object methods declared in the class.
79 garray_T objmethods;
Bram Moolenaarffdaca92022-12-09 21:41:48 +000080 ga_init2(&objmethods, sizeof(ufunc_T *), 10);
Bram Moolenaar00b28d62022-12-08 15:32:33 +000081
82 /*
83 * Go over the body of the class until "endclass" is found.
84 */
85 char_u *theline = NULL;
86 int success = FALSE;
87 for (;;)
88 {
89 vim_free(theline);
90 theline = eap->getline(':', eap->cookie, 0, GETLINE_CONCAT_ALL);
91 if (theline == NULL)
92 break;
93 char_u *line = skipwhite(theline);
94
95 // TODO:
96 // class members (public, read access, private):
97 // static varname
98 // public static varname
99 // static _varname
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000100
101 char_u *p = line;
102 if (checkforcmd(&p, "endclass", 4))
103 {
104 if (STRNCMP(line, "endclass", 8) != 0)
105 semsg(_(e_command_cannot_be_shortened_str), line);
106 else if (*p == '|' || !ends_excmd2(line, p))
107 semsg(_(e_trailing_characters_str), p);
Bram Moolenaar98aeb212022-12-08 22:09:14 +0000108 else
109 success = TRUE;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000110 break;
111 }
112
113 // "this.varname"
114 // "this._varname"
115 // TODO:
116 // "public this.varname"
117 if (STRNCMP(line, "this", 4) == 0)
118 {
119 if (line[4] != '.' || !eval_isnamec1(line[5]))
120 {
121 semsg(_(e_invalid_object_member_declaration_str), line);
122 break;
123 }
124 char_u *varname = line + 5;
125 char_u *varname_end = to_name_end(varname, FALSE);
126
127 char_u *colon = skipwhite(varname_end);
128 // TODO: accept initialization and figure out type from it
129 if (*colon != ':')
130 {
131 emsg(_(e_type_or_initialization_required));
132 break;
133 }
134 if (VIM_ISWHITE(*varname_end))
135 {
136 semsg(_(e_no_white_space_allowed_before_colon_str), varname);
137 break;
138 }
139 if (!VIM_ISWHITE(colon[1]))
140 {
141 semsg(_(e_white_space_required_after_str_str), ":", varname);
142 break;
143 }
144
145 char_u *type_arg = skipwhite(colon + 1);
146 type_T *type = parse_type(&type_arg, &type_list, TRUE);
147 if (type == NULL)
148 break;
149
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000150 char_u *expr_start = skipwhite(type_arg);
151 if (*expr_start == '=' && (!VIM_ISWHITE(expr_start[-1])
152 || !VIM_ISWHITE(expr_start[1])))
153 {
154 semsg(_(e_white_space_required_before_and_after_str_at_str),
155 "=", type_arg);
156 break;
157 }
158 expr_start = skipwhite(expr_start + 1);
159
160 char_u *expr_end = expr_start;
161 evalarg_T evalarg;
162 init_evalarg(&evalarg);
163 skip_expr(&expr_end, &evalarg);
164 clear_evalarg(&evalarg, NULL);
165
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000166 if (ga_grow(&objmembers, 1) == FAIL)
167 break;
168 objmember_T *m = ((objmember_T *)objmembers.ga_data)
169 + objmembers.ga_len;
170 m->om_name = vim_strnsave(varname, varname_end - varname);
171 m->om_type = type;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000172 if (expr_end > expr_start)
173 m->om_init = vim_strnsave(expr_start, expr_end - expr_start);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000174 ++objmembers.ga_len;
175 }
176
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000177 // constructors:
178 // def new()
179 // enddef
180 // def newOther()
181 // enddef
182 // methods:
183 // def someMethod()
184 // enddef
185 // TODO:
186 // static def someMethod()
187 // enddef
188 // def <Tval> someMethod()
189 // enddef
190 // static def <Tval> someMethod()
191 // enddef
192 else if (checkforcmd(&p, "def", 3))
193 {
194 exarg_T ea;
195 garray_T lines_to_free;
196
197 CLEAR_FIELD(ea);
198 ea.cmd = line;
199 ea.arg = p;
200 ea.cmdidx = CMD_def;
201 ea.getline = eap->getline;
202 ea.cookie = eap->cookie;
203
204 ga_init2(&lines_to_free, sizeof(char_u *), 50);
205 ufunc_T *uf = define_function(&ea, NULL, &lines_to_free, TRUE);
206 ga_clear_strings(&lines_to_free);
207
208 // TODO: how about errors?
209 if (uf != NULL && ga_grow(&objmethods, 1) == OK)
210 {
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000211 if (STRNCMP(uf->uf_name, "new", 3) == 0)
212 uf->uf_flags |= FC_NEW;
213
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000214 ((ufunc_T **)objmethods.ga_data)[objmethods.ga_len] = uf;
215 ++objmethods.ga_len;
216 }
217 }
218
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000219 else
220 {
221 semsg(_(e_not_valid_command_in_class_str), line);
222 break;
223 }
224 }
225 vim_free(theline);
226
227 if (success)
228 {
229 class_T *cl = ALLOC_CLEAR_ONE(class_T);
230 if (cl == NULL)
231 goto cleanup;
232 cl->class_refcount = 1;
233 cl->class_name = vim_strnsave(arg, name_end - arg);
234
235 // Members are used by the new() function, add them here.
236 cl->class_obj_member_count = objmembers.ga_len;
Bram Moolenaar98aeb212022-12-08 22:09:14 +0000237 cl->class_obj_members = objmembers.ga_len == 0 ? NULL
238 : ALLOC_MULT(objmember_T, objmembers.ga_len);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000239 if (cl->class_name == NULL
Bram Moolenaar98aeb212022-12-08 22:09:14 +0000240 || (objmembers.ga_len > 0 && cl->class_obj_members == NULL))
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000241 {
242 vim_free(cl->class_name);
243 vim_free(cl->class_obj_members);
244 vim_free(cl);
245 goto cleanup;
246 }
247 mch_memmove(cl->class_obj_members, objmembers.ga_data,
248 sizeof(objmember_T) * objmembers.ga_len);
249 vim_free(objmembers.ga_data);
250
251 int have_new = FALSE;
252 for (int i = 0; i < objmethods.ga_len; ++i)
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000253 if (STRCMP(((ufunc_T **)objmethods.ga_data)[i]->uf_name,
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000254 "new") == 0)
255 {
256 have_new = TRUE;
257 break;
258 }
259 if (!have_new)
260 {
261 // No new() method was defined, add the default constructor.
262 garray_T fga;
263 ga_init2(&fga, 1, 1000);
264 ga_concat(&fga, (char_u *)"new(");
265 for (int i = 0; i < cl->class_obj_member_count; ++i)
266 {
267 if (i > 0)
268 ga_concat(&fga, (char_u *)", ");
269 ga_concat(&fga, (char_u *)"this.");
270 objmember_T *m = cl->class_obj_members + i;
271 ga_concat(&fga, (char_u *)m->om_name);
Bram Moolenaar65b0d162022-12-13 18:43:22 +0000272 ga_concat(&fga, (char_u *)" = v:none");
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000273 }
274 ga_concat(&fga, (char_u *)")\nenddef\n");
275 ga_append(&fga, NUL);
276
277 exarg_T fea;
278 CLEAR_FIELD(fea);
279 fea.cmdidx = CMD_def;
280 fea.cmd = fea.arg = fga.ga_data;
281
282 garray_T lines_to_free;
283 ga_init2(&lines_to_free, sizeof(char_u *), 50);
284
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000285 ufunc_T *nf = define_function(&fea, NULL, &lines_to_free, TRUE);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000286
287 ga_clear_strings(&lines_to_free);
288 vim_free(fga.ga_data);
289
290 if (nf != NULL && ga_grow(&objmethods, 1) == OK)
291 {
292 ((ufunc_T **)objmethods.ga_data)[objmethods.ga_len] = nf;
293 ++objmethods.ga_len;
294
295 nf->uf_flags |= FC_NEW;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000296 nf->uf_ret_type = get_type_ptr(&type_list);
297 if (nf->uf_ret_type != NULL)
298 {
299 nf->uf_ret_type->tt_type = VAR_OBJECT;
300 nf->uf_ret_type->tt_member = (type_T *)cl;
301 nf->uf_ret_type->tt_argcount = 0;
302 nf->uf_ret_type->tt_args = NULL;
303 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000304 }
305 }
306
307 cl->class_obj_method_count = objmethods.ga_len;
308 cl->class_obj_methods = ALLOC_MULT(ufunc_T *, objmethods.ga_len);
309 if (cl->class_obj_methods == NULL)
310 {
311 vim_free(cl->class_name);
312 vim_free(cl->class_obj_members);
313 vim_free(cl->class_obj_methods);
314 vim_free(cl);
315 goto cleanup;
316 }
317 mch_memmove(cl->class_obj_methods, objmethods.ga_data,
318 sizeof(ufunc_T *) * objmethods.ga_len);
319 vim_free(objmethods.ga_data);
320
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000321 // Set the class pointer on all the object methods.
322 for (int i = 0; i < objmethods.ga_len; ++i)
323 {
324 ufunc_T *fp = cl->class_obj_methods[i];
325 fp->uf_class = cl;
326 fp->uf_flags |= FC_OBJECT; // TODO: not for class method
327 }
328
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000329 cl->class_type.tt_type = VAR_CLASS;
330 cl->class_type.tt_member = (type_T *)cl;
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000331 cl->class_object_type.tt_type = VAR_OBJECT;
332 cl->class_object_type.tt_member = (type_T *)cl;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000333 cl->class_type_list = type_list;
334
335 // TODO:
336 // - Add the methods to the class
337 // - array with ufunc_T pointers
338 // - Fill hashtab with object members and methods
339 // - Generate the default new() method, if needed.
340 // Later:
341 // - class members
342 // - class methods
343
344 // Add the class to the script-local variables.
345 typval_T tv;
346 tv.v_type = VAR_CLASS;
347 tv.vval.v_class = cl;
348 set_var_const(cl->class_name, current_sctx.sc_sid,
349 NULL, &tv, FALSE, ASSIGN_DECL, 0);
350 return;
351 }
352
353cleanup:
354 for (int i = 0; i < objmembers.ga_len; ++i)
355 {
356 objmember_T *m = ((objmember_T *)objmembers.ga_data) + i;
357 vim_free(m->om_name);
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000358 vim_free(m->om_init);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000359 }
360 ga_clear(&objmembers);
361
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000362 for (int i = 0; i < objmethods.ga_len; ++i)
363 {
364 ufunc_T *uf = ((ufunc_T **)objmethods.ga_data)[i];
365 func_clear_free(uf, FALSE);
366 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000367 ga_clear(&objmethods);
368 clear_type_list(&type_list);
369}
370
371/*
372 * Find member "name" in class "cl" and return its type.
373 * When not found t_any is returned.
374 */
375 type_T *
376class_member_type(
377 class_T *cl,
378 char_u *name,
379 char_u *name_end,
380 int *member_idx)
381{
382 *member_idx = -1; // not found (yet)
383 size_t len = name_end - name;
384
385 for (int i = 0; i < cl->class_obj_member_count; ++i)
386 {
387 objmember_T *m = cl->class_obj_members + i;
388 if (STRNCMP(m->om_name, name, len) == 0 && m->om_name[len] == NUL)
389 {
390 *member_idx = i;
391 return m->om_type;
392 }
393 }
394 return &t_any;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000395}
396
397/*
398 * Handle ":interface" up to ":endinterface".
399 */
400 void
401ex_interface(exarg_T *eap UNUSED)
402{
403 // TODO
404}
405
406/*
407 * Handle ":enum" up to ":endenum".
408 */
409 void
410ex_enum(exarg_T *eap UNUSED)
411{
412 // TODO
413}
414
415/*
416 * Handle ":type".
417 */
418 void
419ex_type(exarg_T *eap UNUSED)
420{
421 // TODO
422}
423
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000424/*
425 * Evaluate what comes after a class:
426 * - class member: SomeClass.varname
427 * - class method: SomeClass.SomeMethod()
428 * - class constructor: SomeClass.new()
429 * - object member: someObject.varname
430 * - object method: someObject.SomeMethod()
431 *
432 * "*arg" points to the '.'.
433 * "*arg" is advanced to after the member name or method call.
434 *
435 * Returns FAIL or OK.
436 */
437 int
438class_object_index(
439 char_u **arg,
440 typval_T *rettv,
441 evalarg_T *evalarg,
442 int verbose UNUSED) // give error messages
443{
444 // int evaluate = evalarg != NULL
445 // && (evalarg->eval_flags & EVAL_EVALUATE);
446
447 if (VIM_ISWHITE((*arg)[1]))
448 {
449 semsg(_(e_no_white_space_allowed_after_str_str), ".", *arg);
450 return FAIL;
451 }
452
453 ++*arg;
454 char_u *name = *arg;
455 char_u *name_end = find_name_end(name, NULL, NULL, FNE_CHECK_START);
456 if (name_end == name)
457 return FAIL;
458 size_t len = name_end - name;
459
460 class_T *cl = rettv->v_type == VAR_CLASS ? rettv->vval.v_class
461 : rettv->vval.v_object->obj_class;
462 if (*name_end == '(')
463 {
464 for (int i = 0; i < cl->class_obj_method_count; ++i)
465 {
466 ufunc_T *fp = cl->class_obj_methods[i];
Bram Moolenaar4ae00572022-12-09 22:49:23 +0000467 // Use a separate pointer to avoid that ASAN complains about
468 // uf_name[] only being 4 characters.
469 char_u *ufname = (char_u *)fp->uf_name;
470 if (STRNCMP(name, ufname, len) == 0 && ufname[len] == NUL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000471 {
472 typval_T argvars[MAX_FUNC_ARGS + 1];
473 int argcount = 0;
474
475 char_u *argp = name_end;
476 int ret = get_func_arguments(&argp, evalarg, 0,
477 argvars, &argcount);
478 if (ret == FAIL)
479 return FAIL;
480
481 funcexe_T funcexe;
482 CLEAR_FIELD(funcexe);
483 funcexe.fe_evaluate = TRUE;
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000484 if (rettv->v_type == VAR_OBJECT)
485 {
486 funcexe.fe_object = rettv->vval.v_object;
487 ++funcexe.fe_object->obj_refcount;
488 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000489
Bram Moolenaard28d7b92022-12-08 20:42:00 +0000490 // Clear the class or object after calling the function, in
491 // case the refcount is one.
492 typval_T tv_tofree = *rettv;
493 rettv->v_type = VAR_UNKNOWN;
494
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000495 // Call the user function. Result goes into rettv;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000496 int error = call_user_func_check(fp, argcount, argvars,
497 rettv, &funcexe, NULL);
498
Bram Moolenaard28d7b92022-12-08 20:42:00 +0000499 // Clear the previous rettv and the arguments.
500 clear_tv(&tv_tofree);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000501 for (int idx = 0; idx < argcount; ++idx)
502 clear_tv(&argvars[idx]);
503
504 if (error != FCERR_NONE)
505 {
506 user_func_error(error, printable_func_name(fp),
507 funcexe.fe_found_var);
508 return FAIL;
509 }
510 *arg = argp;
511 return OK;
512 }
513 }
514
515 semsg(_(e_method_not_found_on_class_str_str), cl->class_name, name);
516 }
517
518 else if (rettv->v_type == VAR_OBJECT)
519 {
520 for (int i = 0; i < cl->class_obj_member_count; ++i)
521 {
522 objmember_T *m = &cl->class_obj_members[i];
523 if (STRNCMP(name, m->om_name, len) == 0 && m->om_name[len] == NUL)
524 {
525 // The object only contains a pointer to the class, the member
526 // values array follows right after that.
527 object_T *obj = rettv->vval.v_object;
528 typval_T *tv = (typval_T *)(obj + 1) + i;
529 copy_tv(tv, rettv);
530 object_unref(obj);
531
532 *arg = name_end;
533 return OK;
534 }
535 }
536
537 semsg(_(e_member_not_found_on_object_str_str), cl->class_name, name);
538 }
539
540 // TODO: class member
541
542 return FAIL;
543}
544
545/*
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000546 * If "arg" points to a class or object method, return it.
547 * Otherwise return NULL.
548 */
549 ufunc_T *
550find_class_func(char_u **arg)
551{
552 char_u *name = *arg;
553 char_u *name_end = find_name_end(name, NULL, NULL, FNE_CHECK_START);
554 if (name_end == name || *name_end != '.')
555 return NULL;
556
557 size_t len = name_end - name;
558 typval_T tv;
559 tv.v_type = VAR_UNKNOWN;
560 if (eval_variable(name, len, 0, &tv, NULL, EVAL_VAR_NOAUTOLOAD) == FAIL)
561 return NULL;
562 if (tv.v_type != VAR_CLASS && tv.v_type != VAR_OBJECT)
563 {
564 clear_tv(&tv);
565 return NULL;
566 }
567
568 class_T *cl = tv.v_type == VAR_CLASS ? tv.vval.v_class
569 : tv.vval.v_object->obj_class;
570 if (cl == NULL)
571 return NULL;
572 char_u *fname = name_end + 1;
573 char_u *fname_end = find_name_end(fname, NULL, NULL, FNE_CHECK_START);
574 if (fname_end == fname)
575 return NULL;
576 len = fname_end - fname;
577
578 for (int i = 0; i < cl->class_obj_method_count; ++i)
579 {
580 ufunc_T *fp = cl->class_obj_methods[i];
581 // Use a separate pointer to avoid that ASAN complains about
582 // uf_name[] only being 4 characters.
583 char_u *ufname = (char_u *)fp->uf_name;
584 if (STRNCMP(fname, ufname, len) == 0 && ufname[len] == NUL)
585 return fp;
586 }
587
588 return NULL;
589}
590
591/*
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000592 * Make a copy of an object.
593 */
594 void
595copy_object(typval_T *from, typval_T *to)
596{
597 *to = *from;
598 if (to->vval.v_object != NULL)
599 ++to->vval.v_object->obj_refcount;
600}
601
602/*
603 * Free an object.
604 */
605 static void
606object_clear(object_T *obj)
607{
608 class_T *cl = obj->obj_class;
609
610 // the member values are just after the object structure
611 typval_T *tv = (typval_T *)(obj + 1);
612 for (int i = 0; i < cl->class_obj_member_count; ++i)
613 clear_tv(tv + i);
614
Bram Moolenaard28d7b92022-12-08 20:42:00 +0000615 // Remove from the list headed by "first_object".
616 object_cleared(obj);
617
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000618 vim_free(obj);
Bram Moolenaard28d7b92022-12-08 20:42:00 +0000619 class_unref(cl);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000620}
621
622/*
623 * Unreference an object.
624 */
625 void
626object_unref(object_T *obj)
627{
628 if (obj != NULL && --obj->obj_refcount <= 0)
629 object_clear(obj);
630}
631
632/*
633 * Make a copy of a class.
634 */
635 void
636copy_class(typval_T *from, typval_T *to)
637{
638 *to = *from;
639 if (to->vval.v_class != NULL)
640 ++to->vval.v_class->class_refcount;
641}
642
643/*
644 * Unreference a class. Free it when the reference count goes down to zero.
645 */
646 void
Bram Moolenaard28d7b92022-12-08 20:42:00 +0000647class_unref(class_T *cl)
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000648{
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000649 if (cl != NULL && --cl->class_refcount <= 0)
650 {
651 vim_free(cl->class_name);
652
653 for (int i = 0; i < cl->class_obj_member_count; ++i)
654 {
655 objmember_T *m = &cl->class_obj_members[i];
656 vim_free(m->om_name);
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000657 vim_free(m->om_init);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000658 }
659 vim_free(cl->class_obj_members);
660
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000661 for (int i = 0; i < cl->class_obj_method_count; ++i)
662 {
663 ufunc_T *uf = cl->class_obj_methods[i];
664 func_clear_free(uf, FALSE);
665 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000666 vim_free(cl->class_obj_methods);
667
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000668 clear_type_list(&cl->class_type_list);
669
670 vim_free(cl);
671 }
672}
673
Bram Moolenaard28d7b92022-12-08 20:42:00 +0000674static object_T *first_object = NULL;
675
676/*
677 * Call this function when an object has been created. It will be added to the
678 * list headed by "first_object".
679 */
680 void
681object_created(object_T *obj)
682{
683 if (first_object != NULL)
684 {
685 obj->obj_next_used = first_object;
686 first_object->obj_prev_used = obj;
687 }
688 first_object = obj;
689}
690
691/*
692 * Call this function when an object has been cleared and is about to be freed.
693 * It is removed from the list headed by "first_object".
694 */
695 void
696object_cleared(object_T *obj)
697{
698 if (obj->obj_next_used != NULL)
699 obj->obj_next_used->obj_prev_used = obj->obj_prev_used;
700 if (obj->obj_prev_used != NULL)
701 obj->obj_prev_used->obj_next_used = obj->obj_next_used;
702 else if (first_object == obj)
703 first_object = obj->obj_next_used;
704}
705
706/*
707 * Go through the list of all objects and free items without "copyID".
708 */
709 int
710object_free_nonref(int copyID)
711{
712 int did_free = FALSE;
713 object_T *next_obj;
714
715 for (object_T *obj = first_object; obj != NULL; obj = next_obj)
716 {
717 next_obj = obj->obj_next_used;
718 if ((obj->obj_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
719 {
720 // Free the object and items it contains.
721 object_clear(obj);
722 did_free = TRUE;
723 }
724 }
725
726 return did_free;
727}
728
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000729
730#endif // FEAT_EVAL