/* * #%~ * 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.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.Vector; import org.eclipse.emf.ecore.impl.MinimalEObjectImpl; import org.eclipse.uml2.uml.Class; import org.eclipse.uml2.uml.Enumeration; import org.eclipse.uml2.uml.EnumerationLiteral; import org.eclipse.uml2.uml.LiteralUnlimitedNatural; import org.eclipse.uml2.uml.Property; import org.eclipse.uml2.uml.Type; import org.overture.ast.assistant.pattern.PTypeList; import org.overture.ast.factory.AstFactory; import org.overture.ast.lex.LexLocation; import org.overture.ast.lex.LexNameToken; import org.overture.ast.lex.LexQuoteToken; import org.overture.ast.types.AFieldField; import org.overture.ast.types.PType; import org.overture.ide.plugins.uml2.UmlConsole; import org.overture.ide.plugins.uml2.vdm2uml.UmlTypeCreatorBase; public class VdmTypeCreator { final Set<String> basicTypes = new HashSet<String>(Arrays.asList(new String[] { "bool", "char", "token", "int", "nat", "nat1", "rat", "real" })); final String UNION_TYPE = "Union<"; final String MAP_TYPE = "Map<"; final String SET_TYPE = "Set<"; final String SEQ_TYPE = "Seq<"; final String PRODUCT_TYPE = "Product<"; final String OPTIONAL_TYPE = "Optional<"; final String INMAP_TYPE = "InMap<"; final static LexLocation location = new LexLocation(new File("generated"), "generating", 0, 0, 0, 0, 0, 0); private UmlConsole console; public VdmTypeCreator(UmlConsole console) { this.console = console; } public PType convert(Property p) { PType type = convert(p.getType()); if (p.getUpper() == LiteralUnlimitedNatural.UNLIMITED) { if (p.isOrdered()) { if (p.getLower() == 0) { type = AstFactory.newASeqSeqType(location, type); } else if (p.getLower() == 1) { type = AstFactory.newASeq1SeqType(location, type); } } else { type = AstFactory.newASetSetType(location, type); } } else if (p.getLower() == 0 && p.getUpper() == 1) { type = AstFactory.newAOptionalType(location, type); } if (p.getQualifiers().size() == 1) { Property qualifier = p.getQualifiers().get(0); PType fromType = convert(qualifier); if (p.isUnique()) { type = AstFactory.newAInMapMapType(location, fromType, type); } else { type = AstFactory.newAMapMapType(location, fromType, type); } } return type; } public PType convert(Type type) { try { if (type == null) { console.err.println("Found no type. Inserting an \"?\" type as a replacement"); return convert(UmlTypeCreatorBase.ANY_TYPE, null); } String module = null; if (type.getNamespace() != null && type.getNamespace() instanceof Class) { module = type.getNamespace().getName(); } if (type.getName() == null && type instanceof MinimalEObjectImpl) { java.lang.reflect.Field f = MinimalEObjectImpl.class.getDeclaredField("eStorage"); f.setAccessible(true); String storageUri = "" + f.get(type); System.out.println(storageUri); int index = storageUri.lastIndexOf("#"); if (index == -1) { console.err.println("Could not decode \"" + storageUri + "\" inseting an \"?\" type as a replacement"); return convert(UmlTypeCreatorBase.ANY_TYPE, null); } String typeName = storageUri.substring(index + 1); return convert(remapUmlTypes(typeName), module); } else if (type.getName() == null) { console.err.println("Type has no name. Inserting an \"?\" type as a replacement"); return convert(UmlTypeCreatorBase.ANY_TYPE, null); } return convert(type.getName(), module); } catch (Exception e) { e.printStackTrace(); return null; } } private String remapUmlTypes(String name) { if (name.equalsIgnoreCase("Integer")) { return "int"; } else if (name.equalsIgnoreCase("Boolean") || name.equalsIgnoreCase("float") || name.equalsIgnoreCase("long")) { return "bool"; } else if (name.equalsIgnoreCase("short") || name.equalsIgnoreCase("byte")) { return "nat"; } else if (name.equalsIgnoreCase("String")) { return "Seq<Char>"; } else if (name.equalsIgnoreCase("Double")) { return "real"; } console.err.println("Could not match UML type \"" + name + "\" with a VDM type. Inserting an \"?\" type as a replacement"); return UmlTypeCreatorBase.ANY_TYPE; } public PType convert(String type, String module) { if (basicTypes.contains(type.toLowerCase())) { return convertBasicType(type); } else if (type.equals(UmlTypeCreatorBase.VOID_TYPE)) { return AstFactory.newAVoidReturnType(location); } else if (type.equals(UmlTypeCreatorBase.ANY_TYPE)) { return AstFactory.newAUnknownType(location); } else if (type.startsWith(UNION_TYPE)) { return AstFactory.newAUnionType(location, convertGeneric(type)); } else if (type.startsWith(PRODUCT_TYPE)) { return AstFactory.newAProductType(location, convertGeneric(type)); } else if (type.startsWith(MAP_TYPE)) { List<PType> types = convertGeneric(type); return AstFactory.newAMapMapType(location, types.get(0), types.get(1)); } else if (type.startsWith(INMAP_TYPE)) { List<PType> types = convertGeneric(type); return AstFactory.newAInMapMapType(location, types.get(0), types.get(1)); } else if (type.startsWith(SET_TYPE)) { return AstFactory.newASetSetType(location, convertGeneric(type).get(0)); } else if (type.startsWith(SEQ_TYPE)) { return AstFactory.newASeqSeqType(location, convertGeneric(type).get(0)); } else if (type.startsWith("<") && type.endsWith(">")) { return AstFactory.newAQuoteType(new LexQuoteToken(type.substring(1, type.length() - 1), location)); } else if (type.startsWith(OPTIONAL_TYPE)) { return AstFactory.newAOptionalType(location, convertGeneric(type).get(0)); } else { // String module = ""; String name = ""; if (type.contains("::")) { module = type.substring(0, type.indexOf(":")); name = type.substring(type.lastIndexOf(":") + 1); } else { name = type; } LexNameToken typeName = new LexNameToken(module, name, location); return AstFactory.newANamedInvariantType(typeName, null); } } private PType convertBasicType(String type) { String name = type.toLowerCase(); if (name.equals("bool")) { return AstFactory.newABooleanBasicType(location); } else if (name.equals("char")) { return AstFactory.newACharBasicType(location); } else if (name.equals("token")) { return AstFactory.newATokenBasicType(location); } else if (name.equals("int")) { return AstFactory.newAIntNumericBasicType(location); } else if (name.equals("nat")) { return AstFactory.newANatNumericBasicType(location); } else if (name.equals("nat1")) { return AstFactory.newANatOneNumericBasicType(location); } else if (name.equals("rat")) { return AstFactory.newARationalNumericBasicType(location); } else if (name.equals("real")) { return AstFactory.newARealNumericBasicType(location); } return null; } /** * The name must start with < and end with > and be separated by comma. * * @param name * @return */ private PTypeList convertGeneric(String name) { String nameNoLessOrGreater = name.substring(name.indexOf("<") + 1, name.length() - 1); String[] typeStrings = nameNoLessOrGreater.split(","); // decide if the split is valid or if the type is a single generic type boolean notSingleGenericType = true; for (String part : typeStrings) { if (part.replaceAll("[^<]", "").length() != part.replaceAll("[^>]", "").length()) { notSingleGenericType = false; } } PTypeList types = new PTypeList(); if (notSingleGenericType) { for (String t : typeStrings) { types.add(convert(t, null)); } } else { types.add(convert(nameNoLessOrGreater, null)); } return types; } public PType createRecord(Class innerType) { List<AFieldField> fields = new Vector<AFieldField>(); for (Property p : innerType.getOwnedAttributes()) { LexNameToken tagname = new LexNameToken("", p.getName(), location); String tag = p.getName(); PType type = convert(p.getType()); fields.add(AstFactory.newAFieldField(tagname, tag, type, false)); } return AstFactory.newARecordInvariantType(location, fields); } public PType createEnumeration(Enumeration elem) { PTypeList types = new PTypeList(); for (EnumerationLiteral lit : elem.getOwnedLiterals()) { if (lit.getName().startsWith("<") && lit.getName().endsWith(">")) { types.add(convert(lit.getName(), null)); } else { System.out.println("Problem with conversion of enumeration: " + elem.getName()); } } return AstFactory.newAUnionType(location, types); } }