From 128a2eaf75b94374656bab93c139f3ca83981721 Mon Sep 17 00:00:00 2001 From: Marvin Humphrey Date: Sat, 28 Mar 2015 16:22:31 -0700 Subject: [PATCH 1/8] Change ToPtr() to return `uintptr`. Avoid returning `unsafe.Pointer`, so that Go modules which use Clownfish-powered Go modules must import `unsafe` if they are to perform any unsafe operations. --- runtime/go/clownfish/clownfish.go | 6 +++--- runtime/go/clownfish/clownfish_test.go | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/runtime/go/clownfish/clownfish.go b/runtime/go/clownfish/clownfish.go index fe68e496..bb3173ea 100644 --- a/runtime/go/clownfish/clownfish.go +++ b/runtime/go/clownfish/clownfish.go @@ -69,7 +69,7 @@ func init() { } type Obj interface { - ToPtr() unsafe.Pointer + ToPtr() uintptr } type Err struct { @@ -119,8 +119,8 @@ func (obj *String) finalize() { obj.ref = nil } -func (obj *String) ToPtr() unsafe.Pointer { - return unsafe.Pointer(obj.ref) +func (obj *String) ToPtr() uintptr { + return uintptr(unsafe.Pointer(obj.ref)) } func CFStringToGo(ptr unsafe.Pointer) string { diff --git a/runtime/go/clownfish/clownfish_test.go b/runtime/go/clownfish/clownfish_test.go index 1709dfca..a89870ba 100644 --- a/runtime/go/clownfish/clownfish_test.go +++ b/runtime/go/clownfish/clownfish_test.go @@ -18,10 +18,11 @@ package clownfish_test import "git-wip-us.apache.org/repos/asf/lucy-clownfish.git/runtime/go/clownfish" import "testing" +import "unsafe" func TestStuff(t *testing.T) { cfString := clownfish.NewString("foo") - goString := clownfish.CFStringToGo(cfString.ToPtr()) + goString := clownfish.CFStringToGo(unsafe.Pointer(cfString.ToPtr())) if goString != "foo" { t.Error("Round-tripping strings failed") } From cbd99b0b5ba8b1ef57d82ce940ffd9e041ea3eee Mon Sep 17 00:00:00 2001 From: Marvin Humphrey Date: Sat, 28 Mar 2015 15:12:19 -0700 Subject: [PATCH 2/8] Change interface/struct Go model. Instead of mapping abstract classes to Go interfaces and concrete classes to Go structs, create one Go interface and one Go struct for each class. --- runtime/go/clownfish/clownfish.go | 77 ++++++++++++++++++++----------- runtime/go/clownfish/err_test.go | 4 +- 2 files changed, 52 insertions(+), 29 deletions(-) diff --git a/runtime/go/clownfish/clownfish.go b/runtime/go/clownfish/clownfish.go index bb3173ea..d3cc3315 100644 --- a/runtime/go/clownfish/clownfish.go +++ b/runtime/go/clownfish/clownfish.go @@ -72,54 +72,70 @@ type Obj interface { ToPtr() uintptr } -type Err struct { +type implObj struct { + ref *C.cfish_Obj +} + +type Err interface { + Obj + Error() string +} + +type implErr struct { ref *C.cfish_Err } -type String struct { +type String interface { + Obj +} + +type implString struct { ref *C.cfish_String } -type ByteBuf struct { +type implByteBuf struct { ref *C.cfish_ByteBuf } -type Hash struct { +type implHash struct { ref *C.cfish_Hash } -type VArray struct { +type implVArray struct { ref *C.cfish_VArray } -type Class struct { +type implClass struct { ref *C.cfish_Class } -type Method struct { +type implMethod struct { ref *C.cfish_Method } -type LockFreeRegistry struct { +type implLockFreeRegistry struct { ref *C.cfish_LockFreeRegistry } -func NewString(goString string) *String { +func NewString(goString string) String { str := C.CString(goString) len := C.size_t(len(goString)) - obj := &String{ - C.cfish_Str_new_steal_utf8(str, len), - } - runtime.SetFinalizer(obj, (*String).finalize) + cfObj := C.cfish_Str_new_steal_utf8(str, len) + return WRAPString(unsafe.Pointer(cfObj)) +} + +func WRAPString(ptr unsafe.Pointer) String { + obj := &implString{((*C.cfish_String)(ptr))} + runtime.SetFinalizer(obj, (*implString).finalize) return obj } -func (obj *String) finalize() { +func (obj *implString) finalize() { C.cfish_dec_refcount(unsafe.Pointer(obj.ref)) obj.ref = nil } -func (obj *String) ToPtr() uintptr { +func (obj *implString) ToPtr() uintptr { return uintptr(unsafe.Pointer(obj.ref)) } @@ -137,30 +153,36 @@ func CFStringToGo(ptr unsafe.Pointer) string { return C.GoStringN(data, size) } -// TODO: Err should be an interface. -func NewError(mess string) error { +func NewErr(mess string) Err { str := C.CString(mess) len := C.size_t(len(mess)) messC := C.cfish_Str_new_steal_utf8(str, len) - obj := &Err{C.cfish_Err_new(messC)} - runtime.SetFinalizer(obj, (*Err).finalize) + cfObj := C.cfish_Err_new(messC) + return WRAPErr(unsafe.Pointer(cfObj)) +} + +func WRAPErr(ptr unsafe.Pointer) Err { + obj := &implErr{((*C.cfish_Err)(ptr))} + runtime.SetFinalizer(obj, (*implErr).finalize) return obj } -func (obj *Err) finalize() { +func (obj *implErr) finalize() { C.cfish_dec_refcount(unsafe.Pointer(obj.ref)) obj.ref = nil } -func (obj *Err) Error() string { +func (obj *implErr) ToPtr() uintptr { + return uintptr(unsafe.Pointer(obj.ref)) +} + +func (obj *implErr) Error() string { return CFStringToGo(unsafe.Pointer(C.CFISH_Err_Get_Mess(obj.ref))) } //export GoCfish_PanicErr_internal func GoCfish_PanicErr_internal(cfErr *C.cfish_Err) { - goErr := &Err{cfErr} - C.cfish_inc_refcount(unsafe.Pointer(cfErr)) - runtime.SetFinalizer(goErr, (*Err).finalize) + goErr := WRAPErr(unsafe.Pointer(cfErr)) panic(goErr) } @@ -169,18 +191,19 @@ func GoCfish_TrapErr_internal(routine C.CFISH_Err_Attempt_t, context unsafe.Pointer) *C.cfish_Err { err := TrapErr(func() { C.GoCfish_RunRoutine(routine, context) }) if err != nil { - return (err.(*Err)).ref + ptr := (err.(Err)).ToPtr() + return ((*C.cfish_Err)(unsafe.Pointer(ptr))) } return nil } -// Run the supplied routine, and if it panics with a *clownfish.Err, trap and +// Run the supplied routine, and if it panics with a clownfish.Err, trap and // return it. func TrapErr(routine func()) (trapped error) { defer func() { if r := recover(); r != nil { // TODO: pass whitelist of Err types to trap. - myErr, ok := r.(*Err) + myErr, ok := r.(Err) if ok { trapped = myErr } else { diff --git a/runtime/go/clownfish/err_test.go b/runtime/go/clownfish/err_test.go index 060cf1ee..9bdbceb8 100644 --- a/runtime/go/clownfish/err_test.go +++ b/runtime/go/clownfish/err_test.go @@ -22,10 +22,10 @@ import "errors" func TestTrapErr(t *testing.T) { err := clownfish.TrapErr( - func() { panic(clownfish.NewError("mistakes were made")) }, + func() { panic(clownfish.NewErr("mistakes were made")) }, ) if err == nil { - t.Error("Failed to trap *clownfish.Err") + t.Error("Failed to trap clownfish.Err") } } From fcf9dcfb0c746262c0e62e9d0e47a862d1268d74 Mon Sep 17 00:00:00 2001 From: Marvin Humphrey Date: Wed, 3 Dec 2014 20:56:52 -0800 Subject: [PATCH 3/8] Add CFC module for Go/C type mapping. --- compiler/src/CFCGoTypeMap.c | 126 ++++++++++++++++++++++++++++++++++++ compiler/src/CFCGoTypeMap.h | 36 +++++++++++ 2 files changed, 162 insertions(+) create mode 100644 compiler/src/CFCGoTypeMap.c create mode 100644 compiler/src/CFCGoTypeMap.h diff --git a/compiler/src/CFCGoTypeMap.c b/compiler/src/CFCGoTypeMap.c new file mode 100644 index 00000000..f5b689f0 --- /dev/null +++ b/compiler/src/CFCGoTypeMap.c @@ -0,0 +1,126 @@ +/* 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 +#include +#include + +#include "CFCGoTypeMap.h" +#include "CFCParcel.h" +#include "CFCType.h" +#include "CFCUtil.h" + +/* Integer types with implementation-specific widths are tricky to convert. + * If a C `int` and a Go `int` are not the same width, it is potentially + * dangerous to map between them. For example, if a function takes a 32-bit C + * `int` and we wrap that in a Go function which takes a 64-bit Go `int`, a + * user who sees the Go function signature will being misled about the range + * of valid input. + * + * Therefore, we take a mostly conservative approach and err on the side of + * artificially limiting the range. + */ +static struct { + const char *c; + const char *go; +} conversions[] = { + {"bool", "bool"}, + {"char", "int8"}, + {"short", "int16"}, + {"int", "int32"}, + {"long", "int32"}, + {"size_t", "uintptr"}, + {"int8_t", "int8"}, + {"int16_t", "int16"}, + {"int32_t", "int32"}, + {"int64_t", "int64"}, + {"uint8_t", "uint8"}, + {"uint16_t", "uint16"}, + {"uint32_t", "uint32"}, + {"uint64_t", "uint64"}, + {"float", "float32"}, + {"double", "float64"}, +}; + +static int num_conversions = sizeof(conversions) / sizeof(conversions[0]); + +/* TODO: Optimize local conversions by creating a static wrapper function + * which takes a buffer and allocates memory only if the buffer isn't big + * enough. */ + +char* +CFCGoTypeMap_go_type_name(CFCType *type, CFCParcel *current_parcel) { + if (CFCType_is_object(type)) { + // Divide the specifier into prefix and struct name. + const char *specifier = CFCType_get_specifier(type); + size_t prefix_len = 0; + for (size_t max = strlen(specifier); prefix_len < max; prefix_len++) { + if (isupper(specifier[prefix_len])) { + break; + } + } + if (!prefix_len) { + CFCUtil_die("Can't convert object type name '%s'", specifier); + } + const char *struct_sym = specifier + prefix_len; + + // Find the parcel that the type lives in. + CFCParcel** all_parcels = CFCParcel_all_parcels(); + CFCParcel *parcel = NULL; + for (int i = 0; all_parcels[i] != NULL; i++) { + const char *candidate = CFCParcel_get_prefix(all_parcels[i]); + if (strncmp(candidate, specifier, prefix_len) == 0 + && strlen(candidate) == prefix_len + ) { + parcel = all_parcels[i]; + break; + } + } + if (!parcel) { + CFCUtil_die("Can't find parcel for type '%s'", specifier); + } + + // If the type lives in this parcel, return only the struct sym + // without a go package prefix. + if (parcel == current_parcel) { + return CFCUtil_strdup(struct_sym); + } + + // The type lives in another parcel, so prefix its Go package name. + // TODO: Stop downcasing once Clownfish parcel names are constrained + // to lower case. + const char *package_name = CFCParcel_get_name(parcel); + if (strrchr(package_name, '.')) { + package_name = strrchr(package_name, '.') + 1; + } + char *result = CFCUtil_sprintf("%s.%s", package_name, struct_sym); + for (int i = 0; result[i] != '.'; i++) { + result[i] = tolower(result[i]); + } + return result; + } + else if (CFCType_is_primitive(type)) { + const char *specifier = CFCType_get_specifier(type); + for (int i = 0; i < num_conversions; i++) { + if (strcmp(specifier, conversions[i].c) == 0) { + return CFCUtil_strdup(conversions[i].go); + } + } + } + + return NULL; +} + diff --git a/compiler/src/CFCGoTypeMap.h b/compiler/src/CFCGoTypeMap.h new file mode 100644 index 00000000..3af61370 --- /dev/null +++ b/compiler/src/CFCGoTypeMap.h @@ -0,0 +1,36 @@ +/* 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_CFCGOTYPEMAP +#define H_CFCGOTYPEMAP + +#ifdef __cplusplus +extern "C" { +#endif + +struct CFCType; +struct CFCParcel; + +char* +CFCGoTypeMap_go_type_name(struct CFCType *type, + struct CFCParcel *current_parcel); + +#ifdef __cplusplus +} +#endif + +#endif /* H_CFCGOTYPEMAP */ + From fbd9d5425720ee4ad270f065e034c6f5d039f698 Mon Sep 17 00:00:00 2001 From: Marvin Humphrey Date: Sun, 15 Mar 2015 10:42:55 -0700 Subject: [PATCH 4/8] Expose Parcel fetching from Go. --- compiler/go/cfc/cfc.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/compiler/go/cfc/cfc.go b/compiler/go/cfc/cfc.go index 2a1e44fa..930aba81 100644 --- a/compiler/go/cfc/cfc.go +++ b/compiler/go/cfc/cfc.go @@ -67,6 +67,10 @@ func DoStuff() { hierarchy.Build() } +type Parcel struct { + ref *C.CFCParcel +} + type Hierarchy struct { ref *C.CFCHierarchy } @@ -79,6 +83,22 @@ type BindC struct { ref *C.CFCC } +func FetchParcel(name string) *Parcel { + nameC := C.CString(name) + defer C.free(unsafe.Pointer(nameC)) + parcelC := C.CFCParcel_fetch(nameC) + if parcelC == nil { + return nil + } + obj := &Parcel{parcelC} + runtime.SetFinalizer(obj, (*Parcel).finalize) + return obj +} + +func (obj *Parcel) finalize() { + C.CFCBase_decref((*C.CFCBase)(unsafe.Pointer(obj.ref))) +} + func NewHierarchy(dest string) *Hierarchy { destCString := C.CString(dest) defer C.free(unsafe.Pointer(destCString)) From b2cc905f63f4f4d71e57315e86632b76552870f1 Mon Sep 17 00:00:00 2001 From: Marvin Humphrey Date: Sun, 15 Mar 2015 10:46:26 -0700 Subject: [PATCH 5/8] Stub out module for Go bindings. --- compiler/go/cfc/cfc.go | 35 +++++++++++++++ compiler/include/CFC.h | 2 + compiler/src/CFCGo.c | 98 ++++++++++++++++++++++++++++++++++++++++++ compiler/src/CFCGo.h | 63 +++++++++++++++++++++++++++ runtime/go/build.go | 5 +++ 5 files changed, 203 insertions(+) create mode 100644 compiler/src/CFCGo.c create mode 100644 compiler/src/CFCGo.h diff --git a/compiler/go/cfc/cfc.go b/compiler/go/cfc/cfc.go index 930aba81..1f30cd2c 100644 --- a/compiler/go/cfc/cfc.go +++ b/compiler/go/cfc/cfc.go @@ -83,6 +83,10 @@ type BindC struct { ref *C.CFCC } +type BindGo struct { + ref *C.CFCGo +} + func FetchParcel(name string) *Parcel { nameC := C.CString(name) defer C.free(unsafe.Pointer(nameC)) @@ -179,3 +183,34 @@ func (obj *BindC) WriteCallbacks() { func (obj *BindC) WriteHostDefs() { C.CFCC_write_hostdefs(obj.ref) } + +func NewBindGo(hierarchy *Hierarchy) *BindGo { + obj := &BindGo{ + C.CFCGo_new(hierarchy.ref), + } + runtime.SetFinalizer(obj, (*BindGo).finalize) + return obj +} + +func (obj *BindGo) finalize() { + C.CFCBase_decref((*C.CFCBase)(unsafe.Pointer(obj.ref))) +} + +func (obj *BindGo) SetHeader(header string) { + headerCString := C.CString(header) + defer C.free(unsafe.Pointer(headerCString)) + C.CFCGo_set_header(obj.ref, headerCString) +} + +func (obj *BindGo) SetFooter(header string) { + headerCString := C.CString(header) + defer C.free(unsafe.Pointer(headerCString)) + C.CFCGo_set_header(obj.ref, headerCString) +} + +func (obj *BindGo) WriteBindings(parcel *Parcel, dest string) { + destC := C.CString(dest) + defer C.free(unsafe.Pointer(destC)) + C.CFCGo_write_bindings(obj.ref, parcel.ref, destC) +} + diff --git a/compiler/include/CFC.h b/compiler/include/CFC.h index 0fc047b1..2cc85f48 100644 --- a/compiler/include/CFC.h +++ b/compiler/include/CFC.h @@ -43,6 +43,8 @@ #include "CFCBindFunction.h" #include "CFCBindMethod.h" +#include "CFCGo.h" + #include "CFCPerl.h" #include "CFCPerlSub.h" #include "CFCPerlMethod.h" diff --git a/compiler/src/CFCGo.c b/compiler/src/CFCGo.c new file mode 100644 index 00000000..86256645 --- /dev/null +++ b/compiler/src/CFCGo.c @@ -0,0 +1,98 @@ +/* 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 "charmony.h" + +#include +#include +#include +#include + +#define CFC_NEED_BASE_STRUCT_DEF +#include "CFCBase.h" +#include "CFCGo.h" +#include "CFCParcel.h" +#include "CFCClass.h" +#include "CFCMethod.h" +#include "CFCHierarchy.h" +#include "CFCUtil.h" +#include "CFCGoTypeMap.h" + +static void +S_CFCGo_destroy(CFCGo *self); + +struct CFCGo { + CFCBase base; + CFCHierarchy *hierarchy; + char *header; + char *footer; + char *c_header; + char *c_footer; +}; + +static const CFCMeta CFCGO_META = { + "Clownfish::CFC::Binding::Go", + sizeof(CFCGo), + (CFCBase_destroy_t)S_CFCGo_destroy +}; + +CFCGo* +CFCGo_new(CFCHierarchy *hierarchy) { + CFCUTIL_NULL_CHECK(hierarchy); + CFCGo *self = (CFCGo*)CFCBase_allocate(&CFCGO_META); + self->hierarchy = (CFCHierarchy*)CFCBase_incref((CFCBase*)hierarchy); + self->header = CFCUtil_strdup(""); + self->footer = CFCUtil_strdup(""); + self->c_header = CFCUtil_strdup(""); + self->c_footer = CFCUtil_strdup(""); + return self; +} + +static void +S_CFCGo_destroy(CFCGo *self) { + CFCBase_decref((CFCBase*)self->hierarchy); + FREEMEM(self->header); + FREEMEM(self->footer); + FREEMEM(self->c_header); + FREEMEM(self->c_footer); + CFCBase_destroy((CFCBase*)self); +} + +void +CFCGo_set_header(CFCGo *self, const char *header) { + CFCUTIL_NULL_CHECK(header); + free(self->header); + self->header = CFCUtil_strdup(header); + free(self->c_header); + self->c_header = CFCUtil_make_c_comment(header); +} + +void +CFCGo_set_footer(CFCGo *self, const char *footer) { + CFCUTIL_NULL_CHECK(footer); + free(self->footer); + self->footer = CFCUtil_strdup(footer); + free(self->c_footer); + self->c_footer = CFCUtil_make_c_comment(footer); +} + +void +CFCGo_write_bindings(CFCGo *self, CFCParcel *parcel, const char *dest) { + CHY_UNUSED_VAR(self); + CHY_UNUSED_VAR(parcel); + CHY_UNUSED_VAR(dest); +} + diff --git a/compiler/src/CFCGo.h b/compiler/src/CFCGo.h new file mode 100644 index 00000000..0953236d --- /dev/null +++ b/compiler/src/CFCGo.h @@ -0,0 +1,63 @@ +/* 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_CFCGO +#define H_CFCGO + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct CFCGo CFCGo; +struct CFCParcel; +struct CFCHierarchy; + +/** Clownfish::CFC::Binding::Go - Go bindings for a + * Clownfish::CFC::Model::Hierarchy. + * + * Clownfish::CFC::Binding::Go presents an interface for auto-generating CGO + * code to bind C code for a Clownfish parcel to Go. + */ + +/** + * @param hierarchy A CFCHierarchy. + */ + +CFCGo* +CFCGo_new(struct CFCHierarchy *hierarchy); + +/** Set the text which will be prepended to generated CGO files -- for + * instance, an "autogenerated file" warning. + */ +void +CFCGo_set_header(CFCGo *self, const char *header); + +/** Set the text which will be appended to the end of generated CGO files. + */ +void +CFCGo_set_footer(CFCGo *self, const char *footer); + +/** Generate CGO bindings for the specified parcel. + */ +void +CFCGo_write_bindings(CFCGo *self, struct CFCParcel *parcel, const char *dest); + +#ifdef __cplusplus +} +#endif + +#endif /* H_CFCGO */ + diff --git a/runtime/go/build.go b/runtime/go/build.go index 51f4662c..c7465371 100644 --- a/runtime/go/build.go +++ b/runtime/go/build.go @@ -123,6 +123,11 @@ func runCFC() { if modified { cBinding := cfc.NewBindC(hierarchy, autogenHeader, "") cBinding.WriteHostDefs() + goBinding := cfc.NewBindGo(hierarchy) + goBinding.SetHeader(autogenHeader) + parcel := cfc.FetchParcel("Clownfish") + packageDir := path.Join(buildDir, "clownfish") + goBinding.WriteBindings(parcel, packageDir) hierarchy.WriteLog() } } From c123bbf177b0d3c3d139605ce893d71cb36cda88 Mon Sep 17 00:00:00 2001 From: Marvin Humphrey Date: Mon, 16 Mar 2015 21:15:33 -0700 Subject: [PATCH 6/8] Write Go-specific hostdefs rather than reuse C. --- compiler/src/CFCGo.c | 31 ++++++++++++++++++++++++++++++- runtime/go/build.go | 2 -- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/compiler/src/CFCGo.c b/compiler/src/CFCGo.c index 86256645..2e2b0f35 100644 --- a/compiler/src/CFCGo.c +++ b/compiler/src/CFCGo.c @@ -89,10 +89,39 @@ CFCGo_set_footer(CFCGo *self, const char *footer) { self->c_footer = CFCUtil_make_c_comment(footer); } +static void +S_write_hostdefs(CFCGo *self) { + const char pattern[] = + "/*\n" + " * %s\n" + " */\n" + "\n" + "#ifndef H_CFISH_HOSTDEFS\n" + "#define H_CFISH_HOSTDEFS 1\n" + "\n" + "#define CFISH_OBJ_HEAD \\\n" + " size_t refcount;\n" + "\n" + "#endif /* H_CFISH_HOSTDEFS */\n" + "\n" + "%s\n"; + char *content + = CFCUtil_sprintf(pattern, self->header, self->footer); + + // Write if the content has changed. + const char *inc_dest = CFCHierarchy_get_include_dest(self->hierarchy); + char *filepath = CFCUtil_sprintf("%s" CHY_DIR_SEP "cfish_hostdefs.h", + inc_dest); + CFCUtil_write_if_changed(filepath, content, strlen(content)); + + FREEMEM(filepath); + FREEMEM(content); +} + void CFCGo_write_bindings(CFCGo *self, CFCParcel *parcel, const char *dest) { - CHY_UNUSED_VAR(self); CHY_UNUSED_VAR(parcel); CHY_UNUSED_VAR(dest); + S_write_hostdefs(self); } diff --git a/runtime/go/build.go b/runtime/go/build.go index c7465371..3ef57fbe 100644 --- a/runtime/go/build.go +++ b/runtime/go/build.go @@ -121,8 +121,6 @@ func runCFC() { coreBinding := cfc.NewBindCore(hierarchy, autogenHeader, "") modified := coreBinding.WriteAllModified(false) if modified { - cBinding := cfc.NewBindC(hierarchy, autogenHeader, "") - cBinding.WriteHostDefs() goBinding := cfc.NewBindGo(hierarchy) goBinding.SetHeader(autogenHeader) parcel := cfc.FetchParcel("Clownfish") From 3a682749620f3aed1507ce809d60aba71b8d0903 Mon Sep 17 00:00:00 2001 From: Marvin Humphrey Date: Mon, 23 Mar 2015 07:34:46 -0700 Subject: [PATCH 7/8] No host subclassing under Go for now. --- compiler/src/CFCGo.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/src/CFCGo.c b/compiler/src/CFCGo.c index 2e2b0f35..3e210a8c 100644 --- a/compiler/src/CFCGo.c +++ b/compiler/src/CFCGo.c @@ -99,6 +99,8 @@ S_write_hostdefs(CFCGo *self) { "#ifndef H_CFISH_HOSTDEFS\n" "#define H_CFISH_HOSTDEFS 1\n" "\n" + "#define CFISH_NO_DYNAMIC_OVERRIDES\n" + "\n" "#define CFISH_OBJ_HEAD \\\n" " size_t refcount;\n" "\n" From 004de889692f06f69828dc0e8e04bfc1e0b0a849 Mon Sep 17 00:00:00 2001 From: Marvin Humphrey Date: Sat, 4 Apr 2015 16:48:56 -0700 Subject: [PATCH 8/8] Rename ToPtr to TOPTR. Using all caps avoids a potential conflict with Clownfish user-defined method named `To_Ptr` -- though the unlikely `TO_PTR` would still cause a conflict. --- runtime/go/clownfish/clownfish.go | 8 ++++---- runtime/go/clownfish/clownfish_test.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/runtime/go/clownfish/clownfish.go b/runtime/go/clownfish/clownfish.go index d3cc3315..5e884a53 100644 --- a/runtime/go/clownfish/clownfish.go +++ b/runtime/go/clownfish/clownfish.go @@ -69,7 +69,7 @@ func init() { } type Obj interface { - ToPtr() uintptr + TOPTR() uintptr } type implObj struct { @@ -135,7 +135,7 @@ func (obj *implString) finalize() { obj.ref = nil } -func (obj *implString) ToPtr() uintptr { +func (obj *implString) TOPTR() uintptr { return uintptr(unsafe.Pointer(obj.ref)) } @@ -172,7 +172,7 @@ func (obj *implErr) finalize() { obj.ref = nil } -func (obj *implErr) ToPtr() uintptr { +func (obj *implErr) TOPTR() uintptr { return uintptr(unsafe.Pointer(obj.ref)) } @@ -191,7 +191,7 @@ func GoCfish_TrapErr_internal(routine C.CFISH_Err_Attempt_t, context unsafe.Pointer) *C.cfish_Err { err := TrapErr(func() { C.GoCfish_RunRoutine(routine, context) }) if err != nil { - ptr := (err.(Err)).ToPtr() + ptr := (err.(Err)).TOPTR() return ((*C.cfish_Err)(unsafe.Pointer(ptr))) } return nil diff --git a/runtime/go/clownfish/clownfish_test.go b/runtime/go/clownfish/clownfish_test.go index a89870ba..016e4a02 100644 --- a/runtime/go/clownfish/clownfish_test.go +++ b/runtime/go/clownfish/clownfish_test.go @@ -22,7 +22,7 @@ import "unsafe" func TestStuff(t *testing.T) { cfString := clownfish.NewString("foo") - goString := clownfish.CFStringToGo(unsafe.Pointer(cfString.ToPtr())) + goString := clownfish.CFStringToGo(unsafe.Pointer(cfString.TOPTR())) if goString != "foo" { t.Error("Round-tripping strings failed") }