The one-way compile: a block document plus a palette in, one artifact out (ADR-0004 decisions 1-4, 6-7).
compile/3 is a total function of {document, palette}. No process
state, no global registry, no IO, no clock - the same purity ADR-0002
decision 4 imposes on the callbacks, imposed on the pipeline that calls
them. It returns {:ok, %StatifierBlocks.Compiled{}} or
{:error, [%StatifierBlocks.Compiler.Finding{}]}, never raises, and never
partially succeeds.
The pipeline
Each stage runs over the whole document; the first stage that produces
errors stops the compile and reports every error it found. Stopping
rather than accumulating across stages is deliberate - see
StatifierBlocks.Compiler.Finding.
- Document -
StatifierBlocks.Document.validate/1. Structural only; no palette is consulted. - Resolve - every block through
StatifierBlocks.Palette.resolve/2, which also applies an in-memory config migration (ADR-0002 decision 8). Nothing is written back. - Config - every block's
validate_config/1. - Structure -
StatifierBlocks.Assignability.validate/3: may this block land in this slot, by kind tag and by data-flow type (ADR-0003)? - Emit - bottom-up. Each block's
emit/2is called with its children already compiled and summarized, its emission is attributed (StatifierBlocks.Compiler.Attribution), and its child placeholders are spliced with those children's own emissions. - Chart - serialize once through
StatifierBlocks.Compiler.Serializer, which writes the bytes and the provenance map together, then run those bytes throughStatifier.compile/2and map every finding back through provenance (StatifierBlocks.Compiler.Chart).
Findings from every stage are reported in document order over blocks -
StatifierBlocks.Document.blocks/1's pre-order - which is how upstream's
own document-order sort survives the trip.
The Structure stage is not yet whole
Decision 10's table names three things in this stage: slot arity,
:undeclared_slot, and assignability. Only the third runs here.
Palette-aware arity and undeclared-slot validation is sb-da9's,
filed and unworked; this module draws the seam and leaves it empty
rather than growing a second implementation of ADR-0002 decision 6's
rules beside the one that bead will ship. Until it lands the pipeline
simply never visits a slot slots/1 did not declare, so an undeclared
slot's blocks are absent from the emission rather than misplaced in it -
which is a silent drop, and exactly what sb-da9 exists to make loud.
Options
:known_invoke_types- decision 8's opt-in lint. A set (or list) of invoke types the caller believes will be registered; every emitted type absent from it becomes a warning, never an error. SeeStatifierBlocks.Compiler.InvokeTypes.:entry_type- ADR-0003 decision 4's caller-supplied context: the type flowing into the document's root. Defaults to absent, whichStatifierBlocks.Assignabilityreads as:unknown. ADR-0004's own typespec lists only the first option, because it delegated assignability wholesale to ADR-0003 (decision 11) without noticing that ADR-0003's context is caller-supplied and therefore has to arrive through this function. This is that arrival, not a second decision about what assignability means.
Determinism (decision 6)
For a fixed
{document canonical bytes, palette, compiler version}, the generated SCXML is byte-identical on every machine and every run, forever.
All three inputs are real, and StatifierBlocks.CompilationRecord
records all three. What this module contributes to the guarantee is that
it never iterates a bare map: slots are visited in slots/1 declaration
order (ADR-0002 decision 6 made that order meaningful), children in
document order, and attributes are sorted at construction by
StatifierBlocks.Emission.element/3.
The guarantee is not reversible and must not be read as one. Equal
output does not imply equal input: a metadata-only edit changes the
document hash and produces identical SCXML, because metadata is not
compiled. A host may use "same triple" to skip a recompile, and may
not use "same SCXML" to conclude the document is unchanged.
Summary
Types
:known_invoke_types enables decision 8's optional two-registry lint;
:entry_type is ADR-0003 decision 4's caller-supplied context. See the
moduledoc.
Functions
Compiles document against palette.
Decision 6's third determinism input: this package's version.
Types
@type option() :: {:known_invoke_types, Enumerable.t()} | {:entry_type, StatifierBlocks.Assignability.type_expr() | :unknown}
:known_invoke_types enables decision 8's optional two-registry lint;
:entry_type is ADR-0003 decision 4's caller-supplied context. See the
moduledoc.
Functions
@spec compile(StatifierBlocks.Document.t(), StatifierBlocks.Palette.t(), [option()]) :: {:ok, StatifierBlocks.Compiled.t()} | {:error, [StatifierBlocks.Compiler.Finding.t()]}
Compiles document against palette.
Total: {:ok, %StatifierBlocks.Compiled{}} or
{:error, [%StatifierBlocks.Compiler.Finding{}]}, never a raise and
never a partial success. Errors come from the first failing stage only
(decision 10); warnings ride on the artifact when the compile succeeds.
@spec compiler_version() :: String.t()
Decision 6's third determinism input: this package's version.