/******************************************************************************* * Copyright (c) 2010, 2015 Willink Transformations and others. * 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: * E.D.Willink - initial API and implementation * E.D.Willink (CEA LIST) - Bug 388493 * E.D.Willink (Obeo) - Bug 416287 - tuple-valued constraints * Adolfo Sanchez-Barbudo Herrera (University of York) - Lookup Environment/Visitor *******************************************************************************/ package org.eclipse.ocl.xtext.essentialocl.cs2as; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import org.eclipse.emf.ecore.EObject; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.ocl.pivot.BooleanLiteralExp; import org.eclipse.ocl.pivot.CallExp; import org.eclipse.ocl.pivot.CollectionItem; import org.eclipse.ocl.pivot.CollectionLiteralExp; import org.eclipse.ocl.pivot.CollectionLiteralPart; import org.eclipse.ocl.pivot.CollectionRange; import org.eclipse.ocl.pivot.CollectionType; import org.eclipse.ocl.pivot.CompleteClass; import org.eclipse.ocl.pivot.DataType; import org.eclipse.ocl.pivot.Element; import org.eclipse.ocl.pivot.ElementExtension; import org.eclipse.ocl.pivot.EnumLiteralExp; import org.eclipse.ocl.pivot.EnumerationLiteral; import org.eclipse.ocl.pivot.ExpressionInOCL; import org.eclipse.ocl.pivot.FeatureCallExp; import org.eclipse.ocl.pivot.IfExp; import org.eclipse.ocl.pivot.IntegerLiteralExp; import org.eclipse.ocl.pivot.InvalidLiteralExp; import org.eclipse.ocl.pivot.InvalidType; import org.eclipse.ocl.pivot.IterateExp; import org.eclipse.ocl.pivot.Iteration; import org.eclipse.ocl.pivot.IteratorExp; import org.eclipse.ocl.pivot.LetExp; import org.eclipse.ocl.pivot.LoopExp; import org.eclipse.ocl.pivot.MapLiteralExp; import org.eclipse.ocl.pivot.MapLiteralPart; import org.eclipse.ocl.pivot.NamedElement; import org.eclipse.ocl.pivot.NavigationCallExp; import org.eclipse.ocl.pivot.NullLiteralExp; import org.eclipse.ocl.pivot.NumericLiteralExp; import org.eclipse.ocl.pivot.OCLExpression; import org.eclipse.ocl.pivot.Operation; import org.eclipse.ocl.pivot.OperationCallExp; import org.eclipse.ocl.pivot.OppositePropertyCallExp; import org.eclipse.ocl.pivot.Parameter; import org.eclipse.ocl.pivot.PivotFactory; import org.eclipse.ocl.pivot.PivotPackage; import org.eclipse.ocl.pivot.PrimitiveType; import org.eclipse.ocl.pivot.Property; import org.eclipse.ocl.pivot.PropertyCallExp; import org.eclipse.ocl.pivot.SelfType; import org.eclipse.ocl.pivot.ShadowExp; import org.eclipse.ocl.pivot.ShadowPart; import org.eclipse.ocl.pivot.State; import org.eclipse.ocl.pivot.StateExp; import org.eclipse.ocl.pivot.StringLiteralExp; import org.eclipse.ocl.pivot.TemplateParameter; import org.eclipse.ocl.pivot.TupleLiteralExp; import org.eclipse.ocl.pivot.TupleLiteralPart; import org.eclipse.ocl.pivot.Type; import org.eclipse.ocl.pivot.TypeExp; import org.eclipse.ocl.pivot.UnlimitedNaturalLiteralExp; import org.eclipse.ocl.pivot.Variable; import org.eclipse.ocl.pivot.VariableDeclaration; import org.eclipse.ocl.pivot.VariableExp; import org.eclipse.ocl.pivot.internal.complete.StandardLibraryInternal; import org.eclipse.ocl.pivot.internal.manager.PivotMetamodelManager; import org.eclipse.ocl.pivot.internal.manager.TemplateParameterSubstitutionHelper; import org.eclipse.ocl.pivot.internal.manager.TemplateParameterSubstitutionVisitor; import org.eclipse.ocl.pivot.internal.messages.PivotMessagesInternal; import org.eclipse.ocl.pivot.internal.utilities.EnvironmentFactoryInternal; import org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal; import org.eclipse.ocl.pivot.library.LibraryFeature; import org.eclipse.ocl.pivot.utilities.ClassUtil; import org.eclipse.ocl.pivot.utilities.FeatureFilter; import org.eclipse.ocl.pivot.utilities.PivotConstants; import org.eclipse.ocl.pivot.utilities.PivotUtil; import org.eclipse.ocl.pivot.utilities.SingletonIterator; import org.eclipse.ocl.pivot.utilities.StringUtil; import org.eclipse.ocl.pivot.utilities.TypeUtil; import org.eclipse.ocl.pivot.values.TemplateParameterSubstitutions; import org.eclipse.ocl.xtext.base.cs2as.AmbiguitiesAdapter; import org.eclipse.ocl.xtext.base.cs2as.CS2AS; import org.eclipse.ocl.xtext.base.cs2as.CS2ASConversion; import org.eclipse.ocl.xtext.base.utilities.ElementUtil; import org.eclipse.ocl.xtext.basecs.ElementCS; import org.eclipse.ocl.xtext.basecs.ModelElementCS; import org.eclipse.ocl.xtext.basecs.PathElementCS; import org.eclipse.ocl.xtext.basecs.PathNameCS; import org.eclipse.ocl.xtext.basecs.TypedRefCS; import org.eclipse.ocl.xtext.essentialocl.attributes.AbstractOperationMatcher; import org.eclipse.ocl.xtext.essentialocl.attributes.BinaryOperationMatcher; import org.eclipse.ocl.xtext.essentialocl.attributes.NavigationUtil; import org.eclipse.ocl.xtext.essentialocl.attributes.OperationMatcher; import org.eclipse.ocl.xtext.essentialocl.attributes.UnaryOperationMatcher; import org.eclipse.ocl.xtext.essentialoclcs.AbstractNameExpCS; import org.eclipse.ocl.xtext.essentialoclcs.BooleanLiteralExpCS; import org.eclipse.ocl.xtext.essentialoclcs.CollectionLiteralExpCS; import org.eclipse.ocl.xtext.essentialoclcs.CollectionLiteralPartCS; import org.eclipse.ocl.xtext.essentialoclcs.CollectionTypeCS; import org.eclipse.ocl.xtext.essentialoclcs.ContextCS; import org.eclipse.ocl.xtext.essentialoclcs.CurlyBracketedClauseCS; import org.eclipse.ocl.xtext.essentialoclcs.ExpCS; import org.eclipse.ocl.xtext.essentialoclcs.IfExpCS; import org.eclipse.ocl.xtext.essentialoclcs.InfixExpCS; import org.eclipse.ocl.xtext.essentialoclcs.InvalidLiteralExpCS; import org.eclipse.ocl.xtext.essentialoclcs.LetExpCS; import org.eclipse.ocl.xtext.essentialoclcs.LetVariableCS; import org.eclipse.ocl.xtext.essentialoclcs.MapLiteralExpCS; import org.eclipse.ocl.xtext.essentialoclcs.MapLiteralPartCS; import org.eclipse.ocl.xtext.essentialoclcs.MapTypeCS; import org.eclipse.ocl.xtext.essentialoclcs.NameExpCS; import org.eclipse.ocl.xtext.essentialoclcs.NavigatingArgCS; import org.eclipse.ocl.xtext.essentialoclcs.NavigationRole; import org.eclipse.ocl.xtext.essentialoclcs.NestedExpCS; import org.eclipse.ocl.xtext.essentialoclcs.NullLiteralExpCS; import org.eclipse.ocl.xtext.essentialoclcs.NumberLiteralExpCS; import org.eclipse.ocl.xtext.essentialoclcs.OperatorExpCS; import org.eclipse.ocl.xtext.essentialoclcs.PrefixExpCS; import org.eclipse.ocl.xtext.essentialoclcs.RoundBracketedClauseCS; import org.eclipse.ocl.xtext.essentialoclcs.SelfExpCS; import org.eclipse.ocl.xtext.essentialoclcs.ShadowPartCS; import org.eclipse.ocl.xtext.essentialoclcs.SquareBracketedClauseCS; import org.eclipse.ocl.xtext.essentialoclcs.StringLiteralExpCS; import org.eclipse.ocl.xtext.essentialoclcs.TupleLiteralExpCS; import org.eclipse.ocl.xtext.essentialoclcs.TupleLiteralPartCS; import org.eclipse.ocl.xtext.essentialoclcs.TypeLiteralExpCS; import org.eclipse.ocl.xtext.essentialoclcs.UnlimitedNaturalLiteralExpCS; import org.eclipse.ocl.xtext.essentialoclcs.VariableCS; import org.eclipse.ocl.xtext.essentialoclcs.util.AbstractEssentialOCLCSLeft2RightVisitor; public class EssentialOCLCSLeft2RightVisitor extends AbstractEssentialOCLCSLeft2RightVisitor { /** * Configure use of the new auto-generated lookup or the old manually coded lookup. */ public static boolean AUTOGENERATED_LOOKUP = false; public static interface Invocations extends Iterable<NamedElement> { @Nullable NamedElement getSingleResult(); @NonNull Type getSourceType(); } public static class ResolvedInvocation implements Invocations { protected final @NonNull Operation invocation; public ResolvedInvocation(@NonNull Operation invocation) { this.invocation = invocation; } @Override public @NonNull NamedElement getSingleResult() { return invocation; } @Override public @NonNull Type getSourceType() { return ClassUtil.nonNullState(invocation.getOwningClass()); } @Override public Iterator<NamedElement> iterator() { return new SingletonIterator<NamedElement>(invocation); } } public static class UnresolvedInvocations implements Invocations { protected final @NonNull Type asType; protected final @NonNull List<NamedElement> invocations; public UnresolvedInvocations(@NonNull Type asType, @NonNull List<NamedElement> invocations) { this.asType = asType; this.invocations = invocations; } @Override public @Nullable NamedElement getSingleResult() { return invocations.size() == 1 ? invocations.get(0) : null; } @Override public @NonNull Type getSourceType() { return asType; } @Override public Iterator<NamedElement> iterator() { return invocations.iterator(); } } protected final @NonNull EnvironmentFactoryInternal environmentFactory; protected final @NonNull PivotMetamodelManager metamodelManager; protected final @NonNull StandardLibraryInternal standardLibrary; /*protected final @NonNull PivotNameResolver nameResolver;*/ /** * curretRoot identifies the current InfixExpCS/PrefixExpCS tree enabling the initial visit to the containment root to * be distinguished from the subsequent visit within the logical hierarchy. */ private @Nullable OperatorExpCS currentRoot = null; public EssentialOCLCSLeft2RightVisitor(@NonNull CS2ASConversion context) { super(context); this.environmentFactory = context.getEnvironmentFactory(); this.metamodelManager = environmentFactory.getMetamodelManager(); this.standardLibrary = environmentFactory.getStandardLibrary(); /*this.nameResolver = new PivotNameResolver(environmentFactory); // FIXME factory method*/ } protected void checkForInvalidImplicitSourceType(@NonNull ExpCS csInvocationExp) { for (ImplicitSourceTypeIterator it = new ImplicitSourceTypeIterator(csInvocationExp); it.hasNext(); ) { Type next = it.next(); if (isInvalidType(next)) { csInvocationExp.setHasError(true); break; } } } protected @NonNull OperationCallExp createCoercionCallExp(@NonNull OCLExpression sourceExp, @NonNull Operation coercion) { OperationCallExp asCoercionCallExp; asCoercionCallExp = PivotFactory.eINSTANCE.createOperationCallExp(); asCoercionCallExp.setOwnedSource(sourceExp); asCoercionCallExp.setReferredOperation(coercion); asCoercionCallExp.setType(coercion.getType()); asCoercionCallExp.setIsRequired(coercion.isIsRequired()); return asCoercionCallExp; } protected ImplicitSourceTypeIterator createImplicitSourceTypeIterator(@NonNull ElementCS csElement) { return new ImplicitSourceTypeIterator(csElement); } protected @NonNull OCLExpression createImplicitSourceVariableExp(@NonNull AbstractNameExpCS csNameExp, Type owningType) { VariableDeclaration sourceVariable = owningType != null ? getImplicitSource(csNameExp, owningType) : null; if (sourceVariable == null) { @SuppressWarnings("unused") VariableDeclaration sourceVariable2 = owningType != null ? getImplicitSource(csNameExp, owningType) : null; return context.addBadExpressionError(csNameExp, "No implicit source"); } else { return createImplicitVariableExp(sourceVariable); } } protected @NonNull ImplicitSourceVariableIterator createImplicitSourceVariableIterator(@NonNull ModelElementCS csExp) { return new ImplicitSourceVariableIterator(csExp); } protected @NonNull VariableExp createImplicitVariableExp(@NonNull VariableDeclaration variable) { VariableExp variableExp = context.refreshModelElement(VariableExp.class, PivotPackage.Literals.VARIABLE_EXP, null); // FIXME reuse variableExp.setReferredVariable(variable); variableExp.setIsImplicit(true); context.setType(variableExp, variable.getType(), variable.isIsRequired(), variable.getTypeValue()); return variableExp; } /** * let iterations = invocations->selectByKind(Iteration)->select(owningClass <> null) in * let bestIteratorSize = iterations->collect(ownedIterators->size())->min() in * let bestSizeIterations = iterations->select(ownedIterators->size() = bestIteratorSize) in * let owningClasses = bestSizeIterations.owningClass.unspecializedClass->asSet() in * let leafClasses = owningClasses->select(c | owningClasses->intersection(c->closure(superClasses)) = c) in * let leafIterations = bestSizeIterations->select(leafClasses->includes(owningClass.unspecializedClass)) in * leafIterations->any(true) */ protected @Nullable Iteration getBestIteration(@NonNull Invocations invocations, @Nullable RoundBracketedClauseCS csRoundBracketedClause) { int requiredIterators = 0; if (csRoundBracketedClause != null) { for (NavigatingArgCS csArgument : csRoundBracketedClause.getOwnedArguments()) { if (csArgument.getRole() == NavigationRole.ITERATOR) { requiredIterators++; } } } if (requiredIterators == 0) { requiredIterators = 1; // Implicit is always one iterator. } Iteration bestIteration = null; org.eclipse.ocl.pivot.Class bestType = null; for (NamedElement operation : invocations) { if (operation instanceof Iteration) { Iteration iteration = (Iteration) operation; int iteratorsSize = iteration.getOwnedIterators().size(); if (iteratorsSize == requiredIterators) { org.eclipse.ocl.pivot.Class specializedType = iteration.getOwningClass(); if (specializedType != null) { org.eclipse.ocl.pivot.Class unspecializedType = PivotUtil.getUnspecializedTemplateableElement(specializedType); if ((bestType == null) || !metamodelManager.isSuperClassOf(unspecializedType, bestType)) { bestIteration = iteration; bestType = unspecializedType; } } } } } return bestIteration; } protected @Nullable Operation getExampleOperation(@NonNull Invocations invocations, @Nullable OCLExpression sourceExp, @NonNull RoundBracketedClauseCS csRoundBracketedClause) { NamedElement namedElement = invocations.getSingleResult(); if (namedElement != null) { return namedElement instanceof Operation ? (Operation)namedElement : null; } Operation bestOperation = null; int bestDepth = 0; for (NamedElement invocation : invocations) { if (invocation instanceof Operation) { Operation operation = (Operation)invocation; org.eclipse.ocl.pivot.Class owningClass = operation.getOwningClass(); if (owningClass != null) { CompleteClass completeClass = metamodelManager.getCompleteClass(owningClass); int depth = completeClass.getCompleteInheritance().getDepth(); if ((bestOperation == null) || (depth > bestDepth)) { bestOperation = operation; bestDepth = depth; } } } } return bestOperation; } protected @Nullable VariableDeclaration getImplicitSource(@NonNull ModelElementCS csExp, @NonNull Type requiredType) { @Nullable VariableDeclaration lastVariable = null; for (ImplicitSourceVariableIterator it = createImplicitSourceVariableIterator(csExp); it.hasNext(); ) { @NonNull Variable variable = it.next(); lastVariable = variable; Type type = variable.getType(); if ((type != null) && type.conformsTo(standardLibrary, requiredType)) { return variable; } } return lastVariable; // If no good variable found, the outermost variable is the least bad. } // FIXME report all possible variables as bad to user protected @Nullable Invocations getInvocations(@Nullable Type asSourceType, @Nullable Type asSourceTypeValue, @NonNull RoundBracketedClauseCS csRoundBracketedClause) { AbstractNameExpCS csNameExp = csRoundBracketedClause.getOwningNameExp(); PathNameCS csPathName = csNameExp.getOwnedPathName(); if (csPathName == null) { return null; } List<PathElementCS> csPathElements = csPathName.getOwnedPathElements(); if (csPathElements == null) { return null; } int pathSize = csPathElements.size(); if (pathSize <= 0) { return null; } PathElementCS csLastPathElement = csPathElements.get(pathSize-1); if (csLastPathElement == null) { return null; } assert csLastPathElement.getElementType() != null; Element asElement = csLastPathElement.basicGetReferredElement(); if ((asElement instanceof Operation) && !asElement.eIsProxy()) { return new ResolvedInvocation((Operation)asElement); } String name = ElementUtil.getTextName(csLastPathElement); if (name == null) { return null; } int iteratorCount = 0; int expressionCount = 0; for (NavigatingArgCS csArg : csRoundBracketedClause.getOwnedArguments()) { if (csArg.getRole() == NavigationRole.ITERATOR) { iteratorCount++; } else if (csArg.getRole() == NavigationRole.EXPRESSION) { expressionCount++; } } if (pathSize > 1) { // Search for B::b() or a.B::b() candidates in B Type asType = context.getConverter().lookupTypeQualifier(csPathName); if (asType == null) { return null; } Invocations invocations = getInvocations(asType, null, name, iteratorCount, expressionCount); if ((invocations == null) && name.startsWith("_")) { @SuppressWarnings("null")@NonNull String unescapedName = name.substring(1); // FIXME Compatibility invocations = getInvocations(asType, null, unescapedName, iteratorCount, expressionCount); } return invocations; } else if (asSourceType != null) { // Search for a.b() candidates in type of a TemplateParameter asTemplateParameter = asSourceType.isTemplateParameter(); if (asTemplateParameter != null) { List<org.eclipse.ocl.pivot.Class> asConstrainingClasses = asTemplateParameter.getConstrainingClasses(); if (asConstrainingClasses.size() > 0) { asSourceType = ClassUtil.nonNullModel(asConstrainingClasses.get(0)); } } Invocations invocations = getInvocations(asSourceType, asSourceTypeValue, name, iteratorCount, expressionCount); if ((invocations == null) && name.startsWith("_")) { @SuppressWarnings("null")@NonNull String unescapedName = name.substring(1); // FIXME Compatibility invocations = getInvocations(asSourceType, asSourceTypeValue, unescapedName, iteratorCount, expressionCount); } return invocations; } else { // Search for a() candidates in implicit source variable types Invocations invocations = null; for (ImplicitSourceTypeIterator it = createImplicitSourceTypeIterator(csNameExp); (invocations == null) && it.hasNext(); ) { Type asType = it.next(); invocations = getInvocations(asType, null, name, iteratorCount, expressionCount); } if ((invocations == null) && name.startsWith("_")) { @SuppressWarnings("null")@NonNull String unescapedName = name.substring(1); // FIXME Compatibility for (ImplicitSourceTypeIterator it = createImplicitSourceTypeIterator(csNameExp); (invocations == null) && it.hasNext(); ) { Type asType = it.next(); invocations = getInvocations(asType, null, unescapedName, iteratorCount, expressionCount); } } return invocations; } } /** * Return all operations/iterations in asType and its superclasses whose name is name. For iterations the number of iteration iterators must * match iteratorCount unless iteratorCount is zero. For operations the number of parameters must be expressionCount. Returns null if * nothing is found. */ protected @Nullable Invocations getInvocations(@NonNull Type asType, @Nullable Type asTypeValue, @NonNull String name, int iteratorCount, int expressionCount) { TemplateParameter asTemplateParameter = asType.isTemplateParameter(); if (asTemplateParameter != null) { List<org.eclipse.ocl.pivot.Class> asConstrainingClasses = asTemplateParameter.getConstrainingClasses(); if (asConstrainingClasses.size() > 0) { asType = ClassUtil.nonNullModel(asConstrainingClasses.get(0)); } else { asType = standardLibrary.getOclAnyType(); } } Iterable<? extends Operation> nonStaticOperations = metamodelManager.getAllOperations(asType, FeatureFilter.SELECT_NON_STATIC, name); List<NamedElement> invocations = getInvocationsInternal(null, nonStaticOperations, iteratorCount, expressionCount); if (asType instanceof ElementExtension) { // FIXME review me Type asStereotype = ((ElementExtension)asType).getStereotype(); if (asStereotype != null) { Iterable<? extends Operation> stereotypeOperations = metamodelManager.getAllOperations(asStereotype, FeatureFilter.SELECT_NON_STATIC, name); invocations = getInvocationsInternal(invocations, stereotypeOperations, iteratorCount, expressionCount); } } if (asType instanceof DataType) { Type asBehavioralType = ((DataType)asType).getBehavioralClass(); if (asBehavioralType != null) { Iterable<? extends Operation> stereotypeOperations = metamodelManager.getAllOperations(asBehavioralType, FeatureFilter.SELECT_NON_STATIC, name); invocations = getInvocationsInternal(invocations, stereotypeOperations, iteratorCount, expressionCount); } } if (asTypeValue != null) { Iterable<? extends Operation> staticOperations = metamodelManager.getAllOperations(asTypeValue, FeatureFilter.SELECT_STATIC, name); invocations = getInvocationsInternal(invocations, staticOperations, iteratorCount, expressionCount); } return invocations != null ? new UnresolvedInvocations(asType, invocations) : null; } protected @Nullable List<NamedElement> getInvocationsInternal(@Nullable List<NamedElement> invocations, @NonNull Iterable<? extends Operation> allOperations, int iteratorCount, int expressionCount) { for (Operation operation : allOperations) { Operation asOperation = null; if (operation instanceof Iteration) { Iteration candidateIteration = (Iteration) operation; int iteratorsSize = candidateIteration.getOwnedIterators().size(); if ((iteratorCount == 0) || (iteratorCount == iteratorsSize)) { asOperation = candidateIteration; } } else { Operation candidateOperation = operation; int operationsSize = candidateOperation.getOwnedParameters().size(); if (expressionCount == operationsSize) { asOperation = candidateOperation; } } if (asOperation != null) { if (invocations == null) { invocations = new ArrayList<NamedElement>(); } invocations.add(asOperation); } } return invocations; } protected @NonNull OperatorExpCS getRoot(@NonNull OperatorExpCS csOperator) { OperatorExpCS csRoot = csOperator; for (OperatorExpCS csParent = csRoot.getLocalParent(); csParent != null; csParent = csParent.getLocalParent()) { csRoot = csParent; } return csRoot; } protected boolean isInvalidType(@Nullable Type type) { return (type == null) || (type instanceof InvalidType) || ((type instanceof CollectionType) && (((CollectionType)type).getElementType() instanceof InvalidType)); } /** @deprecated use ElementUtil */ @Deprecated protected boolean isRequired(@Nullable TypedRefCS csTypeRef) { return ElementUtil.isRequired(csTypeRef); } protected @NonNull OperationCallExp refreshOperationCallExp(@NonNull AbstractNameExpCS csNameExp, @Nullable OCLExpression sourceExp) { OperationCallExp callExp = context.refreshModelElement(OperationCallExp.class, PivotPackage.Literals.OPERATION_CALL_EXP, csNameExp); callExp.setOwnedSource(sourceExp); return callExp; } protected @NonNull OppositePropertyCallExp refreshOppositePropertyCallExp(@NonNull NameExpCS csNameExp, @NonNull OCLExpression sourceExp, @NonNull Property property) { OppositePropertyCallExp callExp = context.refreshModelElement(OppositePropertyCallExp.class, PivotPackage.Literals.OPPOSITE_PROPERTY_CALL_EXP, csNameExp); callExp.setOwnedSource(sourceExp); callExp.setReferredProperty(property.getOpposite()); return callExp; } protected @NonNull PropertyCallExp refreshPropertyCallExp(@NonNull NameExpCS csNameExp, @NonNull OCLExpression sourceExp, @NonNull Property property) { PropertyCallExp callExp = context.refreshModelElement(PropertyCallExp.class, PivotPackage.Literals.PROPERTY_CALL_EXP, csNameExp); callExp.setOwnedSource(sourceExp); callExp.setReferredProperty(property); return callExp; } protected Element resolveAssociationClassCallExp(@NonNull NameExpCS csNameExp) { // PathNameCS pathName = csNameExp.getPathName(); RoundBracketedClauseCS csRoundBracketedClause = csNameExp.getOwnedRoundBracketedClause(); List<SquareBracketedClauseCS> csSquareBracketedClauses = csNameExp.getOwnedSquareBracketedClauses(); if (csSquareBracketedClauses.size() > 2) { return context.addBadExpressionError(csNameExp, "AssociationClassCallExp must have exactly only one or two square-brackets-clauses"); } if (csRoundBracketedClause != null) { return context.addBadExpressionError(csNameExp, "AssociationClassCallExp must have no round-brackets-clause"); } // SquareBracketedClauseCS csSquareBracketedClause = csSquareBracketedClauses.get(0); // CS2AS.setElementType(pathName, PivotPackage.Literals.ASSOCIATION_CLASS, csNameExp, null); // Element element = pathName.getElement(); // return resolveConstructorExp((Type)element, csNameExp); return null; } protected void resolveAtPre(@Nullable AbstractNameExpCS csNameExp, @NonNull FeatureCallExp featureCallExp) { if (csNameExp != null) { featureCallExp.setIsPre(csNameExp.isIsPre()); } } /** * Resolve an invocation such as name() or source.name(...) or source->name(...) to the best candidate from invocations. * <p> * sourceExp is null for an implicit source invocation. * <p> * csInvocationExp.getNamedElement() must be invoked once, after the left-hand context has been established to enable the lokup to * proceed in a simple (perhaps rivial) fashion. */ protected @Nullable OCLExpression resolveBestInvocation(@Nullable OCLExpression sourceExp, @NonNull RoundBracketedClauseCS csRoundBracketedClause, @NonNull Invocations invocations) { AbstractNameExpCS csNameExp = csRoundBracketedClause.getOwningNameExp(); PathNameCS csPathName = csNameExp.getOwnedPathName(); if (csPathName == null) { return null; } Iteration iteration = getBestIteration(invocations, csRoundBracketedClause); if (iteration != null) { if (sourceExp == null) { sourceExp = createImplicitSourceVariableExp(csNameExp, iteration.getOwningClass()); } LoopExp iterationCallExp = resolveIterationCallExp(csNameExp, sourceExp, iteration); CS2AS.setPathElement(csPathName, iteration, null); resolveIterationContent(csRoundBracketedClause, iterationCallExp); return iterationCallExp; } Operation exampleOperation = getExampleOperation(invocations, sourceExp, csRoundBracketedClause); if (exampleOperation != null) { if (sourceExp == null) { sourceExp = createImplicitSourceVariableExp(csNameExp, exampleOperation.getOwningClass()); } OperationCallExp operationCallExp = refreshOperationCallExp(csNameExp, sourceExp); if (invocations.getSingleResult() != null) { context.setReferredOperation(operationCallExp, exampleOperation); } // // Need to resolve types for operation arguments in order to disambiguate operation names. // resolveOperationArgumentTypes(exampleOperation.getOwnedParameters(), csRoundBracketedClause); // // Resolve the static operation/iteration by name and known operation argument types. // Type explicitSourceType = null; InfixExpCS csNavigationOperator = NavigationUtil.getNavigationInfixExp(csNameExp); if (csNavigationOperator != null) { // For a->X(); X must be resolved in the navigation source type explicitSourceType = csNameExp.getSourceTypeValue() != null ? csNameExp.getSourceTypeValue() : csNameExp.getSourceType(); if (explicitSourceType == null) { return null; } } if (explicitSourceType == null) { explicitSourceType = invocations.getSourceType(); } OperationMatcher matcher = new OperationMatcher(environmentFactory, explicitSourceType, csNameExp.getSourceTypeValue(), csRoundBracketedClause); Operation asOperation = matcher.getBestOperation(invocations, false); // // Try again with argument coercion. // if (asOperation == null) { asOperation = matcher.getBestOperation(invocations, true); } // // Search for invocations with a coerced source. // if (asOperation == null) { Operation asCoercion = null; CompleteClass completeClass = metamodelManager.getCompleteClass(explicitSourceType); for (org.eclipse.ocl.pivot.Class partialClass : completeClass.getPartialClasses()) { if (partialClass instanceof PrimitiveType) { for (Operation coercion : ((PrimitiveType)partialClass).getCoercions()) { Type corcedSourceType = coercion.getType(); Invocations coercedInvocations = getInvocations(corcedSourceType, null, csRoundBracketedClause); if (coercedInvocations != null) { matcher = new OperationMatcher(environmentFactory, corcedSourceType, null, csRoundBracketedClause); asOperation = matcher.getBestOperation(coercedInvocations, false); if (asOperation == null) { asOperation = matcher.getBestOperation(coercedInvocations, true); } } if (asOperation != null) { asCoercion = coercion; break; } } if (asCoercion != null) { break; } } } if (asCoercion != null) { operationCallExp.setOwnedSource(null); OperationCallExp asCoercionCallExp = createCoercionCallExp(sourceExp, asCoercion); operationCallExp.setOwnedSource(asCoercionCallExp); } } CS2AS.setPathElement(csPathName, asOperation, matcher.getAmbiguities()); if (asOperation != null) { return resolveOperationCallExp(csRoundBracketedClause, operationCallExp, asOperation); } } return null; } /** * Return a non-null coercion Operation from argType to parameterType if one is available and needed. */ protected @Nullable Operation resolveCoercionFrom(@NonNull Type argType, @NonNull Type parameterType) { if (!metamodelManager.conformsTo(argType, TemplateParameterSubstitutions.EMPTY, parameterType, TemplateParameterSubstitutions.EMPTY)) { CompleteClass completeClass = metamodelManager.getCompleteClass(argType); for (org.eclipse.ocl.pivot.Class partialClass : completeClass.getPartialClasses()) { if (partialClass instanceof PrimitiveType) { for (Operation coercion : ((PrimitiveType)partialClass).getCoercions()) { Type corcedArgType = coercion.getType(); if ((corcedArgType != null) && metamodelManager.conformsTo(corcedArgType, TemplateParameterSubstitutions.EMPTY, parameterType, TemplateParameterSubstitutions.EMPTY)) { return coercion; } } } } } return null; } protected @NonNull EnumLiteralExp resolveEnumLiteral(@NonNull ExpCS csExp, @NonNull EnumerationLiteral enumerationLiteral) { EnumLiteralExp expression = context.refreshModelElement(EnumLiteralExp.class, PivotPackage.Literals.ENUM_LITERAL_EXP, csExp); context.setType(expression, enumerationLiteral.getOwningEnumeration(), true, null); expression.setReferredLiteral(enumerationLiteral); return expression; } /** * Resolve an invocation such as source.name or source->name */ protected @NonNull OCLExpression resolveExplicitSourceNavigation(@NonNull OCLExpression sourceExp, @NonNull NameExpCS csNameExp) { PathNameCS ownedPathName = ClassUtil.nonNullState(csNameExp.getOwnedPathName()); Element namedElement = context.lookupUndecoratedName(csNameExp, ownedPathName); if ((namedElement instanceof Property) && !namedElement.eIsProxy()) { CallExp callExp = resolvePropertyCallExp(sourceExp, csNameExp, (Property)namedElement); return callExp; } Property oclInvalidProperty = standardLibrary.getOclInvalidProperty(); PropertyCallExp expression = refreshPropertyCallExp(csNameExp, sourceExp, oclInvalidProperty); context.setType(expression, standardLibrary.getOclInvalidType(), false, null); ElementUtil.setLastPathElement(ownedPathName, oclInvalidProperty); return expression; } protected @NonNull OCLExpression resolveImplicitAsSet(@NonNull OCLExpression sourceExp, @NonNull Type sourceType, @NonNull InfixExpCS csOperator) { OperationCallExp expression = context.refreshModelElement(OperationCallExp.class, PivotPackage.Literals.OPERATION_CALL_EXP, null); expression.setIsImplicit(true); PivotUtilInternal.resetContainer(sourceExp); expression.setOwnedSource(sourceExp); expression.setName("oclAsSet"); resolveOperationCall(expression, csOperator); return expression; } /** * Return a non-null implicit collect() call if a sourceExp for a csElement requires an implicit collect. * The return call has no body or return type since they cannot be synthesised until the body is synthesised. */ protected @Nullable IteratorExp resolveImplicitCollect(@NonNull OCLExpression sourceExp, @NonNull InfixExpCS csOperator) { Type actualSourceType = sourceExp.getType(); if (!(actualSourceType instanceof CollectionType)) { return null; } Type elementType = ((CollectionType)actualSourceType).getElementType(); if (elementType == null) { return null; } Invocations invocations = getInvocations(actualSourceType, null, "collect", 1, 0); if (invocations == null) { return null; } Iteration asIteration = getBestIteration(invocations, null); if (asIteration == null) { return null; } boolean isSafe = PivotConstants.SAFE_OBJECT_NAVIGATION_OPERATOR.equals(csOperator.getName()); IteratorExp implicitCollectExp = context.refreshModelElement(IteratorExp.class, PivotPackage.Literals.ITERATOR_EXP, null); implicitCollectExp.setIsImplicit(true); PivotUtilInternal.resetContainer(sourceExp); implicitCollectExp.setOwnedSource(sourceExp); implicitCollectExp.setName(asIteration.getName()); implicitCollectExp.setIsSafe(isSafe); context.setReferredIteration(implicitCollectExp, asIteration); Variable iterator = context.refreshModelElement(Variable.class, PivotPackage.Literals.VARIABLE, null); // FIXME reuse Parameter resolvedIterator = asIteration.getOwnedIterators().get(0); iterator.setRepresentedParameter(resolvedIterator); context.refreshName(iterator, "1_"); context.setType(iterator, elementType, isSafe || ((CollectionType)actualSourceType).isIsNullFree(), null); iterator.setIsImplicit(true); implicitCollectExp.getOwnedIterators().add(iterator); return implicitCollectExp; } /** * Resolve an invocation such as name() or source.name(...) or source->name(...) */ protected @NonNull OCLExpression resolveInvocation(@Nullable OCLExpression sourceExp, @NonNull RoundBracketedClauseCS csRoundBracketedClause) { AbstractNameExpCS csNameExp = csRoundBracketedClause.getOwningNameExp(); PathNameCS csPathName = csNameExp.getOwnedPathName(); if (csPathName != null) { // QVTr overrides to select a wider search List<PathElementCS> csPath = csPathName.getOwnedPathElements(); int pathSize = csPath.size(); if (pathSize > 0) { PathElementCS csLastPathElement = csPath.get(pathSize-1); if (csLastPathElement.getElementType() == null) { csLastPathElement.setElementType(PivotPackage.Literals.OPERATION); } } } Invocations invocations = getInvocations(sourceExp != null ? sourceExp.getType() : null, sourceExp != null ? sourceExp.getTypeValue() : null, csRoundBracketedClause); if (invocations != null) { OCLExpression invocationExp = resolveBestInvocation(sourceExp, csRoundBracketedClause, invocations); if (invocationExp != null) { return invocationExp; } assert csPathName != null; } else { checkForInvalidImplicitSourceType(csNameExp); CS2AS.setPathElement(ClassUtil.nonNullState(csPathName), null, null); } if (sourceExp == null) { sourceExp = createImplicitSourceVariableExp(csNameExp, standardLibrary.getOclAnyType()); } OperationCallExp operationCallExp = refreshOperationCallExp(csNameExp, sourceExp); Operation oclInvalidOperation = standardLibrary.getOclInvalidOperation(); context.setReferredOperation(operationCallExp, oclInvalidOperation); if (csPathName != null) { ElementUtil.setLastPathElement(csPathName, oclInvalidOperation); } context.installPivotUsage(csNameExp, operationCallExp); context.setType(operationCallExp, standardLibrary.getOclInvalidType(), false, null); return operationCallExp; } protected void resolveIterationAccumulators(@NonNull RoundBracketedClauseCS csRoundBracketedClause, @NonNull LoopExp expression) { AbstractNameExpCS csNameExp = csRoundBracketedClause.getOwningNameExp(); Iteration iteration = expression.getReferredIteration(); List<Variable> pivotAccumulators = new ArrayList<Variable>(); // // Explicit accumulator // for (NavigatingArgCS csArgument : csRoundBracketedClause.getOwnedArguments()) { if (csArgument.getRole() != NavigationRole.ACCUMULATOR) { continue; } ExpCS csName = csArgument.getOwnedNameExpression(); Variable acc = PivotUtil.getPivot(Variable.class, csName); if (acc != null) { context.installPivotUsage(csArgument, acc); ExpCS csInit = csArgument.getOwnedInitExpression(); if (csInit != null) { OCLExpression initExpression = context.visitLeft2Right(OCLExpression.class, csInit); acc.setOwnedInit(initExpression); TypedRefCS csAccType = csArgument.getOwnedType(); Type initType = initExpression != null ? initExpression.getType() : null; Type accType; if (csAccType != null) { accType = PivotUtil.getPivot(Type.class, csAccType); } else { accType = initType; } context.setType(acc, accType, false, null); } acc.setRepresentedParameter(iteration.getOwnedAccumulators().get(pivotAccumulators.size())); pivotAccumulators.add(acc); } if (csArgument.getOwnedInitExpression() == null) { context.addDiagnostic(csArgument, "Missing initializer for accumulator"); } // if (csArgument.getOwnedType() != null) { // context.addError(csArgument, "Unexpected type for parameter"); // } } // // Implicit Accumulator // if (expression instanceof IterateExp) { IterateExp iterateExp = (IterateExp)expression; if (pivotAccumulators.size() > 1) { context.addDiagnostic(csNameExp, "Iterate '" + csNameExp.getOwnedPathName() + "' cannot have more than one accumulator"); } else { iterateExp.setOwnedResult(pivotAccumulators.get(0)); } } else if (pivotAccumulators.size() > 0) { context.addDiagnostic(csNameExp, "Iteration '" + csNameExp.getOwnedPathName() + "' cannot have an accumulator"); } } protected void resolveIterationBody(@NonNull RoundBracketedClauseCS csRoundBracketedClause, @NonNull LoopExp expression) { AbstractNameExpCS csNameExp = csRoundBracketedClause.getOwningNameExp(); List<OCLExpression> pivotBodies = new ArrayList<OCLExpression>(); boolean hasIteratorOrAccumulator = false; for (NavigatingArgCS csArgument : csRoundBracketedClause.getOwnedArguments()) { if (csArgument.getRole() == NavigationRole.ITERATOR) { hasIteratorOrAccumulator = true; } else if (csArgument.getRole() == NavigationRole.ACCUMULATOR) { hasIteratorOrAccumulator = true; } else if (csArgument.getRole() == NavigationRole.EXPRESSION) { if (csArgument.getOwnedInitExpression() != null) { context.addDiagnostic(csArgument, "Unexpected initializer for expression"); } if (csArgument.getOwnedType() != null) { context.addDiagnostic(csArgument, "Unexpected type for expression"); } ExpCS name = csArgument.getOwnedNameExpression(); assert name != null; // OCLExpression exp = context.visitLeft2Right(OCLExpression.class, name); OCLExpression exp = !hasIteratorOrAccumulator ? PivotUtil.getPivot(OCLExpression.class, csArgument) : context.visitLeft2Right(OCLExpression.class, name); // context.installPivotElement(csArgument, exp); if (exp != null) { context.installPivotUsage(csArgument, exp); pivotBodies.add(exp); } else { pivotBodies.add(context.addBadExpressionError(csArgument, "Invalid '" + csNameExp.getOwnedPathName() + "' iteration body")); } } } if (pivotBodies.size() != 1) { expression.setOwnedBody(context.addBadExpressionError(csNameExp, "Iteration '" + csNameExp.getOwnedPathName() + "' must have exactly one body")); } else { expression.setOwnedBody(pivotBodies.get(0)); } } protected @NonNull LoopExp resolveIterationCallExp(@NonNull AbstractNameExpCS csNameExp, @NonNull OCLExpression sourceExp, @NonNull Iteration iteration) { LoopExp expression; if (iteration.getOwnedAccumulators().size() > 0) { expression = context.refreshModelElement(IterateExp.class, PivotPackage.Literals.ITERATE_EXP, csNameExp); } else { expression = context.refreshModelElement(IteratorExp.class, PivotPackage.Literals.ITERATOR_EXP, csNameExp); } expression.setOwnedSource(sourceExp); context.setReferredIteration(expression, iteration); return expression; } protected void resolveIterationContent(@NonNull RoundBracketedClauseCS csRoundBracketedClause, @NonNull LoopExp expression) { OCLExpression source = ClassUtil.nonNullState(expression.getOwnedSource()); resolveIterationIterators(csRoundBracketedClause, source, expression); resolveIterationAccumulators(csRoundBracketedClause, expression); resolveOperationArgumentTypes(null, csRoundBracketedClause); resolveIterationBody(csRoundBracketedClause, expression); resolveOperationReturnType(expression); } protected void resolveIterationIterators(@NonNull RoundBracketedClauseCS csRoundBracketedClause, @NonNull OCLExpression source, @NonNull LoopExp expression) { AbstractNameExpCS csNameExp = csRoundBracketedClause.getOwningNameExp(); OperatorExpCS csParent = csNameExp.getLocalParent(); boolean isSafe = false; if (csParent instanceof InfixExpCS) { String operatorName = ((InfixExpCS)csParent).getName(); isSafe = PivotConstants.SAFE_AGGREGATE_NAVIGATION_OPERATOR.equals(operatorName); } // boolean isSafe = PivotUtil.isSafeNavigationOperator(navigationOperatorName); Iteration iteration = expression.getReferredIteration(); List<Variable> pivotIterators = new ArrayList<Variable>(); // // Explicit iterators // int iterationIteratorsSize = iteration.getOwnedIterators().size(); int iteratorIndex = 0; CollectionType sourceCollectionType = (CollectionType)csNameExp.getSourceType(); if (sourceCollectionType.isIsNullFree()) { isSafe = true; } Type rawSourceElementType = sourceCollectionType.getElementType(); // if (sourceType.is) Type sourceElementType = rawSourceElementType != null ? metamodelManager.getPrimaryType(rawSourceElementType) : null; for (int argIndex = 0; argIndex < csRoundBracketedClause.getOwnedArguments().size(); argIndex++) { NavigatingArgCS csArgument = csRoundBracketedClause.getOwnedArguments().get(argIndex); if (csArgument.getRole() != NavigationRole.ITERATOR) { continue; } if (iterationIteratorsSize <= argIndex) { context.addWarning(csArgument, PivotMessagesInternal.RedundantIterator_WARNING_, iteration.getName()); continue; } if (csArgument.getOwnedInitExpression() != null) { context.addDiagnostic(csArgument, "Unexpected initializer for iterator"); } // if (csArgument.getOwnedType() == null) { // context.addError(csArgument, "Missing type for iterator"); // } ExpCS csName = csArgument.getOwnedNameExpression(); Variable iterator = PivotUtil.getPivot(Variable.class, csName); if (iterator != null) { context.installPivotUsage(csArgument, iterator); Parameter formalIterator = iteration.getOwnedIterators().get(iteratorIndex); iterator.setRepresentedParameter(formalIterator); Type varType = null; TypedRefCS csType = csArgument.getOwnedType(); boolean iteratorIsRequired = ElementUtil.isRequired(csType); if (csType != null) { varType = PivotUtil.getPivot(Type.class, csType); } if (varType == null) { varType = sourceElementType; } context.setType(iterator, varType, isSafe || iteratorIsRequired || formalIterator.isIsRequired(), null); pivotIterators.add(iterator); iteratorIndex++; } } // // Implicit Iterators // while (iteratorIndex < iterationIteratorsSize) { Parameter formalIterator = iteration.getOwnedIterators().get(iteratorIndex); String varName = Integer.toString(iteratorIndex+1) + "_"; Variable iterator = context.refreshModelElement(Variable.class, PivotPackage.Literals.VARIABLE, null); context.refreshName(iterator, varName); context.setType(iterator, sourceElementType, isSafe || formalIterator.isIsRequired(), null); iterator.setIsImplicit(true); iterator.setRepresentedParameter(formalIterator); pivotIterators.add(iterator); iteratorIndex++; } context.refreshList(expression.getOwnedIterators(), pivotIterators); } /** * Determine the type of each operation argument so that the appropriate operation overload can be selected. * Arguments aligned with type (MetaClass) parameters are set to be parsed as types avoiding ambiguities from * implicit opposite properties. Iterator bodies are left unresolved. */ protected void resolveOperationArgumentTypes(@Nullable List<Parameter> parameters, @NonNull RoundBracketedClauseCS csRoundBracketedClause) { int argIndex = 0; for (NavigatingArgCS csArgument : csRoundBracketedClause.getOwnedArguments()) { if (csArgument.getRole() == NavigationRole.ITERATOR) { break; } else if (csArgument.getRole() == NavigationRole.ACCUMULATOR) { break; } else if (csArgument.getRole() == NavigationRole.EXPRESSION) { ExpCS csName = csArgument.getOwnedNameExpression(); if (csName != null) { OCLExpression arg = null; boolean isType = false; if (csName instanceof NameExpCS) { if ((parameters != null) && argIndex < parameters.size()) { Parameter parameter = parameters.get(argIndex); if (parameter.isIsTypeof() || (parameter.getTypeId() == standardLibrary.getOclTypeType().getTypeId())) { isType = true; NameExpCS csNameExp = (NameExpCS)csName; PathNameCS csPathName = csNameExp.getOwnedPathName(); Type type = context.getConverter().lookupType(csNameExp, ClassUtil.nonNullState(csPathName)); if (type != null) { arg = resolveTypeExp(csNameExp, type); } } } } if (!isType) { arg = context.visitLeft2Right(OCLExpression.class, csName); } if (arg != null) { context.installPivotUsage(csArgument, arg); } } argIndex++; } } } /** * Complete the installation of each operation argument in its operation call. */ protected void resolveOperationArguments(@NonNull RoundBracketedClauseCS csRoundBracketedClause, @NonNull Operation operation, @NonNull OperationCallExp expression) { @SuppressWarnings("null") @NonNull AbstractNameExpCS csNameExp = csRoundBracketedClause.getOwningNameExp(); List<OCLExpression> pivotArguments = new ArrayList<OCLExpression>(); List<NavigatingArgCS> csArguments = csRoundBracketedClause.getOwnedArguments(); List<Parameter> ownedParameters = operation.getOwnedParameters(); int parametersCount = ownedParameters.size(); int csArgumentCount = csArguments.size(); if (csArgumentCount > 0) { if (csArguments.get(0).getRole() != NavigationRole.EXPRESSION) { context.addDiagnostic(csNameExp, "Operation calls can only specify expressions"); } for (int argIndex = 0; argIndex < csArgumentCount; argIndex++) { NavigatingArgCS csArgument = csArguments.get(argIndex); if (csArgument.getOwnedInitExpression() != null) { context.addDiagnostic(csArgument, "Unexpected initializer for expression"); } if (csArgument.getOwnedType() != null) { context.addDiagnostic(csArgument, "Unexpected type for expression"); } OCLExpression arg = PivotUtil.getPivot(OCLExpression.class, csArgument); if (arg != null) { Type argType = arg.getType(); if (argType != null) { Type parameterType = ownedParameters.get(argIndex).getType(); if (parameterType instanceof SelfType) { parameterType = operation.getOwningClass(); } if (parameterType != null) { Operation asCoercion = resolveCoercionFrom(argType, parameterType); if (asCoercion != null) { arg = createCoercionCallExp(arg, asCoercion); } } } pivotArguments.add(arg); } } } if ((csArgumentCount != parametersCount) && (operation != standardLibrary.basicGetOclInvalidOperation())) { String boundMessage = StringUtil.bind(PivotMessagesInternal.MismatchedArgumentCount_ERROR_, csArgumentCount, parametersCount); context.addDiagnostic(csNameExp, boundMessage); } context.refreshList(expression.getOwnedArguments(), pivotArguments); } protected void resolveOperationCall(@NonNull OperationCallExp expression, @NonNull OperatorExpCS csOperator) { String name = expression.getName(); Type sourceType = PivotUtilInternal.getBehavioralType(expression.getOwnedSource()); Operation asOperation = null; Invocations invocations = null; if (!AUTOGENERATED_LOOKUP) { if ((sourceType != null) && (name != null)) { invocations = getInvocations(sourceType, null, name, 0, expression.getOwnedArguments().size()); if ((invocations == null) && name.startsWith("_")) { @SuppressWarnings("null")@NonNull String unescapedName = name.substring(1); // FIXME Compatibility invocations = getInvocations(sourceType, null, unescapedName, 0, expression.getOwnedArguments().size()); } } } /*else { // metamodelManager.getASMetamodel(); // Ensure metamodel has been loaded SingleResultEnvironment env = nameResolver.computeReferredOperationLookup(expression); if (env.getSize() == 1) { asOperation = (Operation) env.getSingleResult(); context.setReferredOperation(expression, asOperation); resolveOperationReturnType(expression); } else if (sourceType != null && env.getSize() > 1) { invocations = new UnresolvedInvocations(sourceType, env.getAllResults()); } }*/ if (invocations != null) { AbstractOperationMatcher matcher = null; if ((csOperator instanceof InfixExpCS) && !NavigationUtil.isNavigationInfixExp(csOperator)) { // explicit: X op Y matcher = new BinaryOperationMatcher(environmentFactory, sourceType, null, ((InfixExpCS) csOperator).getArgument()); } else { // explicit: op X, or implicit: X.oclAsSet()-> matcher = new UnaryOperationMatcher(environmentFactory, sourceType, null); } asOperation = matcher.getBestOperation(invocations, false); if (asOperation != null) { AmbiguitiesAdapter.setAmbiguities(csOperator, matcher.getAmbiguities()); } else { asOperation = matcher.getBestOperation(invocations, true); } context.setReferredOperation(expression, asOperation); resolveOperationReturnType(expression); } if (asOperation == null) { StringBuilder s = new StringBuilder(); for (OCLExpression argument : expression.getOwnedArguments()) { Type argumentType = PivotUtilInternal.getType(argument); if (s.length() > 0) { s.append(","); } if (argumentType != null) { s.append(argumentType.toString()); } } String boundMessage; if (s.length() > 0) { boundMessage = StringUtil.bind(PivotMessagesInternal.UnresolvedOperationCall_ERROR_, sourceType, csOperator.getName(), s.toString()); } else { boundMessage = StringUtil.bind(PivotMessagesInternal.UnresolvedOperation_ERROR_, sourceType, csOperator.getName()); } // context.addBadExpressionError(csOperator, boundMessage); context.addDiagnostic(csOperator, boundMessage); Operation oclInvalidOperation = standardLibrary.getOclInvalidOperation(); context.setReferredOperation(expression, oclInvalidOperation); // ElementUtil.setLastPathElement(csPathName, oclInvalidOperation); context.setType(expression, standardLibrary.getOclInvalidType(), false, null); } } protected @NonNull OperationCallExp resolveOperationCallExp(@NonNull RoundBracketedClauseCS csRoundBracketedClause, @NonNull OperationCallExp operationCallExp, @NonNull Operation operation) { @SuppressWarnings("null")@NonNull AbstractNameExpCS csNameExp = csRoundBracketedClause.getOwningNameExp(); context.setReferredOperation(operationCallExp, operation); resolveAtPre(csNameExp, operationCallExp); context.installPivotUsage(csNameExp, operationCallExp); resolveOperationArguments(csRoundBracketedClause, operation, operationCallExp); resolveOperationReturnType(operationCallExp); return operationCallExp; } protected void resolveOperationReturnType(@NonNull CallExp callExp) { Operation operation = null; if (callExp instanceof OperationCallExp) { operation = ((OperationCallExp)callExp).getReferredOperation(); } else if (callExp instanceof LoopExp) { operation = ((LoopExp)callExp).getReferredIteration(); } if (operation == null) { return; } Type sourceType = null; Type sourceTypeValue = null; OCLExpression source = callExp.getOwnedSource(); if (source != null) { sourceType = source.getType(); sourceTypeValue = source.getTypeValue(); } TemplateParameterSubstitutions templateSubstitutions = TemplateParameterSubstitutionVisitor.createBindings(environmentFactory, sourceType, sourceTypeValue, operation); @SuppressWarnings("unused") // Should never happen; just for debugging boolean isConformant = true; if (callExp instanceof OperationCallExp) { List<Parameter> parameters = operation.getOwnedParameters(); List<OCLExpression> arguments = ((OperationCallExp)callExp).getOwnedArguments(); int iMax = Math.min(parameters.size(), arguments.size()); for (int i = 0; i < iMax; i++) { Parameter parameter = parameters.get(i); OCLExpression argument = arguments.get(i); Type parameterType = PivotUtilInternal.getType(parameter); Type argumentType = PivotUtilInternal.getType(argument); if ((parameterType != null) && (argumentType != null)) { if (!metamodelManager.conformsTo(argumentType, TemplateParameterSubstitutions.EMPTY, parameterType, templateSubstitutions)) { isConformant = false; } } } } else if (callExp instanceof LoopExp) { if (callExp instanceof IterateExp) { List<Parameter> accumulators = ((Iteration)operation).getOwnedAccumulators(); if (accumulators.size() >= 1) { Parameter accumulator = accumulators.get(0); Variable result = ((IterateExp)callExp).getOwnedResult(); Type accumulatorType = PivotUtilInternal.getType(accumulator); Type resultType = PivotUtilInternal.getType(result); if ((accumulatorType != null) && (resultType != null)) { if (!metamodelManager.conformsTo(resultType, TemplateParameterSubstitutions.EMPTY, accumulatorType, templateSubstitutions)) { isConformant = false; } } } } List<Parameter> parameters = ((Iteration)operation).getOwnedParameters(); if (parameters.size() >= 1) { Parameter parameter = parameters.get(0); OCLExpression body = ((LoopExp)callExp).getOwnedBody(); Type parameterType = PivotUtilInternal.getType(parameter); Type bodyType = PivotUtilInternal.getType(body); if ((bodyType != null) && (parameterType != null)) { if (!metamodelManager.conformsTo(bodyType, TemplateParameterSubstitutions.EMPTY, parameterType, templateSubstitutions)) { isConformant = false; } } } } Type returnType = null; Type formalType = operation.getType(); if ((formalType != null) && (sourceType != null)) { if (operation.isIsTypeof()) { returnType = metamodelManager.specializeType(formalType, callExp, sourceType, null); } else { returnType = metamodelManager.specializeType(formalType, callExp, sourceType, source != null ? source.getTypeValue() : null); } } // // The flattening of collect() and consequently implicit-collect is not modelled accurately so we need to code it. // LibraryFeature implementationClass = operation.getImplementation(); if (implementationClass != null) { Class<? extends LibraryFeature> className = implementationClass.getClass(); TemplateParameterSubstitutionHelper helper = TemplateParameterSubstitutionHelper.getHelper(className); if (helper != null) { returnType = helper.resolveReturnType(metamodelManager, callExp, returnType); } } if (operation.isIsTypeof()) { context.setType(callExp, standardLibrary.getClassType(), operation.isIsRequired(), returnType); } else { context.setType(callExp, returnType, operation.isIsRequired(), null); } } protected @NonNull CallExp resolvePropertyCallExp(@NonNull OCLExpression sourceExp, @NonNull NameExpCS csNameExp, @NonNull Property property) { NavigationCallExp callExp; if (property.isIsImplicit()) { callExp = refreshOppositePropertyCallExp(csNameExp, sourceExp, property); } else { callExp = refreshPropertyCallExp(csNameExp, sourceExp, property); } // if (isInvalidType(property.getType())) { // EssentialOCLUtils.setHasError(csNameExp); // } resolveAtPre(csNameExp, callExp); Type returnType = resolvePropertyReturnType(callExp, csNameExp, property); context.setType(callExp, returnType, property.isIsRequired() && !callExp.isIsSafe(), null); return callExp; } protected @Nullable Type resolvePropertyReturnType(@NonNull NavigationCallExp callExp, @NonNull NameExpCS csNameExp, @NonNull Property property) { Type formalType = property.getType(); if (formalType == null) { return null; } OCLExpression source = callExp.getOwnedSource(); Type actualType; Type sourceType = source != null ? source.getType() : null; if (sourceType != null) { actualType = metamodelManager.specializeType(formalType, callExp, sourceType, source != null ? source.getTypeValue() : null); } else { actualType = formalType; } if (property.isIsStatic() && (actualType.isTemplateParameter() != null)) { actualType = metamodelManager.getMetaclass(actualType); } return actualType; } protected Element resolveRoundBracketedTerm(@NonNull RoundBracketedClauseCS csRoundBracketedClause) { AbstractNameExpCS csNameExp = csRoundBracketedClause.getOwningNameExp(); OperatorExpCS csParent = csNameExp.getLocalParent(); if (NavigationUtil.isNavigationInfixExp(csParent) && (csParent != null) && (csNameExp != ((InfixExpCS)csParent).getSource())) { // source.name(), source->name() are resolved by the parent NavigationOperatorCS return PivotUtil.getPivot(OCLExpression.class, csNameExp); } return resolveInvocation(null, csRoundBracketedClause); } protected @Nullable OCLExpression resolveShadowExp(@NonNull NameExpCS csNameExp) { PathNameCS pathName = csNameExp.getOwnedPathName(); if (pathName == null) { return null; } CurlyBracketedClauseCS csCurlyBracketedClause = csNameExp.getOwnedCurlyBracketedClause(); RoundBracketedClauseCS csRoundBracketedClause = csNameExp.getOwnedRoundBracketedClause(); if (csRoundBracketedClause != null) { // FIXME (TemplateTypeArgument) return context.addBadExpressionError(csNameExp, "ConstructorExp must have no round-brackets-clause"); } if (csNameExp.getOwnedSquareBracketedClauses().size() != 0) { return context.addBadExpressionError(csNameExp, "ConstructorExp must have no square-brackets-clause"); } Type asType = context.lookupType(csNameExp, pathName); @NonNull ShadowExp pivotElement = context.refreshModelElement(ShadowExp.class, PivotPackage.Literals.SHADOW_EXP, csNameExp); pivotElement.setValue(csCurlyBracketedClause.getValue()); pivotElement.setType(asType); for (ShadowPartCS csPart : csCurlyBracketedClause.getOwnedParts()) { assert csPart != null; context.visitLeft2Right(ShadowPart.class, csPart); } context.refreshPivotList(ShadowPart.class, pivotElement.getOwnedParts(), csCurlyBracketedClause.getOwnedParts()); return pivotElement; } protected Element resolveSimpleNameExp(@NonNull NameExpCS csNameExp, @NonNull Element element) { if (element instanceof VariableDeclaration) { return resolveVariableExp(csNameExp, (VariableDeclaration)element); } else if (element instanceof Property) { Property property = (Property) element; OCLExpression sourceExp = createImplicitSourceVariableExp(csNameExp, property.getOwningClass()); return resolvePropertyCallExp(sourceExp, csNameExp, property); } else if (element instanceof Operation) { return context.addBadExpressionError(csNameExp, "No parameters for operation " + ((Operation)element).getName()); } else if (element instanceof Type) { return resolveTypeExp(csNameExp, (Type) element); } else if (element instanceof EnumerationLiteral) { return resolveEnumLiteral(csNameExp, (EnumerationLiteral) element); } else if (element instanceof State) { return resolveStateExp(csNameExp, (State) element); } else { return context.addBadExpressionError(csNameExp, "Unsupported NameExpCS " + element.eClass().getName()); // FIXME } } protected StateExp resolveStateExp(@NonNull ExpCS csExp, @NonNull State state) { StateExp expression = context.refreshModelElement(StateExp.class, PivotPackage.Literals.STATE_EXP, csExp); context.setType(expression, metamodelManager.getASClass("State"), true, null); // FIXME What should this be expression.setReferredState(state); return expression; } protected @NonNull TypeExp resolveTypeExp(@NonNull ExpCS csExp, @NonNull Type type) { TypeExp expression = context.refreshModelElement(TypeExp.class, PivotPackage.Literals.TYPE_EXP, csExp); context.setType(expression, standardLibrary.getClassType(), true, type); expression.setReferredType(type); return expression; } protected @NonNull VariableExp resolveVariableExp(@NonNull NameExpCS csNameExp, @NonNull VariableDeclaration variableDeclaration) { VariableExp expression = context.refreshModelElement(VariableExp.class, PivotPackage.Literals.VARIABLE_EXP, csNameExp); expression.setReferredVariable(variableDeclaration); context.setType(expression, variableDeclaration.getType(), variableDeclaration.isIsRequired(), variableDeclaration.getTypeValue()); return expression; } @Override public Element visitBooleanLiteralExpCS(@NonNull BooleanLiteralExpCS csBooleanLiteralExp) { BooleanLiteralExp expression = PivotUtil.getPivot(BooleanLiteralExp.class, csBooleanLiteralExp); if (expression != null) { expression.setBooleanSymbol(Boolean.valueOf(csBooleanLiteralExp.getSymbol())); context.setType(expression, standardLibrary.getBooleanType(), true, null); } return expression; } @Override public Element visitCollectionLiteralExpCS(@NonNull CollectionLiteralExpCS csCollectionLiteralExp) { Type commonType = null; // InvalidLiteralExp invalidValue = null; boolean isNullFree = true; for (CollectionLiteralPartCS csPart : csCollectionLiteralExp.getOwnedParts()) { assert csPart != null; CollectionLiteralPart pivotPart = context.visitLeft2Right(CollectionLiteralPart.class, csPart); Type asType = pivotPart != null ? pivotPart.getType() : null; Type type = asType != null ? PivotUtilInternal.getType(asType) : null; // if (type instanceof InvalidType) { // FIXME Use propagated reason via InvalidType // if (invalidValue == null) { // invalidValue = metamodelManager.createInvalidValue(csPart, null, "Invalid Collection content", null); // } // } // else if (type != null) { if (commonType == null) { commonType = type; } else if (commonType != type) { commonType = metamodelManager.getCommonType(commonType, TemplateParameterSubstitutions.EMPTY, type, TemplateParameterSubstitutions.EMPTY); } } if (pivotPart instanceof CollectionItem) { if ((((CollectionItem)pivotPart).getOwnedItem() instanceof NullLiteralExp)) { isNullFree = false; } } else if (pivotPart instanceof CollectionRange) { ; } else { isNullFree = false; } } // if (invalidValue != null) { // context.installPivotElement(csCollectionLiteralExp, invalidValue); // return invalidValue; // } CollectionLiteralExp expression = PivotUtil.getPivot(CollectionLiteralExp.class, csCollectionLiteralExp); if (expression != null) { CollectionTypeCS ownedCollectionType = csCollectionLiteralExp.getOwnedType(); String collectionTypeName = ownedCollectionType.getName(); assert collectionTypeName != null; TypedRefCS ownedElementType = ownedCollectionType.getOwnedType(); if (ownedElementType != null) { commonType = (Type) ownedElementType.getPivot(); } if (commonType == null) { commonType = standardLibrary.getOclVoidType(); } Type type = metamodelManager.getCollectionType(collectionTypeName, commonType, isNullFree, null, null); context.setType(expression, type, true, null); expression.setKind(TypeUtil.getCollectionKind((CollectionType) type)); } return expression; } @Override public Element visitCollectionLiteralPartCS(@NonNull CollectionLiteralPartCS csCollectionLiteralPart) { ExpCS csFirst = csCollectionLiteralPart.getOwnedExpression(); if (csFirst == null) { return null; } OCLExpression pivotFirst = context.visitLeft2Right(OCLExpression.class, csFirst); OCLExpression pivotLast = null; ExpCS csLast = csCollectionLiteralPart.getOwnedLastExpression(); if (csLast == null) { CollectionItem expression = PivotUtil.getPivot(CollectionItem.class, csCollectionLiteralPart); if (expression != null) { expression.setOwnedItem(pivotFirst); } } else { CollectionRange expression = PivotUtil.getPivot(CollectionRange.class, csCollectionLiteralPart); if (expression != null) { expression.setOwnedFirst(pivotFirst); pivotLast = context.visitLeft2Right(OCLExpression.class, csLast); expression.setOwnedLast(pivotLast); } } if (pivotFirst == null) { return null; } Type type = pivotFirst.getType(); if (type == null) { return null; } boolean isRequired = pivotFirst.isIsRequired(); if (pivotLast != null) { Type secondType = pivotLast.getType(); if (secondType != null) { type = metamodelManager.getCommonType(type, TemplateParameterSubstitutions.EMPTY, secondType, TemplateParameterSubstitutions.EMPTY); } isRequired &= pivotLast.isIsRequired(); } CollectionLiteralPart expression = PivotUtil.getPivot(CollectionLiteralPart.class, csCollectionLiteralPart); if (expression != null) { context.setType(expression, type, isRequired); } return expression; } @Override public Element visitCollectionTypeCS(@NonNull CollectionTypeCS object) { return null; } @Override public Element visitContextCS(@NonNull ContextCS csContext) { ExpressionInOCL pivotElement = PivotUtil.getPivot(ExpressionInOCL.class, csContext); if (pivotElement != null) { ExpCS csExpression = csContext.getOwnedExpression(); if (csExpression != null) { pivotElement.setBody(csExpression.toString()); OCLExpression expression = context.visitLeft2Right(OCLExpression.class, csExpression); if (expression != null) { PivotUtil.setBody(pivotElement, expression, ElementUtil.getExpressionText(csExpression)); context.setType(pivotElement, expression.getType(), expression.isIsRequired()); } } else { pivotElement.setBody(null); } } return pivotElement; } @Override public Element visitExpCS(@NonNull ExpCS object) { return null; } @Override public Element visitIfExpCS(@NonNull IfExpCS csIfExp) { IfExp expression = PivotUtil.getPivot(IfExp.class, csIfExp); if (expression != null) { ExpCS csIf = csIfExp.getOwnedCondition(); ExpCS csThen = csIfExp.getOwnedThenExpression(); ExpCS csElse = csIfExp.getOwnedElseExpression(); if ((csIf != null) && (csThen != null) && (csElse != null)) { expression.setOwnedCondition(context.visitLeft2Right(OCLExpression.class, csIf)); OCLExpression thenExpression = context.visitLeft2Right(OCLExpression.class, csThen); expression.setOwnedThen(thenExpression); OCLExpression elseExpression = context.visitLeft2Right(OCLExpression.class, csElse); expression.setOwnedElse(elseExpression); Type thenType = thenExpression != null ? thenExpression.getType() : null; Type elseType = elseExpression != null ? elseExpression.getType() : null; Type thenTypeValue = thenExpression != null ? thenExpression.getTypeValue() : null; Type elseTypeValue = elseExpression != null ? elseExpression.getTypeValue() : null; Type commonType = (thenType != null) && (elseType != null) ? metamodelManager.getCommonType(thenType, TemplateParameterSubstitutions.EMPTY, elseType, TemplateParameterSubstitutions.EMPTY) : null; Type commonTypeValue = (thenTypeValue != null) && (elseTypeValue != null) ? metamodelManager.getCommonType(thenTypeValue, TemplateParameterSubstitutions.EMPTY, elseTypeValue, TemplateParameterSubstitutions.EMPTY) : null; boolean isRequired = ((thenExpression != null) && thenExpression.isIsRequired()) && ((elseExpression != null) && elseExpression.isIsRequired()); context.setType(expression, commonType, isRequired, commonTypeValue); } } return expression; } @Override public Element visitInfixExpCS(@NonNull InfixExpCS csInfixExp) { // // If this is a new Operation tree start at its root. // OperatorExpCS csRoot = getRoot(csInfixExp); if (csRoot != currentRoot) { OperatorExpCS savedCurrentRoot = currentRoot; try { currentRoot = csRoot; OCLExpression pivot = context.visitLeft2Right(OCLExpression.class, csRoot); assert csRoot.getPivot() == pivot; return pivot; } finally { currentRoot = savedCurrentRoot; } } OCLExpression pivot; if (NavigationUtil.isNavigationInfixExp(csInfixExp)) { pivot = doVisitNavigationOperatorCS(csInfixExp); } else { pivot = doVisitBinaryOperatorCS(csInfixExp); } assert csInfixExp.getPivot() == pivot; // if (pivot != null) { // context.installPivotUsage(csInfixExp, pivot); // } return pivot; } protected @NonNull OCLExpression doVisitBinaryOperatorCS(@NonNull InfixExpCS csOperator) { OperationCallExp expression = context.refreshModelElement(OperationCallExp.class, PivotPackage.Literals.OPERATION_CALL_EXP, csOperator); String name = csOperator.getName(); assert name != null; context.refreshName(expression, name); ExpCS csSource = csOperator.getSource(); if (csSource != null) { OCLExpression source = context.visitLeft2Right(OCLExpression.class, csSource); expression.setOwnedSource(source); ExpCS csArgument = csOperator.getArgument(); if (csArgument != null) { OCLExpression argument = context.visitLeft2Right(OCLExpression.class, csArgument); List<? extends OCLExpression> newElements = argument != null ? Collections.singletonList(argument) : Collections.<OCLExpression>emptyList(); context.refreshList(expression.getOwnedArguments(), newElements); Type sourceType = PivotUtilInternal.getType(source); Type argumentType = PivotUtilInternal.getType(argument); if ((sourceType != null) && (argumentType != null)) { resolveOperationCall(expression, csOperator); } } } return expression; } protected OCLExpression doVisitNavigationOperatorCS(@NonNull InfixExpCS csOperator) { OCLExpression navigatingExp = null; ExpCS csSource = csOperator.getSource(); if (csSource != null) { OCLExpression sourceExp = context.visitLeft2Right(OCLExpression.class, csSource); if (sourceExp != null) { Type asType = sourceExp.getType(); Type actualSourceType = asType != null ? PivotUtilInternal.getType(asType) : null; if (actualSourceType != null) { ExpCS argument = csOperator.getArgument(); if (argument instanceof NameExpCS) { NameExpCS csNameExp = (NameExpCS) argument; LoopExp implicitCollectExp = null; OCLExpression collectedSourceExp = sourceExp; // // Condition the source for implicit set or implicit collect // String navigationOperatorName = csOperator.getName(); if (PivotUtil.isAggregate(actualSourceType)) { if (PivotUtil.isObjectNavigationOperator(navigationOperatorName)) { implicitCollectExp = resolveImplicitCollect(sourceExp, csOperator); if (implicitCollectExp != null) { @SuppressWarnings("null")@NonNull Variable iterator = implicitCollectExp.getOwnedIterators().get(0); collectedSourceExp = createImplicitVariableExp(iterator); } } } else { if (PivotUtil.isAggregateNavigationOperator(navigationOperatorName)) { collectedSourceExp = resolveImplicitAsSet(sourceExp, actualSourceType, csOperator); } } Type sourceType = collectedSourceExp.getType(); csNameExp.setSourceType(sourceType); csNameExp.setSourceTypeValue(collectedSourceExp.getTypeValue()); // // Resolve the inner call expression // OCLExpression callExp; RoundBracketedClauseCS csRoundBracketedClause = csNameExp.getOwnedRoundBracketedClause(); if (csRoundBracketedClause != null) { callExp = resolveInvocation(collectedSourceExp, csRoundBracketedClause); } else if (argument instanceof NameExpCS) { callExp = resolveExplicitSourceNavigation(collectedSourceExp, (NameExpCS) argument); } else { callExp = context.addBadExpressionError(argument, "bad navigation argument"); } // // Complete the wrapping of the inner call expression in an outer implicit collect expression // if (callExp instanceof CallExp) { boolean isSafe = PivotUtil.isSafeNavigationOperator(navigationOperatorName); // ((CallExp) callExp).setIsSafe(isSafe && (implicitCollectExp == null)); // if (isSafe) { // callExp.setIsRequired(true); // FIXME Why? // } if (implicitCollectExp != null) { implicitCollectExp.setOwnedBody(callExp); resolveOperationReturnType(implicitCollectExp); navigatingExp = implicitCollectExp; } else { ((CallExp) callExp).setIsSafe(isSafe); navigatingExp = callExp; } } else { navigatingExp = callExp; // Place holder for an error } } else if (argument != null) { navigatingExp = context.addBadExpressionError(argument, "bad navigation argument"); } } } if (navigatingExp != null) { context.installPivotUsage(csOperator, navigatingExp); } } return navigatingExp; } @Override public Element visitInvalidLiteralExpCS(@NonNull InvalidLiteralExpCS csInvalidLiteralExp) { InvalidLiteralExp expression = PivotUtil.getPivot(InvalidLiteralExp.class, csInvalidLiteralExp); if (expression == null) { expression = metamodelManager.createInvalidExpression(); } // expression.setType(metamodelManager.getOclInvalidType()); context.installPivotUsage(csInvalidLiteralExp, expression); return expression; } @Override public Element visitLetExpCS(@NonNull LetExpCS csLetExp) { // Each CS Let Variable becomes a Pivot LetExpression and Variable // The CS Let therefore just re-uses the Pivot of the first CS Let Variable LetExp firstLetExp = null; LetExp lastLetExp = null; for (LetVariableCS csLetVariable : csLetExp.getOwnedVariables()) { Variable variable = PivotUtil.getPivot(Variable.class, csLetVariable); if (variable != null) { LetExp letExp; EObject variableContainer = variable.eContainer(); if (variableContainer instanceof LetExp) { letExp = (LetExp)variableContainer; } else { letExp = context.refreshModelElement(LetExp.class, PivotPackage.Literals.LET_EXP, null); // FIXME reuse } letExp.setOwnedVariable(variable); ExpCS csInitExpression = csLetVariable.getOwnedInitExpression(); if (csInitExpression != null) { TypedRefCS csVariableType = csLetVariable.getOwnedType(); Type variableType = csVariableType != null ? PivotUtil.getPivot(Type.class, csVariableType) : null; boolean variableIsRequired = ElementUtil.isRequired(csVariableType); boolean initIsRequired = false; OCLExpression initExpression = context.visitLeft2Right(OCLExpression.class, csInitExpression); Type initType = null; Type initTypeValue = null; if (initExpression != null) { initType = initExpression.getType(); initTypeValue = initExpression.getTypeValue(); initIsRequired = initExpression.isIsRequired(); if ((initType != null) && (variableType != null)) { Operation asCoercion = resolveCoercionFrom(initType, variableType); if (asCoercion != null) { initExpression = createCoercionCallExp(initExpression, asCoercion); } } } variable.setOwnedInit(initExpression); if (variableType == null) { variableType = initType; } context.setType(variable, variableType, initIsRequired || variableIsRequired, initTypeValue); if (lastLetExp != null) { lastLetExp.setOwnedIn(letExp); context.installPivotUsage(csLetExp, letExp); } else { firstLetExp = letExp; context.installPivotUsage(csLetExp, firstLetExp); } lastLetExp = letExp; } } } if (lastLetExp != null) { ExpCS csIn = csLetExp.getOwnedInExpression(); if (csIn != null) { OCLExpression in = context.visitLeft2Right(OCLExpression.class, csIn); lastLetExp.setOwnedIn(in); if (in != null) { Type type = in.getType(); for (OCLExpression letExp = firstLetExp; (letExp != in) && (letExp != null); letExp = ((LetExp)letExp).getOwnedIn()) { context.setType(letExp, type, in.isIsRequired(), in.getTypeValue()); } } } } return firstLetExp; } @Override public Element visitLetVariableCS(@NonNull LetVariableCS csLetVariable) { return null; // Handled by parent } @Override public Element visitMapLiteralExpCS(@NonNull MapLiteralExpCS csMapLiteralExp) { Type commonKeyType = null; Type commonValueType = null; // InvalidLiteralExp invalidValue = null; for (MapLiteralPartCS csPart : csMapLiteralExp.getOwnedParts()) { assert csPart != null; MapLiteralPart pivotPart = context.visitLeft2Right(MapLiteralPart.class, csPart); if (pivotPart != null) { OCLExpression asKey = pivotPart.getOwnedKey(); if (asKey != null) { Type asKeyType = asKey.getType(); if (asKeyType != null) { if (commonKeyType == null) { commonKeyType = asKeyType; } else if (commonKeyType != asKeyType) { commonKeyType = metamodelManager.getCommonType(commonKeyType, TemplateParameterSubstitutions.EMPTY, asKeyType, TemplateParameterSubstitutions.EMPTY); } } } OCLExpression asValue = pivotPart.getOwnedValue(); if (asValue != null) { Type asValueType = asValue.getType(); if (asValueType != null) { if (commonValueType == null) { commonValueType = asValueType; } else if (commonValueType != asValueType) { commonValueType = metamodelManager.getCommonType(commonValueType, TemplateParameterSubstitutions.EMPTY, asValueType, TemplateParameterSubstitutions.EMPTY); } } } } } MapLiteralExp expression = PivotUtil.getPivot(MapLiteralExp.class, csMapLiteralExp); if (expression != null) { MapTypeCS ownedMapType = csMapLiteralExp.getOwnedType(); String mapTypeName = ownedMapType.getName(); assert mapTypeName != null; TypedRefCS ownedKeyType = ownedMapType.getOwnedKeyType(); if (ownedKeyType != null) { commonKeyType = (Type) ownedKeyType.getPivot(); } TypedRefCS ownedValueType = ownedMapType.getOwnedValueType(); if (ownedValueType != null) { commonValueType = (Type) ownedValueType.getPivot(); } if (commonKeyType == null) { commonKeyType = standardLibrary.getOclVoidType(); } if (commonValueType == null) { commonValueType = standardLibrary.getOclVoidType(); } Type type = metamodelManager.getMapType(mapTypeName, commonKeyType, commonValueType); context.setType(expression, type, true, null); } return expression; } @Override public Element visitMapLiteralPartCS(@NonNull MapLiteralPartCS csMapLiteralPart) { ExpCS csKey = csMapLiteralPart.getOwnedKey(); ExpCS csValue = csMapLiteralPart.getOwnedValue(); if ((csKey == null) || (csValue == null)) { return null; } OCLExpression asKey = context.visitLeft2Right(OCLExpression.class, csKey); OCLExpression asValue = context.visitLeft2Right(OCLExpression.class, csValue); MapLiteralPart expression = PivotUtil.getPivot(MapLiteralPart.class, csMapLiteralPart); if (expression != null) { expression.setOwnedKey(asKey); expression.setOwnedValue(asValue); } return expression; } @Override public Element visitMapTypeCS(@NonNull MapTypeCS object) { return null; } @Override public Element visitNameExpCS(@NonNull NameExpCS csNameExp) { PathNameCS csPathName = csNameExp.getOwnedPathName(); if (csPathName == null) { return context.addBadExpressionError(csNameExp, "Missing path name"); } RoundBracketedClauseCS csRoundBracketedClause = csNameExp.getOwnedRoundBracketedClause(); if (csNameExp.getOwnedCurlyBracketedClause() != null) { return resolveShadowExp(csNameExp); } else if (csNameExp.getOwnedSquareBracketedClauses().size() > 0) { return resolveAssociationClassCallExp(csNameExp); } else if (csRoundBracketedClause != null) { return resolveRoundBracketedTerm(csRoundBracketedClause); } checkForInvalidImplicitSourceType(csNameExp); // csNameExp.getPathName().get Element element = context.lookupUndecoratedName(csNameExp, csPathName); if ((element == null) || element.eIsProxy()) { Element pivot = csNameExp.getPivot(); if (pivot instanceof InvalidLiteralExp) { return pivot; } InvalidLiteralExp invalidLiteralExp = metamodelManager.createInvalidExpression(); context.installPivotUsage(csNameExp, invalidLiteralExp); return invalidLiteralExp; } return resolveSimpleNameExp(csNameExp, element); } @Override public Element visitNavigatingArgCS(@NonNull NavigatingArgCS csNavigatingArg) { OCLExpression pivot = PivotUtil.getPivot(OCLExpression.class, csNavigatingArg.getOwnedNameExpression()); if (pivot != null) { context.installPivotUsage(csNavigatingArg, pivot); } return pivot; } @Override public Element visitNestedExpCS(@NonNull NestedExpCS csNestedExp) { ExpCS csSource = csNestedExp.getOwnedExpression(); if (csSource == null) { return null; } OCLExpression pivot = context.visitLeft2Right(OCLExpression.class, csSource); if (pivot != null) { context.installPivotUsage(csNestedExp, pivot); } return pivot; } @Override public Element visitNullLiteralExpCS(@NonNull NullLiteralExpCS csNullLiteralExp) { NullLiteralExp expression = PivotUtil.getPivot(NullLiteralExp.class, csNullLiteralExp); if (expression != null) { context.setType(expression, standardLibrary.getOclVoidType(), false, null); } return expression; } @Override public Element visitNumberLiteralExpCS(@NonNull NumberLiteralExpCS csNumberLiteralExp) { NumericLiteralExp expression = PivotUtil.getPivot(NumericLiteralExp.class, csNumberLiteralExp); if (expression instanceof UnlimitedNaturalLiteralExp) { context.setType(expression, standardLibrary.getUnlimitedNaturalType(), true, null); } else if (expression instanceof IntegerLiteralExp) { context.setType(expression, standardLibrary.getIntegerType(), true, null); } else if (expression != null){ context.setType(expression, standardLibrary.getRealType(), true, null); } return expression; } @Override public Element visitPrefixExpCS(@NonNull PrefixExpCS csPrefixExp) { // // If this is a new Operation tree start at its root. // OperatorExpCS csRoot = getRoot(csPrefixExp); if (csRoot != currentRoot) { OperatorExpCS savedCurrentRoot = currentRoot; try { currentRoot = csRoot; OCLExpression pivot = context.visitLeft2Right(OCLExpression.class, csRoot); assert csRoot.getPivot() == pivot; return pivot; } finally { currentRoot = savedCurrentRoot; } } OperationCallExp asCallExp = context.refreshModelElement(OperationCallExp.class, PivotPackage.Literals.OPERATION_CALL_EXP, csPrefixExp); context.refreshName(asCallExp, csPrefixExp.getName()); ExpCS csSource = csPrefixExp.getSource(); if (csSource != null) { OCLExpression source = context.visitLeft2Right(OCLExpression.class, csSource); if (source != null) { asCallExp.setOwnedSource(source); Type sourceType = PivotUtilInternal.getType(source); if (sourceType != null) { resolveOperationCall(asCallExp, csPrefixExp); } } } assert csPrefixExp.getPivot() == asCallExp; return asCallExp; } @Override public Element visitSelfExpCS(@NonNull SelfExpCS csSelfExp) { // FIXME Just use VariableExpCS VariableExp expression = PivotUtil.getPivot(VariableExp.class, csSelfExp); if (expression != null) { ElementCS parent = csSelfExp.getParent(); if (parent != null) { VariableDeclaration variableDeclaration = context.getConverter().lookupSelf(parent); if (variableDeclaration == null) { return context.addBadExpressionError(csSelfExp, "The context of 'self' is unspecified"); } expression.setReferredVariable(variableDeclaration); context.setType(expression, variableDeclaration.getType(), true, variableDeclaration.getTypeValue()); } } return expression; } @Override public Element visitShadowPartCS(@NonNull ShadowPartCS csShadowPart) { ShadowPart pivotElement = PivotUtil.getPivot(ShadowPart.class, csShadowPart); if (pivotElement != null) { Property property = csShadowPart.getReferredProperty(); pivotElement.setReferredProperty(property); context.refreshName(pivotElement, property.getName()); context.setType(pivotElement, property.getType(), property.isIsRequired()); ExpCS csInitExpression = csShadowPart.getOwnedInitExpression(); if (csInitExpression != null) { OCLExpression initExpression = context.visitLeft2Right(OCLExpression.class, csInitExpression); pivotElement.setOwnedInit(initExpression); } } return pivotElement; } @Override public Element visitStringLiteralExpCS(@NonNull StringLiteralExpCS csStringLiteralExp) { StringLiteralExp pivotElement = PivotUtil.getPivot(StringLiteralExp.class, csStringLiteralExp); if (pivotElement != null) { context.setType(pivotElement, standardLibrary.getStringType(), true, null); } return pivotElement; } @Override public Element visitTupleLiteralExpCS(@NonNull TupleLiteralExpCS csTupleLiteralExp) { TupleLiteralExp expression = PivotUtil.getPivot(TupleLiteralExp.class, csTupleLiteralExp); if (expression != null) { for (TupleLiteralPartCS csPart : csTupleLiteralExp.getOwnedParts()) { assert csPart != null; context.visitLeft2Right(TupleLiteralPart.class, csPart); } String tupleTypeName = "Tuple"; //ownedCollectionType.getName(); List<@NonNull TupleLiteralPart> parts = ClassUtil.nullFree(expression.getOwnedParts()); assert parts != null; Type type = standardLibrary.getCompleteModel().getTupleType(tupleTypeName, parts, null); context.setType(expression, type, true, null); } return expression; } @Override public Element visitTupleLiteralPartCS(@NonNull TupleLiteralPartCS csTupleLiteralPart) { TupleLiteralPart pivotElement = PivotUtil.getPivot(TupleLiteralPart.class, csTupleLiteralPart); if (pivotElement != null) { ExpCS csInitExpression = csTupleLiteralPart.getOwnedInitExpression(); if (csInitExpression != null) { OCLExpression initExpression = context.visitLeft2Right(OCLExpression.class, csInitExpression); pivotElement.setOwnedInit(initExpression); TypedRefCS csType = csTupleLiteralPart.getOwnedType(); Type type = csType != null ? PivotUtil.getPivot(Type.class, csType) : initExpression != null ? initExpression.getType() : null; context.setType(pivotElement, type, (initExpression != null) && initExpression.isIsRequired(), null); } } return pivotElement; } @Override public Element visitTypeLiteralExpCS(@NonNull TypeLiteralExpCS csTypeLiteralExp) { TypedRefCS csType = csTypeLiteralExp.getOwnedType(); // context.visitInOrder(csType, null); Type type = PivotUtil.getPivot(Type.class, csType); return type != null ? resolveTypeExp(csTypeLiteralExp, type) : null; } @Override public Element visitUnlimitedNaturalLiteralExpCS(@NonNull UnlimitedNaturalLiteralExpCS csUnlimitedNaturalLiteralExp) { UnlimitedNaturalLiteralExp expression = PivotUtil.getPivot(UnlimitedNaturalLiteralExp.class, csUnlimitedNaturalLiteralExp); if (expression != null) { context.setType(expression, standardLibrary.getUnlimitedNaturalType(), true, null); } return expression; } @Override public Element visitVariableCS(@NonNull VariableCS csVariable) { Variable variable = PivotUtil.getPivot(Variable.class, csVariable); if (variable != null) { OCLExpression initExpression = PivotUtil.getPivot(OCLExpression.class, csVariable.getOwnedInitExpression()); if (initExpression != null) { Type initType = initExpression.getType(); TypedRefCS csType = csVariable.getOwnedType(); Type type; if (csType != null) { type = PivotUtil.getPivot(Type.class, csType); } else { type = initType; // FIXME deduction is more complex than this } context.setType(variable, type, initExpression.isIsRequired(), initExpression.getTypeValue()); } variable.setOwnedInit(initExpression); } return variable; } }