pub enum Expr {
Lit(ExprLit),
Ref(String),
Unary(UnOp, Box<Expr>),
Binary(BinOp, Box<Expr>, Box<Expr>),
Call(Builtin, Vec<Expr>),
Field(Box<Expr>, String),
Index(Box<Expr>, Box<Expr>),
Let {
name: String,
value: Box<Expr>,
body: Box<Expr>,
},
}Expand description
A pure, total expression in AXON’s closed-catalog expression sublanguage
(v2.26.0). Evaluates to a value with no side effects, no I/O, no recursion
and no unbounded loops — so it is decidable and const-foldable. Mounted as
the condition of an if (and, in later steps, let values + where:
predicates). Field/index access and the builtin catalog land in v2.26.0.
Variants§
Lit(ExprLit)
A typed literal (42, 3.14, true, "hello").
Ref(String)
A reference to a binding or dotted path (x, User.tier).
Unary(UnOp, Box<Expr>)
A unary operation (-x, not x).
Binary(BinOp, Box<Expr>, Box<Expr>)
A binary operation (a + b, a >= b, a and b).
Call(Builtin, Vec<Expr>)
v2.26.0 — a closed-catalog builtin call. args[0] is the receiver
(the value before the .); any further entries are the call arguments.
E.g. recent.length → Call(Length, [Ref("recent")]),
name.starts_with("Dr") → Call(StartsWith, [Ref("name"), Lit(Str)]).
Field(Box<Expr>, String)
v2.26.0 — field access on a non-reference base (items[0].name,
(expr).field). A plain dotted path stays a Ref (a.b.c) for
back-compat; this node is the structured form the JSONB SQL lowering
(deferred v2.26.0) consumes. The String is the field name.
Index(Box<Expr>, Box<Expr>)
v2.26.0 — index access base[index] (array element / string char).
Let
v2.83.0 — let <name> = <value> scoped over <body>: the classic
let-in term, let x = e₁ in e₂.
Why the expression engine and not a list of bindings on the compute.
Every published compute writes a CHAIN —
logic { let a = … let b = … return e } — and the obvious shortcut is
to hang a Vec<(String, Expr)> off ComputeDefinition and substitute at
evaluation time. That is wrong twice over: substitution DUPLICATES the
bound term at every use site (so let t = expensive() evaluates once per
mention, changing cost and, for anything non-total, meaning), and it
confines let to computes when it is a property of expressions.
As a Let term the chain nests — Let(a, e₁, Let(b, e₂, e₃)) — which is
exactly one evaluation per binding, shadowing that falls out of the
nesting instead of being reimplemented, and a let usable anywhere an
expression is.