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.

Reply via email to