blob: 1713496529d91baf1689873fb82ec289617fe577 [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);
Bram Moolenaar74e12742022-12-13 21:14:28 +0000128 char_u *type_arg = colon;
129 type_T *type = NULL;
130 if (*colon == ':')
131 {
132 if (VIM_ISWHITE(*varname_end))
133 {
134 semsg(_(e_no_white_space_allowed_before_colon_str),
135 varname);
136 break;
137 }
138 if (!VIM_ISWHITE(colon[1]))
139 {
140 semsg(_(e_white_space_required_after_str_str), ":",
141 varname);
142 break;
143 }
144 type_arg = skipwhite(colon + 1);
145 type = parse_type(&type_arg, &type_list, TRUE);
146 if (type == NULL)
147 break;
148 }
149
150 char_u *expr_start = skipwhite(type_arg);
151 char_u *expr_end = expr_start;
152 if (type == NULL && *expr_start != '=')
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000153 {
154 emsg(_(e_type_or_initialization_required));
155 break;
156 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000157
Bram Moolenaar74e12742022-12-13 21:14:28 +0000158 if (*expr_start == '=')
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000159 {
Bram Moolenaar74e12742022-12-13 21:14:28 +0000160 if (!VIM_ISWHITE(expr_start[-1]) || !VIM_ISWHITE(expr_start[1]))
161 {
162 semsg(_(e_white_space_required_before_and_after_str_at_str),
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000163 "=", type_arg);
Bram Moolenaar74e12742022-12-13 21:14:28 +0000164 break;
165 }
166 expr_start = skipwhite(expr_start + 1);
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000167
Bram Moolenaar74e12742022-12-13 21:14:28 +0000168 expr_end = expr_start;
169 evalarg_T evalarg;
170 fill_evalarg_from_eap(&evalarg, eap, FALSE);
171 skip_expr(&expr_end, &evalarg);
172
173 if (type == NULL)
174 {
175 // No type specified, use the type of the initializer.
176 typval_T tv;
177 tv.v_type = VAR_UNKNOWN;
178 char_u *expr = expr_start;
179 int res = eval0(expr, &tv, eap, &evalarg);
180
181 if (res == OK)
182 type = typval2type(&tv, get_copyID(), &type_list,
183 TVTT_DO_MEMBER);
184 if (type == NULL)
185 {
186 semsg(_(e_cannot_get_object_member_type_from_initializer_str),
187 expr_start);
188 clear_evalarg(&evalarg, NULL);
189 break;
190 }
191 }
192 clear_evalarg(&evalarg, NULL);
193 }
194 if (!valid_declaration_type(type))
195 break;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000196
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000197 if (ga_grow(&objmembers, 1) == FAIL)
198 break;
199 objmember_T *m = ((objmember_T *)objmembers.ga_data)
200 + objmembers.ga_len;
201 m->om_name = vim_strnsave(varname, varname_end - varname);
202 m->om_type = type;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000203 if (expr_end > expr_start)
204 m->om_init = vim_strnsave(expr_start, expr_end - expr_start);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000205 ++objmembers.ga_len;
206 }
207
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000208 // constructors:
209 // def new()
210 // enddef
211 // def newOther()
212 // enddef
213 // methods:
214 // def someMethod()
215 // enddef
216 // TODO:
217 // static def someMethod()
218 // enddef
219 // def <Tval> someMethod()
220 // enddef
221 // static def <Tval> someMethod()
222 // enddef
223 else if (checkforcmd(&p, "def", 3))
224 {
225 exarg_T ea;
226 garray_T lines_to_free;
227
228 CLEAR_FIELD(ea);
229 ea.cmd = line;
230 ea.arg = p;
231 ea.cmdidx = CMD_def;
232 ea.getline = eap->getline;
233 ea.cookie = eap->cookie;
234
235 ga_init2(&lines_to_free, sizeof(char_u *), 50);
236 ufunc_T *uf = define_function(&ea, NULL, &lines_to_free, TRUE);
237 ga_clear_strings(&lines_to_free);
238
239 // TODO: how about errors?
240 if (uf != NULL && ga_grow(&objmethods, 1) == OK)
241 {
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000242 if (STRNCMP(uf->uf_name, "new", 3) == 0)
243 uf->uf_flags |= FC_NEW;
244
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000245 ((ufunc_T **)objmethods.ga_data)[objmethods.ga_len] = uf;
246 ++objmethods.ga_len;
247 }
248 }
249
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000250 else
251 {
252 semsg(_(e_not_valid_command_in_class_str), line);
253 break;
254 }
255 }
256 vim_free(theline);
257
258 if (success)
259 {
260 class_T *cl = ALLOC_CLEAR_ONE(class_T);
261 if (cl == NULL)
262 goto cleanup;
263 cl->class_refcount = 1;
264 cl->class_name = vim_strnsave(arg, name_end - arg);
265
266 // Members are used by the new() function, add them here.
267 cl->class_obj_member_count = objmembers.ga_len;
Bram Moolenaar98aeb212022-12-08 22:09:14 +0000268 cl->class_obj_members = objmembers.ga_len == 0 ? NULL
269 : ALLOC_MULT(objmember_T, objmembers.ga_len);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000270 if (cl->class_name == NULL
Bram Moolenaar98aeb212022-12-08 22:09:14 +0000271 || (objmembers.ga_len > 0 && cl->class_obj_members == NULL))
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000272 {
273 vim_free(cl->class_name);
274 vim_free(cl->class_obj_members);
275 vim_free(cl);
276 goto cleanup;
277 }
278 mch_memmove(cl->class_obj_members, objmembers.ga_data,
279 sizeof(objmember_T) * objmembers.ga_len);
280 vim_free(objmembers.ga_data);
281
282 int have_new = FALSE;
283 for (int i = 0; i < objmethods.ga_len; ++i)
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000284 if (STRCMP(((ufunc_T **)objmethods.ga_data)[i]->uf_name,
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000285 "new") == 0)
286 {
287 have_new = TRUE;
288 break;
289 }
290 if (!have_new)
291 {
292 // No new() method was defined, add the default constructor.
293 garray_T fga;
294 ga_init2(&fga, 1, 1000);
295 ga_concat(&fga, (char_u *)"new(");
296 for (int i = 0; i < cl->class_obj_member_count; ++i)
297 {
298 if (i > 0)
299 ga_concat(&fga, (char_u *)", ");
300 ga_concat(&fga, (char_u *)"this.");
301 objmember_T *m = cl->class_obj_members + i;
302 ga_concat(&fga, (char_u *)m->om_name);
Bram Moolenaar65b0d162022-12-13 18:43:22 +0000303 ga_concat(&fga, (char_u *)" = v:none");
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000304 }
305 ga_concat(&fga, (char_u *)")\nenddef\n");
306 ga_append(&fga, NUL);
307
308 exarg_T fea;
309 CLEAR_FIELD(fea);
310 fea.cmdidx = CMD_def;
311 fea.cmd = fea.arg = fga.ga_data;
312
313 garray_T lines_to_free;
314 ga_init2(&lines_to_free, sizeof(char_u *), 50);
315
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000316 ufunc_T *nf = define_function(&fea, NULL, &lines_to_free, TRUE);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000317
318 ga_clear_strings(&lines_to_free);
319 vim_free(fga.ga_data);
320
321 if (nf != NULL && ga_grow(&objmethods, 1) == OK)
322 {
323 ((ufunc_T **)objmethods.ga_data)[objmethods.ga_len] = nf;
324 ++objmethods.ga_len;
325
326 nf->uf_flags |= FC_NEW;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000327 nf->uf_ret_type = get_type_ptr(&type_list);
328 if (nf->uf_ret_type != NULL)
329 {
330 nf->uf_ret_type->tt_type = VAR_OBJECT;
331 nf->uf_ret_type->tt_member = (type_T *)cl;
332 nf->uf_ret_type->tt_argcount = 0;
333 nf->uf_ret_type->tt_args = NULL;
334 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000335 }
336 }
337
338 cl->class_obj_method_count = objmethods.ga_len;
339 cl->class_obj_methods = ALLOC_MULT(ufunc_T *, objmethods.ga_len);
340 if (cl->class_obj_methods == NULL)
341 {
342 vim_free(cl->class_name);
343 vim_free(cl->class_obj_members);
344 vim_free(cl->class_obj_methods);
345 vim_free(cl);
346 goto cleanup;
347 }
348 mch_memmove(cl->class_obj_methods, objmethods.ga_data,
349 sizeof(ufunc_T *) * objmethods.ga_len);
350 vim_free(objmethods.ga_data);
351
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000352 // Set the class pointer on all the object methods.
353 for (int i = 0; i < objmethods.ga_len; ++i)
354 {
355 ufunc_T *fp = cl->class_obj_methods[i];
356 fp->uf_class = cl;
357 fp->uf_flags |= FC_OBJECT; // TODO: not for class method
358 }
359
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000360 cl->class_type.tt_type = VAR_CLASS;
361 cl->class_type.tt_member = (type_T *)cl;
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000362 cl->class_object_type.tt_type = VAR_OBJECT;
363 cl->class_object_type.tt_member = (type_T *)cl;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000364 cl->class_type_list = type_list;
365
366 // TODO:
367 // - Add the methods to the class
368 // - array with ufunc_T pointers
369 // - Fill hashtab with object members and methods
370 // - Generate the default new() method, if needed.
371 // Later:
372 // - class members
373 // - class methods
374
375 // Add the class to the script-local variables.
376 typval_T tv;
377 tv.v_type = VAR_CLASS;
378 tv.vval.v_class = cl;
379 set_var_const(cl->class_name, current_sctx.sc_sid,
380 NULL, &tv, FALSE, ASSIGN_DECL, 0);
381 return;
382 }
383
384cleanup:
385 for (int i = 0; i < objmembers.ga_len; ++i)
386 {
387 objmember_T *m = ((objmember_T *)objmembers.ga_data) + i;
388 vim_free(m->om_name);
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000389 vim_free(m->om_init);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000390 }
391 ga_clear(&objmembers);
392
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000393 for (int i = 0; i < objmethods.ga_len; ++i)
394 {
395 ufunc_T *uf = ((ufunc_T **)objmethods.ga_data)[i];
396 func_clear_free(uf, FALSE);
397 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000398 ga_clear(&objmethods);
399 clear_type_list(&type_list);
400}
401
402/*
403 * Find member "name" in class "cl" and return its type.
404 * When not found t_any is returned.
405 */
406 type_T *
407class_member_type(
408 class_T *cl,
409 char_u *name,
410 char_u *name_end,
411 int *member_idx)
412{
413 *member_idx = -1; // not found (yet)
414 size_t len = name_end - name;
415
416 for (int i = 0; i < cl->class_obj_member_count; ++i)
417 {
418 objmember_T *m = cl->class_obj_members + i;
419 if (STRNCMP(m->om_name, name, len) == 0 && m->om_name[len] == NUL)
420 {
421 *member_idx = i;
422 return m->om_type;
423 }
424 }
425 return &t_any;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000426}
427
428/*
429 * Handle ":interface" up to ":endinterface".
430 */
431 void
432ex_interface(exarg_T *eap UNUSED)
433{
434 // TODO
435}
436
437/*
438 * Handle ":enum" up to ":endenum".
439 */
440 void
441ex_enum(exarg_T *eap UNUSED)
442{
443 // TODO
444}
445
446/*
447 * Handle ":type".
448 */
449 void
450ex_type(exarg_T *eap UNUSED)
451{
452 // TODO
453}
454
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000455/*
456 * Evaluate what comes after a class:
457 * - class member: SomeClass.varname
458 * - class method: SomeClass.SomeMethod()
459 * - class constructor: SomeClass.new()
460 * - object member: someObject.varname
461 * - object method: someObject.SomeMethod()
462 *
463 * "*arg" points to the '.'.
464 * "*arg" is advanced to after the member name or method call.
465 *
466 * Returns FAIL or OK.
467 */
468 int
469class_object_index(
470 char_u **arg,
471 typval_T *rettv,
472 evalarg_T *evalarg,
473 int verbose UNUSED) // give error messages
474{
475 // int evaluate = evalarg != NULL
476 // && (evalarg->eval_flags & EVAL_EVALUATE);
477
478 if (VIM_ISWHITE((*arg)[1]))
479 {
480 semsg(_(e_no_white_space_allowed_after_str_str), ".", *arg);
481 return FAIL;
482 }
483
484 ++*arg;
485 char_u *name = *arg;
486 char_u *name_end = find_name_end(name, NULL, NULL, FNE_CHECK_START);
487 if (name_end == name)
488 return FAIL;
489 size_t len = name_end - name;
490
491 class_T *cl = rettv->v_type == VAR_CLASS ? rettv->vval.v_class
492 : rettv->vval.v_object->obj_class;
493 if (*name_end == '(')
494 {
495 for (int i = 0; i < cl->class_obj_method_count; ++i)
496 {
497 ufunc_T *fp = cl->class_obj_methods[i];
Bram Moolenaar4ae00572022-12-09 22:49:23 +0000498 // Use a separate pointer to avoid that ASAN complains about
499 // uf_name[] only being 4 characters.
500 char_u *ufname = (char_u *)fp->uf_name;
501 if (STRNCMP(name, ufname, len) == 0 && ufname[len] == NUL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000502 {
503 typval_T argvars[MAX_FUNC_ARGS + 1];
504 int argcount = 0;
505
506 char_u *argp = name_end;
507 int ret = get_func_arguments(&argp, evalarg, 0,
508 argvars, &argcount);
509 if (ret == FAIL)
510 return FAIL;
511
512 funcexe_T funcexe;
513 CLEAR_FIELD(funcexe);
514 funcexe.fe_evaluate = TRUE;
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000515 if (rettv->v_type == VAR_OBJECT)
516 {
517 funcexe.fe_object = rettv->vval.v_object;
518 ++funcexe.fe_object->obj_refcount;
519 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000520
Bram Moolenaard28d7b92022-12-08 20:42:00 +0000521 // Clear the class or object after calling the function, in
522 // case the refcount is one.
523 typval_T tv_tofree = *rettv;
524 rettv->v_type = VAR_UNKNOWN;
525
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000526 // Call the user function. Result goes into rettv;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000527 int error = call_user_func_check(fp, argcount, argvars,
528 rettv, &funcexe, NULL);
529
Bram Moolenaard28d7b92022-12-08 20:42:00 +0000530 // Clear the previous rettv and the arguments.
531 clear_tv(&tv_tofree);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000532 for (int idx = 0; idx < argcount; ++idx)
533 clear_tv(&argvars[idx]);
534
535 if (error != FCERR_NONE)
536 {
537 user_func_error(error, printable_func_name(fp),
538 funcexe.fe_found_var);
539 return FAIL;
540 }
541 *arg = argp;
542 return OK;
543 }
544 }
545
546 semsg(_(e_method_not_found_on_class_str_str), cl->class_name, name);
547 }
548
549 else if (rettv->v_type == VAR_OBJECT)
550 {
551 for (int i = 0; i < cl->class_obj_member_count; ++i)
552 {
553 objmember_T *m = &cl->class_obj_members[i];
554 if (STRNCMP(name, m->om_name, len) == 0 && m->om_name[len] == NUL)
555 {
556 // The object only contains a pointer to the class, the member
557 // values array follows right after that.
558 object_T *obj = rettv->vval.v_object;
559 typval_T *tv = (typval_T *)(obj + 1) + i;
560 copy_tv(tv, rettv);
561 object_unref(obj);
562
563 *arg = name_end;
564 return OK;
565 }
566 }
567
568 semsg(_(e_member_not_found_on_object_str_str), cl->class_name, name);
569 }
570
571 // TODO: class member
572
573 return FAIL;
574}
575
576/*
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000577 * If "arg" points to a class or object method, return it.
578 * Otherwise return NULL.
579 */
580 ufunc_T *
581find_class_func(char_u **arg)
582{
583 char_u *name = *arg;
584 char_u *name_end = find_name_end(name, NULL, NULL, FNE_CHECK_START);
585 if (name_end == name || *name_end != '.')
586 return NULL;
587
588 size_t len = name_end - name;
589 typval_T tv;
590 tv.v_type = VAR_UNKNOWN;
591 if (eval_variable(name, len, 0, &tv, NULL, EVAL_VAR_NOAUTOLOAD) == FAIL)
592 return NULL;
593 if (tv.v_type != VAR_CLASS && tv.v_type != VAR_OBJECT)
594 {
595 clear_tv(&tv);
596 return NULL;
597 }
598
599 class_T *cl = tv.v_type == VAR_CLASS ? tv.vval.v_class
600 : tv.vval.v_object->obj_class;
601 if (cl == NULL)
602 return NULL;
603 char_u *fname = name_end + 1;
604 char_u *fname_end = find_name_end(fname, NULL, NULL, FNE_CHECK_START);
605 if (fname_end == fname)
606 return NULL;
607 len = fname_end - fname;
608
609 for (int i = 0; i < cl->class_obj_method_count; ++i)
610 {
611 ufunc_T *fp = cl->class_obj_methods[i];
612 // Use a separate pointer to avoid that ASAN complains about
613 // uf_name[] only being 4 characters.
614 char_u *ufname = (char_u *)fp->uf_name;
615 if (STRNCMP(fname, ufname, len) == 0 && ufname[len] == NUL)
616 return fp;
617 }
618
619 return NULL;
620}
621
622/*
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000623 * Make a copy of an object.
624 */
625 void
626copy_object(typval_T *from, typval_T *to)
627{
628 *to = *from;
629 if (to->vval.v_object != NULL)
630 ++to->vval.v_object->obj_refcount;
631}
632
633/*
634 * Free an object.
635 */
636 static void
637object_clear(object_T *obj)
638{
639 class_T *cl = obj->obj_class;
640
641 // the member values are just after the object structure
642 typval_T *tv = (typval_T *)(obj + 1);
643 for (int i = 0; i < cl->class_obj_member_count; ++i)
644 clear_tv(tv + i);
645
Bram Moolenaard28d7b92022-12-08 20:42:00 +0000646 // Remove from the list headed by "first_object".
647 object_cleared(obj);
648
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000649 vim_free(obj);
Bram Moolenaard28d7b92022-12-08 20:42:00 +0000650 class_unref(cl);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000651}
652
653/*
654 * Unreference an object.
655 */
656 void
657object_unref(object_T *obj)
658{
659 if (obj != NULL && --obj->obj_refcount <= 0)
660 object_clear(obj);
661}
662
663/*
664 * Make a copy of a class.
665 */
666 void
667copy_class(typval_T *from, typval_T *to)
668{
669 *to = *from;
670 if (to->vval.v_class != NULL)
671 ++to->vval.v_class->class_refcount;
672}
673
674/*
675 * Unreference a class. Free it when the reference count goes down to zero.
676 */
677 void
Bram Moolenaard28d7b92022-12-08 20:42:00 +0000678class_unref(class_T *cl)
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000679{
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000680 if (cl != NULL && --cl->class_refcount <= 0)
681 {
682 vim_free(cl->class_name);
683
684 for (int i = 0; i < cl->class_obj_member_count; ++i)
685 {
686 objmember_T *m = &cl->class_obj_members[i];
687 vim_free(m->om_name);
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000688 vim_free(m->om_init);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000689 }
690 vim_free(cl->class_obj_members);
691
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000692 for (int i = 0; i < cl->class_obj_method_count; ++i)
693 {
694 ufunc_T *uf = cl->class_obj_methods[i];
695 func_clear_free(uf, FALSE);
696 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000697 vim_free(cl->class_obj_methods);
698
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000699 clear_type_list(&cl->class_type_list);
700
701 vim_free(cl);
702 }
703}
704
Bram Moolenaard28d7b92022-12-08 20:42:00 +0000705static object_T *first_object = NULL;
706
707/*
708 * Call this function when an object has been created. It will be added to the
709 * list headed by "first_object".
710 */
711 void
712object_created(object_T *obj)
713{
714 if (first_object != NULL)
715 {
716 obj->obj_next_used = first_object;
717 first_object->obj_prev_used = obj;
718 }
719 first_object = obj;
720}
721
722/*
723 * Call this function when an object has been cleared and is about to be freed.
724 * It is removed from the list headed by "first_object".
725 */
726 void
727object_cleared(object_T *obj)
728{
729 if (obj->obj_next_used != NULL)
730 obj->obj_next_used->obj_prev_used = obj->obj_prev_used;
731 if (obj->obj_prev_used != NULL)
732 obj->obj_prev_used->obj_next_used = obj->obj_next_used;
733 else if (first_object == obj)
734 first_object = obj->obj_next_used;
735}
736
737/*
738 * Go through the list of all objects and free items without "copyID".
739 */
740 int
741object_free_nonref(int copyID)
742{
743 int did_free = FALSE;
744 object_T *next_obj;
745
746 for (object_T *obj = first_object; obj != NULL; obj = next_obj)
747 {
748 next_obj = obj->obj_next_used;
749 if ((obj->obj_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
750 {
751 // Free the object and items it contains.
752 object_clear(obj);
753 did_free = TRUE;
754 }
755 }
756
757 return did_free;
758}
759
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000760
761#endif // FEAT_EVAL