Gen OVERRIDE callbacks for Python. Generate the C functions which call back into Python from Clownfish-flavored C when a method is overridden.
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/335b61fc Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/335b61fc Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/335b61fc Branch: refs/heads/master Commit: 335b61fc0f35868d1cda0bb1bbd879c616df1ae3 Parents: 02617ac Author: Marvin Humphrey <[email protected]> Authored: Wed Jan 27 19:24:32 2016 -0800 Committer: Marvin Humphrey <[email protected]> Committed: Tue Feb 23 18:22:05 2016 -0800 ---------------------------------------------------------------------- compiler/src/CFCPyMethod.c | 109 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/335b61fc/compiler/src/CFCPyMethod.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCPyMethod.c b/compiler/src/CFCPyMethod.c index 3cc7b96..983df28 100644 --- a/compiler/src/CFCPyMethod.c +++ b/compiler/src/CFCPyMethod.c @@ -15,6 +15,7 @@ */ #include <string.h> +#include <ctype.h> #include "CFCPyMethod.h" #include "CFCPyTypeMap.h" @@ -47,6 +48,93 @@ S_build_unused_vars(CFCVariable **vars); static char* S_maybe_unreachable(CFCType *return_type); +static char* +S_build_py_args(CFCParamList *param_list) { + int num_vars = CFCParamList_num_vars(param_list); + CFCVariable **vars = CFCParamList_get_variables(param_list); + char pattern[] = " PyObject *cfcb_ARGS = S_pack_tuple(%d"; + char *py_args = CFCUtil_sprintf(pattern, num_vars - 1); + + for (int i = 1; vars[i] != NULL; i++) { + const char *var_name = CFCVariable_get_name(vars[i]); + CFCType *type = CFCVariable_get_type(vars[i]); + char *conversion = CFCPyTypeMap_c_to_py(type, var_name); + py_args = CFCUtil_cat(py_args, ",\n ", conversion, NULL); + FREEMEM(conversion); + } + py_args = CFCUtil_cat(py_args, ");", NULL); + + return py_args; +} + +static char* +S_build_pymeth_invocation(CFCMethod *method) { + CFCType *return_type = CFCMethod_get_return_type(method); + const char *micro_sym = CFCSymbol_get_name((CFCSymbol*)method); + char *invocation = NULL; + const char *ret_type_str = CFCType_to_c(return_type); + + if (CFCType_is_void(return_type)) { + const char pattern[] = + " CALL_PYMETH_VOID((PyObject*)self, \"%s\", cfcb_ARGS);"; + invocation = CFCUtil_sprintf(pattern, micro_sym); + } + else if (CFCType_is_object(return_type)) { + const char *nullable + = CFCType_nullable(return_type) ? "true" : "false"; + const char *ret_class = CFCType_get_class_var(return_type); + const char pattern[] = + " %s cfcb_RESULT = (%s)CALL_PYMETH_OBJ((PyObject*)self, \"%s\", cfcb_ARGS, %s, %s);"; + invocation = CFCUtil_sprintf(pattern, ret_type_str, ret_type_str, micro_sym, + ret_class, nullable); + } + else if (CFCType_is_primitive(return_type)) { + char type_upcase[64]; + if (strlen(ret_type_str) > 63) { + CFCUtil_die("Unexpectedly long type name: %s", ret_type_str); + } + for (int i = 0, max = strlen(ret_type_str) + 1; i < max; i++) { + type_upcase[i] = toupper(ret_type_str[i]); + } + const char pattern[] = + " %s cfcb_RESULT = CALL_PYMETH_%s((PyObject*)self, \"%s\", cfcb_ARGS);"; + invocation = CFCUtil_sprintf(pattern, ret_type_str, type_upcase, + micro_sym); + } + else { + CFCUtil_die("Unexpected return type: %s", CFCType_to_c(return_type)); + } + + return invocation; +} + +static char* +S_callback_refcount_mods(CFCParamList *param_list) { + char *refcount_mods = CFCUtil_strdup(""); + CFCVariable **arg_vars = CFCParamList_get_variables(param_list); + + // Adjust refcounts of arguments per method signature, so that Perl code + // does not have to. + for (int i = 0; arg_vars[i] != NULL; i++) { + CFCVariable *var = arg_vars[i]; + CFCType *type = CFCVariable_get_type(var); + const char *name = CFCVariable_get_name(var); + if (!CFCType_is_object(type)) { + continue; + } + else if (CFCType_incremented(type)) { + refcount_mods = CFCUtil_cat(refcount_mods, " CFISH_INCREF(", + name, ");\n", NULL); + } + else if (CFCType_decremented(type)) { + refcount_mods = CFCUtil_cat(refcount_mods, " CFISH_DECREF(", + name, ");\n", NULL); + } + } + + return refcount_mods; +} + char* CFCPyMethod_callback_def(CFCMethod *method, CFCClass *invoker) { CFCParamList *param_list = CFCMethod_get_param_list(method); @@ -57,8 +145,25 @@ CFCPyMethod_callback_def(CFCMethod *method, CFCClass *invoker) { char *override_sym = CFCMethod_full_override_sym(method, invoker); char *content; - //if (CFCMethod_can_be_bound(method)) { - if (false) { + if (CFCMethod_can_be_bound(method)) { + char *py_args = S_build_py_args(param_list); + char *invocation = S_build_pymeth_invocation(method); + char *refcount_mods = S_callback_refcount_mods(param_list); + const char *maybe_return = CFCType_is_void(return_type) + ? "" + : " return cfcb_RESULT;\n"; + + const char pattern[] = + "%s\n" + "%s(%s) {\n" + "%s\n" + "%s\n" + "%s" + "%s" + "}\n"; + content = CFCUtil_sprintf(pattern, ret_type_str, override_sym, params, + py_args, invocation, refcount_mods, + maybe_return); } else { char *unused = S_build_unused_vars(vars);
