/* * #%~ * UML2 Translator * %% * Copyright (C) 2008 - 2014 Overture * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #~% */ package org.overture.ide.plugins.uml2.uml2vdm; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Vector; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.ui.PartInitException; import org.eclipse.uml2.uml.Class; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.Enumeration; import org.eclipse.uml2.uml.Model; import org.eclipse.uml2.uml.Operation; import org.eclipse.uml2.uml.Parameter; import org.eclipse.uml2.uml.Property; import org.eclipse.uml2.uml.Stereotype; import org.overture.ast.analysis.AnalysisException; import org.overture.ast.definitions.AClassClassDefinition; import org.overture.ast.definitions.AExplicitFunctionDefinition; import org.overture.ast.definitions.AExplicitOperationDefinition; import org.overture.ast.definitions.AInstanceVariableDefinition; import org.overture.ast.definitions.ATypeDefinition; import org.overture.ast.definitions.AValueDefinition; import org.overture.ast.definitions.PDefinition; import org.overture.ast.expressions.PExp; import org.overture.ast.factory.AstFactory; import org.overture.ast.lex.Dialect; import org.overture.ast.lex.LexLocation; import org.overture.ast.lex.LexNameToken; import org.overture.ast.patterns.PPattern; import org.overture.ast.types.AAccessSpecifierAccessSpecifier; import org.overture.ast.types.AFunctionType; import org.overture.ast.types.AOperationType; import org.overture.ast.types.PType; import org.overture.config.Settings; import org.overture.ide.plugins.uml2.Activator; import org.overture.ide.plugins.uml2.UmlConsole; import org.overture.parser.lex.LexException; import org.overture.parser.syntax.ParserException; import org.overture.parser.util.ParserUtil; import org.overture.parser.util.ParserUtil.ParserResult; import org.overture.prettyprinter.PrettyPrinterEnv; import org.overture.prettyprinter.PrettyPrinterVisitor; public class Uml2Vdm { final static LexLocation location = new LexLocation(new File("generated"), "generating", 0, 0, 0, 0, 0, 0); Model model; private String extension = "vdmpp"; private VdmTypeCreator tc = null; private UmlConsole console; private PExp NEW_A_UNDEFINED_EXP = AstFactory.newAUndefinedExp(location); public Uml2Vdm() { console = new UmlConsole(); tc = new VdmTypeCreator(console); } public boolean initialize(URI uri, String extension) { if (extension != null) { this.extension = extension; } Resource resource = new ResourceSetImpl().getResource(uri, true); for (EObject c : resource.getContents()) { if (c instanceof Model) { model = (Model) c; } } return model != null; } public void convert(File outputDir) { if (model != null) { try { console.show(); } catch (PartInitException e2) { } console.out.println("#\n# Starting translation of model: " + model.getName() + "\n#"); console.out.println("# Into: " + outputDir + "\n#"); console.out.println("-------------------------------------------------------------------------"); Map<String, AClassClassDefinition> classes = new HashMap<String, AClassClassDefinition>(); for (Element e : model.getOwnedElements()) { if (e instanceof Class) { Class class_ = (Class) e; console.out.println("Converting: " + class_.getName()); classes.put(class_.getName(), createClass(class_)); } } console.out.println("Writing source files"); for (Entry<String, AClassClassDefinition> c : classes.entrySet()) { writeClassFile(outputDir, c); } console.out.println("Conversion completed."); } } private void writeClassFile(File outputDir, Entry<String, AClassClassDefinition> c) { try { outputDir.mkdirs(); FileWriter outFile = new FileWriter(new File(outputDir, c.getKey() + "." + extension)); PrintWriter out = new PrintWriter(outFile); out.println(c.getValue().apply(new PrettyPrinterVisitor(), new PrettyPrinterEnv())); out.close(); } catch (IOException e) { Activator.log("Error in writeclassfile", e); } catch (AnalysisException e) { Activator.log("Error in writeclassfile", e); } } private AClassClassDefinition createClass(Class class_) { AClassClassDefinition c = AstFactory.newAClassClassDefinition(); c.setName(new LexNameToken(class_.getName(), class_.getName(), null)); elementLoop: for (Element elem : class_.getOwnedElements()) { if (elem instanceof Class) { Class innerType = (Class) elem; String innerTypeName = innerType.getName(); AAccessSpecifierAccessSpecifier access = Uml2VdmUtil.createAccessSpecifier(innerType.getVisibility()); if (innerType.getNestedClassifier("record") != null && innerType.getGeneralizations().isEmpty()) { boolean createdType = false; for (EObject innerElem : innerType.getOwnedElements()) { if (innerElem instanceof Stereotype) { Stereotype steriotype = (Stereotype) innerElem; if (steriotype.getName().equals("record")) { console.out.println("\tConverting inner record type= " + innerTypeName); ATypeDefinition innerTypeDef = AstFactory.newATypeDefinition(new LexNameToken(class_.getName(), innerTypeName, location), null, null, null); innerTypeDef.setType(tc.createRecord(innerType)); innerTypeDef.setAccess(access); c.getDefinitions().add(innerTypeDef); createdType = true; break; } } } if (!createdType) { console.err.println("\tFound type= " + innerTypeName + " : " + "unknown type"); } } else if (innerTypeName.equalsIgnoreCase("string")// FIX Modelio 2.2.1 || innerType.getGeneralizations().isEmpty()) { for (PDefinition def : c.getDefinitions()) { if (def.getName().getName().equals(innerTypeName)) { continue elementLoop; } } String innerTypeTypeName = "Seq<Char>"; console.out.println("\tConverting inner type= " + innerTypeName + " : " + innerTypeTypeName + " Warning the actual type of \"" + innerTypeName + "\" is undecidable - inserting \"seq of char\" instead"); ATypeDefinition innerTypeDef = AstFactory.newATypeDefinition(new LexNameToken(class_.getName(), innerTypeName, location), null, null, null); innerTypeDef.setType(AstFactory.newASeqSeqType(location, AstFactory.newACharBasicType(location))); innerTypeDef.setAccess(access); c.getDefinitions().add(innerTypeDef); } else { String innerTypeTypeName = innerType.getGeneralizations().get(0).getGeneral().getName(); console.out.println("\tConverting inner type= " + innerTypeName + " : " + innerTypeTypeName); ATypeDefinition innerTypeDef = AstFactory.newATypeDefinition(new LexNameToken(class_.getName(), innerTypeName, location), null, null, null); innerTypeDef.setType(tc.convert(innerTypeTypeName, null)); innerTypeDef.setAccess(access); c.getDefinitions().add(innerTypeDef); } } else if (elem instanceof Enumeration) { String innerTypeName = ((Enumeration) elem).getName(); console.out.println("\tConverting inner enumeration type= " + innerTypeName); ATypeDefinition innerTypeDef = AstFactory.newATypeDefinition(new LexNameToken(class_.getName(), innerTypeName, location), null, null, null); innerTypeDef.setType(tc.createEnumeration((Enumeration) elem)); AAccessSpecifierAccessSpecifier access = Uml2VdmUtil.createAccessSpecifier(((Enumeration) elem).getVisibility()); innerTypeDef.setAccess(access); c.getDefinitions().add(innerTypeDef); } } for (Property att : class_.getOwnedAttributes()) { if (att.isReadOnly()) { createValue(c, att); } else { createInstanceVar(c, att); } } for (Operation op : class_.getOwnedOperations()) { if (op.isQuery()) { createFunction(c, op); } else { createOperation(c, op); } } return c; } private void createFunction(AClassClassDefinition c, Operation op) { console.out.println("\tConverting function: " + op.getName()); LexNameToken name = new LexNameToken(c.getName().getName(), op.getName(), null); List<List<PPattern>> paramPatternList = new Vector<List<PPattern>>(); List<PPattern> paramPatterns = new Vector<PPattern>(); paramPatternList.add(paramPatterns); List<PType> parameterTypes = new Vector<PType>(); for (Parameter p : op.getOwnedParameters()) { if (p.getName() == null) { continue;// this is the return type } parameterTypes.add(tc.convert(p.getType())); paramPatterns.add(AstFactory.newAIdentifierPattern(new LexNameToken(c.getName().getName(), p.getName(), location))); } AFunctionType type = AstFactory.newAFunctionType(null, true, parameterTypes, tc.convert(op.getType())); AExplicitFunctionDefinition operation = AstFactory.newAExplicitFunctionDefinition(name, null, null, type, paramPatternList, AstFactory.newAUndefinedExp(null), null, null, false, null); operation.setAccess(Uml2VdmUtil.createAccessSpecifier(op.getVisibility(), op.isStatic(), false)); c.getDefinitions().add(operation); } private void createOperation(AClassClassDefinition c, Operation op) { console.out.println("\tConverting operation: " + op.getName()); LexNameToken name = new LexNameToken(c.getName().getName(), op.getName(), null); List<PType> parameterTypes = new Vector<PType>(); List<PPattern> parameters = new Vector<PPattern>(); for (Parameter p : op.getOwnedParameters()) { if (p.getName() == null) { continue;// this is the return type } parameterTypes.add(tc.convert(p.getType())); parameters.add(AstFactory.newAIdentifierPattern(new LexNameToken(c.getName().getName(), p.getName(), location))); } AOperationType type = AstFactory.newAOperationType(null, parameterTypes, tc.convert(op.getType())); AExplicitOperationDefinition operation = AstFactory.newAExplicitOperationDefinition(name, type, parameters, null, null, AstFactory.newANotYetSpecifiedStm(null)); operation.setAccess(Uml2VdmUtil.createAccessSpecifier(op.getVisibility(), op.isStatic(), false)); c.getDefinitions().add(operation); } private void createInstanceVar(AClassClassDefinition c, Property att) { console.out.println("\tConverting instance variable: " + att.getName()); PType type = tc.convert(att); PExp defaultExp = null;// NEW_A_INT_ZERRO_LITERAL_EXP.clone(); if (att.getDefault() != null && !att.getDefault().isEmpty()) { Settings.dialect = Dialect.VDM_PP; ParserResult<PExp> resExp = null; boolean failed = false; try { resExp = ParserUtil.parseExpression(att.getDefault()); } catch (ParserException e) { failed = true; e.printStackTrace(); } catch (LexException e) { failed = true; e.printStackTrace(); } if (resExp.errors.isEmpty() && !failed) { defaultExp = resExp.result; } else { console.err.println("\tFaild to parse expression for attribute: " + att.getName() + " in class " + c.getName().getName() + " default is: " + att.getDefault()); } } AInstanceVariableDefinition inst = AstFactory.newAInstanceVariableDefinition(new LexNameToken(c.getName().getName(), att.getName(), location), type, defaultExp); c.getDefinitions().add(inst); } private void createValue(AClassClassDefinition c, Property att) { console.out.println("\tConverting value: " + att.getName()); PType type = tc.convert(att); PExp defaultExp = NEW_A_UNDEFINED_EXP.clone(); if (att.getDefault() != null && !att.getDefault().isEmpty()) { Settings.dialect = Dialect.VDM_PP; ParserResult<PExp> resExp = null; boolean failed = false; try { resExp = ParserUtil.parseExpression(att.getDefault()); } catch (ParserException e) { failed = true; e.printStackTrace(); } catch (LexException e) { failed = true; e.printStackTrace(); } if (resExp.errors.isEmpty() && !failed) { defaultExp = resExp.result; } else { console.err.println("\tFaild to parse expression for attribute: " + att.getName() + " in class " + c.getName().getName() + " default is: " + att.getDefault()); } } AValueDefinition inst = AstFactory.newAValueDefinition(AstFactory.newAIdentifierPattern(new LexNameToken(c.getName().getName(), att.getName(), location)), null, type, defaultExp); c.getDefinitions().add(inst); } }