Skip to content

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

Linked list in the source model

Linked list BEFORE transformation

Target Model

Linked list in the target model

Linked list AFTER transformation



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):

  1. The head of the linked list is swapped with its tail.
  2. 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:

Snippet from ReverseLinkedList.groovy
class ReverseLinkedList extends YAMTLModule {
    public ReverseLinkedList(EPackage llPk) {
        YAMTLGroovyExtensions_dynamicEMF.init(this)
        header().in('in', llPk).out('out', llPk)

        ruleStore([
            rule('LinkedList2LinkedList')
                .in('s', llPk.LinkedList)
                .out('t', llPk.LinkedList, {
                    t.nodes = fetch(s.nodes) //Mapping
                    t.head = fetch(allInstances(llPk.Node).find{it.next==null})
                }),

            rule('Node2Node')
                .in('s', llPk.Node)
                .out('t', llPk.Node, {
                    t.name = s.name
                    t.next = fetch(allInstances(llPk.Node).find{it.next==s})
                })
        ])
    }
}

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.nodes 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:

Snippet from ReverseLinkedListTest.groovy
1
2
3
4
5
6
// model transformation execution example
def metamodel = YAMTLModule.loadMetamodel(BASE_PATH + '/LinkedList.ecore') as EPackage
def xform = new ReverseLinkedList(metamodel)
xform.loadInputModels(['in': BASE_PATH + '/inputList.xmi'])
xform.execute()
xform.saveOutputModels(['out': BASE_PATH + '/outputList.xmi'])

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

LinkedList.emf
@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

Linked list in the source model

Linked list BEFORE transformation

XMI serialization of the Abstract Syntax

inputList.xmi
<?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

Linked list in the target model

Linked list AFTER transformation

XMI serialization of the Abstract Syntax

outputList.xmi
<?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.

Run gradle tests in IntelliJ

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).

Run Gradle clean and build in VSCode

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.

References


Last update: October 13, 2023