lang

package
v0.6.0-12a Latest Latest
Warning

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

Go to latest
Published: Jun 7, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package lang holds the unobin source language: PEG grammar, lexer, AST.

Scope: parsing of main.ub, kind-prefixed library type bodies, and config.ub into a typed AST. Multi-error reporting with line/column from the parser.

Companion packages:

  • pkg/types - type system and type-expression evaluation
  • pkg/codegen - AST to Go source
  • pkg/resolve - import resolution and lock file

Index

Constants

View Source
const (
	FileUnknown      = parse.FileUnknown
	FileFactory      = parse.FileFactory
	FileExportedType = parse.FileExportedType
	FileConfig       = parse.FileConfig
	FileManifest     = parse.FileManifest

	FieldIdent  = parse.FieldIdent
	FieldString = parse.FieldString

	CompList = parse.CompList
	CompMap  = parse.CompMap

	StringSingleQuoted          = parse.StringSingleQuoted
	StringTripleQuoteSingleLine = parse.StringTripleQuoteSingleLine
	StringLiteralClip           = parse.StringLiteralClip
	StringLiteralStrip          = parse.StringLiteralStrip
	StringFoldedClip            = parse.StringFoldedClip
	StringFoldedStrip           = parse.StringFoldedStrip
	StringJoinedClip            = parse.StringJoinedClip
	StringJoinedStrip           = parse.StringJoinedStrip

	ErrUnknown = parse.ErrUnknown
	ErrParse   = parse.ErrParse
	ErrLex     = parse.ErrLex
	ErrSchema  = parse.ErrSchema
	ErrType    = parse.ErrType
	ErrResolve = parse.ErrResolve
)
View Source
const CoreNamespace = "@core"

CoreNamespace is the language's function namespace: a call qualified with it resolves against the functions the toolchain provides, with no import. The @ keeps it outside the alias namespace, so an import can never collide with it or stand in for it.

View Source
const DefaultMaxColumn = 100

DefaultMaxColumn is the line width used when FormatOptions.MaxColumn is unset.

Variables

View Source
var (
	NewErrorList  = parse.NewErrorList
	Errorf        = parse.Errorf
	PascalToKebab = parse.PascalToKebab
)

Functions

func ConstraintFieldRoots added in v0.6.0

func ConstraintFieldRoots(c ConstraintEntry) []string

ConstraintFieldRoots returns the names of the inputs a constraint reads: the first path segment of each fields: entry for a set constraint, and of every var reference in the when, require, and @for-each expressions for a predicate. The names are sorted and unique.

func Format

func Format(file *File) ([]byte, error)

Format renders a parsed File back to canonical UB source using the default options. Comments captured during parsing are interleaved at their original positions; non-comment whitespace is normalized. Output is stable: re-parsing the result and feeding it back through Format yields the same bytes.

func FormatWith

func FormatWith(file *File, opts FormatOptions) ([]byte, error)

FormatWith renders a parsed File with the supplied options. Zero values fall back to their package defaults.

func ParseSpecs

func ParseSpecs(specs []ConstraintSpec) ([]ConstraintEntry, *ErrorList)

ParseSpecs parses each spec's When and Require source into expressions and returns entries ready for CheckConstraintEntries. A set constraint (empty When and Require) yields an entry with nil expressions. Parse errors are collected; a spec that fails to parse is skipped.

func Render

func Render(v any) string

Render formats v as a UB literal expression on one line. The canonical set (string, bool, int64, float64, []any, map[string]any, nil) renders directly; types implementing ub.Marshaler control their own form; anything else falls through to Go's default formatter so callers never see an empty string.

func RenderKey

func RenderKey(k string) string

RenderKey returns k as a bare kebab-case identifier when it is a valid one, otherwise as a quoted string. Round trips cleanly through the parser either way.

func RenderPretty

func RenderPretty(v any) string

RenderPretty formats v as UB syntax with indented multi-line expansion for non-empty maps and lists. Empty collections render inline as `{}` or `[]`. Atoms render exactly as Render would emit them.

func SensitiveInputs

func SensitiveInputs(block *ObjectLit) map[string]bool

SensitiveInputs returns the set of input names declared with `@sensitive: true` in an `inputs:` block. Nil block yields an empty map.

func SensitiveOutputs

func SensitiveOutputs(block *ObjectLit) map[string]bool

SensitiveOutputs returns the set of output names declared with `@sensitive: true` inside their wrapper in an `outputs:` block. Nil block yields an empty map. The block must already have been passed through ValidateOutputs; entries that are not wrapper objects are skipped silently.

func TypeMessage

func TypeMessage(v any) string

TypeMessage names a parsed value with the unobin type vocabulary so error messages match what the operator wrote, not the Go runtime type they would never see otherwise.

func Walk

func Walk(e Expr, visit func(Expr))

Walk invokes visit for e and then for every nested expression in source order. It recurses into object field values, array elements, call args, infix and prefix operands, dot-path index expressions, conditional branches, comprehension parts, and interpolated-string slots. A nil expression is a no-op so callers can recurse through optional fields without guarding first.

Types

type ArrayLit

type ArrayLit = parse.ArrayLit

type BoolLit

type BoolLit = parse.BoolLit

type Call

type Call = parse.Call

type Comment

type Comment = parse.Comment

type Comprehension

type Comprehension = parse.Comprehension

type ComprehensionKind

type ComprehensionKind = parse.ComprehensionKind

type Conditional

type Conditional = parse.Conditional

type ConstraintEntry

type ConstraintEntry struct {
	Kind    string
	Fields  []string
	When    Expr
	Require Expr
	Message string
	Levels  []ForEachLevel
}

ConstraintEntry is one resolved cross-field constraint, independent of whether it was parsed from a UB constraints block or derived from a Go type at compile time. The set kinds use Fields; a predicate uses When and Require (and an optional Message). A Fields name may splat a list ([*]) to run the rule once per element. A predicate may iterate with Levels, checking when and require once per element of each level's iterable with the level's binding set: a single @each level for the bare @for-each form, named levels for a chained one. goschema builds these directly for Go library types so they run through the same check as UB ones.

type ConstraintEvalFunc added in v0.6.0

type ConstraintEvalFunc func(e Expr, binds []EachBinding) (any, error)

ConstraintEvalFunc reduces a constraint's when, require, or @for-each expression against the input values. binds holds the iteration bindings in scope, outermost first; it is empty outside iteration.

type ConstraintSpec

type ConstraintSpec struct {
	Kind          string
	Fields        []string
	When          string
	Require       string
	Message       string
	ForEach       string
	ForEachLevels []ForEachSpecLevel
}

ConstraintSpec is the embeddable, string-only form of a constraint. The predicate When, Require, and iterables are kept as unobin source so the whole set can be generated into a factory and parsed back at plan time; a set constraint leaves them empty and uses Fields. A bare iteration uses ForEach; a chained one uses ForEachLevels, named levels in order. goschema produces these from a Go type, and codegen bakes them into the factory.

type DefaultSpec added in v0.6.0

type DefaultSpec struct {
	Field    string
	Value    string
	Optional bool
}

DefaultSpec is the embeddable form of one declared input default. Field is the input's var reference (var.mode, var.code.timeout), the spelling every other field reference uses. A Value default holds the default as unobin literal source, parsed and evaluated where it is applied; an Optional marker leaves Value empty and sets Optional, declaring the field may be absent with nothing filled in. goschema produces these from a Go type's Defaults method, and codegen bakes them into the factory.

type DotPath

type DotPath = parse.DotPath

type DotSegment

type DotSegment = parse.DotSegment

type EachBinding added in v0.6.0

type EachBinding struct {
	Name  string
	Key   any
	Value any
}

EachBinding is one named iteration binding in scope for a constraint expression: @each for the bare @for-each form, or a declared name like @rule for a level of a chained one. Either way the binding is a key/value record, read as @name.key and @name.value.

type EachValue added in v0.6.0

type EachValue struct {
	Key   any
	Value any
}

EachValue is one iteration's @each binding, handed to the evaluator alongside a constraint expression when the entry iterates with @for-each: the element index or map key, and the element itself.

type Error

type Error = parse.Error

type ErrorKind

type ErrorKind = parse.ErrorKind

type ErrorList

type ErrorList = parse.ErrorList

func CheckConstraintEntries

func CheckConstraintEntries(
	entries []ConstraintEntry,
	values map[string]any,
	evalAgainstInputs ConstraintEvalFunc,
	display FieldDisplay,
) *ErrorList

CheckConstraintEntries checks already-resolved constraint entries, such as those goschema derives from a Go type at compile time, against the values. It is the same check CheckConstraints runs after parsing a UB block, so Go-derived and UB constraints behave identically.

func CheckConstraintEntry added in v0.6.0

func CheckConstraintEntry(
	idx int,
	c ConstraintEntry,
	values map[string]any,
	evalAgainstInputs ConstraintEvalFunc,
	display FieldDisplay,
) *ErrorList

CheckConstraintEntry checks one resolved constraint entry against the values, reporting any failure under index idx, the entry's position in its type's constraint list, so a diagnostic names the same entry no matter which entries the caller checks.

func CheckConstraints

func CheckConstraints(
	block *ArrayLit,
	values map[string]any,
	evalAgainstInputs ConstraintEvalFunc,
	display FieldDisplay,
) *ErrorList

CheckConstraints evaluates the value-level cross-field constraints in a stack's `constraints:` block against the validated input values. Predicate constraints use evalAgainstInputs to reduce their `when:` and `require:` expressions; pass nil to skip predicate evaluation. Callers should run ValidateConstraints first; malformed entries that slip through are skipped silently.

func ValidateActions

func ValidateActions(block *ObjectLit) *ErrorList

ValidateActions checks the shape of an `actions:` block.

func ValidateCalls added in v0.5.0

func ValidateCalls(f *File) *ErrorList

ValidateCalls walks every expression in f and rejects two kinds of function call: a bare call with no qualifier (a call names either an imported library or @core), and a qualified call whose alias is missing from the file's imports block. @core needs no import; any other @-name is rejected, since the language provides only @core. The type constructors in an input declaration's type (list(string), optional(integer, 0)) are left alone: they share call syntax but denote types; a default inside such a type stays a value and is still checked. Whether a named library function exists is not checked here; that is a runtime concern, since a library's function set lives in compiled Go code. The @core set is fixed and the reference checker enforces it.

func ValidateConfigInputs added in v0.5.0

func ValidateConfigInputs(block *ObjectLit) *ErrorList

ValidateConfigInputs checks that every value in a config file's inputs: block is a static value; see checkStaticConfigBlock.

func ValidateConfigurations added in v0.5.0

func ValidateConfigurations(block *ObjectLit) *ErrorList

ValidateConfigurations applies the same static-value rule to a config file's configurations: block. The block nests by import alias and then configuration name; the walk recurses through both to the leaf values.

func ValidateConstraintReferences

func ValidateConstraintReferences(constraints *ArrayLit, inputs *ObjectLit) *ErrorList

ValidateConstraintReferences checks that every var reference in the `fields:` list of each constraint names a declared input. A reference is checked by the segment after var, the input the path starts from, with any [N] or [*] suffix set aside. Malformed entries are skipped.

func ValidateConstraints

func ValidateConstraints(arr *ArrayLit) *ErrorList

ValidateConstraints walks a `constraints:` array and checks each entry per its declared `kind:`. Field-based kinds take a nonempty `fields:` list of var references, dotted to reach a field inside a nested input; the `predicate` kind takes `when:` and `require:` expressions plus an optional `message:`.

func ValidateDataSources

func ValidateDataSources(block *ObjectLit) *ErrorList

ValidateDataSources checks the shape of a `data:` block.

func ValidateEncryptionConfig

func ValidateEncryptionConfig(block *ObjectLit) *ErrorList

ValidateEncryptionConfig checks the structure of an `encryption:` sub-block nested inside a `state:` block. Same rules as ValidateStateConfig but with `@key-source:` in place of `@backend:` and no further nested blocks.

func ValidateFile

func ValidateFile(f *File) *ErrorList

ValidateFile runs every schema check appropriate to f.Kind and returns the combined diagnostics. The file must already be classified; FileUnknown produces only the top-level-keys error directing the caller to classify.

func ValidateImports

func ValidateImports(block *ObjectLit) *ErrorList

ValidateImports checks an `imports:` block: every entry is an identifier alias bound to a quoted string source URL or local path.

func ValidateInputDeclarations

func ValidateInputDeclarations(block *ObjectLit) *ErrorList

ValidateInputDeclarations checks the shape of an `inputs:` block as it appears in a stack or exported-type body. Every entry must be an identifier name bound to an object declaration carrying a `type:` expression and any number of permitted modifiers; types are promoted here so callers see syntactic and type level errors in one batch.

Config file `inputs:` blocks have a different shape (values, not declarations) and are not validated by this function.

func ValidateInputs

func ValidateInputs(
	decl *ObjectLit, values map[string]any, evalDefault EvalFunc,
) (map[string]any, *ErrorList)

ValidateInputs validates an operator-supplied values map against a stack's `inputs:` declaration. Returns the validated values with `optional(T, default)` defaults applied. Errors cover missing required inputs, unknown keys, type mismatches, and modifier violations. The decl is the parsed `inputs:` block; values is the map produced by loadConfigInputs + applyEnvOverrides. evalDefault reduces default expressions to Go values; pass nil to refuse any default that requires evaluation.

func ValidateLocals

func ValidateLocals(block *ObjectLit) *ErrorList

ValidateLocals checks a `locals:` block. Every entry is a bare identifier name bound to an arbitrary expression; a local's type is inferred from its value, never declared. Names must be unique. The entry is referenced elsewhere as `local.<name>`. The value expression's own validity (references, cycles) is checked in later passes, not here.

func ValidateManifestReplace added in v0.6.0

func ValidateManifestReplace(block *ObjectLit) *ErrorList

ValidateManifestReplace checks a manifest `replace:` block: every entry binds a quoted dependency id (a repo URL) to a quoted local path. The id and path strings are not parsed here; resolution validates the URL and that the path holds a library.

func ValidateManifestRequires added in v0.6.0

func ValidateManifestRequires(block *ObjectLit) *ErrorList

ValidateManifestRequires checks a manifest `requires:` block: every entry binds a quoted dependency id (a repo URL with an optional `//subdir`) to a quoted version floor. The id and version strings are not parsed here; resolution validates the URL and the semver floor.

func ValidateOutputs

func ValidateOutputs(block *ObjectLit) *ErrorList

ValidateOutputs checks an `outputs:` block. Every entry is a bare identifier name bound to an object wrapper of the form `{ value: expr }`, optionally carrying `@sensitive: true`. The wrapper exists so per-output metadata keys can ride alongside the value without ambiguity.

func ValidateResources

func ValidateResources(block *ObjectLit) *ErrorList

ValidateResources checks a `resources:` block level by level: alias, type name, instance name, body.

func ValidateStateConfig

func ValidateStateConfig(block *ObjectLit) *ErrorList

ValidateStateConfig checks the structure of a state: block in a config file. The block must have exactly one @backend: meta-key whose value is a fully-qualified alias.name reference such as core.local. It may include a nested encryption: object of the same form with @key-source:, plus any number of body fields keyed by bare identifiers. Body values are not type-checked here; the resolver decodes them against each backend's declared configuration.

func ValidateTopLevelKeys

func ValidateTopLevelKeys(f *File) *ErrorList

ValidateTopLevelKeys checks that every top-level field in f.Body uses an identifier key permitted for f.Kind, and that no key appears twice. Returns the collected errors. f.Kind must already be classified; FileUnknown produces a single error directing the caller to classify first.

type EvalFunc

type EvalFunc func(e Expr) (any, error)

EvalFunc reduces an expression to a Go value against an empty context. Defaults inside `optional(T, default)` evaluate this way so the validator can apply them without depending on the runtime package.

type Expr

type Expr = parse.Expr

func OutputValueExpr

func OutputValueExpr(e Expr) Expr

OutputValueExpr returns the inner expression of an output entry's wrapper. Every output in an `outputs:` block is of the form `name: { value: expr }`; this helper unwraps to the inner expr. Returns nil when the input is not a wrapper or has no `value:` key (treat as a structural error caught by ValidateOutputs).

func ParseExpr

func ParseExpr(path string, b []byte) (Expr, error)

ParseExpr parses a single unobin expression from b. It wraps parse.ParseExpr so callers depend on pkg/lang alone, such as goschema synthesizing a constraint's when/require expression from Go source.

type Field

type Field = parse.Field

type FieldDisplay added in v0.6.0

type FieldDisplay int

FieldDisplay selects how a constraint diagnostic spells field names. A factory-level check keeps the var root, the name an operator sets; a node-scoped check (a Go type's spec, a composite's own block) prints names relative to the node, matching the keys its body is written with. Lookup always uses the rooted name; only the message changes.

const (
	DisplayRooted FieldDisplay = iota
	DisplayNodeRelative
)

type FieldKey

type FieldKey = parse.FieldKey

type FieldKeyKind

type FieldKeyKind = parse.FieldKeyKind

type File

type File = parse.File

func ParseSource

func ParseSource(path string, b []byte) (*File, error)

ParseSource reads .ub source from b, returns the parsed File, and classifies the result via ClassifyByFilename so callers get a File.Kind without a separate step. The classification is what distinguishes this from parse.ParseSource.

type FileKind

type FileKind = parse.FileKind

func ClassifyByFilename

func ClassifyByFilename(path string) FileKind

ClassifyByFilename returns the file kind implied by the path's basename. `main.ub` is FileFactory and `unobin.manifest` is FileManifest; anything else is FileUnknown. Callers classify FileExportedType (a kind-prefixed `<kind>-<type>.ub` inside a library) and FileConfig (the operator's stack config file, supplied by path flag) from their own context.

type ForEachLevel added in v0.6.0

type ForEachLevel struct {
	Name   string
	In     Expr
	InText string
}

ForEachLevel is one link of a chained @for-each: the binding name, @-spelled, and the iterable its elements come from. InText is the iterable's source form, used to name the element a failure is about. The bare form is a single level binding @each.

type ForEachSpecLevel added in v0.6.0

type ForEachSpecLevel struct {
	Name string
	In   string
}

ForEachSpecLevel is the embeddable form of one chain level, with the iterable kept as unobin source the way a spec's when and require are.

type FormatOptions

type FormatOptions struct {
	// MaxColumn is the soft target line width. The formatter prefers
	// to break long lines so no rendered line exceeds this width. Some
	// constructs (a literal-mode triple-quoted string, or a single
	// token that won't fit anywhere) can still go past this width.
	MaxColumn int

	// WrapStrings, when true, lets the formatter rewrite an overflowing
	// single-quoted string as a folded (>-) or joined (\-) triple-quoted
	// string so the body wraps within the line budget. When false, a
	// single-quoted string keeps its form even when it overflows.
	WrapStrings bool
}

FormatOptions configures Format behavior. The zero value means "use defaults": MaxColumn is taken to be DefaultMaxColumn, and WrapStrings is false.

type Ident

type Ident = parse.Ident

type Infix

type Infix = parse.Infix

type InterpolatedPart

type InterpolatedPart = parse.InterpolatedPart

type InterpolatedString

type InterpolatedString = parse.InterpolatedString

type Node

type Node = parse.Node

type NullLit

type NullLit = parse.NullLit

type NumberLit

type NumberLit = parse.NumberLit

type ObjectLit

type ObjectLit = parse.ObjectLit

type Position

type Position = parse.Position

type Prefix

type Prefix = parse.Prefix

type Span

type Span = parse.Span

type StringForm

type StringForm = parse.StringForm

type StringLit

type StringLit = parse.StringLit

type TypeAtomic

type TypeAtomic = parse.TypeAtomic

type TypeExpr

type TypeExpr = parse.TypeExpr

func PromoteType

func PromoteType(e Expr) (TypeExpr, error)

PromoteType interprets e as a type expression and returns the corresponding TypeExpr tree. Type expressions are syntactically a subset of plain expressions: a bare identifier names an atomic type; a bare call names a constructor (list, set, map, tuple, object, optional, open). Anything outside that subset is rejected with an ErrType diagnostic.

Default values inside optional(T, default) are not promoted; they remain plain Expr because TypeOptional.Default is a value, not a type.

type TypeList

type TypeList = parse.TypeList

type TypeMap

type TypeMap = parse.TypeMap

type TypeObject

type TypeObject = parse.TypeObject

type TypeObjectField

type TypeObjectField = parse.TypeObjectField

type TypeOptional

type TypeOptional = parse.TypeOptional

type TypeTuple

type TypeTuple = parse.TypeTuple

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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