aboutsummaryrefslogtreecommitdiff
path: root/src/term.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/term.c')
-rw-r--r--src/term.c109
1 files changed, 89 insertions, 20 deletions
diff --git a/src/term.c b/src/term.c
index 903ee8a..d52171a 100644
--- a/src/term.c
+++ b/src/term.c
@@ -3,9 +3,11 @@
#include <stdlib.h>
#include <stdio.h>
+#include <assert.h>
#include <log.h>
#include <term.h>
+#include <map.h>
struct term *term_new(term_type_t type, hash_t hash, size_t depth)
{
@@ -19,13 +21,6 @@ struct term *term_new(term_type_t type, hash_t hash, size_t depth)
return term;
}
-void term_refer(struct term *term, size_t depth)
-{
- term->refs++;
- if (depth < term->depth) // lower depths are more important
- term->depth = depth;
-}
-
void term_print(struct term *term)
{
switch (term->type) {
@@ -49,16 +44,90 @@ void term_print(struct term *term)
}
}
-/* void deref_term(struct term *term) */
-/* { */
-/* if (term->type == ABS) { */
-/* deref_term(term->u.abs.term); */
-/* } else if (term->type == APP) { */
-/* deref_term(term->u.app.lhs); */
-/* deref_term(term->u.app.rhs); */
-/* } */
-
-/* // TODO: remove from hashmap? */
-/* if (--term->refs == 0) */
-/* free(term); */
-/* } */
+struct term *term_rehash_abs(struct term *head, struct term *term)
+{
+ if (head->u.abs.term->hash == term->hash)
+ return head;
+
+ hash_t res =
+ hash((uint8_t *)&head->type, sizeof(head->type), term->hash);
+
+ assert(res != head->hash);
+
+ struct term *match = map_get(res);
+ if (match) { // already exists
+ term_refer(match, head->depth);
+ term_deref(head);
+ return match;
+ } else { // create new
+ struct term *new = term_new(ABS, res, head->depth);
+ new->u.abs.term = term;
+ term_refer(term, head->depth + 1);
+ term_deref(head);
+ return new;
+ }
+}
+
+struct term *term_rehash_app(struct term *head, struct term *lhs,
+ struct term *rhs)
+{
+ if (head->u.app.lhs->hash == lhs->hash &&
+ head->u.app.rhs->hash == rhs->hash)
+ return head;
+
+ hash_t res =
+ hash((uint8_t *)&head->type, sizeof(head->type), lhs->hash);
+ res = hash((uint8_t *)&res, sizeof(res), rhs->hash);
+
+ assert(res != head->hash);
+
+ struct term *match = map_get(res);
+ if (match) { // already exists
+ term_refer(match, head->depth);
+ term_deref(head);
+ return match;
+ } else { // create new
+ struct term *new = term_new(APP, res, head->depth);
+ new->u.app.lhs = lhs;
+ new->u.app.rhs = rhs;
+ if (head->u.app.lhs->hash != lhs->hash)
+ term_refer(lhs, head->depth + 1);
+ if (head->u.app.rhs->hash != rhs->hash)
+ term_refer(rhs, head->depth + 1);
+ term_deref(head);
+ return new;
+ }
+}
+
+void term_refer_head(struct term *term, size_t depth)
+{
+ term->refs++;
+ if (depth < term->depth) // lower depths are more important
+ term->depth = depth;
+}
+
+void term_refer(struct term *term, size_t depth)
+{
+ if (term->type == ABS) {
+ term_refer(term->u.abs.term, depth + 1);
+ } else if (term->type == APP) {
+ term_refer(term->u.app.lhs, depth + 1);
+ term_refer(term->u.app.rhs, depth + 1);
+ }
+
+ term_refer_head(term, depth);
+}
+
+void term_deref(struct term *term)
+{
+ if (term->type == ABS) {
+ term_deref(term->u.abs.term);
+ } else if (term->type == APP) {
+ term_deref(term->u.app.lhs);
+ term_deref(term->u.app.rhs);
+ }
+
+ // TODO: remove from hashmap?
+ if (--term->refs == 0)
+ free(term);
+}