blob: f25053a9d26b186d061e3c0383fe7c398612ff31 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2013 IBM Corporation 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:
* IBM - Initial API and implementation
* Zeligsoft - Bug 253252
* Radek Dvorak - Bugs 261128, 265066
* E.D.Willink - Bug 297541
*******************************************************************************/
package org.eclipse.ocl.pivot.internal.evaluation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.BooleanLiteralExp;
import org.eclipse.ocl.pivot.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.CompleteInheritance;
import org.eclipse.ocl.pivot.ConstructorExp;
import org.eclipse.ocl.pivot.ConstructorPart;
import org.eclipse.ocl.pivot.Element;
import org.eclipse.ocl.pivot.EnumLiteralExp;
import org.eclipse.ocl.pivot.EnumerationLiteral;
import org.eclipse.ocl.pivot.ExpressionInOCL;
import org.eclipse.ocl.pivot.IfExp;
import org.eclipse.ocl.pivot.IntegerLiteralExp;
import org.eclipse.ocl.pivot.InvalidLiteralExp;
import org.eclipse.ocl.pivot.IterateExp;
import org.eclipse.ocl.pivot.Iteration;
import org.eclipse.ocl.pivot.IteratorExp;
import org.eclipse.ocl.pivot.LetExp;
import org.eclipse.ocl.pivot.MessageExp;
import org.eclipse.ocl.pivot.NamedElement;
import org.eclipse.ocl.pivot.NavigationCallExp;
import org.eclipse.ocl.pivot.NullLiteralExp;
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.Property;
import org.eclipse.ocl.pivot.PropertyCallExp;
import org.eclipse.ocl.pivot.RealLiteralExp;
import org.eclipse.ocl.pivot.SelfType;
import org.eclipse.ocl.pivot.StateExp;
import org.eclipse.ocl.pivot.StringLiteralExp;
import org.eclipse.ocl.pivot.TupleLiteralExp;
import org.eclipse.ocl.pivot.TupleLiteralPart;
import org.eclipse.ocl.pivot.TupleType;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.TypeExp;
import org.eclipse.ocl.pivot.UnlimitedNaturalLiteralExp;
import org.eclipse.ocl.pivot.UnspecifiedValueExp;
import org.eclipse.ocl.pivot.Variable;
import org.eclipse.ocl.pivot.VariableDeclaration;
import org.eclipse.ocl.pivot.VariableExp;
import org.eclipse.ocl.pivot.evaluation.EvaluationEnvironment;
import org.eclipse.ocl.pivot.evaluation.EvaluationHaltedException;
import org.eclipse.ocl.pivot.evaluation.EvaluationVisitor;
import org.eclipse.ocl.pivot.evaluation.Evaluator;
import org.eclipse.ocl.pivot.evaluation.IterationManager;
import org.eclipse.ocl.pivot.ids.CollectionTypeId;
import org.eclipse.ocl.pivot.ids.IdResolver;
import org.eclipse.ocl.pivot.ids.TuplePartId;
import org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal;
import org.eclipse.ocl.pivot.library.EvaluatorMultipleIterationManager;
import org.eclipse.ocl.pivot.library.EvaluatorSingleIterationManager;
import org.eclipse.ocl.pivot.library.LibraryBinaryOperation;
import org.eclipse.ocl.pivot.library.LibraryFeature;
import org.eclipse.ocl.pivot.library.LibraryIteration;
import org.eclipse.ocl.pivot.library.LibraryOperation;
import org.eclipse.ocl.pivot.library.LibraryProperty;
import org.eclipse.ocl.pivot.util.Visitable;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.ocl.pivot.utilities.ValueUtil;
import org.eclipse.ocl.pivot.values.CollectionValue;
import org.eclipse.ocl.pivot.values.IntegerRange;
import org.eclipse.ocl.pivot.values.IntegerValue;
import org.eclipse.ocl.pivot.values.InvalidValueException;
import org.eclipse.ocl.pivot.values.NullValue;
import org.eclipse.ocl.pivot.values.Unlimited;
import org.eclipse.ocl.pivot.values.UnlimitedNaturalValue;
/**
* An evaluation visitor implementation for OCL expressions.
*/
public class OCLEvaluationVisitor extends AbstractEvaluationVisitor
{
public static boolean isSimpleRange(@NonNull CollectionLiteralExp cl) {
List<CollectionLiteralPart> partsList = cl.getOwnedParts();
int size = partsList.size();
if (size == 1) {
CollectionLiteralPart part = partsList.get(0);
return part instanceof CollectionRange;
}
return false;
}
/**
* Constructor
*
* @param env
* an evaluation environment (map of variable names to values)
* @param modelManager
* a map of classes to their instance lists
*/
public OCLEvaluationVisitor(@NonNull EvaluationEnvironment evalEnv) {
super(evalEnv);
}
// FIXME Revise API so that cannot invoke createNestedEvaluator() by mistake
@Override
public @NonNull EvaluationVisitor createNestedEvaluator() {
EvaluationEnvironment evaluationEnvironment = getEvaluationEnvironment();
EvaluationEnvironment nestedEvalEnv = environmentFactory.createEvaluationEnvironment(evaluationEnvironment, evaluationEnvironment.getExecutableObject());
OCLEvaluationVisitor nestedEvaluationVisitor = new OCLEvaluationVisitor(nestedEvalEnv);
nestedEvaluationVisitor.setMonitor(getMonitor());
return nestedEvaluationVisitor;
}
// FIXME Revise API so that cannot invoke createNestedEvaluator() by mistake
public @NonNull EvaluationVisitor createNestedUndecoratedEvaluator(@NonNull NamedElement operation) { // FIXME Pass 'operation'
return undecoratedVisitor.createNestedEvaluator();
}
@Override
public void dispose() {
if (undecoratedVisitor != this) {
undecoratedVisitor.dispose();
}
}
@Override
public @Nullable Object evaluate(@NonNull OCLExpression body) {
Object value = ((Element) body).accept(undecoratedVisitor);
assert ValueUtil.isBoxed(value); // Make sure Integer/Real are boxed, invalid is an exception, null is null
return value;
}
protected Object evaluatePropertyCallExp(@NonNull NavigationCallExp navigationCallExp, @NonNull Property referredProperty) {
OCLExpression source = navigationCallExp.getOwnedSource();
Type propertyType = navigationCallExp.getType();
assert propertyType != null;
EvaluationVisitor evaluationVisitor = undecoratedVisitor;
Object sourceValue = source != null ? evaluationVisitor.evaluate(source) : null;
LibraryProperty implementation = metamodelManager.getImplementation(navigationCallExp, sourceValue, referredProperty);
try {
return implementation.evaluate(this, propertyType.getTypeId(), sourceValue);
}
catch (InvalidValueException e) {
throw e;
}
catch (Exception e) {
// This is a backstop. Library operations should catch their own exceptions
// and produce a better reason as a result.
throw new InvalidValueException(e, "Failed to evaluate '" + referredProperty + "'", sourceValue, navigationCallExp);
}
}
@Override
public @NonNull EvaluationVisitor getEvaluator() {
return this;
}
public @NonNull LibraryFeature lookupImplementation(@NonNull org.eclipse.ocl.pivot.Class dynamicType, @NonNull Operation staticOperation) {
CompleteInheritance inheritance = metamodelManager.getInheritance(dynamicType);
return inheritance.getPivotClass().lookupImplementation(standardLibrary, staticOperation);
}
@Override
public Object safeVisit(@Nullable Visitable v) {
if (v == null) {
throw new InvalidValueException("null expression");
}
try {
Object result = v.accept(undecoratedVisitor);
assert ValueUtil.isBoxed(result); // Make sure Integer/Real are boxed, invalid is an exception, null is null
return result;
} catch (InvalidValueException e) {
throw e;
} catch (Exception e) {
throw new InvalidValueException(e, "Evaluation Failure");
}
}
/**
* Callback for an AssociationClassCallExp visit. Evaluates the source of the
* expression and then reflectively gets the value of the reference on the
* result. For example, in "self.foo", "self" is the source and would be
* evaluated first, then the value of the reference "foo" would be derived
* on that object.
*
@Override
public Object visitAssociationClassCallExp(@NonNull AssociationClassCallExp ae) {
Object context = ae.getOwnedSource().accept(undecoratedVisitor);
// if ((context == null) || ValuesUtil.isUndefined(context)) {
// return evaluationEnvironment.throwInvalidEvaluation("Undefined context for AssociationClassCall", ae);
// }
// context = ValuesUtil.asValidValue(context);
// evaluate attribute on source value
return evaluationEnvironment.navigateAssociationClass(
ae.getReferredAssociationClass(),
ae.getNavigationSource(),
context);
} */
/**
* Callback for a BooleanLiteralExp visit.
*
* @return the value of the boolean literal as a java.lang.Boolean.
*/
@Override
public Object visitBooleanLiteralExp(@NonNull BooleanLiteralExp booleanLiteralExp) {
boolean value = booleanLiteralExp.isBooleanSymbol();
return value;
}
@Override
public Object visitCollectionItem(@NonNull CollectionItem item) {
throw new UnsupportedOperationException("evaluation of CollectionItem"); //$NON-NLS-1$
}
/**
* Callback for a CollectionLiteralExp visit.
*/
@Override
public Object visitCollectionLiteralExp(@NonNull CollectionLiteralExp cl) {
// construct the appropriate collection from the parts
// based on the collection kind.
List<CollectionLiteralPart> parts = cl.getOwnedParts();
CollectionType type = (CollectionType) cl.getType();
boolean isOrdered = type.isOrdered();
if (isOrdered && isSimpleRange(cl)) {
// literal is of the form: Sequence{first..last}.
// construct a list with a lazy iterator for it.
CollectionRange collRange = (CollectionRange) parts.get(0);
OCLExpression first = collRange.getOwnedFirst();
OCLExpression last = collRange.getOwnedLast();
// evaluate first value
Object firstVal = first.accept(undecoratedVisitor);
// if (firstVal == null) {
// return evaluationEnvironment.throwInvalidEvaluation("Invalid first element", cl, first);
// }
// evaluate last value
Object lastVal = last.accept(undecoratedVisitor);
// if (lastVal == null) {
// return evaluationEnvironment.throwInvalidEvaluation("Invalid last element", cl, last);
// }
IntegerValue firstInteger;
// try {
firstInteger = ValueUtil.asIntegerValue(firstVal);
// } catch (InvalidValueException e) {
// return evaluationEnvironment.throwInvalidEvaluation(e, cl, firstVal, "Non integer first element");
// }
IntegerValue lastInteger;
// try {
lastInteger = ValueUtil.asIntegerValue(lastVal);
// } catch (InvalidValueException e) {
// return evaluationEnvironment.throwInvalidEvaluation(e, cl, lastVal, "Non integer last element");
// }
// construct a lazy integer list for the range
// try {
CollectionTypeId typeId = type.getTypeId();
IntegerRange range = ValueUtil.createRange(firstInteger, lastInteger);
if (type.isUnique()) {
return ValueUtil.createOrderedSetRange(typeId, range);
}
else {
return ValueUtil.createSequenceRange(typeId, range);
}
// } catch (InvalidValueException e) {
// return evaluationEnvironment.throwInvalidEvaluation(e, cl, lastVal, "Non integer first or last element");
// }
} else
{
List<Object> orderedResults = new ArrayList<Object>();
Set<Object> uniqueResults = type.isUnique() ? new HashSet<Object>() : null;
// not a sequence or not a simple range
for (CollectionLiteralPart part : parts) {
if (part instanceof CollectionItem) {
// CollectionItem part
CollectionItem item = (CollectionItem) part;
OCLExpression itemExp = item.getOwnedItem();
Object itemVal = itemExp.accept(undecoratedVisitor);
// Object itemValue = ValuesUtil.asValidValue(itemVal);
if ((uniqueResults == null) || uniqueResults.add(itemVal)) {
orderedResults.add(itemVal);
}
} else {
// Collection range
CollectionRange range = (CollectionRange) part;
OCLExpression first = range.getOwnedFirst();
OCLExpression last = range.getOwnedLast();
// evaluate first value
Object firstVal = first.accept(undecoratedVisitor);
// if (firstVal == null) {
// return evaluationEnvironment.throwInvalidEvaluation("Invalid first element", cl, first);
// }
Object lastVal = last.accept(undecoratedVisitor);
// if (lastVal == null) {
// return evaluationEnvironment.throwInvalidEvaluation("Invalid last element", cl, last);
// }
IntegerValue firstInteger;
// try {
firstInteger = ValueUtil.asIntegerValue(firstVal);
// } catch (InvalidValueException e) {
// return evaluationEnvironment.throwInvalidEvaluation(e, cl, firstVal, "Non integer first element");
// }
IntegerValue lastInteger;
// try {
lastInteger = ValueUtil.asIntegerValue(lastVal);
// } catch (InvalidValueException e) {
// return evaluationEnvironment.throwInvalidEvaluation(e, cl, lastVal, "Non integer last element");
// }
Integer firstInt;
// try {
firstInt = firstInteger.asInteger();
// } catch (InvalidValueException e) {
// return evaluationEnvironment.throwInvalidEvaluation(e, cl, firstInteger, "Out of range first element");
// }
Integer lastInt;
// try {
lastInt = lastInteger.asInteger();
// } catch (InvalidValueException e) {
// return ValuesUtil.createInvalidValue("Out of range last element", e, cl, lastInteger, );
// }
// TODO: enhance IntegerRangeList to support multiple ranges
// add values between first and last inclusive
for (int i = firstInt; true; i++) {
IntegerValue integerValue = ValueUtil.integerValueOf(i);
if ((uniqueResults == null) || uniqueResults.add(integerValue)) {
orderedResults.add(integerValue);
}
if (i >= lastInt) {
break;
}
}
} // end of collection range
} // end of parts iterator
return getIdResolver().createCollectionOfAll(type.isOrdered(), type.isUnique(), ClassUtil.nonNullModel(type.getElementType()).getTypeId(), orderedResults);
} // end of not-simple range case
} // end of Set, OrderedSet, Bag Literals
@Override
public Object visitCollectionRange(@NonNull CollectionRange range) {
throw new UnsupportedOperationException("evaluation of CollectionRange"); //$NON-NLS-1$
}
@Override
public Object visitConstructorExp(@NonNull ConstructorExp ce) {
org.eclipse.ocl.pivot.Class type = ce.getType();
String value = ce.getValue();
Object object;
if (value == null) {
EObject eObject = type.createInstance();
for (ConstructorPart part : ce.getOwnedParts()) {
OCLExpression initExpression = part.getOwnedInit();
if (initExpression != null) {
Object boxedValue = undecoratedVisitor.evaluate(initExpression);
Property referredProperty = part.getReferredProperty();
Class<?> instanceClass = PivotUtil.getEcoreInstanceClass(referredProperty);
Object ecoreValue = getIdResolver().ecoreValueOf(instanceClass, boxedValue);
referredProperty.initValue(eObject, ecoreValue);
}
}
object = eObject;
}
else {
object = type.createInstance(value);
}
return object != null ? ValueUtil.createObjectValue(type.getTypeId(), object) : null;
}
/**
* Callback for an EnumLiteralExp visit. Get the referred enum literal and
* return it as an Integer.
*
* @param el
* the enumeration literal expresion
* @return the enumeration literal as an Integer
*/
@Override
public Object visitEnumLiteralExp(@NonNull EnumLiteralExp el) {
EnumerationLiteral enumLiteral = el.getReferredLiteral();
assert enumLiteral != null;
return enumLiteral.getEnumerationLiteralId();
}
// private static int depth = 0;
@Override
public Object visitExpressionInOCL(@NonNull ExpressionInOCL expression) {
if ((monitor != null) && monitor.isCanceled()) {
throw new EvaluationHaltedException("Canceled");
}
// Object object = getEvaluationEnvironment().getValueOf(expression.getContextVariable());
// System.out.println(++depth + " " + expression.getContextVariable() + " = " + object + "\n\t" + expression);
// try {
Object result = safeVisit(expression.getOwnedBody());
// System.out.println(depth + "\t=> " + result);
return result;
// }
// catch (RuntimeException e) {
// System.out.println(depth + "\t=> " + e);
// throw e;
// }
// finally {
// --depth;
// }
}
/**
* Callback for an IfExp visit.
*/
@Override
public Object visitIfExp(@NonNull IfExp ifExp) {
OCLExpression condition = ifExp.getOwnedCondition();
Object acceptedValue = condition.accept(undecoratedVisitor);
Object evaluatedCondition = ValueUtil.asBoolean(acceptedValue);
OCLExpression expression = null;
if (evaluatedCondition == ValueUtil.TRUE_VALUE) {
expression = ifExp.getOwnedThen();
}
else {
expression = ifExp.getOwnedElse();
}
return expression.accept(undecoratedVisitor);
}
/**
* Callback for an IntegerLiteralExp visit.
*
* @return the value of the integer literal as a java.lang.Integer.
*/
@Override
public Object visitIntegerLiteralExp(@NonNull IntegerLiteralExp integerLiteralExp) {
Number integerSymbol = integerLiteralExp.getIntegerSymbol();
return integerSymbol != null ? ValueUtil.integerValueOf(integerSymbol) : null;
}
@Override
public Object visitInvalidLiteralExp(@NonNull InvalidLiteralExp invalidLiteralExp) {
throw ValueUtil.INVALID_VALUE;
}
/**
* Callback for an IterateExp visit.
*/
@Override
public Object visitIterateExp(@NonNull IterateExp iterateExp) {
if (isCanceled()) {
throw new EvaluationHaltedException("Canceled");
}
Iteration staticIteration = ClassUtil.nonNullModel(iterateExp.getReferredIteration());
OCLExpression source = iterateExp.getOwnedSource();
Object acceptedValue = source.accept(undecoratedVisitor);
CollectionValue sourceValue = ValueUtil.asCollectionValue(acceptedValue);
org.eclipse.ocl.pivot.Class dynamicSourceType = environmentFactory.getIdResolver().getClass(sourceValue.getTypeId(), null);
LibraryIteration implementation = (LibraryIteration) dynamicSourceType.lookupImplementation(standardLibrary, staticIteration);
/* Operation dynamicIteration = metamodelManager.getDynamicOperation((org.eclipse.ocl.pivot.Type) dynamicSourceType, staticIteration);
if (dynamicIteration == null) {
dynamicIteration = staticIteration;
}
LibraryIteration implementation1;
try {
implementation = (LibraryIteration) metamodelManager.getImplementation(dynamicIteration);
} catch (Exception e) {
String implementationClass = dynamicIteration.getImplementationClass();
if (implementationClass != null) {
return evaluationEnvironment.throwInvalidEvaluation(e, iterateExp, null, EvaluatorMessages.ImplementationClassLoadFailure, implementationClass);
}
else {
return evaluationEnvironment.throwInvalidEvaluation(e, iterateExp, null, "Failed to load implementation for '" + dynamicIteration + "'");
}
} */
Object result = null;
try {
Variable accumulator = iterateExp.getOwnedResult();
Object initValue = accumulator.getOwnedInit().accept(undecoratedVisitor);
// if ((initValue == null) || ValuesUtil.isUndefined(initValue)) {
// return evaluationEnvironment.throwInvalidEvaluation(null, iterateExp, initValue, EvaluatorMessages.UndefinedInitialiser);
// }
// initValue = ValuesUtil.asValidValue(initValue);
IterationManager iterationManager;
VariableDeclaration accumulatorVariable = accumulator;
OCLExpression body = ClassUtil.nonNullModel(iterateExp.getOwnedBody());
List<Variable> iterators = iterateExp.getOwnedIterators();
int iSize = iterators.size();
if (iSize == 1) {
VariableDeclaration firstIterator = ClassUtil.nonNullModel(iterators.get(0));
iterationManager = new EvaluatorSingleIterationManager(undecoratedVisitor, body, sourceValue, accumulatorVariable, initValue, firstIterator);
}
else {
VariableDeclaration[] variables = new VariableDeclaration[iSize];
for (int i = 0; i < iSize; i++) {
variables[i] = iterators.get(i);
}
iterationManager = new EvaluatorMultipleIterationManager(undecoratedVisitor, body, sourceValue, accumulatorVariable, initValue, variables);
}
result = implementation.evaluateIteration(iterationManager);
// } catch (InvalidValueException e) {
// return evaluationEnvironment.throwInvalidEvaluation(e);
} catch (InvalidValueException e) {
throw e;
} catch (Exception e) {
// This is a backstop. Library iterations should catch their own exceptions
// and produce a better reason as a result.
throw new InvalidValueException(e, "Failed to evaluate '" + staticIteration + "'", sourceValue, iterateExp); // FIXME dymamicIteration throughout
}
return result;
}
/**
* Callback for an IteratorExp visit.
*/
@Override
public Object visitIteratorExp(@NonNull IteratorExp iteratorExp) {
if ((monitor != null) && monitor.isCanceled()) {
throw new EvaluationHaltedException("Canceled");
}
Iteration staticIteration = ClassUtil.nonNullModel(iteratorExp.getReferredIteration());
CollectionValue sourceValue;
// try {
OCLExpression source = iteratorExp.getOwnedSource();
Object sourceVal = source.accept(undecoratedVisitor);
// if (sourceVal == null) {
// return evaluationEnvironment.throwInvalidEvaluation("null iterator source");
// }
sourceValue = ValueUtil.asCollectionValue(sourceVal);
// } catch (InvalidValueException e) {
// return evaluationEnvironment.throwInvalidEvaluation(e);
// }
org.eclipse.ocl.pivot.Class dynamicSourceType = environmentFactory.getIdResolver().getClass(sourceValue.getTypeId(), null);
LibraryIteration implementation = (LibraryIteration) dynamicSourceType.lookupImplementation(standardLibrary, staticIteration);
/* Operation dynamicIteration = metamodelManager.getDynamicOperation((org.eclipse.ocl.pivot.Type) dynamicSourceType, staticIteration);
if (dynamicIteration == null) {
dynamicIteration = staticIteration;
}
LibraryIteration implementation;
try {
implementation = (LibraryIteration) metamodelManager.getImplementation(dynamicIteration);
} catch (Exception e) {
String implementationClass = dynamicIteration.getImplementationClass();
if (implementationClass != null) {
return evaluationEnvironment.throwInvalidEvaluation(e, iteratorExp, null, EvaluatorMessages.ImplementationClassLoadFailure, implementationClass);
}
else {
return evaluationEnvironment.throwInvalidEvaluation(e, iteratorExp, null, "Failed to load implementation for '" + dynamicIteration + "'");
}
} */
Object result = null;
try {
IterationManager iterationManager;
OCLExpression body = iteratorExp.getOwnedBody();
Type iterationType = PivotUtilInternal.getType(ClassUtil.nonNullModel(iteratorExp.getType()));
Type bodyType = PivotUtilInternal.getType(ClassUtil.nonNullModel(body.getType()));
Object accumulatorValue = implementation.createAccumulatorValue(undecoratedVisitor, iterationType.getTypeId(), bodyType.getTypeId());
List<Variable> iterators = iteratorExp.getOwnedIterators();
int iSize = iterators.size();
if (iSize == 1) {
VariableDeclaration firstIterator = ClassUtil.nonNullModel(iterators.get(0));
iterationManager = new EvaluatorSingleIterationManager(undecoratedVisitor, body, sourceValue, null, accumulatorValue, firstIterator);
}
else {
VariableDeclaration[] variables = new VariableDeclaration[iSize];
for (int i = 0; i < iSize; i++) {
variables[i] = iterators.get(i);
}
iterationManager = new EvaluatorMultipleIterationManager(undecoratedVisitor, body, sourceValue, null, accumulatorValue, variables);
}
result = implementation.evaluateIteration(iterationManager);
// } catch (InvalidValueException e) {
// return evaluationEnvironment.throwInvalidEvaluation(e);
} catch (InvalidValueException e) {
throw e;
} catch (Exception e) {
// This is a backstop. Library iterations should catch their own exceptions
// and produce a better reason as a result.
throw new InvalidValueException(e, "Failed to evaluate '" + staticIteration + "'", sourceValue, iteratorExp);
}
return result;
}
/**
* Callback for LetExp visit.
*/
@Override
public Object visitLetExp(@NonNull LetExp letExp) {
OCLExpression expression = letExp.getOwnedIn(); // Never null when valid
Variable variable = letExp.getOwnedVariable(); // Never null when valid
assert variable != null;
Object value;
try {
value = variable.accept(undecoratedVisitor);
}
catch (EvaluationHaltedException e) {
throw e;
}
catch (InvalidValueException e) {
value = e;
}
// value = ValuesUtil.asValue(value);
EvaluationVisitor nestedVisitor = undecoratedVisitor.createNestedEvaluator();
nestedVisitor.getEvaluationEnvironment().add(variable, value);
try {
return expression.accept(nestedVisitor);
}
finally {
nestedVisitor.dispose();
}
}
@Override
public Object visitMessageExp(@NonNull MessageExp m) {
throw new UnsupportedOperationException("evaluation of MessageExp"); //$NON-NLS-1$
/* T targetResult = safeVisit(messageExp.getTarget());
List<T> argumentResults;
List<OCLExpression> arguments = messageExp.getArgument();
if (arguments.isEmpty()) {
argumentResults = Collections.emptyList();
} else {
argumentResults = new java.util.ArrayList<T>(arguments.size());
for (OCLExpression qual : arguments) {
argumentResults.add(safeVisit(qual));
}
}
return handleMessageExp(messageExp, targetResult, argumentResults);
*/ }
@Override
public Object visitNullLiteralExp(@NonNull NullLiteralExp nullLiteralExp) {
return null;
}
/**
* Callback for an OperationCallExp visit.
*/
@Override
public Object visitOperationCallExp(@NonNull OperationCallExp operationCallExp) {
if ((monitor != null) && monitor.isCanceled()) {
throw new EvaluationHaltedException("Canceled");
}
Evaluator evaluator = undecoratedVisitor.getEvaluator();
Operation apparentOperation = operationCallExp.getReferredOperation();
assert apparentOperation != null;
//
// Resolve source value
//
Object sourceValue;
OCLExpression source = operationCallExp.getOwnedSource();
boolean isValidating = apparentOperation.isValidating();
if (isValidating) {
try {
sourceValue = source.accept(undecoratedVisitor);
}
catch (EvaluationHaltedException e) {
throw e;
}
catch (InvalidValueException e) {
sourceValue = e; // FIXME ?? propagate part of environment
}
}
else {
sourceValue = source.accept(undecoratedVisitor);
}
//
// Resolve source dispatch type
//
List<Parameter> ownedParameters = apparentOperation.getOwnedParameters();
if ((ownedParameters.size() == 1) && (ownedParameters.get(0).getType() instanceof SelfType)) {
//
// Resolve and dispatch OclSelf operation
//
List<OCLExpression> arguments = operationCallExp.getOwnedArguments();
Object onlyArgument = arguments.get(0).accept(undecoratedVisitor);
Operation actualOperation;
if (apparentOperation.isStatic()) {
actualOperation = apparentOperation;
}
else {
IdResolver idResolver = environmentFactory.getIdResolver();
org.eclipse.ocl.pivot.Class actualSourceType = idResolver.getStaticTypeOf(sourceValue);
if (onlyArgument != null) {
org.eclipse.ocl.pivot.Class actualArgType = idResolver.getStaticTypeOf(onlyArgument);
actualSourceType = (org.eclipse.ocl.pivot.Class)actualSourceType.getCommonType(idResolver, actualArgType);
}
actualOperation = actualSourceType.lookupActualOperation(standardLibrary, apparentOperation);
}
LibraryBinaryOperation implementation = (LibraryBinaryOperation) metamodelManager.getImplementation(actualOperation);
try {
Object result = implementation.evaluate(evaluator, operationCallExp.getTypeId(), sourceValue, onlyArgument);
assert !(result instanceof NullValue);
return result;
} catch (InvalidValueException e) {
throw e;
} catch (Exception e) {
// This is a backstop. Library operations should catch their own exceptions
// and produce a better reason as a result.
throw new InvalidValueException(e, "Failed to evaluate '" + apparentOperation + "'", sourceValue, operationCallExp);
}
}
else {
//
// Resolve and dispatch regular operation
//
Operation actualOperation;
if (apparentOperation.isStatic()) {
actualOperation = apparentOperation;
}
else {
IdResolver idResolver = environmentFactory.getIdResolver();
org.eclipse.ocl.pivot.Class actualSourceType = idResolver.getStaticTypeOf(sourceValue);
actualOperation = actualSourceType.lookupActualOperation(standardLibrary, apparentOperation);
}
LibraryOperation implementation = (LibraryOperation) metamodelManager.getImplementation(actualOperation);
try {
Object result = implementation.dispatch(evaluator, operationCallExp, sourceValue);
assert !(result instanceof NullValue);
return result;
} catch (InvalidValueException e) {
throw e;
} catch (Exception e) {
// This is a backstop. Library operations should catch their own exceptions
// and produce a better reason as a result.
throw new InvalidValueException(e, "Failed to evaluate '" + apparentOperation + "'", sourceValue, operationCallExp);
}
}
}
/**
* Callback for an OppositePropertyCallExp visit.
*/
@Override
public Object visitOppositePropertyCallExp(@NonNull OppositePropertyCallExp oppositePropertyCallExp) {
Property oppositeReferredProperty = oppositePropertyCallExp.getReferredProperty();
Property referredProperty = oppositeReferredProperty.getOpposite();
assert referredProperty != null;
return evaluatePropertyCallExp(oppositePropertyCallExp, referredProperty);
}
/**
* Callback for a PropertyCallExp visit.
*/
@Override
public Object visitPropertyCallExp(@NonNull PropertyCallExp propertyCallExp) {
Property referredProperty = propertyCallExp.getReferredProperty();
assert referredProperty != null;
return evaluatePropertyCallExp(propertyCallExp, referredProperty);
}
/**
* Callback for a RealLiteralExp visit.
*
* @return the value of the real literal as a java.lang.Double.
*/
@Override
public Object visitRealLiteralExp(@NonNull RealLiteralExp realLiteralExp) {
Number realSymbol = realLiteralExp.getRealSymbol();
return realSymbol != null ? ValueUtil.realValueOf(realSymbol) : null;
}
@Override
public Object visitStateExp(@NonNull StateExp s) {
return s.getReferredState();
}
/**
* Callback for a StringLiteralExp visit.
*
* @return the value of the string literal as a java.lang.String.
*/
@Override
public Object visitStringLiteralExp(@NonNull StringLiteralExp stringLiteralExp) {
String value = stringLiteralExp.getStringSymbol();
if (value == null) {
throw new InvalidValueException("Invalid String Value", stringLiteralExp);
}
return value;
}
/**
* Callback for a TupleLiteralExp visit.
*
* @param tl
* tuple literal expression
* @return String
*/
@Override
public Object visitTupleLiteralExp(@NonNull TupleLiteralExp tl) {
Type type = ClassUtil.nonNullModel(tl.getType());
Map<TuplePartId, Object> propertyValues = new HashMap<TuplePartId, Object>();
for (TupleLiteralPart part : tl.getOwnedParts()) {
// Set the tuple field with the value of the init expression
propertyValues.put(part.getPartId(), part.accept(undecoratedVisitor));
}
// TupleType tupleType = metamodelManager.getTupleType(type.getName(), propertyValues.keySet());
return ValueUtil.createTupleValue(((TupleType) type).getTupleTypeId(), propertyValues);
}
@Override
public Object visitTupleLiteralPart(@NonNull TupleLiteralPart tp) {
return tp.getOwnedInit().accept(undecoratedVisitor);
}
/**
* Callback for a TypeExp visit.
*/
@Override
public Object visitTypeExp(@NonNull TypeExp t) {
// DomainMetaclass domainMetaclass = (DomainMetaclass)t.getType();
// DomainType instanceType = domainMetaclass.getInstanceType();
// assert instanceType != null;
// return ValuesUtil.createTypeValue(instanceType);
// DomainMetaclass domainMetaclass = (DomainMetaclass)t.getType();
// DomainType instanceType = domainMetaclass.getInstanceType();
// assert instanceType != null;
return t.getReferredType();
}
/**
* Callback for an UnlimitedNaturalLiteralExp visit.
*
* @return the value of the natural literal as a java.lang.Integer.
*/
@Override
public Object visitUnlimitedNaturalLiteralExp(@NonNull UnlimitedNaturalLiteralExp unlimitedNaturalLiteralExp) {
Number unlimitedNaturalSymbol = unlimitedNaturalLiteralExp.getUnlimitedNaturalSymbol();
if (unlimitedNaturalSymbol == null) {
return null;
}
if (unlimitedNaturalSymbol instanceof Unlimited) {
return ValueUtil.UNLIMITED_VALUE;
}
if (unlimitedNaturalSymbol instanceof UnlimitedNaturalValue) {
return unlimitedNaturalSymbol;
}
IntegerValue integerValue = ValueUtil.integerValueOf(unlimitedNaturalSymbol);
if (integerValue.signum() < 0) {
if (integerValue == ValueUtil.integerValueOf(-1)) {
return ValueUtil.UNLIMITED_VALUE;
}
}
return integerValue.asUnlimitedNaturalValue();
}
/**
* Callback for an UnspecifiedValueExp visit.
*/
@Override
public Object visitUnspecifiedValueExp(@NonNull UnspecifiedValueExp uv) {
// TODO: return a "random instance of the type of the expression"
throw new UnsupportedOperationException("evaluation of UnspecifiedValueExp"); //$NON-NLS-1$
}
/**
* Callback for a Variable visit.
*/
@Override
public Object visitVariable(@NonNull Variable variable) {
// return the initial (only) value
OCLExpression initExp = variable.getOwnedInit();
if (initExp == null) {
throw new InvalidValueException("Uninitialized variable", variable);
}
else {
return initExp.accept(undecoratedVisitor);
}
}
/**
* Callback for a VariableExp visit.
*
* @param variableExp
* the variable expression
* @return the value of the variable
*/
@Override
public Object visitVariableExp(@NonNull VariableExp variableExp) {
VariableDeclaration variableDeclaration = variableExp.getReferredVariable();
if (variableDeclaration == null) {
throw new InvalidValueException("Undefined variable", null, null, variableExp);
}
Object value = evaluationEnvironment.getValueOf(variableDeclaration);
if (value instanceof InvalidValueException) {
throw (InvalidValueException)value;
}
else {
return value;
}
}
@Override
public Object visiting(@NonNull Visitable visitable) {
throw new IllegalArgumentException("Unsupported " + visitable.eClass().getName() + " for " + getClass().getSimpleName());
}
}