static void S_run_primitive_tests(CFCTest *test) { CFCParcel *parcel = CFCParcel_new("Parcel", NULL, NULL, NULL); CFCType *type = CFCType_new(CFCTYPE_PRIMITIVE, parcel, "hump_t", 0); OK(test, CFCType_is_primitive(type), "is_primitive"); { CFCType *twin = CFCType_new(CFCTYPE_PRIMITIVE, parcel, "hump_t", 0); OK(test, CFCType_equals(type, twin), "equals"); CFCBase_decref((CFCBase*)twin); } { CFCType *other = CFCType_new(CFCTYPE_PRIMITIVE, parcel, "dump_t", 0); OK(test, !CFCType_equals(type, other), "equals spoiled by specifier"); CFCBase_decref((CFCBase*)other); } { CFCType *other = CFCType_new(CFCTYPE_PRIMITIVE|CFCTYPE_CONST, parcel, "hump_t", 0); OK(test, !CFCType_equals(type, other), "equals spoiled by const"); CFCBase_decref((CFCBase*)other); } CFCBase_decref((CFCBase*)type); CFCBase_decref((CFCBase*)parcel); }
int CFCType_equals(CFCType *self, CFCType *other) { if ((CFCType_const(self) ^ CFCType_const(other)) || (CFCType_nullable(self) ^ CFCType_nullable(other)) || (CFCType_is_void(self) ^ CFCType_is_void(other)) || (CFCType_is_object(self) ^ CFCType_is_object(other)) || (CFCType_is_primitive(self) ^ CFCType_is_primitive(other)) || (CFCType_is_integer(self) ^ CFCType_is_integer(other)) || (CFCType_is_floating(self) ^ CFCType_is_floating(other)) || (CFCType_is_va_list(self) ^ CFCType_is_va_list(other)) || (CFCType_is_arbitrary(self) ^ CFCType_is_arbitrary(other)) || (CFCType_is_composite(self) ^ CFCType_is_composite(other)) || (CFCType_incremented(self) ^ CFCType_incremented(other)) || (CFCType_decremented(self) ^ CFCType_decremented(other)) || !!self->child ^ !!other->child || !!self->array ^ !!other->array ) { return false; } if (self->indirection != other->indirection) { return false; } if (strcmp(self->specifier, other->specifier) != 0) { return false; } if (self->child) { if (!CFCType_equals(self->child, other->child)) { return false; } } if (self->array) { if (strcmp(self->array, other->array) != 0) { return false; } } return true; }
static void S_run_arbitrary_tests(CFCTest *test) { { CFCParcel *neato_parcel = CFCParcel_new("Neato", NULL, NULL, NULL); CFCParcel_register(neato_parcel); CFCType *foo = CFCType_new_arbitrary(neato_parcel, "foo_t"); STR_EQ(test, CFCType_get_specifier(foo), "foo_t", "get_specifier"); STR_EQ(test, CFCType_to_c(foo), "foo_t", "to_c"); CFCType *twin = CFCType_new_arbitrary(neato_parcel, "foo_t"); OK(test, CFCType_equals(foo, twin), "equals"); CFCType *compare_t = CFCType_new_arbitrary(neato_parcel, "Sort_compare_t"); OK(test, !CFCType_equals(foo, compare_t), "equals spoiled by different specifier"); CFCBase_decref((CFCBase*)neato_parcel); CFCBase_decref((CFCBase*)foo); CFCBase_decref((CFCBase*)compare_t); CFCBase_decref((CFCBase*)twin); } { CFCParser *parser = CFCParser_new(); static const char *specifiers[2] = { "foo_t", "Sort_compare_t" }; for (int i = 0; i < 2; ++i) { const char *specifier = specifiers[i]; CFCType *type = CFCTest_parse_type(test, parser, specifier); OK(test, CFCType_is_arbitrary(type), "arbitrary type %s", specifier); CFCBase_decref((CFCBase*)type); } CFCBase_decref((CFCBase*)parser); } CFCParcel_reap_singletons(); }
int CFCMethod_compatible(CFCMethod *self, CFCMethod *other) { if (!other) { return false; } if (strcmp(self->macro_sym, other->macro_sym)) { return false; } int my_public = CFCMethod_public(self); int other_public = CFCMethod_public(other); if (!!my_public != !!other_public) { return false; } // Check arguments and initial values. CFCParamList *my_param_list = self->function.param_list; CFCParamList *other_param_list = other->function.param_list; CFCVariable **my_args = CFCParamList_get_variables(my_param_list); CFCVariable **other_args = CFCParamList_get_variables(other_param_list); const char **my_vals = CFCParamList_get_initial_values(my_param_list); const char **other_vals = CFCParamList_get_initial_values(other_param_list); for (size_t i = 1; ; i++) { // start at 1, skipping self if (!!my_args[i] != !!other_args[i]) { return false; } if (!!my_vals[i] != !!other_vals[i]) { return false; } if (my_vals[i]) { if (strcmp(my_vals[i], other_vals[i])) { return false; } } if (my_args[i]) { if (!CFCVariable_equals(my_args[i], other_args[i])) { return false; } } else { break; } } // Check return types. CFCType *type = CFCMethod_get_return_type(self); CFCType *other_type = CFCMethod_get_return_type(other); if (CFCType_is_object(type)) { // Weak validation to allow covariant object return types. if (!CFCType_is_object(other_type)) { return false; } if (!CFCType_similar(type, other_type)) { return false; } } else { if (!CFCType_equals(type, other_type)) { return false; } } return true; }
static void S_run_composite_tests(CFCTest *test) { CFCParser *parser = CFCParser_new(); CFCParcel *neato_parcel = CFCParcel_new("Neato", NULL, NULL, NULL); CFCParser_set_parcel(parser, neato_parcel); { static const char *type_strings[14] = { "char*", "char**", "char***", "int32_t*", "Obj**", "int8_t[]", "int8_t[1]", "neato_method_t[]", "neato_method_t[1]", "multi_dimensional_t[1][10]", "char * * ", "const Obj**", "const void*", "int8_t[ 3 ]" }; for (int i = 0; i < 14; ++i) { const char *type_string = type_strings[i]; CFCType *type = CFCTest_parse_type(test, parser, type_string); OK(test, CFCType_is_composite(type), "composite type %s", type_string); CFCBase_decref((CFCBase*)type); } } { CFCType *foo = CFCType_new_object(0, neato_parcel, "Foo", 1); CFCType *const_foo = CFCType_new_object(CFCTYPE_CONST, neato_parcel, "Foo", 1); CFCType *composite = CFCType_new_composite(0, foo, 1, NULL); OK(test, CFCType_is_composite(composite), "is_composite"); STR_EQ(test, CFCType_get_specifier(composite), "Foo", "get_specifier delegates to child" ); CFCType *twin = CFCType_new_composite(0, foo, 1, NULL); OK(test, CFCType_equals(composite, twin), "equals"); CFCBase_decref((CFCBase*)twin); CFCType *const_composite = CFCType_new_composite(0, const_foo, 1, NULL); OK(test, !CFCType_equals(composite, const_composite), "equals spoiled by different child"); CFCBase_decref((CFCBase*)const_composite); CFCBase_decref((CFCBase*)composite); CFCBase_decref((CFCBase*)foo); CFCBase_decref((CFCBase*)const_foo); } { CFCType *foo_array = CFCTest_parse_type(test, parser, "foo_t[]"); CFCType_resolve(foo_array); STR_EQ(test, CFCType_get_array(foo_array), "[]", "get_array"); STR_EQ(test, CFCType_to_c(foo_array), "foo_t", "array subscripts not included by to_c"); CFCType *foo_array_array = CFCTest_parse_type(test, parser, "foo_t[][]"); OK(test, !CFCType_equals(foo_array, foo_array_array), "equals spoiled by different array postfixes"); CFCBase_decref((CFCBase*)foo_array); CFCBase_decref((CFCBase*)foo_array_array); } { CFCType *foo_star = CFCTest_parse_type(test, parser, "foo_t*"); CFCType *foo_star_star = CFCTest_parse_type(test, parser, "foo_t**"); OK(test, !CFCType_equals(foo_star, foo_star_star), "equals spoiled by different levels of indirection"); INT_EQ(test, CFCType_get_indirection(foo_star), 1, "foo_t* indirection"); INT_EQ(test, CFCType_get_indirection(foo_star_star), 2, "foo_t** indirection"); CFCBase_decref((CFCBase*)foo_star); CFCBase_decref((CFCBase*)foo_star_star); } CFCBase_decref((CFCBase*)neato_parcel); CFCBase_decref((CFCBase*)parser); }
static void S_run_object_tests(CFCTest *test) { static const char *modifiers[4] = { "const", "incremented", "decremented", "nullable" }; static int flags[4] = { CFCTYPE_CONST, CFCTYPE_INCREMENTED, CFCTYPE_DECREMENTED, CFCTYPE_NULLABLE }; static int (*accessors[4])(CFCType *type) = { CFCType_const, CFCType_incremented, CFCType_decremented, CFCType_nullable }; { CFCParser *parser = CFCParser_new(); CFCParcel *neato_parcel = CFCTest_parse_parcel(test, parser, "parcel Neato;"); static const char *specifiers[4] = { "Foo", "FooJr", "FooIII", "Foo4th" }; for (int i = 0; i < 4; ++i) { const char *specifier = specifiers[i]; char *class_code = CFCUtil_sprintf("class %s {}", specifier); CFCClass *klass = CFCTest_parse_class(test, parser, class_code); FREEMEM(class_code); static const char *prefixes[2] = { "", "neato_" }; char *expect = CFCUtil_sprintf("neato_%s", specifier); for (int j = 0; j < 2; ++j) { char *src = CFCUtil_sprintf("%s%s*", prefixes[j], specifier); CFCType *type = CFCTest_parse_type(test, parser, src); CFCType_resolve(type); STR_EQ(test, CFCType_get_specifier(type), expect, "object_type_specifier: %s", src); OK(test, CFCType_is_object(type), "%s is_object", src); INT_EQ(test, CFCType_get_indirection(type), 1, "%s indirection", src); FREEMEM(src); CFCBase_decref((CFCBase*)type); } FREEMEM(expect); for (int j = 0; j < 4; ++j) { char *src = CFCUtil_sprintf("%s %s*", modifiers[j], specifier); CFCType *type = CFCTest_parse_type(test, parser, src); OK(test, CFCType_is_object(type), "%s is_object", src); OK(test, accessors[j](type), "%s accessor", src); FREEMEM(src); CFCBase_decref((CFCBase*)type); } CFCBase_decref((CFCBase*)klass); CFCClass_clear_registry(); } CFCBase_decref((CFCBase*)neato_parcel); CFCBase_decref((CFCBase*)parser); } CFCParcel *neato_parcel = CFCParcel_new("Neato", NULL, NULL, NULL); CFCClass *foo_class = CFCClass_create(neato_parcel, NULL, "Foo", NULL, NULL, NULL, NULL, NULL, false, false, false); CFCType *foo = CFCType_new_object(0, neato_parcel, "Foo", 1); CFCType_resolve(foo); { CFCType *another_foo = CFCType_new_object(0, neato_parcel, "Foo", 1); CFCType_resolve(another_foo); OK(test, CFCType_equals(foo, another_foo), "equals"); CFCBase_decref((CFCBase*)another_foo); } { CFCClass *bar_class = CFCClass_create(neato_parcel, NULL, "Bar", NULL, NULL, NULL, NULL, NULL, false, false, false); CFCType *bar = CFCType_new_object(0, neato_parcel, "Bar", 1); CFCType_resolve(bar); OK(test, !CFCType_equals(foo, bar), "different specifier spoils equals"); CFCBase_decref((CFCBase*)bar); CFCBase_decref((CFCBase*)bar_class); } { CFCParcel *foreign_parcel = CFCParcel_new("Foreign", NULL, NULL, NULL); CFCClass *foreign_foo_class = CFCClass_create(foreign_parcel, NULL, "Foreign::Foo", NULL, NULL, NULL, NULL, NULL, false, false, false); CFCType *foreign_foo = CFCType_new_object(0, foreign_parcel, "Foo", 1); CFCType_resolve(foreign_foo); OK(test, !CFCType_equals(foo, foreign_foo), "different parcel spoils equals"); STR_EQ(test, CFCType_get_specifier(foreign_foo), "foreign_Foo", "prepend parcel prefix to specifier"); CFCBase_decref((CFCBase*)foreign_parcel); CFCBase_decref((CFCBase*)foreign_foo_class); CFCBase_decref((CFCBase*)foreign_foo); } { for (int i = 0; i < 4; ++i) { CFCType *modified_foo = CFCType_new_object(flags[i], neato_parcel, "Foo", 1); CFCType_resolve(modified_foo); OK(test, accessors[i](modified_foo), "%s", modifiers[i]); OK(test, !accessors[i](foo), "not %s", modifiers[i]); OK(test, !CFCType_equals(foo, modified_foo), "different %s spoils equals", modifiers[i]); OK(test, !CFCType_similar(foo, modified_foo), "different %s spoils similar", modifiers[i]); CFCBase_decref((CFCBase*)modified_foo); } } { 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"); CFCBase_decref((CFCBase*)string_type); } CFCBase_decref((CFCBase*)neato_parcel); CFCBase_decref((CFCBase*)foo_class); CFCBase_decref((CFCBase*)foo); CFCClass_clear_registry(); CFCParcel_reap_singletons(); }
int CFCVariable_equals(CFCVariable *self, CFCVariable *other) { if (!CFCType_equals(self->type, other->type)) { return false; } return CFCSymbol_equals((CFCSymbol*)self, (CFCSymbol*)other); }