blob: e310dec336dbdf25a969ca7a0bc85a51c979bc34 [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/*
Bram Moolenaard505d172022-12-18 21:42:55 +000025 * Parse a member declaration, both object and class member.
26 * Returns OK or FAIL. When OK then "varname_end" is set to just after the
27 * variable name and "type_ret" is set to the decleared or detected type.
28 * "init_expr" is set to the initialisation expression (allocated), if there is
Bram Moolenaar554d0312023-01-05 19:59:18 +000029 * one. For an interface "init_expr" is NULL.
Bram Moolenaard505d172022-12-18 21:42:55 +000030 */
31 static int
32parse_member(
33 exarg_T *eap,
34 char_u *line,
35 char_u *varname,
36 int has_public, // TRUE if "public" seen before "varname"
37 char_u **varname_end,
38 garray_T *type_list,
39 type_T **type_ret,
40 char_u **init_expr)
41{
42 *varname_end = to_name_end(varname, FALSE);
43 if (*varname == '_' && has_public)
44 {
45 semsg(_(e_public_member_name_cannot_start_with_underscore_str), line);
46 return FAIL;
47 }
48
49 char_u *colon = skipwhite(*varname_end);
50 char_u *type_arg = colon;
51 type_T *type = NULL;
52 if (*colon == ':')
53 {
54 if (VIM_ISWHITE(**varname_end))
55 {
56 semsg(_(e_no_white_space_allowed_before_colon_str), varname);
57 return FAIL;
58 }
59 if (!VIM_ISWHITE(colon[1]))
60 {
61 semsg(_(e_white_space_required_after_str_str), ":", varname);
62 return FAIL;
63 }
64 type_arg = skipwhite(colon + 1);
65 type = parse_type(&type_arg, type_list, TRUE);
66 if (type == NULL)
67 return FAIL;
68 }
69
70 char_u *expr_start = skipwhite(type_arg);
71 char_u *expr_end = expr_start;
72 if (type == NULL && *expr_start != '=')
73 {
74 emsg(_(e_type_or_initialization_required));
75 return FAIL;
76 }
77
78 if (*expr_start == '=')
79 {
80 if (!VIM_ISWHITE(expr_start[-1]) || !VIM_ISWHITE(expr_start[1]))
81 {
82 semsg(_(e_white_space_required_before_and_after_str_at_str),
83 "=", type_arg);
84 return FAIL;
85 }
86 expr_start = skipwhite(expr_start + 1);
87
88 expr_end = expr_start;
89 evalarg_T evalarg;
90 fill_evalarg_from_eap(&evalarg, eap, FALSE);
91 skip_expr(&expr_end, NULL);
92
93 if (type == NULL)
94 {
95 // No type specified, use the type of the initializer.
96 typval_T tv;
97 tv.v_type = VAR_UNKNOWN;
98 char_u *expr = expr_start;
99 int res = eval0(expr, &tv, eap, &evalarg);
100
101 if (res == OK)
Bram Moolenaare83c1332023-01-02 21:04:04 +0000102 {
Bram Moolenaard505d172022-12-18 21:42:55 +0000103 type = typval2type(&tv, get_copyID(), type_list,
104 TVTT_DO_MEMBER);
Bram Moolenaare83c1332023-01-02 21:04:04 +0000105 clear_tv(&tv);
106 }
Bram Moolenaard505d172022-12-18 21:42:55 +0000107 if (type == NULL)
108 {
109 semsg(_(e_cannot_get_object_member_type_from_initializer_str),
110 expr_start);
111 clear_evalarg(&evalarg, NULL);
112 return FAIL;
113 }
114 }
115 clear_evalarg(&evalarg, NULL);
116 }
117 if (!valid_declaration_type(type))
118 return FAIL;
119
120 *type_ret = type;
121 if (expr_end > expr_start)
Bram Moolenaar554d0312023-01-05 19:59:18 +0000122 {
123 if (init_expr == NULL)
124 {
125 emsg(_(e_cannot_initialize_member_in_interface));
126 return FAIL;
127 }
Bram Moolenaard505d172022-12-18 21:42:55 +0000128 *init_expr = vim_strnsave(expr_start, expr_end - expr_start);
Bram Moolenaar554d0312023-01-05 19:59:18 +0000129 }
Bram Moolenaard505d172022-12-18 21:42:55 +0000130 return OK;
131}
132
133/*
134 * Add a member to an object or a class.
135 * Returns OK when successful, "init_expr" will be consumed then.
136 * Returns FAIL otherwise, caller might need to free "init_expr".
137 */
138 static int
139add_member(
140 garray_T *gap,
141 char_u *varname,
142 char_u *varname_end,
143 int has_public,
144 type_T *type,
145 char_u *init_expr)
146{
147 if (ga_grow(gap, 1) == FAIL)
148 return FAIL;
149 ocmember_T *m = ((ocmember_T *)gap->ga_data) + gap->ga_len;
150 m->ocm_name = vim_strnsave(varname, varname_end - varname);
=?UTF-8?q?Ola=20S=C3=B6der?=d8742472023-03-05 13:12:32 +0000151 m->ocm_access = has_public ? VIM_ACCESS_ALL
152 : *varname == '_' ? VIM_ACCESS_PRIVATE : VIM_ACCESS_READ;
Bram Moolenaard505d172022-12-18 21:42:55 +0000153 m->ocm_type = type;
154 if (init_expr != NULL)
155 m->ocm_init = init_expr;
156 ++gap->ga_len;
157 return OK;
158}
159
160/*
161 * Move the class or object members found while parsing a class into the class.
162 * "gap" contains the found members.
Bram Moolenaar83677162023-01-08 19:54:10 +0000163 * "parent_members" points to the members in the parent class (if any)
164 * "parent_count" is the number of members in the parent class
Bram Moolenaard505d172022-12-18 21:42:55 +0000165 * "members" will be set to the newly allocated array of members and
166 * "member_count" set to the number of members.
167 * Returns OK or FAIL.
168 */
169 static int
170add_members_to_class(
171 garray_T *gap,
Bram Moolenaar83677162023-01-08 19:54:10 +0000172 ocmember_T *parent_members,
173 int parent_count,
Bram Moolenaard505d172022-12-18 21:42:55 +0000174 ocmember_T **members,
175 int *member_count)
176{
Bram Moolenaar83677162023-01-08 19:54:10 +0000177 *member_count = parent_count + gap->ga_len;
178 *members = *member_count == 0 ? NULL
179 : ALLOC_MULT(ocmember_T, *member_count);
180 if (*member_count > 0 && *members == NULL)
Bram Moolenaard505d172022-12-18 21:42:55 +0000181 return FAIL;
Bram Moolenaar83677162023-01-08 19:54:10 +0000182 for (int i = 0; i < parent_count; ++i)
183 {
184 // parent members need to be copied
Bram Moolenaarae3205a2023-01-15 20:49:00 +0000185 ocmember_T *m = *members + i;
186 *m = parent_members[i];
187 m->ocm_name = vim_strsave(m->ocm_name);
188 if (m->ocm_init != NULL)
189 m->ocm_init = vim_strsave(m->ocm_init);
Bram Moolenaar83677162023-01-08 19:54:10 +0000190 }
Bram Moolenaar8efdcee2022-12-19 12:18:09 +0000191 if (gap->ga_len > 0)
Bram Moolenaar83677162023-01-08 19:54:10 +0000192 // new members are moved
193 mch_memmove(*members + parent_count,
194 gap->ga_data, sizeof(ocmember_T) * gap->ga_len);
Bram Moolenaard505d172022-12-18 21:42:55 +0000195 VIM_CLEAR(gap->ga_data);
196 return OK;
197}
198
199/*
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000200 * Convert a member index "idx" of interface "itf" to the member index of class
201 * "cl" implementing that interface.
202 */
203 int
Bram Moolenaard0200c82023-01-28 15:19:40 +0000204object_index_from_itf_index(class_T *itf, int is_method, int idx, class_T *cl)
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000205{
Bram Moolenaard0200c82023-01-28 15:19:40 +0000206 if (idx > (is_method ? itf->class_obj_method_count
207 : itf->class_obj_member_count))
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000208 {
209 siemsg("index %d out of range for interface %s", idx, itf->class_name);
210 return 0;
211 }
Yegappan Lakshmanan74cc13c2023-08-13 17:41:26 +0200212
213 // If "cl" is the interface or the class that is extended, then the method
214 // index can be used directly and there is no need to search for the method
215 // index in one of the child classes.
216 if (cl == itf)
217 return idx;
218
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000219 itf2class_T *i2c;
220 for (i2c = itf->class_itf2class; i2c != NULL; i2c = i2c->i2c_next)
Bram Moolenaard0200c82023-01-28 15:19:40 +0000221 if (i2c->i2c_class == cl && i2c->i2c_is_method == is_method)
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000222 break;
223 if (i2c == NULL)
224 {
225 siemsg("class %s not found on interface %s",
226 cl->class_name, itf->class_name);
227 return 0;
228 }
229 int *table = (int *)(i2c + 1);
230 return table[idx];
231}
232
233/*
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200234 * Update the interface class lookup table for the member index on the
235 * interface to the member index in the class implementing the interface.
236 * And a lookup table for the object method index on the interface
237 * to the object method index in the class implementing the interface.
238 * This is also used for updating the lookup table for the extended class
239 * hierarchy.
240 */
241 static int
242update_member_method_lookup_table(
243 class_T *ifcl,
244 class_T *cl,
245 garray_T *objmethods,
246 int pobj_method_offset,
247 int is_interface)
248{
249 if (ifcl == NULL)
250 return OK;
251
252 // Table for members.
253 itf2class_T *if2cl = alloc_clear(sizeof(itf2class_T)
254 + ifcl->class_obj_member_count * sizeof(int));
255 if (if2cl == NULL)
256 return FAIL;
257 if2cl->i2c_next = ifcl->class_itf2class;
258 ifcl->class_itf2class = if2cl;
259 if2cl->i2c_class = cl;
260 if2cl->i2c_is_method = FALSE;
261
262 for (int if_i = 0; if_i < ifcl->class_obj_member_count; ++if_i)
263 for (int cl_i = 0; cl_i < cl->class_obj_member_count; ++cl_i)
264 {
265 if (STRCMP(ifcl->class_obj_members[if_i].ocm_name,
266 cl->class_obj_members[cl_i].ocm_name) == 0)
267 {
268 int *table = (int *)(if2cl + 1);
269 table[if_i] = cl_i;
270 break;
271 }
272 }
273
274 // Table for methods.
275 if2cl = alloc_clear(sizeof(itf2class_T)
276 + ifcl->class_obj_method_count * sizeof(int));
277 if (if2cl == NULL)
278 return FAIL;
279 if2cl->i2c_next = ifcl->class_itf2class;
280 ifcl->class_itf2class = if2cl;
281 if2cl->i2c_class = cl;
282 if2cl->i2c_is_method = TRUE;
283
284 for (int if_i = 0; if_i < ifcl->class_obj_method_count; ++if_i)
285 {
286 int done = FALSE;
287 for (int cl_i = 0; cl_i < objmethods->ga_len; ++cl_i)
288 {
289 if (STRCMP(ifcl->class_obj_methods[if_i]->uf_name,
290 ((ufunc_T **)objmethods->ga_data)[cl_i]->uf_name)
291 == 0)
292 {
293 int *table = (int *)(if2cl + 1);
294 table[if_i] = cl_i;
295 done = TRUE;
296 break;
297 }
298 }
299
300 // extended class object method is not overridden by the child class.
301 // Keep the method declared in one of the parent classes in the
302 // lineage.
303 if (!done && !is_interface)
304 {
305 // If "ifcl" is not the immediate parent of "cl", then search in
306 // the intermediate parent classes.
307 if (cl->class_extends != ifcl)
308 {
309 class_T *parent = cl->class_extends;
310 int method_offset = objmethods->ga_len;
311
312 while (!done && parent != NULL && parent != ifcl)
313 {
314
315 for (int cl_i = 0;
316 cl_i < parent->class_obj_method_count_child; ++cl_i)
317 {
318 if (STRCMP(ifcl->class_obj_methods[if_i]->uf_name,
319 parent->class_obj_methods[cl_i]->uf_name)
320 == 0)
321 {
322 int *table = (int *)(if2cl + 1);
323 table[if_i] = method_offset + cl_i;
324 done = TRUE;
325 break;
326 }
327 }
328 method_offset += parent->class_obj_method_count_child;
329 parent = parent->class_extends;
330 }
331 }
332
333 if (!done)
334 {
335 int *table = (int *)(if2cl + 1);
336 table[if_i] = pobj_method_offset + if_i;
337 }
338 }
339 }
340
341 return OK;
342}
343
344/*
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000345 * Handle ":class" and ":abstract class" up to ":endclass".
Bram Moolenaar554d0312023-01-05 19:59:18 +0000346 * Handle ":interface" up to ":endinterface".
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000347 */
348 void
349ex_class(exarg_T *eap)
350{
Bram Moolenaar83ae6152023-02-25 19:59:31 +0000351 int is_class = eap->cmdidx == CMD_class; // FALSE for :interface
352 long start_lnum = SOURCING_LNUM;
Bram Moolenaar554d0312023-01-05 19:59:18 +0000353
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000354 char_u *arg = eap->arg;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000355 int is_abstract = eap->cmdidx == CMD_abstract;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000356 if (is_abstract)
357 {
358 if (STRNCMP(arg, "class", 5) != 0 || !VIM_ISWHITE(arg[5]))
359 {
360 semsg(_(e_invalid_argument_str), arg);
361 return;
362 }
363 arg = skipwhite(arg + 5);
Bram Moolenaar24a8d062023-01-14 13:12:06 +0000364 is_class = TRUE;
365 }
366
367 if (!current_script_is_vim9()
368 || (cmdmod.cmod_flags & CMOD_LEGACY)
369 || !getline_equal(eap->getline, eap->cookie, getsourceline))
370 {
371 if (is_class)
372 emsg(_(e_class_can_only_be_defined_in_vim9_script));
373 else
374 emsg(_(e_interface_can_only_be_defined_in_vim9_script));
375 return;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000376 }
377
378 if (!ASCII_ISUPPER(*arg))
379 {
Bram Moolenaar554d0312023-01-05 19:59:18 +0000380 if (is_class)
381 semsg(_(e_class_name_must_start_with_uppercase_letter_str), arg);
382 else
383 semsg(_(e_interface_name_must_start_with_uppercase_letter_str),
384 arg);
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000385 return;
386 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000387 char_u *name_end = find_name_end(arg, NULL, NULL, FNE_CHECK_START);
388 if (!IS_WHITE_OR_NUL(*name_end))
389 {
Bram Moolenaar554d0312023-01-05 19:59:18 +0000390 semsg(_(e_white_space_required_after_name_str), arg);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000391 return;
392 }
Bram Moolenaar94674f22023-01-06 18:42:20 +0000393 char_u *name_start = arg;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000394
Bram Moolenaara86655a2023-01-12 17:06:27 +0000395 // "export class" gets used when creating the class, don't use "is_export"
396 // for the items inside the class.
397 int class_export = is_export;
398 is_export = FALSE;
399
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000400 // TODO:
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000401 // generics: <Tkey, Tentry>
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000402
Bram Moolenaar83677162023-01-08 19:54:10 +0000403 // Name for "extends BaseClass"
404 char_u *extends = NULL;
405
Bram Moolenaar94674f22023-01-06 18:42:20 +0000406 // Names for "implements SomeInterface"
407 garray_T ga_impl;
408 ga_init2(&ga_impl, sizeof(char_u *), 5);
409
410 arg = skipwhite(name_end);
411 while (*arg != NUL && *arg != '#' && *arg != '\n')
412 {
413 // TODO:
Bram Moolenaar94674f22023-01-06 18:42:20 +0000414 // specifies SomeInterface
Bram Moolenaar83677162023-01-08 19:54:10 +0000415 if (STRNCMP(arg, "extends", 7) == 0 && IS_WHITE_OR_NUL(arg[7]))
416 {
417 if (extends != NULL)
418 {
419 emsg(_(e_duplicate_extends));
420 goto early_ret;
421 }
422 arg = skipwhite(arg + 7);
423 char_u *end = find_name_end(arg, NULL, NULL, FNE_CHECK_START);
424 if (!IS_WHITE_OR_NUL(*end))
425 {
426 semsg(_(e_white_space_required_after_name_str), arg);
427 goto early_ret;
428 }
429 extends = vim_strnsave(arg, end - arg);
430 if (extends == NULL)
431 goto early_ret;
432
433 arg = skipwhite(end + 1);
434 }
435 else if (STRNCMP(arg, "implements", 10) == 0
436 && IS_WHITE_OR_NUL(arg[10]))
Bram Moolenaar94674f22023-01-06 18:42:20 +0000437 {
Bram Moolenaardf8f9472023-01-07 14:51:03 +0000438 if (ga_impl.ga_len > 0)
439 {
440 emsg(_(e_duplicate_implements));
441 goto early_ret;
442 }
Bram Moolenaar94674f22023-01-06 18:42:20 +0000443 arg = skipwhite(arg + 10);
Bram Moolenaardf8f9472023-01-07 14:51:03 +0000444
445 for (;;)
Bram Moolenaar94674f22023-01-06 18:42:20 +0000446 {
Bram Moolenaardf8f9472023-01-07 14:51:03 +0000447 char_u *impl_end = find_name_end(arg, NULL, NULL,
448 FNE_CHECK_START);
449 if (!IS_WHITE_OR_NUL(*impl_end) && *impl_end != ',')
450 {
451 semsg(_(e_white_space_required_after_name_str), arg);
452 goto early_ret;
453 }
454 char_u *iname = vim_strnsave(arg, impl_end - arg);
455 if (iname == NULL)
456 goto early_ret;
457 for (int i = 0; i < ga_impl.ga_len; ++i)
458 if (STRCMP(((char_u **)ga_impl.ga_data)[i], iname) == 0)
459 {
460 semsg(_(e_duplicate_interface_after_implements_str),
461 iname);
462 vim_free(iname);
463 goto early_ret;
464 }
465 if (ga_add_string(&ga_impl, iname) == FAIL)
466 {
467 vim_free(iname);
468 goto early_ret;
469 }
470 if (*impl_end != ',')
471 {
472 arg = skipwhite(impl_end);
473 break;
474 }
475 arg = skipwhite(impl_end + 1);
Bram Moolenaar94674f22023-01-06 18:42:20 +0000476 }
Bram Moolenaar94674f22023-01-06 18:42:20 +0000477 }
478 else
479 {
480 semsg(_(e_trailing_characters_str), arg);
481early_ret:
Bram Moolenaar83677162023-01-08 19:54:10 +0000482 vim_free(extends);
Bram Moolenaar94674f22023-01-06 18:42:20 +0000483 ga_clear_strings(&ga_impl);
484 return;
485 }
486 }
487
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000488 garray_T type_list; // list of pointers to allocated types
489 ga_init2(&type_list, sizeof(type_T *), 10);
490
Bram Moolenaard505d172022-12-18 21:42:55 +0000491 // Growarray with class members declared in the class.
492 garray_T classmembers;
493 ga_init2(&classmembers, sizeof(ocmember_T), 10);
494
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000495 // Growarray with functions declared in the class.
496 garray_T classfunctions;
497 ga_init2(&classfunctions, sizeof(ufunc_T *), 10);
Bram Moolenaard505d172022-12-18 21:42:55 +0000498
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000499 // Growarray with object members declared in the class.
500 garray_T objmembers;
Bram Moolenaard505d172022-12-18 21:42:55 +0000501 ga_init2(&objmembers, sizeof(ocmember_T), 10);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000502
503 // Growarray with object methods declared in the class.
504 garray_T objmethods;
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000505 ga_init2(&objmethods, sizeof(ufunc_T *), 10);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000506
507 /*
Bram Moolenaar554d0312023-01-05 19:59:18 +0000508 * Go over the body of the class/interface until "endclass" or
509 * "endinterface" is found.
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000510 */
511 char_u *theline = NULL;
512 int success = FALSE;
513 for (;;)
514 {
515 vim_free(theline);
516 theline = eap->getline(':', eap->cookie, 0, GETLINE_CONCAT_ALL);
517 if (theline == NULL)
518 break;
519 char_u *line = skipwhite(theline);
520
Bram Moolenaar418b5472022-12-20 13:38:22 +0000521 // Skip empty and comment lines.
522 if (*line == NUL)
523 continue;
524 if (*line == '#')
525 {
526 if (vim9_bad_comment(line))
527 break;
528 continue;
529 }
530
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000531 char_u *p = line;
Bram Moolenaar554d0312023-01-05 19:59:18 +0000532 char *end_name = is_class ? "endclass" : "endinterface";
533 if (checkforcmd(&p, end_name, is_class ? 4 : 5))
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000534 {
Bram Moolenaar554d0312023-01-05 19:59:18 +0000535 if (STRNCMP(line, end_name, is_class ? 8 : 12) != 0)
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000536 semsg(_(e_command_cannot_be_shortened_str), line);
537 else if (*p == '|' || !ends_excmd2(line, p))
538 semsg(_(e_trailing_characters_str), p);
Bram Moolenaar98aeb212022-12-08 22:09:14 +0000539 else
540 success = TRUE;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000541 break;
542 }
Bram Moolenaar554d0312023-01-05 19:59:18 +0000543 char *wrong_name = is_class ? "endinterface" : "endclass";
544 if (checkforcmd(&p, wrong_name, is_class ? 5 : 4))
545 {
Bram Moolenaar657aea72023-01-27 13:16:19 +0000546 semsg(_(e_invalid_command_str_expected_str), line, end_name);
Bram Moolenaar554d0312023-01-05 19:59:18 +0000547 break;
548 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000549
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000550 int has_public = FALSE;
551 if (checkforcmd(&p, "public", 3))
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000552 {
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000553 if (STRNCMP(line, "public", 6) != 0)
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000554 {
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000555 semsg(_(e_command_cannot_be_shortened_str), line);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000556 break;
557 }
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000558 has_public = TRUE;
559 p = skipwhite(line + 6);
560
Bram Moolenaard505d172022-12-18 21:42:55 +0000561 if (STRNCMP(p, "this", 4) != 0 && STRNCMP(p, "static", 6) != 0)
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000562 {
Bram Moolenaard505d172022-12-18 21:42:55 +0000563 emsg(_(e_public_must_be_followed_by_this_or_static));
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000564 break;
565 }
566 }
Bram Moolenaard505d172022-12-18 21:42:55 +0000567
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000568 int has_static = FALSE;
569 char_u *ps = p;
570 if (checkforcmd(&p, "static", 4))
571 {
572 if (STRNCMP(ps, "static", 6) != 0)
573 {
574 semsg(_(e_command_cannot_be_shortened_str), ps);
575 break;
576 }
577 has_static = TRUE;
578 p = skipwhite(ps + 6);
579 }
580
Bram Moolenaard505d172022-12-18 21:42:55 +0000581 // object members (public, read access, private):
582 // "this._varname"
583 // "this.varname"
584 // "public this.varname"
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000585 if (STRNCMP(p, "this", 4) == 0)
586 {
587 if (p[4] != '.' || !eval_isnamec1(p[5]))
588 {
589 semsg(_(e_invalid_object_member_declaration_str), p);
590 break;
591 }
592 char_u *varname = p + 5;
Bram Moolenaard505d172022-12-18 21:42:55 +0000593 char_u *varname_end = NULL;
Bram Moolenaar74e12742022-12-13 21:14:28 +0000594 type_T *type = NULL;
Bram Moolenaard505d172022-12-18 21:42:55 +0000595 char_u *init_expr = NULL;
596 if (parse_member(eap, line, varname, has_public,
Bram Moolenaar554d0312023-01-05 19:59:18 +0000597 &varname_end, &type_list, &type,
598 is_class ? &init_expr: NULL) == FAIL)
Bram Moolenaard505d172022-12-18 21:42:55 +0000599 break;
600 if (add_member(&objmembers, varname, varname_end,
601 has_public, type, init_expr) == FAIL)
Bram Moolenaar74e12742022-12-13 21:14:28 +0000602 {
Bram Moolenaard505d172022-12-18 21:42:55 +0000603 vim_free(init_expr);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000604 break;
605 }
Bram Moolenaard505d172022-12-18 21:42:55 +0000606 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000607
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000608 // constructors:
609 // def new()
610 // enddef
611 // def newOther()
612 // enddef
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000613 // object methods and class functions:
614 // def SomeMethod()
615 // enddef
616 // static def ClassFunction()
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000617 // enddef
618 // TODO:
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000619 // def <Tval> someMethod()
620 // enddef
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000621 else if (checkforcmd(&p, "def", 3))
622 {
623 exarg_T ea;
624 garray_T lines_to_free;
625
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000626 // TODO: error for "public static def Func()"?
627
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000628 CLEAR_FIELD(ea);
629 ea.cmd = line;
630 ea.arg = p;
631 ea.cmdidx = CMD_def;
632 ea.getline = eap->getline;
633 ea.cookie = eap->cookie;
634
635 ga_init2(&lines_to_free, sizeof(char_u *), 50);
Bram Moolenaar554d0312023-01-05 19:59:18 +0000636 ufunc_T *uf = define_function(&ea, NULL, &lines_to_free,
637 is_class ? CF_CLASS : CF_INTERFACE);
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000638 ga_clear_strings(&lines_to_free);
639
Bram Moolenaar6acf7572023-01-01 19:53:30 +0000640 if (uf != NULL)
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000641 {
Bram Moolenaar58b40092023-01-11 15:59:05 +0000642 char_u *name = uf->uf_name;
643 int is_new = STRNCMP(name, "new", 3) == 0;
Bram Moolenaar24a8d062023-01-14 13:12:06 +0000644 if (is_new && is_abstract)
645 {
646 emsg(_(e_cannot_define_new_function_in_abstract_class));
647 success = FALSE;
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200648 func_clear_free(uf, FALSE);
Bram Moolenaar24a8d062023-01-14 13:12:06 +0000649 break;
650 }
Bram Moolenaar6acf7572023-01-01 19:53:30 +0000651 garray_T *fgap = has_static || is_new
652 ? &classfunctions : &objmethods;
Bram Moolenaar58b40092023-01-11 15:59:05 +0000653 // Check the name isn't used already.
654 for (int i = 0; i < fgap->ga_len; ++i)
655 {
656 char_u *n = ((ufunc_T **)fgap->ga_data)[i]->uf_name;
657 if (STRCMP(name, n) == 0)
658 {
659 semsg(_(e_duplicate_function_str), name);
660 break;
661 }
662 }
663
Bram Moolenaar6acf7572023-01-01 19:53:30 +0000664 if (ga_grow(fgap, 1) == OK)
665 {
666 if (is_new)
667 uf->uf_flags |= FC_NEW;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000668
Bram Moolenaar6acf7572023-01-01 19:53:30 +0000669 ((ufunc_T **)fgap->ga_data)[fgap->ga_len] = uf;
670 ++fgap->ga_len;
671 }
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000672 }
673 }
674
675 // class members
676 else if (has_static)
677 {
678 // class members (public, read access, private):
679 // "static _varname"
680 // "static varname"
681 // "public static varname"
682 char_u *varname = p;
683 char_u *varname_end = NULL;
684 type_T *type = NULL;
685 char_u *init_expr = NULL;
686 if (parse_member(eap, line, varname, has_public,
Bram Moolenaar554d0312023-01-05 19:59:18 +0000687 &varname_end, &type_list, &type,
688 is_class ? &init_expr : NULL) == FAIL)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000689 break;
690 if (add_member(&classmembers, varname, varname_end,
691 has_public, type, init_expr) == FAIL)
692 {
693 vim_free(init_expr);
694 break;
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000695 }
696 }
697
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000698 else
699 {
Bram Moolenaar554d0312023-01-05 19:59:18 +0000700 if (is_class)
701 semsg(_(e_not_valid_command_in_class_str), line);
702 else
703 semsg(_(e_not_valid_command_in_interface_str), line);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000704 break;
705 }
706 }
707 vim_free(theline);
708
Bram Moolenaar83677162023-01-08 19:54:10 +0000709 class_T *extends_cl = NULL; // class from "extends" argument
710
711 /*
712 * Check a few things before defining the class.
713 */
714
715 // Check the "extends" class is valid.
716 if (success && extends != NULL)
717 {
718 typval_T tv;
719 tv.v_type = VAR_UNKNOWN;
Bram Moolenaara86655a2023-01-12 17:06:27 +0000720 if (eval_variable_import(extends, &tv) == FAIL)
Bram Moolenaar83677162023-01-08 19:54:10 +0000721 {
722 semsg(_(e_class_name_not_found_str), extends);
723 success = FALSE;
724 }
725 else
726 {
727 if (tv.v_type != VAR_CLASS
728 || tv.vval.v_class == NULL
729 || (tv.vval.v_class->class_flags & CLASS_INTERFACE) != 0)
730 {
731 semsg(_(e_cannot_extend_str), extends);
732 success = FALSE;
733 }
734 else
735 {
736 extends_cl = tv.vval.v_class;
737 ++extends_cl->class_refcount;
738 }
739 clear_tv(&tv);
740 }
741 }
742 VIM_CLEAR(extends);
743
Bram Moolenaara94bd9d2023-01-12 15:01:32 +0000744 class_T **intf_classes = NULL;
745
Bram Moolenaar83677162023-01-08 19:54:10 +0000746 // Check all "implements" entries are valid.
Bram Moolenaar94674f22023-01-06 18:42:20 +0000747 if (success && ga_impl.ga_len > 0)
748 {
Bram Moolenaara94bd9d2023-01-12 15:01:32 +0000749 intf_classes = ALLOC_CLEAR_MULT(class_T *, ga_impl.ga_len);
750
Bram Moolenaar94674f22023-01-06 18:42:20 +0000751 for (int i = 0; i < ga_impl.ga_len && success; ++i)
752 {
753 char_u *impl = ((char_u **)ga_impl.ga_data)[i];
754 typval_T tv;
755 tv.v_type = VAR_UNKNOWN;
Bram Moolenaara86655a2023-01-12 17:06:27 +0000756 if (eval_variable_import(impl, &tv) == FAIL)
Bram Moolenaar94674f22023-01-06 18:42:20 +0000757 {
758 semsg(_(e_interface_name_not_found_str), impl);
759 success = FALSE;
760 break;
761 }
762
763 if (tv.v_type != VAR_CLASS
764 || tv.vval.v_class == NULL
765 || (tv.vval.v_class->class_flags & CLASS_INTERFACE) == 0)
766 {
767 semsg(_(e_not_valid_interface_str), impl);
768 success = FALSE;
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200769 clear_tv(&tv);
770 break;
Bram Moolenaar94674f22023-01-06 18:42:20 +0000771 }
772
Bram Moolenaar94674f22023-01-06 18:42:20 +0000773 class_T *ifcl = tv.vval.v_class;
Bram Moolenaara94bd9d2023-01-12 15:01:32 +0000774 intf_classes[i] = ifcl;
775 ++ifcl->class_refcount;
776
777 // check the members of the interface match the members of the class
Bram Moolenaar94674f22023-01-06 18:42:20 +0000778 for (int loop = 1; loop <= 2 && success; ++loop)
779 {
780 // loop == 1: check class members
781 // loop == 2: check object members
782 int if_count = loop == 1 ? ifcl->class_class_member_count
783 : ifcl->class_obj_member_count;
784 if (if_count == 0)
785 continue;
786 ocmember_T *if_ms = loop == 1 ? ifcl->class_class_members
787 : ifcl->class_obj_members;
788 ocmember_T *cl_ms = (ocmember_T *)(loop == 1
789 ? classmembers.ga_data
790 : objmembers.ga_data);
791 int cl_count = loop == 1 ? classmembers.ga_len
792 : objmembers.ga_len;
793 for (int if_i = 0; if_i < if_count; ++if_i)
794 {
795 int cl_i;
796 for (cl_i = 0; cl_i < cl_count; ++cl_i)
797 {
798 ocmember_T *m = &cl_ms[cl_i];
799 if (STRCMP(if_ms[if_i].ocm_name, m->ocm_name) == 0)
800 {
801 // TODO: check type
802 break;
803 }
804 }
805 if (cl_i == cl_count)
806 {
807 semsg(_(e_member_str_of_interface_str_not_implemented),
808 if_ms[if_i].ocm_name, impl);
809 success = FALSE;
810 break;
811 }
812 }
813 }
814
815 // check the functions/methods of the interface match the
816 // functions/methods of the class
817 for (int loop = 1; loop <= 2 && success; ++loop)
818 {
819 // loop == 1: check class functions
820 // loop == 2: check object methods
821 int if_count = loop == 1 ? ifcl->class_class_function_count
822 : ifcl->class_obj_method_count;
823 if (if_count == 0)
824 continue;
825 ufunc_T **if_fp = loop == 1 ? ifcl->class_class_functions
826 : ifcl->class_obj_methods;
827 ufunc_T **cl_fp = (ufunc_T **)(loop == 1
828 ? classfunctions.ga_data
829 : objmethods.ga_data);
830 int cl_count = loop == 1 ? classfunctions.ga_len
831 : objmethods.ga_len;
832 for (int if_i = 0; if_i < if_count; ++if_i)
833 {
834 char_u *if_name = if_fp[if_i]->uf_name;
835 int cl_i;
836 for (cl_i = 0; cl_i < cl_count; ++cl_i)
837 {
838 char_u *cl_name = cl_fp[cl_i]->uf_name;
839 if (STRCMP(if_name, cl_name) == 0)
840 {
841 // TODO: check return and argument types
842 break;
843 }
844 }
845 if (cl_i == cl_count)
846 {
847 semsg(_(e_function_str_of_interface_str_not_implemented),
848 if_name, impl);
849 success = FALSE;
850 break;
851 }
852 }
853 }
854
855 clear_tv(&tv);
856 }
857 }
858
Bram Moolenaard40f00c2023-01-13 17:36:49 +0000859 if (success)
860 {
h-east61378a12023-04-18 19:07:29 +0100861 // Check no function argument name is used as a class member.
862 // (Object members are always accessed with "this." prefix, so no need
863 // to check them.)
Bram Moolenaard40f00c2023-01-13 17:36:49 +0000864 for (int loop = 1; loop <= 2 && success; ++loop)
865 {
866 garray_T *gap = loop == 1 ? &classfunctions : &objmethods;
867
868 for (int fi = 0; fi < gap->ga_len && success; ++fi)
869 {
870 ufunc_T *uf = ((ufunc_T **)gap->ga_data)[fi];
871
872 for (int i = 0; i < uf->uf_args.ga_len && success; ++i)
873 {
874 char_u *aname = ((char_u **)uf->uf_args.ga_data)[i];
h-east61378a12023-04-18 19:07:29 +0100875 garray_T *mgap = &classmembers;
876
877 for (int mi = 0; mi < mgap->ga_len; ++mi)
Bram Moolenaard40f00c2023-01-13 17:36:49 +0000878 {
h-east61378a12023-04-18 19:07:29 +0100879 char_u *mname = ((ocmember_T *)mgap->ga_data + mi)
880 ->ocm_name;
881 if (STRCMP(aname, mname) == 0)
Bram Moolenaard40f00c2023-01-13 17:36:49 +0000882 {
h-east61378a12023-04-18 19:07:29 +0100883 success = FALSE;
884
885 if (uf->uf_script_ctx.sc_sid > 0)
886 SOURCING_LNUM = uf->uf_script_ctx.sc_lnum;
887
888 semsg(_(e_argument_already_declared_in_class_str),
Bram Moolenaard40f00c2023-01-13 17:36:49 +0000889 aname);
h-east61378a12023-04-18 19:07:29 +0100890 break;
Bram Moolenaard40f00c2023-01-13 17:36:49 +0000891 }
892 }
893 }
894 }
895 }
896 }
897
898
Bram Moolenaareb533502022-12-14 15:06:11 +0000899 class_T *cl = NULL;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000900 if (success)
901 {
Bram Moolenaard505d172022-12-18 21:42:55 +0000902 // "endclass" encountered without failures: Create the class.
903
Bram Moolenaareb533502022-12-14 15:06:11 +0000904 cl = ALLOC_CLEAR_ONE(class_T);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000905 if (cl == NULL)
906 goto cleanup;
Bram Moolenaar554d0312023-01-05 19:59:18 +0000907 if (!is_class)
908 cl->class_flags = CLASS_INTERFACE;
909
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000910 cl->class_refcount = 1;
Bram Moolenaar94674f22023-01-06 18:42:20 +0000911 cl->class_name = vim_strnsave(name_start, name_end - name_start);
Bram Moolenaard505d172022-12-18 21:42:55 +0000912 if (cl->class_name == NULL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000913 goto cleanup;
Bram Moolenaard505d172022-12-18 21:42:55 +0000914
Bram Moolenaard0200c82023-01-28 15:19:40 +0000915 if (extends_cl != NULL)
916 {
917 cl->class_extends = extends_cl;
918 extends_cl->class_flags |= CLASS_EXTENDED;
919 }
Bram Moolenaar83677162023-01-08 19:54:10 +0000920
Bram Moolenaard505d172022-12-18 21:42:55 +0000921 // Add class and object members to "cl".
922 if (add_members_to_class(&classmembers,
Bram Moolenaar83677162023-01-08 19:54:10 +0000923 extends_cl == NULL ? NULL
924 : extends_cl->class_class_members,
925 extends_cl == NULL ? 0
926 : extends_cl->class_class_member_count,
927 &cl->class_class_members,
928 &cl->class_class_member_count) == FAIL
Bram Moolenaard505d172022-12-18 21:42:55 +0000929 || add_members_to_class(&objmembers,
Bram Moolenaar83677162023-01-08 19:54:10 +0000930 extends_cl == NULL ? NULL
931 : extends_cl->class_obj_members,
932 extends_cl == NULL ? 0
933 : extends_cl->class_obj_member_count,
934 &cl->class_obj_members,
935 &cl->class_obj_member_count) == FAIL)
Bram Moolenaard505d172022-12-18 21:42:55 +0000936 goto cleanup;
937
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000938 if (ga_impl.ga_len > 0)
939 {
940 // Move the "implements" names into the class.
941 cl->class_interface_count = ga_impl.ga_len;
942 cl->class_interfaces = ALLOC_MULT(char_u *, ga_impl.ga_len);
943 if (cl->class_interfaces == NULL)
944 goto cleanup;
945 for (int i = 0; i < ga_impl.ga_len; ++i)
946 cl->class_interfaces[i] = ((char_u **)ga_impl.ga_data)[i];
947 VIM_CLEAR(ga_impl.ga_data);
948 ga_impl.ga_len = 0;
949
Bram Moolenaard0200c82023-01-28 15:19:40 +0000950 cl->class_interfaces_cl = intf_classes;
951 intf_classes = NULL;
952 }
953
954 if (cl->class_interface_count > 0 || extends_cl != NULL)
955 {
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200956 // For each interface add a lookup table for the member index on
957 // the interface to the member index in this class.
958 // And a lookup table for the object method index on the interface
Bram Moolenaard0200c82023-01-28 15:19:40 +0000959 // to the object method index in this class.
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200960 for (int i = 0; i < cl->class_interface_count; ++i)
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000961 {
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200962 class_T *ifcl = cl->class_interfaces_cl[i];
Bram Moolenaard0200c82023-01-28 15:19:40 +0000963
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200964 if (update_member_method_lookup_table(ifcl, cl, &objmethods,
965 0, TRUE) == FAIL)
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000966 goto cleanup;
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200967 }
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000968
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200969 // Update the lookup table for the extended class, if nay
970 if (extends_cl != NULL)
971 {
972 class_T *pclass = extends_cl;
973 int pobj_method_offset = objmethods.ga_len;
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000974
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200975 // Update the entire lineage of extended classes.
976 while (pclass != NULL)
Bram Moolenaard0200c82023-01-28 15:19:40 +0000977 {
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200978 if (update_member_method_lookup_table(pclass, cl,
979 &objmethods, pobj_method_offset, FALSE) ==
980 FAIL)
981 goto cleanup;
Bram Moolenaard0200c82023-01-28 15:19:40 +0000982
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200983 pobj_method_offset += pclass->class_obj_method_count_child;
984 pclass = pclass->class_extends;
Bram Moolenaard0200c82023-01-28 15:19:40 +0000985 }
986 }
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000987 }
988
Bram Moolenaar554d0312023-01-05 19:59:18 +0000989 if (is_class && cl->class_class_member_count > 0)
Bram Moolenaard505d172022-12-18 21:42:55 +0000990 {
991 // Allocate a typval for each class member and initialize it.
992 cl->class_members_tv = ALLOC_CLEAR_MULT(typval_T,
993 cl->class_class_member_count);
994 if (cl->class_members_tv != NULL)
995 for (int i = 0; i < cl->class_class_member_count; ++i)
996 {
997 ocmember_T *m = &cl->class_class_members[i];
998 typval_T *tv = &cl->class_members_tv[i];
999 if (m->ocm_init != NULL)
1000 {
1001 typval_T *etv = eval_expr(m->ocm_init, eap);
1002 if (etv != NULL)
1003 {
1004 *tv = *etv;
1005 vim_free(etv);
1006 }
1007 }
1008 else
1009 {
1010 // TODO: proper default value
1011 tv->v_type = m->ocm_type->tt_type;
1012 tv->vval.v_string = NULL;
1013 }
1014 }
1015 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001016
1017 int have_new = FALSE;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001018 for (int i = 0; i < classfunctions.ga_len; ++i)
1019 if (STRCMP(((ufunc_T **)classfunctions.ga_data)[i]->uf_name,
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001020 "new") == 0)
1021 {
1022 have_new = TRUE;
1023 break;
1024 }
Bram Moolenaar24a8d062023-01-14 13:12:06 +00001025 if (is_class && !is_abstract && !have_new)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001026 {
1027 // No new() method was defined, add the default constructor.
1028 garray_T fga;
1029 ga_init2(&fga, 1, 1000);
1030 ga_concat(&fga, (char_u *)"new(");
1031 for (int i = 0; i < cl->class_obj_member_count; ++i)
1032 {
1033 if (i > 0)
1034 ga_concat(&fga, (char_u *)", ");
1035 ga_concat(&fga, (char_u *)"this.");
Bram Moolenaard505d172022-12-18 21:42:55 +00001036 ocmember_T *m = cl->class_obj_members + i;
1037 ga_concat(&fga, (char_u *)m->ocm_name);
Bram Moolenaar65b0d162022-12-13 18:43:22 +00001038 ga_concat(&fga, (char_u *)" = v:none");
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001039 }
1040 ga_concat(&fga, (char_u *)")\nenddef\n");
1041 ga_append(&fga, NUL);
1042
1043 exarg_T fea;
1044 CLEAR_FIELD(fea);
1045 fea.cmdidx = CMD_def;
1046 fea.cmd = fea.arg = fga.ga_data;
1047
1048 garray_T lines_to_free;
1049 ga_init2(&lines_to_free, sizeof(char_u *), 50);
1050
Bram Moolenaar2c011312023-01-07 10:51:30 +00001051 ufunc_T *nf = define_function(&fea, NULL, &lines_to_free, CF_CLASS);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001052
1053 ga_clear_strings(&lines_to_free);
1054 vim_free(fga.ga_data);
1055
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001056 if (nf != NULL && ga_grow(&classfunctions, 1) == OK)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001057 {
Bram Moolenaar58b40092023-01-11 15:59:05 +00001058 ((ufunc_T **)classfunctions.ga_data)[classfunctions.ga_len]
1059 = nf;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001060 ++classfunctions.ga_len;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001061
1062 nf->uf_flags |= FC_NEW;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001063 nf->uf_ret_type = get_type_ptr(&type_list);
1064 if (nf->uf_ret_type != NULL)
1065 {
1066 nf->uf_ret_type->tt_type = VAR_OBJECT;
Bram Moolenaarb1e32ac2023-02-21 12:38:51 +00001067 nf->uf_ret_type->tt_class = cl;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001068 nf->uf_ret_type->tt_argcount = 0;
1069 nf->uf_ret_type->tt_args = NULL;
1070 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001071 }
1072 }
1073
Bram Moolenaar58b40092023-01-11 15:59:05 +00001074 // Move all the functions into the created class.
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001075 // loop 1: class functions, loop 2: object methods
1076 for (int loop = 1; loop <= 2; ++loop)
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001077 {
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001078 garray_T *gap = loop == 1 ? &classfunctions : &objmethods;
1079 int *fcount = loop == 1 ? &cl->class_class_function_count
1080 : &cl->class_obj_method_count;
1081 ufunc_T ***fup = loop == 1 ? &cl->class_class_functions
1082 : &cl->class_obj_methods;
1083
Bram Moolenaar83677162023-01-08 19:54:10 +00001084 int parent_count = 0;
1085 if (extends_cl != NULL)
1086 // Include functions from the parent.
1087 parent_count = loop == 1
1088 ? extends_cl->class_class_function_count
1089 : extends_cl->class_obj_method_count;
1090
1091 *fcount = parent_count + gap->ga_len;
1092 if (*fcount == 0)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001093 {
1094 *fup = NULL;
1095 continue;
1096 }
Bram Moolenaar83677162023-01-08 19:54:10 +00001097 *fup = ALLOC_MULT(ufunc_T *, *fcount);
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001098 if (*fup == NULL)
1099 goto cleanup;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001100
Ernie Rael114ec812023-06-04 18:11:35 +01001101 if (gap->ga_len != 0)
1102 mch_memmove(*fup, gap->ga_data,
1103 sizeof(ufunc_T *) * gap->ga_len);
Bram Moolenaar58b40092023-01-11 15:59:05 +00001104 vim_free(gap->ga_data);
1105 if (loop == 1)
1106 cl->class_class_function_count_child = gap->ga_len;
1107 else
1108 cl->class_obj_method_count_child = gap->ga_len;
1109
Bram Moolenaar83677162023-01-08 19:54:10 +00001110 int skipped = 0;
1111 for (int i = 0; i < parent_count; ++i)
1112 {
1113 // Copy functions from the parent. Can't use the same
1114 // function, because "uf_class" is different and compilation
1115 // will have a different result.
Bram Moolenaar58b40092023-01-11 15:59:05 +00001116 // Put them after the functions in the current class, object
1117 // methods may be overruled, then "super.Method()" is used to
1118 // find a method from the parent.
Bram Moolenaar83677162023-01-08 19:54:10 +00001119 // Skip "new" functions. TODO: not all of them.
1120 if (loop == 1 && STRNCMP(
1121 extends_cl->class_class_functions[i]->uf_name,
1122 "new", 3) == 0)
1123 ++skipped;
1124 else
Bram Moolenaar58b40092023-01-11 15:59:05 +00001125 {
1126 ufunc_T *pf = (loop == 1
Bram Moolenaar83677162023-01-08 19:54:10 +00001127 ? extends_cl->class_class_functions
Bram Moolenaar58b40092023-01-11 15:59:05 +00001128 : extends_cl->class_obj_methods)[i];
1129 (*fup)[gap->ga_len + i - skipped] = copy_function(pf);
1130
1131 // If the child class overrides a function from the parent
1132 // the signature must be equal.
1133 char_u *pname = pf->uf_name;
1134 for (int ci = 0; ci < gap->ga_len; ++ci)
1135 {
1136 ufunc_T *cf = (*fup)[ci];
1137 char_u *cname = cf->uf_name;
1138 if (STRCMP(pname, cname) == 0)
1139 {
1140 where_T where = WHERE_INIT;
1141 where.wt_func_name = (char *)pname;
1142 (void)check_type(pf->uf_func_type, cf->uf_func_type,
1143 TRUE, where);
1144 }
1145 }
1146 }
Bram Moolenaar83677162023-01-08 19:54:10 +00001147 }
1148
Bram Moolenaar83677162023-01-08 19:54:10 +00001149 *fcount -= skipped;
1150
1151 // Set the class pointer on all the functions and object methods.
1152 for (int i = 0; i < *fcount; ++i)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001153 {
1154 ufunc_T *fp = (*fup)[i];
1155 fp->uf_class = cl;
1156 if (loop == 2)
1157 fp->uf_flags |= FC_OBJECT;
1158 }
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001159 }
1160
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001161 cl->class_type.tt_type = VAR_CLASS;
Bram Moolenaarb1e32ac2023-02-21 12:38:51 +00001162 cl->class_type.tt_class = cl;
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001163 cl->class_object_type.tt_type = VAR_OBJECT;
Bram Moolenaarb1e32ac2023-02-21 12:38:51 +00001164 cl->class_object_type.tt_class = cl;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001165 cl->class_type_list = type_list;
1166
1167 // TODO:
Bram Moolenaard505d172022-12-18 21:42:55 +00001168 // - Fill hashtab with object members and methods ?
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001169
1170 // Add the class to the script-local variables.
Bram Moolenaar94674f22023-01-06 18:42:20 +00001171 // TODO: handle other context, e.g. in a function
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001172 typval_T tv;
1173 tv.v_type = VAR_CLASS;
1174 tv.vval.v_class = cl;
Bram Moolenaara86655a2023-01-12 17:06:27 +00001175 is_export = class_export;
Bram Moolenaar83ae6152023-02-25 19:59:31 +00001176 SOURCING_LNUM = start_lnum;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001177 set_var_const(cl->class_name, current_sctx.sc_sid,
Bram Moolenaar83ae6152023-02-25 19:59:31 +00001178 NULL, &tv, FALSE, 0, 0);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001179 return;
1180 }
1181
1182cleanup:
Bram Moolenaareb533502022-12-14 15:06:11 +00001183 if (cl != NULL)
1184 {
1185 vim_free(cl->class_name);
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001186 vim_free(cl->class_class_functions);
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001187 if (cl->class_interfaces != NULL)
1188 {
1189 for (int i = 0; i < cl->class_interface_count; ++i)
1190 vim_free(cl->class_interfaces[i]);
1191 vim_free(cl->class_interfaces);
1192 }
1193 if (cl->class_interfaces_cl != NULL)
1194 {
1195 for (int i = 0; i < cl->class_interface_count; ++i)
1196 class_unref(cl->class_interfaces_cl[i]);
1197 vim_free(cl->class_interfaces_cl);
1198 }
Bram Moolenaareb533502022-12-14 15:06:11 +00001199 vim_free(cl->class_obj_members);
1200 vim_free(cl->class_obj_methods);
1201 vim_free(cl);
1202 }
1203
Bram Moolenaar83677162023-01-08 19:54:10 +00001204 vim_free(extends);
1205 class_unref(extends_cl);
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001206
1207 if (intf_classes != NULL)
1208 {
1209 for (int i = 0; i < ga_impl.ga_len; ++i)
1210 class_unref(intf_classes[i]);
1211 vim_free(intf_classes);
1212 }
Bram Moolenaar94674f22023-01-06 18:42:20 +00001213 ga_clear_strings(&ga_impl);
1214
Bram Moolenaard505d172022-12-18 21:42:55 +00001215 for (int round = 1; round <= 2; ++round)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001216 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001217 garray_T *gap = round == 1 ? &classmembers : &objmembers;
1218 if (gap->ga_len == 0 || gap->ga_data == NULL)
1219 continue;
1220
1221 for (int i = 0; i < gap->ga_len; ++i)
1222 {
1223 ocmember_T *m = ((ocmember_T *)gap->ga_data) + i;
1224 vim_free(m->ocm_name);
1225 vim_free(m->ocm_init);
1226 }
1227 ga_clear(gap);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001228 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001229
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001230 for (int i = 0; i < objmethods.ga_len; ++i)
1231 {
1232 ufunc_T *uf = ((ufunc_T **)objmethods.ga_data)[i];
1233 func_clear_free(uf, FALSE);
1234 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001235 ga_clear(&objmethods);
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001236
1237 for (int i = 0; i < classfunctions.ga_len; ++i)
1238 {
1239 ufunc_T *uf = ((ufunc_T **)classfunctions.ga_data)[i];
1240 func_clear_free(uf, FALSE);
1241 }
1242 ga_clear(&classfunctions);
1243
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001244 clear_type_list(&type_list);
1245}
1246
1247/*
Bram Moolenaarf54cedd2022-12-23 17:56:27 +00001248 * Find member "name" in class "cl", set "member_idx" to the member index and
1249 * return its type.
1250 * When not found "member_idx" is set to -1 and t_any is returned.
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001251 */
1252 type_T *
1253class_member_type(
1254 class_T *cl,
1255 char_u *name,
1256 char_u *name_end,
1257 int *member_idx)
1258{
1259 *member_idx = -1; // not found (yet)
1260 size_t len = name_end - name;
1261
1262 for (int i = 0; i < cl->class_obj_member_count; ++i)
1263 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001264 ocmember_T *m = cl->class_obj_members + i;
1265 if (STRNCMP(m->ocm_name, name, len) == 0 && m->ocm_name[len] == NUL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001266 {
1267 *member_idx = i;
Bram Moolenaard505d172022-12-18 21:42:55 +00001268 return m->ocm_type;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001269 }
1270 }
Bram Moolenaarf54cedd2022-12-23 17:56:27 +00001271
1272 semsg(_(e_unknown_variable_str), name);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001273 return &t_any;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001274}
1275
1276/*
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001277 * Handle ":enum" up to ":endenum".
1278 */
1279 void
1280ex_enum(exarg_T *eap UNUSED)
1281{
1282 // TODO
1283}
1284
1285/*
1286 * Handle ":type".
1287 */
1288 void
1289ex_type(exarg_T *eap UNUSED)
1290{
1291 // TODO
1292}
1293
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001294/*
1295 * Evaluate what comes after a class:
1296 * - class member: SomeClass.varname
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001297 * - class function: SomeClass.SomeMethod()
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001298 * - class constructor: SomeClass.new()
1299 * - object member: someObject.varname
1300 * - object method: someObject.SomeMethod()
1301 *
1302 * "*arg" points to the '.'.
1303 * "*arg" is advanced to after the member name or method call.
1304 *
1305 * Returns FAIL or OK.
1306 */
1307 int
1308class_object_index(
1309 char_u **arg,
1310 typval_T *rettv,
1311 evalarg_T *evalarg,
1312 int verbose UNUSED) // give error messages
1313{
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001314 if (VIM_ISWHITE((*arg)[1]))
1315 {
1316 semsg(_(e_no_white_space_allowed_after_str_str), ".", *arg);
1317 return FAIL;
1318 }
1319
1320 ++*arg;
1321 char_u *name = *arg;
1322 char_u *name_end = find_name_end(name, NULL, NULL, FNE_CHECK_START);
1323 if (name_end == name)
1324 return FAIL;
1325 size_t len = name_end - name;
1326
Bram Moolenaar552bdca2023-02-17 21:08:50 +00001327 class_T *cl;
1328 if (rettv->v_type == VAR_CLASS)
1329 cl = rettv->vval.v_class;
1330 else // VAR_OBJECT
1331 {
1332 if (rettv->vval.v_object == NULL)
1333 {
1334 emsg(_(e_using_null_object));
1335 return FAIL;
1336 }
1337 cl = rettv->vval.v_object->obj_class;
1338 }
1339
Bram Moolenaard13dd302023-03-11 20:56:35 +00001340 if (cl == NULL)
1341 {
1342 emsg(_(e_incomplete_type));
1343 return FAIL;
1344 }
1345
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001346 if (*name_end == '(')
1347 {
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001348 int on_class = rettv->v_type == VAR_CLASS;
1349 int count = on_class ? cl->class_class_function_count
1350 : cl->class_obj_method_count;
1351 for (int i = 0; i < count; ++i)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001352 {
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001353 ufunc_T *fp = on_class ? cl->class_class_functions[i]
1354 : cl->class_obj_methods[i];
Bram Moolenaar4ae00572022-12-09 22:49:23 +00001355 // Use a separate pointer to avoid that ASAN complains about
1356 // uf_name[] only being 4 characters.
1357 char_u *ufname = (char_u *)fp->uf_name;
1358 if (STRNCMP(name, ufname, len) == 0 && ufname[len] == NUL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001359 {
1360 typval_T argvars[MAX_FUNC_ARGS + 1];
1361 int argcount = 0;
1362
1363 char_u *argp = name_end;
1364 int ret = get_func_arguments(&argp, evalarg, 0,
1365 argvars, &argcount);
1366 if (ret == FAIL)
1367 return FAIL;
1368
1369 funcexe_T funcexe;
1370 CLEAR_FIELD(funcexe);
1371 funcexe.fe_evaluate = TRUE;
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001372 if (rettv->v_type == VAR_OBJECT)
1373 {
1374 funcexe.fe_object = rettv->vval.v_object;
1375 ++funcexe.fe_object->obj_refcount;
1376 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001377
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001378 // Clear the class or object after calling the function, in
1379 // case the refcount is one.
1380 typval_T tv_tofree = *rettv;
1381 rettv->v_type = VAR_UNKNOWN;
1382
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001383 // Call the user function. Result goes into rettv;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001384 int error = call_user_func_check(fp, argcount, argvars,
1385 rettv, &funcexe, NULL);
1386
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001387 // Clear the previous rettv and the arguments.
1388 clear_tv(&tv_tofree);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001389 for (int idx = 0; idx < argcount; ++idx)
1390 clear_tv(&argvars[idx]);
1391
1392 if (error != FCERR_NONE)
1393 {
1394 user_func_error(error, printable_func_name(fp),
1395 funcexe.fe_found_var);
1396 return FAIL;
1397 }
1398 *arg = argp;
1399 return OK;
1400 }
1401 }
1402
1403 semsg(_(e_method_not_found_on_class_str_str), cl->class_name, name);
1404 }
1405
1406 else if (rettv->v_type == VAR_OBJECT)
1407 {
1408 for (int i = 0; i < cl->class_obj_member_count; ++i)
1409 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001410 ocmember_T *m = &cl->class_obj_members[i];
1411 if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001412 {
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001413 if (*name == '_')
1414 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001415 semsg(_(e_cannot_access_private_member_str), m->ocm_name);
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001416 return FAIL;
1417 }
1418
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001419 // The object only contains a pointer to the class, the member
1420 // values array follows right after that.
1421 object_T *obj = rettv->vval.v_object;
1422 typval_T *tv = (typval_T *)(obj + 1) + i;
1423 copy_tv(tv, rettv);
1424 object_unref(obj);
1425
1426 *arg = name_end;
1427 return OK;
1428 }
1429 }
1430
1431 semsg(_(e_member_not_found_on_object_str_str), cl->class_name, name);
1432 }
1433
Bram Moolenaard505d172022-12-18 21:42:55 +00001434 else if (rettv->v_type == VAR_CLASS)
1435 {
1436 // class member
1437 for (int i = 0; i < cl->class_class_member_count; ++i)
1438 {
1439 ocmember_T *m = &cl->class_class_members[i];
1440 if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
1441 {
1442 if (*name == '_')
1443 {
1444 semsg(_(e_cannot_access_private_member_str), m->ocm_name);
1445 return FAIL;
1446 }
1447
1448 typval_T *tv = &cl->class_members_tv[i];
1449 copy_tv(tv, rettv);
1450 class_unref(cl);
1451
1452 *arg = name_end;
1453 return OK;
1454 }
1455 }
1456
1457 semsg(_(e_member_not_found_on_class_str_str), cl->class_name, name);
1458 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001459
1460 return FAIL;
1461}
1462
1463/*
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001464 * If "arg" points to a class or object method, return it.
1465 * Otherwise return NULL.
1466 */
1467 ufunc_T *
1468find_class_func(char_u **arg)
1469{
1470 char_u *name = *arg;
1471 char_u *name_end = find_name_end(name, NULL, NULL, FNE_CHECK_START);
1472 if (name_end == name || *name_end != '.')
1473 return NULL;
1474
1475 size_t len = name_end - name;
1476 typval_T tv;
1477 tv.v_type = VAR_UNKNOWN;
Bram Moolenaar993dbc32023-01-01 20:31:30 +00001478 if (eval_variable(name, (int)len,
1479 0, &tv, NULL, EVAL_VAR_NOAUTOLOAD) == FAIL)
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001480 return NULL;
1481 if (tv.v_type != VAR_CLASS && tv.v_type != VAR_OBJECT)
Bram Moolenaareb533502022-12-14 15:06:11 +00001482 goto fail_after_eval;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001483
1484 class_T *cl = tv.v_type == VAR_CLASS ? tv.vval.v_class
1485 : tv.vval.v_object->obj_class;
1486 if (cl == NULL)
Bram Moolenaareb533502022-12-14 15:06:11 +00001487 goto fail_after_eval;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001488 char_u *fname = name_end + 1;
1489 char_u *fname_end = find_name_end(fname, NULL, NULL, FNE_CHECK_START);
1490 if (fname_end == fname)
Bram Moolenaareb533502022-12-14 15:06:11 +00001491 goto fail_after_eval;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001492 len = fname_end - fname;
1493
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001494 int count = tv.v_type == VAR_CLASS ? cl->class_class_function_count
1495 : cl->class_obj_method_count;
1496 ufunc_T **funcs = tv.v_type == VAR_CLASS ? cl->class_class_functions
1497 : cl->class_obj_methods;
1498 for (int i = 0; i < count; ++i)
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001499 {
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001500 ufunc_T *fp = funcs[i];
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001501 // Use a separate pointer to avoid that ASAN complains about
1502 // uf_name[] only being 4 characters.
1503 char_u *ufname = (char_u *)fp->uf_name;
1504 if (STRNCMP(fname, ufname, len) == 0 && ufname[len] == NUL)
Bram Moolenaareb533502022-12-14 15:06:11 +00001505 {
1506 clear_tv(&tv);
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001507 return fp;
Bram Moolenaareb533502022-12-14 15:06:11 +00001508 }
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001509 }
1510
Bram Moolenaareb533502022-12-14 15:06:11 +00001511fail_after_eval:
1512 clear_tv(&tv);
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001513 return NULL;
1514}
1515
1516/*
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001517 * If "name[len]" is a class member in cctx->ctx_ufunc->uf_class return the
1518 * index in class.class_class_members[].
1519 * If "cl_ret" is not NULL set it to the class.
1520 * Otherwise return -1;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001521 */
1522 int
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001523class_member_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001524{
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001525 if (cctx == NULL || cctx->ctx_ufunc == NULL
1526 || cctx->ctx_ufunc->uf_class == NULL)
1527 return -1;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001528 class_T *cl = cctx->ctx_ufunc->uf_class;
1529
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001530 for (int i = 0; i < cl->class_class_member_count; ++i)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001531 {
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001532 ocmember_T *m = &cl->class_class_members[i];
1533 if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001534 {
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001535 if (cl_ret != NULL)
1536 *cl_ret = cl;
1537 return i;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001538 }
1539 }
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001540 return -1;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001541}
1542
1543/*
Bram Moolenaar62a69232023-01-24 15:07:04 +00001544 * Return TRUE if current context "cctx_arg" is inside class "cl".
1545 * Return FALSE if not.
1546 */
1547 int
1548inside_class(cctx_T *cctx_arg, class_T *cl)
1549{
1550 for (cctx_T *cctx = cctx_arg; cctx != NULL; cctx = cctx->ctx_outer)
1551 if (cctx->ctx_ufunc != NULL && cctx->ctx_ufunc->uf_class == cl)
1552 return TRUE;
1553 return FALSE;
1554}
1555
1556/*
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001557 * Make a copy of an object.
1558 */
1559 void
1560copy_object(typval_T *from, typval_T *to)
1561{
1562 *to = *from;
1563 if (to->vval.v_object != NULL)
1564 ++to->vval.v_object->obj_refcount;
1565}
1566
1567/*
1568 * Free an object.
1569 */
1570 static void
1571object_clear(object_T *obj)
1572{
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01001573 // Avoid a recursive call, it can happen if "obj" has a circular reference.
1574 obj->obj_refcount = INT_MAX;
1575
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001576 class_T *cl = obj->obj_class;
1577
Jia-Ju Bai5b0889b2023-08-13 20:04:04 +02001578 if (!cl)
1579 return;
1580
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001581 // the member values are just after the object structure
1582 typval_T *tv = (typval_T *)(obj + 1);
1583 for (int i = 0; i < cl->class_obj_member_count; ++i)
1584 clear_tv(tv + i);
1585
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001586 // Remove from the list headed by "first_object".
1587 object_cleared(obj);
1588
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001589 vim_free(obj);
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001590 class_unref(cl);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001591}
1592
1593/*
1594 * Unreference an object.
1595 */
1596 void
1597object_unref(object_T *obj)
1598{
1599 if (obj != NULL && --obj->obj_refcount <= 0)
1600 object_clear(obj);
1601}
1602
1603/*
1604 * Make a copy of a class.
1605 */
1606 void
1607copy_class(typval_T *from, typval_T *to)
1608{
1609 *to = *from;
1610 if (to->vval.v_class != NULL)
1611 ++to->vval.v_class->class_refcount;
1612}
1613
1614/*
1615 * Unreference a class. Free it when the reference count goes down to zero.
1616 */
1617 void
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001618class_unref(class_T *cl)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001619{
Bram Moolenaard505d172022-12-18 21:42:55 +00001620 if (cl != NULL && --cl->class_refcount <= 0 && cl->class_name != NULL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001621 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001622 // Freeing what the class contains may recursively come back here.
1623 // Clear "class_name" first, if it is NULL the class does not need to
1624 // be freed.
1625 VIM_CLEAR(cl->class_name);
1626
Bram Moolenaar83677162023-01-08 19:54:10 +00001627 class_unref(cl->class_extends);
1628
Bram Moolenaar94674f22023-01-06 18:42:20 +00001629 for (int i = 0; i < cl->class_interface_count; ++i)
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001630 {
Bram Moolenaar94674f22023-01-06 18:42:20 +00001631 vim_free(((char_u **)cl->class_interfaces)[i]);
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001632 if (cl->class_interfaces_cl[i] != NULL)
1633 class_unref(cl->class_interfaces_cl[i]);
1634 }
Bram Moolenaar94674f22023-01-06 18:42:20 +00001635 vim_free(cl->class_interfaces);
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001636 vim_free(cl->class_interfaces_cl);
Bram Moolenaar94674f22023-01-06 18:42:20 +00001637
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001638 itf2class_T *next;
1639 for (itf2class_T *i2c = cl->class_itf2class; i2c != NULL; i2c = next)
1640 {
1641 next = i2c->i2c_next;
1642 vim_free(i2c);
1643 }
1644
Bram Moolenaard505d172022-12-18 21:42:55 +00001645 for (int i = 0; i < cl->class_class_member_count; ++i)
1646 {
1647 ocmember_T *m = &cl->class_class_members[i];
1648 vim_free(m->ocm_name);
1649 vim_free(m->ocm_init);
1650 if (cl->class_members_tv != NULL)
1651 clear_tv(&cl->class_members_tv[i]);
1652 }
1653 vim_free(cl->class_class_members);
1654 vim_free(cl->class_members_tv);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001655
1656 for (int i = 0; i < cl->class_obj_member_count; ++i)
1657 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001658 ocmember_T *m = &cl->class_obj_members[i];
1659 vim_free(m->ocm_name);
1660 vim_free(m->ocm_init);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001661 }
1662 vim_free(cl->class_obj_members);
1663
Bram Moolenaarec8b74f2023-01-01 14:11:27 +00001664 for (int i = 0; i < cl->class_class_function_count; ++i)
1665 {
1666 ufunc_T *uf = cl->class_class_functions[i];
1667 func_clear_free(uf, FALSE);
1668 }
1669 vim_free(cl->class_class_functions);
1670
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001671 for (int i = 0; i < cl->class_obj_method_count; ++i)
1672 {
1673 ufunc_T *uf = cl->class_obj_methods[i];
1674 func_clear_free(uf, FALSE);
1675 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001676 vim_free(cl->class_obj_methods);
1677
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001678 clear_type_list(&cl->class_type_list);
1679
1680 vim_free(cl);
1681 }
1682}
1683
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001684static object_T *first_object = NULL;
1685
1686/*
1687 * Call this function when an object has been created. It will be added to the
1688 * list headed by "first_object".
1689 */
1690 void
1691object_created(object_T *obj)
1692{
1693 if (first_object != NULL)
1694 {
1695 obj->obj_next_used = first_object;
1696 first_object->obj_prev_used = obj;
1697 }
1698 first_object = obj;
1699}
1700
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01001701static object_T *next_nonref_obj = NULL;
1702
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001703/*
1704 * Call this function when an object has been cleared and is about to be freed.
1705 * It is removed from the list headed by "first_object".
1706 */
1707 void
1708object_cleared(object_T *obj)
1709{
1710 if (obj->obj_next_used != NULL)
1711 obj->obj_next_used->obj_prev_used = obj->obj_prev_used;
1712 if (obj->obj_prev_used != NULL)
1713 obj->obj_prev_used->obj_next_used = obj->obj_next_used;
1714 else if (first_object == obj)
1715 first_object = obj->obj_next_used;
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01001716
1717 // update the next object to check if needed
1718 if (obj == next_nonref_obj)
1719 next_nonref_obj = obj->obj_next_used;
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001720}
1721
1722/*
1723 * Go through the list of all objects and free items without "copyID".
1724 */
1725 int
1726object_free_nonref(int copyID)
1727{
1728 int did_free = FALSE;
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001729
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01001730 for (object_T *obj = first_object; obj != NULL; obj = next_nonref_obj)
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001731 {
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01001732 next_nonref_obj = obj->obj_next_used;
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001733 if ((obj->obj_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
1734 {
1735 // Free the object and items it contains.
1736 object_clear(obj);
1737 did_free = TRUE;
1738 }
1739 }
1740
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01001741 next_nonref_obj = NULL;
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001742 return did_free;
1743}
1744
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001745
1746#endif // FEAT_EVAL