Swan model visitor#
The visitor pattern allows for a traversal of a data structure without changing the data structure itself. Thus, several algorithms can be applied to the same data structure.
The Swan visitor implements that pattern with a class which methods to visit each Swan object. T he visitor is therefore responsible for the traversal. The visitor by itself does nothing but traversing the tree. To implement an algorithm, one needs to derive the visitor class and override all or some of the methods.
The advantage of that visitor is that the traversal can be controlled by a derived visitor class,
instead of the accept
method as in the visitor pattern.
For a complete code example, see Visitor.
Overview#
The SwanVisitor
implements the base visitor. It provides:
The
SwanVisitor.visit()
which is the entry point to start visiting an object.The methods SwanVisitor.visit_<class_name>(swan_obj: object, owner: object, property: str). There is one such method for each Swan classes. The
SwanVisitor.visit()
method calls the privateSwanVisitor._visit()
method which dispatches the Swan object argument to the proper SwanVisitor.visit_<class_name> method. Arguments of SwanVisitor.visit_<class_name> are:swan_obj: the visited object.
owner: owner of the swan_object. When an object is visited, it becomes the owner for its own properties which are visited. Note that there is a property for each owner constructor argument. The owner is None for the root visited object.
owner_property: the name of the property in the owner which corresponds to the visited swan_obj. It is None for the root visited object.
For instance, if one visits an ArrayRepetition
object, there are two properties with the same
Expression
type. The corresponding default visitor method is:
def visit_ArrayRepetition(
self,
swan_obj: swan.ArrayRepetition,
owner: Owner,
owner_property: OwnerProperty
) -> None:
"""ArrayRepetition visitor function. Should be overridden."""
# Visit base class(es)
self.visit_Expression(swan_obj, owner, property)
# Visit properties
self._visit(swan_obj.expr, swan_obj, 'expr')
self._visit(swan_obj.size, swan_obj, 'size')
The base class Expression
is visited first. Then the properties expr
and size
are visited.
For each property, the owner is obviously the currently visited swan_obj. Here one can see that
the owner notion is not enough to discriminate the context, as one visits the same type of object (an expression).
The corresponding property names expr
and size
help to discriminated the context. In UML terminology, they would
correspond to a role.
Usage#
The default visitor does nothing but tree traversal. Therefore, one needs to derive a visitor with some meaningful operation.
from typing import Any, Union
from ansys.scadeone.core.svc.swan_visitor import SwanVisitor, Owner, OwnerProperty
class MyVisitor(SwanVisitor):
def __init__(self, *args):
# process my visitor own args
super().__init__()
The methods of SwanVisitor
can be overridden as needed. If one wants to perform a systematic
action while visiting an item, override the SwanVisitor._visit()
method:
def _visit(
self, swan_obj: Any,
owner: Owner,
owner_property: OwnerProperty
) -> None:
# Add some pre-processing here
super()._visit(swan_obj, owner, property)
# add some post-process here
Override any method for which an action is required. Example for a sensor:
def visit_SensorDecl(
self,
swan_obj: swan.SensorDecl,
owner: Owner,
owner_property: OwnerProperty
) -> None:
# do some pre-processing
super().visit_SensorDecl(swan_obj, owner, property)
# do some post-processing
Or one can take the default code and write specific processing. Example for an operator:
def visit_Operator(
self,
swan_obj: swan.Operator,
owner: Owner,
owner_property: OwnerProperty
) -> None:
# do specific processing.
# for instance, do not explore inputs/outputs, body, ...
# which stops the traversal.
SwanVisitor class#
This section describes the methods of the SwanVisitor
.
- class ansys.scadeone.core.svc.swan_visitor.SwanVisitor#
- visit(swan_obj: SwanItem) None #
Entry point. After creation of an instance of a SwanVisitor, this method must be called on a Swan object instance.
- visit_builtin(object: Any, owner: SwanItem | None, owner_property: str | None) None #
Called when visiting a builtin value: str, bool, int or float. Override this method.
- visit_SwanItem(swan_obj: SwanItem, owner: SwanItem | None, owner_property: str | None) None #
Visit of the base class for every Swan constructs. Override this method.
A method is provided for each Swan class. The method name is visit_<SwanClass>. For instance, for the
Operator
class, the method is visit_Operator. The method provides the traversal of the object and its properties. It should be overridden for a specific processing. Look at source in ansys.scadeone.core.svc.swan_visitor.SwanVisitor.visitor.py.- visit_<SwanClass>(swan_obj: object, owner: object, property: str) -> None
Visit a Swan object of type <SwanClass>. This method should be overridden.
- Parameters:
swan_obj – the visited object.
owner – owner of the swan_object. The owner is None for the root visited object.
owner_property – the name of the property in the owner which corresponds to the visited swan_obj. It is None for the root visited object.