Mercurial > vim
comparison src/vim9class.c @ 34472:5c1a025192ed v9.1.0148
patch 9.1.0148: Vim9: can't call internal methods with objects
Commit: https://github.com/vim/vim/commit/d3eae7bc116297f70220f21ded436ed0a88066d8
Author: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Sun Mar 3 16:26:58 2024 +0100
patch 9.1.0148: Vim9: can't call internal methods with objects
Problem: Vim9: can't call internal methods with objects
Solution: Add support for empty(), len() and string() function
calls for objects (Yegappan Lakshmanan)
closes: #14129
Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sun, 03 Mar 2024 16:45:06 +0100 |
parents | 0f2632b04cde |
children | d7b7fa7edb3b |
comparison
equal
deleted
inserted
replaced
34471:7f6302969e3d | 34472:5c1a025192ed |
---|---|
972 } | 972 } |
973 return TRUE; | 973 return TRUE; |
974 } | 974 } |
975 | 975 |
976 /* | 976 /* |
977 * Returns TRUE if 'uf' is a supported builtin method and has the correct | |
978 * method signature. | |
979 */ | |
980 static int | |
981 object_check_builtin_method_sig(ufunc_T *uf) | |
982 { | |
983 char_u *name = uf->uf_name; | |
984 int valid = FALSE; | |
985 type_T method_sig; | |
986 type_T method_rt; | |
987 where_T where = WHERE_INIT; | |
988 | |
989 // validate the method signature | |
990 CLEAR_FIELD(method_sig); | |
991 CLEAR_FIELD(method_rt); | |
992 method_sig.tt_type = VAR_FUNC; | |
993 | |
994 if (STRCMP(name, "len") == 0) | |
995 { | |
996 // def __len(): number | |
997 method_rt.tt_type = VAR_NUMBER; | |
998 method_sig.tt_member = &method_rt; | |
999 valid = TRUE; | |
1000 } | |
1001 else if (STRCMP(name, "empty") == 0) | |
1002 { | |
1003 // def __empty(): bool | |
1004 method_rt.tt_type = VAR_BOOL; | |
1005 method_sig.tt_member = &method_rt; | |
1006 valid = TRUE; | |
1007 } | |
1008 else if (STRCMP(name, "string") == 0) | |
1009 { | |
1010 // def __string(): string | |
1011 method_rt.tt_type = VAR_STRING; | |
1012 method_sig.tt_member = &method_rt; | |
1013 valid = TRUE; | |
1014 } | |
1015 else | |
1016 semsg(_(e_builtin_object_method_str_not_supported), uf->uf_name); | |
1017 | |
1018 where.wt_func_name = (char *)uf->uf_name; | |
1019 where.wt_kind = WT_METHOD; | |
1020 if (valid && !check_type(&method_sig, uf->uf_func_type, TRUE, where)) | |
1021 valid = FALSE; | |
1022 | |
1023 return valid; | |
1024 } | |
1025 | |
1026 /* | |
1027 * Returns TRUE if "funcname" is a supported builtin object method name | |
1028 */ | |
1029 int | |
1030 is_valid_builtin_obj_methodname(char_u *funcname) | |
1031 { | |
1032 switch (funcname[0]) | |
1033 { | |
1034 case 'e': | |
1035 return STRNCMP(funcname, "empty", 5) == 0; | |
1036 | |
1037 case 'l': | |
1038 return STRNCMP(funcname, "len", 3) == 0; | |
1039 | |
1040 case 'n': | |
1041 return STRNCMP(funcname, "new", 3) == 0; | |
1042 | |
1043 case 's': | |
1044 return STRNCMP(funcname, "string", 6) == 0; | |
1045 } | |
1046 | |
1047 return FALSE; | |
1048 } | |
1049 | |
1050 | |
1051 /* | |
1052 * Returns the builtin method "name" in object "obj". Returns NULL if the | |
1053 * method is not found. | |
1054 */ | |
1055 ufunc_T * | |
1056 class_get_builtin_method( | |
1057 class_T *cl, | |
1058 class_builtin_T builtin_method, | |
1059 int *method_idx) | |
1060 { | |
1061 *method_idx = -1; | |
1062 | |
1063 if (cl == NULL) | |
1064 return NULL; | |
1065 | |
1066 *method_idx = cl->class_builtin_methods[builtin_method]; | |
1067 return *method_idx != -1 ? cl->class_obj_methods[*method_idx] : NULL; | |
1068 } | |
1069 | |
1070 /* | |
977 * Update the interface class lookup table for the member index on the | 1071 * Update the interface class lookup table for the member index on the |
978 * interface to the member index in the class implementing the interface. | 1072 * interface to the member index in the class implementing the interface. |
979 * And a lookup table for the object method index on the interface | 1073 * And a lookup table for the object method index on the interface |
980 * to the object method index in the class implementing the interface. | 1074 * to the object method index in the class implementing the interface. |
981 * This is also used for updating the lookup table for the extended class | 1075 * This is also used for updating the lookup table for the extended class |
1322 fp->uf_flags |= FC_OBJECT; | 1416 fp->uf_flags |= FC_OBJECT; |
1323 } | 1417 } |
1324 } | 1418 } |
1325 | 1419 |
1326 return OK; | 1420 return OK; |
1421 } | |
1422 | |
1423 /* | |
1424 * Update the index of object methods called by builtin functions. | |
1425 */ | |
1426 static void | |
1427 update_builtin_method_index(class_T *cl) | |
1428 { | |
1429 int i; | |
1430 | |
1431 for (i = 0; i < CLASS_BUILTIN_MAX; i++) | |
1432 cl->class_builtin_methods[i] = -1; | |
1433 | |
1434 for (i = 0; i < cl->class_obj_method_count; i++) | |
1435 { | |
1436 ufunc_T *uf = cl->class_obj_methods[i]; | |
1437 | |
1438 if (cl->class_builtin_methods[CLASS_BUILTIN_STRING] == -1 | |
1439 && STRCMP(uf->uf_name, "string") == 0) | |
1440 cl->class_builtin_methods[CLASS_BUILTIN_STRING] = i; | |
1441 else if (cl->class_builtin_methods[CLASS_BUILTIN_EMPTY] == -1 && | |
1442 STRCMP(uf->uf_name, "empty") == 0) | |
1443 cl->class_builtin_methods[CLASS_BUILTIN_EMPTY] = i; | |
1444 else if (cl->class_builtin_methods[CLASS_BUILTIN_LEN] == -1 && | |
1445 STRCMP(uf->uf_name, "len") == 0) | |
1446 cl->class_builtin_methods[CLASS_BUILTIN_LEN] = i; | |
1447 } | |
1327 } | 1448 } |
1328 | 1449 |
1329 /* | 1450 /* |
1330 * Return the end of the class name starting at "arg". Valid characters in a | 1451 * Return the end of the class name starting at "arg". Valid characters in a |
1331 * class name are alphanumeric characters and "_". Also handles imported class | 1452 * class name are alphanumeric characters and "_". Also handles imported class |
1719 | 1840 |
1720 if (parse_member(eap, line, varname, has_public, | 1841 if (parse_member(eap, line, varname, has_public, |
1721 &varname_end, &has_type, &type_list, &type, | 1842 &varname_end, &has_type, &type_list, &type, |
1722 is_class ? &init_expr: NULL) == FAIL) | 1843 is_class ? &init_expr: NULL) == FAIL) |
1723 break; | 1844 break; |
1724 if (is_reserved_varname(varname, varname_end)) | 1845 |
1725 { | 1846 if (is_reserved_varname(varname, varname_end) |
1726 vim_free(init_expr); | 1847 || is_duplicate_variable(&classmembers, &objmembers, |
1727 break; | 1848 varname, varname_end)) |
1728 } | |
1729 if (is_duplicate_variable(&classmembers, &objmembers, varname, | |
1730 varname_end)) | |
1731 { | 1849 { |
1732 vim_free(init_expr); | 1850 vim_free(init_expr); |
1733 break; | 1851 break; |
1734 } | 1852 } |
1735 if (add_member(has_static ? &classmembers : &objmembers, varname, | 1853 if (add_member(has_static ? &classmembers : &objmembers, varname, |
1756 // enddef | 1874 // enddef |
1757 else if (checkforcmd(&p, "def", 3)) | 1875 else if (checkforcmd(&p, "def", 3)) |
1758 { | 1876 { |
1759 exarg_T ea; | 1877 exarg_T ea; |
1760 garray_T lines_to_free; | 1878 garray_T lines_to_free; |
1879 int is_new = STRNCMP(p, "new", 3) == 0; | |
1761 | 1880 |
1762 if (has_public) | 1881 if (has_public) |
1763 { | 1882 { |
1764 // "public" keyword is not supported when defining an object or | 1883 // "public" keyword is not supported when defining an object or |
1765 // class method | 1884 // class method |
1772 // No method name following def | 1891 // No method name following def |
1773 semsg(_(e_not_valid_command_in_class_str), line); | 1892 semsg(_(e_not_valid_command_in_class_str), line); |
1774 break; | 1893 break; |
1775 } | 1894 } |
1776 | 1895 |
1777 if (*p == '_' && *(p + 1) == '_') | 1896 if (!is_class && *p == '_') |
1778 { | 1897 { |
1779 // double underscore prefix for a method name is currently | 1898 // private methods are not supported in an interface |
1780 // reserved. This could be used in the future to support | 1899 semsg(_(e_protected_method_not_supported_in_interface), p); |
1781 // object methods called by Vim builtin functions. | 1900 break; |
1782 semsg(_(e_cannot_use_reserved_name_str), p); | 1901 } |
1902 | |
1903 if (has_static && !is_new && SAFE_islower(*p) && | |
1904 is_valid_builtin_obj_methodname(p)) | |
1905 { | |
1906 semsg(_(e_builtin_class_method_not_supported), p); | |
1783 break; | 1907 break; |
1784 } | 1908 } |
1785 | 1909 |
1786 CLEAR_FIELD(ea); | 1910 CLEAR_FIELD(ea); |
1787 ea.cmd = line; | 1911 ea.cmd = line; |
1801 ga_clear_strings(&lines_to_free); | 1925 ga_clear_strings(&lines_to_free); |
1802 | 1926 |
1803 if (uf != NULL) | 1927 if (uf != NULL) |
1804 { | 1928 { |
1805 char_u *name = uf->uf_name; | 1929 char_u *name = uf->uf_name; |
1806 int is_new = STRNCMP(name, "new", 3) == 0; | 1930 |
1807 | 1931 if (is_new && !is_valid_constructor(uf, is_abstract, |
1808 if (!is_class && *name == '_') | 1932 has_static)) |
1809 { | 1933 { |
1810 // private variables are not supported in an interface | 1934 // private variables are not supported in an interface |
1811 semsg(_(e_protected_method_not_supported_in_interface), | 1935 semsg(_(e_protected_method_not_supported_in_interface), |
1812 name); | 1936 name); |
1813 func_clear_free(uf, FALSE); | 1937 func_clear_free(uf, FALSE); |
1814 break; | 1938 break; |
1815 } | 1939 } |
1816 if (is_new && !is_valid_constructor(uf, is_abstract, | 1940 |
1817 has_static)) | 1941 // check for builtin method |
1942 if (!is_new && SAFE_islower(*name) && | |
1943 !object_check_builtin_method_sig(uf)) | |
1818 { | 1944 { |
1819 func_clear_free(uf, FALSE); | 1945 func_clear_free(uf, FALSE); |
1820 break; | 1946 break; |
1821 } | 1947 } |
1822 | 1948 |
1995 // Move all the functions into the created class. | 2121 // Move all the functions into the created class. |
1996 if (add_classfuncs_objmethods(cl, extends_cl, &classfunctions, | 2122 if (add_classfuncs_objmethods(cl, extends_cl, &classfunctions, |
1997 &objmethods) == FAIL) | 2123 &objmethods) == FAIL) |
1998 goto cleanup; | 2124 goto cleanup; |
1999 | 2125 |
2126 update_builtin_method_index(cl); | |
2127 | |
2000 cl->class_type.tt_type = VAR_CLASS; | 2128 cl->class_type.tt_type = VAR_CLASS; |
2001 cl->class_type.tt_class = cl; | 2129 cl->class_type.tt_class = cl; |
2002 cl->class_object_type.tt_type = VAR_OBJECT; | 2130 cl->class_object_type.tt_type = VAR_OBJECT; |
2003 cl->class_object_type.tt_class = cl; | 2131 cl->class_object_type.tt_class = cl; |
2004 cl->class_type_list = type_list; | 2132 cl->class_type_list = type_list; |
3271 return rettv->v_type == VAR_CLASS; | 3399 return rettv->v_type == VAR_CLASS; |
3272 return FALSE; | 3400 return FALSE; |
3273 } | 3401 } |
3274 | 3402 |
3275 /* | 3403 /* |
3404 * Calls the object builtin method "name" with arguments "argv". The value | |
3405 * returned by the builtin method is in "rettv". Returns OK or FAIL. | |
3406 */ | |
3407 static int | |
3408 object_call_builtin_method( | |
3409 object_T *obj, | |
3410 class_builtin_T builtin_method, | |
3411 int argc, | |
3412 typval_T *argv, | |
3413 typval_T *rettv) | |
3414 { | |
3415 ufunc_T *uf; | |
3416 int midx; | |
3417 | |
3418 if (obj == NULL) | |
3419 return FAIL; | |
3420 | |
3421 uf = class_get_builtin_method(obj->obj_class, builtin_method, &midx); | |
3422 if (uf == NULL) | |
3423 return FAIL; | |
3424 | |
3425 funccall_T *fc = create_funccal(uf, rettv); | |
3426 int r; | |
3427 | |
3428 if (fc == NULL) | |
3429 return FAIL; | |
3430 | |
3431 ++obj->obj_refcount; | |
3432 | |
3433 r = call_def_function(uf, argc, argv, 0, NULL, obj, fc, rettv); | |
3434 | |
3435 remove_funccal(); | |
3436 | |
3437 return r; | |
3438 } | |
3439 | |
3440 /* | |
3441 * Calls the object "empty()" method and returns the method retun value. In | |
3442 * case of an error, returns TRUE. | |
3443 */ | |
3444 int | |
3445 object_empty(object_T *obj) | |
3446 { | |
3447 typval_T rettv; | |
3448 | |
3449 if (object_call_builtin_method(obj, CLASS_BUILTIN_EMPTY, 0, NULL, &rettv) | |
3450 == FAIL) | |
3451 return TRUE; | |
3452 | |
3453 return tv_get_bool(&rettv); | |
3454 } | |
3455 | |
3456 /* | |
3457 * Use the object "len()" method to get an object length. Returns 0 if the | |
3458 * method is not found or there is an error. | |
3459 */ | |
3460 int | |
3461 object_len(object_T *obj) | |
3462 { | |
3463 typval_T rettv; | |
3464 | |
3465 if (object_call_builtin_method(obj, CLASS_BUILTIN_LEN, 0, NULL, &rettv) | |
3466 == FAIL) | |
3467 return 0; | |
3468 | |
3469 return tv_to_number(&rettv); | |
3470 } | |
3471 | |
3472 /* | |
3473 * Return a textual representation of object "obj" | |
3474 */ | |
3475 char_u * | |
3476 object_string( | |
3477 object_T *obj, | |
3478 char_u *numbuf, | |
3479 int copyID, | |
3480 int echo_style, | |
3481 int restore_copyID, | |
3482 int composite_val) | |
3483 { | |
3484 typval_T rettv; | |
3485 | |
3486 if (object_call_builtin_method(obj, CLASS_BUILTIN_STRING, 0, NULL, &rettv) | |
3487 == OK | |
3488 && rettv.vval.v_string != NULL) | |
3489 return rettv.vval.v_string; | |
3490 else | |
3491 { | |
3492 garray_T ga; | |
3493 ga_init2(&ga, 1, 50); | |
3494 | |
3495 ga_concat(&ga, (char_u *)"object of "); | |
3496 class_T *cl = obj == NULL ? NULL : obj->obj_class; | |
3497 ga_concat(&ga, cl == NULL ? (char_u *)"[unknown]" | |
3498 : cl->class_name); | |
3499 if (cl != NULL) | |
3500 { | |
3501 ga_concat(&ga, (char_u *)" {"); | |
3502 for (int i = 0; i < cl->class_obj_member_count; ++i) | |
3503 { | |
3504 if (i > 0) | |
3505 ga_concat(&ga, (char_u *)", "); | |
3506 ocmember_T *m = &cl->class_obj_members[i]; | |
3507 ga_concat(&ga, m->ocm_name); | |
3508 ga_concat(&ga, (char_u *)": "); | |
3509 char_u *tf = NULL; | |
3510 ga_concat(&ga, echo_string_core( | |
3511 (typval_T *)(obj + 1) + i, | |
3512 &tf, numbuf, copyID, echo_style, | |
3513 restore_copyID, composite_val)); | |
3514 vim_free(tf); | |
3515 } | |
3516 ga_concat(&ga, (char_u *)"}"); | |
3517 } | |
3518 return ga.ga_data; | |
3519 } | |
3520 } | |
3521 | |
3522 /* | |
3276 * Return TRUE when the class "cl", its base class or one of the implemented | 3523 * Return TRUE when the class "cl", its base class or one of the implemented |
3277 * interfaces matches the class "other_cl". | 3524 * interfaces matches the class "other_cl". |
3278 */ | 3525 */ |
3279 int | 3526 int |
3280 class_instance_of(class_T *cl, class_T *other_cl) | 3527 class_instance_of(class_T *cl, class_T *other_cl) |