Mercurial > vim
comparison src/vim9class.c @ 31653:ec76f9d2319e v9.0.1159
patch 9.0.1159: extends argument for class not implemented yet
Commit: https://github.com/vim/vim/commit/8367716a6e9589d61a771e6c329da05c9b55e61a
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Jan 8 19:54:10 2023 +0000
patch 9.0.1159: extends argument for class not implemented yet
Problem: Extends argument for class not implemented yet.
Solution: Basic implementation of "extends".
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 08 Jan 2023 21:00:05 +0100 |
parents | 520857d1fda7 |
children | 2f1af1b2f82d |
comparison
equal
deleted
inserted
replaced
31652:db9e6699d7b3 | 31653:ec76f9d2319e |
---|---|
158 } | 158 } |
159 | 159 |
160 /* | 160 /* |
161 * Move the class or object members found while parsing a class into the class. | 161 * Move the class or object members found while parsing a class into the class. |
162 * "gap" contains the found members. | 162 * "gap" contains the found members. |
163 * "parent_members" points to the members in the parent class (if any) | |
164 * "parent_count" is the number of members in the parent class | |
163 * "members" will be set to the newly allocated array of members and | 165 * "members" will be set to the newly allocated array of members and |
164 * "member_count" set to the number of members. | 166 * "member_count" set to the number of members. |
165 * Returns OK or FAIL. | 167 * Returns OK or FAIL. |
166 */ | 168 */ |
167 static int | 169 static int |
168 add_members_to_class( | 170 add_members_to_class( |
169 garray_T *gap, | 171 garray_T *gap, |
172 ocmember_T *parent_members, | |
173 int parent_count, | |
170 ocmember_T **members, | 174 ocmember_T **members, |
171 int *member_count) | 175 int *member_count) |
172 { | 176 { |
173 *member_count = gap->ga_len; | 177 *member_count = parent_count + gap->ga_len; |
174 *members = gap->ga_len == 0 ? NULL : ALLOC_MULT(ocmember_T, gap->ga_len); | 178 *members = *member_count == 0 ? NULL |
175 if (gap->ga_len > 0 && *members == NULL) | 179 : ALLOC_MULT(ocmember_T, *member_count); |
180 if (*member_count > 0 && *members == NULL) | |
176 return FAIL; | 181 return FAIL; |
182 for (int i = 0; i < parent_count; ++i) | |
183 { | |
184 // parent members need to be copied | |
185 *members[i] = parent_members[i]; | |
186 members[i]->ocm_name = vim_strsave(members[i]->ocm_name); | |
187 if (members[i]->ocm_init != NULL) | |
188 members[i]->ocm_init = vim_strsave(members[i]->ocm_init); | |
189 } | |
177 if (gap->ga_len > 0) | 190 if (gap->ga_len > 0) |
178 mch_memmove(*members, gap->ga_data, sizeof(ocmember_T) * gap->ga_len); | 191 // new members are moved |
192 mch_memmove(*members + parent_count, | |
193 gap->ga_data, sizeof(ocmember_T) * gap->ga_len); | |
179 VIM_CLEAR(gap->ga_data); | 194 VIM_CLEAR(gap->ga_data); |
180 return OK; | 195 return OK; |
181 } | 196 } |
182 | 197 |
183 /* | 198 /* |
231 | 246 |
232 // TODO: | 247 // TODO: |
233 // generics: <Tkey, Tentry> | 248 // generics: <Tkey, Tentry> |
234 // handle "is_export" if it is set | 249 // handle "is_export" if it is set |
235 | 250 |
251 // Name for "extends BaseClass" | |
252 char_u *extends = NULL; | |
253 | |
236 // Names for "implements SomeInterface" | 254 // Names for "implements SomeInterface" |
237 garray_T ga_impl; | 255 garray_T ga_impl; |
238 ga_init2(&ga_impl, sizeof(char_u *), 5); | 256 ga_init2(&ga_impl, sizeof(char_u *), 5); |
239 | 257 |
240 arg = skipwhite(name_end); | 258 arg = skipwhite(name_end); |
241 while (*arg != NUL && *arg != '#' && *arg != '\n') | 259 while (*arg != NUL && *arg != '#' && *arg != '\n') |
242 { | 260 { |
243 // TODO: | 261 // TODO: |
244 // extends SomeClass | |
245 // specifies SomeInterface | 262 // specifies SomeInterface |
246 if (STRNCMP(arg, "implements", 10) == 0 && IS_WHITE_OR_NUL(arg[10])) | 263 if (STRNCMP(arg, "extends", 7) == 0 && IS_WHITE_OR_NUL(arg[7])) |
264 { | |
265 if (extends != NULL) | |
266 { | |
267 emsg(_(e_duplicate_extends)); | |
268 goto early_ret; | |
269 } | |
270 arg = skipwhite(arg + 7); | |
271 char_u *end = find_name_end(arg, NULL, NULL, FNE_CHECK_START); | |
272 if (!IS_WHITE_OR_NUL(*end)) | |
273 { | |
274 semsg(_(e_white_space_required_after_name_str), arg); | |
275 goto early_ret; | |
276 } | |
277 extends = vim_strnsave(arg, end - arg); | |
278 if (extends == NULL) | |
279 goto early_ret; | |
280 | |
281 arg = skipwhite(end + 1); | |
282 } | |
283 else if (STRNCMP(arg, "implements", 10) == 0 | |
284 && IS_WHITE_OR_NUL(arg[10])) | |
247 { | 285 { |
248 if (ga_impl.ga_len > 0) | 286 if (ga_impl.ga_len > 0) |
249 { | 287 { |
250 emsg(_(e_duplicate_implements)); | 288 emsg(_(e_duplicate_implements)); |
251 goto early_ret; | 289 goto early_ret; |
287 } | 325 } |
288 else | 326 else |
289 { | 327 { |
290 semsg(_(e_trailing_characters_str), arg); | 328 semsg(_(e_trailing_characters_str), arg); |
291 early_ret: | 329 early_ret: |
330 vim_free(extends); | |
292 ga_clear_strings(&ga_impl); | 331 ga_clear_strings(&ga_impl); |
293 return; | 332 return; |
294 } | 333 } |
295 } | 334 } |
296 | 335 |
494 break; | 533 break; |
495 } | 534 } |
496 } | 535 } |
497 vim_free(theline); | 536 vim_free(theline); |
498 | 537 |
499 // Check a few things before defining the class. | 538 class_T *extends_cl = NULL; // class from "extends" argument |
539 | |
540 /* | |
541 * Check a few things before defining the class. | |
542 */ | |
543 | |
544 // Check the "extends" class is valid. | |
545 if (success && extends != NULL) | |
546 { | |
547 typval_T tv; | |
548 tv.v_type = VAR_UNKNOWN; | |
549 if (eval_variable(extends, 0, 0, &tv, NULL, EVAL_VAR_IMPORT) == FAIL) | |
550 { | |
551 semsg(_(e_class_name_not_found_str), extends); | |
552 success = FALSE; | |
553 } | |
554 else | |
555 { | |
556 if (tv.v_type != VAR_CLASS | |
557 || tv.vval.v_class == NULL | |
558 || (tv.vval.v_class->class_flags & CLASS_INTERFACE) != 0) | |
559 { | |
560 semsg(_(e_cannot_extend_str), extends); | |
561 success = FALSE; | |
562 } | |
563 else | |
564 { | |
565 extends_cl = tv.vval.v_class; | |
566 ++extends_cl->class_refcount; | |
567 } | |
568 clear_tv(&tv); | |
569 } | |
570 } | |
571 VIM_CLEAR(extends); | |
572 | |
573 // Check all "implements" entries are valid. | |
500 if (success && ga_impl.ga_len > 0) | 574 if (success && ga_impl.ga_len > 0) |
501 { | 575 { |
502 // Check all "implements" entries are valid and correct. | |
503 for (int i = 0; i < ga_impl.ga_len && success; ++i) | 576 for (int i = 0; i < ga_impl.ga_len && success; ++i) |
504 { | 577 { |
505 char_u *impl = ((char_u **)ga_impl.ga_data)[i]; | 578 char_u *impl = ((char_u **)ga_impl.ga_data)[i]; |
506 typval_T tv; | 579 typval_T tv; |
507 tv.v_type = VAR_UNKNOWN; | 580 tv.v_type = VAR_UNKNOWN; |
508 if (eval_variable(impl, 0, 0, &tv, NULL, | 581 if (eval_variable(impl, 0, 0, &tv, NULL, EVAL_VAR_IMPORT) == FAIL) |
509 EVAL_VAR_VERBOSE + EVAL_VAR_IMPORT) == FAIL) | |
510 { | 582 { |
511 semsg(_(e_interface_name_not_found_str), impl); | 583 semsg(_(e_interface_name_not_found_str), impl); |
512 success = FALSE; | 584 success = FALSE; |
513 break; | 585 break; |
514 } | 586 } |
618 cl->class_refcount = 1; | 690 cl->class_refcount = 1; |
619 cl->class_name = vim_strnsave(name_start, name_end - name_start); | 691 cl->class_name = vim_strnsave(name_start, name_end - name_start); |
620 if (cl->class_name == NULL) | 692 if (cl->class_name == NULL) |
621 goto cleanup; | 693 goto cleanup; |
622 | 694 |
695 cl->class_extends = extends_cl; | |
696 | |
623 if (ga_impl.ga_len > 0) | 697 if (ga_impl.ga_len > 0) |
624 { | 698 { |
625 // Move the "implements" names into the class. | 699 // Move the "implements" names into the class. |
626 cl->class_interface_count = ga_impl.ga_len; | 700 cl->class_interface_count = ga_impl.ga_len; |
627 cl->class_interfaces = ALLOC_MULT(char_u *, ga_impl.ga_len); | 701 cl->class_interfaces = ALLOC_MULT(char_u *, ga_impl.ga_len); |
633 ga_impl.ga_len = 0; | 707 ga_impl.ga_len = 0; |
634 } | 708 } |
635 | 709 |
636 // Add class and object members to "cl". | 710 // Add class and object members to "cl". |
637 if (add_members_to_class(&classmembers, | 711 if (add_members_to_class(&classmembers, |
638 &cl->class_class_members, | 712 extends_cl == NULL ? NULL |
639 &cl->class_class_member_count) == FAIL | 713 : extends_cl->class_class_members, |
714 extends_cl == NULL ? 0 | |
715 : extends_cl->class_class_member_count, | |
716 &cl->class_class_members, | |
717 &cl->class_class_member_count) == FAIL | |
640 || add_members_to_class(&objmembers, | 718 || add_members_to_class(&objmembers, |
641 &cl->class_obj_members, | 719 extends_cl == NULL ? NULL |
642 &cl->class_obj_member_count) == FAIL) | 720 : extends_cl->class_obj_members, |
721 extends_cl == NULL ? 0 | |
722 : extends_cl->class_obj_member_count, | |
723 &cl->class_obj_members, | |
724 &cl->class_obj_member_count) == FAIL) | |
643 goto cleanup; | 725 goto cleanup; |
644 | 726 |
645 if (is_class && cl->class_class_member_count > 0) | 727 if (is_class && cl->class_class_member_count > 0) |
646 { | 728 { |
647 // Allocate a typval for each class member and initialize it. | 729 // Allocate a typval for each class member and initialize it. |
733 int *fcount = loop == 1 ? &cl->class_class_function_count | 815 int *fcount = loop == 1 ? &cl->class_class_function_count |
734 : &cl->class_obj_method_count; | 816 : &cl->class_obj_method_count; |
735 ufunc_T ***fup = loop == 1 ? &cl->class_class_functions | 817 ufunc_T ***fup = loop == 1 ? &cl->class_class_functions |
736 : &cl->class_obj_methods; | 818 : &cl->class_obj_methods; |
737 | 819 |
738 *fcount = gap->ga_len; | 820 int parent_count = 0; |
739 if (gap->ga_len == 0) | 821 if (extends_cl != NULL) |
822 // Include functions from the parent. | |
823 parent_count = loop == 1 | |
824 ? extends_cl->class_class_function_count | |
825 : extends_cl->class_obj_method_count; | |
826 | |
827 *fcount = parent_count + gap->ga_len; | |
828 if (*fcount == 0) | |
740 { | 829 { |
741 *fup = NULL; | 830 *fup = NULL; |
742 continue; | 831 continue; |
743 } | 832 } |
744 *fup = ALLOC_MULT(ufunc_T *, gap->ga_len); | 833 *fup = ALLOC_MULT(ufunc_T *, *fcount); |
745 if (*fup == NULL) | 834 if (*fup == NULL) |
746 goto cleanup; | 835 goto cleanup; |
747 mch_memmove(*fup, gap->ga_data, sizeof(ufunc_T *) * gap->ga_len); | 836 |
837 int skipped = 0; | |
838 for (int i = 0; i < parent_count; ++i) | |
839 { | |
840 // Copy functions from the parent. Can't use the same | |
841 // function, because "uf_class" is different and compilation | |
842 // will have a different result. | |
843 // Skip "new" functions. TODO: not all of them. | |
844 if (loop == 1 && STRNCMP( | |
845 extends_cl->class_class_functions[i]->uf_name, | |
846 "new", 3) == 0) | |
847 ++skipped; | |
848 else | |
849 *fup[i - skipped] = copy_function((loop == 1 | |
850 ? extends_cl->class_class_functions | |
851 : extends_cl->class_obj_methods)[i]); | |
852 } | |
853 | |
854 mch_memmove(*fup + parent_count - skipped, gap->ga_data, | |
855 sizeof(ufunc_T *) * gap->ga_len); | |
748 vim_free(gap->ga_data); | 856 vim_free(gap->ga_data); |
749 | 857 *fcount -= skipped; |
750 // Set the class pointer on all the object methods. | 858 |
751 for (int i = 0; i < gap->ga_len; ++i) | 859 // Set the class pointer on all the functions and object methods. |
860 for (int i = 0; i < *fcount; ++i) | |
752 { | 861 { |
753 ufunc_T *fp = (*fup)[i]; | 862 ufunc_T *fp = (*fup)[i]; |
754 fp->uf_class = cl; | 863 fp->uf_class = cl; |
755 if (loop == 2) | 864 if (loop == 2) |
756 fp->uf_flags |= FC_OBJECT; | 865 fp->uf_flags |= FC_OBJECT; |
784 vim_free(cl->class_obj_members); | 893 vim_free(cl->class_obj_members); |
785 vim_free(cl->class_obj_methods); | 894 vim_free(cl->class_obj_methods); |
786 vim_free(cl); | 895 vim_free(cl); |
787 } | 896 } |
788 | 897 |
898 vim_free(extends); | |
899 class_unref(extends_cl); | |
789 ga_clear_strings(&ga_impl); | 900 ga_clear_strings(&ga_impl); |
790 | 901 |
791 for (int round = 1; round <= 2; ++round) | 902 for (int round = 1; round <= 2; ++round) |
792 { | 903 { |
793 garray_T *gap = round == 1 ? &classmembers : &objmembers; | 904 garray_T *gap = round == 1 ? &classmembers : &objmembers; |
1165 // Freeing what the class contains may recursively come back here. | 1276 // 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 | 1277 // Clear "class_name" first, if it is NULL the class does not need to |
1167 // be freed. | 1278 // be freed. |
1168 VIM_CLEAR(cl->class_name); | 1279 VIM_CLEAR(cl->class_name); |
1169 | 1280 |
1281 class_unref(cl->class_extends); | |
1282 | |
1170 for (int i = 0; i < cl->class_interface_count; ++i) | 1283 for (int i = 0; i < cl->class_interface_count; ++i) |
1171 vim_free(((char_u **)cl->class_interfaces)[i]); | 1284 vim_free(((char_u **)cl->class_interfaces)[i]); |
1172 vim_free(cl->class_interfaces); | 1285 vim_free(cl->class_interfaces); |
1173 | 1286 |
1174 for (int i = 0; i < cl->class_class_member_count; ++i) | 1287 for (int i = 0; i < cl->class_class_member_count; ++i) |