Skip to content

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 name
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 || beither is non-zero (a bool)
a && bboth 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.

Parsing · parse · variables

Evaluating · evaluate

Errors · ExpressionError


static Expression* parse(String* text) throws

The expression text holds, ready to evaluate. Throws an ExpressionError for text that is not one expression.

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.

↑ Topics

Number* evaluate(void) throws
Number* evaluate(Map* vars) throws

The 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).

↑ Topics

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'.

↑ Topics