/***************************************************************************** * Copyright (c) 2011 CEA LIST. * * * 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: * CEA LIST - Initial API and implementation * *****************************************************************************/ package org.eclipse.papyrus.uml.alf.validation.typing; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; //import org.eclipse.papyrus.uml.alf.alf.OperationCallExpressionWithoutDot; import org.eclipse.papyrus.uml.alf.alf.AdditiveExpression; import org.eclipse.papyrus.uml.alf.alf.AlfPackage; import org.eclipse.papyrus.uml.alf.alf.AndExpression; import org.eclipse.papyrus.uml.alf.alf.BOOLEAN_LITERAL; import org.eclipse.papyrus.uml.alf.alf.ClassExtentExpression; import org.eclipse.papyrus.uml.alf.alf.ClassificationExpression; import org.eclipse.papyrus.uml.alf.alf.CollectOrIterateOperation; import org.eclipse.papyrus.uml.alf.alf.ConditionalAndExpression; import org.eclipse.papyrus.uml.alf.alf.ConditionalOrExpression; import org.eclipse.papyrus.uml.alf.alf.ConditionalTestExpression; import org.eclipse.papyrus.uml.alf.alf.EqualityExpression; import org.eclipse.papyrus.uml.alf.alf.ExclusiveOrExpression; import org.eclipse.papyrus.uml.alf.alf.Expression; import org.eclipse.papyrus.uml.alf.alf.ForAllOrExistsOrOneOperation; import org.eclipse.papyrus.uml.alf.alf.INTEGER_LITERAL; import org.eclipse.papyrus.uml.alf.alf.InclusiveOrExpression; import org.eclipse.papyrus.uml.alf.alf.InstanceCreationExpression; import org.eclipse.papyrus.uml.alf.alf.IsUniqueOperation; import org.eclipse.papyrus.uml.alf.alf.LITERAL; import org.eclipse.papyrus.uml.alf.alf.LinkOperationExpression; import org.eclipse.papyrus.uml.alf.alf.MultiplicativeExpression; import org.eclipse.papyrus.uml.alf.alf.NameExpression; import org.eclipse.papyrus.uml.alf.alf.NonLiteralValueSpecification; import org.eclipse.papyrus.uml.alf.alf.NullExpression; import org.eclipse.papyrus.uml.alf.alf.OperationCallExpression; import org.eclipse.papyrus.uml.alf.alf.ParenthesizedExpression; import org.eclipse.papyrus.uml.alf.alf.PrimaryExpression; import org.eclipse.papyrus.uml.alf.alf.PropertyCallExpression; import org.eclipse.papyrus.uml.alf.alf.RelationalExpression; import org.eclipse.papyrus.uml.alf.alf.STRING_LITERAL; import org.eclipse.papyrus.uml.alf.alf.SelectOrRejectOperation; import org.eclipse.papyrus.uml.alf.alf.SequenceConstructionExpression; import org.eclipse.papyrus.uml.alf.alf.SequenceConstructionOrAccessCompletion; import org.eclipse.papyrus.uml.alf.alf.SequenceElement; import org.eclipse.papyrus.uml.alf.alf.SequenceExpansionExpression; import org.eclipse.papyrus.uml.alf.alf.SequenceOperationExpression; import org.eclipse.papyrus.uml.alf.alf.SequenceReductionExpression; import org.eclipse.papyrus.uml.alf.alf.ShiftExpression; import org.eclipse.papyrus.uml.alf.alf.SuffixExpression; import org.eclipse.papyrus.uml.alf.alf.SuperInvocationExpression; import org.eclipse.papyrus.uml.alf.alf.ThisExpression; import org.eclipse.papyrus.uml.alf.alf.Tuple; import org.eclipse.papyrus.uml.alf.alf.TupleElement; import org.eclipse.papyrus.uml.alf.alf.UNLIMITED_LITERAL; import org.eclipse.papyrus.uml.alf.alf.UnaryExpression; import org.eclipse.papyrus.uml.alf.alf.UnqualifiedName; import org.eclipse.papyrus.uml.alf.alf.ValueSpecification; import org.eclipse.papyrus.uml.alf.scoping.AlfScopeProvider; import org.eclipse.papyrus.uml.alf.validation.AlfJavaValidator; import org.eclipse.papyrus.uml.alf.validation.PredefinedBehaviorsAndTypesUtils; import org.eclipse.uml2.common.util.UML2Util; import org.eclipse.uml2.uml.Behavior; import org.eclipse.uml2.uml.Classifier; import org.eclipse.uml2.uml.Enumeration; import org.eclipse.uml2.uml.EnumerationLiteral; import org.eclipse.uml2.uml.Operation; import org.eclipse.uml2.uml.Parameter; import org.eclipse.uml2.uml.ParameterDirectionKind; import org.eclipse.uml2.uml.ParameterableElement; import org.eclipse.uml2.uml.PrimitiveType; import org.eclipse.uml2.uml.TemplateParameter; import org.eclipse.uml2.uml.TemplateableElement; public class TypeUtils { public static TypeFacade _undefined ; public static TypeFacade _integer ; public static TypeFacade _boolean ; public static TypeFacade _unlimited ; public static TypeFacade _natural ; public static TypeFacade _string ; public static TypeFacade _bitString ; public static TypeExpression _nullExpression ; public static TypeFacade _Collection ; public static TypeFacade _Set ; public static TypeFacade _Bag ; public static TypeFacade _Queue ; public static TypeFacade _OrderedSet ; public static TypeFacade _List ; public static TypeFacade _Deque ; public static TypeFacade _Map ; public static TypeFacade _Entry ; public static Map<String, SignatureFacade> predefinedCollectionFunctions ; private SuffixExpression suffixToBeIgnored = null ; public TypeUtils() { } public TypeUtils(SuffixExpression suffixToBeIgnored) { this.suffixToBeIgnored = suffixToBeIgnored ; } public TypeExpression getTypeOfExpression(Expression exp) { return getTypeOfConditionalTestExpression((ConditionalTestExpression)exp) ; } public TypeExpression getTypeOfConditionalTestExpression(ConditionalTestExpression exp) { if (exp.getWhenTrue() != null) { TypeExpression typeOfCondition = getTypeOfConditionalOrExpression(exp.getExp()) ; if (typeOfCondition.getTypeFacade() instanceof ErrorTypeFacade) { ErrorTypeFacade error = (ErrorTypeFacade)typeOfCondition.getTypeFacade() ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } else { if (TypeExpressionFactory.eInstance.createTypeExpression(TypeUtils._boolean).isCompatibleWithMe(typeOfCondition) != 3) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade("An expression of type Boolean is expected. Found an expression of type " + typeOfCondition.getLabel(), exp, AlfPackage.eINSTANCE.getConditionalTestExpression_Exp()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } } TypeExpression typeOfWhenTrue = getTypeOfConditionalTestExpression(exp.getWhenTrue()) ; if (typeOfWhenTrue.getTypeFacade() instanceof ErrorTypeFacade) { ErrorTypeFacade error = (ErrorTypeFacade)typeOfWhenTrue.getTypeFacade() ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } if (exp.getWhenFalse() == null) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade("The \'when false\' alternative is missing", exp, AlfPackage.eINSTANCE.getConditionalTestExpression_WhenFalse()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } else { TypeExpression typeOfWhenFalse = getTypeOfConditionalTestExpression(exp.getWhenFalse()) ; if (typeOfWhenFalse.getTypeFacade() instanceof ErrorTypeFacade) { ErrorTypeFacade error = (ErrorTypeFacade)typeOfWhenFalse.getTypeFacade() ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } else { int falseTrueCompatibility = typeOfWhenFalse.isCompatibleWithMe(typeOfWhenTrue) ; int trueFalseCompatibility = typeOfWhenTrue.isCompatibleWithMe(typeOfWhenFalse) ; if (falseTrueCompatibility == trueFalseCompatibility) { if (falseTrueCompatibility == 0) {// No type compatibility between the two alternatives ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade("The \'when true\' and \'when false\' alternatives must be type compatible", exp, AlfPackage.eINSTANCE.getConditionalTestExpression_WhenTrue()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } else return typeOfWhenTrue ; } else if (falseTrueCompatibility > trueFalseCompatibility) return typeOfWhenFalse ; else // falseTrueCompatibility < trueFalseCompatibility return typeOfWhenTrue ; } } } return getTypeOfConditionalOrExpression((ConditionalOrExpression)exp.getExp()) ; } public TypeExpression getTypeOfConditionalOrExpression(ConditionalOrExpression exp) { if (exp.getExp().size() > 1) { TypeExpression previous = getTypeOfConditionalAndExpression(exp.getExp().get(0)) ; if (previous.getTypeFacade() instanceof ErrorTypeFacade) return previous ; else if (TypeExpressionFactory.eInstance.createTypeExpression(_boolean).isCompatibleWithMe(previous) == 0) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade("Expecting an expression of type Boolean. Found an expression of type " + previous.getLabel(), exp, AlfPackage.eINSTANCE.getConditionalAndExpression_Exp()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } TypeExpression current = null ; for (int i = 1 ; i<exp.getExp().size() ; i++) { List<TypeExpression> argumentTypes = new ArrayList<TypeExpression>() ; argumentTypes.add(previous) ; current = getTypeOfConditionalAndExpression(exp.getExp().get(i)) ; if (current.getTypeFacade() instanceof ErrorTypeFacade) return current ; else if (TypeExpressionFactory.eInstance.createTypeExpression(_boolean).isCompatibleWithMe(current) == 0) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade("Operator || is undefined for (" + previous.getLabel() + ", " + current.getLabel() + ")", exp, AlfPackage.eINSTANCE.getConditionalAndExpression_Exp()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } previous = current ; } return current ; } return getTypeOfConditionalAndExpression((ConditionalAndExpression)exp.getExp().get(0)) ; } public TypeExpression getTypeOfConditionalAndExpression(ConditionalAndExpression exp) { if (exp.getExp().size() > 1) { TypeExpression previous = getTypeOfInclusiveOrExpression(exp.getExp().get(0)) ; if (previous.getTypeFacade() instanceof ErrorTypeFacade) return previous ; else if (TypeExpressionFactory.eInstance.createTypeExpression(_boolean).isCompatibleWithMe(previous) == 0) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade("Expecting an expression of type Boolean. Found an expression of type " + previous.getLabel(), exp, AlfPackage.eINSTANCE.getConditionalAndExpression_Exp()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } TypeExpression current = null ; for (int i = 1 ; i<exp.getExp().size() ; i++) { List<TypeExpression> argumentTypes = new ArrayList<TypeExpression>() ; argumentTypes.add(previous) ; current = getTypeOfInclusiveOrExpression(exp.getExp().get(i)) ; if (current.getTypeFacade() instanceof ErrorTypeFacade) return current ; else if (TypeExpressionFactory.eInstance.createTypeExpression(_boolean).isCompatibleWithMe(current) == 0) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade("Operator && is undefined for (" + previous.getLabel() + ", " + current.getLabel() + ")", exp, AlfPackage.eINSTANCE.getConditionalAndExpression_Exp()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } previous = current ; } return current ; } return getTypeOfInclusiveOrExpression(exp.getExp().get(0)) ; } public TypeExpression getTypeOfInclusiveOrExpression(InclusiveOrExpression exp) { if (exp.getExp().size() > 1) { TypeExpression previous = getTypeOfExclusiveOrExpression(exp.getExp().get(0)) ; if (previous.getTypeFacade() instanceof ErrorTypeFacade) return previous ; TypeExpression current = null ; for (int i = 1 ; i<exp.getExp().size() ; i++) { List<TypeExpression> argumentTypes = new ArrayList<TypeExpression>() ; argumentTypes.add(previous) ; current = getTypeOfExclusiveOrExpression(exp.getExp().get(i)) ; if (current.getTypeFacade() instanceof ErrorTypeFacade) return current ; argumentTypes.add(current) ; List<SignatureFacade> availableSignatures = AlfJavaValidator.predefinedBehaviorsAndTypes.getSignatures("|") ; List<SignatureFacade> applicableSignatures = SignatureFacade.findNearestSignature(argumentTypes, availableSignatures) ; if (applicableSignatures.isEmpty() || applicableSignatures.size()>1 ) { String message = "Operator | is undefined for (" + previous.getLabel() + ", " + current.getLabel() + ")"; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(message, exp, AlfPackage.eINSTANCE.getExclusiveOrExpression_Exp()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } else current = applicableSignatures.get(0).getReturnType() ; previous = current ; } return current ; } return getTypeOfExclusiveOrExpression(exp.getExp().get(0)) ; } public TypeExpression getTypeOfExclusiveOrExpression(ExclusiveOrExpression exp) { if (exp.getExp().size() > 1) { TypeExpression previous = getTypeOfAndExpression(exp.getExp().get(0)) ; if (previous.getTypeFacade() instanceof ErrorTypeFacade) return previous ; TypeExpression current = null ; for (int i = 1 ; i<exp.getExp().size() ; i++) { List<TypeExpression> argumentTypes = new ArrayList<TypeExpression>() ; argumentTypes.add(previous) ; current = getTypeOfAndExpression(exp.getExp().get(i)) ; if (current.getTypeFacade() instanceof ErrorTypeFacade) return current ; argumentTypes.add(current) ; List<SignatureFacade> availableSignatures = AlfJavaValidator.predefinedBehaviorsAndTypes.getSignatures("^") ; List<SignatureFacade> applicableSignatures = SignatureFacade.findNearestSignature(argumentTypes, availableSignatures) ; if (applicableSignatures.isEmpty() || applicableSignatures.size()>1 ) { String message = "Operator ^ is undefined for (" + previous.getLabel() + ", " + current.getLabel() + ")"; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(message, exp, AlfPackage.eINSTANCE.getExclusiveOrExpression_Exp()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } else current = applicableSignatures.get(0).getReturnType() ; previous = current ; } return current ; } return getTypeOfAndExpression(exp.getExp().get(0)) ; } public TypeExpression getTypeOfAndExpression(AndExpression exp) { if (exp.getExp().size() > 1) { TypeExpression previous = getTypeOfEqualityExpression(exp.getExp().get(0)) ; if (previous.getTypeFacade() instanceof ErrorTypeFacade) return previous ; TypeExpression current = null ; for (int i = 1 ; i<exp.getExp().size() ; i++) { List<TypeExpression> argumentTypes = new ArrayList<TypeExpression>() ; argumentTypes.add(previous) ; current = getTypeOfEqualityExpression(exp.getExp().get(i)) ; if (current.getTypeFacade() instanceof ErrorTypeFacade) return current ; argumentTypes.add(current) ; List<SignatureFacade> availableSignatures = AlfJavaValidator.predefinedBehaviorsAndTypes.getSignatures("&") ; List<SignatureFacade> applicableSignatures = SignatureFacade.findNearestSignature(argumentTypes, availableSignatures) ; if (applicableSignatures.isEmpty() || applicableSignatures.size()>1 ) { String message = "Operator & is undefined for (" + previous.getLabel() + ", " + current.getLabel() + ")"; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(message, exp, AlfPackage.eINSTANCE.getAndExpression_Exp()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } else current = applicableSignatures.get(0).getReturnType() ; previous = current ; } return current ; } return getTypeOfEqualityExpression(exp.getExp().get(0)) ; } public TypeExpression getTypeOfEqualityExpression(EqualityExpression exp) { if (exp.getExp().size() > 1) { for (ClassificationExpression classificationExp : exp.getExp()) { TypeExpression argType = getTypeOfClassificationExpression(classificationExp) ; if (argType.getTypeFacade() instanceof ErrorTypeFacade) return argType ; } return TypeExpressionFactory.eInstance.createTypeExpression(_boolean); } return getTypeOfClassificationExpression(exp.getExp().get(0)) ; } public TypeExpression getTypeOfClassificationExpression(ClassificationExpression exp) { if (exp.getOp() != null) { TypeExpression typeOfClassifiedPart = getTypeOfRelationalExpression(exp.getExp()) ; if (typeOfClassifiedPart.getTypeFacade() instanceof ErrorTypeFacade) return typeOfClassifiedPart ; TypeFacade typeOfClassificationPart = TypeFacadeFactory.eInstance.createVoidFacade(exp.getTypeName()) ; if (typeOfClassificationPart instanceof ErrorTypeFacade) return TypeExpressionFactory.eInstance.createTypeExpression(typeOfClassificationPart) ; return TypeExpressionFactory.eInstance.createTypeExpression(_boolean); } return getTypeOfRelationalExpression(exp.getExp()) ; } public TypeExpression getTypeOfRelationalExpression(RelationalExpression exp) { if (exp.getOp() != null) { TypeExpression typeOfLeft = getTypeOfShiftExpression(exp.getLeft()) ; if (typeOfLeft.getTypeFacade() instanceof ErrorTypeFacade) return typeOfLeft ; if (exp.getRight() != null) { TypeExpression typeOfRight = getTypeOfShiftExpression(exp.getRight()) ; if (typeOfRight.getTypeFacade() instanceof ErrorTypeFacade) return typeOfRight ; List<SignatureFacade> availableSignatures = AlfJavaValidator.predefinedBehaviorsAndTypes.getSignatures(exp.getOp()) ; List<TypeExpression> argumentTypes = new ArrayList<TypeExpression>() ; argumentTypes.add(typeOfLeft) ; argumentTypes.add(typeOfRight) ; List<SignatureFacade> applicableSignatures = SignatureFacade.findNearestSignature(argumentTypes, availableSignatures) ; if (applicableSignatures.isEmpty() || applicableSignatures.size()>1) { String message = "Operator " + exp.getOp() + " is undefined for (" + typeOfLeft.getLabel() + ", " + typeOfRight.getLabel() + ")"; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(message, exp, AlfPackage.eINSTANCE.getRelationalExpression_Op()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } else { return applicableSignatures.get(0).getReturnType() ; } } else { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade("Right operand missing", exp, AlfPackage.eINSTANCE.getRelationalExpression_Left()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } } return getTypeOfShiftExpression(exp.getLeft()) ; } public TypeExpression getTypeOfShiftExpression(ShiftExpression exp) { if (exp.getOp() != null) { if (exp.getExp().size() == 2) { TypeExpression typeOfLeft = getTypeOfAdditiveExpression(exp.getExp().get(0)) ; if (typeOfLeft.getTypeFacade() instanceof ErrorTypeFacade) return typeOfLeft ; TypeExpression typeOfRight = getTypeOfAdditiveExpression(exp.getExp().get(1)) ; if (typeOfRight.getTypeFacade() instanceof ErrorTypeFacade) return typeOfRight ; return TypeExpressionFactory.eInstance.createTypeExpression(_bitString); // TODO: rely on PrimitiveBehaviors as soon as AlfLibrary is complete } else if (exp.getExp().size() == 1) { TypeExpression typeOfLeft = getTypeOfAdditiveExpression(exp.getExp().get(0)) ; if (typeOfLeft.getTypeFacade() instanceof ErrorTypeFacade) return typeOfLeft ; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade("Right operand missing", exp, AlfPackage.eINSTANCE.getShiftExpression_Exp()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } } return getTypeOfAdditiveExpression(exp.getExp().get(0)) ; } public TypeExpression getTypeOfAdditiveExpression(AdditiveExpression exp) { if (exp.getExp().size() > 1) { TypeExpression previous = getTypeOfMultiplicativeExpression(exp.getExp().get(0)) ; if (previous.getTypeFacade() instanceof ErrorTypeFacade) return previous ; TypeExpression current = null ; for (int i = 1 ; i<exp.getExp().size() ; i++) { List<TypeExpression> argumentTypes = new ArrayList<TypeExpression>() ; argumentTypes.add(previous) ; current = getTypeOfMultiplicativeExpression(exp.getExp().get(i)) ; if (current.getTypeFacade() instanceof ErrorTypeFacade) return current ; argumentTypes.add(current) ; List<SignatureFacade> availableSignatures = AlfJavaValidator.predefinedBehaviorsAndTypes.getSignatures(exp.getOp().get(i-1)) ; List<SignatureFacade> applicableSignatures = SignatureFacade.findNearestSignature(argumentTypes, availableSignatures) ; if (applicableSignatures.isEmpty() || applicableSignatures.size()>1 ) { String message = "Operator " + exp.getOp().get(i-1) + " is undefined for (" + previous.getLabel() + ", " + current.getLabel() + ")"; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(message, exp, AlfPackage.eINSTANCE.getAdditiveExpression_Exp()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } else current = applicableSignatures.get(0).getReturnType() ; previous = current ; } return current ; } return getTypeOfMultiplicativeExpression(exp.getExp().get(0)) ; } public TypeExpression getTypeOfMultiplicativeExpression(MultiplicativeExpression exp) { if (exp.getExp() == null || exp.getExp().size() == 0) return TypeExpressionFactory.eInstance.createTypeExpression(_undefined) ; if (exp.getExp().size() > 1) { TypeExpression previous = getTypeOfUnaryExpression(exp.getExp().get(0)) ; if (previous.getTypeFacade() instanceof ErrorTypeFacade) return previous ; TypeExpression current = null ; for (int i = 1 ; i<exp.getExp().size() ; i++) { List<TypeExpression> argumentTypes = new ArrayList<TypeExpression>() ; argumentTypes.add(previous) ; current = getTypeOfUnaryExpression(exp.getExp().get(i)) ; if (current.getTypeFacade() instanceof ErrorTypeFacade) return current ; argumentTypes.add(current) ; List<SignatureFacade> availableSignatures = AlfJavaValidator.predefinedBehaviorsAndTypes.getSignatures(exp.getOp().get(i-1)) ; List<SignatureFacade> applicableSignatures = SignatureFacade.findNearestSignature(argumentTypes, availableSignatures) ; if (applicableSignatures.isEmpty() || applicableSignatures.size()>1) { String message = "Operator " + exp.getOp().get(i-1) + " is undefined for (" + previous.getLabel() + ", " + current.getLabel() + ")"; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(message, exp, AlfPackage.eINSTANCE.getMultiplicativeExpression_Exp()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } else current = applicableSignatures.get(0).getReturnType() ; previous = current ; } return current ; } return getTypeOfUnaryExpression(exp.getExp().get(0)) ; } public TypeExpression getTypeOfUnaryExpression(UnaryExpression exp) { TypeExpression typeOfExp = getTypeOfPrimaryExpression(exp.getExp()) ; if (typeOfExp.getTypeFacade() instanceof ErrorTypeFacade) return typeOfExp ; if (exp.getOp() != null) { // '!'|'-'|'+'|'$'|'~' if (exp.getOp().equals("!")) { TypeExpression booleanExpression = TypeExpressionFactory.eInstance.createTypeExpression(_boolean) ; if (booleanExpression.isCompatibleWithMe(typeOfExp) == 0) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "Unrary operator ! does not apply to " + typeOfExp.getLabel(), exp, AlfPackage.eINSTANCE.getUnaryExpression_Op()) ; typeOfExp = TypeExpressionFactory.eInstance.createTypeExpression(error) ; } } else if (exp.getOp().equals("-") || exp.getOp().equals("+")) { TypeExpression integerExpression = TypeExpressionFactory.eInstance.createTypeExpression(_integer) ; TypeExpression naturalExpression = TypeExpressionFactory.eInstance.createTypeExpression(_natural) ; TypeExpression unlimitedExpression = TypeExpressionFactory.eInstance.createTypeExpression(_unlimited) ; if (! (integerExpression.isCompatibleWithMe(typeOfExp)!=0 || naturalExpression.isCompatibleWithMe(typeOfExp) !=0 || unlimitedExpression.isCompatibleWithMe(typeOfExp) !=0)) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "Unary operator " + exp.getOp() + " does not apply to "+ typeOfExp.getLabel(), exp, AlfPackage.eINSTANCE.getUnaryExpression_Op()) ; typeOfExp = TypeExpressionFactory.eInstance.createTypeExpression(error) ; } } else if (exp.getOp().equals("$")) { // Nothing special to do here } else if (exp.getOp().equals("~")) { TypeExpression integerExpression = TypeExpressionFactory.eInstance.createTypeExpression(_integer) ; TypeExpression bitstringExpression = TypeExpressionFactory.eInstance.createTypeExpression(_bitString) ; if (! (integerExpression.isCompatibleWithMe(typeOfExp)!=0 || bitstringExpression.isCompatibleWithMe(typeOfExp) !=0)) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "Unary operator " + exp.getOp() + " does not apply to "+ typeOfExp.getLabel(), exp, AlfPackage.eINSTANCE.getUnaryExpression_Op()) ; typeOfExp = TypeExpressionFactory.eInstance.createTypeExpression(error) ; } } else { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "Undefined unary operator", exp, AlfPackage.eINSTANCE.getUnaryExpression_Op()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } } return typeOfExp ; } public TypeExpression getTypeOfPrimaryExpression(PrimaryExpression exp) { return getTypeOfValueSpecification(exp.getPrefix()) ; } public TypeExpression getTypeOfValueSpecification(ValueSpecification exp) { TypeExpression type = null ; if (exp instanceof NameExpression) type = getTypeOfNameExpression((NameExpression)exp) ; else if (exp instanceof LITERAL) type = getTypeOfLITERAL((LITERAL)exp); else if (exp instanceof ThisExpression) type = getTypeOfThisExpression((ThisExpression)exp); else if (exp instanceof SuperInvocationExpression) type = getTypeOfSuperInvocationExpression((SuperInvocationExpression)exp); else if (exp instanceof InstanceCreationExpression) type = getTypeOfInstanceCreationExpression((InstanceCreationExpression)exp) ; else if (exp instanceof ParenthesizedExpression) type = getTypeOfParenthesizedExpression((ParenthesizedExpression)exp) ; else if (exp instanceof NullExpression) type = getTypeOfNullExpression((NullExpression)exp) ; return type ; } public TypeExpression getTypeOfNullExpression(NullExpression exp) { return TypeUtils._nullExpression ; } public TypeExpression getTypeOfInstanceCreationExpression(InstanceCreationExpression exp) { if (exp.getTuple() != null) { // first try to determine if the expression directly refers to a Class or a DataType try { SignatureFacade s = SignatureFacadeFactory.eInstance.createConstructorFacade(exp) ; if (s.hasReturnType()) { if (exp.getSuffix() != null && exp.getSuffix() != suffixToBeIgnored) { return getTypeOfSuffixExpression(exp.getSuffix(), s.getReturnType()) ; } return s.getReturnType() ; } else { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "Constructor " + exp.getConstructor().getId() + " is illformed (no return type defined)", exp, AlfPackage.eINSTANCE.getInstanceCreationExpression_Constructor()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } } catch (Exception e) { ErrorTypeFacade error = null ; if (e instanceof TypeInferenceException) { TypeInferenceException tie = (TypeInferenceException)e ; error = TypeFacadeFactory.eInstance.createErrorTypeFacade( tie.getErrorMessage(), tie.getErrorSource(), tie.getErrorFeature()) ; } else { error = TypeFacadeFactory.eInstance.createErrorTypeFacade( e.getMessage(), exp, AlfPackage.eINSTANCE.getInstanceCreationExpression_Constructor()) ; } return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } } else { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "An instance creation or sequence creation is expected", exp, AlfPackage.eINSTANCE.getInstanceCreationExpression_Constructor()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } } public TypeExpression getTypeOfSuperInvocationExpression(SuperInvocationExpression exp) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "SuperInvocationExpression are not supported in this version of the Alf editor", exp, AlfPackage.eINSTANCE.getSuperInvocationExpression_OperationName()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } public TypeExpression getTypeOfNonLiteralValueSpecification(NonLiteralValueSpecification exp) { if (exp instanceof NameExpression) return getTypeOfNameExpression((NameExpression)exp) ; if (exp instanceof ThisExpression) return getTypeOfThisExpression((ThisExpression)exp); if (exp instanceof SuperInvocationExpression) return getTypeOfSuperInvocationExpression((SuperInvocationExpression)exp) ; if (exp instanceof InstanceCreationExpression) return getTypeOfInstanceCreationExpression((InstanceCreationExpression)exp) ; if (exp instanceof ParenthesizedExpression) return getTypeOfParenthesizedExpression((ParenthesizedExpression)exp) ; return null ; } public TypeExpression getTypeOfLITERAL(LITERAL exp) { TypeFacade t = _undefined ; if (exp instanceof BOOLEAN_LITERAL) t = _boolean ; else if (exp instanceof STRING_LITERAL) t = _string ; else if (exp instanceof INTEGER_LITERAL) t = _integer ; else if (exp instanceof UNLIMITED_LITERAL) t = _unlimited ; return TypeExpressionFactory.eInstance.createTypeExpression(t) ; } public TypeExpression getTypeOfParenthesizedExpression(ParenthesizedExpression exp) { if (exp.getCasted() != null) // && exp.getSuffix() == null) return getTypeOfCastExpression(exp) ; TypeExpression typeOfParenthesizedExpression = getTypeOfExpression((Expression)exp.getExpOrTypeCast()) ; if (typeOfParenthesizedExpression.getTypeFacade() instanceof ErrorTypeFacade) { return typeOfParenthesizedExpression ; } if (exp.getSuffix() != null && exp.getSuffix() != suffixToBeIgnored) return getTypeOfSuffixExpression(exp.getSuffix(), typeOfParenthesizedExpression) ; return typeOfParenthesizedExpression ; } protected TypeExpression getTypeOfCastExpression(ParenthesizedExpression exp) { TypeExpression typeOfCastedPart = getTypeOfNonLiteralValueSpecification(exp.getCasted()) ; if (typeOfCastedPart.getTypeFacade() instanceof ErrorTypeFacade) return typeOfCastedPart ; TypeFacade castingTypeFacade = TypeFacadeFactory.eInstance.createVoidFacade(exp.getExpOrTypeCast()) ; TypeExpression result = new TypeExpression() ; result.setType(castingTypeFacade) ; result.setMultiplicity(typeOfCastedPart.getMultiplicity()) ; return result ; } protected boolean isACastExpression(NameExpression exp) { EObject container = exp.eContainer() ; EObject cddCastingPart = exp ; while (container != null && ! (container instanceof ParenthesizedExpression)) { cddCastingPart = container ; container = container.eContainer() ; } if (container == null) return false ; else { ParenthesizedExpression cddCastExpression = (ParenthesizedExpression)container ; if (cddCastingPart.eContainingFeature() == AlfPackage.eINSTANCE.getParenthesizedExpression_ExpOrTypeCast()) return cddCastExpression.getCasted() != null ; else return false ; } } public TypeExpression getTypeOfNameExpression(NameExpression exp) { // //if (exp.eContainer() instanceof ClassificationExpression || // exp.eContainer() instanceof SuperInvocationExpression || // exp.eContainer() instanceof InvocationOrAssignementOrDeclarationStatement || // isACastExpression(exp)) { // return TypeExpressionFactory.eInstance.createTypeExpression(_undefined); //} EObject previousPackage = null ; if (exp.getPath() != null) { List<UnqualifiedName> path = exp.getPath().getNamespace() ; // first resolves the first element of the path List<EObject> visiblePackages = AlfScopeProvider.scopingTool.getVisiblePackages(exp).resolveByName(path.get(0).getName()) ; if (visiblePackages.isEmpty()) { // Try to find a classifier List<EObject> visibleClassifiers = AlfScopeProvider.scopingTool.getVisibleClassifiers(exp).resolveByName(path.get(0).getName()) ; if (visibleClassifiers.isEmpty()) { // No classifier found ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade("Could not resolve package " + path.get(0).getName(), path.get(0), AlfPackage.eINSTANCE.getUnqualifiedName_Name()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } else if (visibleClassifiers.size() > 1) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(path.get(0).getName() + " resolves to multiple classifiers", exp.getPath(), AlfPackage.eINSTANCE.getQualifiedNamePath_Namespace()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } else { // Then walks through the path, which shall contain only references to (nested) classifiers List<EObject> nestedVisibleClassifiers ; EObject previousClassifier = visibleClassifiers.get(0) ; for (int i = 1 ; i<path.size() ; i++) { nestedVisibleClassifiers = AlfScopeProvider.scopingTool.getVisibleClassifiers(previousClassifier).resolveByName(path.get(i).getName()) ; if (nestedVisibleClassifiers.isEmpty()) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade("Could not resolve classifier " + path.get(i).getName(), path.get(i), AlfPackage.eINSTANCE.getUnqualifiedName_Name()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } else if (nestedVisibleClassifiers.size() > 1) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(path.get(i).getName() + " resolves to multiple classifiers", exp.getPath(), AlfPackage.eINSTANCE.getQualifiedNamePath_Namespace()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } previousClassifier = nestedVisibleClassifiers.get(0) ; } // TODO : Check if this is reasonable => We make the assumption than the final id can only be a reference to an enumeration if (previousClassifier instanceof Enumeration) { List<EObject> visibleEnumerationLiterals = AlfScopeProvider.scopingTool.getVisibleEnumerationLiterals(previousClassifier).resolveByName(exp.getId()) ; if (visibleEnumerationLiterals.isEmpty()) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade("Could not resolve enumeration literal " + exp.getId(), exp, AlfPackage.eINSTANCE.getNameExpression_Id()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } else if (visibleEnumerationLiterals.size() > 1) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(exp.getId() + " resolves to multiple enumeration literals", exp, AlfPackage.eINSTANCE.getNameExpression_Id()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } else { return TypeExpressionFactory.eInstance.createTypeExpression(previousClassifier) ; } } else { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(path.get(path.size()-1).getName() + " does not resolve to an enumeration", exp.getPath(), AlfPackage.eINSTANCE.getQualifiedNamePath_Namespace()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } } } else if (visiblePackages.size() > 1) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(path.get(0).getName() + " resolves to multiple packages", exp.getPath(), AlfPackage.eINSTANCE.getQualifiedNamePath_Namespace()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } else { List<EObject> nestedVisiblePackages ; previousPackage = visiblePackages.get(0) ; for (int i = 1 ; i<path.size() ; i++) { nestedVisiblePackages = AlfScopeProvider.scopingTool.getVisiblePackages(previousPackage).resolveByName(path.get(i).getName()) ; if (nestedVisiblePackages.isEmpty()) { // Try to find a classifier List<EObject> visibleClassifiers = AlfScopeProvider.scopingTool.getVisibleClassifiers(exp).resolveByName(path.get(i).getName()) ; if (visibleClassifiers.isEmpty()) { // No classifier found ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade("Could not resolve package " + path.get(i).getName(), path.get(i), AlfPackage.eINSTANCE.getUnqualifiedName_Name()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } else if (visibleClassifiers.size() > 1) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(path.get(0).getName() + " resolves to multiple classifiers", exp.getPath(), AlfPackage.eINSTANCE.getQualifiedNamePath_Namespace()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } else { // Then walks through the path, which shall contain only references to (nested) classifiers List<EObject> nestedVisibleClassifiers ; EObject previousClassifier = visibleClassifiers.get(0) ; for (int j = i ; j<path.size() ; j++) { nestedVisibleClassifiers = AlfScopeProvider.scopingTool.getVisibleClassifiers(previousClassifier).resolveByName(path.get(j).getName()) ; if (nestedVisibleClassifiers.isEmpty()) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade("Could not resolve classifier " + path.get(j).getName(), path.get(j), AlfPackage.eINSTANCE.getUnqualifiedName_Name()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } else if (nestedVisibleClassifiers.size() > 1) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(path.get(j).getName() + " resolves to multiple classifiers", exp.getPath(), AlfPackage.eINSTANCE.getQualifiedNamePath_Namespace()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } previousClassifier = nestedVisibleClassifiers.get(0) ; } // TODO : Check if this is reasonable => We make the assumption than the final id can only be a reference to an enumeration if (previousClassifier instanceof Enumeration) { List<EObject> visibleEnumerationLiterals = AlfScopeProvider.scopingTool.getVisibleEnumerationLiterals(previousClassifier).resolveByName(exp.getId()) ; if (visibleEnumerationLiterals.isEmpty()) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade("Could not resolve enumeration literal " + exp.getId(), exp, AlfPackage.eINSTANCE.getNameExpression_Id()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } else if (visibleEnumerationLiterals.size() > 1) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(exp.getId() + " resolves to multiple enumeration literals", exp, AlfPackage.eINSTANCE.getNameExpression_Id()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } else { return TypeExpressionFactory.eInstance.createTypeExpression(previousClassifier) ; } } else { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(path.get(path.size()-1).getName() + " does not resolve to an enumeration", exp.getPath(), AlfPackage.eINSTANCE.getQualifiedNamePath_Namespace()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } } } else if (nestedVisiblePackages.size() > 1) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(path.get(i).getName() + " resolves to multiple packages", exp.getPath(), AlfPackage.eINSTANCE.getQualifiedNamePath_Namespace()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } previousPackage = nestedVisiblePackages.get(0) ; } } } // TODO handle the case of a sequence construction expression TypeExpression typeOfPrefix = null ; if (exp.getPath() == null) { if (exp.getInvocationCompletion()==null) { // && exp.getSequenceConstructionCompletion() == null) { List<EObject> visibleVariableOrParametersOrProperties = AlfScopeProvider.scopingTool.getVisibleVariablesOrParametersOrProperties(exp).resolveByName(exp.getId()) ; if (visibleVariableOrParametersOrProperties.isEmpty()) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "Could not resolve local variable, property or parameter " + exp.getId(), exp, AlfPackage.eINSTANCE.getNameExpression_Id()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } else if (visibleVariableOrParametersOrProperties.size()>1) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( exp.getId() + " resolves to multiple elements", exp, AlfPackage.eINSTANCE.getNameExpression_Id()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } else { EObject resolved = visibleVariableOrParametersOrProperties.get(0) ; typeOfPrefix = TypeExpressionFactory.eInstance.createTypeExpression(resolved) ; } } } else { // TODO: Handle associations here ? // TODO: Handle ClassExtent here ? } if (exp.getInvocationCompletion()!=null ) { //&& exp.getSequenceConstructionCompletion() == null ) { List<TypeExpression> arguments = new ArrayList<TypeExpression>() ; for (TupleElement e : exp.getInvocationCompletion().getTupleElements()) { TypeExpression type = getTypeOfExpression(e.getArgument()) ; if (type.getTypeFacade() != null && type.getTypeFacade() instanceof ErrorTypeFacade) return type ; arguments.add(type) ; } List<EObject> visibleOperationOrBehaviors = AlfScopeProvider.scopingTool.getVisibleOperationsOrBehaviors(previousPackage != null ? previousPackage : exp).resolveByName(exp.getId()) ; if (visibleOperationOrBehaviors.isEmpty()) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "Could not resolve operation or behavior " + exp.getId(), exp, AlfPackage.eINSTANCE.getNameExpression_Id()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } else if (visibleOperationOrBehaviors.size()>1) { List<SignatureFacade> availableSignatures = new ArrayList<SignatureFacade>() ; for (EObject operation : visibleOperationOrBehaviors) { availableSignatures.add(SignatureFacadeFactory.eInstance.createSignatureFacade(operation)) ; } List<SignatureFacade> selectedSignatures = SignatureFacade.findNearestSignature(arguments, availableSignatures) ; if (selectedSignatures.size() > 1) { // could not infer the actual operations even with type of arguments ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( exp.getId() + " resolves to multiple elements", exp, AlfPackage.eINSTANCE.getNameExpression_Id()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } else if (selectedSignatures.size() == 0) { String errorMessage = exp.getId() + " does not apply to arguments (" ; boolean first = true ; for (TypeExpression argType : arguments) { if (!first) errorMessage += ", " ; else first = false ; errorMessage += argType.getLabel() ; } errorMessage += ")" ; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( errorMessage, exp, AlfPackage.eINSTANCE.getNameExpression_Id()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } else { typeOfPrefix = selectedSignatures.get(0).getReturnType() ; } } else { SignatureFacade operationOrBehaviorSignature = SignatureFacadeFactory.eInstance.createSignatureFacade(visibleOperationOrBehaviors.get(0)) ; String argumentsAreCompatible = operationOrBehaviorSignature.isCompatibleWithMe(arguments, true) ; if (! (argumentsAreCompatible.length() == 0)) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( argumentsAreCompatible, exp, AlfPackage.eINSTANCE.getNameExpression_InvocationCompletion()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } typeOfPrefix = operationOrBehaviorSignature.getReturnType() ; } } if (exp.getSequenceConstructionCompletion() != null) { SequenceConstructionOrAccessCompletion sequenceAccessOrConstruction = exp.getSequenceConstructionCompletion() ; if (sequenceAccessOrConstruction.getAccessCompletion() != null) { int prefixUpperBound = typeOfPrefix.getMultiplicity().getUpperBound() ; boolean prefixIsOrdered = typeOfPrefix.getMultiplicity().isOrdered() ; if (! (prefixUpperBound == -1 || prefixUpperBound > 1)) { String errorMessage = "Unexpected index. " + exp.getId() + " is not a collection." ; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( errorMessage, exp, AlfPackage.eINSTANCE.getNameExpression_SequenceConstructionCompletion()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } else if (!prefixIsOrdered){ String errorMessage = "Unexpected index. " + exp.getId() + " is not ordered." ; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( errorMessage, exp, AlfPackage.eINSTANCE.getNameExpression_SequenceConstructionCompletion()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } TypeExpression typeOfIndex = getTypeOfExpression(sequenceAccessOrConstruction.getAccessCompletion().getAccessIndex()) ; if (typeOfIndex.getTypeFacade() instanceof ErrorTypeFacade) { return typeOfIndex ; } else if (! (_integer.isCompatibleWithMe(typeOfIndex.getTypeFacade())== 3 || _natural.isCompatibleWithMe(typeOfIndex.getTypeFacade())==3)) { String errorMessage = "Expecting an expression of type Integer. Found an expression of type " + typeOfIndex.getLabel() ; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( errorMessage, sequenceAccessOrConstruction, AlfPackage.eINSTANCE.getAccessCompletion_AccessIndex()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } else { // need to change the multiplicity of typeOfPrefix //typeOfPrefix.setMultiplicity(MultiplicityFacadeFactory.eInstance.createMultiplicityFacade(0, 1, false, false)) ; typeOfPrefix.setMultiplicity(MultiplicityFacadeFactory.eInstance.createMultiplicityFacade(1, 1, false, false)) ; // TODO: 1..1 is temporary } } } if (exp.getSuffix() != null && exp.getSuffix() != suffixToBeIgnored) { return getTypeOfSuffixExpression(exp.getSuffix(), typeOfPrefix) ; } return typeOfPrefix ; } public TypeExpression getTypeOfThisExpression(ThisExpression exp) { TypeExpression typeOfPrefix = TypeExpressionFactory.eInstance.createTypeExpression(AlfJavaValidator.getContextClassifier()) ; if (typeOfPrefix.getTypeFacade() instanceof ErrorTypeFacade) return typeOfPrefix ; if (exp.getSuffix() != null && exp.getSuffix() != suffixToBeIgnored) { return getTypeOfSuffixExpression(exp.getSuffix(), typeOfPrefix) ; } return typeOfPrefix ; } public TypeExpression getTypeOfSuffixExpression(SuffixExpression exp, TypeExpression propagatedTypeOfPrefix) { // TODO: Support all cases EObject source = exp.eContainer() ; EStructuralFeature containtFeature = exp.eContainingFeature() ; /////////////////////////// TypeExpression typeOfPrefix = propagatedTypeOfPrefix ; if (typeOfPrefix == null) { String errorMessage = "Type of prefix is undefined. Could not validate suffix." ; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, source, containtFeature) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } else if (typeOfPrefix.getTypeFacade() == TypeUtils._undefined) { String errorMessage = "The invocation prefix has no return parameter." ; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, source, containtFeature) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } // If the of prefix is of multiplicity 1 and if it has an operation toSequence (i.e., it is a collection class) // Then, depending on the kind of suffix, it may be necessary to propagate a sequence has the prefix type if (typeOfPrefix.getMultiplicity().getUpperBound() == 1 && (exp instanceof SequenceOperationExpression || exp instanceof SelectOrRejectOperation // || exp.getSuffix() instanceof ... TODO )) { Classifier actualPrefixType = typeOfPrefix.getTypeFacade().extractActualType() ; if( actualPrefixType != null) { Operation toSequenceOperation = null ; for (int i = 0 ; i<actualPrefixType.getAllOperations().size() && toSequenceOperation == null ; i++) { Operation o = actualPrefixType.getAllOperations().get(i) ; if (o.getName().equals("toSequence")) toSequenceOperation = o ; } if (toSequenceOperation != null) { typeOfPrefix = TypeExpressionFactory.eInstance.createTypeExpression(toSequenceOperation.getReturnResult()) ; } } } if (exp instanceof ClassExtentExpression) { // TODO String errorMessage = "Class extent expressions are not supported in this version of the Alf editor" ; ErrorTypeFacade unsupportedCase = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, source, containtFeature) ; return TypeExpressionFactory.eInstance.createTypeExpression(unsupportedCase) ; } else if (exp instanceof LinkOperationExpression) { // TODO String errorMessage = "Link operation expressions are not supported in this version of the Alf editor" ; ErrorTypeFacade unsupportedCase = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, source, containtFeature) ; return TypeExpressionFactory.eInstance.createTypeExpression(unsupportedCase) ; } else if (exp instanceof OperationCallExpression) { return getTypeOfOperationCallExpression((OperationCallExpression)exp, typeOfPrefix) ; } else if (exp instanceof PropertyCallExpression) { return getTypeOfPropertyCallExpression((PropertyCallExpression)exp, typeOfPrefix) ; } else if (exp instanceof SequenceExpansionExpression) { return getTypeOfSequenceExpansionExpression((SequenceExpansionExpression) exp, typeOfPrefix) ; } else if (exp instanceof SequenceOperationExpression) { return getTypeOfSequenceOperationExpression((SequenceOperationExpression)exp, typeOfPrefix) ; } else {// exp instanceof SequenceReductionExpression return getTypeOfSequenceReductionExpression((SequenceReductionExpression) exp, typeOfPrefix) ; } } public TypeExpression getTypeOfSequenceOperationExpression(SequenceOperationExpression exp, TypeExpression typeOfPrefix) { if (exp.getOperationName() == null) { String errorMessage = "Sequence function is missing" ; ErrorTypeFacade unsupportedCase = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, exp, AlfPackage.eINSTANCE.getSequenceOperationExpression_OperationName()) ; return TypeExpressionFactory.eInstance.createTypeExpression(unsupportedCase) ; } // first tries to resolve the behavior name SignatureFacade s = null ; TypeFacade cddBehaviorFacade = TypeFacadeFactory.eInstance.createVoidFacade(exp.getOperationName()) ; if (cddBehaviorFacade instanceof ErrorTypeFacade) { // the behavior has not been found using default strategies. // Tries to find it in predefined collection functions s = TypeUtils.predefinedCollectionFunctions.get(exp.getOperationName().getId()) ; if (s == null) { return TypeExpressionFactory.eInstance.createTypeExpression(cddBehaviorFacade) ; // EObject source = exp.eContainer() ; // EStructuralFeature containingFeature = exp.eContainingFeature() ; // String errorMessage = "Could not resolve collection function " + exp.getOperationName().getId() ; // ErrorTypeFacade unsupportedCase = // TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, source, containingFeature) ; // return TypeExpressionFactory.eInstance.createTypeExpression(unsupportedCase) ; } } else { Classifier cddBehavior = cddBehaviorFacade.extractActualType() ; if (! (cddBehavior instanceof Behavior)) { String errorMessage = cddBehavior.getName() + " does not resolve to a Behavior" ; ErrorTypeFacade unsupportedCase = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, exp, AlfPackage.eINSTANCE.getSequenceOperationExpression_OperationName()) ; return TypeExpressionFactory.eInstance.createTypeExpression(unsupportedCase) ; } else { s = SignatureFacadeFactory.eInstance.createSignatureFacade(cddBehavior) ; } } // if (s.isATemplate()) { // // A binding needs to be done, with the type of the prefix as an actual. // Map<TemplateParameter, ParameterableElement> substitutions = new HashMap<TemplateParameter, ParameterableElement>() ; // for (TemplateParameter tp : ((TemplateableElement)s.getActualSignatureObject()).getOwnedTemplateSignature().getOwnedParameters()) { // substitutions.put(tp,typeOfPrefix.getTypeFacade().extractActualType()) ; // } // String sLabelInCaseOfErrorInBinding = "" + s.getLabel() ; // s = s.bindTemplate(substitutions) ; // if (s == null) { // a problem occurred with binding // EObject source = exp.eContainer() ; // EStructuralFeature containtFeature = exp.eContainingFeature() ; // String errorMessage = "Could not implicitly bind behavior " + sLabelInCaseOfErrorInBinding + " with actual parameter " + typeOfPrefix.getTypeFacade().getLabel() ; // ErrorTypeFacade unsupportedCase = // TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, source, containtFeature) ; // return TypeExpressionFactory.eInstance.createTypeExpression(unsupportedCase) ; // } // } // The signature has been resolved. // Needs to determine if this is a valid signature. i.e. must have its first parameter with direction in or inout, and multiplicity * if (s.getParameters().isEmpty()) { EObject source = exp.eContainer() ; EStructuralFeature containtFeature = exp.eContainingFeature() ; String errorMessage = "Invalid sequence function. Should at least one in or inout parameter with multiplicity *" ; ErrorTypeFacade unsupportedCase = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, source, containtFeature) ; return TypeExpressionFactory.eInstance.createTypeExpression(unsupportedCase) ; } Behavior sequenceFunction = (Behavior)s.getActualSignatureObject() ; Parameter firstParameter = sequenceFunction.getOwnedParameters().get(0) ; if (((firstParameter.getDirection()!= ParameterDirectionKind.IN_LITERAL) && (firstParameter.getDirection() != ParameterDirectionKind.INOUT_LITERAL)) || firstParameter.getUpper() != -1) { EObject source = exp.eContainer() ; EStructuralFeature containtFeature = exp.eContainingFeature() ; String errorMessage = "Invalid sequence function. The first parameter should have direction in or inout, with multiplicity *" ; ErrorTypeFacade unsupportedCase = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, source, containtFeature) ; return TypeExpressionFactory.eInstance.createTypeExpression(unsupportedCase) ; } // Then determines if arguments match parameters of the signature List<TypeExpression> arguments = new ArrayList<TypeExpression>() ; arguments.add(typeOfPrefix) ; for (TupleElement e : exp.getTuple().getTupleElements()) { TypeExpression argType = getTypeOfExpression(e.getArgument()) ; if (argType.getTypeFacade() != null && argType.getTypeFacade() instanceof ErrorTypeFacade) return argType ; arguments.add(argType) ; } String argumentsAreCompatible = s.isCompatibleWithMe(arguments, true) ; if (! (argumentsAreCompatible.length() == 0)) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( argumentsAreCompatible, exp, AlfPackage.eINSTANCE.getSequenceOperationExpression_OperationName()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } TypeExpression typeOfSuffix = s.getReturnType() ; if (exp.getSuffix() != null) { return this.getTypeOfSuffixExpression(exp.getSuffix(), typeOfSuffix) ; } return typeOfSuffix ; } public TypeExpression getTypeOfSequenceReductionExpression(SequenceReductionExpression exp, TypeExpression typeOfPrefix) { int upperBoundOfPrefix = typeOfPrefix.getMultiplicityFacade().getUpperBound() ; // first check if the prefix is a collection if (!(upperBoundOfPrefix > 1) && upperBoundOfPrefix != -1) { EObject source = exp.eContainer() ; EStructuralFeature containtFeature = exp.eContainingFeature() ; String errorMessage = "Prefix must be a collection" ; ErrorTypeFacade unsupportedCase = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, source, containtFeature) ; return TypeExpressionFactory.eInstance.createTypeExpression(unsupportedCase) ; } if (exp.getBehavior() == null) { String errorMessage = "Reduction behavior is missing" ; ErrorTypeFacade unsupportedCase = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, exp, AlfPackage.eINSTANCE.getSequenceReductionExpression_Behavior()) ; return TypeExpressionFactory.eInstance.createTypeExpression(unsupportedCase) ; } // first tries to resolve the behavior name TypeFacade cddBehaviorFacade = TypeFacadeFactory.eInstance.createVoidFacade(exp.getBehavior()) ; if (cddBehaviorFacade instanceof ErrorTypeFacade) return TypeExpressionFactory.eInstance.createTypeExpression(cddBehaviorFacade) ; Classifier cddBehavior = cddBehaviorFacade.extractActualType() ; if (! (cddBehavior instanceof Behavior)) { String errorMessage = cddBehavior.getName() + " does not resolve to a Behavior" ; ErrorTypeFacade unsupportedCase = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, exp, AlfPackage.eINSTANCE.getSequenceReductionExpression_Behavior()) ; return TypeExpressionFactory.eInstance.createTypeExpression(unsupportedCase) ; } Behavior behavior = (Behavior)cddBehavior ; // check that the behavior is a valid reduction behavior // i.e., it has exactly two in parameters and one return parameter, all with multiplicity 1 int n_inputParameters = 0 ; boolean invalidReductionBehavior = false ; boolean returnParameterFound = false ; Classifier paramsType = null ; for (int i = 0 ; i < behavior.getOwnedParameters().size() && !invalidReductionBehavior ; i++) { Parameter p = behavior.getOwnedParameters().get(i) ; switch (p.getDirection()) { case IN_LITERAL: n_inputParameters++ ; if (n_inputParameters > 2) { invalidReductionBehavior = true ; break ; } if (p.getLower() != 1 || p.getUpper() != 1) { invalidReductionBehavior = true ; break ; } if (paramsType == null) { paramsType = (Classifier)p.getType() ; if (paramsType == null) invalidReductionBehavior = true ; } else { if (paramsType != ((Classifier)p.getType())) invalidReductionBehavior = true ; } break; case INOUT_LITERAL: invalidReductionBehavior = true ; break; case OUT_LITERAL: invalidReductionBehavior = true ; break; case RETURN_LITERAL: returnParameterFound = true ; if (p.getLower() != 1 || p.getUpper() != 1) { invalidReductionBehavior = true ; break ; } if (paramsType == null) { paramsType = (Classifier)p.getType() ; if (paramsType == null) invalidReductionBehavior = true ; } else { if (paramsType != ((Classifier)p.getType())) invalidReductionBehavior = true ; } break; } } SignatureFacade behaviorFacade = SignatureFacadeFactory.eInstance.createSignatureFacade(behavior) ; if (! (!invalidReductionBehavior && returnParameterFound)) { String errorMessage = behaviorFacade.getLabel() + " is not a valid reduction behavior. It should have exactly two in parameters, one return parameter, all with multiplicity [1..1], and all with the same type." ; ErrorTypeFacade unsupportedCase = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, exp, AlfPackage.eINSTANCE.getSequenceReductionExpression_Behavior()) ; return TypeExpressionFactory.eInstance.createTypeExpression(unsupportedCase) ; } // The signature is valid. Finally needs to determine if the type of the elements in the collection is compatible with the type of the parameters if (TypeFacadeFactory.eInstance.createTypeFacade(paramsType).isCompatibleWithMe(typeOfPrefix.getTypeFacade()) == 0) { String errorMessage = behaviorFacade.getLabel() + " does not apply to arguments of type " + typeOfPrefix.getTypeFacade().getLabel() ; ErrorTypeFacade unsupportedCase = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, exp, AlfPackage.eINSTANCE.getSequenceReductionExpression_Behavior()) ; return TypeExpressionFactory.eInstance.createTypeExpression(unsupportedCase) ; } TypeExpression typeOfExpression = TypeExpressionFactory.eInstance.createTypeExpression(typeOfPrefix.getTypeFacade()) ; if (exp.getSuffix() != null && exp.getSuffix() != suffixToBeIgnored) return getTypeOfSuffixExpression(exp.getSuffix(), typeOfExpression) ; return typeOfExpression ; } public TypeExpression getTypeOfSequenceExpansionExpression(SequenceExpansionExpression exp, TypeExpression typeOfPrefix) { if (exp instanceof SelectOrRejectOperation) { return getTypeOfSelectOrRejectOperation((SelectOrRejectOperation)exp, typeOfPrefix) ; } else if (exp instanceof CollectOrIterateOperation) { return getTypeOfCollectOrIterateOperation((CollectOrIterateOperation)exp, typeOfPrefix) ; } else if (exp instanceof ForAllOrExistsOrOneOperation) { return getTypeOfForAllOrExistsOrOneOperation((ForAllOrExistsOrOneOperation)exp, typeOfPrefix) ; } else { // exp instanceof IsUniqueOperation return getTypeOfIsUniqueOperation((IsUniqueOperation)exp, typeOfPrefix) ; } } private TypeExpression getTypeOfIsUniqueOperation(IsUniqueOperation exp, TypeExpression typeOfPrefix) { if (exp.getName() == null) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "Local variable definition is missing", exp, AlfPackage.eINSTANCE.getSequenceExpansionExpression_Name()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } // first check that the local variable name is not already used if (! AlfScopeProvider.scopingTool.getVisibleVariablesOrParametersOrProperties(exp.eContainer()).resolveByName(exp.getName()).isEmpty()) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "Local name " + exp.getName() + " is not available", exp, AlfPackage.eINSTANCE.getSequenceExpansionExpression_Name()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } TypeExpression typeOfCondition = getTypeOfExpression(exp.getExpr()) ; if (typeOfCondition.getTypeFacade() instanceof ErrorTypeFacade) return typeOfCondition ; int upperBound = typeOfCondition.getMultiplicity().getUpperBound() ; if (upperBound == 0) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "Expression must be typed", exp, AlfPackage.eINSTANCE.getSequenceExpansionExpression_Expr()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } TypeExpression typeOfExpression = TypeExpressionFactory.eInstance.createTypeExpression(TypeUtils._boolean) ; if (exp.getSuffix() != null && exp.getSuffix() != suffixToBeIgnored) return getTypeOfSuffixExpression(exp.getSuffix(), typeOfExpression) ; return typeOfExpression ; } private TypeExpression getTypeOfForAllOrExistsOrOneOperation(ForAllOrExistsOrOneOperation exp, TypeExpression typeOfPrefix) { if (exp.getName() == null) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "Local variable definition is missing", exp, AlfPackage.eINSTANCE.getSequenceExpansionExpression_Name()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } // first check that the local variable name is not already used if (! AlfScopeProvider.scopingTool.getVisibleVariablesOrParametersOrProperties(exp.eContainer()).resolveByName(exp.getName()).isEmpty()) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "Local name " + exp.getName() + " is not available", exp, AlfPackage.eINSTANCE.getSequenceExpansionExpression_Name()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } TypeExpression typeOfCondition = getTypeOfExpression(exp.getExpr()) ; if (typeOfCondition.getTypeFacade() instanceof ErrorTypeFacade) return typeOfCondition ; if (TypeExpressionFactory.eInstance.createTypeExpression(TypeUtils._boolean).isCompatibleWithMe(typeOfCondition) == 0) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "Expecting an expression of type Boolean. Found an expression of type " + typeOfCondition.getLabel(), exp, AlfPackage.eINSTANCE.getSequenceExpansionExpression_Expr()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } TypeExpression typeOfExpression = TypeExpressionFactory.eInstance.createTypeExpression(TypeUtils._boolean) ; if (exp.getSuffix() != null && exp.getSuffix() != suffixToBeIgnored) return getTypeOfSuffixExpression(exp.getSuffix(), typeOfExpression) ; return typeOfExpression ; } private TypeExpression getTypeOfCollectOrIterateOperation(CollectOrIterateOperation exp, TypeExpression typeOfPrefix) { if (exp.getName() == null) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "Local variable definition is missing", exp, AlfPackage.eINSTANCE.getSequenceExpansionExpression_Name()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } // first check that the local variable name is not already used if (! AlfScopeProvider.scopingTool.getVisibleVariablesOrParametersOrProperties(exp.eContainer()).resolveByName(exp.getName()).isEmpty()) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "Local name " + exp.getName() + " is not available", exp, AlfPackage.eINSTANCE.getSequenceExpansionExpression_Name()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } TypeExpression typeOfCondition = getTypeOfExpression(exp.getExpr()) ; if (typeOfCondition.getTypeFacade() instanceof ErrorTypeFacade) return typeOfCondition ; int lowerBound = typeOfPrefix.getMultiplicity().getLowerBound() * typeOfCondition.getMultiplicity().getLowerBound() ; int upperBound = typeOfPrefix.getMultiplicity().getUpperBound() * typeOfCondition.getMultiplicity().getUpperBound() ; lowerBound = lowerBound < 0 ? -1 : lowerBound ; upperBound = upperBound < 0 ? -1 : upperBound ; if (upperBound == 0) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "Expression must be typed", exp, AlfPackage.eINSTANCE.getSequenceExpansionExpression_Expr()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } TypeExpression typeOfExpression = TypeExpressionFactory.eInstance.createTypeExpression(typeOfCondition.getTypeFacade()) ; typeOfExpression.setMultiplicity( MultiplicityFacadeFactory.eInstance.createMultiplicityFacade( lowerBound, // Lower bound upperBound, // Upper bound typeOfPrefix.getMultiplicity().isUnique(), // is unique typeOfPrefix.getMultiplicity().isOrdered())) ; // is ordered if (exp.getSuffix() != null && exp.getSuffix() != suffixToBeIgnored) return getTypeOfSuffixExpression(exp.getSuffix(), typeOfExpression) ; return typeOfExpression ; } private TypeExpression getTypeOfSelectOrRejectOperation(SelectOrRejectOperation exp, TypeExpression typeOfPrefix) { if (exp.getName() == null) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "Local variable definition is missing", exp, AlfPackage.eINSTANCE.getSequenceExpansionExpression_Name()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } // first check that the local variable name is not already used if (! AlfScopeProvider.scopingTool.getVisibleVariablesOrParametersOrProperties(exp.eContainer()).resolveByName(exp.getName()).isEmpty()) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "Local name " + exp.getName() + " is not available", exp, AlfPackage.eINSTANCE.getSequenceExpansionExpression_Name()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } TypeExpression typeOfCondition = getTypeOfExpression(exp.getExpr()) ; if (typeOfCondition.getTypeFacade() instanceof ErrorTypeFacade) return typeOfCondition ; if (TypeExpressionFactory.eInstance.createTypeExpression(TypeUtils._boolean).isCompatibleWithMe(typeOfCondition) == 0) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( "Expecting an expression of type Boolean. Found an expression of type " + typeOfCondition.getLabel(), exp, AlfPackage.eINSTANCE.getSequenceExpansionExpression_Expr()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } TypeExpression typeOfExpression = TypeExpressionFactory.eInstance.createTypeExpression(typeOfPrefix.getTypeFacade()) ; typeOfExpression.setMultiplicity( MultiplicityFacadeFactory.eInstance.createMultiplicityFacade( 0, // Lower bound typeOfPrefix.getMultiplicity().getUpperBound(), // Upper bound typeOfPrefix.getMultiplicity().isUnique(), // is unique typeOfPrefix.getMultiplicity().isOrdered())) ; // is ordered if (exp.getSuffix() != null && exp.getSuffix() != suffixToBeIgnored) return getTypeOfSuffixExpression(exp.getSuffix(), typeOfExpression) ; return typeOfExpression ; } public TypeExpression getTypeOfPropertyCallExpression(PropertyCallExpression exp, TypeExpression typeOfPrefix) { Classifier type = typeOfPrefix.getTypeFacade().extractActualType() ; EObject source = exp.eContainer() ; EStructuralFeature containtFeature = exp.eContainingFeature() ; if (type == null) { String errorMessage = "Type of prefix is \"any\". Could not validate suffix." ; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, source, containtFeature) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } List<EObject> matchingProperties = AlfScopeProvider.scopingTool.getVisibleVariablesOrParametersOrProperties(type).resolveByName(exp.getPropertyName()) ; if (matchingProperties.size() == 0) { String errorMessage = "Could not resolve property " + exp.getPropertyName() + " for classifier " + type.getName() ; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, source, containtFeature) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } else if (matchingProperties.size() > 1) { String errorMessage = exp.getPropertyName() + " matches multiple properties. Classifier " + type.getName() + " is illformed. Duplicate properties should be renamed or deleted."; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, source, containtFeature) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } else { // exactly one property is matched int upperBoundOfPrefix = typeOfPrefix.getMultiplicityFacade().getUpperBound() ; if (upperBoundOfPrefix == -1 || upperBoundOfPrefix > 1) { String errorMessage = "The prefix of this property call is a collection. An index should be used to access property " + exp.getPropertyName() ; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, source, containtFeature) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } else { TypeExpression typeOfSuffix = TypeExpressionFactory.eInstance.createTypeExpression(matchingProperties.get(0)) ; // Before building the type of this suffix, needs to check if there is a valid index if (exp.getIndex() != null) { if (typeOfSuffix.isACollection()) { // TODO needs to validate the index TypeExpression typeOfIndex = getTypeOfExpression(exp.getIndex()) ; if (typeOfIndex.getTypeFacade() instanceof ErrorTypeFacade) { return typeOfIndex ; } else if (typeOfIndex.isACollection() || typeOfIndex.getTypeFacade() != TypeUtils._integer) { String errorMessage = "Expecting an expression of type Integer. Found an expression of type " + typeOfIndex.getLabel() ; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, exp, AlfPackage.eINSTANCE.getPropertyCallExpression_Index()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } else if (! typeOfSuffix.isOrdered()) { String errorMessage = "Unexpected index. " + exp.getPropertyName() + " is not ordered." ; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, source, containtFeature) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } else { typeOfSuffix = TypeExpressionFactory.eInstance.createTypeExpression(typeOfSuffix.getTypeFacade()) ; } } else { String errorMessage = "Unexpected index. " + exp.getPropertyName() + " is not a collection." ; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, source, containtFeature) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } } if (exp.getSuffix() != null && exp.getSuffix() != suffixToBeIgnored) return getTypeOfSuffixExpression(exp.getSuffix(), typeOfSuffix) ; else return typeOfSuffix ; } } } public TypeExpression getTypeOfOperationCallExpression(OperationCallExpression exp, TypeExpression typeOfPrefix) { Classifier type = typeOfPrefix.getTypeFacade().extractActualType() ; EObject source = exp.eContainer() ; EStructuralFeature containingFeature = exp.eContainingFeature() ; if (type == null) { String errorMessage = "Type of prefix is \"any\". Could not validate suffix." ; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, source, containingFeature) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } List<TypeExpression> arguments = new ArrayList<TypeExpression>() ; for (TupleElement e : exp.getTuple().getTupleElements()) { TypeExpression argType = getTypeOfExpression(e.getArgument()) ; if (argType.getTypeFacade() != null && argType.getTypeFacade() instanceof ErrorTypeFacade) return argType ; arguments.add(argType) ; } List<EObject> matchingOperations = AlfScopeProvider.scopingTool.getVisibleOperationsOrBehaviors(type).resolveByName(exp.getOperationName()) ; TypeExpression typeOfSuffix ; if (matchingOperations.size() == 0) { String errorMessage = "" ; ErrorTypeFacade error = null ; if (exp.getOperationName().equals("destroy")) {// This is the case of the default destructor if (typeOfPrefix.getTypeFacade().extractActualType() instanceof PrimitiveType) errorMessage += "Primitive types do not have destructors." ; else if (arguments.size() > 0) errorMessage += "Default destructor has not parameters" ; if (! (errorMessage.length() == 0)) { error = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, source, containingFeature) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } return TypeExpressionFactory.eInstance.createTypeExpression(_undefined) ; } errorMessage = "Could not resolve operation " + exp.getOperationName() + " for classifier " + type.getName() ; error = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, source, containingFeature) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } else if (matchingOperations.size() > 1) { List<SignatureFacade> availableSignatures = new ArrayList<SignatureFacade>() ; for (EObject operation : matchingOperations) { availableSignatures.add(SignatureFacadeFactory.eInstance.createSignatureFacade(operation)) ; } List<SignatureFacade> selectedSignatures = SignatureFacade.findNearestSignature(arguments, availableSignatures) ; if (selectedSignatures.size() > 1) { // could not infer the actual operations even with type of arguments ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( exp.getOperationName() + " resolves to multiple elements", exp, AlfPackage.eINSTANCE.getOperationCallExpression_OperationName()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } else if (selectedSignatures.size() == 0) { String errorMessage = exp.getOperationName() + " does not apply to arguments (" ; boolean first = true ; for (TypeExpression argType : arguments) { if (!first) errorMessage += ", " ; else first = false ; errorMessage += argType.getLabel() ; } errorMessage += ")" ; ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( errorMessage, exp, AlfPackage.eINSTANCE.getOperationCallExpression_OperationName()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } else { SignatureFacade operationSignature = selectedSignatures.get(0) ; String argumentsAreCompatible = operationSignature.isCompatibleWithMe(arguments, true) ; if (! (argumentsAreCompatible.length() == 0)) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( argumentsAreCompatible, exp, AlfPackage.eINSTANCE.getOperationCallExpression_OperationName()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } typeOfSuffix = selectedSignatures.get(0).getReturnType() ; } } else { // exactly one operation is matched typeOfSuffix = TypeExpressionFactory.eInstance.createTypeExpression(matchingOperations.get(0)) ; SignatureFacade operationSignature = new SignatureFacade(matchingOperations.get(0)) ; String argumentsAreCompatible = operationSignature.isCompatibleWithMe(arguments, true) ; if (! (argumentsAreCompatible.length() == 0)) { ErrorTypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade( argumentsAreCompatible, exp, AlfPackage.eINSTANCE.getOperationCallExpression_OperationName()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error); } typeOfSuffix = operationSignature.getReturnType() ; } if (exp.getSuffix() != null && exp.getSuffix() != suffixToBeIgnored) return getTypeOfSuffixExpression(exp.getSuffix(), typeOfSuffix) ; else return typeOfSuffix ; } public TypeExpression getTypeOfSequenceElement (SequenceElement s) { if (s instanceof Expression) return getTypeOfExpression((Expression)s) ; else // instanceof SequenceConstructionExpression return getTypeOfSequenceConstructionExpression((SequenceConstructionExpression)s) ; } public TypeExpression getTypeOfSequenceConstructionExpression (SequenceConstructionExpression s) { String errorMessage = ""; ErrorTypeFacade error = null ; if (s.getSequenceElement() == null || s.getSequenceElement().isEmpty()) { errorMessage = "Invalid sequence construction expression." ; error = TypeFacadeFactory.eInstance .createErrorTypeFacade(errorMessage, s, AlfPackage.eINSTANCE.getSequenceConstructionExpression_SequenceElement()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } TypeExpression baseType = this.getTypeOfSequenceElement(s.getSequenceElement().get(0)) ; if (baseType.getTypeFacade() instanceof ErrorTypeFacade) return baseType ; if (s.getRangeUpper() != null) { // Sequence is specified as a range TypeExpression upperType = this.getTypeOfExpression(s.getRangeUpper()) ; if (upperType.getTypeFacade() instanceof ErrorTypeFacade) return upperType ; if (upperType.isCompatibleWithMe(baseType) != 0) return TypeExpressionFactory.eInstance.createTypeExpression(upperType.getTypeFacade(), 0, -1, false, true) ; else if (baseType.isCompatibleWithMe(upperType) != 0) return TypeExpressionFactory.eInstance.createTypeExpression(baseType.getTypeFacade(), 0, -1, false, true) ; else { errorMessage += "All the elements in the sequence must be type compatible." ; error = TypeFacadeFactory.eInstance .createErrorTypeFacade(errorMessage, s, AlfPackage.eINSTANCE.getSequenceConstructionExpression_SequenceElement()) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } } else {// Values contained in the sequence are enumerated List<TypeExpression> typeOfSequenceElements = new ArrayList<TypeExpression>() ; typeOfSequenceElements.add(baseType) ; for (int i = 1 ; i < s.getSequenceElement().size() ; i ++) { TypeExpression t = this.getTypeOfSequenceElement(s.getSequenceElement().get(i)) ; if (t.getTypeFacade() instanceof ErrorTypeFacade) return t ; else typeOfSequenceElements.add(t) ; } TypeExpression commonSuperType = this.findCommonSuperType(typeOfSequenceElements) ; if (commonSuperType == null) { errorMessage = "All the elements in the sequence must be type compatible." ; error = TypeFacadeFactory.eInstance .createErrorTypeFacade(errorMessage, s, AlfPackage.eINSTANCE.getSequenceConstructionExpression_SequenceElement()) ; commonSuperType = TypeExpressionFactory.eInstance.createTypeExpression(error) ; } else { commonSuperType.setMultiplicity(MultiplicityFacadeFactory.eInstance.createMultiplicityFacade(-1)) ; } return commonSuperType ; } } private TypeExpression findCommonSuperType(List<TypeExpression> l) { TypeExpression mostGeneral = l.get(0) ; for (int i = 1 ; i < l.size() && mostGeneral != null ; i ++) { TypeExpression current = l.get(i) ; if (mostGeneral == current) ; else if (current.isCompatibleWithMe(mostGeneral) != 0) ; else if (mostGeneral.isCompatibleWithMe(current) != 0) mostGeneral = current ; else mostGeneral = null ; } return mostGeneral ; } public TypeExpression getTypeOfCandidateExpression(EObject exp) { // EObject cddExpression = o ; if (exp instanceof Tuple) return getTypeOfCandidateExpression(exp.eContainer()) ; else if (exp instanceof Expression) return getTypeOfExpression((Expression) exp) ; else if (exp instanceof ConditionalTestExpression) return getTypeOfConditionalTestExpression((ConditionalTestExpression)exp) ; else if (exp instanceof ConditionalOrExpression) return getTypeOfConditionalOrExpression((ConditionalOrExpression) exp) ; else if (exp instanceof ConditionalAndExpression) return getTypeOfConditionalAndExpression((ConditionalAndExpression) exp) ; else if (exp instanceof InclusiveOrExpression) return getTypeOfInclusiveOrExpression((InclusiveOrExpression) exp) ; else if (exp instanceof ExclusiveOrExpression) return getTypeOfExclusiveOrExpression((ExclusiveOrExpression) exp) ; else if (exp instanceof AndExpression) return getTypeOfAndExpression((AndExpression) exp) ; else if (exp instanceof EqualityExpression) return getTypeOfEqualityExpression((EqualityExpression) exp) ; else if (exp instanceof ClassificationExpression) return getTypeOfClassificationExpression((ClassificationExpression) exp) ; else if (exp instanceof RelationalExpression) return getTypeOfRelationalExpression((RelationalExpression) exp) ; else if (exp instanceof ShiftExpression) return getTypeOfShiftExpression((ShiftExpression) exp) ; else if (exp instanceof AdditiveExpression) return getTypeOfAdditiveExpression((AdditiveExpression) exp) ; else if (exp instanceof MultiplicativeExpression) return getTypeOfMultiplicativeExpression((MultiplicativeExpression) exp) ; else if (exp instanceof UnaryExpression) return getTypeOfUnaryExpression((UnaryExpression) exp) ; else if (exp instanceof PrimaryExpression) return getTypeOfPrimaryExpression((PrimaryExpression) exp) ; else if (exp instanceof ValueSpecification) return getTypeOfValueSpecification((ValueSpecification)exp) ; else if (exp instanceof NullExpression) return getTypeOfNullExpression((NullExpression) exp) ; else if (exp instanceof InstanceCreationExpression) return getTypeOfInstanceCreationExpression((InstanceCreationExpression) exp) ; else if (exp instanceof SuperInvocationExpression) return getTypeOfSuperInvocationExpression((SuperInvocationExpression) exp) ; else if (exp instanceof NonLiteralValueSpecification) return getTypeOfNonLiteralValueSpecification((NonLiteralValueSpecification) exp) ; else if (exp instanceof LITERAL) return getTypeOfLITERAL((LITERAL) exp) ; else if (exp instanceof ParenthesizedExpression) return getTypeOfParenthesizedExpression((ParenthesizedExpression) exp) ; else if (exp instanceof NameExpression) return getTypeOfNameExpression((NameExpression) exp) ; else if (exp instanceof ThisExpression) return getTypeOfThisExpression((ThisExpression) exp) ; else if (exp instanceof SequenceOperationExpression) { // This is a suffix expression // First determine type of prefix. TypeUtils localTypeUtil = new TypeUtils((SuffixExpression)exp) ; TypeExpression typeOfPrefix = localTypeUtil.getTypeOfCandidateExpression(exp.eContainer()) ; if (typeOfPrefix.getTypeFacade() instanceof ErrorTypeFacade) return typeOfPrefix ; return getTypeOfSequenceOperationExpression((SequenceOperationExpression) exp, typeOfPrefix) ; } else if (exp instanceof SequenceReductionExpression) { // This is a suffix expression // First determine type of prefix. TypeUtils localTypeUtil = new TypeUtils((SuffixExpression)exp) ; TypeExpression typeOfPrefix = localTypeUtil.getTypeOfCandidateExpression(exp.eContainer()) ; if (typeOfPrefix.getTypeFacade() instanceof ErrorTypeFacade) return typeOfPrefix ; return getTypeOfSequenceReductionExpression((SequenceReductionExpression) exp, typeOfPrefix) ; } else if (exp instanceof SequenceExpansionExpression) { // This is a suffix expression // First determine type of prefix. TypeUtils localTypeUtil = new TypeUtils((SuffixExpression)exp) ; TypeExpression typeOfPrefix = localTypeUtil.getTypeOfCandidateExpression(exp.eContainer()) ; if (typeOfPrefix.getTypeFacade() instanceof ErrorTypeFacade) return typeOfPrefix ; return getTypeOfSequenceExpansionExpression((SequenceExpansionExpression) exp, typeOfPrefix) ; } else if (exp instanceof IsUniqueOperation) { // This is a suffix expression // First determine type of prefix. TypeUtils localTypeUtil = new TypeUtils((SuffixExpression)exp) ; TypeExpression typeOfPrefix = localTypeUtil.getTypeOfCandidateExpression(exp.eContainer()) ; if (typeOfPrefix.getTypeFacade() instanceof ErrorTypeFacade) return typeOfPrefix ; return getTypeOfIsUniqueOperation((IsUniqueOperation) exp, typeOfPrefix) ; } else if (exp instanceof ForAllOrExistsOrOneOperation) { // This is a suffix expression // First determine type of prefix. TypeUtils localTypeUtil = new TypeUtils((SuffixExpression)exp) ; TypeExpression typeOfPrefix = localTypeUtil.getTypeOfCandidateExpression(exp.eContainer()) ; if (typeOfPrefix.getTypeFacade() instanceof ErrorTypeFacade) return typeOfPrefix ; return getTypeOfForAllOrExistsOrOneOperation((ForAllOrExistsOrOneOperation) exp, typeOfPrefix) ; } else if (exp instanceof CollectOrIterateOperation) { // This is a suffix expression // First determine type of prefix. TypeUtils localTypeUtil = new TypeUtils((SuffixExpression)exp) ; TypeExpression typeOfPrefix = localTypeUtil.getTypeOfCandidateExpression(exp.eContainer()) ; if (typeOfPrefix.getTypeFacade() instanceof ErrorTypeFacade) return typeOfPrefix ; return getTypeOfCollectOrIterateOperation((CollectOrIterateOperation) exp, typeOfPrefix) ; } else if (exp instanceof SelectOrRejectOperation) { // This is a suffix expression // First determine type of prefix. TypeUtils localTypeUtil = new TypeUtils((SuffixExpression)exp) ; TypeExpression typeOfPrefix = localTypeUtil.getTypeOfCandidateExpression(exp.eContainer()) ; if (typeOfPrefix.getTypeFacade() instanceof ErrorTypeFacade) return typeOfPrefix ; return getTypeOfSelectOrRejectOperation((SelectOrRejectOperation) exp, typeOfPrefix) ; } else if (exp instanceof PropertyCallExpression) { // This is a suffix expression // First determine type of prefix. TypeUtils localTypeUtil = new TypeUtils((SuffixExpression)exp) ; TypeExpression typeOfPrefix = localTypeUtil.getTypeOfCandidateExpression(exp.eContainer()) ; if (typeOfPrefix.getTypeFacade() instanceof ErrorTypeFacade) return typeOfPrefix ; return getTypeOfPropertyCallExpression((PropertyCallExpression) exp, typeOfPrefix) ; } else if (exp instanceof OperationCallExpression) { // This is a suffix expression // First determine type of prefix. TypeUtils localTypeUtil = new TypeUtils((SuffixExpression)exp) ; TypeExpression typeOfPrefix = localTypeUtil.getTypeOfCandidateExpression(exp.eContainer()) ; if (typeOfPrefix.getTypeFacade() instanceof ErrorTypeFacade) return typeOfPrefix ; return getTypeOfOperationCallExpression((OperationCallExpression) exp, typeOfPrefix) ; } else if (exp instanceof SequenceElement) return getTypeOfSequenceElement ((SequenceElement) exp) ; else if (exp instanceof SequenceConstructionExpression) return getTypeOfSequenceConstructionExpression ((SequenceConstructionExpression) exp) ; String errorMessage = "Not an expression." ; TypeFacade error = TypeFacadeFactory.eInstance.createErrorTypeFacade(errorMessage, exp, null) ; return TypeExpressionFactory.eInstance.createTypeExpression(error) ; } }