| // 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; |
| } |