static void S_run_final_tests(CFCTest *test) { CFCParser *parser = CFCParser_new(); CFCParcel *neato_parcel = CFCTest_parse_parcel(test, parser, "parcel Neato;"); CFCClass *obj_class = CFCTest_parse_class(test, parser, "class Obj {}"); CFCClass *foo_class = CFCTest_parse_class(test, parser, "class Neato::Foo {}"); CFCType *return_type = CFCTest_parse_type(test, parser, "Obj*"); CFCParamList *param_list = CFCTest_parse_param_list(test, parser, "(Foo *self)"); CFCMethod *not_final = CFCMethod_new(neato_parcel, NULL, "Neato::Foo", "Foo", "Return_An_Obj", return_type, param_list, NULL, 0, 0); CFCMethod_resolve_types(not_final); CFCMethod *final = CFCMethod_finalize(not_final); OK(test, CFCMethod_compatible(not_final, final), "finalize clones properly"); OK(test, !CFCMethod_final(not_final), "not final by default"); OK(test, CFCMethod_final(final), "finalize"); CFCBase_decref((CFCBase*)parser); CFCBase_decref((CFCBase*)neato_parcel); CFCBase_decref((CFCBase*)obj_class); CFCBase_decref((CFCBase*)foo_class); CFCBase_decref((CFCBase*)return_type); CFCBase_decref((CFCBase*)param_list); CFCBase_decref((CFCBase*)not_final); CFCBase_decref((CFCBase*)final); CFCClass_clear_registry(); CFCParcel_reap_singletons(); }
static void S_bequeath_methods(CFCClass *self) { for (size_t child_num = 0; self->children[child_num] != NULL; child_num++) { CFCClass *child = self->children[child_num]; // Create array of methods, preserving exact order so vtables match up. size_t num_methods = 0; size_t max_methods = self->num_methods + child->num_methods; CFCMethod **methods = (CFCMethod**)MALLOCATE( (max_methods + 1) * sizeof(CFCMethod*)); // Gather methods which child inherits or overrides. for (size_t i = 0; i < self->num_methods; i++) { CFCMethod *method = self->methods[i]; const char *macro_sym = CFCMethod_get_macro_sym(method); CFCMethod *child_method = CFCClass_method(child, macro_sym); if (child_method) { CFCMethod_override(child_method, method); methods[num_methods++] = child_method; } else { methods[num_methods++] = method; } } // Append novel child methods to array. Child methods which were just // marked via CFCMethod_override() a moment ago are skipped. for (size_t i = 0; i < child->num_methods; i++) { CFCMethod *method = child->methods[i]; if (CFCMethod_novel(method)) { methods[num_methods++] = method; } } methods[num_methods] = NULL; // Manage refcounts and assign new array. Transform to final methods // if child class is a final class. if (child->is_final) { for (size_t i = 0; i < num_methods; i++) { if (CFCMethod_final(methods[i])) { CFCBase_incref((CFCBase*)methods[i]); } else { methods[i] = CFCMethod_finalize(methods[i]); } } } else { for (size_t i = 0; i < num_methods; i++) { CFCBase_incref((CFCBase*)methods[i]); } } for (size_t i = 0; i < child->num_methods; i++) { CFCBase_decref((CFCBase*)child->methods[i]); } FREEMEM(child->methods); child->methods = methods; child->num_methods = num_methods; // Pass it all down to the next generation. S_bequeath_methods(child); child->tree_grown = true; } }