ExpressionEngine.h header

#include <ew/core/ExpressionEngine.h>

Namespace ew::core

Evaluation struct

struct ew::core::Evaluation

The result of evaluating an expression: its value, or the error that stopped it.

Members

std::optional<Value> ew::core::expression::Evaluation::value

The computed value, absent when the expression failed.

QString ew::core::expression::Evaluation::error

Why it failed, empty on success. One of the tokens "#REF!" (a name that does not resolve), "#CIRC!" (a reference cycle), "#DIV/0!" (division by zero) or "#ERR!" (a malformed expression, arithmetic on non-numeric text, or a function given the wrong arguments) – or, where the bindings supply one, a sentence naming the offending name.

Functions

Evaluation ew::core::expression::evaluate(const QString &expression, const Bindings &bindings)

Evaluates expression, resolving its names through bindings.

The language, shared by every surface that takes an expression:

  • decimal numbers, double-quoted text ("hello", with "" for an embedded quote), and the keywords TRUE and FALSE (1 and 0);
  • arithmetic + - * / with the usual precedence, parentheses, and unary minus;
  • the comparisons = == <> != < > <= >=, yielding 1 for true and 0 for false; two numbers compare numerically, anything else as text;
  • the boolean operators AND, OR and NOT (also spellable !), written between or before their operands – gold >= 50 AND NOT hasKey – and binding more loosely than the comparisons, so a condition reads the way it is said;
  • names, resolved by bindings: a cell or range in a spreadsheet, a variable in a branching condition, a field of the object under test (or of one it references) in a validation rule;
  • the aggregate functions SUM, PRODUCT, AVERAGE, MIN, MAX, COUNT and DISTINCT over comma-separated arguments (a name standing for a collection contributes all of its values);
  • the math functions ABS, INT, SQRT, POWER(base, exp), MOD(a, b), ROUND(value[, digits]);
  • the logical functions IF(condition, then, else), AND, OR, NOT; and
  • the text functions CONCAT(...), LEFT(text, n), RIGHT(text, n), MID(text, start, length), LEN(text) (also LENGTH), WORDCOUNT(text), UPPER(text), LOWER(text), TRIM(text), ISEMPTY(value), CONTAINS(text, part), STARTSWITH(text, part), ENDSWITH(text, part) – those three case-insensitive – and MATCHES(text, pattern), testing against a regular expression; and
  • COUNTIF(values..., wanted), how many of the values equal the LAST argument, which is what asks whether a list contains something, or contains only that, or contains none of it.

QString ew::core::expression::expressionProblem(const QString &expression, const Bindings &bindings)

The problem an author must fix before expression can be saved, or an empty string when it is well formed: a malformed expression, or the first name bindings cannot resolve.

Checked WITHOUT the real values, so an expression is judged on what it says rather than on what today's data happens to make it say: price <= 10000 is savable whether or not this object's price is over the line – being false is the whole point of a validation rule.

QStringList ew::core::expression::namesIn(const QString &expression, const Bindings &bindings)

Every name expression mentions, in the order written, with duplicates kept.

A function call is not a name: SUM(price) mentions price. Text inside quotes is not a name either. This is what an editor underlines and what a spreadsheet builds its dependency graph from, so the tokenizer that finds them is the same one that evaluates them – two scanners that disagreed about where a name ends would disagree about what depends on what.

QString ew::core::expression::syntaxProblem(const QString &expression)

The problem with expression's FORM alone – brackets, operators, function arity – judged without any subject to resolve its names against, or an empty string when the form is sound.

For the places that must judge an expression before anything exists to run it on: a rule scoped to a category that is currently empty, an import, a tool call made before the objects are written. Every name is assumed to exist. expressionProblem is the stricter check an editor uses, and is what catches a misspelt name.