aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin Borner2023-05-06 20:19:23 +0200
committerMarvin Borner2023-05-06 20:19:23 +0200
commitb31220aadc24ff137a4fe4bc39780ae63c58e11b (patch)
tree89e431ad99e85f581dbea56d61abac6794386f2a
parentd19f7f5bb99ca1073edb3ce1b13e782a3f598b4a (diff)
Start fresh
-rw-r--r--inc/murmur3.h9
-rw-r--r--inc/parse.h11
-rw-r--r--inc/reduce.h11
-rw-r--r--inc/store.h250
-rw-r--r--inc/term.h37
m---------lib/bdwgc0
-rw-r--r--makefile2
-rw-r--r--src/main.c111
-rw-r--r--src/murmur3.c40
-rw-r--r--src/parse.c75
-rw-r--r--src/reduce.c459
-rw-r--r--src/store.c857
-rw-r--r--src/term.c243
-rw-r--r--src/test.c273
14 files changed, 3 insertions, 2375 deletions
diff --git a/inc/murmur3.h b/inc/murmur3.h
deleted file mode 100644
index c042642..0000000
--- a/inc/murmur3.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef MURMUR3_H
-#define MURMUR3_H
-
-#include <stdint.h>
-#include <stdlib.h>
-
-uint32_t murmur3_32(const uint8_t *key, size_t len, uint32_t seed);
-
-#endif
diff --git a/inc/parse.h b/inc/parse.h
deleted file mode 100644
index c36f296..0000000
--- a/inc/parse.h
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright (c) 2023, Marvin Borner <dev@marvinborner.de>
-
-#ifndef PARSE_H
-#define PARSE_H
-
-#include <term.h>
-
-struct term *parse_blc(const char *term);
-struct term *parse_bruijn(const char *term);
-
-#endif
diff --git a/inc/reduce.h b/inc/reduce.h
deleted file mode 100644
index 82ea189..0000000
--- a/inc/reduce.h
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright (c) 2023, Marvin Borner <dev@marvinborner.de>
-
-#ifndef REDUCER_H
-#define REDUCER_H
-
-#include <term.h>
-
-struct term *reduce(struct term *term, void (*callback)(int, char, void *),
- void *data);
-
-#endif
diff --git a/inc/store.h b/inc/store.h
deleted file mode 100644
index 0161b62..0000000
--- a/inc/store.h
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2020 Samuel Vogelsanger <vogelsangersamuel@gmail.com>
- * Copyright (c) 2023 Marvin Borner <dev@marvinborner.de>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#ifndef STORE_STORE_H
-#define STORE_STORE_H
-
-#include <stdint.h>
-#include <stddef.h>
-
-#ifndef STORE_VERBOSITY
-#define STORE_VERBOSITY 5
-#endif
-
-#define DEBUG_NOTICE(fmt, ...) \
- do { \
- if (STORE_VERBOSITY >= 5) \
- fprintf(stderr, "DEBUG: store: " fmt, __VA_ARGS__); \
- } while (0)
-#define DEBUG_WARN(fmt, ...) \
- do { \
- if (STORE_VERBOSITY >= 4) \
- fprintf(stderr, "DEBUG: store: " fmt, __VA_ARGS__); \
- } while (0)
-
-#ifndef STORE_KEY_T
-#define STORE_KEY_T void *
-#endif
-
-#ifndef STORE_VALUE_T
-#define STORE_VALUE_T void *
-#endif
-
-/**
- * These are mostly for convenience
- */
-
-#define STORE_HASHFN_T(name) uint32_t (*name)(STORE_KEY_T)
-#define STORE_EQUALSFN_T(name) int (*name)(STORE_KEY_T left, STORE_KEY_T right)
-#define STORE_ASSOCFN_T(name) \
- STORE_VALUE_T(*name) \
- (STORE_KEY_T key, STORE_VALUE_T old_value, void *user_data)
-#define STORE_VALUE_EQUALSFN_T(name) \
- int (*name)(STORE_VALUE_T left, STORE_VALUE_T right)
-
-/**
- * These macros help with defining the various callbacks. Use them like so:
- * @code{c}
- * STORE_MAKE_EQUALSFN(equals_int, left, right)
- * {
- * return left == right;
- * }
- * @endcode
- */
-
-#define STORE_MAKE_HASHFN(name, arg_1) uint32_t name(STORE_KEY_T arg_1)
-#define STORE_MAKE_EQUALSFN(name, arg_l, arg_r) \
- int name(STORE_KEY_T arg_l, STORE_KEY_T arg_r)
-#define STORE_MAKE_ASSOCFN(name, key_arg, value_arg, user_data_arg) \
- STORE_VALUE_T name(STORE_KEY_T key_arg, STORE_VALUE_T value_arg, \
- void *user_data_arg)
-#define STORE_MAKE_VALUE_EQUALSFN(name, arg_l, arg_r) \
- int name(STORE_VALUE_T arg_l, STORE_VALUE_T arg_r)
-
-struct store {
- uint32_t ref_count;
- unsigned length;
- struct node *root;
-
- STORE_HASHFN_T(hash);
- STORE_EQUALSFN_T(equals);
-};
-
-/**
- * Creates a new map with the given hash and equals functions. This implementation is based on the assumption that if
- * two keys are equal, their hashes must be equal as well. This is commonly known as the Java Hashcode contract.
- *
- * The reference count of a new map is zero.
- *
- * @param hash
- * @param equals
- * @return
- */
-struct store *store_new(STORE_HASHFN_T(hash), STORE_EQUALSFN_T(equals));
-
-/**
- * Destroys a store. Doesn't clean up the stored key-value-pairs.
- *
- * @param old
- */
-void store_destroy(struct store **store);
-
-/**
- * Atomically increases the reference count of a map.
- *
- * @param store
- * @return
- */
-struct store *store_acquire(struct store *store);
-
-/**
- * Atomically decreases the reference count of a map and calls store_destroy if it caused the count to drop to zero.
- *
- * In either case then sets the reference to NULL.
- *
- * @param store
- */
-void store_release(struct store **store);
-
-/**
- * Returns the number of entries in store.
- *
- * @param store
- * @return the number of entries
- */
-unsigned store_length(const struct store *store);
-
-/**
- * Looks up key and sets *value_receiver to the associated value. Doesn't change value_receiver if key is not set.
- *
- * @param store
- * @param key
- * @param found is set to 0 if key is not set
- * @return
- */
-STORE_VALUE_T store_get(const struct store *store, STORE_KEY_T key, int *found);
-
-/**
- * Returns a new map derived from store but with key set to value.
- * If replaced is not NULL, sets it to indicate if the key is present in store.
- *
- * Reference count of the new map is zero.
- *
- * @param store
- * @param key
- * @param value
- * @param replaced
- * @return a new store
- */
-struct store *store_set(const struct store *store, STORE_KEY_T key,
- STORE_VALUE_T value, int *replaced);
-
-/**
- * Creates a new store with the given hash and equals functions, and inserts the given keys and values.
- * Only the first 'length' elements from keys and values are inserted.
- *
- * Reference count of the new map is zero.
- *
- * @param hash
- * @param equals
- * @param keys
- * @param values
- * @param length
- * @return
- */
-struct store *store_of(STORE_HASHFN_T(hash), STORE_EQUALSFN_T(equals),
- STORE_KEY_T *keys, STORE_VALUE_T *values, size_t length);
-
-/**
- * Returns a new map derived from store, but with key set to the return value of fn.
- * fn is passed the key, the current value for key, and user_data.
- * If key is not present in store, NULL is passed in place of the key and current value.
- *
- * Reference count of the new map is zero.
- *
- * @param store
- * @param key
- * @param fn
- * @param user_data
- * @return
- */
-struct store *store_assoc(const struct store *store, STORE_KEY_T key,
- STORE_ASSOCFN_T(fn), void *user_data);
-
-/**
- * Compares two maps for equality. A lot of short-circuiting is done on the assumption that unequal hashes
- * (for both keys and values) imply inequality. This is commonly known as the Java Hashcode contract: If two values
- * are equal, their hashes must be equal as well.
- *
- * @param left
- * @param right
- * @return
- */
-int store_equals(const struct store *left, const struct store *right,
- STORE_VALUE_EQUALSFN_T(value_equals));
-
-/**
- * An iterator for store. Meant to be put on the stack.
- */
-struct store_iter {
- int stack_level;
- unsigned element_cursor;
- unsigned element_arity;
- unsigned branch_cursor_stack[8];
- unsigned branch_arity_stack[8];
- void *node_stack[8];
-};
-
-/**
- * Initializes an iterator with a store.
- *
- * Example:
- * @code{.c}
- * struct store_iter iter;
- * STORE_KEY_T key;
- * STORE_VAL_T val;
- *
- * store_iter_init(&iter, store);
- * while(store_iter_next(&iter, &key, &val)) {
- * // do something with key and value
- * }
- * @endcode
- *
- * @param iter
- * @param store
- */
-void store_iter_init(struct store_iter *iter, const struct store *store);
-
-/**
- * Advances iter and points key_receiver and value_receiver to the next pair.
- *
- * @param iter
- * @param key_receiver
- * @param value_receiver
- * @return 0 if the end of the store has been reached
- */
-int store_iter_next(struct store_iter *iter, STORE_KEY_T *key_receiver,
- STORE_VALUE_T *value_receiver);
-
-#endif
diff --git a/inc/term.h b/inc/term.h
deleted file mode 100644
index 4f6f5ce..0000000
--- a/inc/term.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2023, Marvin Borner <dev@marvinborner.de>
-
-#ifndef TERM_H
-#define TERM_H
-
-typedef enum { INV, ABS, APP, VAR, CLOSURE, CACHE } term_type;
-
-struct term {
- term_type type;
- union {
- struct {
- int name;
- struct term *term;
- } abs;
- struct {
- struct term *lhs;
- struct term *rhs;
- } app;
- struct {
- int name;
- enum { BARENDREGT_VARIABLE, BRUIJN_INDEX } type;
- } var;
- void *other;
- } u;
-};
-
-void to_barendregt(struct term *term);
-void to_bruijn(struct term *term);
-struct term *new_term(term_type type);
-struct term *duplicate_term(struct term *term);
-int alpha_equivalency(struct term *a, struct term *b);
-void free_term(struct term *term);
-void print_term(struct term *term);
-void print_blc(struct term *term);
-void print_scheme(struct term *term);
-
-#endif
diff --git a/lib/bdwgc b/lib/bdwgc
deleted file mode 160000
-Subproject 1c2f2c679927538fa4969f85c67fafc3b1dddb2
diff --git a/makefile b/makefile
index 92faf23..fff2aa8 100644
--- a/makefile
+++ b/makefile
@@ -13,7 +13,7 @@ OBJS = $(patsubst $(SRC)/%.c, $(BUILD)/%.o, $(SRCS))
CFLAGS_DEBUG = -Wno-error -g -O0 -Wno-unused -fsanitize=address,undefined,leak
CFLAGS_WARNINGS = -Wall -Wextra -Wshadow -Wpointer-arith -Wwrite-strings -Wredundant-decls -Wnested-externs -Wmissing-declarations -Wstrict-prototypes -Wmissing-prototypes -Wcast-qual -Wswitch-default -Wswitch-enum -Wunreachable-code -Wundef -Wold-style-definition -pedantic -Wno-switch-enum
-CFLAGS = $(CFLAGS_WARNINGS) -std=c99 -Ofast -L$(LIB)/bdwgc/lib -lgc -I$(LIB)/bdwgc/inc -I$(INC)
+CFLAGS = $(CFLAGS_WARNINGS) -std=c99 -Ofast -I$(INC)
ifdef TEST # TODO: Somehow clean automagically
CFLAGS += -DTEST -DNTESTS=$(TEST)
diff --git a/src/main.c b/src/main.c
index a4973f7..5b74476 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,114 +1,7 @@
-// Copyright (c) 2023, Marvin Borner <dev@marvinborner.de>
-
-#ifndef TEST
#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <time.h>
-#include <stdlib.h>
-
-#include <reduce.h>
-#include <gc.h>
-#include <parse.h>
-
-static void callback(int i, char ch, void *data)
-{
- (void)i;
- (void)ch;
- (void)data;
- /* printf("%d: %c\n", i, ch); */
-}
-
-#define BUF_SIZE 1024
-static char *read_stdin(void)
-{
- char buffer[BUF_SIZE];
- size_t size = 1;
- char *string = malloc(sizeof(char) * BUF_SIZE);
- if (!string)
- return 0;
- string[0] = '\0';
- while (fgets(buffer, BUF_SIZE, stdin)) {
- char *old = string;
- size += strlen(buffer);
- string = realloc(string, size);
- if (!string) {
- free(old);
- return 0;
- }
- strcat(string, buffer);
- }
-
- if (ferror(stdin)) {
- free(string);
- fprintf(stderr, "Couldn't read from stdin\n");
- return 0;
- }
- return string;
-}
-
-static char *read_file(const char *path)
-{
- FILE *f = fopen(path, "rb");
- if (!f) {
- fprintf(stderr, "Can't open file %s: %s\n", path,
- strerror(errno));
- return 0;
- }
- fseek(f, 0, SEEK_END);
- long fsize = ftell(f);
- fseek(f, 0, SEEK_SET);
-
- char *string = malloc(fsize + 1);
- int ret = fread(string, fsize, 1, f);
- fclose(f);
-
- if (ret != 1) {
- fprintf(stderr, "Can't read file %s: %s\n", path,
- strerror(errno));
- return 0;
- }
-
- string[fsize] = 0;
- return string;
-}
-
-int main(int argc, char **argv)
+int main(int argc, char *argv[])
{
- GC_INIT();
- GC_enable_incremental();
-
- if (argc < 2) {
- fprintf(stderr, "Invalid arguments\n");
- return 1;
- }
-
- char *input;
- if (argv[1][0] == '-') {
- input = read_stdin();
- } else {
- input = read_file(argv[1]);
- }
-
- if (!input)
- return 1;
-
- struct term *parsed = parse_bruijn(input);
-
- clock_t begin = clock();
- struct term *reduced = reduce(parsed, callback, 0);
- clock_t end = clock();
- fprintf(stderr, "reduced in %.5fs\n",
- (double)(end - begin) / CLOCKS_PER_SEC);
-
- to_bruijn(reduced);
- print_blc(reduced);
- free_term(reduced);
- free_term(parsed);
- free(input);
+ printf("hello world!");
return 0;
}
-#else
-__attribute__((unused)) static int testing;
-#endif
diff --git a/src/murmur3.c b/src/murmur3.c
deleted file mode 100644
index bb1f666..0000000
--- a/src/murmur3.c
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "murmur3.h"
-
-#include <string.h>
-
-static inline uint32_t murmur_32_scramble(uint32_t k)
-{
- k *= 0xcc9e2d51;
- k = (k << 15) | (k >> 17);
- k *= 0x1b873593;
- return k;
-}
-
-uint32_t murmur3_32(const uint8_t *key, size_t len, uint32_t seed)
-{
- uint32_t h = seed;
- uint32_t k;
- /* Read in groups of 4. */
- for (size_t i = len >> 2; i; i--) {
- memcpy(&k, key, sizeof(uint32_t));
- key += sizeof(uint32_t);
- h ^= murmur_32_scramble(k);
- h = (h << 13) | (h >> 19);
- h = h * 5 + 0xe6546b64;
- }
- /* Read the rest. */
- k = 0;
- for (size_t i = len & 3; i; i--) {
- k <<= 8;
- k |= key[i - 1];
- }
- h ^= murmur_32_scramble(k);
- /* Finalize. */
- h ^= len;
- h ^= h >> 16;
- h *= 0x85ebca6b;
- h ^= h >> 13;
- h *= 0xc2b2ae35;
- h ^= h >> 16;
- return h;
-}
diff --git a/src/parse.c b/src/parse.c
deleted file mode 100644
index 0b9fd82..0000000
--- a/src/parse.c
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2023, Marvin Borner <dev@marvinborner.de>
-
-#include <stdio.h>
-
-#include <parse.h>
-#include <term.h>
-
-static struct term *rec_bruijn(const char **term)
-{
- struct term *res = 0;
- if (!**term) {
- fprintf(stderr, "invalid parsing state!\n");
- } else if (**term == '[') {
- (*term)++;
- res = new_term(ABS);
- res->u.abs.term = rec_bruijn(term);
- } else if (**term == '(') {
- (*term)++;
- res = new_term(APP);
- res->u.app.lhs = rec_bruijn(term);
- res->u.app.rhs = rec_bruijn(term);
- } else if (**term >= '0' && **term <= '9') {
- res = new_term(VAR);
- res->u.var.name = **term - '0';
- res->u.var.type = BRUIJN_INDEX;
- (*term)++;
- } else {
- (*term)++;
- res = rec_bruijn(term); // this is quite tolerant..
- }
- return res;
-}
-
-static struct term *rec_blc(const char **term)
-{
- struct term *res = 0;
- if (!**term) {
- fprintf(stderr, "invalid parsing state!\n");
- } else if (**term == '0' && *(*term + 1) == '0') {
- (*term) += 2;
- res = new_term(ABS);
- res->u.abs.term = rec_blc(term);
- } else if (**term == '0' && *(*term + 1) == '1') {
- (*term) += 2;
- res = new_term(APP);
- res->u.app.lhs = rec_blc(term);
- res->u.app.rhs = rec_blc(term);
- } else if (**term == '1') {
- const char *cur = *term;
- while (**term == '1')
- (*term)++;
- res = new_term(VAR);
- res->u.var.name = *term - cur - 1;
- res->u.var.type = BRUIJN_INDEX;
- (*term)++;
- } else {
- (*term)++;
- res = rec_blc(term); // this is quite tolerant..
- }
- return res;
-}
-
-struct term *parse_bruijn(const char *term)
-{
- struct term *parsed = rec_bruijn(&term);
- to_barendregt(parsed);
- return parsed;
-}
-
-struct term *parse_blc(const char *term)
-{
- struct term *parsed = rec_blc(&term);
- to_barendregt(parsed);
- return parsed;
-}
diff --git a/src/reduce.c b/src/reduce.c
deleted file mode 100644
index 44c4d97..0000000
--- a/src/reduce.c
+++ /dev/null
@@ -1,459 +0,0 @@
-// Copyright (c) 2023, Marvin Borner <dev@marvinborner.de>
-// based on the RKNL abstract machine
-
-#include <stdlib.h>
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <reduce.h>
-#include <murmur3.h>
-#include <store.h>
-#include <term.h>
-#include <gc.h>
-
-struct tracked {
- void *stuff;
-};
-
-struct stack {
- void *data;
- struct stack *next;
-};
-
-struct closure {
- struct term *term;
- struct store *store;
-};
-
-struct box {
- enum { TODO, DONE } state;
- struct term *term;
-};
-
-struct cache {
- struct box *box;
- struct term *term;
-};
-
-struct conf {
- enum { ECONF, CCONF } type;
- union {
- struct { // closure
- struct term *term;
- struct store *store;
- struct stack *stack;
- } econf; // blue
-
- struct { // computed
- struct stack *stack;
- struct term *term;
- } cconf; // green
- } u;
-};
-
-static int name_generator(void)
-{
- static int current = 0x181202;
- return current++;
-}
-
-static struct stack *stack_push(struct stack *stack, void *data)
-{
- struct stack *new = GC_malloc(sizeof(*new));
- new->data = data;
- new->next = stack;
- return new;
-}
-
-static struct stack *stack_next(struct stack *stack)
-{
- struct stack *next = stack->next;
- return next;
-}
-
-static void econf(struct conf *conf, struct term *term, struct store *store,
- struct stack *stack)
-{
- conf->type = ECONF;
- conf->u.econf.term = term;
- conf->u.econf.store = store;
- conf->u.econf.stack = stack;
-}
-
-static void cconf(struct conf *conf, struct stack *stack, struct term *term)
-{
- conf->type = CCONF;
- conf->u.cconf.stack = stack;
- conf->u.cconf.term = term;
-}
-
-static int transition_1(struct term **term, struct store **store,
- struct stack **stack)
-{
- struct closure *closure = GC_malloc(sizeof(*closure));
- closure->term = (*term)->u.app.rhs;
- closure->store = *store;
-
- struct term *app = new_term(APP);
- app->u.app.lhs = new_term(VAR);
- app->u.app.rhs = new_term(CLOSURE);
- app->u.app.rhs->u.other = closure;
-
- *term = (*term)->u.app.lhs;
- *store = *store;
- *stack = stack_push(*stack, app);
-
- return 0;
-}
-
-static int transition_2(struct stack **stack, struct term **term,
- struct store *store)
-{
- struct box *box = GC_malloc(sizeof(*box));
- box->state = TODO;
- box->term = 0;
-
- struct closure *closure = GC_malloc(sizeof(*closure));
- closure->term = *term;
- closure->store = store;
-
- struct cache *cache = GC_malloc(sizeof(*cache));
- cache->box = box;
- cache->term = new_term(CLOSURE);
- cache->term->u.other = closure;
-
- *stack = *stack;
- *term = new_term(CACHE);
- (*term)->u.other = cache;
-
- return 0;
-}
-
-static int transition_3(struct term **term, struct store **store,
- struct stack **stack, struct box *box)
-{
- assert(box->term->type == CLOSURE);
-
- struct cache *cache = GC_malloc(sizeof(*cache));
- cache->box = box;
- cache->term = new_term(VAR);
-
- struct term *cache_term = new_term(CACHE);
- cache_term->u.other = cache;
-
- struct closure *closure = box->term->u.other;
- *term = closure->term;
- *store = closure->store;
- *stack = stack_push(*stack, cache_term);
-
- return 0;
-}
-
-static int transition_4(struct stack **stack, struct term **term,
- struct box *box)
-{
- *stack = *stack;
- *term = box->term;
-
- return 0;
-}
-
-static int transition_5(struct stack **stack, struct term **term,
- struct term *peek_term)
-{
- struct cache *cache = peek_term->u.other;
- struct box *box = cache->box;
-
- box->state = DONE;
- box->term = *term;
-
- *stack = stack_next(*stack);
- *term = *term;
-
- return 0;
-}
-
-static int transition_6(struct term **term, struct store **store,
- struct stack **stack, struct term *peek_term,
- struct closure *closure)
-{
- struct box *box = GC_malloc(sizeof(*box));
- box->state = TODO;
- box->term = peek_term->u.app.rhs;
-
- *term = closure->term->u.abs.term;
- *store = store_set(closure->store, &closure->term->u.abs.name, box, 0);
- *stack = stack_next(*stack);
-
- return 0;
-}
-
-static int transition_7(struct term **term, struct store **store,
- struct stack **stack, struct box *box,
- struct closure *closure)
-{
- int x = name_generator();
-
- struct box *var_box = GC_malloc(sizeof(*var_box));
- var_box->state = DONE;
- var_box->term = new_term(VAR);
- var_box->term->u.var.name = x;
-
- struct cache *cache = GC_malloc(sizeof(*cache));
- cache->box = box;
- cache->term = new_term(VAR);
-
- struct term *cache_term = new_term(CACHE);
- cache_term->u.other = cache;
-
- struct term *abs = new_term(ABS);
- abs->u.abs.name = x;
- abs->u.abs.term = new_term(VAR);
-
- *term = closure->term->u.abs.term;
- *store = store_set(closure->store, (void *)&closure->term->u.abs.name,
- var_box, 0);
- *stack = stack_push(*stack, cache_term);
- *stack = stack_push(*stack, abs);
-
- return 0;
-}
-
-static int transition_8(struct stack **stack, struct term **term,
- struct box *box)
-{
- *stack = *stack;
- *term = box->term;
-
- return 0;
-}
-
-static int transition_9(struct term **term, struct store **store,
- struct stack **stack, struct term *peek_term)
-{
- struct closure *closure = peek_term->u.app.rhs->u.other;
-
- struct term *app = new_term(APP);
- app->u.app.lhs = *term;
- app->u.app.rhs = new_term(VAR);
-
- *term = closure->term;
- *store = closure->store;
- *stack = stack_push(stack_next(*stack), app);
-
- return 0;
-}
-
-static int transition_10(struct stack **stack, struct term **term,
- struct term *peek_term)
-{
- struct term *app = new_term(APP);
- app->u.app.lhs = peek_term->u.app.lhs;
- app->u.app.rhs = *term;
-
- *stack = stack_next(*stack);
- *term = app;
-
- return 0;
-}
-
-static int transition_11(struct stack **stack, struct term **term,
- struct term *peek_term)
-{
- struct term *abs = new_term(ABS);
- abs->u.abs.name = peek_term->u.abs.name;
- abs->u.abs.term = *term;
-
- *stack = stack_next(*stack);
- *term = abs;
-
- return 0;
-}
-
-static int transition_closure(struct conf *conf, int i,
- void (*callback)(int, char, void *), void *data)
-{
- struct term *term = conf->u.econf.term;
- struct store *store = conf->u.econf.store;
- struct stack *stack = conf->u.econf.stack;
-
- int ret = 1;
- switch (term->type) {
- case APP: // (1)
- callback(i, '1', data);
- ret = transition_1(&term, &store, &stack);
- econf(conf, term, store, stack);
- return ret;
- case ABS: // (2)
- callback(i, '2', data);
- ret = transition_2(&stack, &term, store);
- cconf(conf, stack, term);
- return ret;
- case VAR:;
- struct box *box = store_get(store, &term->u.var.name, 0);
- if (!box) {
- box = GC_malloc(sizeof(*box));
- box->state = DONE;
- box->term = term;
- }
- if (box->state == TODO) { // (3)
- callback(i, '3', data);
- ret = transition_3(&term, &store, &stack, box);
- econf(conf, term, store, stack);
- return ret;
- } else if (box->state == DONE) { // (4)
- callback(i, '4', data);
- ret = transition_4(&stack, &term, box);
- cconf(conf, stack, term);
- return ret;
- }
- fprintf(stderr, "Invalid box state %d\n", box->state);
- return 1;
- default:
- fprintf(stderr, "Invalid econf type %d\n", term->type);
- return 1;
- }
-}
-
-static int transition_computed(struct conf *conf, int i,
- void (*callback)(int, char, void *), void *data)
-{
- struct stack *stack = conf->u.cconf.stack;
- struct term *term = conf->u.cconf.term;
- if (!stack) {
- fprintf(stderr, "Invalid stack!\n");
- return 1;
- }
- int ret = 1;
- struct term *peek_term = stack->data;
- if (peek_term && peek_term->type == CACHE) { // (5)
- struct cache *cache = peek_term->u.other;
- struct term *cache_term = cache->term;
- if (cache_term->type == VAR && !cache_term->u.var.name) {
- callback(i, '5', data);
- ret = transition_5(&stack, &term, peek_term);
- cconf(conf, stack, term);
- return ret;
- }
- }
- if (peek_term && peek_term->type == APP &&
- peek_term->u.app.lhs->type == VAR &&
- !peek_term->u.app.lhs->u.var.name && term->type == CACHE &&
- ((struct cache *)term->u.other)->term->type == CLOSURE) { // (6)
- struct closure *closure =
- ((struct cache *)term->u.other)->term->u.other;
- if (closure->term->type == ABS) {
- callback(i, '6', data);
- struct store *store;
- ret = transition_6(&term, &store, &stack, peek_term,
- closure);
- econf(conf, term, store, stack);
- return ret;
- }
- }
- if (term->type == CACHE &&
- ((struct cache *)term->u.other)->term->type == CLOSURE) {
- struct box *box = ((struct cache *)term->u.other)->box;
- struct closure *closure =
- ((struct cache *)term->u.other)->term->u.other;
- if (closure->term->type == ABS && box->state == TODO &&
- !box->term) { // (7)
- callback(i, '7', data);
- struct store *store;
- ret = transition_7(&term, &store, &stack, box, closure);
- econf(conf, term, store, stack);
- return ret;
- }
- if (closure->term->type == ABS && box->state == DONE) { // (8)
- callback(i, '8', data);
- ret = transition_8(&stack, &term, box);
- cconf(conf, stack, term);
- return ret;
- }
- }
- if (peek_term && peek_term->type == APP &&
- peek_term->u.app.lhs->type == VAR &&
- !peek_term->u.app.lhs->u.var.name &&
- peek_term->u.app.rhs->type == CLOSURE) { // (9)
- callback(i, '9', data);
- struct store *store;
- ret = transition_9(&term, &store, &stack, peek_term);
- econf(conf, term, store, stack);
- return ret;
- }
- if (peek_term && peek_term->type == APP &&
- peek_term->u.app.rhs->type == VAR &&
- !peek_term->u.app.rhs->u.var.name) { // (10)
- callback(i, 'A', data);
- ret = transition_10(&stack, &term, peek_term);
- cconf(conf, stack, term);
- return ret;
- }
- if (peek_term && peek_term->type == ABS &&
- peek_term->u.abs.term->type == VAR &&
- !peek_term->u.abs.term->u.var.name) { // (11)
- callback(i, 'B', data);
- ret = transition_11(&stack, &term, peek_term);
- cconf(conf, stack, term);
- return ret;
- }
- if (!peek_term)
- return 1;
-
- // If implemented *correctly* it's proven that this can't happen
- fprintf(stderr, "Invalid cconf transition state\n");
- return 1;
-}
-
-static int transition(struct conf *conf, int i,
- void (*callback)(int, char, void *), void *data)
-{
- if (conf->type == ECONF) {
- return transition_closure(conf, i, callback, data);
- } else if (conf->type == CCONF) {
- return transition_computed(conf, i, callback, data);
- }
- fprintf(stderr, "Invalid transition state %x\n", conf->type);
- return 1;
-}
-
-static struct conf *for_each_state(struct conf *conf, int i,
- void (*callback)(int, char, void *),
- void *data)
-{
- int ret = 0;
- while (!ret)
- ret = transition(conf, i++, callback, data);
- return conf;
-}
-
-static int hash_var_equal(void *lhs, void *rhs)
-{
- /* return memcmp(lhs, rhs, sizeof(int)); */
- return *(int *)lhs == *(int *)rhs;
-}
-
-static uint32_t hash_var(void *key)
-{
- return murmur3_32((uint8_t *)key, sizeof(int), 0);
-}
-
-struct term *reduce(struct term *term, void (*callback)(int, char, void *),
- void *data)
-{
- struct stack stack = { 0 };
- struct store *store = store_new(hash_var, hash_var_equal);
- struct conf conf = {
- .type = ECONF,
- .u.econf.term = term,
- .u.econf.store = store,
- .u.econf.stack = &stack,
- };
- for_each_state(&conf, 0, callback, data);
- assert(conf.type == CCONF);
-
- struct term *ret = duplicate_term(conf.u.cconf.term);
-
- return ret;
-}
diff --git a/src/store.c b/src/store.c
deleted file mode 100644
index db3ccef..0000000
--- a/src/store.c
+++ /dev/null
@@ -1,857 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2020 Samuel Vogelsanger <vogelsangersamuel@gmail.com>
- * Copyright (c) 2023 Marvin Borner <dev@marvinborner.de>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * All the ref-counting specific code was marked with a "//reference counting" comment. If you need to modify this to
- * work with your own memory policy, it is recommended to start looking at those places to understand when and where
- * memory is allocated and freed.
- */
-
-#include <malloc.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <store.h>
-#include <gc.h>
-
-#define store_node_debug_fmt \
- "node{element_arity=%u, element_map=%08x, branch_arity=%u, branch_map=%08x, ref_count=%u}"
-#define store_node_debug_args(node) \
- node->element_arity, node->element_map, node->branch_arity, \
- node->branch_map, node->ref_count
-
-#define HASH_PARTITION_WIDTH 5u
-#define HASH_TOTAL_WIDTH (8 * sizeof(uint32_t))
-
-/*
- * Helper functions
- */
-
-static unsigned bitcount(uint32_t value)
-{
- // taken from http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
- value = value -
- ((value >> 1u) & 0x55555555u); // reuse input as temporary
- value = (value & 0x33333333u) + ((value >> 2u) & 0x33333333u); // temp
- return (((value + (value >> 4u)) & 0xF0F0F0Fu) * 0x1010101u) >>
- 24u; // count
-}
-
-static uint32_t store_mask(uint32_t hash, unsigned shift)
-{
- return (hash >> shift) & ((1u << HASH_PARTITION_WIDTH) - 1);
-}
-
-static unsigned store_index(uint32_t bitmap, uint32_t bitpos)
-{
- return bitcount(bitmap & (bitpos - 1));
-}
-
-/*
- * Data structure definitions
- */
-
-struct kv {
- STORE_KEY_T key;
- STORE_VALUE_T val;
-};
-
-#define STORE_NODE_ELEMENT_T struct kv
-#define STORE_NODE_BRANCH_T struct node *
-
-struct node {
- uint8_t element_arity;
- uint8_t branch_arity;
- uint16_t ref_count; // reference counting
- uint32_t element_map;
- uint32_t branch_map;
- STORE_NODE_ELEMENT_T content[];
-};
-
-struct collision_node {
- uint8_t element_arity; // MUST SHARE LAYOUT WITH struct node
- uint8_t branch_arity; // MUST SHARE LAYOUT WITH struct node
- uint16_t ref_count; // MUST SHARE LAYOUT WITH struct node // reference counting
- STORE_NODE_ELEMENT_T content[];
-};
-
-static struct node empty_node = {
- .branch_arity = 0,
- .element_arity = 0,
- .ref_count = 1,
- .branch_map = 0,
- .element_map = 0,
-};
-
-#define STORE_NODE_ELEMENTS(node) (node)->content
-#define STORE_NODE_BRANCHES(node) \
- ((STORE_NODE_BRANCH_T *)&(node)->content[(node)->element_arity])
-
-#define STORE_NODE_ELEMENTS_SIZE(length) \
- (sizeof(STORE_NODE_ELEMENT_T) * (length))
-#define STORE_NODE_BRANCHES_SIZE(length) \
- (sizeof(STORE_NODE_BRANCH_T) * (length))
-
-#define STORE_NODE_ELEMENT_AT(node, bitpos) \
- STORE_NODE_ELEMENTS(node)[store_index(node->element_map, bitpos)]
-#define STORE_NODE_BRANCH_AT(node, bitpos) \
- STORE_NODE_BRANCHES(node)[store_index(node->branch_map, bitpos)]
-
-/*
- * static function declarations
- */
-
-// node constructor
-static struct node *node_new(uint32_t element_map, uint32_t branch_map,
- STORE_NODE_ELEMENT_T const *elements,
- uint8_t element_arity,
- STORE_NODE_BRANCH_T const *branches,
- uint8_t branch_arity);
-
-// collision node variant
-static struct collision_node *
-collision_node_new(const STORE_NODE_ELEMENT_T *values, uint8_t element_arity);
-
-// destructor
-static void node_destroy(struct node *node);
-
-// reference counting
-static struct node *store_node_acquire(struct node *node);
-
-// reference counting
-static void store_node_release(struct node *node);
-
-// top-level functions
-static STORE_VALUE_T node_get(struct node *node, STORE_EQUALSFN_T(equals),
- STORE_KEY_T key, uint32_t hash, unsigned shift,
- int *found);
-
-static struct node *node_update(struct node *node, STORE_HASHFN_T(hashfn),
- STORE_EQUALSFN_T(equals), STORE_KEY_T key,
- STORE_VALUE_T value, uint32_t hash,
- unsigned shift, int *found);
-
-static struct node *node_assoc(struct node *node, STORE_HASHFN_T(hashfn),
- STORE_EQUALSFN_T(equals), STORE_KEY_T key,
- STORE_ASSOCFN_T(fn), void *user_data,
- uint32_t hash, unsigned shift, int *found);
-
-// collision node variants
-static STORE_VALUE_T collision_node_get(struct collision_node *node,
- STORE_EQUALSFN_T(equals),
- STORE_KEY_T key, int *found);
-
-static struct collision_node *
-collision_node_update(struct collision_node *node, STORE_EQUALSFN_T(equals),
- STORE_KEY_T key, STORE_VALUE_T value, int *found);
-
-static struct collision_node *collision_node_assoc(struct collision_node *node,
- STORE_EQUALSFN_T(equals),
- STORE_KEY_T key,
- STORE_ASSOCFN_T(fn),
- void *user_data, int *found);
-
-// helper functions for creation of modified nodes
-static struct node *node_merge(uint32_t hash_l, STORE_KEY_T key_l,
- STORE_VALUE_T value_l, uint32_t hash_r,
- STORE_KEY_T key_r, STORE_VALUE_T value_r,
- unsigned shift);
-
-static struct node *node_clone_update_branch(struct node *node, uint32_t bitpos,
- struct node *branch);
-
-static struct node *node_clone_pushdown(struct node *node, uint32_t bitpos,
- struct node *branch);
-
-static struct node *node_clone_insert_element(struct node *node,
- uint32_t bitpos, STORE_KEY_T key,
- STORE_VALUE_T value);
-
-static struct node *node_clone_update_element(struct node *node,
- uint32_t bitpos,
- STORE_VALUE_T value);
-
-// collision node variants
-static struct collision_node *
-collision_node_clone_insert_element(struct collision_node *node,
- STORE_KEY_T key, STORE_VALUE_T value);
-
-static struct collision_node *
-collision_node_clone_update_element(struct collision_node *node, unsigned index,
- STORE_VALUE_T value);
-
-// equality
-static int node_equals(struct node *left, struct node *right,
- STORE_EQUALSFN_T(key_equals),
- STORE_VALUE_EQUALSFN_T(value_equals), unsigned shift);
-
-static int collision_node_equals(struct collision_node *left,
- struct collision_node *right,
- STORE_EQUALSFN_T(key_equals),
- STORE_VALUE_EQUALSFN_T(value_equals));
-
-// store private constructor
-static struct store *store_from(struct node *root, unsigned length,
- STORE_HASHFN_T(hash), STORE_EQUALSFN_T(equals));
-
-// iterator helper functions
-static void iter_push(struct store_iter *iterator, struct node *node);
-
-static void iter_pop(struct store_iter *iterator);
-
-/*
- * definitions
- */
-
-static void node_destroy(struct node *node)
-{
- DEBUG_NOTICE(" destroying " store_node_debug_fmt "@%p\n",
- store_node_debug_args(node), (void *)node);
-
- GC_free(node);
-}
-
-// reference counting
-static struct node *store_node_acquire(struct node *node)
-{
- if (node == &empty_node)
- return node;
- node->ref_count++;
- return node;
-}
-
-// reference counting
-static void store_node_release(struct node *node)
-{
- if (node == &empty_node)
- return;
-
- if (node->ref_count-- == 1)
- node_destroy(node);
-}
-
-/**
- * WARNING: all branches in <code>branches</code> are "acquired", i.e. their reference count is incremented.
- * Do not pass an "almost correct" list of branches.
- */
-static struct node *node_new(uint32_t element_map, uint32_t branch_map,
- STORE_NODE_ELEMENT_T const *elements,
- uint8_t element_arity,
- STORE_NODE_BRANCH_T const *branches,
- uint8_t branch_arity)
-{
- const size_t content_size = STORE_NODE_ELEMENTS_SIZE(element_arity) +
- STORE_NODE_BRANCHES_SIZE(branch_arity);
- struct node *result = GC_malloc(sizeof(*result) + content_size);
-
- result->element_arity = element_arity;
- result->branch_arity = branch_arity;
- result->ref_count = 0;
- result->element_map = element_map;
- result->branch_map = branch_map;
-
- if (elements) {
- memcpy(STORE_NODE_ELEMENTS(result), elements,
- STORE_NODE_ELEMENTS_SIZE(element_arity));
- }
-
- STORE_NODE_BRANCH_T *branches_dest =
- (STORE_NODE_BRANCH_T *)STORE_NODE_BRANCHES(result);
- // reference counting
- for (int i = 0; i < branch_arity; ++i) {
- branches_dest[i] = store_node_acquire(branches[i]);
- }
-
- return result;
-}
-
-static STORE_VALUE_T collision_node_get(struct collision_node *node,
- STORE_EQUALSFN_T(equals),
- STORE_KEY_T key, int *found)
-{
- for (unsigned i = 0; i < node->element_arity; ++i) {
- struct kv kv = node->content[i];
- if (equals(kv.key, key)) {
- *found = 1;
- return kv.val;
- }
- }
-
- *found = 0;
- return (STORE_VALUE_T)0;
-}
-
-static STORE_VALUE_T node_get(struct node *node, STORE_EQUALSFN_T(equals),
- STORE_KEY_T key, uint32_t hash, unsigned shift,
- int *found)
-{
- if (shift >= HASH_TOTAL_WIDTH)
- return collision_node_get((struct collision_node *)node, equals,
- key, found);
-
- const uint32_t bitpos = 1u << store_mask(hash, shift);
-
- if (node->branch_map & bitpos) {
- return node_get(STORE_NODE_BRANCH_AT(node, bitpos), equals, key,
- hash, shift + HASH_PARTITION_WIDTH, found);
-
- } else if (node->element_map & bitpos) {
- STORE_NODE_ELEMENT_T kv = STORE_NODE_ELEMENT_AT(node, bitpos);
- if (equals(kv.key, key)) {
- *found = 1;
- return kv.val;
- }
- }
-
- *found = 0;
- return (STORE_VALUE_T)0;
-}
-
-static struct node *node_clone_insert_element(struct node *node,
- uint32_t bitpos, STORE_KEY_T key,
- STORE_VALUE_T value)
-{
- STORE_NODE_ELEMENT_T elements[1u << HASH_PARTITION_WIDTH];
- const unsigned index = store_index(node->element_map, bitpos);
-
- // copy <element_arity> chunks in total
- memcpy(elements, STORE_NODE_ELEMENTS(node),
- STORE_NODE_ELEMENTS_SIZE(index)); // copy first <index> chunks
- elements[index].key = (STORE_KEY_T)key;
- elements[index].val = (STORE_VALUE_T)value;
- memcpy(&elements[index + 1], // start copying into one-past-<index>
- &STORE_NODE_ELEMENTS(node)[index], // start copying from <index>
- STORE_NODE_ELEMENTS_SIZE(
- node->element_arity -
- index) // <index> chunks already copied, <element_arity> - <index> remaining
- );
-
- return node_new(node->element_map | bitpos, node->branch_map, elements,
- node->element_arity + 1, STORE_NODE_BRANCHES(node),
- node->branch_arity);
-}
-
-static struct node *node_clone_update_element(struct node *node,
- uint32_t bitpos,
- STORE_VALUE_T value)
-{
- STORE_NODE_ELEMENT_T elements[1u << HASH_PARTITION_WIDTH];
- const unsigned index = store_index(node->element_map, bitpos);
-
- memcpy(elements, STORE_NODE_ELEMENTS(node),
- STORE_NODE_ELEMENTS_SIZE(node->element_arity));
- elements[index].val = (STORE_VALUE_T)value;
- return node_new(node->element_map, node->branch_map, elements,
- node->element_arity, STORE_NODE_BRANCHES(node),
- node->branch_arity);
-}
-
-static struct node *node_clone_update_branch(struct node *node, uint32_t bitpos,
- struct node *branch)
-{
- STORE_NODE_BRANCH_T branches[1u << HASH_PARTITION_WIDTH];
- const unsigned index = store_index(node->branch_map, bitpos);
-
- memcpy(branches, STORE_NODE_BRANCHES(node),
- STORE_NODE_BRANCHES_SIZE(node->branch_arity));
- branches[index] = branch;
- return node_new(node->element_map, node->branch_map,
- STORE_NODE_ELEMENTS(node), node->element_arity,
- branches, node->branch_arity);
-}
-
-static struct node *node_clone_pushdown(struct node *node, uint32_t bitpos,
- struct node *branch)
-{
- STORE_NODE_ELEMENT_T elements[1u << HASH_PARTITION_WIDTH];
- STORE_NODE_BRANCH_T branches[1u << HASH_PARTITION_WIDTH];
- const unsigned element_index = store_index(node->element_map, bitpos);
- const unsigned branch_index = store_index(node->branch_map, bitpos);
-
- memcpy(elements, STORE_NODE_ELEMENTS(node),
- STORE_NODE_ELEMENTS_SIZE(element_index));
- memcpy(&elements[element_index],
- &STORE_NODE_ELEMENTS(node)[element_index + 1],
- STORE_NODE_ELEMENTS_SIZE(node->element_arity -
- (element_index + 1)));
-
- memcpy(branches, STORE_NODE_BRANCHES(node),
- STORE_NODE_BRANCHES_SIZE(branch_index));
- memcpy(&branches[branch_index + 1],
- &STORE_NODE_BRANCHES(node)[branch_index],
- STORE_NODE_BRANCHES_SIZE(node->branch_arity - branch_index));
- branches[branch_index] = branch;
-
- return node_new(node->element_map & ~bitpos, node->branch_map | bitpos,
- elements, node->element_arity - 1, branches,
- node->branch_arity + 1);
-}
-
-static struct collision_node *
-collision_node_new(const STORE_NODE_ELEMENT_T *values, uint8_t element_arity)
-{
- size_t content_size = sizeof(STORE_NODE_ELEMENT_T) * element_arity;
- struct collision_node *result =
- GC_malloc(sizeof(*result) + content_size);
-
- result->element_arity = element_arity;
- result->branch_arity = 0;
- result->ref_count = 0;
-
- memcpy(result->content, values,
- STORE_NODE_ELEMENTS_SIZE(element_arity));
-
- return result;
-}
-
-static struct node *node_merge(uint32_t hash_l, STORE_KEY_T key_l,
- STORE_VALUE_T value_l, uint32_t hash_r,
- STORE_KEY_T key_r, STORE_VALUE_T value_r,
- unsigned shift)
-{
- uint32_t bitpos_l = 1u << store_mask(hash_l, shift);
- uint32_t bitpos_r = 1u << store_mask(hash_r, shift);
-
- if (shift >= HASH_TOTAL_WIDTH) {
- STORE_NODE_ELEMENT_T elements[2];
- elements[0].key = (STORE_KEY_T)key_l;
- elements[0].val = (STORE_VALUE_T)value_l;
- elements[1].key = (STORE_KEY_T)key_r;
- elements[1].val = (STORE_VALUE_T)value_r;
-
- return (struct node *)collision_node_new(elements, 2);
-
- } else if (bitpos_l != bitpos_r) {
- STORE_NODE_ELEMENT_T elements[2];
-
- if (bitpos_l <= bitpos_r) {
- elements[0].key = (STORE_KEY_T)key_l;
- elements[0].val = (STORE_VALUE_T)value_l;
- elements[1].key = (STORE_KEY_T)key_r;
- elements[1].val = (STORE_VALUE_T)value_r;
- } else {
- elements[0].key = (STORE_KEY_T)key_r;
- elements[0].val = (STORE_VALUE_T)value_r;
- elements[1].key = (STORE_KEY_T)key_l;
- elements[1].val = (STORE_VALUE_T)value_l;
- }
-
- return node_new(bitpos_l | bitpos_r, 0u, elements, 2, NULL, 0);
-
- } else {
- struct node *sub_node =
- node_merge(hash_l, key_l, value_l, hash_r, key_r,
- value_r, shift + HASH_PARTITION_WIDTH);
-
- return node_new(0, bitpos_l, NULL, 0, &sub_node, 1);
- }
-}
-
-static struct collision_node *
-collision_node_clone_update_element(struct collision_node *node, unsigned index,
- STORE_VALUE_T value)
-{
- STORE_NODE_ELEMENT_T elements[node->element_arity];
-
- memcpy(elements, node->content,
- STORE_NODE_ELEMENTS_SIZE(node->element_arity));
- elements[index].val = (STORE_VALUE_T)value;
-
- return collision_node_new(elements, node->element_arity);
-}
-
-static struct collision_node *
-collision_node_clone_insert_element(struct collision_node *node,
- STORE_KEY_T key, STORE_VALUE_T value)
-{
- STORE_NODE_ELEMENT_T elements[node->element_arity + 1];
-
- memcpy(elements, node->content,
- STORE_NODE_ELEMENTS_SIZE(node->element_arity));
- elements[node->element_arity].key = (STORE_KEY_T)key;
- elements[node->element_arity].val = (STORE_VALUE_T)value;
-
- return collision_node_new(elements, node->element_arity + 1);
-}
-
-static struct collision_node *
-collision_node_update(struct collision_node *node, STORE_EQUALSFN_T(equals),
- STORE_KEY_T key, STORE_VALUE_T value, int *found)
-{
- for (unsigned i = 0; i < node->element_arity; ++i) {
- struct kv kv = node->content[i];
- if (equals(kv.key, key)) {
- *found = 1;
-
- return collision_node_clone_update_element(node, i,
- value);
- }
- }
-
- return collision_node_clone_insert_element(node, key, value);
-}
-
-static struct node *node_update(struct node *node, STORE_HASHFN_T(hashfn),
- STORE_EQUALSFN_T(equals), STORE_KEY_T key,
- STORE_VALUE_T value, uint32_t hash,
- unsigned shift, int *found)
-{
- if (shift >= HASH_TOTAL_WIDTH)
- return (struct node *)collision_node_update(
- (struct collision_node *)node, equals, key, value,
- found);
-
- const uint32_t bitpos = 1u << store_mask(hash, shift);
-
- if (node->branch_map & bitpos) {
- struct node *sub_node = STORE_NODE_BRANCH_AT(node, bitpos);
- struct node *new_sub_node =
- node_update(sub_node, hashfn, equals, key, value, hash,
- shift + HASH_PARTITION_WIDTH, found);
- return node_clone_update_branch(node, bitpos, new_sub_node);
-
- } else if (node->element_map & bitpos) {
- STORE_KEY_T current_key =
- STORE_NODE_ELEMENT_AT(node, bitpos).key;
-
- if (equals(current_key, key)) {
- *found = 1;
- return node_clone_update_element(node, bitpos, value);
-
- } else {
- STORE_VALUE_T current_value =
- STORE_NODE_ELEMENT_AT(node, bitpos).val;
- struct node *sub_node =
- node_merge(hashfn(current_key), current_key,
- current_value, hashfn(key), key,
- value, shift + HASH_PARTITION_WIDTH);
- return node_clone_pushdown(node, bitpos, sub_node);
- }
-
- } else {
- return node_clone_insert_element(node, bitpos, key, value);
- }
-}
-
-static struct collision_node *collision_node_assoc(struct collision_node *node,
- STORE_EQUALSFN_T(equals),
- STORE_KEY_T key,
- STORE_ASSOCFN_T(fn),
- void *user_data, int *found)
-{
- STORE_VALUE_T new_value;
- for (unsigned i = 0; i < node->element_arity; ++i) {
- struct kv kv = node->content[i];
- if (equals(kv.key, key)) {
- *found = 1;
- STORE_VALUE_T old_value = kv.val;
- new_value = fn(key, old_value, user_data);
- return collision_node_clone_update_element(node, i,
- new_value);
- }
- }
-
- new_value = fn((STORE_KEY_T)0, (STORE_VALUE_T)0, user_data);
- return collision_node_clone_insert_element(node, key, new_value);
-}
-
-static struct node *node_assoc(struct node *node, STORE_HASHFN_T(hashfn),
- STORE_EQUALSFN_T(equals), STORE_KEY_T key,
- STORE_ASSOCFN_T(fn), void *user_data,
- uint32_t hash, unsigned shift, int *found)
-{
- if (shift >= HASH_TOTAL_WIDTH)
- return (struct node *)collision_node_assoc(
- (struct collision_node *)node, equals, key, fn,
- user_data, found);
-
- const uint32_t bitpos = 1u << store_mask(hash, shift);
-
- if (node->branch_map & bitpos) {
- struct node *sub_node = STORE_NODE_BRANCH_AT(node, bitpos);
- struct node *new_sub_node =
- node_assoc(sub_node, hashfn, equals, key, fn, user_data,
- hash, shift + HASH_PARTITION_WIDTH, found);
- return node_clone_update_branch(node, bitpos, new_sub_node);
-
- } else if (node->element_map & bitpos) {
- STORE_KEY_T current_key =
- STORE_NODE_ELEMENT_AT(node, bitpos).key;
-
- if (equals(current_key, key)) {
- *found = 1;
- STORE_VALUE_T old_value =
- STORE_NODE_ELEMENT_AT(node, bitpos).val;
- STORE_VALUE_T new_value = fn(key, old_value, user_data);
- return node_clone_update_element(node, bitpos,
- new_value);
-
- } else {
- STORE_VALUE_T current_value =
- STORE_NODE_ELEMENT_AT(node, bitpos).val;
- STORE_VALUE_T new_value =
- fn((STORE_KEY_T)0, (STORE_VALUE_T)0, user_data);
- struct node *sub_node =
- node_merge(hashfn(current_key), current_key,
- current_value, hash, key, new_value,
- shift + HASH_PARTITION_WIDTH);
- return node_clone_pushdown(node, bitpos, sub_node);
- }
-
- } else {
- STORE_VALUE_T value =
- fn((STORE_KEY_T)0, (STORE_VALUE_T)0, user_data);
- return node_clone_insert_element(node, bitpos, key, value);
- }
-}
-
-static int collision_node_equals(struct collision_node *left,
- struct collision_node *right,
- STORE_EQUALSFN_T(key_equals),
- STORE_VALUE_EQUALSFN_T(value_equals))
-{
- if (left == right)
- return 1;
- if (left->element_arity != right->element_arity)
- return 0;
-
- for (unsigned left_i = 0; left_i < left->element_arity; ++left_i) {
- struct kv left_element = STORE_NODE_ELEMENTS(left)[left_i];
-
- for (unsigned right_i = 0; right_i < right->element_arity;
- ++right_i) {
- struct kv right_element =
- STORE_NODE_ELEMENTS(right)[right_i];
-
- if (key_equals(left_element.key, right_element.key) &&
- value_equals(left_element.val, right_element.val))
- goto found_matching_element;
- }
- return 0; // compared left_element to all elements in right node, no match.
-
- found_matching_element:
- continue;
- }
- return 1; // compared all elements in left node, never had an element without match.
-}
-
-static int node_equals(struct node *left, struct node *right,
- STORE_EQUALSFN_T(key_equals),
- STORE_VALUE_EQUALSFN_T(value_equals), unsigned shift)
-{
- if (shift >= HASH_TOTAL_WIDTH)
- return collision_node_equals((struct collision_node *)left,
- (struct collision_node *)right,
- key_equals, value_equals);
- if (left == right)
- return 1;
- if (left->element_map != right->element_map)
- return 0;
- if (left->branch_map != right->branch_map)
- return 0;
- for (unsigned i = 0; i < left->element_arity; ++i) {
- struct kv left_element = STORE_NODE_ELEMENTS(left)[i];
- struct kv right_element = STORE_NODE_ELEMENTS(right)[i];
- if (!key_equals(left_element.key, right_element.key) ||
- !value_equals(left_element.val, right_element.val))
- return 0;
- }
- for (unsigned i = 0; i < left->branch_arity; ++i) {
- struct node *left_branch = STORE_NODE_BRANCHES(left)[i];
- struct node *right_branch = STORE_NODE_BRANCHES(right)[i];
- if (!node_equals(left_branch, right_branch, key_equals,
- value_equals, shift + HASH_PARTITION_WIDTH))
- return 0;
- }
- return 1;
-}
-
-static struct store *store_from(struct node *root, unsigned length,
- STORE_HASHFN_T(hash), STORE_EQUALSFN_T(equals))
-{
- struct store *result = GC_malloc(sizeof(*result));
- result->ref_count = 0;
- result->root = root;
- result->length = length;
- result->hash = hash;
- result->equals = equals;
- return result;
-}
-
-void store_destroy(struct store **store)
-{
- DEBUG_NOTICE("destroying store@%p\n", (void *)*store);
-
- store_node_release((*store)->root);
- GC_free(*store);
- *store = NULL;
-}
-
-struct store *store_new(STORE_HASHFN_T(hash), STORE_EQUALSFN_T(equals))
-{
- return store_from((struct node *)&empty_node, 0, hash, equals);
-}
-
-struct store *store_acquire(struct store *store)
-{
- store->ref_count++;
- DEBUG_NOTICE("ACQ %p: %d\n", (void *)store, store->ref_count);
- return store;
-}
-
-void store_release(struct store **store)
-{
- DEBUG_NOTICE("REL %p: %d\n", (void *)*store, (*store)->ref_count - 1);
- if ((*store)->ref_count-- == 1)
- store_destroy(store);
-}
-
-struct store *store_of(STORE_HASHFN_T(hash), STORE_EQUALSFN_T(equals),
- STORE_KEY_T *keys, STORE_VALUE_T *values, size_t length)
-{
- struct store *result = store_new(hash, equals);
- while (length--) {
- struct store *tmp =
- store_set(result, keys[length], values[length], NULL);
- store_destroy(&result);
- result = tmp;
- }
- return result;
-}
-
-unsigned store_length(const struct store *store)
-{
- return store->length;
-}
-
-struct store *store_set(const struct store *store, STORE_KEY_T key,
- STORE_VALUE_T value, int *replaced)
-{
- const uint32_t hash = store->hash(key);
- int found = 0;
- int *found_p = replaced ? replaced : &found;
- *found_p = 0;
- struct node *new_root = store_node_acquire(
- node_update(store->root, store->hash, store->equals, key, value,
- hash, 0, found_p));
- return store_from(new_root, store->length + (*found_p ? 0 : 1),
- store->hash, store->equals);
-}
-
-STORE_VALUE_T store_get(const struct store *store, STORE_KEY_T key, int *found)
-{
- uint32_t hash = store->hash(key);
- int tmp = 0;
- return node_get(store->root, store->equals, key, hash, 0,
- found ? found : &tmp);
-}
-
-struct store *store_assoc(const struct store *store, STORE_KEY_T key,
- STORE_ASSOCFN_T(fn), void *user_data)
-{
- const uint32_t hash = store->hash(key);
- int found = 0;
- struct node *new_root = store_node_acquire(
- node_assoc(store->root, store->hash, store->equals, key, fn,
- user_data, hash, 0, &found));
- return store_from(new_root, store->length + (found ? 0 : 1),
- store->hash, store->equals);
-}
-
-int store_equals(const struct store *left, const struct store *right,
- STORE_VALUE_EQUALSFN_T(value_equals))
-{
- if (left == right)
- return 1;
- else if (store_length(left) != store_length(right))
- return 0;
- else
- return node_equals(left->root, right->root, left->equals,
- value_equals, 0);
-}
-
-void store_iter_init(struct store_iter *iterator, const struct store *store)
-{
- iterator->stack_level = 0;
- iterator->element_cursor = 0;
- iterator->element_arity = store->root->element_arity;
- iterator->branch_cursor_stack[0] = 0;
- iterator->branch_arity_stack[0] = store->root->branch_arity;
- iterator->node_stack[0] = store->root;
-}
-
-static void iter_push(struct store_iter *iterator, struct node *node)
-{
- iterator->stack_level += 1;
- iterator->element_cursor = 0;
- iterator->element_arity = node->element_arity;
- iterator->branch_cursor_stack[iterator->stack_level] = 0;
- iterator->branch_arity_stack[iterator->stack_level] =
- node->branch_arity;
- iterator->node_stack[iterator->stack_level] = node;
-}
-
-static void iter_pop(struct store_iter *iterator)
-{
- iterator->stack_level -= 1;
-}
-
-int store_iter_next(struct store_iter *iterator, STORE_KEY_T *key,
- STORE_VALUE_T *value)
-{
- if (iterator->stack_level == -1)
- return 0;
-
- struct node *current_node = iterator->node_stack[iterator->stack_level];
- unsigned *branch_cursor =
- iterator->branch_cursor_stack + iterator->stack_level;
- if (*branch_cursor == 0 &&
- iterator->element_cursor <
- current_node->element_arity) { // todo: write test for this
- *key = STORE_NODE_ELEMENTS(
- current_node)[iterator->element_cursor]
- .key;
- *value = STORE_NODE_ELEMENTS(
- current_node)[iterator->element_cursor]
- .val;
- ++iterator->element_cursor;
- return 1;
-
- } else {
- if (*branch_cursor <
- iterator->branch_arity_stack[iterator->stack_level]) {
- iter_push(iterator,
- STORE_NODE_BRANCHES(
- current_node)[*branch_cursor]);
- ++*branch_cursor;
- return store_iter_next(iterator, key, value);
-
- } else {
- iter_pop(iterator);
- return store_iter_next(iterator, key, value);
- }
- }
-}
diff --git a/src/term.c b/src/term.c
deleted file mode 100644
index cf66f01..0000000
--- a/src/term.c
+++ /dev/null
@@ -1,243 +0,0 @@
-// Copyright (c) 2023, Marvin Borner <dev@marvinborner.de>
-
-#include <stdlib.h>
-#include <assert.h>
-#include <stdio.h>
-
-#include <term.h>
-#include <gc.h>
-
-static int name_generator(void)
-{
- static int current = 0x4242; // TODO: idk?
- return current++;
-}
-
-#define MAX_CONVERSION_VARS 256
-static void to_barendregt_helper(struct term *term, int *vars, int size)
-{
- assert(size < MAX_CONVERSION_VARS);
- switch (term->type) {
- case ABS:
- vars[size] = name_generator();
- term->u.abs.name = vars[size];
- to_barendregt_helper(term->u.abs.term, vars, size + 1);
- break;
- case APP:
- to_barendregt_helper(term->u.app.lhs, vars, size);
- to_barendregt_helper(term->u.app.rhs, vars, size);
- break;
- case VAR:
- if (term->u.var.type == BARENDREGT_VARIABLE)
- break;
- int ind = size - term->u.var.name - 1;
- if (ind < 0) {
- fprintf(stderr, "Unbound variable %d\n",
- term->u.var.name);
- term->u.var.name = name_generator();
- } else {
- term->u.var.name = vars[size - term->u.var.name - 1];
- }
- term->u.var.type = BARENDREGT_VARIABLE;
- break;
- default:
- fprintf(stderr, "Invalid type %d\n", term->type);
- }
-}
-
-static void to_bruijn_helper(struct term *term, int *vars, int size)
-{
- assert(size < MAX_CONVERSION_VARS);
- switch (term->type) {
- case ABS:
- vars[size] = term->u.abs.name;
- to_bruijn_helper(term->u.abs.term, vars, size + 1);
- term->u.abs.name = 0;
- break;
- case APP:
- to_bruijn_helper(term->u.app.lhs, vars, size);
- to_bruijn_helper(term->u.app.rhs, vars, size);
- break;
- case VAR:
- if (term->u.var.type == BRUIJN_INDEX)
- break;
- int ind = -1;
- for (int i = 0; i < size; i++) {
- if (vars[i] == term->u.var.name) {
- ind = i;
- break;
- }
- }
- if (ind < 0) {
- fprintf(stderr, "Unbound variable %d\n",
- term->u.var.name);
- }
- term->u.var.name = size - ind - 1;
- term->u.var.type = BRUIJN_INDEX;
- break;
- default:
- fprintf(stderr, "Invalid type %d\n", term->type);
- }
-}
-
-void to_barendregt(struct term *term)
-{
- int vars[MAX_CONVERSION_VARS] = { 0 };
- to_barendregt_helper(term, vars, 0);
-}
-
-void to_bruijn(struct term *term)
-{
- int vars[MAX_CONVERSION_VARS] = { 0 };
- to_bruijn_helper(term, vars, 0);
-}
-
-struct term *new_term(term_type type)
-{
- struct term *term = GC_malloc(sizeof(*term));
- if (!term) {
- fprintf(stderr, "Out of memory!\n");
- abort();
- }
- term->type = type;
- return term;
-}
-
-struct term *duplicate_term(struct term *term)
-{
- switch (term->type) {
- case ABS:;
- struct term *abs = new_term(ABS);
- abs->u.abs.name = term->u.abs.name;
- abs->u.abs.term = duplicate_term(term->u.abs.term);
- return abs;
- case APP:;
- struct term *app = new_term(APP);
- app->u.app.lhs = duplicate_term(term->u.app.lhs);
- app->u.app.rhs = duplicate_term(term->u.app.rhs);
- return app;
- case VAR:;
- struct term *var = new_term(VAR);
- var->u.var.name = term->u.var.name;
- var->u.var.type = term->u.var.type;
- return var;
- default:
- fprintf(stderr, "Invalid type %d\n", term->type);
- }
- return term;
-}
-
-int alpha_equivalency(struct term *a, struct term *b)
-{
- if (a->type != b->type)
- return 0;
-
- switch (a->type) {
- case ABS:
- assert(!a->u.abs.name); // TODO: Only bruijn right now
- return a->u.abs.name == b->u.abs.name &&
- alpha_equivalency(a->u.abs.term, b->u.abs.term);
- case APP:
- return alpha_equivalency(a->u.app.lhs, b->u.app.lhs) &&
- alpha_equivalency(a->u.app.rhs, b->u.app.rhs);
- case VAR:;
- assert(a->u.var.type == BRUIJN_INDEX &&
- b->u.var.type == BRUIJN_INDEX);
- return a->u.var.name == b->u.var.name;
- default:
- fprintf(stderr, "Invalid type %d\n", a->type);
- }
- return 0;
-}
-
-void free_term(struct term *term)
-{
- switch (term->type) {
- case ABS:
- free_term(term->u.abs.term);
- GC_free(term);
- break;
- case APP:
- free_term(term->u.app.lhs);
- free_term(term->u.app.rhs);
- GC_free(term);
- break;
- case VAR:
- GC_free(term);
- break;
- default:
- fprintf(stderr, "Invalid type %d\n", term->type);
- }
-}
-
-void print_term(struct term *term)
-{
- switch (term->type) {
- case ABS:
- if (term->u.abs.name)
- printf("[{%d} ", term->u.abs.name);
- else
- printf("[");
- print_term(term->u.abs.term);
- printf("]");
- break;
- case APP:
- printf("(");
- print_term(term->u.app.lhs);
- printf(" ");
- print_term(term->u.app.rhs);
- printf(")");
- break;
- case VAR:
- printf("%d", term->u.var.name);
- break;
- default:
- fprintf(stderr, "Invalid type %d\n", term->type);
- }
-}
-
-void print_blc(struct term *term)
-{
- switch (term->type) {
- case ABS:
- printf("00");
- print_blc(term->u.abs.term);
- break;
- case APP:
- printf("01");
- print_blc(term->u.app.lhs);
- print_blc(term->u.app.rhs);
- break;
- case VAR:
- assert(term->u.var.type == BRUIJN_INDEX);
- for (int i = 0; i <= term->u.var.name; i++)
- printf("1");
- printf("0");
- break;
- default:
- fprintf(stderr, "Invalid type %d\n", term->type);
- }
-}
-
-void print_scheme(struct term *term)
-{
- switch (term->type) {
- case ABS:
- printf("(*lam \"%d\" ", term->u.abs.name);
- print_scheme(term->u.abs.term);
- printf(")");
- break;
- case APP:
- printf("(*app ");
- print_scheme(term->u.app.lhs);
- printf(" ");
- print_scheme(term->u.app.rhs);
- printf(")");
- break;
- case VAR:
- printf("(*var \"%d\")", term->u.var.name);
- break;
- default:
- fprintf(stderr, "Invalid type %d\n", term->type);
- }
-}
diff --git a/src/test.c b/src/test.c
deleted file mode 100644
index 9c2ecc3..0000000
--- a/src/test.c
+++ /dev/null
@@ -1,273 +0,0 @@
-// Copyright (c) 2023, Marvin Borner <dev@marvinborner.de>
-
-#ifdef TEST
-#ifndef NTESTS
-#define NTESTS 6
-#endif
-
-#ifndef STARTTEST
-#define STARTTEST 0
-#endif
-
-#define TESTDIR "./tests/"
-
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-#include <time.h>
-
-#include <gc.h>
-#include <parse.h>
-#include <term.h>
-#include <reduce.h>
-
-struct test {
- struct term *in;
- struct term *res;
- struct term *red;
- char *trans;
- struct {
- int alpha;
- int trans;
- } equivalency;
-};
-
-static int name_generator(void)
-{
- static int current = 0xbadbad;
- return current++;
-}
-
-static void *church(int n, void(*f(void *, int)), void *x, int name)
-{
- if (n == 0)
- return x;
- return church(n - 1, f, f(x, name), name);
-}
-
-static void *church_numeral_builder(void *x, int name)
-{
- struct term *app = new_term(APP);
- app->u.app.lhs = new_term(VAR);
- app->u.app.lhs->u.var.name = name;
- app->u.app.lhs->u.var.type = BARENDREGT_VARIABLE;
- app->u.app.rhs = x;
- return app;
-}
-
-static struct term *church_numeral(int n)
-{
- struct term *abs = new_term(ABS);
- abs->u.abs.name = name_generator();
- abs->u.abs.term = new_term(ABS);
-
- struct term *var = new_term(VAR);
- var->u.var.name = name_generator();
- var->u.var.type = BARENDREGT_VARIABLE;
-
- abs->u.abs.term->u.abs.name = var->u.var.name;
- abs->u.abs.term->u.abs.term =
- church(n, church_numeral_builder, var, abs->u.abs.name);
-
- return abs;
-}
-
-static struct term *identity(void)
-{
- struct term *abs = new_term(ABS);
- abs->u.abs.name = name_generator();
- abs->u.abs.term = new_term(VAR);
- abs->u.abs.term->u.var.name = abs->u.abs.name;
- abs->u.abs.term->u.var.type = BARENDREGT_VARIABLE;
- return abs;
-}
-
-static struct term *omega(void)
-{
- struct term *abs = new_term(ABS);
- abs->u.abs.name = name_generator();
- abs->u.abs.term = new_term(APP);
- abs->u.abs.term->u.app.lhs = new_term(VAR);
- abs->u.abs.term->u.app.lhs->u.var.name = abs->u.abs.name;
- abs->u.abs.term->u.app.lhs->u.var.type = BARENDREGT_VARIABLE;
- abs->u.abs.term->u.app.rhs = new_term(VAR);
- abs->u.abs.term->u.app.rhs->u.var.name = abs->u.abs.name;
- abs->u.abs.term->u.app.rhs->u.var.type = BARENDREGT_VARIABLE;
- return abs;
-}
-
-static void counter_callback(int i, char ch, void *data)
-{
- (void)ch;
- *(int *)data = i;
-}
-
-static void test_church_transitions(void)
-{
- const int limit = 18;
-
- int deviations = 0;
- double time = 0;
-
- for (int n = 1; n <= limit; n++) {
- struct term *app = new_term(APP);
- app->u.app.lhs = new_term(APP);
- app->u.app.lhs->u.app.lhs = church_numeral(n);
- app->u.app.lhs->u.app.rhs = church_numeral(2);
- app->u.app.rhs = identity();
- int counter;
-
- clock_t begin = clock();
- struct term *red = reduce(app, counter_callback, &counter);
- clock_t end = clock();
- time += (double)(end - begin) / CLOCKS_PER_SEC;
-
- free_term(red);
- free_term(app);
-
- int expected = 10 * (2 << (n - 1)) + n * 5 + 5;
- if (counter + 1 != expected)
- deviations++;
- }
-
- printf("Test church ((n 2) I) with n<=%d: %.5fs, %d transition deviations\n",
- limit, time, deviations);
-}
-
-static void test_explode(void)
-{
- const int limit = 23;
-
- int deviations = 0;
- double time = 0;
-
- for (int n = 1; n <= limit; n++) {
- struct term *abs = new_term(ABS);
- abs->u.abs.name = name_generator();
- abs->u.abs.term = new_term(APP);
- abs->u.abs.term->u.app.lhs = new_term(APP);
- abs->u.abs.term->u.app.lhs->u.app.lhs = church_numeral(n);
- abs->u.abs.term->u.app.lhs->u.app.rhs = omega();
- abs->u.abs.term->u.app.rhs = new_term(VAR);
- abs->u.abs.term->u.app.rhs->u.var.name = abs->u.abs.name;
- abs->u.abs.term->u.app.rhs->u.var.type = BARENDREGT_VARIABLE;
-
- int counter;
-
- clock_t begin = clock();
- struct term *red = reduce(abs, counter_callback, &counter);
- clock_t end = clock();
- time += (double)(end - begin) / CLOCKS_PER_SEC;
-
- free_term(red);
- free_term(abs);
-
- int expected = 9 * n + 15;
- if (counter + 1 != expected)
- deviations++;
- }
-
- printf("Test explode (λx.((n ω) x)) with n<=%d: %.5fs, %d transition deviations\n",
- limit, time, deviations);
-}
-
-static char *read_file(const char *path)
-{
- FILE *f = fopen(path, "rb");
- if (!f) {
- fprintf(stderr, "Can't open file %s: %s\n", path,
- strerror(errno));
- return 0;
- }
- fseek(f, 0, SEEK_END);
- long fsize = ftell(f);
- fseek(f, 0, SEEK_SET);
-
- char *string = malloc(fsize + 1);
- int ret = fread(string, fsize, 1, f);
- fclose(f);
-
- if (ret != 1) {
- fprintf(stderr, "Can't read file %s: %s\n", path,
- strerror(errno));
- return 0;
- }
-
- string[fsize] = 0;
- return string;
-}
-
-static void callback(int i, char ch, void *data)
-{
- struct test *test = data;
- if (ch != test->trans[i]) {
- fprintf(stderr, "Transition deviation at index %d!\n", i);
- test->equivalency.trans = 0;
- }
-}
-
-int main(void)
-{
- GC_INIT();
- GC_enable_incremental();
-
- struct test tests[NTESTS] = { 0 };
-
- char in_template[] = TESTDIR "x.in";
- char red_template[] = TESTDIR "x.red";
- char trans_template[] = TESTDIR "x.trans";
- int offset = strlen(TESTDIR);
- for (int i = 0; i < NTESTS; i++) {
- char ch = '0' + i + 1 + STARTTEST;
- in_template[offset] = ch;
- red_template[offset] = ch;
- trans_template[offset] = ch;
- tests[i].trans = read_file(trans_template);
-
- char *in = read_file(in_template);
- tests[i].in = parse_bruijn(in);
- free(in);
-
- char *red = read_file(red_template);
- tests[i].red = parse_bruijn(red);
- to_bruijn(tests[i].red);
- free(red);
-
- tests[i].equivalency.trans = 1;
- }
-
- clock_t begin = clock();
- for (int i = 0; i < NTESTS; i++) {
- tests[i].res = reduce(tests[i].in, callback, &tests[i]);
- printf("Test %d done\n", i + 1 + STARTTEST);
- }
- clock_t end = clock();
-
- for (int i = 0; i < NTESTS; i++) {
- to_bruijn(tests[i].res);
- tests[i].equivalency.alpha =
- alpha_equivalency(tests[i].res, tests[i].red);
- free_term(tests[i].res);
- free_term(tests[i].red);
- free(tests[i].trans);
- }
-
- printf("\n=== REDUCTION SUMMARY ===\n");
- printf("Reduced tests in %.5fs\n",
- (double)(end - begin) / CLOCKS_PER_SEC);
- for (int i = 0; i < NTESTS; i++) {
- if (tests[i].equivalency.alpha && tests[i].equivalency.trans)
- continue;
- printf("Test %d: [failed]\n\talpha-equivalency: %d\n\ttrans-equivalency: %d\n",
- i + 1 + STARTTEST, tests[i].equivalency.alpha,
- tests[i].equivalency.trans);
- }
-
- printf("\n=== OTHER TESTS ===\n");
- test_church_transitions();
- test_explode();
-}
-#else
-__attribute__((unused)) static int no_testing;
-#endif