Documentation
¶
Overview ¶
Package functy implements an imperative language whose values are cty values and whose expressions are HCL. A functy source file is a sequence of function declarations; compiling it yields ordinary cty function.Function values that can be added to an *hcl.EvalContext and called from any HCL expression.
The statement grammar (func, var, if/else, for/while, switch, ...) is parsed by functy itself, while every embedded expression and type annotation is handed to HCL (hclsyntax.ParseExpression and ext/typeexpr), so operators, templates, function calls, and the cty type-constraint grammar behave exactly as they do elsewhere in HCL.
Index ¶
- Constants
- func BuildFunction(fn *FuncDecl, evalCtxFn func() *hcl.EvalContext) function.Function
- type Assign
- type Block
- type Break
- type Case
- type CondBranch
- type Continue
- type Decl
- type Defer
- type ExprStmt
- type For
- type ForKind
- type FuncDecl
- type IfChain
- type Param
- type Parser
- type Result
- type Return
- type Scope
- type Signal
- type SignalKind
- type Source
- type Statement
- type Switch
- type Throw
- type Try
- type VarDecl
Constants ¶
const Extension = ".cty"
Extension is the file extension for functy source files.
Variables ¶
This section is empty.
Functions ¶
func BuildFunction ¶
func BuildFunction(fn *FuncDecl, evalCtxFn func() *hcl.EvalContext) function.Function
BuildFunction builds a single cty function from a parsed declaration.
cty has no native optional parameters, so only the required parameters go in Spec.Params; optional parameters and the variadic parameter are collected via a VarParam and mapped back to names (applying defaults) inside the Impl.
Types ¶
type Assign ¶
type Assign struct {
Name string
Expr hcl.Expression
SrcRange hcl.Range
}
Assign reassigns an existing binding found by walking the scope chain.
type Case ¶
type Case struct {
Values []hcl.Expression
Body []Statement
SrcRange hcl.Range
}
Case is one case clause; it matches if any of its values equals the subject.
type CondBranch ¶
type CondBranch struct {
Condition hcl.Expression
Body []Statement
SrcRange hcl.Range
}
CondBranch is one condition-guarded branch of an if chain.
type Decl ¶
type Decl struct {
Name string
Type cty.Type // from an optional `: T`; cty.NilType if unannotated
Expr hcl.Expression // initializer, lazily evaluated (nil if none)
DefRange hcl.Range
}
Decl is a collected top-level var/const declaration, returned unevaluated so a host can fold it into its own dependency-sorting and evaluation pass. Expr.Variables() exposes the references needed for that sort.
type Defer ¶
type Defer struct {
Expr hcl.Expression
SrcRange hcl.Range
}
Defer schedules Expr to run when the enclosing function exits, in LIFO order.
type ExprStmt ¶
type ExprStmt struct {
Expr hcl.Expression
SrcRange hcl.Range
}
ExprStmt evaluates an expression purely for its side effects; the value is discarded.
type For ¶
type For struct {
Kind ForKind
// ForCond / ForClause:
Init Statement // ForClause init clause (nil otherwise)
Cond hcl.Expression // condition (nil = always true)
Post Statement // ForClause post clause (nil otherwise)
// ForRange:
KeyName string // first range variable ("" if absent)
ValName string // second range variable ("" if only one is given)
Collection hcl.Expression // collection being ranged over
Body []Statement
SrcRange hcl.Range
}
For is the unified loop node covering all loop forms.
type FuncDecl ¶
type FuncDecl struct {
Name string
Params []Param
RetType cty.Type // cty.NilType when no return type is annotated (dynamic)
Body []Statement
DefRange hcl.Range
}
FuncDecl is a top-level function declaration.
type IfChain ¶
type IfChain struct {
Branches []CondBranch
Else []Statement
SrcRange hcl.Range
}
IfChain is an if / else-if / else chain. Else is nil when there is no final else clause.
type Param ¶
type Param struct {
Name string
Type cty.Type // cty.NilType when unannotated (dynamic)
Default hcl.Expression // non-nil for an optional parameter
Variadic bool // true for the trailing *rest parameter
DefRange hcl.Range
}
Param is a single function parameter.
A parameter is required unless it has a Default or is Variadic. A typed parameter (Type != cty.NilType) converts its argument to that type. For a variadic parameter, Type is the *element* type: `*rest: T` collects the extra arguments into a list(T), while an untyped `*rest` collects them into a tuple.
type Parser ¶
type Parser struct {
// contains filtered or unexported fields
}
Parser parses functy source into a Result. Options accrue via chained setters; the zero value (via NewParser) accepts only function declarations.
func (*Parser) AllowTopLevelConst ¶
AllowTopLevelConst controls whether a top-level `const` declaration is collected into Result.Consts (true) or reported as a parse error (false, the default).
func (*Parser) AllowTopLevelVar ¶
AllowTopLevelVar controls whether a top-level `var` declaration is collected into Result.Vars (true) or reported as a parse error (false, the default).
func (*Parser) Parse ¶
Parse parses a single functy source. The returned Result holds the parsed declarations even when diagnostics contain errors (best-effort recovery), so callers should check diags before using it.
func (*Parser) ParseAll ¶
func (p *Parser) ParseAll(sources []Source) (*Result, hcl.Diagnostics)
ParseAll parses several sources and merges their declarations into one Result. Per-source declarations are concatenated in order; duplicate function names across sources are detected later by Result.Compile.
type Result ¶
type Result struct {
Funcs []*FuncDecl // parsed function declarations
Consts []Decl // top-level const declarations (only when enabled)
Vars []Decl // top-level var declarations (only when enabled)
}
Result is the outcome of parsing one or more functy sources. It is a struct (rather than a bare map) so additional collected output can be added without breaking callers.
func (*Result) Compile ¶
func (r *Result) Compile(evalCtxFn func() *hcl.EvalContext) (map[string]function.Function, hcl.Diagnostics)
Compile turns the parsed function declarations into cty functions. Each function captures evalCtxFn and calls it at invocation time (late binding), so a function may call sibling functions and reference host globals that are finalized after compilation — enabling recursion and mutual recursion.
Duplicate function names within the result are reported as errors; the host is responsible for detecting collisions against its own built-in functions when it merges the returned map into its registry.
type Return ¶
type Return struct {
Expr hcl.Expression
SrcRange hcl.Range
}
Return exits the enclosing function. Expr is nil for a bare return.
type Scope ¶
type Scope struct {
// contains filtered or unexported fields
}
Scope is a chained lexical scope. Variable lookup walks outward through the parent chain; the nearest binding wins. Declare always creates a binding in the innermost scope (shadowing any outer one); Set reassigns the nearest existing binding, converting to its pinned type.
dirty supports the interpreter's eval-context cache: it is set whenever a binding in this scope changes, so the interpreter knows to rebuild the merged *hcl.EvalContext before the next statement. Statements that cannot mutate a binding (a bare expression evaluated for its side effects, for instance) leave it clear, so consecutive such statements reuse one context.
func NewScope ¶
NewScope creates a scope with the given parent (nil for a function root). A fresh scope is dirty so the interpreter builds its context once before use.
func (*Scope) Declare ¶
Declare introduces a new binding in this (innermost) scope, shadowing any binding of the same name in an enclosing scope. For a typed declaration the initial value is converted to ty.
type Signal ¶
type Signal struct {
Kind SignalKind
Value cty.Value // meaningful only for SignalReturn
}
Signal carries a control-flow transfer up the call stack. A nil *Signal means normal completion (fall-through to the next statement).
type SignalKind ¶
type SignalKind int
SignalKind classifies a non-local control-flow transfer that propagates out of statement execution.
const ( // SignalReturn unwinds to the enclosing function with a value. SignalReturn SignalKind = iota // SignalBreak exits the innermost enclosing loop. SignalBreak // SignalContinue skips to the next iteration of the innermost loop. SignalContinue // SignalError unwinds a raised error (from throw or a failing expression) // until a try/catch handles it or it leaves the function. SignalError )
type Source ¶
Source is a single functy source: its filename (used in diagnostics) and raw bytes. ParseSources collects these from files, directories, and embedded filesystems.
func ParseSources ¶
func ParseSources(inputs ...any) ([]Source, hcl.Diagnostics)
ParseSources collects functy sources from a heterogeneous set of inputs, returning the raw bytes of each (it does not parse them — call Parser.Parse). Each argument may be:
- a string path to a .cty file, or to a directory (walked recursively, skipping dot-directories, collecting every .cty file);
- a []string of such paths;
- an embed.FS (walked recursively for .cty files);
- a Source, used as-is;
- a []byte, treated as the bytes of one anonymous source.
This mirrors how a host discovers .vcl/.vinit files, but yields raw bytes because functy has its own front-end.
type Statement ¶
type Statement interface {
// contains filtered or unexported methods
}
Statement is implemented by every functy statement node.
type Switch ¶
Switch is a switch statement. Subject is nil for the expression-less form, whose case values are boolean expressions evaluated like an if/else chain. Default is nil when there is no default clause.
type Throw ¶
type Throw struct {
Expr hcl.Expression
SrcRange hcl.Range
}
Throw raises an error whose value is Expr (a string becomes { message = <string>, value = null }; an object is used directly).
type Try ¶
type Try struct {
Body []Statement
HasCatch bool
CatchName string // error binding name; "" when omitted (catch { ... })
Catch []Statement
Finally []Statement
SrcRange hcl.Range
}
Try runs Body, optionally routing a raised error to a catch block and always running a finally block. At least one of Catch/Finally is present.