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; }
int CFCType_similar(CFCType *self, CFCType *other) { if (!CFCType_is_object(self)) { CFCUtil_die("Attempt to call 'similar' on a non-object type"); } if ((CFCType_const(self) ^ CFCType_const(other)) || (CFCType_nullable(self) ^ CFCType_nullable(other)) || (CFCType_incremented(self) ^ CFCType_incremented(other)) || (CFCType_decremented(self) ^ CFCType_decremented(other)) || (CFCType_is_object(self) ^ CFCType_is_object(other)) ) { return false; } return true; }
static void S_run_integer_tests(CFCTest *test) { { CFCType *type = CFCType_new_integer(CFCTYPE_CONST, "int32_t"); OK(test, CFCType_const(type), "const"); STR_EQ(test, CFCType_get_specifier(type), "int32_t", "get_specifier"); STR_EQ(test, CFCType_to_c(type), "const int32_t", "'const' in C representation"); CFCBase_decref((CFCBase*)type); } { CFCParser *parser = CFCParser_new(); static const char *specifiers[14] = { "bool", "char", "short", "int", "long", "size_t", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t" }; for (int i = 0; i < 14; ++i) { const char *specifier = specifiers[i]; CFCType *type; type = CFCTest_parse_type(test, parser, specifier); OK(test, CFCType_is_integer(type), "%s is_integer", specifier); CFCBase_decref((CFCBase*)type); char *const_specifier = CFCUtil_sprintf("const %s", specifier); type = CFCTest_parse_type(test, parser, const_specifier); OK(test, CFCType_is_integer(type), "%s is_integer", const_specifier); OK(test, CFCType_const(type), "%s is const", const_specifier); FREEMEM(const_specifier); CFCBase_decref((CFCBase*)type); } CFCBase_decref((CFCBase*)parser); } }
static void S_run_void_tests(CFCTest *test) { CFCParser *parser = CFCParser_new(); { CFCType *type = CFCType_new_void(false); STR_EQ(test, CFCType_get_specifier(type), "void", "get_specifier"); STR_EQ(test, CFCType_to_c(type), "void", "to_c"); OK(test, CFCType_is_void(type), "is_void"); CFCBase_decref((CFCBase*)type); } { CFCType *type = CFCType_new_void(true); STR_EQ(test, CFCType_to_c(type), "const void", "'const' in C representation"); CFCBase_decref((CFCBase*)type); } { CFCType *type = CFCTest_parse_type(test, parser, "void"); OK(test, CFCType_is_void(type), "void is_void"); CFCBase_decref((CFCBase*)type); } { CFCType *type = CFCTest_parse_type(test, parser, "const void"); OK(test, CFCType_is_void(type), "const void is_void"); OK(test, CFCType_const(type), "const void is const"); CFCBase_decref((CFCBase*)type); } CFCBase_decref((CFCBase*)parser); }
const char* CFCType_to_c(CFCType *self) { char *c_string = self->c_string; if (c_string) { return c_string; } if (CFCType_is_composite(self)) { // NOTE: Array postfixes are NOT included. const char *child_c_string = CFCType_to_c(self->child); size_t child_c_len = strlen(child_c_string); size_t amount = child_c_len + self->indirection; c_string = (char*)MALLOCATE(amount + 1); strcpy(c_string, child_c_string); for (int i = 0; i < self->indirection; i++) { strncat(c_string, "*", 1); } } else if (CFCType_is_object(self)) { if (CFCType_const(self)) { c_string = CFCUtil_sprintf("const %s*", self->specifier); } else { c_string = CFCUtil_sprintf("%s*", self->specifier); } } else { if (CFCType_const(self)) { c_string = CFCUtil_sprintf("const %s", self->specifier); } else { c_string = CFCUtil_strdup(self->specifier); } } self->c_string = c_string; return c_string; }
static void S_run_float_tests(CFCTest *test) { { CFCType *type = CFCType_new_float(CFCTYPE_CONST, "float"); OK(test, CFCType_const(type), "const"); STR_EQ(test, CFCType_get_specifier(type), "float", "get_specifier"); STR_EQ(test, CFCType_to_c(type), "const float", "'const' in C representation"); CFCBase_decref((CFCBase*)type); } { CFCParser *parser = CFCParser_new(); static const char *specifiers[2] = { "float", "double" }; for (int i = 0; i < 2; ++i) { const char *specifier = specifiers[i]; CFCType *type; type = CFCTest_parse_type(test, parser, specifier); OK(test, CFCType_is_floating(type), "%s is_floating", specifier); CFCBase_decref((CFCBase*)type); char *const_specifier = CFCUtil_sprintf("const %s", specifier); type = CFCTest_parse_type(test, parser, const_specifier); OK(test, CFCType_is_floating(type), "%s is_floating", const_specifier); OK(test, CFCType_const(type), "%s is const", const_specifier); FREEMEM(const_specifier); CFCBase_decref((CFCBase*)type); } CFCBase_decref((CFCBase*)parser); } }
static void S_run_tests(CFCTest *test) { CFCParser *parser = CFCParser_new(); OK(test, parser != NULL, "new"); { CFCParcel *fish = CFCTest_parse_parcel(test, parser, "parcel Fish;"); CFCParcel *registered = CFCParcel_new("Crustacean", "Crust", NULL, false); CFCParcel_register(registered); CFCParcel *parcel = CFCTest_parse_parcel(test, parser, "parcel Crustacean;"); OK(test, parcel == registered, "Fetch registered parcel"); OK(test, CFCParser_get_parcel(parser) == parcel, "parcel_definition sets internal var"); CFCBase_decref((CFCBase*)fish); CFCBase_decref((CFCBase*)registered); CFCBase_decref((CFCBase*)parcel); } { static const char *const specifiers[8] = { "foo", "_foo", "foo_yoo", "FOO", "Foo", "fOO", "f00", "foo_foo_foo" }; for (int i = 0; i < 8; ++i) { const char *specifier = specifiers[i]; char *src = CFCUtil_sprintf("int32_t %s;", specifier); CFCVariable *var = CFCTest_parse_variable(test, parser, src); STR_EQ(test, CFCVariable_micro_sym(var), specifier, "identifier/declarator: %s", specifier); FREEMEM(src); CFCBase_decref((CFCBase*)var); } } { static const char *const specifiers[6] = { "void", "float", "uint32_t", "int64_t", "uint8_t", "bool" }; for (int i = 0; i < 6; ++i) { const char *specifier = specifiers[i]; char *src = CFCUtil_sprintf("int32_t %s;", specifier); CFCBase *result = CFCParser_parse(parser, src); OK(test, result == NULL, "reserved word not parsed as identifier: %s", specifier); FREEMEM(src); CFCBase_decref(result); } } { static const char *const type_strings[7] = { "bool", "const char *", "Obj*", "i32_t", "char[]", "long[1]", "i64_t[30]" }; for (int i = 0; i < 7; ++i) { const char *type_string = type_strings[i]; CFCType *type = CFCTest_parse_type(test, parser, type_string); CFCBase_decref((CFCBase*)type); } } { static const char *const class_names[7] = { "ByteBuf", "Obj", "ANDMatcher", "Foo", "FooJr", "FooIII", "Foo4th" }; CFCClass *class_list[8]; for (int i = 0; i < 7; ++i) { char *class_code = CFCUtil_sprintf("class %s {}", class_names[i]); CFCClass *klass = CFCTest_parse_class(test, parser, class_code); class_list[i] = klass; FREEMEM(class_code); } class_list[7] = NULL; for (int i = 0; i < 7; ++i) { const char *class_name = class_names[i]; char *src = CFCUtil_sprintf("%s*", class_name); char *expected = CFCUtil_sprintf("crust_%s", class_name); CFCType *type = CFCTest_parse_type(test, parser, src); CFCType_resolve(type, class_list); STR_EQ(test, CFCType_get_specifier(type), expected, "object_type_specifier: %s", class_name); FREEMEM(src); FREEMEM(expected); CFCBase_decref((CFCBase*)type); } for (int i = 0; i < 7; ++i) { CFCBase_decref((CFCBase*)class_list[i]); } CFCClass_clear_registry(); } { CFCType *type = CFCTest_parse_type(test, parser, "const char"); OK(test, CFCType_const(type), "type_qualifier const"); CFCBase_decref((CFCBase*)type); } { static const char *const exposures[2] = { "public", "" }; static int (*const accessors[2])(CFCSymbol *sym) = { CFCSymbol_public, CFCSymbol_parcel }; for (int i = 0; i < 2; ++i) { const char *exposure = exposures[i]; char *src = CFCUtil_sprintf("%s inert int32_t foo;", exposure); CFCVariable *var = CFCTest_parse_variable(test, parser, src); OK(test, accessors[i]((CFCSymbol*)var), "exposure_specifier %s", exposure); FREEMEM(src); CFCBase_decref((CFCBase*)var); } } { static const char *const hex_constants[] = { "0x1", "0x0a", "0xFFFFFFFF", "-0xFC", NULL }; S_test_initial_value(test, parser, hex_constants, "int32_t", "hex_constant:"); } { static const char *const integer_constants[] = { "1", "-9999", "0", "10000", NULL }; S_test_initial_value(test, parser, integer_constants, "int32_t", "integer_constant:"); } { static const char *const float_constants[] = { "1.0", "-9999.999", "0.1", "0.0", NULL }; S_test_initial_value(test, parser, float_constants, "double", "float_constant:"); } { static const char *const string_literals[] = { "\"blah\"", "\"blah blah\"", "\"\\\"blah\\\" \\\"blah\\\"\"", NULL }; S_test_initial_value(test, parser, string_literals, "String*", "string_literal:"); } { static const char *const composites[5] = { "int[]", "i32_t **", "Foo **", "Foo ***", "const void *" }; for (int i = 0; i < 5; ++i) { const char *composite = composites[i]; CFCType *type = CFCTest_parse_type(test, parser, composite); OK(test, CFCType_is_composite(type), "composite_type: %s", composite); CFCBase_decref((CFCBase*)type); } } { static const char *const object_types[5] = { "Obj *", "incremented Foo*", "decremented String *" }; for (int i = 0; i < 3; ++i) { const char *object_type = object_types[i]; CFCType *type = CFCTest_parse_type(test, parser, object_type); OK(test, CFCType_is_object(type), "object_type: %s", object_type); CFCBase_decref((CFCBase*)type); } } { static const char *const param_list_strings[3] = { "()", "(int foo)", "(Obj *foo, Foo **foo_ptr)" }; for (int i = 0; i < 3; ++i) { const char *param_list_string = param_list_strings[i]; CFCParamList *param_list = CFCTest_parse_param_list(test, parser, param_list_string); INT_EQ(test, CFCParamList_num_vars(param_list), i, "param list num_vars: %d", i); CFCBase_decref((CFCBase*)param_list); } } { CFCParamList *param_list = CFCTest_parse_param_list(test, parser, "(int foo, ...)"); OK(test, CFCParamList_variadic(param_list), "variadic param list"); CFCBase_decref((CFCBase*)param_list); } { const char *param_list_string = "(int foo = 0xFF, char *bar =\"blah\")"; CFCParamList *param_list = CFCTest_parse_param_list(test, parser, param_list_string); const char **initial_values = CFCParamList_get_initial_values(param_list); STR_EQ(test, initial_values[0], "0xFF", "param list initial_values[0]"); STR_EQ(test, initial_values[1], "\"blah\"", "param list initial_values[1]"); OK(test, initial_values[2] == NULL, "param list initial_values[2]"); CFCBase_decref((CFCBase*)param_list); } { CFCParser_set_class_name(parser, "Stuff::Obj"); CFCParser_set_class_cnick(parser, "Obj"); const char *method_string = "public Foo* Spew_Foo(Obj *self, uint32_t *how_many);"; CFCMethod *method = CFCTest_parse_method(test, parser, method_string); CFCBase_decref((CFCBase*)method); const char *var_string = "public inert Hash *hash;"; CFCVariable *var = CFCTest_parse_variable(test, parser, var_string); CFCBase_decref((CFCBase*)var); } { static const char *const class_names[4] = { "Foo", "Foo::FooJr", "Foo::FooJr::FooIII", "Foo::FooJr::FooIII::Foo4th" }; for (int i = 0; i < 4; ++i) { const char *class_name = class_names[i]; char *class_string = CFCUtil_sprintf("class %s { }", class_name); CFCClass *klass = CFCTest_parse_class(test, parser, class_string); STR_EQ(test, CFCClass_get_class_name(klass), class_name, "class_name: %s", class_name); FREEMEM(class_string); CFCBase_decref((CFCBase*)klass); } } { static const char *const cnicks[2] = { "Food", "FF" }; for (int i = 0; i < 2; ++i) { const char *cnick = cnicks[i]; char *class_string = CFCUtil_sprintf("class Foodie%s cnick %s { }", cnick, cnick); CFCClass *klass = CFCTest_parse_class(test, parser, class_string); STR_EQ(test, CFCClass_get_cnick(klass), cnick, "cnick: %s", cnick); FREEMEM(class_string); CFCBase_decref((CFCBase*)klass); } } CFCBase_decref((CFCBase*)parser); CFCClass_clear_registry(); CFCParcel_reap_singletons(); }