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 {