pyfcstm.simulate
Simulation runtime for executing hierarchical finite state machines.
This package provides a cycle-based execution runtime for state machines parsed from the pyfcstm DSL. Each cycle advances the state machine through transitions and lifecycle actions until reaching a stable stoppable state or terminating.
The runtime supports hierarchical state machines with composite states, lifecycle actions (enter/during/exit), aspect-oriented actions (>> during before/after), and speculative validation to ensure transitions can reach valid stable states.
State types include leaf states (can execute during actions), composite states (contain children and require initial transitions), pseudo states (skip ancestor aspect actions), and stoppable states (non-pseudo leaf states where cycles stabilize).
Lifecycle actions execute at specific points: enter when entering a state, during while in a leaf state each cycle, and exit when leaving a state. Aspect actions (>> during before/after) execute before or after all descendant leaf during actions, enabling cross-cutting concerns like logging or validation.
The runtime validates transitions speculatively before executing them, ensuring
they can eventually reach a stoppable state or terminate. If validation fails or
exceeds safety limits (1000 steps or 64 stack depth), the transition is rejected
and variables roll back to the previous stable state. Each successful
SimulationRuntime cycle returns CycleResult, an immutable value
object that preserves the legacy None value while exposing canonical input,
consumed, and unconsumed event paths.
Abstract actions can be implemented by registering Python handlers that receive
read-only execution context. The runtime validates handler targets, rejects
duplicate registrations by default, supports explicit duplicate cleanup modes,
and provides session cleanup for handler diagnostics. Handlers can be registered
individually or organized in classes using the @abstract_handler decorator
for better state management.
Public API map:
Export |
Purpose |
|---|---|
|
Execute parsed state-machine models cycle by cycle. |
|
Expose immutable state, variable, and action metadata to abstract handlers. |
|
Mark object methods for bulk abstract-handler registration. |
Runtime exceptions |
Report DFS convergence, event normalization, expression execution, and action-reference failures. |
|
Classify event-path input syntax for simulator utilities. |
Basic usage:
from pyfcstm.dsl import parse_with_grammar_entry
from pyfcstm.model import parse_dsl_node_to_state_machine
from pyfcstm.simulate import SimulationRuntime
ast = parse_with_grammar_entry(dsl_code, 'state_machine_dsl')
sm = parse_dsl_node_to_state_machine(ast)
runtime = SimulationRuntime(sm)
# Execute cycles
result = runtime.cycle() # Initialize and execute first cycle
assert result.input_events == ()
runtime.cycle(['EventName']) # Execute with events
# Access state and variables
current_state = runtime.current_state
variables = runtime.vars
Public exports:
+--------------------------------------+--------------------------------------+
| Symbol | Purpose |
+======================================+======================================+
| ``SimulationRuntime`` | Stateful simulator runtime. |
+--------------------------------------+--------------------------------------+
| ``CycleResult`` | Immutable per-cycle result metadata. |
+--------------------------------------+--------------------------------------+
| ``ReadOnlyExecutionContext`` | Abstract-handler callback context. |
+--------------------------------------+--------------------------------------+
| ``abstract_handler`` | Decorator for callback registration. |
+--------------------------------------+--------------------------------------+
Abstract handler registration:
from pyfcstm.simulate import abstract_handler
class MyHandlers:
@abstract_handler('System.Active.Init')
def handle_init(self, ctx):
print(f"State: {ctx.get_full_state_path()}")
print(f"Counter: {ctx.get_var('counter')}")
handlers = MyHandlers()
runtime.register_handlers_from_object(handlers)
__all__
- pyfcstm.simulate.__all__ = ['CycleResult', 'ReadOnlyExecutionContext', 'SimulationRuntime', 'SimulationRuntimeActionReferenceError', 'SimulationRuntimeDfsError', 'SimulationRuntimeEventError', 'SimulationRuntimeExpressionError', 'SimulationRuntimeTerminalStateError', 'abstract_handler', 'is_state_resolve_event_path']
Built-in mutable sequence.
If no argument is given, the constructor creates a new empty list. The argument must be an iterable if specified.