Autogenerate CGO method bindings.

Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/8f15e5a1
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/8f15e5a1
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/8f15e5a1

Branch: refs/heads/master
Commit: 8f15e5a1be84bba8c497c54180d8715015d45255
Parents: 0d5e92e
Author: Marvin Humphrey <[email protected]>
Authored: Mon Apr 6 20:11:42 2015 -0700
Committer: Marvin Humphrey <[email protected]>
Committed: Wed May 6 14:28:15 2015 -0700

----------------------------------------------------------------------
 compiler/src/CFCGo.c       |  19 ++++++-
 compiler/src/CFCGoClass.c  |  22 ++++++++
 compiler/src/CFCGoClass.h  |   3 ++
 compiler/src/CFCGoFunc.c   | 100 ++++++++++++++++++++++++++++++++++++
 compiler/src/CFCGoFunc.h   |  43 ++++++++++++++++
 compiler/src/CFCGoMethod.c | 109 ++++++++++++++++++++++++++++++++++++++++
 compiler/src/CFCGoMethod.h |   3 ++
 7 files changed, 298 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8f15e5a1/compiler/src/CFCGo.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGo.c b/compiler/src/CFCGo.c
index 36d1263..be67747 100644
--- a/compiler/src/CFCGo.c
+++ b/compiler/src/CFCGo.c
@@ -30,6 +30,7 @@
 #include "CFCHierarchy.h"
 #include "CFCUtil.h"
 #include "CFCGoClass.h"
+#include "CFCGoMethod.h"
 #include "CFCGoTypeMap.h"
 
 static void
@@ -191,9 +192,15 @@ S_gen_autogen_go(CFCGo *self, CFCParcel *parcel) {
     CFCGoClass **registry = CFCGoClass_registry();
     char *type_decs   = CFCUtil_strdup("");
     char *boilerplate = CFCUtil_strdup("");
+    char *meth_defs   = CFCUtil_strdup("");
 
     for (int i = 0; registry[i] != NULL; i++) {
         CFCGoClass *class_binding = registry[i];
+        CFCClass *client = CFCGoClass_get_client(class_binding);
+
+        if (CFCClass_get_parcel(client) != parcel) {
+            continue;
+        }
 
         char *type_dec = CFCGoClass_go_typing(class_binding);
         type_decs = CFCUtil_cat(type_decs, type_dec, "\n", NULL);
@@ -202,6 +209,10 @@ S_gen_autogen_go(CFCGo *self, CFCParcel *parcel) {
         char *boiler_code = CFCGoClass_boilerplate_funcs(class_binding);
         boilerplate = CFCUtil_cat(boilerplate, boiler_code, "\n", NULL);
         FREEMEM(boiler_code);
+
+        char *glue = CFCGoClass_gen_meth_glue(class_binding);
+        meth_defs = CFCUtil_cat(meth_defs, glue, "\n", NULL);
+        FREEMEM(glue);
     }
 
     char pattern[] =
@@ -213,9 +224,15 @@ S_gen_autogen_go(CFCGo *self, CFCParcel *parcel) {
         "\n"
         "%s\n"
         "\n"
+        "// Method bindings.\n"
+        "\n"
+        "%s\n"
+        "\n"
         ;
-    char *content = CFCUtil_sprintf(pattern, type_decs, boilerplate);
+    char *content
+        = CFCUtil_sprintf(pattern, type_decs, boilerplate, meth_defs);
 
+    FREEMEM(meth_defs);
     FREEMEM(boilerplate);
     FREEMEM(type_decs);
     return content;

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8f15e5a1/compiler/src/CFCGoClass.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGoClass.c b/compiler/src/CFCGoClass.c
index d35d3f3..50e512c 100644
--- a/compiler/src/CFCGoClass.c
+++ b/compiler/src/CFCGoClass.c
@@ -266,6 +266,15 @@ S_lazy_init_method_bindings(CFCGoClass *self) {
             continue;
         }
 
+        // Only include novel methods.
+        if (!CFCMethod_novel(method)) {
+            continue;
+        }
+        const char *sym = CFCMethod_get_macro_sym(method);
+        if (!CFCClass_fresh_method(self->client, sym)) {
+            continue;
+        }
+
         /* Create the binding, add it to the array.
          */
         CFCGoMethod *meth_binding = CFCGoMethod_new(method);
@@ -280,3 +289,16 @@ S_lazy_init_method_bindings(CFCGoClass *self) {
     self->num_bound       = num_bound;
 }
 
+char*
+CFCGoClass_gen_meth_glue(CFCGoClass *self) {
+    S_lazy_init_method_bindings(self);
+    char *meth_defs = CFCUtil_strdup("");
+    for (size_t i = 0; self->method_bindings[i] != NULL; i++) {
+        CFCGoMethod *meth_binding = self->method_bindings[i];
+        char *method_def = CFCGoMethod_func_def(meth_binding);
+        meth_defs = CFCUtil_cat(meth_defs, method_def, "\n", NULL);
+        FREEMEM(method_def);
+    }
+    return meth_defs;
+}
+

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8f15e5a1/compiler/src/CFCGoClass.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGoClass.h b/compiler/src/CFCGoClass.h
index a1f603c..98d5fce 100644
--- a/compiler/src/CFCGoClass.h
+++ b/compiler/src/CFCGoClass.h
@@ -70,6 +70,9 @@ CFCGoClass_go_typing(CFCGoClass *self);
 char*
 CFCGoClass_boilerplate_funcs(CFCGoClass *self);
 
+char*
+CFCGoClass_gen_meth_glue(CFCGoClass *self);
+
 #ifdef __cplusplus
 }
 #endif

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8f15e5a1/compiler/src/CFCGoFunc.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGoFunc.c b/compiler/src/CFCGoFunc.c
new file mode 100644
index 0000000..db540aa
--- /dev/null
+++ b/compiler/src/CFCGoFunc.c
@@ -0,0 +1,100 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <string.h>
+#include <stdio.h>
+#include "CFCGoFunc.h"
+#include "CFCGoTypeMap.h"
+#include "CFCBase.h"
+#include "CFCFunction.h"
+#include "CFCUtil.h"
+#include "CFCParcel.h"
+#include "CFCParamList.h"
+#include "CFCVariable.h"
+#include "CFCType.h"
+
+#ifndef true
+    #define true 1
+    #define false 0
+#endif
+
+char*
+CFCGoFunc_go_meth_name(const char *orig) {
+    char *go_name = CFCUtil_strdup(orig);
+    for (int i = 0, j = 0, max = strlen(go_name) + 1; i < max; i++) {
+        if (go_name[i] != '_') {
+            go_name[j++] = go_name[i];
+        }
+    }
+    return go_name;
+}
+
+char*
+CFCGoFunc_func_start(CFCParcel *parcel, const char *name,
+                     CFCParamList *param_list, CFCType *return_type,
+                     int is_method) {
+    CFCVariable **param_vars = CFCParamList_get_variables(param_list);
+    char *invocant;
+    if (is_method) {
+        CFCVariable *var = param_vars[0];
+        CFCType *type = CFCVariable_get_type(var);
+        char *go_type_name = CFCGoTypeMap_go_type_name(type, parcel);
+        invocant = CFCUtil_sprintf("(%s *%sIMP) ", CFCVariable_micro_sym(var),
+                                   go_type_name);
+        FREEMEM(go_type_name);
+    }
+    else {
+        invocant = CFCUtil_strdup("");
+    }
+
+    char *params = CFCUtil_strdup("");
+    int start = is_method ? 1 : 0;
+    for (int i = start; param_vars[i] != NULL; i++) {
+        CFCVariable *var = param_vars[i];
+        CFCType *type = CFCVariable_get_type(var);
+        char *go_type_name = CFCGoTypeMap_go_type_name(type, parcel);
+        if (i > start) {
+            params = CFCUtil_cat(params, ", ", NULL);
+        }
+        params = CFCUtil_cat(params, CFCVariable_micro_sym(var), " ",
+                             go_type_name, NULL);
+        FREEMEM(go_type_name);
+    }
+
+    char *ret_type_str;
+    if (CFCType_is_void(return_type)) {
+        ret_type_str = CFCUtil_strdup("");
+    }
+    else {
+        ret_type_str = CFCGoTypeMap_go_type_name(return_type, parcel);
+        if (ret_type_str == NULL) {
+            CFCUtil_die("Can't convert invalid type in method %s", name);
+        }
+    }
+
+    char pattern[] =
+        "func %s%s(%s) %s {\n"
+    ;
+    char *content
+        = CFCUtil_sprintf(pattern, invocant, name, params, ret_type_str);
+
+    FREEMEM(invocant);
+    FREEMEM(params);
+    FREEMEM(ret_type_str);
+    return content;
+}
+

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8f15e5a1/compiler/src/CFCGoFunc.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGoFunc.h b/compiler/src/CFCGoFunc.h
new file mode 100644
index 0000000..d9ee98b
--- /dev/null
+++ b/compiler/src/CFCGoFunc.h
@@ -0,0 +1,43 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef H_CFCGOFUNC
+#define H_CFCGOFUNC
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct CFCFunction;
+struct CFCParcel;
+struct CFCType;
+struct CFCParamList;
+
+char*
+CFCGoFunc_go_meth_name(const char *orig);
+
+char*
+CFCGoFunc_func_start(struct CFCParcel *parcel, const char *name,
+                     struct CFCParamList *param_list,
+                     struct CFCType *return_type, int is_method);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_CFCGOFUNC */
+

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8f15e5a1/compiler/src/CFCGoMethod.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGoMethod.c b/compiler/src/CFCGoMethod.c
index ae1999e..7aef897 100644
--- a/compiler/src/CFCGoMethod.c
+++ b/compiler/src/CFCGoMethod.c
@@ -21,6 +21,7 @@
 
 #define CFC_NEED_BASE_STRUCT_DEF
 #include "CFCBase.h"
+#include "CFCGoFunc.h"
 #include "CFCGoMethod.h"
 #include "CFCUtil.h"
 #include "CFCClass.h"
@@ -66,3 +67,111 @@ S_CFCGoMethod_destroy(CFCGoMethod *self) {
     CFCBase_destroy((CFCBase*)self);
 }
 
+static char*
+S_prep_cfargs(CFCParamList *param_list) {
+    CFCVariable **vars = CFCParamList_get_variables(param_list);
+    char *cfargs = CFCUtil_strdup("");
+    for (int i = 0; vars[i] != NULL; i++) {
+        CFCVariable *var = vars[i];
+        CFCType *type = CFCVariable_get_type(var);
+        const char *name = CFCVariable_micro_sym(var);
+        if (i > 0) {
+            cfargs = CFCUtil_cat(cfargs, ", ", NULL);
+        }
+        if (CFCType_is_primitive(type)) {
+            cfargs = CFCUtil_cat(cfargs, "C.", CFCType_get_specifier(type),
+                                 "(", name, ")", NULL);
+        }
+        else if (CFCType_is_object(type)) {
+            char *obj_pattern;
+            if (CFCType_decremented(type)) {
+                obj_pattern = 
"%s(*C.%s)(unsafe.Pointer(C.cfish_inc_refcount(unsafe.Pointer(%s.TOPTR()))))";
+            }
+            else {
+                obj_pattern = "%s(*C.%s)(unsafe.Pointer(%s.TOPTR()))";
+            }
+            char *temp = CFCUtil_sprintf(obj_pattern, cfargs,
+                                         CFCType_get_specifier(type), name);
+            FREEMEM(cfargs);
+            cfargs = temp;
+        }
+    }
+    return cfargs;
+}
+
+char*
+CFCGoMethod_func_def(CFCGoMethod *self) {
+    CFCMethod    *method     = self->method;
+    CFCParcel    *parcel     = CFCMethod_get_parcel(method);
+    CFCParamList *param_list = CFCMethod_get_param_list(method);
+    CFCType      *ret_type   = CFCMethod_get_return_type(method);
+    char *name = CFCGoFunc_go_meth_name(CFCMethod_get_macro_sym(method));
+    char *first_line = CFCGoFunc_func_start(parcel, name, param_list,
+                                            ret_type, true);
+    char *full_meth_sym = CFCMethod_full_method_sym(method, NULL);
+
+    char *cfargs = S_prep_cfargs(param_list);
+
+    char *ret_type_str;
+    char *maybe_retval;
+    char *maybe_return;
+    if (CFCType_is_void(ret_type)) {
+        ret_type_str = CFCUtil_strdup("");
+        maybe_retval = CFCUtil_strdup("");
+        maybe_return = CFCUtil_strdup("");
+    }
+    else {
+        ret_type_str = CFCGoTypeMap_go_type_name(ret_type, parcel);
+        if (ret_type_str == NULL) {
+            CFCUtil_die("Can't convert invalid type in method %s", name);
+        }
+        maybe_retval = CFCUtil_strdup("retvalCF := ");
+
+        if (CFCType_is_primitive(ret_type)) {
+            maybe_return = CFCUtil_sprintf("\treturn %s(retvalCF)\n", 
ret_type_str);
+        }
+        else if (CFCType_is_object(ret_type)) {
+            char *go_type_name = CFCGoTypeMap_go_type_name(ret_type, parcel);
+            char *struct_name  = go_type_name;
+            char *go_package   = CFCUtil_strdup(go_type_name);
+            for (int i = strlen(go_package) - 1; i >= 0; i--) {
+                if (go_package[i] == '.') {
+                    struct_name += i + 1;
+                    break;
+                }
+                go_package[i] = '\0';
+            }
+            char *pattern;
+            if (CFCType_incremented(ret_type)) {
+                pattern = "\treturn %sWRAP%s(unsafe.Pointer(retvalCF))\n";
+            }
+            else {
+                pattern = "\treturn 
%sWRAP%s(unsafe.Pointer(C.cfish_inc_refcount(unsafe.Pointer(retvalCF))))\n";
+            }
+            maybe_return = CFCUtil_sprintf(pattern, go_package, struct_name);
+            FREEMEM(go_type_name);
+            FREEMEM(go_package);
+        }
+        else {
+            CFCUtil_die("Unexpected type: %s", CFCType_to_c(ret_type));
+        }
+    }
+
+    char pattern[] =
+        "%s"
+        "\t%sC.%s(%s)\n"
+        "%s"
+        "}\n"
+        ;
+    char *content = CFCUtil_sprintf(pattern, first_line, maybe_retval,
+                                    full_meth_sym, cfargs, maybe_return);
+
+    FREEMEM(maybe_retval);
+    FREEMEM(maybe_return);
+    FREEMEM(ret_type_str);
+    FREEMEM(cfargs);
+    FREEMEM(first_line);
+    FREEMEM(name);
+    return content;
+}
+

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8f15e5a1/compiler/src/CFCGoMethod.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGoMethod.h b/compiler/src/CFCGoMethod.h
index be8c1a6..b94529e 100644
--- a/compiler/src/CFCGoMethod.h
+++ b/compiler/src/CFCGoMethod.h
@@ -30,6 +30,9 @@ struct CFCMethod;
 CFCGoMethod*
 CFCGoMethod_new(struct CFCMethod *method);
 
+char*
+CFCGoMethod_func_def(CFCGoMethod *self);
+
 #ifdef __cplusplus
 }
 #endif

Reply via email to