morph 0.1.0
Asynchronous bridge between GUI thread and business models
Loading...
Searching...
No Matches
expression.hpp File Reference

The expr/1 expression language of the UI document: parsing a JSON expression into an Expr tree, checking it against the names a document declares, and evaluating it. More...

#include <algorithm>
#include <array>
#include <chrono>
#include <compare>
#include <cstddef>
#include <cstdint>
#include <expected>
#include <functional>
#include <iterator>
#include <map>
#include <memory>
#include <optional>
#include <ranges>
#include <set>
#include <span>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "../render/i18n.hpp"
#include "../render/locale_format.hpp"
#include "../util/datetime.hpp"
#include "../util/rational.hpp"
#include "message.hpp"
#include "value.hpp"

Go to the source code of this file.

Classes

struct  morph::ui::Expr
 One node of a parsed expression. Immutable once parsed; shared between the document and its readers. More...
struct  morph::ui::detail::FunctionSpec
 The signature of a library function. More...
class  morph::ui::detail::ExprParser
 Reads one JSON expression tree into Expr nodes, counting them against the size bound. More...
struct  morph::ui::detail::ExprParser::FormKeys
 The keys a form may carry beside its own. More...
class  morph::ui::NameResolver
 What an expression's names resolve to, for checkExpression: the document's scopes implement it. More...
class  morph::ui::PermissiveResolver
 A resolver that accepts every name as any: for an expression checked outside a document. More...
class  morph::ui::detail::ExprChecker
 Walks an expression once, resolving names and checking the statically known types. More...
struct  morph::ui::UnitInfo
 One unit of the server's unit systems, as x-unitAlternatives declares it. More...
struct  morph::ui::FormatContext
 What the display functions and t format with: the client's locale and its formatting facts. More...
class  morph::ui::Environment
 What an evaluated expression reads: the interpreter implements it over its reactive values. More...
struct  morph::ui::detail::Number
 A number taken apart for arithmetic: its exact value, whether it is an int, and its unit. More...
class  morph::ui::detail::Evaluator
 Evaluates expressions against an environment, with the comprehension variables in scope. More...
class  morph::ui::StaticEnvironment
 An environment that holds its values: for tests, and for evaluating outside a mounted screen. More...

Typedefs

using morph::ui::ExprPtr = std::shared_ptr<Expr const>
 A shared, immutable expression node.
using morph::ui::detail::KindSet = std::uint16_t
 A set of type kinds, as bits.
using morph::ui::UnitTable = std::map<std::string, UnitInfo, std::less<>>
 The units a client knows, by id. A unit missing from the table is its own canonical unit.
using morph::ui::DateFormatter = std::function<std::string(time::DateTime local, std::string_view style, bool withTime)>
 Formats a date for display: the instant already shifted to the display zone, the style (short, medium or long), and whether to show the time.

Enumerations

enum class  morph::ui::ExprKind : std::uint8_t {
  Literal , Ref , Row , Query ,
  Pending , Error , Result , ErrorKind ,
  Can , Pref , Call , If ,
  Object , List , Map , Filter ,
  Env , Session , Host
}
 The forms of an expr/1 expression (spec 5 §4). More...
enum class  morph::ui::FunctionId : std::uint8_t {
  And , Or , Not , Eq ,
  Ne , Lt , Le , Gt ,
  Ge , Add , Sub , Mul ,
  Div , Neg , Round , Engaged ,
  Coalesce , Concat , Format , Trim ,
  Length , IsEmpty , Contains , Count ,
  Sum , Mean , Min , Max ,
  Any , All , First , Includes ,
  IndexOf , Number , DecimalText , QuantityText ,
  Money , Date , DateTime , Translate ,
  ParseDecimal , ConcatLists
}
 The functions of the expr/1 library. More...

Functions

constexpr bool morph::ui::isName (std::string_view text) noexcept
 Whether a string is a document name: [A-Za-z_][A-Za-z0-9_]*.
constexpr KindSet morph::ui::detail::kindBit (TypeKind kind) noexcept
 The bit of one kind.
constexpr FunctionSpec const & morph::ui::detail::functionSpec (FunctionId function)
 The signature of a function.
template<std::size_t N>
constexpr bool morph::ui::detail::oneOf (std::array< std::string_view, N > const &names, std::string_view name) noexcept
 Whether a name is one of a closed set.
std::expected< std::vector< std::string >, std::string > morph::ui::detail::splitPath (std::string_view text)
 Splits head.a.b into its segments.
std::expected< ExprPtr, Refusal > morph::ui::parseExpression (Json const &json, std::string const &path="")
 Parses one expression.
std::vector< std::string_view > morph::ui::functionNames ()
 The names of the expr/1 library, in FunctionId order.
Type morph::ui::detail::typeOfValue (Value const &value)
 The static type of a literal.
std::expected< Type, std::string > morph::ui::detail::typeAlong (Type const &type, std::string_view head, std::span< std::string const > path)
 The type a field path reads from a value of a known type.
std::expected< Type, Refusal > morph::ui::checkExpression (Expr const &expr, NameResolver const &resolver)
 Checks an expression against the names a document declares.
Value morph::ui::walk (Value const &value, std::span< std::string const > path)
 Reads a path out of a value: a record's field by name, a list's element by index.
std::optional< Number > morph::ui::detail::numeric (Value const &value)
 Takes a numeric value apart.
Value morph::ui::detail::makeNumber (math::Rational const &value, bool integer, std::string const *unit)
 Builds a numeric value.
std::optional< math::Rational > morph::ui::detail::convertUnit (math::Rational const &value, std::string_view from, std::string_view target, UnitTable const &units)
 Converts an exact value between two units of one dimension.
std::string morph::ui::detail::unitDisplay (std::string const &unit, UnitTable const &units)
 The display text of a unit.
std::uint32_t morph::ui::detail::currencyDigits (std::string_view currency)
 The fraction digits a currency shows (ISO 4217's minor unit).
Value morph::ui::evaluate (Expr const &expr, Environment const &env)
 Evaluates an expression.

Variables

constexpr std::size_t morph::ui::kMaxExpressionNodes = 256
 The most nodes one expression may have; a document with a larger expression is refused at load.
constexpr KindSet morph::ui::detail::kAllKinds = 0xFFFF
 Every kind.
constexpr KindSet morph::ui::detail::kNumeric = kindBit(TypeKind::Int) | kindBit(TypeKind::Decimal) | kindBit(TypeKind::Quantity)
 The numbers.
constexpr KindSet morph::ui::detail::kOrdered = kNumeric | kindBit(TypeKind::Timestamp) | kindBit(TypeKind::String)
 The ordered kinds.
constexpr std::array< FunctionSpec, 42 > morph::ui::detail::kFunctions
 The library, indexed by FunctionId.
constexpr std::array< std::string_view, 5 > morph::ui::detail::kEnvNames = {"widthClass", "locale", "platform", "online", "backend"}
 The names {"env": ...} reads.
constexpr std::array< std::string_view, 6 > morph::ui::detail::kSessionNames
 The names {"session": ...} reads.

Detailed Description

The expr/1 expression language of the UI document: parsing a JSON expression into an Expr tree, checking it against the names a document declares, and evaluating it.

Specified in docs/spec/ui/expressions.md.

Definition in file expression.hpp.

Typedef Documentation

◆ ExprPtr

using morph::ui::ExprPtr = std::shared_ptr<Expr const>

A shared, immutable expression node.

Definition at line 133 of file expression.hpp.

◆ KindSet

using morph::ui::detail::KindSet = std::uint16_t

A set of type kinds, as bits.

Definition at line 160 of file expression.hpp.

◆ UnitTable

using morph::ui::UnitTable = std::map<std::string, UnitInfo, std::less<>>

The units a client knows, by id. A unit missing from the table is its own canonical unit.

Definition at line 1040 of file expression.hpp.

◆ DateFormatter

using morph::ui::DateFormatter = std::function<std::string(time::DateTime local, std::string_view style, bool withTime)>

Formats a date for display: the instant already shifted to the display zone, the style (short, medium or long), and whether to show the time.

Definition at line 1044 of file expression.hpp.

Enumeration Type Documentation

◆ ExprKind

enum class morph::ui::ExprKind : std::uint8_t
strong

The forms of an expr/1 expression (spec 5 §4).

Enumerator
Literal 

A JSON scalar, or {"lit": v}.

Ref 

{"ref": "name.path"}.

Row 

{"row": "path"}.

Query 

{"query": "q"}: a query's value.

Pending 

{"pending": "q"}: whether a query or mutation is in flight.

Error 

{"error": "q"}: a query's or mutation's error text.

Result 

{"result": "m"}: a mutation's last result.

ErrorKind 

{"errorKind": "m"}: the kind of a query's or mutation's error.

Can 

{"can": "m"}: whether the principal may run a mutation or query.

Pref 

{"pref": "point.path"}: the user's choice at a customization point.

Call 

{"fn": "name", "args": [...]}, and {"t": ...}.

If 

{"if": [cond, then, else]}.

Object 

{"obj": {...}}.

List 

{"list": [...]}.

Map 

{"map": e, "as": "x", "to": e}.

Filter 

{"filter": e, "as": "x", "where": e}.

Env 

{"env": "name"}: the client environment.

Session 

{"session": "name"}: a session attribute.

Host 

{"host": "name"}: a value the application registered with the client.

Definition at line 62 of file expression.hpp.

◆ FunctionId

enum class morph::ui::FunctionId : std::uint8_t
strong

The functions of the expr/1 library.

Definition at line 85 of file expression.hpp.

Function Documentation

◆ isName()

bool morph::ui::isName ( std::string_view text)
nodiscardconstexprnoexcept

Whether a string is a document name: [A-Za-z_][A-Za-z0-9_]*.

Parameters
textThe candidate.
Returns
Whether text is a well-formed name.

Definition at line 45 of file expression.hpp.

◆ kindBit()

KindSet morph::ui::detail::kindBit ( TypeKind kind)
nodiscardconstexprnoexcept

The bit of one kind.

Parameters
kindThe kind.
Returns
Its bit.

Definition at line 165 of file expression.hpp.

◆ functionSpec()

FunctionSpec const & morph::ui::detail::functionSpec ( FunctionId function)
nodiscardconstexpr

The signature of a function.

Parameters
functionThe function.
Returns
Its entry in kFunctions.

Definition at line 261 of file expression.hpp.

◆ oneOf()

template<std::size_t N>
bool morph::ui::detail::oneOf ( std::array< std::string_view, N > const & names,
std::string_view name )
nodiscardconstexprnoexcept

Whether a name is one of a closed set.

Parameters
namesThe set.
nameThe candidate.
Returns
Whether name is in names.

Definition at line 277 of file expression.hpp.

◆ splitPath()

std::expected< std::vector< std::string >, std::string > morph::ui::detail::splitPath ( std::string_view text)
inlinenodiscard

Splits head.a.b into its segments.

Parameters
textThe dotted path.
Returns
The segments, or the reason the path is malformed.

Definition at line 284 of file expression.hpp.

◆ parseExpression()

std::expected< ExprPtr, Refusal > morph::ui::parseExpression ( Json const & json,
std::string const & path = "" )
inlinenodiscard

Parses one expression.

Every form of spec 5 §4 is read; an unknown form, a key that does not belong to its form, a malformed name, an unknown function or wrong arity, a number with a fraction, or more than kMaxExpressionNodes nodes is refused.

Parameters
jsonThe expression's JSON.
pathIts JSON Pointer inside the document, carried by every node and every refusal.
Returns
The expression, or the refusal.

Definition at line 666 of file expression.hpp.

◆ functionNames()

std::vector< std::string_view > morph::ui::functionNames ( )
inlinenodiscard

The names of the expr/1 library, in FunctionId order.

Returns
The names.

Definition at line 672 of file expression.hpp.

◆ typeOfValue()

Type morph::ui::detail::typeOfValue ( Value const & value)
inlinenodiscard

The static type of a literal.

Parameters
valueThe literal.
Returns
Its type; any for null.

Definition at line 766 of file expression.hpp.

◆ typeAlong()

std::expected< Type, std::string > morph::ui::detail::typeAlong ( Type const & type,
std::string_view head,
std::span< std::string const > path )
inlinenodiscard

The type a field path reads from a value of a known type.

Parameters
typeThe type of the head.
headThe head's name, for the reason.
pathThe path.
Returns
any when the path can read something, or why it cannot.

Definition at line 779 of file expression.hpp.

◆ checkExpression()

std::expected< Type, Refusal > morph::ui::checkExpression ( Expr const & expr,
NameResolver const & resolver )
inlinenodiscard

Checks an expression against the names a document declares.

Every reference is resolved through resolver, comprehension variables first; the arguments of a function, the condition of if and the where of filter are checked against their accepted kinds where the argument's type is statically known; a literal t fallback must be in the ui/1 message subset.

Parameters
exprThe expression.
resolverWhat the document's names resolve to.
Returns
The expression's static type (any where it cannot be known), or the refusal.

Definition at line 1024 of file expression.hpp.

◆ walk()

Value morph::ui::walk ( Value const & value,
std::span< std::string const > path )
inlinenodiscard

Reads a path out of a value: a record's field by name, a list's element by index.

Parameters
valueThe value.
pathThe segments.
Returns
The value at the path, or null when a segment does not exist.

Definition at line 1118 of file expression.hpp.

◆ numeric()

std::optional< Number > morph::ui::detail::numeric ( Value const & value)
inlinenodiscard

Takes a numeric value apart.

Parameters
valueThe value.
Returns
The number, or std::nullopt when it is not one.

Definition at line 1157 of file expression.hpp.

◆ makeNumber()

Value morph::ui::detail::makeNumber ( math::Rational const & value,
bool integer,
std::string const * unit )
inlinenodiscard

Builds a numeric value.

Parameters
valueThe exact value.
integerWhether every operand was an int.
unitThe unit, or nullptr.
Returns
A quantity with a unit; an int when integral and every operand was one; a decimal otherwise.

Definition at line 1175 of file expression.hpp.

◆ convertUnit()

std::optional< math::Rational > morph::ui::detail::convertUnit ( math::Rational const & value,
std::string_view from,
std::string_view target,
UnitTable const & units )
inlinenodiscard

Converts an exact value between two units of one dimension.

Parameters
valueThe value in from.
fromIts unit.
targetThe wanted unit.
unitsThe unit table.
Returns
The value in target, its places widened by the decimal places of the conversion ratio; std::nullopt when the units do not convert or the result overflows.

Definition at line 1192 of file expression.hpp.

◆ unitDisplay()

std::string morph::ui::detail::unitDisplay ( std::string const & unit,
UnitTable const & units )
inlinenodiscard

The display text of a unit.

Parameters
unitThe unit id.
unitsThe unit table.
Returns
Its display text, or the id.

Definition at line 1242 of file expression.hpp.

◆ currencyDigits()

std::uint32_t morph::ui::detail::currencyDigits ( std::string_view currency)
inlinenodiscard

The fraction digits a currency shows (ISO 4217's minor unit).

Parameters
currencyThe currency code.
Returns
0, 2 or 3.

Definition at line 1250 of file expression.hpp.

◆ evaluate()

Value morph::ui::evaluate ( Expr const & expr,
Environment const & env )
inlinenodiscard

Evaluates an expression.

Total: it always returns. A function whose required argument is null yields null; and, or and not are three-valued; a type mismatch, an overflow, a division by zero or a unit that does not convert yields null and is reported through Environment::report with the failing node's path.

Parameters
exprThe expression.
envWhat it reads.
Returns
Its value.

Definition at line 2051 of file expression.hpp.

Variable Documentation

◆ kMaxExpressionNodes

std::size_t morph::ui::kMaxExpressionNodes = 256
inlineconstexpr

The most nodes one expression may have; a document with a larger expression is refused at load.

Definition at line 40 of file expression.hpp.

◆ kAllKinds

KindSet morph::ui::detail::kAllKinds = 0xFFFF
inlineconstexpr

Every kind.

Definition at line 170 of file expression.hpp.

◆ kNumeric

KindSet morph::ui::detail::kNumeric = kindBit(TypeKind::Int) | kindBit(TypeKind::Decimal) | kindBit(TypeKind::Quantity)
inlineconstexpr

The numbers.

Definition at line 172 of file expression.hpp.

◆ kOrdered

KindSet morph::ui::detail::kOrdered = kNumeric | kindBit(TypeKind::Timestamp) | kindBit(TypeKind::String)
inlineconstexpr

The ordered kinds.

Definition at line 174 of file expression.hpp.

◆ kFunctions

std::array<FunctionSpec, 42> morph::ui::detail::kFunctions
inlineconstexpr

The library, indexed by FunctionId.

Definition at line 192 of file expression.hpp.

◆ kEnvNames

std::array<std::string_view, 5> morph::ui::detail::kEnvNames = {"widthClass", "locale", "platform", "online", "backend"}
inlineconstexpr

The names {"env": ...} reads.

Definition at line 266 of file expression.hpp.

◆ kSessionNames

std::array<std::string_view, 6> morph::ui::detail::kSessionNames
inlineconstexpr
Initial value:
= {"principal", "userName", "displayName",
"userKey", "tenant", "authenticated"}

The names {"session": ...} reads.

Definition at line 269 of file expression.hpp.