functy

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jul 1, 2026 License: MIT Imports: 13 Imported by: 0

README

functy

An imperative language whose values are cty values and whose expressions are HCL.

Pronounced funk-tie — the -ty rhymes with cty ("see-tie"). But I won't be mad if you pronounce it funk-tee. I sometimes forget too.

functy is not aiming to compete with Starlark, Tengo, or any of the various JavaScript or Lua implementations for Go. It is intended specifically for use in software that is already relying on HCL / Cty but which needs more expressive power than eg the HCL user function add-on.

go-cty describes itself this way:

One could think of cty as being the reflection API for a language that doesn't exist, or that doesn't exist yet.

functy aims to be that language.

CI

Overview

functy is a small Go-inspired imperative language that compiles to ordinary cty function.Function values. You write functions with familiar control flow — if/else, for/while, switch, try/catch — and every expression is a real HCL expression: operators, string templates ("hello ${name}"), function calls, conditionals, and the cty type-constraint grammar all behave exactly as they do in HCL/Terraform.

The result is a thin, honest imperative skin over cty + HCL: its values are cty values, its types are cty types, and the functions it produces are callable from any HCL evaluation context — alongside the host application's own functions.

func classify(n: number) -> string {
    if n > 0 {
        return "positive"
    } else if n < 0 {
        return "negative"
    } else {
        return "zero"
    }
}

func greet(name: string = "world") -> string {
    return "hello ${name}"
}

functy source files use the .cty extension.

Installation

As a library:

go get github.com/tsarna/functy

The library depends only on github.com/hashicorp/hcl/v2 and github.com/zclconf/go-cty.

As a CLI:

go install github.com/tsarna/functy/cmd/functy@latest

CLI quick start

$ cat > math.cty <<'EOF'
func add(a: number, b: number) -> number {
    return a + b
}
func main() -> number {
    return add(2, 3)
}
EOF

$ functy run math.cty
5

$ functy run math.cty --func add -- 2 3
5

$ functy check math.cty
ok

See doc/cli.md for the full CLI reference and doc/language.md for the language reference.

Library usage

Parse a source, compile it against a late-bound eval context, and call the resulting functions:

package main

import (
	"fmt"

	"github.com/hashicorp/hcl/v2"
	"github.com/tsarna/functy"
	"github.com/zclconf/go-cty/cty"
	"github.com/zclconf/go-cty/cty/function"
)

func main() {
	src := []byte(`func add(a: number, b: number) -> number { return a + b }`)

	res, diags := functy.NewParser().Parse(src, "add.cty")
	if diags.HasErrors() {
		panic(diags.Error())
	}

	// The eval context is late-bound so functions can call one another (and
	// reference host globals finalized later).
	var ctx *hcl.EvalContext
	funcs, diags := res.Compile(func() *hcl.EvalContext { return ctx })
	if diags.HasErrors() {
		panic(diags.Error())
	}
	ctx = &hcl.EvalContext{
		Functions: funcs,
		Variables: map[string]cty.Value{},
	}

	out, err := funcs["add"].Call([]cty.Value{cty.NumberIntVal(2), cty.NumberIntVal(3)})
	if err != nil {
		panic(err)
	}
	fmt.Println(out.AsBigFloat()) // 5
}

A host typically merges the compiled functions with its own function library and ambient values into one eval context. functy.ParseSources collects .cty sources from file paths, directories, or an embed.FS; Parser.ParseAll parses several sources into one Result.

A host can also register its own named types so they can be used in annotations:

p := functy.NewParser().
    RegisterType("bus", busCapsuleType).            // identity-enforced capsule type
    RegisterOpenType("ctx", isContextObject)        // predicate-backed open type

Identity types must match by type; open types must satisfy a predicate and pass through untouched (extra attributes preserved). See doc/language.md.

Type system as a reusable component

functy's type system is usable on its own, independent of parsing .cty programs — as a richer alternative to ext/typeexpr (the result is a TypeConstraint that can enforce values via Coerce, not just a cty.Type), or for a host to type-check its own configuration:

r := functy.NewTypeResolver().RegisterType("bus", busCapsuleType)

// Resolve a type annotation (from a string, or an hcl.Expression):
tc, diags := r.ParseType([]byte("list(string)"), "config")
// tc.Cty()  -> cty.List(cty.String)
// tc.Coerce(value) -> the value converted/validated, or an error

// ResolveType(expr) takes an already-parsed hcl.Expression (e.g. a decoded HCL
// attribute) — the typeexpr.TypeConstraint analog.

A Parser holds a TypeResolver (Parser.Types()) and registers named types on it, so a host registers its capsule/open types once and uses them both for parsing .cty files and for resolving standalone annotations.

Status

functy implements a complete core language: typed and dynamic variables, reassignment, all control-flow forms, variadic and optional parameters, structured error handling (try/catch/finally, throw, defer, and val, err = expr error capture), a null (void) return type, and the functy run / functy check CLI commands.

Types are resolved by functy's own resolver (not ext/typeexpr), with a host-pluggable named-type environment for capsule and open types, type aliases, and opt-in strict typing.

Designed-but-not-yet-implemented features (a REPL, a formatter, module imports, closures, a functy standard library, nested open types, ...) are recorded in FUTURE.md. The design rationale ("why a language, not an embedded one") is in DESIGN.md, and the internal architecture is in CONTRIBUTING.md.

License

MIT, like cty itself — see LICENSE.

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 is handed to HCL (hclsyntax.ParseExpression), so operators, templates, and function calls behave exactly as they do elsewhere in HCL. Type annotations are resolved by functy's own TypeResolver — a superset of the ext/typeexpr grammar that also supports host-registered capsule and open (predicate-backed) named types.

Index

Constants

View Source
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 Block

type Block struct {
	Body     []Statement
	SrcRange hcl.Range
}

Block is a bare { ... } that introduces a nested lexical scope.

type Break

type Break struct {
	Label    string // "" for the innermost loop
	SrcRange hcl.Range
}

Break exits an enclosing loop: the innermost one, or the loop named by Label.

type CaptureAssign added in v0.3.0

type CaptureAssign struct {
	ValName  string // "_" to discard the value
	ErrName  string // "_" to discard the error
	Declare  bool   // true for the `:=` declare-and-capture form
	Expr     hcl.Expression
	ValRange hcl.Range // the value target, for diagnostics
	ErrRange hcl.Range // the error target, for diagnostics
	SrcRange hcl.Range
}

CaptureAssign is the two-target error-capture assignment `val, err = expr`. It evaluates Expr exactly once; on success it assigns the value to ValName and null to ErrName, and on failure it assigns null to ValName and the caught error to ErrName. Either target may be "_" (the blank identifier) to discard it. It is statement-level sugar for a try/catch — the function never unwinds.

When Declare is false (the `val, err = expr` operator) both non-blank targets must already be declared, like a plain `=`. When Declare is true (the `val, err := expr` shorthand) each non-blank target is newly declared (untyped) in the current scope, like a pair of `var`s.

type CatchClause added in v0.3.0

type CatchClause struct {
	Name     string         // "" when omitted
	Type     TypeConstraint // nil = no type filter
	Guard    hcl.Expression // nil = no guard
	Body     []Statement
	SrcRange hcl.Range
}

CatchClause is one `catch [name] [: type] [if guard] { ... }` clause. It matches a raised error iff its type filter's Coerce succeeds (Type == nil matches any shape) and its guard evaluates true (Guard == nil is unconditional); a clause with both Type and Guard nil is the catch-all. The bound name receives the raw error value (the filter is a gate, not a cast).

type Clause added in v0.3.0

type Clause struct {
	Values    []hcl.Expression
	IsDefault bool
	Body      []Statement
	SrcRange  hcl.Range
}

Clause is one case or default clause of a switch. For a case clause Values holds the match expressions (it runs if any equals the subject, or — in the expression-less form — if any is true); the default clause has IsDefault true and no Values. A body whose final statement is Fallthrough transfers control to the next clause in source order.

type CondBranch

type CondBranch struct {
	Condition hcl.Expression
	Body      []Statement
	SrcRange  hcl.Range
}

CondBranch is one condition-guarded branch of an if chain.

type Continue

type Continue struct {
	Label    string // "" for the innermost loop
	SrcRange hcl.Range
}

Continue skips to the next iteration of an enclosing loop: the innermost one, or the loop named by Label.

type Decl

type Decl struct {
	Name     string
	Type     TypeConstraint // from an optional `: T`; nil 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 Directive added in v0.2.0

type Directive struct {
	Namespace string
	Name      string
	Args      string
	Range     hcl.Range
}

Directive is a collected directive comment, following Go's convention: a line comment with no space after `//`, of the form `//<namespace>:<name> [args]`. A space after `//` (`// functy: …`) makes it ordinary prose, not a directive.

functy interprets only its own `functy:` namespace (strict, require); every other namespace is collected and passed through untouched for the host to act on (e.g. `//vinculum:cache 5m`).

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 Fallthrough added in v0.3.0

type Fallthrough struct{ SrcRange hcl.Range }

Fallthrough transfers control to the next clause of the enclosing switch, running its body without testing. It is legal only as the final statement of a case or default body, and not in the last clause.

type For

type For struct {
	Kind ForKind

	// Label is the loop's label ("" if unlabeled); a labeled break/continue whose
	// target equals this label is consumed by this loop rather than an inner one.
	Label string

	// 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 ForKind

type ForKind int

ForKind distinguishes the three surface forms of a for/while loop.

const (
	// ForCond is `for cond { ... }`, `while cond { ... }`, or the infinite
	// `for { ... }` (Cond nil).
	ForCond ForKind = iota
	// ForClause is the three-clause `for init; cond; post { ... }`.
	ForClause
	// ForRange is `for v in coll { ... }` or `for k, v in coll { ... }`.
	ForRange
)

type FuncDecl

type FuncDecl struct {
	Name     string
	Params   []Param
	RetType  TypeConstraint // nil 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     TypeConstraint // nil 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 and the built-in type grammar.

func NewParser

func NewParser() *Parser

NewParser returns a Parser with default options.

func (*Parser) AllowTopLevelConst

func (p *Parser) AllowTopLevelConst(v bool) *Parser

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

func (p *Parser) AllowTopLevelVar(v bool) *Parser

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

func (p *Parser) Parse(src []byte, filename string) (*Result, hcl.Diagnostics)

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 together and merges their declarations into one Result. The sources share one namespace: type aliases declared in any source are visible to every source (see parseSources), and per-source function/var/ const declarations are concatenated in order (duplicate function names across sources are detected later by Result.Compile).

func (*Parser) RegisterOpenType added in v0.2.0

func (p *Parser) RegisterOpenType(name string, pred func(cty.Value) error) *Parser

RegisterOpenType registers a named open type backed by a predicate. An annotation naming it requires the value to satisfy pred and otherwise passes it through untouched (non-destructive), so extra attributes survive — suitable for marker-capsule objects (e.g. a ctx carrying _ctx plus other fields) and required-attribute objects (e.g. an error with at least a message). Returns the Parser for chaining.

func (*Parser) RegisterType added in v0.2.0

func (p *Parser) RegisterType(name string, ty cty.Type) *Parser

RegisterType registers a named (capsule) type. An annotation naming it is enforced by type identity: a value must already be of ty (or null), unless ty itself defines a conversion. Hosts use this for their cty capsule and rich-object types. Returns the Parser for chaining.

func (*Parser) RequireDeclaredTypes added in v0.2.0

func (p *Parser) RequireDeclaredTypes(v bool) *Parser

RequireDeclaredTypes requires every var/const declaration to carry a type (`: T`). See RequireParamTypes for the off-by-default and tighten-only semantics.

func (*Parser) RequireParamTypes added in v0.2.0

func (p *Parser) RequireParamTypes(v bool) *Parser

RequireParamTypes, when set, requires every function parameter to carry an explicit type annotation (`: T`; `any` is allowed but must be written). Off by default. A file may additionally request this via a //functy: directive, but a file can never relax a host-set requirement. Returns the Parser for chaining.

func (*Parser) RequireReturnType added in v0.2.0

func (p *Parser) RequireReturnType(v bool) *Parser

RequireReturnType requires every function to declare a return type (`-> T`). See RequireParamTypes for the off-by-default and tighten-only semantics.

func (*Parser) Types added in v0.2.0

func (p *Parser) Types() *TypeResolver

Types returns the parser's TypeResolver. Named types registered through the Parser are registered on it, so a host can resolve standalone type annotations (TypeResolver.ResolveType / ParseType) against the very same named types it uses for parsing `.cty` files.

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)
	Types  []TypeAlias // top-level type aliases (project-scoped across all sources)

	// Directives are the directive comments from each source's leading comment
	// block (file-scope), across all sources. functy acts on its own `functy:`
	// namespace; others are passed through for the host.
	Directives []Directive
}

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

func NewScope(parent *Scope) *Scope

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

func (s *Scope) Declare(name string, tc TypeConstraint, val cty.Value) error

Declare introduces a new binding in this (innermost) scope, shadowing any binding of the same name in an enclosing scope. For a typed declaration (a non-nil constraint) the initial value is coerced through it.

func (*Scope) Get

func (s *Scope) Get(name string) (cty.Value, bool)

Get looks up a variable's value by walking the scope chain outward.

func (*Scope) Set

func (s *Scope) Set(name string, val cty.Value) error

Set reassigns the nearest existing binding of name, coercing the value through that binding's constraint. It is an error if name is not declared in any enclosing scope, or if the value cannot satisfy the constraint.

func (*Scope) ToMap

func (s *Scope) ToMap() map[string]cty.Value

ToMap flattens the scope chain into a single name->value map, inner scopes taking precedence over outer ones.

type Signal

type Signal struct {
	Kind  SignalKind
	Value cty.Value // meaningful only for SignalReturn
	Label string    // target loop label for SignalBreak / SignalContinue ("" = innermost)
}

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
	// SignalFallthrough transfers control to the next clause of the enclosing
	// switch. It is produced only by a Fallthrough statement and is always
	// consumed by execSwitch, never escaping the switch.
	SignalFallthrough
)

type Source

type Source struct {
	Filename string
	Bytes    []byte
}

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

type Switch struct {
	Subject  hcl.Expression
	Clauses  []Clause
	SrcRange hcl.Range
}

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. Clauses are in source order; at most one is the default.

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 ThrownError added in v0.3.0

type ThrownError struct{ Value cty.Value }

ThrownError is the Go error a functy function returns at its cty.Function boundary when an uncaught throw unwinds out of it. It carries the raw error value so a functy catch (or a Go host, via errors.As) recovers the full error object; Error() renders the message for any other caller.

func (*ThrownError) Error added in v0.3.0

func (e *ThrownError) Error() string

type Try

type Try struct {
	Body     []Statement
	Catches  []CatchClause
	Finally  []Statement
	SrcRange hcl.Range
}

Try runs Body, routing a raised error through its catch clauses (first match wins) and always running a finally block. At least one of Catches/Finally is present.

type TypeAlias added in v0.2.0

type TypeAlias struct {
	Name     string
	Type     TypeConstraint
	DefRange hcl.Range
}

TypeAlias is a resolved top-level `type Name = <type>` declaration. Aliases are project-scoped: every alias collected from the sources parsed together is visible to every source (like the function namespace), so a function in one file may use a type declared in another.

type TypeConstraint added in v0.2.0

type TypeConstraint interface {
	// Coerce applies the constraint to a value, returning the value to store or
	// an error if it does not satisfy the constraint.
	Coerce(cty.Value) (cty.Value, error)
	// Cty returns the underlying cty.Type (dynamic for `any`, void, and open
	// predicate types).
	Cty() cty.Type
	String() string
}

TypeConstraint is a resolved type annotation: it knows how to coerce a value to satisfy the annotation and exposes the underlying cty.Type. A nil TypeConstraint means "dynamic" (no annotation) — no coercion is applied.

It is the single source of truth for a declared type. Cty() derives the cty.Type, so callers that only need the type (host introspection, generated docs) need not carry it separately; Coerce() applies the enforcement.

Three coercion disciplines exist: structural/primitive annotations convert the value (cty/convert); a named (capsule) type is checked by identity; an open type is checked by a predicate and otherwise passed through untouched. This is why functy owns its resolver rather than delegating to ext/typeexpr, whose closed grammar cannot name capsule types or express open ("at least these attributes") types — and why a bare cty.Type cannot represent every constraint (a predicate type's Cty() is only dynamic).

func ConvertType added in v0.2.0

func ConvertType(ty cty.Type) TypeConstraint

ConvertType wraps a concrete cty.Type as a TypeConstraint enforced by conversion (cty/convert). Useful for a host that already has a cty.Type — for example a backward-compatible path for a type that was specified some other way.

type TypeResolver added in v0.2.0

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

TypeResolver is functy's type system as a standalone, reusable component. It resolves functy type annotations (the same grammar used in `.cty` source) into TypeConstraints, against the built-in types plus any host-registered named types. It is usable independently of parsing functy programs — for example as a richer alternative to ext/typeexpr (a TypeConstraint carries enforcement via Coerce, not just a cty.Type), or for a host to type-check its own configuration (e.g. resolving a declared type and enforcing a value with Coerce).

A Parser holds one (see Parser.Types); register named types once and use them both for parsing `.cty` files and for resolving standalone annotations.

func NewTypeResolver added in v0.2.0

func NewTypeResolver() *TypeResolver

NewTypeResolver returns a resolver with functy's built-in types (including the `error` open type) and no host registrations.

func (*TypeResolver) ParseType added in v0.2.0

func (r *TypeResolver) ParseType(src []byte, filename string) (TypeConstraint, hcl.Diagnostics)

ParseType lexes a type annotation from source bytes and resolves it — a convenience for annotations stored as strings (e.g. a host config field).

func (*TypeResolver) RegisterOpenType added in v0.2.0

func (r *TypeResolver) RegisterOpenType(name string, pred func(cty.Value) error) *TypeResolver

RegisterOpenType registers a named open type backed by a predicate. See Parser.RegisterOpenType. Returns the resolver for chaining.

func (*TypeResolver) RegisterType added in v0.2.0

func (r *TypeResolver) RegisterType(name string, ty cty.Type) *TypeResolver

RegisterType registers a named (capsule) type, enforced by type identity. See Parser.RegisterType. Returns the resolver for chaining.

func (*TypeResolver) ResolveType added in v0.2.0

func (r *TypeResolver) ResolveType(expr hcl.Expression) (TypeConstraint, hcl.Diagnostics)

ResolveType resolves a parsed type-annotation expression (e.g. an HCL attribute value) into a TypeConstraint — the analog of typeexpr.TypeConstraint, but yielding a constraint that can enforce values, not just a cty.Type. `null` is not accepted here (it is only meaningful as a function return type).

type VarDecl

type VarDecl struct {
	Name     string
	Type     TypeConstraint // nil when unannotated (dynamic)
	Init     hcl.Expression
	SrcRange hcl.Range
}

VarDecl declares a new local binding in the current scope.

Type is cty.NilType for a dynamic variable. Init is nil for a declaration with no initializer, which defaults to null (of the declared type, if any).

Directories

Path Synopsis
cmd
functy command
Command functy is a small CLI for loading and running functy source files.
Command functy is a small CLI for loading and running functy source files.

Jump to

Keyboard shortcuts

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