pyfcstm.model.model

State machine module for parsing and representing hierarchical state machines.

This module provides classes and functions for working with state machines, including:

  • Representation of states, transitions, events, and operations

  • Parsing state machine DSL nodes into state machine objects

  • Exporting state machines to AST nodes and PlantUML diagrams

The module implements a hierarchical state machine model with support for:

  • Nested states

  • Entry, during, and exit actions

  • Guards and effects on transitions

  • Abstract function declarations

  • Variable definitions

Operation

class pyfcstm.model.model.Operation(var_name: str, expr: Expr)[source]

Represents an operation that assigns a value to a variable.

An operation consists of a variable name and an expression that will be assigned to the variable when the operation is executed.

Parameters:
  • var_name (str) – The name of the variable to assign to

  • expr (Expr) – The expression to evaluate and assign to the variable

Example:

>>> op = Operation(var_name="counter", expr=some_expr)
>>> op.var_name
'counter'
to_ast_node() OperationAssignment[source]

Convert this operation to an AST node.

Returns:

An operation assignment AST node

Return type:

dsl_nodes.OperationAssignment

var_name_to_ast_node() Name[source]

Convert the variable name to an AST node.

Returns:

A name AST node

Return type:

dsl_nodes.Name

Event

class pyfcstm.model.model.Event(name: str, state_path: Tuple[str, ...])[source]

Represents an event that can trigger state transitions.

An event has a name and is associated with a specific state path in the state machine hierarchy.

Parameters:
  • name (str) – The name of the event

  • state_path (Tuple[str, ...]) – The path to the state that owns this event

Example:

>>> event = Event(name="button_pressed", state_path=("root", "idle"))
>>> event.path
('root', 'idle', 'button_pressed')
property path: Tuple[str, ...]

Get the full path of the event including the state path and event name.

Returns:

The full path to the event

Return type:

Tuple[str, …]

Transition

class pyfcstm.model.model.Transition(from_state: str | _StateSingletonMark, to_state: str | _StateSingletonMark, event: Event | None, guard: Expr | None, effects: List[Operation], parent_ref: ReferenceType | None = None)[source]

Represents a transition between states in a state machine.

A transition defines how the state machine moves from one state to another, potentially triggered by an event, guarded by a condition, and with effects that execute when the transition occurs.

Parameters:
  • from_state (Union[str, dsl_nodes._StateSingletonMark]) – The source state name or special state marker

  • to_state (Union[str, dsl_nodes._StateSingletonMark]) – The target state name or special state marker

  • event (Optional[Event]) – The event that triggers this transition, if any

  • guard (Optional[Expr]) – The condition that must be true for the transition to occur, if any

  • effects (List[Operation]) – Operations to execute when the transition occurs

  • parent_ref (Optional[weakref.ReferenceType]) – Weak reference to the parent state

Example:

>>> transition = Transition(
...     from_state="idle",
...     to_state="active",
...     event=None,
...     guard=None,
...     effects=[]
... )
property parent: State | None

Get the parent state of this transition.

Returns:

The parent state or None if no parent is set

Return type:

Optional[‘State’]

to_ast_node() TransitionDefinition[source]

Convert this transition to an AST node.

Returns:

A transition definition AST node

Return type:

dsl_nodes.TransitionDefinition

OnStage

class pyfcstm.model.model.OnStage(stage: str, aspect: str | None, name: str | None, doc: str | None, operations: List[Operation], is_abstract: bool)[source]

Represents an action that occurs during a specific stage of a state’s lifecycle.

OnStage can represent enter, during, or exit actions, and can be either concrete operations or abstract function declarations.

Parameters:
  • stage (str) – The lifecycle stage (‘enter’, ‘during’, or ‘exit’)

  • aspect (Optional[str]) – For ‘during’ actions in composite states, specifies if the action occurs ‘before’ or ‘after’ substates

  • name (Optional[str]) – For abstract functions, the name of the function

  • doc (Optional[str]) – For abstract functions, the documentation string

  • operations (List[Operation]) – For concrete actions, the list of operations to execute

  • is_abstract (bool) – Whether this is an abstract function declaration

Example:

>>> on_enter = OnStage(
...     stage="enter",
...     aspect=None,
...     name="init_counter",
...     doc=None,
...     operations=[],
...     is_abstract=False
... )
property is_aspect: bool

Check if this is an aspect-oriented action.

Returns:

False for OnStage instances (always)

Return type:

bool

to_ast_node() EnterStatement | DuringStatement | ExitStatement[source]

Convert this OnStage to an appropriate AST node based on the stage.

Returns:

An enter, during, or exit statement AST node

Return type:

Union[dsl_nodes.EnterStatement, dsl_nodes.DuringStatement, dsl_nodes.ExitStatement]

Raises:

ValueError – If the stage is not one of ‘enter’, ‘during’, or ‘exit’

OnAspect

class pyfcstm.model.model.OnAspect(stage: str, aspect: str | None, name: str | None, doc: str | None, operations: List[Operation], is_abstract: bool)[source]

Represents an aspect-oriented action that occurs during a specific stage of a state’s lifecycle.

OnAspect is specifically used for aspect-oriented programming features in the state machine, allowing actions to be defined that apply across multiple states.

Parameters:
  • stage (str) – The lifecycle stage (currently only supports ‘during’)

  • aspect (Optional[str]) – Specifies if the action occurs ‘before’ or ‘after’ substates

  • name (Optional[str]) – For abstract functions, the name of the function

  • doc (Optional[str]) – For abstract functions, the documentation string

  • operations (List[Operation]) – For concrete actions, the list of operations to execute

  • is_abstract (bool) – Whether this is an abstract function declaration

Example:

>>> aspect = OnAspect(
...     stage="during",
...     aspect="before",
...     name="log_entry",
...     doc=None,
...     operations=[],
...     is_abstract=True
... )
property is_aspect: bool

Check if this is an aspect-oriented action.

Returns:

True for OnAspect instances (always)

Return type:

bool

to_ast_node() DuringAspectStatement[source]

Convert this OnAspect to an appropriate AST node based on the stage.

Returns:

A during aspect statement AST node

Return type:

Union[dsl_nodes.DuringAspectStatement]

Raises:

ValueError – If the stage is not ‘during’

State

class pyfcstm.model.model.State(name: str, path: Tuple[str, ...], substates: Dict[str, State], events: Dict[str, Event] | None = None, transitions: List[Transition] | None = None, on_enters: List[OnStage] | None = None, on_durings: List[OnStage] | None = None, on_exits: List[OnStage] | None = None, on_during_aspects: List[OnAspect] | None = None, parent_ref: ReferenceType | None = None, substate_name_to_id: Dict[str, int] | None = None, is_pseudo: bool = False)[source]

Represents a state in a hierarchical state machine.

A state can contain substates, transitions between those substates, and actions that execute on enter, during, or exit of the state.

Parameters:
  • name (str) – The name of the state

  • path (Tuple[str, ...]) – The full path to this state in the hierarchy

  • substates (Dict[str, 'State']) – Dictionary mapping substate names to State objects

  • events (Dict[str, Event]) – Dictionary mapping event names to Event objects

  • transitions (List[Transition]) – List of transitions between substates

  • on_enters (List[OnStage]) – List of actions to execute when entering the state

  • on_durings (List[OnStage]) – List of actions to execute while in the state

  • on_exits (List[OnStage]) – List of actions to execute when exiting the state

  • on_during_aspects (List[OnAspect]) – List of aspect-oriented actions for the during stage

  • parent_ref (Optional[weakref.ReferenceType]) – Weak reference to the parent state

  • substate_name_to_id (Dict[str, int]) – Dictionary mapping substate names to numeric IDs

Example:

>>> state = State(
...     name="idle",
...     path=("root", "idle"),
...     substates={}
... )
>>> state.is_leaf_state
True
property abstract_on_during_aspects: List[OnAspect]

Get all abstract during aspect actions.

Returns:

List of abstract during aspect actions

Return type:

List[OnAspect]

property abstract_on_durings: List[OnStage]

Get all abstract during actions.

Returns:

List of abstract during actions

Return type:

List[OnStage]

property abstract_on_enters: List[OnStage]

Get all abstract enter actions.

Returns:

List of abstract enter actions

Return type:

List[OnStage]

property abstract_on_exits: List[OnStage]

Get all abstract exit actions.

Returns:

List of abstract exit actions

Return type:

List[OnStage]

property is_leaf_state: bool

Check if this state is a leaf state (has no substates).

Returns:

True if this is a leaf state, False otherwise

Return type:

bool

property is_root_state: bool

Check if this state is the root state (has no parent).

Returns:

True if this is the root state, False otherwise

Return type:

bool

iter_on_during_after_aspect_recursively(is_abstract: bool | None = None, with_ids: bool = False) List[Tuple[int, State, OnAspect | OnStage] | Tuple[State, OnAspect | OnStage]][source]

Recursively iterate through ‘after’ aspect during actions from this state to the root state.

This method traverses the state hierarchy from this state to the root state, yielding all ‘after’ aspect during actions along the way.

Parameters:
  • is_abstract (Optional[bool]) – If provided, filter to only abstract (True) or non-abstract (False) actions

  • with_ids (bool) – Whether to include numeric IDs with the actions

Yield:

Tuples of (state, action) or (id, state, action) if with_ids is True

Return type:

List[Union[Tuple[int, ‘State’, Union[OnAspect, OnStage]], Tuple[‘State’, Union[OnAspect, OnStage]]]]

iter_on_during_aspect_recursively(is_abstract: bool | None = None, with_ids: bool = False) List[Tuple[int, State, OnAspect | OnStage] | Tuple[State, OnAspect | OnStage]][source]

Recursively iterate through all during actions in the proper execution order.

This method yields actions in the following order:

  1. ‘Before’ aspect actions from root state to this state

  2. Regular during actions for this state

  3. ‘After’ aspect actions from this state to root state

Parameters:
  • is_abstract (Optional[bool]) – If provided, filter to only abstract (True) or non-abstract (False) actions

  • with_ids (bool) – Whether to include numeric IDs with the actions

Yield:

Tuples of (state, action) or (id, state, action) if with_ids is True

Return type:

List[Union[Tuple[int, ‘State’, Union[OnAspect, OnStage]], Tuple[‘State’, Union[OnAspect, OnStage]]]]

iter_on_during_before_aspect_recursively(is_abstract: bool | None = None, with_ids: bool = False) List[Tuple[int, State, OnAspect | OnStage] | Tuple[State, OnAspect | OnStage]][source]

Recursively iterate through ‘before’ aspect during actions from parent states to this state.

This method traverses the state hierarchy from the root state to this state, yielding all ‘before’ aspect during actions along the way.

Parameters:
  • is_abstract (Optional[bool]) – If provided, filter to only abstract (True) or non-abstract (False) actions

  • with_ids (bool) – Whether to include numeric IDs with the actions

Yield:

Tuples of (state, action) or (id, state, action) if with_ids is True

Return type:

List[Union[Tuple[int, ‘State’, Union[OnAspect, OnStage]], Tuple[‘State’, Union[OnAspect, OnStage]]]]

list_on_during_aspect_recursively(is_abstract: bool | None = None, with_ids: bool = False) List[Tuple[int, State, OnAspect | OnStage] | Tuple[State, OnAspect | OnStage]][source]

Get a list of all during actions in the proper execution order.

This is a convenience method that collects the results of iter_on_during_aspect_recursively.

Parameters:
  • is_abstract (Optional[bool]) – If provided, filter to only abstract (True) or non-abstract (False) actions

  • with_ids (bool) – Whether to include numeric IDs with the actions

Returns:

List of during actions in execution order

Return type:

List[Union[Tuple[int, ‘State’, Union[OnAspect, OnStage]], Tuple[‘State’, Union[OnAspect, OnStage]]]]

list_on_during_aspects(is_abstract: bool | None = None, aspect: str | None = None, with_ids: bool = False) List[Tuple[int, OnAspect] | OnAspect][source]

Get a list of during aspect actions, optionally filtered by abstract status, aspect, and with IDs.

Parameters:
  • is_abstract (Optional[bool]) – If provided, filter to only abstract (True) or non-abstract (False) actions

  • aspect (Optional[str]) – If provided, filter to only actions with the given aspect (‘before’ or ‘after’)

  • with_ids (bool) – Whether to include numeric IDs with the actions

Returns:

List of during aspect actions, optionally with IDs

Return type:

List[Union[Tuple[int, OnAspect], OnAspect]]

list_on_durings(is_abstract: bool | None = None, aspect: str | None = None, with_ids: bool = False) List[Tuple[int, OnStage] | OnStage][source]

Get a list of during actions, optionally filtered by abstract status, aspect, and with IDs.

Parameters:
  • is_abstract (Optional[bool]) – If provided, filter to only abstract (True) or non-abstract (False) actions

  • aspect (Optional[str]) – If provided, filter to only actions with the given aspect (‘before’ or ‘after’)

  • with_ids (bool) – Whether to include numeric IDs with the actions

Returns:

List of during actions, optionally with IDs

Return type:

List[Union[Tuple[int, OnStage], OnStage]]

list_on_enters(is_abstract: bool | None = None, with_ids: bool = False) List[Tuple[int, OnStage] | OnStage][source]

Get a list of enter actions, optionally filtered by abstract status and with IDs.

Parameters:
  • is_abstract (Optional[bool]) – If provided, filter to only abstract (True) or non-abstract (False) actions

  • with_ids (bool) – Whether to include numeric IDs with the actions

Returns:

List of enter actions, optionally with IDs

Return type:

List[Union[Tuple[int, OnStage], OnStage]]

list_on_exits(is_abstract: bool | None = None, with_ids: bool = False) List[Tuple[int, OnStage] | OnStage][source]

Get a list of exit actions, optionally filtered by abstract status and with IDs.

Parameters:
  • is_abstract (Optional[bool]) – If provided, filter to only abstract (True) or non-abstract (False) actions

  • with_ids (bool) – Whether to include numeric IDs with the actions

Returns:

List of exit actions, optionally with IDs

Return type:

List[Union[Tuple[int, OnStage], OnStage]]

property non_abstract_on_during_aspects: List[OnAspect]

Get all non-abstract during aspect actions.

Returns:

List of non-abstract during aspect actions

Return type:

List[OnAspect]

property non_abstract_on_durings: List[OnStage]

Get all non-abstract during actions.

Returns:

List of non-abstract during actions

Return type:

List[OnStage]

property non_abstract_on_enters: List[OnStage]

Get all non-abstract enter actions.

Returns:

List of non-abstract enter actions

Return type:

List[OnStage]

property non_abstract_on_exits: List[OnStage]

Get all non-abstract exit actions.

Returns:

List of non-abstract exit actions

Return type:

List[OnStage]

property parent: State | None

Get the parent state of this state.

Returns:

The parent state or None if this is the root state

Return type:

Optional[‘State’]

to_ast_node() StateDefinition[source]

Convert this state to an AST node.

Returns:

A state definition AST node

Return type:

dsl_nodes.StateDefinition

to_plantuml() str[source]

Convert this state to PlantUML notation.

Returns:

PlantUML representation of the state

Return type:

str

to_transition_ast_node(transition: Transition) TransitionDefinition[source]

Convert a transition to an AST node in the context of this state.

Parameters:

transition (Transition) – The transition to convert

Returns:

A transition definition AST node

Return type:

dsl_nodes.TransitionDefinition

classmethod transition_to_ast_node(self: State | None, transition: Transition) TransitionDefinition[source]

Convert a transition to an AST node, considering the context of its parent state.

Parameters:
  • self (Optional['State']) – The parent state, or None

  • transition (Transition) – The transition to convert

Returns:

A transition definition AST node

Return type:

dsl_nodes.TransitionDefinition

property transitions_entering_children: List[Transition]

Get all transitions that start from the initial state (INIT_STATE).

These are the transitions that define the initial substate when entering this state.

Returns:

List of transitions from INIT_STATE

Return type:

List[Transition]

property transitions_entering_children_simplified: List[Transition | None]

Get a simplified list of transitions entering child states.

If there’s a default transition (no event or guard), only include that one. Otherwise include all transitions and add None at the end.

Returns:

List of transitions, possibly with None at the end

Return type:

List[Optional[Transition]]

property transitions_from: List[Transition]

Get all transitions that start from this state.

For non-root states, these are transitions in the parent state where this state is the source. For the root state, a synthetic transition to EXIT_STATE is returned.

Returns:

List of transitions from this state

Return type:

List[Transition]

property transitions_to: List[Transition]

Get all transitions that end at this state.

For non-root states, these are transitions in the parent state where this state is the target. For the root state, a synthetic transition from INIT_STATE is returned.

Returns:

List of transitions to this state

Return type:

List[Transition]

walk_states()[source]

Iterate through this state and all its substates recursively.

Yield:

Each state in the hierarchy, starting with this one

Return type:

Iterator[‘State’]

VarDefine

class pyfcstm.model.model.VarDefine(name: str, type: str, init: Expr)[source]

Represents a variable definition in a state machine.

Parameters:
  • name (str) – The name of the variable

  • type (str) – The type of the variable

  • init (Expr) – The initial value expression

Example:

>>> var_def = VarDefine(name="counter", type="int", init=some_expr)
>>> var_def.name
'counter'
name_ast_node() Name[source]

Convert the variable name to an AST node.

Returns:

A name AST node

Return type:

dsl_nodes.Name

to_ast_node() DefAssignment[source]

Convert this variable definition to an AST node.

Returns:

A definition assignment AST node

Return type:

dsl_nodes.DefAssignment

StateMachine

class pyfcstm.model.model.StateMachine(defines: Dict[str, VarDefine], root_state: State)[source]

Represents a complete state machine with variable definitions and a root state.

Parameters:
  • defines (Dict[str, VarDefine]) – Dictionary mapping variable names to their definitions

  • root_state (State) – The root state of the state machine

Example:

>>> sm = StateMachine(defines={}, root_state=some_state)
>>> list(sm.walk_states())  # Get all states in the machine
[...]
to_ast_node() StateMachineDSLProgram[source]

Convert this state machine to an AST node.

Returns:

A state machine DSL program AST node

Return type:

dsl_nodes.StateMachineDSLProgram

to_plantuml() str[source]

Convert this state machine to PlantUML notation.

Returns:

PlantUML representation of the state machine

Return type:

str

walk_states()[source]

Iterate through all states in the state machine.

Yield:

Each state in the hierarchy

Return type:

Iterator[State]

parse_dsl_node_to_state_machine

pyfcstm.model.model.parse_dsl_node_to_state_machine(dnode: StateMachineDSLProgram) StateMachine[source]

Parse a state machine DSL program AST node into a StateMachine object.

This function validates the state machine structure and builds a complete StateMachine object with all states, transitions, events, and variable definitions.

Parameters:

dnode (dsl_nodes.StateMachineDSLProgram) – The state machine DSL program AST node to parse

Returns:

The parsed state machine

Return type:

StateMachine

Raises:

SyntaxError – If there are syntax errors in the state machine definition, such as duplicate variable definitions, unknown states in transitions, missing entry transitions, etc.

Example:

>>> # Assuming you have a parsed DSL node
>>> state_machine = parse_dsl_node_to_state_machine(dsl_program_node)
>>> state_machine.root_state.name
'root'