|
@@ -23,15 +23,15 @@ On the other hand, procedural algorithms are relatively easy (when implemented n
|
|
|
The functions on model transformations are exposed using the *transformation_add_MT* and *transformation_execute_MT* operations.
|
|
|
Examples as shown in the previous section::
|
|
|
|
|
|
- >>> def callback():
|
|
|
- ... instantiate(None, "Association", edge=("PetriNets/Transition", "ReachabilityGraph/Transition"), ID="PN2RG_Transition")
|
|
|
+ >>> def callback(model):
|
|
|
+ ... instantiate(model, "Association", edge=("PetriNets/Transition", "ReachabilityGraph/Transition"), ID="PN2RG_Transition")
|
|
|
>>> transformation_add_MT({"PetriNets": "formalisms/PetriNets"}, {"ReachabilityGraph": "formalisms/ReachabilityGraph"}, "models/pn_analyse", open("models/pn_analyse.mvc", "r").read(), callback)
|
|
|
|
|
|
A situation in which model transformations are effective, is when the transformation is to map a Domain Specific Language (DSL) to a General Purpose Language (GPL).
|
|
|
For example, when defining a mapping between a RPGame DSL and the PetriNets formalism, to facilitate formal analysis::
|
|
|
|
|
|
- >>> def callback():
|
|
|
- ... instantiate(None, "Association", edge=("RPGame/Tile", "PetriNets/Place"), ID="Tracability_link")
|
|
|
+ >>> def callback(model):
|
|
|
+ ... instantiate(model, "Association", edge=("RPGame/Tile", "PetriNets/Place"), ID="Tracability_link")
|
|
|
>>> rule = \
|
|
|
... """
|
|
|
... Composite composite {
|
|
@@ -81,8 +81,8 @@ As with model transformations, the names of model entities are prefixed with the
|
|
|
|
|
|
For example, when defining the PetriNets analysis in action language, which is a much better match than model transformations::
|
|
|
|
|
|
- >>> def callback():
|
|
|
- ... instantiate(None, "Association", edge=("PetriNets/Transition", "ReachabilityGraph/Transition"), ID="PN2RG_Transition")
|
|
|
+ >>> def callback(model):
|
|
|
+ ... instantiate(model, "Association", edge=("PetriNets/Transition", "ReachabilityGraph/Transition"), ID="PN2RG_Transition")
|
|
|
>>> code = \
|
|
|
... """
|
|
|
... include "primitives.alh"
|
|
@@ -114,8 +114,8 @@ As with model transformations, the names of model entities are prefixed with the
|
|
|
|
|
|
For example, when defining an operation to refine or revise a model in a DSL with respect to the requirements, such as the RPGame language from before::
|
|
|
|
|
|
- >>> def callback():
|
|
|
- ... instantiate(None, "Association", edge=("Requirements/Actor", "RPGame/Player"))
|
|
|
+ >>> def callback(model):
|
|
|
+ ... instantiate(model, "Association", edge=("Requirements/Actor", "RPGame/Player"))
|
|
|
>>> transformation_add_MANUAL({"RPGame": "formalisms/RPGame", "Requirements": "formalisms/Requirements"}, {"RPGame": "formalisms/RPGame"}, "revise_rpg", callback)
|
|
|
|
|
|
Its execution, however, differs significantly from before, as we will see next.
|
|
@@ -134,9 +134,9 @@ As before, the first parameter of the operations (*model_name*) should be set to
|
|
|
|
|
|
For example, to specify the operations that have to be done in a manual operation, all in Python syntax::
|
|
|
|
|
|
- >>> def callback():
|
|
|
- ... tiles = [instantiate(None, "RPGame/Tile") for _ in range(100)]
|
|
|
- ... left_links = [instantiate(None, "RPGame/left", edge=(tiles[i], tiles[i+1])) for i in range(len(tiles) - 1)]
|
|
|
+ >>> def callback(model):
|
|
|
+ ... tiles = [instantiate(model, "RPGame/Tile") for _ in range(100)]
|
|
|
+ ... left_links = [instantiate(model, "RPGame/left", edge=(tiles[i], tiles[i+1])) for i in range(len(tiles) - 1)]
|
|
|
... ...
|
|
|
>>> transformation_execute_MANUAL("revise_rpg", {"RPGame": "models/my_rpg", "Requirements": "models/rpg_requirements"}, {"RPGame": "models/my_rpg"}, callback)
|
|
|
|
|
@@ -144,12 +144,12 @@ Alternatively, the operations might only be known at runtime, thereby requiring
|
|
|
Note that, in this case, the code in the callback is effectively the user interface offered to the user in this specific context.
|
|
|
As such, the code can be completely tailored to the domain and problem at hand (e.g., a *create random level* operation).
|
|
|
|
|
|
- >>> def callback():
|
|
|
+ >>> def callback(model):
|
|
|
... while True:
|
|
|
... print("Please perform operation on RPGame!)"
|
|
|
... inp = raw_input()
|
|
|
... if inp == "new tile":
|
|
|
- ... instantiate(None, "RPGame/Tile")
|
|
|
+ ... instantiate(model, "RPGame/Tile")
|
|
|
... elif inp == "create random level":
|
|
|
... ...
|
|
|
... ...
|
|
@@ -163,6 +163,63 @@ Instead, the callback is invoked when the action language, either standalone or
|
|
|
The return value of the callback is made available to the action language (fragment) when it executes the *input* operations, and can be a single primitive type, or a list.
|
|
|
In case it is a list, the primitive types are offered to the action language individually, requiring multiple *input* calls.
|
|
|
|
|
|
+Statechart callbacks
|
|
|
+^^^^^^^^^^^^^^^^^^^^
|
|
|
+
|
|
|
+While manual operations can refer to a Python function as callback, this is not the case for the execution of a model transformation or action language fragment.
|
|
|
+In this case, a more complex interaction is required, which depends on the use of SCCD (Statecharts + Class Diagrams).
|
|
|
+When executing the activity, a reference to a running statechart is passed, instead of a callback function.
|
|
|
+This statechart can have an input and output port, which can be used to communicate with the Modelverse.
|
|
|
+Data sent on the output port will arrive in the running activity (in the *input()* call), and data sent out in the activity with *output(X)* will be received on the input port.
|
|
|
+
|
|
|
+An example is given below of a model transformation that prints out a Petri Net using a model transformation::
|
|
|
+
|
|
|
+ >>> ctrl = log_output.Controller(keep_running=False)
|
|
|
+ >>> thrd = threading.Thread(target=ctrl.start)
|
|
|
+ >>> thrd.daemon = True
|
|
|
+ >>> thrd.start()
|
|
|
+
|
|
|
+ >>> transformation_execute_MT("test/print_pn", {"PetriNet": "test/my_pn"}, {}, (ctrl, "inp", "outp"))
|
|
|
+
|
|
|
+This command starts up the model transformation and immediately connects it to a running Statechart called *log_output*.
|
|
|
+Its definition is shown below::
|
|
|
+
|
|
|
+ <?xml version="1.0" encoding="UTF-8"?>
|
|
|
+ <diagram author="Yentl Van Tendeloo" name="Logging">
|
|
|
+ <description>
|
|
|
+ Print all incoming data
|
|
|
+ </description>
|
|
|
+
|
|
|
+ <inport name="inp"/>
|
|
|
+ <outport name="outp"/>
|
|
|
+
|
|
|
+ <class name="Logging" default="true">
|
|
|
+ <scxml initial="init">
|
|
|
+ <state id="init">
|
|
|
+ <transition event="input" port="inp" target=".">
|
|
|
+ <parameter name="value"/>
|
|
|
+ <script>
|
|
|
+ print(value)
|
|
|
+ </script>
|
|
|
+ </transition>
|
|
|
+
|
|
|
+ <transition after="0.1" target="."/>
|
|
|
+
|
|
|
+ <transition event="terminate" port="inp" target="../finished">
|
|
|
+ <script>
|
|
|
+ print("Terminating")
|
|
|
+ </script>
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+
|
|
|
+ <state id="finished"/>
|
|
|
+ </scxml>
|
|
|
+ </class>
|
|
|
+ </diagram>
|
|
|
+
|
|
|
+Similarly, the SCCD model could have raised input to its output port (*outp*), which would then be received in the transformation.
|
|
|
+Note that the call to *transformation_execute_MT* is always blocking and always returns whether or not the activity was successfully terminated.
|
|
|
+
|
|
|
Process Model
|
|
|
-------------
|
|
|
|