blob: 00b1f7d98fa19c22c6627e6bf883990b0be36824 [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
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +020070 char_u *init_arg = skipwhite(type_arg);
71 if (type == NULL && *init_arg != '=')
Bram Moolenaard505d172022-12-18 21:42:55 +000072 {
73 emsg(_(e_type_or_initialization_required));
74 return FAIL;
75 }
76
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +020077 if (init_expr == NULL && *init_arg == '=')
Bram Moolenaard505d172022-12-18 21:42:55 +000078 {
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +020079 emsg(_(e_cannot_initialize_member_in_interface));
80 return FAIL;
81 }
82
83 if (*init_arg == '=')
84 {
85 evalarg_T evalarg;
86 char_u *expr_start, *expr_end;
87
88 if (!VIM_ISWHITE(init_arg[-1]) || !VIM_ISWHITE(init_arg[1]))
Bram Moolenaard505d172022-12-18 21:42:55 +000089 {
90 semsg(_(e_white_space_required_before_and_after_str_at_str),
91 "=", type_arg);
92 return FAIL;
93 }
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +020094 init_arg = skipwhite(init_arg + 1);
Bram Moolenaard505d172022-12-18 21:42:55 +000095
Bram Moolenaard505d172022-12-18 21:42:55 +000096 fill_evalarg_from_eap(&evalarg, eap, FALSE);
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +020097 (void)skip_expr_concatenate(&init_arg, &expr_start, &expr_end, &evalarg);
Bram Moolenaard505d172022-12-18 21:42:55 +000098
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +020099 // No type specified for the member. Set it to "any" and the correct type will be
100 // set when the object is instantiated.
Bram Moolenaard505d172022-12-18 21:42:55 +0000101 if (type == NULL)
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +0200102 type = &t_any;
Bram Moolenaard505d172022-12-18 21:42:55 +0000103
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +0200104 *init_expr = vim_strnsave(expr_start, expr_end - expr_start);
105 // Free the memory pointed by expr_start.
Bram Moolenaard505d172022-12-18 21:42:55 +0000106 clear_evalarg(&evalarg, NULL);
107 }
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +0200108 else if (!valid_declaration_type(type))
Bram Moolenaard505d172022-12-18 21:42:55 +0000109 return FAIL;
110
111 *type_ret = type;
Bram Moolenaard505d172022-12-18 21:42:55 +0000112 return OK;
113}
114
115/*
116 * Add a member to an object or a class.
117 * Returns OK when successful, "init_expr" will be consumed then.
118 * Returns FAIL otherwise, caller might need to free "init_expr".
119 */
120 static int
121add_member(
122 garray_T *gap,
123 char_u *varname,
124 char_u *varname_end,
125 int has_public,
126 type_T *type,
127 char_u *init_expr)
128{
129 if (ga_grow(gap, 1) == FAIL)
130 return FAIL;
131 ocmember_T *m = ((ocmember_T *)gap->ga_data) + gap->ga_len;
132 m->ocm_name = vim_strnsave(varname, varname_end - varname);
=?UTF-8?q?Ola=20S=C3=B6der?=d8742472023-03-05 13:12:32 +0000133 m->ocm_access = has_public ? VIM_ACCESS_ALL
134 : *varname == '_' ? VIM_ACCESS_PRIVATE : VIM_ACCESS_READ;
Bram Moolenaard505d172022-12-18 21:42:55 +0000135 m->ocm_type = type;
136 if (init_expr != NULL)
137 m->ocm_init = init_expr;
138 ++gap->ga_len;
139 return OK;
140}
141
142/*
143 * Move the class or object members found while parsing a class into the class.
144 * "gap" contains the found members.
Bram Moolenaar83677162023-01-08 19:54:10 +0000145 * "parent_members" points to the members in the parent class (if any)
146 * "parent_count" is the number of members in the parent class
Bram Moolenaard505d172022-12-18 21:42:55 +0000147 * "members" will be set to the newly allocated array of members and
148 * "member_count" set to the number of members.
149 * Returns OK or FAIL.
150 */
151 static int
152add_members_to_class(
153 garray_T *gap,
Bram Moolenaar83677162023-01-08 19:54:10 +0000154 ocmember_T *parent_members,
155 int parent_count,
Bram Moolenaard505d172022-12-18 21:42:55 +0000156 ocmember_T **members,
157 int *member_count)
158{
Bram Moolenaar83677162023-01-08 19:54:10 +0000159 *member_count = parent_count + gap->ga_len;
160 *members = *member_count == 0 ? NULL
161 : ALLOC_MULT(ocmember_T, *member_count);
162 if (*member_count > 0 && *members == NULL)
Bram Moolenaard505d172022-12-18 21:42:55 +0000163 return FAIL;
Bram Moolenaar83677162023-01-08 19:54:10 +0000164 for (int i = 0; i < parent_count; ++i)
165 {
166 // parent members need to be copied
Bram Moolenaarae3205a2023-01-15 20:49:00 +0000167 ocmember_T *m = *members + i;
168 *m = parent_members[i];
169 m->ocm_name = vim_strsave(m->ocm_name);
170 if (m->ocm_init != NULL)
171 m->ocm_init = vim_strsave(m->ocm_init);
Bram Moolenaar83677162023-01-08 19:54:10 +0000172 }
Bram Moolenaar8efdcee2022-12-19 12:18:09 +0000173 if (gap->ga_len > 0)
Bram Moolenaar83677162023-01-08 19:54:10 +0000174 // new members are moved
175 mch_memmove(*members + parent_count,
176 gap->ga_data, sizeof(ocmember_T) * gap->ga_len);
Bram Moolenaard505d172022-12-18 21:42:55 +0000177 VIM_CLEAR(gap->ga_data);
178 return OK;
179}
180
181/*
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000182 * Convert a member index "idx" of interface "itf" to the member index of class
183 * "cl" implementing that interface.
184 */
185 int
Bram Moolenaard0200c82023-01-28 15:19:40 +0000186object_index_from_itf_index(class_T *itf, int is_method, int idx, class_T *cl)
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000187{
Bram Moolenaard0200c82023-01-28 15:19:40 +0000188 if (idx > (is_method ? itf->class_obj_method_count
189 : itf->class_obj_member_count))
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000190 {
191 siemsg("index %d out of range for interface %s", idx, itf->class_name);
192 return 0;
193 }
Yegappan Lakshmanan74cc13c2023-08-13 17:41:26 +0200194
195 // If "cl" is the interface or the class that is extended, then the method
196 // index can be used directly and there is no need to search for the method
197 // index in one of the child classes.
198 if (cl == itf)
199 return idx;
200
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000201 itf2class_T *i2c;
202 for (i2c = itf->class_itf2class; i2c != NULL; i2c = i2c->i2c_next)
Bram Moolenaard0200c82023-01-28 15:19:40 +0000203 if (i2c->i2c_class == cl && i2c->i2c_is_method == is_method)
Bram Moolenaar29ac5df2023-01-16 19:43:47 +0000204 break;
205 if (i2c == NULL)
206 {
207 siemsg("class %s not found on interface %s",
208 cl->class_name, itf->class_name);
209 return 0;
210 }
211 int *table = (int *)(i2c + 1);
212 return table[idx];
213}
214
215/*
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200216 * Check whether a class named "extends_name" is present. If the class is
217 * valid, then "extends_clp" is set with the class pointer.
218 * Returns TRUE if the class name "extends_names" is a valid class.
219 */
220 static int
221validate_extends_class(char_u *extends_name, class_T **extends_clp)
222{
223 typval_T tv;
224 int success = FALSE;
225
226 tv.v_type = VAR_UNKNOWN;
227 if (eval_variable_import(extends_name, &tv) == FAIL)
228 {
229 semsg(_(e_class_name_not_found_str), extends_name);
230 return success;
231 }
232 else
233 {
234 if (tv.v_type != VAR_CLASS
235 || tv.vval.v_class == NULL
236 || (tv.vval.v_class->class_flags & CLASS_INTERFACE) != 0)
237 semsg(_(e_cannot_extend_str), extends_name);
238 else
239 {
240 class_T *extends_cl = tv.vval.v_class;
241 ++extends_cl->class_refcount;
242 *extends_clp = extends_cl;
243 success = TRUE;
244 }
245 clear_tv(&tv);
246 }
247
248 return success;
249}
250
251/*
252 * Check the members of the interface class "ifcl" match the class members
253 * ("classmembers_gap") and object members ("objmembers_gap") of a class.
254 * Returns TRUE if the class and object member names are valid.
255 */
256 static int
257validate_interface_members(
258 char_u *intf_class_name,
259 class_T *ifcl,
260 garray_T *classmembers_gap,
261 garray_T *objmembers_gap)
262{
263 int success = TRUE;
264
265 for (int loop = 1; loop <= 2 && success; ++loop)
266 {
267 // loop == 1: check class members
268 // loop == 2: check object members
269 int if_count = loop == 1 ? ifcl->class_class_member_count
270 : ifcl->class_obj_member_count;
271 if (if_count == 0)
272 continue;
273 ocmember_T *if_ms = loop == 1 ? ifcl->class_class_members
274 : ifcl->class_obj_members;
275 ocmember_T *cl_ms = (ocmember_T *)(loop == 1
276 ? classmembers_gap->ga_data
277 : objmembers_gap->ga_data);
278 int cl_count = loop == 1 ? classmembers_gap->ga_len
279 : objmembers_gap->ga_len;
280 for (int if_i = 0; if_i < if_count; ++if_i)
281 {
282 int cl_i;
283 for (cl_i = 0; cl_i < cl_count; ++cl_i)
284 {
285 ocmember_T *m = &cl_ms[cl_i];
286 where_T where = WHERE_INIT;
287
288 if (STRCMP(if_ms[if_i].ocm_name, m->ocm_name) != 0)
289 continue;
290
291 // Ensure the type is matching.
292 where.wt_func_name = (char *)m->ocm_name;
293 where.wt_kind = WT_MEMBER;
294 if (check_type_maybe(if_ms[if_i].ocm_type, m->ocm_type, TRUE,
295 where) != OK)
296 success = FALSE;
297
298 break;
299 }
300 if (cl_i == cl_count)
301 {
302 semsg(_(e_member_str_of_interface_str_not_implemented),
303 if_ms[if_i].ocm_name, intf_class_name);
304 success = FALSE;
305 break;
306 }
307 }
308 }
309
310 return success;
311}
312
313/*
314 * Check the functions/methods of the interface class "ifcl" match the class
315 * methods ("classfunctions_gap") and object functions ("objmemthods_gap") of a
316 * class.
317 * Returns TRUE if the class and object member names are valid.
318 */
319 static int
320validate_interface_methods(
321 char_u *intf_class_name,
322 class_T *ifcl,
323 garray_T *classfunctions_gap,
324 garray_T *objmethods_gap)
325{
326 int success = TRUE;
327
328 for (int loop = 1; loop <= 2 && success; ++loop)
329 {
330 // loop == 1: check class functions
331 // loop == 2: check object methods
332 int if_count = loop == 1 ? ifcl->class_class_function_count
333 : ifcl->class_obj_method_count;
334 if (if_count == 0)
335 continue;
336 ufunc_T **if_fp = loop == 1 ? ifcl->class_class_functions
337 : ifcl->class_obj_methods;
338 ufunc_T **cl_fp = (ufunc_T **)(loop == 1
339 ? classfunctions_gap->ga_data
340 : objmethods_gap->ga_data);
341 int cl_count = loop == 1 ? classfunctions_gap->ga_len
342 : objmethods_gap->ga_len;
343 for (int if_i = 0; if_i < if_count; ++if_i)
344 {
345 char_u *if_name = if_fp[if_i]->uf_name;
346 int cl_i;
347 for (cl_i = 0; cl_i < cl_count; ++cl_i)
348 {
349 char_u *cl_name = cl_fp[cl_i]->uf_name;
350 if (STRCMP(if_name, cl_name) == 0)
351 {
352 where_T where = WHERE_INIT;
353
354 // Ensure the type is matching.
355 where.wt_func_name = (char *)if_name;
356 where.wt_kind = WT_METHOD;
357 if (check_type_maybe(if_fp[if_i]->uf_func_type,
358 cl_fp[cl_i]->uf_func_type, TRUE, where) != OK)
359 success = FALSE;
360 break;
361 }
362 }
363 if (cl_i == cl_count)
364 {
365 semsg(_(e_function_str_of_interface_str_not_implemented),
366 if_name, intf_class_name);
367 success = FALSE;
368 break;
369 }
370 }
371 }
372
373 return success;
374}
375
376/*
377 * Validate all the "implements" classes when creating a new class. The
378 * classes are returned in "intf_classes". The class functions, class methods,
379 * object methods and object members in the new class are in
380 * "classfunctions_gap", "classmembers_gap", "objmethods_gap", and
381 * "objmembers_gap" respectively.
382 */
383 static int
384validate_implements_classes(
385 garray_T *impl_gap,
386 class_T **intf_classes,
387 garray_T *classfunctions_gap,
388 garray_T *classmembers_gap,
389 garray_T *objmethods_gap,
390 garray_T *objmembers_gap)
391{
392 int success = TRUE;
393
394 for (int i = 0; i < impl_gap->ga_len && success; ++i)
395 {
396 char_u *impl = ((char_u **)impl_gap->ga_data)[i];
397 typval_T tv;
398 tv.v_type = VAR_UNKNOWN;
399 if (eval_variable_import(impl, &tv) == FAIL)
400 {
401 semsg(_(e_interface_name_not_found_str), impl);
402 success = FALSE;
403 break;
404 }
405
406 if (tv.v_type != VAR_CLASS
407 || tv.vval.v_class == NULL
408 || (tv.vval.v_class->class_flags & CLASS_INTERFACE) == 0)
409 {
410 semsg(_(e_not_valid_interface_str), impl);
411 success = FALSE;
412 clear_tv(&tv);
413 break;
414 }
415
416 class_T *ifcl = tv.vval.v_class;
417 intf_classes[i] = ifcl;
418 ++ifcl->class_refcount;
419
420 // check the members of the interface match the members of the class
421 success = validate_interface_members(impl, ifcl, classmembers_gap,
422 objmembers_gap);
423
424 // check the functions/methods of the interface match the
425 // functions/methods of the class
426 success = validate_interface_methods(impl, ifcl, classfunctions_gap,
427 objmethods_gap);
428 clear_tv(&tv);
429 }
430
431 return success;
432}
433
434/*
435 * Check no function argument name is used as a class member.
436 * (Object members are always accessed with "this." prefix, so no need
437 * to check them.)
438 */
439 static int
440check_func_arg_names(
441 garray_T *classfunctions_gap,
442 garray_T *objmethods_gap,
443 garray_T *classmembers_gap)
444{
445 int success = TRUE;
446
447 // loop 1: class functions, loop 2: object methods
448 for (int loop = 1; loop <= 2 && success; ++loop)
449 {
450 garray_T *gap = loop == 1 ? classfunctions_gap : objmethods_gap;
451
452 for (int fi = 0; fi < gap->ga_len && success; ++fi)
453 {
454 ufunc_T *uf = ((ufunc_T **)gap->ga_data)[fi];
455
456 for (int i = 0; i < uf->uf_args.ga_len && success; ++i)
457 {
458 char_u *aname = ((char_u **)uf->uf_args.ga_data)[i];
459 garray_T *mgap = classmembers_gap;
460
461 // Check all the class member names
462 for (int mi = 0; mi < mgap->ga_len; ++mi)
463 {
464 char_u *mname = ((ocmember_T *)mgap->ga_data + mi)
465 ->ocm_name;
466 if (STRCMP(aname, mname) == 0)
467 {
468 success = FALSE;
469
470 if (uf->uf_script_ctx.sc_sid > 0)
471 SOURCING_LNUM = uf->uf_script_ctx.sc_lnum;
472
473 semsg(_(e_argument_already_declared_in_class_str),
474 aname);
475 break;
476 }
477 }
478 }
479 }
480 }
481
482 return success;
483}
484
485/*
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200486 * Update the interface class lookup table for the member index on the
487 * interface to the member index in the class implementing the interface.
488 * And a lookup table for the object method index on the interface
489 * to the object method index in the class implementing the interface.
490 * This is also used for updating the lookup table for the extended class
491 * hierarchy.
492 */
493 static int
494update_member_method_lookup_table(
495 class_T *ifcl,
496 class_T *cl,
497 garray_T *objmethods,
498 int pobj_method_offset,
499 int is_interface)
500{
501 if (ifcl == NULL)
502 return OK;
503
504 // Table for members.
505 itf2class_T *if2cl = alloc_clear(sizeof(itf2class_T)
506 + ifcl->class_obj_member_count * sizeof(int));
507 if (if2cl == NULL)
508 return FAIL;
509 if2cl->i2c_next = ifcl->class_itf2class;
510 ifcl->class_itf2class = if2cl;
511 if2cl->i2c_class = cl;
512 if2cl->i2c_is_method = FALSE;
513
514 for (int if_i = 0; if_i < ifcl->class_obj_member_count; ++if_i)
515 for (int cl_i = 0; cl_i < cl->class_obj_member_count; ++cl_i)
516 {
517 if (STRCMP(ifcl->class_obj_members[if_i].ocm_name,
518 cl->class_obj_members[cl_i].ocm_name) == 0)
519 {
520 int *table = (int *)(if2cl + 1);
521 table[if_i] = cl_i;
522 break;
523 }
524 }
525
526 // Table for methods.
527 if2cl = alloc_clear(sizeof(itf2class_T)
528 + ifcl->class_obj_method_count * sizeof(int));
529 if (if2cl == NULL)
530 return FAIL;
531 if2cl->i2c_next = ifcl->class_itf2class;
532 ifcl->class_itf2class = if2cl;
533 if2cl->i2c_class = cl;
534 if2cl->i2c_is_method = TRUE;
535
536 for (int if_i = 0; if_i < ifcl->class_obj_method_count; ++if_i)
537 {
538 int done = FALSE;
539 for (int cl_i = 0; cl_i < objmethods->ga_len; ++cl_i)
540 {
541 if (STRCMP(ifcl->class_obj_methods[if_i]->uf_name,
542 ((ufunc_T **)objmethods->ga_data)[cl_i]->uf_name)
543 == 0)
544 {
545 int *table = (int *)(if2cl + 1);
546 table[if_i] = cl_i;
547 done = TRUE;
548 break;
549 }
550 }
551
552 // extended class object method is not overridden by the child class.
553 // Keep the method declared in one of the parent classes in the
554 // lineage.
555 if (!done && !is_interface)
556 {
557 // If "ifcl" is not the immediate parent of "cl", then search in
558 // the intermediate parent classes.
559 if (cl->class_extends != ifcl)
560 {
561 class_T *parent = cl->class_extends;
562 int method_offset = objmethods->ga_len;
563
564 while (!done && parent != NULL && parent != ifcl)
565 {
566
567 for (int cl_i = 0;
568 cl_i < parent->class_obj_method_count_child; ++cl_i)
569 {
570 if (STRCMP(ifcl->class_obj_methods[if_i]->uf_name,
571 parent->class_obj_methods[cl_i]->uf_name)
572 == 0)
573 {
574 int *table = (int *)(if2cl + 1);
575 table[if_i] = method_offset + cl_i;
576 done = TRUE;
577 break;
578 }
579 }
580 method_offset += parent->class_obj_method_count_child;
581 parent = parent->class_extends;
582 }
583 }
584
585 if (!done)
586 {
587 int *table = (int *)(if2cl + 1);
588 table[if_i] = pobj_method_offset + if_i;
589 }
590 }
591 }
592
593 return OK;
594}
595
596/*
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200597 * Update the member and object method lookup tables for a new class in the
598 * interface class.
599 * For each interface add a lookup table for the member index on the interface
600 * to the member index in the new class. And a lookup table for the object
601 * method index on the interface to the object method index in the new class.
602 */
603 static int
604add_lookup_tables(class_T *cl, class_T *extends_cl, garray_T *objmethods_gap)
605{
606 for (int i = 0; i < cl->class_interface_count; ++i)
607 {
608 class_T *ifcl = cl->class_interfaces_cl[i];
609
610 if (update_member_method_lookup_table(ifcl, cl, objmethods_gap,
611 0, TRUE) == FAIL)
612 return FAIL;
613 }
614
615 // Update the lookup table for the extended class, if nay
616 if (extends_cl != NULL)
617 {
618 class_T *pclass = extends_cl;
619 int pobj_method_offset = objmethods_gap->ga_len;
620
621 // Update the entire lineage of extended classes.
622 while (pclass != NULL)
623 {
624 if (update_member_method_lookup_table(pclass, cl,
625 objmethods_gap, pobj_method_offset, FALSE) == FAIL)
626 return FAIL;
627
628 pobj_method_offset += pclass->class_obj_method_count_child;
629 pclass = pclass->class_extends;
630 }
631 }
632
633 return OK;
634}
635
636/*
637 * Add class members to a new class. Allocate a typval for each class member
638 * and initialize it.
639 */
640 static void
641add_class_members(class_T *cl, exarg_T *eap)
642{
643 // Allocate a typval for each class member and initialize it.
644 cl->class_members_tv = ALLOC_CLEAR_MULT(typval_T,
645 cl->class_class_member_count);
646 if (cl->class_members_tv == NULL)
647 return;
648
649 for (int i = 0; i < cl->class_class_member_count; ++i)
650 {
651 ocmember_T *m = &cl->class_class_members[i];
652 typval_T *tv = &cl->class_members_tv[i];
653 if (m->ocm_init != NULL)
654 {
655 typval_T *etv = eval_expr(m->ocm_init, eap);
656 if (etv != NULL)
657 {
658 *tv = *etv;
659 vim_free(etv);
660 }
661 }
662 else
663 {
664 // TODO: proper default value
665 tv->v_type = m->ocm_type->tt_type;
666 tv->vval.v_string = NULL;
667 }
668 }
669}
670
671/*
Yegappan Lakshmanan6ac15442023-08-20 18:20:17 +0200672 * Add a default constructor method (new()) to the class "cl".
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200673 */
674 static void
675add_default_constructor(
676 class_T *cl,
677 garray_T *classfunctions_gap,
678 garray_T *type_list_gap)
679{
680 garray_T fga;
681
682 ga_init2(&fga, 1, 1000);
683 ga_concat(&fga, (char_u *)"new(");
684 for (int i = 0; i < cl->class_obj_member_count; ++i)
685 {
686 if (i > 0)
687 ga_concat(&fga, (char_u *)", ");
688 ga_concat(&fga, (char_u *)"this.");
689 ocmember_T *m = cl->class_obj_members + i;
690 ga_concat(&fga, (char_u *)m->ocm_name);
691 ga_concat(&fga, (char_u *)" = v:none");
692 }
693 ga_concat(&fga, (char_u *)")\nenddef\n");
694 ga_append(&fga, NUL);
695
696 exarg_T fea;
697 CLEAR_FIELD(fea);
698 fea.cmdidx = CMD_def;
699 fea.cmd = fea.arg = fga.ga_data;
700
701 garray_T lines_to_free;
702 ga_init2(&lines_to_free, sizeof(char_u *), 50);
703
704 ufunc_T *nf = define_function(&fea, NULL, &lines_to_free, CF_CLASS);
705
706 ga_clear_strings(&lines_to_free);
707 vim_free(fga.ga_data);
708
709 if (nf != NULL && ga_grow(classfunctions_gap, 1) == OK)
710 {
711 ((ufunc_T **)classfunctions_gap->ga_data)[classfunctions_gap->ga_len]
712 = nf;
713 ++classfunctions_gap->ga_len;
714
715 nf->uf_flags |= FC_NEW;
716 nf->uf_ret_type = get_type_ptr(type_list_gap);
717 if (nf->uf_ret_type != NULL)
718 {
719 nf->uf_ret_type->tt_type = VAR_OBJECT;
720 nf->uf_ret_type->tt_class = cl;
721 nf->uf_ret_type->tt_argcount = 0;
722 nf->uf_ret_type->tt_args = NULL;
723 }
724 }
725}
726
727/*
728 * Add the class functions and object methods to the new class "cl".
729 * When extending a class, add the functions and methods from the parent class
730 * also.
731 */
732 static int
733add_classfuncs_objmethods(
734 class_T *cl,
735 class_T *extends_cl,
736 garray_T *classfunctions_gap,
737 garray_T *objmethods_gap)
738{
739 // loop 1: class functions, loop 2: object methods
740 for (int loop = 1; loop <= 2; ++loop)
741 {
742 garray_T *gap = loop == 1 ? classfunctions_gap : objmethods_gap;
743 int *fcount = loop == 1 ? &cl->class_class_function_count
744 : &cl->class_obj_method_count;
745 ufunc_T ***fup = loop == 1 ? &cl->class_class_functions
746 : &cl->class_obj_methods;
747
748 int parent_count = 0;
749 if (extends_cl != NULL)
750 // Include functions from the parent.
751 parent_count = loop == 1
752 ? extends_cl->class_class_function_count
753 : extends_cl->class_obj_method_count;
754
755 *fcount = parent_count + gap->ga_len;
756 if (*fcount == 0)
757 {
758 *fup = NULL;
759 continue;
760 }
761 *fup = ALLOC_MULT(ufunc_T *, *fcount);
762 if (*fup == NULL)
763 return FAIL;
764
765 if (gap->ga_len != 0)
766 mch_memmove(*fup, gap->ga_data, sizeof(ufunc_T *) * gap->ga_len);
767 vim_free(gap->ga_data);
768 if (loop == 1)
769 cl->class_class_function_count_child = gap->ga_len;
770 else
771 cl->class_obj_method_count_child = gap->ga_len;
772
773 int skipped = 0;
774 for (int i = 0; i < parent_count; ++i)
775 {
776 // Copy functions from the parent. Can't use the same
777 // function, because "uf_class" is different and compilation
778 // will have a different result.
779 // Put them after the functions in the current class, object
780 // methods may be overruled, then "super.Method()" is used to
781 // find a method from the parent.
782 // Skip "new" functions. TODO: not all of them.
783 if (loop == 1 && STRNCMP(
784 extends_cl->class_class_functions[i]->uf_name,
785 "new", 3) == 0)
786 ++skipped;
787 else
788 {
789 ufunc_T *pf = (loop == 1
790 ? extends_cl->class_class_functions
791 : extends_cl->class_obj_methods)[i];
792 (*fup)[gap->ga_len + i - skipped] = copy_function(pf);
793
794 // If the child class overrides a function from the parent
795 // the signature must be equal.
796 char_u *pname = pf->uf_name;
797 for (int ci = 0; ci < gap->ga_len; ++ci)
798 {
799 ufunc_T *cf = (*fup)[ci];
800 char_u *cname = cf->uf_name;
801 if (STRCMP(pname, cname) == 0)
802 {
803 where_T where = WHERE_INIT;
804 where.wt_func_name = (char *)pname;
805 where.wt_kind = WT_METHOD;
806 (void)check_type(pf->uf_func_type, cf->uf_func_type,
807 TRUE, where);
808 }
809 }
810 }
811 }
812
813 *fcount -= skipped;
814
815 // Set the class pointer on all the functions and object methods.
816 for (int i = 0; i < *fcount; ++i)
817 {
818 ufunc_T *fp = (*fup)[i];
819 fp->uf_class = cl;
820 if (loop == 2)
821 fp->uf_flags |= FC_OBJECT;
822 }
823 }
824
825 return OK;
826}
827
828/*
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000829 * Handle ":class" and ":abstract class" up to ":endclass".
Bram Moolenaar554d0312023-01-05 19:59:18 +0000830 * Handle ":interface" up to ":endinterface".
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000831 */
832 void
833ex_class(exarg_T *eap)
834{
Bram Moolenaar83ae6152023-02-25 19:59:31 +0000835 int is_class = eap->cmdidx == CMD_class; // FALSE for :interface
836 long start_lnum = SOURCING_LNUM;
Bram Moolenaar554d0312023-01-05 19:59:18 +0000837
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000838 char_u *arg = eap->arg;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000839 int is_abstract = eap->cmdidx == CMD_abstract;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000840 if (is_abstract)
841 {
842 if (STRNCMP(arg, "class", 5) != 0 || !VIM_ISWHITE(arg[5]))
843 {
844 semsg(_(e_invalid_argument_str), arg);
845 return;
846 }
847 arg = skipwhite(arg + 5);
Bram Moolenaar24a8d062023-01-14 13:12:06 +0000848 is_class = TRUE;
849 }
850
851 if (!current_script_is_vim9()
852 || (cmdmod.cmod_flags & CMOD_LEGACY)
853 || !getline_equal(eap->getline, eap->cookie, getsourceline))
854 {
855 if (is_class)
856 emsg(_(e_class_can_only_be_defined_in_vim9_script));
857 else
858 emsg(_(e_interface_can_only_be_defined_in_vim9_script));
859 return;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000860 }
861
862 if (!ASCII_ISUPPER(*arg))
863 {
Bram Moolenaar554d0312023-01-05 19:59:18 +0000864 if (is_class)
865 semsg(_(e_class_name_must_start_with_uppercase_letter_str), arg);
866 else
867 semsg(_(e_interface_name_must_start_with_uppercase_letter_str),
868 arg);
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000869 return;
870 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000871 char_u *name_end = find_name_end(arg, NULL, NULL, FNE_CHECK_START);
872 if (!IS_WHITE_OR_NUL(*name_end))
873 {
Bram Moolenaar554d0312023-01-05 19:59:18 +0000874 semsg(_(e_white_space_required_after_name_str), arg);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000875 return;
876 }
Bram Moolenaar94674f22023-01-06 18:42:20 +0000877 char_u *name_start = arg;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000878
Bram Moolenaara86655a2023-01-12 17:06:27 +0000879 // "export class" gets used when creating the class, don't use "is_export"
880 // for the items inside the class.
881 int class_export = is_export;
882 is_export = FALSE;
883
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000884 // TODO:
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000885 // generics: <Tkey, Tentry>
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000886
Bram Moolenaar83677162023-01-08 19:54:10 +0000887 // Name for "extends BaseClass"
888 char_u *extends = NULL;
889
Bram Moolenaar94674f22023-01-06 18:42:20 +0000890 // Names for "implements SomeInterface"
891 garray_T ga_impl;
892 ga_init2(&ga_impl, sizeof(char_u *), 5);
893
894 arg = skipwhite(name_end);
895 while (*arg != NUL && *arg != '#' && *arg != '\n')
896 {
897 // TODO:
Bram Moolenaar94674f22023-01-06 18:42:20 +0000898 // specifies SomeInterface
Bram Moolenaar83677162023-01-08 19:54:10 +0000899 if (STRNCMP(arg, "extends", 7) == 0 && IS_WHITE_OR_NUL(arg[7]))
900 {
901 if (extends != NULL)
902 {
903 emsg(_(e_duplicate_extends));
904 goto early_ret;
905 }
906 arg = skipwhite(arg + 7);
907 char_u *end = find_name_end(arg, NULL, NULL, FNE_CHECK_START);
908 if (!IS_WHITE_OR_NUL(*end))
909 {
910 semsg(_(e_white_space_required_after_name_str), arg);
911 goto early_ret;
912 }
913 extends = vim_strnsave(arg, end - arg);
914 if (extends == NULL)
915 goto early_ret;
916
917 arg = skipwhite(end + 1);
918 }
919 else if (STRNCMP(arg, "implements", 10) == 0
920 && IS_WHITE_OR_NUL(arg[10]))
Bram Moolenaar94674f22023-01-06 18:42:20 +0000921 {
Bram Moolenaardf8f9472023-01-07 14:51:03 +0000922 if (ga_impl.ga_len > 0)
923 {
924 emsg(_(e_duplicate_implements));
925 goto early_ret;
926 }
Bram Moolenaar94674f22023-01-06 18:42:20 +0000927 arg = skipwhite(arg + 10);
Bram Moolenaardf8f9472023-01-07 14:51:03 +0000928
929 for (;;)
Bram Moolenaar94674f22023-01-06 18:42:20 +0000930 {
Bram Moolenaardf8f9472023-01-07 14:51:03 +0000931 char_u *impl_end = find_name_end(arg, NULL, NULL,
932 FNE_CHECK_START);
933 if (!IS_WHITE_OR_NUL(*impl_end) && *impl_end != ',')
934 {
935 semsg(_(e_white_space_required_after_name_str), arg);
936 goto early_ret;
937 }
938 char_u *iname = vim_strnsave(arg, impl_end - arg);
939 if (iname == NULL)
940 goto early_ret;
941 for (int i = 0; i < ga_impl.ga_len; ++i)
942 if (STRCMP(((char_u **)ga_impl.ga_data)[i], iname) == 0)
943 {
944 semsg(_(e_duplicate_interface_after_implements_str),
945 iname);
946 vim_free(iname);
947 goto early_ret;
948 }
949 if (ga_add_string(&ga_impl, iname) == FAIL)
950 {
951 vim_free(iname);
952 goto early_ret;
953 }
954 if (*impl_end != ',')
955 {
956 arg = skipwhite(impl_end);
957 break;
958 }
959 arg = skipwhite(impl_end + 1);
Bram Moolenaar94674f22023-01-06 18:42:20 +0000960 }
Bram Moolenaar94674f22023-01-06 18:42:20 +0000961 }
962 else
963 {
964 semsg(_(e_trailing_characters_str), arg);
965early_ret:
Bram Moolenaar83677162023-01-08 19:54:10 +0000966 vim_free(extends);
Bram Moolenaar94674f22023-01-06 18:42:20 +0000967 ga_clear_strings(&ga_impl);
968 return;
969 }
970 }
971
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000972 garray_T type_list; // list of pointers to allocated types
973 ga_init2(&type_list, sizeof(type_T *), 10);
974
Bram Moolenaard505d172022-12-18 21:42:55 +0000975 // Growarray with class members declared in the class.
976 garray_T classmembers;
977 ga_init2(&classmembers, sizeof(ocmember_T), 10);
978
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000979 // Growarray with functions declared in the class.
980 garray_T classfunctions;
981 ga_init2(&classfunctions, sizeof(ufunc_T *), 10);
Bram Moolenaard505d172022-12-18 21:42:55 +0000982
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000983 // Growarray with object members declared in the class.
984 garray_T objmembers;
Bram Moolenaard505d172022-12-18 21:42:55 +0000985 ga_init2(&objmembers, sizeof(ocmember_T), 10);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000986
987 // Growarray with object methods declared in the class.
988 garray_T objmethods;
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000989 ga_init2(&objmethods, sizeof(ufunc_T *), 10);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000990
991 /*
Bram Moolenaar554d0312023-01-05 19:59:18 +0000992 * Go over the body of the class/interface until "endclass" or
993 * "endinterface" is found.
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000994 */
995 char_u *theline = NULL;
996 int success = FALSE;
997 for (;;)
998 {
999 vim_free(theline);
1000 theline = eap->getline(':', eap->cookie, 0, GETLINE_CONCAT_ALL);
1001 if (theline == NULL)
1002 break;
1003 char_u *line = skipwhite(theline);
1004
Bram Moolenaar418b5472022-12-20 13:38:22 +00001005 // Skip empty and comment lines.
1006 if (*line == NUL)
1007 continue;
1008 if (*line == '#')
1009 {
1010 if (vim9_bad_comment(line))
1011 break;
1012 continue;
1013 }
1014
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001015 char_u *p = line;
Bram Moolenaar554d0312023-01-05 19:59:18 +00001016 char *end_name = is_class ? "endclass" : "endinterface";
1017 if (checkforcmd(&p, end_name, is_class ? 4 : 5))
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001018 {
Bram Moolenaar554d0312023-01-05 19:59:18 +00001019 if (STRNCMP(line, end_name, is_class ? 8 : 12) != 0)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001020 semsg(_(e_command_cannot_be_shortened_str), line);
1021 else if (*p == '|' || !ends_excmd2(line, p))
1022 semsg(_(e_trailing_characters_str), p);
Bram Moolenaar98aeb212022-12-08 22:09:14 +00001023 else
1024 success = TRUE;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001025 break;
1026 }
Bram Moolenaar554d0312023-01-05 19:59:18 +00001027 char *wrong_name = is_class ? "endinterface" : "endclass";
1028 if (checkforcmd(&p, wrong_name, is_class ? 5 : 4))
1029 {
Bram Moolenaar657aea72023-01-27 13:16:19 +00001030 semsg(_(e_invalid_command_str_expected_str), line, end_name);
Bram Moolenaar554d0312023-01-05 19:59:18 +00001031 break;
1032 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001033
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001034 int has_public = FALSE;
1035 if (checkforcmd(&p, "public", 3))
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001036 {
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001037 if (STRNCMP(line, "public", 6) != 0)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001038 {
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001039 semsg(_(e_command_cannot_be_shortened_str), line);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001040 break;
1041 }
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001042 has_public = TRUE;
1043 p = skipwhite(line + 6);
1044
Bram Moolenaard505d172022-12-18 21:42:55 +00001045 if (STRNCMP(p, "this", 4) != 0 && STRNCMP(p, "static", 6) != 0)
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001046 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001047 emsg(_(e_public_must_be_followed_by_this_or_static));
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001048 break;
1049 }
1050 }
Bram Moolenaard505d172022-12-18 21:42:55 +00001051
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001052 int has_static = FALSE;
1053 char_u *ps = p;
1054 if (checkforcmd(&p, "static", 4))
1055 {
1056 if (STRNCMP(ps, "static", 6) != 0)
1057 {
1058 semsg(_(e_command_cannot_be_shortened_str), ps);
1059 break;
1060 }
1061 has_static = TRUE;
1062 p = skipwhite(ps + 6);
1063 }
1064
Bram Moolenaard505d172022-12-18 21:42:55 +00001065 // object members (public, read access, private):
1066 // "this._varname"
1067 // "this.varname"
1068 // "public this.varname"
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001069 if (STRNCMP(p, "this", 4) == 0)
1070 {
1071 if (p[4] != '.' || !eval_isnamec1(p[5]))
1072 {
1073 semsg(_(e_invalid_object_member_declaration_str), p);
1074 break;
1075 }
1076 char_u *varname = p + 5;
Bram Moolenaard505d172022-12-18 21:42:55 +00001077 char_u *varname_end = NULL;
Bram Moolenaar74e12742022-12-13 21:14:28 +00001078 type_T *type = NULL;
Bram Moolenaard505d172022-12-18 21:42:55 +00001079 char_u *init_expr = NULL;
1080 if (parse_member(eap, line, varname, has_public,
Bram Moolenaar554d0312023-01-05 19:59:18 +00001081 &varname_end, &type_list, &type,
1082 is_class ? &init_expr: NULL) == FAIL)
Bram Moolenaard505d172022-12-18 21:42:55 +00001083 break;
1084 if (add_member(&objmembers, varname, varname_end,
1085 has_public, type, init_expr) == FAIL)
Bram Moolenaar74e12742022-12-13 21:14:28 +00001086 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001087 vim_free(init_expr);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001088 break;
1089 }
Bram Moolenaard505d172022-12-18 21:42:55 +00001090 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001091
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001092 // constructors:
1093 // def new()
1094 // enddef
1095 // def newOther()
1096 // enddef
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001097 // object methods and class functions:
1098 // def SomeMethod()
1099 // enddef
1100 // static def ClassFunction()
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001101 // enddef
1102 // TODO:
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001103 // def <Tval> someMethod()
1104 // enddef
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001105 else if (checkforcmd(&p, "def", 3))
1106 {
1107 exarg_T ea;
1108 garray_T lines_to_free;
1109
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001110 // TODO: error for "public static def Func()"?
1111
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001112 CLEAR_FIELD(ea);
1113 ea.cmd = line;
1114 ea.arg = p;
1115 ea.cmdidx = CMD_def;
1116 ea.getline = eap->getline;
1117 ea.cookie = eap->cookie;
1118
1119 ga_init2(&lines_to_free, sizeof(char_u *), 50);
Bram Moolenaar554d0312023-01-05 19:59:18 +00001120 ufunc_T *uf = define_function(&ea, NULL, &lines_to_free,
1121 is_class ? CF_CLASS : CF_INTERFACE);
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001122 ga_clear_strings(&lines_to_free);
1123
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001124 if (uf != NULL)
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001125 {
Bram Moolenaar58b40092023-01-11 15:59:05 +00001126 char_u *name = uf->uf_name;
1127 int is_new = STRNCMP(name, "new", 3) == 0;
Bram Moolenaar24a8d062023-01-14 13:12:06 +00001128 if (is_new && is_abstract)
1129 {
1130 emsg(_(e_cannot_define_new_function_in_abstract_class));
1131 success = FALSE;
Yegappan Lakshmananb1027282023-08-19 11:26:42 +02001132 func_clear_free(uf, FALSE);
Bram Moolenaar24a8d062023-01-14 13:12:06 +00001133 break;
1134 }
Yegappan Lakshmanan6ac15442023-08-20 18:20:17 +02001135 if (is_new)
1136 {
1137 // A return type should not be specified for the new()
1138 // constructor method.
1139 if (uf->uf_ret_type->tt_type != VAR_VOID)
1140 {
1141 emsg(_(e_cannot_use_a_return_type_with_new));
1142 success = FALSE;
1143 func_clear_free(uf, FALSE);
1144 break;
1145 }
1146 }
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001147 garray_T *fgap = has_static || is_new
1148 ? &classfunctions : &objmethods;
Bram Moolenaar58b40092023-01-11 15:59:05 +00001149 // Check the name isn't used already.
1150 for (int i = 0; i < fgap->ga_len; ++i)
1151 {
1152 char_u *n = ((ufunc_T **)fgap->ga_data)[i]->uf_name;
1153 if (STRCMP(name, n) == 0)
1154 {
1155 semsg(_(e_duplicate_function_str), name);
1156 break;
1157 }
1158 }
1159
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001160 if (ga_grow(fgap, 1) == OK)
1161 {
1162 if (is_new)
1163 uf->uf_flags |= FC_NEW;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001164
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001165 ((ufunc_T **)fgap->ga_data)[fgap->ga_len] = uf;
1166 ++fgap->ga_len;
1167 }
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001168 }
1169 }
1170
1171 // class members
1172 else if (has_static)
1173 {
1174 // class members (public, read access, private):
1175 // "static _varname"
1176 // "static varname"
1177 // "public static varname"
1178 char_u *varname = p;
1179 char_u *varname_end = NULL;
1180 type_T *type = NULL;
1181 char_u *init_expr = NULL;
1182 if (parse_member(eap, line, varname, has_public,
Bram Moolenaar554d0312023-01-05 19:59:18 +00001183 &varname_end, &type_list, &type,
1184 is_class ? &init_expr : NULL) == FAIL)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001185 break;
1186 if (add_member(&classmembers, varname, varname_end,
1187 has_public, type, init_expr) == FAIL)
1188 {
1189 vim_free(init_expr);
1190 break;
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001191 }
1192 }
1193
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001194 else
1195 {
Bram Moolenaar554d0312023-01-05 19:59:18 +00001196 if (is_class)
1197 semsg(_(e_not_valid_command_in_class_str), line);
1198 else
1199 semsg(_(e_not_valid_command_in_interface_str), line);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001200 break;
1201 }
1202 }
1203 vim_free(theline);
1204
Bram Moolenaar83677162023-01-08 19:54:10 +00001205 class_T *extends_cl = NULL; // class from "extends" argument
1206
1207 /*
1208 * Check a few things before defining the class.
1209 */
1210
1211 // Check the "extends" class is valid.
1212 if (success && extends != NULL)
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001213 success = validate_extends_class(extends, &extends_cl);
Bram Moolenaar83677162023-01-08 19:54:10 +00001214 VIM_CLEAR(extends);
1215
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001216 class_T **intf_classes = NULL;
1217
Bram Moolenaar83677162023-01-08 19:54:10 +00001218 // Check all "implements" entries are valid.
Bram Moolenaar94674f22023-01-06 18:42:20 +00001219 if (success && ga_impl.ga_len > 0)
1220 {
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001221 intf_classes = ALLOC_CLEAR_MULT(class_T *, ga_impl.ga_len);
1222
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001223 success = validate_implements_classes(&ga_impl, intf_classes,
1224 &classfunctions, &classmembers,
1225 &objmethods, &objmembers);
Bram Moolenaar94674f22023-01-06 18:42:20 +00001226 }
1227
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001228 // Check no function argument name is used as a class member.
Bram Moolenaard40f00c2023-01-13 17:36:49 +00001229 if (success)
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001230 success = check_func_arg_names(&classfunctions, &objmethods,
1231 &classmembers);
Bram Moolenaard40f00c2023-01-13 17:36:49 +00001232
Bram Moolenaareb533502022-12-14 15:06:11 +00001233 class_T *cl = NULL;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001234 if (success)
1235 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001236 // "endclass" encountered without failures: Create the class.
1237
Bram Moolenaareb533502022-12-14 15:06:11 +00001238 cl = ALLOC_CLEAR_ONE(class_T);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001239 if (cl == NULL)
1240 goto cleanup;
Bram Moolenaar554d0312023-01-05 19:59:18 +00001241 if (!is_class)
1242 cl->class_flags = CLASS_INTERFACE;
1243
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001244 cl->class_refcount = 1;
Bram Moolenaar94674f22023-01-06 18:42:20 +00001245 cl->class_name = vim_strnsave(name_start, name_end - name_start);
Bram Moolenaard505d172022-12-18 21:42:55 +00001246 if (cl->class_name == NULL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001247 goto cleanup;
Bram Moolenaard505d172022-12-18 21:42:55 +00001248
Bram Moolenaard0200c82023-01-28 15:19:40 +00001249 if (extends_cl != NULL)
1250 {
1251 cl->class_extends = extends_cl;
1252 extends_cl->class_flags |= CLASS_EXTENDED;
1253 }
Bram Moolenaar83677162023-01-08 19:54:10 +00001254
Bram Moolenaard505d172022-12-18 21:42:55 +00001255 // Add class and object members to "cl".
1256 if (add_members_to_class(&classmembers,
Bram Moolenaar83677162023-01-08 19:54:10 +00001257 extends_cl == NULL ? NULL
1258 : extends_cl->class_class_members,
1259 extends_cl == NULL ? 0
1260 : extends_cl->class_class_member_count,
1261 &cl->class_class_members,
1262 &cl->class_class_member_count) == FAIL
Bram Moolenaard505d172022-12-18 21:42:55 +00001263 || add_members_to_class(&objmembers,
Bram Moolenaar83677162023-01-08 19:54:10 +00001264 extends_cl == NULL ? NULL
1265 : extends_cl->class_obj_members,
1266 extends_cl == NULL ? 0
1267 : extends_cl->class_obj_member_count,
1268 &cl->class_obj_members,
1269 &cl->class_obj_member_count) == FAIL)
Bram Moolenaard505d172022-12-18 21:42:55 +00001270 goto cleanup;
1271
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001272 if (ga_impl.ga_len > 0)
1273 {
1274 // Move the "implements" names into the class.
1275 cl->class_interface_count = ga_impl.ga_len;
1276 cl->class_interfaces = ALLOC_MULT(char_u *, ga_impl.ga_len);
1277 if (cl->class_interfaces == NULL)
1278 goto cleanup;
1279 for (int i = 0; i < ga_impl.ga_len; ++i)
1280 cl->class_interfaces[i] = ((char_u **)ga_impl.ga_data)[i];
1281 VIM_CLEAR(ga_impl.ga_data);
1282 ga_impl.ga_len = 0;
1283
Bram Moolenaard0200c82023-01-28 15:19:40 +00001284 cl->class_interfaces_cl = intf_classes;
1285 intf_classes = NULL;
1286 }
1287
1288 if (cl->class_interface_count > 0 || extends_cl != NULL)
1289 {
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001290 // Add a method and member lookup table to each of the interface
1291 // classes.
1292 if (add_lookup_tables(cl, extends_cl, &objmethods) == FAIL)
1293 goto cleanup;
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001294 }
1295
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001296 // Allocate a typval for each class member and initialize it.
Bram Moolenaar554d0312023-01-05 19:59:18 +00001297 if (is_class && cl->class_class_member_count > 0)
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001298 add_class_members(cl, eap);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001299
Yegappan Lakshmanan6ac15442023-08-20 18:20:17 +02001300 int have_new = FALSE;
1301 ufunc_T *class_func = NULL;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001302 for (int i = 0; i < classfunctions.ga_len; ++i)
Yegappan Lakshmanan6ac15442023-08-20 18:20:17 +02001303 {
1304 class_func = ((ufunc_T **)classfunctions.ga_data)[i];
1305 if (STRCMP(class_func->uf_name, "new") == 0)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001306 {
1307 have_new = TRUE;
1308 break;
1309 }
Yegappan Lakshmanan6ac15442023-08-20 18:20:17 +02001310 }
1311
1312 if (have_new)
1313 // The return type of new() is an object of class "cl"
1314 class_func->uf_ret_type->tt_class = cl;
1315 else if (is_class && !is_abstract && !have_new)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001316 // No new() method was defined, add the default constructor.
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001317 add_default_constructor(cl, &classfunctions, &type_list);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001318
Bram Moolenaar58b40092023-01-11 15:59:05 +00001319 // Move all the functions into the created class.
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001320 if (add_classfuncs_objmethods(cl, extends_cl, &classfunctions,
1321 &objmethods) == FAIL)
1322 goto cleanup;
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001323
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001324 cl->class_type.tt_type = VAR_CLASS;
Bram Moolenaarb1e32ac2023-02-21 12:38:51 +00001325 cl->class_type.tt_class = cl;
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001326 cl->class_object_type.tt_type = VAR_OBJECT;
Bram Moolenaarb1e32ac2023-02-21 12:38:51 +00001327 cl->class_object_type.tt_class = cl;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001328 cl->class_type_list = type_list;
1329
1330 // TODO:
Bram Moolenaard505d172022-12-18 21:42:55 +00001331 // - Fill hashtab with object members and methods ?
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001332
1333 // Add the class to the script-local variables.
Bram Moolenaar94674f22023-01-06 18:42:20 +00001334 // TODO: handle other context, e.g. in a function
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001335 typval_T tv;
1336 tv.v_type = VAR_CLASS;
1337 tv.vval.v_class = cl;
Bram Moolenaara86655a2023-01-12 17:06:27 +00001338 is_export = class_export;
Bram Moolenaar83ae6152023-02-25 19:59:31 +00001339 SOURCING_LNUM = start_lnum;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001340 set_var_const(cl->class_name, current_sctx.sc_sid,
Bram Moolenaar83ae6152023-02-25 19:59:31 +00001341 NULL, &tv, FALSE, 0, 0);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001342 return;
1343 }
1344
1345cleanup:
Bram Moolenaareb533502022-12-14 15:06:11 +00001346 if (cl != NULL)
1347 {
1348 vim_free(cl->class_name);
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001349 vim_free(cl->class_class_functions);
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001350 if (cl->class_interfaces != NULL)
1351 {
1352 for (int i = 0; i < cl->class_interface_count; ++i)
1353 vim_free(cl->class_interfaces[i]);
1354 vim_free(cl->class_interfaces);
1355 }
1356 if (cl->class_interfaces_cl != NULL)
1357 {
1358 for (int i = 0; i < cl->class_interface_count; ++i)
1359 class_unref(cl->class_interfaces_cl[i]);
1360 vim_free(cl->class_interfaces_cl);
1361 }
Bram Moolenaareb533502022-12-14 15:06:11 +00001362 vim_free(cl->class_obj_members);
1363 vim_free(cl->class_obj_methods);
1364 vim_free(cl);
1365 }
1366
Bram Moolenaar83677162023-01-08 19:54:10 +00001367 vim_free(extends);
1368 class_unref(extends_cl);
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001369
1370 if (intf_classes != NULL)
1371 {
1372 for (int i = 0; i < ga_impl.ga_len; ++i)
1373 class_unref(intf_classes[i]);
1374 vim_free(intf_classes);
1375 }
Bram Moolenaar94674f22023-01-06 18:42:20 +00001376 ga_clear_strings(&ga_impl);
1377
Bram Moolenaard505d172022-12-18 21:42:55 +00001378 for (int round = 1; round <= 2; ++round)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001379 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001380 garray_T *gap = round == 1 ? &classmembers : &objmembers;
1381 if (gap->ga_len == 0 || gap->ga_data == NULL)
1382 continue;
1383
1384 for (int i = 0; i < gap->ga_len; ++i)
1385 {
1386 ocmember_T *m = ((ocmember_T *)gap->ga_data) + i;
1387 vim_free(m->ocm_name);
1388 vim_free(m->ocm_init);
1389 }
1390 ga_clear(gap);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001391 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001392
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001393 for (int i = 0; i < objmethods.ga_len; ++i)
1394 {
1395 ufunc_T *uf = ((ufunc_T **)objmethods.ga_data)[i];
1396 func_clear_free(uf, FALSE);
1397 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001398 ga_clear(&objmethods);
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001399
1400 for (int i = 0; i < classfunctions.ga_len; ++i)
1401 {
1402 ufunc_T *uf = ((ufunc_T **)classfunctions.ga_data)[i];
1403 func_clear_free(uf, FALSE);
1404 }
1405 ga_clear(&classfunctions);
1406
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001407 clear_type_list(&type_list);
1408}
1409
1410/*
Bram Moolenaarf54cedd2022-12-23 17:56:27 +00001411 * Find member "name" in class "cl", set "member_idx" to the member index and
1412 * return its type.
1413 * When not found "member_idx" is set to -1 and t_any is returned.
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001414 */
1415 type_T *
1416class_member_type(
1417 class_T *cl,
1418 char_u *name,
1419 char_u *name_end,
1420 int *member_idx)
1421{
1422 *member_idx = -1; // not found (yet)
1423 size_t len = name_end - name;
1424
1425 for (int i = 0; i < cl->class_obj_member_count; ++i)
1426 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001427 ocmember_T *m = cl->class_obj_members + i;
1428 if (STRNCMP(m->ocm_name, name, len) == 0 && m->ocm_name[len] == NUL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001429 {
1430 *member_idx = i;
Bram Moolenaard505d172022-12-18 21:42:55 +00001431 return m->ocm_type;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001432 }
1433 }
Bram Moolenaarf54cedd2022-12-23 17:56:27 +00001434
1435 semsg(_(e_unknown_variable_str), name);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001436 return &t_any;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001437}
1438
1439/*
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001440 * Handle ":enum" up to ":endenum".
1441 */
1442 void
1443ex_enum(exarg_T *eap UNUSED)
1444{
1445 // TODO
1446}
1447
1448/*
1449 * Handle ":type".
1450 */
1451 void
1452ex_type(exarg_T *eap UNUSED)
1453{
1454 // TODO
1455}
1456
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001457/*
1458 * Evaluate what comes after a class:
1459 * - class member: SomeClass.varname
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001460 * - class function: SomeClass.SomeMethod()
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001461 * - class constructor: SomeClass.new()
1462 * - object member: someObject.varname
1463 * - object method: someObject.SomeMethod()
1464 *
1465 * "*arg" points to the '.'.
1466 * "*arg" is advanced to after the member name or method call.
1467 *
1468 * Returns FAIL or OK.
1469 */
1470 int
1471class_object_index(
1472 char_u **arg,
1473 typval_T *rettv,
1474 evalarg_T *evalarg,
1475 int verbose UNUSED) // give error messages
1476{
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001477 if (VIM_ISWHITE((*arg)[1]))
1478 {
1479 semsg(_(e_no_white_space_allowed_after_str_str), ".", *arg);
1480 return FAIL;
1481 }
1482
1483 ++*arg;
1484 char_u *name = *arg;
1485 char_u *name_end = find_name_end(name, NULL, NULL, FNE_CHECK_START);
1486 if (name_end == name)
1487 return FAIL;
1488 size_t len = name_end - name;
1489
Bram Moolenaar552bdca2023-02-17 21:08:50 +00001490 class_T *cl;
1491 if (rettv->v_type == VAR_CLASS)
1492 cl = rettv->vval.v_class;
1493 else // VAR_OBJECT
1494 {
1495 if (rettv->vval.v_object == NULL)
1496 {
1497 emsg(_(e_using_null_object));
1498 return FAIL;
1499 }
1500 cl = rettv->vval.v_object->obj_class;
1501 }
1502
Bram Moolenaard13dd302023-03-11 20:56:35 +00001503 if (cl == NULL)
1504 {
1505 emsg(_(e_incomplete_type));
1506 return FAIL;
1507 }
1508
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001509 if (*name_end == '(')
1510 {
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001511 int on_class = rettv->v_type == VAR_CLASS;
1512 int count = on_class ? cl->class_class_function_count
1513 : cl->class_obj_method_count;
1514 for (int i = 0; i < count; ++i)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001515 {
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001516 ufunc_T *fp = on_class ? cl->class_class_functions[i]
1517 : cl->class_obj_methods[i];
Bram Moolenaar4ae00572022-12-09 22:49:23 +00001518 // Use a separate pointer to avoid that ASAN complains about
1519 // uf_name[] only being 4 characters.
1520 char_u *ufname = (char_u *)fp->uf_name;
1521 if (STRNCMP(name, ufname, len) == 0 && ufname[len] == NUL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001522 {
1523 typval_T argvars[MAX_FUNC_ARGS + 1];
1524 int argcount = 0;
1525
1526 char_u *argp = name_end;
1527 int ret = get_func_arguments(&argp, evalarg, 0,
1528 argvars, &argcount);
1529 if (ret == FAIL)
1530 return FAIL;
1531
1532 funcexe_T funcexe;
1533 CLEAR_FIELD(funcexe);
1534 funcexe.fe_evaluate = TRUE;
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001535 if (rettv->v_type == VAR_OBJECT)
1536 {
1537 funcexe.fe_object = rettv->vval.v_object;
1538 ++funcexe.fe_object->obj_refcount;
1539 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001540
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001541 // Clear the class or object after calling the function, in
1542 // case the refcount is one.
1543 typval_T tv_tofree = *rettv;
1544 rettv->v_type = VAR_UNKNOWN;
1545
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001546 // Call the user function. Result goes into rettv;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001547 int error = call_user_func_check(fp, argcount, argvars,
1548 rettv, &funcexe, NULL);
1549
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001550 // Clear the previous rettv and the arguments.
1551 clear_tv(&tv_tofree);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001552 for (int idx = 0; idx < argcount; ++idx)
1553 clear_tv(&argvars[idx]);
1554
1555 if (error != FCERR_NONE)
1556 {
1557 user_func_error(error, printable_func_name(fp),
1558 funcexe.fe_found_var);
1559 return FAIL;
1560 }
1561 *arg = argp;
1562 return OK;
1563 }
1564 }
1565
1566 semsg(_(e_method_not_found_on_class_str_str), cl->class_name, name);
1567 }
1568
1569 else if (rettv->v_type == VAR_OBJECT)
1570 {
1571 for (int i = 0; i < cl->class_obj_member_count; ++i)
1572 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001573 ocmember_T *m = &cl->class_obj_members[i];
1574 if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001575 {
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001576 if (*name == '_')
1577 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001578 semsg(_(e_cannot_access_private_member_str), m->ocm_name);
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001579 return FAIL;
1580 }
1581
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001582 // The object only contains a pointer to the class, the member
1583 // values array follows right after that.
1584 object_T *obj = rettv->vval.v_object;
1585 typval_T *tv = (typval_T *)(obj + 1) + i;
1586 copy_tv(tv, rettv);
1587 object_unref(obj);
1588
1589 *arg = name_end;
1590 return OK;
1591 }
1592 }
1593
1594 semsg(_(e_member_not_found_on_object_str_str), cl->class_name, name);
1595 }
1596
Bram Moolenaard505d172022-12-18 21:42:55 +00001597 else if (rettv->v_type == VAR_CLASS)
1598 {
1599 // class member
1600 for (int i = 0; i < cl->class_class_member_count; ++i)
1601 {
1602 ocmember_T *m = &cl->class_class_members[i];
1603 if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
1604 {
1605 if (*name == '_')
1606 {
1607 semsg(_(e_cannot_access_private_member_str), m->ocm_name);
1608 return FAIL;
1609 }
1610
1611 typval_T *tv = &cl->class_members_tv[i];
1612 copy_tv(tv, rettv);
1613 class_unref(cl);
1614
1615 *arg = name_end;
1616 return OK;
1617 }
1618 }
1619
1620 semsg(_(e_member_not_found_on_class_str_str), cl->class_name, name);
1621 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001622
1623 return FAIL;
1624}
1625
1626/*
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001627 * If "arg" points to a class or object method, return it.
1628 * Otherwise return NULL.
1629 */
1630 ufunc_T *
1631find_class_func(char_u **arg)
1632{
1633 char_u *name = *arg;
1634 char_u *name_end = find_name_end(name, NULL, NULL, FNE_CHECK_START);
1635 if (name_end == name || *name_end != '.')
1636 return NULL;
1637
1638 size_t len = name_end - name;
1639 typval_T tv;
1640 tv.v_type = VAR_UNKNOWN;
Bram Moolenaar993dbc32023-01-01 20:31:30 +00001641 if (eval_variable(name, (int)len,
1642 0, &tv, NULL, EVAL_VAR_NOAUTOLOAD) == FAIL)
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001643 return NULL;
1644 if (tv.v_type != VAR_CLASS && tv.v_type != VAR_OBJECT)
Bram Moolenaareb533502022-12-14 15:06:11 +00001645 goto fail_after_eval;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001646
1647 class_T *cl = tv.v_type == VAR_CLASS ? tv.vval.v_class
1648 : tv.vval.v_object->obj_class;
1649 if (cl == NULL)
Bram Moolenaareb533502022-12-14 15:06:11 +00001650 goto fail_after_eval;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001651 char_u *fname = name_end + 1;
1652 char_u *fname_end = find_name_end(fname, NULL, NULL, FNE_CHECK_START);
1653 if (fname_end == fname)
Bram Moolenaareb533502022-12-14 15:06:11 +00001654 goto fail_after_eval;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001655 len = fname_end - fname;
1656
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001657 int count = tv.v_type == VAR_CLASS ? cl->class_class_function_count
1658 : cl->class_obj_method_count;
1659 ufunc_T **funcs = tv.v_type == VAR_CLASS ? cl->class_class_functions
1660 : cl->class_obj_methods;
1661 for (int i = 0; i < count; ++i)
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001662 {
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001663 ufunc_T *fp = funcs[i];
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001664 // Use a separate pointer to avoid that ASAN complains about
1665 // uf_name[] only being 4 characters.
1666 char_u *ufname = (char_u *)fp->uf_name;
1667 if (STRNCMP(fname, ufname, len) == 0 && ufname[len] == NUL)
Bram Moolenaareb533502022-12-14 15:06:11 +00001668 {
1669 clear_tv(&tv);
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001670 return fp;
Bram Moolenaareb533502022-12-14 15:06:11 +00001671 }
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001672 }
1673
Bram Moolenaareb533502022-12-14 15:06:11 +00001674fail_after_eval:
1675 clear_tv(&tv);
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001676 return NULL;
1677}
1678
1679/*
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001680 * If "name[len]" is a class member in cctx->ctx_ufunc->uf_class return the
1681 * index in class.class_class_members[].
1682 * If "cl_ret" is not NULL set it to the class.
1683 * Otherwise return -1;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001684 */
1685 int
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001686class_member_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001687{
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001688 if (cctx == NULL || cctx->ctx_ufunc == NULL
1689 || cctx->ctx_ufunc->uf_class == NULL)
1690 return -1;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001691 class_T *cl = cctx->ctx_ufunc->uf_class;
1692
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001693 for (int i = 0; i < cl->class_class_member_count; ++i)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001694 {
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001695 ocmember_T *m = &cl->class_class_members[i];
1696 if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001697 {
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001698 if (cl_ret != NULL)
1699 *cl_ret = cl;
1700 return i;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001701 }
1702 }
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001703 return -1;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001704}
1705
1706/*
Bram Moolenaar62a69232023-01-24 15:07:04 +00001707 * Return TRUE if current context "cctx_arg" is inside class "cl".
1708 * Return FALSE if not.
1709 */
1710 int
1711inside_class(cctx_T *cctx_arg, class_T *cl)
1712{
1713 for (cctx_T *cctx = cctx_arg; cctx != NULL; cctx = cctx->ctx_outer)
1714 if (cctx->ctx_ufunc != NULL && cctx->ctx_ufunc->uf_class == cl)
1715 return TRUE;
1716 return FALSE;
1717}
1718
1719/*
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001720 * Make a copy of an object.
1721 */
1722 void
1723copy_object(typval_T *from, typval_T *to)
1724{
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +02001725 if (from->vval.v_object == NULL)
1726 to->vval.v_object = NULL;
1727 else
1728 {
1729 to->vval.v_object = from->vval.v_object;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001730 ++to->vval.v_object->obj_refcount;
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +02001731 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001732}
1733
1734/*
1735 * Free an object.
1736 */
1737 static void
1738object_clear(object_T *obj)
1739{
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01001740 // Avoid a recursive call, it can happen if "obj" has a circular reference.
1741 obj->obj_refcount = INT_MAX;
1742
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001743 class_T *cl = obj->obj_class;
1744
Jia-Ju Bai5b0889b2023-08-13 20:04:04 +02001745 if (!cl)
1746 return;
1747
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001748 // the member values are just after the object structure
1749 typval_T *tv = (typval_T *)(obj + 1);
1750 for (int i = 0; i < cl->class_obj_member_count; ++i)
1751 clear_tv(tv + i);
1752
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001753 // Remove from the list headed by "first_object".
1754 object_cleared(obj);
1755
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001756 vim_free(obj);
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001757 class_unref(cl);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001758}
1759
1760/*
1761 * Unreference an object.
1762 */
1763 void
1764object_unref(object_T *obj)
1765{
1766 if (obj != NULL && --obj->obj_refcount <= 0)
1767 object_clear(obj);
1768}
1769
1770/*
1771 * Make a copy of a class.
1772 */
1773 void
1774copy_class(typval_T *from, typval_T *to)
1775{
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +02001776 if (from->vval.v_class == NULL)
1777 to->vval.v_class = NULL;
1778 else
1779 {
1780 to->vval.v_class = from->vval.v_class;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001781 ++to->vval.v_class->class_refcount;
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +02001782 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001783}
1784
1785/*
1786 * Unreference a class. Free it when the reference count goes down to zero.
1787 */
1788 void
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001789class_unref(class_T *cl)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001790{
Bram Moolenaard505d172022-12-18 21:42:55 +00001791 if (cl != NULL && --cl->class_refcount <= 0 && cl->class_name != NULL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001792 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001793 // Freeing what the class contains may recursively come back here.
1794 // Clear "class_name" first, if it is NULL the class does not need to
1795 // be freed.
1796 VIM_CLEAR(cl->class_name);
1797
Bram Moolenaar83677162023-01-08 19:54:10 +00001798 class_unref(cl->class_extends);
1799
Bram Moolenaar94674f22023-01-06 18:42:20 +00001800 for (int i = 0; i < cl->class_interface_count; ++i)
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001801 {
Bram Moolenaar94674f22023-01-06 18:42:20 +00001802 vim_free(((char_u **)cl->class_interfaces)[i]);
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001803 if (cl->class_interfaces_cl[i] != NULL)
1804 class_unref(cl->class_interfaces_cl[i]);
1805 }
Bram Moolenaar94674f22023-01-06 18:42:20 +00001806 vim_free(cl->class_interfaces);
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001807 vim_free(cl->class_interfaces_cl);
Bram Moolenaar94674f22023-01-06 18:42:20 +00001808
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001809 itf2class_T *next;
1810 for (itf2class_T *i2c = cl->class_itf2class; i2c != NULL; i2c = next)
1811 {
1812 next = i2c->i2c_next;
1813 vim_free(i2c);
1814 }
1815
Bram Moolenaard505d172022-12-18 21:42:55 +00001816 for (int i = 0; i < cl->class_class_member_count; ++i)
1817 {
1818 ocmember_T *m = &cl->class_class_members[i];
1819 vim_free(m->ocm_name);
1820 vim_free(m->ocm_init);
1821 if (cl->class_members_tv != NULL)
1822 clear_tv(&cl->class_members_tv[i]);
1823 }
1824 vim_free(cl->class_class_members);
1825 vim_free(cl->class_members_tv);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001826
1827 for (int i = 0; i < cl->class_obj_member_count; ++i)
1828 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001829 ocmember_T *m = &cl->class_obj_members[i];
1830 vim_free(m->ocm_name);
1831 vim_free(m->ocm_init);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001832 }
1833 vim_free(cl->class_obj_members);
1834
Bram Moolenaarec8b74f2023-01-01 14:11:27 +00001835 for (int i = 0; i < cl->class_class_function_count; ++i)
1836 {
1837 ufunc_T *uf = cl->class_class_functions[i];
1838 func_clear_free(uf, FALSE);
1839 }
1840 vim_free(cl->class_class_functions);
1841
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001842 for (int i = 0; i < cl->class_obj_method_count; ++i)
1843 {
1844 ufunc_T *uf = cl->class_obj_methods[i];
1845 func_clear_free(uf, FALSE);
1846 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001847 vim_free(cl->class_obj_methods);
1848
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001849 clear_type_list(&cl->class_type_list);
1850
1851 vim_free(cl);
1852 }
1853}
1854
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001855static object_T *first_object = NULL;
1856
1857/*
1858 * Call this function when an object has been created. It will be added to the
1859 * list headed by "first_object".
1860 */
1861 void
1862object_created(object_T *obj)
1863{
1864 if (first_object != NULL)
1865 {
1866 obj->obj_next_used = first_object;
1867 first_object->obj_prev_used = obj;
1868 }
1869 first_object = obj;
1870}
1871
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01001872static object_T *next_nonref_obj = NULL;
1873
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001874/*
1875 * Call this function when an object has been cleared and is about to be freed.
1876 * It is removed from the list headed by "first_object".
1877 */
1878 void
1879object_cleared(object_T *obj)
1880{
1881 if (obj->obj_next_used != NULL)
1882 obj->obj_next_used->obj_prev_used = obj->obj_prev_used;
1883 if (obj->obj_prev_used != NULL)
1884 obj->obj_prev_used->obj_next_used = obj->obj_next_used;
1885 else if (first_object == obj)
1886 first_object = obj->obj_next_used;
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01001887
1888 // update the next object to check if needed
1889 if (obj == next_nonref_obj)
1890 next_nonref_obj = obj->obj_next_used;
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001891}
1892
1893/*
1894 * Go through the list of all objects and free items without "copyID".
1895 */
1896 int
1897object_free_nonref(int copyID)
1898{
1899 int did_free = FALSE;
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001900
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01001901 for (object_T *obj = first_object; obj != NULL; obj = next_nonref_obj)
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001902 {
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01001903 next_nonref_obj = obj->obj_next_used;
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001904 if ((obj->obj_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
1905 {
1906 // Free the object and items it contains.
1907 object_clear(obj);
1908 did_free = TRUE;
1909 }
1910 }
1911
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01001912 next_nonref_obj = NULL;
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001913 return did_free;
1914}
1915
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001916
1917#endif // FEAT_EVAL