From 821939c6a6eb5761708146783ebd562422c2a7f7 Mon Sep 17 00:00:00 2001
From: Camil Staps
Date: Thu, 25 Aug 2016 20:29:50 +0200
Subject: pedantic

---
 interpreter/eval.c | 258 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 258 insertions(+)
 create mode 100644 interpreter/eval.c

(limited to 'interpreter/eval.c')

diff --git a/interpreter/eval.c b/interpreter/eval.c
new file mode 100644
index 0000000..fb07e92
--- /dev/null
+++ b/interpreter/eval.c
@@ -0,0 +1,258 @@
+#include "eval.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "mem.h"
+#include "print.h"
+
+void free_rules_until(fuspel* new, fuspel* old) {
+	while (new != old) {
+		fuspel* _new = new->rest;
+		free_rewrite_rule(&new->rule);
+		my_free(new);
+		new = _new;
+	}
+}
+
+typedef struct replacements {
+	char* what;
+	expression* with;
+	struct replacements* rest;
+} replacements;
+
+void replace(char* name, expression* new, expression* expr) {
+	if (!expr)
+		return;
+
+	switch (expr->kind) {
+		case EXPR_NAME:
+			if (!strcmp(expr->var1, name)) {
+				cpy_expression(expr, new);
+				break;
+			}
+		case EXPR_INT:
+			break;
+		case EXPR_TUPLE:
+		case EXPR_LIST:
+		case EXPR_APP:
+			replace(name, new, expr->var1);
+			replace(name, new, expr->var2);
+			break;
+	}
+}
+
+void replace_all(replacements* repls, expression* expr) {
+	while (repls) {
+		replace(repls->what, repls->with, expr);
+		repls = repls->rest;
+	}
+}
+
+replacements* push_replacement(char* what, expression* with, replacements* rest) {
+	replacements* new = my_calloc(1, sizeof(replacements));
+	new->what = what;
+	new->with = my_calloc(1, sizeof(expression));
+	cpy_expression(new->with, with);
+	new->rest = rest;
+	return new;
+}
+
+void free_replacements(replacements* repls) {
+	if (repls) {
+		free_replacements(repls->rest);
+		repls->rest = NULL;
+		free_expression(repls->with);
+		my_free(repls->with);
+		my_free(repls);
+	}
+}
+
+unsigned match_expr(fuspel* rules, expression* to_match, expression* expr,
+		replacements** repls) {
+	unsigned matches;
+
+	if (to_match->kind != EXPR_NAME) {
+		expr = eval_rnf(rules, expr);
+		if (!expr)
+			return 0;
+	}
+
+	switch (to_match->kind) {
+		case EXPR_NAME:
+			*repls = push_replacement(to_match->var1, expr, *repls);
+			free_expression(expr);
+			my_free(expr);
+			return 1;
+		case EXPR_INT:
+			matches = eq_expression(to_match, expr);
+			free_expression(expr);
+			my_free(expr);
+			return matches;
+		case EXPR_LIST:
+			if (!to_match->var1) {
+				matches = eq_expression(to_match, expr);
+				free_expression(expr);
+				my_free(expr);
+				return matches;
+			}
+		case EXPR_TUPLE:
+			if (to_match->kind != expr->kind) {
+				free_expression(expr);
+				my_free(expr);
+				return 0;
+			}
+			matches =
+				match_expr(rules, to_match->var1, expr->var1, repls) &&
+				match_expr(rules, to_match->var2, expr->var2, repls);
+			free_expression(expr);
+			my_free(expr);
+			return matches;
+		default:
+			free_expression(expr);
+			my_free(expr);
+			return 0;
+	}
+}
+
+unsigned match_rule(fuspel* rules, rewrite_rule* rule, expression* expr,
+		replacements** repls) {
+	expression** expr_args;
+	unsigned char i;
+
+	switch (expr->kind) {
+		case EXPR_NAME:
+			return (!strcmp(expr->var1, rule->name) &&
+				empty_args_list(rule->args)) ? 1 : 0;
+		case EXPR_APP:
+			expr_args = flatten_app_args(expr);
+			i = 0;
+			if (!strcmp(expr_args[0]->var1, rule->name)) {
+				expression* _expr = expr_args[++i];
+				arg_list* args = rule->args;
+				fuspel* _rules = rules;
+				while (!empty_args_list(args)) {
+					if (!match_expr(_rules, &args->elem, _expr, repls)) {
+						free_rules_until(_rules, rules);
+						my_free(expr_args);
+						return 0;
+					}
+
+					args = args->rest;
+					_expr = expr_args[++i];
+
+					if (!empty_args_list(args) && !_expr) {
+						free_rules_until(_rules, rules);
+						my_free(expr_args);
+						return 0;
+					}
+				}
+				my_free(expr_args);
+				return 1;
+			}
+			my_free(expr_args);
+		default:
+			return 0;
+	}
+}
+
+expression* eval_rnf(fuspel* rules, expression* expr) {
+	expression* result = my_calloc(1, sizeof(expression));
+
+	fuspel* _rules = rules;
+
+	replacements** repls = my_calloc(1, sizeof(replacements*));
+
+	switch (expr->kind) {
+		case EXPR_INT:
+		case EXPR_TUPLE:
+		case EXPR_LIST:
+			cpy_expression(result, expr);
+			break;
+
+		case EXPR_NAME:
+		case EXPR_APP:
+			while (_rules) {
+				if (match_rule(rules, &_rules->rule, expr, repls)) {
+					expression* old_result = result;
+					cpy_expression(result, &_rules->rule.rhs);
+					replace_all(*repls, result);
+					free_replacements(*repls);
+					my_free(repls);
+					result = eval_rnf(rules, old_result);
+					free_expression(old_result);
+					my_free(old_result);
+					return result;
+				}
+				free_replacements(*repls);
+				my_free(repls);
+				repls = my_calloc(1, sizeof(replacements*));
+				_rules = _rules->rest;
+			}
+			cpy_expression(result, expr);
+			break;
+	}
+
+	free_replacements(*repls);
+	my_free(repls);
+
+	return result;
+}
+
+expression* eval(fuspel* rules, expression* expr) {
+	expression *e1, *e2;
+	fuspel* _rules = rules;
+	expression* result = my_calloc(1, sizeof(expression));
+	replacements** repls = my_calloc(1, sizeof(replacements*));
+
+	printf("Evaluating: ");
+	print_expression(expr);
+	printf("\n");
+
+	switch (expr->kind) {
+		case EXPR_INT:
+			cpy_expression(result, expr);
+			break;
+
+		case EXPR_NAME:
+		case EXPR_APP:
+			while (_rules) {
+				if (match_rule(rules, &_rules->rule, expr, repls)) {
+					expression* old_result = result;
+					cpy_expression(result, &_rules->rule.rhs);
+					replace_all(*repls, result);
+					result = eval(rules, old_result);
+					free_expression(old_result);
+					my_free(old_result);
+					free_replacements(*repls);
+					my_free(repls);
+					return result;
+				}
+				free_replacements(*repls);
+				my_free(repls);
+				repls = my_calloc(1, sizeof(replacements*));
+				_rules = _rules->rest;
+			}
+			cpy_expression(result, expr);
+			break;
+
+		case EXPR_LIST:
+			if (!expr->var1) {
+				cpy_expression(result, expr);
+				break;
+			}
+		case EXPR_TUPLE:
+			e1 = eval(rules, expr->var1);
+			e2 = eval(rules, expr->var2);
+
+			result->kind = expr->kind;
+			result->var1 = e1;
+			result->var2 = e2;
+			break;
+	}
+
+	free_replacements(*repls);
+	my_free(repls);
+
+	return result;
+}
-- 
cgit v1.2.3