Introduce `Unwrap`, `UnwrapNullable`.

Replace `UnwrapClownfish` with new functions that perform valid
nil-checking.  For nullable parameters, perform better error checking in
Go in order to throw better errors.


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

Branch: refs/heads/master
Commit: 7988b5ffd869afe613ab7becc3805a219b2f5c2f
Parents: 699a22b
Author: Marvin Humphrey <[email protected]>
Authored: Thu Aug 27 19:39:19 2015 -0700
Committer: Marvin Humphrey <[email protected]>
Committed: Tue Sep 8 19:09:24 2015 -0700

----------------------------------------------------------------------
 compiler/src/CFCGoFunc.c          | 34 +++++++++++++++++----------
 runtime/go/clownfish/clownfish.go | 43 ++++++++++++++++++++--------------
 2 files changed, 48 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/7988b5ff/compiler/src/CFCGoFunc.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGoFunc.c b/compiler/src/CFCGoFunc.c
index 34d3d48..0528c11 100644
--- a/compiler/src/CFCGoFunc.c
+++ b/compiler/src/CFCGoFunc.c
@@ -109,11 +109,11 @@ S_prep_start(CFCParcel *parcel, const char *name, 
CFCClass *invoker,
         // be nullable if it has a default value of "NULL".  (Since Go does
         // not support default values for method parameters, this is the only
         // default value we care about.)
-        const char *nullable = CFCType_nullable(type) ? "true" : "false";
+        int nullable = CFCType_nullable(type);
         if (default_values[i] != NULL
             && strcmp(default_values[i], "NULL") == 0
            ) {
-            nullable = "true";
+            nullable = true;
         }
 
         const char *class_var = NULL;
@@ -136,20 +136,29 @@ S_prep_start(CFCParcel *parcel, const char *name, 
CFCClass *invoker,
 
         if (class_var == NULL || (targ == IS_METHOD && i == 0)) {
             // Just unwrap -- don't convert.
-            char *pattern;
-            if (CFCType_decremented(type)) {
-                pattern =
-                    "\t%sCF := 
(*C.%s)(unsafe.Pointer(C.cfish_incref(%sUnwrapClownfish(%s, \"%s\", %s))))\n";
+            char *unwrapped;
+            if (nullable) {
+                unwrapped = CFCUtil_sprintf("%sUnwrapNullable(%s)",
+                                            clownfish_dot, go_name);
             }
             else {
-                pattern =
-                    "\t%sCF := (*C.%s)(%sUnwrapClownfish(%s, \"%s\", %s))\n";
+                unwrapped = CFCUtil_sprintf("%sUnwrap(%s, \"%s\")",
+                                            clownfish_dot, go_name, go_name);
+            }
+
+            if (CFCType_decremented(type)) {
+                char *pattern = "unsafe.Pointer(C.cfish_incref(%s))";
+                char *temp = CFCUtil_sprintf(pattern, unwrapped);
+                FREEMEM(unwrapped);
+                unwrapped = temp;
             }
-            char *conversion = CFCUtil_sprintf(pattern, go_name, struct_name,
-                                               clownfish_dot, go_name,
-                                               go_name, nullable);
+
+            char *conversion
+                = CFCUtil_sprintf("\t%sCF := (*C.%s)(%s)\n", go_name,
+                                  struct_name, unwrapped);
             converted = CFCUtil_cat(converted, conversion, NULL);
             FREEMEM(conversion);
+            FREEMEM(unwrapped);
             continue;
         }
 
@@ -157,7 +166,8 @@ S_prep_start(CFCParcel *parcel, const char *name, CFCClass 
*invoker,
             "\t%sCF := (*C.%s)(%sGoToClownfish(%s, unsafe.Pointer(C.%s), 
%s))\n";
         char *conversion = CFCUtil_sprintf(pattern, go_name, struct_name,
                                            clownfish_dot, go_name,
-                                           class_var, nullable);
+                                           class_var,
+                                           nullable ? "true" : "false");
         converted = CFCUtil_cat(converted, conversion, NULL);
         FREEMEM(conversion);
         if (CFCType_decremented(type)) {

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/7988b5ff/runtime/go/clownfish/clownfish.go
----------------------------------------------------------------------
diff --git a/runtime/go/clownfish/clownfish.go 
b/runtime/go/clownfish/clownfish.go
index b5a9401..b31ed5f 100644
--- a/runtime/go/clownfish/clownfish.go
+++ b/runtime/go/clownfish/clownfish.go
@@ -66,6 +66,7 @@ GoCfish_RunRoutine(CFISH_Err_Attempt_t routine, void 
*context) {
 import "C"
 import "runtime"
 import "unsafe"
+import "reflect"
 import "fmt"
 import "math"
 import "sync"
@@ -124,7 +125,7 @@ type ObjIMP struct {
 }
 
 func GetClass(o Obj) Class {
-       objCF := (*C.cfish_Obj)(unsafe.Pointer(o.TOPTR()))
+       objCF := (*C.cfish_Obj)(Unwrap(o, "o"))
        classCF := C.cfish_Obj_get_class(objCF)
        return WRAPClass(unsafe.Pointer(classCF))
 }
@@ -137,7 +138,7 @@ func FetchClass(className string) Class {
 }
 
 func (c *ClassIMP) GetMethods() []Method {
-       self := (*C.cfish_Class)(unsafe.Pointer(c.TOPTR()))
+       self := (*C.cfish_Class)(Unwrap(c, "c"))
        methsVec := C.CFISH_Class_Get_Methods(self)
        size := C.CFISH_Vec_Get_Size(methsVec)
        meths := make([]Method, 0, int(size))
@@ -149,7 +150,7 @@ func (c *ClassIMP) GetMethods() []Method {
 }
 
 func (c *ClassIMP) MakeObj() Obj {
-       self := (*C.cfish_Class)(unsafe.Pointer(c.TOPTR()))
+       self := (*C.cfish_Class)(Unwrap(c, "c"))
        retvalCF := C.CFISH_Class_Make_Obj_IMP(self)
        return WRAPAny(unsafe.Pointer(retvalCF))
 }
@@ -170,7 +171,7 @@ func NewString(goString string) String {
 }
 
 func NewStringIterator(str String, offset uintptr) StringIterator {
-       strCF := (*C.cfish_String)(unsafe.Pointer(str.TOPTR()))
+       strCF := (*C.cfish_String)(Unwrap(str, "str"))
        iter := C.cfish_StrIter_new(strCF, C.size_t(offset))
        return WRAPStringIterator(unsafe.Pointer(iter))
 }
@@ -192,13 +193,13 @@ func NewHash(size int) Hash {
 }
 
 func NewHashIterator(hash Hash) HashIterator {
-       hashCF := (*C.cfish_Hash)(unsafe.Pointer(hash.TOPTR()))
+       hashCF := (*C.cfish_Hash)(Unwrap(hash, "hash"))
        cfObj := C.cfish_HashIter_new(hashCF)
        return WRAPHashIterator(unsafe.Pointer(cfObj))
 }
 
 func (h *HashIMP) Keys() []string {
-       self := (*C.cfish_Hash)(unsafe.Pointer(h.TOPTR()))
+       self := (*C.cfish_Hash)(Unwrap(h, "h"))
        keysCF := C.CFISH_Hash_Keys(self)
        numKeys := C.CFISH_Vec_Get_Size(keysCF)
        keys := make([]string, 0, int(numKeys))
@@ -224,7 +225,7 @@ func (o *ObjIMP) TOPTR() uintptr {
 }
 
 func (o *ObjIMP)Clone() Obj {
-       self := (*C.cfish_Obj)(unsafe.Pointer(o.TOPTR()))
+       self := (*C.cfish_Obj)(Unwrap(o, "o"))
        dupe := C.CFISH_Obj_Clone(self)
        return WRAPAny(unsafe.Pointer(dupe)).(Obj)
 }
@@ -310,17 +311,25 @@ func GoToClownfish(value interface{}, class 
unsafe.Pointer, nullable bool) unsaf
        panic(NewErr(fmt.Sprintf("Can't convert a %T to %s", value, className)))
 }
 
-func UnwrapClownfish(value Obj, name string, nullable bool) unsafe.Pointer {
+func UnwrapNullable(value Obj) unsafe.Pointer {
        if value == nil {
-               if nullable {
-                       return nil
-               } else {
-                       panic(NewErr(fmt.Sprintf("%s cannot be nil", name)))
-               }
+               return nil
+       }
+       val := reflect.ValueOf(value)
+       if val.IsNil() {
+               return nil
        }
        return unsafe.Pointer(value.TOPTR())
 }
 
+func Unwrap(value Obj, name string) unsafe.Pointer {
+       ptr := UnwrapNullable(value)
+       if ptr == nil {
+               panic(NewErr(fmt.Sprintf("%s cannot be nil", name)))
+       }
+       return ptr
+}
+
 func goToString(value interface{}) unsafe.Pointer {
        switch v := value.(type) {
        case string:
@@ -628,19 +637,19 @@ func TrapErr(routine func()) (trapped error) {
 }
 
 func (s *StringIMP) CodePointAt(tick uintptr) rune {
-       self := ((*C.cfish_String)(unsafe.Pointer(s.TOPTR())))
+       self := ((*C.cfish_String)(Unwrap(s, "s")))
        retvalCF := C.CFISH_Str_Code_Point_At(self, C.size_t(tick))
        return rune(retvalCF)
 }
 
 func (s *StringIMP) CodePointFrom(tick uintptr) rune {
-       self := ((*C.cfish_String)(unsafe.Pointer(s.TOPTR())))
+       self := ((*C.cfish_String)(Unwrap(s, "s")))
        retvalCF := C.CFISH_Str_Code_Point_From(self, C.size_t(tick))
        return rune(retvalCF)
 }
 
 func (s *StringIMP) SwapChars(match, replacement rune) string {
-       self := ((*C.cfish_String)(unsafe.Pointer(s.TOPTR())))
+       self := ((*C.cfish_String)(Unwrap(s, "s")))
        retvalCF := C.CFISH_Str_Swap_Chars(self, C.int32_t(match), 
C.int32_t(replacement))
        defer C.cfish_dec_refcount(unsafe.Pointer(retvalCF))
        return CFStringToGo(unsafe.Pointer(retvalCF))
@@ -665,6 +674,6 @@ func NewBlob(content []byte) Blob {
 }
 
 func (b *BlobIMP) GetBuf() uintptr {
-       self := (*C.cfish_Blob)(unsafe.Pointer(b.TOPTR()))
+       self := (*C.cfish_Blob)(Unwrap(b, "b"))
        return uintptr(unsafe.Pointer(C.CFISH_Blob_Get_Buf(self)))
 }

Reply via email to