Rework setup of parent/child relationship Set up parent/child relationship of classes in CFCParcel. Connect and sort classes in a single function.
Make sure that prereq parcels are registered first. Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/a3231bcc Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/a3231bcc Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/a3231bcc Branch: refs/heads/master Commit: a3231bcc2fa05743b8b82c94a04f0df30bf06d97 Parents: 682278c Author: Nick Wellnhofer <wellnho...@aevum.de> Authored: Tue Feb 28 14:11:25 2017 +0100 Committer: Nick Wellnhofer <wellnho...@aevum.de> Committed: Thu Mar 2 20:08:05 2017 +0100 ---------------------------------------------------------------------- compiler/perl/lib/Clownfish/CFC.xs | 12 ----- compiler/src/CFCClass.c | 32 ++------------ compiler/src/CFCClass.h | 5 --- compiler/src/CFCHierarchy.c | 78 ++++++++++----------------------- compiler/src/CFCParcel.c | 50 ++++++++++++++------- compiler/src/CFCParcel.h | 5 ++- 6 files changed, 64 insertions(+), 118 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/a3231bcc/compiler/perl/lib/Clownfish/CFC.xs ---------------------------------------------------------------------- diff --git a/compiler/perl/lib/Clownfish/CFC.xs b/compiler/perl/lib/Clownfish/CFC.xs index 81504f4..b0205d9 100644 --- a/compiler/perl/lib/Clownfish/CFC.xs +++ b/compiler/perl/lib/Clownfish/CFC.xs @@ -264,7 +264,6 @@ ALIAS: get_exposure = 2 get_name = 4 get_nickname = 6 - set_parent = 7 get_parent = 8 get_path_part = 10 get_parent_class_name = 12 @@ -303,17 +302,6 @@ PPCODE: retval = newSVpvn(value, strlen(value)); } break; - case 7: { - CFCClass *parent = NULL; - if (SvOK(ST(1)) - && sv_derived_from(ST(1), "Clownfish::CFC::Model::Class") - ) { - IV objint = SvIV((SV*)SvRV(ST(1))); - parent = INT2PTR(CFCClass*, objint); - } - CFCClass_set_parent(self, parent); - break; - } case 8: { CFCClass *parent = CFCClass_get_parent(self); retval = S_cfcbase_to_perlref(parent); http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/a3231bcc/compiler/src/CFCClass.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCClass.c b/compiler/src/CFCClass.c index 9d63055..0a16a6b 100644 --- a/compiler/src/CFCClass.c +++ b/compiler/src/CFCClass.c @@ -76,10 +76,6 @@ struct CFCClass { char *include_h; }; -// Link up parents and kids. -static void -S_establish_ancestry(CFCClass *self); - // Pass down member vars to from parent to children. static void S_bequeath_member_vars(CFCClass *self); @@ -365,16 +361,12 @@ CFCClass_add_child(CFCClass *self, CFCClass *child) { = (CFCClass*)CFCBase_incref((CFCBase*)child); self->children[self->num_kids] = NULL; + // Set parent of child. + CFCWeakPtr_set(&child->parent, (CFCBase*)self); + // Add parcel dependency. CFCParcel *parcel = CFCClass_get_parcel(self); CFCParcel *child_parcel = CFCClass_get_parcel(child); - if (!CFCParcel_has_prereq(child_parcel, parcel)) { - CFCUtil_die("Class '%s' inherits from '%s', but parcel '%s' is not a" - " prerequisite of '%s'", - child->name, self->name, - CFCParcel_get_name(parcel), - CFCParcel_get_name(child_parcel)); - } CFCParcel_add_inherited_parcel(child_parcel, parcel); } @@ -569,18 +561,6 @@ S_bequeath_methods(CFCClass *self) { } } -// Let the children know who their parent class is. -static void -S_establish_ancestry(CFCClass *self) { - for (size_t i = 0; i < self->num_kids; i++) { - CFCClass *child = self->children[i]; - // This is a circular reference and thus a memory leak, but we don't - // care, because we have to have everything in memory at once anyway. - CFCClass_set_parent(child, self); - S_establish_ancestry(child); - } -} - static CFCBase** S_copy_cfcbase_array(CFCBase **array, size_t num_elems) { CFCBase **copy = (CFCBase**)MALLOCATE((num_elems + 1) * sizeof(CFCBase*)); @@ -596,7 +576,6 @@ CFCClass_grow_tree(CFCClass *self) { if (self->tree_grown) { CFCUtil_die("Can't call grow_tree more than once"); } - S_establish_ancestry(self); // Copy fresh variabless for root class. self->member_vars @@ -713,11 +692,6 @@ CFCClass_get_nickname(CFCClass *self) { return self->nickname; } -void -CFCClass_set_parent(CFCClass *self, CFCClass *parent) { - CFCWeakPtr_set(&self->parent, (CFCBase*)parent); -} - CFCClass* CFCClass_get_parent(CFCClass *self) { return (CFCClass*)CFCWeakPtr_deref(self->parent); http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/a3231bcc/compiler/src/CFCClass.h ---------------------------------------------------------------------- diff --git a/compiler/src/CFCClass.h b/compiler/src/CFCClass.h index bcb87f4..ca86906 100644 --- a/compiler/src/CFCClass.h +++ b/compiler/src/CFCClass.h @@ -200,11 +200,6 @@ CFCClass_inert_vars(CFCClass *self); const char* CFCClass_get_nickname(CFCClass *self); -/** Set the parent Class. (Not class name, Class.) - */ -void -CFCClass_set_parent(CFCClass *self, CFCClass *parent); - CFCClass* CFCClass_get_parent(CFCClass *self); http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/a3231bcc/compiler/src/CFCHierarchy.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCHierarchy.c b/compiler/src/CFCHierarchy.c index 1e44db3..0b5100c 100644 --- a/compiler/src/CFCHierarchy.c +++ b/compiler/src/CFCHierarchy.c @@ -68,7 +68,7 @@ typedef struct CFCFindFilesContext { } CFCFindFilesContext; static void -S_parse_source_cfp_files(const char *source_dir); +S_parse_source_cfp_files(CFCHierarchy *self, const char *source_dir); static void S_find_prereqs(CFCHierarchy *self, CFCParcel *parcel); @@ -93,9 +93,6 @@ static char* S_extract_path_part(const char *path, const char *dir, const char *ext); static void -S_connect_classes(CFCHierarchy *self); - -static void S_add_file(CFCHierarchy *self, CFCFile *file); static void @@ -216,24 +213,12 @@ void CFCHierarchy_build(CFCHierarchy *self) { // Read .cfp files. for (size_t i = 0; self->sources[i] != NULL; i++) { - S_parse_source_cfp_files(self->sources[i]); + S_parse_source_cfp_files(self, self->sources[i]); } - // Copy array of source parcels. CFCParcel **parcels = CFCParcel_all_parcels(); - size_t num_source_parcels = 0; - while (parcels[num_source_parcels] != NULL) { num_source_parcels++; } - size_t alloc_size = num_source_parcels * sizeof(CFCParcel*); - CFCParcel **source_parcels = (CFCParcel**)MALLOCATE(alloc_size); - memcpy(source_parcels, parcels, alloc_size); - - // Find prerequisite parcels. - for (size_t i = 0; i < num_source_parcels; i++) { - S_find_prereqs(self, source_parcels[i]); - } // Read .cfh files of included parcels. - parcels = CFCParcel_all_parcels(); for (size_t i = 0; parcels[i] != NULL; i++) { CFCParcel *parcel = parcels[i]; if (CFCParcel_included(parcel)) { @@ -252,19 +237,18 @@ CFCHierarchy_build(CFCHierarchy *self) { CFCClass_resolve_types(self->classes[i]); } - S_connect_classes(self); - for (size_t i = 0; self->trees[i] != NULL; i++) { - CFCClass_grow_tree(self->trees[i]); - } + // It's important that prereq parcels are processed first. for (size_t i = 0; parcels[i] != NULL; i++) { - CFCParcel_sort_classes(parcels[i]); + CFCParcel_connect_and_sort_classes(parcels[i]); } - FREEMEM(source_parcels); + for (size_t i = 0; self->trees[i] != NULL; i++) { + CFCClass_grow_tree(self->trees[i]); + } } static void -S_parse_source_cfp_files(const char *source_dir) { +S_parse_source_cfp_files(CFCHierarchy *self, const char *source_dir) { CFCFindFilesContext context; context.ext = ".cfp"; context.paths = (char**)CALLOCATE(1, sizeof(char*)); @@ -278,6 +262,7 @@ S_parse_source_cfp_files(const char *source_dir) { 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) { @@ -285,9 +270,13 @@ S_parse_source_cfp_files(const char *source_dir) { CFCParcel_get_name(parcel), CFCParcel_get_cfp_path(existing), path); } - else { - CFCParcel_register(parcel); - } + + // 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); @@ -536,32 +525,6 @@ S_extract_path_part(const char *path, const char *dir, const char *ext) { return CFCUtil_strndup(src, path_part_len); } -static void -S_connect_classes(CFCHierarchy *self) { - // Wrangle the classes into hierarchies and figure out inheritance. - for (int i = 0; self->classes[i] != NULL; i++) { - CFCClass *klass = self->classes[i]; - const char *parent_name = CFCClass_get_parent_class_name(klass); - if (parent_name) { - for (size_t j = 0; ; j++) { - CFCClass *maybe_parent = self->classes[j]; - if (!maybe_parent) { - CFCUtil_die("Parent class '%s' not defined", parent_name); - } - const char *maybe_parent_name - = CFCClass_get_name(maybe_parent); - if (strcmp(parent_name, maybe_parent_name) == 0) { - CFCClass_add_child(maybe_parent, klass); - break; - } - } - } - else { - S_add_tree(self, klass); - } - } -} - void CFCHierarchy_read_host_data_json(CFCHierarchy *self, const char *host_lang) { CHY_UNUSED_VAR(self); @@ -700,6 +663,8 @@ S_add_file(CFCHierarchy *self, CFCFile *file) { self->files[self->num_files] = NULL; for (size_t i = 0; classes[i] != NULL; i++) { + CFCClass *klass = classes[i]; + if (self->num_classes == self->classes_cap) { self->classes_cap += 10; self->classes = (CFCClass**)REALLOCATE( @@ -707,8 +672,13 @@ S_add_file(CFCHierarchy *self, CFCFile *file) { (self->classes_cap + 1) * sizeof(CFCClass*)); } self->classes[self->num_classes++] - = (CFCClass*)CFCBase_incref((CFCBase*)classes[i]); + = (CFCClass*)CFCBase_incref((CFCBase*)klass); self->classes[self->num_classes] = NULL; + + const char *parent_name = CFCClass_get_parent_class_name(klass); + if (!parent_name) { + S_add_tree(self, klass); + } } } http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/a3231bcc/compiler/src/CFCParcel.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCParcel.c b/compiler/src/CFCParcel.c index 35f4cee..07c5ce6 100644 --- a/compiler/src/CFCParcel.c +++ b/compiler/src/CFCParcel.c @@ -56,7 +56,7 @@ static void S_set_prereqs(CFCParcel *self, CFCJson *node, const char *path); static CFCClass* -S_fetch_class(CFCParcel *self, const char *class_name, int search_prereqs); +S_fetch_class(CFCParcel *self, const char *class_name, int level); static CFCParcel **registry = NULL; static size_t num_registered = 0; @@ -596,7 +596,7 @@ void CFCParcel_add_class(CFCParcel *self, CFCClass *klass) { // Ensure unique class name. const char *class_name = CFCClass_get_name(klass); - CFCClass *other = S_fetch_class(self, class_name, true); + CFCClass *other = S_fetch_class(self, class_name, 2); if (other) { CFCUtil_die("Two classes with name %s", class_name); } @@ -636,7 +636,7 @@ S_compare_class_name(const void *va, const void *vb) { } void -CFCParcel_sort_classes(CFCParcel *self) { +CFCParcel_connect_and_sort_classes(CFCParcel *self) { size_t num_classes = self->num_classes; size_t alloc_size = (num_classes + 1) * sizeof(CFCClass*); CFCClass **classes = self->classes; @@ -652,12 +652,26 @@ CFCParcel_sort_classes(CFCParcel *self) { // Root and child classes are sorted by name to get a deterministic // order. - // Find subtree roots in parcel. + // Set up parent/child relationship of classes and find subtree roots + // in parcel. size_t todo = num_classes; for (size_t i = 0; i < num_classes; i++) { CFCClass *klass = classes[i]; - CFCClass *parent = CFCClass_get_parent(klass); + CFCClass *parent = NULL; + + const char *parent_name = CFCClass_get_parent_class_name(klass); + if (parent_name) { + parent = S_fetch_class(self, parent_name, 1); + if (!parent) { + CFCUtil_die("Parent class '%s' of '%s' not found in parcel" + " '%s' or its prerequisites", parent_name, + CFCClass_get_name(klass), self->name); + } + CFCClass_add_child(parent, klass); + } + if (!parent || !CFCClass_in_parcel(parent, self)) { + // Subtree root. sorted[--todo] = klass; } } @@ -670,17 +684,16 @@ CFCParcel_sort_classes(CFCParcel *self) { CFCClass *klass = sorted[todo++]; sorted[num_sorted++] = klass; - // Find children in parcel. + // Push children on stack. Since this function is called first for + // prereq parcels, we can be sure that the class doesn't have + // children from another parcel yet. CFCClass **children = CFCClass_children(klass); size_t prev_todo = todo; for (size_t i = 0; children[i]; i++) { - CFCClass *child = children[i]; - if (CFCClass_in_parcel(child, self)) { - if (todo <= num_sorted) { - CFCUtil_die("Internal error in CFCParcel_sort_classes"); - } - sorted[--todo] = child; + if (todo <= num_sorted) { + CFCUtil_die("Internal error in CFCParcel_sort_classes"); } + sorted[--todo] = children[i]; } qsort(&sorted[todo], prev_todo - todo, sizeof(sorted[0]), @@ -699,11 +712,15 @@ CFCParcel_sort_classes(CFCParcel *self) { CFCClass* CFCParcel_class(CFCParcel *self, const char *class_name) { - return S_fetch_class(self, class_name, false); + return S_fetch_class(self, class_name, 0); } static CFCClass* -S_fetch_class(CFCParcel *self, const char *class_name, int search_prereqs) { +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) { @@ -711,13 +728,14 @@ S_fetch_class(CFCParcel *self, const char *class_name, int search_prereqs) { } } - if (!search_prereqs) { return NULL; } + 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, true); + CFCClass *klass = S_fetch_class(prereq_parcel, class_name, level); if (klass) { return klass; } } http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/a3231bcc/compiler/src/CFCParcel.h ---------------------------------------------------------------------- diff --git a/compiler/src/CFCParcel.h b/compiler/src/CFCParcel.h index 96fe074..deaee9f 100644 --- a/compiler/src/CFCParcel.h +++ b/compiler/src/CFCParcel.h @@ -182,10 +182,11 @@ CFCParcel_read_host_data_json(CFCParcel *self, const char *host_lang); void CFCParcel_add_class(CFCParcel *self, struct CFCClass *klass); -/** Sort parents before child classes. +/** Set up parent/child relationship of classes and sort parents before + * child classes. */ void -CFCParcel_sort_classes(CFCParcel *self); +CFCParcel_connect_and_sort_classes(CFCParcel *self); /** Search for a class by class name. Doesn't search prereqs. Returns * NULL if no class was found.