Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Expression-language reference

panproto-expr evaluates a call-by-value expression AST with no I/O operations. Evaluation is bounded and fallible. The default limits are 100,000 reduction steps, recursion depth 256, and 10,000 elements in list literals and selected list-producing paths. Reaching a limit returns an ExprError. It does not establish that every expression terminates before the limit.

Builtin names are first-class values. A lexical environment binding shadows a builtin of the same name, and an unapplied builtin may be partially applied until it receives its declared arity. eval_with_resolver routes context-dependent builtins through the supplied resolver wherever they occur, including inside lambdas, bindings, and comprehensions.

The language is used for field transforms and instance queries. Expression language: denotational semantics gives the model behind the evaluator.

Surface grammar

panproto-expr-parser accepts a Haskell-style syntax and lowers it to Expr.

FormSyntax
Literals42, 3.5, "text", True, False, Nothing
Lambda and application\x -> body, f x
Bindinglet x = value in body. Layout or braces permit several bindings.
Conditional and matchif p then a else b and case value of { pattern -> body }
Records{ name = value, count }. The second field uses record punning.
Lists[a, b], inclusive range [a..b], comprehension `[f x
Accessrecord.field, list[index], node->edge_name
Sequencinglist-oriented do notation and postfix where bindings

Open-ended ranges such as [a..] are parse errors. The parser lowers map f xs, filter p xs, and flat_map f xs to an AST with the list first and function last. It lowers fold f z xs to [xs, z, f]. This AST argument order is the serialized compatibility contract.

Operators

From lower to higher precedence, the infix operators are pipe &, ||, &&, comparisons (==, /=, <, <=, >, >=), string concatenation ++, addition and subtraction, then multiplication, division, and remainder (*, /, %, div, mod). Unary - and not bind more tightly. And and Or evaluate both AST arguments before applying the builtin. They do not short-circuit.

Values and type tags

Runtime Literal values include booleans, 64-bit integers and floats, UTF-8 strings, bytes, null, records, lists, and closures. Lists can contain values of different kinds. The lightweight ExprType inference API has fewer tags:

ExprTypeMeaning
Int, Float, Str, BoolScalar tags.
ListList with no element-type parameter.
RecordOrdered string-keyed fields.
AnyUnknown or polymorphic. Inference also uses it for null, bytes, and closures.

Type inference is best effort. Application, field access, and indexing generally infer as Any, while evaluation still performs runtime type and arity checks.

Builtins

BuiltinOp currently has 60 variants.

FamilyOperationsContract notes
Arithmetic and roundingAdd, Sub, Mul, Div, Mod, Neg, Abs, Floor, Ceil, RoundInteger arithmetic is checked. Division and remainder reject zero divisors. Float-to-integer rounding rejects NaN, infinity, and out-of-range results.
ComparisonEq, Neq, Lt, Lte, Gt, GteOrdering accepts integer and float pairs, including mixed numeric pairs, or two strings.
BooleanAnd, Or, NotArguments are eager.
StringConcat, Len, Slice, Upper, Lower, Trim, Split, Join, Replace, ContainsLen counts UTF-8 bytes, while Slice indexes Unicode scalar values. Contains also tests list membership.
ListMap, Filter, Fold, FlatMap, Append, Head, Tail, Reverse, Length, RangeRange includes both bounds and returns an empty list when stop < start. The evaluator enforces max_list_len for list literals, Map, FlatMap, and Range. The generic builtin handler does not apply that limit to every list-returning operation.
RecordMergeRecords, Keys, Values, HasFieldIn a merge, fields from the second record replace equal keys from the first.
UtilityDefaultVal, Clamp, TruncateStrDefaultVal substitutes only for null.
CoercionIntToFloat, FloatToInt, IntToStr, FloatToStr, StrToInt, StrToFloatString parses can return ParseError. FloatToInt can return FloatNotRepresentable.
InspectionTypeOf, IsNull, IsListInspect runtime values.
Instance traversalEdge, Children, HasEdge, EdgeCount, AnchorThe pure evaluator returns NoInstanceContext. Use eval_with_instance, eval_with_element_ops, or another BuiltinResolver to supply graph context.

Evaluation errors

ExprError is non-exhaustive.

VariantCause
StepLimitExceededThe reduction budget was exhausted.
DepthExceededRecursive evaluation exceeded max_depth.
ListLengthExceededA list constructor or a budgeted list-producing path exceeded max_list_len.
UnboundVariableThe environment has no binding for a variable.
TypeError, ArityMismatch, NotAFunctionA value or call has the wrong runtime shape.
IndexOutOfBounds, FieldNotFound, NonExhaustiveMatchLookup or pattern matching failed.
DivisionByZero, Overflow, FloatNotRepresentable, ParseErrorA numeric operation or coercion failed.
NoInstanceContextAn instance-traversal builtin was evaluated without an instance resolver.
InternalDispatchA builtin reached the wrong internal family handler.

Source

The AST and builtin enum live in expr.rs, builtin implementations in builtin.rs, evaluation and defaults in eval.rs, and the surface grammar in parser.rs.

See also