From fffd970490b37a1c53cdef0afa78272aee9dc2eb Mon Sep 17 00:00:00 2001 From: Marvin Humphrey Date: Sat, 11 Jul 2015 16:01:41 -0700 Subject: [PATCH 1/6] Add placeholder for generated constructors. --- compiler/src/CFCGo.c | 12 +++++++++++- compiler/src/CFCGoClass.c | 5 +++++ compiler/src/CFCGoClass.h | 3 +++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/compiler/src/CFCGo.c b/compiler/src/CFCGo.c index e571cc52..3b3af2e9 100644 --- a/compiler/src/CFCGo.c +++ b/compiler/src/CFCGo.c @@ -232,6 +232,7 @@ S_gen_autogen_go(CFCGo *self, CFCParcel *parcel) { CFCGoClass **registry = CFCGoClass_registry(); char *type_decs = CFCUtil_strdup(""); char *boilerplate = CFCUtil_strdup(""); + char *ctors = CFCUtil_strdup(""); char *meth_defs = CFCUtil_strdup(""); for (int i = 0; registry[i] != NULL; i++) { @@ -250,6 +251,10 @@ S_gen_autogen_go(CFCGo *self, CFCParcel *parcel) { boilerplate = CFCUtil_cat(boilerplate, boiler_code, "\n", NULL); FREEMEM(boiler_code); + char *ctor_code = CFCGoClass_gen_ctors(class_binding); + ctors = CFCUtil_cat(ctors, ctor_code, "\n", NULL); + FREEMEM(ctor_code); + char *glue = CFCGoClass_gen_meth_glue(class_binding); meth_defs = CFCUtil_cat(meth_defs, glue, "\n", NULL); FREEMEM(glue); @@ -264,15 +269,20 @@ S_gen_autogen_go(CFCGo *self, CFCParcel *parcel) { "\n" "%s\n" "\n" + "// Constructors.\n" + "\n" + "%s\n" + "\n" "// Method bindings.\n" "\n" "%s\n" "\n" ; char *content - = CFCUtil_sprintf(pattern, type_decs, boilerplate, meth_defs); + = CFCUtil_sprintf(pattern, type_decs, boilerplate, ctors, meth_defs); FREEMEM(meth_defs); + FREEMEM(ctors); FREEMEM(boilerplate); FREEMEM(type_decs); return content; diff --git a/compiler/src/CFCGoClass.c b/compiler/src/CFCGoClass.c index cffa762c..28d00d8c 100644 --- a/compiler/src/CFCGoClass.c +++ b/compiler/src/CFCGoClass.c @@ -259,6 +259,11 @@ CFCGoClass_boilerplate_funcs(CFCGoClass *self) { return content; } +char* +CFCGoClass_gen_ctors(CFCGoClass *self) { + return CFCUtil_strdup(""); +} + static void S_lazy_init_method_bindings(CFCGoClass *self) { if (self->method_bindings) { diff --git a/compiler/src/CFCGoClass.h b/compiler/src/CFCGoClass.h index 27911795..bfe88cae 100644 --- a/compiler/src/CFCGoClass.h +++ b/compiler/src/CFCGoClass.h @@ -70,6 +70,9 @@ CFCGoClass_go_typing(CFCGoClass *self); char* CFCGoClass_boilerplate_funcs(CFCGoClass *self); +char* +CFCGoClass_gen_ctors(CFCGoClass *self); + char* CFCGoClass_gen_meth_glue(CFCGoClass *self); From 3f6266df84139f93812015400e67f64d2eb733f6 Mon Sep 17 00:00:00 2001 From: Marvin Humphrey Date: Mon, 13 Jul 2015 17:21:14 -0700 Subject: [PATCH 2/6] Generalize Go-to-cfish arg list prep. Make the functionality which converts Go argument lists to Clownfish-flavored-C argument lists more widely available. --- compiler/src/CFCGoFunc.c | 72 ++++++++++++++++++++++++++++++++++++++ compiler/src/CFCGoFunc.h | 7 ++++ compiler/src/CFCGoMethod.c | 59 +------------------------------ 3 files changed, 80 insertions(+), 58 deletions(-) diff --git a/compiler/src/CFCGoFunc.c b/compiler/src/CFCGoFunc.c index 31386058..ad74bde4 100644 --- a/compiler/src/CFCGoFunc.c +++ b/compiler/src/CFCGoFunc.c @@ -35,6 +35,12 @@ #define GO_NAME_BUF_SIZE 128 +enum { + IS_METHOD = 1, + IS_FUNC = 2, + IS_CTOR = 3 +}; + char* CFCGoFunc_go_meth_name(const char *orig) { char *go_name = CFCUtil_strdup(orig); @@ -101,6 +107,72 @@ CFCGoFunc_func_start(CFCParcel *parcel, const char *name, CFCClass *invoker, return content; } +static char* +S_prep_cfargs(CFCParcel *parcel, CFCClass *invoker, + CFCParamList *param_list, int targ) { + CFCVariable **vars = CFCParamList_get_variables(param_list); + char go_name[GO_NAME_BUF_SIZE]; + char *cfargs = CFCUtil_strdup(""); + + for (int i = 0; vars[i] != NULL; i++) { + CFCVariable *var = vars[i]; + CFCType *type = CFCVariable_get_type(var); + if (targ == IS_METHOD && i == 0) { + CFCGoTypeMap_go_meth_receiever(CFCClass_get_struct_sym(invoker), + param_list, go_name, + GO_NAME_BUF_SIZE); + } + else { + CFCGoTypeMap_go_arg_name(param_list, i, go_name, GO_NAME_BUF_SIZE); + } + + if (i > 0) { + cfargs = CFCUtil_cat(cfargs, ", ", NULL); + } + + if (CFCType_is_primitive(type)) { + 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. + && (targ != IS_METHOD || i != 0) + ) { + const char *format; + if (CFCParcel_is_cfish(parcel)) { + format = "%s((*C.cfish_String)(unsafe.Pointer(NewString(%s).TOPTR())))"; + } + else { + format = "%s((*C.cfish_String)(unsafe.Pointer(clownfish.NewString(%s).TOPTR())))"; + } + char *temp = CFCUtil_sprintf(format, cfargs, go_name); + FREEMEM(cfargs); + cfargs = temp; + } + else if (CFCType_is_object(type)) { + + char *obj_pattern; + if (CFCType_decremented(type)) { + obj_pattern = "(*C.%s)(unsafe.Pointer(C.cfish_inc_refcount(unsafe.Pointer(%s.TOPTR()))))"; + } + else { + obj_pattern = "(*C.%s)(unsafe.Pointer(%s.TOPTR()))"; + } + char *temp = CFCUtil_sprintf(obj_pattern, + CFCType_get_specifier(type), go_name); + cfargs = CFCUtil_cat(cfargs, temp, NULL); + FREEMEM(temp); + } + } + return cfargs; +} + +char* +CFCGoFunc_meth_cfargs(CFCParcel *parcel, CFCClass *invoker, + CFCParamList *param_list) { + return S_prep_cfargs(parcel, invoker, param_list, IS_METHOD); +} + char* CFCGoFunc_return_statement(CFCParcel *parcel, CFCType *return_type, const char *cf_retval) { diff --git a/compiler/src/CFCGoFunc.h b/compiler/src/CFCGoFunc.h index 213b5500..e11fa0db 100644 --- a/compiler/src/CFCGoFunc.h +++ b/compiler/src/CFCGoFunc.h @@ -37,6 +37,13 @@ CFCGoFunc_func_start(struct CFCParcel *parcel, const char *name, struct CFCParamList *param_list, struct CFCType *return_type, int is_method); +/** Convert Go method arguments to comma-separated Clownfish-flavored C + * arguments, to be passed to a Clownfish method. + */ +char* +CFCGoFunc_meth_cfargs(struct CFCParcel *parcel, struct CFCClass *invoker, + struct CFCParamList *param_list); + /** Generate a Go return statement which maps from a CGO Clownfish type to a * Go type. * diff --git a/compiler/src/CFCGoMethod.c b/compiler/src/CFCGoMethod.c index b095347f..f5b7cb4e 100644 --- a/compiler/src/CFCGoMethod.c +++ b/compiler/src/CFCGoMethod.c @@ -133,63 +133,6 @@ CFCGoMethod_get_sig(CFCGoMethod *self, CFCClass *invoker) { } } -#define GO_NAME_BUF_SIZE 128 - -static char* -S_prep_cfargs(CFCParcel *parcel, CFCClass *invoker, - CFCParamList *param_list) { - CFCVariable **vars = CFCParamList_get_variables(param_list); - char go_name[GO_NAME_BUF_SIZE]; - char *cfargs = CFCUtil_strdup(""); - - for (int i = 0; vars[i] != NULL; i++) { - CFCVariable *var = vars[i]; - CFCType *type = CFCVariable_get_type(var); - if (i == 0) { - CFCGoTypeMap_go_meth_receiever(CFCClass_get_struct_sym(invoker), - param_list, go_name, - GO_NAME_BUF_SIZE); - } - else { - cfargs = CFCUtil_cat(cfargs, ", ", NULL); - CFCGoTypeMap_go_arg_name(param_list, i, go_name, GO_NAME_BUF_SIZE); - } - - if (CFCType_is_primitive(type)) { - cfargs = CFCUtil_cat(cfargs, "C.", CFCType_get_specifier(type), - "(", go_name, ")", NULL); - } - else if (CFCType_is_string_type(type) - && i != 0) { // Don't convert a clownfish.String invocant. - const char *format; - if (CFCParcel_is_cfish(parcel)) { - format = "%s((*C.cfish_String)(unsafe.Pointer(NewString(%s).TOPTR())))"; - } - else { - format = "%s((*C.cfish_String)(unsafe.Pointer(clownfish.NewString(%s).TOPTR())))"; - } - char *temp = CFCUtil_sprintf(format, cfargs, go_name); - FREEMEM(cfargs); - cfargs = temp; - } - else if (CFCType_is_object(type)) { - - char *obj_pattern; - if (CFCType_decremented(type)) { - obj_pattern = "(*C.%s)(unsafe.Pointer(C.cfish_inc_refcount(unsafe.Pointer(%s.TOPTR()))))"; - } - else { - obj_pattern = "(*C.%s)(unsafe.Pointer(%s.TOPTR()))"; - } - char *temp = CFCUtil_sprintf(obj_pattern, - CFCType_get_specifier(type), go_name); - cfargs = CFCUtil_cat(cfargs, temp, NULL); - FREEMEM(temp); - } - } - return cfargs; -} - char* CFCGoMethod_func_def(CFCGoMethod *self, CFCClass *invoker) { if (!self->method || CFCMethod_excluded_from_host(self->method)) { @@ -211,7 +154,7 @@ CFCGoMethod_func_def(CFCGoMethod *self, CFCClass *invoker) { cfunc = CFCMethod_full_method_sym(novel_method, invoker); } - char *cfargs = S_prep_cfargs(parcel, invoker, param_list); + char *cfargs = CFCGoFunc_meth_cfargs(parcel, invoker, param_list); char *maybe_retval; char *maybe_return; From 858fa345086d119f750544449ba78a8545603860 Mon Sep 17 00:00:00 2001 From: Marvin Humphrey Date: Mon, 13 Jul 2015 17:57:29 -0700 Subject: [PATCH 3/6] Generalize Go func first line conversion. Prepare to make the conversion function which generates the first part of a Go method binding work with constructors and inert functions in addition to methods. --- compiler/src/CFCGoFunc.c | 18 ++++++++++++------ compiler/src/CFCGoFunc.h | 4 ++-- compiler/src/CFCGoMethod.c | 4 ++-- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/compiler/src/CFCGoFunc.c b/compiler/src/CFCGoFunc.c index ad74bde4..3bde6b1b 100644 --- a/compiler/src/CFCGoFunc.c +++ b/compiler/src/CFCGoFunc.c @@ -52,15 +52,14 @@ CFCGoFunc_go_meth_name(const char *orig) { return go_name; } -char* -CFCGoFunc_func_start(CFCParcel *parcel, const char *name, CFCClass *invoker, - CFCParamList *param_list, CFCType *return_type, - int is_method) { +static char* +S_prep_start(CFCParcel *parcel, const char *name, CFCClass *invoker, + CFCParamList *param_list, CFCType *return_type, int targ) { CFCVariable **param_vars = CFCParamList_get_variables(param_list); char *invocant; char go_name[GO_NAME_BUF_SIZE]; - if (is_method) { + if (targ == IS_METHOD) { const char *struct_sym = CFCClass_get_struct_sym(invoker); CFCGoTypeMap_go_meth_receiever(struct_sym, param_list, go_name, GO_NAME_BUF_SIZE); @@ -71,7 +70,7 @@ CFCGoFunc_func_start(CFCParcel *parcel, const char *name, CFCClass *invoker, } char *params = CFCUtil_strdup(""); - int start = is_method ? 1 : 0; + int start = targ == IS_METHOD ? 1 : 0; for (int i = start; param_vars[i] != NULL; i++) { CFCVariable *var = param_vars[i]; CFCType *type = CFCVariable_get_type(var); @@ -107,6 +106,13 @@ CFCGoFunc_func_start(CFCParcel *parcel, const char *name, CFCClass *invoker, return content; } +char* +CFCGoFunc_meth_start(CFCParcel *parcel, const char *name, CFCClass *invoker, + CFCParamList *param_list, CFCType *return_type) { + return S_prep_start(parcel, name, invoker, param_list, return_type, + IS_METHOD); +} + static char* S_prep_cfargs(CFCParcel *parcel, CFCClass *invoker, CFCParamList *param_list, int targ) { diff --git a/compiler/src/CFCGoFunc.h b/compiler/src/CFCGoFunc.h index e11fa0db..a2b71eec 100644 --- a/compiler/src/CFCGoFunc.h +++ b/compiler/src/CFCGoFunc.h @@ -32,10 +32,10 @@ char* CFCGoFunc_go_meth_name(const char *orig); char* -CFCGoFunc_func_start(struct CFCParcel *parcel, const char *name, +CFCGoFunc_meth_start(struct CFCParcel *parcel, const char *name, struct CFCClass *invoker, struct CFCParamList *param_list, - struct CFCType *return_type, int is_method); + struct CFCType *return_type); /** Convert Go method arguments to comma-separated Clownfish-flavored C * arguments, to be passed to a Clownfish method. diff --git a/compiler/src/CFCGoMethod.c b/compiler/src/CFCGoMethod.c index f5b7cb4e..5e52d942 100644 --- a/compiler/src/CFCGoMethod.c +++ b/compiler/src/CFCGoMethod.c @@ -144,8 +144,8 @@ CFCGoMethod_func_def(CFCGoMethod *self, CFCClass *invoker) { CFCParamList *param_list = CFCMethod_get_param_list(novel_method); CFCType *ret_type = CFCMethod_get_return_type(novel_method); char *name = CFCGoFunc_go_meth_name(CFCMethod_get_name(novel_method)); - char *first_line = CFCGoFunc_func_start(parcel, name, invoker, - param_list, ret_type, true); + char *first_line = CFCGoFunc_meth_start(parcel, name, invoker, + param_list, ret_type); char *cfunc; if (CFCMethod_novel(self->method) && CFCMethod_final(self->method)) { cfunc = CFCUtil_strdup(CFCMethod_imp_func(self->method, invoker)); From 5c86308e5ed25c74d1c0b5568f3acbae336e759a Mon Sep 17 00:00:00 2001 From: Marvin Humphrey Date: Mon, 13 Jul 2015 19:03:41 -0700 Subject: [PATCH 4/6] Auto-generate Go bindings for constructors. --- compiler/src/CFCGoClass.c | 49 ++++++++++++++++++++++++++++++- compiler/src/CFCGoClass.h | 3 ++ compiler/src/CFCGoFunc.c | 12 ++++++++ compiler/src/CFCGoFunc.h | 12 ++++++++ runtime/go/clownfish/clownfish.go | 8 ----- 5 files changed, 75 insertions(+), 9 deletions(-) diff --git a/compiler/src/CFCGoClass.c b/compiler/src/CFCGoClass.c index 28d00d8c..be7cc9b4 100644 --- a/compiler/src/CFCGoClass.c +++ b/compiler/src/CFCGoClass.c @@ -17,6 +17,11 @@ #include #include +#ifndef true +#define true 1 +#define false 0 +#endif + #define CFC_NEED_BASE_STRUCT_DEF #include "CFCBase.h" #include "CFCGoClass.h" @@ -29,6 +34,7 @@ #include "CFCSymbol.h" #include "CFCVariable.h" #include "CFCType.h" +#include "CFCGoFunc.h" #include "CFCGoMethod.h" #include "CFCGoTypeMap.h" @@ -40,6 +46,7 @@ struct CFCGoClass { CFCGoMethod **method_bindings; size_t num_bound; int suppress_struct; + int suppress_ctor; }; static CFCGoClass **registry = NULL; @@ -259,9 +266,44 @@ CFCGoClass_boilerplate_funcs(CFCGoClass *self) { return content; } + char* CFCGoClass_gen_ctors(CFCGoClass *self) { - return CFCUtil_strdup(""); + CFCFunction *ctor_func = CFCClass_function(self->client, "new"); + if (self->suppress_ctor + || !ctor_func + || !CFCFunction_public(ctor_func) + || !CFCFunction_can_be_bound(ctor_func) + ) { + return CFCUtil_strdup(""); + } + CFCParcel *parcel = CFCClass_get_parcel(self->client); + CFCParamList *param_list = CFCFunction_get_param_list(ctor_func); + CFCType *ret_type = CFCFunction_get_return_type(ctor_func); + const char *struct_sym = CFCClass_get_struct_sym(self->client); + char *name = CFCUtil_sprintf("New%s", struct_sym); + char *cfunc = CFCFunction_full_func_sym(ctor_func, self->client); + char *cfargs = CFCGoFunc_ctor_cfargs(parcel, param_list); + char *first_line + = CFCGoFunc_ctor_start(parcel, name, param_list, ret_type); + char *ret_statement + = CFCGoFunc_return_statement(parcel, ret_type, "retvalCF"); + + char pattern[] = + "%s" + "\tretvalCF := C.%s(%s)\n" + "%s" + "}\n" + ; + char *content = CFCUtil_sprintf(pattern, first_line, cfunc, + cfargs, ret_statement); + + FREEMEM(ret_statement); + FREEMEM(cfargs); + FREEMEM(cfunc); + FREEMEM(first_line); + FREEMEM(name); + return content; } static void @@ -364,3 +406,8 @@ CFCGoClass_set_suppress_struct(CFCGoClass *self, int suppress_struct) { self->suppress_struct = !!suppress_struct; } +void +CFCGoClass_set_suppress_ctor(CFCGoClass *self, int suppress_ctor) { + self->suppress_ctor = !!suppress_ctor; +} + diff --git a/compiler/src/CFCGoClass.h b/compiler/src/CFCGoClass.h index bfe88cae..6a2db341 100644 --- a/compiler/src/CFCGoClass.h +++ b/compiler/src/CFCGoClass.h @@ -82,6 +82,9 @@ CFCGoClass_spec_method(CFCGoClass *self, const char *name, const char *sig); void CFCGoClass_set_suppress_struct(CFCGoClass *self, int suppress_struct); +void +CFCGoClass_set_suppress_ctor(CFCGoClass *self, int suppress_ctor); + #ifdef __cplusplus } #endif diff --git a/compiler/src/CFCGoFunc.c b/compiler/src/CFCGoFunc.c index 3bde6b1b..b9177b35 100644 --- a/compiler/src/CFCGoFunc.c +++ b/compiler/src/CFCGoFunc.c @@ -113,6 +113,13 @@ CFCGoFunc_meth_start(CFCParcel *parcel, const char *name, CFCClass *invoker, IS_METHOD); } +char* +CFCGoFunc_ctor_start(CFCParcel *parcel, const char *name, + CFCParamList *param_list, CFCType *return_type) { + return S_prep_start(parcel, name, NULL, param_list, return_type, + IS_CTOR); +} + static char* S_prep_cfargs(CFCParcel *parcel, CFCClass *invoker, CFCParamList *param_list, int targ) { @@ -179,6 +186,11 @@ CFCGoFunc_meth_cfargs(CFCParcel *parcel, CFCClass *invoker, return S_prep_cfargs(parcel, invoker, param_list, IS_METHOD); } +char* +CFCGoFunc_ctor_cfargs(CFCParcel *parcel, CFCParamList *param_list) { + return S_prep_cfargs(parcel, NULL, param_list, IS_CTOR); +} + char* CFCGoFunc_return_statement(CFCParcel *parcel, CFCType *return_type, const char *cf_retval) { diff --git a/compiler/src/CFCGoFunc.h b/compiler/src/CFCGoFunc.h index a2b71eec..b22276a3 100644 --- a/compiler/src/CFCGoFunc.h +++ b/compiler/src/CFCGoFunc.h @@ -37,6 +37,11 @@ CFCGoFunc_meth_start(struct CFCParcel *parcel, const char *name, struct CFCParamList *param_list, struct CFCType *return_type); +char* +CFCGoFunc_ctor_start(struct CFCParcel *parcel, const char *name, + struct CFCParamList *param_list, + struct CFCType *return_type); + /** Convert Go method arguments to comma-separated Clownfish-flavored C * arguments, to be passed to a Clownfish method. */ @@ -44,6 +49,13 @@ char* CFCGoFunc_meth_cfargs(struct CFCParcel *parcel, struct CFCClass *invoker, struct CFCParamList *param_list); +/** Convert Go method arguments to comma-separated Clownfish-flavored C + * arguments, to be passed to a Clownfish `new` function. + */ +char* +CFCGoFunc_ctor_cfargs(struct CFCParcel *parcel, + struct CFCParamList *param_list); + /** Generate a Go return statement which maps from a CGO Clownfish type to a * Go type. * diff --git a/runtime/go/clownfish/clownfish.go b/runtime/go/clownfish/clownfish.go index 83f38ab3..9a13cffb 100644 --- a/runtime/go/clownfish/clownfish.go +++ b/runtime/go/clownfish/clownfish.go @@ -106,14 +106,6 @@ func CFStringToGo(ptr unsafe.Pointer) string { return C.GoStringN(data, size) } -func NewErr(mess string) Err { - str := C.CString(mess) - len := C.size_t(len(mess)) - messC := C.cfish_Str_new_steal_utf8(str, len) - cfObj := C.cfish_Err_new(messC) - return WRAPErr(unsafe.Pointer(cfObj)) -} - func (e *ErrIMP) Error() string { mess := C.CFISH_Err_Get_Mess((*C.cfish_Err)(unsafe.Pointer(e.ref))) return CFStringToGo(unsafe.Pointer(mess)) From e340a510dbcd00ea44aecc97101d9da88fa19805 Mon Sep 17 00:00:00 2001 From: Marvin Humphrey Date: Tue, 14 Jul 2015 12:01:13 -0700 Subject: [PATCH 5/6] Make Err constructor public. --- runtime/core/Clownfish/Err.cfh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/core/Clownfish/Err.cfh b/runtime/core/Clownfish/Err.cfh index d8631196..f1992d61 100644 --- a/runtime/core/Clownfish/Err.cfh +++ b/runtime/core/Clownfish/Err.cfh @@ -43,10 +43,10 @@ public class Clownfish::Err inherits Clownfish::Obj { inert void init_class(); - inert incremented Err* + public inert incremented Err* new(decremented String *mess); - inert Err* + public inert Err* init(Err *self, decremented String *mess); public void From da43ffd0af8c862dfc4598f11bb9cd7de5e6b760 Mon Sep 17 00:00:00 2001 From: Marvin Humphrey Date: Tue, 14 Jul 2015 12:08:58 -0700 Subject: [PATCH 6/6] Ensure that converted args outlive call. Eliminate a race condition by ensuring that the refcount decrement of a converted argument does not happen until after the call into C completes. --- compiler/src/CFCGoFunc.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/compiler/src/CFCGoFunc.c b/compiler/src/CFCGoFunc.c index b9177b35..060e62be 100644 --- a/compiler/src/CFCGoFunc.c +++ b/compiler/src/CFCGoFunc.c @@ -70,6 +70,7 @@ S_prep_start(CFCParcel *parcel, const char *name, CFCClass *invoker, } char *params = CFCUtil_strdup(""); + char *converted = CFCUtil_strdup(""); int start = targ == IS_METHOD ? 1 : 0; for (int i = start; param_vars[i] != NULL; i++) { CFCVariable *var = param_vars[i]; @@ -81,6 +82,26 @@ S_prep_start(CFCParcel *parcel, const char *name, CFCClass *invoker, } params = CFCUtil_cat(params, go_name, " ", go_type_name, NULL); FREEMEM(go_type_name); + + // 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 *ret_type_str; @@ -96,11 +117,13 @@ S_prep_start(CFCParcel *parcel, const char *name, CFCClass *invoker, char pattern[] = "func %s%s(%s) %s {\n" + "%s" ; - char *content - = CFCUtil_sprintf(pattern, invocant, name, params, ret_type_str); + char *content = CFCUtil_sprintf(pattern, invocant, name, params, + ret_type_str, converted); FREEMEM(invocant); + FREEMEM(converted); FREEMEM(params); FREEMEM(ret_type_str); return content; @@ -151,16 +174,7 @@ S_prep_cfargs(CFCParcel *parcel, CFCClass *invoker, // Don't convert a clownfish.String invocant. && (targ != IS_METHOD || i != 0) ) { - const char *format; - if (CFCParcel_is_cfish(parcel)) { - format = "%s((*C.cfish_String)(unsafe.Pointer(NewString(%s).TOPTR())))"; - } - else { - format = "%s((*C.cfish_String)(unsafe.Pointer(clownfish.NewString(%s).TOPTR())))"; - } - char *temp = CFCUtil_sprintf(format, cfargs, go_name); - FREEMEM(cfargs); - cfargs = temp; + cfargs = CFCUtil_cat(cfargs, go_name, "CF", NULL); } else if (CFCType_is_object(type)) {