mirror of
				https://github.com/eledio-devices/thirdparty-tinyexpr.git
				synced 2025-10-31 00:32:38 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			605 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			605 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * TINYEXPR - Tiny recursive descent parser and evaluation engine in C
 | |
|  *
 | |
|  * Copyright (c) 2015, 2016 Lewis Van Winkle
 | |
|  *
 | |
|  * http://CodePlea.com
 | |
|  *
 | |
|  * This software is provided 'as-is', without any express or implied
 | |
|  * warranty. In no event will the authors be held liable for any damages
 | |
|  * arising from the use of this software.
 | |
|  *
 | |
|  * Permission is granted to anyone to use this software for any purpose,
 | |
|  * including commercial applications, and to alter it and redistribute it
 | |
|  * freely, subject to the following restrictions:
 | |
|  *
 | |
|  * 1. The origin of this software must not be misrepresented; you must not
 | |
|  * claim that you wrote the original software. If you use this software
 | |
|  * in a product, an acknowledgement in the product documentation would be
 | |
|  * appreciated but is not required.
 | |
|  * 2. Altered source versions must be plainly marked as such, and must not be
 | |
|  * misrepresented as being the original software.
 | |
|  * 3. This notice may not be removed or altered from any source distribution.
 | |
|  */
 | |
| 
 | |
| #include "tinyexpr.h"
 | |
| #include <stdio.h>
 | |
| #include "minctest.h"
 | |
| 
 | |
| 
 | |
| typedef struct {
 | |
|     const char *expr;
 | |
|     double answer;
 | |
| } test_case;
 | |
| 
 | |
| typedef struct {
 | |
|     const char *expr1;
 | |
|     const char *expr2;
 | |
| } test_equ;
 | |
| 
 | |
| 
 | |
| 
 | |
| void test_results() {
 | |
|     test_case cases[] = {
 | |
|         {"1", 1},
 | |
|         {"1 ", 1},
 | |
|         {"(1)", 1},
 | |
| 
 | |
|         {"pi", 3.14159},
 | |
|         {"atan(1)*4 - pi", 0},
 | |
|         {"e", 2.71828},
 | |
| 
 | |
|         {"2+1", 2+1},
 | |
|         {"(((2+(1))))", 2+1},
 | |
|         {"3+2", 3+2},
 | |
| 
 | |
|         {"3+2+4", 3+2+4},
 | |
|         {"(3+2)+4", 3+2+4},
 | |
|         {"3+(2+4)", 3+2+4},
 | |
|         {"(3+2+4)", 3+2+4},
 | |
| 
 | |
|         {"3*2*4", 3*2*4},
 | |
|         {"(3*2)*4", 3*2*4},
 | |
|         {"3*(2*4)", 3*2*4},
 | |
|         {"(3*2*4)", 3*2*4},
 | |
| 
 | |
|         {"3-2-4", 3-2-4},
 | |
|         {"(3-2)-4", (3-2)-4},
 | |
|         {"3-(2-4)", 3-(2-4)},
 | |
|         {"(3-2-4)", 3-2-4},
 | |
| 
 | |
|         {"3/2/4", 3.0/2.0/4.0},
 | |
|         {"(3/2)/4", (3.0/2.0)/4.0},
 | |
|         {"3/(2/4)", 3.0/(2.0/4.0)},
 | |
|         {"(3/2/4)", 3.0/2.0/4.0},
 | |
| 
 | |
|         {"(3*2/4)", 3.0*2.0/4.0},
 | |
|         {"(3/2*4)", 3.0/2.0*4.0},
 | |
|         {"3*(2/4)", 3.0*(2.0/4.0)},
 | |
| 
 | |
|         {"asin sin .5", 0.5},
 | |
|         {"sin asin .5", 0.5},
 | |
|         {"ln exp .5", 0.5},
 | |
|         {"exp ln .5", 0.5},
 | |
| 
 | |
|         {"asin sin-.5", -0.5},
 | |
|         {"asin sin-0.5", -0.5},
 | |
|         {"asin sin -0.5", -0.5},
 | |
|         {"asin (sin -0.5)", -0.5},
 | |
|         {"asin (sin (-0.5))", -0.5},
 | |
|         {"asin sin (-0.5)", -0.5},
 | |
|         {"(asin sin (-0.5))", -0.5},
 | |
| 
 | |
|         {"log10 1000", 3},
 | |
|         {"log10 1e3", 3},
 | |
|         {"log10 1000", 3},
 | |
|         {"log10 1e3", 3},
 | |
|         {"log10(1000)", 3},
 | |
|         {"log10(1e3)", 3},
 | |
|         {"log10 1.0e3", 3},
 | |
|         {"10^5*5e-5", 5},
 | |
| 
 | |
| #ifdef TE_NAT_LOG
 | |
|         {"log 1000", 6.9078},
 | |
|         {"log e", 1},
 | |
|         {"log (e^10)", 10},
 | |
| #else
 | |
|         {"log 1000", 3},
 | |
| #endif
 | |
| 
 | |
|         {"ln (e^10)", 10},
 | |
|         {"100^.5+1", 11},
 | |
|         {"100 ^.5+1", 11},
 | |
|         {"100^+.5+1", 11},
 | |
|         {"100^--.5+1", 11},
 | |
|         {"100^---+-++---++-+-+-.5+1", 11},
 | |
| 
 | |
|         {"100^-.5+1", 1.1},
 | |
|         {"100^---.5+1", 1.1},
 | |
|         {"100^+---.5+1", 1.1},
 | |
|         {"1e2^+---.5e0+1e0", 1.1},
 | |
|         {"--(1e2^(+(-(-(-.5e0))))+1e0)", 1.1},
 | |
| 
 | |
|         {"sqrt 100 + 7", 17},
 | |
|         {"sqrt 100 * 7", 70},
 | |
|         {"sqrt (100 * 100)", 100},
 | |
| 
 | |
|         {"1,2", 2},
 | |
|         {"1,2+1", 3},
 | |
|         {"1+1,2+2,2+1", 3},
 | |
|         {"1,2,3", 3},
 | |
|         {"(1,2),3", 3},
 | |
|         {"1,(2,3)", 3},
 | |
|         {"-(1,(2,3))", -3},
 | |
| 
 | |
|         {"2^2", 4},
 | |
|         {"pow(2,2)", 4},
 | |
| 
 | |
|         {"atan2(1,1)", 0.7854},
 | |
|         {"atan2(1,2)", 0.4636},
 | |
|         {"atan2(2,1)", 1.1071},
 | |
|         {"atan2(3,4)", 0.6435},
 | |
|         {"atan2(3+3,4*2)", 0.6435},
 | |
|         {"atan2(3+3,(4*2))", 0.6435},
 | |
|         {"atan2((3+3),4*2)", 0.6435},
 | |
|         {"atan2((3+3),(4*2))", 0.6435},
 | |
| 
 | |
|     };
 | |
| 
 | |
| 
 | |
|     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;
 | |
|         const double ev = te_interp(expr, &err);
 | |
|         lok(!err);
 | |
|         lfequal(ev, answer);
 | |
| 
 | |
|         if (err) {
 | |
|             printf("FAILED: %s (%d)\n", expr, err);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void test_syntax() {
 | |
|     test_case errors[] = {
 | |
|         {"", 1},
 | |
|         {"1+", 2},
 | |
|         {"1)", 2},
 | |
|         {"(1", 2},
 | |
|         {"1**1", 3},
 | |
|         {"1*2(+4", 4},
 | |
|         {"1*2(1+4", 4},
 | |
|         {"a+5", 1},
 | |
|         {"A+5", 1},
 | |
|         {"Aa+5", 1},
 | |
|         {"1^^5", 3},
 | |
|         {"1**5", 3},
 | |
|         {"sin(cos5", 8},
 | |
|     };
 | |
| 
 | |
| 
 | |
|     int i;
 | |
|     for (i = 0; i < sizeof(errors) / sizeof(test_case); ++i) {
 | |
|         const char *expr = errors[i].expr;
 | |
|         const int e = errors[i].answer;
 | |
| 
 | |
|         int err;
 | |
|         const double r = te_interp(expr, &err);
 | |
|         lequal(err, e);
 | |
|         lok(r != r);
 | |
| 
 | |
|         te_expr *n = te_compile(expr, 0, 0, &err);
 | |
|         lequal(err, e);
 | |
|         lok(!n);
 | |
| 
 | |
|         if (err != e) {
 | |
|             printf("FAILED: %s\n", expr);
 | |
|         }
 | |
| 
 | |
|         const double k = te_interp(expr, 0);
 | |
|         lok(k != k);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| 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);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| 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);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| #define cross_check(a, b) do {\
 | |
|     if ((b)!=(b)) break;\
 | |
|     expr = te_compile((a), lookup, 2, &err);\
 | |
|     lfequal(te_eval(expr), (b));\
 | |
|     lok(!err);\
 | |
|     te_free(expr);\
 | |
| }while(0)
 | |
| 
 | |
| void test_functions() {
 | |
| 
 | |
|     double x, y;
 | |
|     te_variable lookup[] = {{"x", &x}, {"y", &y}};
 | |
| 
 | |
|     int err;
 | |
|     te_expr *expr;
 | |
| 
 | |
|     for (x = -5; x < 5; x += .2) {
 | |
|         cross_check("abs x", fabs(x));
 | |
|         cross_check("acos x", acos(x));
 | |
|         cross_check("asin x", asin(x));
 | |
|         cross_check("atan x", atan(x));
 | |
|         cross_check("ceil x", ceil(x));
 | |
|         cross_check("cos x", cos(x));
 | |
|         cross_check("cosh x", cosh(x));
 | |
|         cross_check("exp x", exp(x));
 | |
|         cross_check("floor x", floor(x));
 | |
|         cross_check("ln x", log(x));
 | |
|         cross_check("log10 x", log10(x));
 | |
|         cross_check("sin x", sin(x));
 | |
|         cross_check("sinh x", sinh(x));
 | |
|         cross_check("sqrt x", sqrt(x));
 | |
|         cross_check("tan x", tan(x));
 | |
|         cross_check("tanh x", tanh(x));
 | |
| 
 | |
|         for (y = -2; y < 2; y += .2) {
 | |
|             if (fabs(x) < 0.01) break;
 | |
|             cross_check("atan2(x,y)", atan2(x, y));
 | |
|             cross_check("pow(x,y)", pow(x, y));
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| double sum0() {
 | |
|     return 6;
 | |
| }
 | |
| double sum1(double a) {
 | |
|     return a * 2;
 | |
| }
 | |
| double sum2(double a, double b) {
 | |
|     return a + b;
 | |
| }
 | |
| double sum3(double a, double b, double c) {
 | |
|     return a + b + c;
 | |
| }
 | |
| double sum4(double a, double b, double c, double d) {
 | |
|     return a + b + c + d;
 | |
| }
 | |
| double sum5(double a, double b, double c, double d, double e) {
 | |
|     return a + b + c + d + e;
 | |
| }
 | |
| double sum6(double a, double b, double c, double d, double e, double f) {
 | |
|     return a + b + c + d + e + f;
 | |
| }
 | |
| double sum7(double a, double b, double c, double d, double e, double f, double g) {
 | |
|     return a + b + c + d + e + f + g;
 | |
| }
 | |
| 
 | |
| 
 | |
| 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 clo0(void *context) {
 | |
|     if (context) return *((double*)context) + 6;
 | |
|     return 6;
 | |
| }
 | |
| double clo1(void *context, double a) {
 | |
|     if (context) return *((double*)context) + a * 2;
 | |
|     return a * 2;
 | |
| }
 | |
| double clo2(void *context, double a, double b) {
 | |
|     if (context) return *((double*)context) + a + b;
 | |
|     return a + b;
 | |
| }
 | |
| 
 | |
| double cell(void *context, double a) {
 | |
|     double *c = context;
 | |
|     return c[(int)a];
 | |
| }
 | |
| 
 | |
| 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_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_pow() {
 | |
| #ifdef TE_POW_FROM_RIGHT
 | |
|     test_equ cases[] = {
 | |
|         {"2^3^4", "2^(3^4)"},
 | |
|         {"-2^2", "-(2^2)"},
 | |
|         {"--2^2", "(2^2)"},
 | |
|         {"---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", "2^2"},
 | |
|         {"---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);
 | |
|     }
 | |
| 
 | |
| }
 | |
| 
 | |
| int main(int argc, char *argv[])
 | |
| {
 | |
|     lrun("Results", test_results);
 | |
|     lrun("Syntax", test_syntax);
 | |
|     lrun("NaNs", test_nans);
 | |
|     lrun("Variables", test_variables);
 | |
|     lrun("Functions", test_functions);
 | |
|     lrun("Dynamic", test_dynamic);
 | |
|     lrun("Closure", test_closure);
 | |
|     lrun("Optimize", test_optimize);
 | |
|     lrun("Pow", test_pow);
 | |
|     lresults();
 | |
| 
 | |
|     return lfails != 0;
 | |
| }
 |