pub enum Expr {
Show 13 variants
Struct {
name: String,
name_span: ExprSpan,
fields: Vec<RecordInit>,
span: ExprSpan,
},
Literal {
value: Literal,
span: ExprSpan,
},
Ident {
name: String,
span: ExprSpan,
},
Op {
name: String,
operands: Vec<Expr>,
span: ExprSpan,
},
Apply {
callee: Box<Expr>,
args: Vec<Expr>,
span: ExprSpan,
},
Member {
receiver: Box<Expr>,
name: String,
name_span: ExprSpan,
args: Option<Vec<Expr>>,
span: ExprSpan,
},
Tuple {
elements: Vec<Expr>,
span: ExprSpan,
},
Array {
elements: Vec<Expr>,
type_annotation: Option<TypeExpr>,
annotation_span: Option<ExprSpan>,
span: ExprSpan,
},
TupleIndex {
base: Box<Expr>,
index: usize,
span: ExprSpan,
},
If {
cond: Box<Expr>,
then_branch: Box<Expr>,
else_branch: Option<Box<Expr>>,
span: ExprSpan,
},
Logical {
op: LogicalOp,
lhs: Box<Expr>,
rhs: Box<Expr>,
span: ExprSpan,
},
Cast {
expr: Box<Expr>,
type_name: String,
span: ExprSpan,
},
Closure {
params: Vec<ClosureParam>,
body: Box<Expr>,
span: ExprSpan,
},
}Expand description
A parsed CEL expression with source spans on every node.
Built by AstContext; consumed as-is by adam-lang (method
bodies/initializers), the language server (hover/goto), the formatter, and the future
macro-compilation backend. Carries no resolved types or operator overloads — resolution is
deferred to a later, separate type-checking phase.
Logical is kept distinct from If (rather than desugaring a || b to
if a { true } else { b }, which is how DynSegmentContext
executes it) so a formatter can round-trip a || b as a || b.
Variants§
Struct
A named record constructor, unresolved until semantic checking.
§Examples
use cel_parser::{AstContext, Expr, OpLookup, Parser};
let expr = Parser::<AstContext>::new(OpLookup::new())
.parse_str_ast("Point { x: 1.0 }").unwrap();
assert!(matches!(expr, Expr::Struct { fields, .. } if fields.len() == 1));Fields
fields: Vec<RecordInit>Field labels and expressions in their written evaluation order.
Literal
A literal value (10i32, "x", true, (), …).
Ident
A bare identifier reference or zero-arg builtin lookup (x, pi) — unresolved.
Op
A prefix (arity 1) or infix (arity 2) operator application (-x, a + b, a == b).
Fields
Apply
A call: callee(args...) — the grammar’s "()" operator.
Fields
Member
A direct receiver operation (receiver.name or receiver.name(args...)).
The label is not an identifier reference. Type and overload resolution are deferred.
§Examples
use cel_parser::{AstContext, Expr, OpLookup, Parser};
let expr = Parser::<AstContext>::new(OpLookup::new()).parse_str_ast("a.x()").unwrap();
assert!(matches!(expr, Expr::Member { args: Some(args), .. } if args.is_empty()));Fields
Tuple
A tuple literal ((a, b, ...); a 1-tuple is (a,)).
Fields
Array
An array literal ([a, b, ...], [a, b]: [T], or []: [T]). An unannotated empty array
is still rejected by the grammar (see https://github.com/stlab/cel-rs/issues/212), but
a typed empty array is recorded here with elements.is_empty(). type_annotation stores
the complete recursive array type exactly as written, including nested arrays and custom
leaf names such as Custom. Whether the elements share one type, whether
type_annotation names a complete array type are deferred to the later type-checking phase (see the module doc
comment), same as TupleIndex’s deferred bounds check.
Fields
TupleIndex
A tuple index (base.N). Whether base is actually a tuple and N is in range is
unchecked here — deferred to the type-checking phase (see the module doc comment).
Fields
If
An if cond { then } else { else_ } expression.
Fields
Logical
A short-circuiting &&/||.
Fields
Cast
A cast (expr as Type). Whether type_name is a recognized type and whether a
conversion from expr’s type exists is unchecked here — deferred to the type-checking
phase (see the module doc comment), same as TupleIndex’s deferred bounds check.
Fields
Closure
A closure literal (|x: i32| x + 1, or || 1i32 with no parameters).