Help us shape the future of Go! Take the 2026 Go Developer Survey

expr

package
v0.21.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 29, 2026 License: AGPL-3.0 Imports: 10 Imported by: 0

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

Constants

This section is empty.

Variables

View Source
var Null = value.Null

Null is the FEEL null value.

Functions

func AsInt

func AsInt(v Value) (int, bool)

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

func CheckCallsError(src string, declared ...string) error

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

func ContextKeys(v Value) ([]string, bool)

ContextKeys answers a FEEL context's member names in the context's own order, and whether v is a context at all.

func DurationNanos

func DurationNanos(v Value) (int64, bool)

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

func InstantNanos(v Value) (int64, bool)

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

func IsTrue(v Value) bool

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

func ToJSON(v Value) (string, bool)

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

type CallFault struct {
	Name    string
	Message string
}

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

func CheckCalls(src string, declared ...string) []CallFault

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

func Compile(src string, vars ...string) (*Compiled, error)

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

func CompileAuto(src string) (*Compiled, error)

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

func (c *Compiled) Eval(vars map[string]Value) (Value, error)

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

func (c *Compiled) Inputs() []string

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

func (c *Compiled) Source() string

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

type Value = value.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

func AsList(v Value) ([]Value, bool)

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 Bool

func Bool(b bool) Value

Bool returns a FEEL boolean value.

func ContextMember added in v0.20.0

func ContextMember(v Value, name string) (Value, bool)

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

func ContextOf(members map[string]Value) Value

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

func DateTime(t time.Time) Value

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

func FromJSON(raw any) Value

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

func FromStored(kind ValueKind, b bool, text string) Value

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

func ListOf(elems ...Value) Value

ListOf builds a FEEL list value from the given elements — the inverse of AsList, for assembling a multi-instance output collection (ADR-0077).

func Number

func Number(i int64) Value

Number returns a FEEL number value for an integer, for building bindings.

func ParseJSON

func ParseJSON(text string) (Value, error)

ParseJSON decodes canonical JSON text into a FEEL value, the inverse of ToJSON. Numbers are read exactly (json.Number) so decimals aren't routed through a float before FEEL parses them.

func String

func String(s string) Value

String returns a FEEL string value.

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).

const (
	KindNull ValueKind = iota
	KindBool
	KindNumber
	KindString
	// KindJSON is a structured value (list or context). Its text is a canonical
	// JSON encoding, re-parsed by FromStored into a FEEL list/context.
	KindJSON
)

func Classify

func Classify(v Value) (ValueKind, bool, string)

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.

func (ValueKind) Label added in v0.9.0

func (k ValueKind) Label() string

Label is the word a kind is shown under wherever a result reaches a person: the FEEL evaluate route sends it, and the FEEL assistant reports its own checks with it, so the two cannot come to describe one result differently.

Directories

Path Synopsis
Package feelers renders the template language Atlas's forms already speak.
Package feelers renders the template language Atlas's forms already speak.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL