aboutsummaryrefslogtreecommitdiff
path: root/src/reduce.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/reduce.c')
-rw-r--r--src/reduce.c49
1 files changed, 44 insertions, 5 deletions
diff --git a/src/reduce.c b/src/reduce.c
index 3fc7c48..07d1bfa 100644
--- a/src/reduce.c
+++ b/src/reduce.c
@@ -9,24 +9,63 @@
#include <log.h>
#include <assert.h>
-// only substitutes (and therefore rehashes) -> no explicit beta reduction
+static struct term *shift(struct term *term, size_t level, size_t amount)
+{
+ debug("shifting %lx\n", term->hash & HASH_MASK);
+ if (term->type == VAR) {
+ if (level > term->u.var.index)
+ return term;
+ struct term *rehashed =
+ term_rehash_var(term, term->u.var.index + amount);
+ return rehashed;
+ } else if (term->type == ABS) {
+ struct term *previous = term->u.abs.term;
+ struct term *new = shift(term->u.abs.term, level + 1, amount);
+ if (previous->hash == new->hash)
+ return term; // nothing changed
+ struct term *rehashed = term_rehash_abs(term, new);
+ /* term_rehash_parents(rehashed); */
+ /* if (rehashed->u.abs.term->hash == (*substitution)->hash) */
+ /* term_deref_head(previous, 1); */
+ 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 = shift(term->u.app.lhs, level, amount);
+ struct term *rhs = shift(term->u.app.rhs, level, amount);
+ 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); */
+ return rehashed;
+ }
+ fatal("invalid type %d\n", term->type);
+}
+
+// only substitutes (and therefore increments indices and rehashes)
static struct term *substitute(struct term *term, struct term *substitution,
size_t level)
{
- debug("substituting %lx with %lx\n", term->hash, substitution->hash);
+ debug("substituting %lx with %lx\n", term->hash & HASH_MASK,
+ substitution->hash & HASH_MASK);
if (term->type == VAR) {
if (term->u.var.index == level) {
+ substitution->refs += 1; // TODO: Kinda hacky
+ shift(substitution, 0, level);
+ substitution->refs -= 1;
return substitution;
- } else {
+ } else if (term->u.var.index < level) {
term_deref(substitution, 1);
return term;
+ } else {
+ fatal("implement\n");
}
} else if (term->type == ABS) {
struct term *previous = term->u.abs.term;
struct term *new =
substitute(term->u.abs.term, substitution, level + 1);
if (previous->hash == new->hash)
- return new; // nothing changed
+ return term; // nothing changed
struct term *rehashed = term_rehash_abs(term, new);
term_rehash_parents(rehashed);
if (rehashed->u.abs.term->hash == substitution->hash)
@@ -55,7 +94,7 @@ struct term *reduce(struct term *term)
if (!term_is_beta_redex(term))
fatal("can't reduce non-beta-redex %d\n", term->type);
- debug("reducing %lx\n", term->hash);
+ debug("reducing %lx\n", term->hash & HASH_MASK);
struct term *reduced = substitute(term->u.app.lhs, term->u.app.rhs, -1);
return reduced;