diff options
Diffstat (limited to 'src/term.c')
-rw-r--r-- | src/term.c | 77 |
1 files changed, 76 insertions, 1 deletions
@@ -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) |