/*******************************************************************************
* Copyright (c) 2014, 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
*******************************************************************************/
package org.eclipse.ocl.pivot.internal.manager;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.CallExp;
import org.eclipse.ocl.pivot.CollectionType;
import org.eclipse.ocl.pivot.LoopExp;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal;
import org.eclipse.ocl.pivot.library.LibraryFeature;
import org.eclipse.ocl.pivot.library.collection.CollectionAsBagOperation;
import org.eclipse.ocl.pivot.library.collection.CollectionAsOrderedSetOperation;
import org.eclipse.ocl.pivot.library.collection.CollectionAsSequenceOperation;
import org.eclipse.ocl.pivot.library.collection.CollectionAsSetOperation;
import org.eclipse.ocl.pivot.library.collection.CollectionExcludingAllOperation;
import org.eclipse.ocl.pivot.library.collection.CollectionExcludingOperation;
import org.eclipse.ocl.pivot.library.collection.CollectionFlattenOperation;
import org.eclipse.ocl.pivot.library.collection.CollectionIntersectionOperation;
import org.eclipse.ocl.pivot.library.collection.CollectionMinOperation;
import org.eclipse.ocl.pivot.library.collection.OrderedCollectionAtOperation;
import org.eclipse.ocl.pivot.library.collection.OrderedCollectionFirstOperation;
import org.eclipse.ocl.pivot.library.collection.OrderedCollectionLastOperation;
import org.eclipse.ocl.pivot.library.iterator.AnyIteration;
import org.eclipse.ocl.pivot.library.iterator.CollectIteration;
import org.eclipse.ocl.pivot.library.iterator.RejectIteration;
import org.eclipse.ocl.pivot.library.iterator.SelectIteration;
import org.eclipse.ocl.pivot.library.iterator.SortedByIteration;
/**
* TemplateParameterSubstitutionHelper instances support irregular YemplateParameterSubstitution deduction for difficult to
* model operations such as flatten().
* <p>
* The TemplateParameterSubstitutionHelper maintains a registry of helpers indexed by their implementatin class.
*/
public abstract class TemplateParameterSubstitutionHelper
{
public void resolveUnmodeledTemplateParameterSubstitutions(@NonNull TemplateParameterSubstitutionVisitor templateParameterSubstitutions, @NonNull CallExp callExp) {}
public @Nullable Type resolveBodyType(@NonNull PivotMetamodelManager metamodelManager, @NonNull CallExp callExp, @Nullable Type bodyType) {
return bodyType;
}
public @Nullable Type resolveReturnType(@NonNull PivotMetamodelManager metamodelManager, @NonNull CallExp callExp, @Nullable Type returnType) {
return returnType;
}
private static @NonNull Map<Class<? extends LibraryFeature>, TemplateParameterSubstitutionHelper> className2helper = new HashMap<Class<? extends LibraryFeature>, TemplateParameterSubstitutionHelper>();
public static void addHelper(@NonNull Class<? extends LibraryFeature> className, @NonNull TemplateParameterSubstitutionHelper helper) {
className2helper.put(className, helper);
}
public static @Nullable TemplateParameterSubstitutionHelper getHelper(@NonNull Class<? extends LibraryFeature> className) {
return className2helper.get(className);
}
//
// Special case processing for collect() return and body types.
//
private static class CollectionCollectHelper extends TemplateParameterSubstitutionHelper
{
@Override
public @Nullable Type resolveBodyType(@NonNull PivotMetamodelManager metamodelManager, @NonNull CallExp callExp, @Nullable Type returnType) {
LoopExp loopExp = (LoopExp)callExp;
OCLExpression body = loopExp.getOwnedBody();
Type asType = body != null ? body.getType() : null;
Type bodyType = asType != null ? PivotUtilInternal.getNonLambdaType(asType) : null;
if (bodyType != null) {
@NonNull Type elementType = bodyType;
// if (bodyType instanceof CollectionType) {
while (elementType instanceof CollectionType) {
Type elementType2 = ((CollectionType)elementType).getElementType();
if (elementType2 != null) {
elementType = elementType2;
}
}
// }
return elementType;
}
return returnType;
}
@Override
public @Nullable Type resolveReturnType(@NonNull PivotMetamodelManager metamodelManager, @NonNull CallExp callExp, @Nullable Type returnType) {
LoopExp loopExp = (LoopExp)callExp;
OCLExpression body = loopExp.getOwnedBody();
Type asType = body != null ? body.getType() : null;
Type bodyType = asType != null ? PivotUtilInternal.getNonLambdaType(asType) : null;
if (bodyType != null) {
@NonNull Type elementType = bodyType;
// if (bodyType instanceof CollectionType) {
while (elementType instanceof CollectionType) {
Type elementType2 = ((CollectionType)elementType).getElementType();
if (elementType2 != null) {
elementType = elementType2;
}
}
// }
boolean isOrdered = (returnType instanceof CollectionType) && ((CollectionType)returnType).isOrdered();
boolean isNullFree = asType instanceof CollectionType && ((CollectionType)asType).isIsNullFree();
boolean isRequired = !(asType instanceof CollectionType) && (body != null) && body.isIsRequired();
returnType = metamodelManager.getCollectionType(isOrdered, false, elementType, isNullFree || isRequired, null, null); // FIXME null, null
}
return returnType;
}
}
//
// Special case processing for flatten() return type.
//
private static class CollectionFlattenHelper extends TemplateParameterSubstitutionHelper
{
@Override
public void resolveUnmodeledTemplateParameterSubstitutions(@NonNull TemplateParameterSubstitutionVisitor templateParameterSubstitutions, @NonNull CallExp callExp) {
Type elementType = callExp.getOwnedSource().getType();
while (elementType instanceof CollectionType) {
elementType = ((CollectionType)elementType).getElementType();
}
templateParameterSubstitutions.put(1, elementType);
}
}
//
// Special case processing for return types based pn the source.
//
private static class CollectionSourceHelper extends TemplateParameterSubstitutionHelper
{
@Override
public @Nullable Type resolveReturnType(@NonNull PivotMetamodelManager metamodelManager, @NonNull CallExp callExp, @Nullable Type returnType) {
if (returnType instanceof CollectionType) {
OCLExpression ownedSource = callExp.getOwnedSource();
if (ownedSource != null) {
Type sourceType = ownedSource.getType();
CollectionType collectionType = (CollectionType)returnType;
if ((sourceType instanceof CollectionType) && ((CollectionType)sourceType).isIsNullFree() && !collectionType.isIsNullFree()) {
@SuppressWarnings("null")@NonNull Type elementType = collectionType.getElementType();
returnType = metamodelManager.getCollectionType(collectionType.isOrdered(), collectionType.isUnique(),
elementType, true, collectionType.getLowerValue(), collectionType.getUpperValue());
}
}
}
return returnType;
}
}
static
{
addHelper(AnyIteration.class, new CollectionSourceHelper());
addHelper(CollectIteration.class, new CollectionCollectHelper());
addHelper(CollectionAsBagOperation.class, new CollectionSourceHelper());
addHelper(CollectionAsOrderedSetOperation.class, new CollectionSourceHelper());
addHelper(CollectionAsSequenceOperation.class, new CollectionSourceHelper());
addHelper(CollectionAsSetOperation.class, new CollectionSourceHelper());
addHelper(CollectionExcludingOperation.class, new CollectionSourceHelper());
addHelper(CollectionExcludingAllOperation.class, new CollectionSourceHelper());
// addHelper(CollectionIncludingOperation.class, new CollectionSourceAndArgumentHelper());
// addHelper(CollectionIncludingAllOperation.class, new CollectionSourceAndArgumentHelper());
addHelper(CollectionIntersectionOperation.class, new CollectionSourceHelper()/*OrArgument*/);
addHelper(CollectionMinOperation.class, new CollectionSourceHelper());
addHelper(OrderedCollectionAtOperation.class, new CollectionSourceHelper());
addHelper(OrderedCollectionFirstOperation.class, new CollectionSourceHelper());
addHelper(OrderedCollectionLastOperation.class, new CollectionSourceHelper());
addHelper(CollectionFlattenOperation.class, new CollectionFlattenHelper());
addHelper(RejectIteration.class, new CollectionSourceHelper());
addHelper(SelectIteration.class, new CollectionSourceHelper());
addHelper(SortedByIteration.class, new CollectionSourceHelper());
}
}