StatifierBlocks.Compiler.Context (StatifierBlocks v0.1.0)

Copy Markdown View Source

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_id and state_id - the block's own, precomputed;
  • children - slot name to the ordered list of child summaries, each carrying only block_id, state_id and done_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.

t()

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

child_summary()

@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.

t()

@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

children(context, slot)

@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.

done_event(context)

@spec done_event(t()) :: String.t()

The done.state event this block's state raises, for a block type that needs to name its own completion.

done_id(context)

@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.

new(block_id, document_id, children \\ %{})

Builds the context for block_id under document_id, with children keyed by slot name in the order slots/1 declared them.

role_id(context, 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.

summary(block_id)

@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.