Mercurial > vim
comparison src/vim9class.c @ 33506:f61713271934 v9.0.2002
patch 9.0.2002: Vim9: need cleanup of class related interface code
Commit: https://github.com/vim/vim/commit/b852305dbf42f1206ecc6ae414fc200235fe2963
Author: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Sun Oct 8 19:07:39 2023 +0200
patch 9.0.2002: Vim9: need cleanup of class related interface code
Problem: Vim9: need cleanup of class related interface code
Solution: Remove the unused class variable and class method related code
for interfaces.
Remove unused class variable and class method related code for
interfaces.
Refactor the code.
Optimize the object/class member double lookup in compile_lhs().
Change unused global functions to static functions.
closes: #13302
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sun, 08 Oct 2023 19:15:06 +0200 |
parents | bff8ac203a22 |
children | c8bd88bdb630 |
comparison
equal
deleted
inserted
replaced
33505:398e729a5cd9 | 33506:f61713271934 |
---|---|
553 */ | 553 */ |
554 static int | 554 static int |
555 intf_variable_present( | 555 intf_variable_present( |
556 char_u *intf_class_name, | 556 char_u *intf_class_name, |
557 ocmember_T *if_var, | 557 ocmember_T *if_var, |
558 int is_class_var, | |
559 ocmember_T *cl_mt, | 558 ocmember_T *cl_mt, |
560 int cl_member_count, | 559 int cl_member_count, |
561 class_T *extends_cl) | 560 class_T *extends_cl) |
562 { | 561 { |
563 int variable_present = FALSE; | 562 int variable_present = FALSE; |
598 break; | 597 break; |
599 } | 598 } |
600 | 599 |
601 if (!variable_present && extends_cl != NULL) | 600 if (!variable_present && extends_cl != NULL) |
602 { | 601 { |
603 int ext_cl_count = is_class_var | 602 int ext_cl_count = extends_cl->class_obj_member_count; |
604 ? extends_cl->class_class_member_count | 603 ocmember_T *ext_cl_mt = extends_cl->class_obj_members; |
605 : extends_cl->class_obj_member_count; | |
606 ocmember_T *ext_cl_mt = is_class_var | |
607 ? extends_cl->class_class_members | |
608 : extends_cl->class_obj_members; | |
609 return intf_variable_present(intf_class_name, if_var, | 604 return intf_variable_present(intf_class_name, if_var, |
610 is_class_var, ext_cl_mt, | 605 ext_cl_mt, ext_cl_count, |
611 ext_cl_count, | |
612 extends_cl->class_extends); | 606 extends_cl->class_extends); |
613 } | 607 } |
614 | 608 |
615 return variable_present; | 609 return variable_present; |
616 } | 610 } |
617 | 611 |
618 /* | 612 /* |
619 * Check the variables of the interface class "ifcl" match the class variables | 613 * Check the variables of the interface class "ifcl" match object variables |
620 * ("classmembers_gap") and object variables ("objmembers_gap") of a class. | 614 * ("objmembers_gap") of a class. |
621 * Returns TRUE if the class and object variables names are valid. | 615 * Returns TRUE if the object variables names are valid. |
622 */ | 616 */ |
623 static int | 617 static int |
624 validate_interface_variables( | 618 validate_interface_variables( |
625 char_u *intf_class_name, | 619 char_u *intf_class_name, |
626 class_T *ifcl, | 620 class_T *ifcl, |
627 garray_T *classmembers_gap, | |
628 garray_T *objmembers_gap, | 621 garray_T *objmembers_gap, |
629 class_T *extends_cl) | 622 class_T *extends_cl) |
630 { | 623 { |
631 for (int loop = 1; loop <= 2; ++loop) | 624 int if_count = ifcl->class_obj_member_count; |
632 { | 625 if (if_count == 0) |
633 // loop == 1: check class variables | 626 return TRUE; |
634 // loop == 2: check object variables | 627 |
635 int is_class_var = (loop == 1); | 628 ocmember_T *if_ms = ifcl->class_obj_members; |
636 int if_count = is_class_var ? ifcl->class_class_member_count | 629 ocmember_T *cl_ms = (ocmember_T *)(objmembers_gap->ga_data); |
637 : ifcl->class_obj_member_count; | 630 int cl_count = objmembers_gap->ga_len; |
638 if (if_count == 0) | 631 for (int if_i = 0; if_i < if_count; ++if_i) |
639 continue; | 632 { |
640 ocmember_T *if_ms = is_class_var ? ifcl->class_class_members | 633 if (!intf_variable_present(intf_class_name, &if_ms[if_i], cl_ms, |
641 : ifcl->class_obj_members; | 634 cl_count, extends_cl)) |
642 ocmember_T *cl_ms = (ocmember_T *)(is_class_var | 635 { |
643 ? classmembers_gap->ga_data | 636 semsg(_(e_variable_str_of_interface_str_not_implemented), |
644 : objmembers_gap->ga_data); | 637 if_ms[if_i].ocm_name, intf_class_name); |
645 int cl_count = is_class_var ? classmembers_gap->ga_len | 638 return FALSE; |
646 : objmembers_gap->ga_len; | |
647 for (int if_i = 0; if_i < if_count; ++if_i) | |
648 { | |
649 if (!intf_variable_present(intf_class_name, &if_ms[if_i], | |
650 is_class_var, cl_ms, cl_count, extends_cl)) | |
651 { | |
652 semsg(_(e_variable_str_of_interface_str_not_implemented), | |
653 if_ms[if_i].ocm_name, intf_class_name); | |
654 return FALSE; | |
655 } | |
656 } | 639 } |
657 } | 640 } |
658 | 641 |
659 return TRUE; | 642 return TRUE; |
660 } | 643 } |
683 * in "extends_cl". For a class method, 'is_class_method' is TRUE. | 666 * in "extends_cl". For a class method, 'is_class_method' is TRUE. |
684 */ | 667 */ |
685 static int | 668 static int |
686 intf_method_present( | 669 intf_method_present( |
687 ufunc_T *if_ufunc, | 670 ufunc_T *if_ufunc, |
688 int is_class_method, | |
689 ufunc_T **cl_fp, | 671 ufunc_T **cl_fp, |
690 int cl_count, | 672 int cl_count, |
691 class_T *extends_cl) | 673 class_T *extends_cl) |
692 { | 674 { |
693 int method_present = FALSE; | 675 int method_present = FALSE; |
705 } | 687 } |
706 } | 688 } |
707 | 689 |
708 if (!method_present && extends_cl != NULL) | 690 if (!method_present && extends_cl != NULL) |
709 { | 691 { |
710 ufunc_T **ext_cl_fp = (ufunc_T **)(is_class_method | 692 ufunc_T **ext_cl_fp = (ufunc_T **)(extends_cl->class_obj_methods); |
711 ? extends_cl->class_class_functions | 693 int ext_cl_count = extends_cl->class_obj_method_count; |
712 : extends_cl->class_obj_methods); | 694 return intf_method_present(if_ufunc, ext_cl_fp, ext_cl_count, |
713 int ext_cl_count = is_class_method | 695 extends_cl->class_extends); |
714 ? extends_cl->class_class_function_count | |
715 : extends_cl->class_obj_method_count; | |
716 return intf_method_present(if_ufunc, is_class_method, ext_cl_fp, | |
717 ext_cl_count, | |
718 extends_cl->class_extends); | |
719 } | 696 } |
720 | 697 |
721 return method_present; | 698 return method_present; |
722 } | 699 } |
723 | 700 |
731 */ | 708 */ |
732 static int | 709 static int |
733 validate_interface_methods( | 710 validate_interface_methods( |
734 char_u *intf_class_name, | 711 char_u *intf_class_name, |
735 class_T *ifcl, | 712 class_T *ifcl, |
736 garray_T *classfunctions_gap, | |
737 garray_T *objmethods_gap, | 713 garray_T *objmethods_gap, |
738 class_T *extends_cl) | 714 class_T *extends_cl) |
739 { | 715 { |
740 for (int loop = 1; loop <= 2; ++loop) | 716 int if_count = ifcl->class_obj_method_count; |
741 { | 717 if (if_count == 0) |
742 // loop == 1: check class methods | 718 return TRUE; |
743 // loop == 2: check object methods | 719 |
744 int is_class_method = (loop == 1); | 720 ufunc_T **if_fp = ifcl->class_obj_methods; |
745 int if_count = is_class_method ? ifcl->class_class_function_count | 721 ufunc_T **cl_fp = (ufunc_T **)(objmethods_gap->ga_data); |
746 : ifcl->class_obj_method_count; | 722 int cl_count = objmethods_gap->ga_len; |
747 if (if_count == 0) | 723 for (int if_i = 0; if_i < if_count; ++if_i) |
748 continue; | 724 { |
749 ufunc_T **if_fp = is_class_method ? ifcl->class_class_functions | 725 char_u *if_name = if_fp[if_i]->uf_name; |
750 : ifcl->class_obj_methods; | 726 |
751 ufunc_T **cl_fp = (ufunc_T **)(is_class_method | 727 if (!intf_method_present(if_fp[if_i], cl_fp, cl_count, extends_cl)) |
752 ? classfunctions_gap->ga_data | 728 { |
753 : objmethods_gap->ga_data); | 729 semsg(_(e_method_str_of_interface_str_not_implemented), |
754 int cl_count = is_class_method ? classfunctions_gap->ga_len | 730 if_name, intf_class_name); |
755 : objmethods_gap->ga_len; | 731 return FALSE; |
756 for (int if_i = 0; if_i < if_count; ++if_i) | |
757 { | |
758 char_u *if_name = if_fp[if_i]->uf_name; | |
759 | |
760 if (!intf_method_present(if_fp[if_i], is_class_method, cl_fp, | |
761 cl_count, extends_cl)) | |
762 { | |
763 semsg(_(e_method_str_of_interface_str_not_implemented), | |
764 if_name, intf_class_name); | |
765 return FALSE; | |
766 } | |
767 } | 732 } |
768 } | 733 } |
769 | 734 |
770 return TRUE; | 735 return TRUE; |
771 } | 736 } |
779 */ | 744 */ |
780 static int | 745 static int |
781 validate_implements_classes( | 746 validate_implements_classes( |
782 garray_T *impl_gap, | 747 garray_T *impl_gap, |
783 class_T **intf_classes, | 748 class_T **intf_classes, |
784 garray_T *classfunctions_gap, | |
785 garray_T *classmembers_gap, | |
786 garray_T *objmethods_gap, | 749 garray_T *objmethods_gap, |
787 garray_T *objmembers_gap, | 750 garray_T *objmembers_gap, |
788 class_T *extends_cl) | 751 class_T *extends_cl) |
789 { | 752 { |
790 int success = TRUE; | 753 int success = TRUE; |
814 class_T *ifcl = tv.vval.v_class; | 777 class_T *ifcl = tv.vval.v_class; |
815 intf_classes[i] = ifcl; | 778 intf_classes[i] = ifcl; |
816 ++ifcl->class_refcount; | 779 ++ifcl->class_refcount; |
817 | 780 |
818 // check the variables of the interface match the members of the class | 781 // check the variables of the interface match the members of the class |
819 success = validate_interface_variables(impl, ifcl, classmembers_gap, | 782 success = validate_interface_variables(impl, ifcl, objmembers_gap, |
820 objmembers_gap, extends_cl); | 783 extends_cl); |
821 | 784 |
822 // check the functions/methods of the interface match the | 785 // check the functions/methods of the interface match the |
823 // functions/methods of the class | 786 // functions/methods of the class |
824 if (success) | 787 if (success) |
825 success = validate_interface_methods(impl, ifcl, | 788 success = validate_interface_methods(impl, ifcl, objmethods_gap, |
826 classfunctions_gap, objmethods_gap, | 789 extends_cl); |
827 extends_cl); | |
828 clear_tv(&tv); | 790 clear_tv(&tv); |
829 } | 791 } |
830 | 792 |
831 return success; | 793 return success; |
832 } | 794 } |
1871 if (success && ga_impl.ga_len > 0) | 1833 if (success && ga_impl.ga_len > 0) |
1872 { | 1834 { |
1873 intf_classes = ALLOC_CLEAR_MULT(class_T *, ga_impl.ga_len); | 1835 intf_classes = ALLOC_CLEAR_MULT(class_T *, ga_impl.ga_len); |
1874 | 1836 |
1875 success = validate_implements_classes(&ga_impl, intf_classes, | 1837 success = validate_implements_classes(&ga_impl, intf_classes, |
1876 &classfunctions, &classmembers, | 1838 &objmethods, &objmembers, extends_cl); |
1877 &objmethods, &objmembers, | |
1878 extends_cl); | |
1879 } | 1839 } |
1880 | 1840 |
1881 // Check no function argument name is used as a class member. | 1841 // Check no function argument name is used as a class member. |
1882 if (success) | 1842 if (success) |
1883 success = check_func_arg_names(&classfunctions, &objmethods, | 1843 success = check_func_arg_names(&classfunctions, &objmethods, |
2170 emsg_var_cl_define(e_cannot_access_private_variable_str, | 2130 emsg_var_cl_define(e_cannot_access_private_variable_str, |
2171 m->ocm_name, 0, cl); | 2131 m->ocm_name, 0, cl); |
2172 return FAIL; | 2132 return FAIL; |
2173 } | 2133 } |
2174 | 2134 |
2175 // The object only contains a pointer to the class, the member | |
2176 // values array follows right after that. | |
2177 object_T *obj = rettv->vval.v_object; | |
2178 if (is_object) | 2135 if (is_object) |
2179 { | 2136 { |
2137 // The object only contains a pointer to the class, the member values | |
2138 // array follows right after that. | |
2139 object_T *obj = rettv->vval.v_object; | |
2180 typval_T *tv = (typval_T *)(obj + 1) + m_idx; | 2140 typval_T *tv = (typval_T *)(obj + 1) + m_idx; |
2181 copy_tv(tv, rettv); | 2141 copy_tv(tv, rettv); |
2142 object_unref(obj); | |
2182 } | 2143 } |
2183 else | 2144 else |
2145 { | |
2184 copy_tv(&cl->class_members_tv[m_idx], rettv); | 2146 copy_tv(&cl->class_members_tv[m_idx], rettv); |
2185 | 2147 class_unref(cl); |
2186 object_unref(obj); | 2148 } |
2149 | |
2150 return OK; | |
2151 } | |
2152 | |
2153 /* | |
2154 * Call an object or class method "name" in class "cl". The method return | |
2155 * value is returned in "rettv". | |
2156 */ | |
2157 static int | |
2158 call_oc_method( | |
2159 class_T *cl, | |
2160 char_u *name, | |
2161 size_t len, | |
2162 char_u *name_end, | |
2163 evalarg_T *evalarg, | |
2164 char_u **arg, | |
2165 typval_T *rettv) | |
2166 { | |
2167 ufunc_T *fp; | |
2168 typval_T argvars[MAX_FUNC_ARGS + 1]; | |
2169 int argcount = 0; | |
2170 | |
2171 fp = method_lookup(cl, rettv->v_type, name, len, NULL); | |
2172 if (fp == NULL) | |
2173 { | |
2174 method_not_found_msg(cl, rettv->v_type, name, len); | |
2175 return FAIL; | |
2176 } | |
2177 | |
2178 if (*fp->uf_name == '_') | |
2179 { | |
2180 // Cannot access a private method outside of a class | |
2181 semsg(_(e_cannot_access_private_method_str), fp->uf_name); | |
2182 return FAIL; | |
2183 } | |
2184 | |
2185 char_u *argp = name_end; | |
2186 int ret = get_func_arguments(&argp, evalarg, 0, argvars, &argcount); | |
2187 if (ret == FAIL) | |
2188 return FAIL; | |
2189 | |
2190 funcexe_T funcexe; | |
2191 CLEAR_FIELD(funcexe); | |
2192 funcexe.fe_evaluate = TRUE; | |
2193 if (rettv->v_type == VAR_OBJECT) | |
2194 { | |
2195 funcexe.fe_object = rettv->vval.v_object; | |
2196 ++funcexe.fe_object->obj_refcount; | |
2197 } | |
2198 | |
2199 // Clear the class or object after calling the function, in | |
2200 // case the refcount is one. | |
2201 typval_T tv_tofree = *rettv; | |
2202 rettv->v_type = VAR_UNKNOWN; | |
2203 | |
2204 // Call the user function. Result goes into rettv; | |
2205 int error = call_user_func_check(fp, argcount, argvars, rettv, &funcexe, | |
2206 NULL); | |
2207 | |
2208 // Clear the previous rettv and the arguments. | |
2209 clear_tv(&tv_tofree); | |
2210 for (int idx = 0; idx < argcount; ++idx) | |
2211 clear_tv(&argvars[idx]); | |
2212 | |
2213 if (error != FCERR_NONE) | |
2214 { | |
2215 user_func_error(error, printable_func_name(fp), funcexe.fe_found_var); | |
2216 return FAIL; | |
2217 } | |
2218 *arg = argp; | |
2187 | 2219 |
2188 return OK; | 2220 return OK; |
2189 } | 2221 } |
2190 | 2222 |
2191 /* | 2223 /* |
2240 emsg(_(e_incomplete_type)); | 2272 emsg(_(e_incomplete_type)); |
2241 return FAIL; | 2273 return FAIL; |
2242 } | 2274 } |
2243 | 2275 |
2244 if (*name_end == '(') | 2276 if (*name_end == '(') |
2245 { | 2277 // Invoke the class or object method |
2246 ufunc_T *fp; | 2278 return call_oc_method(cl, name, len, name_end, evalarg, arg, rettv); |
2247 | 2279 |
2248 fp = method_lookup(cl, rettv->v_type, name, len, NULL); | 2280 else if (rettv->v_type == VAR_OBJECT || rettv->v_type == VAR_CLASS) |
2249 if (fp == NULL) | |
2250 { | |
2251 method_not_found_msg(cl, rettv->v_type, name, len); | |
2252 return FAIL; | |
2253 } | |
2254 | |
2255 typval_T argvars[MAX_FUNC_ARGS + 1]; | |
2256 int argcount = 0; | |
2257 | |
2258 if (*fp->uf_name == '_') | |
2259 { | |
2260 // Cannot access a private method outside of a class | |
2261 semsg(_(e_cannot_access_private_method_str), name); | |
2262 return FAIL; | |
2263 } | |
2264 | |
2265 char_u *argp = name_end; | |
2266 int ret = get_func_arguments(&argp, evalarg, 0, | |
2267 argvars, &argcount); | |
2268 if (ret == FAIL) | |
2269 return FAIL; | |
2270 | |
2271 funcexe_T funcexe; | |
2272 CLEAR_FIELD(funcexe); | |
2273 funcexe.fe_evaluate = TRUE; | |
2274 if (rettv->v_type == VAR_OBJECT) | |
2275 { | |
2276 funcexe.fe_object = rettv->vval.v_object; | |
2277 ++funcexe.fe_object->obj_refcount; | |
2278 } | |
2279 | |
2280 // Clear the class or object after calling the function, in | |
2281 // case the refcount is one. | |
2282 typval_T tv_tofree = *rettv; | |
2283 rettv->v_type = VAR_UNKNOWN; | |
2284 | |
2285 // Call the user function. Result goes into rettv; | |
2286 int error = call_user_func_check(fp, argcount, argvars, | |
2287 rettv, &funcexe, NULL); | |
2288 | |
2289 // Clear the previous rettv and the arguments. | |
2290 clear_tv(&tv_tofree); | |
2291 for (int idx = 0; idx < argcount; ++idx) | |
2292 clear_tv(&argvars[idx]); | |
2293 | |
2294 if (error != FCERR_NONE) | |
2295 { | |
2296 user_func_error(error, printable_func_name(fp), | |
2297 funcexe.fe_found_var); | |
2298 return FAIL; | |
2299 } | |
2300 *arg = argp; | |
2301 return OK; | |
2302 } | |
2303 | |
2304 else if (rettv->v_type == VAR_OBJECT) | |
2305 { | 2281 { |
2306 // Search in the object member variable table and the class member | 2282 // Search in the object member variable table and the class member |
2307 // variable table. | 2283 // variable table. |
2308 if (get_member_tv(cl, TRUE, name, len, rettv) == OK) | 2284 int is_object = rettv->v_type == VAR_OBJECT; |
2285 if (get_member_tv(cl, is_object, name, len, rettv) == OK) | |
2309 { | 2286 { |
2310 *arg = name_end; | 2287 *arg = name_end; |
2311 return OK; | 2288 return OK; |
2312 } | 2289 } |
2313 | 2290 |
2314 if (did_emsg == did_emsg_save) | 2291 if (did_emsg == did_emsg_save) |
2315 member_not_found_msg(cl, VAR_OBJECT, name, len); | 2292 member_not_found_msg(cl, is_object, name, len); |
2316 } | |
2317 | |
2318 else if (rettv->v_type == VAR_CLASS) | |
2319 { | |
2320 int m_idx; | |
2321 | |
2322 // class member | |
2323 ocmember_T *m = class_member_lookup(cl, name, len, &m_idx); | |
2324 if (m == NULL) | |
2325 { | |
2326 member_not_found_msg(cl, VAR_CLASS, name, len); | |
2327 return FAIL; | |
2328 } | |
2329 | |
2330 if (*name == '_') | |
2331 { | |
2332 emsg_var_cl_define(e_cannot_access_private_variable_str, | |
2333 m->ocm_name, 0, cl); | |
2334 return FAIL; | |
2335 } | |
2336 | |
2337 typval_T *tv = &cl->class_members_tv[m_idx]; | |
2338 copy_tv(tv, rettv); | |
2339 class_unref(cl); | |
2340 | |
2341 *arg = name_end; | |
2342 return OK; | |
2343 } | 2293 } |
2344 | 2294 |
2345 return FAIL; | 2295 return FAIL; |
2346 } | 2296 } |
2347 | 2297 |
2431 *idx = ret_idx; | 2381 *idx = ret_idx; |
2432 return ret_m; | 2382 return ret_m; |
2433 } | 2383 } |
2434 | 2384 |
2435 /* | 2385 /* |
2386 * Returns a pointer to the class method "name" in class "cl". | |
2387 * Returns NULL if the method is not found. | |
2388 * The method index is set in "idx". | |
2389 */ | |
2390 static ufunc_T * | |
2391 class_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx) | |
2392 { | |
2393 ufunc_T *ret_fp = NULL; | |
2394 int ret_idx = -1; | |
2395 for (int i = 0; i < cl->class_class_function_count; ++i) | |
2396 { | |
2397 ufunc_T *fp = cl->class_class_functions[i]; | |
2398 char_u *ufname = (char_u *)fp->uf_name; | |
2399 if (STRNCMP(name, ufname, namelen) == 0 && ufname[namelen] == NUL) | |
2400 { | |
2401 ret_fp = fp; | |
2402 ret_idx = i; | |
2403 break; | |
2404 } | |
2405 } | |
2406 if (idx != NULL) | |
2407 *idx = ret_idx; | |
2408 return ret_fp; | |
2409 } | |
2410 | |
2411 /* | |
2436 * Returns the index of class method "name" in the class "cl". | 2412 * Returns the index of class method "name" in the class "cl". |
2437 * Returns -1, if the method is not found. | 2413 * Returns -1, if the method is not found. |
2438 */ | 2414 */ |
2439 int | 2415 int |
2440 class_method_idx(class_T *cl, char_u *name, size_t namelen) | 2416 class_method_idx(class_T *cl, char_u *name, size_t namelen) |
2443 class_method_lookup(cl, name, namelen, &idx); | 2419 class_method_lookup(cl, name, namelen, &idx); |
2444 return idx; | 2420 return idx; |
2445 } | 2421 } |
2446 | 2422 |
2447 /* | 2423 /* |
2448 * Returns a pointer to the class method "name" in class "cl". | |
2449 * Returns NULL if the method is not found. | |
2450 * The method index is set in "idx". | |
2451 */ | |
2452 ufunc_T * | |
2453 class_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx) | |
2454 { | |
2455 ufunc_T *ret_fp = NULL; | |
2456 int ret_idx = -1; | |
2457 for (int i = 0; i < cl->class_class_function_count; ++i) | |
2458 { | |
2459 ufunc_T *fp = cl->class_class_functions[i]; | |
2460 char_u *ufname = (char_u *)fp->uf_name; | |
2461 if (STRNCMP(name, ufname, namelen) == 0 && ufname[namelen] == NUL) | |
2462 { | |
2463 ret_fp = fp; | |
2464 ret_idx = i; | |
2465 break; | |
2466 } | |
2467 } | |
2468 if (idx != NULL) | |
2469 *idx = ret_idx; | |
2470 return ret_fp; | |
2471 } | |
2472 | |
2473 /* | |
2474 * Returns the index of object member variable "name" in the class "cl". | 2424 * Returns the index of object member variable "name" in the class "cl". |
2475 * Returns -1, if the variable is not found. | 2425 * Returns -1, if the variable is not found. |
2476 * If "namelen" is zero, then it is assumed that "name" is NUL terminated. | 2426 * If "namelen" is zero, then it is assumed that "name" is NUL terminated. |
2477 */ | 2427 */ |
2478 int | 2428 static int |
2479 object_member_idx(class_T *cl, char_u *name, size_t namelen) | 2429 object_member_idx(class_T *cl, char_u *name, size_t namelen) |
2480 { | 2430 { |
2481 int idx; | 2431 int idx; |
2482 object_member_lookup(cl, name, namelen, &idx); | 2432 object_member_lookup(cl, name, namelen, &idx); |
2483 return idx; | 2433 return idx; |
2517 *idx = ret_idx; | 2467 *idx = ret_idx; |
2518 return ret_m; | 2468 return ret_m; |
2519 } | 2469 } |
2520 | 2470 |
2521 /* | 2471 /* |
2522 * Returns the index of object method "name" in the class "cl". | |
2523 * Returns -1, if the method is not found. | |
2524 */ | |
2525 int | |
2526 object_method_idx(class_T *cl, char_u *name, size_t namelen) | |
2527 { | |
2528 int idx; | |
2529 object_method_lookup(cl, name, namelen, &idx); | |
2530 return idx; | |
2531 } | |
2532 | |
2533 /* | |
2534 * Returns a pointer to the object method "name" in class "cl". | 2472 * Returns a pointer to the object method "name" in class "cl". |
2535 * Returns NULL if the method is not found. | 2473 * Returns NULL if the method is not found. |
2536 * The object method index is set in "idx". | 2474 * The object method index is set in "idx". |
2537 */ | 2475 */ |
2538 ufunc_T * | 2476 static ufunc_T * |
2539 object_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx) | 2477 object_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx) |
2540 { | 2478 { |
2541 ufunc_T *ret_fp = NULL; | 2479 ufunc_T *ret_fp = NULL; |
2542 int ret_idx = -1; | 2480 int ret_idx = -1; |
2543 for (int i = 0; i < cl->class_obj_method_count; ++i) | 2481 for (int i = 0; i < cl->class_obj_method_count; ++i) |
2554 } | 2492 } |
2555 } | 2493 } |
2556 if (idx != NULL) | 2494 if (idx != NULL) |
2557 *idx = ret_idx; | 2495 *idx = ret_idx; |
2558 return ret_fp; | 2496 return ret_fp; |
2497 } | |
2498 | |
2499 /* | |
2500 * Returns the index of object method "name" in the class "cl". | |
2501 * Returns -1, if the method is not found. | |
2502 */ | |
2503 int | |
2504 object_method_idx(class_T *cl, char_u *name, size_t namelen) | |
2505 { | |
2506 int idx; | |
2507 object_method_lookup(cl, name, namelen, &idx); | |
2508 return idx; | |
2559 } | 2509 } |
2560 | 2510 |
2561 /* | 2511 /* |
2562 * Lookup a class or object member variable by name. If v_type is VAR_CLASS, | 2512 * Lookup a class or object member variable by name. If v_type is VAR_CLASS, |
2563 * then lookup a class member variable and if it is VAR_OBJECT, then lookup a | 2513 * then lookup a class member variable and if it is VAR_OBJECT, then lookup a |
2680 ++to->vval.v_object->obj_refcount; | 2630 ++to->vval.v_object->obj_refcount; |
2681 } | 2631 } |
2682 } | 2632 } |
2683 | 2633 |
2684 /* | 2634 /* |
2685 * Free an object. | |
2686 */ | |
2687 static void | |
2688 object_clear(object_T *obj) | |
2689 { | |
2690 // Avoid a recursive call, it can happen if "obj" has a circular reference. | |
2691 obj->obj_refcount = INT_MAX; | |
2692 | |
2693 class_T *cl = obj->obj_class; | |
2694 | |
2695 if (!cl) | |
2696 return; | |
2697 | |
2698 // the member values are just after the object structure | |
2699 typval_T *tv = (typval_T *)(obj + 1); | |
2700 for (int i = 0; i < cl->class_obj_member_count; ++i) | |
2701 clear_tv(tv + i); | |
2702 | |
2703 // Remove from the list headed by "first_object". | |
2704 object_cleared(obj); | |
2705 | |
2706 vim_free(obj); | |
2707 class_unref(cl); | |
2708 } | |
2709 | |
2710 /* | |
2711 * Unreference an object. | |
2712 */ | |
2713 void | |
2714 object_unref(object_T *obj) | |
2715 { | |
2716 if (obj != NULL && --obj->obj_refcount <= 0) | |
2717 object_clear(obj); | |
2718 } | |
2719 | |
2720 /* | |
2721 * Make a copy of a class. | 2635 * Make a copy of a class. |
2722 */ | 2636 */ |
2723 void | 2637 void |
2724 copy_class(typval_T *from, typval_T *to) | 2638 copy_class(typval_T *from, typval_T *to) |
2725 { | 2639 { |
2864 | 2778 |
2865 /* | 2779 /* |
2866 * Call this function when an object has been cleared and is about to be freed. | 2780 * Call this function when an object has been cleared and is about to be freed. |
2867 * It is removed from the list headed by "first_object". | 2781 * It is removed from the list headed by "first_object". |
2868 */ | 2782 */ |
2869 void | 2783 static void |
2870 object_cleared(object_T *obj) | 2784 object_cleared(object_T *obj) |
2871 { | 2785 { |
2872 if (obj->obj_next_used != NULL) | 2786 if (obj->obj_next_used != NULL) |
2873 obj->obj_next_used->obj_prev_used = obj->obj_prev_used; | 2787 obj->obj_next_used->obj_prev_used = obj->obj_prev_used; |
2874 if (obj->obj_prev_used != NULL) | 2788 if (obj->obj_prev_used != NULL) |
2880 if (obj == next_nonref_obj) | 2794 if (obj == next_nonref_obj) |
2881 next_nonref_obj = obj->obj_next_used; | 2795 next_nonref_obj = obj->obj_next_used; |
2882 } | 2796 } |
2883 | 2797 |
2884 /* | 2798 /* |
2799 * Free an object. | |
2800 */ | |
2801 static void | |
2802 object_clear(object_T *obj) | |
2803 { | |
2804 // Avoid a recursive call, it can happen if "obj" has a circular reference. | |
2805 obj->obj_refcount = INT_MAX; | |
2806 | |
2807 class_T *cl = obj->obj_class; | |
2808 | |
2809 if (!cl) | |
2810 return; | |
2811 | |
2812 // the member values are just after the object structure | |
2813 typval_T *tv = (typval_T *)(obj + 1); | |
2814 for (int i = 0; i < cl->class_obj_member_count; ++i) | |
2815 clear_tv(tv + i); | |
2816 | |
2817 // Remove from the list headed by "first_object". | |
2818 object_cleared(obj); | |
2819 | |
2820 vim_free(obj); | |
2821 class_unref(cl); | |
2822 } | |
2823 | |
2824 /* | |
2825 * Unreference an object. | |
2826 */ | |
2827 void | |
2828 object_unref(object_T *obj) | |
2829 { | |
2830 if (obj != NULL && --obj->obj_refcount <= 0) | |
2831 object_clear(obj); | |
2832 } | |
2833 | |
2834 /* | |
2885 * Go through the list of all objects and free items without "copyID". | 2835 * Go through the list of all objects and free items without "copyID". |
2886 */ | 2836 */ |
2887 int | 2837 int |
2888 object_free_nonref(int copyID) | 2838 object_free_nonref(int copyID) |
2889 { | 2839 { |