Context for closures is now stored separately for each closure.

This commit is contained in:
Lewis Van Winkle
2016-02-25 13:34:58 -06:00
parent a23801c45f
commit a44620f187
3 changed files with 34 additions and 28 deletions

24
test.c
View File

@@ -432,11 +432,14 @@ double cell(void *context, double a) {
void test_closure() { void test_closure() {
double extra;
double c[] = {5,6,7,8,9};
te_variable lookup[] = { te_variable lookup[] = {
{"c0", clo0, TE_CLOSURE0}, {"c0", clo0, TE_CLOSURE0, &extra},
{"c1", clo1, TE_CLOSURE1}, {"c1", clo1, TE_CLOSURE1, &extra},
{"c2", clo2, TE_CLOSURE2}, {"c2", clo2, TE_CLOSURE2, &extra},
{"cell", cell, TE_CLOSURE1}, {"cell", cell, TE_CLOSURE1, c},
}; };
test_case cases[] = { test_case cases[] = {
@@ -445,7 +448,6 @@ void test_closure() {
{"c2 (10, 20)", 30}, {"c2 (10, 20)", 30},
}; };
double extra = 10;
int i; int i;
for (i = 0; i < sizeof(cases) / sizeof(test_case); ++i) { for (i = 0; i < sizeof(cases) / sizeof(test_case); ++i) {
const char *expr = cases[i].expr; const char *expr = cases[i].expr;
@@ -454,13 +456,17 @@ void test_closure() {
int err; int err;
te_expr *ex = te_compile(expr, lookup, sizeof(lookup)/sizeof(te_variable), &err); te_expr *ex = te_compile(expr, lookup, sizeof(lookup)/sizeof(te_variable), &err);
lok(ex); lok(ex);
lfequal(te_eval(ex), answer);
lfequal(te_eval_closure(ex, &extra), answer + extra); extra = 0;
lfequal(te_eval(ex), answer + extra);
extra = 10;
lfequal(te_eval(ex), answer + extra);
te_free(ex); te_free(ex);
} }
double c[] = {5,6,7,8,9};
test_case cases2[] = { test_case cases2[] = {
{"cell 0", 5}, {"cell 0", 5},
{"cell 1", 6}, {"cell 1", 6},
@@ -475,7 +481,7 @@ void test_closure() {
int err; int err;
te_expr *ex = te_compile(expr, lookup, sizeof(lookup)/sizeof(te_variable), &err); te_expr *ex = te_compile(expr, lookup, sizeof(lookup)/sizeof(te_variable), &err);
lok(ex); lok(ex);
lfequal(te_eval_closure(ex, c), answer); lfequal(te_eval(ex), answer);
te_free(ex); te_free(ex);
} }
} }

View File

@@ -44,6 +44,7 @@ typedef struct state {
const char *next; const char *next;
int type; int type;
union {double value; const double *bound; const void *function;}; union {double value; const double *bound; const void *function;};
void *context;
const te_variable *lookup; const te_variable *lookup;
int lookup_len; int lookup_len;
@@ -188,10 +189,12 @@ void next_token(state *s) {
s->bound = var->address; s->bound = var->address;
break; break;
case TE_FUNCTION0: case TE_FUNCTION1: case TE_FUNCTION2: case TE_FUNCTION3:
case TE_FUNCTION4: case TE_FUNCTION5: case TE_FUNCTION6: case TE_FUNCTION7:
case TE_CLOSURE0: case TE_CLOSURE1: case TE_CLOSURE2: case TE_CLOSURE3: case TE_CLOSURE0: case TE_CLOSURE1: case TE_CLOSURE2: case TE_CLOSURE3:
case TE_CLOSURE4: case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7: case TE_CLOSURE4: case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7:
s->context = var->context;
case TE_FUNCTION0: case TE_FUNCTION1: case TE_FUNCTION2: case TE_FUNCTION3:
case TE_FUNCTION4: case TE_FUNCTION5: case TE_FUNCTION6: case TE_FUNCTION7:
s->type = var->type; s->type = var->type;
s->function = var->address; s->function = var->address;
break; break;
@@ -245,6 +248,7 @@ static te_expr *base(state *s) {
case TE_CLOSURE0: case TE_CLOSURE0:
ret = new_expr(s->type, 0); ret = new_expr(s->type, 0);
ret->function = s->function; ret->function = s->function;
ret->context = s->context;
next_token(s); next_token(s);
if (s->type == TOK_OPEN) { if (s->type == TOK_OPEN) {
next_token(s); next_token(s);
@@ -260,6 +264,7 @@ static te_expr *base(state *s) {
case TE_CLOSURE1: case TE_CLOSURE1:
ret = new_expr(s->type, 0); ret = new_expr(s->type, 0);
ret->function = s->function; ret->function = s->function;
ret->context = s->context;
next_token(s); next_token(s);
ret->parameters[0] = power(s); ret->parameters[0] = power(s);
break; break;
@@ -272,6 +277,7 @@ static te_expr *base(state *s) {
ret = new_expr(s->type, 0); ret = new_expr(s->type, 0);
ret->function = s->function; ret->function = s->function;
ret->context = s->context;
next_token(s); next_token(s);
if (s->type != TOK_OPEN) { if (s->type != TOK_OPEN) {
@@ -396,15 +402,10 @@ static te_expr *list(state *s) {
double te_eval(const te_expr *n) { double te_eval(const te_expr *n) {
return te_eval_closure(n, 0);
}
double te_eval_closure(const te_expr *n, void *context) {
if (!n) return 0.0/0.0; if (!n) return 0.0/0.0;
#define TE_FUN(...) ((double(*)(__VA_ARGS__))n->function) #define TE_FUN(...) ((double(*)(__VA_ARGS__))n->function)
#define M(e) te_eval_closure(n->parameters[e], context) #define M(e) te_eval(n->parameters[e])
switch(n->type) { switch(n->type) {
case TE_CONSTANT: return n->value; case TE_CONSTANT: return n->value;
@@ -427,14 +428,14 @@ double te_eval_closure(const te_expr *n, void *context) {
case TE_CLOSURE0: case TE_CLOSURE1: case TE_CLOSURE2: case TE_CLOSURE3: case TE_CLOSURE0: case TE_CLOSURE1: case TE_CLOSURE2: case TE_CLOSURE3:
case TE_CLOSURE4: case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7: case TE_CLOSURE4: case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7:
switch(ARITY(n->type)) { switch(ARITY(n->type)) {
case 0: return TE_FUN(void*)(context); case 0: return TE_FUN(void*)(n->context);
case 1: return TE_FUN(void*, double)(context, M(0)); case 1: return TE_FUN(void*, double)(n->context, M(0));
case 2: return TE_FUN(void*, double, double)(context, M(0), M(1)); case 2: return TE_FUN(void*, double, double)(n->context, M(0), M(1));
case 3: return TE_FUN(void*, double, double, double)(context, M(0), M(1), M(2)); case 3: return TE_FUN(void*, double, double, double)(n->context, M(0), M(1), M(2));
case 4: return TE_FUN(void*, double, double, double, double)(context, M(0), M(1), M(2), M(3)); case 4: return TE_FUN(void*, double, double, double, double)(n->context, M(0), M(1), M(2), M(3));
case 5: return TE_FUN(void*, double, double, double, double, double)(context, M(0), M(1), M(2), M(3), M(4)); case 5: return TE_FUN(void*, double, double, double, double, double)(n->context, M(0), M(1), M(2), M(3), M(4));
case 6: return TE_FUN(void*, double, double, double, double, double, double)(context, M(0), M(1), M(2), M(3), M(4), M(5)); case 6: return TE_FUN(void*, double, double, double, double, double, double)(n->context, M(0), M(1), M(2), M(3), M(4), M(5));
case 7: return TE_FUN(void*, double, double, double, double, double, double, double)(context, M(0), M(1), M(2), M(3), M(4), M(5), M(6)); case 7: return TE_FUN(void*, double, double, double, double, double, double, double)(n->context, M(0), M(1), M(2), M(3), M(4), M(5), M(6));
default: return 0.0/0.0; default: return 0.0/0.0;
} }

View File

@@ -35,6 +35,7 @@ extern "C" {
typedef struct te_expr { typedef struct te_expr {
int type; int type;
union {double value; const double *bound; const void *function;}; union {double value; const double *bound; const void *function;};
void *context;
struct te_expr *parameters[]; struct te_expr *parameters[];
} te_expr; } te_expr;
@@ -51,6 +52,7 @@ typedef struct te_variable {
const char *name; const char *name;
const void *address; const void *address;
int type; int type;
void *context;
} te_variable; } te_variable;
@@ -66,9 +68,6 @@ te_expr *te_compile(const char *expression, const te_variable *variables, int va
/* Evaluates the expression. */ /* Evaluates the expression. */
double te_eval(const te_expr *n); double te_eval(const te_expr *n);
/* Evaluates the expression while passing a closure to any bound closure functions. */
double te_eval_closure(const te_expr *n, void *context);
/* Prints debugging information on the syntax tree. */ /* Prints debugging information on the syntax tree. */
void te_print(const te_expr *n); void te_print(const te_expr *n);