Documentation
¶
Overview ¶
Package expr is Atlas's boundary to a FEEL engine. It wraps github.com/pblumer/feel so the rest of Atlas depends on this small, stable surface rather than on the FEEL library's full API.
It implements the ADR-0008 contract: expressions are compiled once at deploy time (parse + type-check + lower to a closure) and evaluated many times with no re-parsing and minimal allocation on the hot path. Compilation also reports an expression's inputs — the variable names it reads — so the engine can load only those from a scope instead of materializing the whole variable set.
Reuse of an existing FEEL engine (versus building our own subset) is exactly what ADR-0008 permits when the library offers a genuine compile-once/eval-many API; feel does. See ADR-0015.
Index ¶
- Variables
- func AsInt(v Value) (int, bool)
- func BuiltinNames() []string
- func CheckCallsError(src string, declared ...string) error
- func ContextKeys(v Value) ([]string, bool)
- func DurationNanos(v Value) (int64, bool)
- func InstantNanos(v Value) (int64, bool)
- func IsTrue(v Value) bool
- func ToJSON(v Value) (string, bool)
- type CallFault
- type Compiled
- type Value
- func AsList(v Value) ([]Value, bool)
- func Bool(b bool) Value
- func ContextMember(v Value, name string) (Value, bool)
- func ContextOf(members map[string]Value) Value
- func DateTime(t time.Time) Value
- func FromJSON(raw any) Value
- func FromStored(kind ValueKind, b bool, text string) Value
- func ListOf(elems ...Value) Value
- func Number(i int64) Value
- func ParseJSON(text string) (Value, error)
- func String(s string) Value
- type ValueKind
Constants ¶
This section is empty.
Variables ¶
var Null = value.Null
Null is the FEEL null value.
Functions ¶
func AsInt ¶
AsInt returns a FEEL number as an int and true if v is a whole number within int range, else 0 and false. Used for a multi-instance loop cardinality (ADR-0077).
func BuiltinNames ¶ added in v0.9.0
func BuiltinNames() []string
BuiltinNames lists every built-in function this build can call, sorted. It is the registry CheckCalls judges against, so anything that offers functions to somebody writing FEEL — a prompt, a picker — and is built from this list cannot offer one that the deploy would then refuse.
func CheckCallsError ¶ added in v0.7.0
CheckCallsError is CheckCalls as one error, or nil when there is nothing to say — the shape a compile step wants.
func ContextKeys ¶ added in v0.20.0
ContextKeys answers a FEEL context's member names in the context's own order, and whether v is a context at all.
func DurationNanos ¶
DurationNanos returns the length in nanoseconds of a FEEL days-and-time duration value (e.g. the result of duration("PT1H")), and whether v is one. A years-and- months duration is calendar-dependent and not convertible to a fixed length, so it reports false — matching the ISO-8601 duration subset Atlas accepts (ADR-0057).
func InstantNanos ¶
InstantNanos returns the unix-nanosecond instant of a FEEL date-time value, or a date (resolved to midnight in its own zone), and whether v is one of those (ADR-0057).
func IsTrue ¶
IsTrue reports whether v is FEEL boolean true. A non-boolean (including null, the result of a failed comparison) is not true — which is how a sequence-flow condition that doesn't evaluate to true is simply not taken.
func ToJSON ¶
ToJSON encodes a FEEL value as canonical JSON, reporting whether it could. It is canonical — object keys are sorted (encoding/json sorts map keys) and numbers keep their exact decimal text — so the same value always yields the same bytes, which replay depends on. ok is false only if the value contains something with no JSON image (it never does for lists/contexts of scalars).
Types ¶
type CallFault ¶ added in v0.7.0
CallFault is one call an expression makes that this build can only answer with null. Name is the callee as written, and Message is the sentence to put in front of whoever wrote it.
func CheckCalls ¶ added in v0.7.0
CheckCalls reports every call in src that this build cannot make: a callee no built-in has, and a built-in called with a number of arguments its signature cannot accept. declared names the variables the caller will bind, which are exempt — a declared variable could hold a function value, and the engine calls it at run time.
A source that does not parse yields no faults: the syntax error is the real fault and the compiler reports it, so saying anything here would be a second message about one mistake.
type Compiled ¶
type Compiled struct {
// contains filtered or unexported fields
}
Compiled is a FEEL expression compiled once. It is immutable and safe for concurrent evaluation (like the CompiledProcess it lives in). Evaluate it with Eval; Inputs reports the variables it reads, and Source the text it was written as.
func Compile ¶
Compile parses, type-checks and lowers src into a reusable form. vars declares the variable names the expression is allowed to reference; referencing a name not in vars is a compile error, which is how deploy-time validation catches a script that reads an undeclared variable.
func CompileAuto ¶
CompileAuto compiles src while discovering the variable names it references: it starts with no declared variables and, each time the FEEL compiler reports an "unknown variable", declares that name and retries, until the expression compiles. This lets a script author reference process variables without declaring them up front, while still letting the compiler — not us — decide what is a genuine free variable (bound loop/quantifier names, path members and built-ins never surface as unknown). A syntax or type error (not a missing declaration) is returned as-is.
func (*Compiled) Eval ¶
Eval evaluates the expression against the given variable bindings. Names in vars that the expression does not read are ignored; declared names absent from vars evaluate as FEEL null.
func (*Compiled) Inputs ¶
Inputs returns the variable names the expression actually reads (sorted, unique) — a subset of the names passed to Compile.
func (*Compiled) Source ¶ added in v0.4.0
Source returns the expression as it was written. A compiled expression is otherwise opaque, so an explanation of what the engine decided — a loop's condition on the replay, a message naming the expression that failed — would have to re-read the model to quote it. Kept once at compile time (deploy), so nothing on the hot path pays for it.
type Value ¶
Value is a FEEL runtime value. Re-exported so engine code refers to expr.Value rather than importing the FEEL value package throughout.
func AsList ¶
AsList returns the elements of a FEEL list value and true, or nil and false if v is not a list. It fans a multi-instance activity's input collection into its per-iteration items (ADR-0077).
func ContextMember ¶ added in v0.20.0
ContextMember answers the member name of a FEEL context, and whether v is a context that holds it. With ContextKeys it is how the template language (expr/feelers) reads a loop item's fields without the rest of Atlas importing the FEEL value package.
func ContextOf ¶ added in v0.20.0
ContextOf builds a FEEL context from values that are already FEEL values — for a binding whose members include something JSON has no image of, such as the instant an authorization request is evaluated at (ADR-0475). Members go in sorted key order, as FromJSON's do, so the context iterates the same way every time.
func DateTime ¶ added in v0.5.0
DateTime returns a FEEL date-and-time value for a Go instant, for building bindings. It exists because a binding that must be *compared* to a moment — a task's due date against `now` — cannot be a number: FEEL's `<` on numbers and its `<` on instants are different comparisons, and only the second one accepts `now + duration("P3D")` on the other side. Binding the instant rather than calling now() inside the expression is also what makes a scan deterministic: every row is judged against one moment instead of each against its own.
func FromJSON ¶
FromJSON converts a decoded JSON value (map[string]any / []any / json.Number / string / bool / nil, as produced by encoding/json with UseNumber) into a FEEL value: an object becomes a context, an array a list, recursively. A number that fails to parse degrades to FEEL null rather than erroring, matching FromStored's defensive contract.
func FromStored ¶
FromStored reconstructs a FEEL value from Atlas's stored form — the inverse of Classify — for binding variables into an evaluation. An unparseable number, or unparseable stored JSON, becomes null.
func ListOf ¶
ListOf builds a FEEL list value from the given elements — the inverse of AsList, for assembling a multi-instance output collection (ADR-0077).
type ValueKind ¶
type ValueKind uint8
ValueKind classifies a FEEL value into the subset Atlas persists: the scalars, plus KindJSON for structured values (objects and lists).
func Classify ¶
Classify reduces a FEEL value to a storable (kind, bool, text) triple: text is the number's canonical decimal string or the string's contents. Lists and contexts are stored under KindJSON as canonical JSON so they round-trip; other non-scalars (temporals, ranges, functions) are rendered to their canonical FEEL text and stored as a string — lossy but stable — until Atlas models them.