Documentation
¶
Overview ¶
Package core holds the domain-agnostic parts of the directives system.
Nothing here knows about any specific directive. Every shipped directive (at_route, at_retry, …) and every user-provided directive depends on core, never the other way around. The dependency graph is strictly: directive -> core -> compiler.
Index ¶
- func AtErr(ctx *Context, line int, name, msg string) error
- func AtErrf(ctx *Context, line int, name, format string, args ...any) error
- func DispatchRecovery(ctx context.Context, input any, err error, spec RecoverySpec) (any, error)
- func IsKnownXerrKind(k string) bool
- func KnownXerrKinds() []string
- func Names() []string
- func NewRecoveryAction(name string, upstream action.Executable, spec RecoverySpec) (*action.BuiltAction[any, any], error)
- func ParseFloat(s string) (float64, error)
- func ParseInt(s string) (int, error)
- func ParseList(s string) []string
- func RecoveryMiddleware(spec RecoverySpec) action.Middleware[any, any]
- func Register(d Directive)
- func RegisterAtomPolicy(ap AtomPolicy)
- func RegisterPipelineWrapper(pw PipelineWrapper)
- func RegisterRegistryContributor(rc RegistryContributor)
- func SplitBlock(lines []string, start int) (header string, body []string, next int, err error)
- func SplitNameAndAttrs(s string) (string, map[string]string, error)
- func SplitTopLevel(s string, sep byte) []string
- func StripDirectivePrefix(line, name string) (rest string, ok bool)
- func TrimQuotes(s string) string
- type ActionMeta
- type AssertDecl
- type AtomAdvisor
- type AtomPolicy
- type CapabilityEnvelope
- type Context
- type Directive
- type GateRule
- type HookDecl
- type OnErrorDecl
- type OnErrorRule
- type Pipeline
- type PipelineWrapper
- type Pool
- type Position
- type Preprocessed
- type RecoveryMatch
- type RecoveryRule
- type RecoverySpec
- type RegistryContributor
- type Requirement
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DispatchRecovery ¶
DispatchRecovery routes a failure according to spec. On success (err == nil) it returns input unchanged. On failure the first matching rule wins; else is the fallback; if nothing matches the original error is returned unchanged.
func IsKnownXerrKind ¶
IsKnownXerrKind reports whether k is one of the known kinds.
func KnownXerrKinds ¶
func KnownXerrKinds() []string
KnownXerrKinds lists the xerr.Kind string values the DSL accepts in `@on_error { when error.kind == "X" }` and `@retry NAME { only: [X] }`. Hand-maintained rather than reflected from kernel/xerr — the DSL is a stable surface and adding a kind should be deliberate.
func Names ¶
func Names() []string
Names returns the registered directive names in registration order.
func NewRecoveryAction ¶
func NewRecoveryAction( name string, upstream action.Executable, spec RecoverySpec, ) (*action.BuiltAction[any, any], error)
NewRecoveryAction wraps a whole pipeline with rule-based routing. Used by @on_error.
func ParseFloat ¶
func RecoveryMiddleware ¶
func RecoveryMiddleware(spec RecoverySpec) action.Middleware[any, any]
RecoveryMiddleware wraps a single atom with rule-based routing. Used by @fallback. Install with UseFirst so the middleware is outermost and observes timeout, retry, and cancellation failures from the whole inner chain.
func Register ¶
func Register(d Directive)
Register adds a directive to the global registry. Called from each directive's init(). Duplicate names panic — this is a programming error, not a runtime condition.
func RegisterAtomPolicy ¶
func RegisterAtomPolicy(ap AtomPolicy)
RegisterAtomPolicy opts a directive into the per-atom advice phase.
func RegisterPipelineWrapper ¶
func RegisterPipelineWrapper(pw PipelineWrapper)
RegisterPipelineWrapper opts a directive into the post-compile pipeline wrapping phase.
func RegisterRegistryContributor ¶
func RegisterRegistryContributor(rc RegistryContributor)
RegisterRegistryContributor opts a directive into the pre-compile action registration phase.
func SplitBlock ¶
SplitBlock extracts the header and body of a `{ ... }` block.
Two forms are supported:
Multi-line blocks, one entry per line:
@foo name { key: value, other: value }
Single-line blocks with top-level comma-separated entries:
@foo name { key: value, other: value }
Both forms produce the same body layout: one entry per element of the returned slice. That means a directive can iterate over body uniformly and never has to care whether the author wrote the block on one line or spread it out.
Every entry is split through SplitTopLevel, so trailing commas (a natural style when fields are one-per-line) are stripped consistently, and commas inside quoted strings, nested braces, or nested brackets do not split entries.
The returned `next` index always points to the first line after the block. Single-line blocks advance by one; multi-line blocks advance past the closing brace.
func SplitTopLevel ¶
func StripDirectivePrefix ¶
func TrimQuotes ¶
Types ¶
type ActionMeta ¶
type AssertDecl ¶
type AtomAdvisor ¶
AtomAdvisor is called once per atom during the AST walk. It inspects the atom name and modifiers, and may attach middleware to the atom's builder. Returning without doing anything is the fast path.
The advisor must not retain the builder or the modifiers slice beyond the call.
type AtomPolicy ¶
type AtomPolicy interface {
Directive
AtomAdvisor(pre *Preprocessed) AtomAdvisor
}
AtomPolicy lets a directive influence individual atoms. @retry (and future @fallback, @approval) use this. Called once per atom, only when a matching declaration exists.
func AtomPolicies ¶
func AtomPolicies() []AtomPolicy
AtomPolicies returns a copy of the registered atom policies.
type CapabilityEnvelope ¶
type Context ¶
type Context struct {
Out *Preprocessed
BaseDir string
File string
Body []string
ValidateProfile func(string) error
IncludeResolver func(absPath string) (*Preprocessed, error)
}
Context is the per-file state a directive sees during Apply.
Body is the file split into lines. Directives that consume a block (via SplitBlock) leave Body untouched. Directives that rewrite a single line can write back into Body[i].
ValidateProfile and IncludeResolver are nil in byte-source mode.
type Directive ¶
type Directive interface {
Name() string
Apply(ctx *Context, lines []string, i int) (next int, err error)
}
Directive is the interface every DSL directive implements.
Apply consumes one or more lines starting at index i and returns the index of the first line after the directive. Most directives consume exactly one line (i+1). Block directives consume the header, the body between `{` and `}`, and the closing brace (see SplitBlock).
type OnErrorDecl ¶
type OnErrorDecl struct {
Pos Position
Rules []OnErrorRule
Else string
}
OnErrorDecl is the parsed `@on_error { ... }` block.
type OnErrorRule ¶
OnErrorRule is one `when COND -> TARGET` clause.
type PipelineWrapper ¶
type PipelineWrapper interface {
Directive
WrapPipeline(pre *Preprocessed, inner action.Executable) (action.Executable, error)
}
PipelineWrapper lets a directive wrap the whole compiled pipeline with additional behaviour. @on_error uses this. Called once, after compilation.
func PipelineWrappers ¶
func PipelineWrappers() []PipelineWrapper
PipelineWrappers returns a copy of the registered wrappers.
type Position ¶
Position is the source location of a directive or atom, used in error messages. Same type as the compiler's Position so positions flow through both layers without conversion.
type Preprocessed ¶
type Preprocessed struct {
File string
Description string
Asserts []AssertDecl
Profile string
ProfilePos Position
Requires []Requirement
Capabilities CapabilityEnvelope
Gates []GateRule
Pools []Pool
Hooks []HookDecl
Config map[string]string
Includes []string
Pipelines []Pipeline
Action *ActionMeta
Declarations map[string]any
DSL string
}
Preprocessed is the parsed representation of one .flow file.
Typed fields cover the shape every directive must agree on. Anything a single directive owns goes into Declarations, keyed by directive name. That keeps Preprocessed stable when a new directive is added.
type RecoveryMatch ¶
type RecoveryMatch uint8
RecoveryMatch selects which error property a rule tests.
const ( // MatchByKind compares xerr.KindFrom(err) to Rule.Kind. MatchByKind RecoveryMatch = iota + 1 // MatchBySuspended matches errors.Is(err, dag.ErrSuspended). MatchBySuspended )
type RecoveryRule ¶
type RecoveryRule struct {
Match RecoveryMatch
Kind string
Target string
}
RecoveryRule is one `when COND -> TARGET` clause in runtime form.
func ParseRecoveryBlock ¶
func ParseRecoveryBlock(body []string, ctx *Context, baseLine int, directiveName string) ([]RecoveryRule, string, error)
ParseRecoveryBlock parses the body lines of a recovery block — the lines between `{` and `}`. It returns the rules and the else target.
baseLine is the index of the block header so error positions point at the file the block lives in. directiveName is used in error messages ("on_error", "fallback").
Shared by @on_error and @fallback because the block grammar is identical for both.
type RecoverySpec ¶
type RecoverySpec struct {
Rules []RecoveryRule
Else string
}
RecoverySpec is the runtime form of a recovery block.
type RegistryContributor ¶
type RegistryContributor interface {
Directive
RegisterActions(pre *Preprocessed, base *action.Registry) ([]action.AnyAction, error)
}
RegistryContributor lets a directive register actions the pipeline can call by name. @route, @pipeline, and @pool use this. Called once, before compilation.
func RegistryContributors ¶
func RegistryContributors() []RegistryContributor
RegistryContributors returns a copy of the registered contributors.