The .hsm DSL is the human authoring form for reviewed state-machine definitions. It lowers to verified-tsm.machine.v1 JSON IR, which remains the canonical tooling and generator input.
The grammar is designed to be readable in review and straightforward to lower into generated C++, test fixtures, diagrams, and trace artifacts. Backend generators may choose different identifier spellings, but the lowered IR uses dotted names for hierarchy and scoped events.
EBNF
machine ::= "machine" ident "{" section* "}"
section ::= namespace
| initial
| states
| events
| guards
| actions
| defaults
| transitions
namespace ::= "namespace" dotted_name ";"
initial ::= "initial" dotted_name ";"
states ::= "states" "inferred" ";"
| "states" "{" state_item* "}"
state_item ::= ident ";"
| ident ","
| ident "{" "initial" ident ";"
"states" "{" ident_list "}" "}"
events ::= "events" "inferred" ";"
| "events" "{" event_item* "}"
event_item ::= "inferred" ";"
| "leaf" "{" ident_list "}"
| "payload" "{" payload_event* "}"
| ident ";"
| ident ","
payload_event ::= ident "{" payload_field* "}" ";"
payload_field ::= ident ident ";"
guards ::= "guards" "inferred" ";"
| "guards" "{" ident_list "}"
actions ::= "actions" "inferred" ";"
| "actions" "{" ident_list "}"
defaults ::= "defaults" "{" default_item* "}"
default_item ::= ("kind" | "guard" | "action") ":"? ident ("," | ";")?
transitions ::= "transitions" "{" transition_item* "}"
transition_item ::= transition
| ident "{" group_item* "}"
group_item ::= "action" ident ";"
| transition
transition ::= name_ref "+" name_ref "=>" name_ref transition_attrs? ";"
transition_attrs ::= "{" transition_attr* "}"
transition_attr ::= ("kind" | "guard" | "action") ":"? ident ("," | ";")?
name_ref ::= "Self" | dotted_name
dotted_name ::= ident ("." ident)*
ident_list ::= ident ("," ident)* ","?
ident ::= /[A-Za-z_][A-Za-z0-9_]*/
Lowering Rules
- Omitted
states, events, guards, and actions sections are inferred. The shortest useful machine names an initial state and a transition table.
states inferred; derives flat states from the initial state and transition endpoints. It is equivalent to omitting the states section. Scoped names are intentionally rejected in this mode.
- Explicit composite states lower to dotted child names such as
PreOp.MailboxReady.
- In a transition group, unqualified child states resolve relative to the group state when the child exists.
Self resolves to the current transition group state.
events inferred; derives event membership from transition rows.
- Payload events must be declared explicitly. Inference can add missing payload-free events.
- Duplicate unguarded
(source, event) transition rows are rejected.
Example
This DS402 power-drive example omits states and events; both are inferred from the complete transition table.
machine PowerDrive {
namespace examples.ds402;
initial NotReadyToSwitchOn;
defaults {
kind external;
}
transitions {
NotReadyToSwitchOn + InternalReady => SwitchOnDisabled;
SwitchOnDisabled + Shutdown => ReadyToSwitchOn;
ReadyToSwitchOn + SwitchOn => SwitchedOn;
ReadyToSwitchOn + DisableVoltage => SwitchOnDisabled;
SwitchedOn + EnableOperation => OperationEnabled;
SwitchedOn + Shutdown => ReadyToSwitchOn;
SwitchedOn + DisableVoltage => SwitchOnDisabled;
OperationEnabled + SwitchOn => SwitchedOn;
OperationEnabled + Shutdown => ReadyToSwitchOn;
OperationEnabled + DisableVoltage => SwitchOnDisabled;
OperationEnabled + QuickStop => QuickStopActive;
QuickStopActive + EnableOperation => OperationEnabled;
QuickStopActive + DisableVoltage => SwitchOnDisabled;
SwitchOnDisabled + FaultDetected => FaultReactionActive;
ReadyToSwitchOn + FaultDetected => FaultReactionActive;
SwitchedOn + FaultDetected => FaultReactionActive;
OperationEnabled + FaultDetected => FaultReactionActive;
QuickStopActive + FaultDetected => FaultReactionActive;
FaultReactionActive + FaultReactionComplete => Fault;
Fault + FaultReset => SwitchOnDisabled;
}
}