diff --git a/test.c b/test.c index 5c01dab..076ec8b 100644 --- a/test.c +++ b/test.c @@ -432,11 +432,14 @@ double cell(void *context, double a) { void test_closure() { + double extra; + double c[] = {5,6,7,8,9}; + te_variable lookup[] = { - {"c0", clo0, TE_CLOSURE0}, - {"c1", clo1, TE_CLOSURE1}, - {"c2", clo2, TE_CLOSURE2}, - {"cell", cell, TE_CLOSURE1}, + {"c0", clo0, TE_CLOSURE0, &extra}, + {"c1", clo1, TE_CLOSURE1, &extra}, + {"c2", clo2, TE_CLOSURE2, &extra}, + {"cell", cell, TE_CLOSURE1, c}, }; test_case cases[] = { @@ -445,7 +448,6 @@ void test_closure() { {"c2 (10, 20)", 30}, }; - double extra = 10; int i; for (i = 0; i < sizeof(cases) / sizeof(test_case); ++i) { const char *expr = cases[i].expr; @@ -454,13 +456,17 @@ void test_closure() { int err; te_expr *ex = te_compile(expr, lookup, sizeof(lookup)/sizeof(te_variable), &err); 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); } - double c[] = {5,6,7,8,9}; test_case cases2[] = { {"cell 0", 5}, {"cell 1", 6}, @@ -475,7 +481,7 @@ void test_closure() { int err; te_expr *ex = te_compile(expr, lookup, sizeof(lookup)/sizeof(te_variable), &err); lok(ex); - lfequal(te_eval_closure(ex, c), answer); + lfequal(te_eval(ex), answer); te_free(ex); } } diff --git a/tinyexpr.c b/tinyexpr.c index 0e281e1..068216d 100644 --- a/tinyexpr.c +++ b/tinyexpr.c @@ -44,6 +44,7 @@ typedef struct state { const char *next; int type; union {double value; const double *bound; const void *function;}; + void *context; const te_variable *lookup; int lookup_len; @@ -188,10 +189,12 @@ void next_token(state *s) { s->bound = var->address; 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_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->function = var->address; break; @@ -245,6 +248,7 @@ static te_expr *base(state *s) { case TE_CLOSURE0: ret = new_expr(s->type, 0); ret->function = s->function; + ret->context = s->context; next_token(s); if (s->type == TOK_OPEN) { next_token(s); @@ -260,6 +264,7 @@ static te_expr *base(state *s) { case TE_CLOSURE1: ret = new_expr(s->type, 0); ret->function = s->function; + ret->context = s->context; next_token(s); ret->parameters[0] = power(s); break; @@ -272,6 +277,7 @@ static te_expr *base(state *s) { ret = new_expr(s->type, 0); ret->function = s->function; + ret->context = s->context; next_token(s); if (s->type != TOK_OPEN) { @@ -396,15 +402,10 @@ static te_expr *list(state *s) { 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; #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) { 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_CLOSURE4: case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7: switch(ARITY(n->type)) { - case 0: return TE_FUN(void*)(context); - case 1: return TE_FUN(void*, double)(context, M(0)); - case 2: return TE_FUN(void*, double, double)(context, M(0), M(1)); - case 3: return TE_FUN(void*, double, double, double)(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 5: return TE_FUN(void*, double, double, double, double, double)(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 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 0: return TE_FUN(void*)(n->context); + case 1: return TE_FUN(void*, double)(n->context, M(0)); + case 2: return TE_FUN(void*, double, double)(n->context, M(0), M(1)); + 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)(n->context, M(0), M(1), M(2), M(3)); + 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)(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)(n->context, M(0), M(1), M(2), M(3), M(4), M(5), M(6)); default: return 0.0/0.0; } diff --git a/tinyexpr.h b/tinyexpr.h index ec7b780..07e00bc 100644 --- a/tinyexpr.h +++ b/tinyexpr.h @@ -35,6 +35,7 @@ extern "C" { typedef struct te_expr { int type; union {double value; const double *bound; const void *function;}; + void *context; struct te_expr *parameters[]; } te_expr; @@ -51,6 +52,7 @@ typedef struct te_variable { const char *name; const void *address; int type; + void *context; } te_variable; @@ -66,9 +68,6 @@ te_expr *te_compile(const char *expression, const te_variable *variables, int va /* Evaluates the expression. */ 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. */ void te_print(const te_expr *n);