| /******************************************************************************* |
| * 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.common.util.TreeIterator; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.ocl.pivot.AbstractIfExp; |
| 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.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.IfPatternExp; |
| 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.LambdaCallExp; |
| import org.eclipse.ocl.pivot.LambdaLiteralExp; |
| import org.eclipse.ocl.pivot.LambdaType; |
| 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.ParameterType; |
| import org.eclipse.ocl.pivot.PatternClass; |
| import org.eclipse.ocl.pivot.PatternExp; |
| import org.eclipse.ocl.pivot.PatternValue; |
| 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.RealLiteralExp; |
| 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.utilities.ValueUtil; |
| import org.eclipse.ocl.pivot.values.IntegerValue; |
| import org.eclipse.ocl.pivot.values.RealValue; |
| import org.eclipse.ocl.pivot.values.TemplateParameterSubstitutions; |
| import org.eclipse.ocl.pivot.values.UnlimitedNaturalValue; |
| 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.MultiplicityCS; |
| 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.IfThenExpCS; |
| import org.eclipse.ocl.xtext.essentialoclcs.InfixExpCS; |
| import org.eclipse.ocl.xtext.essentialoclcs.InvalidLiteralExpCS; |
| import org.eclipse.ocl.xtext.essentialoclcs.LambdaLiteralExpCS; |
| 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.PatternExpCS; |
| 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 class Range implements Comparable<Range> |
| { |
| public @NonNull RealValue lower; |
| public @Nullable RealValue upper; // null for unlimited |
| |
| public Range(@NonNull RealValue lower, @Nullable RealValue upper) { |
| this.lower = lower; |
| this.upper = upper; |
| } |
| |
| @Override |
| public int compareTo(Range o) { |
| return lower.compareTo(o.lower); |
| } |
| |
| @Override |
| public String toString() { |
| return lower.toString() + ".." + (upper != null ? upper.toString() : "*"); |
| } |
| } |
| |
| 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; |
| } |
| } |
| } |
| |
| /** |
| * Return the number of items in parts when uniqueness is not applied. |
| * <p> |
| * Return a non-negative number for a statically deterministic number of parts. |
| */ |
| protected @NonNull Range computeNonUniqueItemsSize(@NonNull List<CollectionLiteralPart> parts) { |
| IntegerValue minSize = ValueUtil.ZERO_VALUE; |
| IntegerValue maxSize = ValueUtil.ZERO_VALUE; // null if unlimited |
| for (CollectionLiteralPart part : parts) { |
| if (part instanceof CollectionRange) { |
| CollectionRange collectionRange = (CollectionRange)part; |
| OCLExpression firstExpression = collectionRange.getOwnedFirst(); |
| OCLExpression lastExpression = collectionRange.getOwnedLast(); |
| if ((firstExpression instanceof IntegerLiteralExp) && (lastExpression instanceof IntegerLiteralExp)) { |
| IntegerValue first = ValueUtil.integerValueOf(((IntegerLiteralExp)firstExpression).getIntegerSymbol()); |
| IntegerValue last = ValueUtil.integerValueOf(((IntegerLiteralExp)lastExpression).getIntegerSymbol()); |
| IntegerValue rangeMinusOne = last.subtractInteger(first); |
| if (rangeMinusOne.signum() >= 0) { |
| IntegerValue range = rangeMinusOne.addInteger(ValueUtil.ONE_VALUE); |
| minSize = minSize.addInteger(range); |
| if (maxSize != null) { |
| maxSize = maxSize.addInteger(range); |
| } |
| } |
| } |
| else { |
| maxSize = null; |
| } |
| } |
| else { |
| minSize = minSize.addInteger(ValueUtil.ONE_VALUE); |
| if (maxSize != null) { |
| maxSize = maxSize.addInteger(ValueUtil.ONE_VALUE); |
| } |
| } |
| } |
| return new Range(minSize, maxSize); |
| } |
| |
| /** |
| * Return the number of items in parts when uniqueness is applied. |
| * <p> |
| * Return a non-negative number for a statically deterministic number of parts. |
| */ |
| protected @NonNull Range computeUniqueItemsSize(@NonNull List<CollectionLiteralPart> parts) { // FIXME unique |
| boolean hasIndeterminateItems = false; |
| RealValue maxSize = ValueUtil.ZERO_VALUE; // null if unlimited |
| List<Range> ranges = new ArrayList<Range>(); |
| for (CollectionLiteralPart part : parts) { |
| if (part instanceof CollectionRange) { |
| CollectionRange collectionRange = (CollectionRange)part; |
| OCLExpression firstExpression = collectionRange.getOwnedFirst(); |
| OCLExpression lastExpression = collectionRange.getOwnedLast(); |
| if ((firstExpression instanceof IntegerLiteralExp) && (lastExpression instanceof IntegerLiteralExp)) { |
| IntegerValue first = ValueUtil.integerValueOf(((IntegerLiteralExp)firstExpression).getIntegerSymbol()); |
| IntegerValue last = ValueUtil.integerValueOf(((IntegerLiteralExp)lastExpression).getIntegerSymbol()); |
| if (last.compareTo(first) >= 0) { |
| ranges.add(new Range(first, last)); // last >= first is a range of last+1-first elements, assess overlaps |
| } |
| else { |
| // last < first is a redundant range, ignore it |
| } |
| } |
| else { |
| maxSize = null; // Could be anything from 0 entries upwards |
| } |
| } |
| else { |
| CollectionItem collectionItem = (CollectionItem)part; |
| OCLExpression itemExpression = collectionItem.getOwnedItem(); |
| if (itemExpression instanceof IntegerLiteralExp) { |
| IntegerValue item = ValueUtil.integerValueOf(((IntegerLiteralExp)itemExpression).getIntegerSymbol()); |
| ranges.add(new Range(item, item)); // item is a range of 1 element, assess overlaps |
| } |
| else if (itemExpression instanceof RealLiteralExp) { |
| RealValue item = ValueUtil.realValueOf(((RealLiteralExp)itemExpression).getRealSymbol()); |
| ranges.add(new Range(item, item)); // item is a range of 1 element, assess overlaps |
| } |
| else { |
| hasIndeterminateItems = true; |
| if (maxSize != null) { |
| maxSize = maxSize.addInteger(ValueUtil.ONE_VALUE); // but we cannot in general tell whether it is a distinct value |
| } |
| } |
| } |
| } |
| // |
| // Scan the sorted-by-first value ranges to count the number of unique values. |
| // |
| Collections.sort(ranges); |
| RealValue minSize = ValueUtil.ZERO_VALUE; |
| RealValue cursorValue = null; // Next not-yet-included value, null not started |
| for (@SuppressWarnings("null")@NonNull Range range : ranges) { |
| RealValue lower = range.lower; |
| RealValue upper = range.upper; |
| assert upper != null; // and upper >= lower |
| RealValue nextInclusiveLower = null; |
| RealValue nextExclusiveUpper = upper.addReal(ValueUtil.ONE_VALUE); |
| if (cursorValue == null) { |
| nextInclusiveLower = lower; |
| } |
| else if (nextExclusiveUpper.compareTo(cursorValue) >= 0) { |
| if (lower.compareTo(cursorValue) >= 0) { |
| nextInclusiveLower = lower; |
| } |
| else { |
| nextInclusiveLower = cursorValue; |
| } |
| } |
| if (nextInclusiveLower != null) { |
| RealValue increasedSize = nextExclusiveUpper.subtractReal(nextInclusiveLower); |
| minSize = minSize.addReal(increasedSize); |
| if (maxSize != null) { |
| maxSize = maxSize.addReal(increasedSize); |
| } |
| cursorValue = nextExclusiveUpper; |
| } |
| } |
| if (hasIndeterminateItems && (minSize == ValueUtil.ZERO_VALUE)) { |
| minSize = ValueUtil.ONE_VALUE; // at least one indeterminate value |
| } |
| return new Range(minSize, maxSize); |
| } |
| |
| 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; |
| } |
| |
| protected @NonNull SourceVariableIterator createSourceVariableIterator(@NonNull ModelElementCS csExp) { |
| return new SourceVariableIterator(csExp); |
| } |
| |
| /** |
| * 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.asTemplateParameter(); |
| 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); |
| // } |
| // for (ImplicitSourceVariableIterator it = createImplicitSourceVariableIterator(csNameExp); (invocations == null) && it.hasNext(); ) { |
| for (SourceVariableIterator it = createSourceVariableIterator(csNameExp); (invocations == null) && it.hasNext(); ) { |
| Variable asVariable = it.next(); |
| Type asType = asVariable.getType(); |
| OCLExpression asInit = asVariable.getOwnedInit(); |
| if (asInit instanceof LambdaLiteralExp) { |
| asType = asInit.getType(); |
| if (name.equals(asVariable.getName()) && (iteratorCount == 0) && (expressionCount == ((LambdaType)asType).getOwnedParameterTypes().size())) { |
| List<NamedElement> list = new ArrayList<NamedElement>(); |
| list.add(asVariable); |
| invocations = new UnresolvedInvocations(asType, list); |
| asVariable.setType(asType); // FIXME should not need this poke |
| asVariable.setIsRequired(true); |
| } |
| } |
| else if ((asType instanceof LambdaType) && (asVariable.eContainmentFeature() == PivotPackage.Literals.LOOP_EXP__OWNED_ITERATORS)) { |
| if (name.equals(asVariable.getName()) && (iteratorCount == 0) && (expressionCount == ((LambdaType)asType).getOwnedParameterTypes().size())) { |
| List<NamedElement> list = new ArrayList<NamedElement>(); |
| list.add(asVariable); |
| invocations = new UnresolvedInvocations(asType, list); |
| } |
| } |
| else if (SourceVariableIterator.canBeImplicitSource(asVariable)) { |
| if (asType != null) { |
| 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.asTemplateParameter(); |
| 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 (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; |
| } |
| if ((sourceExp == null) && (invocations.getSourceType() instanceof LambdaType)) { |
| Variable lambda = (Variable) invocations.getSingleResult(); |
| assert lambda != null; |
| LambdaCallExp lambdaCallExp = resolveLambdaCallExp(csRoundBracketedClause, lambda); |
| return lambdaCallExp; |
| } |
| 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.getType(); |
| 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); |
| } |
| |
| protected @NonNull LambdaCallExp resolveLambdaCallExp(@NonNull RoundBracketedClauseCS csRoundBracketedClause, @NonNull Variable lambda) { |
| AbstractNameExpCS csNameExp = csRoundBracketedClause.getOwningNameExp(); |
| LambdaCallExp expression = context.refreshModelElement(LambdaCallExp.class, PivotPackage.Literals.LAMBDA_CALL_EXP, csNameExp); |
| for (NavigatingArgCS csArgument : csRoundBracketedClause.getOwnedArguments()) { |
| ExpCS csExpression = csArgument.getOwnedNameExpression(); |
| if (csExpression != null){ |
| OCLExpression asExpression = context.visitLeft2Right(OCLExpression.class, csExpression); |
| if (asExpression != null) { |
| expression.getOwnedArguments().add(asExpression); |
| } |
| } |
| } |
| expression.setOwnedSource(PivotUtil.createVariableExp(lambda)); |
| LambdaType lambdaType = (LambdaType) lambda.getType(); |
| if (lambdaType != null) { // FIXME |
| ParameterType resultType = lambdaType.getOwnedResultType(); |
| expression.setType(resultType.getType()); |
| expression.setIsRequired(resultType.isIsNonNull()); |
| } |
| return expression; |
| } |
| |
| /** |
| * 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.getType(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) { |
| @SuppressWarnings("null")@NonNull 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 @Nullable PatternExp resolvePatternExp(@Nullable PatternExp asPatternExp, @Nullable ExpCS csPattern) { |
| if (csPattern == null) { |
| return null; |
| } |
| if (asPatternExp == null) { |
| asPatternExp = PivotFactory.eINSTANCE.createPatternExp(); |
| assert asPatternExp != null; |
| } |
| PatternValue asPatternValue = context.visitLeft2Right(PatternValue.class, csPattern); |
| asPatternExp.setOwnedPattern(asPatternValue); |
| List<Variable> asPatternVariables = new ArrayList<Variable>(); |
| for (TreeIterator<EObject> tit = asPatternExp.eAllContents(); tit.hasNext(); ) { |
| EObject eObject = tit.next(); |
| if (eObject instanceof PatternValue) { |
| Variable asVariable = ((PatternValue) eObject).getReferredVariable(); |
| if (!asPatternVariables.contains(asVariable)) { |
| asPatternVariables.add(asVariable); |
| } |
| } |
| else { |
| tit.prune(); |
| } |
| } |
| PivotUtilInternal.refreshList(asPatternExp.getOwnedVariables(), asPatternVariables); |
| return asPatternExp; |
| } |
| |
| 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()) { |
| actualType = metamodelManager.getMetaclass(actualType); |
| } |
| return PivotUtilInternal.getType(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; |
| MultiplicityCS csMultiplicity = csCollectionLiteralExp.getOwnedType().getOwnedMultiplicity(); |
| Boolean declaredIsNullFree = csMultiplicity != null ? csMultiplicity.isIsNullFree() : null; |
| boolean contentIsNullFree = 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 (declaredIsNullFree == null) { |
| if (pivotPart instanceof CollectionItem) { |
| if ((((CollectionItem)pivotPart).getOwnedItem() instanceof NullLiteralExp)) { |
| contentIsNullFree = false; |
| } |
| } |
| else if (pivotPart instanceof CollectionRange) { |
| ; |
| } |
| else { |
| contentIsNullFree = 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; |
| org.eclipse.ocl.pivot.Class collectionClass = standardLibrary.getRequiredLibraryType(collectionTypeName); |
| boolean isNullFree; |
| IntegerValue lowerValue; |
| UnlimitedNaturalValue upperValue; |
| if (csMultiplicity != null) { |
| lowerValue = ValueUtil.integerValueOf(csMultiplicity.getLower()); |
| int upper = csMultiplicity.getUpper(); |
| upperValue = upper != -1 ? ValueUtil.unlimitedNaturalValueOf(upper) : ValueUtil.UNLIMITED_VALUE; |
| isNullFree = csMultiplicity.isIsNullFree(); |
| } |
| else { |
| Range partsBounds; |
| List<CollectionLiteralPart> asParts = expression.getOwnedParts(); |
| if ((collectionClass instanceof CollectionType) && ((CollectionType)collectionClass).isUnique()) { |
| partsBounds = computeUniqueItemsSize(asParts); |
| } |
| else { |
| partsBounds = computeNonUniqueItemsSize(asParts); |
| } |
| lowerValue = partsBounds.lower.round(); |
| upperValue = partsBounds.upper != null ? partsBounds.upper.round().asUnlimitedNaturalValue() : ValueUtil.UNLIMITED_VALUE; |
| isNullFree = contentIsNullFree; |
| } |
| TypedRefCS ownedElementType = ownedCollectionType.getOwnedType(); |
| if (ownedElementType != null) { |
| commonType = (Type) ownedElementType.getPivot(); |
| } |
| if (commonType == null) { |
| commonType = standardLibrary.getOclVoidType(); |
| } |
| Type type = metamodelManager.getCollectionType(collectionTypeName, commonType, isNullFree, lowerValue, upperValue); |
| 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); |
| } |
| } |
| 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) { |
| ExpCS csElse = csIfExp.getOwnedElseExpression(); |
| if (csElse == null) { |
| return PivotUtil.getPivot(IfExp.class, csIfExp); |
| } |
| OCLExpression asElse = context.visitLeft2Right(OCLExpression.class, csElse); |
| List<IfThenExpCS> csIfThens = csIfExp.getOwnedIfThenExpressions(); |
| for (int i = csIfThens.size(); --i >= 0; ) { |
| IfThenExpCS csIfThen = csIfThens.get(i); |
| AbstractIfExp asAbstractIf = PivotUtil.getPivot(AbstractIfExp.class, csIfThen); |
| if (asAbstractIf != null) { |
| asAbstractIf.setIsElseIf(i > 0); |
| ExpCS csCondition = csIfThen.getOwnedCondition(); |
| ExpCS csThen = csIfThen.getOwnedThenExpression(); |
| if ((csCondition != null) && (csThen != null)) { |
| if (asAbstractIf instanceof IfPatternExp) { |
| IfPatternExp asIfPatternExp = (IfPatternExp)asAbstractIf; |
| asIfPatternExp.setOwnedPattern(resolvePatternExp(asIfPatternExp.getOwnedPattern(), csIfThen.getOwnedPattern())); |
| asIfPatternExp.setOwnedSource(context.visitLeft2Right(OCLExpression.class, csCondition)); |
| } |
| else { |
| IfExp asIfExp = (IfExp)asAbstractIf; |
| asIfExp.setOwnedCondition(context.visitLeft2Right(OCLExpression.class, csCondition)); |
| } |
| OCLExpression asThen = context.visitLeft2Right(OCLExpression.class, csThen); |
| asAbstractIf.setOwnedThen(asThen); |
| asAbstractIf.setOwnedElse(asElse); |
| Type thenType = asThen != null ? asThen.getType() : null; |
| Type elseType = asElse != null ? asElse.getType() : null; |
| Type thenTypeValue = asThen != null ? asThen.getTypeValue() : null; |
| Type elseTypeValue = asElse != null ? asElse.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 = ((asThen != null) && asThen.isIsRequired()) && ((asElse != null) && asElse.isIsRequired()); |
| context.setType(asAbstractIf, commonType, isRequired, commonTypeValue); |
| } |
| asElse = asAbstractIf; |
| } |
| } |
| if (asElse != null) { |
| context.installPivotUsage(csIfExp, asElse); |
| } |
| return asElse; |
| } |
| |
| @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 visitLambdaLiteralExpCS(@NonNull LambdaLiteralExpCS csLambdaLiteralExp) { |
| LambdaLiteralExp asLambdaExpression = PivotUtil.getPivot(LambdaLiteralExp.class, csLambdaLiteralExp); |
| if (asLambdaExpression != null) { |
| /* TypedRefCS csResultType = csLambdaLiteralExp.getOwnedType(); |
| if (csResultType != null) { |
| Type asResultType = PivotUtil.getPivot(Type.class, csResultType); |
| String name = csLambdaLiteralExp.getName(); |
| asLambdaExpression.setName(name); |
| if ((asResultType != null) && (name != null)) { |
| List<Parameter> asParameters = new ArrayList<Parameter>(); |
| List<ParameterType> parameterTypes = new ArrayList<ParameterType>(); |
| for (ParameterCS csParameter: csLambdaLiteralExp.getOwnedParameters()) { |
| Parameter asParameter = PivotUtil.getPivot(Parameter.class, csParameter); |
| if (asParameter != null) { |
| asParameters.add(asParameter); |
| Type asParameterType = asParameter.getType(); |
| if (asParameterType != null) { |
| parameterTypes.add(PivotUtil.createParameterType(asParameterType, ElementUtil.isRequired(csParameter.getOwnedType()))); |
| } |
| } |
| } |
| ParameterType resultParameterType = PivotUtil.createParameterType(asResultType, ElementUtil.isRequired(csResultType)); |
| LambdaType lambdaType = context.getMetamodelManager().getCompleteModel().getLambdaType(name, parameterTypes, resultParameterType, null); |
| context.setType(asLambdaExpression, lambdaType, true, null); |
| PivotUtilInternal.refreshList(asLambdaExpression.getOwnedParameters(), asParameters); |
| } */ |
| ExpCS csBody = csLambdaLiteralExp.getOwnedExpression(); |
| OCLExpression asBody = csBody != null ? context.visitLeft2Right(OCLExpression.class, csBody) : null; |
| asLambdaExpression.setOwnedBody(asBody); |
| // } |
| } |
| return asLambdaExpression; |
| } |
| |
| @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 visitPatternExpCS(@NonNull PatternExpCS csElement) { |
| PatternClass asPatternClass = PivotUtil.getPivot(PatternClass.class, csElement); |
| if (asPatternClass != null) { |
| org.eclipse.ocl.pivot.Class asClass = PivotUtil.getPivot(org.eclipse.ocl.pivot.Class.class, csElement.getOwnedPatternType()); |
| if (asClass != null) { |
| asPatternClass.setReferredClass(asClass); |
| Variable asVariable = PivotUtil.createVariable(csElement.getPatternVariableName(), asClass, true, null); |
| asPatternClass.setReferredVariable(asVariable); |
| } |
| } |
| return asPatternClass; |
| } |
| |
| @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<TupleLiteralPart> parts = 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.getType(); |
| context.setType(pivotElement, type, 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; |
| } |
| } |