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);

Reply via email to