Code contained in statecharts¶
A statechart can write code to be executed under some circumstances.
For example, the on entry
property on a statechart
, guard
or action
on a transition or the
on entry
and on exit
property for a state.
In PySS, these pieces of code can be evaluated and executed by Evaluator
instances.
Code evaluator¶
An Evaluator
must provide two methods and an attribute:
-
class
pyss.evaluator.
Evaluator
¶ Base class for any evaluator.
An instance of this class defines what can be done with piece of codes contained in a statechart (condition, action, etc.).
-
context
¶ The context of this evaluator. A context is a dict-like mapping between variables and values that is expected to be exposed through
evaluate_condition
andexecute_action
.
-
evaluate_condition
(condition: str, event: pyss.model.Event) → bool¶ Evaluate the condition of a guarded transition.
Parameters: - condition – A one-line Boolean expression
- event – The event (if any) that could fire the transition.
Returns: True or False
-
execute_action
(action: str, event: pyss.model.Event=None) → list¶ Execute given action (multi-lines code) and return a (possibly empty) list of internal events to be considered by a statechart simulator.
Parameters: - action – A (possibly multi-lined) code to execute.
- event – an
Event
instance in case of a transition action.
Returns: A possibly empty list of
Event
instances
-
By default, PySS provides two built-in Evaluator
subclasses:
- A
DummyEvaluator
that always evaluate a guard toTrue
and silently ignoresaction
,on entry
andon exit
. Its context is an empty dictionary.- A
PythonEvaluator
that brings Python into our statecharts and which is used by default.
Built-in Python code evaluator¶
An instance of PythonEvaluator
can evaluate and execute Python code expressed in the statechart.
The key point to understand how it works is the concept of context
, which is a dictionary-like structure that contains the data
that are exposed to the pieces of code of the statechart (ie. override __locals__
).
As an example, consider the following partial statechart definition.
statechart:
# ...
on entry: x = 1
states:
- name: s1
on entry: x += 1
When the statechart is initialized, the context
of a PythonEvaluator
is {'x': 1}
.
When s1 is entered, the code will be evaluated with this context.
After the execution of x += 1
, the context associates 2
to x
.
When a PythonEvaluator
instance is initialized, a prepopulated context can be specified:
from pyss.evaluator import PythonEvaluator
import math as my_favorite_module
evaluator = PythonEvaluator({'x': 1, 'math': my_favorite_module})
By default, the context exposes an Event
and a send
function.
They can be used to send internal event to the simulator, eg., on entry: send(Event('Hello World!'))
.
Unless you override its entry in the context, the __builtins__
of Python are automatically exposed.
This implies you can use nearly everything from Python in your code.
-
class
pyss.evaluator.
PythonEvaluator
(initial_context: dict=None)¶ Evaluator that interprets Python code.
An initial context can be provided, as a dictionary (will be used as
__locals__
). Unless overridden, the context also exposes:- The
__builtins__
of Python, - The
Event
class and, - A
send
method that takesEvent
instances and send them to the statechart.
When one of
evaluate_condition
orexecute_action
method is called with an event parameter, it is also exposed by the context through the keyevent
.Parameters: initial_context – a dictionary that will be used as __locals__
- The
If an exception occurred while executing or evaluating a piece of code, it is propagated by the evaluator.
Examples¶
Consider the following statechart that performs simple arithmetic operations.
statechart:
name: statechart with executable content
on entry: |
x = 1
y = 2
initial: s1
states:
- name: s1
transitions:
- target: s2
action: |
x += 1
- name: s2
on_entry: |
y += 1
transitions:
- target: s3
- name: s3
type: final # x = 2, y = 3
The statechart here shows a more intricate example.