From a121da47ff968f6acc45ab6cf491d01878174193 Mon Sep 17 00:00:00 2001 From: Marvin Humphrey Date: Mon, 3 Aug 2015 16:50:49 -0700 Subject: [PATCH 1/3] Convert nullable args safely. Use `GoToClownfish`, which can handle nil values safely, rather than the lower-level `GoToString` etc. which are not nil-safe. --- compiler/src/CFCGoFunc.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/compiler/src/CFCGoFunc.c b/compiler/src/CFCGoFunc.c index 26700345..bb6a2613 100644 --- a/compiler/src/CFCGoFunc.c +++ b/compiler/src/CFCGoFunc.c @@ -87,17 +87,29 @@ S_prep_start(CFCParcel *parcel, const char *name, CFCClass *invoker, // Convert certain types and defer their destruction until after the // Clownfish call returns. - 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 if (CFCType_cfish_hash(type)) { convertible = "Hash"; } - else { continue; } + const char *class_var; + if (CFCType_cfish_string(type)) { + class_var = "CFISH_STRING"; + } + else if (CFCType_cfish_vector(type)) { + class_var = "CFISH_VECTOR"; + } + else if (CFCType_cfish_blob(type)) { + class_var = "CFISH_BLOB"; + } + else if (CFCType_cfish_hash(type)) { + class_var = "CFISH_HASH"; + } + else { + continue; + } + const char *struct_name = CFCType_get_specifier(type); + const char *nullable = CFCType_nullable(type) ? "true" : "false"; char pattern[] = - "\t%sCF := (*C.cfish_%s)(%sGoTo%s(%s))\n"; - char *conversion = CFCUtil_sprintf(pattern, go_name, convertible, - clownfish_dot, convertible, - go_name); + "\t%sCF := (*C.%s)(%sGoToClownfish(%s, unsafe.Pointer(C.%s), %s))\n"; + char *conversion = CFCUtil_sprintf(pattern, go_name, struct_name, + clownfish_dot, go_name, + class_var, nullable); converted = CFCUtil_cat(converted, conversion, NULL); FREEMEM(conversion); if (CFCType_decremented(type)) { From 258e19a8a57ed453eb4298566eac2062c7560028 Mon Sep 17 00:00:00 2001 From: Marvin Humphrey Date: Mon, 3 Aug 2015 17:08:57 -0700 Subject: [PATCH 2/3] Change "is_string_type" to "cfish_string". Be consistent with "cfish_vector", "cfish_blob", etc. -- which we also need to test for. --- compiler/perl/lib/Clownfish/CFC.pm | 48 +++++++++++++++--------------- compiler/perl/lib/Clownfish/CFC.xs | 8 ++--- compiler/perl/t/100-type.t | 12 ++++---- compiler/perl/t/105-object_type.t | 4 +-- compiler/src/CFCGoFunc.c | 4 +-- compiler/src/CFCGoTypeMap.c | 2 +- compiler/src/CFCTestType.c | 6 ++-- compiler/src/CFCType.c | 5 ---- compiler/src/CFCType.h | 5 ---- 9 files changed, 42 insertions(+), 52 deletions(-) diff --git a/compiler/perl/lib/Clownfish/CFC.pm b/compiler/perl/lib/Clownfish/CFC.pm index 738acd36..6f033647 100644 --- a/compiler/perl/lib/Clownfish/CFC.pm +++ b/compiler/perl/lib/Clownfish/CFC.pm @@ -465,19 +465,19 @@ BEGIN { XSLoader::load( 'Clownfish::CFC', '0.4.0' ) } use Carp; our %new_PARAMS = ( - const => undef, - specifier => undef, - indirection => undef, - parcel => undef, - void => undef, - object => undef, - primitive => undef, - integer => undef, - floating => undef, - string_type => undef, - va_list => undef, - arbitrary => undef, - composite => undef, + const => undef, + specifier => undef, + indirection => undef, + parcel => undef, + void => undef, + object => undef, + primitive => undef, + integer => undef, + floating => undef, + cfish_string => undef, + va_list => undef, + arbitrary => undef, + composite => undef, ); sub new { @@ -487,17 +487,17 @@ BEGIN { XSLoader::load( 'Clownfish::CFC', '0.4.0' ) } verify_args( \%new_PARAMS, %args ) or confess $@; my $flags = 0; - $flags |= CONST if $args{const}; - $flags |= NULLABLE if $args{nullable}; - $flags |= VOID if $args{void}; - $flags |= OBJECT if $args{object}; - $flags |= PRIMITIVE if $args{primitive}; - $flags |= INTEGER if $args{integer}; - $flags |= FLOATING if $args{floating}; - $flags |= STRING_TYPE if $args{string_type}; - $flags |= VA_LIST if $args{va_list}; - $flags |= ARBITRARY if $args{arbitrary}; - $flags |= COMPOSITE if $args{composite}; + $flags |= CONST if $args{const}; + $flags |= NULLABLE if $args{nullable}; + $flags |= VOID if $args{void}; + $flags |= OBJECT if $args{object}; + $flags |= PRIMITIVE if $args{primitive}; + $flags |= INTEGER if $args{integer}; + $flags |= FLOATING if $args{floating}; + $flags |= CFISH_STRING if $args{cfish_string}; + $flags |= VA_LIST if $args{va_list}; + $flags |= ARBITRARY if $args{arbitrary}; + $flags |= COMPOSITE if $args{composite}; my $parcel = $args{parcel} diff --git a/compiler/perl/lib/Clownfish/CFC.xs b/compiler/perl/lib/Clownfish/CFC.xs index c779c5bc..27fa9421 100644 --- a/compiler/perl/lib/Clownfish/CFC.xs +++ b/compiler/perl/lib/Clownfish/CFC.xs @@ -1533,10 +1533,10 @@ CODE: OUTPUT: RETVAL unsigned -STRING_TYPE(...) +CFISH_STRING(...) CODE: CHY_UNUSED_VAR(items); - RETVAL = CFCTYPE_STRING_TYPE; + RETVAL = CFCTYPE_CFISH_STRING; OUTPUT: RETVAL unsigned @@ -1583,7 +1583,7 @@ ALIAS: is_primitive = 18 is_integer = 20 is_floating = 22 - is_string_type = 24 + cfish_string = 24 is_va_list = 26 is_arbitrary = 28 is_composite = 30 @@ -1640,7 +1640,7 @@ PPCODE: retval = newSViv(CFCType_is_floating(self)); break; case 24: - retval = newSViv(CFCType_is_string_type(self)); + retval = newSViv(CFCType_cfish_string(self)); break; case 26: retval = newSViv(CFCType_is_va_list(self)); diff --git a/compiler/perl/t/100-type.t b/compiler/perl/t/100-type.t index a881883a..cc04fe9c 100644 --- a/compiler/perl/t/100-type.t +++ b/compiler/perl/t/100-type.t @@ -33,10 +33,10 @@ is( $type->to_c, "mytype_t", "to_c()" ); ok( !$type->const, "const() is off by default" ); is( $type->get_specifier, "mytype_t", "get_specifier()" ); -ok( !$type->is_object, "is_object() false by default" ); -ok( !$type->is_integer, "is_integer() false by default" ); -ok( !$type->is_floating, "is_floating() false by default" ); -ok( !$type->is_void, "is_void() false by default" ); -ok( !$type->is_composite, "is_composite() false by default" ); -ok( !$type->is_string_type, "is_string_type() false by default" ); +ok( !$type->is_object, "is_object() false by default" ); +ok( !$type->is_integer, "is_integer() false by default" ); +ok( !$type->is_floating, "is_floating() false by default" ); +ok( !$type->is_void, "is_void() false by default" ); +ok( !$type->is_composite, "is_composite() false by default" ); +ok( !$type->cfish_string, "cfish_string() false by default" ); diff --git a/compiler/perl/t/105-object_type.t b/compiler/perl/t/105-object_type.t index 04d7722d..3e0e7e32 100644 --- a/compiler/perl/t/105-object_type.t +++ b/compiler/perl/t/105-object_type.t @@ -152,6 +152,6 @@ my $string_type = Clownfish::CFC::Model::Type->new_object( parcel => 'Neato', specifier => 'String', ); -ok( !$foo_type->is_string_type, "Not is_string_type" ); -ok( $string_type->is_string_type, "is_string_type" ); +ok( !$foo_type->cfish_string, "Not cfish_string" ); +ok( $string_type->cfish_string, "cfish_string" ); diff --git a/compiler/src/CFCGoFunc.c b/compiler/src/CFCGoFunc.c index bb6a2613..ea6c09e3 100644 --- a/compiler/src/CFCGoFunc.c +++ b/compiler/src/CFCGoFunc.c @@ -185,7 +185,7 @@ 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) + else if ((CFCType_cfish_string(type) || CFCType_cfish_blob(type) || CFCType_cfish_vector(type) || CFCType_cfish_hash(type)) @@ -245,7 +245,7 @@ CFCGoFunc_return_statement(CFCParcel *parcel, CFCType *return_type, if (CFCType_is_primitive(return_type)) { statement = CFCUtil_sprintf("\treturn %s(retvalCF)\n", ret_type_str); } - else if (CFCType_is_string_type(return_type)) { + else if (CFCType_cfish_string(return_type)) { char pattern[] = "%s\treturn %sCFStringToGo(unsafe.Pointer(retvalCF))\n"; statement = CFCUtil_sprintf(pattern, maybe_decref, clownfish_dot); diff --git a/compiler/src/CFCGoTypeMap.c b/compiler/src/CFCGoTypeMap.c index fbee678b..703c890a 100644 --- a/compiler/src/CFCGoTypeMap.c +++ b/compiler/src/CFCGoTypeMap.c @@ -93,7 +93,7 @@ static int num_go_keywords = sizeof(go_keywords) / sizeof(go_keywords[0]); char* CFCGoTypeMap_go_type_name(CFCType *type, CFCParcel *current_parcel) { - if (CFCType_is_string_type(type)) { + if (CFCType_cfish_string(type)) { return CFCUtil_strdup("string"); } else if (CFCType_cfish_blob(type)) { diff --git a/compiler/src/CFCTestType.c b/compiler/src/CFCTestType.c index c598f4c7..5e0d6dfe 100644 --- a/compiler/src/CFCTestType.c +++ b/compiler/src/CFCTestType.c @@ -99,7 +99,7 @@ S_run_basic_tests(CFCTest *test) { TEST_BOOL_ACCESSOR(type, is_primitive); TEST_BOOL_ACCESSOR(type, is_integer); TEST_BOOL_ACCESSOR(type, is_floating); - TEST_BOOL_ACCESSOR(type, is_string_type); + TEST_BOOL_ACCESSOR(type, cfish_string); TEST_BOOL_ACCESSOR(type, is_va_list); TEST_BOOL_ACCESSOR(type, is_arbitrary); TEST_BOOL_ACCESSOR(type, is_composite); @@ -389,8 +389,8 @@ S_run_object_tests(CFCTest *test) { { CFCType *string_type = CFCType_new_object(0, neato_parcel, "String", 1); - OK(test, CFCType_is_string_type(string_type), "%s", "is_string_type"); - OK(test, !CFCType_is_string_type(foo), "not %s", "not is_string_type"); + OK(test, CFCType_cfish_string(string_type), "%s", "cfish_string"); + OK(test, !CFCType_cfish_string(foo), "not %s", "not cfish_string"); CFCBase_decref((CFCBase*)string_type); } diff --git a/compiler/src/CFCType.c b/compiler/src/CFCType.c index 0c882cfd..87f1a85d 100644 --- a/compiler/src/CFCType.c +++ b/compiler/src/CFCType.c @@ -510,11 +510,6 @@ CFCType_cfish_obj(CFCType *self) { return !!(self->flags & CFCTYPE_CFISH_OBJ); } -int -CFCType_is_string_type(CFCType *self) { - return !!(self->flags & CFCTYPE_CFISH_STRING); -} - int CFCType_cfish_string(CFCType *self) { return !!(self->flags & CFCTYPE_CFISH_STRING); diff --git a/compiler/src/CFCType.h b/compiler/src/CFCType.h index 31800fc7..4fa50427 100644 --- a/compiler/src/CFCType.h +++ b/compiler/src/CFCType.h @@ -268,11 +268,6 @@ CFCType_is_floating(CFCType *self); 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 From 8c26a1d851753f2d692fff82ff681d303eacb3c6 Mon Sep 17 00:00:00 2001 From: Marvin Humphrey Date: Mon, 3 Aug 2015 17:19:23 -0700 Subject: [PATCH 3/3] Map clownfish.Obj to Go `interface{}`. --- compiler/src/CFCGoFunc.c | 13 +++++++++++-- compiler/src/CFCGoTypeMap.c | 5 ++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/compiler/src/CFCGoFunc.c b/compiler/src/CFCGoFunc.c index ea6c09e3..d8a33c80 100644 --- a/compiler/src/CFCGoFunc.c +++ b/compiler/src/CFCGoFunc.c @@ -88,7 +88,10 @@ S_prep_start(CFCParcel *parcel, const char *name, CFCClass *invoker, // Convert certain types and defer their destruction until after the // Clownfish call returns. const char *class_var; - if (CFCType_cfish_string(type)) { + if (CFCType_cfish_obj(type)) { + class_var = "CFISH_OBJ"; + } + else if (CFCType_cfish_string(type)) { class_var = "CFISH_STRING"; } else if (CFCType_cfish_vector(type)) { @@ -185,7 +188,8 @@ S_prep_cfargs(CFCParcel *parcel, CFCClass *invoker, cfargs = CFCUtil_cat(cfargs, "C.", CFCType_get_specifier(type), "(", go_name, ")", NULL); } - else if ((CFCType_cfish_string(type) + else if ((CFCType_cfish_obj(type) + || CFCType_cfish_string(type) || CFCType_cfish_blob(type) || CFCType_cfish_vector(type) || CFCType_cfish_hash(type)) @@ -245,6 +249,11 @@ CFCGoFunc_return_statement(CFCParcel *parcel, CFCType *return_type, if (CFCType_is_primitive(return_type)) { statement = CFCUtil_sprintf("\treturn %s(retvalCF)\n", ret_type_str); } + else if (CFCType_cfish_obj(return_type)) { + char pattern[] = + "%s\treturn %sToGo(unsafe.Pointer(retvalCF))\n"; + statement = CFCUtil_sprintf(pattern, maybe_decref, clownfish_dot); + } else if (CFCType_cfish_string(return_type)) { char pattern[] = "%s\treturn %sCFStringToGo(unsafe.Pointer(retvalCF))\n"; diff --git a/compiler/src/CFCGoTypeMap.c b/compiler/src/CFCGoTypeMap.c index 703c890a..f8757c60 100644 --- a/compiler/src/CFCGoTypeMap.c +++ b/compiler/src/CFCGoTypeMap.c @@ -93,7 +93,10 @@ static int num_go_keywords = sizeof(go_keywords) / sizeof(go_keywords[0]); char* CFCGoTypeMap_go_type_name(CFCType *type, CFCParcel *current_parcel) { - if (CFCType_cfish_string(type)) { + if (CFCType_cfish_obj(type)) { + return CFCUtil_strdup("interface{}"); + } + else if (CFCType_cfish_string(type)) { return CFCUtil_strdup("string"); } else if (CFCType_cfish_blob(type)) {