aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin Borner2023-06-01 23:08:07 +0200
committerMarvin Borner2023-06-01 23:08:07 +0200
commitc9b0537a1f04c8a28e1f9aa9a6112a1e59653eea (patch)
treeec403ce89057acf409ac8ccb21c0538d207f5a47
parentc062eaeea09592cbdf7e5d732e992d0cdd8eedc5 (diff)
Some work on derefs
-rw-r--r--src/reduce.c21
-rw-r--r--src/schedule.c2
-rw-r--r--src/term.c48
3 files changed, 53 insertions, 18 deletions
diff --git a/src/reduce.c b/src/reduce.c
index 9e7520d..38baf06 100644
--- a/src/reduce.c
+++ b/src/reduce.c
@@ -4,6 +4,7 @@
#include <stdio.h>
#include <term.h>
+#include <map.h>
#include <reduce.h>
#include <log.h>
#include <assert.h>
@@ -13,26 +14,28 @@ static struct term *substitute(struct term *term, struct term *substitution,
{
if (term->type == VAR) {
if (term->u.var.index == level) {
- // TODO: deref index
+ term_deref_head(term);
return substitution;
} else {
return term;
}
} else if (term->type == ABS) {
+ hash_t previous = term->u.abs.term->hash;
struct term *new =
substitute(term->u.abs.term, substitution, level + 1);
- if (term->u.abs.term->hash == new->hash)
+ if (previous == new->hash)
return term; // nothing changed
struct term *rehashed = term_rehash_abs(term, new);
term_rehash_parents(rehashed);
return rehashed;
} else if (term->type == APP) {
+ hash_t previous_lhs = term->u.app.lhs->hash;
+ hash_t previous_rhs = term->u.app.rhs->hash;
struct term *lhs =
substitute(term->u.app.lhs, substitution, level);
struct term *rhs =
substitute(term->u.app.rhs, substitution, level);
- if (term->u.app.lhs->hash == lhs->hash &&
- term->u.app.rhs->hash == rhs->hash)
+ if (previous_lhs == lhs->hash && previous_rhs == rhs->hash)
return term; // nothing changed
struct term *rehashed = term_rehash_app(term, lhs, rhs);
term_rehash_parents(rehashed);
@@ -45,8 +48,12 @@ static struct term *substitute(struct term *term, struct term *substitution,
// ([X] Y) -> X/Y
struct term *reduce(struct term *term)
{
- assert(term->type == APP);
- assert(term->u.app.lhs->type == ABS);
+ if (term->type != APP || term->u.app.lhs->type != ABS)
+ fatal("can't reduce non-beta-redex %d\n", term->type);
- return substitute(term->u.app.lhs, term->u.app.rhs, -1);
+ map_delete(term->u.app.lhs->parents, term);
+ map_delete(term->u.app.rhs->parents, term);
+ struct term *reduced = substitute(term->u.app.lhs, term->u.app.rhs, -1);
+ term_deref_head(term);
+ return reduced;
}
diff --git a/src/schedule.c b/src/schedule.c
index 93cd700..1362b1e 100644
--- a/src/schedule.c
+++ b/src/schedule.c
@@ -69,6 +69,8 @@ void schedule_add(struct term *term)
void schedule(void)
{
while (pqueue_size(queue) > 0) {
+ map_dump(map_all_terms());
+
// TODO: check finished programs
size_t position = choose_position();
struct term *term = pqueue_pop_at(queue, position);
diff --git a/src/term.c b/src/term.c
index a2f361b..bd0868c 100644
--- a/src/term.c
+++ b/src/term.c
@@ -9,6 +9,22 @@
#include <term.h>
#include <map.h>
+// doesn't care about ref count
+static void term_destroy_head(struct term *term)
+{
+ term_print(term);
+ fprintf(stderr, "\n");
+ map_delete(map_all_terms(), term);
+ map_destroy(term->parents);
+ free(term);
+}
+
+static void term_destroy_parent(void *item)
+{
+ struct term *term = *(struct term **)item;
+ term_destroy_head(term);
+}
+
struct term *term_new(term_type_t type, hash_t hash, size_t depth)
{
struct term *term = malloc(sizeof(*term));
@@ -18,7 +34,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, 0);
+ term->parents =
+ hashmap_new(sizeof(struct term *), 0, term_destroy_parent);
return term;
}
@@ -55,12 +72,15 @@ 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;
}
}
@@ -77,6 +97,8 @@ struct term *term_rehash_app(struct term *head, struct term *lhs,
struct term *match = map_get(map_all_terms(), res);
if (match) { // already exists
+ term_refer_head(match, head->depth);
+ term_deref(head);
return match;
} else { // create new
struct term *new = term_new(APP, res, head->depth);
@@ -85,6 +107,7 @@ struct term *term_rehash_app(struct term *head, struct term *lhs,
map_set(map_all_terms(), new);
map_set(lhs->parents, new);
map_set(rhs->parents, new);
+ term_deref_head(head);
return new;
}
}
@@ -98,25 +121,30 @@ struct term *term_rehash_var(struct term *head, size_t index)
struct term *match = map_get(map_all_terms(), res);
if (match) { // already exists
+ term_refer_head(match, head->depth);
+ term_deref(head);
return match;
} else { // create new
struct term *new = term_new(APP, res, head->depth);
new->u.var.index = index;
map_set(map_all_terms(), new);
+ term_deref_head(head);
return new;
}
}
struct term *term_rehash(struct term *term)
{
- if (term->type == ABS) {
+ if (term->type == ABS)
return term_rehash_abs(term, term->u.abs.term);
- } else if (term->type == APP) {
+
+ if (term->type == APP)
return term_rehash_app(term, term->u.app.lhs, term->u.app.rhs);
- } else if (term->type == VAR) {
+
+ if (term->type == VAR)
return term_rehash_var(term, term->u.var.index);
- }
- return term;
+
+ fatal("invalid type %d\n", term->type);
}
// returns the direct parent
@@ -186,12 +214,10 @@ void term_refer(struct term *term, size_t depth)
void term_deref_head(struct term *term)
{
+ assert(term->refs);
term->refs--;
- if (term->refs == 0) {
- map_delete(map_all_terms(), term);
- map_destroy(term->parents);
- free(term);
- }
+ if (!term->refs)
+ term_destroy_head(term);
}
void term_deref(struct term *term)