expr

package
v0.7.3 Latest Latest
Warning

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

Go to latest
Published: Oct 6, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

Package expr is the funcd reference engine (ADR-0095): one typed `${{ … }}` expression grammar shared across the platform. The contents of `${{ … }}` are native JavaScript, parsed and evaluated by goja (pure-Go ECMAScript); funcd runs a type-checker over goja's parser AST that admits only a typed subset and rejects the rest at reconcile — so every expression is statically checkable against a JSON-Schema contract before anything runs, in a language users already know.

Two modes: Select (a reference or computed value, returned by Eval) and Condition (a boolean expression, returned by EvalBool). The lifecycle is always Parse → Check → Eval/EvalBool: Parse validates the grammar, Check validates every path/type/operator against a context-scoped Resolver, and Eval/EvalBool run the compiled program against the actual documents. Eval before a successful Check (or in the wrong mode) is a programming error surfaced as a fault.Internal, never a panic.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Budget added in v0.3.0

type Budget struct {
	// contains filtered or unexported fields
}

Budget is what evaluations spend together: the length of the strings their concatenations, literals and replaceAll calls build or hold, their running time, and how much larger than their documents their results are. Eval and EvalBool spend a fresh Budget per call. A consumer that builds one value from several expressions over the same documents (a Sensor action input, ADR-0109) evaluates them within one Budget, so splitting an expression into many does not multiply what it may cost. A Budget is not safe for concurrent use.

func NewBudget added in v0.3.0

func NewBudget() *Budget

NewBudget returns the budget of one evaluation.

type Expr

type Expr struct {
	// contains filtered or unexported fields
}

Expr is a parsed (and, after Check, validated) expression. It is safe to Check once and then Eval/EvalBool concurrently.

func Parse

func Parse(src string, mode Mode) (*Expr, error)

Parse validates the `${{ … }}` wrapper and parses its JavaScript with goja's parser. Grammar errors are positioned fault.Invalid. The whole source must be a single `${{ … }}` template — no surrounding text (no string interpolation).

func (*Expr) Check

func (e *Expr) Check(r Resolver) error

Check statically validates the expression against the resolver: every reference path exists and is typed, every operator/method matches its operand types, only the admitted JS subset is used, the defaults rule holds (an optional field must declare a default or be `!== undefined`-guarded), and — in Condition mode — the whole expression is boolean. It records the referenced roots and defaulted references so Eval needs no resolver.

func (*Expr) Eval

func (e *Expr) Eval(docs map[string]json.RawMessage) (json.RawMessage, error)

Eval evaluates a Select-mode expression against the documents (keyed by matched root) and returns the referenced or computed value. It must be called only after a successful Check on a Select-mode expression.

func (*Expr) EvalBool

func (e *Expr) EvalBool(docs map[string]json.RawMessage) (bool, error)

EvalBool evaluates a Condition-mode expression and returns its boolean result. It must be called only after a successful Check on a Condition-mode expression.

func (*Expr) EvalWithin added in v0.3.0

func (e *Expr) EvalWithin(b *Budget, docs map[string]json.RawMessage) (json.RawMessage, error)

EvalWithin is Eval spending b, which it shares with the other evaluations within b (see Budget).

func (*Expr) Roots

func (e *Expr) Roots() []string

Roots reports the distinct root documents the expression references, populated after a successful Check (nil before).

type Field

type Field struct {
	// Type is the JSON-Schema type: "string", "number", "integer", "boolean",
	// "array" or "object". A Resolver typing paths from the actual documents leaves
	// it empty (with Required false) for a field missing from its document: only an
	// `X !== undefined` probe may read it, and that guard's && operand goes unread.
	Type string
	// Items is the element type when Type == "array"; empty otherwise.
	Items string
	// Required reports whether the field is required by its schema.
	Required bool
	// HasDefault reports whether the schema declares a default for the field.
	HasDefault bool
	// Default is the declared default, substituted at evaluation when absent.
	Default json.RawMessage
}

Field is what a Resolver reports for a resolved path: the JSON-Schema type, the element type for arrays, whether the field is required, and its declared default.

type Mode

type Mode int

Mode selects the grammar's evaluation mode.

const (
	// Select allows a reference or computed value and returns it from Eval.
	Select Mode = iota
	// Condition requires a boolean expression and returns it from EvalBool.
	Condition
)

type Resolver

type Resolver interface {
	// Roots reports the root documents this resolver exposes.
	Roots() []string
	// Resolve reports the Field at path under root: fault.NotFound when the path is
	// absent from the schema, fault.Invalid for a malformed request.
	Resolve(root string, path []string) (Field, error)
}

Resolver answers path lookups against a consumer's JSON-Schema contracts. Implementations are context-scoped: Roots reports the exposed root documents (Check matches an expression's leading member segments against it, longest-first) and Resolve reports the Field at a path under one of those roots. Resolve(root, nil) with Required false and no default marks an optional root (ADR-0166): Check admits a longer reference under it only in the right operand of `root !== undefined && …`. Only a document-backed Resolver reports an absent root, as the zero Field; Eval binds it as undefined.

Jump to

Keyboard shortcuts

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