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)