The structured FSM surface reuses the generic family parser.

Types

  • type GraphEdge = GraphEdge
  • type EventSpec = EventSpec
  • type Transition = Row
  • type AtomTransition
  • type FsmAction = Keep | Next | Stop

    Checked callback result for the preferred typed FSM surface. Constructors are ordinary Cure values; action_to_beam is the single private-shape lowering point to the tuple vocabulary required by gen_statem.

Functions

  • # fn action_to_beam(action: FsmAction(s, d)) -> BeamTerm
  • # fn add_atom(value: Atom, values: List(Atom)) -> List(Atom)
  • # fn add_event(event: Syntax, payload: List(Syntax), found: List(EventSpec)) -> List(EventSpec)
  • # fn add_optional_syntax_name(value: Option(Syntax), found: List(Syntax)) -> List(Syntax)
  • # fn add_syntax_name(value: Syntax, found: List(Syntax)) -> List(Syntax)
  • # fn all_atoms_in(values: List(Atom), catalogue: List(Atom)) -> Bool
  • # fn atom_in(value: Atom, values: List(Atom)) -> Bool
  • # fn captured_parameter_patterns(parameters: List(Syntax)) -> List(Syntax)
  • # fn captured_parameter_types(parameters: List(Syntax)) -> List(Syntax)
  • # fn compact_deadlock(states: List(Atom), terminals: List(Atom), edges: List(GraphEdge)) -> Bool
  • # fn compact_edge_in(from: Option(Atom), event: Atom, edges: List(GraphEdge)) -> Bool
  • # fn compact_edges(transitions: List(TransitionDefinitionSyntax)) -> List(GraphEdge)
  • # fn compact_outgoing(state: Atom, edges: List(GraphEdge)) -> Bool
  • # fn contains_event(values: List(EventSpec), expected: Atom) -> Bool
  • # fn contains_syntax_name(values: List(Syntax), expected: Atom) -> Bool
  • # fn derive_fsm_family(name: ModuleNameSyntax, definition: FsmDefinitionSyntax) -> Syntax

    Expand the structured fsm family into a gen_statem module.

    The event type is a companion of the machine, so it is declared INSIDE the generated module as Event -- the same place the transition-table emitter puts its State/Event/Data. Declaring it beside the machine instead would bind a name nobody wrote into the enclosing scope, and two sibling modules each holding an fsm would collide on it.

  • # fn derive_transition_table(name: ModuleNameSyntax, data: TypeSyntax, definition: TransitionTableDefinitionSyntax) -> Syntax
  • # fn dispatch(s: Type, e: Type, transitions: List(Transition(s, e)), state: s, event: e, data: a) -> Tuple(Atom, s, a)
  • # fn dispatch_atom(transitions: List(Transition(Atom, Atom)), state: Atom, event: Atom, data: a) -> Tuple(Atom, Atom, a)

    Exact encoder for atom-labelled transition tables. Keeping it separate lets the ordinary dispatch algebra remain generic.

  • # fn duplicate_compact_edge(edges: List(GraphEdge)) -> Bool
  • # fn emit_fsm_parts(name_syntax: Syntax, state_type: Syntax, event_declarations: List(Syntax), event_body: Syntax) -> Syntax
  • # fn emit_transition_table(name: Syntax, data: Syntax, initial: Syntax, states: List(Syntax), events: List(EventSpec), transitions: List(TransitionDefinitionSyntax)) -> Syntax
  • # fn emit_typed_fsm_parts(name_syntax: Syntax, data_type: Syntax, state_name_type: Syntax, initial_state: Syntax, event_declarations: List(Syntax), event_body: Syntax) -> Syntax
  • # fn event_pattern(event: Syntax, parameters: List(Syntax)) -> Syntax
  • # fn event_variants(values: List(EventSpec)) -> List(Syntax)
  • # fn expand_reachable(edges: List(GraphEdge), reachable: List(Atom)) -> List(Atom)
  • # fn explicit_response_arms(transitions: List(TransitionDefinitionSyntax)) -> List(Syntax)
  • # fn explicit_transition_arms(transitions: List(TransitionDefinitionSyntax)) -> List(Syntax)
  • # fn find_event(values: List(EventSpec), expected: Atom) -> Option(EventSpec)
  • # fn first_explicit_source(transitions: List(TransitionDefinitionSyntax)) -> Option(Syntax)
  • # fn first_state(transitions: List(Transition(Atom, Atom))) -> Atom

    Compatibility helper for the original atom-labelled transition-table macro. Typed callers use first_state_or, whose fallback has the same state type as the table.

  • # fn first_state_or(s: Type, e: Type, transitions: List(Transition(s, e)), fallback: s) -> s
  • # fn fsm_handler(body: Syntax) -> Syntax

    checked block, so normalize each arm here in ordinary source-level syntax.

  • # fn fsm_handler_arm(arm: Syntax) -> Syntax
  • # fn fsm_handler_arm_node(values: List(Attr), children: List(Syntax)) -> Syntax
  • # fn fsm_handler_arms(arms: List(Syntax)) -> List(Syntax)
  • # fn fsm_handler_node(values: List(Attr), children: List(Syntax)) -> Syntax
  • # fn keep(s: Type, data: d) -> FsmAction(s, d)
  • # fn next(state: s, data: d) -> FsmAction(s, d)
  • # fn option_present(a: Type, value: Option(a)) -> Bool
  • # fn optional_payload(payload: Option(List(Syntax))) -> List(Syntax)
  • # fn optional_syntax_key(value: Option(Syntax)) -> Option(Atom)
  • # fn payload_types_equal(left: List(Syntax), right: List(Syntax)) -> Bool
  • # fn reachable_atoms(fuel: List(Atom), reachable: List(Atom), edges: List(GraphEdge)) -> List(Atom)

    At most |states| monotone passes are needed to saturate a finite graph. Recursing on the shrinking catalogue is visibly structural to the totality checker, unlike a conventional BFS whose work queue can grow.

  • # fn response_arm(edge: TransitionDefinitionSyntax, state_pattern: Syntax) -> Syntax
  • # fn same_optional_atom(left: Option(Atom), right: Option(Atom)) -> Bool
  • # fn select_initial(explicit: Option(Syntax), transitions: List(TransitionDefinitionSyntax)) -> Option(Syntax)
  • # fn stop(s: Type, reason: ExitReason, data: d) -> FsmAction(s, d)
  • # fn syntax_constructor(value: Syntax) -> Syntax
  • # fn syntax_key(value: Syntax) -> Option(Atom)
  • # fn syntax_keys(values: List(Syntax)) -> List(Atom)
  • # fn syntax_name(value: Syntax) -> Option(String)
  • # fn syntax_name_atom(value: Syntax) -> Option(Atom)

    Constructor keys include arity (:Opened/0) for duplicate checking. Public graph metadata instead preserves the identifier the author wrote.

  • # fn syntax_variants(values: List(Syntax)) -> List(Syntax)
  • # fn transition(s: Type, e: Type, from: s, event: e, to: s) -> Transition(s, e)

    A transition row is ordinary data. The macro surface above expands rows to this checked ADT so users can compose, inspect, and transform tables with normal Cure functions.

  • # fn transition_arm(edge: TransitionDefinitionSyntax, state_pattern: Syntax) -> Syntax
  • # fn transition_decision(transitions: List(TransitionDefinitionSyntax)) -> Syntax

    Compile the table as one linear tuple match. Explicit rows are emitted before wildcard rows, which gives them precedence through ordinary pattern ordering. The previous nested state/event decision duplicated its complete fallback twice per row; moderately sized FSMs therefore produced an exponential Syntax value and exhausted computed-macro normalization.

  • # fn transition_events(transitions: List(TransitionDefinitionSyntax), found: List(EventSpec)) -> List(EventSpec)
  • # fn transition_metadata(transitions: List(TransitionDefinitionSyntax)) -> List(Syntax)

    Emit the graph as ordinary generated data. Tooling and tests can inspect exactly the rows which drive decide/3, without keeping a second table in host code. Wildcard rows have a distinct constructor so callers cannot accidentally mistake them for a concrete source state.

  • # fn transition_response_decision(transitions: List(TransitionDefinitionSyntax)) -> Syntax

    responds?/2 shares the same ordered patterns as decide/3. It answers whether the compiled graph has a row for a state/event shape; guards are deliberately not evaluated because they may depend on transition data.

  • # fn transition_states(transitions: List(TransitionDefinitionSyntax), found: List(Syntax)) -> List(Syntax)
  • # fn transition_update(update: Option(ExpressionSyntax)) -> Syntax
  • # fn validate_compact_graph(initial: Syntax, states: List(Syntax), terminals: List(Syntax), transitions: List(TransitionDefinitionSyntax)) -> Option(Atom)
  • # fn validate_event_payloads(transitions: List(TransitionDefinitionSyntax), found: List(EventSpec)) -> Option(Atom)
  • # fn wildcard_response_arms(transitions: List(TransitionDefinitionSyntax)) -> List(Syntax)
  • # fn wildcard_transition_arms(transitions: List(TransitionDefinitionSyntax)) -> List(Syntax)