/* * #%~ * 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.vdm2uml; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.eclipse.uml2.uml.Class; import org.eclipse.uml2.uml.Classifier; import org.eclipse.uml2.uml.Enumeration; import org.eclipse.uml2.uml.Model; import org.eclipse.uml2.uml.Package; import org.eclipse.uml2.uml.PrimitiveType; import org.eclipse.uml2.uml.RedefinableTemplateSignature; import org.eclipse.uml2.uml.Stereotype; import org.eclipse.uml2.uml.TemplateBinding; import org.eclipse.uml2.uml.TemplateParameter; import org.eclipse.uml2.uml.TemplateParameterSubstitution; import org.eclipse.uml2.uml.UMLPackage; import org.overture.ast.types.ABooleanBasicType; import org.overture.ast.types.ACharBasicType; import org.overture.ast.types.AClassType; import org.overture.ast.types.AFieldField; import org.overture.ast.types.AInMapMapType; import org.overture.ast.types.AIntNumericBasicType; import org.overture.ast.types.ANamedInvariantType; import org.overture.ast.types.ANatNumericBasicType; import org.overture.ast.types.ANatOneNumericBasicType; import org.overture.ast.types.AOptionalType; import org.overture.ast.types.AProductType; import org.overture.ast.types.AQuoteType; import org.overture.ast.types.ARationalNumericBasicType; import org.overture.ast.types.ARealNumericBasicType; import org.overture.ast.types.ARecordInvariantType; import org.overture.ast.types.SSetType; import org.overture.ast.types.ATokenBasicType; import org.overture.ast.types.AUnionType; import org.overture.ast.types.AUnknownType; import org.overture.ast.types.AVoidType; import org.overture.ast.types.PType; import org.overture.ast.types.SBasicType; import org.overture.ast.types.SInvariantType; import org.overture.ast.types.SMapType; import org.overture.ast.types.SNumericBasicType; import org.overture.ast.types.SSeqType; import org.overture.ide.plugins.uml2.UmlConsole; /** * For help see: http://www.eclipse.org/modeling/mdt/uml2/docs/articles/Getting_Started_with_UML2/article.html * * @author kel */ public class UmlTypeCreator extends UmlTypeCreatorBase { public static final String BASIC_VDM_TYPES_PACKAGE = "Basic VDM Types"; public interface ClassTypeLookup { Class lookup(AClassType type); Class lookup(String className); } private class TypeMap extends HashMap<String, Classifier> { /** * */ private static final long serialVersionUID = 1L; @Override public String toString() { StringBuilder sb = new StringBuilder(); for (java.util.Map.Entry<String, Classifier> entry : this.entrySet()) { sb.append(entry.getKey() + ": " + entry.getValue().getName() + "\n"); } return sb.toString(); } // @Override // public Classifier put(String key, Classifier value) // { // // TODO Auto-generated method stub // return super.put(key, value); // } } private Model modelWorkingCopy = null; private final Map<String, Classifier> types = new TypeMap(); private final ClassTypeLookup classLookup; private Package bindingPackage; private Package combositeTypePackage; private Package basicTypePackage; private UmlConsole console = null; private Map<String, Classifier> templateParameterTypes; public UmlTypeCreator(ClassTypeLookup classLookup, UmlConsole console) { this.classLookup = classLookup; this.console = console; } public void setModelWorkingCopy(Model modelWorkingCopy) { this.modelWorkingCopy = modelWorkingCopy; } public void create(Class class_, PType type) { System.out.println(type + " " + type.getClass().getName().toString() + " " + getName(type)); if (types.get(getName(type)) != null) { return; } if (type instanceof AUnionType) { createNewUmlUnionType(class_, (AUnionType) type); return; } else if (type instanceof SInvariantType) { createNewUmlInvariantType(class_, (SInvariantType) type); return; } else if (type instanceof SBasicType) { convertBasicType(class_, (SBasicType) type); return; } else if (type instanceof SMapType) { createMapType(class_, (SMapType) type); return; } else if (type instanceof AOptionalType) { createOptionalType(class_, (AOptionalType) type); return; } else if (type instanceof AProductType) { createProductType(class_, (AProductType) type); return; } else if (type instanceof SSeqType) { createSeqType(class_, (SSeqType) type); return; } else if (type instanceof SSetType) { createSetType(class_, (SSetType) type); return; } else if (type instanceof AUnknownType) { types.put(getName(type), getVdmBasicTypePackage().createOwnedPrimitiveType(ANY_TYPE)); return; } else if (type instanceof AVoidType) { types.put(getName(type), getVdmBasicTypePackage().createOwnedPrimitiveType(VOID_TYPE)); return; // } else if (type instanceof ABracketType) { // } else if (type instanceof AClassType) { // } else if (type instanceof AFunctionType) { // } else if (type instanceof AOperationType) { // } else if (type instanceof AParameterType) { // } else if (type instanceof AQuoteType) { // } else if (type instanceof AUndefinedType) { // } else if (type instanceof AUnresolvedType) { // } else if (type instanceof AVoidReturnType) { } if (type instanceof AClassType && classLookup.lookup((AClassType) type) != null) { return; } if (!types.containsKey(getName(type))) { if (console != null) { console.err.println("Unable to convert type: " + type + " - Inserting \"Unknown\" type as a replacement and continues"); } Classifier unknownType = modelWorkingCopy.createOwnedPrimitiveType(UNKNOWN_TYPE); unknownType.addKeyword(getName(type)); types.put(getName(type), unknownType); } } private void createOptionalType(Class class_, AOptionalType type) { // create(class_, type.getType()); createTemplateType(class_, type, templateOptionalName, new String[] { "T" }, type.getType()); } private void createSetType(Class class_, SSetType type) { createTemplateType(class_, type, templateSetName, new String[] { "T" }, type.getSetof()); } private void createSeqType(Class class_, SSeqType type) { createTemplateType(class_, type, templateSeqName, new String[] { "T" }, type.getSeqof()); } private void createMapType(Class class_, SMapType type) { createTemplateType(class_, type, type instanceof AInMapMapType ? templateInMapName : templateMapName, new String[] { "D", "R" }, type.getFrom(), type.getTo()); } private void createUnionType(Class class_, AUnionType type) { createTemplateType(class_, type, getTemplateUnionName(type.getTypes().size()), getTemplateNames(type.getTypes().size()), type.getTypes()); } private void createProductType(Class class_, AProductType type) { createTemplateType(class_, type, getTemplateProductName(type.getTypes().size()), getTemplateNames(type.getTypes().size()), type.getTypes()); } private void createTemplateType(Class class_, PType type, String templateName, String[] templateSignatureNames, Collection<? extends PType> innertypes) { createTemplateType(class_, type, templateName, templateSignatureNames, innertypes.toArray(new PType[] {})); } private void createTemplateType(Class class_, PType type, String templateName, String[] templateSignatureNames, PType... innertypes) { if (!types.containsKey(templateName)) { if (combositeTypePackage == null) { combositeTypePackage = this.modelWorkingCopy.createNestedPackage("Composite VDM Types"); } Class templateSetClass = combositeTypePackage.createOwnedClass(templateName, false); RedefinableTemplateSignature templateT = (RedefinableTemplateSignature) templateSetClass.createOwnedTemplateSignature(); String name = ""; int i = 0; for (String signature : templateSignatureNames) { if (i > 0) { name += ","; } name += signature; i++; TemplateParameter p = templateT.createOwnedParameter(UMLPackage.Literals.CLASSIFIER_TEMPLATE_PARAMETER); Class cc = (Class) p.createOwnedParameteredElement(UMLPackage.Literals.CLASS); cc.setName(signature); } templateT.setName(name); types.put(templateName, templateSetClass); } // check if binding class exists Classifier bindingClass = types.get(getName(type)); if (bindingClass == null) { if (bindingPackage == null) { bindingPackage = this.modelWorkingCopy.createNestedPackage("Binding classes"); } Classifier templateSetClass = types.get(templateName); bindingClass = bindingPackage.createOwnedClass(getName(type), false); TemplateBinding binding = bindingClass.createTemplateBinding(templateSetClass.getOwnedTemplateSignature()); if (innertypes.length == templateSetClass.getOwnedTemplateSignature().getOwnedParameters().size()) { for (int i = 0; i < innertypes.length; i++) { TemplateParameterSubstitution substitution = binding.createParameterSubstitution(); if (getUmlType(innertypes[i]) == null) { create(class_, innertypes[i]); } substitution.setActual(getUmlType(innertypes[i])); substitution.setFormal(templateSetClass.getOwnedTemplateSignature().getOwnedParameters().get(i)); } } // for (PType innerType : innertypes) // { // TemplateParameterSubstitution substitution = binding.createParameterSubstitution(); // if (getUmlType(innerType) == null) // { // create(class_, innerType); // } // substitution.setActual(getUmlType(innerType)); // } types.put(getName(type), bindingClass); } } private void createNewUmlUnionType(Class class_, AUnionType type) { if (Vdm2UmlUtil.isUnionOfQuotes(type)) { String qualifiedName = getName(type); String simpleName = qualifiedName.substring(qualifiedName.lastIndexOf(':') + 1); String className = qualifiedName.substring(0, qualifiedName.indexOf(':')); Class owningClass = classLookup.lookup(className); Enumeration enumeration = (Enumeration) owningClass.createNestedClassifier(simpleName, UMLPackage.Literals.ENUMERATION); // Enumeration enumeration = modelWorkingCopy.createOwnedEnumeration(getName(type)); for (PType t : type.getTypes()) { if (t instanceof AQuoteType) { String value = "<" + ((AQuoteType) t).getValue().getValue() + ">"; enumeration.createOwnedLiteral(value); PrimitiveType quoteClass = getVdmBasicTypePackage().createOwnedPrimitiveType(value); types.put(value, quoteClass); } } // class_.createNestedClassifier(name.module+"::"+name.name, enumeration.eClass()); types.put(getName(type), enumeration); } else { // do the constraint XOR createUnionType(class_, type); } } private void createNewUmlInvariantType(Class class_, SInvariantType type) { if (type instanceof ANamedInvariantType) { PType ptype = ((ANamedInvariantType) type).getType(); if (!getName(ptype).equals(getName(type))) { String simpleName = getName(type); simpleName = simpleName.substring(simpleName.lastIndexOf(':') + 1); Class owningClass = null; if (class_.getName().equals(type.getLocation().getModule())) { owningClass = class_; } else { owningClass = classLookup.lookup(type.getLocation().getModule()); } Classifier recordClass = owningClass.createNestedClassifier(simpleName, UMLPackage.Literals.CLASS); types.put(getName(type), recordClass); create(class_, ptype); recordClass.createGeneralization(getUmlType(ptype)); } else { create(class_, ptype); } } else if (type instanceof ARecordInvariantType) { String simpleName = getName(type); simpleName = simpleName.substring(simpleName.lastIndexOf(':') + 1); Class owningClass = null; if (class_.getName().equals(type.getLocation().getModule())) { owningClass = class_; } else { owningClass = classLookup.lookup(type.getLocation().getModule()); } Class recordClass = (Class) owningClass.createNestedClassifier(simpleName, UMLPackage.Literals.CLASS); for (AFieldField field : ((ARecordInvariantType) type).getFields()) { create(class_, field.getType()); recordClass.createOwnedAttribute(field.getTag(), getUmlType(field.getType())); } Stereotype sterotype = (Stereotype) recordClass.createNestedClassifier("steriotype", UMLPackage.Literals.STEREOTYPE); sterotype.setName("record"); types.put(getName(type), recordClass); } } public Classifier getUmlType(PType type) { // while(Vdm2UmlUtil.isOptional(type)) // { // type = ((AOptionalType) type).getType(); // } String name = getName(type); if (types.containsKey(name)) { return types.get(name); } else if (type instanceof AClassType && classLookup.lookup((AClassType) type) != null) { return classLookup.lookup((AClassType) type); } // else // { // System.err.println("Trying to find unknown type: "+name); return null; // } } private void convertBasicType(Class class_, SBasicType type) { String typeName = null; if (type instanceof ABooleanBasicType) { typeName = "bool"; } else if (type instanceof ACharBasicType) { typeName = "char"; } else if (type instanceof SNumericBasicType) { convertNumericType((SNumericBasicType) type); return; } else if (type instanceof ATokenBasicType) { typeName = "token"; } else { assert false : "Should not happen"; } if (!types.containsKey(getName(type))) { types.put(getName(type), getVdmBasicTypePackage().createOwnedPrimitiveType(typeName)); } } private void convertNumericType(SNumericBasicType type) { String typeName = null; if (type instanceof AIntNumericBasicType) { typeName = "int"; } else if (type instanceof ANatNumericBasicType) { typeName = "nat"; } else if (type instanceof ANatOneNumericBasicType) { typeName = "nat1"; } else if (type instanceof ARationalNumericBasicType) { typeName = "rat"; } else if (type instanceof ARealNumericBasicType) { typeName = "real"; } else { assert false : "Should not happen"; return; } if (!types.containsKey(getName(type))) { types.put(getName(type), getVdmBasicTypePackage().createOwnedPrimitiveType(typeName)); } } private Package getVdmBasicTypePackage() { if (basicTypePackage == null) { basicTypePackage = this.modelWorkingCopy.createNestedPackage(BASIC_VDM_TYPES_PACKAGE); } return basicTypePackage; } public void addTemplateTypes(Map<String, Classifier> templateParameterTypes) { this.templateParameterTypes = templateParameterTypes; this.types.putAll(templateParameterTypes); } public void removeTemplateTypees() { if (this.templateParameterTypes != null) { for (String name : this.templateParameterTypes.keySet()) { this.types.remove(name); } } } }