blob: 3868ac3907a81e4a4e0ef05255fc4d2daf56e5e7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2015 The University of York, 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:
* Horacio Hoyos - initial API and implementation
******************************************************************************/
package org.eclipse.qvtd.pivot.qvtimperative.evaluation;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.Import;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.OppositePropertyCallExp;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.Variable;
import org.eclipse.ocl.pivot.internal.evaluation.BasicEvaluationVisitor;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.ocl.pivot.values.InvalidValueException;
import org.eclipse.qvtd.pivot.qvtbase.BaseModel;
import org.eclipse.qvtd.pivot.qvtbase.Domain;
import org.eclipse.qvtd.pivot.qvtbase.Function;
import org.eclipse.qvtd.pivot.qvtbase.FunctionParameter;
import org.eclipse.qvtd.pivot.qvtbase.Pattern;
import org.eclipse.qvtd.pivot.qvtbase.Predicate;
import org.eclipse.qvtd.pivot.qvtbase.Rule;
import org.eclipse.qvtd.pivot.qvtbase.Transformation;
import org.eclipse.qvtd.pivot.qvtbase.TypedModel;
import org.eclipse.qvtd.pivot.qvtcorebase.Assignment;
import org.eclipse.qvtd.pivot.qvtcorebase.BottomPattern;
import org.eclipse.qvtd.pivot.qvtcorebase.CoreDomain;
import org.eclipse.qvtd.pivot.qvtcorebase.CorePattern;
import org.eclipse.qvtd.pivot.qvtcorebase.EnforcementOperation;
import org.eclipse.qvtd.pivot.qvtcorebase.GuardPattern;
import org.eclipse.qvtd.pivot.qvtcorebase.PropertyAssignment;
import org.eclipse.qvtd.pivot.qvtcorebase.RealizedVariable;
import org.eclipse.qvtd.pivot.qvtcorebase.VariableAssignment;
import org.eclipse.qvtd.pivot.qvtimperative.ImperativeBottomPattern;
import org.eclipse.qvtd.pivot.qvtimperative.ImperativeModel;
import org.eclipse.qvtd.pivot.qvtimperative.Mapping;
import org.eclipse.qvtd.pivot.qvtimperative.MappingCall;
import org.eclipse.qvtd.pivot.qvtimperative.MappingCallBinding;
import org.eclipse.qvtd.pivot.qvtimperative.MappingLoop;
import org.eclipse.qvtd.pivot.qvtimperative.MappingSequence;
import org.eclipse.qvtd.pivot.qvtimperative.MappingStatement;
import org.eclipse.qvtd.pivot.qvtimperative.VariablePredicate;
/**
* QVTimperativeEvaluationVisitor is the class for ...
*/
public class QVTiEvaluationVisitor extends BasicEvaluationVisitor implements IQVTiEvaluationVisitor
{
// private static final Logger logger = Logger.getLogger(QVTiAbstractEvaluationVisitor.class);
protected final @NonNull QVTiExecutor executor;
/**
* Instantiates a new qV tcore evaluation visitor impl.
*/
public QVTiEvaluationVisitor(@NonNull QVTiExecutor executor) {
super(executor);
this.executor = executor;
}
@Override
public @Nullable Object visitAssignment(@NonNull Assignment object) {
return visiting(object);
}
@Override
public @Nullable Object visitBaseModel(@NonNull BaseModel object) {
return visiting(object);
}
@Override
public @Nullable Object visitBottomPattern(@NonNull BottomPattern object) {
return visiting(object);
}
@Override
public @Nullable Object visitCoreDomain(@NonNull CoreDomain object) {
return visiting(object);
}
@Override
public @Nullable Object visitDomain(@NonNull Domain object) {
return visiting(object);
}
@Override
public @Nullable Object visitCorePattern(@NonNull CorePattern object) {
return visiting(object);
}
@Override
public @Nullable Object visitEnforcementOperation(@NonNull EnforcementOperation object) {
return visiting(object);
}
@Override
public @Nullable Object visitFunction(@NonNull Function object) {
return visiting(object);
}
@Override
public @Nullable Object visitFunctionParameter(@NonNull FunctionParameter object) {
return visiting(object);
}
@Override
public @Nullable Object visitGuardPattern(@NonNull GuardPattern object) {
return visiting(object);
}
@Override
public @Nullable Object visitImperativeBottomPattern(@NonNull ImperativeBottomPattern object) {
return visitBottomPattern(object);
}
@Override
public @Nullable Object visitImperativeModel(@NonNull ImperativeModel imperativeModel) {
for (org.eclipse.ocl.pivot.Package pkge : imperativeModel.getOwnedPackages()) {
pkge.accept(undecoratedVisitor);
}
return true;
}
@Override
public @Nullable Object visitImport(@NonNull Import object) {
return visiting(object);
}
@Override
public @Nullable Object visitMapping(@NonNull Mapping mapping) {
return executor.internalExecuteMapping(mapping, undecoratedVisitor);
}
@Override
public @Nullable Object visitMappingCall(@NonNull MappingCall mappingCall) {
Map<Variable, Object> variable2value = new HashMap<Variable, Object>();
for (MappingCallBinding binding : mappingCall.getBinding()) {
Variable boundVariable = binding.getBoundVariable();
if (boundVariable == null) {
return null;
}
Type varType = boundVariable.getType();
if (varType == null) {
return null;
}
OCLExpression value = binding.getValue();
if (value == null) {
return null;
}
Object valueOrValues = value.accept(undecoratedVisitor);
Type valueType = idResolver.getDynamicTypeOf(valueOrValues);
if (valueType.conformsTo(standardLibrary, varType)) {
variable2value.put(boundVariable, valueOrValues);
}
else {
return null;
}
}
Mapping referredMapping = mappingCall.getReferredMapping();
if (referredMapping == null) {
return null;
}
context.pushEvaluationEnvironment(referredMapping, mappingCall);
try {
for (Map.Entry<Variable,Object> entry : variable2value.entrySet()) {
@SuppressWarnings("null")@NonNull Variable variable = entry.getKey();
context.replace(variable, entry.getValue());
}
return executor.internalExecuteMappingCall(mappingCall, undecoratedVisitor);
}
finally {
context.popEvaluationEnvironment();
}
}
@Override
public @Nullable Object visitMappingCallBinding(@NonNull MappingCallBinding object) {
return visiting(object); // MappingCallBinding is serviced by the parent MappingCall
}
@Override
public @Nullable Object visitMappingLoop(@NonNull MappingLoop mappingLoop) {
Object inValues = mappingLoop.getOwnedSource().accept(undecoratedVisitor);
if (inValues instanceof Iterable<?>) {
List<Variable> iterators = mappingLoop.getOwnedIterators();
if (iterators.size() > 0) {
Variable iterator = ClassUtil.nonNullState(iterators.get(0));
for (Object object : (Iterable<?>)inValues) {
context.replace(iterator, object);
mappingLoop.getOwnedBody().accept(undecoratedVisitor);
}
}
}
return true;
}
@Override
public @Nullable Object visitMappingSequence(@NonNull MappingSequence mappingSequence) {
for (MappingStatement mappingStatement : mappingSequence.getMappingStatements()) {
if (mappingStatement != null) {
context.pushEvaluationEnvironment(mappingStatement, mappingSequence);
try {
mappingStatement.accept(undecoratedVisitor);
}
finally {
context.popEvaluationEnvironment();
}
}
}
return true;
}
@Override
public @Nullable Object visitMappingStatement(@NonNull MappingStatement object) {
return visiting(object); // MappingStatement is abstract
}
@Override
public Object visitOppositePropertyCallExp(@NonNull OppositePropertyCallExp oppositePropertyCallExp) {
QVTiModelManager modelManager = (QVTiModelManager) context.getModelManager();
Integer cacheIndex = modelManager.getTransformationAnalysis().getCacheIndex(oppositePropertyCallExp);
if (cacheIndex == null) {
return super.visitOppositePropertyCallExp(oppositePropertyCallExp);
}
Object sourceValue = null;
OCLExpression source = oppositePropertyCallExp.getOwnedSource();
if (source != null) {
sourceValue = source.accept(undecoratedVisitor);
if (sourceValue != null) {
Object middleOpposite = modelManager.getUnnavigableOpposite(cacheIndex, sourceValue);
return ClassUtil.nonNullState(middleOpposite);
}
}
throw new InvalidValueException("Failed to evaluate '" + oppositePropertyCallExp.getReferredProperty() + "'", sourceValue, oppositePropertyCallExp);
}
@Override
public @Nullable Object visitPackage(@NonNull org.eclipse.ocl.pivot.Package pkge) {
return true;
}
@Override
public @Nullable Object visitPattern(@NonNull Pattern object) {
return visiting(object);
}
@Override
public @Nullable Object visitPredicate(@NonNull Predicate predicate) {
// Each predicate has a conditionExpression that is an OCLExpression
OCLExpression exp = predicate.getConditionExpression();
// The predicated is visited with a nested environment
Object expResult = exp.accept(undecoratedVisitor);
return expResult;
}
@Override
public @Nullable Object visitPropertyAssignment(@NonNull PropertyAssignment propertyAssignment) {
Object slotObject = propertyAssignment.getSlotExpression().accept(undecoratedVisitor);
if (slotObject instanceof EObject) {
try {
Object boxedValue = propertyAssignment.getValue().accept(undecoratedVisitor);
Property targetProperty = propertyAssignment.getTargetProperty();
Class<?> instanceClass = PivotUtil.getEcoreInstanceClass(targetProperty);
Object ecoreValue = idResolver.ecoreValueOf(instanceClass, boxedValue);
return executor.internalExecutePropertyAssignment(propertyAssignment, slotObject, ecoreValue);
}
catch (NotReadyValueException e) {
executor.internalExecutePropertyAssignment(propertyAssignment, slotObject, e);
// throw e;
}
} else {
throw new IllegalArgumentException("Unsupported " + propertyAssignment.eClass().getName()
+ " specification. The assigment slot expression evaluates to non-ecore value");
}
return true;
}
@Override
public @Nullable Object visitRealizedVariable(@NonNull RealizedVariable realizedVariable) {
return executor.internalExecuteRealizedVariable(realizedVariable, undecoratedVisitor);
}
@Override
public @Nullable Object visitRule(@NonNull Rule object) {
return visiting(object);
}
@Override
public @Nullable Object visitTransformation(@NonNull Transformation transformation) {
return executor.internalExecuteTransformation(transformation, undecoratedVisitor);
}
@Override
public @Nullable Object visitTypedModel(@NonNull TypedModel object) {
return visiting(object);
}
@Override
public @Nullable Object visitVariableAssignment(@NonNull VariableAssignment variableAssignment) {
Variable targetVariable = variableAssignment.getTargetVariable() ;
if (targetVariable != null) {
OCLExpression valueExpression = variableAssignment.getValue();
if (valueExpression != null) {
try {
Object value = valueExpression.accept(undecoratedVisitor);
context.replace(targetVariable, value);
return value;
}
catch (RuntimeException e) {
context.replace(targetVariable, e);
throw e;
}
}
}
return null;
}
@Override
public @Nullable Object visitVariablePredicate(@NonNull VariablePredicate variablePredicate) {
// Each predicate has a conditionExpression that is an OCLExpression
OCLExpression exp = variablePredicate.getConditionExpression();
if (exp == null) {
return false;
}
Object value = exp.accept(undecoratedVisitor);
Variable variable = variablePredicate.getTargetVariable();
Type guardType = variable.getType();
Type valueType = idResolver.getDynamicTypeOf(value);
if ((guardType != null) && valueType.conformsTo(standardLibrary, guardType)) {
context.replace(variable, value);
} else {
// The initialisation fails, the guard is not met
return false;
}
return true;
}
}