Expression
Expression parses an arithmetic expression once and evaluates it as often as
needed against a set of variables (NSExpression in shape): a computed column,
a rule such as price * qty, or the arithmetic of a small scripting layer.
From 0.72.
#import "Expression.xc" // not in the Foundation umbrella: import it by nameOverview
Section titled “Overview”try { Expression* e = Expression.parse(String.withCString("qty * price + tax")); Map* vars = new Map(); vars.set(String.withCString("qty"), Number.withI64((i64)3)); vars.set(String.withCString("price"), Number.withI64((i64)200)); vars.set(String.withCString("tax"), Number.withDouble(12.5d)); Stdio.printf("%@\n", e.evaluate(vars)); // 612.500000 }catch (ExpressionError x) { Stdio.printf("%s\n", x.message().cString()); }The language, from the loosest binding to the tightest:
a || b | either is non-zero (a bool) |
a && b | both are non-zero (a bool) |
== != < > <= >= | compare (a bool) |
+ - | add, subtract |
* / % | multiply, divide, remainder |
- ! + | negate, not, plus (prefix) |
42 0x2A 2.5 1e3 true false name f(a, b) ( … ) | values |
Names are letters, digits and _ after a letter or _. The functions are
min and max (one or more arguments) and abs (one). && and || evaluate
their right side only when they need it, so 0 && missing is false even
with no value for missing.
Numbers. Values are Numbers. An operation on two
integers stays an exact 64-bit integer (wrapping on overflow, as i64 does):
/ truncates toward zero and % takes the sign of the left side, so -7 / 2
is -3 and -7 % 3 is -1. If either side is a double, the operation is done
in double. A comparison or a logical operator gives
Number.withBool. A literal with a . or
an exponent is a double, read exactly as JSON reads
one.
Topics
Section titled “Topics”Evaluating · evaluate
Errors · ExpressionError
Parsing
Section titled “Parsing”static Expression* parse(String* text) throwsThe expression text holds, ready to evaluate. Throws an
ExpressionError for text that is not one expression.
variables
Section titled “variables”Array* variables(void)The names of the variables it uses (Strings), each once, in the order they
first appear: a * b + a - c gives a, b, c.
Evaluating
Section titled “Evaluating”evaluate
Section titled “evaluate”Number* evaluate(void) throwsNumber* evaluate(Map* vars) throwsThe value, with each variable taken from vars, a Map
from its name (a String) to a Number. Throws an
ExpressionError for a variable with no Number in vars,
and for an integer / or % by zero (a double division by zero gives inf,
as in C).
Errors
Section titled “Errors”ExpressionError
Section titled “ExpressionError”class ExpressionError <Error>String* message(void)What parse and evaluate throw. A parse error gives
the byte offset, as in bad expression at byte 6: expected ')'; an evaluation
error names the problem, as in no Number for the variable 'qty'.