compile

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Jul 8, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

Package compile lowers a parsed Quill module to a single deterministic Go source file whose render function writes the template's output to an io.Writer. The generated function evaluates expressions through the same runtime operations (package runtime) and callable registry (package ext) the tree-walking interpreter uses, so the compiled output is byte-identical to the interpreter's for every construct in the compilable subset, including runtime error text and template:line positions.

The compiled variable scope is Go locals: every template name binds a runtime.Value local, shadowing uses compile-time generations, and loop copy-back assigns the inner generation back to the enclosing frame exactly where the interpreter's execFor copy-back would. Value semantics mirror the interpreter's copy-on-write contract: binds mark arrays shared where Scope.Set would, and member assignment unrolls the interpreter's ownPath (privatize-and-rebind) per site.

Constructs outside the compilable subset are detected and reported as a typed *NotCompilableError naming the construct; Module never emits silently wrong code for them.

Index

Constants

This section is empty.

Variables

View Source
var ErrNotCompilable error = notCompilableSentinel{}

ErrNotCompilable is the sentinel every *NotCompilableError matches through errors.Is, so callers can classify a compilation failure without inspecting the concrete type. It is an immutable value, not a pointer to a mutable struct, so it cannot be corrupted by a caller that classifies against it.

Functions

This section is empty.

Types

type LineMapEntry

type LineMapEntry struct {
	// Generated is the 1-based line number of the marker in Result.Source.
	Generated int
	// Source is the 1-based template line the following statements lower.
	Source int
}

LineMapEntry maps one generated source line to the template line whose lowering begins there. The generated file carries the same information as "//q:l N" marker comments; Result.LineMap is the parsed table.

type NotCompilableError

type NotCompilableError struct {
	// Construct names the unsupported construct, e.g. "@macro" or "function \"include\"".
	Construct string
	// Template is the template name the construct appears in.
	Template string
	// Line is the 1-based template line of the construct, or 0 when unknown.
	Line int
}

NotCompilableError reports a template construct outside the compilable subset. It names the construct and the template line it appears on.

func (*NotCompilableError) Error

func (e *NotCompilableError) Error() string

Error renders the construct name with its template:line position.

func (*NotCompilableError) Is

func (e *NotCompilableError) Is(target error) bool

Is reports whether target is the ErrNotCompilable sentinel or any *NotCompilableError, so errors.Is classification works on every construct instance and against the immutable sentinel alike.

type Options

type Options struct {
	// PackageName is the package clause of the generated file. Empty selects
	// "qtpl". It must be a valid Go identifier and not a Go keyword.
	PackageName string
	// FuncName is the name of the generated render function. Empty selects
	// "Render". It must be a valid Go identifier and not a Go keyword.
	FuncName string
	// AutoescapeHTML selects the module-level output strategy: html when true,
	// off when false, matching the engine's WithAutoescapeHTML option. An
	// @escape region overrides it for its body at compile time.
	AutoescapeHTML bool
	// LenientVariables selects the engine's lenient migration mode
	// (WithStrictVariables(false)): an undefined read yields null and a for
	// over a non-iterable yields an empty loop. The zero value is the engine
	// default, strict variables.
	LenientVariables bool
	// TabWidth is the number of spaces one @tab indent level expands to,
	// matching the engine's WithTabWidth option. Zero selects the engine
	// default of 4. The generated render function carries this width on the
	// engine handle it injects into needs-environment callables, so the tab
	// filter and tab() function honor it exactly like the facade's.
	TabWidth int
	// RandomSeed fixes the seed of the engine's randomness callables (the
	// random() function and the shuffle filter) for deterministic output,
	// matching the engine's WithRandomSeed option. It applies only when
	// RandomSeedSet is true; the zero value leaves the callables on the engine
	// default, a time-seeded source per call. A compiled render seeded like
	// its facade counterpart produces byte-identical random output; an
	// UNSEEDED template whose output depends on random()/shuffle draws from
	// two independent time-seeded sources, so its output compares to the
	// facade's distributionally, never byte-wise.
	RandomSeed int64
	// RandomSeedSet reports whether RandomSeed is meaningful, distinguishing a
	// deliberate seed of zero from the unseeded engine default.
	RandomSeedSet bool
	// Types is the host static-typing registry the gradual type checker
	// consults, matching the engine's WithTypes option. Module runs the same
	// load-time checker the facade runs, so a nil registry behaves exactly
	// like a facade built without WithTypes: Object types are opaque and host
	// callables dynamic, while in-template annotations are still enforced.
	Types *check.Registry
	// Templates carries the sibling modules a static @include may inline, keyed
	// by template name (the same map Unit consumes as its whole template set).
	// A Module compilation reaches an included partial's statements only through
	// this map; a name absent from it makes a plain @include of that literal a
	// typed subset rejection, and an ignore-missing @include of it a
	// gate-guarded render-nothing. The entry itself may appear here and is
	// ignored. Unit fills this from its own templates argument, so a Unit needs
	// nothing set here.
	Templates map[string]*ast.Node
}

Options configures one Module compilation.

type Result

type Result struct {
	// Source is the gofmt-formatted generated Go file.
	Source []byte
	// FuncName is the name of the generated render function.
	FuncName string
	// LineMap maps generated lines to template lines, sorted by Generated.
	LineMap []LineMapEntry
}

Result is the output of a successful Module call.

func Module

func Module(name string, mod *ast.Node, opts Options) (*Result, error)

Module compiles a parsed template module to one Go source file containing a render function with the signature

func <FuncName>(ctx context.Context, w io.Writer, exts *ext.Set, vars map[string]runtime.Value, rc compiled.RenderCache) error

alongside an exported <FuncName>Manifest value (package compiled) describing the unit to the Environment's by-name dispatch: quill.WithCompiled installs the manifest and serves renders of the entry template through the generated function whenever the Environment's configuration matches the manifest's fingerprint and the loader still serves the compiled source bytes.

The name parameter is the template name errors and the file header cite; when the module's parse source is available it takes precedence so error positions match the interpreter's exactly.

Module runs the facade's load-time gates before lowering: the gradual type checker (check.Check with Options.Types) and the literal-regex validation of `matches` patterns, so a template the facade rejects at load fails here with the same error. A construct outside the compilable subset returns a *NotCompilableError; any other error is an internal failure.

Byte parity with the facade holds for every compiled construct EXCEPT unseeded randomness: without a RandomSeed on both sides, random() and the shuffle filter draw from independent time-seeded sources, so such output compares distributionally only. Seeding Options and the facade identically restores byte parity.

func Unit

func Unit(entry string, templates map[string]*ast.Node, opts Options) (*Result, error)

Unit compiles a multi-template unit to one Go source file: the entry template plus every template its static composition references (@extends parents, @use traits, and block(name, "other") targets), with the most-derived block bodies inlined into the topmost parent's statement list at compile time, exactly where the interpreter's merged block table would resolve them. parent() lowers to an inline capture of the next definition down its chain, and error positions cite the defining member template's name and line, so output and error text stay byte-identical to the facade's for every compiled construct.

The entry names the template a by-name render serves; templates maps every unit member name to its parsed module (extra entries are ignored). The composition must be static: a dynamic @extends operand, a candidate list whose first candidate is not a member, a member referenced but missing from templates, macros or imports on the entry, and every construct outside Module's compilable subset return a typed *NotCompilableError naming the construct. A composition the interpreter rejects at render entry with a deterministic error (a non-traitable @use target, an invalid trait alias, a too-deep inheritance chain) compiles to a render function returning exactly that error.

The generated manifest embeds every member template's source, so the Environment's dispatch gate (quill.WithCompiled) byte-verifies the whole unit against its loader before serving the compiled render. Byte parity carries Module's one documented exception, unseeded randomness.

Jump to

Keyboard shortcuts

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