static CFCClass* S_class_by_struct_sym_prereq(CFCParcel *self, const char *struct_sym, size_t prefix_len) { CFCClass *klass = S_class_by_struct_sym(self, struct_sym, prefix_len); if (klass && prefix_len != 0) { return klass; } for (size_t i = 0; self->prereqs[i]; ++i) { const char *prereq_name = CFCPrereq_get_name(self->prereqs[i]); CFCParcel *prereq_parcel = CFCParcel_fetch(prereq_name); CFCClass *candidate = S_class_by_struct_sym(prereq_parcel, struct_sym, prefix_len); if (candidate) { if (prefix_len != 0) { return candidate; } if (klass) { CFCUtil_warn("Type '%s' is ambiguous. Do you mean %s or %s?", struct_sym, CFCClass_full_struct_sym(klass), CFCClass_full_struct_sym(candidate)); return NULL; } klass = candidate; } } return klass; }
static CFCClass* S_fetch_class(CFCParcel *self, const char *class_name, int level) { // level == 0: Only search parcel. // level == 1: Search parcel and direct prereqs. // level == 2: Search parcel an indirect prereqs. for (size_t i = 0; self->classes[i]; ++i) { CFCClass *klass = self->classes[i]; if (strcmp(CFCClass_get_name(klass), class_name) == 0) { return klass; } } if (level == 0) { return NULL; } if (level == 1) { level = 0; } for (size_t i = 0; self->prereqs[i]; ++i) { const char *prereq_name = CFCPrereq_get_name(self->prereqs[i]); CFCParcel *prereq_parcel = CFCParcel_fetch(prereq_name); CFCClass *klass = S_fetch_class(prereq_parcel, class_name, level); if (klass) { return klass; } } return NULL; }
void CFCPython_write_bindings(CFCPython *self, const char *parcel_name, const char *dest) { CFCParcel *parcel = CFCParcel_fetch(parcel_name); if (parcel == NULL) { CFCUtil_die("Unknown parcel: %s", parcel_name); } S_write_hostdefs(self); S_write_module_file(self, parcel, dest); }
CFCParcel* CFCParcel_clownfish_parcel(void) { CFCParcel *parcel = CFCParcel_fetch("Lucy"); if (!parcel) { CFCVersion *version = CFCVersion_new("v0.3.0"); parcel = CFCParcel_new("Lucy", "Lucy", version); CFCParcel_register(parcel); CFCBase_decref((CFCBase*)version); CFCBase_decref((CFCBase*)parcel); } return parcel; }
void CFCParcel_register(CFCParcel *self) { CFCParcel *existing = CFCParcel_fetch(self->name); if (existing) { CFCUtil_die("Parcel '%s' already registered", self->name); } if (!num_registered) { // Init default parcel as first. registry = (CFCParcel**)CALLOCATE(3, sizeof(CFCParcel*)); CFCParcel *def = CFCParcel_default_parcel(); registry[0] = (CFCParcel*)CFCBase_incref((CFCBase*)def); num_registered++; } size_t size = (num_registered + 2) * sizeof(CFCParcel*); registry = (CFCParcel**)REALLOCATE(registry, size); registry[num_registered++] = (CFCParcel*)CFCBase_incref((CFCBase*)self); registry[num_registered] = NULL; }
static void S_parse_source_cfp_files(CFCHierarchy *self, const char *source_dir) { CFCFindFilesContext context; context.ext = ".cfp"; context.paths = (char**)CALLOCATE(1, sizeof(char*)); context.num_paths = 0; CFCUtil_walk(source_dir, S_find_files, &context); // Parse .cfp files and register the parcels they define. for (int i = 0; context.paths[i] != NULL; i++) { const char *path = context.paths[i]; char *path_part = S_extract_path_part(path, source_dir, ".cfp"); CFCFileSpec *file_spec = CFCFileSpec_new(source_dir, path_part, ".cfp", false); CFCParcel *parcel = CFCParcel_new_from_file(file_spec); const char *name = CFCParcel_get_name(parcel); CFCParcel *existing = CFCParcel_fetch(name); if (existing) { CFCUtil_die("Parcel '%s' defined twice in %s and %s", CFCParcel_get_name(parcel), CFCParcel_get_cfp_path(existing), path); } // Make sure to register prereq parcels first, so that prereq // parent classes precede subclasses. S_find_prereqs(self, parcel); CFCParcel_register(parcel); CFCBase_decref((CFCBase*)parcel); CFCBase_decref((CFCBase*)file_spec); FREEMEM(path_part); } CFCUtil_free_string_array(context.paths); }
static void S_run_include_tests(CFCTest *test) { { CFCHierarchy *hierarchy = CFCHierarchy_new(T_CFDEST); CFCHierarchy_add_source_dir(hierarchy, T_CFEXT); CFCHierarchy_add_include_dir(hierarchy, T_CFBASE); const char **include_dirs = CFCHierarchy_get_include_dirs(hierarchy); STR_EQ(test, include_dirs[0], T_CFBASE, "include_dirs[0]"); OK(test, include_dirs[1] == NULL, "include_dirs[1]"); CFCHierarchy_build(hierarchy); CFCClass **classes = CFCHierarchy_ordered_classes(hierarchy); CFCClass *rottweiler = NULL;; int num_classes; int num_source_classes = 0; for (num_classes = 0; classes[num_classes]; ++num_classes) { CFCClass *klass = classes[num_classes]; int expect_included = 1; const char *class_name = CFCClass_get_name(klass); if (strcmp(class_name, "Animal::Rottweiler") == 0) { rottweiler = klass; expect_included = 0; ++num_source_classes; } INT_EQ(test, CFCClass_included(klass), expect_included, "included"); } INT_EQ(test, num_classes, 5, "class count"); INT_EQ(test, num_source_classes, 1, "source class count"); STR_EQ(test, CFCClass_get_name(CFCClass_get_parent(rottweiler)), "Animal::Dog", "parent of included class"); FREEMEM(classes); CFCBase_decref((CFCBase*)hierarchy); CFCClass_clear_registry(); CFCParcel_reap_singletons(); } { CFCHierarchy *hierarchy = CFCHierarchy_new(T_CFDEST); CFCHierarchy_add_source_dir(hierarchy, T_CFBASE); CFCHierarchy_add_source_dir(hierarchy, T_CFEXT); CFCHierarchy_build(hierarchy); CFCClass **classes = CFCHierarchy_ordered_classes(hierarchy); CFCClass *rottweiler = NULL;; int num_classes; for (num_classes = 0; classes[num_classes]; ++num_classes) { CFCClass *klass = classes[num_classes]; const char *class_name = CFCClass_get_name(klass); if (strcmp(class_name, "Animal::Rottweiler") == 0) { rottweiler = klass; } OK(test, !CFCClass_included(klass), "not included"); } INT_EQ(test, num_classes, 5, "class count"); OK(test, rottweiler != NULL, "found rottweiler"); STR_EQ(test, CFCClass_get_name(CFCClass_get_parent(rottweiler)), "Animal::Dog", "parent of class from second source"); FREEMEM(classes); CFCBase_decref((CFCBase*)hierarchy); CFCClass_clear_registry(); CFCParcel_reap_singletons(); } { CFCHierarchy *hierarchy = CFCHierarchy_new(T_CFDEST); CFCHierarchy_add_include_dir(hierarchy, T_CFBASE); CFCHierarchy_add_include_dir(hierarchy, T_CFEXT); CFCHierarchy_add_prereq(hierarchy, "AnimalExtension"); CFCHierarchy_build(hierarchy); CFCParcel *animal = CFCParcel_fetch("Animal"); OK(test, animal != NULL, "parcel Animal registered"); OK(test, CFCParcel_required(animal), "parcel Animal required"); CFCParcel *animal_ext = CFCParcel_fetch("AnimalExtension"); OK(test, animal_ext != NULL, "parcel AnimalExtension registered"); OK(test, CFCParcel_required(animal_ext), "parcel AnimalExtension required"); CFCClass **classes = CFCHierarchy_ordered_classes(hierarchy); int num_classes = 0; while (classes[num_classes]) { ++num_classes; } INT_EQ(test, num_classes, 5, "class count"); FREEMEM(classes); CFCBase_decref((CFCBase*)hierarchy); CFCClass_clear_registry(); CFCParcel_reap_singletons(); } rmdir(T_CFDEST_INCLUDE); rmdir(T_CFDEST_SOURCE); rmdir(T_CFDEST); }