blob: 151f015a9bda34fe3bea540d1fbea254d5876084 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2015 Borland Software 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:
* Borland Software Corporation - initial API and implementation
* Christopher Gerking - bugs 302594, 309762, 310991, 325192, 377882, 388325,
* 392080, 392153, 394498, 397215, 397218, 269744,
* 415660, 415315, 414642, 427237, 428618, 425069
* Alex Paperno - bugs 294127, 416584, 419299, 267917, 420970, 424584
* Christine Gerpheide - bugs 432969
*******************************************************************************/
package org.eclipse.m2m.internal.qvt.oml.evaluator;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EModelElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EParameter;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.m2m.internal.qvt.oml.NLS;
import org.eclipse.m2m.internal.qvt.oml.QvtPlugin;
import org.eclipse.m2m.internal.qvt.oml.ast.binding.ASTBindingHelper;
import org.eclipse.m2m.internal.qvt.oml.ast.binding.IModuleSourceInfo;
import org.eclipse.m2m.internal.qvt.oml.ast.env.IVirtualOperationTable;
import org.eclipse.m2m.internal.qvt.oml.ast.env.InternalEvaluationEnv;
import org.eclipse.m2m.internal.qvt.oml.ast.env.ModelParameterExtent;
import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtEvaluationResult;
import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalEnv;
import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalEnvFactory;
import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalEvaluationEnv;
import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalModuleEnv;
import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalStdLibrary;
import org.eclipse.m2m.internal.qvt.oml.ast.parser.ConstructorOperationAdapter;
import org.eclipse.m2m.internal.qvt.oml.ast.parser.IntermediateClassFactory;
import org.eclipse.m2m.internal.qvt.oml.ast.parser.IntermediateClassFactory.ExceptionClassInstance;
import org.eclipse.m2m.internal.qvt.oml.ast.parser.QvtOperationalParserUtil;
import org.eclipse.m2m.internal.qvt.oml.ast.parser.QvtOperationalUtil;
import org.eclipse.m2m.internal.qvt.oml.blackbox.BlackboxRegistry;
import org.eclipse.m2m.internal.qvt.oml.emf.util.EmfUtil;
import org.eclipse.m2m.internal.qvt.oml.evaluator.TransformationInstance.InternalTransformation;
import org.eclipse.m2m.internal.qvt.oml.evaluator.iterators.QvtIterationTemplateCollectSelect;
import org.eclipse.m2m.internal.qvt.oml.evaluator.iterators.QvtIterationTemplateForExp;
import org.eclipse.m2m.internal.qvt.oml.evaluator.iterators.QvtIterationTemplateXCollect;
import org.eclipse.m2m.internal.qvt.oml.evaluator.iterators.QvtIterationTemplateXSelect;
import org.eclipse.m2m.internal.qvt.oml.expressions.Constructor;
import org.eclipse.m2m.internal.qvt.oml.expressions.ConstructorBody;
import org.eclipse.m2m.internal.qvt.oml.expressions.ContextualProperty;
import org.eclipse.m2m.internal.qvt.oml.expressions.DirectionKind;
import org.eclipse.m2m.internal.qvt.oml.expressions.EntryOperation;
import org.eclipse.m2m.internal.qvt.oml.expressions.ExpressionsPackage;
import org.eclipse.m2m.internal.qvt.oml.expressions.Helper;
import org.eclipse.m2m.internal.qvt.oml.expressions.ImperativeCallExp;
import org.eclipse.m2m.internal.qvt.oml.expressions.ImperativeOperation;
import org.eclipse.m2m.internal.qvt.oml.expressions.Library;
import org.eclipse.m2m.internal.qvt.oml.expressions.MappingBody;
import org.eclipse.m2m.internal.qvt.oml.expressions.MappingCallExp;
import org.eclipse.m2m.internal.qvt.oml.expressions.MappingOperation;
import org.eclipse.m2m.internal.qvt.oml.expressions.MappingParameter;
import org.eclipse.m2m.internal.qvt.oml.expressions.ModelParameter;
import org.eclipse.m2m.internal.qvt.oml.expressions.ModelType;
import org.eclipse.m2m.internal.qvt.oml.expressions.Module;
import org.eclipse.m2m.internal.qvt.oml.expressions.ModuleImport;
import org.eclipse.m2m.internal.qvt.oml.expressions.ObjectExp;
import org.eclipse.m2m.internal.qvt.oml.expressions.OperationBody;
import org.eclipse.m2m.internal.qvt.oml.expressions.OperationalTransformation;
import org.eclipse.m2m.internal.qvt.oml.expressions.ResolveExp;
import org.eclipse.m2m.internal.qvt.oml.expressions.ResolveInExp;
import org.eclipse.m2m.internal.qvt.oml.expressions.VarParameter;
import org.eclipse.m2m.internal.qvt.oml.expressions.impl.ImperativeOperationImpl;
import org.eclipse.m2m.internal.qvt.oml.expressions.impl.OperationBodyImpl;
import org.eclipse.m2m.internal.qvt.oml.library.Context;
import org.eclipse.m2m.internal.qvt.oml.library.EObjectEStructuralFeaturePair;
import org.eclipse.m2m.internal.qvt.oml.library.LateResolveInTask;
import org.eclipse.m2m.internal.qvt.oml.library.LateResolveTask;
import org.eclipse.m2m.internal.qvt.oml.library.QvtResolveUtil;
import org.eclipse.m2m.internal.qvt.oml.stdlib.CallHandler;
import org.eclipse.m2m.internal.qvt.oml.stdlib.ConversionUtils;
import org.eclipse.m2m.internal.qvt.oml.stdlib.DictionaryImpl;
import org.eclipse.m2m.internal.qvt.oml.stdlib.MutableListImpl;
import org.eclipse.m2m.internal.qvt.oml.stdlib.model.ExceptionInstance;
import org.eclipse.m2m.internal.qvt.oml.trace.Trace;
import org.eclipse.m2m.internal.qvt.oml.trace.TraceRecord;
import org.eclipse.m2m.qvt.oml.blackbox.java.JavaModelExtent;
import org.eclipse.m2m.qvt.oml.blackbox.java.JavaModelInstance;
import org.eclipse.m2m.qvt.oml.blackbox.java.JavaModelType;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.AltExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.AssertExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.AssignExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.BlockExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.BreakExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.CatchExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.ComputeExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.ContinueExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.DictLiteralExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.DictLiteralPart;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.ForExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.ImperativeIterateExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.ImperativeLoopExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.InstantiationExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.ListType;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.LogExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.OrderedTupleLiteralExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.OrderedTupleLiteralPart;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.RaiseExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.ReturnExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.SeverityKind;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.SwitchExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.TryExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.UnlinkExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.UnpackExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.VariableInitExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.WhileExp;
import org.eclipse.m2m.qvt.oml.util.Dictionary;
import org.eclipse.m2m.qvt.oml.util.IContext;
import org.eclipse.m2m.qvt.oml.util.Log;
import org.eclipse.ocl.Environment;
import org.eclipse.ocl.EnvironmentFactory;
import org.eclipse.ocl.EvaluationEnvironment;
import org.eclipse.ocl.EvaluationVisitor;
import org.eclipse.ocl.EvaluationVisitorImpl;
import org.eclipse.ocl.ParserException;
import org.eclipse.ocl.ecore.CallOperationAction;
import org.eclipse.ocl.ecore.Constraint;
import org.eclipse.ocl.ecore.EcoreFactory;
import org.eclipse.ocl.ecore.SendSignalAction;
import org.eclipse.ocl.expressions.CollectionItem;
import org.eclipse.ocl.expressions.CollectionLiteralExp;
import org.eclipse.ocl.expressions.CollectionLiteralPart;
import org.eclipse.ocl.expressions.CollectionRange;
import org.eclipse.ocl.expressions.EnumLiteralExp;
import org.eclipse.ocl.expressions.IfExp;
import org.eclipse.ocl.expressions.OCLExpression;
import org.eclipse.ocl.expressions.OperationCallExp;
import org.eclipse.ocl.expressions.PropertyCallExp;
import org.eclipse.ocl.expressions.Variable;
import org.eclipse.ocl.expressions.VariableExp;
import org.eclipse.ocl.types.BagType;
import org.eclipse.ocl.types.CollectionType;
import org.eclipse.ocl.types.SetType;
import org.eclipse.ocl.types.TupleType;
import org.eclipse.ocl.types.VoidType;
import org.eclipse.ocl.util.CollectionUtil;
import org.eclipse.ocl.util.Tuple;
import org.eclipse.ocl.utilities.PredefinedType;
import org.eclipse.ocl.utilities.UMLReflection;
public class QvtOperationalEvaluationVisitorImpl
extends EvaluationVisitorImpl<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter,
EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject>
implements QvtOperationalEvaluationVisitor, InternalEvaluator, DeferredAssignmentListener {
private static int tempCounter = 0;
private boolean myIsSuppressLoggin = false;
private QvtOperationalEvaluationEnv myEvalEnv;
// FIXME - move me to the root environment?
private OCLAnnotationSupport oclAnnotationSupport;
public QvtOperationalEvaluationVisitorImpl(QvtOperationalEnv env, QvtOperationalEvaluationEnv evalEnv) {
super(env, evalEnv, evalEnv.createExtentMap(null));
myEvalEnv = evalEnv;
}
protected QvtOperationalEvaluationVisitorImpl(QvtOperationalEvaluationVisitorImpl parent, QvtOperationalEvaluationEnv nestedEvalEnv) {
this(parent.getOperationalEnv(), nestedEvalEnv);
oclAnnotationSupport = parent.getOCLAnnotationSupport();
}
protected InternalEvaluator createNestedEvaluationVisitor(QvtOperationalEvaluationVisitorImpl parent, QvtOperationalEvaluationEnv nestedEvalEnv) {
InternalEvaluator evalVisitor = (InternalEvaluator) getOperationalEnv().getFactory().createEvaluationVisitor(
parent.getOperationalEnv(), nestedEvalEnv, nestedEvalEnv.createExtentMap(null));
if (evalVisitor instanceof QvtOperationalEvaluationVisitorImpl) {
// ensure shared instance of oclAnnotationSupport to avoid repeated OCL parsing
((QvtOperationalEvaluationVisitorImpl) evalVisitor).oclAnnotationSupport = getOCLAnnotationSupport();
}
return evalVisitor;
}
public Object visitDictLiteralExp(DictLiteralExp dictLiteralExp) {
Dictionary<Object, Object> result = new DictionaryImpl<Object, Object>();
for (DictLiteralPart part : dictLiteralExp.getPart()) {
Object key = visitExpression(part.getKey());
Object value = visitExpression(part.getValue());
if(key != getInvalid() && value != getInvalid())
result.put(key, value);
}
return result;
}
@Override
public Object visitVariableExp(VariableExp<EClassifier, EParameter> v) {
QvtOperationalEvaluationEnv evalEnv = getOperationalEvaluationEnv();
Variable<EClassifier, EParameter> vd = v.getReferredVariable();
String varName = vd.getName();
Object value = evalEnv.getValueOf(varName);
if(QvtOperationalEnv.THIS.equals(varName)) {
EClassifier varType = v.getType();
if(varType instanceof Module) {
Module referredThisModule = (Module)varType;
ModuleInstance thisObj = evalEnv.getThisOfType(referredThisModule);
// only if not null, the variables is part of the QVT type system.
// otherwise, it may be a custom variable in non-QVT execution context, like ImperativeOCL
if(thisObj != null) {
return thisObj;
}
}
} else if(vd instanceof ModelParameter) {
OperationalTransformation transformation = (OperationalTransformation) vd.eContainer();
TransformationInstance transformationInstance = (TransformationInstance)evalEnv.getThisOfType(transformation);
assert transformationInstance != null;
ModelInstance model = transformationInstance.getModel((ModelParameter)vd);
assert model != null;
return model;
}
return value;
}
/**
* Creates evaluation visitor for an non-transformation execution client.
* <p>
* No main entry operation is available, the execution flow is undefined and
* it is the responsibility of the executor client.
* </p>
* <code>Note:</code>Only helper operation can be executed on the resulting
* visitor by an external clients.
*
* @see #executeHelperOperation(Helper, Object, List)
*/
public static QvtOperationalEvaluationVisitorImpl createNonTransformationExecutionContextVisitor(Context context, ImportToNonTransformCtxHelper importProvider) {
QvtOperationalEnv env = (QvtOperationalEnv)QvtOperationalEnvFactory.INSTANCE.createEnvironment();
QvtOperationalEvaluationEnv evalEnv = QvtOperationalEnvFactory.INSTANCE.createEvaluationEnvironment(context, null);
return createNonTransformationExecutionContextVisitor(env, evalEnv, importProvider);
}
public static QvtOperationalEvaluationVisitorImpl createNonTransformationExecutionContextVisitor(
QvtOperationalEnv env, QvtOperationalEvaluationEnv evalEnv, ImportToNonTransformCtxHelper importsProvider) {
QvtOperationalEvaluationVisitorImpl visitor = new QvtOperationalEvaluationVisitorImpl(env, evalEnv);
InternalEvaluationEnv internalEvalEnv = evalEnv.getAdapter(InternalEvaluationEnv.class);
ThisInstanceResolver importsByAccess = importsProvider.createImportedInstanceResolver();
internalEvalEnv.setThisResolver(importsByAccess);
// initialize those module only newly instantiated, therefore uninitialized yet
for (ModuleInstance nextModuleToInit : importsProvider.getModuleInstances(false)) {
// the call bellow makes sure that all of its imported modules gets initialized
// if not done already due to other dependent modules
ModuleInstance.Internal internalModule = nextModuleToInit.getAdapter(ModuleInstance.Internal.class);
// check if initialized as the module we iterate through might cross-refence, so
// get initialized in the meantime
if(!internalModule.isInitialized()) {
visitor.initModule(nextModuleToInit, null);
}
}
return visitor;
}
public static QvtOperationalEvaluationVisitor createVisitor(QvtOperationalEnv env, QvtOperationalEvaluationEnv evalEnv) {
return new QvtOperationalEvaluationVisitorImpl(env, evalEnv).createInterruptibleVisitor();
}
@Override
public EvaluationEnvironment<EClassifier, EOperation, EStructuralFeature, EClass, EObject> getEvaluationEnvironment() {
return myEvalEnv;
}
public void setOperationalEvaluationEnv(QvtOperationalEvaluationEnv evalEnv) {
myEvalEnv = evalEnv;
}
protected void pushedStack(QvtOperationalEvaluationEnv env) {
}
protected void poppedStack() {
}
public IContext getContext() {
return getOperationalEvaluationEnv().getContext();
}
public void notifyAfterDeferredAssign(final AssignExp assignExp, Object leftValue) {
// do nothing special here, subclasses may customize
}
@Override
public Object visitIfExp(IfExp<EClassifier> ie) {
// get condition
OCLExpression<EClassifier> condition = ie.getCondition();
// evaluate condition
Object condVal = visitExpression(condition);
if (isUndefined(condVal)) {
return getInvalid();
}
Boolean condValBool = (Boolean) condVal;
if (condValBool.booleanValue()) {
return visitExpression(ie.getThenExpression());
}
if (ie.getElseExpression() != null) {
return visitExpression(ie.getElseExpression());
}
return null;
}
@SuppressWarnings("unchecked")
public Object visitAssignExp(final AssignExp assignExp) {
QvtOperationalEvaluationEnv env = getOperationalEvaluationEnv();
InternalEvaluationEnv internEnv = env.getAdapter(InternalEvaluationEnv.class);
boolean isDeferred = false;
// TODO: modify the following code for more complex l-values
OCLExpression<EClassifier> lValue = assignExp.getLeft();
if (assignExp.getValue().size() == 1) {
isDeferred = QvtResolveUtil.hasDeferredRightSideValue(assignExp);
if (isDeferred) {
Object ownerObj = getAssignExpLValueOwner(lValue);
if (ownerObj instanceof EObject) {
PropertyCallExp<EClassifier, EStructuralFeature> lvalueExp = (PropertyCallExp<EClassifier, EStructuralFeature>) assignExp
.getLeft();
EStructuralFeature referredProperty = lvalueExp.getReferredProperty();
internEnv
.setLastAssignmentLvalueEval(new EObjectEStructuralFeaturePair((EObject) ownerObj, referredProperty));
}
}
}
Object exprValue = null;
for (OCLExpression<EClassifier> exp : assignExp.getValue()) {
exprValue = visitExpression(exp);
}
if (isDeferred) {
// the source of resolve calls has been evaluated above ->
// assignment of the left value is not executed now
// but at deferred time in the end of the transformation
return null;
}
if (lValue instanceof VariableExp<?, ?>) {
VariableExp<EClassifier, EParameter> varExp = (VariableExp<EClassifier, EParameter>) lValue;
Variable<EClassifier, EParameter> referredVariable = varExp.getReferredVariable();
if (referredVariable != null) {
String varName = referredVariable.getName();
Object oldValue = getRuntimeValue(varName);
EClassifier variableType = lValue.getType();
Object newValue = env.assign(variableType, oldValue, exprValue, assignExp.isIsReset());
replaceInEnv(varName, newValue, variableType);
}
} else if (lValue instanceof PropertyCallExp<?, ?>) {
Object ownerObj = getAssignExpLValueOwner(lValue);
if (ownerObj instanceof EObject) {
EObject oldIP = setCurrentEnvInstructionPointer(assignExp);
env.callSetter((EObject) ownerObj,
((PropertyCallExp<EClassifier, EStructuralFeature>) lValue).getReferredProperty(), exprValue,
isUndefined(exprValue), assignExp.isIsReset());
setCurrentEnvInstructionPointer(oldIP);
}
} else {
throw new UnsupportedOperationException("Unsupported LValue type: " + ((lValue == null) ? null : lValue.getType())); //$NON-NLS-1$
}
return exprValue;
}
private Object getAssignExpLValueOwner(OCLExpression<EClassifier> lValue) {
if (lValue instanceof PropertyCallExp<?, ?>) {
@SuppressWarnings("unchecked")
PropertyCallExp<EClassifier, EParameter> propertyCallExp = (PropertyCallExp<EClassifier, EParameter>) lValue;
OCLExpression<EClassifier> sourceExp = propertyCallExp.getSource();
Object owner = visitExpression(sourceExp);
// obtain correct owner for features of modules, which are possibly defined in an extended module that is not an explicit supertype (fixed by bug 302594/310991)
if (owner instanceof ModuleInstance) {
ModuleInstance moduleInstance = (ModuleInstance) owner;
Object property = ((PropertyCallExp<?,?>) lValue).getReferredProperty();
EClassifier containingClassifier = getUMLReflection().getOwningClassifier(property);
if (containingClassifier instanceof Module) {
owner = moduleInstance.getThisInstanceOf((Module) containingClassifier);
}
}
return owner;
}
return null;
}
private Object visitConfigProperty(EStructuralFeature configProperty) {
setCurrentEnvInstructionPointer(configProperty);
IContext context = getOperationalEvaluationEnv().getContext();
Object rawValue = context.getConfigProperty(configProperty.getName());
EClassifier propertyType = configProperty.getEType();
Object value = rawValue;
if (!context.getConfigProperties().containsKey(configProperty.getName())) {
//leave non-specified configuration property as undefined
//value = EvaluationUtil.createInitialValue(propertyType, getEnvironment().getOCLStandardLibrary(), getEvaluationEnvironment());
}
else if(rawValue instanceof String && propertyType != getEnvironment().getOCLStandardLibrary().getString()) {
try {
value = ConversionUtils.createFromString(propertyType, (String) rawValue);
}
catch (IllegalArgumentException e) {
value = getInvalid();
}
}
if(value == getInvalid()) {
// we failed to parse the value
throwQVTException(new QvtRuntimeException(NLS.bind(EvaluationMessages.QvtOperationalEvaluationVisitorImpl_invalidConfigPropertyValue, configProperty.getName(), rawValue)));
}
return value;
}
public Object visitEntryOperation(EntryOperation entryOperation) {
visitImperativeOperation(entryOperation);
return new OperationCallResult(visitOperationBody(entryOperation.getBody()), getOperationalEvaluationEnv());
}
public Object visitHelper(Helper helper) {
visitImperativeOperation(helper);
if (helper.isIsBlackbox()) {
Object result = doVisitBlackboxOperation(helper);
return new OperationCallResult(result, getOperationalEvaluationEnv());
}
return new OperationCallResult(visitOperationBody(helper.getBody()), getOperationalEvaluationEnv());
}
public Object visitImperativeOperation(ImperativeOperation imperativeOperation) {
List<Object> args = getOperationalEvaluationEnv().getOperationArgs();
Iterator<Object> argIt = args.iterator();
QvtOperationalEvaluationEnv env = getOperationalEvaluationEnv();
for (EParameter nextParam : imperativeOperation.getEParameters()) {
if (!argIt.hasNext()) {
throw new IllegalArgumentException("arguments mismatch: got" + args + ", expected " + //$NON-NLS-1$ //$NON-NLS-2$
imperativeOperation.getEParameters());
}
VarParameter param = (VarParameter) nextParam;
Object arg = argIt.next();
if (param.getKind() != DirectionKind.OUT) {
addToEnv(param.getName(), arg, param.getEType());
}
}
EClassifier contextType = QvtOperationalParserUtil.getContextualType(imperativeOperation);
if (contextType != null) {
addToEnv(Environment.SELF_VARIABLE_NAME, env.getOperationSelf(), contextType);
}
pushedStack(getOperationalEvaluationEnv());
return null;
}
private Object doVisitBlackboxOperation(ImperativeOperation operation) {
assert operation.isIsBlackbox() : "Blackbox operation expected"; //$NON-NLS-1$
QvtOperationalModuleEnv moduleEnv = ASTBindingHelper.resolveModuleEnvironment(operation.eContainer());
Collection<CallHandler> handlers = BlackboxRegistry.INSTANCE.getBlackboxCallHandler(operation, moduleEnv);
if (handlers.isEmpty()) {
throwQVTException(new QvtRuntimeException(NLS.bind(EvaluationMessages.NoBlackboxOperationFound,
QvtOperationalParserUtil.safeGetMappingQualifiedName(getOperationalEnv(), operation))));
}
if (handlers.size() > 1) {
throwQVTException(new QvtRuntimeException(NLS.bind(EvaluationMessages.AmbiguousBlackboxOperationFound,
QvtOperationalParserUtil.safeGetMappingQualifiedName(getOperationalEnv(), operation))));
}
QvtOperationalEvaluationEnv evalEnv = getOperationalEvaluationEnv();
return handlers.iterator().next().invoke(evalEnv.getThisOfType(QvtOperationalParserUtil.getOwningModule(operation)), evalEnv.getOperationSelf(), evalEnv.getOperationArgs().toArray(), evalEnv);
}
public Object visitLibrary(Library library) {
return null;
}
public Object visitLocalProperty(EStructuralFeature property) {
OCLExpression<EClassifier> initExp = QvtOperationalParserUtil.getInitExpression(property);
if(initExp != null) {
return visitExpression(initExp);
}
return null;
}
public Object visitContextualProperty(ContextualProperty contextualProperty) {
if(contextualProperty.getInitExpression() != null) {
return visitExpression(contextualProperty.getInitExpression());
}
return null;
}
private boolean isWhenPreconditionSatisfied(MappingOperation mappingOperation) {
for (OCLExpression<EClassifier> nextCond : mappingOperation.getWhen()) {
if(!Boolean.TRUE.equals(visitExpression(nextCond))) {
return false;
}
}
return true;
}
private boolean isWherePreconditionSatisfied(MappingOperation mappingOperation) {
if (false == mappingOperation.getWhere() instanceof BlockExp) {
return true;
}
for (OCLExpression<EClassifier> nextCond : ((BlockExp) mappingOperation.getWhere()).getBody()) {
if(!Boolean.TRUE.equals(visitExpression(nextCond))) {
return false;
}
}
return true;
}
private void setupInitialResultValue(MappingBody mappingBody) {
ImperativeOperation operation = mappingBody.getOperation();
QvtOperationalEvaluationEnv evalEnv = getOperationalEvaluationEnv();
// Note: the variables for result parameters may not be set or existing yet
// define variables if not done already by the reusing mapping caller so
// avoid overriding values
for (VarParameter resultParam : operation.getResult()) {
if(evalEnv.getValueOf(resultParam.getName()) == null) {
Object initialValue = EvaluationUtil.createInitialValue(resultParam.getEType(), getStandardLibrary(), evalEnv);
replaceInEnv(resultParam.getName(), initialValue, resultParam.getEType());
}
}
if(operation.getResult().size() > 1) {
if(evalEnv.getValueOf(Environment.RESULT_VARIABLE_NAME) == null) {
Object initialValue = EvaluationUtil.createInitialValue(operation.getEType(), getStandardLibrary(), evalEnv);
replaceInEnv(Environment.RESULT_VARIABLE_NAME, initialValue, operation.getEType());
}
}
}
public Object visitMappingBody(MappingBody mappingBody) {
QvtOperationalEvaluationEnv evalEnv = getOperationalEvaluationEnv();
MappingOperation currentMappingCalled = (MappingOperation) mappingBody.getOperation();
setupInitialResultValue(mappingBody);
for (OCLExpression<EClassifier> initExp : mappingBody.getInitSection()) {
visitExpression(initExp);
}
if(!mappingBody.getInitSection().isEmpty()) {
// setup a meaningful IP after init section to avoid pointing to the last expression of init
// section, so in case of error a proper error location can be computed
setCurrentEnvInstructionPointer(currentMappingCalled);
}
Object result = createOrGetResult(currentMappingCalled);
createOutParams(currentMappingCalled);
setOutParamsValues(currentMappingCalled, myEvalEnv.getOperationArgs());
TraceUtil.addTraceRecord(getOperationalEvaluationEnv(), currentMappingCalled);
// call inherited mappings
if(!currentMappingCalled.getInherited().isEmpty()) {
for (MappingOperation extendedMapping : currentMappingCalled.getInherited()) {
// consider overriding mapping
ImperativeOperation overridingOper = EvaluationUtil.getOverridingOperation(getOperationalEvaluationEnv(), extendedMapping);
if (overridingOper instanceof MappingOperation) {
extendedMapping = (MappingOperation) overridingOper;
}
executeImperativeOperation(extendedMapping, evalEnv.getOperationSelf(), evalEnv.getOperationArgs(), true);
}
}
visitOperationBody(mappingBody);
// TODO investigate possibility to modify result
for (OCLExpression<EClassifier> endExp : mappingBody.getEndSection()) {
visitExpression(endExp);
}
// call merged mappings
callMergedMappings(currentMappingCalled, evalEnv);
return result;
}
private void callMergedMappings(MappingOperation mappingOperation, QvtOperationalEvaluationEnv evalEnv) {
for (MappingOperation extendedMapping : mappingOperation.getMerged()) {
// consider overriding mapping
ImperativeOperation overridingOper = EvaluationUtil.getOverridingOperation(getOperationalEvaluationEnv(), extendedMapping);
if (overridingOper instanceof MappingOperation) {
extendedMapping = (MappingOperation) overridingOper;
}
executeImperativeOperation(extendedMapping, evalEnv.getOperationSelf(), evalEnv.getOperationArgs(), true);
}
}
public Object visitMappingCallExp(MappingCallExp mappingCallExp) {
return visitOperationCallExp(mappingCallExp);
}
@Override
public Object visitOperationCallExp(OperationCallExp<EClassifier, EOperation> operationCallExp) {
// TODO - review the note bellow
// set IP of the current stack (represented by the top operation fEnv)
// to the this operation call in order to reflect this call position
// in possible QVT stack, in case an exception is thrown
EObject oldIP = setCurrentEnvInstructionPointer(operationCallExp);
Object result = doVisitOperationCallExp(operationCallExp);
setCurrentEnvInstructionPointer(oldIP);
return result;
}
protected Object doVisitOperationCallExp(OperationCallExp<EClassifier, EOperation> operationCallExp) {
EOperation referredOperation = operationCallExp.getReferredOperation();
boolean isImperative = QvtOperationalUtil.isImperativeOperation(referredOperation);
if (isImperative && !CallHandler.Access.hasHandler(referredOperation)) {
Object source = visitExpression(operationCallExp.getSource());
if (((ImperativeOperation) referredOperation).getContext() != null) {
source = EvaluationUtil.doImplicitListCoercion(
((ImperativeOperation) referredOperation).getContext().getEType(), source);
}
List<Object> args = makeArgs(operationCallExp);
// does not make sense continue at all, call on invalid results in invalid
if(source == getInvalid()) {
return source;
}
ImperativeOperation method = null;
if (QvtOperationalParserUtil.isOverloadableMapping(referredOperation, getOperationalEnv())) {
EOperation actualOperation = findOperationByActualSourceType(source, referredOperation);
if(actualOperation instanceof ImperativeOperation) {
method = (ImperativeOperation) actualOperation;
}
}
if((method == null) && referredOperation instanceof ImperativeOperation) {
// we can't dispatch non-imperative as we already evaluated the source
method = (ImperativeOperation)referredOperation;
}
if(method != null) {
if (QvtOperationalParserUtil.isContextual(method) && source == null) {
if (QvtOperationalParserUtil.getContextualType(method) != getStandardLibrary().getOclVoid()) {
return getInvalid();
}
}
if(operationCallExp instanceof ImperativeCallExp) {
ImperativeCallExp imperativeCall = (ImperativeCallExp) operationCallExp;
if(imperativeCall.isIsVirtual()) {
ImperativeOperation overridingOper = EvaluationUtil.getOverridingOperation(getOperationalEvaluationEnv(), method);
if(overridingOper != null) {
method = overridingOper;
}
}
}
OperationCallResult opResult = executeImperativeOperation(method, source, args, false);
if (operationCallExp instanceof MappingCallExp && opResult instanceof MappingCallResult
&& method instanceof MappingOperation) {
if (((MappingCallExp) operationCallExp).isIsStrict() && ((MappingCallResult) opResult).isPreconditionFailed()) {
throwQVTException(new QvtAssertionFailed(NLS.bind(EvaluationMessages.MappingPreconditionFailed,
method.getName())));
}
retrieveOutArgs(operationCallExp, ((MappingCallResult) opResult).myEvalEnv.getOperationArgs(),
(MappingOperation) method);
}
return EvaluationUtil.doImplicitListCoercion(referredOperation.getEType(), opResult.myResult);
}
}
Object result = null;
try {
result = super.visitOperationCallExp(operationCallExp);
}
catch (QvtRuntimeException e) {
throw e;
}
catch (RuntimeException ex) {
//Logger.getLogger().log(Logger.WARNING, "QvtEvaluator: failed to evaluate oclOperationCall", ex);//$NON-NLS-1$
result = getInvalid();
}
return result;
}
/**
* Finds operation based on the actual type of the source object as per
* virtual call semantics.
*
* @param source
* the self instance of the contextual type
* @param referredOperation
* the operation referred by the call expresion in the AST
* @return the actual operation to call, which is either the passed referred
* operation or another one defined in the bottom-most class in the
* type hierarchy of the source object
*/
private EOperation findOperationByActualSourceType(Object source, EOperation referredOperation) {
EOperation actualOperation = referredOperation;
IVirtualOperationTable vTable = getVirtualTable(referredOperation);
if(vTable != null) {
EClassifier sourceEClass = getEvaluationEnvironment().getType(source);
if(sourceEClass != null) {
InternalEvaluationEnv internEnv = getOperationalEvaluationEnv().getAdapter(InternalEvaluationEnv.class);
EOperation oper = vTable.lookupActualOperation(sourceEClass, getEnvironment(), internEnv);
if(oper != null) {
actualOperation = oper;
}
}
}
return actualOperation;
}
@Override
public Object visitEnumLiteralExp(EnumLiteralExp<EClassifier, EEnumLiteral> el) {
return el.getReferredEnumLiteral().getInstance();
}
/**
* @return result object or <code>null</code> in case that no result
* variable is declared and <code>OclInvalid</code> in case the
* precondition failed and the body was not executed.
*/
public Object visitMappingOperation(MappingOperation mappingOperation) {
visitImperativeOperation(mappingOperation);
QvtOperationalEvaluationEnv evalEnv = getOperationalEvaluationEnv();
if (!isWhenPreconditionSatisfied(mappingOperation)) {
// return Invalid, to indicate precondition failure to the caller. It is used instead of
// of 'null' as it is a legal value for no result inout mapping, even
// the precondition holds
return new MappingCallResult(null, evalEnv, MappingCallResult.PRECOND_FAILED);
}
MappingCallResult result = executeMappingBody(mappingOperation, evalEnv);
if (!isWherePreconditionSatisfied(mappingOperation)) {
throwQVTException(new QvtAssertionFailed(NLS.bind(EvaluationMessages.MappingPostconditionFailed,
mappingOperation.getName())));
}
return result;
}
protected MappingCallResult executeMappingBody(MappingOperation mappingOperation, QvtOperationalEvaluationEnv evalEnv) {
// check the traces whether the relation already holds
TraceRecord traceRecord = TraceUtil.getTraceRecord(evalEnv, mappingOperation);
if (traceRecord != null) {
return new MappingCallResult(TraceUtil.fetchResultFromTrace(evalEnv, traceRecord), evalEnv, MappingCallResult.FETCHED_FROM_TRACE);
}
if(!mappingOperation.getDisjunct().isEmpty()) {
return dispatchDisjunctMapping(mappingOperation);
}
if (mappingOperation.isIsBlackbox()) {
Object result = doVisitBlackboxOperation(mappingOperation);
if (isUndefined(result)) {
throwQVTException(new QvtRuntimeException(NLS.bind(EvaluationMessages.BlackboxMappingFailedToAssignResult,
QvtOperationalParserUtil.safeGetMappingQualifiedName(getOperationalEnv(), mappingOperation))));
}
replaceInEnv(Environment.RESULT_VARIABLE_NAME, result, mappingOperation.getEType());
TraceUtil.addTraceRecord(getOperationalEvaluationEnv(), mappingOperation);
// call merged mappings
callMergedMappings(mappingOperation, evalEnv);
return new MappingCallResult(result, evalEnv, MappingCallResult.BODY_EXECUTED);
}
return new MappingCallResult(((OperationBodyImpl) mappingOperation.getBody()).accept(getVisitor()), evalEnv,
MappingCallResult.BODY_EXECUTED);
}
public Object execute(OperationalTransformation transformation) throws QvtRuntimeException {
boolean isSuppressLoggin = myIsSuppressLoggin;
try {
myIsSuppressLoggin = true;
return transformation.accept(getVisitor());
} finally {
myIsSuppressLoggin = isSuppressLoggin;
}
}
public Object visitModule(Module module) {
if (module instanceof OperationalTransformation == false) {
throw new IllegalArgumentException(NLS.bind(EvaluationMessages.ExtendedOclEvaluatorVisitorImpl_ModuleNotExecutable, module.getName()));
}
try {
return doVisitTransformation((OperationalTransformation) module);
}
catch (QvtRuntimeException e) {
if (!myIsSuppressLoggin) {
StringWriter strWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(strWriter);
e.printQvtStackTrace(printWriter);
Log logger = getContext().getLog();
logger.log(EvaluationMessages.TerminatingExecution);
logger.log(strWriter.getBuffer().toString());
}
throw e;
} finally {
IntermediatePropertyModelAdapter.cleanup(module);
getOperationalEvaluationEnv().cleanup();
}
}
/**
* Executes the given helper operation with actual arguments passed.
*
* @param method
* the helper operation to execute
* @param self
* the contextual instance in case of contextual operation,
* otherwise the default instance of the module which defines the
* called operation
* @param args
* the actual parameter values
* @return return the value directly returned by the operation
*/
public Object executeHelperOperation(Helper method, Object self, List<Object> args) {
Helper actualHelper = method;
EOperation actualOperation = findOperationByActualSourceType(self, method);
if(actualOperation instanceof Helper) {
actualHelper = (Helper) actualOperation;
} else {
// Remark - the case when the actual operation is not imperative but
// a meta-model operation the virtual call will be dispatched by using
// a normal operation call
return getEvaluationEnvironment().callOperation(method, -1, self, args.toArray(new Object[args.size()]));
}
OperationCallResult result = executeImperativeOperation(actualHelper, self, args, false);
return result.myResult;
}
@SuppressWarnings("unchecked")
public Object visitInstantiationExp(InstantiationExp objectExp) {
// should instantiate the module transformation
EClass _class = objectExp.getInstantiatedClass();
if (_class instanceof OperationalTransformation) {
EList<org.eclipse.ocl.ecore.OCLExpression> formalArguments = objectExp.getArgument();
List<ModelInstance> actualArguments = new ArrayList<ModelInstance>(formalArguments.size());
for (OCLExpression<EClassifier> nextArg : formalArguments) {
Object argVal = visitExpression(nextArg);
if(argVal instanceof ModelInstance == false) {
throwQVTException(new QvtRuntimeException(EvaluationMessages.QvtOperationalEvaluationVisitorImpl_UndefModelParamInTransf));
}
ModelInstance modelInstance = (ModelInstance) argVal;
actualArguments.add(modelInstance);
}
OperationalTransformation targetTransf = (OperationalTransformation)_class;
QvtOperationalEvaluationEnv currentEnv = getOperationalEvaluationEnv();
// create a nested environment for constructor invocation representing
// the root environment of explicitly called transformation
// Empty default context, no configuration property is available
// Remark: Can we set configuration property in the concrete syntax on the explicit transf object.
// bug 416584: Now we need to access configuration properties of non-entry modules
Context nestedContext = EvaluationUtil.createAggregatedContext(currentEnv);
QvtOperationalEnvFactory envFactory = getOperationalEnv().getFactory();
QvtOperationalEvaluationEnv nestedEvalEnv = envFactory.createEvaluationEnvironment(nestedContext, null);
//bug 392153: reuse existing trace for nested environment
Trace trace = currentEnv.getAdapter(InternalEvaluationEnv.class).getTraces();
nestedEvalEnv.getAdapter(InternalEvaluationEnv.class).setTraces(trace);
// send arguments into the entry operation
nestedEvalEnv.getOperationArgs().addAll(actualArguments);
// Use per transformation instance visitor
InternalEvaluator nestedVisitor = createNestedEvaluationVisitor(this, nestedEvalEnv);
try {
setOperationalEvaluationEnv(nestedEvalEnv);
ModuleInstance moduleInstance = nestedVisitor.callTransformationImplicitConstructor(targetTransf, actualArguments);
return moduleInstance;
} finally {
setOperationalEvaluationEnv(currentEnv);
}
}
else {
Object owner = createInstance(objectExp.getType(), (ModelParameter) objectExp.getExtent());
EList<org.eclipse.ocl.ecore.OCLExpression> formalArguments = objectExp.getArgument();
List<Object> actualArguments = new ArrayList<Object>(formalArguments.size());
for (OCLExpression<EClassifier> nextArg : formalArguments) {
Object argVal = visitExpression(nextArg);
actualArguments.add(argVal);
}
Adapter adapter = EcoreUtil.getAdapter(objectExp.eAdapters(), ConstructorOperationAdapter.class);
if (adapter != null) {
Constructor constructorOp = ((ConstructorOperationAdapter) adapter).getReferredConstructor();
for (int i = 0, in = constructorOp.getEParameters().size(); i < in; ++i) {
actualArguments.set(i, EvaluationUtil.doImplicitListCoercion(
constructorOp.getEParameters().get(i).getEType(), actualArguments.get(i)));
}
executeImperativeOperation(constructorOp, owner, actualArguments, false);
}
else {
if (objectExp.getArgument().isEmpty()) {
// it's OK since default constructor is called
}
else if (objectExp.getEType() instanceof CollectionType<?,?> && owner instanceof Collection<?>) {
((Collection<Object>) owner).addAll(actualArguments);
}
else {
throwQVTException(new QvtRuntimeException("Undefined constructor is called")); //$NON-NLS-1$
}
}
return owner;
}
}
public TransformationInstance callTransformationImplicitConstructor(OperationalTransformation transformation, List<ModelInstance> transfArgs) {
ModuleInstanceFactory eFactory = (ModuleInstanceFactory)transformation.getEFactoryInstance();
assert eFactory != null : "Module class must have factory"; //$NON-NLS-1$
TransformationInstance instance = (TransformationInstance) eFactory.create(transformation);
// Note: need to make the main executed transf available via this
// so all super module have access to env::getCurrentTransformation()
getEvaluationEnvironment().add(QvtOperationalEnv.THIS, instance);
ModelParameterHelper modelParameters = new ModelParameterHelper(transformation, transfArgs);
initModule(instance, modelParameters);
CallHandler handler = createTransformationHandler();
InternalTransformation internTransf = instance.getAdapter(InternalTransformation.class);
internTransf.setTransformationHandler(handler);
// we are initialized set back the pointer to the module
setCurrentEnvInstructionPointer(transformation);
return instance;
}
private CallHandler createTransformationHandler() {
return new CallHandler() {
public OperationCallResult invoke(ModuleInstance moduleInstance, Object source, Object[] args, QvtOperationalEvaluationEnv evalEnv) {
assert (args.length == 0) : "transformation instance must be invoked with zero arguments";
TransformationInstance transformationInstance = (TransformationInstance) source;
try {
evaluateModelParameterConditions(transformationInstance, evalEnv);
OperationalTransformation transformation = transformationInstance.getTransformation();
if (transformation.isIsBlackbox()) {
QvtOperationalModuleEnv moduleEnv = ASTBindingHelper.resolveModuleEnvironment(transformationInstance.getModule());
Collection<CallHandler> handlers = BlackboxRegistry.INSTANCE.getBlackboxCallHandler(
transformation, moduleEnv);
if (handlers.isEmpty()) {
throwQVTException(new QvtRuntimeException(NLS.bind(EvaluationMessages.NoBlackboxOperationFound,
QvtOperationalParserUtil.safeGetQualifiedName(getOperationalEnv(), transformation))));
}
if (handlers.size() > 1) {
throwQVTException(new QvtRuntimeException(NLS.bind(EvaluationMessages.AmbiguousBlackboxOperationFound,
QvtOperationalParserUtil.safeGetQualifiedName(getOperationalEnv(), transformation))));
}
List<Object> actualArgs = makeBlackboxTransformationArgs(transformationInstance, evalEnv);
Object result = handlers.iterator().next().invoke(transformationInstance, source, actualArgs.toArray(), evalEnv);
return new OperationCallResult(result, evalEnv);
}
else {
return runMainEntry(transformation, makeEntryOperationArgs(transformation));
}
} finally {
transformationInstance.getAdapter(InternalTransformation.class).dispose();
}
}
};
}
// FIXME - review the strange case of having various return types
private Object doVisitTransformation(OperationalTransformation transformation) {
QvtOperationalEvaluationEnv evaluationEnv = getOperationalEvaluationEnv();
List<ModelInstance> modelArgs = EvaluationUtil.getTransfromationModelArguments(evaluationEnv, transformation);
TransformationInstance moduleInstance = callTransformationImplicitConstructor(transformation, modelArgs);
InternalTransformation internTransf = moduleInstance.getAdapter(InternalTransformation.class);
CallHandler handler = internTransf.getTransformationHandler();
// call main entry operation or blackbox implementation
OperationCallResult callResult = (OperationCallResult) handler.invoke(
null,
moduleInstance,
Collections.emptyList().toArray(),
evaluationEnv);
QvtEvaluationResult evalResult = EvaluationUtil.createEvaluationResult(callResult.myEvalEnv);
if (evalResult.getModelExtents().isEmpty()) {
if (callResult.myResult instanceof EObject) {
// compatibility reason, make the main() operation return value available in an extent
ModelParameterExtent modelParameter = new ModelParameterExtent(
Collections.singletonList((EObject) callResult.myResult), null, null);
evaluationEnv.addModelExtent(modelParameter);
evalResult.getModelExtents().add(modelParameter.getContents());
} else {
return callResult.myResult;
}
}
return evalResult;
}
protected void processDeferredTasks() {
InternalEvaluationEnv internalEvalEnv = getOperationalEvaluationEnv().getAdapter(InternalEvaluationEnv.class);
internalEvalEnv.processDeferredTasks();
}
public Object visitModuleImport(ModuleImport moduleImport) {
return null;
}
public Object visitObjectExp(ObjectExp objectExp) {
InternalEvaluationEnv internEnv = getOperationalEvaluationEnv().getAdapter(InternalEvaluationEnv.class);
internEnv.setCurrentIP(objectExp);
Object owner = getOutOwner(objectExp);
if(objectExp.getBody() != null) {
EList<org.eclipse.ocl.ecore.OCLExpression> contents = objectExp.getBody().getContent();
for (OCLExpression<EClassifier> exp : contents) {
visitExpression(exp);
}
}
// owner may have changed in body content, so retrieve it again (fixed by bug 388325)
owner = getOutOwner(objectExp);
if (getOperationalEnv().isTemporaryElement(objectExp.getName())) {
getOperationalEvaluationEnv().remove(objectExp.getName());
}
return owner;
}
public Object visitReturnExp(ReturnExp returnExp) {
Object value = null;
OCLExpression<EClassifier> valueExp = returnExp.getValue();
if(valueExp != null) {
value = visitExpression(valueExp);
}
// Wrap the result of the expression in an OperationCallResult object.
// This type breaks control flow, so the value arrives directly at its
// calling operation, where it is unwrapped again and returned.
return new OperationCallResult(value, getOperationalEvaluationEnv());
}
public Object visitOperationBody(OperationBody operationBody) {
Object result = null;
for (OCLExpression<EClassifier> exp : operationBody.getContent()) {
result = visitExpression(exp);
// If control flow was broken (by means of a return statement,
// stop executing the next lines and return this result.
if(result instanceof BreakingResult) {
if(result instanceof OperationCallResult) {
result = ((OperationCallResult)result).myResult;
}
else {
result = null;
}
break;
}
}
ImperativeOperation operation = operationBody.getOperation();
if(operation.getEType() == getStandardLibrary().getOclVoid()) {
result = null;
}
if(operation.getResult().size() > 1) {
return createTupleResult(operation);
}
return result;
}
public Object visitVarParameter(VarParameter varParameter) {
return null;
}
public Object visitVariableInitExp(VariableInitExp variableInitExp) {
org.eclipse.ocl.ecore.Variable referredVariable = variableInitExp.getReferredVariable();
OCLExpression<EClassifier> initExpression = referredVariable.getInitExpression();
Object value = null;
if(initExpression != null) {
value = visitExpression(initExpression);
// check that collection is initialized to empty collection in case of 'null'
} else {
value = EvaluationUtil.createInitialValue(referredVariable.getType(), getEnvironment().getOCLStandardLibrary(),
getEvaluationEnvironment());
}
replaceInEnv(referredVariable.getName(),
EvaluationUtil.doImplicitListCoercion(variableInitExp.getType(), value), variableInitExp.getType());
return variableInitExp.isWithResult() ? value : null;
}
public Object visitBlockExp(BlockExp blockExp) {
return visitBlockExpImpl(blockExp.getBody(), blockExp.eContainer() instanceof ImperativeOperation);
}
private Object visitBlockExpImpl(EList<org.eclipse.ocl.ecore.OCLExpression> expList, boolean isInImperativeOper) {
List<String> scopeVars = null;
Object result = null;
for (OCLExpression<EClassifier> exp : expList) {
if((exp instanceof VariableInitExp) && !isInImperativeOper) {
if(scopeVars == null) {
scopeVars = new LinkedList<String>();
}
VariableInitExp varInitExp = (VariableInitExp) exp;
scopeVars.add(varInitExp.getName());
}
result = visitExpression(exp);
if(result instanceof BreakingResult) {
break;
}
// Return null, unless control flow is broken (by break, continue or return).
// When control flow is broken, propagate this upward in the AST.
result = null;
}
if(scopeVars != null) {
EvaluationEnvironment<EClassifier, EOperation, EStructuralFeature, EClass, EObject> evalEnv = getEvaluationEnvironment();
for (String varName : scopeVars) {
evalEnv.remove(varName);
}
}
return result;
}
public Object visitComputeExp(ComputeExp computeExp) {
Variable<EClassifier, EParameter> returnedElement = computeExp.getReturnedElement();
Object initExpressionValue = null;
OCLExpression<EClassifier> initExpression = returnedElement.getInitExpression();
if (initExpression != null) {
initExpressionValue = visitExpression(initExpression);
}
replaceInEnv(returnedElement.getName(), initExpressionValue, returnedElement.getType());
Object result = visitExpression(computeExp.getBody());
Object returnedValue = getEvaluationEnvironment().remove(returnedElement.getName());
if(result instanceof BreakingResult) {
// Control flow was broken (break or continue).
// Instead of returning the value, propagate this.
return result;
}
return returnedValue;
}
public Object visitWhileExp(WhileExp whileExp) {
Object result = null;
while (true) {
Object condition = visitExpression(whileExp.getCondition());
if (Boolean.TRUE.equals(condition)) {
result = visitExpression(whileExp.getBody());
if(result instanceof BreakingResult) {
// Control flow is being broken (break, continue, or return).
if(result instanceof BreakResult) {
// Result must be null, unless it comes from a return statement.
result = null;
break;
}
if(result instanceof ContinueResult) {
// Instead of breaking out of the loop, continue with the next iteration.
result = null;
continue;
}
break;
}
} else {
break;
}
}
return result;
}
private static class SwitchAltExpResult {
public Object myCondition;
public Object myResult;
}
public Object visitAltExp(AltExp switchAltExp) {
SwitchAltExpResult result = new SwitchAltExpResult();
result.myCondition = visitExpression(switchAltExp.getCondition());
if (Boolean.TRUE.equals(result.myCondition)) {
result.myResult = visitExpression(switchAltExp.getBody());
}
return result;
}
public Object visitSwitchExp(SwitchExp switchExp) {
for (AltExp altExp : switchExp.getAlternativePart()) {
Object altResult = visitExpression(altExp);
if (altResult instanceof SwitchAltExpResult) {
if (isUndefined(((SwitchAltExpResult) altResult).myCondition)) {
return getInvalid();
}
if (Boolean.TRUE.equals(((SwitchAltExpResult) altResult).myCondition)) {
return ((SwitchAltExpResult) altResult).myResult;
}
}
else if (Boolean.TRUE.equals(altResult)) {
return null;
}
}
OCLExpression<EClassifier> elsePart = switchExp.getElsePart();
if (elsePart != null) {
return visitExpression(elsePart);
}
return null;
}
/* resolve expressions family */
public Object visitResolveExp(ResolveExp resolveExp) {
if (resolveExp.isIsDeferred()) {
InternalEvaluationEnv internalEvalEnv = getOperationalEvaluationEnv().getAdapter(InternalEvaluationEnv.class);
if(!internalEvalEnv.isDeferredExecution()) {
LateResolveTask lateResolveTask = new LateResolveTask(resolveExp, internalEvalEnv.getLastAssignmentLvalueEval(),
(QvtOperationalEvaluationVisitor) getVisitor(), getOperationalEvaluationEnv(), this);
internalEvalEnv.addDeferredTask(lateResolveTask);
return null;
}
}
return QvtResolveUtil.resolveNow(resolveExp, this, getOperationalEvaluationEnv());
}
public Object visitResolveInExp(ResolveInExp resolveInExp) {
if (resolveInExp.isIsDeferred()) {
InternalEvaluationEnv internalEvalEnv = getOperationalEvaluationEnv().getAdapter(InternalEvaluationEnv.class);
if(!internalEvalEnv.isDeferredExecution()) {
LateResolveInTask lateResolveInTask = new LateResolveInTask(resolveInExp, internalEvalEnv.getLastAssignmentLvalueEval(),
(QvtOperationalEvaluationVisitor) getVisitor(), getOperationalEvaluationEnv(), this);
internalEvalEnv.addDeferredTask(lateResolveInTask);
return null;
}
}
return QvtResolveUtil.resolveInNow(resolveInExp, this, getOperationalEvaluationEnv());
}
public Object visitModelType(ModelType modelType) {
return null;
}
public Object visitLogExp(LogExp logExp) {
doVisitLogExp(logExp, getContext().getLog(), null);
return null;
}
private String doVisitLogExp(LogExp logExp, Log logger, String messagePrefix) {
if(logExp.getCondition() != null && !Boolean.TRUE.equals(visitExpression(logExp.getCondition()))) {
return null;
}
Object invalid = getInvalid();
String invalidRepr = "<Invalid>"; //$NON-NLS-1$
// process logging level
Integer level = null;
EList<OCLExpression<EClassifier>> args = logExp.getArgument();
if(args.size() > 2) {
Object levelObj = visitExpression(args.get(2));
level = NumberConversions.strictConvertNumber(levelObj, Integer.class);
}
Object message = visitExpression(args.get(0));
if(message == null) {
message = "<null>"; //$NON-NLS-1$
} else if(message == invalid) {
message = invalidRepr;
}
Object logEntry = message;
if(messagePrefix != null) {
logEntry = messagePrefix + " : " + message; //$NON-NLS-1$
}
Object element = null;
Object formatedElement = null;
if(args.size() > 1) {
element = visitExpression(args.get(1));
if(element == invalid) {
formatedElement = invalidRepr;
} else {
formatedElement = EvaluationUtil.formatLoggedElement(element);
}
}
if(level == null) {
if(element == null) {
logger.log(String.valueOf(logEntry));
} else {
logger.log(String.valueOf(logEntry), formatedElement);
}
} else {
if(element == null) {
logger.log(level, String.valueOf(logEntry));
} else {
logger.log(level, String.valueOf(logEntry), formatedElement);
}
}
return message.toString();
}
public Object visitAssertExp(AssertExp assertExp) {
Object assertionValue = visitExpression(assertExp.getAssertion());
if(!Boolean.TRUE.equals(assertionValue)) {
InternalEvaluationEnv internEvalEnv = getOperationalEvaluationEnv().getAdapter(InternalEvaluationEnv.class);
Module currentModule = internEvalEnv.getCurrentModule().getModule();
IModuleSourceInfo moduleSource = ASTBindingHelper.getModuleSourceBinding(currentModule);
String source;
if(moduleSource != null) {
source = moduleSource.getSourceURI().lastSegment();
} else {
source = EvaluationMessages.UknownSourceLabel;
}
StringBuilder locationBuf = new StringBuilder(source);
if(assertExp.getStartPosition() >= 0 && moduleSource != null) {
int lineNum = moduleSource.getLineNumberProvider().getLineNumber(assertExp.getStartPosition());
locationBuf.append(':').append(lineNum);
}
String message = NLS.bind(EvaluationMessages.AssertFailedMessage, assertExp.getSeverity(), locationBuf.toString());
Log logger = getContext().getLog();
String logMessage = null;
if(assertExp.getLog() != null) {
logMessage = doVisitLogExp(assertExp.getLog(), logger, message);
} else {
logger.log(message);
}
if(SeverityKind.FATAL.equals(assertExp.getSeverity())) {
String msg = (logMessage == null ? EvaluationMessages.FatalAssertionFailed : logMessage);
throwQVTException(new QvtAssertionFailed(msg));
}
}
return null;
}
public Object visitImperativeLoopExp(ImperativeLoopExp imperativeLoopExp) {
throw new UnsupportedOperationException();
}
public Object visitForExp(ForExp forExp) {
Object sourceValue = visitExpression(forExp.getSource());
if (!isUndefined(sourceValue)) {
// generate a name for the result variable and add it to the environment
String resultName = generateName();
getEvaluationEnvironment().add(resultName, null);
Collection<?> sourceCollection = (Collection<?>) sourceValue;
// get the list of ocl iterators
List<Variable<EClassifier, EParameter>> iterators = forExp.getIterator();
// get the condition expression
OCLExpression<EClassifier> condition = forExp.getCondition();
// get the body expression
OCLExpression<EClassifier> body = forExp.getBody();
// evaluate
QvtIterationTemplateForExp.getInstance(getVisitor()).evaluate(
sourceCollection, iterators, null, condition, body, resultName, "forOne".equals(forExp.getName())); //$NON-NLS-1$
// remove result name from environment
getEvaluationEnvironment().remove(resultName);
}
return null;
}
public Object visitImperativeIterateExp(ImperativeIterateExp imperativeIterateExp) {
EClassifier sourceType = imperativeIterateExp.getSource().getType();
if (sourceType instanceof PredefinedType<?>) {
Object sourceValue = visitExpression(imperativeIterateExp.getSource());
// value of iteration expression is undefined if the source is
// null or OclInvalid
if (isUndefined(sourceValue)) {
return getInvalid();
}
// get initial result value based on the source type
@SuppressWarnings("unchecked")
CollectionType<EClassifier, EOperation> collType = (CollectionType<EClassifier, EOperation>) imperativeIterateExp.getSource().getType();
Object initResultVal = null;
if (imperativeIterateExp.getName().equals("xselect")) { //$NON-NLS-1$
initResultVal = EvaluationUtil.createNewCollectionOfSameKind((Collection<?>) sourceValue);
} else if (imperativeIterateExp.getName().equals("xcollect") //$NON-NLS-1$
|| imperativeIterateExp.getName().equals("collectselect")) { //$NON-NLS-1$
initResultVal = ((collType instanceof SetType<?,?>) || (collType instanceof BagType<?,?>)) ?
CollectionUtil.createNewBag() : CollectionUtil.createNewSequence();
}
// generate a name for the result variable and add it to the environment
String resultName = generateName();
getEvaluationEnvironment().add(resultName, initResultVal);
Collection<?> sourceCollection = (Collection<?>) sourceValue;
// get the list of ocl iterators
List<Variable<EClassifier, EParameter>> iterators = imperativeIterateExp.getIterator();
// get the target expression
Variable<EClassifier, EParameter> target = imperativeIterateExp.getTarget();
// get the condition expression
OCLExpression<EClassifier> condition = imperativeIterateExp.getCondition();
// get the body expression
OCLExpression<EClassifier> body = imperativeIterateExp.getBody();
// evaluate
Object result = null;
if ("xcollect".equals(imperativeIterateExp.getName())) { //$NON-NLS-1$
result = QvtIterationTemplateXCollect.getInstance(getVisitor()).evaluate(
sourceCollection, iterators, target, condition, body, resultName, false);
} else if ("xselect".equals(imperativeIterateExp.getName())) { //$NON-NLS-1$
result = QvtIterationTemplateXSelect.getInstance(getVisitor()).evaluate(
sourceCollection, iterators, target, condition, body, resultName, false);
} else if ("collectselect".equals(imperativeIterateExp.getName())) { //$NON-NLS-1$
result = QvtIterationTemplateCollectSelect.getInstance(getVisitor()).evaluate(
sourceCollection, iterators, target, condition, body, resultName, false);
} else if ("collectOne".equals(imperativeIterateExp.getName())) { //$NON-NLS-1$
result = QvtIterationTemplateXCollect.getInstance(getVisitor()).evaluate(
sourceCollection, iterators, target, condition, body, resultName, true);
} else if ("selectOne".equals(imperativeIterateExp.getName())) { //$NON-NLS-1$
result = QvtIterationTemplateXSelect.getInstance(getVisitor()).evaluate(
sourceCollection, iterators, target, condition, body, resultName, true);
} else if ("collectselectOne".equals(imperativeIterateExp.getName())) { //$NON-NLS-1$
result = QvtIterationTemplateCollectSelect.getInstance(getVisitor()).evaluate(
sourceCollection, iterators, target, condition, body, resultName, true);
}
// remove result name from environment
getEvaluationEnvironment().remove(resultName);
return result;
}
String message = NLS.bind(EvaluationMessages.IteratorNotImpl, imperativeIterateExp.getName());
throw new UnsupportedOperationException(message);
}
public Object visitConstructor(Constructor constructor) {
visitImperativeOperation(constructor);
QvtOperationalEvaluationEnv env = getOperationalEvaluationEnv();
if (constructor.isIsBlackbox()) {
Object result = doVisitBlackboxOperation(constructor);
return new OperationCallResult(result, env);
}
env.add(Environment.RESULT_VARIABLE_NAME, env.remove(Environment.SELF_VARIABLE_NAME));
return new OperationCallResult(visitOperationBody(constructor.getBody()), env);
}
public Object visitConstructorBody(ConstructorBody constructorBody) {
return visitOperationBody(constructorBody);
}
public Object visitBreakExp(BreakExp astNode) {
return BREAK;
}
public Object visitCatchtExp(CatchExp astNode) {
// TODO Auto-generated method stub
return null;
}
public Object visitContinueExp(ContinueExp astNode) {
return CONTINUE;
}
public Object visitDictLiteralPart(DictLiteralPart astNode) {
// TODO Auto-generated method stub
return null;
}
public Object visitOrderedTupleLiteralExp(OrderedTupleLiteralExp astNode) {
// TODO Auto-generated method stub
return null;
}
public Object visitOrderedTupleLiteralPart(OrderedTupleLiteralPart astNode) {
// TODO Auto-generated method stub
return null;
}
public Object visitRaiseExp(RaiseExp raiseExp) {
Object value = null;
if(raiseExp.getArgument() != null) {
value = visitExpression(raiseExp.getArgument());
}
String argument = (value instanceof String) ? (String)value : null;
QvtException exception = new QvtException(argument, (EClass)raiseExp.getException());
exception.setStackQvtTrace(new QvtStackTraceBuilder(getOperationalEvaluationEnv()).buildStackTrace());
throw exception;
}
public Object visitTryExp(TryExp tryExp) {
try {
return visitBlockExpImpl(tryExp.getTryBody(), tryExp.eContainer() instanceof ImperativeOperation);
}
catch (QvtException exception) {
boolean processed = false;
OUTERMOST: for (CatchExp catchExp : tryExp.getExceptClause()) {
for (EClassifier excType : catchExp.getException()) {
if (EmfUtil.isAssignableFrom(excType, exception.getExceptionType())) {
processed = processCatch(catchExp, exception);
break OUTERMOST;
}
}
if (catchExp.getException().isEmpty()) { // catch all
processed = processCatch(catchExp, exception);
break OUTERMOST;
}
}
if (!processed) {
throw exception;
}
}
return null;
}
private boolean processCatch(CatchExp catchExp, QvtException exception) {
QvtOperationalEvaluationEnv evalEnv = getOperationalEvaluationEnv();
String varName = null;
org.eclipse.ocl.ecore.Variable catchVariable = ASTBindingHelper.getCatchVariable(catchExp);
if (catchVariable != null) {
ExceptionInstance excObject = null;
if (exception.getExceptionType().getEPackage() == QvtOperationalStdLibrary.INSTANCE.getStdLibModule()) {
excObject = QvtOperationalStdLibrary.INSTANCE.getStdlibFactory().createException(exception.getExceptionType(),
exception.getMessage(), exception.getQvtStackTrace());
}
else {
ExceptionClassInstance exceptionImpl = (ExceptionClassInstance) createInstance(exception.getExceptionType(), null);
exceptionImpl.setArgument(exception.getMessage());
exceptionImpl.setStackElements(exception.getQvtStackTrace());
excObject = exceptionImpl;
}
varName = catchVariable.getName();
evalEnv.add(varName, excObject);
}
visitBlockExpImpl(catchExp.getBody(), catchExp.eContainer() instanceof ImperativeOperation);
if (varName != null) {
evalEnv.remove(varName);
}
return true;
}
public Object visitUnlinkExp(UnlinkExp astNode) {
// TODO Auto-generated method stub
return null;
}
public Object visitUnpackExp(UnpackExp astNode) {
// TODO Auto-generated method stub
return null;
}
private static synchronized String generateName() {
return "__qvtresult__" + tempCounter++;//$NON-NLS-1$
}
/**
* Initializes the model parameters and properties of the given module
* instance and all instances associated via import.
*
* @param moduleInstance
* the instance to initialize
* @param modelParameters
* helper for binding transformation parameters
*/
private void initModule(ModuleInstance moduleInstance, ModelParameterHelper modelParameters) {
Module type = moduleInstance.getModule();
QvtOperationalEnv env = (QvtOperationalEnv) getEnvironment();
QvtOperationalEvaluationEnv currentEvalEnv = getOperationalEvaluationEnv();
QvtOperationalEvaluationEnv nestedEvalEnv = (QvtOperationalEvaluationEnv) env.getFactory().createEvaluationEnvironment(getOperationalEvaluationEnv());
// ensure 'this' instance available in the initialization code
nestedEvalEnv.add(QvtOperationalEnv.THIS, moduleInstance);
// propagate arguments, provided it is a transformation module
nestedEvalEnv.getOperationArgs().addAll(currentEvalEnv.getOperationArgs());
// point to the module we are initializing
nestedEvalEnv.getAdapter(InternalEvaluationEnv.class).setCurrentIP(type);
try {
setOperationalEvaluationEnv(nestedEvalEnv);
// push stack before a chance for exception, to have push/pop in balance
pushedStack(nestedEvalEnv);
// eventually cause STO exception
EvaluationUtil.checkCurrentStackDepth(currentEvalEnv);
// do initialization of model params here to ensure existing out extent for objects created during initialization of imported modules (fixed by bug 392080)
doInitModelParams(moduleInstance, modelParameters);
for (ModuleImport moduleImport : type.getModuleImport()) {
Module importedModule = moduleImport.getImportedModule();
ModuleInstance importedInstance = moduleInstance.getThisInstanceOf(importedModule);
if(importedInstance != null) {
ModuleInstance.Internal importedInternal = importedInstance.getAdapter(ModuleInstance.Internal.class);
if(!importedInternal.isInitialized()) {
initModule(importedInstance, modelParameters);
}
}
}
doInitModule(moduleInstance);
moduleInstance.getAdapter(ModuleInstance.Internal.class).setInitialized();
} finally {
setOperationalEvaluationEnv(getOperationalEvaluationEnv().getParent());
poppedStack();
}
}
private void doInitModelParams(ModuleInstance moduleInstance, ModelParameterHelper modelParameters) {
if(modelParameters != null && moduleInstance.getModule().eClass() == ExpressionsPackage.eINSTANCE.getOperationalTransformation()) {
modelParameters.initModelParameters((TransformationInstance) moduleInstance);
}
}
private void doInitModule(ModuleInstance moduleInstance) {
Module module = moduleInstance.getModule();
QvtOperationalEvaluationEnv env = getOperationalEvaluationEnv();
for (EStructuralFeature feature : module.getConfigProperty()) {
Object propValue = visitConfigProperty(feature);
env.callSetter(moduleInstance, feature, propValue, isUndefined(propValue), true);
}
for (EStructuralFeature feature : module.getEStructuralFeatures()) {
if(feature instanceof ContextualProperty || module.getConfigProperty().contains(feature)) {
continue;
}
setCurrentEnvInstructionPointer(feature);
OCLExpression<EClassifier> initExp = QvtOperationalParserUtil.getInitExpression(feature);
Object propValue = null;
if(initExp != null) {
propValue = visitExpression(initExp);
}
else {
propValue = EvaluationUtil.createInitialValue(feature.getEType(), getEnvironment().getOCLStandardLibrary(), getEvaluationEnvironment());
}
env.callSetter(moduleInstance, feature, propValue, isUndefined(propValue), true);
}
// for (Rename rename : module.getOwnedRenaming()) {
// ((RenameImpl) rename).accept(getVisitor());
// }
}
private IVirtualOperationTable getVirtualTable(EOperation operation) {
return IVirtualOperationTable.Access.INSTANCE.getVirtualTable(operation);
}
private Object createOrGetResult(MappingOperation mappingOperation) {
Object result = null;
for (VarParameter varParam : mappingOperation.getResult()) {
result = getRuntimeValue(varParam.getName());
if (isUndefined(result)) {
if (false == varParam.getEType() instanceof VoidType<?>) {
result = createInstance(varParam.getEType(), ((MappingParameter) varParam).getExtent());
replaceInEnv(varParam.getName(), result, varParam.getEType());
}
}
}
if (mappingOperation.getResult().size() > 1) {
result = createTupleResult(mappingOperation);
replaceInEnv(Environment.RESULT_VARIABLE_NAME, result, mappingOperation.getEType());
}
else {
result = getRuntimeValue(Environment.RESULT_VARIABLE_NAME);
}
return result;
}
private void createOutParams(MappingOperation mappingOperation) {
for (EParameter nextParam : mappingOperation.getEParameters()) {
VarParameter param = (VarParameter) nextParam;
Object paramValue = getRuntimeValue(param.getName());
if (isUndefined(paramValue) && param.getKind() == DirectionKind.OUT) {
paramValue = createInstance(param.getType(), ((MappingParameter) param).getExtent());
replaceInEnv(param.getName(), paramValue, param.getType());
}
}
}
private void createOutParamsDisjunct(MappingOperation operation, List<Object> argValues) {
Iterator<EParameter> itParams = operation.getEParameters().iterator();
Iterator<Object> itValue = argValues.iterator();
while (itParams.hasNext()) {
MappingParameter param = (MappingParameter) itParams.next();
Object argValue = itValue.next();
if (param.getKind() == DirectionKind.OUT) {
replaceInEnv(param.getName(), argValue, param.getType());
}
}
}
private void setOutParamsValues(MappingOperation operation, List<Object> argValues) {
Iterator<EParameter> itParams = operation.getEParameters().iterator();
ListIterator<Object> itArgument = argValues.listIterator();
while (itArgument.hasNext()) {
MappingParameter mappingParam = (MappingParameter) itParams.next();
itArgument.next();
if (mappingParam.getKind() == DirectionKind.OUT) {
itArgument.set(getRuntimeValue(mappingParam.getName()));
}
}
}
/**
* Tag interface which represents an evaluation result which,
* when encountered, breaks control flow.
*
* Examples of this are break, continue, and return.
*/
public static interface BreakingResult {
}
/**
* Type of result which represents the situation in which a break statement is encountered.
*/
public static class BreakResult implements BreakingResult {
BreakResult() { }
}
protected final static BreakResult BREAK = new BreakResult();
/**
* Type of result which represents the situation in which a continue statement is encountered.
*/
public static class ContinueResult implements BreakingResult {
ContinueResult() { }
}
protected final static ContinueResult CONTINUE = new ContinueResult();
/**
* The result of an operation call.
* Represents the situation where a return statement was encountered.
*/
public static class OperationCallResult implements BreakingResult {
public Object myResult;
public QvtOperationalEvaluationEnv myEvalEnv;
OperationCallResult(Object myResult, QvtOperationalEvaluationEnv myEvalEnv) {
this.myResult = myResult;
this.myEvalEnv = myEvalEnv;
}
}
private static class MappingCallResult extends OperationCallResult {
static final int BODY_EXECUTED = 0;
static final int PRECOND_FAILED = 2;
static final int FETCHED_FROM_TRACE = 4;
static final int NO_DISJUNCT_SELECTED = 8;
int myStatus;
private MappingCallResult(Object myResult, QvtOperationalEvaluationEnv myEvalEnv, int status) {
super(myResult, myEvalEnv);
myStatus = status;
}
boolean isBodyExecuted() { return myStatus == BODY_EXECUTED; }
boolean isPreconditionFailed() { return (myStatus & PRECOND_FAILED) != 0; };
//boolean isFetchedFromTrace() { return (myStatus & FETCHED_FROM_TRACE) != 0; };
//boolean isNoDisjunctSelected() { return (myStatus & NO_DISJUCT_SELECTED) != 0; };
}
private OperationCallResult executeImperativeOperation(ImperativeOperation method, Object source, List<Object> args, boolean isReusingMappingCall) {
QvtOperationalEvaluationEnv oldEvalEnv = getOperationalEvaluationEnv();
boolean isMapping = method instanceof MappingOperation;
// eventually cause STO exception
EvaluationUtil.checkCurrentStackDepth(oldEvalEnv);
// create a nested evaluation environment for this operation call
QvtOperationalEvaluationEnv nestedEnv = getOperationalEnv().getFactory().createEvaluationEnvironment(
oldEvalEnv.getContext(), oldEvalEnv);
nestedEnv.setOperation(method);
nestedEnv.getOperationArgs().addAll(args);
if (source != getInvalid()) {
nestedEnv.setOperationSelf(source);
}
if(isReusingMappingCall) {
// let the reused mapping see the reusing caller's out/result parameters
EvaluationUtil.mapOperationOutAndResultParams(oldEvalEnv, nestedEnv);
}
// setup 'this' module variable
Module targetModule = QvtOperationalParserUtil.getOwningModule(method);
assert targetModule != null;
// Resolves the target module instance to call from the currently executed module 'this'
ModuleInstance calledThisInstance = oldEvalEnv.getThisOfType(targetModule);
assert calledThisInstance != null;
setOperationalEvaluationEnv(nestedEnv);
// add 'this' to the nested environment
addToEnv(QvtOperationalEnv.THIS, calledThisInstance, targetModule);
// set IP initially to the method header
setCurrentEnvInstructionPointer(method);
OperationCallResult callResult = null;
try {
Object result = ((ImperativeOperationImpl) method).accept(getVisitor());
assert result instanceof OperationCallResult;
assert !isMapping || result instanceof MappingCallResult;
callResult = (OperationCallResult)result;
}
catch (StackOverflowError e) {
throwQVTException(new QvtStackOverFlowError(e));
}
catch (QvtRuntimeException e) {
throw e;
}
catch (RuntimeException e) {
String errorMessage = EvaluationMessages.QvtOperationalEvaluationVisitorImpl_unexpectedRuntimeExc;
QvtPlugin.error(errorMessage, e);
throwQVTException(new QvtRuntimeException(errorMessage, e));
}
finally {
if(isMapping && isReusingMappingCall && callResult != null) {
// reflect our output in the reusing mapping caller
if(((MappingCallResult)callResult).isBodyExecuted()) {
EvaluationUtil.mapOperationOutAndResultParams(nestedEnv, oldEvalEnv);
}
}
setOperationalEvaluationEnv(oldEvalEnv);
poppedStack();
}
return callResult;
}
private MappingCallResult dispatchDisjunctMapping(MappingOperation method) {
QvtOperationalEvaluationEnv evalEnv = getOperationalEvaluationEnv();
Object source = evalEnv.getOperationSelf();
List<Object> args = evalEnv.getOperationArgs();
for (MappingOperation nextDisjunct : method.getDisjunct()) {
// consider overriding mapping (fixed by bug 309762)
ImperativeOperation overridingOper = EvaluationUtil.getOverridingOperation(getOperationalEvaluationEnv(), nextDisjunct);
if (overridingOper instanceof MappingOperation) {
nextDisjunct = (MappingOperation) overridingOper;
}
EClassifier ctxType = QvtOperationalParserUtil.getContextualType(nextDisjunct);
if(ctxType != null) {
if(!evalEnv.isKindOf(source, nextDisjunct.getContext().getEType())) {
continue;
}
}
if(!dispatchDisjunctMappingArgumentsMatch(nextDisjunct)) {
continue;
}
MappingCallResult result = (MappingCallResult) executeImperativeOperation(nextDisjunct, source, args, false);
if(!result.isPreconditionFailed()) {
// precondition holds, mapping either executed, fetched from trace, or disjuncted
result.myStatus = MappingCallResult.BODY_EXECUTED; // from disjuncting mapping consider as executed
// add trace record for disjuncting mapping (fixed by bug 377882)
replaceInEnv(Environment.RESULT_VARIABLE_NAME, result.myResult, method.getEType());
//retrieveOutArgs((OperationCallExp<EClassifier, EOperation>)source, result.myEvalEnv.getOperationArgs(), nextDisjunct);
createOutParamsDisjunct(method, result.myEvalEnv.getOperationArgs());
setOutParamsValues(method, args);
TraceUtil.addTraceRecord(evalEnv, method);
return result;
}
}
return new MappingCallResult(null, myEvalEnv, MappingCallResult.NO_DISJUNCT_SELECTED);
}
private boolean dispatchDisjunctMappingArgumentsMatch(MappingOperation disjunct) {
List<EParameter> params = disjunct.getEParameters();
QvtOperationalEvaluationEnv evalEnv = getOperationalEvaluationEnv();
List<Object> args = evalEnv.getOperationArgs();
if(params.size() != args.size()) {
return false;
}
for (int i = 0; i < args.size(); i++) {
Object nextArg = args.get(i);
EClassifier nextParamType = params.get(i).getEType();
if(nextArg != null && !evalEnv.isKindOf(nextArg, nextParamType)) {
return false;
}
}
return true;
}
protected final void throwQVTException(QvtRuntimeException exception) throws QvtRuntimeException {
getOperationalEvaluationEnv().getAdapter(InternalEvaluationEnv.class)
.throwQVTException(exception);
}
@Override
protected Object call(EOperation operation, OCLExpression<EClassifier> body, Object target, Object[] args) {
if(target instanceof EObject) {
EObject eTarget = (EObject) target;
if(OCLAnnotationSupport.isDynamicInstance(eTarget)) {
if(operation.eClass() != eTarget.eClass()) {
// check if not overridden for a sub-class
EOperation actualOperation = getOCLAnnotationSupport().resolveDynamic(operation, eTarget);
if(actualOperation != null && actualOperation != operation) {
OCLExpression<EClassifier> actualOperBody = getOperationBody(actualOperation);
if(actualOperBody != null) {
Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> myEnv = getEnvironment();
EnvironmentFactory<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> factory = myEnv
.getFactory();
// create a nested evaluation environment for this
// operation call
EvaluationEnvironment<EClassifier, EOperation, EStructuralFeature, EClass, EObject> nested = factory
.createEvaluationEnvironment(getEvaluationEnvironment());
// bind "self"
nested.add(Environment.SELF_VARIABLE_NAME, target);
// add the parameter bindings to the local variables
if (args.length > 0) {
int i = 0;
UMLReflection<?, ?, EOperation, ?, ?, EParameter, ?, ?, ?, ?> uml = myEnv.getUMLReflection();
for (EParameter param : uml.getParameters(operation)) {
nested.add(uml.getName(param), args[i]);
}
}
EvaluationVisitor<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> visitor = factory
.createEvaluationVisitor(myEnv, nested, getExtentMap());
if(visitor instanceof QvtOperationalEvaluationVisitorImpl) {
// ensure shared instance of oclAnnotationSupport to avoid repeated OCL parsing
((QvtOperationalEvaluationVisitorImpl)visitor).oclAnnotationSupport = getOCLAnnotationSupport();
}
return visitor.visitExpression(actualOperBody);
}
}
}
}
}
return super.call(operation, body, target, args);
}
@Override
public Object visitCollectionLiteralExp(CollectionLiteralExp<EClassifier> cl) {
if (cl.getType() instanceof ListType) {
Collection<Object> result = new MutableListImpl<Object>();
for (CollectionLiteralPart<EClassifier> part : cl.getPart()) {
if (part instanceof CollectionItem<?>) {
// CollectionItem part
CollectionItem<EClassifier> item = (CollectionItem<EClassifier>) part;
OCLExpression<EClassifier> itemExp = item.getItem();
Object itemVal = visitExpression(itemExp);
if (itemVal == getInvalid()) {
return getInvalid(); // can't have an invalid element in a collection
}
result.add(itemVal);
} else {
// Collection range
CollectionRange<EClassifier> range = (CollectionRange<EClassifier>) part;
OCLExpression<EClassifier> first = range.getFirst();
OCLExpression<EClassifier> last = range.getLast();
// evaluate first value
Object firstVal = visitExpression(first);
Object lastVal = visitExpression(last);
if (firstVal == getInvalid() || lastVal == getInvalid()) {
return getInvalid(); // can't have an invalid element in a collection
}
if (firstVal instanceof Integer && lastVal instanceof Integer) {
// TODO: enhance IntegerRangeList to support multiple ranges
// add values between first and last inclusive
int firstInt = ((Integer) firstVal).intValue();
int lastInt = ((Integer) lastVal).intValue();
for (int i = firstInt; i <= lastInt; i++) {
result.add(new Integer(i));
}
}
} // end of collection range
} // end of parts iterator
return result;
}
return super.visitCollectionLiteralExp(cl);
}
@Override
protected Object navigate(EStructuralFeature property, OCLExpression<EClassifier> derivation, Object target) {
Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> myEnv = getEnvironment();
EnvironmentFactory<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> factory = myEnv
.getFactory();
// create a nested evaluation environment for this property call
EvaluationEnvironment<EClassifier, EOperation, EStructuralFeature, EClass, EObject> nested = factory
.createEvaluationEnvironment(getEvaluationEnvironment());
// bind "self"
nested.add(Environment.SELF_VARIABLE_NAME, target);
EvaluationVisitor<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> visitor = factory
.createEvaluationVisitor(myEnv, nested, getExtentMap());
if(visitor instanceof QvtOperationalEvaluationVisitorImpl) {
// ensure shared instance of oclAnnotationSupport to avoid repeated OCL parsing
((QvtOperationalEvaluationVisitorImpl)visitor).oclAnnotationSupport = getOCLAnnotationSupport();
}
return visitor.visitExpression(derivation);
}
@Override
protected OCLExpression<EClassifier> getPropertyBody(EStructuralFeature property) {
if(OCLAnnotationSupport.isDynamicClassFeature(property)) {
return getOCLAnnotationSupport().getDerivedProperty(property);
}
return super.getPropertyBody(property);
}
@Override
protected OCLExpression<EClassifier> getOperationBody(EOperation operation) {
if(operation == null) {
return null;
}
if(OCLAnnotationSupport.isDynamicClassOperation(operation)) {
return getOCLAnnotationSupport().getBody(operation);
}
return super.getOperationBody(operation);
}
private OCLAnnotationSupport getOCLAnnotationSupport() {
if(oclAnnotationSupport == null) {
oclAnnotationSupport = new OCLAnnotationSupport();
oclAnnotationSupport.setErrorHandler(new OCLAnnotationSupport.ParseErrorHandler() {
org.eclipse.ocl.ecore.OCLExpression invalidBodyExpr = EcoreFactory.eINSTANCE.createInvalidLiteralExp();
public org.eclipse.ocl.ecore.OCLExpression handleError(ParserException parserException, EModelElement contextElement) {
QvtPlugin.error("Failed to parse OCL annotation :" + //$NON-NLS-1$
getUMLReflection().getQualifiedName(contextElement) , parserException);
return invalidBodyExpr;
}
});
}
return oclAnnotationSupport;
}
protected QvtOperationalEnv getOperationalEnv() {
return (QvtOperationalEnv) getEnvironment();
}
public QvtOperationalEvaluationEnv getOperationalEvaluationEnv() {
return (QvtOperationalEvaluationEnv) getEvaluationEnvironment();
}
/**
* Adds the given variable value into evaluation environment.
*
* @param varName
* the name of the variable
* @param value
* the value of the variable
* @param declaredType
* the type of the variable (optional) or <code>null</code>
*/
protected void addToEnv(String varName, Object value, EClassifier declaredType) {
getOperationalEvaluationEnv().add(varName, value);
}
/**
* Replaces the given variable value in evaluation environment.
*
* @param varName
* the name of the variable to replace
* @param value
* the new value of the variable
* @param declaredType
* the type of the variable (optional) or <code>null</code>
*/
protected void replaceInEnv(String varName, Object value, EClassifier declaredType) {
getOperationalEvaluationEnv().replace(varName, value);
}
private Object getRuntimeValue(final String name) {
return getEvaluationEnvironment().getValueOf(name);
}
private Object getOutOwner(final ObjectExp objectExp) {
Object owner = getRuntimeValue(objectExp.getName());
if (owner != null) {
if (objectExp.getType() instanceof CollectionType<?, ?> == false) {
if (!oclIsKindOf(owner, objectExp.getType())) {
throw new RuntimeException(MessageFormat.format(
EvaluationMessages.ExtendedOclEvaluatorVisitorImpl_InvalidObjectExpType, new Object[] {
objectExp.getName(), owner, objectExp.getType() }));
}
}
} else {
owner = createInstance(objectExp.getType(), (ModelParameter) objectExp.getExtent());
if(objectExp.getName() != null) {
getOperationalEvaluationEnv().replace(objectExp.getName(), owner);
}
}
return owner;
}
/**
* Creates tuple value representing the result of the given operation.
*
* @param operation
* the operation currently executed by this environment
*
* @return the tuple value collecting all result parameters, never <code>null</code>
*/
private Tuple<EOperation, EStructuralFeature> createTupleResult(ImperativeOperation operation) {
boolean isMapping = operation.eClass() == ExpressionsPackage.eINSTANCE.getMappingOperation();
QvtOperationalEvaluationEnv evalEnv = getOperationalEvaluationEnv();
EList<VarParameter> resultParams = operation.getResult();
HashMap<EStructuralFeature, Object> values = new HashMap<EStructuralFeature, Object>(2);
@SuppressWarnings("unchecked")
TupleType<EClassifier, EStructuralFeature> tupleType = (TupleType<EClassifier, EStructuralFeature>)operation.getEType();
for (EStructuralFeature tupleProp : tupleType.oclProperties()) {
Object propVal = evalEnv.getValueOf(tupleProp.getName());
if(propVal == null && isMapping) {
ModelParameter extent = null;
for (VarParameter resultParam : resultParams) {
if(tupleProp.getName().equals(resultParam.getName())) {
MappingParameter mappingParameter = (MappingParameter) resultParam;
extent = mappingParameter.getExtent();
break;
}
}
propVal = createInstance(tupleProp.getEType(), extent);
}
values.put(tupleProp, propVal);
evalEnv.replace(tupleProp.getName(), propVal, tupleProp.getEType());
}
return evalEnv.createTuple(operation.getEType(), values);
}
private List<Object> makeArgs(OperationCallExp<EClassifier, EOperation> operationCallExp) {
EOperation referredOperation = operationCallExp.getReferredOperation();
Iterator<EParameter> iterParam = referredOperation.getEParameters().iterator();
List<Object> argValues = new ArrayList<Object>();
for (OCLExpression<EClassifier> arg : operationCallExp.getArgument()) {
Object value = visitExpression(arg);
EParameter param = iterParam.next();
argValues.add(EvaluationUtil.doImplicitListCoercion(param.getEType(), value));
}
return argValues;
}
private void retrieveOutArgs(OperationCallExp<EClassifier, EOperation> operationCallExp, List<Object> argValues, MappingOperation operation) {
Iterator<OCLExpression<EClassifier>> itArgument = operationCallExp.getArgument().iterator();
Iterator<EParameter> itParams = operation.getEParameters().iterator();
Iterator<Object> itValue = argValues.iterator();
while (itArgument.hasNext()) {
OCLExpression<EClassifier> arg = itArgument.next();
MappingParameter mappingParam = (MappingParameter) itParams.next();
Object argValue = itValue.next();
if (mappingParam.getKind() != DirectionKind.OUT) {
continue;
}
if (arg instanceof VariableExp<?, ?>) {
@SuppressWarnings("unchecked")
VariableExp<EClassifier, EParameter> varExp = (VariableExp<EClassifier, EParameter>) arg;
Variable<EClassifier, EParameter> referredVariable = varExp.getReferredVariable();
if (referredVariable != null) {
String varName = referredVariable.getName();
EClassifier variableType = arg.getType();
replaceInEnv(varName, argValue, variableType);
}
} else if (arg instanceof PropertyCallExp<?, ?>) {
Object ownerObj = getAssignExpLValueOwner(arg);
if (ownerObj instanceof EObject) {
@SuppressWarnings("unchecked")
PropertyCallExp<EClassifier, EStructuralFeature> propCallExp = ((PropertyCallExp<EClassifier, EStructuralFeature>) arg);
QvtOperationalEvaluationEnv env = getOperationalEvaluationEnv();
EObject oldIP = setCurrentEnvInstructionPointer(operationCallExp);
env.callSetter((EObject) ownerObj, propCallExp.getReferredProperty(), argValue, isUndefined(argValue), true);
setCurrentEnvInstructionPointer(oldIP);
}
} else {
throw new UnsupportedOperationException("Unsupported LValue type: " + ((arg == null) ? null : arg.getType())); //$NON-NLS-1$
}
}
}
private List<Object> makeEntryOperationArgs(OperationalTransformation module) {
assert !module.isIsBlackbox() : "Non-blackbox module expected";
ImperativeOperation entryPoint = QvtOperationalParserUtil.getMainOperation(module);
if (entryPoint == null) {
throw new IllegalArgumentException(NLS.bind(EvaluationMessages.ExtendedOclEvaluatorVisitorImpl_ModuleNotExecutable, module.getName()));
}
List<Object> args = new ArrayList<Object>(entryPoint.getEParameters().size());
int paramIndex = 0;
for (EParameter param : entryPoint.getEParameters()) {
int matchedIndex = paramIndex;
MappingParameter mappingParam = (MappingParameter) param;
if (mappingParam.getKind() == DirectionKind.OUT) {
args.add(null);
continue;
}
if (mappingParam.getExtent() != null) {
int modelParamIndex = 0;
for (ModelParameter modelParam : module.getModelParameter()) {
if (modelParam == mappingParam.getExtent()) {
matchedIndex = modelParamIndex;
break;
}
modelParamIndex++;
}
}
if (matchedIndex < getOperationalEvaluationEnv().getOperationArgs().size()) {
Object envArg = getOperationalEvaluationEnv().getOperationArgs().get(matchedIndex);
ModelInstance argModel = (ModelInstance) envArg;
ModelParameterExtent argExtent = argModel.getExtent();
List<EObject> initialObjects = argExtent.getInitialObjects();
if(!initialObjects.isEmpty()) {
args.add(initialObjects.get(0));
}
}
else {
throw new IllegalArgumentException("entry operation arguments mismatch: no argument for " + mappingParam + " parameter"); //$NON-NLS-1$ //$NON-NLS-2$
}
paramIndex++;
}
return args;
}
private List<Object> makeBlackboxTransformationArgs(TransformationInstance transformation, QvtOperationalEvaluationEnv evalEnv) {
assert transformation.getTransformation().isIsBlackbox() : "Blackbox transformation expected";
List<Object> actualArgs = new ArrayList<Object>();
for (ModelParameter param : EvaluationUtil.getBlackboxSignature(transformation.getTransformation())) {
ModelInstance modelInst = transformation.getModel(param);
Object arg = createJavaModelInstance(modelInst, evalEnv);
actualArgs.add(arg);
}
for (EStructuralFeature p : transformation.getTransformation().getConfigProperty()) {
Object val = evalEnv.navigateProperty(p, Collections.emptyList(), transformation);
((Context) evalEnv.getContext()).setConfigProperty(p.getName(), val);
}
return actualArgs;
}
private JavaModelInstance createJavaModelInstance(final ModelInstance modelInst, final QvtOperationalEvaluationEnv evalEnv) {
return new JavaModelInstance() {
final JavaModelType modelType = new JavaModelType() {
public String getName() {
return modelInst.getModelType().getName();
}
public List<EPackage> getMetamodels() {
return modelInst.getModelType().getMetamodel();
}
};
final JavaModelExtent modelExtent = new JavaModelExtent() {
public void removeObject(EObject obj) {
modelInst.getExtent().removeElement(obj);
}
public List<EObject> getRootObjects() {
return modelInst.getExtent().getRootObjects();
}
public List<Object> getAllObjects() {
return modelInst.getExtent().getAllObjects();
}
public void addObject(EObject obj) {
modelInst.getExtent().addObject(obj);
}
};
public JavaModelType getType() {
return modelType;
}
public JavaModelExtent getExtent() {
return modelExtent;
}
};
}
// private EStructuralFeature getRenamedProperty(EStructuralFeature property) {
// EAnnotation annotation = property.getEAnnotation(Environment.OCL_NAMESPACE_URI);
// if (annotation != null) {
// for (EObject nextAnn : annotation.getContents()) {
// if (false == nextAnn instanceof Constraint) {
// continue;
// }
// Constraint cnt = (Constraint) nextAnn;
// if (QvtOperationalEnv.RENAMED_PROPERTY_STEREOTYPE.equals(cnt.getStereotype())
// && !cnt.getConstrainedElements().isEmpty()
// && cnt.getConstrainedElements().get(0) instanceof EStructuralFeature) {
// return (EStructuralFeature) cnt.getConstrainedElements().get(0);
// }
// }
// }
// return property;
// }
/**
* Wraps the environment's creatInstance() and transforms failures to QVT exception
*/
protected Object createInstance(EClassifier type, ModelParameter extent) throws QvtRuntimeException {
Object newInstance = null;
try {
if(type instanceof CollectionType<?, ?>) {
@SuppressWarnings("unchecked")
CollectionType<EClassifier, EOperation> collectionType = (CollectionType<EClassifier, EOperation>)type;
newInstance = EvaluationUtil.createNewCollection(collectionType);
} else {
newInstance = getOperationalEvaluationEnv().createInstance(type, extent);
EFactory eFactory = type.getEPackage().getEFactoryInstance();
if(eFactory instanceof IntermediateClassFactory) {
IntermediateClassFactory intermFactory = (IntermediateClassFactory) eFactory;
intermFactory.doInstancePropertyInit(newInstance, this);
}
}
} catch (IllegalArgumentException e) {
throwQVTException(new QvtRuntimeException(e));
}
return newInstance;
}
protected EObject setCurrentEnvInstructionPointer(EObject node) {
InternalEvaluationEnv internEnv = getOperationalEvaluationEnv().getAdapter(InternalEvaluationEnv.class);
if(node != null) {
return internEnv.setCurrentIP(node);
}
return internEnv.getCurrentIP();
}
protected InternalEvaluator createInterruptibleVisitor() {
final IProgressMonitor monitor = getContext().getProgressMonitor();
class InterruptVisitor extends QvtGenericVisitorDecorator.Any {
public InterruptVisitor() {
super(QvtOperationalEvaluationVisitorImpl.this);
}
@Override
protected Object genericVisitAny(Object object) {
if(monitor != null && monitor.isCanceled()) {
throwQVTException(new QvtInterruptedExecutionException());
}
// set the current instruction pointer
if(object instanceof EObject) {
InternalEvaluationEnv evalEnv = getOperationalEvaluationEnv().getAdapter(InternalEvaluationEnv.class);
evalEnv.setCurrentIP((EObject)object);
}
return null;
}
};
return new InterruptVisitor();
}
public OperationCallResult runMainEntry(OperationalTransformation transformation, List<Object> args) {
ImperativeOperation entryOperation = QvtOperationalParserUtil.getMainOperation(transformation);
OperationCallResult result = executeImperativeOperation(entryOperation, null, args, false);
processDeferredTasks();
return result;
}
private void evaluateModelParameterConditions(TransformationInstance transformationInstance, QvtOperationalEvaluationEnv evalEnv) {
for (ModelParameter parameter : transformationInstance.getTransformation().getModelParameter()) {
if (parameter.getEType() instanceof ModelType && parameter.getKind() != DirectionKind.OUT) {
ModelType parameterType = (ModelType) parameter.getEType();
ModelInstance modelInstance = transformationInstance.getModel(parameter);
for (OCLExpression<EClassifier> whereExpression : parameterType.getAdditionalCondition()) {
myEvalEnv.add(Environment.SELF_VARIABLE_NAME, modelInstance);
try {
boolean isConditionMet = Boolean.TRUE.equals(visitExpression(whereExpression));
if(!isConditionMet) {
throwQVTException(new QvtAssertionFailed(NLS.bind(EvaluationMessages.ModelTypeConstraintFailed,
parameter.getName(), transformationInstance.getTransformation().getName())));
}
}
finally {
myEvalEnv.remove(Environment.SELF_VARIABLE_NAME);
}
}
}
}
}
}