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 2015/05/07 00:18:46 UTC

[20/23] lucy-clownfish git commit: Enable customized Go method bindings.

Enable customized Go method bindings.

Allow Clownfish methods to be bound to Go using custom signatures, and
allow arbitrary methods to be added.  In both cases, the expectation is
that the user will supply the implementation code, as customizing the
signature disables autogenerating the default binding (which would
presumably not match the custom signature).


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

Branch: refs/heads/master
Commit: 905b30ac531a852fd45060367a380a9110b13d6c
Parents: 98c71c1
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Sun Apr 12 09:24:13 2015 -0700
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Wed May 6 14:28:16 2015 -0700

----------------------------------------------------------------------
 compiler/go/cfc/cfc.go     | 14 +++++++++
 compiler/src/CFCGoClass.c  | 69 +++++++++++++++++++++++++----------------
 compiler/src/CFCGoClass.h  |  3 ++
 compiler/src/CFCGoMethod.c | 41 +++++++++++++++++++++---
 compiler/src/CFCGoMethod.h | 13 ++++++--
 runtime/go/build.go        | 11 +++++++
 6 files changed, 119 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/905b30ac/compiler/go/cfc/cfc.go
----------------------------------------------------------------------
diff --git a/compiler/go/cfc/cfc.go b/compiler/go/cfc/cfc.go
index 8d09880..fa9b8d7 100644
--- a/compiler/go/cfc/cfc.go
+++ b/compiler/go/cfc/cfc.go
@@ -266,3 +266,17 @@ func (obj *BindGoClass) finalize() {
 func (obj *BindGoClass) Register() {
 	C.CFCGoClass_register(obj.ref)
 }
+
+func (obj *BindGoClass) SpecMethod(name, sig string) {
+	var nameC *C.char
+	if name != "" {
+		nameC = C.CString(name)
+		defer C.free(unsafe.Pointer(nameC))
+	}
+	var sigC *C.char
+	if sig != "" {
+		sigC = C.CString(sig)
+		defer C.free(unsafe.Pointer(sigC))
+	}
+	C.CFCGoClass_spec_method(obj.ref, nameC, sigC)
+}

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/905b30ac/compiler/src/CFCGoClass.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGoClass.c b/compiler/src/CFCGoClass.c
index d75eaad..6e32f68 100644
--- a/compiler/src/CFCGoClass.c
+++ b/compiler/src/CFCGoClass.c
@@ -190,50 +190,35 @@ CFCGoClass_go_typing(CFCGoClass *self) {
             go_struct_def = CFCUtil_strdup("");
         }
 
-        // Temporary hack until it's possible to customize interfaces.
-        char *temp_hack_iface_methods;
-        if (strcmp(self->class_name, "Clownfish::Obj") == 0) {
-            temp_hack_iface_methods = CFCUtil_strdup("\tTOPTR() uintptr\n");
-        }
-        else if (strcmp(self->class_name, "Clownfish::Err") == 0) {
-            temp_hack_iface_methods = CFCUtil_strdup("\tError() string\n");
-        }
-        else {
-            temp_hack_iface_methods = CFCUtil_strdup("");
-        }
-
         char *novel_iface = CFCUtil_strdup("");
         S_lazy_init_method_bindings(self);
         for (int i = 0; self->method_bindings[i] != NULL; i++) {
             CFCGoMethod *meth_binding = self->method_bindings[i];
             CFCMethod *method = CFCGoMethod_get_client(meth_binding);
-            if (!CFCMethod_novel(method)) {
-                continue;
-            }
-            const char *sym = CFCMethod_get_macro_sym(method);
-            if (!CFCClass_fresh_method(self->client, sym)) {
-                continue;
+            if (method) {
+                if (!CFCMethod_novel(method)) {
+                    continue;
+                }
+                const char *sym = CFCMethod_get_macro_sym(method);
+                if (!CFCClass_fresh_method(self->client, sym)) {
+                    continue;
+                }
             }
 
-            char *iface_sig = CFCGoMethod_iface_sig(meth_binding);
-            novel_iface
-                = CFCUtil_cat(novel_iface, "\t", iface_sig, "\n", NULL);
-            FREEMEM(iface_sig);
+            const char *sig = CFCGoMethod_get_sig(meth_binding);
+            novel_iface = CFCUtil_cat(novel_iface, "\t", sig, "\n", NULL);
         }
 
         char pattern[] =
             "type %s interface {\n"
             "%s"
             "%s"
-            "%s"
             "}\n"
             "\n"
             "%s"
             ;
         content = CFCUtil_sprintf(pattern, short_struct, parent_iface,
-                                  temp_hack_iface_methods, novel_iface,
-                                  go_struct_def);
-        FREEMEM(temp_hack_iface_methods);
+                                  novel_iface, go_struct_def);
         FREEMEM(go_struct_def);
         FREEMEM(parent_iface);
     }
@@ -328,3 +313,35 @@ CFCGoClass_gen_meth_glue(CFCGoClass *self) {
     return meth_defs;
 }
 
+void
+CFCGoClass_spec_method(CFCGoClass *self, const char *name, const char *sig) {
+    CFCUTIL_NULL_CHECK(sig);
+    S_lazy_init_method_bindings(self);
+    if (!name) {
+        CFCGoMethod *meth_binding = CFCGoMethod_new(NULL);
+        CFCGoMethod_customize(meth_binding, sig);
+
+        size_t size = (self->num_bound + 2) * sizeof(CFCGoMethod*);
+        self->method_bindings
+            = (CFCGoMethod**)REALLOCATE(self->method_bindings, size);
+        self->method_bindings[self->num_bound] = meth_binding;
+        self->num_bound++;
+        self->method_bindings[self->num_bound] = NULL;
+    }
+    else {
+        CFCGoMethod *binding = NULL;
+        for (int i = 0; self->method_bindings[i] != NULL; i++) {
+            CFCGoMethod *candidate = self->method_bindings[i];
+            CFCMethod *meth = CFCGoMethod_get_client(candidate);
+            if (meth && strcmp(name, CFCMethod_get_macro_sym(meth)) == 0) {
+                binding = candidate;
+                break;
+            }
+        }
+        if (!binding) {
+            CFCUtil_die("Can't find a method named '%s'", name);
+        }
+        CFCGoMethod_customize(binding, sig);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/905b30ac/compiler/src/CFCGoClass.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGoClass.h b/compiler/src/CFCGoClass.h
index 98d5fce..b074a4f 100644
--- a/compiler/src/CFCGoClass.h
+++ b/compiler/src/CFCGoClass.h
@@ -73,6 +73,9 @@ CFCGoClass_boilerplate_funcs(CFCGoClass *self);
 char*
 CFCGoClass_gen_meth_glue(CFCGoClass *self);
 
+void
+CFCGoClass_spec_method(CFCGoClass *self, const char *name, const char *sig);
+
 #ifdef __cplusplus
 }
 #endif

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/905b30ac/compiler/src/CFCGoMethod.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGoMethod.c b/compiler/src/CFCGoMethod.c
index 2575153..fb05659 100644
--- a/compiler/src/CFCGoMethod.c
+++ b/compiler/src/CFCGoMethod.c
@@ -42,6 +42,7 @@
 struct CFCGoMethod {
     CFCBase     base;
     CFCMethod  *method;
+    char       *sig;
 };
 
 static void
@@ -58,12 +59,14 @@ CFCGoMethod_new(CFCMethod *method) {
     CFCGoMethod *self
         = (CFCGoMethod*)CFCBase_allocate(&CFCGOMETHOD_META);
     self->method = (CFCMethod*)CFCBase_incref((CFCBase*)method);
+    self->sig    = NULL;
     return self;
 }
 
 static void
 S_CFCGoMethod_destroy(CFCGoMethod *self) {
     CFCBase_decref((CFCBase*)self->method);
+    FREEMEM(self->sig);
     CFCBase_destroy((CFCBase*)self);
 }
 
@@ -72,8 +75,21 @@ CFCGoMethod_get_client(CFCGoMethod *self) {
     return self->method;
 }
 
-char*
-CFCGoMethod_iface_sig(CFCGoMethod *self) {
+void
+CFCGoMethod_customize(CFCGoMethod *self, const char *sig) {
+    FREEMEM(self->sig);
+    self->sig = CFCUtil_strdup(sig);
+    if (self->method) {
+        CFCMethod_exclude_from_host(self->method);
+    }
+}
+
+static void
+S_lazy_init_sig(CFCGoMethod *self) {
+    if (self->sig || !self->method) {
+        return;
+    }
+
     CFCMethod *method = self->method;
     CFCParcel *parcel = CFCMethod_get_parcel(method);
     CFCType *return_type = CFCMethod_get_return_type(method);
@@ -96,12 +112,25 @@ CFCGoMethod_iface_sig(CFCGoMethod *self) {
         FREEMEM(go_type);
     }
 
-    char *sig = CFCUtil_sprintf("%s(%s) %s", name, args, go_ret_type);
+    self->sig = CFCUtil_sprintf("%s(%s) %s", name, args, go_ret_type);
 
     FREEMEM(args);
     FREEMEM(go_ret_type);
     FREEMEM(name);
-    return sig;
+}
+
+const char*
+CFCGoMethod_get_sig(CFCGoMethod *self) {
+    if (self->sig) {
+        return self->sig;
+    }
+    else if (!self->method) {
+        return "";
+    }
+    else {
+        S_lazy_init_sig(self);
+        return self->sig;
+    }
 }
 
 #define GO_NAME_BUF_SIZE 128
@@ -149,6 +178,10 @@ S_prep_cfargs(CFCClass *invoker, CFCParamList *param_list) {
 
 char*
 CFCGoMethod_func_def(CFCGoMethod *self, CFCClass *invoker) {
+    if (!self->method || CFCMethod_excluded_from_host(self->method)) {
+        return CFCUtil_strdup("");
+    }
+
     CFCMethod    *novel_method = CFCMethod_find_novel_method(self->method);
     CFCParcel    *parcel     = CFCClass_get_parcel(invoker);
     CFCParamList *param_list = CFCMethod_get_param_list(novel_method);

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/905b30ac/compiler/src/CFCGoMethod.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGoMethod.h b/compiler/src/CFCGoMethod.h
index 55314d8..2d956e9 100644
--- a/compiler/src/CFCGoMethod.h
+++ b/compiler/src/CFCGoMethod.h
@@ -34,8 +34,17 @@ CFCGoMethod_new(struct CFCMethod *method);
 struct CFCMethod*
 CFCGoMethod_get_client(CFCGoMethod *self);
 
-char*
-CFCGoMethod_iface_sig(CFCGoMethod *self);
+/** Customize the a Go method binding.  Supply a method signature to be
+ * inserted into the Go interface and suppress the default method
+ * implementation.
+ */
+void
+CFCGoMethod_customize(CFCGoMethod *self, const char *sig);
+
+/** Retrieve the Go interface method signature.
+ */
+const char*
+CFCGoMethod_get_sig(CFCGoMethod *self);
 
 char*
 CFCGoMethod_func_def(CFCGoMethod *self, struct CFCClass *invoker);

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/905b30ac/runtime/go/build.go
----------------------------------------------------------------------
diff --git a/runtime/go/build.go b/runtime/go/build.go
index cf4cb82..4a182c7 100644
--- a/runtime/go/build.go
+++ b/runtime/go/build.go
@@ -127,12 +127,23 @@ func runCFC() {
 		goBinding.SetHeader(autogenHeader)
 		goBinding.SetSuppressInit(true)
 		parcel := cfc.FetchParcel("Clownfish")
+		specMethods(parcel)
 		packageDir := path.Join(buildDir, "clownfish")
 		goBinding.WriteBindings(parcel, packageDir)
 		hierarchy.WriteLog()
 	}
 }
 
+func specMethods(parcel *cfc.Parcel) {
+	objBinding := cfc.NewGoClass(parcel, "Clownfish::Obj")
+	objBinding.SpecMethod("", "TOPTR() uintptr")
+	objBinding.Register()
+
+	errBinding := cfc.NewGoClass(parcel, "Clownfish::Err")
+	errBinding.SpecMethod("", "Error() string")
+	errBinding.Register()
+}
+
 func prep() {
 	configure()
 	runCFC()