aboutsummaryrefslogtreecommitdiff
path: root/src/term.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/term.c')
-rw-r--r--src/term.c77
1 files changed, 76 insertions, 1 deletions
diff --git a/src/term.c b/src/term.c
index 5abe758..bf712d6 100644
--- a/src/term.c
+++ b/src/term.c
@@ -11,13 +11,33 @@
#include <map.h>
// doesn't care about ref count
-void term_destroy_head(struct term *term)
+// this is needed to destroy possibly multiple parents
+static void term_destroy_head(struct term *term)
{
map_delete(map_all_terms(), term);
+
+ // recursively destroy own parents
+ map_destroy(term->parents);
+
+ // remove term from child's parents
+ if (term->type == ABS) {
+ map_delete(term->u.abs.term->parents, term);
+ } else if (term->type == APP) {
+ map_delete(term->u.app.lhs->parents, term);
+ map_delete(term->u.app.rhs->parents, term);
+ }
+
schedule_remove(term);
free(term);
}
+static void term_destroy_parent(void *item)
+{
+ struct term *term = *(struct term **)item;
+ fprintf(stderr, "%p parent\n", term);
+ term_destroy_head(term);
+}
+
struct term *term_new(term_type_t type, hash_t hash, size_t depth)
{
struct term *term = malloc(sizeof(*term));
@@ -27,6 +47,8 @@ struct term *term_new(term_type_t type, hash_t hash, size_t depth)
term->refs = 1;
term->hash = hash;
term->depth = depth;
+ term->parents =
+ hashmap_new(sizeof(struct term *), 0, term_destroy_parent);
return term;
}
@@ -69,11 +91,14 @@ struct term *term_rehash_abs(struct term *head, struct term *term)
struct term *match = map_get(map_all_terms(), res);
if (match) { // already exists
term_refer_head(match, head->depth);
+ /* term_deref_head(head); */
return match;
} else { // create new
struct term *new = term_new(ABS, res, head->depth);
new->u.abs.term = term;
map_set(map_all_terms(), new);
+ map_set(term->parents, new);
+ /* term_deref_head(head); */
return new;
}
}
@@ -98,6 +123,8 @@ struct term *term_rehash_app(struct term *head, struct term *lhs,
new->u.app.lhs = lhs;
new->u.app.rhs = rhs;
map_set(map_all_terms(), new);
+ map_set(lhs->parents, new);
+ map_set(rhs->parents, new);
term_deref_head(head);
return new;
}
@@ -138,6 +165,53 @@ struct term *term_rehash(struct term *term)
fatal("invalid type %d\n", term->type);
}
+// returns the direct parent
+void term_rehash_parents(struct term *term)
+{
+ if (!term->parents)
+ return;
+
+ // we need to convert the parent hashmap to a list
+ // so we can replace the rehashed elements while looping
+ // TODO: Abstract list lib?
+ struct parent_list {
+ struct term *term;
+ struct parent_list *next;
+ };
+ struct parent_list *parents = calloc(sizeof(*parents), 1);
+
+ size_t iter = 0;
+ void *iter_val;
+ while (hashmap_iter(term->parents, &iter, &iter_val)) {
+ struct parent_list *new = malloc(sizeof(*parents));
+ new->term = *(struct term **)iter_val;
+ new->next = parents;
+ parents = new;
+ }
+
+ struct parent_list *iterator = parents;
+ while (iterator && iterator->term) {
+ struct term *parent = iterator->term;
+ hash_t previous = parent->hash;
+ struct term *new = term_rehash(parent);
+ if (previous == new->hash) {
+ struct parent_list *next = iterator->next;
+ free(iterator);
+ iterator = next;
+ continue;
+ }
+
+ map_delete(term->parents, parent);
+ map_set(term->parents, new);
+
+ term_rehash_parents(new);
+
+ struct parent_list *next = iterator->next;
+ free(iterator);
+ iterator = next;
+ }
+}
+
void term_refer_head(struct term *term, size_t depth)
{
term->refs++;
@@ -159,6 +233,7 @@ void term_refer(struct term *term, size_t depth)
void term_deref_head(struct term *term)
{
+ fprintf(stderr, "%p deref\n", term);
assert(term->refs);
term->refs--;
if (!term->refs)