blob: 4a8dd7c0ef654012ea684fe656f920e074eb160d [file] [log] [blame]
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * vim9class.c: Vim9 script class support
12 */
13
14#define USING_FLOAT_STUFF
15#include "vim.h"
16
17#if defined(FEAT_EVAL) || defined(PROTO)
18
19// When not generating protos this is included in proto.h
20#ifdef PROTO
21# include "vim9.h"
22#endif
23
24/*
Bram Moolenaard505d172022-12-18 21:42:55 +000025 * Parse a member declaration, both object and class member.
26 * Returns OK or FAIL. When OK then "varname_end" is set to just after the
27 * variable name and "type_ret" is set to the decleared or detected type.
28 * "init_expr" is set to the initialisation expression (allocated), if there is
Bram Moolenaar554d0312023-01-05 19:59:18 +000029 * one. For an interface "init_expr" is NULL.
Bram Moolenaard505d172022-12-18 21:42:55 +000030 */
31 static int
32parse_member(
33 exarg_T *eap,
34 char_u *line,
35 char_u *varname,
36 int has_public, // TRUE if "public" seen before "varname"
37 char_u **varname_end,
38 garray_T *type_list,
39 type_T **type_ret,
40 char_u **init_expr)
41{
42 *varname_end = to_name_end(varname, FALSE);
43 if (*varname == '_' && has_public)
44 {
45 semsg(_(e_public_member_name_cannot_start_with_underscore_str), line);
46 return FAIL;
47 }
48
49 char_u *colon = skipwhite(*varname_end);
50 char_u *type_arg = colon;
51 type_T *type = NULL;
52 if (*colon == ':')
53 {
54 if (VIM_ISWHITE(**varname_end))
55 {
56 semsg(_(e_no_white_space_allowed_before_colon_str), varname);
57 return FAIL;
58 }
59 if (!VIM_ISWHITE(colon[1]))
60 {
61 semsg(_(e_white_space_required_after_str_str), ":", varname);
62 return FAIL;
63 }
64 type_arg = skipwhite(colon + 1);
65 type = parse_type(&type_arg, type_list, TRUE);
66 if (type == NULL)
67 return FAIL;
68 }
69
70 char_u *expr_start = skipwhite(type_arg);
71 char_u *expr_end = expr_start;
72 if (type == NULL && *expr_start != '=')
73 {
74 emsg(_(e_type_or_initialization_required));
75 return FAIL;
76 }
77
78 if (*expr_start == '=')
79 {
80 if (!VIM_ISWHITE(expr_start[-1]) || !VIM_ISWHITE(expr_start[1]))
81 {
82 semsg(_(e_white_space_required_before_and_after_str_at_str),
83 "=", type_arg);
84 return FAIL;
85 }
86 expr_start = skipwhite(expr_start + 1);
87
88 expr_end = expr_start;
89 evalarg_T evalarg;
90 fill_evalarg_from_eap(&evalarg, eap, FALSE);
91 skip_expr(&expr_end, NULL);
92
93 if (type == NULL)
94 {
95 // No type specified, use the type of the initializer.
96 typval_T tv;
97 tv.v_type = VAR_UNKNOWN;
98 char_u *expr = expr_start;
99 int res = eval0(expr, &tv, eap, &evalarg);
100
101 if (res == OK)
Bram Moolenaare83c1332023-01-02 21:04:04 +0000102 {
Bram Moolenaard505d172022-12-18 21:42:55 +0000103 type = typval2type(&tv, get_copyID(), type_list,
104 TVTT_DO_MEMBER);
Bram Moolenaare83c1332023-01-02 21:04:04 +0000105 clear_tv(&tv);
106 }
Bram Moolenaard505d172022-12-18 21:42:55 +0000107 if (type == NULL)
108 {
109 semsg(_(e_cannot_get_object_member_type_from_initializer_str),
110 expr_start);
111 clear_evalarg(&evalarg, NULL);
112 return FAIL;
113 }
114 }
115 clear_evalarg(&evalarg, NULL);
116 }
117 if (!valid_declaration_type(type))
118 return FAIL;
119
120 *type_ret = type;
121 if (expr_end > expr_start)
Bram Moolenaar554d0312023-01-05 19:59:18 +0000122 {
123 if (init_expr == NULL)
124 {
125 emsg(_(e_cannot_initialize_member_in_interface));
126 return FAIL;
127 }
Bram Moolenaard505d172022-12-18 21:42:55 +0000128 *init_expr = vim_strnsave(expr_start, expr_end - expr_start);
Bram Moolenaar554d0312023-01-05 19:59:18 +0000129 }
Bram Moolenaard505d172022-12-18 21:42:55 +0000130 return OK;
131}
132
133/*
134 * Add a member to an object or a class.
135 * Returns OK when successful, "init_expr" will be consumed then.
136 * Returns FAIL otherwise, caller might need to free "init_expr".
137 */
138 static int
139add_member(
140 garray_T *gap,
141 char_u *varname,
142 char_u *varname_end,
143 int has_public,
144 type_T *type,
145 char_u *init_expr)
146{
147 if (ga_grow(gap, 1) == FAIL)
148 return FAIL;
149 ocmember_T *m = ((ocmember_T *)gap->ga_data) + gap->ga_len;
150 m->ocm_name = vim_strnsave(varname, varname_end - varname);
151 m->ocm_access = has_public ? ACCESS_ALL
152 : *varname == '_' ? ACCESS_PRIVATE : ACCESS_READ;
153 m->ocm_type = type;
154 if (init_expr != NULL)
155 m->ocm_init = init_expr;
156 ++gap->ga_len;
157 return OK;
158}
159
160/*
161 * Move the class or object members found while parsing a class into the class.
162 * "gap" contains the found members.
163 * "members" will be set to the newly allocated array of members and
164 * "member_count" set to the number of members.
165 * Returns OK or FAIL.
166 */
167 static int
168add_members_to_class(
169 garray_T *gap,
170 ocmember_T **members,
171 int *member_count)
172{
173 *member_count = gap->ga_len;
174 *members = gap->ga_len == 0 ? NULL : ALLOC_MULT(ocmember_T, gap->ga_len);
175 if (gap->ga_len > 0 && *members == NULL)
176 return FAIL;
Bram Moolenaar8efdcee2022-12-19 12:18:09 +0000177 if (gap->ga_len > 0)
178 mch_memmove(*members, gap->ga_data, sizeof(ocmember_T) * gap->ga_len);
Bram Moolenaard505d172022-12-18 21:42:55 +0000179 VIM_CLEAR(gap->ga_data);
180 return OK;
181}
182
183/*
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000184 * Handle ":class" and ":abstract class" up to ":endclass".
Bram Moolenaar554d0312023-01-05 19:59:18 +0000185 * Handle ":interface" up to ":endinterface".
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000186 */
187 void
188ex_class(exarg_T *eap)
189{
Bram Moolenaar554d0312023-01-05 19:59:18 +0000190 int is_class = eap->cmdidx == CMD_class; // FALSE for :interface
191
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000192 if (!current_script_is_vim9()
193 || (cmdmod.cmod_flags & CMOD_LEGACY)
194 || !getline_equal(eap->getline, eap->cookie, getsourceline))
195 {
Bram Moolenaar554d0312023-01-05 19:59:18 +0000196 if (is_class)
197 emsg(_(e_class_can_only_be_defined_in_vim9_script));
198 else
199 emsg(_(e_interface_can_only_be_defined_in_vim9_script));
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000200 return;
201 }
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000202
203 char_u *arg = eap->arg;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000204 int is_abstract = eap->cmdidx == CMD_abstract;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000205 if (is_abstract)
206 {
207 if (STRNCMP(arg, "class", 5) != 0 || !VIM_ISWHITE(arg[5]))
208 {
209 semsg(_(e_invalid_argument_str), arg);
210 return;
211 }
212 arg = skipwhite(arg + 5);
213 }
214
215 if (!ASCII_ISUPPER(*arg))
216 {
Bram Moolenaar554d0312023-01-05 19:59:18 +0000217 if (is_class)
218 semsg(_(e_class_name_must_start_with_uppercase_letter_str), arg);
219 else
220 semsg(_(e_interface_name_must_start_with_uppercase_letter_str),
221 arg);
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000222 return;
223 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000224 char_u *name_end = find_name_end(arg, NULL, NULL, FNE_CHECK_START);
225 if (!IS_WHITE_OR_NUL(*name_end))
226 {
Bram Moolenaar554d0312023-01-05 19:59:18 +0000227 semsg(_(e_white_space_required_after_name_str), arg);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000228 return;
229 }
Bram Moolenaar94674f22023-01-06 18:42:20 +0000230 char_u *name_start = arg;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000231
232 // TODO:
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000233 // generics: <Tkey, Tentry>
Bram Moolenaard505d172022-12-18 21:42:55 +0000234 // handle "is_export" if it is set
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000235
Bram Moolenaar94674f22023-01-06 18:42:20 +0000236 // Names for "implements SomeInterface"
237 garray_T ga_impl;
238 ga_init2(&ga_impl, sizeof(char_u *), 5);
239
240 arg = skipwhite(name_end);
241 while (*arg != NUL && *arg != '#' && *arg != '\n')
242 {
243 // TODO:
244 // extends SomeClass
245 // specifies SomeInterface
246 if (STRNCMP(arg, "implements", 10) == 0 && IS_WHITE_OR_NUL(arg[10]))
247 {
Bram Moolenaardf8f9472023-01-07 14:51:03 +0000248 if (ga_impl.ga_len > 0)
249 {
250 emsg(_(e_duplicate_implements));
251 goto early_ret;
252 }
Bram Moolenaar94674f22023-01-06 18:42:20 +0000253 arg = skipwhite(arg + 10);
Bram Moolenaardf8f9472023-01-07 14:51:03 +0000254
255 for (;;)
Bram Moolenaar94674f22023-01-06 18:42:20 +0000256 {
Bram Moolenaardf8f9472023-01-07 14:51:03 +0000257 char_u *impl_end = find_name_end(arg, NULL, NULL,
258 FNE_CHECK_START);
259 if (!IS_WHITE_OR_NUL(*impl_end) && *impl_end != ',')
260 {
261 semsg(_(e_white_space_required_after_name_str), arg);
262 goto early_ret;
263 }
264 char_u *iname = vim_strnsave(arg, impl_end - arg);
265 if (iname == NULL)
266 goto early_ret;
267 for (int i = 0; i < ga_impl.ga_len; ++i)
268 if (STRCMP(((char_u **)ga_impl.ga_data)[i], iname) == 0)
269 {
270 semsg(_(e_duplicate_interface_after_implements_str),
271 iname);
272 vim_free(iname);
273 goto early_ret;
274 }
275 if (ga_add_string(&ga_impl, iname) == FAIL)
276 {
277 vim_free(iname);
278 goto early_ret;
279 }
280 if (*impl_end != ',')
281 {
282 arg = skipwhite(impl_end);
283 break;
284 }
285 arg = skipwhite(impl_end + 1);
Bram Moolenaar94674f22023-01-06 18:42:20 +0000286 }
Bram Moolenaar94674f22023-01-06 18:42:20 +0000287 }
288 else
289 {
290 semsg(_(e_trailing_characters_str), arg);
291early_ret:
292 ga_clear_strings(&ga_impl);
293 return;
294 }
295 }
296
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000297 garray_T type_list; // list of pointers to allocated types
298 ga_init2(&type_list, sizeof(type_T *), 10);
299
Bram Moolenaard505d172022-12-18 21:42:55 +0000300 // Growarray with class members declared in the class.
301 garray_T classmembers;
302 ga_init2(&classmembers, sizeof(ocmember_T), 10);
303
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000304 // Growarray with functions declared in the class.
305 garray_T classfunctions;
306 ga_init2(&classfunctions, sizeof(ufunc_T *), 10);
Bram Moolenaard505d172022-12-18 21:42:55 +0000307
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000308 // Growarray with object members declared in the class.
309 garray_T objmembers;
Bram Moolenaard505d172022-12-18 21:42:55 +0000310 ga_init2(&objmembers, sizeof(ocmember_T), 10);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000311
312 // Growarray with object methods declared in the class.
313 garray_T objmethods;
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000314 ga_init2(&objmethods, sizeof(ufunc_T *), 10);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000315
316 /*
Bram Moolenaar554d0312023-01-05 19:59:18 +0000317 * Go over the body of the class/interface until "endclass" or
318 * "endinterface" is found.
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000319 */
320 char_u *theline = NULL;
321 int success = FALSE;
322 for (;;)
323 {
324 vim_free(theline);
325 theline = eap->getline(':', eap->cookie, 0, GETLINE_CONCAT_ALL);
326 if (theline == NULL)
327 break;
328 char_u *line = skipwhite(theline);
329
Bram Moolenaar418b5472022-12-20 13:38:22 +0000330 // Skip empty and comment lines.
331 if (*line == NUL)
332 continue;
333 if (*line == '#')
334 {
335 if (vim9_bad_comment(line))
336 break;
337 continue;
338 }
339
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000340 char_u *p = line;
Bram Moolenaar554d0312023-01-05 19:59:18 +0000341 char *end_name = is_class ? "endclass" : "endinterface";
342 if (checkforcmd(&p, end_name, is_class ? 4 : 5))
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000343 {
Bram Moolenaar554d0312023-01-05 19:59:18 +0000344 if (STRNCMP(line, end_name, is_class ? 8 : 12) != 0)
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000345 semsg(_(e_command_cannot_be_shortened_str), line);
346 else if (*p == '|' || !ends_excmd2(line, p))
347 semsg(_(e_trailing_characters_str), p);
Bram Moolenaar98aeb212022-12-08 22:09:14 +0000348 else
349 success = TRUE;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000350 break;
351 }
Bram Moolenaar554d0312023-01-05 19:59:18 +0000352 char *wrong_name = is_class ? "endinterface" : "endclass";
353 if (checkforcmd(&p, wrong_name, is_class ? 5 : 4))
354 {
355 semsg(_(e_invalid_command_str), line);
356 break;
357 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000358
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000359 int has_public = FALSE;
360 if (checkforcmd(&p, "public", 3))
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000361 {
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000362 if (STRNCMP(line, "public", 6) != 0)
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000363 {
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000364 semsg(_(e_command_cannot_be_shortened_str), line);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000365 break;
366 }
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000367 has_public = TRUE;
368 p = skipwhite(line + 6);
369
Bram Moolenaard505d172022-12-18 21:42:55 +0000370 if (STRNCMP(p, "this", 4) != 0 && STRNCMP(p, "static", 6) != 0)
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000371 {
Bram Moolenaard505d172022-12-18 21:42:55 +0000372 emsg(_(e_public_must_be_followed_by_this_or_static));
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000373 break;
374 }
375 }
Bram Moolenaard505d172022-12-18 21:42:55 +0000376
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000377 int has_static = FALSE;
378 char_u *ps = p;
379 if (checkforcmd(&p, "static", 4))
380 {
381 if (STRNCMP(ps, "static", 6) != 0)
382 {
383 semsg(_(e_command_cannot_be_shortened_str), ps);
384 break;
385 }
386 has_static = TRUE;
387 p = skipwhite(ps + 6);
388 }
389
Bram Moolenaard505d172022-12-18 21:42:55 +0000390 // object members (public, read access, private):
391 // "this._varname"
392 // "this.varname"
393 // "public this.varname"
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000394 if (STRNCMP(p, "this", 4) == 0)
395 {
396 if (p[4] != '.' || !eval_isnamec1(p[5]))
397 {
398 semsg(_(e_invalid_object_member_declaration_str), p);
399 break;
400 }
401 char_u *varname = p + 5;
Bram Moolenaard505d172022-12-18 21:42:55 +0000402 char_u *varname_end = NULL;
Bram Moolenaar74e12742022-12-13 21:14:28 +0000403 type_T *type = NULL;
Bram Moolenaard505d172022-12-18 21:42:55 +0000404 char_u *init_expr = NULL;
405 if (parse_member(eap, line, varname, has_public,
Bram Moolenaar554d0312023-01-05 19:59:18 +0000406 &varname_end, &type_list, &type,
407 is_class ? &init_expr: NULL) == FAIL)
Bram Moolenaard505d172022-12-18 21:42:55 +0000408 break;
409 if (add_member(&objmembers, varname, varname_end,
410 has_public, type, init_expr) == FAIL)
Bram Moolenaar74e12742022-12-13 21:14:28 +0000411 {
Bram Moolenaard505d172022-12-18 21:42:55 +0000412 vim_free(init_expr);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000413 break;
414 }
Bram Moolenaard505d172022-12-18 21:42:55 +0000415 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000416
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000417 // constructors:
418 // def new()
419 // enddef
420 // def newOther()
421 // enddef
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000422 // object methods and class functions:
423 // def SomeMethod()
424 // enddef
425 // static def ClassFunction()
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000426 // enddef
427 // TODO:
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000428 // def <Tval> someMethod()
429 // enddef
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000430 else if (checkforcmd(&p, "def", 3))
431 {
432 exarg_T ea;
433 garray_T lines_to_free;
434
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000435 // TODO: error for "public static def Func()"?
436
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000437 CLEAR_FIELD(ea);
438 ea.cmd = line;
439 ea.arg = p;
440 ea.cmdidx = CMD_def;
441 ea.getline = eap->getline;
442 ea.cookie = eap->cookie;
443
444 ga_init2(&lines_to_free, sizeof(char_u *), 50);
Bram Moolenaar554d0312023-01-05 19:59:18 +0000445 ufunc_T *uf = define_function(&ea, NULL, &lines_to_free,
446 is_class ? CF_CLASS : CF_INTERFACE);
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000447 ga_clear_strings(&lines_to_free);
448
Bram Moolenaar6acf7572023-01-01 19:53:30 +0000449 if (uf != NULL)
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000450 {
Bram Moolenaar6acf7572023-01-01 19:53:30 +0000451 int is_new = STRNCMP(uf->uf_name, "new", 3) == 0;
452 garray_T *fgap = has_static || is_new
453 ? &classfunctions : &objmethods;
454 if (ga_grow(fgap, 1) == OK)
455 {
456 if (is_new)
457 uf->uf_flags |= FC_NEW;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000458
Bram Moolenaar6acf7572023-01-01 19:53:30 +0000459 ((ufunc_T **)fgap->ga_data)[fgap->ga_len] = uf;
460 ++fgap->ga_len;
461 }
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000462 }
463 }
464
465 // class members
466 else if (has_static)
467 {
468 // class members (public, read access, private):
469 // "static _varname"
470 // "static varname"
471 // "public static varname"
472 char_u *varname = p;
473 char_u *varname_end = NULL;
474 type_T *type = NULL;
475 char_u *init_expr = NULL;
476 if (parse_member(eap, line, varname, has_public,
Bram Moolenaar554d0312023-01-05 19:59:18 +0000477 &varname_end, &type_list, &type,
478 is_class ? &init_expr : NULL) == FAIL)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000479 break;
480 if (add_member(&classmembers, varname, varname_end,
481 has_public, type, init_expr) == FAIL)
482 {
483 vim_free(init_expr);
484 break;
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000485 }
486 }
487
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000488 else
489 {
Bram Moolenaar554d0312023-01-05 19:59:18 +0000490 if (is_class)
491 semsg(_(e_not_valid_command_in_class_str), line);
492 else
493 semsg(_(e_not_valid_command_in_interface_str), line);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000494 break;
495 }
496 }
497 vim_free(theline);
498
Bram Moolenaar94674f22023-01-06 18:42:20 +0000499 // Check a few things before defining the class.
500 if (success && ga_impl.ga_len > 0)
501 {
502 // Check all "implements" entries are valid and correct.
503 for (int i = 0; i < ga_impl.ga_len && success; ++i)
504 {
505 char_u *impl = ((char_u **)ga_impl.ga_data)[i];
506 typval_T tv;
507 tv.v_type = VAR_UNKNOWN;
508 if (eval_variable(impl, 0, 0, &tv, NULL,
509 EVAL_VAR_VERBOSE + EVAL_VAR_IMPORT) == FAIL)
510 {
511 semsg(_(e_interface_name_not_found_str), impl);
512 success = FALSE;
513 break;
514 }
515
516 if (tv.v_type != VAR_CLASS
517 || tv.vval.v_class == NULL
518 || (tv.vval.v_class->class_flags & CLASS_INTERFACE) == 0)
519 {
520 semsg(_(e_not_valid_interface_str), impl);
521 success = FALSE;
522 }
523
524 // check the members of the interface match the members of the class
525 class_T *ifcl = tv.vval.v_class;
526 for (int loop = 1; loop <= 2 && success; ++loop)
527 {
528 // loop == 1: check class members
529 // loop == 2: check object members
530 int if_count = loop == 1 ? ifcl->class_class_member_count
531 : ifcl->class_obj_member_count;
532 if (if_count == 0)
533 continue;
534 ocmember_T *if_ms = loop == 1 ? ifcl->class_class_members
535 : ifcl->class_obj_members;
536 ocmember_T *cl_ms = (ocmember_T *)(loop == 1
537 ? classmembers.ga_data
538 : objmembers.ga_data);
539 int cl_count = loop == 1 ? classmembers.ga_len
540 : objmembers.ga_len;
541 for (int if_i = 0; if_i < if_count; ++if_i)
542 {
543 int cl_i;
544 for (cl_i = 0; cl_i < cl_count; ++cl_i)
545 {
546 ocmember_T *m = &cl_ms[cl_i];
547 if (STRCMP(if_ms[if_i].ocm_name, m->ocm_name) == 0)
548 {
549 // TODO: check type
550 break;
551 }
552 }
553 if (cl_i == cl_count)
554 {
555 semsg(_(e_member_str_of_interface_str_not_implemented),
556 if_ms[if_i].ocm_name, impl);
557 success = FALSE;
558 break;
559 }
560 }
561 }
562
563 // check the functions/methods of the interface match the
564 // functions/methods of the class
565 for (int loop = 1; loop <= 2 && success; ++loop)
566 {
567 // loop == 1: check class functions
568 // loop == 2: check object methods
569 int if_count = loop == 1 ? ifcl->class_class_function_count
570 : ifcl->class_obj_method_count;
571 if (if_count == 0)
572 continue;
573 ufunc_T **if_fp = loop == 1 ? ifcl->class_class_functions
574 : ifcl->class_obj_methods;
575 ufunc_T **cl_fp = (ufunc_T **)(loop == 1
576 ? classfunctions.ga_data
577 : objmethods.ga_data);
578 int cl_count = loop == 1 ? classfunctions.ga_len
579 : objmethods.ga_len;
580 for (int if_i = 0; if_i < if_count; ++if_i)
581 {
582 char_u *if_name = if_fp[if_i]->uf_name;
583 int cl_i;
584 for (cl_i = 0; cl_i < cl_count; ++cl_i)
585 {
586 char_u *cl_name = cl_fp[cl_i]->uf_name;
587 if (STRCMP(if_name, cl_name) == 0)
588 {
589 // TODO: check return and argument types
590 break;
591 }
592 }
593 if (cl_i == cl_count)
594 {
595 semsg(_(e_function_str_of_interface_str_not_implemented),
596 if_name, impl);
597 success = FALSE;
598 break;
599 }
600 }
601 }
602
603 clear_tv(&tv);
604 }
605 }
606
Bram Moolenaareb533502022-12-14 15:06:11 +0000607 class_T *cl = NULL;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000608 if (success)
609 {
Bram Moolenaard505d172022-12-18 21:42:55 +0000610 // "endclass" encountered without failures: Create the class.
611
Bram Moolenaareb533502022-12-14 15:06:11 +0000612 cl = ALLOC_CLEAR_ONE(class_T);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000613 if (cl == NULL)
614 goto cleanup;
Bram Moolenaar554d0312023-01-05 19:59:18 +0000615 if (!is_class)
616 cl->class_flags = CLASS_INTERFACE;
617
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000618 cl->class_refcount = 1;
Bram Moolenaar94674f22023-01-06 18:42:20 +0000619 cl->class_name = vim_strnsave(name_start, name_end - name_start);
Bram Moolenaard505d172022-12-18 21:42:55 +0000620 if (cl->class_name == NULL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000621 goto cleanup;
Bram Moolenaard505d172022-12-18 21:42:55 +0000622
Bram Moolenaar94674f22023-01-06 18:42:20 +0000623 if (ga_impl.ga_len > 0)
624 {
625 // Move the "implements" names into the class.
626 cl->class_interface_count = ga_impl.ga_len;
627 cl->class_interfaces = ALLOC_MULT(char_u *, ga_impl.ga_len);
628 if (cl->class_interfaces == NULL)
629 goto cleanup;
630 for (int i = 0; i < ga_impl.ga_len; ++i)
631 cl->class_interfaces[i] = ((char_u **)ga_impl.ga_data)[i];
Bram Moolenaar7d4d87b2023-01-06 18:59:08 +0000632 VIM_CLEAR(ga_impl.ga_data);
Bram Moolenaar94674f22023-01-06 18:42:20 +0000633 ga_impl.ga_len = 0;
634 }
635
Bram Moolenaard505d172022-12-18 21:42:55 +0000636 // Add class and object members to "cl".
637 if (add_members_to_class(&classmembers,
638 &cl->class_class_members,
639 &cl->class_class_member_count) == FAIL
640 || add_members_to_class(&objmembers,
641 &cl->class_obj_members,
642 &cl->class_obj_member_count) == FAIL)
643 goto cleanup;
644
Bram Moolenaar554d0312023-01-05 19:59:18 +0000645 if (is_class && cl->class_class_member_count > 0)
Bram Moolenaard505d172022-12-18 21:42:55 +0000646 {
647 // Allocate a typval for each class member and initialize it.
648 cl->class_members_tv = ALLOC_CLEAR_MULT(typval_T,
649 cl->class_class_member_count);
650 if (cl->class_members_tv != NULL)
651 for (int i = 0; i < cl->class_class_member_count; ++i)
652 {
653 ocmember_T *m = &cl->class_class_members[i];
654 typval_T *tv = &cl->class_members_tv[i];
655 if (m->ocm_init != NULL)
656 {
657 typval_T *etv = eval_expr(m->ocm_init, eap);
658 if (etv != NULL)
659 {
660 *tv = *etv;
661 vim_free(etv);
662 }
663 }
664 else
665 {
666 // TODO: proper default value
667 tv->v_type = m->ocm_type->tt_type;
668 tv->vval.v_string = NULL;
669 }
670 }
671 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000672
673 int have_new = FALSE;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000674 for (int i = 0; i < classfunctions.ga_len; ++i)
675 if (STRCMP(((ufunc_T **)classfunctions.ga_data)[i]->uf_name,
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000676 "new") == 0)
677 {
678 have_new = TRUE;
679 break;
680 }
Bram Moolenaar94674f22023-01-06 18:42:20 +0000681 if (is_class && !have_new)
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000682 {
683 // No new() method was defined, add the default constructor.
684 garray_T fga;
685 ga_init2(&fga, 1, 1000);
686 ga_concat(&fga, (char_u *)"new(");
687 for (int i = 0; i < cl->class_obj_member_count; ++i)
688 {
689 if (i > 0)
690 ga_concat(&fga, (char_u *)", ");
691 ga_concat(&fga, (char_u *)"this.");
Bram Moolenaard505d172022-12-18 21:42:55 +0000692 ocmember_T *m = cl->class_obj_members + i;
693 ga_concat(&fga, (char_u *)m->ocm_name);
Bram Moolenaar65b0d162022-12-13 18:43:22 +0000694 ga_concat(&fga, (char_u *)" = v:none");
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000695 }
696 ga_concat(&fga, (char_u *)")\nenddef\n");
697 ga_append(&fga, NUL);
698
699 exarg_T fea;
700 CLEAR_FIELD(fea);
701 fea.cmdidx = CMD_def;
702 fea.cmd = fea.arg = fga.ga_data;
703
704 garray_T lines_to_free;
705 ga_init2(&lines_to_free, sizeof(char_u *), 50);
706
Bram Moolenaar2c011312023-01-07 10:51:30 +0000707 ufunc_T *nf = define_function(&fea, NULL, &lines_to_free, CF_CLASS);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000708
709 ga_clear_strings(&lines_to_free);
710 vim_free(fga.ga_data);
711
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000712 if (nf != NULL && ga_grow(&classfunctions, 1) == OK)
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000713 {
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000714 ((ufunc_T **)classfunctions.ga_data)[classfunctions.ga_len] = nf;
715 ++classfunctions.ga_len;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000716
717 nf->uf_flags |= FC_NEW;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000718 nf->uf_ret_type = get_type_ptr(&type_list);
719 if (nf->uf_ret_type != NULL)
720 {
721 nf->uf_ret_type->tt_type = VAR_OBJECT;
722 nf->uf_ret_type->tt_member = (type_T *)cl;
723 nf->uf_ret_type->tt_argcount = 0;
724 nf->uf_ret_type->tt_args = NULL;
725 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000726 }
727 }
728
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000729 // loop 1: class functions, loop 2: object methods
730 for (int loop = 1; loop <= 2; ++loop)
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000731 {
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000732 garray_T *gap = loop == 1 ? &classfunctions : &objmethods;
733 int *fcount = loop == 1 ? &cl->class_class_function_count
734 : &cl->class_obj_method_count;
735 ufunc_T ***fup = loop == 1 ? &cl->class_class_functions
736 : &cl->class_obj_methods;
737
738 *fcount = gap->ga_len;
739 if (gap->ga_len == 0)
740 {
741 *fup = NULL;
742 continue;
743 }
744 *fup = ALLOC_MULT(ufunc_T *, gap->ga_len);
745 if (*fup == NULL)
746 goto cleanup;
747 mch_memmove(*fup, gap->ga_data, sizeof(ufunc_T *) * gap->ga_len);
748 vim_free(gap->ga_data);
749
750 // Set the class pointer on all the object methods.
751 for (int i = 0; i < gap->ga_len; ++i)
752 {
753 ufunc_T *fp = (*fup)[i];
754 fp->uf_class = cl;
755 if (loop == 2)
756 fp->uf_flags |= FC_OBJECT;
757 }
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000758 }
759
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000760 cl->class_type.tt_type = VAR_CLASS;
761 cl->class_type.tt_member = (type_T *)cl;
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000762 cl->class_object_type.tt_type = VAR_OBJECT;
763 cl->class_object_type.tt_member = (type_T *)cl;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000764 cl->class_type_list = type_list;
765
766 // TODO:
Bram Moolenaard505d172022-12-18 21:42:55 +0000767 // - Fill hashtab with object members and methods ?
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000768
769 // Add the class to the script-local variables.
Bram Moolenaar94674f22023-01-06 18:42:20 +0000770 // TODO: handle other context, e.g. in a function
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000771 typval_T tv;
772 tv.v_type = VAR_CLASS;
773 tv.vval.v_class = cl;
774 set_var_const(cl->class_name, current_sctx.sc_sid,
775 NULL, &tv, FALSE, ASSIGN_DECL, 0);
776 return;
777 }
778
779cleanup:
Bram Moolenaareb533502022-12-14 15:06:11 +0000780 if (cl != NULL)
781 {
782 vim_free(cl->class_name);
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000783 vim_free(cl->class_class_functions);
Bram Moolenaareb533502022-12-14 15:06:11 +0000784 vim_free(cl->class_obj_members);
785 vim_free(cl->class_obj_methods);
786 vim_free(cl);
787 }
788
Bram Moolenaar94674f22023-01-06 18:42:20 +0000789 ga_clear_strings(&ga_impl);
790
Bram Moolenaard505d172022-12-18 21:42:55 +0000791 for (int round = 1; round <= 2; ++round)
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000792 {
Bram Moolenaard505d172022-12-18 21:42:55 +0000793 garray_T *gap = round == 1 ? &classmembers : &objmembers;
794 if (gap->ga_len == 0 || gap->ga_data == NULL)
795 continue;
796
797 for (int i = 0; i < gap->ga_len; ++i)
798 {
799 ocmember_T *m = ((ocmember_T *)gap->ga_data) + i;
800 vim_free(m->ocm_name);
801 vim_free(m->ocm_init);
802 }
803 ga_clear(gap);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000804 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000805
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000806 for (int i = 0; i < objmethods.ga_len; ++i)
807 {
808 ufunc_T *uf = ((ufunc_T **)objmethods.ga_data)[i];
809 func_clear_free(uf, FALSE);
810 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000811 ga_clear(&objmethods);
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000812
813 for (int i = 0; i < classfunctions.ga_len; ++i)
814 {
815 ufunc_T *uf = ((ufunc_T **)classfunctions.ga_data)[i];
816 func_clear_free(uf, FALSE);
817 }
818 ga_clear(&classfunctions);
819
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000820 clear_type_list(&type_list);
821}
822
823/*
Bram Moolenaarf54cedd2022-12-23 17:56:27 +0000824 * Find member "name" in class "cl", set "member_idx" to the member index and
825 * return its type.
826 * When not found "member_idx" is set to -1 and t_any is returned.
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000827 */
828 type_T *
829class_member_type(
830 class_T *cl,
831 char_u *name,
832 char_u *name_end,
833 int *member_idx)
834{
835 *member_idx = -1; // not found (yet)
836 size_t len = name_end - name;
837
838 for (int i = 0; i < cl->class_obj_member_count; ++i)
839 {
Bram Moolenaard505d172022-12-18 21:42:55 +0000840 ocmember_T *m = cl->class_obj_members + i;
841 if (STRNCMP(m->ocm_name, name, len) == 0 && m->ocm_name[len] == NUL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000842 {
843 *member_idx = i;
Bram Moolenaard505d172022-12-18 21:42:55 +0000844 return m->ocm_type;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000845 }
846 }
Bram Moolenaarf54cedd2022-12-23 17:56:27 +0000847
848 semsg(_(e_unknown_variable_str), name);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000849 return &t_any;
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000850}
851
852/*
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000853 * Handle ":enum" up to ":endenum".
854 */
855 void
856ex_enum(exarg_T *eap UNUSED)
857{
858 // TODO
859}
860
861/*
862 * Handle ":type".
863 */
864 void
865ex_type(exarg_T *eap UNUSED)
866{
867 // TODO
868}
869
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000870/*
871 * Evaluate what comes after a class:
872 * - class member: SomeClass.varname
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000873 * - class function: SomeClass.SomeMethod()
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000874 * - class constructor: SomeClass.new()
875 * - object member: someObject.varname
876 * - object method: someObject.SomeMethod()
877 *
878 * "*arg" points to the '.'.
879 * "*arg" is advanced to after the member name or method call.
880 *
881 * Returns FAIL or OK.
882 */
883 int
884class_object_index(
885 char_u **arg,
886 typval_T *rettv,
887 evalarg_T *evalarg,
888 int verbose UNUSED) // give error messages
889{
890 // int evaluate = evalarg != NULL
891 // && (evalarg->eval_flags & EVAL_EVALUATE);
892
893 if (VIM_ISWHITE((*arg)[1]))
894 {
895 semsg(_(e_no_white_space_allowed_after_str_str), ".", *arg);
896 return FAIL;
897 }
898
899 ++*arg;
900 char_u *name = *arg;
901 char_u *name_end = find_name_end(name, NULL, NULL, FNE_CHECK_START);
902 if (name_end == name)
903 return FAIL;
904 size_t len = name_end - name;
905
906 class_T *cl = rettv->v_type == VAR_CLASS ? rettv->vval.v_class
907 : rettv->vval.v_object->obj_class;
908 if (*name_end == '(')
909 {
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000910 int on_class = rettv->v_type == VAR_CLASS;
911 int count = on_class ? cl->class_class_function_count
912 : cl->class_obj_method_count;
913 for (int i = 0; i < count; ++i)
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000914 {
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000915 ufunc_T *fp = on_class ? cl->class_class_functions[i]
916 : cl->class_obj_methods[i];
Bram Moolenaar4ae00572022-12-09 22:49:23 +0000917 // Use a separate pointer to avoid that ASAN complains about
918 // uf_name[] only being 4 characters.
919 char_u *ufname = (char_u *)fp->uf_name;
920 if (STRNCMP(name, ufname, len) == 0 && ufname[len] == NUL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000921 {
922 typval_T argvars[MAX_FUNC_ARGS + 1];
923 int argcount = 0;
924
925 char_u *argp = name_end;
926 int ret = get_func_arguments(&argp, evalarg, 0,
927 argvars, &argcount);
928 if (ret == FAIL)
929 return FAIL;
930
931 funcexe_T funcexe;
932 CLEAR_FIELD(funcexe);
933 funcexe.fe_evaluate = TRUE;
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000934 if (rettv->v_type == VAR_OBJECT)
935 {
936 funcexe.fe_object = rettv->vval.v_object;
937 ++funcexe.fe_object->obj_refcount;
938 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000939
Bram Moolenaard28d7b92022-12-08 20:42:00 +0000940 // Clear the class or object after calling the function, in
941 // case the refcount is one.
942 typval_T tv_tofree = *rettv;
943 rettv->v_type = VAR_UNKNOWN;
944
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000945 // Call the user function. Result goes into rettv;
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000946 int error = call_user_func_check(fp, argcount, argvars,
947 rettv, &funcexe, NULL);
948
Bram Moolenaard28d7b92022-12-08 20:42:00 +0000949 // Clear the previous rettv and the arguments.
950 clear_tv(&tv_tofree);
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000951 for (int idx = 0; idx < argcount; ++idx)
952 clear_tv(&argvars[idx]);
953
954 if (error != FCERR_NONE)
955 {
956 user_func_error(error, printable_func_name(fp),
957 funcexe.fe_found_var);
958 return FAIL;
959 }
960 *arg = argp;
961 return OK;
962 }
963 }
964
965 semsg(_(e_method_not_found_on_class_str_str), cl->class_name, name);
966 }
967
968 else if (rettv->v_type == VAR_OBJECT)
969 {
970 for (int i = 0; i < cl->class_obj_member_count; ++i)
971 {
Bram Moolenaard505d172022-12-18 21:42:55 +0000972 ocmember_T *m = &cl->class_obj_members[i];
973 if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000974 {
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000975 if (*name == '_')
976 {
Bram Moolenaard505d172022-12-18 21:42:55 +0000977 semsg(_(e_cannot_access_private_member_str), m->ocm_name);
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000978 return FAIL;
979 }
980
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000981 // The object only contains a pointer to the class, the member
982 // values array follows right after that.
983 object_T *obj = rettv->vval.v_object;
984 typval_T *tv = (typval_T *)(obj + 1) + i;
985 copy_tv(tv, rettv);
986 object_unref(obj);
987
988 *arg = name_end;
989 return OK;
990 }
991 }
992
993 semsg(_(e_member_not_found_on_object_str_str), cl->class_name, name);
994 }
995
Bram Moolenaard505d172022-12-18 21:42:55 +0000996 else if (rettv->v_type == VAR_CLASS)
997 {
998 // class member
999 for (int i = 0; i < cl->class_class_member_count; ++i)
1000 {
1001 ocmember_T *m = &cl->class_class_members[i];
1002 if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
1003 {
1004 if (*name == '_')
1005 {
1006 semsg(_(e_cannot_access_private_member_str), m->ocm_name);
1007 return FAIL;
1008 }
1009
1010 typval_T *tv = &cl->class_members_tv[i];
1011 copy_tv(tv, rettv);
1012 class_unref(cl);
1013
1014 *arg = name_end;
1015 return OK;
1016 }
1017 }
1018
1019 semsg(_(e_member_not_found_on_class_str_str), cl->class_name, name);
1020 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001021
1022 return FAIL;
1023}
1024
1025/*
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001026 * If "arg" points to a class or object method, return it.
1027 * Otherwise return NULL.
1028 */
1029 ufunc_T *
1030find_class_func(char_u **arg)
1031{
1032 char_u *name = *arg;
1033 char_u *name_end = find_name_end(name, NULL, NULL, FNE_CHECK_START);
1034 if (name_end == name || *name_end != '.')
1035 return NULL;
1036
1037 size_t len = name_end - name;
1038 typval_T tv;
1039 tv.v_type = VAR_UNKNOWN;
Bram Moolenaar993dbc32023-01-01 20:31:30 +00001040 if (eval_variable(name, (int)len,
1041 0, &tv, NULL, EVAL_VAR_NOAUTOLOAD) == FAIL)
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001042 return NULL;
1043 if (tv.v_type != VAR_CLASS && tv.v_type != VAR_OBJECT)
Bram Moolenaareb533502022-12-14 15:06:11 +00001044 goto fail_after_eval;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001045
1046 class_T *cl = tv.v_type == VAR_CLASS ? tv.vval.v_class
1047 : tv.vval.v_object->obj_class;
1048 if (cl == NULL)
Bram Moolenaareb533502022-12-14 15:06:11 +00001049 goto fail_after_eval;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001050 char_u *fname = name_end + 1;
1051 char_u *fname_end = find_name_end(fname, NULL, NULL, FNE_CHECK_START);
1052 if (fname_end == fname)
Bram Moolenaareb533502022-12-14 15:06:11 +00001053 goto fail_after_eval;
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001054 len = fname_end - fname;
1055
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001056 int count = tv.v_type == VAR_CLASS ? cl->class_class_function_count
1057 : cl->class_obj_method_count;
1058 ufunc_T **funcs = tv.v_type == VAR_CLASS ? cl->class_class_functions
1059 : cl->class_obj_methods;
1060 for (int i = 0; i < count; ++i)
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001061 {
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001062 ufunc_T *fp = funcs[i];
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001063 // Use a separate pointer to avoid that ASAN complains about
1064 // uf_name[] only being 4 characters.
1065 char_u *ufname = (char_u *)fp->uf_name;
1066 if (STRNCMP(fname, ufname, len) == 0 && ufname[len] == NUL)
Bram Moolenaareb533502022-12-14 15:06:11 +00001067 {
1068 clear_tv(&tv);
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001069 return fp;
Bram Moolenaareb533502022-12-14 15:06:11 +00001070 }
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001071 }
1072
Bram Moolenaareb533502022-12-14 15:06:11 +00001073fail_after_eval:
1074 clear_tv(&tv);
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +00001075 return NULL;
1076}
1077
1078/*
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001079 * If "name[len]" is a class member in cctx->ctx_ufunc->uf_class return the
1080 * index in class.class_class_members[].
1081 * If "cl_ret" is not NULL set it to the class.
1082 * Otherwise return -1;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001083 */
1084 int
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001085class_member_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001086{
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001087 if (cctx == NULL || cctx->ctx_ufunc == NULL
1088 || cctx->ctx_ufunc->uf_class == NULL)
1089 return -1;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001090 class_T *cl = cctx->ctx_ufunc->uf_class;
1091
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001092 for (int i = 0; i < cl->class_class_member_count; ++i)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001093 {
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001094 ocmember_T *m = &cl->class_class_members[i];
1095 if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001096 {
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001097 if (cl_ret != NULL)
1098 *cl_ret = cl;
1099 return i;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001100 }
1101 }
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001102 return -1;
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001103}
1104
1105/*
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001106 * Make a copy of an object.
1107 */
1108 void
1109copy_object(typval_T *from, typval_T *to)
1110{
1111 *to = *from;
1112 if (to->vval.v_object != NULL)
1113 ++to->vval.v_object->obj_refcount;
1114}
1115
1116/*
1117 * Free an object.
1118 */
1119 static void
1120object_clear(object_T *obj)
1121{
1122 class_T *cl = obj->obj_class;
1123
1124 // the member values are just after the object structure
1125 typval_T *tv = (typval_T *)(obj + 1);
1126 for (int i = 0; i < cl->class_obj_member_count; ++i)
1127 clear_tv(tv + i);
1128
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001129 // Remove from the list headed by "first_object".
1130 object_cleared(obj);
1131
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001132 vim_free(obj);
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001133 class_unref(cl);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001134}
1135
1136/*
1137 * Unreference an object.
1138 */
1139 void
1140object_unref(object_T *obj)
1141{
1142 if (obj != NULL && --obj->obj_refcount <= 0)
1143 object_clear(obj);
1144}
1145
1146/*
1147 * Make a copy of a class.
1148 */
1149 void
1150copy_class(typval_T *from, typval_T *to)
1151{
1152 *to = *from;
1153 if (to->vval.v_class != NULL)
1154 ++to->vval.v_class->class_refcount;
1155}
1156
1157/*
1158 * Unreference a class. Free it when the reference count goes down to zero.
1159 */
1160 void
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001161class_unref(class_T *cl)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001162{
Bram Moolenaard505d172022-12-18 21:42:55 +00001163 if (cl != NULL && --cl->class_refcount <= 0 && cl->class_name != NULL)
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001164 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001165 // Freeing what the class contains may recursively come back here.
1166 // Clear "class_name" first, if it is NULL the class does not need to
1167 // be freed.
1168 VIM_CLEAR(cl->class_name);
1169
Bram Moolenaar94674f22023-01-06 18:42:20 +00001170 for (int i = 0; i < cl->class_interface_count; ++i)
1171 vim_free(((char_u **)cl->class_interfaces)[i]);
1172 vim_free(cl->class_interfaces);
1173
Bram Moolenaard505d172022-12-18 21:42:55 +00001174 for (int i = 0; i < cl->class_class_member_count; ++i)
1175 {
1176 ocmember_T *m = &cl->class_class_members[i];
1177 vim_free(m->ocm_name);
1178 vim_free(m->ocm_init);
1179 if (cl->class_members_tv != NULL)
1180 clear_tv(&cl->class_members_tv[i]);
1181 }
1182 vim_free(cl->class_class_members);
1183 vim_free(cl->class_members_tv);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001184
1185 for (int i = 0; i < cl->class_obj_member_count; ++i)
1186 {
Bram Moolenaard505d172022-12-18 21:42:55 +00001187 ocmember_T *m = &cl->class_obj_members[i];
1188 vim_free(m->ocm_name);
1189 vim_free(m->ocm_init);
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001190 }
1191 vim_free(cl->class_obj_members);
1192
Bram Moolenaarec8b74f2023-01-01 14:11:27 +00001193 for (int i = 0; i < cl->class_class_function_count; ++i)
1194 {
1195 ufunc_T *uf = cl->class_class_functions[i];
1196 func_clear_free(uf, FALSE);
1197 }
1198 vim_free(cl->class_class_functions);
1199
Bram Moolenaarffdaca92022-12-09 21:41:48 +00001200 for (int i = 0; i < cl->class_obj_method_count; ++i)
1201 {
1202 ufunc_T *uf = cl->class_obj_methods[i];
1203 func_clear_free(uf, FALSE);
1204 }
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001205 vim_free(cl->class_obj_methods);
1206
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001207 clear_type_list(&cl->class_type_list);
1208
1209 vim_free(cl);
1210 }
1211}
1212
Bram Moolenaard28d7b92022-12-08 20:42:00 +00001213static object_T *first_object = NULL;
1214
1215/*
1216 * Call this function when an object has been created. It will be added to the
1217 * list headed by "first_object".
1218 */
1219 void
1220object_created(object_T *obj)
1221{
1222 if (first_object != NULL)
1223 {
1224 obj->obj_next_used = first_object;
1225 first_object->obj_prev_used = obj;
1226 }
1227 first_object = obj;
1228}
1229
1230/*
1231 * Call this function when an object has been cleared and is about to be freed.
1232 * It is removed from the list headed by "first_object".
1233 */
1234 void
1235object_cleared(object_T *obj)
1236{
1237 if (obj->obj_next_used != NULL)
1238 obj->obj_next_used->obj_prev_used = obj->obj_prev_used;
1239 if (obj->obj_prev_used != NULL)
1240 obj->obj_prev_used->obj_next_used = obj->obj_next_used;
1241 else if (first_object == obj)
1242 first_object = obj->obj_next_used;
1243}
1244
1245/*
1246 * Go through the list of all objects and free items without "copyID".
1247 */
1248 int
1249object_free_nonref(int copyID)
1250{
1251 int did_free = FALSE;
1252 object_T *next_obj;
1253
1254 for (object_T *obj = first_object; obj != NULL; obj = next_obj)
1255 {
1256 next_obj = obj->obj_next_used;
1257 if ((obj->obj_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
1258 {
1259 // Free the object and items it contains.
1260 object_clear(obj);
1261 did_free = TRUE;
1262 }
1263 }
1264
1265 return did_free;
1266}
1267
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00001268
1269#endif // FEAT_EVAL