One compiled <scxml>, <state>, <parallel>, <final>, or <history>
element - the interned, indexed counterpart to Statifier.Document.State
(and, for index 0, to Statifier.Document itself).
kind :: :scxml | :state | :parallel | :final | :history. Unlike the
Document layer, :scxml is a real kind here: the root is state index 0,
parent: nil, id: nil (Statifier.Machine's moduledoc), so LCCA and
get_transition_domain need no root special case.
atomic?/compound? are not stored - Statifier.Machine.atomic?/2 and
compound?/2 derive them from children, the same divergence-avoidance
reasoning Statifier.Document.State already states for why kind stays
the element kind.
Fields that are kind-scoped
| Field | Meaningful on |
|---|---|
id | any (nilable except it is always nil on :scxml) |
parent | any (nil only at index 0) |
last | any - the high end of this state's self-inclusive descendant range, index being the low end |
children | any ([] on an atomic state) |
initial | :state, :scxml - [] on :parallel, :final, :history, and any atomic state |
history_type | :history |
history_children | any compound/parallel state - its own direct :history children, so exit-time recording finds them without scanning |
transitions | :state, :parallel, :history - the state's own selectable transitions' t_index list |
onentry / onexit | any - [Machine.Block.t()], one entry per <onentry>/<onexit> element the state wrote |
initial_transition | :state, :scxml - the <initial> element's transition t_index, or nil |
history_default | :history - its default transition's t_index |
donedata | :final - the compiled Machine.Donedata.t(), or nil |
data | :state, :parallel, :scxml - the d_indexes this state's own <datamodel> declares, [] when it has none |
invoke | :state, :parallel - the compiled Machine.Invoke.t() list this state's own <invoke> children produced, in document order, [] when it has none |
attribute_locations | any - the owning element's own written-attribute spans, carried verbatim |
Every field in the table except donedata, data and invoke is written
in one pass: the compiler's state-interning walk builds each
%Statifier.Machine.State{} whole, index and t_index/c_index references
included - attribute_locations among them, carried straight from the
source node at both construction sites. Those three are the exception, each
folded on after that walk by its own helper (Statifier.Compiler's
with_donedata/2, with_data/2 and with_invoke/2) once its own
compilation pass has run, so they are the only fields whose values are not
known when the struct is first built.
attribute_locations
attribute_locations is the owning Statifier.Document.State's own map,
carried through unchanged rather than distilled into per-attribute
*_location fields - the escape hatch Statifier.Machine.Invoke's
moduledoc describes, applied here because id, initial and a history's
type each have an attribute-level diagnostic use and none pays for a field
of its own.
At index 0 the source is %Statifier.Document{} itself, not a
Statifier.Document.State, exactly as location at index 0 is the
document's own - so the root's map holds the <scxml> element's written
attributes (initial, name, datamodel, binding, version, xmlns),
and is %{} only for a document that wrote none of them.
The map keeps Statifier.Document's key-presence contract verbatim: an
entry exists only for an attribute the author actually wrote. A :history
state whose history_type is :shallow because lowering applied the
default carries no :type key; one that wrote type="shallow" does. %{}
means the element wrote no attributes at all.
Summary
Types
@type t() :: %Statifier.Machine.State{ attribute_locations: Statifier.Document.attribute_locations(), children: [non_neg_integer()], data: [non_neg_integer()], donedata: Statifier.Machine.Donedata.t() | nil, history_children: [non_neg_integer()], history_default: non_neg_integer() | nil, history_type: :shallow | :deep | nil, id: String.t() | nil, index: non_neg_integer(), initial: [non_neg_integer()], initial_transition: non_neg_integer() | nil, invoke: [Statifier.Machine.Invoke.t()], kind: :scxml | :state | :parallel | :final | :history, last: non_neg_integer(), location: Statifier.Parser.Location.t(), onentry: [Statifier.Machine.Block.t()], onexit: [Statifier.Machine.Block.t()], parent: non_neg_integer() | nil, transitions: [non_neg_integer()] }