Linked List Reversal - YAMTL Implementation
To demonstrate the YAMTL capabilities, let's look at a simple example that reverses a linked list using YAMTL. A linked list with 2 nodes (N1 and N2) is reversed through model transformation.
Source Model
Target Model
YAMTL Transformation
There are 2 aspects of the linked list which are changed from the source model to the target model (thus requiring two tranformation rules):
- The head of the linked list is swapped with its tail.
- The nodes are reversed i.e. pointing to the previous node instead of the next one.
YAMTL Definition
The YAMTL definition is in a Groovy script as follows:
Let's understand each line of code to learn the YAMTL syntax and semantics.
In Line 1, the class (also name of the file) extends YAMTLModule
(which is imported) to highlight the code block containing YAMTL definition.
In Line 2, the public method has an argument llPk
(referring to linked list package) of the type EPackage
. This adds EMF extensions to interpret getters/setters of an EObject and reference to classifiers inside an EPackage. Now, the classes in the .emf
file can be accessed.
In Line 3, the YAMTL Groovy Extensions for EMF import is initialised.
In Line 4, the in and out parameters (of the source and target models respectively) for the model transformation is defined.
In Line 6, the list of transformation rules is initialised using ruleStore
operation. Each rule is contained here, separated by commas (,).
In Line 7-9, the first rule LinkedList2LinkedList
is created with the input source element 's' of the Node
type accessed from the llPk
package. The corresponding target element 't' is of the data type Node
and the out
operation also contains execution statements written in curly braces {}
.
In Line 10, nodes of the LinkedList
's' are all fetched and assigned to the target LinkedList
element 't'. Here, the references or mappings of the nodes are passed to the target element.
In Line 11, all llPk.node
s are queried to find a Node
object that does not reference or point to another Node
object i.e. it points to null
. The result of the fetch
operation is assigned as the head
attribute of the target element. Remember, this is one of the aspects discussed above, the head of the linked list is swapped with its tail.
In Line 14-16, a new rule Node2Node
is defined, its source element 's' and target element 't' have been initialised. Both elements are of the same type Node
accessed via the llPk
package.
In Line 17, the source element's name
attribute is assigned to the target element's name
field.
In Line 18, all Node
objects in the source model are queried to find a Node
object that has a name
attribute which points/references to the source element 's'. The resultant Node
object is fetched and assigned to the target element's next
attribute. Recall, the second transformation aspect previously discussed, each node points to the previous node instead of the next one.
Transformation Test Script
Besides the actual transformation definition, you will also need a Groovy test script that automates the entire transformation process. Here, the relevant project files are configured and test assertions are implemented. Check out a snippet from the test script for the linked list reversal example below:
The transformation is executed through a Gradle build run which also runs this test script. In the code snippet above, a groovy method contains the code for model transformation execution and tests assertion. First, the metamodel
is loaded from a .ecore
file as an EPackage
. Then, xform
initialises a new ReverseLinkedList
transformation definition and passes the metamodel as an EPackage
(llPk
was a reference to the metamodel). The input parameter within the YAMTL definition script is set to be the relative location to the inputList.xmi
file which contains the source model. This source model is loaded into the model transformation, the transformation rules are executed and the output model returned from ReverseLinkedList()
is saved at a defined location through the output parameter. After the transformation is completed, some tests can be run to check the contents of the generated target model. The output model is compared against an expected output expectedOutput.xmi
using EMFComparator
.
Source and Target Metamodel
@namespace(uri="linkedlist", prefix="")
package linkedlist;
class LinkedList {
ref Node head;
val Node[*] nodes;
}
class Node {
attr String name;
ref Node next;
}
The Emfatic textual syntax is used to define the metamodel. The corresponding ECore file "LinkedList.ecore" can then be generated if the Emfatic software package is installed.
Source Model
Graphical Concrete Syntax
XMI serialization of the Abstract Syntax
<?xml version="1.0" encoding="UTF-8"?>
<LinkedList
xmi:version="2.0"
xmlns:xmi="http://www.omg.org/XMI"
xmlns="linkedlist"
head="//@nodes.0">
<nodes name="N1"
next="//@nodes.1" />
<nodes name="N2" />
</LinkedList>
The source model conforms to the source metamodel (LinkedList.emf
). The Groovy test script loads the source model, applies the transformation and saves the target model generated.
Target Model
Graphical Concrete Syntax
XMI serialization of the Abstract Syntax
<?xml version="1.0" encoding="ISO-8859-1"?>
<LinkedList
xmi:version="2.0"
xmlns:xmi="http://www.omg.org/XMI"
xmlns="linkedlist"
head="//@nodes.1">
<nodes name="N1" />
<nodes name="N2" next="//@nodes.0" />
</LinkedList>
This is the output file you should expect when you correctly run the YAMTL program.
Development Platforms
Download the linked list reversal project (ZIP file). You can unzip and import the project into an IDE of your choice. This documentation will provide details on how to setup the example project on Eclipse, IntelliJ and VSCode.
YAMTL uses groovy scripts to define the models and transformations so generally any IDE will need some Groovy support through extensions/plug-ins. Make sure to have YAMTL correctly configured or do the necessary steps found in the YAMTL Workspace Configuration section before you run the project.
Eclipse
Unzip the downloaded project. In Eclipse, click on File → Import → Existing Projects into Workspace → Select root directory → Finish
. This will import and load the project in the IDE.
Right click on src/test/groovy/linkedListReversal/ReverseLinkedListTest.groovy
then Run as → JUnit Test
. Once the test is completed, a new outputList.xmi
will be generated in the model
directory. Examine this file and notice if the linked list has been reversed.
IntelliJ
Within IntelliJ, go to File → Open
and open the project.
Right click on src/test/groovy/linkedListReversal
folder then 'Run Tests...'.
Alternatively, click on the green run button in the top bar to run Tests in 'yamtl-linkedlistreversal'
which builds the project and generates an outputList.xmi
in the model
directory.
Examine this file and notice if the linked list has been reversed.
VSCode
In VSCode, import the project by doing File → Open
.
After you have imported the example project into the workspace, click on the Gradle icon in the left sidebar. Then perform Tasks → build → clean
. Do Tasks → build → build
to build the entire Gradle project (it also runs the ReverseLinkedListTest.groovy
file).
Once the project is successfully built, an outputList.xmi
will be generated in the model
directory. Examine this file and notice if the linked list has been reversed.