blob: 898dcbd4f2555743e3fb2bb2802ceaeb3c681dc9 [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
Yegappan Lakshmanan2ba9d2e2023-08-28 21:26:23 +020027 * variable name and "type_ret" is set to the declared or detected type.
Bram Moolenaard505d172022-12-18 21:42:55 +000028 * "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 Lakshmanand4e4ecb2023-08-27 18:35:45 +020099 // No type specified for the member. Set it to "any" and the correct
100 // type will be 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;
Yegappan Lakshmanancd7293b2023-08-27 19:18:23 +0200360 // Ensure the public/private access level is matching.
361 if (if_fp[if_i]->uf_private != cl_fp[cl_i]->uf_private)
362 {
363 semsg(_(e_interface_str_and_class_str_function_access_not_same),
364 cl_name, if_name);
365 success = FALSE;
366 }
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200367 break;
368 }
369 }
370 if (cl_i == cl_count)
371 {
372 semsg(_(e_function_str_of_interface_str_not_implemented),
373 if_name, intf_class_name);
374 success = FALSE;
375 break;
376 }
377 }
378 }
379
380 return success;
381}
382
383/*
384 * Validate all the "implements" classes when creating a new class. The
385 * classes are returned in "intf_classes". The class functions, class methods,
386 * object methods and object members in the new class are in
387 * "classfunctions_gap", "classmembers_gap", "objmethods_gap", and
388 * "objmembers_gap" respectively.
389 */
390 static int
391validate_implements_classes(
392 garray_T *impl_gap,
393 class_T **intf_classes,
394 garray_T *classfunctions_gap,
395 garray_T *classmembers_gap,
396 garray_T *objmethods_gap,
397 garray_T *objmembers_gap)
398{
399 int success = TRUE;
400
401 for (int i = 0; i < impl_gap->ga_len && success; ++i)
402 {
403 char_u *impl = ((char_u **)impl_gap->ga_data)[i];
404 typval_T tv;
405 tv.v_type = VAR_UNKNOWN;
406 if (eval_variable_import(impl, &tv) == FAIL)
407 {
408 semsg(_(e_interface_name_not_found_str), impl);
409 success = FALSE;
410 break;
411 }
412
413 if (tv.v_type != VAR_CLASS
414 || tv.vval.v_class == NULL
415 || (tv.vval.v_class->class_flags & CLASS_INTERFACE) == 0)
416 {
417 semsg(_(e_not_valid_interface_str), impl);
418 success = FALSE;
419 clear_tv(&tv);
420 break;
421 }
422
423 class_T *ifcl = tv.vval.v_class;
424 intf_classes[i] = ifcl;
425 ++ifcl->class_refcount;
426
427 // check the members of the interface match the members of the class
428 success = validate_interface_members(impl, ifcl, classmembers_gap,
429 objmembers_gap);
430
431 // check the functions/methods of the interface match the
432 // functions/methods of the class
433 success = validate_interface_methods(impl, ifcl, classfunctions_gap,
434 objmethods_gap);
435 clear_tv(&tv);
436 }
437
438 return success;
439}
440
441/*
442 * Check no function argument name is used as a class member.
443 * (Object members are always accessed with "this." prefix, so no need
444 * to check them.)
445 */
446 static int
447check_func_arg_names(
448 garray_T *classfunctions_gap,
449 garray_T *objmethods_gap,
450 garray_T *classmembers_gap)
451{
452 int success = TRUE;
453
454 // loop 1: class functions, loop 2: object methods
455 for (int loop = 1; loop <= 2 && success; ++loop)
456 {
457 garray_T *gap = loop == 1 ? classfunctions_gap : objmethods_gap;
458
459 for (int fi = 0; fi < gap->ga_len && success; ++fi)
460 {
461 ufunc_T *uf = ((ufunc_T **)gap->ga_data)[fi];
462
463 for (int i = 0; i < uf->uf_args.ga_len && success; ++i)
464 {
465 char_u *aname = ((char_u **)uf->uf_args.ga_data)[i];
466 garray_T *mgap = classmembers_gap;
467
468 // Check all the class member names
469 for (int mi = 0; mi < mgap->ga_len; ++mi)
470 {
471 char_u *mname = ((ocmember_T *)mgap->ga_data + mi)
472 ->ocm_name;
473 if (STRCMP(aname, mname) == 0)
474 {
475 success = FALSE;
476
477 if (uf->uf_script_ctx.sc_sid > 0)
478 SOURCING_LNUM = uf->uf_script_ctx.sc_lnum;
479
480 semsg(_(e_argument_already_declared_in_class_str),
481 aname);
482 break;
483 }
484 }
485 }
486 }
487 }
488
489 return success;
490}
491
492/*
Yegappan Lakshmanan2ba9d2e2023-08-28 21:26:23 +0200493 * Returns TRUE if the member "varname" is already defined.
494 */
495 static int
496is_duplicate_member(garray_T *mgap, char_u *varname, char_u *varname_end)
497{
498 char_u *pstr = (*varname == '_') ? varname + 1 : varname;
499
500 for (int i = 0; i < mgap->ga_len; ++i)
501 {
502 ocmember_T *m = ((ocmember_T *)mgap->ga_data) + i;
503 char_u *qstr = *m->ocm_name == '_' ? m->ocm_name + 1 : m->ocm_name;
504 if (STRNCMP(pstr, qstr, varname_end - pstr) == 0)
505 {
506 char_u *name = vim_strnsave(varname, varname_end - varname);
507 semsg(_(e_duplicate_member_str), name);
508 vim_free(name);
509 return TRUE;
510 }
511 }
512
513 return FALSE;
514}
515
516/*
517 * Returns TRUE if the method "name" is already defined.
518 */
519 static int
520is_duplicate_method(garray_T *fgap, char_u *name)
521{
522 char_u *pstr = (*name == '_') ? name + 1 : name;
523
524 for (int i = 0; i < fgap->ga_len; ++i)
525 {
526 char_u *n = ((ufunc_T **)fgap->ga_data)[i]->uf_name;
527 char_u *qstr = *n == '_' ? n + 1 : n;
528 if (STRCMP(pstr, qstr) == 0)
529 {
530 semsg(_(e_duplicate_function_str), name);
531 return TRUE;
532 }
533 }
534
535 return FALSE;
536}
537
538/*
Gianmaria Bajo4b9777a2023-08-29 22:26:30 +0200539 * Returns TRUE if the constructor is valid.
540 */
541 static int
542is_valid_constructor(ufunc_T *uf, int is_abstract, int has_static)
543{
544 // Constructors are not allowed in abstract classes.
545 if (is_abstract)
546 {
547 emsg(_(e_cannot_define_new_function_in_abstract_class));
548 return FALSE;
549 }
550 // A constructor is always static, no need to define it so.
551 if (has_static)
552 {
553 emsg(_(e_cannot_define_new_function_as_static));
554 return FALSE;
555 }
556 // A return type should not be specified for the new()
557 // constructor method.
558 if (uf->uf_ret_type->tt_type != VAR_VOID)
559 {
560 emsg(_(e_cannot_use_a_return_type_with_new));
561 return FALSE;
562 }
563 return TRUE;
564}
565
566/*
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200567 * Update the interface class lookup table for the member index on the
568 * interface to the member index in the class implementing the interface.
569 * And a lookup table for the object method index on the interface
570 * to the object method index in the class implementing the interface.
571 * This is also used for updating the lookup table for the extended class
572 * hierarchy.
573 */
574 static int
575update_member_method_lookup_table(
576 class_T *ifcl,
577 class_T *cl,
578 garray_T *objmethods,
579 int pobj_method_offset,
580 int is_interface)
581{
582 if (ifcl == NULL)
583 return OK;
584
585 // Table for members.
586 itf2class_T *if2cl = alloc_clear(sizeof(itf2class_T)
587 + ifcl->class_obj_member_count * sizeof(int));
588 if (if2cl == NULL)
589 return FAIL;
590 if2cl->i2c_next = ifcl->class_itf2class;
591 ifcl->class_itf2class = if2cl;
592 if2cl->i2c_class = cl;
593 if2cl->i2c_is_method = FALSE;
594
595 for (int if_i = 0; if_i < ifcl->class_obj_member_count; ++if_i)
596 for (int cl_i = 0; cl_i < cl->class_obj_member_count; ++cl_i)
597 {
598 if (STRCMP(ifcl->class_obj_members[if_i].ocm_name,
599 cl->class_obj_members[cl_i].ocm_name) == 0)
600 {
601 int *table = (int *)(if2cl + 1);
602 table[if_i] = cl_i;
603 break;
604 }
605 }
606
607 // Table for methods.
608 if2cl = alloc_clear(sizeof(itf2class_T)
609 + ifcl->class_obj_method_count * sizeof(int));
610 if (if2cl == NULL)
611 return FAIL;
612 if2cl->i2c_next = ifcl->class_itf2class;
613 ifcl->class_itf2class = if2cl;
614 if2cl->i2c_class = cl;
615 if2cl->i2c_is_method = TRUE;
616
617 for (int if_i = 0; if_i < ifcl->class_obj_method_count; ++if_i)
618 {
619 int done = FALSE;
620 for (int cl_i = 0; cl_i < objmethods->ga_len; ++cl_i)
621 {
622 if (STRCMP(ifcl->class_obj_methods[if_i]->uf_name,
623 ((ufunc_T **)objmethods->ga_data)[cl_i]->uf_name)
624 == 0)
625 {
626 int *table = (int *)(if2cl + 1);
627 table[if_i] = cl_i;
628 done = TRUE;
629 break;
630 }
631 }
632
633 // extended class object method is not overridden by the child class.
634 // Keep the method declared in one of the parent classes in the
635 // lineage.
636 if (!done && !is_interface)
637 {
638 // If "ifcl" is not the immediate parent of "cl", then search in
639 // the intermediate parent classes.
640 if (cl->class_extends != ifcl)
641 {
642 class_T *parent = cl->class_extends;
643 int method_offset = objmethods->ga_len;
644
645 while (!done && parent != NULL && parent != ifcl)
646 {
647
648 for (int cl_i = 0;
649 cl_i < parent->class_obj_method_count_child; ++cl_i)
650 {
651 if (STRCMP(ifcl->class_obj_methods[if_i]->uf_name,
652 parent->class_obj_methods[cl_i]->uf_name)
653 == 0)
654 {
655 int *table = (int *)(if2cl + 1);
656 table[if_i] = method_offset + cl_i;
657 done = TRUE;
658 break;
659 }
660 }
661 method_offset += parent->class_obj_method_count_child;
662 parent = parent->class_extends;
663 }
664 }
665
666 if (!done)
667 {
668 int *table = (int *)(if2cl + 1);
669 table[if_i] = pobj_method_offset + if_i;
670 }
671 }
672 }
673
674 return OK;
675}
676
677/*
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200678 * Update the member and object method lookup tables for a new class in the
679 * interface class.
680 * For each interface add a lookup table for the member index on the interface
681 * to the member index in the new class. And a lookup table for the object
682 * method index on the interface to the object method index in the new class.
683 */
684 static int
685add_lookup_tables(class_T *cl, class_T *extends_cl, garray_T *objmethods_gap)
686{
687 for (int i = 0; i < cl->class_interface_count; ++i)
688 {
689 class_T *ifcl = cl->class_interfaces_cl[i];
690
691 if (update_member_method_lookup_table(ifcl, cl, objmethods_gap,
692 0, TRUE) == FAIL)
693 return FAIL;
694 }
695
696 // Update the lookup table for the extended class, if nay
697 if (extends_cl != NULL)
698 {
699 class_T *pclass = extends_cl;
700 int pobj_method_offset = objmethods_gap->ga_len;
701
702 // Update the entire lineage of extended classes.
703 while (pclass != NULL)
704 {
705 if (update_member_method_lookup_table(pclass, cl,
706 objmethods_gap, pobj_method_offset, FALSE) == FAIL)
707 return FAIL;
708
709 pobj_method_offset += pclass->class_obj_method_count_child;
710 pclass = pclass->class_extends;
711 }
712 }
713
714 return OK;
715}
716
717/*
718 * Add class members to a new class. Allocate a typval for each class member
719 * and initialize it.
720 */
721 static void
722add_class_members(class_T *cl, exarg_T *eap)
723{
724 // Allocate a typval for each class member and initialize it.
725 cl->class_members_tv = ALLOC_CLEAR_MULT(typval_T,
726 cl->class_class_member_count);
727 if (cl->class_members_tv == NULL)
728 return;
729
730 for (int i = 0; i < cl->class_class_member_count; ++i)
731 {
732 ocmember_T *m = &cl->class_class_members[i];
733 typval_T *tv = &cl->class_members_tv[i];
734 if (m->ocm_init != NULL)
735 {
736 typval_T *etv = eval_expr(m->ocm_init, eap);
737 if (etv != NULL)
738 {
739 *tv = *etv;
740 vim_free(etv);
741 }
742 }
743 else
744 {
745 // TODO: proper default value
746 tv->v_type = m->ocm_type->tt_type;
747 tv->vval.v_string = NULL;
748 }
749 }
750}
751
752/*
Yegappan Lakshmanan6ac15442023-08-20 18:20:17 +0200753 * Add a default constructor method (new()) to the class "cl".
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +0200754 */
755 static void
756add_default_constructor(
757 class_T *cl,
758 garray_T *classfunctions_gap,
759 garray_T *type_list_gap)
760{
761 garray_T fga;
762
763 ga_init2(&fga, 1, 1000);
764 ga_concat(&fga, (char_u *)"new(");
765 for (int i = 0; i < cl->class_obj_member_count; ++i)
766 {
767 if (i > 0)
768 ga_concat(&fga, (char_u *)", ");
769 ga_concat(&fga, (char_u *)"this.");
770 ocmember_T *m = cl->class_obj_members + i;
771 ga_concat(&fga, (char_u *)m->ocm_name);
772 ga_concat(&fga, (char_u *)" = v:none");
773 }
774 ga_concat(&fga, (char_u *)")\nenddef\n");
775 ga_append(&fga, NUL);
776
777 exarg_T fea;
778 CLEAR_FIELD(fea);
779 fea.cmdidx = CMD_def;
780 fea.cmd = fea.arg = fga.ga_data;
781
782 garray_T lines_to_free;
783 ga_init2(&lines_to_free, sizeof(char_u *), 50);
784
785 ufunc_T *nf = define_function(&fea, NULL, &lines_to_free, CF_CLASS);
786
787 ga_clear_strings(&lines_to_free);
788 vim_free(fga.ga_data);
789
790 if (nf != NULL && ga_grow(classfunctions_gap, 1) == OK)
791 {
792 ((ufunc_T **)classfunctions_gap->ga_data)[classfunctions_gap->ga_len]
793 = nf;
794 ++classfunctions_gap->ga_len;
795
796 nf->uf_flags |= FC_NEW;
797 nf->uf_ret_type = get_type_ptr(type_list_gap);
798 if (nf->uf_ret_type != NULL)
799 {
800 nf->uf_ret_type->tt_type = VAR_OBJECT;
801 nf->uf_ret_type->tt_class = cl;
802 nf->uf_ret_type->tt_argcount = 0;
803 nf->uf_ret_type->tt_args = NULL;
804 }
805 }
806}
807
808/*
809 * Add the class functions and object methods to the new class "cl".
810 * When extending a class, add the functions and methods from the parent class
811 * also.
812 */
813 static int
814add_classfuncs_objmethods(
815 class_T *cl,
816 class_T *extends_cl,
817 garray_T *classfunctions_gap,
818 garray_T *objmethods_gap)
819{
820 // loop 1: class functions, loop 2: object methods
821 for (int loop = 1; loop <= 2; ++loop)
822 {
823 garray_T *gap = loop == 1 ? classfunctions_gap : objmethods_gap;
824 int *fcount = loop == 1 ? &cl->class_class_function_count
825 : &cl->class_obj_method_count;
826 ufunc_T ***fup = loop == 1 ? &cl->class_class_functions
827 : &cl->class_obj_methods;
828
829 int parent_count = 0;
830 if (extends_cl != NULL)
831 // Include functions from the parent.
832 parent_count = loop == 1
833 ? extends_cl->class_class_function_count
834 : extends_cl->class_obj_method_count;
835
836 *fcount = parent_count + gap->ga_len;
837 if (*fcount == 0)
838 {
839 *fup = NULL;
840 continue;
841 }
842 *fup = ALLOC_MULT(ufunc_T *, *fcount);
843 if (*fup == NULL)
844 return FAIL;
845
846 if (gap->ga_len != 0)
847 mch_memmove(*fup, gap->ga_data, sizeof(ufunc_T *) * gap->ga_len);
848 vim_free(gap->ga_data);
849 if (loop == 1)
850 cl->class_class_function_count_child = gap->ga_len;
851 else
852 cl->class_obj_method_count_child = gap->ga_len;
853
854 int skipped = 0;
855 for (int i = 0; i < parent_count; ++i)
856 {
857 // Copy functions from the parent. Can't use the same
858 // function, because "uf_class" is different and compilation
859 // will have a different result.
860 // Put them after the functions in the current class, object
861 // methods may be overruled, then "super.Method()" is used to
862 // find a method from the parent.
863 // Skip "new" functions. TODO: not all of them.
864 if (loop == 1 && STRNCMP(
865 extends_cl->class_class_functions[i]->uf_name,
866 "new", 3) == 0)
867 ++skipped;
868 else
869 {
870 ufunc_T *pf = (loop == 1
871 ? extends_cl->class_class_functions
872 : extends_cl->class_obj_methods)[i];
873 (*fup)[gap->ga_len + i - skipped] = copy_function(pf);
874
875 // If the child class overrides a function from the parent
876 // the signature must be equal.
877 char_u *pname = pf->uf_name;
878 for (int ci = 0; ci < gap->ga_len; ++ci)
879 {
880 ufunc_T *cf = (*fup)[ci];
881 char_u *cname = cf->uf_name;
882 if (STRCMP(pname, cname) == 0)
883 {
884 where_T where = WHERE_INIT;
885 where.wt_func_name = (char *)pname;
886 where.wt_kind = WT_METHOD;
887 (void)check_type(pf->uf_func_type, cf->uf_func_type,
888 TRUE, where);
889 }
890 }
891 }
892 }
893
894 *fcount -= skipped;
895
896 // Set the class pointer on all the functions and object methods.
897 for (int i = 0; i < *fcount; ++i)
898 {
899 ufunc_T *fp = (*fup)[i];
900 fp->uf_class = cl;
901 if (loop == 2)
902 fp->uf_flags |= FC_OBJECT;
903 }
904 }
905
906 return OK;
907}
908
909/*
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000910 * Handle ":class" and ":abstract class" up to ":endclass".
Bram Moolenaar554d0312023-01-05 19:59:18 +0000911 * Handle ":interface" up to ":endinterface".
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000912 */
913 void
914ex_class(exarg_T *eap)
915{
Bram Moolenaar83ae6152023-02-25 19:59:31 +0000916 int is_class = eap->cmdidx == CMD_class; // FALSE for :interface
917 long start_lnum = SOURCING_LNUM;
Bram Moolenaar554d0312023-01-05 19:59:18 +0000918
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000919 char_u *arg = eap->arg;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000920 int is_abstract = eap->cmdidx == CMD_abstract;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000921 if (is_abstract)
922 {
923 if (STRNCMP(arg, "class", 5) != 0 || !VIM_ISWHITE(arg[5]))
924 {
925 semsg(_(e_invalid_argument_str), arg);
926 return;
927 }
928 arg = skipwhite(arg + 5);
Bram Moolenaar24a8d062023-01-14 13:12:06 +0000929 is_class = TRUE;
930 }
931
932 if (!current_script_is_vim9()
933 || (cmdmod.cmod_flags & CMOD_LEGACY)
934 || !getline_equal(eap->getline, eap->cookie, getsourceline))
935 {
936 if (is_class)
937 emsg(_(e_class_can_only_be_defined_in_vim9_script));
938 else
939 emsg(_(e_interface_can_only_be_defined_in_vim9_script));
940 return;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000941 }
942
943 if (!ASCII_ISUPPER(*arg))
944 {
Bram Moolenaar554d0312023-01-05 19:59:18 +0000945 if (is_class)
946 semsg(_(e_class_name_must_start_with_uppercase_letter_str), arg);
947 else
948 semsg(_(e_interface_name_must_start_with_uppercase_letter_str),
949 arg);
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000950 return;
951 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000952 char_u *name_end = find_name_end(arg, NULL, NULL, FNE_CHECK_START);
953 if (!IS_WHITE_OR_NUL(*name_end))
954 {
Bram Moolenaar554d0312023-01-05 19:59:18 +0000955 semsg(_(e_white_space_required_after_name_str), arg);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000956 return;
957 }
Bram Moolenaar94674f22023-01-06 18:42:20 +0000958 char_u *name_start = arg;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000959
Bram Moolenaara86655a2023-01-12 17:06:27 +0000960 // "export class" gets used when creating the class, don't use "is_export"
961 // for the items inside the class.
962 int class_export = is_export;
963 is_export = FALSE;
964
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000965 // TODO:
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000966 // generics: <Tkey, Tentry>
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000967
Bram Moolenaar83677162023-01-08 19:54:10 +0000968 // Name for "extends BaseClass"
969 char_u *extends = NULL;
970
Bram Moolenaar94674f22023-01-06 18:42:20 +0000971 // Names for "implements SomeInterface"
972 garray_T ga_impl;
973 ga_init2(&ga_impl, sizeof(char_u *), 5);
974
975 arg = skipwhite(name_end);
976 while (*arg != NUL && *arg != '#' && *arg != '\n')
977 {
978 // TODO:
Bram Moolenaar94674f22023-01-06 18:42:20 +0000979 // specifies SomeInterface
Bram Moolenaar83677162023-01-08 19:54:10 +0000980 if (STRNCMP(arg, "extends", 7) == 0 && IS_WHITE_OR_NUL(arg[7]))
981 {
982 if (extends != NULL)
983 {
984 emsg(_(e_duplicate_extends));
985 goto early_ret;
986 }
987 arg = skipwhite(arg + 7);
988 char_u *end = find_name_end(arg, NULL, NULL, FNE_CHECK_START);
989 if (!IS_WHITE_OR_NUL(*end))
990 {
991 semsg(_(e_white_space_required_after_name_str), arg);
992 goto early_ret;
993 }
994 extends = vim_strnsave(arg, end - arg);
995 if (extends == NULL)
996 goto early_ret;
997
998 arg = skipwhite(end + 1);
999 }
1000 else if (STRNCMP(arg, "implements", 10) == 0
1001 && IS_WHITE_OR_NUL(arg[10]))
Bram Moolenaar94674f22023-01-06 18:42:20 +00001002 {
Bram Moolenaardf8f9472023-01-07 14:51:03 +00001003 if (ga_impl.ga_len > 0)
1004 {
1005 emsg(_(e_duplicate_implements));
1006 goto early_ret;
1007 }
Bram Moolenaar94674f22023-01-06 18:42:20 +00001008 arg = skipwhite(arg + 10);
Bram Moolenaardf8f9472023-01-07 14:51:03 +00001009
1010 for (;;)
Bram Moolenaar94674f22023-01-06 18:42:20 +00001011 {
Bram Moolenaardf8f9472023-01-07 14:51:03 +00001012 char_u *impl_end = find_name_end(arg, NULL, NULL,
1013 FNE_CHECK_START);
1014 if (!IS_WHITE_OR_NUL(*impl_end) && *impl_end != ',')
1015 {
1016 semsg(_(e_white_space_required_after_name_str), arg);
1017 goto early_ret;
1018 }
1019 char_u *iname = vim_strnsave(arg, impl_end - arg);
1020 if (iname == NULL)
1021 goto early_ret;
1022 for (int i = 0; i < ga_impl.ga_len; ++i)
1023 if (STRCMP(((char_u **)ga_impl.ga_data)[i], iname) == 0)
1024 {
1025 semsg(_(e_duplicate_interface_after_implements_str),
1026 iname);
1027 vim_free(iname);
1028 goto early_ret;
1029 }
1030 if (ga_add_string(&ga_impl, iname) == FAIL)
1031 {
1032 vim_free(iname);
1033 goto early_ret;
1034 }
1035 if (*impl_end != ',')
1036 {
1037 arg = skipwhite(impl_end);
1038 break;
1039 }
1040 arg = skipwhite(impl_end + 1);
Bram Moolenaar94674f22023-01-06 18:42:20 +00001041 }
Bram Moolenaar94674f22023-01-06 18:42:20 +00001042 }
1043 else
1044 {
1045 semsg(_(e_trailing_characters_str), arg);
1046early_ret:
Bram Moolenaar83677162023-01-08 19:54:10 +00001047 vim_free(extends);
Bram Moolenaar94674f22023-01-06 18:42:20 +00001048 ga_clear_strings(&ga_impl);
1049 return;
1050 }
1051 }
1052
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001053 garray_T type_list; // list of pointers to allocated types
1054 ga_init2(&type_list, sizeof(type_T *), 10);
1055
Bram Moolenaard505d172022-12-18 21:42:55 +00001056 // Growarray with class members declared in the class.
1057 garray_T classmembers;
1058 ga_init2(&classmembers, sizeof(ocmember_T), 10);
1059
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001060 // Growarray with functions declared in the class.
1061 garray_T classfunctions;
1062 ga_init2(&classfunctions, sizeof(ufunc_T *), 10);
Bram Moolenaard505d172022-12-18 21:42:55 +00001063
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001064 // Growarray with object members declared in the class.
1065 garray_T objmembers;
Bram Moolenaard505d172022-12-18 21:42:55 +00001066 ga_init2(&objmembers, sizeof(ocmember_T), 10);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001067
1068 // Growarray with object methods declared in the class.
1069 garray_T objmethods;
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001070 ga_init2(&objmethods, sizeof(ufunc_T *), 10);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001071
1072 /*
Bram Moolenaar554d0312023-01-05 19:59:18 +00001073 * Go over the body of the class/interface until "endclass" or
1074 * "endinterface" is found.
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001075 */
1076 char_u *theline = NULL;
1077 int success = FALSE;
1078 for (;;)
1079 {
1080 vim_free(theline);
1081 theline = eap->getline(':', eap->cookie, 0, GETLINE_CONCAT_ALL);
1082 if (theline == NULL)
1083 break;
1084 char_u *line = skipwhite(theline);
1085
Bram Moolenaar418b5472022-12-20 13:38:22 +00001086 // Skip empty and comment lines.
1087 if (*line == NUL)
1088 continue;
1089 if (*line == '#')
1090 {
1091 if (vim9_bad_comment(line))
1092 break;
1093 continue;
1094 }
1095
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001096 char_u *p = line;
Bram Moolenaar554d0312023-01-05 19:59:18 +00001097 char *end_name = is_class ? "endclass" : "endinterface";
1098 if (checkforcmd(&p, end_name, is_class ? 4 : 5))
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001099 {
Bram Moolenaar554d0312023-01-05 19:59:18 +00001100 if (STRNCMP(line, end_name, is_class ? 8 : 12) != 0)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001101 semsg(_(e_command_cannot_be_shortened_str), line);
1102 else if (*p == '|' || !ends_excmd2(line, p))
1103 semsg(_(e_trailing_characters_str), p);
Bram Moolenaar98aeb212022-12-08 22:09:14 +00001104 else
1105 success = TRUE;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001106 break;
1107 }
Bram Moolenaar554d0312023-01-05 19:59:18 +00001108 char *wrong_name = is_class ? "endinterface" : "endclass";
1109 if (checkforcmd(&p, wrong_name, is_class ? 5 : 4))
1110 {
Bram Moolenaar657aea72023-01-27 13:16:19 +00001111 semsg(_(e_invalid_command_str_expected_str), line, end_name);
Bram Moolenaar554d0312023-01-05 19:59:18 +00001112 break;
1113 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001114
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001115 int has_public = FALSE;
1116 if (checkforcmd(&p, "public", 3))
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001117 {
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001118 if (STRNCMP(line, "public", 6) != 0)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001119 {
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001120 semsg(_(e_command_cannot_be_shortened_str), line);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001121 break;
1122 }
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001123 has_public = TRUE;
1124 p = skipwhite(line + 6);
1125
Bram Moolenaard505d172022-12-18 21:42:55 +00001126 if (STRNCMP(p, "this", 4) != 0 && STRNCMP(p, "static", 6) != 0)
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001127 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001128 emsg(_(e_public_must_be_followed_by_this_or_static));
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001129 break;
1130 }
1131 }
Bram Moolenaard505d172022-12-18 21:42:55 +00001132
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001133 int has_static = FALSE;
1134 char_u *ps = p;
1135 if (checkforcmd(&p, "static", 4))
1136 {
1137 if (STRNCMP(ps, "static", 6) != 0)
1138 {
1139 semsg(_(e_command_cannot_be_shortened_str), ps);
1140 break;
1141 }
1142 has_static = TRUE;
1143 p = skipwhite(ps + 6);
1144 }
1145
Bram Moolenaard505d172022-12-18 21:42:55 +00001146 // object members (public, read access, private):
1147 // "this._varname"
1148 // "this.varname"
1149 // "public this.varname"
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001150 if (STRNCMP(p, "this", 4) == 0)
1151 {
1152 if (p[4] != '.' || !eval_isnamec1(p[5]))
1153 {
1154 semsg(_(e_invalid_object_member_declaration_str), p);
1155 break;
1156 }
Yegappan Lakshmanan2ba9d2e2023-08-28 21:26:23 +02001157 if (has_static)
1158 {
1159 emsg(_(e_static_cannot_be_followed_by_this));
1160 break;
1161 }
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001162 char_u *varname = p + 5;
Bram Moolenaard505d172022-12-18 21:42:55 +00001163 char_u *varname_end = NULL;
Bram Moolenaar74e12742022-12-13 21:14:28 +00001164 type_T *type = NULL;
Bram Moolenaard505d172022-12-18 21:42:55 +00001165 char_u *init_expr = NULL;
1166 if (parse_member(eap, line, varname, has_public,
Bram Moolenaar554d0312023-01-05 19:59:18 +00001167 &varname_end, &type_list, &type,
1168 is_class ? &init_expr: NULL) == FAIL)
Bram Moolenaard505d172022-12-18 21:42:55 +00001169 break;
Yegappan Lakshmanan2ba9d2e2023-08-28 21:26:23 +02001170 if (is_duplicate_member(&objmembers, varname, varname_end))
1171 {
1172 vim_free(init_expr);
1173 break;
1174 }
Bram Moolenaard505d172022-12-18 21:42:55 +00001175 if (add_member(&objmembers, varname, varname_end,
1176 has_public, type, init_expr) == FAIL)
Bram Moolenaar74e12742022-12-13 21:14:28 +00001177 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001178 vim_free(init_expr);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001179 break;
1180 }
Bram Moolenaard505d172022-12-18 21:42:55 +00001181 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001182
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001183 // constructors:
1184 // def new()
1185 // enddef
1186 // def newOther()
1187 // enddef
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001188 // object methods and class functions:
1189 // def SomeMethod()
1190 // enddef
1191 // static def ClassFunction()
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001192 // enddef
1193 // TODO:
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001194 // def <Tval> someMethod()
1195 // enddef
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001196 else if (checkforcmd(&p, "def", 3))
1197 {
1198 exarg_T ea;
1199 garray_T lines_to_free;
1200
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001201 // TODO: error for "public static def Func()"?
1202
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001203 CLEAR_FIELD(ea);
1204 ea.cmd = line;
1205 ea.arg = p;
1206 ea.cmdidx = CMD_def;
1207 ea.getline = eap->getline;
1208 ea.cookie = eap->cookie;
1209
1210 ga_init2(&lines_to_free, sizeof(char_u *), 50);
Bram Moolenaar554d0312023-01-05 19:59:18 +00001211 ufunc_T *uf = define_function(&ea, NULL, &lines_to_free,
1212 is_class ? CF_CLASS : CF_INTERFACE);
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001213 ga_clear_strings(&lines_to_free);
1214
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001215 if (uf != NULL)
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001216 {
Bram Moolenaar58b40092023-01-11 15:59:05 +00001217 char_u *name = uf->uf_name;
1218 int is_new = STRNCMP(name, "new", 3) == 0;
Gianmaria Bajo4b9777a2023-08-29 22:26:30 +02001219
1220 if (is_new && !is_valid_constructor(uf, is_abstract, has_static))
Bram Moolenaar24a8d062023-01-14 13:12:06 +00001221 {
Yegappan Lakshmananb1027282023-08-19 11:26:42 +02001222 func_clear_free(uf, FALSE);
Bram Moolenaar24a8d062023-01-14 13:12:06 +00001223 break;
1224 }
Gianmaria Bajo4b9777a2023-08-29 22:26:30 +02001225
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001226 garray_T *fgap = has_static || is_new
1227 ? &classfunctions : &objmethods;
Bram Moolenaar58b40092023-01-11 15:59:05 +00001228 // Check the name isn't used already.
Yegappan Lakshmanan2ba9d2e2023-08-28 21:26:23 +02001229 if (is_duplicate_method(fgap, name))
1230 break;
Bram Moolenaar58b40092023-01-11 15:59:05 +00001231
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001232 if (ga_grow(fgap, 1) == OK)
1233 {
1234 if (is_new)
1235 uf->uf_flags |= FC_NEW;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001236
Yegappan Lakshmanancd7293b2023-08-27 19:18:23 +02001237 // If the method name starts with '_', then it a private
1238 // method.
1239 if (*name == '_')
1240 uf->uf_private = TRUE;
1241
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001242 ((ufunc_T **)fgap->ga_data)[fgap->ga_len] = uf;
1243 ++fgap->ga_len;
1244 }
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001245 }
1246 }
1247
1248 // class members
1249 else if (has_static)
1250 {
1251 // class members (public, read access, private):
1252 // "static _varname"
1253 // "static varname"
1254 // "public static varname"
1255 char_u *varname = p;
1256 char_u *varname_end = NULL;
1257 type_T *type = NULL;
1258 char_u *init_expr = NULL;
1259 if (parse_member(eap, line, varname, has_public,
Bram Moolenaar554d0312023-01-05 19:59:18 +00001260 &varname_end, &type_list, &type,
1261 is_class ? &init_expr : NULL) == FAIL)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001262 break;
Yegappan Lakshmanan2ba9d2e2023-08-28 21:26:23 +02001263 if (is_duplicate_member(&classmembers, varname, varname_end))
1264 {
1265 vim_free(init_expr);
1266 break;
1267 }
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001268 if (add_member(&classmembers, varname, varname_end,
1269 has_public, type, init_expr) == FAIL)
1270 {
1271 vim_free(init_expr);
1272 break;
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001273 }
1274 }
1275
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001276 else
1277 {
Bram Moolenaar554d0312023-01-05 19:59:18 +00001278 if (is_class)
1279 semsg(_(e_not_valid_command_in_class_str), line);
1280 else
1281 semsg(_(e_not_valid_command_in_interface_str), line);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001282 break;
1283 }
1284 }
1285 vim_free(theline);
1286
Bram Moolenaar83677162023-01-08 19:54:10 +00001287 class_T *extends_cl = NULL; // class from "extends" argument
1288
1289 /*
1290 * Check a few things before defining the class.
1291 */
1292
1293 // Check the "extends" class is valid.
1294 if (success && extends != NULL)
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001295 success = validate_extends_class(extends, &extends_cl);
Bram Moolenaar83677162023-01-08 19:54:10 +00001296 VIM_CLEAR(extends);
1297
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001298 class_T **intf_classes = NULL;
1299
Bram Moolenaar83677162023-01-08 19:54:10 +00001300 // Check all "implements" entries are valid.
Bram Moolenaar94674f22023-01-06 18:42:20 +00001301 if (success && ga_impl.ga_len > 0)
1302 {
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001303 intf_classes = ALLOC_CLEAR_MULT(class_T *, ga_impl.ga_len);
1304
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001305 success = validate_implements_classes(&ga_impl, intf_classes,
1306 &classfunctions, &classmembers,
1307 &objmethods, &objmembers);
Bram Moolenaar94674f22023-01-06 18:42:20 +00001308 }
1309
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001310 // Check no function argument name is used as a class member.
Bram Moolenaard40f00c2023-01-13 17:36:49 +00001311 if (success)
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001312 success = check_func_arg_names(&classfunctions, &objmethods,
1313 &classmembers);
Bram Moolenaard40f00c2023-01-13 17:36:49 +00001314
Bram Moolenaareb533502022-12-14 15:06:11 +00001315 class_T *cl = NULL;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001316 if (success)
1317 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001318 // "endclass" encountered without failures: Create the class.
1319
Bram Moolenaareb533502022-12-14 15:06:11 +00001320 cl = ALLOC_CLEAR_ONE(class_T);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001321 if (cl == NULL)
1322 goto cleanup;
Bram Moolenaar554d0312023-01-05 19:59:18 +00001323 if (!is_class)
1324 cl->class_flags = CLASS_INTERFACE;
1325
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001326 cl->class_refcount = 1;
Bram Moolenaar94674f22023-01-06 18:42:20 +00001327 cl->class_name = vim_strnsave(name_start, name_end - name_start);
Bram Moolenaard505d172022-12-18 21:42:55 +00001328 if (cl->class_name == NULL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001329 goto cleanup;
Bram Moolenaard505d172022-12-18 21:42:55 +00001330
Bram Moolenaard0200c82023-01-28 15:19:40 +00001331 if (extends_cl != NULL)
1332 {
1333 cl->class_extends = extends_cl;
1334 extends_cl->class_flags |= CLASS_EXTENDED;
1335 }
Bram Moolenaar83677162023-01-08 19:54:10 +00001336
Bram Moolenaard505d172022-12-18 21:42:55 +00001337 // Add class and object members to "cl".
1338 if (add_members_to_class(&classmembers,
Bram Moolenaar83677162023-01-08 19:54:10 +00001339 extends_cl == NULL ? NULL
1340 : extends_cl->class_class_members,
1341 extends_cl == NULL ? 0
1342 : extends_cl->class_class_member_count,
1343 &cl->class_class_members,
1344 &cl->class_class_member_count) == FAIL
Bram Moolenaard505d172022-12-18 21:42:55 +00001345 || add_members_to_class(&objmembers,
Bram Moolenaar83677162023-01-08 19:54:10 +00001346 extends_cl == NULL ? NULL
1347 : extends_cl->class_obj_members,
1348 extends_cl == NULL ? 0
1349 : extends_cl->class_obj_member_count,
1350 &cl->class_obj_members,
1351 &cl->class_obj_member_count) == FAIL)
Bram Moolenaard505d172022-12-18 21:42:55 +00001352 goto cleanup;
1353
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001354 if (ga_impl.ga_len > 0)
1355 {
1356 // Move the "implements" names into the class.
1357 cl->class_interface_count = ga_impl.ga_len;
1358 cl->class_interfaces = ALLOC_MULT(char_u *, ga_impl.ga_len);
1359 if (cl->class_interfaces == NULL)
1360 goto cleanup;
1361 for (int i = 0; i < ga_impl.ga_len; ++i)
1362 cl->class_interfaces[i] = ((char_u **)ga_impl.ga_data)[i];
1363 VIM_CLEAR(ga_impl.ga_data);
1364 ga_impl.ga_len = 0;
1365
Bram Moolenaard0200c82023-01-28 15:19:40 +00001366 cl->class_interfaces_cl = intf_classes;
1367 intf_classes = NULL;
1368 }
1369
1370 if (cl->class_interface_count > 0 || extends_cl != NULL)
1371 {
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001372 // Add a method and member lookup table to each of the interface
1373 // classes.
1374 if (add_lookup_tables(cl, extends_cl, &objmethods) == FAIL)
1375 goto cleanup;
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001376 }
1377
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001378 // Allocate a typval for each class member and initialize it.
Bram Moolenaar554d0312023-01-05 19:59:18 +00001379 if (is_class && cl->class_class_member_count > 0)
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001380 add_class_members(cl, eap);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001381
Yegappan Lakshmanan6ac15442023-08-20 18:20:17 +02001382 int have_new = FALSE;
1383 ufunc_T *class_func = NULL;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001384 for (int i = 0; i < classfunctions.ga_len; ++i)
Yegappan Lakshmanan6ac15442023-08-20 18:20:17 +02001385 {
1386 class_func = ((ufunc_T **)classfunctions.ga_data)[i];
1387 if (STRCMP(class_func->uf_name, "new") == 0)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001388 {
1389 have_new = TRUE;
1390 break;
1391 }
Yegappan Lakshmanan6ac15442023-08-20 18:20:17 +02001392 }
1393
1394 if (have_new)
1395 // The return type of new() is an object of class "cl"
1396 class_func->uf_ret_type->tt_class = cl;
1397 else if (is_class && !is_abstract && !have_new)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001398 // No new() method was defined, add the default constructor.
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001399 add_default_constructor(cl, &classfunctions, &type_list);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001400
Bram Moolenaar58b40092023-01-11 15:59:05 +00001401 // Move all the functions into the created class.
Yegappan Lakshmanan4b1cc792023-08-19 22:39:33 +02001402 if (add_classfuncs_objmethods(cl, extends_cl, &classfunctions,
1403 &objmethods) == FAIL)
1404 goto cleanup;
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001405
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001406 cl->class_type.tt_type = VAR_CLASS;
Bram Moolenaarb1e32ac2023-02-21 12:38:51 +00001407 cl->class_type.tt_class = cl;
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001408 cl->class_object_type.tt_type = VAR_OBJECT;
Bram Moolenaarb1e32ac2023-02-21 12:38:51 +00001409 cl->class_object_type.tt_class = cl;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001410 cl->class_type_list = type_list;
1411
1412 // TODO:
Bram Moolenaard505d172022-12-18 21:42:55 +00001413 // - Fill hashtab with object members and methods ?
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001414
1415 // Add the class to the script-local variables.
Bram Moolenaar94674f22023-01-06 18:42:20 +00001416 // TODO: handle other context, e.g. in a function
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001417 typval_T tv;
1418 tv.v_type = VAR_CLASS;
1419 tv.vval.v_class = cl;
Bram Moolenaara86655a2023-01-12 17:06:27 +00001420 is_export = class_export;
Bram Moolenaar83ae6152023-02-25 19:59:31 +00001421 SOURCING_LNUM = start_lnum;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001422 set_var_const(cl->class_name, current_sctx.sc_sid,
Bram Moolenaar83ae6152023-02-25 19:59:31 +00001423 NULL, &tv, FALSE, 0, 0);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001424 return;
1425 }
1426
1427cleanup:
Bram Moolenaareb533502022-12-14 15:06:11 +00001428 if (cl != NULL)
1429 {
1430 vim_free(cl->class_name);
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001431 vim_free(cl->class_class_functions);
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001432 if (cl->class_interfaces != NULL)
1433 {
1434 for (int i = 0; i < cl->class_interface_count; ++i)
1435 vim_free(cl->class_interfaces[i]);
1436 vim_free(cl->class_interfaces);
1437 }
1438 if (cl->class_interfaces_cl != NULL)
1439 {
1440 for (int i = 0; i < cl->class_interface_count; ++i)
1441 class_unref(cl->class_interfaces_cl[i]);
1442 vim_free(cl->class_interfaces_cl);
1443 }
Bram Moolenaareb533502022-12-14 15:06:11 +00001444 vim_free(cl->class_obj_members);
1445 vim_free(cl->class_obj_methods);
1446 vim_free(cl);
1447 }
1448
Bram Moolenaar83677162023-01-08 19:54:10 +00001449 vim_free(extends);
1450 class_unref(extends_cl);
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001451
1452 if (intf_classes != NULL)
1453 {
1454 for (int i = 0; i < ga_impl.ga_len; ++i)
1455 class_unref(intf_classes[i]);
1456 vim_free(intf_classes);
1457 }
Bram Moolenaar94674f22023-01-06 18:42:20 +00001458 ga_clear_strings(&ga_impl);
1459
Bram Moolenaard505d172022-12-18 21:42:55 +00001460 for (int round = 1; round <= 2; ++round)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001461 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001462 garray_T *gap = round == 1 ? &classmembers : &objmembers;
1463 if (gap->ga_len == 0 || gap->ga_data == NULL)
1464 continue;
1465
1466 for (int i = 0; i < gap->ga_len; ++i)
1467 {
1468 ocmember_T *m = ((ocmember_T *)gap->ga_data) + i;
1469 vim_free(m->ocm_name);
1470 vim_free(m->ocm_init);
1471 }
1472 ga_clear(gap);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001473 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001474
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001475 for (int i = 0; i < objmethods.ga_len; ++i)
1476 {
1477 ufunc_T *uf = ((ufunc_T **)objmethods.ga_data)[i];
1478 func_clear_free(uf, FALSE);
1479 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001480 ga_clear(&objmethods);
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001481
1482 for (int i = 0; i < classfunctions.ga_len; ++i)
1483 {
1484 ufunc_T *uf = ((ufunc_T **)classfunctions.ga_data)[i];
1485 func_clear_free(uf, FALSE);
1486 }
1487 ga_clear(&classfunctions);
1488
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001489 clear_type_list(&type_list);
1490}
1491
1492/*
Bram Moolenaarf54cedd2022-12-23 17:56:27 +00001493 * Find member "name" in class "cl", set "member_idx" to the member index and
1494 * return its type.
1495 * When not found "member_idx" is set to -1 and t_any is returned.
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001496 */
1497 type_T *
1498class_member_type(
1499 class_T *cl,
1500 char_u *name,
1501 char_u *name_end,
1502 int *member_idx)
1503{
1504 *member_idx = -1; // not found (yet)
1505 size_t len = name_end - name;
1506
1507 for (int i = 0; i < cl->class_obj_member_count; ++i)
1508 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001509 ocmember_T *m = cl->class_obj_members + i;
1510 if (STRNCMP(m->ocm_name, name, len) == 0 && m->ocm_name[len] == NUL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001511 {
1512 *member_idx = i;
Bram Moolenaard505d172022-12-18 21:42:55 +00001513 return m->ocm_type;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001514 }
1515 }
Bram Moolenaarf54cedd2022-12-23 17:56:27 +00001516
1517 semsg(_(e_unknown_variable_str), name);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001518 return &t_any;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001519}
1520
1521/*
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001522 * Handle ":enum" up to ":endenum".
1523 */
1524 void
1525ex_enum(exarg_T *eap UNUSED)
1526{
1527 // TODO
1528}
1529
1530/*
1531 * Handle ":type".
1532 */
1533 void
1534ex_type(exarg_T *eap UNUSED)
1535{
1536 // TODO
1537}
1538
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001539/*
1540 * Evaluate what comes after a class:
1541 * - class member: SomeClass.varname
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001542 * - class function: SomeClass.SomeMethod()
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001543 * - class constructor: SomeClass.new()
1544 * - object member: someObject.varname
1545 * - object method: someObject.SomeMethod()
1546 *
1547 * "*arg" points to the '.'.
1548 * "*arg" is advanced to after the member name or method call.
1549 *
1550 * Returns FAIL or OK.
1551 */
1552 int
1553class_object_index(
1554 char_u **arg,
1555 typval_T *rettv,
1556 evalarg_T *evalarg,
1557 int verbose UNUSED) // give error messages
1558{
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001559 if (VIM_ISWHITE((*arg)[1]))
1560 {
1561 semsg(_(e_no_white_space_allowed_after_str_str), ".", *arg);
1562 return FAIL;
1563 }
1564
1565 ++*arg;
1566 char_u *name = *arg;
1567 char_u *name_end = find_name_end(name, NULL, NULL, FNE_CHECK_START);
1568 if (name_end == name)
1569 return FAIL;
1570 size_t len = name_end - name;
1571
Bram Moolenaar552bdca2023-02-17 21:08:50 +00001572 class_T *cl;
1573 if (rettv->v_type == VAR_CLASS)
1574 cl = rettv->vval.v_class;
1575 else // VAR_OBJECT
1576 {
1577 if (rettv->vval.v_object == NULL)
1578 {
1579 emsg(_(e_using_null_object));
1580 return FAIL;
1581 }
1582 cl = rettv->vval.v_object->obj_class;
1583 }
1584
Bram Moolenaard13dd302023-03-11 20:56:35 +00001585 if (cl == NULL)
1586 {
1587 emsg(_(e_incomplete_type));
1588 return FAIL;
1589 }
1590
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001591 if (*name_end == '(')
1592 {
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001593 int on_class = rettv->v_type == VAR_CLASS;
1594 int count = on_class ? cl->class_class_function_count
1595 : cl->class_obj_method_count;
1596 for (int i = 0; i < count; ++i)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001597 {
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001598 ufunc_T *fp = on_class ? cl->class_class_functions[i]
1599 : cl->class_obj_methods[i];
Bram Moolenaar4ae00572022-12-09 22:49:23 +00001600 // Use a separate pointer to avoid that ASAN complains about
1601 // uf_name[] only being 4 characters.
1602 char_u *ufname = (char_u *)fp->uf_name;
1603 if (STRNCMP(name, ufname, len) == 0 && ufname[len] == NUL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001604 {
1605 typval_T argvars[MAX_FUNC_ARGS + 1];
1606 int argcount = 0;
1607
Yegappan Lakshmanancd7293b2023-08-27 19:18:23 +02001608 if (fp->uf_private)
1609 {
1610 // Cannot access a private method outside of a class
1611 semsg(_(e_cannot_access_private_method_str), name);
1612 return FAIL;
1613 }
1614
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001615 char_u *argp = name_end;
1616 int ret = get_func_arguments(&argp, evalarg, 0,
1617 argvars, &argcount);
1618 if (ret == FAIL)
1619 return FAIL;
1620
1621 funcexe_T funcexe;
1622 CLEAR_FIELD(funcexe);
1623 funcexe.fe_evaluate = TRUE;
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001624 if (rettv->v_type == VAR_OBJECT)
1625 {
1626 funcexe.fe_object = rettv->vval.v_object;
1627 ++funcexe.fe_object->obj_refcount;
1628 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001629
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001630 // Clear the class or object after calling the function, in
1631 // case the refcount is one.
1632 typval_T tv_tofree = *rettv;
1633 rettv->v_type = VAR_UNKNOWN;
1634
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001635 // Call the user function. Result goes into rettv;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001636 int error = call_user_func_check(fp, argcount, argvars,
1637 rettv, &funcexe, NULL);
1638
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001639 // Clear the previous rettv and the arguments.
1640 clear_tv(&tv_tofree);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001641 for (int idx = 0; idx < argcount; ++idx)
1642 clear_tv(&argvars[idx]);
1643
1644 if (error != FCERR_NONE)
1645 {
1646 user_func_error(error, printable_func_name(fp),
1647 funcexe.fe_found_var);
1648 return FAIL;
1649 }
1650 *arg = argp;
1651 return OK;
1652 }
1653 }
1654
1655 semsg(_(e_method_not_found_on_class_str_str), cl->class_name, name);
1656 }
1657
1658 else if (rettv->v_type == VAR_OBJECT)
1659 {
1660 for (int i = 0; i < cl->class_obj_member_count; ++i)
1661 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001662 ocmember_T *m = &cl->class_obj_members[i];
1663 if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001664 {
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001665 if (*name == '_')
1666 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001667 semsg(_(e_cannot_access_private_member_str), m->ocm_name);
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001668 return FAIL;
1669 }
1670
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001671 // The object only contains a pointer to the class, the member
1672 // values array follows right after that.
1673 object_T *obj = rettv->vval.v_object;
1674 typval_T *tv = (typval_T *)(obj + 1) + i;
1675 copy_tv(tv, rettv);
1676 object_unref(obj);
1677
1678 *arg = name_end;
1679 return OK;
1680 }
1681 }
1682
1683 semsg(_(e_member_not_found_on_object_str_str), cl->class_name, name);
1684 }
1685
Bram Moolenaard505d172022-12-18 21:42:55 +00001686 else if (rettv->v_type == VAR_CLASS)
1687 {
1688 // class member
1689 for (int i = 0; i < cl->class_class_member_count; ++i)
1690 {
1691 ocmember_T *m = &cl->class_class_members[i];
1692 if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
1693 {
1694 if (*name == '_')
1695 {
1696 semsg(_(e_cannot_access_private_member_str), m->ocm_name);
1697 return FAIL;
1698 }
1699
1700 typval_T *tv = &cl->class_members_tv[i];
1701 copy_tv(tv, rettv);
1702 class_unref(cl);
1703
1704 *arg = name_end;
1705 return OK;
1706 }
1707 }
1708
1709 semsg(_(e_member_not_found_on_class_str_str), cl->class_name, name);
1710 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001711
1712 return FAIL;
1713}
1714
1715/*
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001716 * If "arg" points to a class or object method, return it.
1717 * Otherwise return NULL.
1718 */
1719 ufunc_T *
1720find_class_func(char_u **arg)
1721{
1722 char_u *name = *arg;
1723 char_u *name_end = find_name_end(name, NULL, NULL, FNE_CHECK_START);
1724 if (name_end == name || *name_end != '.')
1725 return NULL;
1726
1727 size_t len = name_end - name;
1728 typval_T tv;
1729 tv.v_type = VAR_UNKNOWN;
Bram Moolenaar993dbc32023-01-01 20:31:30 +00001730 if (eval_variable(name, (int)len,
1731 0, &tv, NULL, EVAL_VAR_NOAUTOLOAD) == FAIL)
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001732 return NULL;
1733 if (tv.v_type != VAR_CLASS && tv.v_type != VAR_OBJECT)
Bram Moolenaareb533502022-12-14 15:06:11 +00001734 goto fail_after_eval;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001735
1736 class_T *cl = tv.v_type == VAR_CLASS ? tv.vval.v_class
1737 : tv.vval.v_object->obj_class;
1738 if (cl == NULL)
Bram Moolenaareb533502022-12-14 15:06:11 +00001739 goto fail_after_eval;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001740 char_u *fname = name_end + 1;
1741 char_u *fname_end = find_name_end(fname, NULL, NULL, FNE_CHECK_START);
1742 if (fname_end == fname)
Bram Moolenaareb533502022-12-14 15:06:11 +00001743 goto fail_after_eval;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001744 len = fname_end - fname;
1745
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001746 int count = tv.v_type == VAR_CLASS ? cl->class_class_function_count
1747 : cl->class_obj_method_count;
1748 ufunc_T **funcs = tv.v_type == VAR_CLASS ? cl->class_class_functions
1749 : cl->class_obj_methods;
1750 for (int i = 0; i < count; ++i)
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001751 {
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001752 ufunc_T *fp = funcs[i];
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001753 // Use a separate pointer to avoid that ASAN complains about
1754 // uf_name[] only being 4 characters.
1755 char_u *ufname = (char_u *)fp->uf_name;
1756 if (STRNCMP(fname, ufname, len) == 0 && ufname[len] == NUL)
Bram Moolenaareb533502022-12-14 15:06:11 +00001757 {
1758 clear_tv(&tv);
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001759 return fp;
Bram Moolenaareb533502022-12-14 15:06:11 +00001760 }
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001761 }
1762
Bram Moolenaareb533502022-12-14 15:06:11 +00001763fail_after_eval:
1764 clear_tv(&tv);
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001765 return NULL;
1766}
1767
1768/*
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001769 * If "name[len]" is a class member in cctx->ctx_ufunc->uf_class return the
1770 * index in class.class_class_members[].
1771 * If "cl_ret" is not NULL set it to the class.
1772 * Otherwise return -1;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001773 */
1774 int
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001775class_member_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001776{
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001777 if (cctx == NULL || cctx->ctx_ufunc == NULL
1778 || cctx->ctx_ufunc->uf_class == NULL)
1779 return -1;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001780 class_T *cl = cctx->ctx_ufunc->uf_class;
1781
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001782 for (int i = 0; i < cl->class_class_member_count; ++i)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001783 {
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001784 ocmember_T *m = &cl->class_class_members[i];
1785 if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001786 {
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001787 if (cl_ret != NULL)
1788 *cl_ret = cl;
1789 return i;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001790 }
1791 }
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001792 return -1;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001793}
1794
1795/*
Bram Moolenaar62a69232023-01-24 15:07:04 +00001796 * Return TRUE if current context "cctx_arg" is inside class "cl".
1797 * Return FALSE if not.
1798 */
1799 int
1800inside_class(cctx_T *cctx_arg, class_T *cl)
1801{
1802 for (cctx_T *cctx = cctx_arg; cctx != NULL; cctx = cctx->ctx_outer)
1803 if (cctx->ctx_ufunc != NULL && cctx->ctx_ufunc->uf_class == cl)
1804 return TRUE;
1805 return FALSE;
1806}
1807
1808/*
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001809 * Make a copy of an object.
1810 */
1811 void
1812copy_object(typval_T *from, typval_T *to)
1813{
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +02001814 if (from->vval.v_object == NULL)
1815 to->vval.v_object = NULL;
1816 else
1817 {
1818 to->vval.v_object = from->vval.v_object;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001819 ++to->vval.v_object->obj_refcount;
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +02001820 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001821}
1822
1823/*
1824 * Free an object.
1825 */
1826 static void
1827object_clear(object_T *obj)
1828{
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01001829 // Avoid a recursive call, it can happen if "obj" has a circular reference.
1830 obj->obj_refcount = INT_MAX;
1831
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001832 class_T *cl = obj->obj_class;
1833
Jia-Ju Bai5b0889b2023-08-13 20:04:04 +02001834 if (!cl)
Yegappan Lakshmanand4e4ecb2023-08-27 18:35:45 +02001835 return;
Jia-Ju Bai5b0889b2023-08-13 20:04:04 +02001836
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001837 // the member values are just after the object structure
1838 typval_T *tv = (typval_T *)(obj + 1);
1839 for (int i = 0; i < cl->class_obj_member_count; ++i)
1840 clear_tv(tv + i);
1841
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001842 // Remove from the list headed by "first_object".
1843 object_cleared(obj);
1844
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001845 vim_free(obj);
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001846 class_unref(cl);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001847}
1848
1849/*
1850 * Unreference an object.
1851 */
1852 void
1853object_unref(object_T *obj)
1854{
1855 if (obj != NULL && --obj->obj_refcount <= 0)
1856 object_clear(obj);
1857}
1858
1859/*
1860 * Make a copy of a class.
1861 */
1862 void
1863copy_class(typval_T *from, typval_T *to)
1864{
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +02001865 if (from->vval.v_class == NULL)
1866 to->vval.v_class = NULL;
1867 else
1868 {
1869 to->vval.v_class = from->vval.v_class;
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001870 ++to->vval.v_class->class_refcount;
Yegappan Lakshmanan618e47d2023-08-22 21:29:28 +02001871 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001872}
1873
1874/*
1875 * Unreference a class. Free it when the reference count goes down to zero.
1876 */
1877 void
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001878class_unref(class_T *cl)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001879{
Bram Moolenaard505d172022-12-18 21:42:55 +00001880 if (cl != NULL && --cl->class_refcount <= 0 && cl->class_name != NULL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001881 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001882 // Freeing what the class contains may recursively come back here.
1883 // Clear "class_name" first, if it is NULL the class does not need to
1884 // be freed.
1885 VIM_CLEAR(cl->class_name);
1886
Bram Moolenaar83677162023-01-08 19:54:10 +00001887 class_unref(cl->class_extends);
1888
Bram Moolenaar94674f22023-01-06 18:42:20 +00001889 for (int i = 0; i < cl->class_interface_count; ++i)
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001890 {
Bram Moolenaar94674f22023-01-06 18:42:20 +00001891 vim_free(((char_u **)cl->class_interfaces)[i]);
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001892 if (cl->class_interfaces_cl[i] != NULL)
1893 class_unref(cl->class_interfaces_cl[i]);
1894 }
Bram Moolenaar94674f22023-01-06 18:42:20 +00001895 vim_free(cl->class_interfaces);
Bram Moolenaara94bd9d2023-01-12 15:01:32 +00001896 vim_free(cl->class_interfaces_cl);
Bram Moolenaar94674f22023-01-06 18:42:20 +00001897
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001898 itf2class_T *next;
1899 for (itf2class_T *i2c = cl->class_itf2class; i2c != NULL; i2c = next)
1900 {
1901 next = i2c->i2c_next;
1902 vim_free(i2c);
1903 }
1904
Bram Moolenaard505d172022-12-18 21:42:55 +00001905 for (int i = 0; i < cl->class_class_member_count; ++i)
1906 {
1907 ocmember_T *m = &cl->class_class_members[i];
1908 vim_free(m->ocm_name);
1909 vim_free(m->ocm_init);
1910 if (cl->class_members_tv != NULL)
1911 clear_tv(&cl->class_members_tv[i]);
1912 }
1913 vim_free(cl->class_class_members);
1914 vim_free(cl->class_members_tv);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001915
1916 for (int i = 0; i < cl->class_obj_member_count; ++i)
1917 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001918 ocmember_T *m = &cl->class_obj_members[i];
1919 vim_free(m->ocm_name);
1920 vim_free(m->ocm_init);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001921 }
1922 vim_free(cl->class_obj_members);
1923
Bram Moolenaarec8b74f2023-01-01 14:11:27 +00001924 for (int i = 0; i < cl->class_class_function_count; ++i)
1925 {
1926 ufunc_T *uf = cl->class_class_functions[i];
1927 func_clear_free(uf, FALSE);
1928 }
1929 vim_free(cl->class_class_functions);
1930
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001931 for (int i = 0; i < cl->class_obj_method_count; ++i)
1932 {
1933 ufunc_T *uf = cl->class_obj_methods[i];
1934 func_clear_free(uf, FALSE);
1935 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001936 vim_free(cl->class_obj_methods);
1937
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001938 clear_type_list(&cl->class_type_list);
1939
1940 vim_free(cl);
1941 }
1942}
1943
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001944static object_T *first_object = NULL;
1945
1946/*
1947 * Call this function when an object has been created. It will be added to the
1948 * list headed by "first_object".
1949 */
1950 void
1951object_created(object_T *obj)
1952{
1953 if (first_object != NULL)
1954 {
1955 obj->obj_next_used = first_object;
1956 first_object->obj_prev_used = obj;
1957 }
1958 first_object = obj;
1959}
1960
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01001961static object_T *next_nonref_obj = NULL;
1962
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001963/*
1964 * Call this function when an object has been cleared and is about to be freed.
1965 * It is removed from the list headed by "first_object".
1966 */
1967 void
1968object_cleared(object_T *obj)
1969{
1970 if (obj->obj_next_used != NULL)
1971 obj->obj_next_used->obj_prev_used = obj->obj_prev_used;
1972 if (obj->obj_prev_used != NULL)
1973 obj->obj_prev_used->obj_next_used = obj->obj_next_used;
1974 else if (first_object == obj)
1975 first_object = obj->obj_next_used;
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01001976
1977 // update the next object to check if needed
1978 if (obj == next_nonref_obj)
1979 next_nonref_obj = obj->obj_next_used;
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001980}
1981
1982/*
1983 * Go through the list of all objects and free items without "copyID".
1984 */
1985 int
1986object_free_nonref(int copyID)
1987{
1988 int did_free = FALSE;
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001989
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01001990 for (object_T *obj = first_object; obj != NULL; obj = next_nonref_obj)
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001991 {
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01001992 next_nonref_obj = obj->obj_next_used;
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001993 if ((obj->obj_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
1994 {
1995 // Free the object and items it contains.
1996 object_clear(obj);
1997 did_free = TRUE;
1998 }
1999 }
2000
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01002001 next_nonref_obj = NULL;
Bram Moolenaard28d7b92022-12-08 20:42:00 +00002002 return did_free;
2003}
2004
LemonBoyafe04662023-08-23 21:08:11 +02002005/*
Yegappan Lakshmanand4e4ecb2023-08-27 18:35:45 +02002006 * Return TRUE when the class "cl", its base class or one of the implemented
2007 * interfaces matches the class "other_cl".
LemonBoyafe04662023-08-23 21:08:11 +02002008 */
2009 int
2010class_instance_of(class_T *cl, class_T *other_cl)
2011{
2012 if (cl == other_cl)
2013 return TRUE;
2014
2015 // Recursively check the base classes.
2016 for (; cl != NULL; cl = cl->class_extends)
2017 {
2018 if (cl == other_cl)
2019 return TRUE;
2020 // Check the implemented interfaces.
2021 for (int i = cl->class_interface_count - 1; i >= 0; --i)
2022 if (cl->class_interfaces_cl[i] == other_cl)
2023 return TRUE;
2024 }
2025
2026 return FALSE;
2027}
2028
2029/*
2030 * "instanceof(object, classinfo)" function
2031 */
2032 void
2033f_instanceof(typval_T *argvars, typval_T *rettv)
2034{
2035 typval_T *object_tv = &argvars[0];
2036 typval_T *classinfo_tv = &argvars[1];
2037 listitem_T *li;
2038
2039 rettv->vval.v_number = VVAL_FALSE;
2040
2041 if (check_for_object_arg(argvars, 0) == FAIL
2042 || check_for_class_or_list_arg(argvars, 1) == FAIL)
2043 return;
2044
2045 if (classinfo_tv->v_type == VAR_LIST)
2046 {
2047 FOR_ALL_LIST_ITEMS(classinfo_tv->vval.v_list, li)
2048 {
2049 if (li->li_tv.v_type != VAR_CLASS)
2050 {
2051 emsg(_(e_class_required));
2052 return;
2053 }
2054
2055 if (class_instance_of(object_tv->vval.v_object->obj_class,
2056 li->li_tv.vval.v_class) == TRUE)
2057 {
2058 rettv->vval.v_number = VVAL_TRUE;
2059 return;
2060 }
2061 }
2062 }
2063 else if (classinfo_tv->v_type == VAR_CLASS)
2064 {
2065 rettv->vval.v_number = class_instance_of(object_tv->vval.v_object->obj_class,
2066 classinfo_tv->vval.v_class);
2067 }
2068}
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00002069
2070#endif // FEAT_EVAL