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/08/03 23:47:40 UTC
[1/7] lucy-clownfish git commit: Identify convertible core types more
robustly.
Repository: lucy-clownfish
Updated Branches:
refs/heads/master 570984e73 -> 1fc8c00a1
Identify convertible core types more robustly.
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/978a011e
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/978a011e
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/978a011e
Branch: refs/heads/master
Commit: 978a011e36d376319e3afb106995f7ca9822e06a
Parents: 570984e
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Sat Jul 25 17:51:10 2015 -0700
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Fri Jul 31 11:03:02 2015 -0700
----------------------------------------------------------------------
compiler/src/CFCType.c | 116 ++++++++++++++++++++++++++++++++++----------
compiler/src/CFCType.h | 81 ++++++++++++++++++++++++-------
2 files changed, 154 insertions(+), 43 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/978a011e/compiler/src/CFCType.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCType.c b/compiler/src/CFCType.c
index ee04abf..0c882cf 100644
--- a/compiler/src/CFCType.c
+++ b/compiler/src/CFCType.c
@@ -63,18 +63,25 @@ S_check_flags(int supplied, int acceptable, const char *type_name) {
int bad = (supplied & ~acceptable);
if (bad) {
char bad_flag[20];
- if ((bad & CFCTYPE_CONST)) { strcpy(bad_flag, "CONST"); }
- else if ((bad & CFCTYPE_NULLABLE)) { strcpy(bad_flag, "NULLABLE"); }
- else if ((bad & CFCTYPE_INCREMENTED)) { strcpy(bad_flag, "INCREMENTED"); }
- else if ((bad & CFCTYPE_DECREMENTED)) { strcpy(bad_flag, "DECREMENTED"); }
- else if ((bad & CFCTYPE_OBJECT)) { strcpy(bad_flag, "OBJECT"); }
- else if ((bad & CFCTYPE_PRIMITIVE)) { strcpy(bad_flag, "PRIMITIVE"); }
- else if ((bad & CFCTYPE_INTEGER)) { strcpy(bad_flag, "INTEGER"); }
- else if ((bad & CFCTYPE_FLOATING)) { strcpy(bad_flag, "FLOATING"); }
- else if ((bad & CFCTYPE_STRING_TYPE)) { strcpy(bad_flag, "STRING_TYPE"); }
- else if ((bad & CFCTYPE_VA_LIST)) { strcpy(bad_flag, "VA_LIST"); }
- else if ((bad & CFCTYPE_ARBITRARY)) { strcpy(bad_flag, "ARBITRARY"); }
- else if ((bad & CFCTYPE_COMPOSITE)) { strcpy(bad_flag, "COMPOSITE"); }
+ if ((bad & CFCTYPE_CONST)) { strcpy(bad_flag, "CONST"); }
+ else if ((bad & CFCTYPE_NULLABLE)) { strcpy(bad_flag, "NULLABLE"); }
+ else if ((bad & CFCTYPE_INCREMENTED)) { strcpy(bad_flag, "INCREMENTED"); }
+ else if ((bad & CFCTYPE_DECREMENTED)) { strcpy(bad_flag, "DECREMENTED"); }
+ else if ((bad & CFCTYPE_OBJECT)) { strcpy(bad_flag, "OBJECT"); }
+ else if ((bad & CFCTYPE_PRIMITIVE)) { strcpy(bad_flag, "PRIMITIVE"); }
+ else if ((bad & CFCTYPE_INTEGER)) { strcpy(bad_flag, "INTEGER"); }
+ else if ((bad & CFCTYPE_FLOATING)) { strcpy(bad_flag, "FLOATING"); }
+ else if ((bad & CFCTYPE_CFISH_OBJ)) { strcpy(bad_flag, "CFISH_OBJ"); }
+ else if ((bad & CFCTYPE_CFISH_STRING)) { strcpy(bad_flag, "CFISH_STRING"); }
+ else if ((bad & CFCTYPE_CFISH_BLOB)) { strcpy(bad_flag, "CFISH_BLOB"); }
+ else if ((bad & CFCTYPE_CFISH_INTEGER)) { strcpy(bad_flag, "CFISH_INTEGER"); }
+ else if ((bad & CFCTYPE_CFISH_FLOAT)) { strcpy(bad_flag, "CFISH_FLOAT"); }
+ else if ((bad & CFCTYPE_CFISH_BOOLEAN)) { strcpy(bad_flag, "CFISH_BOOLEAN"); }
+ else if ((bad & CFCTYPE_CFISH_VECTOR)) { strcpy(bad_flag, "CFISH_VECTOR"); }
+ else if ((bad & CFCTYPE_CFISH_HASH)) { strcpy(bad_flag, "CFISH_HASH"); }
+ else if ((bad & CFCTYPE_VA_LIST)) { strcpy(bad_flag, "VA_LIST"); }
+ else if ((bad & CFCTYPE_ARBITRARY)) { strcpy(bad_flag, "ARBITRARY"); }
+ else if ((bad & CFCTYPE_COMPOSITE)) { strcpy(bad_flag, "COMPOSITE"); }
else {
CFCUtil_die("Unknown flags: %d", bad);
}
@@ -182,12 +189,36 @@ CFCType_new_object(int flags, CFCParcel *parcel, const char *specifier,
// Add flags.
flags |= CFCTYPE_OBJECT;
- if (strcmp(specifier, "String") == 0
- || strcmp(specifier, "cfish_String") == 0
- ) {
- // Determine whether this type is a string type.
- flags |= CFCTYPE_STRING_TYPE;
+ static struct {
+ char *sym;
+ char *full_sym;
+ int flag;
+ } cfish_types[] = {
+ {"Obj", "cfish_Obj", CFCTYPE_CFISH_OBJ},
+ {"String", "cfish_String", CFCTYPE_CFISH_STRING},
+ {"Blob", "cfish_Blob", CFCTYPE_CFISH_BLOB},
+ {"Integer", "cfish_Integer", CFCTYPE_CFISH_INTEGER},
+ {"Float", "cfish_Float", CFCTYPE_CFISH_FLOAT},
+ {"Boolean", "cfish_Boolean", CFCTYPE_CFISH_BOOLEAN},
+ {"Vector", "cfish_Vector", CFCTYPE_CFISH_VECTOR},
+ {"Hash", "cfish_Hash", CFCTYPE_CFISH_HASH}
+ };
+ int count_cfish_types = sizeof(cfish_types) / sizeof(cfish_types[0]);
+ int acceptable_flags = CFCTYPE_OBJECT
+ | CFCTYPE_CONST
+ | CFCTYPE_NULLABLE
+ | CFCTYPE_INCREMENTED
+ | CFCTYPE_DECREMENTED;
+ for (int i = 0; i < count_cfish_types; i++) {
+ if (strcmp(specifier, cfish_types[i].sym) == 0
+ || strcmp(specifier, cfish_types[i].full_sym) == 0
+ ) {
+ flags |= cfish_types[i].flag;
+ acceptable_flags |= cfish_types[i].flag;
+ break;
+ }
}
+ S_check_flags(flags, acceptable_flags, "Object");
// Validate specifier.
if (!isalpha(*specifier)) {
@@ -204,14 +235,6 @@ CFCType_new_object(int flags, CFCParcel *parcel, const char *specifier,
CFCUtil_die("Invalid specifier: '%s'", specifier);
}
- int acceptable_flags = CFCTYPE_OBJECT
- | CFCTYPE_STRING_TYPE
- | CFCTYPE_CONST
- | CFCTYPE_NULLABLE
- | CFCTYPE_INCREMENTED
- | CFCTYPE_DECREMENTED;
- S_check_flags(flags, acceptable_flags, "Object");
-
return CFCType_new(flags, parcel, specifier, 1);
}
@@ -481,9 +504,50 @@ CFCType_is_floating(CFCType *self) {
return !!(self->flags & CFCTYPE_FLOATING);
}
+
+int
+CFCType_cfish_obj(CFCType *self) {
+ return !!(self->flags & CFCTYPE_CFISH_OBJ);
+}
+
int
CFCType_is_string_type(CFCType *self) {
- return !!(self->flags & CFCTYPE_STRING_TYPE);
+ return !!(self->flags & CFCTYPE_CFISH_STRING);
+}
+
+int
+CFCType_cfish_string(CFCType *self) {
+ return !!(self->flags & CFCTYPE_CFISH_STRING);
+}
+
+int
+CFCType_cfish_blob(CFCType *self) {
+ return !!(self->flags & CFCTYPE_CFISH_BLOB);
+}
+
+int
+CFCType_cfish_integer(CFCType *self) {
+ return !!(self->flags & CFCTYPE_CFISH_INTEGER);
+}
+
+int
+CFCType_cfish_float(CFCType *self) {
+ return !!(self->flags & CFCTYPE_CFISH_FLOAT);
+}
+
+int
+CFCType_cfish_boolean(CFCType *self) {
+ return !!(self->flags & CFCTYPE_CFISH_BOOLEAN);
+}
+
+int
+CFCType_cfish_vector(CFCType *self) {
+ return !!(self->flags & CFCTYPE_CFISH_VECTOR);
+}
+
+int
+CFCType_cfish_hash(CFCType *self) {
+ return !!(self->flags & CFCTYPE_CFISH_HASH);
}
int
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/978a011e/compiler/src/CFCType.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCType.h b/compiler/src/CFCType.h
index f351eba..31800fc 100644
--- a/compiler/src/CFCType.h
+++ b/compiler/src/CFCType.h
@@ -28,19 +28,26 @@ typedef struct CFCType CFCType;
struct CFCClass;
struct CFCParcel;
-#define CFCTYPE_CONST 0x00000001
-#define CFCTYPE_NULLABLE 0x00000002
-#define CFCTYPE_VOID 0x00000004
-#define CFCTYPE_INCREMENTED 0x00000008
-#define CFCTYPE_DECREMENTED 0x00000010
-#define CFCTYPE_OBJECT 0x00000020
-#define CFCTYPE_PRIMITIVE 0x00000040
-#define CFCTYPE_INTEGER 0x00000080
-#define CFCTYPE_FLOATING 0x00000100
-#define CFCTYPE_STRING_TYPE 0x00000200
-#define CFCTYPE_VA_LIST 0x00000400
-#define CFCTYPE_ARBITRARY 0x00000800
-#define CFCTYPE_COMPOSITE 0x00001000
+#define CFCTYPE_CONST (1 << 0)
+#define CFCTYPE_NULLABLE (1 << 1)
+#define CFCTYPE_VOID (1 << 2)
+#define CFCTYPE_INCREMENTED (1 << 3)
+#define CFCTYPE_DECREMENTED (1 << 4)
+#define CFCTYPE_OBJECT (1 << 5)
+#define CFCTYPE_PRIMITIVE (1 << 6)
+#define CFCTYPE_INTEGER (1 << 7)
+#define CFCTYPE_FLOATING (1 << 8)
+#define CFCTYPE_CFISH_OBJ (1 << 9)
+#define CFCTYPE_CFISH_STRING (1 << 10)
+#define CFCTYPE_CFISH_BLOB (1 << 12)
+#define CFCTYPE_CFISH_INTEGER (1 << 13)
+#define CFCTYPE_CFISH_FLOAT (1 << 14)
+#define CFCTYPE_CFISH_BOOLEAN (1 << 15)
+#define CFCTYPE_CFISH_VECTOR (1 << 16)
+#define CFCTYPE_CFISH_HASH (1 << 17)
+#define CFCTYPE_VA_LIST (1 << 18)
+#define CFCTYPE_ARBITRARY (1 << 19)
+#define CFCTYPE_COMPOSITE (1 << 20)
/** Generic constructor.
*
@@ -104,8 +111,9 @@ CFCType_new_float(int flags, const char *specifier);
*
* The Parcel's prefix will be prepended to the specifier by new_object().
*
- * @param flags Allowed flags: OBJECT, STRING_TYPE, CONST, NULLABLE,
- * INCREMENTED, DECREMENTED.
+ * @param flags Allowed flags: OBJECT, CFISH_OBJ, CFISH_STRING, CFISH_BLOB,
+ * CFISH_INTEGER, CFISH_FLOAT, CFISH_BOOLEAN, CFISH_VECTOR, CFISH_HASH, CONST,
+ * NULLABLE, INCREMENTED, DECREMENTED.
* @param parcel A Clownfish::CFC::Model::Parcel.
* @param specifier Required. Must follow the rules for
* Clownfish::CFC::Model::Class class name components.
@@ -255,12 +263,51 @@ CFCType_is_integer(CFCType *self);
int
CFCType_is_floating(CFCType *self);
-/** Returns true if $type represents a Clownfish type which holds unicode
- * strings.
+/** Returns true if the type is Clownfish::Obj.
+ */
+int
+CFCType_cfish_obj(CFCType *self);
+
+/** Returns true if the type is Clownfish::String.
*/
int
CFCType_is_string_type(CFCType *self);
+/** Returns true if the type is Clownfish::String.
+ */
+int
+CFCType_cfish_string(CFCType *self);
+
+/** Returns true if the type is Clownfish::Blob.
+ */
+int
+CFCType_cfish_blob(CFCType *self);
+
+/** Returns true if the type is Clownfish::Integer.
+ */
+int
+CFCType_cfish_integer(CFCType *self);
+
+/** Returns true if the type is Clownfish::Float.
+ */
+int
+CFCType_cfish_float(CFCType *self);
+
+/** Returns true if the type is Clownfish::Boolean
+ */
+int
+CFCType_cfish_boolean(CFCType *self);
+
+/** Returns true if the type is Clownfish::Vector.
+ */
+int
+CFCType_cfish_vector(CFCType *self);
+
+/** Returns true if the type is Clownfish::Hash.
+ */
+int
+CFCType_cfish_hash(CFCType *self);
+
int
CFCType_is_va_list(CFCType *self);
[2/7] lucy-clownfish git commit: Wrap any Clownfish object from Go.
Posted by ma...@apache.org.
Wrap any Clownfish object from Go.
Produce a Go func for each Clownfish class, which, given a Clownfish
C-space object pointer, wraps it in the appropriate Go struct yet
returns a clownfish.Obj. Register these funcs in the `clownfish` Go
package and make them accessible via `clownfish.WRAPAny`.
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/56e4ab9c
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/56e4ab9c
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/56e4ab9c
Branch: refs/heads/master
Commit: 56e4ab9c21f1b5a9db1cea38ca58cca8539f1a1f
Parents: 978a011
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Mon Jul 27 19:49:59 2015 -0700
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Fri Jul 31 11:05:37 2015 -0700
----------------------------------------------------------------------
compiler/src/CFCGo.c | 29 ++++++++++++++++++++-
compiler/src/CFCGoClass.c | 23 +++++++++++++++--
compiler/src/CFCGoClass.h | 3 +++
runtime/go/clownfish/clownfish.go | 46 ++++++++++++++++++++++++++++++++++
4 files changed, 98 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/56e4ab9c/compiler/src/CFCGo.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGo.c b/compiler/src/CFCGo.c
index 3b3af2e..a5812a3 100644
--- a/compiler/src/CFCGo.c
+++ b/compiler/src/CFCGo.c
@@ -223,17 +223,21 @@ S_gen_init_code(CFCGo *self, CFCParcel *parcel) {
const char pattern[] =
"func init() {\n"
" C.%sbootstrap_parcel()\n"
+ " initWRAP()\n"
"}\n";
return CFCUtil_sprintf(pattern, prefix);
}
static char*
S_gen_autogen_go(CFCGo *self, CFCParcel *parcel) {
+ const char *clownfish_dot = CFCParcel_is_cfish(parcel)
+ ? "" : "clownfish.";
CFCGoClass **registry = CFCGoClass_registry();
char *type_decs = CFCUtil_strdup("");
char *boilerplate = CFCUtil_strdup("");
char *ctors = CFCUtil_strdup("");
char *meth_defs = CFCUtil_strdup("");
+ char *wrap_funcs = CFCUtil_strdup("");
for (int i = 0; registry[i] != NULL; i++) {
CFCGoClass *class_binding = registry[i];
@@ -258,6 +262,22 @@ S_gen_autogen_go(CFCGo *self, CFCParcel *parcel) {
char *glue = CFCGoClass_gen_meth_glue(class_binding);
meth_defs = CFCUtil_cat(meth_defs, glue, "\n", NULL);
FREEMEM(glue);
+
+ char *wrap_func = CFCGoClass_gen_wrap_func_reg(class_binding);
+ wrap_funcs = CFCUtil_cat(wrap_funcs, wrap_func, NULL);
+ FREEMEM(wrap_func);
+ }
+
+ if (strlen(wrap_funcs)) {
+ char pattern[] =
+ "\tnewEntries := map[unsafe.Pointer]%sWrapFunc{\n%s"
+ "\t}\n"
+ "\t%sRegisterWrapFuncs(newEntries)\n"
+ ;
+ char *temp = CFCUtil_sprintf(pattern, clownfish_dot, wrap_funcs,
+ clownfish_dot);
+ FREEMEM(wrap_funcs);
+ wrap_funcs = temp;
}
char pattern[] =
@@ -269,6 +289,11 @@ S_gen_autogen_go(CFCGo *self, CFCParcel *parcel) {
"\n"
"%s\n"
"\n"
+ "// Register WRAP functions.\n"
+ "func initWRAP() {\n"
+ "%s"
+ "}\n"
+ "\n"
"// Constructors.\n"
"\n"
"%s\n"
@@ -279,8 +304,10 @@ S_gen_autogen_go(CFCGo *self, CFCParcel *parcel) {
"\n"
;
char *content
- = CFCUtil_sprintf(pattern, type_decs, boilerplate, ctors, meth_defs);
+ = CFCUtil_sprintf(pattern, type_decs, boilerplate, wrap_funcs,
+ ctors, meth_defs);
+ FREEMEM(wrap_funcs);
FREEMEM(meth_defs);
FREEMEM(ctors);
FREEMEM(boilerplate);
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/56e4ab9c/compiler/src/CFCGoClass.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGoClass.c b/compiler/src/CFCGoClass.c
index d02aeb8..4392b61 100644
--- a/compiler/src/CFCGoClass.c
+++ b/compiler/src/CFCGoClass.c
@@ -250,18 +250,24 @@ CFCGoClass_boilerplate_funcs(CFCGoClass *self) {
else if (CFCClass_inert(self->client)) {
content = CFCUtil_strdup("");
} else {
+ const char *clownfish_dot = CFCParcel_is_cfish(self->parcel)
+ ? "" : "clownfish.";
const char *short_struct = CFCClass_get_struct_sym(self->client);
- const char *full_struct = CFCClass_full_struct_sym(self->client);
char pattern[] =
"func WRAP%s(ptr unsafe.Pointer) %s {\n"
"\tobj := &%sIMP{}\n"
"\tobj.INITOBJ(ptr)\n"
"\treturn obj\n"
"}\n"
+ "\n"
+ "func WRAP%sASOBJ(ptr unsafe.Pointer) %sObj {\n"
+ "\treturn WRAP%s(ptr)\n"
+ "}\n"
;
content = CFCUtil_sprintf(pattern, short_struct, short_struct,
- short_struct, full_struct, short_struct);
+ short_struct, short_struct, clownfish_dot,
+ short_struct);
}
return content;
}
@@ -368,6 +374,19 @@ CFCGoClass_gen_meth_glue(CFCGoClass *self) {
return meth_defs;
}
+char*
+CFCGoClass_gen_wrap_func_reg(CFCGoClass *self) {
+ if (CFCClass_inert(self->client)) {
+ return CFCUtil_strdup("");
+ }
+ char pattern[] =
+ "\t\tunsafe.Pointer(C.%s): WRAP%sASOBJ,\n";
+
+ const char *short_struct = CFCClass_get_struct_sym(self->client);
+ const char *class_var = CFCClass_full_class_var(self->client);
+ return CFCUtil_sprintf(pattern, class_var, short_struct);
+}
+
void
CFCGoClass_spec_method(CFCGoClass *self, const char *name, const char *sig) {
CFCUTIL_NULL_CHECK(sig);
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/56e4ab9c/compiler/src/CFCGoClass.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGoClass.h b/compiler/src/CFCGoClass.h
index 6a2db34..4e2cacf 100644
--- a/compiler/src/CFCGoClass.h
+++ b/compiler/src/CFCGoClass.h
@@ -76,6 +76,9 @@ CFCGoClass_gen_ctors(CFCGoClass *self);
char*
CFCGoClass_gen_meth_glue(CFCGoClass *self);
+char*
+CFCGoClass_gen_wrap_func_reg(CFCGoClass *self);
+
void
CFCGoClass_spec_method(CFCGoClass *self, const char *name, const char *sig);
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/56e4ab9c/runtime/go/clownfish/clownfish.go
----------------------------------------------------------------------
diff --git a/runtime/go/clownfish/clownfish.go b/runtime/go/clownfish/clownfish.go
index 2c5f40e..0fb7e32 100644
--- a/runtime/go/clownfish/clownfish.go
+++ b/runtime/go/clownfish/clownfish.go
@@ -62,10 +62,56 @@ GoCfish_RunRoutine(CFISH_Err_Attempt_t routine, void *context) {
import "C"
import "runtime"
import "unsafe"
+import "fmt"
+import "sync"
+
+const (
+ maxUint = ^uint(0)
+ minUint = 0
+ maxInt = int(^uint(0) >> 1)
+ minInt = -(maxInt - 1)
+)
+
+type WrapFunc func(unsafe.Pointer)Obj
+var wrapRegMutex sync.Mutex
+var wrapReg *map[unsafe.Pointer]WrapFunc
func init() {
C.GoCfish_glue_exported_symbols()
C.cfish_bootstrap_parcel()
+ initWRAP()
+}
+
+func RegisterWrapFuncs(newEntries map[unsafe.Pointer]WrapFunc) {
+ wrapRegMutex.Lock()
+ newSize := len(newEntries)
+ if wrapReg != nil {
+ newSize += len(*wrapReg)
+ }
+ newReg := make(map[unsafe.Pointer]WrapFunc, newSize)
+ if wrapReg != nil {
+ for k, v := range *wrapReg {
+ newReg[k] = v
+ }
+ }
+ for k, v := range newEntries {
+ newReg[k] = v
+ }
+ wrapReg = &newReg
+ wrapRegMutex.Unlock()
+}
+
+func WRAPAny(ptr unsafe.Pointer) Obj {
+ if ptr == nil {
+ return nil
+ }
+ class := C.cfish_Obj_get_class((*C.cfish_Obj)(ptr))
+ wrapFunc := (*wrapReg)[unsafe.Pointer(class)]
+ if wrapFunc == nil {
+ className := CFStringToGo(unsafe.Pointer(C.CFISH_Class_Get_Name((*C.cfish_Class)(class))))
+ panic(fmt.Sprintf("Failed to find WRAP function for %s", className))
+ }
+ return wrapFunc(ptr)
}
type ObjIMP struct {
[7/7] lucy-clownfish git commit: Merge branch
'CLOWNFISH-56-go-composites'
Posted by ma...@apache.org.
Merge branch 'CLOWNFISH-56-go-composites'
Perform the following conversions in Go/Clownfish glue code:
* Blob: `[]byte`
* Vector: `[]interface{}`
* Hash: `map[string]interface{}`
This closes #28.
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/1fc8c00a
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/1fc8c00a
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/1fc8c00a
Branch: refs/heads/master
Commit: 1fc8c00a18eee056b0a008f76bcc6289c7d3920a
Parents: 570984e a665132
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Mon Aug 3 14:44:47 2015 -0700
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Mon Aug 3 14:44:47 2015 -0700
----------------------------------------------------------------------
compiler/src/CFCGo.c | 29 +-
compiler/src/CFCGoClass.c | 23 +-
compiler/src/CFCGoClass.h | 3 +
compiler/src/CFCGoFunc.c | 79 +++--
compiler/src/CFCGoTypeMap.c | 9 +
compiler/src/CFCType.c | 116 ++++++--
compiler/src/CFCType.h | 81 +++--
runtime/go/build.go | 8 +
runtime/go/clownfish/clownfish.go | 445 +++++++++++++++++++++++++++-
runtime/go/clownfish/clownfish_test.go | 236 ++++++++++++++-
10 files changed, 943 insertions(+), 86 deletions(-)
----------------------------------------------------------------------
[4/7] lucy-clownfish git commit: Map Vector to Go `[]interface{}`.
Posted by ma...@apache.org.
Map Vector to Go `[]interface{}`.
Convert Vector to slice of empty interface for both input (func
parameters) and output (return types).
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/04a57319
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/04a57319
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/04a57319
Branch: refs/heads/master
Commit: 04a573198d2467a87c293833669a00e6f5e2e16b
Parents: 55d40ac
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Thu Jul 30 16:23:20 2015 -0700
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Fri Jul 31 11:06:27 2015 -0700
----------------------------------------------------------------------
compiler/src/CFCGoFunc.c | 65 +++++++++++++++++-----------------
compiler/src/CFCGoTypeMap.c | 3 ++
runtime/go/build.go | 4 +++
runtime/go/clownfish/clownfish.go | 8 +++++
4 files changed, 48 insertions(+), 32 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/04a57319/compiler/src/CFCGoFunc.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGoFunc.c b/compiler/src/CFCGoFunc.c
index 060e62b..64f2255 100644
--- a/compiler/src/CFCGoFunc.c
+++ b/compiler/src/CFCGoFunc.c
@@ -55,6 +55,8 @@ CFCGoFunc_go_meth_name(const char *orig) {
static char*
S_prep_start(CFCParcel *parcel, const char *name, CFCClass *invoker,
CFCParamList *param_list, CFCType *return_type, int targ) {
+ const char *clownfish_dot = CFCParcel_is_cfish(parcel)
+ ? "" : "clownfish.";
CFCVariable **param_vars = CFCParamList_get_variables(param_list);
char *invocant;
char go_name[GO_NAME_BUF_SIZE];
@@ -85,22 +87,21 @@ S_prep_start(CFCParcel *parcel, const char *name, CFCClass *invoker,
// Convert certain types and defer their destruction until after the
// Clownfish call returns.
- if (CFCType_is_string_type(type)) {
- const char *cf_prefix = CFCParcel_is_cfish(parcel)
- ? "" : "clownfish.";
- char pattern[] =
- "%s\t%sCF := C.cfish_Str_new_steal_utf8("
- "C.CString(%s), C.size_t(len(%s)))\n"
- ;
- char *temp = CFCUtil_sprintf(pattern, converted, go_name, go_name,
- go_name, go_name);
- FREEMEM(converted);
- converted = temp;
- if (!CFCType_decremented(type)) {
- converted = CFCUtil_cat(converted,
- "\tdefer C.cfish_dec_refcount(unsafe.Pointer(", go_name,
- "CF))\n", NULL);
- }
+ char *convertible = NULL;
+ if (CFCType_cfish_string(type)) { convertible = "String"; }
+ else if (CFCType_cfish_vector(type)) { convertible = "Vector"; }
+ else { continue; }
+ char pattern[] =
+ "\t%sCF := (*C.cfish_%s)(%sGoTo%s(%s))\n";
+ char *conversion = CFCUtil_sprintf(pattern, go_name, convertible,
+ clownfish_dot, convertible,
+ go_name);
+ converted = CFCUtil_cat(converted, conversion, NULL);
+ FREEMEM(conversion);
+ if (CFCType_decremented(type)) {
+ converted = CFCUtil_cat(converted,
+ "\tdefer C.cfish_decref(unsafe.Pointer(",
+ go_name, "CF))\n", NULL);
}
}
@@ -170,8 +171,9 @@ S_prep_cfargs(CFCParcel *parcel, CFCClass *invoker,
cfargs = CFCUtil_cat(cfargs, "C.", CFCType_get_specifier(type),
"(", go_name, ")", NULL);
}
- else if (CFCType_is_string_type(type)
- // Don't convert a clownfish.String invocant.
+ else if ((CFCType_is_string_type(type)
+ || CFCType_cfish_vector(type))
+ // Don't convert an invocant.
&& (targ != IS_METHOD || i != 0)
) {
cfargs = CFCUtil_cat(cfargs, go_name, "CF", NULL);
@@ -208,7 +210,12 @@ CFCGoFunc_ctor_cfargs(CFCParcel *parcel, CFCParamList *param_list) {
char*
CFCGoFunc_return_statement(CFCParcel *parcel, CFCType *return_type,
const char *cf_retval) {
+ const char *clownfish_dot = CFCParcel_is_cfish(parcel)
+ ? "" : "clownfish.";
+ const char *maybe_decref = CFCType_incremented(return_type)
+ ? "\tdefer C.cfish_decref(unsafe.Pointer(retvalCF))\n" : "";
char *statement = NULL;
+
if (CFCType_is_void(return_type)) {
return CFCUtil_strdup("");
}
@@ -223,20 +230,14 @@ CFCGoFunc_return_statement(CFCParcel *parcel, CFCType *return_type,
statement = CFCUtil_sprintf("\treturn %s(retvalCF)\n", ret_type_str);
}
else if (CFCType_is_string_type(return_type)) {
- const char *clownfish_dot = CFCParcel_is_cfish(parcel)
- ? "" : "clownfish.";
- if (CFCType_incremented(return_type)) {
- char pattern[] =
- "\tdefer C.cfish_dec_refcount(unsafe.Pointer(retvalCF))\n"
- "\treturn %sCFStringToGo(unsafe.Pointer(retvalCF))\n"
- ;
- statement = CFCUtil_sprintf(pattern, clownfish_dot);
- }
- else {
- char pattern[] =
- "\treturn %sCFStringToGo(unsafe.Pointer(retvalCF))\n";
- statement = CFCUtil_sprintf(pattern, clownfish_dot);
- }
+ char pattern[] =
+ "%s\treturn %sCFStringToGo(unsafe.Pointer(retvalCF))\n";
+ statement = CFCUtil_sprintf(pattern, maybe_decref, clownfish_dot);
+ }
+ else if (CFCType_cfish_vector(return_type)) {
+ char pattern[] =
+ "%s\treturn %sVectorToGo(unsafe.Pointer(retvalCF))\n";
+ statement = CFCUtil_sprintf(pattern, maybe_decref, clownfish_dot);
}
else if (CFCType_is_object(return_type)) {
char *go_type_name = CFCGoTypeMap_go_type_name(return_type, parcel);
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/04a57319/compiler/src/CFCGoTypeMap.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGoTypeMap.c b/compiler/src/CFCGoTypeMap.c
index 7ddbf08..15e42a7 100644
--- a/compiler/src/CFCGoTypeMap.c
+++ b/compiler/src/CFCGoTypeMap.c
@@ -96,6 +96,9 @@ CFCGoTypeMap_go_type_name(CFCType *type, CFCParcel *current_parcel) {
if (CFCType_is_string_type(type)) {
return CFCUtil_strdup("string");
}
+ else if (CFCType_cfish_vector(type)) {
+ return CFCUtil_strdup("[]interface{}");
+ }
else if (CFCType_is_object(type)) {
// Divide the specifier into prefix and struct name.
const char *specifier = CFCType_get_specifier(type);
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/04a57319/runtime/go/build.go
----------------------------------------------------------------------
diff --git a/runtime/go/build.go b/runtime/go/build.go
index 186eebd..fd96fd1 100644
--- a/runtime/go/build.go
+++ b/runtime/go/build.go
@@ -148,6 +148,10 @@ func specMethods(parcel *cfc.Parcel) {
stringBinding.SpecMethod("Code_Point_From", "CodePointFrom(uintptr) rune")
stringBinding.SpecMethod("Swap_Chars", "SwapChars(rune, rune) string")
stringBinding.Register()
+
+ vecBinding := cfc.NewGoClass(parcel, "Clownfish::Vector")
+ vecBinding.SetSuppressCtor(true)
+ vecBinding.Register()
}
func prep() {
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/04a57319/runtime/go/clownfish/clownfish.go
----------------------------------------------------------------------
diff --git a/runtime/go/clownfish/clownfish.go b/runtime/go/clownfish/clownfish.go
index 21eb567..eefd831 100644
--- a/runtime/go/clownfish/clownfish.go
+++ b/runtime/go/clownfish/clownfish.go
@@ -130,6 +130,14 @@ func NewString(goString string) String {
return WRAPString(unsafe.Pointer(cfObj))
}
+func NewVector(size int) Vector {
+ if (size < 0 || uint64(size) > ^uint64(0)) {
+ panic(NewErr(fmt.Sprintf("Param 'size' out of range: %d", size)))
+ }
+ cfObj := C.cfish_Vec_new(C.size_t(size))
+ return WRAPVector(unsafe.Pointer(cfObj))
+}
+
func (o *ObjIMP) INITOBJ(ptr unsafe.Pointer) {
o.ref = uintptr(ptr)
runtime.SetFinalizer(o, ClearRef)
[3/7] lucy-clownfish git commit: Add GoToClownfish/ToGo conversion
routines.
Posted by ma...@apache.org.
Add GoToClownfish/ToGo conversion routines.
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/55d40ac6
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/55d40ac6
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/55d40ac6
Branch: refs/heads/master
Commit: 55d40ac67b7a076050c15e652d51f4a5dfc937a6
Parents: 56e4ab9
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Fri Jul 24 14:23:44 2015 -0700
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Fri Jul 31 11:05:42 2015 -0700
----------------------------------------------------------------------
runtime/go/clownfish/clownfish.go | 383 +++++++++++++++++++++++++++-
runtime/go/clownfish/clownfish_test.go | 236 ++++++++++++++++-
2 files changed, 611 insertions(+), 8 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/55d40ac6/runtime/go/clownfish/clownfish.go
----------------------------------------------------------------------
diff --git a/runtime/go/clownfish/clownfish.go b/runtime/go/clownfish/clownfish.go
index 0fb7e32..21eb567 100644
--- a/runtime/go/clownfish/clownfish.go
+++ b/runtime/go/clownfish/clownfish.go
@@ -18,6 +18,8 @@ package clownfish
/*
+#include <limits.h>
+
#include "charmony.h"
#include "Clownfish/Obj.h"
@@ -26,7 +28,9 @@ package clownfish
#include "Clownfish/String.h"
#include "Clownfish/Blob.h"
#include "Clownfish/Hash.h"
+#include "Clownfish/HashIterator.h"
#include "Clownfish/Vector.h"
+#include "Clownfish/Num.h"
#include "Clownfish/Boolean.h"
#include "Clownfish/Util/Memory.h"
#include "Clownfish/Method.h"
@@ -63,6 +67,7 @@ import "C"
import "runtime"
import "unsafe"
import "fmt"
+import "math"
import "sync"
const (
@@ -139,7 +144,315 @@ func (o *ObjIMP) TOPTR() uintptr {
return o.ref
}
+func certifyCF(value interface{}, class *C.cfish_Class) {
+ cfObj, ok := value.(Obj)
+ if ok {
+ if C.cfish_Obj_is_a((*C.cfish_Obj)(unsafe.Pointer(cfObj.TOPTR())), class) {
+ return
+ }
+ }
+ className := StringToGo(unsafe.Pointer(C.CFISH_Class_Get_Name(class)))
+ panic(NewErr(fmt.Sprintf("Can't convert a %T to %s", value, className)))
+}
+
+// Convert a Go type into an incremented Clownfish object. If the supplied
+// object is a Clownfish object wrapped in a Go struct, extract the Clownfish
+// object and incref it before returning its address.
+func GoToClownfish(value interface{}, class unsafe.Pointer, nullable bool) unsafe.Pointer {
+ klass := (*C.cfish_Class)(class)
+
+ // Check for nil values.
+ if value == nil {
+ if nullable {
+ return nil
+ } else if class != nil {
+ className := StringToGo(unsafe.Pointer(C.CFISH_Class_Get_Name(klass)))
+ panic(NewErr("Cannot be nil, must be a valid " + className))
+ } else {
+ panic(NewErr("Cannot be nil"))
+ }
+ }
+
+ // Default to accepting any type.
+ if klass == nil {
+ klass = C.CFISH_OBJ
+ }
+
+ // Convert the value according to its type if possible.
+ var converted unsafe.Pointer
+ switch v := value.(type) {
+ case string:
+ if klass == C.CFISH_STRING || klass == C.CFISH_OBJ {
+ converted = GoToString(value)
+ }
+ case []byte:
+ if klass == C.CFISH_BLOB || klass == C.CFISH_OBJ {
+ converted = GoToBlob(value)
+ }
+ case int:
+ if klass == C.CFISH_INTEGER || klass == C.CFISH_OBJ {
+ converted = GoToInteger(value)
+ }
+ case uint:
+ if klass == C.CFISH_INTEGER || klass == C.CFISH_OBJ {
+ converted = GoToInteger(value)
+ }
+ case uintptr:
+ if klass == C.CFISH_INTEGER || klass == C.CFISH_OBJ {
+ converted = GoToInteger(value)
+ }
+ case int64:
+ if klass == C.CFISH_INTEGER || klass == C.CFISH_OBJ {
+ converted = GoToInteger(value)
+ }
+ case int32:
+ if klass == C.CFISH_INTEGER || klass == C.CFISH_OBJ {
+ converted = GoToInteger(value)
+ }
+ case int16:
+ if klass == C.CFISH_INTEGER || klass == C.CFISH_OBJ {
+ converted = GoToInteger(value)
+ }
+ case int8:
+ if klass == C.CFISH_INTEGER || klass == C.CFISH_OBJ {
+ converted = GoToInteger(value)
+ }
+ case uint64:
+ if klass == C.CFISH_INTEGER || klass == C.CFISH_OBJ {
+ converted = GoToInteger(value)
+ }
+ case uint32:
+ if klass == C.CFISH_INTEGER || klass == C.CFISH_OBJ {
+ converted = GoToInteger(value)
+ }
+ case uint16:
+ if klass == C.CFISH_INTEGER || klass == C.CFISH_OBJ {
+ converted = GoToInteger(value)
+ }
+ case uint8:
+ if klass == C.CFISH_INTEGER || klass == C.CFISH_OBJ {
+ converted = GoToInteger(value)
+ }
+ case float32:
+ if klass == C.CFISH_FLOAT || klass == C.CFISH_OBJ {
+ converted = GoToFloat(value)
+ }
+ case float64:
+ if klass == C.CFISH_FLOAT || klass == C.CFISH_OBJ {
+ converted = GoToFloat(value)
+ }
+ case []interface{}:
+ if klass == C.CFISH_VECTOR || klass == C.CFISH_OBJ {
+ converted = GoToVector(value)
+ }
+ case map[string]interface{}:
+ if klass == C.CFISH_HASH || klass == C.CFISH_OBJ {
+ converted = GoToHash(value)
+ }
+ case Obj:
+ converted = unsafe.Pointer(C.cfish_incref(unsafe.Pointer(v.TOPTR())))
+ }
+
+ // Confirm that we got what we were looking for and return.
+ if converted != nil {
+ if C.cfish_Obj_is_a((*C.cfish_Obj)(converted), klass) {
+ return unsafe.Pointer(C.cfish_incref(converted))
+ }
+ }
+
+ // Report a conversion error.
+ className := StringToGo(unsafe.Pointer(C.CFISH_Class_Get_Name(klass)))
+ panic(NewErr(fmt.Sprintf("Can't convert a %T to %s", value, className)))
+}
+
+func GoToString(value interface{}) unsafe.Pointer {
+ switch v := value.(type) {
+ case string:
+ size := len(v)
+ str := C.CString(v)
+ return unsafe.Pointer(C.cfish_Str_new_steal_utf8(str, C.size_t(size)))
+ case Obj:
+ certifyCF(v, C.CFISH_STRING)
+ return unsafe.Pointer(C.cfish_incref(unsafe.Pointer(v.TOPTR())))
+ default:
+ mess := fmt.Sprintf("Can't convert %T to clownfish.String", v)
+ panic(NewErr(mess))
+ }
+}
+
+func GoToBlob(value interface{}) unsafe.Pointer {
+ switch v := value.(type) {
+ case []byte:
+ size := C.size_t(len(v))
+ var buf *C.char = nil
+ if size > 0 {
+ buf = ((*C.char)(unsafe.Pointer(&v[0])))
+ }
+ return unsafe.Pointer(C.cfish_Blob_new(buf, size))
+ case Obj:
+ certifyCF(v, C.CFISH_BLOB)
+ return unsafe.Pointer(C.cfish_incref(unsafe.Pointer(v.TOPTR())))
+ default:
+ mess := fmt.Sprintf("Can't convert %T to clownfish.Blob", v)
+ panic(NewErr(mess))
+ }
+}
+
+func GoToInteger(value interface{}) unsafe.Pointer {
+ switch v := value.(type) {
+ case int:
+ return unsafe.Pointer(C.cfish_Int_new(C.int64_t(v)))
+ case uint:
+ if v > math.MaxInt64 {
+ mess := fmt.Sprintf("uint value too large: %v", v)
+ panic(NewErr(mess))
+ }
+ return unsafe.Pointer(C.cfish_Int_new(C.int64_t(v)))
+ case uintptr:
+ if v > math.MaxInt64 {
+ mess := fmt.Sprintf("uintptr value too large: %v", v)
+ panic(NewErr(mess))
+ }
+ return unsafe.Pointer(C.cfish_Int_new(C.int64_t(v)))
+ case uint64:
+ if v > math.MaxInt64 {
+ mess := fmt.Sprintf("uint64 value too large: %v", v)
+ panic(NewErr(mess))
+ }
+ return unsafe.Pointer(C.cfish_Int_new(C.int64_t(v)))
+ case uint32:
+ return unsafe.Pointer(C.cfish_Int_new(C.int64_t(v)))
+ case uint16:
+ return unsafe.Pointer(C.cfish_Int_new(C.int64_t(v)))
+ case uint8:
+ return unsafe.Pointer(C.cfish_Int_new(C.int64_t(v)))
+ case int64:
+ return unsafe.Pointer(C.cfish_Int_new(C.int64_t(v)))
+ case int32:
+ return unsafe.Pointer(C.cfish_Int_new(C.int64_t(v)))
+ case int16:
+ return unsafe.Pointer(C.cfish_Int_new(C.int64_t(v)))
+ case int8:
+ return unsafe.Pointer(C.cfish_Int_new(C.int64_t(v)))
+ case Obj:
+ certifyCF(v, C.CFISH_INTEGER)
+ return unsafe.Pointer(C.cfish_incref(unsafe.Pointer(v.TOPTR())))
+ default:
+ mess := fmt.Sprintf("Can't convert %T to clownfish.Integer", v)
+ panic(NewErr(mess))
+ }
+}
+
+func GoToFloat(value interface{}) unsafe.Pointer {
+ switch v := value.(type) {
+ case float32:
+ return unsafe.Pointer(C.cfish_Float_new(C.double(v)))
+ case float64:
+ return unsafe.Pointer(C.cfish_Float_new(C.double(v)))
+ case Obj:
+ certifyCF(v, C.CFISH_FLOAT)
+ return unsafe.Pointer(C.cfish_incref(unsafe.Pointer(v.TOPTR())))
+ default:
+ mess := fmt.Sprintf("Can't convert %T to clownfish.Float", v)
+ panic(NewErr(mess))
+ }
+}
+
+func GoToBoolean(value interface{}) unsafe.Pointer {
+ switch v := value.(type) {
+ case bool:
+ if v {
+ return unsafe.Pointer(C.cfish_incref(unsafe.Pointer(C.CFISH_TRUE)))
+ } else {
+ return unsafe.Pointer(C.cfish_incref(unsafe.Pointer(C.CFISH_FALSE)))
+ }
+ case Obj:
+ certifyCF(v, C.CFISH_BOOLEAN)
+ return unsafe.Pointer(C.cfish_incref(unsafe.Pointer(v.TOPTR())))
+ default:
+ mess := fmt.Sprintf("Can't convert %T to clownfish.Boolean", v)
+ panic(NewErr(mess))
+ }
+}
+
+func GoToVector(value interface{}) unsafe.Pointer {
+ switch v := value.(type) {
+ case []interface{}:
+ size := len(v)
+ vec := C.cfish_Vec_new(C.size_t(size))
+ for i := 0; i < size; i++ {
+ elem := GoToClownfish(v[i], nil, true)
+ C.CFISH_Vec_Store(vec, C.size_t(i), (*C.cfish_Obj)(elem))
+ }
+ return unsafe.Pointer(vec)
+ case Obj:
+ certifyCF(v, C.CFISH_VECTOR)
+ return unsafe.Pointer(C.cfish_incref(unsafe.Pointer(v.TOPTR())))
+ default:
+ mess := fmt.Sprintf("Can't convert %T to clownfish.Vector", v)
+ panic(NewErr(mess))
+ }
+}
+
+func GoToHash(value interface{}) unsafe.Pointer {
+ switch v := value.(type) {
+ case map[string]interface{}:
+ size := len(v)
+ hash := C.cfish_Hash_new(C.size_t(size))
+ for key, val := range v {
+ newVal := GoToClownfish(val, nil, true)
+ keySize := len(key)
+ keyStr := C.CString(key)
+ cfKey := C.cfish_Str_new_steal_utf8(keyStr, C.size_t(keySize))
+ defer C.cfish_dec_refcount(unsafe.Pointer(cfKey))
+ C.CFISH_Hash_Store(hash, cfKey, (*C.cfish_Obj)(newVal))
+ }
+ return unsafe.Pointer(hash)
+ case Obj:
+ certifyCF(v, C.CFISH_HASH)
+ return unsafe.Pointer(C.cfish_incref(unsafe.Pointer(v.TOPTR())))
+ default:
+ mess := fmt.Sprintf("Can't convert %T to clownfish.Hash", v)
+ panic(NewErr(mess))
+ }
+}
+
+func ToGo(ptr unsafe.Pointer) interface{} {
+ if ptr == nil {
+ return nil
+ }
+ class := C.cfish_Obj_get_class((*C.cfish_Obj)(ptr))
+ if class == C.CFISH_STRING {
+ return CFStringToGo(ptr)
+ } else if class == C.CFISH_BLOB {
+ return BlobToGo(ptr)
+ } else if class == C.CFISH_VECTOR {
+ return VectorToGo(ptr)
+ } else if class == C.CFISH_HASH {
+ return HashToGo(ptr)
+ } else if class == C.CFISH_BOOLEAN {
+ if ptr == unsafe.Pointer(C.CFISH_TRUE) {
+ return true
+ } else {
+ return false
+ }
+ } else if class == C.CFISH_INTEGER {
+ val := C.CFISH_Int_Get_Value((*C.cfish_Integer)(ptr))
+ return int64(val)
+ } else if class == C.CFISH_FLOAT {
+ val := C.CFISH_Float_Get_Value((*C.cfish_Float)(ptr))
+ return float64(val)
+ } else {
+ // Don't convert to a native Go type, but wrap in a Go struct.
+ return WRAPAny(ptr)
+ }
+}
+
func CFStringToGo(ptr unsafe.Pointer) string {
+ return StringToGo(ptr)
+}
+
+func StringToGo(ptr unsafe.Pointer) string {
cfString := (*C.cfish_String)(ptr)
if cfString == nil {
return ""
@@ -149,13 +462,77 @@ func CFStringToGo(ptr unsafe.Pointer) string {
defer C.cfish_dec_refcount(unsafe.Pointer(cfString))
}
data := C.CFISH_Str_Get_Ptr8(cfString)
- size := C.int(C.CFISH_Str_Get_Size(cfString))
- return C.GoStringN(data, size)
+ size := C.CFISH_Str_Get_Size(cfString)
+ if size > C.size_t(C.INT_MAX) {
+ panic(fmt.Sprintf("Overflow: %d > %d", size, C.INT_MAX))
+ }
+ return C.GoStringN(data, C.int(size))
+}
+
+func BlobToGo(ptr unsafe.Pointer) []byte {
+ blob := (*C.cfish_Blob)(ptr)
+ if blob == nil {
+ return nil
+ }
+ class := C.cfish_Obj_get_class((*C.cfish_Obj)(ptr))
+ if class != C.CFISH_BLOB {
+ mess := "Not a Blob: " + StringToGo(unsafe.Pointer(C.CFISH_Class_Get_Name(class)))
+ panic(NewErr(mess))
+ }
+ data := C.CFISH_Blob_Get_Buf(blob)
+ size := C.CFISH_Blob_Get_Size(blob)
+ if size > C.size_t(C.INT_MAX) {
+ panic(fmt.Sprintf("Overflow: %d > %d", size, C.INT_MAX))
+ }
+ return C.GoBytes(unsafe.Pointer(data), C.int(size))
+}
+
+func VectorToGo(ptr unsafe.Pointer) []interface{} {
+ vec := (*C.cfish_Vector)(ptr)
+ if vec == nil {
+ return nil
+ }
+ class := C.cfish_Obj_get_class((*C.cfish_Obj)(ptr))
+ if class != C.CFISH_VECTOR {
+ mess := "Not a Vector: " + StringToGo(unsafe.Pointer(C.CFISH_Class_Get_Name(class)))
+ panic(NewErr(mess))
+ }
+ size := C.CFISH_Vec_Get_Size(vec)
+ if size > C.size_t(maxInt) {
+ panic(fmt.Sprintf("Overflow: %d > %d", size, maxInt))
+ }
+ slice := make([]interface{}, int(size))
+ for i := 0; i < int(size); i++ {
+ slice[i] = ToGo(unsafe.Pointer(C.CFISH_Vec_Fetch(vec, C.size_t(i))))
+ }
+ return slice
+}
+
+func HashToGo(ptr unsafe.Pointer) map[string]interface{} {
+ hash := (*C.cfish_Hash)(ptr)
+ if hash == nil {
+ return nil
+ }
+ class := C.cfish_Obj_get_class((*C.cfish_Obj)(ptr))
+ if class != C.CFISH_HASH {
+ mess := "Not a Hash: " + StringToGo(unsafe.Pointer(C.CFISH_Class_Get_Name(class)))
+ panic(NewErr(mess))
+ }
+ size := C.CFISH_Hash_Get_Size(hash)
+ m := make(map[string]interface{}, int(size))
+ iter := C.cfish_HashIter_new(hash)
+ defer C.cfish_dec_refcount(unsafe.Pointer(iter))
+ for C.CFISH_HashIter_Next(iter) {
+ key := C.CFISH_HashIter_Get_Key(iter)
+ val := C.CFISH_HashIter_Get_Value(iter)
+ m[StringToGo(unsafe.Pointer(key))] = ToGo(unsafe.Pointer(val))
+ }
+ return m
}
func (e *ErrIMP) Error() string {
mess := C.CFISH_Err_Get_Mess((*C.cfish_Err)(unsafe.Pointer(e.ref)))
- return CFStringToGo(unsafe.Pointer(mess))
+ return StringToGo(unsafe.Pointer(mess))
}
//export GoCfish_PanicErr_internal
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/55d40ac6/runtime/go/clownfish/clownfish_test.go
----------------------------------------------------------------------
diff --git a/runtime/go/clownfish/clownfish_test.go b/runtime/go/clownfish/clownfish_test.go
index 6103f24..6b31527 100644
--- a/runtime/go/clownfish/clownfish_test.go
+++ b/runtime/go/clownfish/clownfish_test.go
@@ -18,11 +18,237 @@ package clownfish
import "testing"
import "unsafe"
+import "reflect"
+import "math"
-func TestStuff(t *testing.T) {
- cfString := NewString("foo")
- goString := CFStringToGo(unsafe.Pointer(cfString.TOPTR()))
- if goString != "foo" {
- t.Error("Round-tripping strings failed")
+func deepCheck(t *testing.T, got, expected interface{}) {
+ if !reflect.DeepEqual(got, expected) {
+ t.Errorf("Expected %v got %v", expected, got)
}
}
+
+func TestStringToGo(t *testing.T) {
+ strings := []string{"foo", "", "z\u0000z"}
+ for _, val := range strings {
+ got := StringToGo(unsafe.Pointer(NewString(val).TOPTR()))
+ deepCheck(t, got, val)
+ }
+}
+
+func TestBlobToGo(t *testing.T) {
+ strings := []string{"foo", "", "z\u0000z"}
+ for _, str := range strings {
+ expected := []byte(str)
+ got := BlobToGo(unsafe.Pointer(NewBlob(expected).TOPTR()))
+ deepCheck(t, got, expected)
+ }
+}
+
+func TestIntegerToGo(t *testing.T) {
+ values := []int64{math.MaxInt64, math.MinInt64, 0, 1, -1}
+ for _, val := range values {
+ got := ToGo(unsafe.Pointer(NewInteger(val).TOPTR()))
+ deepCheck(t, got, val)
+ }
+}
+
+func TestFloatToGo(t *testing.T) {
+ values := []float64{math.MaxFloat64, math.SmallestNonzeroFloat64,
+ 0.0, -0.0, 0.5, -0.5, math.Inf(1), math.Inf(-1)}
+ for _, val := range values {
+ got := ToGo(unsafe.Pointer(NewFloat(val).TOPTR()))
+ deepCheck(t, got, val)
+ }
+ notNum := ToGo(unsafe.Pointer(NewFloat(math.NaN()).TOPTR()))
+ if !math.IsNaN(notNum.(float64)) {
+ t.Error("Didn't convert NaN cleanly")
+ }
+}
+
+func TestBoolToGo(t *testing.T) {
+ values := []bool{true, false}
+ for _, val := range values {
+ got := ToGo(unsafe.Pointer(NewBoolean(val).TOPTR()))
+ deepCheck(t, got, val)
+ }
+}
+
+func TestVectorToGo(t *testing.T) {
+ vec := NewVector(3)
+ vec.Push(NewString("foo"))
+ vec.Push(NewInteger(42))
+ //vec.Push(nil)
+ inner := NewVector(1)
+ inner.Push(NewString("bar"))
+ vec.Push(inner)
+ expected := []interface{}{
+ "foo",
+ int64(42),
+ //nil,
+ []interface{}{"bar"},
+ }
+ got := VectorToGo(unsafe.Pointer(vec.TOPTR()))
+ deepCheck(t, got, expected)
+}
+
+func TestHashToGo(t *testing.T) {
+ hash := NewHash(0)
+ hash.Store("str", NewString("foo"))
+ hash.Store("bool", NewBoolean(false))
+ hash.Store("float", NewFloat(-0.5))
+ hash.Store("int", NewInteger(42))
+ //hash.Store("nil", nil)
+ vec := NewVector(1)
+ vec.Push(NewString("bar"))
+ hash.Store("vector", vec)
+ got := HashToGo(unsafe.Pointer(hash.TOPTR()))
+
+ expected := map[string]interface{}{
+ "str": "foo",
+ "bool": false,
+ "float": -0.5,
+ "int": int64(42),
+ //"nil": nil,
+ "vector": []interface{}{"bar"},
+ }
+ deepCheck(t, got, expected)
+}
+
+func TestNilToGo(t *testing.T) {
+ got := ToGo(unsafe.Pointer(uintptr(0)))
+ if got != nil {
+ t.Errorf("Expected nil, got %v", got)
+ }
+}
+
+func TestGoToNil(t *testing.T) {
+ if GoToClownfish(nil, nil, true) != nil {
+ t.Error("Convert nullable nil successfully")
+ }
+}
+
+func TestGoToNilNotNullable(t *testing.T) {
+ defer func() { recover() }()
+ GoToClownfish(nil, nil, false) // should panic
+ t.Error("Non-nullable nil should trigger error") // should be unreachable
+}
+
+func TestGoToString(t *testing.T) {
+ strings := []string{"foo", "", "z\u0000z"}
+ for _, val := range strings {
+ got := WRAPAny(GoToString(val))
+ if _, ok := got.(String); !ok {
+ t.Errorf("Not a String, but a %T", got)
+ }
+ if ToGo(unsafe.Pointer(got.TOPTR())).(string) != val {
+ t.Error("Round trip failed")
+ }
+ }
+}
+
+func TestGoToBlob(t *testing.T) {
+ strings := []string{"foo", "", "z\u0000z"}
+ for _, str := range strings {
+ val := []byte(str)
+ got := WRAPAny(GoToBlob(val))
+ if _, ok := got.(Blob); !ok {
+ t.Errorf("Not a Blob, but a %T", got)
+ }
+ if !reflect.DeepEqual(ToGo(unsafe.Pointer(got.TOPTR())), val) {
+ t.Error("Round trip failed")
+ }
+ }
+}
+
+func checkIntConv(t *testing.T, got Obj) {
+ if _, ok := got.(Integer); !ok {
+ t.Errorf("Not an Integer, but a %T", got)
+ }
+}
+
+func TestGoToInteger(t *testing.T) {
+ checkIntConv(t, WRAPAny(GoToClownfish(int(42), nil, true)))
+ checkIntConv(t, WRAPAny(GoToClownfish(uint(42), nil, true)))
+ checkIntConv(t, WRAPAny(GoToClownfish(int64(42), nil, true)))
+ checkIntConv(t, WRAPAny(GoToClownfish(int32(42), nil, true)))
+ checkIntConv(t, WRAPAny(GoToClownfish(int16(42), nil, true)))
+ checkIntConv(t, WRAPAny(GoToClownfish(int8(42), nil, true)))
+ checkIntConv(t, WRAPAny(GoToClownfish(uint64(42), nil, true)))
+ checkIntConv(t, WRAPAny(GoToClownfish(uint32(42), nil, true)))
+ checkIntConv(t, WRAPAny(GoToClownfish(uint16(42), nil, true)))
+ checkIntConv(t, WRAPAny(GoToClownfish(uint8(42), nil, true)))
+ checkIntConv(t, WRAPAny(GoToClownfish(byte(42), nil, true)))
+ checkIntConv(t, WRAPAny(GoToClownfish(rune(42), nil, true)))
+}
+
+func TestGoToIntegerRangeError(t *testing.T) {
+ defer func() { recover() }()
+ GoToClownfish(uint64(math.MaxUint64), nil, true)
+ t.Error("Truncation didn't cause error")
+}
+
+func TestGoToFloat(t *testing.T) {
+ var got Obj
+
+ values := []float64{math.MaxFloat64, math.SmallestNonzeroFloat64,
+ 0.0, -0.0, 0.5, -0.5, math.Inf(1), math.Inf(-1)}
+ for _, val := range values {
+ got := WRAPAny(GoToFloat(val))
+ if _, ok := got.(Float); !ok {
+ t.Errorf("Not a Float, but a %T", got)
+ }
+ if !reflect.DeepEqual(ToGo(unsafe.Pointer(got.TOPTR())), val) {
+ t.Error("Round trip failed")
+ }
+ }
+
+ // NaN
+ got = WRAPAny(GoToFloat(math.NaN()))
+ if !math.IsNaN(ToGo(unsafe.Pointer(got.TOPTR())).(float64)) {
+ t.Error("Didn't convert NaN cleanly")
+ }
+
+ // float32
+ expected := float32(0.5)
+ got = WRAPAny(GoToClownfish(expected, nil, false))
+ deepCheck(t, got.(Float).GetValue(), float64(expected))
+}
+
+func TestGoToBoolean(t *testing.T) {
+ values := []bool{true, false}
+ for _, val := range values {
+ got := WRAPAny(GoToBoolean(val))
+ if _, ok := got.(Boolean); !ok {
+ t.Errorf("Not a Boolean, but a %T", got)
+ }
+ if !reflect.DeepEqual(ToGo(unsafe.Pointer(got.TOPTR())), val) {
+ t.Error("Round trip failed")
+ }
+ }
+}
+
+func TestGoToHash(t *testing.T) {
+ expected := map[string]interface{}{
+ "foo": int64(1),
+ "bar": []interface{}{},
+ }
+ got := WRAPAny(GoToHash(expected))
+ if _, ok := got.(Hash); !ok {
+ t.Errorf("Not a Hash, but a %T", got)
+ }
+ deepCheck(t, ToGo(unsafe.Pointer(got.TOPTR())), expected)
+}
+
+func TestGoToVector(t *testing.T) {
+ expected := []interface{}{
+ "foo",
+ "bar",
+ []interface{}{},
+ int64(-1),
+ }
+ got := WRAPAny(GoToVector(expected))
+ if _, ok := got.(Vector); !ok {
+ t.Errorf("Not a Vector, but a %T", got)
+ }
+ deepCheck(t, ToGo(unsafe.Pointer(got.TOPTR())), expected)
+}
[5/7] lucy-clownfish git commit: Map Blob to Go `[]byte`.
Posted by ma...@apache.org.
Map Blob to Go `[]byte`.
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/df024469
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/df024469
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/df024469
Branch: refs/heads/master
Commit: df0244695968125e31b2c2825cfb72ebf0c5951c
Parents: 04a5731
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Thu Jul 30 18:10:35 2015 -0700
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Fri Jul 31 11:06:32 2015 -0700
----------------------------------------------------------------------
compiler/src/CFCGoFunc.c | 7 +++++++
compiler/src/CFCGoTypeMap.c | 3 +++
2 files changed, 10 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/df024469/compiler/src/CFCGoFunc.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGoFunc.c b/compiler/src/CFCGoFunc.c
index 64f2255..80a6e8d 100644
--- a/compiler/src/CFCGoFunc.c
+++ b/compiler/src/CFCGoFunc.c
@@ -90,6 +90,7 @@ S_prep_start(CFCParcel *parcel, const char *name, CFCClass *invoker,
char *convertible = NULL;
if (CFCType_cfish_string(type)) { convertible = "String"; }
else if (CFCType_cfish_vector(type)) { convertible = "Vector"; }
+ else if (CFCType_cfish_blob(type)) { convertible = "Blob"; }
else { continue; }
char pattern[] =
"\t%sCF := (*C.cfish_%s)(%sGoTo%s(%s))\n";
@@ -172,6 +173,7 @@ S_prep_cfargs(CFCParcel *parcel, CFCClass *invoker,
"(", go_name, ")", NULL);
}
else if ((CFCType_is_string_type(type)
+ || CFCType_cfish_blob(type)
|| CFCType_cfish_vector(type))
// Don't convert an invocant.
&& (targ != IS_METHOD || i != 0)
@@ -234,6 +236,11 @@ CFCGoFunc_return_statement(CFCParcel *parcel, CFCType *return_type,
"%s\treturn %sCFStringToGo(unsafe.Pointer(retvalCF))\n";
statement = CFCUtil_sprintf(pattern, maybe_decref, clownfish_dot);
}
+ else if (CFCType_cfish_blob(return_type)) {
+ char pattern[] =
+ "%s\treturn %sBlobToGo(unsafe.Pointer(retvalCF))\n";
+ statement = CFCUtil_sprintf(pattern, maybe_decref, clownfish_dot);
+ }
else if (CFCType_cfish_vector(return_type)) {
char pattern[] =
"%s\treturn %sVectorToGo(unsafe.Pointer(retvalCF))\n";
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/df024469/compiler/src/CFCGoTypeMap.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGoTypeMap.c b/compiler/src/CFCGoTypeMap.c
index 15e42a7..afd5345 100644
--- a/compiler/src/CFCGoTypeMap.c
+++ b/compiler/src/CFCGoTypeMap.c
@@ -96,6 +96,9 @@ CFCGoTypeMap_go_type_name(CFCType *type, CFCParcel *current_parcel) {
if (CFCType_is_string_type(type)) {
return CFCUtil_strdup("string");
}
+ else if (CFCType_cfish_blob(type)) {
+ return CFCUtil_strdup("[]byte");
+ }
else if (CFCType_cfish_vector(type)) {
return CFCUtil_strdup("[]interface{}");
}
[6/7] lucy-clownfish git commit: Map Hash to `map[string]interface{}`.
Posted by ma...@apache.org.
Map Hash to `map[string]interface{}`.
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/a665132d
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/a665132d
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/a665132d
Branch: refs/heads/master
Commit: a665132d860925f4de24cd0182a0021a44a6a6ed
Parents: df02446
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Thu Jul 30 18:20:06 2015 -0700
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Fri Jul 31 11:06:32 2015 -0700
----------------------------------------------------------------------
compiler/src/CFCGoFunc.c | 9 ++++++++-
compiler/src/CFCGoTypeMap.c | 3 +++
runtime/go/build.go | 4 ++++
runtime/go/clownfish/clownfish.go | 8 ++++++++
4 files changed, 23 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/a665132d/compiler/src/CFCGoFunc.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGoFunc.c b/compiler/src/CFCGoFunc.c
index 80a6e8d..2670034 100644
--- a/compiler/src/CFCGoFunc.c
+++ b/compiler/src/CFCGoFunc.c
@@ -91,6 +91,7 @@ S_prep_start(CFCParcel *parcel, const char *name, CFCClass *invoker,
if (CFCType_cfish_string(type)) { convertible = "String"; }
else if (CFCType_cfish_vector(type)) { convertible = "Vector"; }
else if (CFCType_cfish_blob(type)) { convertible = "Blob"; }
+ else if (CFCType_cfish_hash(type)) { convertible = "Hash"; }
else { continue; }
char pattern[] =
"\t%sCF := (*C.cfish_%s)(%sGoTo%s(%s))\n";
@@ -174,7 +175,8 @@ S_prep_cfargs(CFCParcel *parcel, CFCClass *invoker,
}
else if ((CFCType_is_string_type(type)
|| CFCType_cfish_blob(type)
- || CFCType_cfish_vector(type))
+ || CFCType_cfish_vector(type)
+ || CFCType_cfish_hash(type))
// Don't convert an invocant.
&& (targ != IS_METHOD || i != 0)
) {
@@ -246,6 +248,11 @@ CFCGoFunc_return_statement(CFCParcel *parcel, CFCType *return_type,
"%s\treturn %sVectorToGo(unsafe.Pointer(retvalCF))\n";
statement = CFCUtil_sprintf(pattern, maybe_decref, clownfish_dot);
}
+ else if (CFCType_cfish_hash(return_type)) {
+ char pattern[] =
+ "%s\treturn %sHashToGo(unsafe.Pointer(retvalCF))\n";
+ statement = CFCUtil_sprintf(pattern, maybe_decref, clownfish_dot);
+ }
else if (CFCType_is_object(return_type)) {
char *go_type_name = CFCGoTypeMap_go_type_name(return_type, parcel);
char *struct_name = go_type_name;
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/a665132d/compiler/src/CFCGoTypeMap.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCGoTypeMap.c b/compiler/src/CFCGoTypeMap.c
index afd5345..fbee678 100644
--- a/compiler/src/CFCGoTypeMap.c
+++ b/compiler/src/CFCGoTypeMap.c
@@ -102,6 +102,9 @@ CFCGoTypeMap_go_type_name(CFCType *type, CFCParcel *current_parcel) {
else if (CFCType_cfish_vector(type)) {
return CFCUtil_strdup("[]interface{}");
}
+ else if (CFCType_cfish_hash(type)) {
+ return CFCUtil_strdup("map[string]interface{}");
+ }
else if (CFCType_is_object(type)) {
// Divide the specifier into prefix and struct name.
const char *specifier = CFCType_get_specifier(type);
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/a665132d/runtime/go/build.go
----------------------------------------------------------------------
diff --git a/runtime/go/build.go b/runtime/go/build.go
index fd96fd1..71a8c6b 100644
--- a/runtime/go/build.go
+++ b/runtime/go/build.go
@@ -152,6 +152,10 @@ func specMethods(parcel *cfc.Parcel) {
vecBinding := cfc.NewGoClass(parcel, "Clownfish::Vector")
vecBinding.SetSuppressCtor(true)
vecBinding.Register()
+
+ hashBinding := cfc.NewGoClass(parcel, "Clownfish::Hash")
+ hashBinding.SetSuppressCtor(true)
+ hashBinding.Register()
}
func prep() {
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/a665132d/runtime/go/clownfish/clownfish.go
----------------------------------------------------------------------
diff --git a/runtime/go/clownfish/clownfish.go b/runtime/go/clownfish/clownfish.go
index eefd831..d5e3190 100644
--- a/runtime/go/clownfish/clownfish.go
+++ b/runtime/go/clownfish/clownfish.go
@@ -138,6 +138,14 @@ func NewVector(size int) Vector {
return WRAPVector(unsafe.Pointer(cfObj))
}
+func NewHash(size int) Hash {
+ if (size < 0 || uint64(size) > ^uint64(0)) {
+ panic(NewErr(fmt.Sprintf("Param 'size' out of range: %d", size)))
+ }
+ cfObj := C.cfish_Hash_new(C.size_t(size))
+ return WRAPHash(unsafe.Pointer(cfObj))
+}
+
func (o *ObjIMP) INITOBJ(ptr unsafe.Pointer) {
o.ref = uintptr(ptr)
runtime.SetFinalizer(o, ClearRef)