Tutorial | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Downloads


QVT Tutorial - 7

Each Location has to be transformed into a Mode. The Name and InitialState are easy attributes to transform, but what about the Shape and Dimension? This depends on the Class type.

I will present two ways to map this. The first is easier to use, but the second can be very handy when you're dealing with more difficult metamodels.

mapping Location::toMode() : Mode {
 Name := self.Name;
 InitialState := self.IsInitial;
 
 Modifications := self.updates.map toModifications();
 
 if (self.oclIsTypeOf(Rectangle)) then {
 Shape := "Rectangle";
 Dimension := self.oclAsType(Rectangle).Edge;
 } endif;
 
 if (self.oclIsTypeOf(Ellipse)) then {
 Shape := "Ellipse";
 Dimension := self.oclAsType(Ellipse).Radius;
 } endif;
 
 if (self.oclIsTypeOf(Triangle)) then {
 Shape := "Triangle";
 Dimension := self.oclAsType(Triangle).Side;
 } endif;
}

mapping Update::toModifications() : OrderedSet(Modification) {
 
}

To determine the Shape and Dimension, we could simply check the type of each Location. The easiest way to do this would be three separate if-constructs, but it is also possible with if/elif constructs or a switch/case statement.

Maybe useful to know: QVT supports conditional expressions, i.e. let there be a numerical variable "a" which value depends on the value of "b": "a := ( if (b>1) then 10 else 100 endif; )". This would be the shortest solution for the problem above.

About the "Modifications"-part, the next part of this Tutorial will look at the "Update::toModifications()" mapping.

An other way to accomplish this part of the transformation, would be using the "disjuncts" and "inherits" options of QVT. The option "disjuncts" compares the object to one of the mapping after the keyword "disjuncts". The first match will transform the object.
The other one, "inherits", includes an entire mapping, it inherits it.

Example:

mapping Location::toMode() : Mode
disjuncts Rectangle::fromRectangle, Ellipse::fromEllipse, Triangle::fromTriangle1, Triangle::fromTriangle2 { 
 log("This log is never reached, disjunct mappings don't use their body.") 
}

mapping Rectangle::fromRectangle() : Mode 
inherits Location::Updates {
 Shape := "Rectangle";
 Dimension := self.Edge;
}

mapping Ellipse::fromEllipse() : Mode 
inherits Location::Updates {
 Shape := "Ellipse";
 Dimension := self.Radius;
}

mapping Triangle::fromTriangle1() : Mode
inherits Location::Updates 
when { 1 = 2 }
{
 /* Since the condition doesn't hold (1 is obviously not equal to 2),
 this mapping won't be executed for a Triangle object. The one below
 will, because there are no conditions, and the input object is a
 Triangle.
*/ 
}

mapping Triangle::fromTriangle2() : Mode 
inherits Location::Updates {
 Shape := "Triangle";
 Dimension := self.Side; 
}

mapping Location::Updates() : Mode { 
 Name := self.Name;
 InitialState := self.IsInitial;
 Modifications := self.updates.map toModifications();
}

mapping Update::toModifications() : OrderedSet(Modification) {
 
}

As far as I know, it is not possible to use "inherits" in the same mapping that uses "disjuncts". Because a disjunct-mapping doesn't use its body, we have to use the "inherit" option in all the sub-mappings (i.e. fromRectangle, ...).

It might be useful to know that the mapping from "inherits" is executed first, so before the body of the mapping itself. This means that before the Shape and Dimension are assigned, the Mode gets a Name etc. If you don't want this (i.e. the Name should be assigned after the Mode has a Shape and dimension), you should use "merges" instead of "inherits".

We're almost finished with the transformation. The last thing is transforming the Update with its Variables to Modifications. Continue...