From 6a8087c889bfb24db6dbc4aa306cf6d34b4d0423 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Wed, 27 May 2015 17:23:59 +0200 Subject: [PATCH 1/3] Make Obj_Get_Class inert --- runtime/core/Clownfish/Obj.c | 2 +- runtime/core/Clownfish/Obj.cfh | 4 ++-- runtime/core/Clownfish/Test/TestObj.c | 4 ++-- runtime/go/build.go | 1 + runtime/go/clownfish/clownfish.go | 6 ++++++ runtime/perl/buildlib/Clownfish/Build/Binding.pm | 8 ++++++++ runtime/perl/t/binding/019-obj.t | 10 +++++++++- 7 files changed, 29 insertions(+), 6 deletions(-) diff --git a/runtime/core/Clownfish/Obj.c b/runtime/core/Clownfish/Obj.c index 6e990779..d10d7d88 100644 --- a/runtime/core/Clownfish/Obj.c +++ b/runtime/core/Clownfish/Obj.c @@ -78,7 +78,7 @@ Obj_To_String_IMP(Obj *self) { } Class* -Obj_Get_Class_IMP(Obj *self) { +Obj_get_class(Obj *self) { return self->klass; } diff --git a/runtime/core/Clownfish/Obj.cfh b/runtime/core/Clownfish/Obj.cfh index d4d20adb..b9d9fd45 100644 --- a/runtime/core/Clownfish/Obj.cfh +++ b/runtime/core/Clownfish/Obj.cfh @@ -65,8 +65,8 @@ public abstract class Clownfish::Obj { /** Return the object's Class. */ - public Class* - Get_Class(Obj *self); + public inert Class* + get_class(Obj *self); /** Return the name of the class that the object belongs to. */ diff --git a/runtime/core/Clownfish/Test/TestObj.c b/runtime/core/Clownfish/Test/TestObj.c index d7639888..5067edd4 100644 --- a/runtime/core/Clownfish/Test/TestObj.c +++ b/runtime/core/Clownfish/Test/TestObj.c @@ -88,12 +88,12 @@ test_Equals(TestBatchRunner *runner) { static void test_Is_A(TestBatchRunner *runner) { String *string = Str_new_from_trusted_utf8("", 0); - Class *str_class = Str_Get_Class(string); + Class *str_class = Obj_get_class((Obj*)string); String *class_name = Str_Get_Class_Name(string); TEST_TRUE(runner, Str_Is_A(string, STRING), "String Is_A String."); TEST_TRUE(runner, Str_Is_A(string, OBJ), "String Is_A Obj."); - TEST_TRUE(runner, str_class == STRING, "Get_Class"); + TEST_TRUE(runner, str_class == STRING, "get_class"); TEST_TRUE(runner, Str_Equals(Class_Get_Name(STRING), (Obj*)class_name), "Get_Class_Name"); diff --git a/runtime/go/build.go b/runtime/go/build.go index 4a182c77..da7330dc 100644 --- a/runtime/go/build.go +++ b/runtime/go/build.go @@ -137,6 +137,7 @@ func runCFC() { func specMethods(parcel *cfc.Parcel) { objBinding := cfc.NewGoClass(parcel, "Clownfish::Obj") objBinding.SpecMethod("", "TOPTR() uintptr") + objBinding.SpecMethod("", "GetClass() Class") objBinding.Register() errBinding := cfc.NewGoClass(parcel, "Clownfish::Err") diff --git a/runtime/go/clownfish/clownfish.go b/runtime/go/clownfish/clownfish.go index 143c7c6b..0a47ab03 100644 --- a/runtime/go/clownfish/clownfish.go +++ b/runtime/go/clownfish/clownfish.go @@ -92,6 +92,12 @@ func (o *ObjIMP) TOPTR() uintptr { return o.ref } +func (o *ObjIMP) GetClass() Class { + cfObj := (*C.cfish_Obj)(unsafe.Pointer(o.ref)) + class := C.cfish_Obj_get_class(cfObj) + return WRAPClass(unsafe.Pointer(class)) +} + func CFStringToGo(ptr unsafe.Pointer) string { cfString := (*C.cfish_String)(ptr) if cfString == nil { diff --git a/runtime/perl/buildlib/Clownfish/Build/Binding.pm b/runtime/perl/buildlib/Clownfish/Build/Binding.pm index 07ad5bde..14805bda 100644 --- a/runtime/perl/buildlib/Clownfish/Build/Binding.pm +++ b/runtime/perl/buildlib/Clownfish/Build/Binding.pm @@ -486,6 +486,14 @@ END_DESCRIPTION my $xs_code = <<'END_XS_CODE'; MODULE = Clownfish PACKAGE = Clownfish::Obj +SV* +get_class(self) + cfish_Obj *self +CODE: + cfish_Class *klass = cfish_Obj_get_class(self); + RETVAL = (SV*)CFISH_Class_To_Host(klass); +OUTPUT: RETVAL + bool is_a(self, class_name) cfish_Obj *self; diff --git a/runtime/perl/t/binding/019-obj.t b/runtime/perl/t/binding/019-obj.t index 5ac44e8d..93ad0e87 100644 --- a/runtime/perl/t/binding/019-obj.t +++ b/runtime/perl/t/binding/019-obj.t @@ -16,7 +16,7 @@ use strict; use warnings; -use Test::More tests => 21; +use Test::More tests => 24; package TestObj; use base qw( Clownfish::Obj ); @@ -85,6 +85,14 @@ eval { thaw($frozen) }; like( $@, qr/implement/, "thawing an Obj throws an exception rather than segfaults" ); +my $obj_class = $object->get_class; +isa_ok( $obj_class, "Clownfish::Class", + "get_class returns a Clownfish::Class" ); +my $testobj_class = Clownfish::Class->fetch_class('TestObj'); +isa_ok( $testobj_class, "Clownfish::Class", + "fetch_class returns a Clownfish::Class" ); +is( $$obj_class, $$testobj_class, "get_class returns correct class" ); + ok( $object->is_a("Clownfish::Obj"), "custom is_a correct" ); ok( !$object->is_a("Clownfish::Object"), "custom is_a too long" ); ok( !$object->is_a("Clownfish"), "custom is_a substring" ); From 2bec8bc4fa14f587ddc5b5e1ed52f6ff7ccd3d4b Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Wed, 27 May 2015 17:47:31 +0200 Subject: [PATCH 2/3] Make Obj_Get_Class_Name inert --- compiler/src/CFCPerl.c | 2 +- runtime/core/Clownfish/CharBuf.c | 2 +- runtime/core/Clownfish/Err.c | 6 +++--- runtime/core/Clownfish/Err.cfh | 2 +- runtime/core/Clownfish/Obj.c | 6 +++--- runtime/core/Clownfish/Obj.cfh | 4 ++-- runtime/core/Clownfish/Test/TestObj.c | 4 ++-- runtime/core/Clownfish/TestHarness/TestFormatter.c | 2 +- runtime/core/Clownfish/TestHarness/TestSuite.c | 2 +- runtime/go/build.go | 1 + runtime/go/clownfish/clownfish.go | 6 ++++++ runtime/perl/buildlib/Clownfish/Build/Binding.pm | 8 ++++++++ 12 files changed, 30 insertions(+), 15 deletions(-) diff --git a/compiler/src/CFCPerl.c b/compiler/src/CFCPerl.c index 7916a5b1..ecfb35e5 100644 --- a/compiler/src/CFCPerl.c +++ b/compiler/src/CFCPerl.c @@ -610,7 +610,7 @@ S_write_callbacks_c(CFCPerl *self) { " LEAVE;\n" " if (!nullable && !retval) {\n" " CFISH_THROW(CFISH_ERR, \"%%o#%%s cannot return NULL\",\n" - " CFISH_Obj_Get_Class_Name((cfish_Obj*)vself),\n" + " cfish_Obj_get_class_name((cfish_Obj*)vself),\n" " meth_name);\n" " }\n" " return retval;\n" diff --git a/runtime/core/Clownfish/CharBuf.c b/runtime/core/Clownfish/CharBuf.c index b0ceb8bb..089390f1 100644 --- a/runtime/core/Clownfish/CharBuf.c +++ b/runtime/core/Clownfish/CharBuf.c @@ -352,7 +352,7 @@ CB_Mimic_IMP(CharBuf *self, Obj *other) { size = twin->size; } else { - THROW(ERR, "CharBuf can't mimic %o", Obj_Get_Class_Name(other)); + THROW(ERR, "CharBuf can't mimic %o", Obj_get_class_name(other)); return; // unreachable } SI_mimic_utf8(self, ptr, size); diff --git a/runtime/core/Clownfish/Err.c b/runtime/core/Clownfish/Err.c index 68c23654..dad6ae90 100644 --- a/runtime/core/Clownfish/Err.c +++ b/runtime/core/Clownfish/Err.c @@ -212,7 +212,7 @@ Err_downcast(Obj *obj, Class *klass, const char *file, int line, const char *func) { if (obj && !SI_obj_is_a(obj, klass)) { Err_throw_at(ERR, file, line, func, "Can't downcast from %o to %o", - Obj_Get_Class_Name(obj), Class_Get_Name(klass)); + Obj_get_class_name(obj), Class_Get_Name(klass)); } return obj; } @@ -226,14 +226,14 @@ Err_certify(Obj *obj, Class *klass, const char *file, int line, } else if (!SI_obj_is_a(obj, klass)) { Err_throw_at(ERR, file, line, func, "Can't downcast from %o to %o", - Obj_Get_Class_Name(obj), Class_Get_Name(klass)); + Obj_get_class_name(obj), Class_Get_Name(klass)); } return obj; } void Err_abstract_method_call(Obj *obj, Class *klass, const char *method_name) { - String *class_name = obj ? Obj_Get_Class_Name(obj) : Class_Get_Name(klass); + String *class_name = obj ? Obj_get_class_name(obj) : Class_Get_Name(klass); THROW(ERR, "Abstract method '%s' not defined by %o", method_name, class_name); } diff --git a/runtime/core/Clownfish/Err.cfh b/runtime/core/Clownfish/Err.cfh index db568496..d8631196 100644 --- a/runtime/core/Clownfish/Err.cfh +++ b/runtime/core/Clownfish/Err.cfh @@ -237,7 +237,7 @@ cfish_Err_abstract_class_check(cfish_Obj *obj, cfish_Class *klass) { cfish_Class *const my_class = (cfish_Class*)((cfish_Dummy*)obj)->klass; if (my_class == klass) { cfish_String *mess = CFISH_MAKE_MESS("%o is an abstract class", - CFISH_Obj_Get_Class_Name(obj)); + cfish_Obj_get_class_name(obj)); CFISH_DECREF_NN(obj); cfish_Err_throw_mess(CFISH_ERR, mess); } diff --git a/runtime/core/Clownfish/Obj.c b/runtime/core/Clownfish/Obj.c index d10d7d88..a1196f86 100644 --- a/runtime/core/Clownfish/Obj.c +++ b/runtime/core/Clownfish/Obj.c @@ -64,13 +64,13 @@ Obj_Equals_IMP(Obj *self, Obj *other) { String* Obj_To_String_IMP(Obj *self) { #if (CHY_SIZEOF_PTR == 4) - return Str_newf("%o@0x%x32", Obj_Get_Class_Name(self), self); + return Str_newf("%o@0x%x32", Obj_get_class_name(self), self); #elif (CHY_SIZEOF_PTR == 8) int64_t iaddress = CHY_PTR_TO_I64(self); uint64_t address = (uint64_t)iaddress; uint32_t address_hi = address >> 32; uint32_t address_lo = address & 0xFFFFFFFF; - return Str_newf("%o@0x%x32%x32", Obj_Get_Class_Name(self), address_hi, + return Str_newf("%o@0x%x32%x32", Obj_get_class_name(self), address_hi, address_lo); #else #error "Unexpected pointer size." @@ -83,7 +83,7 @@ Obj_get_class(Obj *self) { } String* -Obj_Get_Class_Name_IMP(Obj *self) { +Obj_get_class_name(Obj *self) { return Class_Get_Name(self->klass); } diff --git a/runtime/core/Clownfish/Obj.cfh b/runtime/core/Clownfish/Obj.cfh index b9d9fd45..7f4074b6 100644 --- a/runtime/core/Clownfish/Obj.cfh +++ b/runtime/core/Clownfish/Obj.cfh @@ -70,8 +70,8 @@ public abstract class Clownfish::Obj { /** Return the name of the class that the object belongs to. */ - public String* - Get_Class_Name(Obj *self); + public inert String* + get_class_name(Obj *self); /** Indicate whether the object is a descendent of `ancestor`. */ diff --git a/runtime/core/Clownfish/Test/TestObj.c b/runtime/core/Clownfish/Test/TestObj.c index 5067edd4..edf98f81 100644 --- a/runtime/core/Clownfish/Test/TestObj.c +++ b/runtime/core/Clownfish/Test/TestObj.c @@ -89,13 +89,13 @@ static void test_Is_A(TestBatchRunner *runner) { String *string = Str_new_from_trusted_utf8("", 0); Class *str_class = Obj_get_class((Obj*)string); - String *class_name = Str_Get_Class_Name(string); + String *class_name = Obj_get_class_name((Obj*)string); TEST_TRUE(runner, Str_Is_A(string, STRING), "String Is_A String."); TEST_TRUE(runner, Str_Is_A(string, OBJ), "String Is_A Obj."); TEST_TRUE(runner, str_class == STRING, "get_class"); TEST_TRUE(runner, Str_Equals(Class_Get_Name(STRING), (Obj*)class_name), - "Get_Class_Name"); + "get_class_name"); DECREF(string); } diff --git a/runtime/core/Clownfish/TestHarness/TestFormatter.c b/runtime/core/Clownfish/TestHarness/TestFormatter.c index 797ae84a..0d7288a5 100644 --- a/runtime/core/Clownfish/TestHarness/TestFormatter.c +++ b/runtime/core/Clownfish/TestHarness/TestFormatter.c @@ -76,7 +76,7 @@ TestFormatterCF_Batch_Prologue_IMP(TestFormatterCF *self, TestBatch *batch, uint32_t num_planned) { UNUSED_VAR(self); UNUSED_VAR(num_planned); - String *class_name = TestBatch_Get_Class_Name(batch); + String *class_name = Obj_get_class_name((Obj*)batch); char *utf8 = Str_To_Utf8(class_name); printf("Running %s...\n", utf8); FREEMEM(utf8); diff --git a/runtime/core/Clownfish/TestHarness/TestSuite.c b/runtime/core/Clownfish/TestHarness/TestSuite.c index 856525b8..3d84424c 100644 --- a/runtime/core/Clownfish/TestHarness/TestSuite.c +++ b/runtime/core/Clownfish/TestHarness/TestSuite.c @@ -67,7 +67,7 @@ TestSuite_Run_Batch_IMP(TestSuite *self, String *class_name, for (uint32_t i = 0; i < size; ++i) { TestBatch *batch = (TestBatch*)Vec_Fetch(self->batches, i); - if (Str_Equals(TestBatch_Get_Class_Name(batch), (Obj*)class_name)) { + if (Str_Equals(Obj_get_class_name((Obj*)batch), (Obj*)class_name)) { TestBatchRunner *runner = TestBatchRunner_new(formatter); bool result = TestBatchRunner_Run_Batch(runner, batch); DECREF(runner); diff --git a/runtime/go/build.go b/runtime/go/build.go index da7330dc..8a38e119 100644 --- a/runtime/go/build.go +++ b/runtime/go/build.go @@ -138,6 +138,7 @@ func specMethods(parcel *cfc.Parcel) { objBinding := cfc.NewGoClass(parcel, "Clownfish::Obj") objBinding.SpecMethod("", "TOPTR() uintptr") objBinding.SpecMethod("", "GetClass() Class") + objBinding.SpecMethod("", "GetClassName() string") objBinding.Register() errBinding := cfc.NewGoClass(parcel, "Clownfish::Err") diff --git a/runtime/go/clownfish/clownfish.go b/runtime/go/clownfish/clownfish.go index 0a47ab03..6de109ee 100644 --- a/runtime/go/clownfish/clownfish.go +++ b/runtime/go/clownfish/clownfish.go @@ -98,6 +98,12 @@ func (o *ObjIMP) GetClass() Class { return WRAPClass(unsafe.Pointer(class)) } +func (o *ObjIMP) GetClassName() string { + cfObj := (*C.cfish_Obj)(unsafe.Pointer(o.ref)) + className := C.cfish_Obj_get_class_name(cfObj) + return CFStringToGo(unsafe.Pointer(className)) +} + func CFStringToGo(ptr unsafe.Pointer) string { cfString := (*C.cfish_String)(ptr) if cfString == nil { diff --git a/runtime/perl/buildlib/Clownfish/Build/Binding.pm b/runtime/perl/buildlib/Clownfish/Build/Binding.pm index 14805bda..aa9ca762 100644 --- a/runtime/perl/buildlib/Clownfish/Build/Binding.pm +++ b/runtime/perl/buildlib/Clownfish/Build/Binding.pm @@ -494,6 +494,14 @@ CODE: RETVAL = (SV*)CFISH_Class_To_Host(klass); OUTPUT: RETVAL +SV* +get_class_name(self) + cfish_Obj *self +CODE: + cfish_String *class_name = cfish_Obj_get_class_name(self); + RETVAL = cfish_XSBind_str_to_sv(aTHX_ class_name); +OUTPUT: RETVAL + bool is_a(self, class_name) cfish_Obj *self; From fb12719d11db946293900a688ac3547e6ab75f17 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Wed, 27 May 2015 18:34:31 +0200 Subject: [PATCH 3/3] Make Obj_Is_A inert --- runtime/core/Clownfish/Blob.c | 2 +- runtime/core/Clownfish/ByteBuf.c | 2 +- runtime/core/Clownfish/CharBuf.c | 6 +++--- runtime/core/Clownfish/Hash.c | 2 +- runtime/core/Clownfish/Num.c | 8 ++++---- runtime/core/Clownfish/Obj.c | 2 +- runtime/core/Clownfish/Obj.cfh | 4 ++-- runtime/core/Clownfish/String.c | 4 ++-- runtime/core/Clownfish/Test/TestObj.c | 10 +++++----- runtime/core/Clownfish/Vector.c | 2 +- runtime/go/build.go | 1 + runtime/go/clownfish/clownfish.go | 9 ++++++++- .../perl/buildlib/Clownfish/Build/Binding.pm | 6 +----- runtime/perl/xs/XSBind.c | 18 +++++++++--------- runtime/ruby/ext/Bind.c | 4 ++-- 15 files changed, 42 insertions(+), 38 deletions(-) diff --git a/runtime/core/Clownfish/Blob.c b/runtime/core/Clownfish/Blob.c index d0133993..07663966 100644 --- a/runtime/core/Clownfish/Blob.c +++ b/runtime/core/Clownfish/Blob.c @@ -103,7 +103,7 @@ bool Blob_Equals_IMP(Blob *self, Obj *other) { Blob *const twin = (Blob*)other; if (twin == self) { return true; } - if (!Obj_Is_A(other, BLOB)) { return false; } + if (!Obj_is_a(other, BLOB)) { return false; } return SI_equals_bytes(self, twin->buf, twin->size); } diff --git a/runtime/core/Clownfish/ByteBuf.c b/runtime/core/Clownfish/ByteBuf.c index d7439f59..f32fa2c4 100644 --- a/runtime/core/Clownfish/ByteBuf.c +++ b/runtime/core/Clownfish/ByteBuf.c @@ -116,7 +116,7 @@ bool BB_Equals_IMP(ByteBuf *self, Obj *other) { ByteBuf *const twin = (ByteBuf*)other; if (twin == self) { return true; } - if (!Obj_Is_A(other, BYTEBUF)) { return false; } + if (!Obj_is_a(other, BYTEBUF)) { return false; } return SI_equals_bytes(self, twin->buf, twin->size); } diff --git a/runtime/core/Clownfish/CharBuf.c b/runtime/core/Clownfish/CharBuf.c index 089390f1..e5e3aa2c 100644 --- a/runtime/core/Clownfish/CharBuf.c +++ b/runtime/core/Clownfish/CharBuf.c @@ -182,7 +182,7 @@ CB_VCatF_IMP(CharBuf *self, const char *pattern, va_list args) { if (!obj) { CB_Cat_Trusted_Utf8(self, "[NULL]", 6); } - else if (Obj_Is_A(obj, STRING)) { + else if (Obj_is_a(obj, STRING)) { CB_Cat(self, (String*)obj); } else { @@ -341,12 +341,12 @@ void CB_Mimic_IMP(CharBuf *self, Obj *other) { const char *ptr; size_t size; - if (Obj_Is_A(other, CHARBUF)) { + if (Obj_is_a(other, CHARBUF)) { CharBuf *twin = (CharBuf*)other; ptr = twin->ptr; size = twin->size; } - else if (Obj_Is_A(other, STRING)) { + else if (Obj_is_a(other, STRING)) { String *twin = (String*)other; ptr = twin->ptr; size = twin->size; diff --git a/runtime/core/Clownfish/Hash.c b/runtime/core/Clownfish/Hash.c index 90e89594..54a4c262 100644 --- a/runtime/core/Clownfish/Hash.c +++ b/runtime/core/Clownfish/Hash.c @@ -262,7 +262,7 @@ Hash_Equals_IMP(Hash *self, Obj *other) { Hash *twin = (Hash*)other; if (twin == self) { return true; } - if (!Obj_Is_A(other, HASH)) { return false; } + if (!Obj_is_a(other, HASH)) { return false; } if (self->size != twin->size) { return false; } HashEntry *entry = (HashEntry*)self->entries; diff --git a/runtime/core/Clownfish/Num.c b/runtime/core/Clownfish/Num.c index aeb94291..d13c2426 100644 --- a/runtime/core/Clownfish/Num.c +++ b/runtime/core/Clownfish/Num.c @@ -41,7 +41,7 @@ bool Num_Equals_IMP(Num *self, Obj *other) { Num *twin = (Num*)other; if (twin == self) { return true; } - if (!Obj_Is_A(other, NUM)) { return false; } + if (!Obj_is_a(other, NUM)) { return false; } if (Num_To_F64(self) != Num_To_F64(twin)) { return false; } if (Num_To_I64(self) != Num_To_I64(twin)) { return false; } return true; @@ -84,7 +84,7 @@ IntNum_init(IntNum *self) { int32_t IntNum_Compare_To_IMP(IntNum *self, Obj *other) { - if (!Obj_Is_A(other, INTNUM)) { + if (!Obj_is_a(other, INTNUM)) { return -Obj_Compare_To(other, (Obj*)self); } int64_t self_value = IntNum_To_I64(self); @@ -283,8 +283,8 @@ bool Int64_Equals_IMP(Integer64 *self, Obj *other) { Num *twin = (Num*)other; if (twin == (Num*)self) { return true; } - if (!Obj_Is_A(other, NUM)) { return false; } - if (Num_Is_A(twin, FLOATNUM)) { + if (!Obj_is_a(other, NUM)) { return false; } + if (Obj_is_a(other, FLOATNUM)) { double floating_val = Num_To_F64(twin); int64_t int_val = (int64_t)floating_val; if ((double)int_val != floating_val) { return false; } diff --git a/runtime/core/Clownfish/Obj.c b/runtime/core/Clownfish/Obj.c index a1196f86..888ebf40 100644 --- a/runtime/core/Clownfish/Obj.c +++ b/runtime/core/Clownfish/Obj.c @@ -43,7 +43,7 @@ Obj_Destroy_IMP(Obj *self) { } bool -Obj_Is_A_IMP(Obj *self, Class *ancestor) { +Obj_is_a(Obj *self, Class *ancestor) { Class *klass = self ? self->klass : NULL; while (klass != NULL) { diff --git a/runtime/core/Clownfish/Obj.cfh b/runtime/core/Clownfish/Obj.cfh index 7f4074b6..e212ad5e 100644 --- a/runtime/core/Clownfish/Obj.cfh +++ b/runtime/core/Clownfish/Obj.cfh @@ -75,8 +75,8 @@ public abstract class Clownfish::Obj { /** Indicate whether the object is a descendent of `ancestor`. */ - public bool - Is_A(Obj *self, Class *ancestor); + public inert bool + is_a(Obj *self, Class *ancestor); /** Generic stringification: "ClassName@hex_mem_address". */ diff --git a/runtime/core/Clownfish/String.c b/runtime/core/Clownfish/String.c index 382ef6c0..a1ac8751 100644 --- a/runtime/core/Clownfish/String.c +++ b/runtime/core/Clownfish/String.c @@ -353,7 +353,7 @@ bool Str_Equals_IMP(String *self, Obj *other) { String *const twin = (String*)other; if (twin == self) { return true; } - if (!Obj_Is_A(other, STRING)) { return false; } + if (!Obj_is_a(other, STRING)) { return false; } return Str_Equals_Utf8_IMP(self, twin->ptr, twin->size); } @@ -602,7 +602,7 @@ bool StrIter_Equals_IMP(StringIterator *self, Obj *other) { StringIterator *const twin = (StringIterator*)other; if (twin == self) { return true; } - if (!Obj_Is_A(other, STRINGITERATOR)) { return false; } + if (!Obj_is_a(other, STRINGITERATOR)) { return false; } return self->string == twin->string && self->byte_offset == twin->byte_offset; } diff --git a/runtime/core/Clownfish/Test/TestObj.c b/runtime/core/Clownfish/Test/TestObj.c index edf98f81..10073374 100644 --- a/runtime/core/Clownfish/Test/TestObj.c +++ b/runtime/core/Clownfish/Test/TestObj.c @@ -86,13 +86,13 @@ test_Equals(TestBatchRunner *runner) { } static void -test_Is_A(TestBatchRunner *runner) { +test_is_a(TestBatchRunner *runner) { String *string = Str_new_from_trusted_utf8("", 0); Class *str_class = Obj_get_class((Obj*)string); String *class_name = Obj_get_class_name((Obj*)string); - TEST_TRUE(runner, Str_Is_A(string, STRING), "String Is_A String."); - TEST_TRUE(runner, Str_Is_A(string, OBJ), "String Is_A Obj."); + TEST_TRUE(runner, Obj_is_a((Obj*)string, STRING), "String is_a String."); + TEST_TRUE(runner, Obj_is_a((Obj*)string, OBJ), "String is_a Obj."); TEST_TRUE(runner, str_class == STRING, "get_class"); TEST_TRUE(runner, Str_Equals(Class_Get_Name(STRING), (Obj*)class_name), "get_class_name"); @@ -122,7 +122,7 @@ S_verify_abstract_error(TestBatchRunner *runner, Err_Attempt_t routine, sprintf(message, "%s() is abstract", name); Err *error = Err_trap(routine, context); TEST_TRUE(runner, error != NULL - && Err_Is_A(error, ERR) + && Obj_is_a((Obj*)error, ERR) && Str_Find_Utf8(Err_Get_Mess(error), "bstract", 7) != -1, message); DECREF(error); @@ -145,7 +145,7 @@ TestObj_Run_IMP(TestObj *self, TestBatchRunner *runner) { test_refcounts(runner); test_To_String(runner); test_Equals(runner); - test_Is_A(runner); + test_is_a(runner); test_abstract_routines(runner); } diff --git a/runtime/core/Clownfish/Vector.c b/runtime/core/Clownfish/Vector.c index 1fa775cf..3f72eea5 100644 --- a/runtime/core/Clownfish/Vector.c +++ b/runtime/core/Clownfish/Vector.c @@ -256,7 +256,7 @@ bool Vec_Equals_IMP(Vector *self, Obj *other) { Vector *twin = (Vector*)other; if (twin == self) { return true; } - if (!Obj_Is_A(other, VECTOR)) { return false; } + if (!Obj_is_a(other, VECTOR)) { return false; } if (twin->size != self->size) { return false; } diff --git a/runtime/go/build.go b/runtime/go/build.go index 8a38e119..655b2010 100644 --- a/runtime/go/build.go +++ b/runtime/go/build.go @@ -139,6 +139,7 @@ func specMethods(parcel *cfc.Parcel) { objBinding.SpecMethod("", "TOPTR() uintptr") objBinding.SpecMethod("", "GetClass() Class") objBinding.SpecMethod("", "GetClassName() string") + objBinding.SpecMethod("", "IsA() bool") objBinding.Register() errBinding := cfc.NewGoClass(parcel, "Clownfish::Err") diff --git a/runtime/go/clownfish/clownfish.go b/runtime/go/clownfish/clownfish.go index 6de109ee..2c446b94 100644 --- a/runtime/go/clownfish/clownfish.go +++ b/runtime/go/clownfish/clownfish.go @@ -104,12 +104,19 @@ func (o *ObjIMP) GetClassName() string { return CFStringToGo(unsafe.Pointer(className)) } +func (o *ObjIMP) IsA(class Class) bool { + cfObj := (*C.cfish_Obj)(unsafe.Pointer(o.ref)) + cfClass := (*C.cfish_Class)(unsafe.Pointer(class.ref)) + retvalCF := C.cfish_Obj_is_a(cfObj, cfClass) + return bool(retvalCF) +} + func CFStringToGo(ptr unsafe.Pointer) string { cfString := (*C.cfish_String)(ptr) if cfString == nil { return "" } - if !C.CFISH_Str_Is_A(cfString, C.CFISH_STRING) { + if !C.cfish_Obj_is_a((*C.cfish_Obj)(ptr), C.CFISH_STRING) { cfString := C.CFISH_Str_To_String(cfString) defer C.cfish_dec_refcount(unsafe.Pointer(cfString)) } diff --git a/runtime/perl/buildlib/Clownfish/Build/Binding.pm b/runtime/perl/buildlib/Clownfish/Build/Binding.pm index aa9ca762..8097d6bf 100644 --- a/runtime/perl/buildlib/Clownfish/Build/Binding.pm +++ b/runtime/perl/buildlib/Clownfish/Build/Binding.pm @@ -392,9 +392,6 @@ sub bind_obj { To_String Equals ); - my @hand_rolled = qw( - Is_A - ); my $pod_spec = Clownfish::CFC::Binding::Perl::Pod->new; my $synopsis = <<'END_SYNOPSIS'; @@ -509,7 +506,7 @@ is_a(self, class_name) CODE: { cfish_Class *target = cfish_Class_fetch_class(class_name); - RETVAL = CFISH_Obj_Is_A(self, target); + RETVAL = cfish_Obj_is_a(self, target); } OUTPUT: RETVAL END_XS_CODE @@ -522,7 +519,6 @@ END_XS_CODE alias => 'DESTROY', method => 'Destroy', ); - $binding->exclude_method($_) for @hand_rolled; $binding->append_xs($xs_code); $binding->set_pod_spec($pod_spec); diff --git a/runtime/perl/xs/XSBind.c b/runtime/perl/xs/XSBind.c index eca81457..ab2d8ae7 100644 --- a/runtime/perl/xs/XSBind.c +++ b/runtime/perl/xs/XSBind.c @@ -145,22 +145,22 @@ XSBind_cfish_to_perl(pTHX_ cfish_Obj *obj) { if (obj == NULL) { return newSV(0); } - else if (CFISH_Obj_Is_A(obj, CFISH_STRING)) { + else if (cfish_Obj_is_a(obj, CFISH_STRING)) { return XSBind_str_to_sv(aTHX_ (cfish_String*)obj); } - else if (CFISH_Obj_Is_A(obj, CFISH_BLOB)) { + else if (cfish_Obj_is_a(obj, CFISH_BLOB)) { return XSBind_blob_to_sv(aTHX_ (cfish_Blob*)obj); } - else if (CFISH_Obj_Is_A(obj, CFISH_BYTEBUF)) { + else if (cfish_Obj_is_a(obj, CFISH_BYTEBUF)) { return XSBind_bb_to_sv(aTHX_ (cfish_ByteBuf*)obj); } - else if (CFISH_Obj_Is_A(obj, CFISH_VECTOR)) { + else if (cfish_Obj_is_a(obj, CFISH_VECTOR)) { return S_cfish_array_to_perl_array(aTHX_ (cfish_Vector*)obj); } - else if (CFISH_Obj_Is_A(obj, CFISH_HASH)) { + else if (cfish_Obj_is_a(obj, CFISH_HASH)) { return S_cfish_hash_to_perl_hash(aTHX_ (cfish_Hash*)obj); } - else if (CFISH_Obj_Is_A(obj, CFISH_FLOATNUM)) { + else if (cfish_Obj_is_a(obj, CFISH_FLOATNUM)) { return newSVnv(CFISH_FloatNum_To_F64((cfish_FloatNum*)obj)); } else if (obj == (cfish_Obj*)CFISH_TRUE) { @@ -169,15 +169,15 @@ XSBind_cfish_to_perl(pTHX_ cfish_Obj *obj) { else if (obj == (cfish_Obj*)CFISH_FALSE) { return newSViv(0); } - else if (sizeof(IV) == 8 && CFISH_Obj_Is_A(obj, CFISH_INTNUM)) { + else if (sizeof(IV) == 8 && cfish_Obj_is_a(obj, CFISH_INTNUM)) { int64_t num = CFISH_IntNum_To_I64((cfish_IntNum*)obj); return newSViv((IV)num); } - else if (sizeof(IV) == 4 && CFISH_Obj_Is_A(obj, CFISH_INTEGER32)) { + else if (sizeof(IV) == 4 && cfish_Obj_is_a(obj, CFISH_INTEGER32)) { int32_t num = (int32_t)CFISH_Int32_To_I64((cfish_Integer32*)obj); return newSViv((IV)num); } - else if (sizeof(IV) == 4 && CFISH_Obj_Is_A(obj, CFISH_INTEGER64)) { + else if (sizeof(IV) == 4 && cfish_Obj_is_a(obj, CFISH_INTEGER64)) { int64_t num = CFISH_Int64_To_I64((cfish_Integer64*)obj); return newSVnv((double)num); // lossy } diff --git a/runtime/ruby/ext/Bind.c b/runtime/ruby/ext/Bind.c index fa8a130e..a12b1e10 100644 --- a/runtime/ruby/ext/Bind.c +++ b/runtime/ruby/ext/Bind.c @@ -20,10 +20,10 @@ VALUE Bind_cfish_to_ruby(cfish_Obj *obj) { - if (CFISH_Obj_Is_A(obj, CFISH_STRING)) { + if (cfish_Obj_is_a(obj, CFISH_STRING)) { return Bind_str_to_ruby((cfish_String*)obj); } - else if (CFISH_Obj_Is_A(obj, CFISH_VECTOR)) { + else if (cfish_Obj_is_a(obj, CFISH_VECTOR)) { return S_cfish_array_to_ruby_array((cfish_Vector*)obj); } }