core

package
v0.20.2 Latest Latest
Warning

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

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

Documentation

Overview

Plik: flow/core/resolver.go

Index

Constants

View Source
const VersionUnknown = "dev"

VersionUnknown marks a compiler with no release identity. It is the default for `go run` and for binaries built without the linker's -X github.com/nexssp/flow/cli.Version=... injection.

Variables

View Source
var Version = VersionUnknown

Version is the compiler version string that the @flow_version directive compares against. It is populated by the CLI at init time from its linker-injected build metadata. When a test or embedded runner leaves it unset, VersionUnknown tells the directive to accept any constraint — a source build has no release identity to compare.

Functions

func Analyze

func Analyze(resolver CapabilityResolver, expr Expr) error

Analyze runs polymorphic contract validation on the AST. It is a compile-time gate: any edge whose producer output cannot be coerced into the consumer input fails here, before Execute is ever reached.

The rule mirrors runtime Coerce exactly — nominal assignability first, then a JSON round-trip for the same struct-to-struct cases the runtime decoder handles. If a pipeline compiles here, it will not fail at runtime with "cannot coerce input into target".

func ApplyConstants added in v0.19.0

func ApplyConstants(lines []string, start int, constants map[string]string)

ApplyConstants rewrites `${key}` references in lines[start:] to their declared values. It is the single substitution primitive for compile-time constants; both the @const directive handlers and the @include merge path call it.

Substitution is textual and idempotent: an already-substituted value no longer contains a `${...}` pattern, so re-application over the same slice is a no-op. Lines that contain no `${` are skipped without a replacement pass, keeping the common case free of allocations.

lines is mutated in place. start is a half-open lower bound: lines [0, start) are untouched.

func AtomNames

func AtomNames(e Expr) []string

func Build

func Build(
	ctx context.Context,
	resolver CapabilityResolver,
	modifiers *ModifierTable,
	e Expr,
	advisers ...AtomAdviseFunc,
) (action.AnyAction, error)

Build lowers an AST into a runnable action tree, resolving every capability through the supplied resolver.

The function is a thin dispatcher: every node implements its own Build method. Core never switches on concrete AST types.

func BuildEnv

func BuildEnv(input any) map[string]any

func ComposedPipe

func ComposedPipe(left, right action.AnyAction) action.AnyAction

ComposedPipe is the Flow adapter for Kernel's dynamic pipe composition. Flow owns the DSL/lowering decision; Kernel owns invocation, cancellation, error propagation, and lifecycle behavior.

func Decode

func Decode[T any](raw map[string]string) (T, error)

Decode mapuje string map na typowany struct opcji. To jest kontrakt, którego każdy zewnętrzny Bundle używa do odczytu swojego bloku @require.

Tagi:

flow:"key"      nazwa klucza w bloku @require
default:"..."   wartość gdy klucz nieobecny

Nieznane klucze są odrzucane — literówka w .nflow ma się wywalić głośno przy ładowaniu, nie cicho zdefaultować.

Obsługiwane typy pól: string, bool, int, int64, time.Duration, float64. Każdy inny to błąd projektowy Bundle.

func IndexTopLevel

func IndexTopLevel(s string, target byte) int

IndexTopLevel returns the index of the first occurrence of target in s at bracket depth zero, outside quoted strings. Returns -1 when absent. Companion to SplitTopLevel.

func IsReservedActionName added in v0.14.0

func IsReservedActionName(name string) bool

IsReservedActionName reports whether name is reserved by the nflow grammar.

func ModifierName added in v0.14.0

func ModifierName(raw string) string

ModifierName returns the name portion of a raw modifier string, before any '='.

func ModifierOwnerName added in v0.14.0

func ModifierOwnerName(owner ModifierOwner) string

ModifierOwnerName renders an owner for use in error messages.

func ModifiersToMap

func ModifiersToMap(modifiers []string) map[string]any

ModifiersToMap parses a slice of raw modifier strings (e.g. "ext=txt", "by=rel_path", "tests") into a map of parameters for stream sources and operators.

func ParseBlockOptions

func ParseBlockOptions(lines []string, start int) (opts map[string]string, next int, err error)

ParseBlockOptions reads a `{ key: value, ... }` block via ReadBlock and parses each entry as a `key: value` pair. Returns nil for an empty block.

func ParseList

func ParseList(line string) []string

ParseList extracts the first bracketed list `[a, b, c]` from a line. Returns nil for `[]` or when no brackets are present.

func Preprocess

func Preprocess(ctx context.Context, dt *DirectiveTable, source, file string) (clean string, meta map[string]any, err error)

Preprocess executes directives from the dt table.

Cycle detection uses a call-stack, not a global set. This allows diamond dependencies (A → B → common, A → C → common) while still catching true cycles (A → B → A). The error message carries the exact include chain so the user sees which edge closes the loop.

Source fragments referenced by directives are read through the loader installed with WithSourceLoader; the default reads from the filesystem.

func PreprocessDots

func PreprocessDots(src string) string

PreprocessDots rewrites a user-authored expression for expr-lang: leading-dot references become bare identifiers (`.name` → `name`), a bare `.` becomes `__root__`, and `.` after an identifier, `)`, `]`, `#`, or `@` is left alone as member access.

Quoted strings (`"`, `'`, “ ` “) are copied verbatim; backslash escapes inside them are honored, so a `.` inside `"a.b"` survives untouched. This is the single implementation used by assert, loop, match, @on_error, and projection — no other package should implement its own dot rewriting.

func ReadBlock

func ReadBlock(lines []string, start int) (body []string, next int, err error)

ReadBlock extracts the raw body of a `{ ... }` block starting at lines[start]. Handles all three shapes uniformly:

inline:      @x NAME { a: 1, b: 2 }
multi-line:  @x NAME {
               a: 1
               b: 2
             }
tail-brace:  @x NAME {
               a: 1
               b: 2 }

Returns one entry per top-level comma-separated element. Callers interpret entries: `key: value` for @config/@llm/@sandbox/@pool, `Field Type` for @schema.

Comments (`#`, `//`) and blank lines inside the block are dropped.

func Register

func Register(id string, factory BundleFactory)

Register registers a bundle factory under the given ID.

func RegisterBoundary

func RegisterBoundary(spec BoundarySpec)

func RegisterBundle

func RegisterBundle(id string, factory BundleFactory)

RegisterBundle to alias do Register dla pełnej kompatybilności.

func RunAction

func RunAction() *action.BuiltAction[RunReq, RunRes]

func SourceError

func SourceError(pos Position, format string, args ...any) error

SourceError creates a compile-time error carrying pos. The returned error implements Positioned, so diagnostics can extract the exact file:line:col — no string parsing required.

%w in format is passed to fmt.Errorf, so wrapped errors are reachable via errors.Is / errors.As as usual.

func SplitTopLevel

func SplitTopLevel(s string, sep byte) []string

SplitTopLevel splits s on sep, respecting quoted strings (" ' `), balanced brackets, and backslash escapes. Returns the raw segments, not trimmed. Callers trim themselves.

func StripExprComments added in v0.19.0

func StripExprComments(raw string) string

StripExprComments removes `#` comments from an expression that will be handed to expr-lang.

`#` is depth-aware: inside parentheses `#` is expr-lang's iterator placeholder — filter(# > 0), all(items, # != "x"), map(#.name) — and survives verbatim. Only at parenthesis depth 0 does `#` begin a comment, because that is the only position where a bare `#` would be syntactically invalid in expr-lang.

Line terminators (\n, \r\n) are preserved so any error expr-lang reports keeps its line number aligned with the source text the expression was cut from. That alignment is what wrapMacroError and the projection diagnostic rely on.

Every path that hands user-authored text to expr-lang goes through this function: @assert, assert(), loop() until, match() conditions, @on_error conditions and targets, and projection bodies.

func SuggestModifierFix

func SuggestModifierFix(target action.AnyAction, name string) string

SuggestModifierFix returns a human-readable explanation for why a modifier name cannot be applied to a given action, or empty when no better fix than "unknown modifier" is available.

The dominant real-world mistake: the author writes :file=... where the action takes @{ file: ... }. The check against the action's Req struct catches that before the runtime sees a modifier-table miss.

func TranslateKeyword added in v0.14.0

func TranslateKeyword(name string) (string, bool)

TranslateKeyword resolves a parsed atom name to its canonical action name. It returns ("", false) when name is not a native keyword.

func TrimQuotes

func TrimQuotes(s string) string

TrimQuotes removes one matched pair of surrounding quotes (" ' `), or returns s unchanged.

func ValidateBundle

func ValidateBundle(b Bundle) error

func ValidateModifierValue added in v0.14.0

func ValidateModifierValue(kind ModifierKind, value string) error

ValidateModifierValue checks that value matches the modifier's kind. It does not run Apply; callers that mutate a builder use it to fail fast with a stable message before invoking the handler.

func WithCompileConfig

func WithCompileConfig(ctx context.Context, cfg map[string]string, cliArgs []string) context.Context

func WithSourceLoader added in v0.17.0

func WithSourceLoader(ctx context.Context, loader SourceLoader) context.Context

WithSourceLoader installs a loader for directive-referenced sources. The default loader reads from the filesystem.

func WithStrict

func WithStrict(ctx context.Context) context.Context

WithStrict returns ctx marked for strict validation.

Types

type ArgFieldSpec added in v0.14.0

type ArgFieldSpec struct {
	Name string
	Kind ArgKind
	// Optional suppresses the default required-field check for capability
	// references. It has no effect on ArgAny, ArgString, ArgInt, or ArgBool.
	Optional bool
}

ArgFieldSpec declares the compiler-level kind of one argument of a capability. Bundles publish their specs via Bundle.ArgSchemas.

type ArgKind added in v0.14.0

type ArgKind uint8

ArgKind describes the compiler-level type of one capability argument.

const (
	// ArgAny is untyped; no compile-time validation applies.
	ArgAny ArgKind = iota
	// ArgString is a plain string; the value is passed through.
	ArgString
	// ArgInt is an integer literal.
	ArgInt
	// ArgBool is a boolean literal.
	ArgBool
	// ArgCapabilityRef is a statically resolved reference to an action.
	// The parser must present a bare identifier; quoted strings are
	// rejected, and the value is translated through TranslateKeyword
	// and verified against the resolver at compile time.
	ArgCapabilityRef
	// ArgCapabilityRefList is a list of ArgCapabilityRef.
	ArgCapabilityRefList
)

type AssertExpr

type AssertExpr struct {
	Condition string
	Message   string
	Pos       Position
}

AssertExpr: assert(condition, message).

func (*AssertExpr) Analyze

func (*AssertExpr) Build

func (*AssertExpr) Children

func (a *AssertExpr) Children() []Expr

func (*AssertExpr) Node

func (*AssertExpr) Node()

type Associativity

type Associativity uint8
const (
	Left Associativity = iota
	Right
)

type Atom

type Atom struct {
	Name            string
	Params          map[string]string
	Modifiers       []string
	ModifierSources []ModifierSource // parallel to Modifiers; same length
	Args            map[string]*Value
	Prompt          string
	Targets         []string
	Excludes        []string
	// ConfigInject marks an atom written as `op @config`. For stream
	// operators, every field of the operator's config struct that has
	// a matching @config.<json_name> value is injected into its
	// parameters at build time.
	ConfigInject bool
	Pos          Position // source position of the atom, for compile-time diagnostics
}

Atom is a single runtime action call.

func (*Atom) Analyze

func (*Atom) Analyze(CapabilityResolver) error

func (*Atom) Build

func (a *Atom) Build(ctx context.Context, bCtx *BuildContext) (action.AnyAction, error)

func (*Atom) Children

func (*Atom) Children() []Expr

func (*Atom) Node

func (*Atom) Node()

type AtomAdviseFunc

type AtomAdviseFunc func(atom *Atom, builder *action.Builder[any, any]) error

type AtomSpec

type AtomSpec struct {
	Name        string          `json:"name"`
	Description string          `json:"description,omitempty"`
	Tags        []string        `json:"tags,omitempty"`
	Scope       string          `json:"scope,omitempty"`
	ReqFields   []FieldSpec     `json:"req_fields,omitempty"`
	ResFields   []FieldSpec     `json:"res_fields,omitempty"`
	Example     json.RawMessage `json:"example,omitempty"`
}

type BoundarySpec

type BoundarySpec struct {
	Name        string
	Description string
	Consume     func(stream action.AnyStreamAction) *action.Builder[any, any]
}

BoundarySpec is a stream-to-unary adapter. It is the only place in a pipeline where iter.Seq2[T, error] becomes a single value.

func BoundaryByName

func BoundaryByName(name string) (BoundarySpec, bool)

func NamedBoundaries

func NamedBoundaries() []BoundarySpec

type BuildContext

type BuildContext struct {
	Resolver  CapabilityResolver
	Modifiers *ModifierTable
	Advisers  []AtomAdviseFunc
}

BuildContext carries every dependency a node needs to lower itself into a runnable action. It is deliberately a small value struct: the AST knows how to Build itself, core just provides the pieces.

type Bundle

type Bundle struct {
	ID           string
	Alias        string // Local @require qualifier replacing library namespaces for this compilation.
	Libraries    []action.Library
	Directives   []Directive
	Modifiers    []Modifier
	Operators    []Operator
	Primaries    []PrimaryExtension
	Materialize  Materializer
	OnPreprocess func(meta map[string]any) PreprocessContributions
	AtomAdvise   func(atom *Atom, builder *action.Builder[any, any]) error
	WrapPipeline func(meta map[string]any, inner action.AnyAction) (action.AnyAction, error)
	Hooks        []action.AnyHook

	ArgSchemas map[string][]ArgFieldSpec

	AcceptedOptions []string

	SelfTest func() []SelfTestSection
	Fixtures fs.FS

	// Shutdowns are invoked by the runner host after the outer invocation
	// completes. Compile and Execute do not close bundle resources.
	Shutdowns []ShutdownFunc
}

Bundle is one extension distribution.

func (Bundle) AllSelfTests

func (b Bundle) AllSelfTests() []SelfTestSection

type BundleFactory

type BundleFactory func(opts map[string]string) Bundle

func Lookup

func Lookup(id string) (BundleFactory, bool)

Lookup znajduje zarejestrowany bundle po dokładnym ID.

func LookupBundleForModule

func LookupBundleForModule(target string) (BundleFactory, bool)

LookupBundleForModule provides backward compatibility for unit tests.

type CapabilityContract

type CapabilityContract struct {
	Name   string
	Input  TypeDescriptor
	Output TypeDescriptor
}

type CapabilityRef added in v0.14.0

type CapabilityRef struct {
	Raw       string
	Canonical string
}

CapabilityRef is a statically resolved reference to an action, stream, or operator. Raw is the identifier as written in the DSL; Canonical is the name after translating native keywords. Both are held so diagnostics can point at the source form.

func ParseCapabilityRef added in v0.14.0

func ParseCapabilityRef(raw string) (CapabilityRef, error)

ParseCapabilityRef parses a single bare identifier. Quoted values are rejected: a capability reference is grammar, not data.

func ParseCapabilityRefList added in v0.14.0

func ParseCapabilityRefList(line string) ([]CapabilityRef, error)

ParseCapabilityRefList parses `[noop, const]` into capability references. It reuses ParseList for splitting, then runs every entry through ParseCapabilityRef so quoted members are rejected.

type CapabilityResolver

type CapabilityResolver interface {
	Action(name string) (action.AnyAction, bool)
	Stream(name string) (action.AnyStreamAction, bool)
	Operator(name string) (action.NamedOperator, bool)
	Mount(lib action.Library) error
	MountWithAlias(lib action.Library, alias string) error
}

CapabilityResolver odcina rdzeń kompilatora od twardej bazy akcji.

type Catalog

type Catalog struct {
	Atoms      []AtomSpec      `json:"atoms"`
	Sources    []SourceSpec    `json:"sources"`
	Operators  []OperatorSpec  `json:"operators"`
	Modifiers  []ModifierSpec  `json:"modifiers"`
	Directives []DirectiveSpec `json:"directives"`
}

Catalog is a machine-readable dump of the compiler surface: every atom, stream source, operator, modifier, and directive known to the resolver and tables. Consumed by `nflow catalog`, `nflow list`, `nflow show`, and the linter. Regenerated on every build — no manual maintenance.

func BuildCatalog

func BuildCatalog(
	resolver CapabilityResolver,
	mt *ModifierTable,
	dt *DirectiveTable,
	ot *OperatorTable,
) Catalog

BuildCatalog extracts the full compiler surface from the live resolver and tables. Atom fields come from TypedPayload when the atom is a *BuiltAction[Req, Res]; free-form actions show no fields.

type CompileAndRunReq

type CompileAndRunReq struct {
	Source  string
	Payload any
}

type CompileOption

type CompileOption func(*compileConfig)

func BundleConfig

func BundleConfig(bundles ...Bundle) []CompileOption

BundleConfig collects every extension point from a set of bundles into a single set of CompileOptions. Called once at startup.

func WithArgSchemas added in v0.14.0

func WithArgSchemas(schemas map[string][]ArgFieldSpec) CompileOption

func WithAtomAdvisors

func WithAtomAdvisors(fns ...AtomAdviseFunc) CompileOption

func WithCLIArgs added in v0.19.0

func WithCLIArgs(args []string) CompileOption

WithCLIArgs carries the raw command-line flags into the compile context so @flag.X references can be resolved and validated at compile time. A nil slice disables @flag validation, which is the right behavior for embedded runs and pure-compile tests that do not model a CLI invocation; an empty non-nil slice enables validation with zero known flags, so any @flag reference in the source is rejected.

func WithConfigMap

func WithConfigMap(cfg map[string]string) CompileOption

WithConfigMap carries the @config key→value map into the compile context. It is called by the config bundle's OnPreprocess hook after preprocessing has collected the source's @config directives. A nil map leaves any existing config untouched so an unrelated option (e.g. WithCLIArgs from the CLI) is not silently wiped by a later call.

func WithLineModifiers added in v0.14.0

func WithLineModifiers(lookups ...LineLookup) CompileOption

WithLineModifiers appends line-indexed modifier lookups. Multiple options accumulate; later lookups override earlier ones on the same modifier name. Extensions compose lookups this way — a pipeline's inherited policy is registered before nested @scope spans.

func WithOnPreprocess

func WithOnPreprocess(fns ...OnPreprocessFunc) CompileOption

func WithPipelineWrappers

func WithPipelineWrappers(fns ...PipelineWrapFunc) CompileOption

type CompileReq

type CompileReq struct {
	Source             string
	Name               string
	Line               int
	InheritedPrimaries []PrimaryExtension
	Prepared           *PreparedSource
}

type CompileRes

type CompileRes struct {
	Program action.AnyAction
	Meta    map[string]any
	AST     Expr
}

type ConditionalExpr

type ConditionalExpr struct {
	Cond Expr
	Then Expr
	Else Expr
	Pos  Position
}

ConditionalExpr: cond ? then : else.

func (*ConditionalExpr) Analyze

func (*ConditionalExpr) Build

func (*ConditionalExpr) Children

func (c *ConditionalExpr) Children() []Expr

func (*ConditionalExpr) Node

func (*ConditionalExpr) Node()

type ContractProvider

type ContractProvider interface {
	Contract(name string) (CapabilityContract, bool)
}

type Directive

type Directive struct {
	Name    string
	Example string
	Handler func(context.Context, DirectiveReq) (DirectiveRes, error)
}

func (Directive) Action

type DirectiveReq

type DirectiveReq struct {
	Lines   []string
	Body    []string
	I       int
	Out     map[string]any
	File    string
	BaseDir string
	Table   *DirectiveTable

	// Recurse runs the full preprocess on another .nflow file and
	// returns its cleaned body plus merged metadata. Used by @include
	// so directives in included files produce declarations in the
	// parent's Out map.
	Recurse func(absPath string) (clean string, meta map[string]any, err error)
}

type DirectiveRes

type DirectiveRes struct {
	Next int

	// BlankLines lists 0-based line indices whose output must be empty
	// even when the source line has content. Block directives use it
	// to remove their own delimiter lines (e.g. @scope's header and
	// closing brace) without consuming the body, so nested directives
	// inside the body still run through the outer preprocess loop.
	BlankLines []int
}

type DirectiveSpec

type DirectiveSpec struct {
	Name    string `json:"name"`
	Example string `json:"example,omitempty"`
}

type DirectiveTable

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

func NewDirectiveTable

func NewDirectiveTable(ds ...Directive) *DirectiveTable

func (*DirectiveTable) Actions

func (t *DirectiveTable) Actions() []action.AnyAction

func (*DirectiveTable) All

func (t *DirectiveTable) All() []Directive

func (*DirectiveTable) ByName

type DynamicResolver

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

func NewDynamicResolver

func NewDynamicResolver(baseLibs ...action.Library) (*DynamicResolver, error)

func (*DynamicResolver) Action

func (r *DynamicResolver) Action(name string) (action.AnyAction, bool)

func (*DynamicResolver) ActionNames added in v0.11.0

func (r *DynamicResolver) ActionNames() []string

ActionNames returns every canonical action name in stable order.

func (*DynamicResolver) Actions added in v0.11.0

func (r *DynamicResolver) Actions() []action.AnyAction

Actions returns each mounted action once, keyed by its canonical metadata name.

func (*DynamicResolver) Contract

func (r *DynamicResolver) Contract(name string) (CapabilityContract, bool)

func (*DynamicResolver) Mount

func (r *DynamicResolver) Mount(lib action.Library) error

func (*DynamicResolver) MountWithAlias

func (r *DynamicResolver) MountWithAlias(lib action.Library, alias string) error

func (*DynamicResolver) Operator

func (r *DynamicResolver) Operator(name string) (action.NamedOperator, bool)

func (*DynamicResolver) Operators added in v0.11.0

func (r *DynamicResolver) Operators() []action.NamedOperator

Operators returns mounted stream operators in stable order.

func (*DynamicResolver) Stream

func (r *DynamicResolver) Stream(name string) (action.AnyStreamAction, bool)

func (*DynamicResolver) Streams added in v0.11.0

func (r *DynamicResolver) Streams() []action.AnyStreamAction

Streams returns mounted stream sources in stable order.

type Expr

type Expr interface {
	Node()
	Children() []Expr
	Analyze(resolver CapabilityResolver) error
	Build(ctx context.Context, bCtx *BuildContext) (action.AnyAction, error)
}

Expr is the root of the AST. Every node knows how to report its children, how to validate its contract (Analyze), and how to lower itself into a runnable action (Build). Core never switches on concrete AST types.

type FallbackExpr

type FallbackExpr struct {
	L, R Expr
	Pos  Position
}

FallbackExpr: left || right.

func (*FallbackExpr) Analyze

func (f *FallbackExpr) Analyze(r CapabilityResolver) error

func (*FallbackExpr) Build

func (f *FallbackExpr) Build(ctx context.Context, bCtx *BuildContext) (action.AnyAction, error)

func (*FallbackExpr) Children

func (f *FallbackExpr) Children() []Expr

func (*FallbackExpr) Node

func (*FallbackExpr) Node()

type FieldSpec

type FieldSpec struct {
	Name     string `json:"name"`
	Type     string `json:"type"`
	Required bool   `json:"required,omitempty"`
	Usage    string `json:"usage,omitempty"`
}

type KeywordMapping added in v0.14.0

type KeywordMapping struct {
	Keyword string
	Target  string
}

KeywordMapping pairs a native DSL keyword with the canonical action name it compiles to.

func KeywordMappings added in v0.14.0

func KeywordMappings() []KeywordMapping

KeywordMappings returns the canonical keyword list. The returned slice is owned by core and must not be mutated.

type KeywordPrimary

type KeywordPrimary interface {
	PrimaryExtension
	Keyword() string
}

KeywordPrimary is the keyword-dispatch contract.

type Lexer

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

func NewLexer

func NewLexer(src string) *Lexer

func (*Lexer) Next

func (l *Lexer) Next() Token

type LineLookup added in v0.14.0

type LineLookup struct {
	Source ModifierSource
	Fn     func(line int) []string
}

LineLookup pairs a line-indexed modifier function with the source that produced it. Every modifier Fn returns is attributed to Source.

func LineModifiersFromOptions added in v0.14.0

func LineModifiersFromOptions(mt *ModifierTable, opts []CompileOption) []LineLookup

LineModifiersFromOptions returns the line-indexed modifier lookups that the given CompileOptions would install, each filtered through mt so non-inheritable metadata modifiers are dropped and unknown modifiers pass through for ApplyAll to reject. Sources are preserved.

Used by diagnostics such as nflow explain that need to render inherited modifiers without compiling a program. Extensions publish their lookups through Bundle.OnPreprocess as CompileOptions.

type LoopExpr

type LoopExpr struct {
	Body  Expr
	Until string
	Pos   Position
}

LoopExpr: loop(body) until(condition).

func (*LoopExpr) Analyze

func (l *LoopExpr) Analyze(r CapabilityResolver) error

func (*LoopExpr) Build

func (l *LoopExpr) Build(ctx context.Context, bCtx *BuildContext) (action.AnyAction, error)

func (*LoopExpr) Children

func (l *LoopExpr) Children() []Expr

func (*LoopExpr) Node

func (*LoopExpr) Node()

type MapEntry

type MapEntry struct {
	Key   string
	Value *Value
}

type MaterializeReq

type MaterializeReq struct {
	Ctx      context.Context
	Meta     map[string]any
	Resolver CapabilityResolver
	Compile  func(name, source string, modifiers ...string) (action.AnyAction, error)
	Alias    string
}

MaterializeReq passes context, metadata, and compiler to the materialization phase.

type Materializer

type Materializer func(req MaterializeReq) error

Materializer converts declarations from meta into executable actions in the resolver.

type MergeablePrimary added in v0.14.0

type MergeablePrimary interface {
	PrimaryExtension
	MergeWith(older PrimaryExtension) PrimaryExtension
}

MergeablePrimary is implemented by primary extensions that know how to combine themselves with an already-installed primary handling the same token or keyword.

NewPrimaryExtensionTable calls MergeWith instead of panicking when it encounters a duplicate and the newer extension implements this interface. The older extension is passed as the argument; the newer decides how to combine them.

This is what lets a bundle whose primary carries per-compilation state — the macros bundle is the canonical case — be installed more than once during a sub-pipeline compile without triggering the "duplicates fail loudly" panic. A genuine cross-bundle conflict (two unrelated bundles claiming the same token) still panics, because neither implements the interface.

type Modifier

type Modifier struct {
	Name        string
	Owner       ModifierOwner
	ValueKind   ModifierKind
	Unique      bool
	Inheritable bool
	Example     string
	Apply       func(b *action.Builder[any, any], raw string) error
}

Modifier is one `:name` or `:name=value` annotation on an atom.

Name is the identifier without the leading colon. Apply runs once per occurrence, in source order, on the atom's builder. The raw string is the DSL text after `=`, or "" for a flag. The parser has already stripped surrounding quotes and expanded adjacent tokens, so no modifier needs to worry about either.

Owner declares which subsystem owns the name. A modifier whose name is reserved by the Kernel or the grammar must be declared by its owner; NewModifierTable panics on a mismatch.

func Duration

func Duration(name string, apply func(*action.Builder[any, any], time.Duration) *action.Builder[any, any]) Modifier

func Flag

func Flag(name string, apply func(*action.Builder[any, any]) *action.Builder[any, any]) Modifier

Flag handles modifiers that take no value (`:coalesce`, `:dedup`). Passing a value is rejected loudly — `:dedup=yes` in the DSL is a mistake the author should see, not silently accept.

func Float64

func Float64(name string, apply func(*action.Builder[any, any], float64) *action.Builder[any, any]) Modifier

func Int

func Int(name string, apply func(*action.Builder[any, any], int) *action.Builder[any, any]) Modifier

func Int32

func Int32(name string, apply func(*action.Builder[any, any], int32) *action.Builder[any, any]) Modifier

func Int64

func Int64(name string, apply func(*action.Builder[any, any], int64) *action.Builder[any, any]) Modifier

func String

func String(name string, apply func(*action.Builder[any, any], string) *action.Builder[any, any]) Modifier

func StringList

func StringList(name string, apply func(*action.Builder[any, any], []string) *action.Builder[any, any]) Modifier

func WithInheritable added in v0.14.0

func WithInheritable(m Modifier) Modifier

WithInheritable marks a modifier as eligible for scope inheritance. @scope and @pipeline propagate only inheritable modifiers to nested atoms; metadata modifiers (tags, status, route) stay on the wrapper they were declared on.

func WithOwner added in v0.14.0

func WithOwner(m Modifier, owner ModifierOwner) Modifier

WithOwner returns m with the given owner. The Kernel policy bundle uses it to declare its modifiers as OwnerKernel without a package-level constructor for every policy.

func WithUnique added in v0.14.0

func WithUnique(m Modifier) Modifier

WithUnique marks a modifier as single-use: applying it more than once to the same atom is a compile-time error.

type ModifierKind added in v0.14.0

type ModifierKind uint8

ModifierKind describes the compiler-level value shape of a modifier. The typed constructors (Duration, Int, Flag, ...) set it automatically, so most code never references it directly.

const (
	// ModifierKindAny accepts any value. It is the zero value, so a
	// modifier built via a raw struct literal (not a typed constructor)
	// performs no value validation.
	ModifierKindAny ModifierKind = iota
	ModifierKindFlag
	ModifierKindString
	ModifierKindStringList
	ModifierKindInt
	ModifierKindInt32
	ModifierKindInt64
	ModifierKindFloat64
	ModifierKindDuration
)

func (ModifierKind) String added in v0.14.0

func (k ModifierKind) String() string

String returns a stable identifier for the kind, suitable for JSON catalogs, lint messages, and CLI output.

type ModifierOwner added in v0.14.0

type ModifierOwner uint8

ModifierOwner identifies which subsystem owns a modifier name.

const (
	// OwnerBundle means the modifier is owned by the bundle that
	// declares it. Any bundle may declare a modifier with this owner.
	OwnerBundle ModifierOwner = iota
	// OwnerKernel means the modifier is a standard Kernel policy
	// modifier. Only the modifiers_core bundle may declare it.
	OwnerKernel
	// OwnerGrammar means the modifier is owned by the nflow grammar.
	// No bundle may declare it.
	OwnerGrammar
)

func RequiredModifierOwner added in v0.14.0

func RequiredModifierOwner(name string) ModifierOwner

RequiredModifierOwner returns the owner required by a modifier name. A name not in any reserved set requires OwnerBundle.

type ModifierSource added in v0.14.0

type ModifierSource struct {
	Kind  string
	Label string
}

ModifierSource records where a modifier came from. Both fields are free-form strings: core never interprets them. Extensions and the parser populate them; `nflow explain` renders them.

Kind is a short category. Reserved values: "atom" for a modifier written directly on the atom. Extensions add their own ("scope", "profile", "pipeline", …).

Label identifies the specific origin within a kind — a profile name, a pipeline name. Empty when the kind alone is enough.

type ModifierSpec

type ModifierSpec struct {
	Name      string `json:"name"`
	ValueKind string `json:"value_kind"`
	Example   string `json:"example,omitempty"`
}

type ModifierTable

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

ModifierTable indexes modifiers by name. Construction is eager: a duplicate name, or a reserved name declared by the wrong owner, panics.

func NewModifierTable

func NewModifierTable(modifiers ...Modifier) *ModifierTable

func (*ModifierTable) Actions

func (t *ModifierTable) Actions() []action.AnyAction

func (*ModifierTable) All

func (t *ModifierTable) All() []Modifier

func (*ModifierTable) ApplyAll

func (t *ModifierTable) ApplyAll(target action.AnyAction, raws []string) (action.AnyAction, error)

ApplyAll wraps target once, applies every modifier in source order, and builds once. Two allocations total: the Builder and the BuiltAction.

When a modifier name is unknown, the hint path checks whether the name matches a field of the action's request struct. That is the common DSL-author mistake — writing :file=... where the action takes @{ file: ... } — and it produces a fix-the-typo message instead of a bare "unknown modifier".

func (*ModifierTable) ByName

func (t *ModifierTable) ByName(name string) (Modifier, bool)

type OnPreprocessFunc

type OnPreprocessFunc func(meta map[string]any) PreprocessContributions

OnPreprocessFunc is the compile-time hook fired between Preprocess and Parse. BundleConfig wires it from Bundle.OnPreprocess.

type Operator

type Operator struct {
	Meta    OperatorMeta
	Handler func(context.Context, OperatorReq) (OperatorRes, error)
}

func (Operator) Action

type OperatorMeta

type OperatorMeta struct {
	Name          string
	Token         TokenType
	Precedence    int
	Associativity Associativity
	Description   string
	Example       string
}

type OperatorReq

type OperatorReq struct {
	Left  Expr
	Right Expr
	Meta  *OperatorMeta
}

type OperatorRes

type OperatorRes struct {
	Node Expr
}

type OperatorSpec

type OperatorSpec struct {
	Name        string `json:"name"`
	Token       string `json:"token,omitempty"`
	Description string `json:"description,omitempty"`
	Example     string `json:"example,omitempty"`
}

type OperatorTable

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

func NewOperatorTable

func NewOperatorTable(ops ...Operator) *OperatorTable

func (*OperatorTable) Actions

func (t *OperatorTable) Actions() []action.AnyAction

func (*OperatorTable) All

func (t *OperatorTable) All() []OperatorMeta

func (*OperatorTable) ByName

func (*OperatorTable) ByToken

type ParallelExpr

type ParallelExpr struct {
	Branches []Expr
	Pos      Position
}

ParallelExpr: N branches executed concurrently.

func (*ParallelExpr) Analyze

func (p *ParallelExpr) Analyze(r CapabilityResolver) error

func (*ParallelExpr) Build

func (p *ParallelExpr) Build(ctx context.Context, bCtx *BuildContext) (action.AnyAction, error)

func (*ParallelExpr) Children

func (p *ParallelExpr) Children() []Expr

func (*ParallelExpr) Node

func (*ParallelExpr) Node()

type Parser

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

func NewParser

func NewParser(ctx context.Context, ops *OperatorTable, src string) *Parser

NewParser is the no-file convenience used in tests. Parse errors report only the line number.

func NewParserWithFile

func NewParserWithFile(
	ctx context.Context,
	ops *OperatorTable,
	primaries *PrimaryExtensionTable,
	src, file string,
) *Parser

NewParserWithFile carries the source path so parse errors are formatted as `file:line`, which terminals make clickable.

func NewParserWithFileOffset

func NewParserWithFileOffset(
	ctx context.Context,
	ops *OperatorTable,
	primaries *PrimaryExtensionTable,
	src, file string,
	lineBase int,
) *Parser

NewParserWithFileOffset additionally shifts reported line numbers by lineBase. Used when a fragment (e.g. a @pipeline body) is parsed in isolation but its errors must point at the parent file's lines.

func NewParserWithPrimaries

func NewParserWithPrimaries(
	ctx context.Context,
	ops *OperatorTable,
	primaries *PrimaryExtensionTable,
	src string,
) *Parser

NewParserWithPrimaries is kept for compatibility with callers that pass a primaries table explicitly.

func (*Parser) Advance

func (p *Parser) Advance()

Advance is an alias for Next, exported for external primary extensions.

func (*Parser) Context added in v0.14.0

func (p *Parser) Context() context.Context

Context returns the parser's context. Extensions reach caller-installed values through it — a trace sink, a policy context, a filename-keyed cache. The parser itself never reads those values; only primaries and line lookups do. It is the sanctioned way for an extension to reach a caller-provided sink without package-level state.

func (*Parser) Cur

func (p *Parser) Cur() Token

Cur returns the token under the cursor.

func (*Parser) Current

func (p *Parser) Current() Token

Current is an alias for Cur, exported for external primary extensions.

func (*Parser) Fail

func (p *Parser) Fail(_ int, format string, args ...any) error

Fail reports a parse error at the given line offset by lineBase. Exported so external primary extensions can format errors the same way the built-in parser does.

func (*Parser) File

func (p *Parser) File() string

File returns the source file path, or "".

func (*Parser) Next

func (p *Parser) Next()

Next advances the cursor by one token.

func (*Parser) Parse

func (p *Parser) Parse() (Expr, error)

func (*Parser) ParseExpr

func (p *Parser) ParseExpr(minPrec int) (Expr, error)

ParseExpr parses a sub-expression with the given minimum precedence. Exported so primary extensions can recurse without reimplementing the precedence-climbing loop.

func (*Parser) Peek added in v0.16.0

func (p *Parser) Peek(offset int) Token

Peek returns the token at offset from Cur without advancing. Peek(0) is the current token; offsets beyond the input return the final EOF token.

func (*Parser) Position added in v0.19.0

func (p *Parser) Position() Position

Position returns the parser's current source position, including file, line, and column. Exposed so primary extensions can stamp AST nodes they construct without re-implementing column arithmetic.

func (*Parser) Src

func (p *Parser) Src() string

Src returns the source text under parse.

func (*Parser) SubParse

func (p *Parser) SubParse(src string) (Expr, error)

SubParse parses a fresh source fragment in this parser's context. The same operator table, primary table, and source-file metadata are reused. External primary extensions call it to re-enter the parser with substituted text.

func (*Parser) WithLineModifiers added in v0.14.0

func (p *Parser) WithLineModifiers(lookups ...LineLookup) *Parser

WithLineModifiers replaces the parser's line-modifier lookup chain. The parser calls them in order; later lookups win over earlier ones on modifier-name collision.

type PipeExpr

type PipeExpr struct {
	L, R Expr
	Pos  Position
}

PipeExpr: left -> right.

func (*PipeExpr) Analyze

func (p *PipeExpr) Analyze(r CapabilityResolver) error

func (*PipeExpr) Build

func (p *PipeExpr) Build(ctx context.Context, bCtx *BuildContext) (action.AnyAction, error)

func (*PipeExpr) Children

func (p *PipeExpr) Children() []Expr

func (*PipeExpr) Node

func (*PipeExpr) Node()

type PipelineWrapFunc

type PipelineWrapFunc func(meta map[string]any, inner action.AnyAction) (action.AnyAction, error)

type Position

type Position struct {
	File string
	Line int
	Col  int
}

func PositionOf added in v0.19.0

func PositionOf(err error) (Position, bool)

PositionOf walks the unwrap chain of err and returns the first Position it finds. The bool is false when no positioned error exists.

func (Position) String

func (p Position) String() string

type Positioned added in v0.19.0

type Positioned interface {
	Position() Position
}

Positioned is implemented by errors that carry a source position. Walk the chain with errors.As to find the first one.

type PostfixExtension added in v0.16.0

type PostfixExtension interface {
	PrimaryExtension
	PostfixToken() TokenType
	MatchesPostfix(p *Parser) bool
	ParsePostfix(p *Parser, left Expr) (Expr, error)
}

PostfixExtension handles an operator-like form whose left operand has already been parsed. MatchesPostfix must not advance the parser; ParsePostfix is called only after it returns true.

type PreparedSource added in v0.14.0

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

PreparedSource is the result of preprocessing one source. Its fields are intentionally opaque so callers can inspect metadata and pass the value to CompileAction without separating the source from its metadata.

func PrepareSource added in v0.14.0

func PrepareSource(ctx context.Context, dt *DirectiveTable, source, name string, opts ...CompileOption) (*PreparedSource, error)

PrepareSource preprocesses source and computes its extension contributions once. Use the returned value when metadata must be inspected before the same source is compiled, such as runner materialization.

func (*PreparedSource) Contributions added in v0.14.0

func (p *PreparedSource) Contributions() PreprocessContributions

Contributions returns compile-time contributions already computed for this source. It does not invoke extension callbacks again.

func (*PreparedSource) Metadata added in v0.14.0

func (p *PreparedSource) Metadata() map[string]any

Metadata returns the directive metadata associated with this source.

type PreprocessContributions

type PreprocessContributions struct {
	Primaries   []PrimaryExtension
	CompileOpts []CompileOption
}

func PreprocessContributionsFromMeta

func PreprocessContributionsFromMeta(meta map[string]any, opts ...CompileOption) PreprocessContributions

type PrimaryExtension

type PrimaryExtension interface {
	Name() string
	Parse(p *Parser) (Expr, error)
}

PrimaryExtension przechwytuje jeden token-form i zamienia go w węzeł AST. W parsePrimary extensions mają pierwszeństwo przed built-inami.

Kontrakt jest celowo minimalny: rozszerzenie implementuje Name i Parse, oraz — w zależności od tego, czym rozszerza parser — jedno z:

TokenType() TokenType  — dispatch po tokenie (np. TokAtPrompt)
Keyword()   string     — dispatch po nazwie identu (np. "loop")

Rozszerzenie może implementować jedno, drugie, albo oba.

type PrimaryExtensionTable

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

func DefaultPrimaryExtensions

func DefaultPrimaryExtensions() *PrimaryExtensionTable

DefaultPrimaryExtensions zwraca PUSTĄ tabelę. Core nie zna żadnego konkretnego rozszerzenia.

func NewPrimaryExtensionTable

func NewPrimaryExtensionTable(exts ...PrimaryExtension) *PrimaryExtensionTable

func (*PrimaryExtensionTable) All

func (*PrimaryExtensionTable) ByKeyword

func (t *PrimaryExtensionTable) ByKeyword(kw string) (PrimaryExtension, bool)

func (*PrimaryExtensionTable) ByPostfix added in v0.16.0

ByPostfix returns the postfix extension registered for tok, if any.

func (*PrimaryExtensionTable) ByToken

type ProjectionExpr

type ProjectionExpr struct {
	Raw string
	Pos Position
}

ProjectionExpr: raw content `{ ... }`.

func (*ProjectionExpr) Analyze

func (*ProjectionExpr) Build

func (*ProjectionExpr) Children

func (p *ProjectionExpr) Children() []Expr

func (*ProjectionExpr) Node

func (*ProjectionExpr) Node()

type RunReq

type RunReq struct {
	Program action.AnyAction
	Payload any
}

type RunRes

type RunRes struct {
	Output any
}

type SelfTestFeature

type SelfTestFeature struct {
	Name   string
	DSL    string
	Files  map[string]string
	Skip   string
	Source string
}

type SelfTestSection

type SelfTestSection struct {
	Name     string
	Features []SelfTestFeature
}

type ShutdownFunc added in v0.15.0

type ShutdownFunc func(context.Context) error

ShutdownFunc releases a resource explicitly owned by a bundle. Implementations must honor ctx so host shutdown remains bounded.

type SourceLoader added in v0.17.0

type SourceLoader interface {
	Load(currentFile, target string) (data []byte, resolvedPath string, err error)
}

SourceLoader resolves a directive-referenced source fragment such as the target of @include. CurrentFile is the path of the file that issued the reference; Target is the raw path from the directive.

The returned resolvedPath is used for cycle detection and error reporting. Its only requirement is stability for the same file across calls within one preprocess run.

type SourceSpec

type SourceSpec struct {
	Name        string      `json:"name"`
	Description string      `json:"description,omitempty"`
	Tags        []string    `json:"tags,omitempty"`
	ReqFields   []FieldSpec `json:"req_fields,omitempty"`
}

SourceSpec describes a stream source (fs.walk, cov.items, ...). A source has a typed request but no typed item — the item type is a per-item element, not a whole response.

type Token

type Token struct {
	Type   TokenType
	Lit    string
	Line   int
	Offset int
}

type TokenPrimary

type TokenPrimary interface {
	PrimaryExtension
	TokenType() TokenType
}

TokenPrimary is the token-dispatch contract.

type TokenType

type TokenType uint8
const (
	TokEOF TokenType = iota
	TokIdent
	TokString
	TokNumber
	TokArrow
	TokPipe
	TokAmpersand
	TokOrOr
	TokLParen
	TokRParen
	TokLBrace
	TokRBrace
	TokColon
	TokEquals
	TokComma
	TokQuestion
	TokHash
	TokTilde
	TokAtBrace
	TokAtPrompt
)

func (TokenType) String

func (t TokenType) String() string

type TypeDescriptor

type TypeDescriptor struct {
	Type   reflect.Type
	Stream bool
}

type Value

type Value struct {
	Kind  ValueKind
	Str   string
	Num   float64
	Bool  bool
	Ref   string
	Map   []MapEntry
	Slice []*Value
}

func (*Value) IsWholeStateRef

func (v *Value) IsWholeStateRef() bool

type ValueKind

type ValueKind uint8
const (
	ValueString ValueKind = iota
	ValueBare
	ValueNumber
	ValueBool
	ValueNull
	ValueRef
	ValueMap
	ValueSlice
)

Jump to

Keyboard shortcuts

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