blob: a209ea4a729394fdab57b58b93f2417abbe7bf00 [file] [log] [blame]
/**
* Copyright (c) 2008 - 2010 OptXware Research and Development LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Daniel Varro - Initial API and implementation
*/
/**
* Copyright (c) 2008 OptXware Research and Development LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Daniel Varro - Initial API and implementation
*/
package org.eclipse.viatra2.lpgparser.typechecker;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.viatra2.core.IModelElement;
import org.eclipse.viatra2.core.IModelManager;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.enums.ValueKind;
/**
* This class provides elementary boolean operations over the lattice of
* VPM types.
*
* Valid strings of types representations are as follows
* - "TOP": All concepts and terms are instances
* - "MODELELEMENT": All element from the model space are instances
* - "ENTITY": All entities are instances
* - "RELATION": All relations are instances
* - FQN of any element from the VPM model space, with special treatment for
* - datatypes.String
* - datatypes.Boolean
* - datatypes.Integer
* - datatypes.Double
* - datatypes.MultiplicityKind
* - "BOTTOM": The error type, no instances are available
* @author varro
*
*/
public class TypeResolver {
/**
* Retrieves the least upper bound (LUB, or OR-join) of types
* typeStr1 and typeStr2 according to the VPM type hierarchy
* @param modelManager
* @param typeStr1
* @param typeStr2
* @return String representation of the LUB type
*/
public String leastUpperBound(IModelManager modelManager, String typeStr1, String typeStr2) {
// If typeStr1 <- typeStr2, then typeStr1
if (isSupertype(modelManager, typeStr1, typeStr2)) {
return typeStr1;
}
// If typeStr2 <- typeStr1, then typeStr2
else if (isSupertype(modelManager, typeStr2, typeStr1)) {
return typeStr2;
}
// if (typeStr1 != null && typeStr2 != null) {
// String result = checkOrPrimitiveTypes(typeStr1, typeStr2);
// if (result != null) {
// return result;
// }
// }
// First lookup the FQN typeStr1 in the model space
IModelElement me1 = modelManager.getElementByName(typeStr1);
// Then lookup the FQN typeStr2 in the model space
IModelElement me2 = modelManager.getElementByName(typeStr2);
// Return the TOP type if any of them is unresolvable
if (me1 == null || me2 == null) {
return "TOP";
}
// If me2 -> me1, return the more general me1
if (me1.isSubtypeOf(me2)) {
return me1.getFullyQualifiedName();
}
// If me1 -> me2, return the more general me2
else if (me2.isSubtypeOf(me1)) {
return me2.getFullyQualifiedName();
}
Set<IModelElement> commonSupertypes = new HashSet<IModelElement>();
traverseSupertypeHierarchy(me1, me2, commonSupertypes);
if (!commonSupertypes.isEmpty()) {
if (commonSupertypes.size() == 1) {
return commonSupertypes.iterator().next().getFullyQualifiedName();
}
else {
// TODO: Report error if multiple resolutions are possible
return "BOTTOM";
}
}
if (me1.isEntity() && me2.isEntity()) {
return "ENTITY";
}
else if (me1.isRelation() && me2.isRelation()) {
return "RELATION";
}
else {
return "MODELELEMENT";
}
}
protected void traverseSupertypeHierarchy(IModelElement current,
IModelElement other, Set<IModelElement> resolutionSet) {
List<IModelElement> toTraverseList = new ArrayList<IModelElement>();
for (IModelElement element : current.getSupertypes()) {
if (other.isSupertypeOf(element)) {
boolean subtypeFound = false;
Iterator<IModelElement> iter = resolutionSet.iterator();
while (!subtypeFound && iter.hasNext()) {
IModelElement existing = iter.next();
if (element.isSubtypeOf(existing)) {
subtypeFound = true;
}
}
if (!subtypeFound) {
resolutionSet.add(element);
}
}
else {
toTraverseList.add(element);
}
}
for (IModelElement toTraverse : toTraverseList) {
traverseSupertypeHierarchy(toTraverse, other, resolutionSet);
}
}
protected String checkOrPrimitiveTypes(String typeStr1, String typeStr2) {
if (typeStr1.equals("TOP") || typeStr2.equals("TOP")) {
return "TOP";
}
// TODO: Check how to mask a bottom
// else if (typeStr1.equals("BOTTOM") || typeStr2.equals("BOTTOM") ) {
// return "TOP";
// }
else if (typeStr1.equals("BOTTOM")) {
return typeStr2;
}
else if ( typeStr2.equals("BOTTOM")) {
return typeStr1;
}
else if (typeStr1.equals("MODELELEMENT") &&
(typeStr2.equals("ENTITY") ||
typeStr2.equals("RELATION"))) {
return "MODELELEMENT";
}
else if (typeStr2.equals("MODELELEMENT") &&
(typeStr1.equals("ENTITY") ||
typeStr1.equals("RELATION"))) {
return "MODELELEMENT";
}
else if (typeStr1.equals("ENTITY") && typeStr2.equals("ENTITY")) {
return "ENTITY";
}
else if (typeStr1.equals("RELATION") && typeStr2.equals("RELATION")) {
return "RELATION";
}
else if (typeStr1.equals("RELATION") && typeStr2.equals("ENTITY") ||
typeStr1.equals("ENTITY") && typeStr2.equals("RELATION")) {
return "MODELELEMENT";
}
else return null;
}
protected String checkAndPrimitiveTypes(String typeStr1, String typeStr2) {
if (typeStr1.equals("TOP") ) {
return typeStr2;
}
else if (typeStr2.equals("TOP")) {
return typeStr1;
}
else if (typeStr1.equals("BOTTOM") ||
typeStr2.equals("BOTTOM")) {
return "BOTTOM";
}
// else if (typeStr1.equals("MODELELEMENT") &&
// (typeStr2.equals("ENTITY") ||
// typeStr2.equals("RELATION"))) {
// return "TOP";
// }
else if ( typeStr2.equals("MODELELEMENT") && typeStr1.equals("MODELELEMENT")) {
return "MODELELEMENT";
}
else if ( typeStr2.equals("MODELELEMENT") && typeStr1.equals("ENTITY") ||
typeStr1.equals("MODELELEMENT") && typeStr2.equals("ENTITY") ) {
return "ENTITY";
}
else if (typeStr2.equals("MODELELEMENT") && typeStr1.equals("RELATION") ||
typeStr1.equals("MODELELEMENT") && typeStr2.equals("RELATION") ) {
return "RELATION";
}
else if (typeStr1.equals("ENTITY") && typeStr2.equals("RELATION") ||
typeStr2.equals("ENTITY") && typeStr1.equals("RELATION")) {
return "BOTTOM";
}
else return null;
}
public String greatestLowerBound(IModelManager modelManager, String typeStr1, String typeStr2) {
// If typeStr1 <- typeStr2
if (isSupertype(modelManager, typeStr1, typeStr2)) {
return typeStr2;
}
// If typeStr2 <- typeStr1
else if (isSupertype(modelManager, typeStr2, typeStr1)) {
return typeStr1;
}
// // Check for primitive types
// if (typeStr1 != null && typeStr2 != null) {
// String result = checkAndPrimitiveTypes(typeStr1, typeStr2);
// if (result != null) {
// return result;
// }
// }
// First lookup the FQN typeStr1 in the model space
IModelElement me1 = modelManager.getElementByName(typeStr1);
// Then lookup the FQN typeStr2 in the model space
IModelElement me2 = modelManager.getElementByName(typeStr2);
// Return the TOP type if any of them is unresolvable
if (me1 == null || me2 == null) {
return "BOTTOM";
}
// If me2 -> me1, return the less general me2
if (me1.isSubtypeOf(me2)) {
return me2.getFullyQualifiedName();
}
// If me1 -> me2, return the less general me1
else if (me2.isSubtypeOf(me1)) {
return me1.getFullyQualifiedName();
}
Set<IModelElement> commonSubtypes = new HashSet<IModelElement>();
traverseSubtypeHierarchy(me1, me2, commonSubtypes);
if (!commonSubtypes.isEmpty()) {
if (commonSubtypes.size() == 1) {
return commonSubtypes.iterator().next().getFullyQualifiedName();
}
// TODO: Report error if multiple resolutions are possible
else {
return "BOTTOM";
}
}
if (me1.isEntity() && me2.isEntity()) {
return "ENTITY";
}
else if (me1.isRelation() && me2.isRelation()) {
return "RELATION";
}
else {
return "BOTTOM";
}
}
protected void traverseSubtypeHierarchy(IModelElement current,
IModelElement other, Set<IModelElement> resolutionSet) {
List<IModelElement> toTraverseList = new ArrayList<IModelElement>();
for (IModelElement element : current.getSubtypes()) {
if (other.isSubtypeOf(element)) {
boolean supertypeFound = false;
Iterator<IModelElement> iter = resolutionSet.iterator();
while (!supertypeFound && iter.hasNext()) {
IModelElement existing = iter.next();
if (element.isSupertypeOf(existing)) {
supertypeFound = true;
}
}
if (!supertypeFound) {
resolutionSet.add(current);
}
}
else {
toTraverseList.add(element);
}
}
for (IModelElement toTraverse : toTraverseList) {
traverseSubtypeHierarchy(toTraverse, other, resolutionSet);
}
}
/**
* Checks if the model element represented by supertypeStr is a supertype of
* the model element represented by subtypeStr according to the model manager.
* If any of the two strings are "TOP", it returns with true.
* @param modelManager : {@link IModelManager} to query types
* @param supertypeStr : string representation of the supertype
* @param subtypeStr : string representation of the subtype
* @return true, if the supertype relation holds
*/
public boolean isSupertype(IModelManager modelManager, String supertypeStr, String subtypeStr) {
// TODO: Check if the handling of TOP and BOTTOM is correct
if (supertypeStr.equals("TOP") || subtypeStr.equals("TOP")) {
return true;
}
else if (supertypeStr.equals("BOTTOM")) {
return false;
}
else if (subtypeStr.equals("BOTTOM")) {
return true;
}
else if (supertypeStr.equals("MODELELEMENT")) {
if (subtypeStr.equals("MODELELEMENT") ||
subtypeStr.equals("ENTITY") ||
subtypeStr.equals("RELATION")) {
return true;
}
else {
IModelElement subElem = modelManager.getElementByName(subtypeStr);
if (subElem != null) {
return true;
}
else {
return false;
}
}
}
else if (supertypeStr.equals("ENTITY")) {
if (subtypeStr.equals("ENTITY")) {
return true;
}
else if (subtypeStr.equals("MODELELEMENT") ||
subtypeStr.equals("RELATION")) {
return false;
}
else {
IModelElement subElem = modelManager.getElementByName(subtypeStr);
if (subElem != null && subElem.isEntity()) {
return true;
}
else {
return false;
}
}
}
else if (supertypeStr.equals("RELATION")) {
if (subtypeStr.equals("RELATION")) {
return true;
}
else if (subtypeStr.equals("MODELELEMENT") ||
subtypeStr.equals("ENTITY")) {
return false;
}
else {
IModelElement subElem = modelManager.getElementByName(subtypeStr);
if (subElem != null && subElem.isRelation()) {
return true;
}
else {
return false;
}
}
}
else {
IModelElement superElem = modelManager.getElementByName(supertypeStr);
IModelElement subElem = modelManager.getElementByName(subtypeStr);
if (superElem != null && subElem != null && (subElem == superElem ||
superElem.isSupertypeOf(subElem))) {
return true;
}
else {
return false;
}
}
}
/**
* Returns the fully qualified name of the type of a model element
* @param modelElement : the model element to be queried
* @return : the FQN of the type of this model element
*/
public String lookupType(IModelElement modelElement) {
Collection<IModelElement> types = modelElement.getTypes();
int size = types.size();
switch (size) {
case 0:
// No type is found
if (modelElement.isEntity()) {
return "ENTITY";
}
else if (modelElement.isRelation()) {
return "RELATION";
}
else return "MODELELEMENT";
case 1:
// A single type is found
return types.iterator().next().getFullyQualifiedName();
default:
// More than a single type is found
// TODO: Refine this if needed to more sophisticated type handling
if (modelElement.isEntity()) {
return "ENTITY";
}
else if (modelElement.isRelation()) {
return "RELATION";
}
else return "MODELELEMENT";
}
}
/**
* Obtains the ValueKind for a given type. It resolves references to
* built-in types, i.e. String, Boolean, Integer, Double
* (which reside in the "datatypes" model fragment)
* @param typeStr : fully qualified name of a model element
* @return ValueKind
*/
public ValueKind getValueKind(String typeStr) {
if (typeStr.equals("datatypes.String")) {
return ValueKind.STRING_LITERAL;
}
else if (typeStr.equals("datatypes.Boolean")) {
return ValueKind.BOOLEAN_LITERAL;
}
else if (typeStr.equals("datatypes.Integer")) {
return ValueKind.INTEGER_LITERAL;
}
else if (typeStr.equals("datatypes.Double")) {
return ValueKind.DOUBLE_LITERAL;
}
else if (typeStr.equals("datatypes.Multiplicity")) {
return ValueKind.MULTIPLICITY_LITERAL;
}
else if (typeStr.equals("TOP")) {
return ValueKind.UNDEF_LITERAL;
}
else if (typeStr.equals("BOTTOM")) {
return ValueKind.ERROR_LITERAL;
}
else {
return ValueKind.MODELELEMENT_LITERAL;
}
}
}