blob: cc4410d510b8ab8700ce71aae8fd36b878fd46fd [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
Yegappan Lakshmanane651e112023-09-04 07:51:01 +020024static class_T *first_class = NULL;
25static class_T *next_nonref_class = NULL;
26
27/*
28 * Call this function when a class has been created. It will be added to the
29 * list headed by "first_class".
30 */
31 static void
32class_created(class_T *cl)
33{
34 if (first_class != NULL)
35 {
36 cl->class_next_used = first_class;
37 first_class->class_prev_used = cl;
38 }
39 first_class = cl;
40}
41
42/*
43 * Call this function when a class has been cleared and is about to be freed.
44 * It is removed from the list headed by "first_class".
45 */
46 static void
47class_cleared(class_T *cl)
48{
49 if (cl->class_next_used != NULL)
50 cl->class_next_used->class_prev_used = cl->class_prev_used;
51 if (cl->class_prev_used != NULL)
52 cl->class_prev_used->class_next_used = cl->class_next_used;
53 else if (first_class == cl)
54 first_class = cl->class_next_used;
55
56 // update the next class to check if needed
57 if (cl == next_nonref_class)
58 next_nonref_class = cl->class_next_used;
59}
60
Bram Moolenaarc1c365c2022-12-04 20:13:24 +000061/*
Bram Moolenaard505d172022-12-18 21:42:55 +000062 * Parse a member declaration, both object and class member.
63 * Returns OK or FAIL. When OK then "varname_end" is set to just after the
Yegappan Lakshmanan2ba9d2e2023-08-28 21:26:23 +020064 * variable name and "type_ret" is set to the declared or detected type.
Bram Moolenaard505d172022-12-18 21:42:55 +000065 * "init_expr" is set to the initialisation expression (allocated), if there is
Bram Moolenaar554d0312023-01-05 19:59:18 +000066 * one. For an interface "init_expr" is NULL.
Bram Moolenaard505d172022-12-18 21:42:55 +000067 */
68 static int
69parse_member(
Yegappan Lakshmananeb91e242023-08-31 18:10:46 +020070 exarg_T *eap,
71 char_u *line,
72 char_u *varname,
Yegappan Lakshmanan3775f772023-09-01 22:05:45 +020073 int has_public, // TRUE if "public" seen before "varname"
Yegappan Lakshmananeb91e242023-08-31 18:10:46 +020074 char_u **varname_end,
Yegappan Lakshmanan3775f772023-09-01 22:05:45 +020075 garray_T *type_list,
Yegappan Lakshmananeb91e242023-08-31 18:10:46 +020076 type_T **type_ret,
77 char_u **init_expr)
Bram Moolenaard505d172022-12-18 21:42:55 +000078{
79 *varname_end = to_name_end(varname, FALSE);
80 if (*varname == '_' && has_public)
81 {
82 semsg(_(e_public_member_name_cannot_start_with_underscore_str), line);
83 return FAIL;
84 }
85
86 char_u *colon = skipwhite(*varname_end);
87 char_u *type_arg = colon;
88 type_T *type = NULL;
89 if (*colon == ':')
90 {
91 if (VIM_ISWHITE(**varname_end))
92 {
93 semsg(_(e_no_white_space_allowed_before_colon_str), varname);
94 return FAIL;
95 }
96 if (!VIM_ISWHITE(colon[1]))
97 {
98 semsg(_(e_white_space_required_after_str_str), ":", varname);
99 return FAIL;
100 }
101 type_arg = skipwhite(colon + 1);
102 type = parse_type(&type_arg, type_list, TRUE);
103 if (type == NULL)
104 return FAIL;
105 }
106
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +0200107 char_u *init_arg = skipwhite(type_arg);
108 if (type == NULL && *init_arg != '=')
Bram Moolenaard505d172022-12-18 21:42:55 +0000109 {
110 emsg(_(e_type_or_initialization_required));
111 return FAIL;
112 }
113
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +0200114 if (init_expr == NULL && *init_arg == '=')
Bram Moolenaard505d172022-12-18 21:42:55 +0000115 {
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +0200116 emsg(_(e_cannot_initialize_member_in_interface));
117 return FAIL;
118 }
119
120 if (*init_arg == '=')
121 {
122 evalarg_T evalarg;
123 char_u *expr_start, *expr_end;
124
125 if (!VIM_ISWHITE(init_arg[-1]) || !VIM_ISWHITE(init_arg[1]))
Bram Moolenaard505d172022-12-18 21:42:55 +0000126 {
127 semsg(_(e_white_space_required_before_and_after_str_at_str),
128 "=", type_arg);
129 return FAIL;
130 }
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +0200131 init_arg = skipwhite(init_arg + 1);
Bram Moolenaard505d172022-12-18 21:42:55 +0000132
Bram Moolenaard505d172022-12-18 21:42:55 +0000133 fill_evalarg_from_eap(&evalarg, eap, FALSE);
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +0200134 (void)skip_expr_concatenate(&init_arg, &expr_start, &expr_end, &evalarg);
Bram Moolenaard505d172022-12-18 21:42:55 +0000135
Yegappan Lakshmanand4e4ecb2023-08-27 18:35:45 +0200136 // No type specified for the member. Set it to "any" and the correct
137 // type will be set when the object is instantiated.
Bram Moolenaard505d172022-12-18 21:42:55 +0000138 if (type == NULL)
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +0200139 type = &t_any;
Bram Moolenaard505d172022-12-18 21:42:55 +0000140
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +0200141 *init_expr = vim_strnsave(expr_start, expr_end - expr_start);
142 // Free the memory pointed by expr_start.
Bram Moolenaard505d172022-12-18 21:42:55 +0000143 clear_evalarg(&evalarg, NULL);
144 }
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +0200145 else if (!valid_declaration_type(type))
Bram Moolenaard505d172022-12-18 21:42:55 +0000146 return FAIL;
147
148 *type_ret = type;
Bram Moolenaard505d172022-12-18 21:42:55 +0000149 return OK;
150}
151
152/*
153 * Add a member to an object or a class.
154 * Returns OK when successful, "init_expr" will be consumed then.
155 * Returns FAIL otherwise, caller might need to free "init_expr".
156 */
157 static int
158add_member(
Yegappan Lakshmanan3775f772023-09-01 22:05:45 +0200159 garray_T *gap,
160 char_u *varname,
161 char_u *varname_end,
162 int has_public,
163 type_T *type,
164 char_u *init_expr)
Bram Moolenaard505d172022-12-18 21:42:55 +0000165{
166 if (ga_grow(gap, 1) == FAIL)
167 return FAIL;
168 ocmember_T *m = ((ocmember_T *)gap->ga_data) + gap->ga_len;
169 m->ocm_name = vim_strnsave(varname, varname_end - varname);
=?UTF-8?q?Ola=20S=C3=B6der?=d8742472023-03-05 13:12:32 +0000170 m->ocm_access = has_public ? VIM_ACCESS_ALL
171 : *varname == '_' ? VIM_ACCESS_PRIVATE : VIM_ACCESS_READ;
Bram Moolenaard505d172022-12-18 21:42:55 +0000172 m->ocm_type = type;
173 if (init_expr != NULL)
174 m->ocm_init = init_expr;
175 ++gap->ga_len;
176 return OK;
177}
178
179/*
180 * Move the class or object members found while parsing a class into the class.
181 * "gap" contains the found members.
Bram Moolenaar83677162023-01-08 19:54:10 +0000182 * "parent_members" points to the members in the parent class (if any)
183 * "parent_count" is the number of members in the parent class
Bram Moolenaard505d172022-12-18 21:42:55 +0000184 * "members" will be set to the newly allocated array of members and
185 * "member_count" set to the number of members.
186 * Returns OK or FAIL.
187 */
188 static int
189add_members_to_class(
190 garray_T *gap,
Bram Moolenaar83677162023-01-08 19:54:10 +0000191 ocmember_T *parent_members,
192 int parent_count,
Bram Moolenaard505d172022-12-18 21:42:55 +0000193 ocmember_T **members,
194 int *member_count)
195{
Bram Moolenaar83677162023-01-08 19:54:10 +0000196 *member_count = parent_count + gap->ga_len;
197 *members = *member_count == 0 ? NULL
198 : ALLOC_MULT(ocmember_T, *member_count);
199 if (*member_count > 0 && *members == NULL)
Bram Moolenaard505d172022-12-18 21:42:55 +0000200 return FAIL;
Bram Moolenaar83677162023-01-08 19:54:10 +0000201 for (int i = 0; i < parent_count; ++i)
202 {
203 // parent members need to be copied
Bram Moolenaarae3205a2023-01-15 20:49:00 +0000204 ocmember_T *m = *members + i;
205 *m = parent_members[i];
206 m->ocm_name = vim_strsave(m->ocm_name);
207 if (m->ocm_init != NULL)
208 m->ocm_init = vim_strsave(m->ocm_init);
Bram Moolenaar83677162023-01-08 19:54:10 +0000209 }
Bram Moolenaar8efdcee2022-12-19 12:18:09 +0000210 if (gap->ga_len > 0)
Bram Moolenaar83677162023-01-08 19:54:10 +0000211 // new members are moved
212 mch_memmove(*members + parent_count,
213 gap->ga_data, sizeof(ocmember_T) * gap->ga_len);
Bram Moolenaard505d172022-12-18 21:42:55 +0000214 VIM_CLEAR(gap->ga_data);
215 return OK;
216}
217
218/*
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000219 * Convert a member index "idx" of interface "itf" to the member index of class
220 * "cl" implementing that interface.
221 */
222 int
Ernie Rael18143d32023-09-04 22:30:41 +0200223object_index_from_itf_index(class_T *itf, int is_method, int idx, class_T *cl,
224 int is_static)
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000225{
Ernie Rael18143d32023-09-04 22:30:41 +0200226 if (idx >= (is_method ? itf->class_obj_method_count
227 : is_static ? itf->class_class_member_count
Bram Moolenaard0200c82023-01-28 15:19:40 +0000228 : itf->class_obj_member_count))
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000229 {
230 siemsg("index %d out of range for interface %s", idx, itf->class_name);
231 return 0;
232 }
Yegappan Lakshmanan74cc13c2023-08-13 17:41:26 +0200233
234 // If "cl" is the interface or the class that is extended, then the method
235 // index can be used directly and there is no need to search for the method
236 // index in one of the child classes.
237 if (cl == itf)
238 return idx;
239
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000240 itf2class_T *i2c;
241 for (i2c = itf->class_itf2class; i2c != NULL; i2c = i2c->i2c_next)
Bram Moolenaard0200c82023-01-28 15:19:40 +0000242 if (i2c->i2c_class == cl && i2c->i2c_is_method == is_method)
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000243 break;
244 if (i2c == NULL)
245 {
246 siemsg("class %s not found on interface %s",
247 cl->class_name, itf->class_name);
248 return 0;
249 }
Ernie Rael18143d32023-09-04 22:30:41 +0200250 if (is_static)
251 {
252 // TODO: Need a table for fast lookup?
253 char_u *name = itf->class_class_members[idx].ocm_name;
254 for (int i = 0; i < i2c->i2c_class->class_class_member_count; ++i)
255 {
256 ocmember_T *m = &i2c->i2c_class->class_class_members[i];
257 if (STRCMP(name, m->ocm_name) == 0)
258 {
259 return i;
260 }
261 }
262 siemsg("class %s, interface %s, static %s not found",
263 cl->class_name, itf->class_name, name);
264 return 0;
265 }
266 else
267 {
268 // A table follows the i2c for the class
269 int *table = (int *)(i2c + 1);
270 return table[idx];
271 }
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000272}
273
274/*
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200275 * Check whether a class named "extends_name" is present. If the class is
276 * valid, then "extends_clp" is set with the class pointer.
277 * Returns TRUE if the class name "extends_names" is a valid class.
278 */
279 static int
280validate_extends_class(char_u *extends_name, class_T **extends_clp)
281{
282 typval_T tv;
283 int success = FALSE;
284
285 tv.v_type = VAR_UNKNOWN;
286 if (eval_variable_import(extends_name, &tv) == FAIL)
287 {
288 semsg(_(e_class_name_not_found_str), extends_name);
289 return success;
290 }
291 else
292 {
293 if (tv.v_type != VAR_CLASS
294 || tv.vval.v_class == NULL
295 || (tv.vval.v_class->class_flags & CLASS_INTERFACE) != 0)
296 semsg(_(e_cannot_extend_str), extends_name);
297 else
298 {
299 class_T *extends_cl = tv.vval.v_class;
300 ++extends_cl->class_refcount;
301 *extends_clp = extends_cl;
302 success = TRUE;
303 }
304 clear_tv(&tv);
305 }
306
307 return success;
308}
309
310/*
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +0200311 * Check whether a class/object member variable in "classmembers_gap" /
312 * "objmembers_gap" is a duplicate of a member in any of the extended parent
313 * class lineage. Returns TRUE if there are no duplicates.
314 */
315 static int
316validate_extends_members(
317 garray_T *classmembers_gap,
318 garray_T *objmembers_gap,
319 class_T *extends_cl)
320{
321 for (int loop = 1; loop <= 2; ++loop)
322 {
323 // loop == 1: check class members
324 // loop == 2: check object members
325 int member_count = loop == 1 ? classmembers_gap->ga_len
326 : objmembers_gap->ga_len;
327 if (member_count == 0)
328 continue;
329 ocmember_T *members = (ocmember_T *)(loop == 1
330 ? classmembers_gap->ga_data
331 : objmembers_gap->ga_data);
332
333 // Validate each member variable
334 for (int c_i = 0; c_i < member_count; c_i++)
335 {
336 class_T *p_cl = extends_cl;
337 ocmember_T *c_m = members + c_i;
338 char_u *pstr = (*c_m->ocm_name == '_')
339 ? c_m->ocm_name + 1 : c_m->ocm_name;
340
341 // Check in all the parent classes in the lineage
342 while (p_cl != NULL)
343 {
344 int p_member_count = loop == 1
345 ? p_cl->class_class_member_count
346 : p_cl->class_obj_member_count;
347 if (p_member_count == 0)
348 continue;
349 ocmember_T *p_members = (loop == 1
350 ? p_cl->class_class_members
351 : p_cl->class_obj_members);
352
353 // Compare against all the members in the parent class
354 for (int p_i = 0; p_i < p_member_count; p_i++)
355 {
356 ocmember_T *p_m = p_members + p_i;
357 char_u *qstr = (*p_m->ocm_name == '_')
358 ? p_m->ocm_name + 1 : p_m->ocm_name;
359 if (STRCMP(pstr, qstr) == 0)
360 {
361 semsg(_(e_duplicate_member_str), c_m->ocm_name);
362 return FALSE;
363 }
364 }
365
366 p_cl = p_cl->class_extends;
367 }
368 }
369 }
370
371 return TRUE;
372}
373
374/*
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200375 * Check the members of the interface class "ifcl" match the class members
376 * ("classmembers_gap") and object members ("objmembers_gap") of a class.
377 * Returns TRUE if the class and object member names are valid.
378 */
379 static int
380validate_interface_members(
381 char_u *intf_class_name,
382 class_T *ifcl,
383 garray_T *classmembers_gap,
384 garray_T *objmembers_gap)
385{
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +0200386 for (int loop = 1; loop <= 2; ++loop)
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200387 {
388 // loop == 1: check class members
389 // loop == 2: check object members
390 int if_count = loop == 1 ? ifcl->class_class_member_count
391 : ifcl->class_obj_member_count;
392 if (if_count == 0)
393 continue;
394 ocmember_T *if_ms = loop == 1 ? ifcl->class_class_members
395 : ifcl->class_obj_members;
396 ocmember_T *cl_ms = (ocmember_T *)(loop == 1
397 ? classmembers_gap->ga_data
398 : objmembers_gap->ga_data);
399 int cl_count = loop == 1 ? classmembers_gap->ga_len
400 : objmembers_gap->ga_len;
401 for (int if_i = 0; if_i < if_count; ++if_i)
402 {
403 int cl_i;
404 for (cl_i = 0; cl_i < cl_count; ++cl_i)
405 {
406 ocmember_T *m = &cl_ms[cl_i];
407 where_T where = WHERE_INIT;
408
409 if (STRCMP(if_ms[if_i].ocm_name, m->ocm_name) != 0)
410 continue;
411
412 // Ensure the type is matching.
413 where.wt_func_name = (char *)m->ocm_name;
414 where.wt_kind = WT_MEMBER;
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +0200415 if (check_type(if_ms[if_i].ocm_type, m->ocm_type, TRUE,
416 where) == FAIL)
417 return FALSE;
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200418
Yegappan Lakshmananeb91e242023-08-31 18:10:46 +0200419 if (if_ms[if_i].ocm_access != m->ocm_access)
420 {
421 semsg(_(e_member_str_of_interface_str_has_different_access),
422 if_ms[if_i].ocm_name, intf_class_name);
423 return FALSE;
424 }
425
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200426 break;
427 }
428 if (cl_i == cl_count)
429 {
430 semsg(_(e_member_str_of_interface_str_not_implemented),
431 if_ms[if_i].ocm_name, intf_class_name);
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +0200432 return FALSE;
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200433 }
434 }
435 }
436
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +0200437 return TRUE;
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200438}
439
440/*
441 * Check the functions/methods of the interface class "ifcl" match the class
442 * methods ("classfunctions_gap") and object functions ("objmemthods_gap") of a
443 * class.
444 * Returns TRUE if the class and object member names are valid.
445 */
446 static int
447validate_interface_methods(
448 char_u *intf_class_name,
449 class_T *ifcl,
450 garray_T *classfunctions_gap,
451 garray_T *objmethods_gap)
452{
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +0200453 for (int loop = 1; loop <= 2; ++loop)
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200454 {
455 // loop == 1: check class functions
456 // loop == 2: check object methods
457 int if_count = loop == 1 ? ifcl->class_class_function_count
458 : ifcl->class_obj_method_count;
459 if (if_count == 0)
460 continue;
461 ufunc_T **if_fp = loop == 1 ? ifcl->class_class_functions
462 : ifcl->class_obj_methods;
463 ufunc_T **cl_fp = (ufunc_T **)(loop == 1
464 ? classfunctions_gap->ga_data
465 : objmethods_gap->ga_data);
466 int cl_count = loop == 1 ? classfunctions_gap->ga_len
467 : objmethods_gap->ga_len;
468 for (int if_i = 0; if_i < if_count; ++if_i)
469 {
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +0200470 char_u *if_name = if_fp[if_i]->uf_name;
471 int cl_i;
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200472 for (cl_i = 0; cl_i < cl_count; ++cl_i)
473 {
474 char_u *cl_name = cl_fp[cl_i]->uf_name;
475 if (STRCMP(if_name, cl_name) == 0)
476 {
477 where_T where = WHERE_INIT;
478
479 // Ensure the type is matching.
480 where.wt_func_name = (char *)if_name;
481 where.wt_kind = WT_METHOD;
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +0200482 if (check_type(if_fp[if_i]->uf_func_type,
483 cl_fp[cl_i]->uf_func_type, TRUE, where) == FAIL)
484 return FALSE;
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200485 break;
486 }
487 }
488 if (cl_i == cl_count)
489 {
490 semsg(_(e_function_str_of_interface_str_not_implemented),
491 if_name, intf_class_name);
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +0200492 return FALSE;
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200493 }
494 }
495 }
496
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +0200497 return TRUE;
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200498}
499
500/*
501 * Validate all the "implements" classes when creating a new class. The
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +0200502 * classes are returned in "intf_classes". The class functions, class members,
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200503 * object methods and object members in the new class are in
504 * "classfunctions_gap", "classmembers_gap", "objmethods_gap", and
505 * "objmembers_gap" respectively.
506 */
507 static int
508validate_implements_classes(
509 garray_T *impl_gap,
510 class_T **intf_classes,
511 garray_T *classfunctions_gap,
512 garray_T *classmembers_gap,
513 garray_T *objmethods_gap,
514 garray_T *objmembers_gap)
515{
516 int success = TRUE;
517
518 for (int i = 0; i < impl_gap->ga_len && success; ++i)
519 {
520 char_u *impl = ((char_u **)impl_gap->ga_data)[i];
521 typval_T tv;
522 tv.v_type = VAR_UNKNOWN;
523 if (eval_variable_import(impl, &tv) == FAIL)
524 {
525 semsg(_(e_interface_name_not_found_str), impl);
526 success = FALSE;
527 break;
528 }
529
530 if (tv.v_type != VAR_CLASS
531 || tv.vval.v_class == NULL
532 || (tv.vval.v_class->class_flags & CLASS_INTERFACE) == 0)
533 {
534 semsg(_(e_not_valid_interface_str), impl);
535 success = FALSE;
536 clear_tv(&tv);
537 break;
538 }
539
540 class_T *ifcl = tv.vval.v_class;
541 intf_classes[i] = ifcl;
542 ++ifcl->class_refcount;
543
544 // check the members of the interface match the members of the class
545 success = validate_interface_members(impl, ifcl, classmembers_gap,
546 objmembers_gap);
547
548 // check the functions/methods of the interface match the
549 // functions/methods of the class
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +0200550 if (success)
551 success = validate_interface_methods(impl, ifcl,
552 classfunctions_gap, objmethods_gap);
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200553 clear_tv(&tv);
554 }
555
556 return success;
557}
558
559/*
560 * Check no function argument name is used as a class member.
561 * (Object members are always accessed with "this." prefix, so no need
562 * to check them.)
563 */
564 static int
565check_func_arg_names(
566 garray_T *classfunctions_gap,
567 garray_T *objmethods_gap,
568 garray_T *classmembers_gap)
569{
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200570 // loop 1: class functions, loop 2: object methods
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +0200571 for (int loop = 1; loop <= 2; ++loop)
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200572 {
573 garray_T *gap = loop == 1 ? classfunctions_gap : objmethods_gap;
574
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +0200575 for (int fi = 0; fi < gap->ga_len; ++fi)
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200576 {
577 ufunc_T *uf = ((ufunc_T **)gap->ga_data)[fi];
578
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +0200579 for (int i = 0; i < uf->uf_args.ga_len; ++i)
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200580 {
581 char_u *aname = ((char_u **)uf->uf_args.ga_data)[i];
582 garray_T *mgap = classmembers_gap;
583
584 // Check all the class member names
585 for (int mi = 0; mi < mgap->ga_len; ++mi)
586 {
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +0200587 char_u *mname =
588 ((ocmember_T *)mgap->ga_data + mi)->ocm_name;
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200589 if (STRCMP(aname, mname) == 0)
590 {
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200591 if (uf->uf_script_ctx.sc_sid > 0)
592 SOURCING_LNUM = uf->uf_script_ctx.sc_lnum;
593
594 semsg(_(e_argument_already_declared_in_class_str),
595 aname);
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +0200596
597 return FALSE;
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200598 }
599 }
600 }
601 }
602 }
603
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +0200604 return TRUE;
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200605}
606
607/*
Yegappan Lakshmanan2ba9d2e2023-08-28 21:26:23 +0200608 * Returns TRUE if the member "varname" is already defined.
609 */
610 static int
611is_duplicate_member(garray_T *mgap, char_u *varname, char_u *varname_end)
612{
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +0200613 char_u *name = vim_strnsave(varname, varname_end - varname);
614 char_u *pstr = (*name == '_') ? name + 1 : name;
615 int dup = FALSE;
Yegappan Lakshmanan2ba9d2e2023-08-28 21:26:23 +0200616
617 for (int i = 0; i < mgap->ga_len; ++i)
618 {
619 ocmember_T *m = ((ocmember_T *)mgap->ga_data) + i;
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +0200620 char_u *qstr = *m->ocm_name == '_' ? m->ocm_name + 1 : m->ocm_name;
621 if (STRCMP(pstr, qstr) == 0)
Yegappan Lakshmanan2ba9d2e2023-08-28 21:26:23 +0200622 {
Yegappan Lakshmanan2ba9d2e2023-08-28 21:26:23 +0200623 semsg(_(e_duplicate_member_str), name);
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +0200624 dup = TRUE;
625 break;
Yegappan Lakshmanan2ba9d2e2023-08-28 21:26:23 +0200626 }
627 }
628
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +0200629 vim_free(name);
630 return dup;
Yegappan Lakshmanan2ba9d2e2023-08-28 21:26:23 +0200631}
632
633/*
634 * Returns TRUE if the method "name" is already defined.
635 */
636 static int
637is_duplicate_method(garray_T *fgap, char_u *name)
638{
639 char_u *pstr = (*name == '_') ? name + 1 : name;
640
641 for (int i = 0; i < fgap->ga_len; ++i)
642 {
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +0200643 char_u *n = ((ufunc_T **)fgap->ga_data)[i]->uf_name;
644 char_u *qstr = *n == '_' ? n + 1 : n;
Yegappan Lakshmanan2ba9d2e2023-08-28 21:26:23 +0200645 if (STRCMP(pstr, qstr) == 0)
646 {
647 semsg(_(e_duplicate_function_str), name);
648 return TRUE;
649 }
650 }
651
652 return FALSE;
653}
654
655/*
Gianmaria Bajo4b9777a2023-08-29 22:26:30 +0200656 * Returns TRUE if the constructor is valid.
657 */
658 static int
659is_valid_constructor(ufunc_T *uf, int is_abstract, int has_static)
660{
661 // Constructors are not allowed in abstract classes.
662 if (is_abstract)
663 {
664 emsg(_(e_cannot_define_new_function_in_abstract_class));
665 return FALSE;
666 }
667 // A constructor is always static, no need to define it so.
668 if (has_static)
669 {
670 emsg(_(e_cannot_define_new_function_as_static));
671 return FALSE;
672 }
673 // A return type should not be specified for the new()
674 // constructor method.
675 if (uf->uf_ret_type->tt_type != VAR_VOID)
676 {
677 emsg(_(e_cannot_use_a_return_type_with_new));
678 return FALSE;
679 }
680 return TRUE;
681}
682
683/*
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200684 * Update the interface class lookup table for the member index on the
685 * interface to the member index in the class implementing the interface.
686 * And a lookup table for the object method index on the interface
687 * to the object method index in the class implementing the interface.
688 * This is also used for updating the lookup table for the extended class
689 * hierarchy.
690 */
691 static int
692update_member_method_lookup_table(
Yegappan Lakshmanan3775f772023-09-01 22:05:45 +0200693 class_T *ifcl,
694 class_T *cl,
Yegappan Lakshmananeb91e242023-08-31 18:10:46 +0200695 garray_T *objmethods,
696 int pobj_method_offset,
697 int is_interface)
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200698{
699 if (ifcl == NULL)
700 return OK;
701
702 // Table for members.
703 itf2class_T *if2cl = alloc_clear(sizeof(itf2class_T)
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +0200704 + ifcl->class_obj_member_count * sizeof(int));
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200705 if (if2cl == NULL)
706 return FAIL;
707 if2cl->i2c_next = ifcl->class_itf2class;
708 ifcl->class_itf2class = if2cl;
709 if2cl->i2c_class = cl;
710 if2cl->i2c_is_method = FALSE;
711
712 for (int if_i = 0; if_i < ifcl->class_obj_member_count; ++if_i)
713 for (int cl_i = 0; cl_i < cl->class_obj_member_count; ++cl_i)
714 {
715 if (STRCMP(ifcl->class_obj_members[if_i].ocm_name,
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +0200716 cl->class_obj_members[cl_i].ocm_name) == 0)
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200717 {
718 int *table = (int *)(if2cl + 1);
719 table[if_i] = cl_i;
720 break;
721 }
722 }
723
724 // Table for methods.
725 if2cl = alloc_clear(sizeof(itf2class_T)
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +0200726 + ifcl->class_obj_method_count * sizeof(int));
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200727 if (if2cl == NULL)
728 return FAIL;
729 if2cl->i2c_next = ifcl->class_itf2class;
730 ifcl->class_itf2class = if2cl;
731 if2cl->i2c_class = cl;
732 if2cl->i2c_is_method = TRUE;
733
734 for (int if_i = 0; if_i < ifcl->class_obj_method_count; ++if_i)
735 {
736 int done = FALSE;
737 for (int cl_i = 0; cl_i < objmethods->ga_len; ++cl_i)
738 {
739 if (STRCMP(ifcl->class_obj_methods[if_i]->uf_name,
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +0200740 ((ufunc_T **)objmethods->ga_data)[cl_i]->uf_name) == 0)
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200741 {
742 int *table = (int *)(if2cl + 1);
743 table[if_i] = cl_i;
744 done = TRUE;
745 break;
746 }
747 }
748
749 // extended class object method is not overridden by the child class.
750 // Keep the method declared in one of the parent classes in the
751 // lineage.
752 if (!done && !is_interface)
753 {
754 // If "ifcl" is not the immediate parent of "cl", then search in
755 // the intermediate parent classes.
756 if (cl->class_extends != ifcl)
757 {
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +0200758 class_T *parent = cl->class_extends;
759 int method_offset = objmethods->ga_len;
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200760
761 while (!done && parent != NULL && parent != ifcl)
762 {
763
764 for (int cl_i = 0;
765 cl_i < parent->class_obj_method_count_child; ++cl_i)
766 {
767 if (STRCMP(ifcl->class_obj_methods[if_i]->uf_name,
768 parent->class_obj_methods[cl_i]->uf_name)
769 == 0)
770 {
771 int *table = (int *)(if2cl + 1);
772 table[if_i] = method_offset + cl_i;
773 done = TRUE;
774 break;
775 }
776 }
777 method_offset += parent->class_obj_method_count_child;
778 parent = parent->class_extends;
779 }
780 }
781
782 if (!done)
783 {
784 int *table = (int *)(if2cl + 1);
785 table[if_i] = pobj_method_offset + if_i;
786 }
787 }
788 }
789
790 return OK;
791}
792
793/*
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200794 * Update the member and object method lookup tables for a new class in the
795 * interface class.
796 * For each interface add a lookup table for the member index on the interface
797 * to the member index in the new class. And a lookup table for the object
798 * method index on the interface to the object method index in the new class.
799 */
800 static int
801add_lookup_tables(class_T *cl, class_T *extends_cl, garray_T *objmethods_gap)
802{
803 for (int i = 0; i < cl->class_interface_count; ++i)
804 {
805 class_T *ifcl = cl->class_interfaces_cl[i];
806
807 if (update_member_method_lookup_table(ifcl, cl, objmethods_gap,
808 0, TRUE) == FAIL)
809 return FAIL;
810 }
811
812 // Update the lookup table for the extended class, if nay
813 if (extends_cl != NULL)
814 {
815 class_T *pclass = extends_cl;
816 int pobj_method_offset = objmethods_gap->ga_len;
817
818 // Update the entire lineage of extended classes.
819 while (pclass != NULL)
820 {
821 if (update_member_method_lookup_table(pclass, cl,
822 objmethods_gap, pobj_method_offset, FALSE) == FAIL)
823 return FAIL;
824
825 pobj_method_offset += pclass->class_obj_method_count_child;
826 pclass = pclass->class_extends;
827 }
828 }
829
830 return OK;
831}
832
833/*
834 * Add class members to a new class. Allocate a typval for each class member
835 * and initialize it.
836 */
837 static void
838add_class_members(class_T *cl, exarg_T *eap)
839{
840 // Allocate a typval for each class member and initialize it.
841 cl->class_members_tv = ALLOC_CLEAR_MULT(typval_T,
842 cl->class_class_member_count);
843 if (cl->class_members_tv == NULL)
844 return;
845
846 for (int i = 0; i < cl->class_class_member_count; ++i)
847 {
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +0200848 ocmember_T *m = &cl->class_class_members[i];
849 typval_T *tv = &cl->class_members_tv[i];
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200850 if (m->ocm_init != NULL)
851 {
852 typval_T *etv = eval_expr(m->ocm_init, eap);
853 if (etv != NULL)
854 {
855 *tv = *etv;
856 vim_free(etv);
857 }
858 }
859 else
860 {
861 // TODO: proper default value
862 tv->v_type = m->ocm_type->tt_type;
863 tv->vval.v_string = NULL;
864 }
865 }
866}
867
868/*
Yegappan Lakshmanan6ac15442023-08-20 18:20:17 +0200869 * Add a default constructor method (new()) to the class "cl".
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200870 */
871 static void
872add_default_constructor(
873 class_T *cl,
874 garray_T *classfunctions_gap,
875 garray_T *type_list_gap)
876{
877 garray_T fga;
878
879 ga_init2(&fga, 1, 1000);
880 ga_concat(&fga, (char_u *)"new(");
881 for (int i = 0; i < cl->class_obj_member_count; ++i)
882 {
883 if (i > 0)
884 ga_concat(&fga, (char_u *)", ");
885 ga_concat(&fga, (char_u *)"this.");
886 ocmember_T *m = cl->class_obj_members + i;
887 ga_concat(&fga, (char_u *)m->ocm_name);
888 ga_concat(&fga, (char_u *)" = v:none");
889 }
890 ga_concat(&fga, (char_u *)")\nenddef\n");
891 ga_append(&fga, NUL);
892
893 exarg_T fea;
894 CLEAR_FIELD(fea);
895 fea.cmdidx = CMD_def;
896 fea.cmd = fea.arg = fga.ga_data;
897
898 garray_T lines_to_free;
899 ga_init2(&lines_to_free, sizeof(char_u *), 50);
900
901 ufunc_T *nf = define_function(&fea, NULL, &lines_to_free, CF_CLASS);
902
903 ga_clear_strings(&lines_to_free);
904 vim_free(fga.ga_data);
905
906 if (nf != NULL && ga_grow(classfunctions_gap, 1) == OK)
907 {
908 ((ufunc_T **)classfunctions_gap->ga_data)[classfunctions_gap->ga_len]
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +0200909 = nf;
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200910 ++classfunctions_gap->ga_len;
911
912 nf->uf_flags |= FC_NEW;
913 nf->uf_ret_type = get_type_ptr(type_list_gap);
914 if (nf->uf_ret_type != NULL)
915 {
916 nf->uf_ret_type->tt_type = VAR_OBJECT;
917 nf->uf_ret_type->tt_class = cl;
918 nf->uf_ret_type->tt_argcount = 0;
919 nf->uf_ret_type->tt_args = NULL;
920 }
921 }
922}
923
924/*
925 * Add the class functions and object methods to the new class "cl".
926 * When extending a class, add the functions and methods from the parent class
927 * also.
928 */
929 static int
930add_classfuncs_objmethods(
931 class_T *cl,
932 class_T *extends_cl,
933 garray_T *classfunctions_gap,
934 garray_T *objmethods_gap)
935{
936 // loop 1: class functions, loop 2: object methods
937 for (int loop = 1; loop <= 2; ++loop)
938 {
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +0200939 garray_T *gap = loop == 1 ? classfunctions_gap : objmethods_gap;
940 int *fcount = loop == 1 ? &cl->class_class_function_count
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200941 : &cl->class_obj_method_count;
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +0200942 ufunc_T ***fup = loop == 1 ? &cl->class_class_functions
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200943 : &cl->class_obj_methods;
944
945 int parent_count = 0;
946 if (extends_cl != NULL)
947 // Include functions from the parent.
948 parent_count = loop == 1
949 ? extends_cl->class_class_function_count
950 : extends_cl->class_obj_method_count;
951
952 *fcount = parent_count + gap->ga_len;
953 if (*fcount == 0)
954 {
955 *fup = NULL;
956 continue;
957 }
958 *fup = ALLOC_MULT(ufunc_T *, *fcount);
959 if (*fup == NULL)
960 return FAIL;
961
962 if (gap->ga_len != 0)
963 mch_memmove(*fup, gap->ga_data, sizeof(ufunc_T *) * gap->ga_len);
964 vim_free(gap->ga_data);
965 if (loop == 1)
966 cl->class_class_function_count_child = gap->ga_len;
967 else
968 cl->class_obj_method_count_child = gap->ga_len;
969
970 int skipped = 0;
971 for (int i = 0; i < parent_count; ++i)
972 {
973 // Copy functions from the parent. Can't use the same
974 // function, because "uf_class" is different and compilation
975 // will have a different result.
976 // Put them after the functions in the current class, object
977 // methods may be overruled, then "super.Method()" is used to
978 // find a method from the parent.
979 // Skip "new" functions. TODO: not all of them.
980 if (loop == 1 && STRNCMP(
981 extends_cl->class_class_functions[i]->uf_name,
982 "new", 3) == 0)
983 ++skipped;
984 else
985 {
986 ufunc_T *pf = (loop == 1
987 ? extends_cl->class_class_functions
988 : extends_cl->class_obj_methods)[i];
989 (*fup)[gap->ga_len + i - skipped] = copy_function(pf);
990
991 // If the child class overrides a function from the parent
992 // the signature must be equal.
993 char_u *pname = pf->uf_name;
994 for (int ci = 0; ci < gap->ga_len; ++ci)
995 {
996 ufunc_T *cf = (*fup)[ci];
997 char_u *cname = cf->uf_name;
998 if (STRCMP(pname, cname) == 0)
999 {
1000 where_T where = WHERE_INIT;
1001 where.wt_func_name = (char *)pname;
1002 where.wt_kind = WT_METHOD;
1003 (void)check_type(pf->uf_func_type, cf->uf_func_type,
1004 TRUE, where);
1005 }
1006 }
1007 }
1008 }
1009
1010 *fcount -= skipped;
1011
1012 // Set the class pointer on all the functions and object methods.
1013 for (int i = 0; i < *fcount; ++i)
1014 {
1015 ufunc_T *fp = (*fup)[i];
1016 fp->uf_class = cl;
1017 if (loop == 2)
1018 fp->uf_flags |= FC_OBJECT;
1019 }
1020 }
1021
1022 return OK;
1023}
1024
1025/*
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001026 * Handle ":class" and ":abstract class" up to ":endclass".
Bram Moolenaar554d0312023-01-05 19:59:18 +00001027 * Handle ":interface" up to ":endinterface".
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001028 */
1029 void
1030ex_class(exarg_T *eap)
1031{
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +02001032 int is_class = eap->cmdidx == CMD_class; // FALSE for :interface
1033 long start_lnum = SOURCING_LNUM;
1034 char_u *arg = eap->arg;
1035 int is_abstract = eap->cmdidx == CMD_abstract;
Bram Moolenaar554d0312023-01-05 19:59:18 +00001036
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001037 if (is_abstract)
1038 {
1039 if (STRNCMP(arg, "class", 5) != 0 || !VIM_ISWHITE(arg[5]))
1040 {
1041 semsg(_(e_invalid_argument_str), arg);
1042 return;
1043 }
1044 arg = skipwhite(arg + 5);
Bram Moolenaar24a8d062023-01-14 13:12:06 +00001045 is_class = TRUE;
1046 }
1047
1048 if (!current_script_is_vim9()
1049 || (cmdmod.cmod_flags & CMOD_LEGACY)
1050 || !getline_equal(eap->getline, eap->cookie, getsourceline))
1051 {
1052 if (is_class)
1053 emsg(_(e_class_can_only_be_defined_in_vim9_script));
1054 else
1055 emsg(_(e_interface_can_only_be_defined_in_vim9_script));
1056 return;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001057 }
1058
1059 if (!ASCII_ISUPPER(*arg))
1060 {
Bram Moolenaar554d0312023-01-05 19:59:18 +00001061 if (is_class)
1062 semsg(_(e_class_name_must_start_with_uppercase_letter_str), arg);
1063 else
1064 semsg(_(e_interface_name_must_start_with_uppercase_letter_str),
1065 arg);
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001066 return;
1067 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001068 char_u *name_end = find_name_end(arg, NULL, NULL, FNE_CHECK_START);
1069 if (!IS_WHITE_OR_NUL(*name_end))
1070 {
Bram Moolenaar554d0312023-01-05 19:59:18 +00001071 semsg(_(e_white_space_required_after_name_str), arg);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001072 return;
1073 }
Bram Moolenaar94674f22023-01-06 18:42:20 +00001074 char_u *name_start = arg;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001075
Bram Moolenaara86655a2023-01-12 17:06:27 +00001076 // "export class" gets used when creating the class, don't use "is_export"
1077 // for the items inside the class.
1078 int class_export = is_export;
1079 is_export = FALSE;
1080
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001081 // TODO:
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001082 // generics: <Tkey, Tentry>
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001083
Bram Moolenaar83677162023-01-08 19:54:10 +00001084 // Name for "extends BaseClass"
1085 char_u *extends = NULL;
1086
Bram Moolenaar94674f22023-01-06 18:42:20 +00001087 // Names for "implements SomeInterface"
1088 garray_T ga_impl;
1089 ga_init2(&ga_impl, sizeof(char_u *), 5);
1090
1091 arg = skipwhite(name_end);
1092 while (*arg != NUL && *arg != '#' && *arg != '\n')
1093 {
1094 // TODO:
Bram Moolenaar94674f22023-01-06 18:42:20 +00001095 // specifies SomeInterface
Bram Moolenaar83677162023-01-08 19:54:10 +00001096 if (STRNCMP(arg, "extends", 7) == 0 && IS_WHITE_OR_NUL(arg[7]))
1097 {
1098 if (extends != NULL)
1099 {
1100 emsg(_(e_duplicate_extends));
1101 goto early_ret;
1102 }
1103 arg = skipwhite(arg + 7);
1104 char_u *end = find_name_end(arg, NULL, NULL, FNE_CHECK_START);
1105 if (!IS_WHITE_OR_NUL(*end))
1106 {
1107 semsg(_(e_white_space_required_after_name_str), arg);
1108 goto early_ret;
1109 }
1110 extends = vim_strnsave(arg, end - arg);
1111 if (extends == NULL)
1112 goto early_ret;
1113
1114 arg = skipwhite(end + 1);
1115 }
1116 else if (STRNCMP(arg, "implements", 10) == 0
1117 && IS_WHITE_OR_NUL(arg[10]))
Bram Moolenaar94674f22023-01-06 18:42:20 +00001118 {
Bram Moolenaardf8f9472023-01-07 14:51:03 +00001119 if (ga_impl.ga_len > 0)
1120 {
1121 emsg(_(e_duplicate_implements));
1122 goto early_ret;
1123 }
Bram Moolenaar94674f22023-01-06 18:42:20 +00001124 arg = skipwhite(arg + 10);
Bram Moolenaardf8f9472023-01-07 14:51:03 +00001125
1126 for (;;)
Bram Moolenaar94674f22023-01-06 18:42:20 +00001127 {
Bram Moolenaardf8f9472023-01-07 14:51:03 +00001128 char_u *impl_end = find_name_end(arg, NULL, NULL,
1129 FNE_CHECK_START);
1130 if (!IS_WHITE_OR_NUL(*impl_end) && *impl_end != ',')
1131 {
1132 semsg(_(e_white_space_required_after_name_str), arg);
1133 goto early_ret;
1134 }
1135 char_u *iname = vim_strnsave(arg, impl_end - arg);
1136 if (iname == NULL)
1137 goto early_ret;
1138 for (int i = 0; i < ga_impl.ga_len; ++i)
1139 if (STRCMP(((char_u **)ga_impl.ga_data)[i], iname) == 0)
1140 {
1141 semsg(_(e_duplicate_interface_after_implements_str),
1142 iname);
1143 vim_free(iname);
1144 goto early_ret;
1145 }
1146 if (ga_add_string(&ga_impl, iname) == FAIL)
1147 {
1148 vim_free(iname);
1149 goto early_ret;
1150 }
1151 if (*impl_end != ',')
1152 {
1153 arg = skipwhite(impl_end);
1154 break;
1155 }
1156 arg = skipwhite(impl_end + 1);
Bram Moolenaar94674f22023-01-06 18:42:20 +00001157 }
Bram Moolenaar94674f22023-01-06 18:42:20 +00001158 }
1159 else
1160 {
1161 semsg(_(e_trailing_characters_str), arg);
1162early_ret:
Bram Moolenaar83677162023-01-08 19:54:10 +00001163 vim_free(extends);
Bram Moolenaar94674f22023-01-06 18:42:20 +00001164 ga_clear_strings(&ga_impl);
1165 return;
1166 }
1167 }
1168
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001169 garray_T type_list; // list of pointers to allocated types
1170 ga_init2(&type_list, sizeof(type_T *), 10);
1171
Bram Moolenaard505d172022-12-18 21:42:55 +00001172 // Growarray with class members declared in the class.
1173 garray_T classmembers;
1174 ga_init2(&classmembers, sizeof(ocmember_T), 10);
1175
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001176 // Growarray with functions declared in the class.
1177 garray_T classfunctions;
1178 ga_init2(&classfunctions, sizeof(ufunc_T *), 10);
Bram Moolenaard505d172022-12-18 21:42:55 +00001179
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001180 // Growarray with object members declared in the class.
1181 garray_T objmembers;
Bram Moolenaard505d172022-12-18 21:42:55 +00001182 ga_init2(&objmembers, sizeof(ocmember_T), 10);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001183
1184 // Growarray with object methods declared in the class.
1185 garray_T objmethods;
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001186 ga_init2(&objmethods, sizeof(ufunc_T *), 10);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001187
1188 /*
Bram Moolenaar554d0312023-01-05 19:59:18 +00001189 * Go over the body of the class/interface until "endclass" or
1190 * "endinterface" is found.
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001191 */
1192 char_u *theline = NULL;
1193 int success = FALSE;
1194 for (;;)
1195 {
1196 vim_free(theline);
1197 theline = eap->getline(':', eap->cookie, 0, GETLINE_CONCAT_ALL);
1198 if (theline == NULL)
1199 break;
1200 char_u *line = skipwhite(theline);
1201
Bram Moolenaar418b5472022-12-20 13:38:22 +00001202 // Skip empty and comment lines.
1203 if (*line == NUL)
1204 continue;
1205 if (*line == '#')
1206 {
1207 if (vim9_bad_comment(line))
1208 break;
1209 continue;
1210 }
1211
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001212 char_u *p = line;
Bram Moolenaar554d0312023-01-05 19:59:18 +00001213 char *end_name = is_class ? "endclass" : "endinterface";
1214 if (checkforcmd(&p, end_name, is_class ? 4 : 5))
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001215 {
Bram Moolenaar554d0312023-01-05 19:59:18 +00001216 if (STRNCMP(line, end_name, is_class ? 8 : 12) != 0)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001217 semsg(_(e_command_cannot_be_shortened_str), line);
1218 else if (*p == '|' || !ends_excmd2(line, p))
1219 semsg(_(e_trailing_characters_str), p);
Bram Moolenaar98aeb212022-12-08 22:09:14 +00001220 else
1221 success = TRUE;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001222 break;
1223 }
Bram Moolenaar554d0312023-01-05 19:59:18 +00001224 char *wrong_name = is_class ? "endinterface" : "endclass";
1225 if (checkforcmd(&p, wrong_name, is_class ? 5 : 4))
1226 {
Bram Moolenaar657aea72023-01-27 13:16:19 +00001227 semsg(_(e_invalid_command_str_expected_str), line, end_name);
Bram Moolenaar554d0312023-01-05 19:59:18 +00001228 break;
1229 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001230
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001231 int has_public = FALSE;
1232 if (checkforcmd(&p, "public", 3))
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001233 {
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001234 if (STRNCMP(line, "public", 6) != 0)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001235 {
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001236 semsg(_(e_command_cannot_be_shortened_str), line);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001237 break;
1238 }
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001239 has_public = TRUE;
1240 p = skipwhite(line + 6);
1241
Bram Moolenaard505d172022-12-18 21:42:55 +00001242 if (STRNCMP(p, "this", 4) != 0 && STRNCMP(p, "static", 6) != 0)
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001243 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001244 emsg(_(e_public_must_be_followed_by_this_or_static));
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001245 break;
1246 }
1247 }
Bram Moolenaard505d172022-12-18 21:42:55 +00001248
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001249 int has_static = FALSE;
1250 char_u *ps = p;
1251 if (checkforcmd(&p, "static", 4))
1252 {
1253 if (STRNCMP(ps, "static", 6) != 0)
1254 {
1255 semsg(_(e_command_cannot_be_shortened_str), ps);
1256 break;
1257 }
1258 has_static = TRUE;
1259 p = skipwhite(ps + 6);
1260 }
1261
Bram Moolenaard505d172022-12-18 21:42:55 +00001262 // object members (public, read access, private):
1263 // "this._varname"
1264 // "this.varname"
1265 // "public this.varname"
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001266 if (STRNCMP(p, "this", 4) == 0)
1267 {
1268 if (p[4] != '.' || !eval_isnamec1(p[5]))
1269 {
1270 semsg(_(e_invalid_object_member_declaration_str), p);
1271 break;
1272 }
Yegappan Lakshmanan2ba9d2e2023-08-28 21:26:23 +02001273 if (has_static)
1274 {
1275 emsg(_(e_static_cannot_be_followed_by_this));
1276 break;
1277 }
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001278 char_u *varname = p + 5;
Bram Moolenaard505d172022-12-18 21:42:55 +00001279 char_u *varname_end = NULL;
Bram Moolenaar74e12742022-12-13 21:14:28 +00001280 type_T *type = NULL;
Bram Moolenaard505d172022-12-18 21:42:55 +00001281 char_u *init_expr = NULL;
1282 if (parse_member(eap, line, varname, has_public,
Bram Moolenaar554d0312023-01-05 19:59:18 +00001283 &varname_end, &type_list, &type,
1284 is_class ? &init_expr: NULL) == FAIL)
Bram Moolenaard505d172022-12-18 21:42:55 +00001285 break;
Yegappan Lakshmanan2ba9d2e2023-08-28 21:26:23 +02001286 if (is_duplicate_member(&objmembers, varname, varname_end))
1287 {
1288 vim_free(init_expr);
1289 break;
1290 }
Bram Moolenaard505d172022-12-18 21:42:55 +00001291 if (add_member(&objmembers, varname, varname_end,
1292 has_public, type, init_expr) == FAIL)
Bram Moolenaar74e12742022-12-13 21:14:28 +00001293 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001294 vim_free(init_expr);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001295 break;
1296 }
Bram Moolenaard505d172022-12-18 21:42:55 +00001297 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001298
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001299 // constructors:
1300 // def new()
1301 // enddef
1302 // def newOther()
1303 // enddef
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001304 // object methods and class functions:
1305 // def SomeMethod()
1306 // enddef
1307 // static def ClassFunction()
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001308 // enddef
1309 // TODO:
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001310 // def <Tval> someMethod()
1311 // enddef
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001312 else if (checkforcmd(&p, "def", 3))
1313 {
1314 exarg_T ea;
1315 garray_T lines_to_free;
1316
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001317 // TODO: error for "public static def Func()"?
1318
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001319 CLEAR_FIELD(ea);
1320 ea.cmd = line;
1321 ea.arg = p;
1322 ea.cmdidx = CMD_def;
1323 ea.getline = eap->getline;
1324 ea.cookie = eap->cookie;
1325
1326 ga_init2(&lines_to_free, sizeof(char_u *), 50);
Bram Moolenaar554d0312023-01-05 19:59:18 +00001327 ufunc_T *uf = define_function(&ea, NULL, &lines_to_free,
1328 is_class ? CF_CLASS : CF_INTERFACE);
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001329 ga_clear_strings(&lines_to_free);
1330
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001331 if (uf != NULL)
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001332 {
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +02001333 char_u *name = uf->uf_name;
1334 int is_new = STRNCMP(name, "new", 3) == 0;
Gianmaria Bajo4b9777a2023-08-29 22:26:30 +02001335
1336 if (is_new && !is_valid_constructor(uf, is_abstract, has_static))
Bram Moolenaar24a8d062023-01-14 13:12:06 +00001337 {
Yegappan Lakshmananb1027282023-08-19 11:26:42 +02001338 func_clear_free(uf, FALSE);
Bram Moolenaar24a8d062023-01-14 13:12:06 +00001339 break;
1340 }
Gianmaria Bajo4b9777a2023-08-29 22:26:30 +02001341
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001342 garray_T *fgap = has_static || is_new
1343 ? &classfunctions : &objmethods;
Bram Moolenaar58b40092023-01-11 15:59:05 +00001344 // Check the name isn't used already.
Yegappan Lakshmanan2ba9d2e2023-08-28 21:26:23 +02001345 if (is_duplicate_method(fgap, name))
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +02001346 {
1347 success = FALSE;
1348 func_clear_free(uf, FALSE);
Yegappan Lakshmanan2ba9d2e2023-08-28 21:26:23 +02001349 break;
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +02001350 }
Bram Moolenaar58b40092023-01-11 15:59:05 +00001351
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001352 if (ga_grow(fgap, 1) == OK)
1353 {
1354 if (is_new)
1355 uf->uf_flags |= FC_NEW;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001356
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001357 ((ufunc_T **)fgap->ga_data)[fgap->ga_len] = uf;
1358 ++fgap->ga_len;
1359 }
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001360 }
1361 }
1362
1363 // class members
1364 else if (has_static)
1365 {
1366 // class members (public, read access, private):
1367 // "static _varname"
1368 // "static varname"
1369 // "public static varname"
1370 char_u *varname = p;
1371 char_u *varname_end = NULL;
1372 type_T *type = NULL;
1373 char_u *init_expr = NULL;
1374 if (parse_member(eap, line, varname, has_public,
Bram Moolenaar554d0312023-01-05 19:59:18 +00001375 &varname_end, &type_list, &type,
1376 is_class ? &init_expr : NULL) == FAIL)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001377 break;
Yegappan Lakshmanan2ba9d2e2023-08-28 21:26:23 +02001378 if (is_duplicate_member(&classmembers, varname, varname_end))
1379 {
1380 vim_free(init_expr);
1381 break;
1382 }
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001383 if (add_member(&classmembers, varname, varname_end,
1384 has_public, type, init_expr) == FAIL)
1385 {
1386 vim_free(init_expr);
1387 break;
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001388 }
1389 }
1390
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001391 else
1392 {
Bram Moolenaar554d0312023-01-05 19:59:18 +00001393 if (is_class)
1394 semsg(_(e_not_valid_command_in_class_str), line);
1395 else
1396 semsg(_(e_not_valid_command_in_interface_str), line);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001397 break;
1398 }
1399 }
1400 vim_free(theline);
1401
Bram Moolenaar83677162023-01-08 19:54:10 +00001402 class_T *extends_cl = NULL; // class from "extends" argument
1403
1404 /*
1405 * Check a few things before defining the class.
1406 */
1407
1408 // Check the "extends" class is valid.
1409 if (success && extends != NULL)
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001410 success = validate_extends_class(extends, &extends_cl);
Bram Moolenaar83677162023-01-08 19:54:10 +00001411 VIM_CLEAR(extends);
1412
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +02001413 // Check the new class members and object members doesn't duplicate the
1414 // members in the extended class lineage.
1415 if (success && extends_cl != NULL)
1416 success = validate_extends_members(&classmembers, &objmembers,
1417 extends_cl);
1418
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001419 class_T **intf_classes = NULL;
1420
Bram Moolenaar83677162023-01-08 19:54:10 +00001421 // Check all "implements" entries are valid.
Bram Moolenaar94674f22023-01-06 18:42:20 +00001422 if (success && ga_impl.ga_len > 0)
1423 {
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001424 intf_classes = ALLOC_CLEAR_MULT(class_T *, ga_impl.ga_len);
1425
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001426 success = validate_implements_classes(&ga_impl, intf_classes,
1427 &classfunctions, &classmembers,
1428 &objmethods, &objmembers);
Bram Moolenaar94674f22023-01-06 18:42:20 +00001429 }
1430
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001431 // Check no function argument name is used as a class member.
Bram Moolenaard40f00c2023-01-13 17:36:49 +00001432 if (success)
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001433 success = check_func_arg_names(&classfunctions, &objmethods,
1434 &classmembers);
Bram Moolenaard40f00c2023-01-13 17:36:49 +00001435
Bram Moolenaareb533502022-12-14 15:06:11 +00001436 class_T *cl = NULL;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001437 if (success)
1438 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001439 // "endclass" encountered without failures: Create the class.
1440
Bram Moolenaareb533502022-12-14 15:06:11 +00001441 cl = ALLOC_CLEAR_ONE(class_T);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001442 if (cl == NULL)
1443 goto cleanup;
Bram Moolenaar554d0312023-01-05 19:59:18 +00001444 if (!is_class)
1445 cl->class_flags = CLASS_INTERFACE;
1446
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001447 cl->class_refcount = 1;
Bram Moolenaar94674f22023-01-06 18:42:20 +00001448 cl->class_name = vim_strnsave(name_start, name_end - name_start);
Bram Moolenaard505d172022-12-18 21:42:55 +00001449 if (cl->class_name == NULL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001450 goto cleanup;
Bram Moolenaard505d172022-12-18 21:42:55 +00001451
Bram Moolenaard0200c82023-01-28 15:19:40 +00001452 if (extends_cl != NULL)
1453 {
1454 cl->class_extends = extends_cl;
1455 extends_cl->class_flags |= CLASS_EXTENDED;
1456 }
Bram Moolenaar83677162023-01-08 19:54:10 +00001457
Bram Moolenaard505d172022-12-18 21:42:55 +00001458 // Add class and object members to "cl".
1459 if (add_members_to_class(&classmembers,
Bram Moolenaar83677162023-01-08 19:54:10 +00001460 extends_cl == NULL ? NULL
1461 : extends_cl->class_class_members,
1462 extends_cl == NULL ? 0
1463 : extends_cl->class_class_member_count,
1464 &cl->class_class_members,
1465 &cl->class_class_member_count) == FAIL
Bram Moolenaard505d172022-12-18 21:42:55 +00001466 || add_members_to_class(&objmembers,
Bram Moolenaar83677162023-01-08 19:54:10 +00001467 extends_cl == NULL ? NULL
1468 : extends_cl->class_obj_members,
1469 extends_cl == NULL ? 0
1470 : extends_cl->class_obj_member_count,
1471 &cl->class_obj_members,
1472 &cl->class_obj_member_count) == FAIL)
Bram Moolenaard505d172022-12-18 21:42:55 +00001473 goto cleanup;
1474
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001475 if (ga_impl.ga_len > 0)
1476 {
1477 // Move the "implements" names into the class.
1478 cl->class_interface_count = ga_impl.ga_len;
1479 cl->class_interfaces = ALLOC_MULT(char_u *, ga_impl.ga_len);
1480 if (cl->class_interfaces == NULL)
1481 goto cleanup;
1482 for (int i = 0; i < ga_impl.ga_len; ++i)
1483 cl->class_interfaces[i] = ((char_u **)ga_impl.ga_data)[i];
1484 VIM_CLEAR(ga_impl.ga_data);
1485 ga_impl.ga_len = 0;
1486
Bram Moolenaard0200c82023-01-28 15:19:40 +00001487 cl->class_interfaces_cl = intf_classes;
1488 intf_classes = NULL;
1489 }
1490
1491 if (cl->class_interface_count > 0 || extends_cl != NULL)
1492 {
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001493 // Add a method and member lookup table to each of the interface
1494 // classes.
1495 if (add_lookup_tables(cl, extends_cl, &objmethods) == FAIL)
1496 goto cleanup;
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001497 }
1498
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001499 // Allocate a typval for each class member and initialize it.
Bram Moolenaar554d0312023-01-05 19:59:18 +00001500 if (is_class && cl->class_class_member_count > 0)
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001501 add_class_members(cl, eap);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001502
Yegappan Lakshmanan6ac15442023-08-20 18:20:17 +02001503 int have_new = FALSE;
1504 ufunc_T *class_func = NULL;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001505 for (int i = 0; i < classfunctions.ga_len; ++i)
Yegappan Lakshmanan6ac15442023-08-20 18:20:17 +02001506 {
1507 class_func = ((ufunc_T **)classfunctions.ga_data)[i];
1508 if (STRCMP(class_func->uf_name, "new") == 0)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001509 {
1510 have_new = TRUE;
1511 break;
1512 }
Yegappan Lakshmanan6ac15442023-08-20 18:20:17 +02001513 }
1514
1515 if (have_new)
1516 // The return type of new() is an object of class "cl"
1517 class_func->uf_ret_type->tt_class = cl;
1518 else if (is_class && !is_abstract && !have_new)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001519 // No new() method was defined, add the default constructor.
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001520 add_default_constructor(cl, &classfunctions, &type_list);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001521
Bram Moolenaar58b40092023-01-11 15:59:05 +00001522 // Move all the functions into the created class.
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001523 if (add_classfuncs_objmethods(cl, extends_cl, &classfunctions,
1524 &objmethods) == FAIL)
1525 goto cleanup;
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001526
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001527 cl->class_type.tt_type = VAR_CLASS;
Bram Moolenaarb1e32ac2023-02-21 12:38:51 +00001528 cl->class_type.tt_class = cl;
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001529 cl->class_object_type.tt_type = VAR_OBJECT;
Bram Moolenaarb1e32ac2023-02-21 12:38:51 +00001530 cl->class_object_type.tt_class = cl;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001531 cl->class_type_list = type_list;
1532
Yegappan Lakshmanane651e112023-09-04 07:51:01 +02001533 class_created(cl);
1534
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001535 // TODO:
Bram Moolenaard505d172022-12-18 21:42:55 +00001536 // - Fill hashtab with object members and methods ?
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001537
1538 // Add the class to the script-local variables.
Bram Moolenaar94674f22023-01-06 18:42:20 +00001539 // TODO: handle other context, e.g. in a function
Ernie Rael21d32122023-09-02 15:09:18 +02001540 // TODO: does uf_hash need to be cleared?
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001541 typval_T tv;
1542 tv.v_type = VAR_CLASS;
1543 tv.vval.v_class = cl;
Bram Moolenaara86655a2023-01-12 17:06:27 +00001544 is_export = class_export;
Bram Moolenaar83ae6152023-02-25 19:59:31 +00001545 SOURCING_LNUM = start_lnum;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001546 set_var_const(cl->class_name, current_sctx.sc_sid,
Bram Moolenaar83ae6152023-02-25 19:59:31 +00001547 NULL, &tv, FALSE, 0, 0);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001548 return;
1549 }
1550
1551cleanup:
Bram Moolenaareb533502022-12-14 15:06:11 +00001552 if (cl != NULL)
1553 {
1554 vim_free(cl->class_name);
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001555 vim_free(cl->class_class_functions);
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001556 if (cl->class_interfaces != NULL)
1557 {
1558 for (int i = 0; i < cl->class_interface_count; ++i)
1559 vim_free(cl->class_interfaces[i]);
1560 vim_free(cl->class_interfaces);
1561 }
1562 if (cl->class_interfaces_cl != NULL)
1563 {
1564 for (int i = 0; i < cl->class_interface_count; ++i)
1565 class_unref(cl->class_interfaces_cl[i]);
1566 vim_free(cl->class_interfaces_cl);
1567 }
Bram Moolenaareb533502022-12-14 15:06:11 +00001568 vim_free(cl->class_obj_members);
1569 vim_free(cl->class_obj_methods);
1570 vim_free(cl);
1571 }
1572
Bram Moolenaar83677162023-01-08 19:54:10 +00001573 vim_free(extends);
1574 class_unref(extends_cl);
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001575
1576 if (intf_classes != NULL)
1577 {
1578 for (int i = 0; i < ga_impl.ga_len; ++i)
1579 class_unref(intf_classes[i]);
1580 vim_free(intf_classes);
1581 }
Bram Moolenaar94674f22023-01-06 18:42:20 +00001582 ga_clear_strings(&ga_impl);
1583
Bram Moolenaard505d172022-12-18 21:42:55 +00001584 for (int round = 1; round <= 2; ++round)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001585 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001586 garray_T *gap = round == 1 ? &classmembers : &objmembers;
1587 if (gap->ga_len == 0 || gap->ga_data == NULL)
1588 continue;
1589
1590 for (int i = 0; i < gap->ga_len; ++i)
1591 {
1592 ocmember_T *m = ((ocmember_T *)gap->ga_data) + i;
1593 vim_free(m->ocm_name);
1594 vim_free(m->ocm_init);
1595 }
1596 ga_clear(gap);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001597 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001598
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001599 for (int i = 0; i < objmethods.ga_len; ++i)
1600 {
1601 ufunc_T *uf = ((ufunc_T **)objmethods.ga_data)[i];
1602 func_clear_free(uf, FALSE);
1603 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001604 ga_clear(&objmethods);
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001605
1606 for (int i = 0; i < classfunctions.ga_len; ++i)
1607 {
1608 ufunc_T *uf = ((ufunc_T **)classfunctions.ga_data)[i];
1609 func_clear_free(uf, FALSE);
1610 }
1611 ga_clear(&classfunctions);
1612
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001613 clear_type_list(&type_list);
1614}
1615
1616/*
Bram Moolenaarf54cedd2022-12-23 17:56:27 +00001617 * Find member "name" in class "cl", set "member_idx" to the member index and
1618 * return its type.
Yegappan Lakshmanan3775f772023-09-01 22:05:45 +02001619 * When "is_object" is TRUE, then look for object members. Otherwise look for
1620 * class members.
Bram Moolenaarf54cedd2022-12-23 17:56:27 +00001621 * When not found "member_idx" is set to -1 and t_any is returned.
Ernie Rael456ae552023-09-01 18:54:54 +02001622 * Set *p_m ocmmember_T if not NULL
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001623 */
1624 type_T *
1625class_member_type(
Yegappan Lakshmananeb91e242023-08-31 18:10:46 +02001626 class_T *cl,
Yegappan Lakshmanan3775f772023-09-01 22:05:45 +02001627 int is_object,
Yegappan Lakshmananeb91e242023-08-31 18:10:46 +02001628 char_u *name,
1629 char_u *name_end,
1630 int *member_idx,
Ernie Rael456ae552023-09-01 18:54:54 +02001631 ocmember_T **p_m)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001632{
1633 *member_idx = -1; // not found (yet)
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +02001634 size_t len = name_end - name;
1635 int member_count = is_object ? cl->class_obj_member_count
1636 : cl->class_class_member_count;
1637 ocmember_T *members = is_object ? cl->class_obj_members
1638 : cl->class_class_members;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001639
Yegappan Lakshmanan3775f772023-09-01 22:05:45 +02001640 for (int i = 0; i < member_count; ++i)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001641 {
Yegappan Lakshmanan3775f772023-09-01 22:05:45 +02001642 ocmember_T *m = members + i;
Bram Moolenaard505d172022-12-18 21:42:55 +00001643 if (STRNCMP(m->ocm_name, name, len) == 0 && m->ocm_name[len] == NUL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001644 {
1645 *member_idx = i;
Ernie Rael456ae552023-09-01 18:54:54 +02001646 if (p_m != NULL)
1647 *p_m = m;
Bram Moolenaard505d172022-12-18 21:42:55 +00001648 return m->ocm_type;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001649 }
1650 }
Bram Moolenaarf54cedd2022-12-23 17:56:27 +00001651
1652 semsg(_(e_unknown_variable_str), name);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001653 return &t_any;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001654}
1655
1656/*
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001657 * Handle ":enum" up to ":endenum".
1658 */
1659 void
1660ex_enum(exarg_T *eap UNUSED)
1661{
1662 // TODO
1663}
1664
1665/*
1666 * Handle ":type".
1667 */
1668 void
1669ex_type(exarg_T *eap UNUSED)
1670{
1671 // TODO
1672}
1673
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001674/*
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +02001675 * Returns OK if a member variable named "name" is present in the class "cl".
1676 * Otherwise returns FAIL. If found, the member variable typval is set in
1677 * "rettv". If "is_object" is TRUE, then the object member variable table is
1678 * searched. Otherwise the class member variable table is searched.
1679 */
1680 static int
1681get_member_tv(
1682 class_T *cl,
1683 int is_object,
1684 char_u *name,
1685 size_t namelen,
1686 typval_T *rettv)
1687{
1688 int member_count = is_object ? cl->class_obj_member_count
1689 : cl->class_class_member_count;
1690 ocmember_T *members = is_object ? cl->class_obj_members
1691 : cl->class_class_members;
1692
1693 for (int i = 0; i < member_count; ++i)
1694 {
1695 ocmember_T *m = &members[i];
1696 if (STRNCMP(name, m->ocm_name, namelen) == 0
1697 && m->ocm_name[namelen] == NUL)
1698 {
1699 if (*name == '_')
1700 {
1701 semsg(_(e_cannot_access_private_member_str), m->ocm_name);
1702 return FAIL;
1703 }
1704
1705 // The object only contains a pointer to the class, the member
1706 // values array follows right after that.
1707 object_T *obj = rettv->vval.v_object;
1708 if (is_object)
1709 {
1710 typval_T *tv = (typval_T *)(obj + 1) + i;
1711 copy_tv(tv, rettv);
1712 }
1713 else
1714 copy_tv(&cl->class_members_tv[i], rettv);
1715
1716 object_unref(obj);
1717
1718 return OK;
1719 }
1720 }
1721
1722 return FAIL;
1723}
1724
1725/*
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001726 * Evaluate what comes after a class:
1727 * - class member: SomeClass.varname
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001728 * - class function: SomeClass.SomeMethod()
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001729 * - class constructor: SomeClass.new()
1730 * - object member: someObject.varname
1731 * - object method: someObject.SomeMethod()
1732 *
1733 * "*arg" points to the '.'.
1734 * "*arg" is advanced to after the member name or method call.
1735 *
1736 * Returns FAIL or OK.
1737 */
1738 int
1739class_object_index(
1740 char_u **arg,
1741 typval_T *rettv,
1742 evalarg_T *evalarg,
1743 int verbose UNUSED) // give error messages
1744{
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001745 if (VIM_ISWHITE((*arg)[1]))
1746 {
1747 semsg(_(e_no_white_space_allowed_after_str_str), ".", *arg);
1748 return FAIL;
1749 }
1750
1751 ++*arg;
1752 char_u *name = *arg;
1753 char_u *name_end = find_name_end(name, NULL, NULL, FNE_CHECK_START);
1754 if (name_end == name)
1755 return FAIL;
1756 size_t len = name_end - name;
1757
Bram Moolenaar552bdca2023-02-17 21:08:50 +00001758 class_T *cl;
1759 if (rettv->v_type == VAR_CLASS)
1760 cl = rettv->vval.v_class;
1761 else // VAR_OBJECT
1762 {
1763 if (rettv->vval.v_object == NULL)
1764 {
1765 emsg(_(e_using_null_object));
1766 return FAIL;
1767 }
1768 cl = rettv->vval.v_object->obj_class;
1769 }
1770
Bram Moolenaard13dd302023-03-11 20:56:35 +00001771 if (cl == NULL)
1772 {
1773 emsg(_(e_incomplete_type));
1774 return FAIL;
1775 }
1776
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001777 if (*name_end == '(')
1778 {
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001779 int on_class = rettv->v_type == VAR_CLASS;
1780 int count = on_class ? cl->class_class_function_count
1781 : cl->class_obj_method_count;
1782 for (int i = 0; i < count; ++i)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001783 {
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001784 ufunc_T *fp = on_class ? cl->class_class_functions[i]
1785 : cl->class_obj_methods[i];
Bram Moolenaar4ae00572022-12-09 22:49:23 +00001786 // Use a separate pointer to avoid that ASAN complains about
1787 // uf_name[] only being 4 characters.
1788 char_u *ufname = (char_u *)fp->uf_name;
1789 if (STRNCMP(name, ufname, len) == 0 && ufname[len] == NUL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001790 {
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +02001791 typval_T argvars[MAX_FUNC_ARGS + 1];
1792 int argcount = 0;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001793
Yegappan Lakshmanane3b6c782023-08-29 22:32:02 +02001794 if (*ufname == '_')
Yegappan Lakshmanancd7293b2023-08-27 19:18:23 +02001795 {
1796 // Cannot access a private method outside of a class
1797 semsg(_(e_cannot_access_private_method_str), name);
1798 return FAIL;
1799 }
1800
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001801 char_u *argp = name_end;
1802 int ret = get_func_arguments(&argp, evalarg, 0,
1803 argvars, &argcount);
1804 if (ret == FAIL)
1805 return FAIL;
1806
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +02001807 funcexe_T funcexe;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001808 CLEAR_FIELD(funcexe);
1809 funcexe.fe_evaluate = TRUE;
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001810 if (rettv->v_type == VAR_OBJECT)
1811 {
1812 funcexe.fe_object = rettv->vval.v_object;
1813 ++funcexe.fe_object->obj_refcount;
1814 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001815
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001816 // Clear the class or object after calling the function, in
1817 // case the refcount is one.
1818 typval_T tv_tofree = *rettv;
1819 rettv->v_type = VAR_UNKNOWN;
1820
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001821 // Call the user function. Result goes into rettv;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001822 int error = call_user_func_check(fp, argcount, argvars,
1823 rettv, &funcexe, NULL);
1824
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001825 // Clear the previous rettv and the arguments.
1826 clear_tv(&tv_tofree);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001827 for (int idx = 0; idx < argcount; ++idx)
1828 clear_tv(&argvars[idx]);
1829
1830 if (error != FCERR_NONE)
1831 {
1832 user_func_error(error, printable_func_name(fp),
1833 funcexe.fe_found_var);
1834 return FAIL;
1835 }
1836 *arg = argp;
1837 return OK;
1838 }
1839 }
1840
1841 semsg(_(e_method_not_found_on_class_str_str), cl->class_name, name);
1842 }
1843
1844 else if (rettv->v_type == VAR_OBJECT)
1845 {
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +02001846 // Search in the object member variable table and the class member
1847 // variable table.
1848 if (get_member_tv(cl, TRUE, name, len, rettv) == OK
1849 || get_member_tv(cl, FALSE, name, len, rettv) == OK)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001850 {
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +02001851 *arg = name_end;
1852 return OK;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001853 }
1854
1855 semsg(_(e_member_not_found_on_object_str_str), cl->class_name, name);
1856 }
1857
Bram Moolenaard505d172022-12-18 21:42:55 +00001858 else if (rettv->v_type == VAR_CLASS)
1859 {
1860 // class member
1861 for (int i = 0; i < cl->class_class_member_count; ++i)
1862 {
1863 ocmember_T *m = &cl->class_class_members[i];
1864 if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
1865 {
1866 if (*name == '_')
1867 {
1868 semsg(_(e_cannot_access_private_member_str), m->ocm_name);
1869 return FAIL;
1870 }
Ernie Rael18143d32023-09-04 22:30:41 +02001871 if ((cl->class_flags & CLASS_INTERFACE) != 0)
1872 {
1873 semsg(_(e_interface_static_direct_access_str),
1874 cl->class_name, m->ocm_name);
1875 return FAIL;
1876 }
Bram Moolenaard505d172022-12-18 21:42:55 +00001877
1878 typval_T *tv = &cl->class_members_tv[i];
1879 copy_tv(tv, rettv);
1880 class_unref(cl);
1881
1882 *arg = name_end;
1883 return OK;
1884 }
1885 }
1886
1887 semsg(_(e_member_not_found_on_class_str_str), cl->class_name, name);
1888 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001889
1890 return FAIL;
1891}
1892
1893/*
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001894 * If "arg" points to a class or object method, return it.
1895 * Otherwise return NULL.
1896 */
1897 ufunc_T *
1898find_class_func(char_u **arg)
1899{
1900 char_u *name = *arg;
1901 char_u *name_end = find_name_end(name, NULL, NULL, FNE_CHECK_START);
1902 if (name_end == name || *name_end != '.')
1903 return NULL;
1904
Yegappan Lakshmanan1689e842023-09-06 20:23:23 +02001905 size_t len = name_end - name;
1906 typval_T tv;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001907 tv.v_type = VAR_UNKNOWN;
Bram Moolenaar993dbc32023-01-01 20:31:30 +00001908 if (eval_variable(name, (int)len,
1909 0, &tv, NULL, EVAL_VAR_NOAUTOLOAD) == FAIL)
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001910 return NULL;
1911 if (tv.v_type != VAR_CLASS && tv.v_type != VAR_OBJECT)
Bram Moolenaareb533502022-12-14 15:06:11 +00001912 goto fail_after_eval;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001913
1914 class_T *cl = tv.v_type == VAR_CLASS ? tv.vval.v_class
1915 : tv.vval.v_object->obj_class;
1916 if (cl == NULL)
Bram Moolenaareb533502022-12-14 15:06:11 +00001917 goto fail_after_eval;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001918 char_u *fname = name_end + 1;
1919 char_u *fname_end = find_name_end(fname, NULL, NULL, FNE_CHECK_START);
1920 if (fname_end == fname)
Bram Moolenaareb533502022-12-14 15:06:11 +00001921 goto fail_after_eval;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001922 len = fname_end - fname;
1923
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001924 int count = tv.v_type == VAR_CLASS ? cl->class_class_function_count
1925 : cl->class_obj_method_count;
1926 ufunc_T **funcs = tv.v_type == VAR_CLASS ? cl->class_class_functions
1927 : cl->class_obj_methods;
1928 for (int i = 0; i < count; ++i)
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001929 {
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001930 ufunc_T *fp = funcs[i];
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001931 // Use a separate pointer to avoid that ASAN complains about
1932 // uf_name[] only being 4 characters.
1933 char_u *ufname = (char_u *)fp->uf_name;
1934 if (STRNCMP(fname, ufname, len) == 0 && ufname[len] == NUL)
Bram Moolenaareb533502022-12-14 15:06:11 +00001935 {
1936 clear_tv(&tv);
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001937 return fp;
Bram Moolenaareb533502022-12-14 15:06:11 +00001938 }
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001939 }
1940
Bram Moolenaareb533502022-12-14 15:06:11 +00001941fail_after_eval:
1942 clear_tv(&tv);
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001943 return NULL;
1944}
1945
1946/*
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001947 * If "name[len]" is a class member in cctx->ctx_ufunc->uf_class return the
1948 * index in class.class_class_members[].
1949 * If "cl_ret" is not NULL set it to the class.
1950 * Otherwise return -1;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001951 */
1952 int
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001953class_member_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001954{
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001955 if (cctx == NULL || cctx->ctx_ufunc == NULL
1956 || cctx->ctx_ufunc->uf_class == NULL)
1957 return -1;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001958 class_T *cl = cctx->ctx_ufunc->uf_class;
1959
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001960 for (int i = 0; i < cl->class_class_member_count; ++i)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001961 {
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001962 ocmember_T *m = &cl->class_class_members[i];
1963 if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001964 {
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001965 if (cl_ret != NULL)
1966 *cl_ret = cl;
1967 return i;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001968 }
1969 }
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001970 return -1;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001971}
1972
1973/*
Bram Moolenaar62a69232023-01-24 15:07:04 +00001974 * Return TRUE if current context "cctx_arg" is inside class "cl".
1975 * Return FALSE if not.
1976 */
1977 int
1978inside_class(cctx_T *cctx_arg, class_T *cl)
1979{
1980 for (cctx_T *cctx = cctx_arg; cctx != NULL; cctx = cctx->ctx_outer)
1981 if (cctx->ctx_ufunc != NULL && cctx->ctx_ufunc->uf_class == cl)
1982 return TRUE;
1983 return FALSE;
1984}
1985
1986/*
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001987 * Make a copy of an object.
1988 */
1989 void
1990copy_object(typval_T *from, typval_T *to)
1991{
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +02001992 if (from->vval.v_object == NULL)
1993 to->vval.v_object = NULL;
1994 else
1995 {
1996 to->vval.v_object = from->vval.v_object;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001997 ++to->vval.v_object->obj_refcount;
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +02001998 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001999}
2000
2001/*
2002 * Free an object.
2003 */
2004 static void
2005object_clear(object_T *obj)
2006{
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01002007 // Avoid a recursive call, it can happen if "obj" has a circular reference.
2008 obj->obj_refcount = INT_MAX;
2009
Bram Moolenaar00b28d62022-12-08 15:32:33 +00002010 class_T *cl = obj->obj_class;
2011
Jia-Ju Bai5b0889b2023-08-13 20:04:04 +02002012 if (!cl)
Yegappan Lakshmanand4e4ecb2023-08-27 18:35:45 +02002013 return;
Jia-Ju Bai5b0889b2023-08-13 20:04:04 +02002014
Bram Moolenaar00b28d62022-12-08 15:32:33 +00002015 // the member values are just after the object structure
2016 typval_T *tv = (typval_T *)(obj + 1);
2017 for (int i = 0; i < cl->class_obj_member_count; ++i)
2018 clear_tv(tv + i);
2019
Bram Moolenaard28d7b92022-12-08 20:42:00 +00002020 // Remove from the list headed by "first_object".
2021 object_cleared(obj);
2022
Bram Moolenaar00b28d62022-12-08 15:32:33 +00002023 vim_free(obj);
Bram Moolenaard28d7b92022-12-08 20:42:00 +00002024 class_unref(cl);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00002025}
2026
2027/*
2028 * Unreference an object.
2029 */
2030 void
2031object_unref(object_T *obj)
2032{
2033 if (obj != NULL && --obj->obj_refcount <= 0)
2034 object_clear(obj);
2035}
2036
2037/*
2038 * Make a copy of a class.
2039 */
2040 void
2041copy_class(typval_T *from, typval_T *to)
2042{
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +02002043 if (from->vval.v_class == NULL)
2044 to->vval.v_class = NULL;
2045 else
2046 {
2047 to->vval.v_class = from->vval.v_class;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00002048 ++to->vval.v_class->class_refcount;
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +02002049 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00002050}
2051
2052/*
Yegappan Lakshmanane651e112023-09-04 07:51:01 +02002053 * Free the class "cl" and its contents.
2054 */
2055 static void
2056class_free(class_T *cl)
2057{
2058 // Freeing what the class contains may recursively come back here.
2059 // Clear "class_name" first, if it is NULL the class does not need to
2060 // be freed.
2061 VIM_CLEAR(cl->class_name);
2062
2063 class_unref(cl->class_extends);
2064
2065 for (int i = 0; i < cl->class_interface_count; ++i)
2066 {
2067 vim_free(((char_u **)cl->class_interfaces)[i]);
2068 if (cl->class_interfaces_cl[i] != NULL)
2069 class_unref(cl->class_interfaces_cl[i]);
2070 }
2071 vim_free(cl->class_interfaces);
2072 vim_free(cl->class_interfaces_cl);
2073
2074 itf2class_T *next;
2075 for (itf2class_T *i2c = cl->class_itf2class; i2c != NULL; i2c = next)
2076 {
2077 next = i2c->i2c_next;
2078 vim_free(i2c);
2079 }
2080
2081 for (int i = 0; i < cl->class_class_member_count; ++i)
2082 {
2083 ocmember_T *m = &cl->class_class_members[i];
2084 vim_free(m->ocm_name);
2085 vim_free(m->ocm_init);
2086 if (cl->class_members_tv != NULL)
2087 clear_tv(&cl->class_members_tv[i]);
2088 }
2089 vim_free(cl->class_class_members);
2090 vim_free(cl->class_members_tv);
2091
2092 for (int i = 0; i < cl->class_obj_member_count; ++i)
2093 {
2094 ocmember_T *m = &cl->class_obj_members[i];
2095 vim_free(m->ocm_name);
2096 vim_free(m->ocm_init);
2097 }
2098 vim_free(cl->class_obj_members);
2099
2100 for (int i = 0; i < cl->class_class_function_count; ++i)
2101 {
2102 ufunc_T *uf = cl->class_class_functions[i];
2103 func_clear_free(uf, FALSE);
2104 }
2105 vim_free(cl->class_class_functions);
2106
2107 for (int i = 0; i < cl->class_obj_method_count; ++i)
2108 {
2109 ufunc_T *uf = cl->class_obj_methods[i];
2110 func_clear_free(uf, FALSE);
2111 }
2112 vim_free(cl->class_obj_methods);
2113
2114 clear_type_list(&cl->class_type_list);
2115
2116 class_cleared(cl);
2117
2118 vim_free(cl);
2119}
2120
2121/*
Bram Moolenaar00b28d62022-12-08 15:32:33 +00002122 * Unreference a class. Free it when the reference count goes down to zero.
2123 */
2124 void
Bram Moolenaard28d7b92022-12-08 20:42:00 +00002125class_unref(class_T *cl)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00002126{
Bram Moolenaard505d172022-12-18 21:42:55 +00002127 if (cl != NULL && --cl->class_refcount <= 0 && cl->class_name != NULL)
Yegappan Lakshmanane651e112023-09-04 07:51:01 +02002128 class_free(cl);
2129}
2130
2131/*
2132 * Go through the list of all classes and free items without "copyID".
2133 */
2134 int
2135class_free_nonref(int copyID)
2136{
2137 int did_free = FALSE;
2138
2139 for (class_T *cl = first_class; cl != NULL; cl = next_nonref_class)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00002140 {
Yegappan Lakshmanane651e112023-09-04 07:51:01 +02002141 next_nonref_class = cl->class_next_used;
2142 if ((cl->class_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00002143 {
Yegappan Lakshmanane651e112023-09-04 07:51:01 +02002144 // Free the class and items it contains.
2145 class_free(cl);
2146 did_free = TRUE;
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00002147 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00002148 }
Yegappan Lakshmanane651e112023-09-04 07:51:01 +02002149
2150 next_nonref_class = NULL;
2151 return did_free;
2152}
2153
2154 int
2155set_ref_in_classes(int copyID)
2156{
2157 for (class_T *cl = first_class; cl != NULL; cl = cl->class_next_used)
2158 set_ref_in_item_class(cl, copyID, NULL, NULL);
2159
2160 return FALSE;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00002161}
2162
Bram Moolenaard28d7b92022-12-08 20:42:00 +00002163static object_T *first_object = NULL;
2164
2165/*
2166 * Call this function when an object has been created. It will be added to the
2167 * list headed by "first_object".
2168 */
2169 void
2170object_created(object_T *obj)
2171{
2172 if (first_object != NULL)
2173 {
2174 obj->obj_next_used = first_object;
2175 first_object->obj_prev_used = obj;
2176 }
2177 first_object = obj;
2178}
2179
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01002180static object_T *next_nonref_obj = NULL;
2181
Bram Moolenaard28d7b92022-12-08 20:42:00 +00002182/*
2183 * Call this function when an object has been cleared and is about to be freed.
2184 * It is removed from the list headed by "first_object".
2185 */
2186 void
2187object_cleared(object_T *obj)
2188{
2189 if (obj->obj_next_used != NULL)
2190 obj->obj_next_used->obj_prev_used = obj->obj_prev_used;
2191 if (obj->obj_prev_used != NULL)
2192 obj->obj_prev_used->obj_next_used = obj->obj_next_used;
2193 else if (first_object == obj)
2194 first_object = obj->obj_next_used;
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01002195
2196 // update the next object to check if needed
2197 if (obj == next_nonref_obj)
2198 next_nonref_obj = obj->obj_next_used;
Bram Moolenaard28d7b92022-12-08 20:42:00 +00002199}
2200
2201/*
2202 * Go through the list of all objects and free items without "copyID".
2203 */
2204 int
2205object_free_nonref(int copyID)
2206{
2207 int did_free = FALSE;
Bram Moolenaard28d7b92022-12-08 20:42:00 +00002208
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01002209 for (object_T *obj = first_object; obj != NULL; obj = next_nonref_obj)
Bram Moolenaard28d7b92022-12-08 20:42:00 +00002210 {
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01002211 next_nonref_obj = obj->obj_next_used;
Bram Moolenaard28d7b92022-12-08 20:42:00 +00002212 if ((obj->obj_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
2213 {
2214 // Free the object and items it contains.
2215 object_clear(obj);
2216 did_free = TRUE;
2217 }
2218 }
2219
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01002220 next_nonref_obj = NULL;
Bram Moolenaard28d7b92022-12-08 20:42:00 +00002221 return did_free;
2222}
2223
LemonBoyafe04662023-08-23 21:08:11 +02002224/*
Yegappan Lakshmanand4e4ecb2023-08-27 18:35:45 +02002225 * Return TRUE when the class "cl", its base class or one of the implemented
2226 * interfaces matches the class "other_cl".
LemonBoyafe04662023-08-23 21:08:11 +02002227 */
2228 int
2229class_instance_of(class_T *cl, class_T *other_cl)
2230{
2231 if (cl == other_cl)
2232 return TRUE;
2233
2234 // Recursively check the base classes.
2235 for (; cl != NULL; cl = cl->class_extends)
2236 {
2237 if (cl == other_cl)
2238 return TRUE;
2239 // Check the implemented interfaces.
2240 for (int i = cl->class_interface_count - 1; i >= 0; --i)
2241 if (cl->class_interfaces_cl[i] == other_cl)
2242 return TRUE;
2243 }
2244
2245 return FALSE;
2246}
2247
2248/*
2249 * "instanceof(object, classinfo)" function
2250 */
2251 void
2252f_instanceof(typval_T *argvars, typval_T *rettv)
2253{
2254 typval_T *object_tv = &argvars[0];
2255 typval_T *classinfo_tv = &argvars[1];
2256 listitem_T *li;
2257
2258 rettv->vval.v_number = VVAL_FALSE;
2259
2260 if (check_for_object_arg(argvars, 0) == FAIL
2261 || check_for_class_or_list_arg(argvars, 1) == FAIL)
2262 return;
2263
2264 if (classinfo_tv->v_type == VAR_LIST)
2265 {
2266 FOR_ALL_LIST_ITEMS(classinfo_tv->vval.v_list, li)
2267 {
2268 if (li->li_tv.v_type != VAR_CLASS)
2269 {
2270 emsg(_(e_class_required));
2271 return;
2272 }
2273
2274 if (class_instance_of(object_tv->vval.v_object->obj_class,
2275 li->li_tv.vval.v_class) == TRUE)
2276 {
2277 rettv->vval.v_number = VVAL_TRUE;
2278 return;
2279 }
2280 }
2281 }
2282 else if (classinfo_tv->v_type == VAR_CLASS)
2283 {
2284 rettv->vval.v_number = class_instance_of(object_tv->vval.v_object->obj_class,
2285 classinfo_tv->vval.v_class);
2286 }
2287}
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00002288
2289#endif // FEAT_EVAL