void test_closure() { double extra; double c[] = {5,6,7,8,9}; te_variable lookup[] = { {"c0", clo0, TE_CLOSURE0, &extra}, {"c1", clo1, TE_CLOSURE1, &extra}, {"c2", clo2, TE_CLOSURE2, &extra}, {"cell", cell, TE_CLOSURE1, c}, }; test_case cases[] = { {"c0", 6}, {"c1 4", 8}, {"c2 (10, 20)", 30}, }; int i; for (i = 0; i < sizeof(cases) / sizeof(test_case); ++i) { const char *expr = cases[i].expr; const double answer = cases[i].answer; int err; te_expr *ex = te_compile(expr, lookup, sizeof(lookup)/sizeof(te_variable), &err); lok(ex); extra = 0; lfequal(te_eval(ex), answer + extra); extra = 10; lfequal(te_eval(ex), answer + extra); te_free(ex); } test_case cases2[] = { {"cell 0", 5}, {"cell 1", 6}, {"cell 0 + cell 1", 11}, {"cell 1 * cell 3 + cell 4", 57}, }; for (i = 0; i < sizeof(cases2) / sizeof(test_case); ++i) { const char *expr = cases2[i].expr; const double answer = cases2[i].answer; int err; te_expr *ex = te_compile(expr, lookup, sizeof(lookup)/sizeof(te_variable), &err); lok(ex); lfequal(te_eval(ex), answer); te_free(ex); } }
void test_pow() { #ifdef TE_POW_FROM_RIGHT test_equ cases[] = { {"2^3^4", "2^(3^4)"}, {"-2^2", "-(2^2)"}, {"-(2)^2", "-(2^2)"}, {"-(2*1)^2", "-(2^2)"}, {"-2^2", "-4"}, {"2^1.1^1.2^1.3", "2^(1.1^(1.2^1.3))"}, {"-a^b", "-(a^b)"}, {"-a^-b", "-(a^-b)"} }; #else test_equ cases[] = { {"2^3^4", "(2^3)^4"}, {"-2^2", "(-2)^2"}, {"-2^2", "4"}, {"2^1.1^1.2^1.3", "((2^1.1)^1.2)^1.3"}, {"-a^b", "(-a)^b"}, {"-a^-b", "(-a)^(-b)"} }; #endif double a = 2, b = 3; te_variable lookup[] = { {"a", &a}, {"b", &b} }; int i; for (i = 0; i < sizeof(cases) / sizeof(test_equ); ++i) { const char *expr1 = cases[i].expr1; const char *expr2 = cases[i].expr2; te_expr *ex1 = te_compile(expr1, lookup, sizeof(lookup)/sizeof(te_variable), 0); te_expr *ex2 = te_compile(expr2, lookup, sizeof(lookup)/sizeof(te_variable), 0); lok(ex1); lok(ex2); double r1 = te_eval(ex1); double r2 = te_eval(ex2); fflush(stdout); lfequal(r1, r2); te_free(ex1); te_free(ex2); } }
void test_optimize() { test_case cases[] = { {"5+5", 10}, {"pow(2,2)", 4}, {"sqrt 100", 10}, {"pi * 2", 6.2832}, }; int i; for (i = 0; i < sizeof(cases) / sizeof(test_case); ++i) { const char *expr = cases[i].expr; const double answer = cases[i].answer; int err; te_expr *ex = te_compile(expr, 0, 0, &err); lok(ex); /* The answer should be know without * even running eval. */ lfequal(ex->value, answer); lfequal(te_eval(ex), answer); te_free(ex); } }
void test_nans() { const char *nans[] = { "0/0", "1%0", "1%(1%0)", "(1%0)%1", }; int i; for (i = 0; i < sizeof(nans) / sizeof(const char *); ++i) { const char *expr = nans[i]; int err; const double r = te_interp(expr, &err); lequal(err, 0); lok(r != r); te_expr *n = te_compile(expr, 0, 0, &err); lok(n); lequal(err, 0); const double c = te_eval(n); lok(c != c); te_free(n); } }
int TinyExpr::TestExpr(const char *expression) { int error; te_variable vars[] = {{"x", NULL}, {"a", NULL}, {"b", NULL}, {"c", NULL}, {"d", NULL}}; te_expr *expr = te_compile(expression, vars, 5, &error); if (!error) te_free(expr); return error; }
void test_dynamic() { double x, f; te_variable lookup[] = { {"x", &x}, {"f", &f}, {"sum0", sum0, TE_FUNCTION0}, {"sum1", sum1, TE_FUNCTION1}, {"sum2", sum2, TE_FUNCTION2}, {"sum3", sum3, TE_FUNCTION3}, {"sum4", sum4, TE_FUNCTION4}, {"sum5", sum5, TE_FUNCTION5}, {"sum6", sum6, TE_FUNCTION6}, {"sum7", sum7, TE_FUNCTION7}, }; test_case cases[] = { {"x", 2}, {"f+x", 7}, {"x+x", 4}, {"x+f", 7}, {"f+f", 10}, {"f+sum0", 11}, {"sum0+sum0", 12}, {"sum0()+sum0", 12}, {"sum0+sum0()", 12}, {"sum0()+(0)+sum0()", 12}, {"sum1 sum0", 12}, {"sum1(sum0)", 12}, {"sum1 f", 10}, {"sum1 x", 4}, {"sum2 (sum0, x)", 8}, {"sum3 (sum0, x, 2)", 10}, {"sum2(2,3)", 5}, {"sum3(2,3,4)", 9}, {"sum4(2,3,4,5)", 14}, {"sum5(2,3,4,5,6)", 20}, {"sum6(2,3,4,5,6,7)", 27}, {"sum7(2,3,4,5,6,7,8)", 35}, }; x = 2; f = 5; int i; for (i = 0; i < sizeof(cases) / sizeof(test_case); ++i) { const char *expr = cases[i].expr; const double answer = cases[i].answer; int err; te_expr *ex = te_compile(expr, lookup, sizeof(lookup)/sizeof(te_variable), &err); lok(ex); lfequal(te_eval(ex), answer); te_free(ex); } }
double te_interp(const char *expression, int *error) { te_expr *n = te_compile(expression, 0, 0, error); double ret; if (n) { ret = te_eval(n); te_free(n); } else { ret = NAN; } return ret; }
void te_free_parameters(te_expr *n) { if (!n) return; switch (TYPE_MASK(n->type)) { case TE_FUNCTION7: case TE_CLOSURE7: te_free(n->parameters[6]); case TE_FUNCTION6: case TE_CLOSURE6: te_free(n->parameters[5]); case TE_FUNCTION5: case TE_CLOSURE5: te_free(n->parameters[4]); case TE_FUNCTION4: case TE_CLOSURE4: te_free(n->parameters[3]); case TE_FUNCTION3: case TE_CLOSURE3: te_free(n->parameters[2]); case TE_FUNCTION2: case TE_CLOSURE2: te_free(n->parameters[1]); case TE_FUNCTION1: case TE_CLOSURE1: te_free(n->parameters[0]); } }
te_expr *te_compile(const char *expression, const te_variable *variables, int var_count, int *error) { state s; s.start = s.next = expression; s.lookup = variables; s.lookup_len = var_count; next_token(&s); te_expr *root = list(&s); if (s.type != TOK_END) { te_free(root); if (error) { *error = (s.next - s.start); if (*error == 0) *error = 1; } return 0; } else { optimize(root); if (error) *error = 0; return root; } }
void test_variables() { double x, y, test; te_variable lookup[] = {{"x", &x}, {"y", &y}, {"test", &test}}; int err; te_expr *expr1 = te_compile("cos x + sin y", lookup, 2, &err); lok(expr1); lok(!err); te_expr *expr2 = te_compile("x+x+x-y", lookup, 2, &err); lok(expr2); lok(!err); te_expr *expr3 = te_compile("x*y^3", lookup, 2, &err); lok(expr3); lok(!err); te_expr *expr4 = te_compile("test+5", lookup, 3, &err); lok(expr4); lok(!err); for (y = 2; y < 3; ++y) { for (x = 0; x < 5; ++x) { double ev; ev = te_eval(expr1); lfequal(ev, cos(x) + sin(y)); ev = te_eval(expr2); lfequal(ev, x+x+x-y); ev = te_eval(expr3); lfequal(ev, x*y*y*y); test = x; ev = te_eval(expr4); lfequal(ev, x+5); } } te_free(expr1); te_free(expr2); te_free(expr3); te_free(expr4); te_expr *expr5 = te_compile("xx*y^3", lookup, 2, &err); lok(!expr5); lok(err); te_expr *expr6 = te_compile("tes", lookup, 3, &err); lok(!expr6); lok(err); te_expr *expr7 = te_compile("sinn x", lookup, 2, &err); lok(!expr7); lok(err); te_expr *expr8 = te_compile("si x", lookup, 2, &err); lok(!expr8); lok(err); }
void te_free(te_expr *n) { if (!n) return; if (n->left) te_free(n->left); if (n->right) te_free(n->right); free(n); }