hsm.ex is the Elixir implementation of the StateForward hierarchical state
machine DSL/runtime. It is a native Elixir package, not a wrapper around another
language implementation.
This repository contains the initial Elixir runtime and tests for the shared HSM DSL contract. Implemented areas include:
- model definition, states, final states, transitions, initial transitions
- nested state entry/exit ordering
- guards, effects, entry actions, exit actions, operation references
- typed attributes, runtime type validation,
on_set,on_call, and predicatewhen - choice, shallow history, deep history, deferral, completion, snapshots
- deterministic logical-time timers via
HSM.tick/2and cancellable host-clock timers - external, internal, local, and self transition kinds
- start, stop, and restart lifecycle behavior
- group dispatch, group snapshots, broadcast dispatch, context helpers, and kind utilities
- runtime
ID,Name, andQualifiedNamehelpers - runtime event constructors and inherited event/state/pseudostate/transition kind helpers
- canonical
Dispatchexport without processed/deferred status payloads - per-recipient event metadata ownership for group/broadcast dispatch
- normalized behavior error tracing in the conformance runner
- nested dispatch queue reentrancy with FIFO-after-current ordering
- deterministic async behavior ordering and cancellable activity handles
Config.Queue,Config.Clock, andDefaultClockruntime hooks for the immutable Elixir runtime
model =
HSM.define("Door", [
HSM.initial(HSM.target("closed")),
HSM.state("closed", [
HSM.transition([
HSM.on("open"),
HSM.target("open")
])
]),
HSM.state("open")
])
machine = model |> HSM.new() |> HSM.start()
{machine, :processed} = HSM.dispatch(machine, "open")
HSM.state(machine)
#=> "/Door/open"The shared DSL specifies PascalCase API names. Elixir reserves uppercase identifiers for aliases in normal call syntax, so this package exposes idiomatic snake_case functions for ordinary use and PascalCase atom exports for tooling or generated bindings:
model = apply(HSM, :Define, ["Door", [HSM.initial(HSM.target("closed")), HSM.state("closed")]])mix test
mix hsm.conformance ../hsm/conformance/cases/*.jsonThe current suite covers core transition flow, nested initial entry, guard
selection, choice fallback, source-qualified parent transitions, deferral
replay/FIFO ordering, history defaults, root completion transitions, on_call, timer
behavior, transition kinds, lifecycle restart/stop, validation, and snapshots.
Shared conformance also covers group dispatch, group snapshots, broadcast
dispatch, event ownership, nested dispatch reentrancy, and normalized behavior
errors for the supported immutable instance API. Local ExUnit coverage exercises
custom queue hooks, runtime-priority queue events, synchronous hook validation,
clock hooks, host-clock timer cancellation, typed attribute writes, event/kind
helpers, deterministic async ordering, and cancellable activity handles.
The conformance runner executes supported shared JSON cases and exits 77 when
all requested cases are explicit unsupported-feature skips.