blob: 8c60b4a2cb69017f745d364d7767919aafc46971 [file] [log] [blame]
// Copyright (c) 2013 Willink Transformations, University of York and others.
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v2.0
// which accompanies this distribution, and is available at
// http://www.eclipse.org/legal/epl-v20.html
//
// Contributors:
// Adolfo Sanchez-Barbudo Herrera (Univerisity of York) - Initial API and implementation
import VisitorPatternLibrary;
modeltype ECORE "strict" uses ecore('http://www.eclipse.org/emf/2002/Ecore');
transformation DerivedVisitorPatternTransf(inout packages : ECORE,
inout superVisitorPackage : ECORE,
inout rootVisitorPackage : ECORE);
configuration property derivedVisitorInterfaceName : String;
configuration property derivedVisitorInterfaceQualifiedName : String;
configuration property rootVisitorInterfaceName : String;
configuration property rootVisitorInterfaceQualifiedName : String;
configuration property superVisitorInterfaceName : String;
configuration property superVisitorInterfaceQualifiedName : String;
main()
{
var rootVisitorClass := rootVisitorPackage.rootObjects()![EPackage]
.getVisitorInterface(rootVisitorInterfaceName, rootVisitorInterfaceQualifiedName, null);
var superVisitorClass := superVisitorPackage.rootObjects()![EPackage]
.getVisitorInterface(superVisitorInterfaceName, superVisitorInterfaceQualifiedName, null);
packages.rootObjects()[EPackage]->forEach(package) {
var derivedVisitorClass := package.getVisitorInterface(derivedVisitorInterfaceName,
derivedVisitorInterfaceQualifiedName,
superVisitorClass);
package.eClassifiers[EClass]->map weaveAcceptMethods(derivedVisitorClass, rootVisitorClass);
}
}
helper EPackage::getVisitorInterface(in visitorInterfaceName : String, in visitorInterfaceQualifiedName : String,
in superVisitorClass : EClass) : EClass{
var visitorClass := self.findClass(visitorInterfaceName, visitorInterfaceQualifiedName);
if (visitorClass.oclIsUndefined()) then {
self.map addVisitorInterface(visitorInterfaceName,
visitorInterfaceQualifiedName,
superVisitorClass);
// FIXME inout mapping doesnt return out result -> Bug ?, try out parameter
visitorClass := self.findClass(visitorInterfaceName, visitorInterfaceQualifiedName);
} endif;
return visitorClass;
}
mapping inout EPackage::addVisitorInterface(in visitorName : String,
in visitorInstanceClassName : String,
in superVisitorClass : EClass)// FIXME see above <- : EClass
when { self.eClassifiers->select(name = visitorName)->isEmpty(); }
{
var visitor := object EClass {
name := visitorName;
instanceClassName := visitorInstanceClassName;
_abstract := true;
interface := true;
};
if (not superVisitorClass.oclIsUndefined()) then {
if (superVisitorClass.eTypeParameters->isEmpty()) then {
visitor.eSuperTypes += superVisitorClass;
} else {
var typeParameter := object EGenericType {
eClassifier := superVisitorClass;
};
visitor.eGenericSuperTypes += typeParameter;
superVisitorClass.eTypeParameters->forEach(x) {
var argument := x.clone().oclAsType(ETypeParameter);
visitor.eTypeParameters += argument;
typeParameter.eTypeArguments += object EGenericType {
eTypeParameter := argument;
};
};
} endif;
} else { // If no super visitor provided, we need parametrize the visitor
visitor.eTypeParameters += object ETypeParameter {
name := "R"; // FIXME
};
}endif;
self.eClassifiers += visitor;
}
mapping inout EClass::weaveAcceptMethods(in derivedVisitorClass: EClass, in rootVisitorClass: EClass)
when { self.eOperations->select(name = 'accept')->isEmpty()
and not self._abstract
and not self.interface; }
{
var acceptOp := createAcceptMethod(derivedVisitorClass);
// We create the accept method for the visitor
acceptOp.eAnnotations += createGenModelAnnotation("return v.visit" + self.name + "(this);");
eOperations += acceptOp;
// and the polymorphic accept method for the base visitor class
acceptOp := createAcceptMethod(rootVisitorClass);
// TODO automatically compute type parameters and posibly the argument visitor value
acceptOp.eAnnotations += createGenModelAnnotation("return ((" + derivedVisitorClass.name + "<R>)v).visit" + self.name + "(this);");
eOperations += acceptOp;
}