Mercurial > vim
comparison src/vim9class.c @ 34508:d7b7fa7edb3b v9.1.0160
patch 9.1.0160: Vim9: Add support for using a class type of itself in an object method
Commit: https://github.com/vim/vim/commit/35b867b685cedbcbba9d44695077ecc9a6995f4c
Author: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Sat Mar 9 15:44:19 2024 +0100
patch 9.1.0160: Vim9: Add support for using a class type of itself in an object method
Problem: Add support for using a class type of itself in an object
method (thinca)
Solution: Vim9: Add support for using a class type of itself in an
object method (Yegappan Lakshmanan)
fixes: #12369
closes: #14165
Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sat, 09 Mar 2024 16:00:02 +0100 |
parents | 5c1a025192ed |
children | 5b25ec43f208 |
comparison
equal
deleted
inserted
replaced
34507:ee1ce4ddcb29 | 34508:d7b7fa7edb3b |
---|---|
206 * "gap" contains the found members. | 206 * "gap" contains the found members. |
207 * "parent_members" points to the members in the parent class (if any) | 207 * "parent_members" points to the members in the parent class (if any) |
208 * "parent_count" is the number of members in the parent class | 208 * "parent_count" is the number of members in the parent class |
209 * "members" will be set to the newly allocated array of members and | 209 * "members" will be set to the newly allocated array of members and |
210 * "member_count" set to the number of members. | 210 * "member_count" set to the number of members. |
211 * Returns OK or FAIL. | 211 * Returns OK on success and FAIL on memory allocation failure. |
212 */ | 212 */ |
213 static int | 213 static int |
214 add_members_to_class( | 214 add_members_to_class( |
215 garray_T *gap, | 215 garray_T *gap, |
216 ocmember_T *parent_members, | 216 ocmember_T *parent_members, |
299 * valid, then "extends_clp" is set with the class pointer. | 299 * valid, then "extends_clp" is set with the class pointer. |
300 * Returns TRUE if the class name "extends_names" is a valid class. | 300 * Returns TRUE if the class name "extends_names" is a valid class. |
301 */ | 301 */ |
302 static int | 302 static int |
303 validate_extends_class( | 303 validate_extends_class( |
304 class_T *cl, | |
304 char_u *extends_name, | 305 char_u *extends_name, |
305 class_T **extends_clp, | 306 class_T **extends_clp, |
306 int is_class) | 307 int is_class) |
307 { | 308 { |
308 typval_T tv; | 309 typval_T tv; |
309 int success = FALSE; | 310 int success = FALSE; |
311 | |
312 if (STRCMP(cl->class_name, extends_name) == 0) | |
313 { | |
314 semsg(_(e_cannot_extend_str), extends_name); | |
315 return success; | |
316 } | |
310 | 317 |
311 tv.v_type = VAR_UNKNOWN; | 318 tv.v_type = VAR_UNKNOWN; |
312 if (eval_variable_import(extends_name, &tv) == FAIL) | 319 if (eval_variable_import(extends_name, &tv) == FAIL) |
313 { | 320 { |
314 semsg(_(e_class_name_not_found_str), extends_name); | 321 semsg(_(e_class_name_not_found_str), extends_name); |
1640 | 1647 |
1641 // Growarray with object methods declared in the class. | 1648 // Growarray with object methods declared in the class. |
1642 garray_T objmethods; | 1649 garray_T objmethods; |
1643 ga_init2(&objmethods, sizeof(ufunc_T *), 10); | 1650 ga_init2(&objmethods, sizeof(ufunc_T *), 10); |
1644 | 1651 |
1652 class_T *cl = NULL; | |
1653 class_T *extends_cl = NULL; // class from "extends" argument | |
1654 class_T **intf_classes = NULL; | |
1655 | |
1656 cl = ALLOC_CLEAR_ONE(class_T); | |
1657 if (cl == NULL) | |
1658 goto cleanup; | |
1659 if (!is_class) | |
1660 cl->class_flags = CLASS_INTERFACE; | |
1661 else if (is_abstract) | |
1662 cl->class_flags = CLASS_ABSTRACT; | |
1663 | |
1664 cl->class_refcount = 1; | |
1665 cl->class_name = vim_strnsave(name_start, name_end - name_start); | |
1666 if (cl->class_name == NULL) | |
1667 goto cleanup; | |
1668 | |
1669 // Add the class to the script-local variables. | |
1670 // TODO: handle other context, e.g. in a function | |
1671 // TODO: does uf_hash need to be cleared? | |
1672 typval_T tv; | |
1673 tv.v_type = VAR_CLASS; | |
1674 tv.vval.v_class = cl; | |
1675 is_export = class_export; | |
1676 SOURCING_LNUM = start_lnum; | |
1677 int rc = set_var_const(cl->class_name, current_sctx.sc_sid, | |
1678 NULL, &tv, FALSE, 0, 0); | |
1679 if (rc == FAIL) | |
1680 goto cleanup; | |
1681 | |
1645 /* | 1682 /* |
1646 * Go over the body of the class/interface until "endclass" or | 1683 * Go over the body of the class/interface until "endclass" or |
1647 * "endinterface" is found. | 1684 * "endinterface" is found. |
1648 */ | 1685 */ |
1649 char_u *theline = NULL; | 1686 char_u *theline = NULL; |
1979 break; | 2016 break; |
1980 } | 2017 } |
1981 } | 2018 } |
1982 vim_free(theline); | 2019 vim_free(theline); |
1983 | 2020 |
1984 class_T *extends_cl = NULL; // class from "extends" argument | |
1985 | |
1986 /* | 2021 /* |
1987 * Check a few things before defining the class. | 2022 * Check a few things before defining the class. |
1988 */ | 2023 */ |
1989 | 2024 |
1990 // Check the "extends" class is valid. | 2025 // Check the "extends" class is valid. |
1991 if (success && extends != NULL) | 2026 if (success && extends != NULL) |
1992 success = validate_extends_class(extends, &extends_cl, is_class); | 2027 success = validate_extends_class(cl, extends, &extends_cl, is_class); |
1993 VIM_CLEAR(extends); | 2028 VIM_CLEAR(extends); |
1994 | 2029 |
1995 // Check the new object methods to make sure their access (public or | 2030 // Check the new object methods to make sure their access (public or |
1996 // private) is the same as that in the extended class lineage. | 2031 // private) is the same as that in the extended class lineage. |
1997 if (success && extends_cl != NULL) | 2032 if (success && extends_cl != NULL) |
2014 if (success && !is_abstract && extends_cl != NULL | 2049 if (success && !is_abstract && extends_cl != NULL |
2015 && (extends_cl->class_flags & CLASS_ABSTRACT)) | 2050 && (extends_cl->class_flags & CLASS_ABSTRACT)) |
2016 success = validate_abstract_class_methods(&classfunctions, | 2051 success = validate_abstract_class_methods(&classfunctions, |
2017 &objmethods, extends_cl); | 2052 &objmethods, extends_cl); |
2018 | 2053 |
2019 class_T **intf_classes = NULL; | |
2020 | |
2021 // Check all "implements" entries are valid. | 2054 // Check all "implements" entries are valid. |
2022 if (success && ga_impl.ga_len > 0) | 2055 if (success && ga_impl.ga_len > 0) |
2023 { | 2056 { |
2024 intf_classes = ALLOC_CLEAR_MULT(class_T *, ga_impl.ga_len); | 2057 intf_classes = ALLOC_CLEAR_MULT(class_T *, ga_impl.ga_len); |
2025 | 2058 |
2030 // Check no function argument name is used as a class member. | 2063 // Check no function argument name is used as a class member. |
2031 if (success) | 2064 if (success) |
2032 success = check_func_arg_names(&classfunctions, &objmethods, | 2065 success = check_func_arg_names(&classfunctions, &objmethods, |
2033 &classmembers); | 2066 &classmembers); |
2034 | 2067 |
2035 class_T *cl = NULL; | |
2036 if (success) | 2068 if (success) |
2037 { | 2069 { |
2038 // "endclass" encountered without failures: Create the class. | 2070 // "endclass" encountered without failures: Create the class. |
2039 | |
2040 cl = ALLOC_CLEAR_ONE(class_T); | |
2041 if (cl == NULL) | |
2042 goto cleanup; | |
2043 if (!is_class) | |
2044 cl->class_flags = CLASS_INTERFACE; | |
2045 else if (is_abstract) | |
2046 cl->class_flags = CLASS_ABSTRACT; | |
2047 | |
2048 cl->class_refcount = 1; | |
2049 cl->class_name = vim_strnsave(name_start, name_end - name_start); | |
2050 if (cl->class_name == NULL) | |
2051 goto cleanup; | |
2052 | 2071 |
2053 if (extends_cl != NULL) | 2072 if (extends_cl != NULL) |
2054 { | 2073 { |
2055 cl->class_extends = extends_cl; | 2074 cl->class_extends = extends_cl; |
2056 extends_cl->class_flags |= CLASS_EXTENDED; | 2075 extends_cl->class_flags |= CLASS_EXTENDED; |
2134 class_created(cl); | 2153 class_created(cl); |
2135 | 2154 |
2136 // TODO: | 2155 // TODO: |
2137 // - Fill hashtab with object members and methods ? | 2156 // - Fill hashtab with object members and methods ? |
2138 | 2157 |
2139 // Add the class to the script-local variables. | |
2140 // TODO: handle other context, e.g. in a function | |
2141 // TODO: does uf_hash need to be cleared? | |
2142 typval_T tv; | |
2143 tv.v_type = VAR_CLASS; | |
2144 tv.vval.v_class = cl; | |
2145 is_export = class_export; | |
2146 SOURCING_LNUM = start_lnum; | |
2147 set_var_const(cl->class_name, current_sctx.sc_sid, | |
2148 NULL, &tv, FALSE, 0, 0); | |
2149 return; | 2158 return; |
2150 } | 2159 } |
2151 | 2160 |
2152 cleanup: | 2161 cleanup: |
2153 if (cl != NULL) | |
2154 { | |
2155 vim_free(cl->class_name); | |
2156 vim_free(cl->class_class_functions); | |
2157 if (cl->class_interfaces != NULL) | |
2158 { | |
2159 for (int i = 0; i < cl->class_interface_count; ++i) | |
2160 vim_free(cl->class_interfaces[i]); | |
2161 vim_free(cl->class_interfaces); | |
2162 } | |
2163 if (cl->class_interfaces_cl != NULL) | |
2164 { | |
2165 for (int i = 0; i < cl->class_interface_count; ++i) | |
2166 class_unref(cl->class_interfaces_cl[i]); | |
2167 vim_free(cl->class_interfaces_cl); | |
2168 } | |
2169 vim_free(cl->class_obj_members); | |
2170 vim_free(cl->class_obj_methods); | |
2171 vim_free(cl); | |
2172 } | |
2173 | |
2174 vim_free(extends); | 2162 vim_free(extends); |
2175 class_unref(extends_cl); | 2163 class_unref(extends_cl); |
2176 | 2164 |
2177 if (intf_classes != NULL) | 2165 if (intf_classes != NULL) |
2178 { | 2166 { |