Tiny Expression Evaluator (or TinyEE) is a simple expression language running on .NET's Dynamic Language Runtime.
Its main strengths are:
- Simple syntax: everything is an expression that returns a value. There is no looping, assignment or side-effect to worry about.
- Easy to use and integrate with other system. The dll is tiny and there is no external dependency other than the core .NET framework
It's designed to be a power tool for domain experts to define rules and calculations that augment an existing system.
##Quick start The easiest way to use TinyEE is to call its static method Tee.Evaluate(expression) :
TEE.Evaluate("2^20") //returns 1048576To use variables in your expression, pass in an object as the second parameter (dictionary and callback delegate are also supported).
TEE.Evaluate("z = (x+y)^3 = x^3 + 3*x^2*y + 3*x*y^2 + y^3", new{x=3,y=2,z=125})
//returns TrueFor cases when an expression is evaluated multiple times (such as in a plotting app), you can improve performance using cached compilation. The struct returned by Compiled() holds a reference to a compiled delegate, which can be invoked repeatedly without incurring any parsing overhead:
var expr = parsedExpr.Compile("x^3 + 3*x^2*y + 3*x*y^2 + y^3");//compiled
var result1 = expr.Evaluate(new{x=2,y=3});//result1 = 125
var result2 = expr.Evaluate(new{x=5,y=4});//result2 = 729To get the list of variables in an expression, get a ParsedExpression:
var parsedExpr = TEE.Parse("z = x^3 + 3*x^2*y + 3*x*y^2 + y^3");
var variables = parsedExpr.Variables;//variables = [z,x,y]##Syntax Reference The syntax borrows a lot from C#, JavaScript and Excel formula. When in doubt, there are 2 things to remember:
- Everything is a value expression.
- Everything is dynamic.
Literal data types
| Type | Example | CLR type |
|---|---|---|
| Null | null | null |
| String | "A Review of \"A Tale of Two Cities\" and \"Moby Dick\"" | System.String |
| Boolean | True, False | System.Boolean |
| Integer | -1234567890 | System.Int32 |
| Decimal | +1234567890.555 | System.Double |
| Integer range | 0..1048576 | IEnumerable<int> (lazily-evaluated) |
| List | ["a string", 12, true, [0,1,2]] | Object[] |
| Hash | { name:"Yoda", age:900, isMaster:true } | Dictionary<string,object> |
Basic Arithmetics
| Type | Example |
|---|---|
| Addition | x + y |
| Subtraction | x - y |
| Multiplication | x * y |
| Modulo | x % y |
| Power | x ^ y |
| Negation | -x |
Comparision
| Type | Example |
|---|---|
| Equal | x = y |
| Not Equal | x <> y |
| Greater than | x > y |
| Greater than or Equal | x >= y |
| Less than | x < y |
| Less than or Equal | x <= y |
Logical
| Type | Example |
|---|---|
| AND | x and y |
| OR | x or y |
| NOT | not x |
Object
| Type | Example | Note |
|---|---|---|
| Variable | x + $math.Max(y,z) | Variable names are case-sensitive, x and X are not the same. Their names must start with a character or the dollar sign ($). |
| Method call | "anton".ToUpper() | |
| Member Access | person.Name.Length | |
| Indexer Access | table.Rows[0]["column-0"] | |
| Global function call | SUM(x,y) | Note that global function names are allow to be case-insensitive, SUM() and sum() are the same. |
| Grouping | (x + y) * z |
Branching
| Type | Example | Note | |||
|---|---|---|---|---|---|
| Conditional | booleanVar ? "value-if-true" : "value-if-false" | ||||
| Coalescing | nullableVar ?: "fallback-value" | This is similar to c#'s ?? operator or Javascript's use of ||. Unlike Javasript, however, this operator does not perform type conversion. |
Chaining and nesting Almost all expression can be chained or nested.
- Property and indexer:
table01A.Rows[3]["col3"]
- Function call:
100>10 ? Sum(Max(1,2),Max(0,1),Max(-5,3)) : Sum(Min(-2,-3),Min(1,2))
- Comparision:
x > y > z
- Conditional:
condition1
? "value 1"
: condition2
? "value 2"
: "value 3"
Operator precedence and associativity
The following table shows all operators in order of precedence from highest to lowest:
| Operator type | Operator |
|---|---|
| Primary | () f(x) x[y] x.y |
| Arithmetics | - ^ * / % + - |
| Comparison | = > < >= <= <> |
| Boolean | not and or |
| Branching | x?:y x?y:z |
All expressions are evaluated from left to right. The expression 2^2^2^2, for example, is evaluated as ((2^2)^2)^2 == 256 (same as in C# and Excel (but differs from Mathematical convention))
##Main APIs
| Class | Function | Description |
|---|---|---|
| TinyEE.TEE | Evaluate(string):object | Parse, compile and evaluate an expression with no variables |
| Evaluate(string,object):object | Parse, compile and evaluate an expression with a context object. Variables within the expression are resolved using the context's properties and fields. Both anonymous and named objects are supported. | |
| Evaluate(string,Func<string,object>):object | Parse, compile and evaluate an expression with a context functor. The functor will be called when a variable needs to be resolved. | |
| Parse(string):ParsedExpression | Parse an expression (no compilation or evaluation yet). The metadata from the returned object can be useful in building a dependency graph or in transforming to another language. | |
| Compile(string):CompiledExpression | Parse and compile an expression (no evaluation yet). The returned struct simply wraps around a delegate to the compiled code and can be called over and over again. |
##Benchmark //TODO
##Credits TinyEE's parser and scanner are generated by Herre Kuijpers's excellent Tiny Parser Generator. All thanks go to him.
##License MS-PL