aboutsummaryrefslogtreecommitdiff
path: root/interpreter
diff options
context:
space:
mode:
authorCamil Staps2016-08-25 23:10:47 +0200
committerCamil Staps2016-08-25 23:10:47 +0200
commit686f487cd9506d6f16b8d90565bcfa035769324b (patch)
treeca1197b58c7d56376cb65124617a6a40d91e131c /interpreter
parentAdded examples (diff)
Fix issue with trailing arguments
Diffstat (limited to 'interpreter')
-rw-r--r--interpreter/eval.c71
-rw-r--r--interpreter/syntax.c9
-rw-r--r--interpreter/syntax.h1
3 files changed, 69 insertions, 12 deletions
diff --git a/interpreter/eval.c b/interpreter/eval.c
index 8e9b04f..6468bb8 100644
--- a/interpreter/eval.c
+++ b/interpreter/eval.c
@@ -1,10 +1,8 @@
#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) {
@@ -113,7 +111,18 @@ unsigned match_expr(fuspel* rules, expression* to_match, expression* expr,
}
}
-unsigned match_rule(fuspel* rules, rewrite_rule* rule, expression* expr,
+/**
+ * Return value:
+ * < 0: rule does not match expr
+ * n: rule matches expr; n arguments at the end cannot be touched
+ *
+ * E.g., a rule
+ * f x y = (x,y)
+ * can be applied to
+ * f 1 2 3 4
+ * but 2 arguments cannot be touched (3 and 4).
+ */
+char match_rule(fuspel* rules, rewrite_rule* rule, expression* expr,
replacements** repls) {
expression** expr_args;
unsigned char i;
@@ -121,19 +130,21 @@ unsigned match_rule(fuspel* rules, rewrite_rule* rule, expression* expr,
switch (expr->kind) {
case EXPR_NAME:
return (!strcmp(expr->var1, rule->name) &&
- empty_args_list(rule->args)) ? 1 : 0;
+ empty_args_list(rule->args)) ? 0 : -1;
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;
+ unsigned char args_len = len_arg_list(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;
+ return -1;
}
args = args->rest;
@@ -142,16 +153,44 @@ unsigned match_rule(fuspel* rules, rewrite_rule* rule, expression* expr,
if (!empty_args_list(args) && !_expr) {
free_rules_until(_rules, rules);
my_free(expr_args);
- return 0;
+ return -1;
}
}
+ while (_expr) _expr = expr_args[++i];
my_free(expr_args);
- return 1;
+ return i - args_len - 1;
}
my_free(expr_args);
default:
- return 0;
+ return -1;
+ }
+}
+
+/**
+ * If
+ * app: f x y
+ * from: g 1 2 3 4
+ * n: 3
+ *
+ * Then the result will be:
+ * f x y 2 3 4
+ */
+expression* append_to_app(expression* app, expression* from, unsigned char n) {
+ expression *_from, *_app;
+ unsigned char i;
+ for (; n > 0; n--) {
+ _app = my_calloc(1, sizeof(expression));
+ _app->kind = EXPR_APP;
+ _app->var1 = app;
+ _app->var2 = my_calloc(1, sizeof(expression));
+
+ _from = from;
+ for (i = 1; i < n; i++) _from = _from->var1;
+ cpy_expression(_app->var2, _from->var2);
+
+ app = _app;
}
+ return app;
}
expression* eval_rnf(fuspel* rules, expression* expr) {
@@ -171,8 +210,12 @@ expression* eval_rnf(fuspel* rules, expression* expr) {
case EXPR_NAME:
case EXPR_APP:
while (_rules) {
- if (match_rule(rules, &_rules->rule, expr, repls)) {
- expression* old_result = result;
+ char skip_args;
+ if ((skip_args = match_rule(
+ rules, &_rules->rule, expr, repls)) >= 0) {
+ expression *old_result;
+ result = append_to_app(result, expr, skip_args);
+ old_result = result;
cpy_expression(result, &_rules->rule.rhs);
replace_all(*repls, result);
free_replacements(*repls);
@@ -211,10 +254,14 @@ expression* eval(fuspel* rules, expression* expr) {
case EXPR_NAME:
case EXPR_APP:
while (_rules) {
- if (match_rule(rules, &_rules->rule, expr, repls)) {
- expression* old_result = result;
+ char skip_args;
+ if ((skip_args = match_rule(
+ rules, &_rules->rule, expr, repls)) >= 0) {
+ expression *old_result;
cpy_expression(result, &_rules->rule.rhs);
replace_all(*repls, result);
+ result = append_to_app(result, expr, skip_args);
+ old_result = result;
result = eval(rules, result);
free_expression(old_result);
my_free(old_result);
diff --git a/interpreter/syntax.c b/interpreter/syntax.c
index 4eb845a..7a0dd39 100644
--- a/interpreter/syntax.c
+++ b/interpreter/syntax.c
@@ -20,6 +20,15 @@ unsigned empty_args_list(arg_list* list) {
return !list;
}
+unsigned char len_arg_list(arg_list* list) {
+ unsigned char i = 0;
+ while (list) {
+ i++;
+ list = list->rest;
+ }
+ return i;
+}
+
void cpy_expression(expression* dst, expression* src) {
free_expression(dst);
dst->kind = src->kind;
diff --git a/interpreter/syntax.h b/interpreter/syntax.h
index 05f09c7..bed4fcd 100644
--- a/interpreter/syntax.h
+++ b/interpreter/syntax.h
@@ -62,6 +62,7 @@ typedef struct fuspel {
} fuspel;
unsigned empty_args_list(arg_list*);
+unsigned char len_arg_list(arg_list*);
void cpy_expression(expression* dst, expression* src);
unsigned eq_expression(expression*, expression*);