What a block type is entitled to know while emitting, and nothing more (ADR-0004 decision 4).
The compiler walks the document bottom-up and calls emit/2 with the
children already compiled. The context it passes carries four things:
block_idandstate_id- the block's own, precomputed;children- slot name to the ordered list of child summaries, each carrying onlyblock_id,state_idanddone_event. A child's emitted SCXML is deliberately absent: a parent that could read it would be a parent that could depend on it, and decision 2 exists to prevent that;document_id- for the rare type that names the document in a send target;role_id/2- decision 3's minting function, reached through this struct so the compiler owns the namespacing.
The palette is deliberately absent. A block type resolving another block
type would be a block type compiling its own children, which is the
compiler's job, and would make emit/2's purity depend on a value it did
not receive.
The "done" role is conventional, not reserved
Decision 2 makes every block's state compound with a <final> child, so
that entering the final raises done.state.<state id> and a parent needs
nothing but the child's id to wire it. done_id/1 mints that child's id
under the role "done"; the core vocabulary uses it uniformly. Nothing
stops a host type from minting the same role itself - it is the same id -
or from using a different one, so long as some final child is reachable.
A block whose state can never reach a final is a block no parent can
sequence after.
Summary
Types
Everything a parent may know about one compiled child: its block id, the state it compiled to, and the event that state raises when it is done.
Functions
The ordered child summaries in slot, or [] for a slot with no
children - including one the document never wrote.
The done.state event this block's state raises, for a block type that
needs to name its own completion.
The id of this block's conventional <final> child - role_id(ctx, "done") with the error arm discharged, since "done" is a literal role
this module knows is valid.
Builds the context for block_id under document_id, with children
keyed by slot name in the order slots/1 declared them.
Mints the id of an auxiliary state this block emits inside its own
state, under role (decision 3).
The summary of one compiled child, for a parent building a summary of its own or wiring a transition to a sibling.
Types
@type child_summary() :: %{ block_id: StatifierBlocks.Block.id(), state_id: StatifierBlocks.Compiler.StateId.t(), done_event: String.t() }
Everything a parent may know about one compiled child: its block id, the state it compiled to, and the event that state raises when it is done.
@type t() :: %StatifierBlocks.Compiler.Context{ block_id: StatifierBlocks.Block.id(), children: %{optional(StatifierBlocks.Block.slot_name()) => [child_summary()]}, document_id: StatifierBlocks.Document.id(), state_id: StatifierBlocks.Compiler.StateId.t() }
Functions
@spec children(t(), StatifierBlocks.Block.slot_name()) :: [child_summary()]
The ordered child summaries in slot, or [] for a slot with no
children - including one the document never wrote.
The done.state event this block's state raises, for a block type that
needs to name its own completion.
@spec done_id(t()) :: StatifierBlocks.Compiler.StateId.t()
The id of this block's conventional <final> child - role_id(ctx, "done") with the error arm discharged, since "done" is a literal role
this module knows is valid.
@spec new(StatifierBlocks.Block.id(), StatifierBlocks.Document.id(), %{ optional(StatifierBlocks.Block.slot_name()) => [child_summary()] }) :: t()
Builds the context for block_id under document_id, with children
keyed by slot name in the order slots/1 declared them.
@spec role_id(t(), StatifierBlocks.Compiler.StateId.role()) :: {:ok, StatifierBlocks.Compiler.StateId.t()} | {:error, {:invalid_role, StatifierBlocks.Block.id(), StatifierBlocks.Compiler.StateId.role()}}
Mints the id of an auxiliary state this block emits inside its own
state, under role (decision 3).
Returns {:error, {:invalid_role, block_id, role}} for a role the
compiler could not invert; a block type that passes a literal role never
sees that arm, and one that builds a role from config handles it as the
ordinary Emit finding it is.
@spec summary(StatifierBlocks.Block.id()) :: child_summary()
The summary of one compiled child, for a parent building a summary of its own or wiring a transition to a sibling.