.. _modelling-a-model-transformation: Modelling a Model Transformation ================================ A model transformation consists of a set of rules that match and rewrite parts of the model, and a schedule that governs the order in which rules are executed. In the next subsections, we explain how to create these elements. In :ref:`executing-a-model-transformation`, we explain how to execute the modelled transformation. In this section, we make use of the *TransformationEditor* toolbar: .. image:: img/transformation_editor.png Compiling a Language to a Pattern Language ------------------------------------------ A prerequisite to modelling rules is to compile the language of the models you want to transform to a pattern language. This pattern language is used in the rules you model, and is very similar to the original language. This makes modelling the patterns very intuitive (since almost the same syntax is used), while changing the language to accomodate the matching and rewriting process. .. image:: img/compilation_toolbar.png To compile a language to a pattern language, press the third button on the *CompileMenu* toolbar. Navigate to the abstract syntax metamodel you want to compile: .. image:: img/compile_pattern.png Pressing the 'ok' button will create the abstract syntax metamodel *TrafficLight.pattern.metamodel* and the formalism toolbar *TrafficLight.defaultIcons.pattern.metamodel* in the */Formalisms/TrafficLight* user folder. This formalism is used alongside :ref:`the-rule-language` to model the rules of the model transformation. The pattern language differs from the original language in three ways: * Its constraints are **relaxed**. More precisely, abstract classes in the original language are made concrete, and minimum cardinalities are removed. * Elements in the language are **augmented** with four attributes: *__pLabel*, *__pMatchSubtypes*, *__pPivotIn*, and *__pPivotOut*. We will only use the two first ones. *__pLabel* is used to identify elements across LHS/RHS/NAC patterns, and *__pMatchSubtypes* indicates that instances of subclasses should also be matched. * The type of the attributes of each element is changed to *code*. This allows to model *constraints* in LHS/NAC patterns on the values of the attributes in the host model and *actions* in RHS patterns to compute the new values of the attributes after rewriting. .. warning:: Constraint and action code in patterns is written in Python! Initializing Schedules/Rules ---------------------------- A formalism created with the "new formalism" button on the *MainMenu* toolbar (see :ref:`overview`) comes initialized with two schedules: *OperationalSemantics/T_OperationalSemantics.model* and *TranslationalSemantics/T_TranslationalSemantics.model*. These can be used to model the schedule of the formalism's operational semantics (a simulator) and translational semantics (a mapping onto a domain with known semantics), respectively. If you want to initialize a new schedule, use the fourth button on the *TransformationEditor* toolbar. This will present you with a file browser, which allows you to choose a location and a name for the schedule. The schedule will automatically open in a new AToMPM instance. .. warning:: A schedule's name has to start with the T\_ prefix! If you want to initialize a new rule, use the fifth button on the *TransformationEditor* toolbar. This will present you with a file browser, which allows you to choose a location and a name for the rule. The rule will automatically open in a new AToMPM instance. .. warning:: A rule's name has to start with the R\_ prefix! .. _the-rule-language: The Rule Language ----------------- When creating a rule, it is initialized with the three basic components of every rule: a *Negative Application Condition* (NAC), a *Left-Hand-Side* (LHS), and a *Right-Hand-Side* (RHS). .. image:: img/rule_init.png :scale: 50 In general, a rule has to have exactly one LHS, exactly one RHS, and zero or more NACs. The LHS is used to *match a pattern* in the host model. It is a positive application condition: if the pattern is found in the host model, the rule can be applied. If the pattern in one of the NACs is found, however, the rule is disabled. The RHS is used to *rewrite the pattern* in the host model. To model the patterns, we need to load the pattern language we compiled earlier. Press the third button on the *TransformationEditor* toolbar. Navigate to your pattern metamodel: .. image:: img/load_pattern_metamodel.png This will load the formalism toolbar of the pattern language for use in LHS, RHS, and NAC patterns. LHS and NAC ^^^^^^^^^^^ The LHS and NACs are so-called *precondition patterns*. When a rule is selected for execution, it will try to find a match in the host model for the LHS. If one is found, it will try to match all the NACs. If a match is found for one of them, the rule is not executed. .. image:: img/example_LHS.png In the example LHS above, we try to find the current interrupt in the interrupt list, but only if the clock has advanced to a point in time *after or equal to* the time specified in that interrupt. To do this, we model: * An instance of *__pInterrupt* (with label '1'). Each attribute has to assign a boolean value to the 'result' variable, indicating whether the instance can be matched based on the value of the attribute. The current value can be accessed using the *getAttr()* function. For a complete overview of functions that can be called from action and condition code in patterns, see :ref:`mt-action-library`. In our example, we only want to make sure the *current* attribute is *True*. We set all conditions to *result = True* (the default), except for the *current* attribute, where we require *result = (getAttr() == True)* -- or, more simply, *result = getAttr()*. * An instance of the *AbstractInterrupt*, connected to the first interrupt. We instantiate the abstract class here, because potentially, it is the *end* of the list, and we want to make sure to match both normal interrupts and end interrupts. * The *Time* instance (which we know is a singleton). The condition that the clock needs to have advanced beyond the time specified in the current interrupt cannot be modelled as a condition on one single attribute, since it spans multiple instances (the *Time* instance and the first *Interrupt* instance). A precondition pattern also allows a global condition, which needs to be satisfied in order for the pattern to match. In this case, we get the current time, the event time, and compare them. Again, the resulting boolean is assigned to the variable *result*. When executing the transformation, AToMPM will try to find a match for each of the pattern elements. If one is found, it will map each *__pLabel* value to a matched element:: { '0': '1': '2': '3':