The Z Expression Language

Author: zoly

Scope: A simple but easy to extend language for doing expression evalutions and calculations in java Designed to be a generic and simple to use java component.

Now there are a few other components out there that do a similar job, here is what it's different (or not :-) ) about this particular implementation:

1. Implemented using javaCC

2. Supports Structured variables (data) (var1.var2.var3)

3. How you name and structure your variables does matter! you can aggregate across them using wildcards. Supports wildcard based structured data manipulation (example: add all variables that match: *time ) , lambda functions

4. Expressions are compiled providing good execution performance, executes faster than mvel

5. Automatic paralelization.

6. Integer mathematical operations do not overflow. Real number representation can be selected: float, number, BigDecimal or GnuBigFloat (a native implementation based on GNU MP lib)

7. Everything is an object, numbers, strings, functions.....you can apply operators across any object if the operation is undefined you will get an exception...

8. There is only one type of variable: reference to object, you declare a variable by assigning an object to it, all variables are global (this will probably change). Functions are variables and are defined via an assigment

9. ZEL uses the last value out principle, expressions will return the last evaluated expression.There is a return keyword that can be used, but it is optional.

10. Support for deterministic functions, executions will be cached for deterministic functions

11. LGPL license

Here is how you would use the evaluator in your java code:

Memory memory = new Memory();
memory.addValue("a", new OperableInteger(0)); memory.addValue("b", new OperableInteger(5));
Number result = (Number) Program.compile( "c = a+b ;").execute(memory);
Number c = memory.getValue("c");

or the more performant(at least twice faster) via local variables:

Memory memory = new Memory();
Number result = (java.lang.Number) Program.compile(
                    "c=a+b;","a", "b").execute(memory,new OperableInteger(0),new OperableInteger(5));
Number c = memory.getValue("c");

you can also specify your floating point implementations:

the Java Double implementation:

 OperableNumber n = (OperableNumber) Program.compile("a = 0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1;",
   ExtendedMathContext.DOUBLE64_MATHCONTEXT).execute();
 System.out.println("Double result: " + n);

or the Java BigDecimal implementation:

 OperableNumber n = (OperableNumber) Program.compile("a = 0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1;",
   ExtendedMathContext.DECIMAL64_MATHCONTEXT).execute();
 System.out.println("BigDecimal result: " + n);

or the GNU MP native implementation:

 OperableNumber n = (OperableNumber) Program.compile("a = 0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1;",
   ExtendedMathContext.NATIVE.GNUFLOAT512_MATHCONTEXT).execute();
 System.out.println("GnuFloat result: " + n);

 If you want to use automatic paralelization to increase performance you can:

        String program =
                "futureValCompInt = lambda (pv,rate,n){ " +
                "sleep(10);" +
                "return pv * exp(rate * n) * 1.33 *1.33 * 1.33 *1.33 *1.33 * sqrt(10000) ; " +
                "};" +
                "val1 = futureValCompInt(100000, 0.045, 10);" +
                "val2 = futureValCompInt(100000, 0.05, 10);" +
                "val3 = val1 + val2;";

        Program compiledProgram = Program.compile(program);

        // execute single threaded
        Object result1 = compiledProgram.execute();

        // execute with paralelization enabled
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(4, 4,
                10, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(5));
        threadPool.prestartAllCoreThreads();
        Object result2 = ((Future<Object>)compiledProgram.execute( new ConcurrentHashMap<Object, Object>(), null, null, null, threadPool)).get();

  As you can observe when you run the above example the val1 and val2 are computed in parallel doubling your performance.

Keywords: context, print, return, global, sum, avg, rmin, wmax, nvl, custom, count, min, max, vmax, vref, log, exp, sqrt, lambda, arg, null, nill

Arithmetic Operators: = (assign) + (add) - (substract) / (divide) * (multiply) ** (pow)

Boolean Operators: && (and) || (or) ^ (xor)

Comparison Operators: (less) (greater) = (less or equal) = (greater or equal) == (equal) != (not equal)

Other Operators: ? (Conditional operator)

Referencing Operators: . (structure member reference) [] (table reference usefull for numeric and string references)

Sample program:

var1.var2 = (1+2)*2; var3[1].orig=3 ; var3[2].orig=4 ;
context var1; var4 = 2*3+5;
pono = var4 - var2 +global.var3[1].orig-global.var3[2].orig;
print "result:";print pono; value[1].var1[1] = 1;
value[2].var1[2] = 2; value[1].var1[3] = 3;
print "result:"; print rmax("value[`*`].var1[`*`]");
print min("value[`*`].var1[`*`]");
print avg("value[`*`].var1[`*`]");
print sum("value[`*`].var1[`*`]");

How to define your own functions? it is like defining any variable, you do it with an assigment:

Implementation of the fibonacci function using deterministic functions:
fib= lambda deterministic (x) { fib( x-1) + fib( x-2); };
fib(0) = 0;
fib(1)=1;
print fib(10);

"clasical" fibonacci implementation:
fib= lambda(x){ return (x == 0) ? 0 : (x == 1) ? 1 : fib( x-1) + fib( x-2); };
print fib(10);

Other ways of declaring lambda functions:
abc=1; afe=2;bfa =3;x=0;
aSum=lambda(return for(\"`a*`\",lambda(x=x+arg(0);)););
return aSum();

care must be exercised because at this point in time every variable is alocated in the heap. and preety much every variable is global. At a later time I will add a way to define local variables... most likely it will be a special character that will mark them (prefix or suffix)

Built in Functions

sum(`regexp`) Sums up all variables that match the provided simple regular expression.

avg(`regexp`) Averages all variables that match the provided simple regular expression.

wmin(`regexp`) Calculates min of all variables that match the provided simple regular expression.

count(`regexp`) Counts all variables that match the provided simple regular expression.

wmax(`regexp`) Calculates max of all variables that match the provided simple regular expression.

for(`regexp`, function) applies function of every var that matche regexp (example: abc=1; afe=2;bfa =3;x=0;result=for(`a*`,lambda(x=x+arg(0);)); )

lambda( program; ) returns a pointer to the define function

arg( number ) returns function argument by position

nvl(expr, defval) returns expr if expr is not null or defval if expr is null.

min(a,b,c,�..) Returns the minimum from the provided parameters

zin(a) Returns zero if provided parameter is negative

max(a,b,c,�..) Returns the maximum from the provided parameters

vref (variable, level) returns the value of the relative reference from the provided level of the variable ex for variable a[5].b the result for level 1 would be 5 and for level 2 would be "b"

exp(value) exponential function

log(value) natural logarithm function

sqrt(value) square root function

decode(expresion,x1,y1,x2,y2,...,default) if expression = x1 return y1, if expression = x2 return y2 .... else return default value