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
- Variables
- func Format(file *File) ([]byte, error)
- func FormatWith(file *File, opts FormatOptions) ([]byte, error)
- func ParseSpecs(specs []ConstraintSpec) ([]ConstraintEntry, *ErrorList)
- func Render(v any) string
- func RenderKey(k string) string
- func RenderPretty(v any) string
- func SensitiveInputs(block *ObjectLit) map[string]bool
- func SensitiveOutputs(block *ObjectLit) map[string]bool
- func TypeMessage(v any) string
- func Walk(e Expr, visit func(Expr))
- type ArrayLit
- type BoolLit
- type Call
- type Comment
- type Comprehension
- type ComprehensionKind
- type Conditional
- type ConstraintEntry
- type ConstraintSpec
- type DotPath
- type DotSegment
- type Error
- type ErrorKind
- type ErrorList
- func CheckConstraintEntries(entries []ConstraintEntry, values map[string]any, evalAgainstInputs EvalFunc) *ErrorList
- func CheckConstraints(block *ArrayLit, values map[string]any, evalAgainstInputs EvalFunc) *ErrorList
- func ValidateActions(block *ObjectLit) *ErrorList
- func ValidateCalls(f *File) *ErrorList
- func ValidateConfigInputs(block *ObjectLit) *ErrorList
- func ValidateConfigurations(block *ObjectLit) *ErrorList
- func ValidateConstraintReferences(constraints *ArrayLit, inputs *ObjectLit) *ErrorList
- func ValidateConstraints(arr *ArrayLit) *ErrorList
- func ValidateDataSources(block *ObjectLit) *ErrorList
- func ValidateEncryptionConfig(block *ObjectLit) *ErrorList
- func ValidateFile(f *File) *ErrorList
- func ValidateImports(block *ObjectLit) *ErrorList
- func ValidateInputDeclarations(block *ObjectLit) *ErrorList
- func ValidateInputs(decl *ObjectLit, values map[string]any, evalDefault EvalFunc) (map[string]any, *ErrorList)
- func ValidateLocals(block *ObjectLit) *ErrorList
- func ValidateManifestReplace(block *ObjectLit) *ErrorList
- func ValidateManifestRequires(block *ObjectLit) *ErrorList
- func ValidateOutputs(block *ObjectLit) *ErrorList
- func ValidateResources(block *ObjectLit) *ErrorList
- func ValidateStateConfig(block *ObjectLit) *ErrorList
- func ValidateTopLevelKeys(f *File) *ErrorList
- type EvalFunc
- type Expr
- type Field
- type FieldKey
- type FieldKeyKind
- type File
- type FileKind
- type FormatOptions
- type Ident
- type Infix
- type InterpolatedPart
- type InterpolatedString
- type Node
- type NullLit
- type NumberLit
- type ObjectLit
- type Position
- type Prefix
- type Span
- type StringForm
- type StringLit
- type TypeAtomic
- type TypeExpr
- type TypeList
- type TypeMap
- type TypeObject
- type TypeObjectField
- type TypeOptional
- type TypeSet
- type TypeTuple
Constants ¶
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 )
const DefaultMaxColumn = 100
DefaultMaxColumn is the line width used when FormatOptions.MaxColumn is unset.
Variables ¶
var ( NewErrorList = parse.NewErrorList Errorf = parse.Errorf PascalToKebab = parse.PascalToKebab )
Functions ¶
func Format ¶
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 ¶
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 ¶
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 ¶
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 ¶
SensitiveInputs returns the set of input names declared with `@sensitive: true` in an `inputs:` block. Nil block yields an empty map.
func SensitiveOutputs ¶
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 ¶
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 ¶
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 Comprehension ¶
type Comprehension = parse.Comprehension
type ComprehensionKind ¶
type ComprehensionKind = parse.ComprehensionKind
type Conditional ¶
type Conditional = parse.Conditional
type ConstraintEntry ¶
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). goschema builds these directly for Go library types so they run through the same check as UB ones.
type ConstraintSpec ¶
type ConstraintSpec struct {
Kind string
Fields []string
When string
Require string
Message string
}
ConstraintSpec is the embeddable, string-only form of a constraint. The predicate When and Require 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 both empty and uses Fields. goschema produces these from a Go type, and codegen bakes them into the factory.
type DotSegment ¶
type DotSegment = parse.DotSegment
type ErrorList ¶
func CheckConstraintEntries ¶
func CheckConstraintEntries( entries []ConstraintEntry, values map[string]any, evalAgainstInputs EvalFunc, ) *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 CheckConstraints ¶
func CheckConstraints( block *ArrayLit, values map[string]any, evalAgainstInputs EvalFunc, ) *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 ¶
ValidateActions checks the shape of an `actions:` block.
func ValidateCalls ¶ added in v0.5.0
ValidateCalls walks every expression in f and rejects two kinds of function call: a bare call with no library qualifier (every function lives in a library, so a call must name one, e.g. core.format), and a qualified call whose alias is missing from the file's imports block. 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 function exists is not checked here; that is a runtime concern, since a library's function set lives in compiled Go code.
func ValidateConfigInputs ¶ added in v0.5.0
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
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 ¶
ValidateConstraintReferences checks that every name in the `fields:` list of each constraint corresponds to a declared input. Constraint entries with the wrong shape are skipped.
func ValidateConstraints ¶
ValidateConstraints walks a `constraints:` array and checks each entry's shape per its declared `kind:`. Field-based kinds carry a nonempty `fields:` list of input names; the `predicate` kind carries `when:` and `require:` expressions plus an optional `message:`.
func ValidateDataSources ¶
ValidateDataSources checks the shape of a `data:` block.
func ValidateEncryptionConfig ¶
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 ¶
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 ¶
ValidateImports checks an `imports:` block: every entry is an identifier alias bound to a quoted string source URL or local path.
func ValidateInputDeclarations ¶
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 ¶
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
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
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 ¶
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 ¶
ValidateResources checks a `resources:` block level by level: alias, type name, instance name, body.
func ValidateStateConfig ¶
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 ¶
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 ¶
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 ¶
func OutputValueExpr ¶
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).
type FieldKeyKind ¶
type FieldKeyKind = parse.FieldKeyKind
type File ¶
func ParseSource ¶
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 ¶
func ClassifyByFilename ¶
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 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 InterpolatedPart ¶
type InterpolatedPart = parse.InterpolatedPart
type InterpolatedString ¶
type InterpolatedString = parse.InterpolatedString
type StringForm ¶
type StringForm = parse.StringForm
type TypeAtomic ¶
type TypeAtomic = parse.TypeAtomic
type TypeExpr ¶
func PromoteType ¶
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). 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 TypeObject ¶
type TypeObject = parse.TypeObject
type TypeObjectField ¶
type TypeObjectField = parse.TypeObjectField
type TypeOptional ¶
type TypeOptional = parse.TypeOptional