You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by ma...@apache.org on 2012/11/14 03:22:12 UTC
[lucy-commits] [5/7] git commit: refs/heads/master - Move code for generating
callbacks.
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 <ma...@rectangular.com>
Authored: Fri Nov 9 18:26:35 2012 -0800
Committer: Marvin Humphrey <ma...@rectangular.com>
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