Mercurial > vim
diff src/vim9expr.c @ 33540:86dbcbb94fdb v9.0.2019
patch 9.0.2019: Vim9: no support for funcrefs
Commit: https://github.com/vim/vim/commit/29bb67f1beefc7fd393dbfd9ee77d92f1db3a3c0
Author: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Sat Oct 14 11:18:50 2023 +0200
patch 9.0.2019: Vim9: no support for funcrefs
Problem: Vim9: no support for funcrefs
Solution: Add support for object/class funcref members
closes: #11981 #12417 #12960 #12324 #13333
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sat, 14 Oct 2023 11:30:07 +0200 |
parents | bff8ac203a22 |
children | c470d4fd5eba |
line wrap: on
line diff
--- a/src/vim9expr.c +++ b/src/vim9expr.c @@ -281,6 +281,8 @@ inside_class_hierarchy(cctx_T *cctx_arg, static int compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type) { + int m_idx; + if (VIM_ISWHITE((*arg)[1])) { semsg(_(e_no_white_space_allowed_after_str_str), ".", *arg); @@ -365,17 +367,34 @@ compile_class_object_index(cctx_T *cctx, break; } } + ocmember_T *ocm = NULL; if (ufunc == NULL) { - method_not_found_msg(cl, type->tt_type, name, len); - return FAIL; + // could be a funcref in a member variable + ocm = member_lookup(cl, type->tt_type, name, len, &m_idx); + if (ocm == NULL || ocm->ocm_type->tt_type != VAR_FUNC) + { + method_not_found_msg(cl, type->tt_type, name, len); + return FAIL; + } + if (type->tt_type == VAR_CLASS) + { + if (generate_CLASSMEMBER(cctx, TRUE, cl, m_idx) == FAIL) + return FAIL; + } + else + { + if (generate_GET_OBJ_MEMBER(cctx, m_idx, ocm->ocm_type) == + FAIL) + return FAIL; + } } // A private object method can be used only inside the class where it // is defined or in one of the child classes. // A private class method can be used only in the class where it is // defined. - if (*ufunc->uf_name == '_' && + if (ocm == NULL && *ufunc->uf_name == '_' && ((type->tt_type == VAR_OBJECT && !inside_class_hierarchy(cctx, cl)) || (type->tt_type == VAR_CLASS @@ -393,6 +412,8 @@ compile_class_object_index(cctx_T *cctx, if (compile_arguments(arg, cctx, &argcount, CA_NOT_SPECIAL) == FAIL) return FAIL; + if (ocm != NULL) + return generate_PCALL(cctx, argcount, name, ocm->ocm_type, TRUE); if (type->tt_type == VAR_OBJECT && (cl->class_flags & (CLASS_INTERFACE | CLASS_EXTENDED))) return generate_CALL(cctx, ufunc, cl, fi, argcount); @@ -401,7 +422,6 @@ compile_class_object_index(cctx_T *cctx, if (type->tt_type == VAR_OBJECT) { - int m_idx; ocmember_T *m = object_member_lookup(cl, name, len, &m_idx); if (m_idx >= 0) { @@ -418,15 +438,21 @@ compile_class_object_index(cctx_T *cctx, return generate_GET_OBJ_MEMBER(cctx, m_idx, m->ocm_type); } - // Could be a function reference: "obj.Func". + // Could be an object method reference: "obj.Func". m_idx = object_method_idx(cl, name, len); if (m_idx >= 0) { ufunc_T *fp = cl->class_obj_methods[m_idx]; - if (type->tt_type == VAR_OBJECT - && (cl->class_flags & (CLASS_INTERFACE | CLASS_EXTENDED))) - return generate_FUNCREF(cctx, fp, cl, m_idx, NULL); - return generate_FUNCREF(cctx, fp, NULL, 0, NULL); + // Private methods are not accessible outside the class + if (*name == '_' && !inside_class(cctx, cl)) + { + semsg(_(e_cannot_access_private_method_str), fp->uf_name); + return FAIL; + } + *arg = name_end; + if (type->tt_type == VAR_OBJECT) + return generate_FUNCREF(cctx, fp, cl, TRUE, m_idx, NULL); + return generate_FUNCREF(cctx, fp, NULL, FALSE, 0, NULL); } member_not_found_msg(cl, VAR_OBJECT, name, len); @@ -451,6 +477,24 @@ compile_class_object_index(cctx_T *cctx, *arg = name_end; return generate_CLASSMEMBER(cctx, TRUE, cl, idx); } + + // Could be a class method reference: "class.Func". + m_idx = class_method_idx(cl, name, len); + if (m_idx >= 0) + { + ufunc_T *fp = cl->class_class_functions[m_idx]; + // Private methods are not accessible outside the class + if (*name == '_' && !inside_class(cctx, cl)) + { + semsg(_(e_cannot_access_private_method_str), fp->uf_name); + return FAIL; + } + *arg = name_end; + if (type->tt_type == VAR_CLASS) + return generate_FUNCREF(cctx, fp, cl, FALSE, m_idx, NULL); + return generate_FUNCREF(cctx, fp, NULL, FALSE, 0, NULL); + } + member_not_found_msg(cl, VAR_CLASS, name, len); } @@ -716,6 +760,7 @@ compile_load( { size_t len = end - *arg; int idx; + int method_idx; int gen_load = FALSE; int gen_load_outer = 0; int outer_loop_depth = -1; @@ -764,13 +809,27 @@ compile_load( else gen_load = TRUE; } - else if ((idx = cctx_class_member_idx(cctx, *arg, len, &cl)) >= 0) + else if (cctx->ctx_ufunc->uf_defclass != NULL && + (((idx = + cctx_class_member_idx(cctx, *arg, len, &cl)) >= 0) + || ((method_idx = + cctx_class_method_idx(cctx, *arg, len, &cl)) >= 0))) { - // Referencing a class variable without the class name. - // A class variable can be referenced without the class name - // only in the class where the function is defined. + // Referencing a class variable or method without the class + // name. A class variable or method can be referenced without + // the class name only in the class where the function is + // defined. if (cctx->ctx_ufunc->uf_defclass == cl) - res = generate_CLASSMEMBER(cctx, TRUE, cl, idx); + { + if (idx >= 0) + res = generate_CLASSMEMBER(cctx, TRUE, cl, idx); + else + { + ufunc_T *fp = cl->class_class_functions[method_idx]; + res = generate_FUNCREF(cctx, fp, cl, FALSE, method_idx, + NULL); + } + } else { semsg(_(e_class_variable_str_accessible_only_inside_class_str), @@ -1387,7 +1446,7 @@ compile_lambda(char_u **arg, cctx_T *cct // The function reference count will be 1. When the ISN_FUNCREF // instruction is deleted the reference count is decremented and the // function is freed. - return generate_FUNCREF(cctx, ufunc, NULL, 0, NULL); + return generate_FUNCREF(cctx, ufunc, NULL, FALSE, 0, NULL); } func_ptr_unref(ufunc);