Move code for generating callbacks. Move code for generating callbacks from CFCBindMethod to CFCPerlMethod in anticipation of inlining Perl-specific code and eliminating Clownfish::Host.
Project: http://git-wip-us.apache.org/repos/asf/lucy/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/96084df9 Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/96084df9 Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/96084df9 Branch: refs/heads/master Commit: 96084df9a5a7bd6b9408c1ce90d39cf3b87155de Parents: 10262d3 Author: Marvin Humphrey <[email protected]> Authored: Fri Nov 9 18:26:35 2012 -0800 Committer: Marvin Humphrey <[email protected]> Committed: Tue Nov 13 18:12:33 2012 -0800 ---------------------------------------------------------------------- clownfish/compiler/perl/lib/Clownfish/CFC.xs | 8 - clownfish/compiler/src/CFCBindMethod.c | 330 ------------------ clownfish/compiler/src/CFCBindMethod.h | 7 - clownfish/compiler/src/CFCPerl.c | 2 +- clownfish/compiler/src/CFCPerlMethod.c | 376 +++++++++++++++++++++ clownfish/compiler/src/CFCPerlMethod.h | 7 + 6 files changed, 384 insertions(+), 346 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy/blob/96084df9/clownfish/compiler/perl/lib/Clownfish/CFC.xs ---------------------------------------------------------------------- diff --git a/clownfish/compiler/perl/lib/Clownfish/CFC.xs b/clownfish/compiler/perl/lib/Clownfish/CFC.xs index fd7012e..058f3b9 100644 --- a/clownfish/compiler/perl/lib/Clownfish/CFC.xs +++ b/clownfish/compiler/perl/lib/Clownfish/CFC.xs @@ -1818,14 +1818,6 @@ CODE: OUTPUT: RETVAL SV* -callback_def(unused, meth) - SV *unused; - CFCMethod *meth; -CODE: - RETVAL = S_sv_eat_c_string(CFCBindMeth_callback_def(meth)); -OUTPUT: RETVAL - -SV* _method_def(meth, klass) CFCMethod *meth; CFCClass *klass; http://git-wip-us.apache.org/repos/asf/lucy/blob/96084df9/clownfish/compiler/src/CFCBindMethod.c ---------------------------------------------------------------------- diff --git a/clownfish/compiler/src/CFCBindMethod.c b/clownfish/compiler/src/CFCBindMethod.c index 4e17be1..85ac99e 100644 --- a/clownfish/compiler/src/CFCBindMethod.c +++ b/clownfish/compiler/src/CFCBindMethod.c @@ -48,46 +48,6 @@ S_build_unused_vars(CFCVariable **vars); static char* S_maybe_unreachable(CFCType *return_type); -/* Return a string which maps arguments to various arg wrappers conforming - * to Host's callback interface. For instance, (int32_t foo, Obj *bar) - * produces the following: - * - * CFISH_ARG_I32("foo", foo), - * CFISH_ARG_OBJ("bar", bar) - */ -static char* -S_callback_params(CFCMethod *method); - -/* Adapt the refcounts of parameters and return types, since Host_callback_xxx - * has no impact on refcounts aside from Host_callback_obj returning an - * incremented Obj. - */ -static char* -S_callback_refcount_mods(CFCMethod *method); - -/* Return a function which throws a runtime error indicating which variable - * couldn't be mapped. TODO: it would be better to resolve all these cases at - * compile-time. - */ -static char* -S_invalid_callback_def(CFCMethod *method); - -// Create a callback for a method which operates in a void context. -static char* -S_void_callback_def(CFCMethod *method, const char *callback_params, - const char *refcount_mods); - -// Create a callback which returns a primitive type. -static char* -S_primitive_callback_def(CFCMethod *method, const char *callback_params, - const char *refcount_mods); - -/* Create a callback which returns an object type -- either a generic object or - * a string. */ -static char* -S_obj_callback_def(CFCMethod *method, const char *callback_params, - const char *refcount_mods); - char* CFCBindMeth_method_def(CFCMethod *method, CFCClass *klass) { if (CFCMethod_final(method)) { @@ -356,293 +316,3 @@ CFCBindMeth_callback_dec(CFCMethod *method) { return callback_dec; } -char* -CFCBindMeth_callback_def(CFCMethod *method) { - CFCType *return_type = CFCMethod_get_return_type(method); - char *params = S_callback_params(method); - char *callback_def = NULL; - char *refcount_mods = S_callback_refcount_mods(method); - - if (!params) { - // Can't map vars, because there's at least one type in the argument - // list we don't yet support. Return a callback wrapper that throws - // an error error. - callback_def = S_invalid_callback_def(method); - } - else if (CFCType_is_void(return_type)) { - callback_def = S_void_callback_def(method, params, refcount_mods); - } - else if (CFCType_is_object(return_type)) { - callback_def = S_obj_callback_def(method, params, refcount_mods); - } - else if (CFCType_is_integer(return_type) - || CFCType_is_floating(return_type) - ) { - callback_def = S_primitive_callback_def(method, params, refcount_mods); - } - else { - // Can't map return type. - callback_def = S_invalid_callback_def(method); - } - - FREEMEM(params); - FREEMEM(refcount_mods); - return callback_def; -} - -static char* -S_callback_params(CFCMethod *method) { - const char *micro_sym = CFCSymbol_micro_sym((CFCSymbol*)method); - CFCParamList *param_list = CFCMethod_get_param_list(method); - unsigned num_params = CFCParamList_num_vars(param_list) - 1; - size_t needed = strlen(micro_sym) + 30; - char *params = (char*)MALLOCATE(needed); - - // TODO: use something other than micro_sym here. - sprintf(params, "self, \"%s\", %u", micro_sym, num_params); - - // Iterate over arguments, mapping them to various arg wrappers which - // conform to Host's callback interface. - CFCVariable **arg_vars = CFCParamList_get_variables(param_list); - for (int i = 1; arg_vars[i] != NULL; i++) { - CFCVariable *var = arg_vars[i]; - const char *name = CFCVariable_micro_sym(var); - size_t name_len = strlen(name); - CFCType *type = CFCVariable_get_type(var); - const char *c_type = CFCType_to_c(type); - size_t size = strlen(params) - + strlen(c_type) - + name_len * 2 - + 30; - char *new_buf = (char*)MALLOCATE(size); - - if (CFCType_is_string_type(type)) { - sprintf(new_buf, "%s, CFISH_ARG_STR(\"%s\", %s)", params, name, name); - } - else if (CFCType_is_object(type)) { - sprintf(new_buf, "%s, CFISH_ARG_OBJ(\"%s\", %s)", params, name, name); - } - else if (CFCType_is_integer(type)) { - int width = CFCType_get_width(type); - if (width) { - if (width <= 4) { - sprintf(new_buf, "%s, CFISH_ARG_I32(\"%s\", %s)", params, - name, name); - } - else { - sprintf(new_buf, "%s, CFISH_ARG_I64(\"%s\", %s)", params, - name, name); - } - } - else { - sprintf(new_buf, "%s, CFISH_ARG_I(%s, \"%s\", %s)", params, - c_type, name, name); - } - } - else if (CFCType_is_floating(type)) { - sprintf(new_buf, "%s, CFISH_ARG_F64(\"%s\", %s)", params, name, name); - } - else { - // Can't map variable type. Signal to caller. - FREEMEM(params); - FREEMEM(new_buf); - return NULL; - } - - FREEMEM(params); - params = new_buf; - } - - return params; -} - -static char* -S_callback_refcount_mods(CFCMethod *method) { - char *refcount_mods = CFCUtil_strdup(""); - CFCType *return_type = CFCMethod_get_return_type(method); - CFCParamList *param_list = CFCMethod_get_param_list(method); - CFCVariable **arg_vars = CFCParamList_get_variables(param_list); - - // Host_callback_obj returns an incremented object. If this method does - // not return an incremented object, we must cancel out that refcount. - // (No function can return a decremented object.) - if (CFCType_is_object(return_type) && !CFCType_incremented(return_type)) { - refcount_mods = CFCUtil_cat(refcount_mods, - "\n CFISH_DECREF(retval);", NULL); - } - - // The Host_callback_xxx functions have no effect on the refcounts of - // arguments, so we need to adjust them after the fact. - for (int i = 0; arg_vars[i] != NULL; i++) { - CFCVariable *var = arg_vars[i]; - CFCType *type = CFCVariable_get_type(var); - const char *name = CFCVariable_micro_sym(var); - if (!CFCType_is_object(type)) { - continue; - } - else if (CFCType_incremented(type)) { - refcount_mods = CFCUtil_cat(refcount_mods, "\n CFISH_INCREF(", - name, ");", NULL); - } - else if (CFCType_decremented(type)) { - refcount_mods = CFCUtil_cat(refcount_mods, "\n CFISH_DECREF(", - name, ");", NULL); - } - } - - return refcount_mods; -} - -static char* -S_invalid_callback_def(CFCMethod *method) { - size_t meth_sym_size = CFCMethod_full_method_sym(method, NULL, NULL, 0); - char *full_method_sym = (char*)MALLOCATE(meth_sym_size); - CFCMethod_full_method_sym(method, NULL, full_method_sym, meth_sym_size); - - const char *override_sym = CFCMethod_full_override_sym(method); - CFCParamList *param_list = CFCMethod_get_param_list(method); - const char *params = CFCParamList_to_c(param_list); - CFCVariable **param_vars = CFCParamList_get_variables(param_list); - - // Thwart compiler warnings. - CFCType *return_type = CFCMethod_get_return_type(method); - const char *ret_type_str = CFCType_to_c(return_type); - char *unused = S_build_unused_vars(param_vars); - char *unreachable = S_maybe_unreachable(return_type); - - char pattern[] = - "%s\n" - "%s(%s) {%s\n" - " CFISH_THROW(CFISH_ERR, \"Can't override %s via binding\");%s\n" - "}\n"; - size_t size = sizeof(pattern) - + strlen(ret_type_str) - + strlen(override_sym) - + strlen(params) - + strlen(unused) - + strlen(full_method_sym) - + strlen(unreachable) - + 20; - char *callback_def = (char*)MALLOCATE(size); - sprintf(callback_def, pattern, ret_type_str, override_sym, params, unused, - full_method_sym, unreachable); - - FREEMEM(full_method_sym); - FREEMEM(unreachable); - FREEMEM(unused); - return callback_def; -} - -static char* -S_void_callback_def(CFCMethod *method, const char *callback_params, - const char *refcount_mods) { - const char *override_sym = CFCMethod_full_override_sym(method); - const char *params = CFCParamList_to_c(CFCMethod_get_param_list(method)); - const char pattern[] = - "void\n" - "%s(%s) {\n" - " cfish_Host_callback(%s);%s\n" - "}\n"; - size_t size = sizeof(pattern) - + strlen(override_sym) - + strlen(params) - + strlen(callback_params) - + strlen(refcount_mods) - + 200; - char *callback_def = (char*)MALLOCATE(size); - sprintf(callback_def, pattern, override_sym, params, callback_params, - refcount_mods); - return callback_def; -} - -static char* -S_primitive_callback_def(CFCMethod *method, const char *callback_params, - const char *refcount_mods) { - const char *override_sym = CFCMethod_full_override_sym(method); - const char *params = CFCParamList_to_c(CFCMethod_get_param_list(method)); - CFCType *return_type = CFCMethod_get_return_type(method); - const char *ret_type_str = CFCType_to_c(return_type); - char cb_func_name[40]; - if (CFCType_is_floating(return_type)) { - strcpy(cb_func_name, "cfish_Host_callback_f64"); - } - else if (CFCType_is_integer(return_type)) { - strcpy(cb_func_name, "cfish_Host_callback_i64"); - } - else if (strcmp(ret_type_str, "void*") == 0) { - strcpy(cb_func_name, "cfish_Host_callback_host"); - } - else { - CFCUtil_die("unrecognized type: %s", ret_type_str); - } - - char pattern[] = - "%s\n" - "%s(%s) {\n" - " return (%s)%s(%s);%s\n" - "}\n"; - size_t size = sizeof(pattern) - + strlen(ret_type_str) - + strlen(override_sym) - + strlen(params) - + strlen(ret_type_str) - + strlen(cb_func_name) - + strlen(callback_params) - + strlen(refcount_mods) - + 20; - char *callback_def = (char*)MALLOCATE(size); - sprintf(callback_def, pattern, ret_type_str, override_sym, params, - ret_type_str, cb_func_name, callback_params, refcount_mods); - - return callback_def; -} - -static char* -S_obj_callback_def(CFCMethod *method, const char *callback_params, - const char *refcount_mods) { - const char *override_sym = CFCMethod_full_override_sym(method); - const char *params = CFCParamList_to_c(CFCMethod_get_param_list(method)); - CFCType *return_type = CFCMethod_get_return_type(method); - const char *ret_type_str = CFCType_to_c(return_type); - const char *cb_func_name = CFCType_is_string_type(return_type) - ? "cfish_Host_callback_str" - : "cfish_Host_callback_obj"; - - char *nullable_check = CFCUtil_strdup(""); - if (!CFCType_nullable(return_type)) { - const char *macro_sym = CFCMethod_get_macro_sym(method); - char pattern[] = - "\n if (!retval) { CFISH_THROW(CFISH_ERR, " - "\"%s() for class '%%o' cannot return NULL\", " - "Cfish_Obj_Get_Class_Name((cfish_Obj*)self)); }"; - size_t size = sizeof(pattern) + strlen(macro_sym) + 30; - nullable_check = (char*)REALLOCATE(nullable_check, size); - sprintf(nullable_check, pattern, macro_sym); - } - - char pattern[] = - "%s\n" - "%s(%s) {\n" - " %s retval = (%s)%s(%s);%s%s\n" - " return retval;\n" - "}\n"; - size_t size = sizeof(pattern) - + strlen(ret_type_str) - + strlen(override_sym) - + strlen(params) - + strlen(ret_type_str) - + strlen(ret_type_str) - + strlen(cb_func_name) - + strlen(callback_params) - + strlen(nullable_check) - + strlen(refcount_mods) - + 30; - char *callback_def = (char*)MALLOCATE(size); - sprintf(callback_def, pattern, ret_type_str, override_sym, params, - ret_type_str, ret_type_str, cb_func_name, callback_params, - nullable_check, refcount_mods); - - FREEMEM(nullable_check); - return callback_def; -} - http://git-wip-us.apache.org/repos/asf/lucy/blob/96084df9/clownfish/compiler/src/CFCBindMethod.h ---------------------------------------------------------------------- diff --git a/clownfish/compiler/src/CFCBindMethod.h b/clownfish/compiler/src/CFCBindMethod.h index fc15c4f..85945da 100644 --- a/clownfish/compiler/src/CFCBindMethod.h +++ b/clownfish/compiler/src/CFCBindMethod.h @@ -62,13 +62,6 @@ CFCBindMeth_abstract_method_def(struct CFCMethod *method); char* CFCBindMeth_callback_dec(struct CFCMethod *method); -/** Return C code implementing a callback to the Host for this method. This - * code is used when a Host method has overridden a method in a Clownfish - * class. - */ -char* -CFCBindMeth_callback_def(struct CFCMethod *method); - #ifdef __cplusplus } #endif http://git-wip-us.apache.org/repos/asf/lucy/blob/96084df9/clownfish/compiler/src/CFCPerl.c ---------------------------------------------------------------------- diff --git a/clownfish/compiler/src/CFCPerl.c b/clownfish/compiler/src/CFCPerl.c index ca30ad2..7e15e21 100644 --- a/clownfish/compiler/src/CFCPerl.c +++ b/clownfish/compiler/src/CFCPerl.c @@ -536,7 +536,7 @@ CFCPerl_write_callbacks(CFCPerl *self) { // Define callback. if (CFCMethod_novel(method) && !CFCMethod_final(method)) { - char *cb_def = CFCBindMeth_callback_def(method); + char *cb_def = CFCPerlMethod_callback_def(method); content = CFCUtil_cat(content, cb_def, "\n", NULL); FREEMEM(cb_def); } http://git-wip-us.apache.org/repos/asf/lucy/blob/96084df9/clownfish/compiler/src/CFCPerlMethod.c ---------------------------------------------------------------------- diff --git a/clownfish/compiler/src/CFCPerlMethod.c b/clownfish/compiler/src/CFCPerlMethod.c index 7c91f0b..aab6429 100644 --- a/clownfish/compiler/src/CFCPerlMethod.c +++ b/clownfish/compiler/src/CFCPerlMethod.c @@ -23,6 +23,7 @@ #include "CFCUtil.h" #include "CFCClass.h" #include "CFCMethod.h" +#include "CFCSymbol.h" #include "CFCType.h" #include "CFCParcel.h" #include "CFCParamList.h" @@ -51,6 +52,60 @@ S_xsub_def_labeled_params(CFCPerlMethod *self); static char* S_xsub_def_positional_args(CFCPerlMethod *self); +/* Take a NULL-terminated list of CFCVariables and build up a string of + * directives like: + * + * UNUSED_VAR(var1); + * UNUSED_VAR(var2); + */ +static char* +S_build_unused_vars(CFCVariable **vars); + +/* Create an unreachable return statement if necessary, in order to thwart + * compiler warnings. */ +static char* +S_maybe_unreachable(CFCType *return_type); + +/* Return a string which maps arguments to various arg wrappers conforming + * to Host's callback interface. For instance, (int32_t foo, Obj *bar) + * produces the following: + * + * CFISH_ARG_I32("foo", foo), + * CFISH_ARG_OBJ("bar", bar) + */ +static char* +S_callback_params(CFCMethod *method); + +/* Adapt the refcounts of parameters and return types, since Host_callback_xxx + * has no impact on refcounts aside from Host_callback_obj returning an + * incremented Obj. + */ +static char* +S_callback_refcount_mods(CFCMethod *method); + +/* Return a function which throws a runtime error indicating which variable + * couldn't be mapped. TODO: it would be better to resolve all these cases at + * compile-time. + */ +static char* +S_invalid_callback_def(CFCMethod *method); + +// Create a callback for a method which operates in a void context. +static char* +S_void_callback_def(CFCMethod *method, const char *callback_params, + const char *refcount_mods); + +// Create a callback which returns a primitive type. +static char* +S_primitive_callback_def(CFCMethod *method, const char *callback_params, + const char *refcount_mods); + +/* Create a callback which returns an object type -- either a generic object or + * a string. */ +static char* +S_obj_callback_def(CFCMethod *method, const char *callback_params, + const char *refcount_mods); + const static CFCMeta CFCPERLMETHOD_META = { "Clownfish::CFC::Binding::Perl::Method", sizeof(CFCPerlMethod), @@ -370,3 +425,324 @@ S_xsub_def_positional_args(CFCPerlMethod *self) { return xsub; } +char* +CFCPerlMethod_callback_def(CFCMethod *method) { + CFCType *return_type = CFCMethod_get_return_type(method); + char *params = S_callback_params(method); + char *callback_def = NULL; + char *refcount_mods = S_callback_refcount_mods(method); + + if (!params) { + // Can't map vars, because there's at least one type in the argument + // list we don't yet support. Return a callback wrapper that throws + // an error error. + callback_def = S_invalid_callback_def(method); + } + else if (CFCType_is_void(return_type)) { + callback_def = S_void_callback_def(method, params, refcount_mods); + } + else if (CFCType_is_object(return_type)) { + callback_def = S_obj_callback_def(method, params, refcount_mods); + } + else if (CFCType_is_integer(return_type) + || CFCType_is_floating(return_type) + ) { + callback_def = S_primitive_callback_def(method, params, refcount_mods); + } + else { + // Can't map return type. + callback_def = S_invalid_callback_def(method); + } + + FREEMEM(params); + FREEMEM(refcount_mods); + return callback_def; +} + +static char* +S_build_unused_vars(CFCVariable **vars) { + char *unused = CFCUtil_strdup(""); + + for (int i = 0; vars[i] != NULL; i++) { + const char *var_name = CFCVariable_micro_sym(vars[i]); + size_t size = strlen(unused) + strlen(var_name) + 80; + unused = (char*)REALLOCATE(unused, size); + strcat(unused, "\n CHY_UNUSED_VAR("); + strcat(unused, var_name); + strcat(unused, ");"); + } + + return unused; +} + +static char* +S_maybe_unreachable(CFCType *return_type) { + char *return_statement; + if (CFCType_is_void(return_type)) { + return_statement = CFCUtil_strdup(""); + } + else { + const char *ret_type_str = CFCType_to_c(return_type); + return_statement = (char*)MALLOCATE(strlen(ret_type_str) + 60); + sprintf(return_statement, "\n CHY_UNREACHABLE_RETURN(%s);", + ret_type_str); + } + return return_statement; +} + +static char* +S_callback_params(CFCMethod *method) { + const char *micro_sym = CFCSymbol_micro_sym((CFCSymbol*)method); + CFCParamList *param_list = CFCMethod_get_param_list(method); + unsigned num_params = CFCParamList_num_vars(param_list) - 1; + size_t needed = strlen(micro_sym) + 30; + char *params = (char*)MALLOCATE(needed); + + // TODO: use something other than micro_sym here. + sprintf(params, "self, \"%s\", %u", micro_sym, num_params); + + // Iterate over arguments, mapping them to various arg wrappers which + // conform to Host's callback interface. + CFCVariable **arg_vars = CFCParamList_get_variables(param_list); + for (int i = 1; arg_vars[i] != NULL; i++) { + CFCVariable *var = arg_vars[i]; + const char *name = CFCVariable_micro_sym(var); + size_t name_len = strlen(name); + CFCType *type = CFCVariable_get_type(var); + const char *c_type = CFCType_to_c(type); + size_t size = strlen(params) + + strlen(c_type) + + name_len * 2 + + 30; + char *new_buf = (char*)MALLOCATE(size); + + if (CFCType_is_string_type(type)) { + sprintf(new_buf, "%s, CFISH_ARG_STR(\"%s\", %s)", params, name, name); + } + else if (CFCType_is_object(type)) { + sprintf(new_buf, "%s, CFISH_ARG_OBJ(\"%s\", %s)", params, name, name); + } + else if (CFCType_is_integer(type)) { + int width = CFCType_get_width(type); + if (width) { + if (width <= 4) { + sprintf(new_buf, "%s, CFISH_ARG_I32(\"%s\", %s)", params, + name, name); + } + else { + sprintf(new_buf, "%s, CFISH_ARG_I64(\"%s\", %s)", params, + name, name); + } + } + else { + sprintf(new_buf, "%s, CFISH_ARG_I(%s, \"%s\", %s)", params, + c_type, name, name); + } + } + else if (CFCType_is_floating(type)) { + sprintf(new_buf, "%s, CFISH_ARG_F64(\"%s\", %s)", params, name, name); + } + else { + // Can't map variable type. Signal to caller. + FREEMEM(params); + FREEMEM(new_buf); + return NULL; + } + + FREEMEM(params); + params = new_buf; + } + + return params; +} + +static char* +S_callback_refcount_mods(CFCMethod *method) { + char *refcount_mods = CFCUtil_strdup(""); + CFCType *return_type = CFCMethod_get_return_type(method); + CFCParamList *param_list = CFCMethod_get_param_list(method); + CFCVariable **arg_vars = CFCParamList_get_variables(param_list); + + // Host_callback_obj returns an incremented object. If this method does + // not return an incremented object, we must cancel out that refcount. + // (No function can return a decremented object.) + if (CFCType_is_object(return_type) && !CFCType_incremented(return_type)) { + refcount_mods = CFCUtil_cat(refcount_mods, + "\n CFISH_DECREF(retval);", NULL); + } + + // The Host_callback_xxx functions have no effect on the refcounts of + // arguments, so we need to adjust them after the fact. + for (int i = 0; arg_vars[i] != NULL; i++) { + CFCVariable *var = arg_vars[i]; + CFCType *type = CFCVariable_get_type(var); + const char *name = CFCVariable_micro_sym(var); + if (!CFCType_is_object(type)) { + continue; + } + else if (CFCType_incremented(type)) { + refcount_mods = CFCUtil_cat(refcount_mods, "\n CFISH_INCREF(", + name, ");", NULL); + } + else if (CFCType_decremented(type)) { + refcount_mods = CFCUtil_cat(refcount_mods, "\n CFISH_DECREF(", + name, ");", NULL); + } + } + + return refcount_mods; +} + +static char* +S_invalid_callback_def(CFCMethod *method) { + size_t meth_sym_size = CFCMethod_full_method_sym(method, NULL, NULL, 0); + char *full_method_sym = (char*)MALLOCATE(meth_sym_size); + CFCMethod_full_method_sym(method, NULL, full_method_sym, meth_sym_size); + + const char *override_sym = CFCMethod_full_override_sym(method); + CFCParamList *param_list = CFCMethod_get_param_list(method); + const char *params = CFCParamList_to_c(param_list); + CFCVariable **param_vars = CFCParamList_get_variables(param_list); + + // Thwart compiler warnings. + CFCType *return_type = CFCMethod_get_return_type(method); + const char *ret_type_str = CFCType_to_c(return_type); + char *unused = S_build_unused_vars(param_vars); + char *unreachable = S_maybe_unreachable(return_type); + + char pattern[] = + "%s\n" + "%s(%s) {%s\n" + " CFISH_THROW(CFISH_ERR, \"Can't override %s via binding\");%s\n" + "}\n"; + size_t size = sizeof(pattern) + + strlen(ret_type_str) + + strlen(override_sym) + + strlen(params) + + strlen(unused) + + strlen(full_method_sym) + + strlen(unreachable) + + 20; + char *callback_def = (char*)MALLOCATE(size); + sprintf(callback_def, pattern, ret_type_str, override_sym, params, unused, + full_method_sym, unreachable); + + FREEMEM(full_method_sym); + FREEMEM(unreachable); + FREEMEM(unused); + return callback_def; +} + +static char* +S_void_callback_def(CFCMethod *method, const char *callback_params, + const char *refcount_mods) { + const char *override_sym = CFCMethod_full_override_sym(method); + const char *params = CFCParamList_to_c(CFCMethod_get_param_list(method)); + const char pattern[] = + "void\n" + "%s(%s) {\n" + " cfish_Host_callback(%s);%s\n" + "}\n"; + size_t size = sizeof(pattern) + + strlen(override_sym) + + strlen(params) + + strlen(callback_params) + + strlen(refcount_mods) + + 200; + char *callback_def = (char*)MALLOCATE(size); + sprintf(callback_def, pattern, override_sym, params, callback_params, + refcount_mods); + return callback_def; +} + +static char* +S_primitive_callback_def(CFCMethod *method, const char *callback_params, + const char *refcount_mods) { + const char *override_sym = CFCMethod_full_override_sym(method); + const char *params = CFCParamList_to_c(CFCMethod_get_param_list(method)); + CFCType *return_type = CFCMethod_get_return_type(method); + const char *ret_type_str = CFCType_to_c(return_type); + char cb_func_name[40]; + if (CFCType_is_floating(return_type)) { + strcpy(cb_func_name, "cfish_Host_callback_f64"); + } + else if (CFCType_is_integer(return_type)) { + strcpy(cb_func_name, "cfish_Host_callback_i64"); + } + else if (strcmp(ret_type_str, "void*") == 0) { + strcpy(cb_func_name, "cfish_Host_callback_host"); + } + else { + CFCUtil_die("unrecognized type: %s", ret_type_str); + } + + char pattern[] = + "%s\n" + "%s(%s) {\n" + " return (%s)%s(%s);%s\n" + "}\n"; + size_t size = sizeof(pattern) + + strlen(ret_type_str) + + strlen(override_sym) + + strlen(params) + + strlen(ret_type_str) + + strlen(cb_func_name) + + strlen(callback_params) + + strlen(refcount_mods) + + 20; + char *callback_def = (char*)MALLOCATE(size); + sprintf(callback_def, pattern, ret_type_str, override_sym, params, + ret_type_str, cb_func_name, callback_params, refcount_mods); + + return callback_def; +} + +static char* +S_obj_callback_def(CFCMethod *method, const char *callback_params, + const char *refcount_mods) { + const char *override_sym = CFCMethod_full_override_sym(method); + const char *params = CFCParamList_to_c(CFCMethod_get_param_list(method)); + CFCType *return_type = CFCMethod_get_return_type(method); + const char *ret_type_str = CFCType_to_c(return_type); + const char *cb_func_name = CFCType_is_string_type(return_type) + ? "cfish_Host_callback_str" + : "cfish_Host_callback_obj"; + + char *nullable_check = CFCUtil_strdup(""); + if (!CFCType_nullable(return_type)) { + const char *macro_sym = CFCMethod_get_macro_sym(method); + char pattern[] = + "\n if (!retval) { CFISH_THROW(CFISH_ERR, " + "\"%s() for class '%%o' cannot return NULL\", " + "Cfish_Obj_Get_Class_Name((cfish_Obj*)self)); }"; + size_t size = sizeof(pattern) + strlen(macro_sym) + 30; + nullable_check = (char*)REALLOCATE(nullable_check, size); + sprintf(nullable_check, pattern, macro_sym); + } + + char pattern[] = + "%s\n" + "%s(%s) {\n" + " %s retval = (%s)%s(%s);%s%s\n" + " return retval;\n" + "}\n"; + size_t size = sizeof(pattern) + + strlen(ret_type_str) + + strlen(override_sym) + + strlen(params) + + strlen(ret_type_str) + + strlen(ret_type_str) + + strlen(cb_func_name) + + strlen(callback_params) + + strlen(nullable_check) + + strlen(refcount_mods) + + 30; + char *callback_def = (char*)MALLOCATE(size); + sprintf(callback_def, pattern, ret_type_str, override_sym, params, + ret_type_str, ret_type_str, cb_func_name, callback_params, + nullable_check, refcount_mods); + + FREEMEM(nullable_check); + return callback_def; +} + http://git-wip-us.apache.org/repos/asf/lucy/blob/96084df9/clownfish/compiler/src/CFCPerlMethod.h ---------------------------------------------------------------------- diff --git a/clownfish/compiler/src/CFCPerlMethod.h b/clownfish/compiler/src/CFCPerlMethod.h index 5c4638d..dbd19c0 100644 --- a/clownfish/compiler/src/CFCPerlMethod.h +++ b/clownfish/compiler/src/CFCPerlMethod.h @@ -54,6 +54,13 @@ CFCPerlMethod_destroy(CFCPerlMethod *self); char* CFCPerlMethod_xsub_def(CFCPerlMethod *self); +/** Return C code implementing a callback to Perl for this method. This code + * is run when a Perl subclass has overridden a method in a Clownfish base + * class. + */ +char* +CFCPerlMethod_callback_def(struct CFCMethod *method); + #ifdef __cplusplus } #endif
