package com.sap.runlet.interpreter; import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.eclipse.emf.ecore.resource.ResourceSet; import ui.templates.TemplatesPackage; import behavioral.actions.ActionsPackage; import behavioral.actions.Statement; import com.sap.ap.metamodel.utils.MetamodelUtils; import com.sap.ap.metamodel.utils.StringFormatter; import com.sap.runlet.abstractinterpreter.AbstractRunletInterpreter; import com.sap.runlet.abstractinterpreter.DebugSession; import com.sap.runlet.abstractinterpreter.objects.AbstractValueObject; import com.sap.runlet.abstractinterpreter.objects.ClassTypedObject; import com.sap.runlet.abstractinterpreter.objects.MultiValuedObject; import com.sap.runlet.abstractinterpreter.objects.RunletObject; import com.sap.runlet.abstractinterpreter.repository.Repository; import com.sap.runlet.interpreter.expressions.AllInterpreter; import com.sap.runlet.interpreter.expressions.AnonymousFunctionExpressionInterpreter; import com.sap.runlet.interpreter.expressions.AsListInterpreter; import com.sap.runlet.interpreter.expressions.AssociationEndNavigationInterpreter; import com.sap.runlet.interpreter.expressions.BinaryLiteralInterpreter; import com.sap.runlet.interpreter.expressions.BooleanLiteralInterpreter; import com.sap.runlet.interpreter.expressions.ContentEqualsInterpreter; import com.sap.runlet.interpreter.expressions.DimensionExpressionInterpreter; import com.sap.runlet.interpreter.expressions.EqualsInterpreter; import com.sap.runlet.interpreter.expressions.ExcludingAtInterpreter; import com.sap.runlet.interpreter.expressions.ExcludingInterpreter; import com.sap.runlet.interpreter.expressions.FunctionFromMethodExpressionInterpreter; import com.sap.runlet.interpreter.expressions.GroupByInterpreter; import com.sap.runlet.interpreter.expressions.HeadInterpreter; import com.sap.runlet.interpreter.expressions.IncludingAtInterpreter; import com.sap.runlet.interpreter.expressions.IncludingInterpreter; import com.sap.runlet.interpreter.expressions.IterateInterpreter; import com.sap.runlet.interpreter.expressions.MapInterpreter; import com.sap.runlet.interpreter.expressions.MethodCallInterpreter; import com.sap.runlet.interpreter.expressions.NumberLiteralInterpreter; import com.sap.runlet.interpreter.expressions.ObjectCountInterpreter; import com.sap.runlet.interpreter.expressions.ObjectCreationInterpreter; import com.sap.runlet.interpreter.expressions.ObjectLiteralInterpreter; import com.sap.runlet.interpreter.expressions.OqlQueryInterpreter; import com.sap.runlet.interpreter.expressions.ReplaceInterpreter; import com.sap.runlet.interpreter.expressions.SelectionInterpreter; import com.sap.runlet.interpreter.expressions.SignatureCallInterpreter; import com.sap.runlet.interpreter.expressions.SnapshotInterpreter; import com.sap.runlet.interpreter.expressions.StringLiteralInterpreter; import com.sap.runlet.interpreter.expressions.TailInterpreter; import com.sap.runlet.interpreter.expressions.TernaryInterpreter; import com.sap.runlet.interpreter.expressions.ThisInterpreter; import com.sap.runlet.interpreter.expressions.TimePointLiteralInterpreter; import com.sap.runlet.interpreter.expressions.VariableExpressionInterpreter; import com.sap.runlet.interpreter.nativestdlib.BinaryInterpreter; import com.sap.runlet.interpreter.nativestdlib.BooleanInterpreter; import com.sap.runlet.interpreter.nativestdlib.CalendarInterpreter; import com.sap.runlet.interpreter.nativestdlib.NumberInterpreter; import com.sap.runlet.interpreter.nativestdlib.StringInterpreter; import com.sap.runlet.interpreter.nativestdlib.TimepointInterpreter; import com.sap.runlet.interpreter.objects.ConvertedMultiObject; import com.sap.runlet.interpreter.objects.FunctionFromMethodObject; import com.sap.runlet.interpreter.objects.FunctionObject; import com.sap.runlet.interpreter.objects.ValueObject; import com.sap.runlet.interpreter.signatureimplementations.BlockInterpreter; import com.sap.runlet.interpreter.signatureimplementations.CellSetInterpreter; import com.sap.runlet.interpreter.signatureimplementations.LinkAdditionInterpreter; import com.sap.runlet.interpreter.signatureimplementations.LinkRemovalInterpreter; import com.sap.runlet.interpreter.signatureimplementations.LinkSettingInterpreter; import com.sap.runlet.interpreter.signatureimplementations.LinkTraversalInterpreter; import com.sap.runlet.interpreter.signatureimplementations.StringTemplateInterpreter; import com.sap.runlet.interpreter.statements.AddLinkInterpreter; import com.sap.runlet.interpreter.statements.AssignmentInterpreter; import com.sap.runlet.interpreter.statements.CommitInterpreter; import com.sap.runlet.interpreter.statements.DeleteInterpreter; import com.sap.runlet.interpreter.statements.ExpressionStatementInterpreter; import com.sap.runlet.interpreter.statements.ForeachInterpreter; import com.sap.runlet.interpreter.statements.IfInterpreter; import com.sap.runlet.interpreter.statements.NamedValueDeclarationInterpreter; import com.sap.runlet.interpreter.statements.RemoveLinkInterpreter; import com.sap.runlet.interpreter.statements.ReturnInterpreter; import com.sap.runlet.interpreter.statements.RollbackInterpreter; import com.sap.runlet.interpreter.statements.StoreInterpreter; import com.sap.runlet.interpreter.statements.WhileInterpreter; import data.classes.ActualObjectParameter; import data.classes.Association; import data.classes.AssociationEnd; import data.classes.ClassTypeDefinition; import data.classes.ClassesPackage; import data.classes.ConverterBetweenParametrizations; import data.classes.MethodSignature; import data.classes.NativeImpl; import data.classes.Parameter; import data.classes.SapClass; import data.classes.SignatureImplementation; import data.classes.TypeDefinition; import dataaccess.analytics.AnalyticsPackage; import dataaccess.expressions.Expression; import dataaccess.expressions.ExpressionsPackage; import dataaccess.expressions.collectionexpressions.CollectionexpressionsPackage; import dataaccess.expressions.fp.FpPackage; import dataaccess.expressions.literals.LiteralsPackage; import dataaccess.query.QueryPackage; /** * An interpreter for River models. The entry point is an {@link Expression} * that will be evaluated or a {@link SignatureImplementation} or a * {@link Statement} that will be executed. * <p> * * An interpreter is intended to be used to handle a single request at a time. * When serialized, multiple calls can come in from different threads. In other * words, the interpreter does not pertain to a single particular thread. * However, if multiple requests are to be handled in parallel, use * {@link #spawn()} to get an interpreter that shares the state of this * interpreter except for having a new, separate call stack. * <p> * * The class is <tt>synchronized</tt> because only one Java thread should be * using it at a time. An interpreter should be {@link #spawn() spawned} in * order to use it in a different rhread. * <p> * * TODO how do the contents of the transactionBuffer blend into the contents of * the linkContainer? When an instance is created (ObjectCreationExpression), it * has no links attached. The object will have a <tt>null</tt> snapshot. The * link container can know that if it doesn't contain any links for it, it won't * find any in the repository either because without a snapshot an entity won't * be stored in the repository. * <p> * * @author Axel Uhl (D043530) */ public class RunletInterpreter extends AbstractRunletInterpreter<SapClass, TypeDefinition, ClassTypeDefinition, Association, AssociationEnd, Statement, Expression, SignatureImplementation, RunletStackFrame, NativeImpl, RunletInterpreter> { /** * Used for polymorphic method resolution. */ private final MethodCallResolver methodCallResolver; /** * Registers the sub-interpreters for various parts of the language. It * registers those sub-interpreters (e.g., for expressions and statements) * that it knows. Clients may use the respective <tt>register...</tt> * methods to register more or other interpreters. * * @param repository * used to load/store objects durably / persistently */ public RunletInterpreter(ResourceSet resourceSet, Repository<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> repository) { super(resourceSet, repository, Activator.getDefault().getModelAdapter(), new NativeInterpreterFactory(), new RunletLinkContainer(repository, Activator.getDefault().getModelAdapter())); methodCallResolver = new MethodCallResolver(resourceSet); } /** * Like {@link RunletInterpreter#RiverInterpreter(ResourceSet, Repository)}, * only that also a {@link #debugSession debug session} can be set. */ public RunletInterpreter(ResourceSet resourceSet, Repository<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> repository, DebugSession debugSession) { this(resourceSet, repository); setDebugSession(debugSession); } /** * Spawns a new interpreter for parallel execution. This interpreter re-uses * the registries for subinterpreters for expressions, statements etc., the * MOIN {@link #ResourceSet}, the {@link #debugSession} as well as the shared * state consisting of the {@link #linkContainer}. The spawned interpreter * has a new {@link #callstack call stack} that is initialized with the * <tt>parent</tt> interpreter's top stack frame. * <p> * * This means that a spawned interpreter may not have all of the first stack * frame's scope parent frames on its own stack. If this first frame happens * to have a scope parent, this is referenced by a regular Java reference. * <p> * * The spawned interpreter created here will start out with an empty set of * {@link #runningChildren} child interpreters. It starts out in non- * {@link #running running} mode. * <p> */ private RunletInterpreter(RunletInterpreter parent) { super(parent); methodCallResolver = parent.getMethodCallResolver(); } @Override protected void initExpressionInterpreterFactory(ResourceSet resourceSet) { // expressions getExpressionInterpreterFactory().registerInterpreter(StringLiteralInterpreter.class, LiteralsPackage.eINSTANCE.getStringLiteral()); getExpressionInterpreterFactory().registerInterpreter(NumberLiteralInterpreter.class, LiteralsPackage.eINSTANCE.getNumberLiteral()); getExpressionInterpreterFactory().registerInterpreter(TimePointLiteralInterpreter.class, LiteralsPackage.eINSTANCE.getTimePointLiteral()); getExpressionInterpreterFactory().registerInterpreter(BooleanLiteralInterpreter.class, LiteralsPackage.eINSTANCE.getBooleanLiteral()); getExpressionInterpreterFactory().registerInterpreter(BinaryLiteralInterpreter.class, LiteralsPackage.eINSTANCE.getBinaryLiteral()); getExpressionInterpreterFactory().registerInterpreter(ObjectLiteralInterpreter.class, LiteralsPackage.eINSTANCE.getObjectLiteral()); getExpressionInterpreterFactory().registerInterpreter(MethodCallInterpreter.class, ExpressionsPackage.eINSTANCE.getMethodCallExpression()); getExpressionInterpreterFactory().registerInterpreter(SignatureCallInterpreter.class, ExpressionsPackage.eINSTANCE.getFunctionCallExpression()); getExpressionInterpreterFactory().registerInterpreter(VariableExpressionInterpreter.class, ExpressionsPackage.eINSTANCE.getVariableExpression()); getExpressionInterpreterFactory().registerInterpreter(ThisInterpreter.class, ExpressionsPackage.eINSTANCE.getThis()); getExpressionInterpreterFactory().registerInterpreter(EqualsInterpreter.class, ExpressionsPackage.eINSTANCE.getEquals()); getExpressionInterpreterFactory().registerInterpreter(ContentEqualsInterpreter.class, ExpressionsPackage.eINSTANCE.getContentEquals()); getExpressionInterpreterFactory().registerInterpreter(ObjectCreationInterpreter.class, ExpressionsPackage.eINSTANCE.getObjectCreationExpression()); getExpressionInterpreterFactory().registerInterpreter(FunctionFromMethodExpressionInterpreter.class, FpPackage.eINSTANCE.getFunctionFromMethodExpr()); getExpressionInterpreterFactory().registerInterpreter(AnonymousFunctionExpressionInterpreter.class, FpPackage.eINSTANCE.getAnonymousFunctionExpr()); getExpressionInterpreterFactory().registerInterpreter(AssociationEndNavigationInterpreter.class, ExpressionsPackage.eINSTANCE.getAssociationEndNavigationExpression()); getExpressionInterpreterFactory().registerInterpreter(IterateInterpreter.class, CollectionexpressionsPackage.eINSTANCE.getIterate()); getExpressionInterpreterFactory().registerInterpreter(DimensionExpressionInterpreter.class, AnalyticsPackage.eINSTANCE.getDimensionExpression()); getExpressionInterpreterFactory().registerInterpreter(IncludingInterpreter.class, CollectionexpressionsPackage.eINSTANCE.getIncluding()); getExpressionInterpreterFactory().registerInterpreter(ExcludingInterpreter.class, CollectionexpressionsPackage.eINSTANCE.getExcluding()); getExpressionInterpreterFactory().registerInterpreter(IncludingAtInterpreter.class, CollectionexpressionsPackage.eINSTANCE.getIncludingAt()); getExpressionInterpreterFactory().registerInterpreter(ExcludingAtInterpreter.class, CollectionexpressionsPackage.eINSTANCE.getExcludingAt()); getExpressionInterpreterFactory().registerInterpreter(ObjectCountInterpreter.class, ExpressionsPackage.eINSTANCE.getObjectCount()); getExpressionInterpreterFactory().registerInterpreter(AllInterpreter.class, persistence.expressions.ExpressionsPackage.eINSTANCE.getAll()); getExpressionInterpreterFactory().registerInterpreter(CommitInterpreter.class, persistence.expressions.ExpressionsPackage.eINSTANCE.getCommit()); getExpressionInterpreterFactory().registerInterpreter(ReplaceInterpreter.class, ExpressionsPackage.eINSTANCE.getReplace()); getExpressionInterpreterFactory().registerInterpreter(SnapshotInterpreter.class, persistence.expressions.ExpressionsPackage.eINSTANCE.getSnapshot()); getExpressionInterpreterFactory().registerInterpreter(AsListInterpreter.class, ExpressionsPackage.eINSTANCE.getAsList()); getExpressionInterpreterFactory().registerInterpreter(HeadInterpreter.class, ExpressionsPackage.eINSTANCE.getHead()); getExpressionInterpreterFactory().registerInterpreter(TailInterpreter.class, ExpressionsPackage.eINSTANCE.getTail()); getExpressionInterpreterFactory().registerInterpreter(TernaryInterpreter.class, ExpressionsPackage.eINSTANCE.getTernary()); getExpressionInterpreterFactory().registerInterpreter(SelectionInterpreter.class, QueryPackage.eINSTANCE.getSelection()); getExpressionInterpreterFactory().registerInterpreter(OqlQueryInterpreter.class, QueryPackage.eINSTANCE.getOqlQuery()); getExpressionInterpreterFactory().registerInterpreter(MapInterpreter.class, ExpressionsPackage.eINSTANCE.getMap()); getExpressionInterpreterFactory().registerInterpreter(GroupByInterpreter.class, AnalyticsPackage.eINSTANCE.getGroupBy()); } @Override protected void initStatementInterpreterFactory(ResourceSet resourceSet) { // statements getStatementInterpreterFactory().registerInterpreter(ReturnInterpreter.class, ActionsPackage.eINSTANCE.getReturn()); getStatementInterpreterFactory().registerInterpreter(NamedValueDeclarationInterpreter.class, ActionsPackage.eINSTANCE.getNamedValueDeclaration()); getStatementInterpreterFactory().registerInterpreter(IfInterpreter.class, ActionsPackage.eINSTANCE.getIfElse()); getStatementInterpreterFactory().registerInterpreter(WhileInterpreter.class, ActionsPackage.eINSTANCE.getWhileLoop()); getStatementInterpreterFactory().registerInterpreter(ForeachInterpreter.class, ActionsPackage.eINSTANCE.getForeach()); getStatementInterpreterFactory().registerInterpreter(AssignmentInterpreter.class, ActionsPackage.eINSTANCE.getAssignment()); getStatementInterpreterFactory().registerInterpreter(ExpressionStatementInterpreter.class, ActionsPackage.eINSTANCE.getExpressionStatement()); getStatementInterpreterFactory().registerInterpreter(AddLinkInterpreter.class, ActionsPackage.eINSTANCE.getAddLink()); getStatementInterpreterFactory().registerInterpreter(RemoveLinkInterpreter.class, ActionsPackage.eINSTANCE.getRemoveLink()); getStatementInterpreterFactory().registerInterpreter(StoreInterpreter.class, persistence.actions.ActionsPackage.eINSTANCE.getStore()); getStatementInterpreterFactory().registerInterpreter(DeleteInterpreter.class, persistence.actions.ActionsPackage.eINSTANCE.getDelete()); getStatementInterpreterFactory().registerInterpreter(RollbackInterpreter.class, persistence.actions.ActionsPackage.eINSTANCE.getRollback()); } @Override protected void initSignatureImplementationInterpreterFactory(ResourceSet resourceSet) { // signature implementations getSignatureImplementationInterpreterFactory().registerInterpreter(RunletNativeInterpreter.class, ClassesPackage.eINSTANCE.getNativeImpl()); getSignatureImplementationInterpreterFactory().registerInterpreter(BlockInterpreter.class, ActionsPackage.eINSTANCE.getBlock()); getSignatureImplementationInterpreterFactory().registerInterpreter(LinkTraversalInterpreter.class, ClassesPackage.eINSTANCE.getLinkTraversal()); getSignatureImplementationInterpreterFactory().registerInterpreter(LinkAdditionInterpreter.class, ClassesPackage.eINSTANCE.getLinkAddition()); getSignatureImplementationInterpreterFactory().registerInterpreter(LinkRemovalInterpreter.class, ClassesPackage.eINSTANCE.getLinkRemoval()); getSignatureImplementationInterpreterFactory().registerInterpreter(LinkSettingInterpreter.class, ClassesPackage.eINSTANCE.getLinkSetting()); getSignatureImplementationInterpreterFactory().registerInterpreter(StringTemplateInterpreter.class, TemplatesPackage.eINSTANCE.getStringTemplate()); getSignatureImplementationInterpreterFactory().registerInterpreter(CellSetInterpreter.class, AnalyticsPackage.eINSTANCE.getCellSet()); } @Override protected void initNativeInterpreterFactory(ResourceSet resourceSet) { final String NUMBER_CLASS_NAME = "Number"; final String STRING_CLASS_NAME = "String"; final String BOOLEAN_CLASS_NAME = "Boolean"; final String BINARY_CLASS_NAME = "Binary"; final String TIMEPOINT_CLASS_NAME = "TimePoint"; final String SNAPSHOT_CLASS_NAME = "Snapshot"; final String CALENDAR_CLASS_NAME = "Calendar"; registerNativeImplementationInterpreter(NumberInterpreter.class, MetamodelUtils.findClass(resourceSet, NUMBER_CLASS_NAME)); registerNativeImplementationInterpreter(StringInterpreter.class, MetamodelUtils.findClass(resourceSet, STRING_CLASS_NAME)); registerNativeImplementationInterpreter(BooleanInterpreter.class, MetamodelUtils.findClass(resourceSet, BOOLEAN_CLASS_NAME)); registerNativeImplementationInterpreter(BinaryInterpreter.class, MetamodelUtils.findClass(resourceSet, BINARY_CLASS_NAME)); registerNativeImplementationInterpreter(TimepointInterpreter.class, MetamodelUtils.findClass(resourceSet, TIMEPOINT_CLASS_NAME)); registerNativeImplementationInterpreter(com.sap.runlet.interpreter.nativestdlib.SnapshotInterpreter.class, MetamodelUtils.findClass(resourceSet, SNAPSHOT_CLASS_NAME)); registerNativeImplementationInterpreter(CalendarInterpreter.class, MetamodelUtils.findClass(resourceSet, CALENDAR_CLASS_NAME)); } /** * If necessary, applies implicit conversion to <tt>ro</tt> into an object * that conforms to <tt>targetType</tt>. In particular, if <tt>ro</tt> is a * value object that is instance of an object-parameterized class, and the * target type definition is of the same class but with different object * parameters, the conversion method will be applied. If the <tt>ro</tt>'s * actual object parameters already match those of <tt>targetType</tt> or * more generally, if <tt>ro</tt> already conforms to <tt>targetType</tt>, * no conversion is applied, and <tt>ro</tt> is returned. * <p> * * If <tt>ro</tt> is a {@link MultiValuedObject} with a * {@link ClassTypeDefinition} as its type that has as its <tt>clazz</tt> a * {@link SapClass#isValueType() value type} class, a "copy on write" * strategy is applied: if recursively any object contained is the * multi-object requires conversion, the multi-object is cloned and the * contained value(s) requiring conversion is replaced in the clone. */ public RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> convert( RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> ro, TypeDefinition targetType) { // TODO refactor such that this becomes a method on RiverObject that can be used polymorphically RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> result = ro; if (ro instanceof ValueObject) { if (!(targetType.getInnermost() instanceof ClassTypeDefinition)) { throw new RuntimeException("Cannot convert a value object into the non class-like type " + StringFormatter.toString(targetType)); } try { result = convert((ValueObject) ro, (ClassTypeDefinition) targetType.getInnermost()); } catch (Exception e) { throw new RuntimeException(e); } } else { TypeDefinition innermost = ro.getType().getInnermost(); if (ro instanceof MultiValuedObject<?, ?, ?> && innermost instanceof ClassTypeDefinition && ((ClassTypeDefinition) innermost).getClazz().isValueType()) { return new ConvertedMultiObject((MultiValuedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>) ro, targetType, this, targetType.isOrdered(), targetType.isUnique()); } } return result; } /** * When a value is used where an object of an object-parameterized value * type is expected, a conversion may be necessary in case the actual object * parameters of the object's type do not match the target type's actual * object parameters. For example, if a <tt>Number|3|</tt> object is used * where a <tt>Number|1|</tt> is expected, the precision must be reduced by * applying a rounding conversion. * * @param vo * the object to convert * @param targetType * the type into which to convert <tt>vo</tt>; it is assumed that * <tt>vo.getType().conformsTo(targetType)</tt> holds. * @return <tt>vo</tt> in case no conversion is necessary, or the converted * object as computed by the conversion routine on * <tt>vo.getType()</tt> * @throws RuntimeException * in case a conversion would be necessary but <tt>vo</tt>'s * type does not offer a conversion routine * @see {@link SapClass#getConverterBetweenParametrizations()} */ public ValueObject convert(ValueObject vo, ClassTypeDefinition targetType) throws SecurityException, IllegalArgumentException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { List<RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>> voParameterValues = vo.getActualObjectParameters(); List<RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>> targetParameterValues = new LinkedList<RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>>(); for (ActualObjectParameter aop : targetType.getObjectParameters()) { RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> targetParameterValue = evaluate(aop.getValue()); targetParameterValues.add(targetParameterValue); } if (targetParameterValues.size() < targetType.getClazz().getFormalObjectParameters().size()) { for (int i = targetParameterValues.size(); i < targetType.getClazz().getFormalObjectParameters().size(); i++) { RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> defaultParameterValue = evaluate(targetType.getClazz().getFormalObjectParameters().get(i).getDefaultValue()); targetParameterValues.add(defaultParameterValue); } } ValueObject result; // TODO should this use logicallyEquals? What about an entity object // used as parameter for a value class? if (!voParameterValues.equals(targetParameterValues)) { // conversion necessary; find conversion method and invoke on vo // with targetType's // actual parameters as arguments: ConverterBetweenParametrizations converter = vo.getType().getClazz().getConverterBetweenParametrizations(); if (converter == null) { throw new RuntimeException("No implicit conversion between " + vo.getType().getClazz().getName() + " and " + targetType.getClazz().getName()); } MethodSignature converterSig = converter.getConversionMethod(); FunctionFromMethodObject ffmo = new FunctionFromMethodObject(/* type */null, converterSig.getImplementation(), vo); RunletStackFrame newStackFrame = pushArgumentsToStackFrame(targetParameterValues, ffmo); push(newStackFrame); try { result = (ValueObject) ffmo.evaluate(this); } finally { pop(); } } else { result = vo; } return result; } /** * The formal parameters are taken from <tt>evaluator</tt>'s * implementation's signature. They may be distinct from the parameters in * the signature to which the call was statically bound and may only * <em>conform</tt> but not be the same. The <tt>values</tt> are bound * positionally which makes it important that <tt>values</tt> is a {@link List} and not just * a {@link Collection}.<p> * * Before passing, each argument is submitted to {@link #convert(RunletObject, TypeDefinition)} * to ensure that any assignment conversion required will be performed. This particularly * includes the implicit conversions defined for object-parameterized types where the object's * converter will be invoked if the target type has different actual object parameters than * the parameter object. * * @return a new stack frame in which for each formal parameter as defined * in <tt>evaluator</tt>'s implementation's signature a * {@link RunletObject} has been registered from <tt>values</tt> */ public RunletStackFrame pushArgumentsToStackFrame(List<RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>> values, FunctionObject evaluator) { RunletStackFrame result = new RunletStackFrame(); // constructs a new stack frame // with no scope parent Iterator<RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>> v = values.iterator(); for (Parameter parameter : evaluator.getImplementation().getImplementedSignature().getInput()) { RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> paramValue = v.next(); RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> convertedParamValue = convert(paramValue, parameter.getType()); result.enterValue(parameter, convertedParamValue); } return result; } /** * Implements the polymorphism strategy. When a method is to be invoked on * an object, the object's runtime type needs to be considered in order to * determine the right implementation for the method signature invoked. * <p> * * The algorithm checks if there is a signature on the runtime type of the * <tt>thiz</tt> object that conforms to <tt>calledSignature</tt>. If one is * found, it is returned. If none is found, the set of adapters known for * <tt>thiz</tt>'s runtime class are transitively checked for matching * implementations. If none is found, this means there is a conformance * problem where <tt>thiz</tt> does not conform to the class by which * <tt>calledSignature</tt> is defined which points to a problem in the * design-time's type checks. A {@link RuntimeException} is thrown in this * case. Otherwise, the signature implementation found in an adapter will be * returned. */ public SignatureImplementation resolveMethodCallToImplementation(MethodSignature calledSignature, ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> thiz) { return getMethodCallResolver().getImplementation(calledSignature, thiz.getType().getClazz(), getResourceSet()); } private MethodCallResolver getMethodCallResolver() { return methodCallResolver; } /** * Spawns a new interpreter for parallel execution. This interpreter re-uses * the registries for subinterpreters for expressions, statements etc., the * {@link #resourceSet} as well as the shared state consisting of the * {@link #linkContainer}. The spawned interpreter has a new * {@link #callstack call stack} that is initialized with this interpreter's * top stack frame. * <p> * * This means that a spawned interpreter may not have all of the first stack * frame's scope parent frames on its own stack. If this first frame happens * to have a scope parent, this is referenced by a regular Java reference. * <p> */ @Override public RunletInterpreter spawn() { RunletInterpreter result = new RunletInterpreter(this); return result; } /** * Assembles a value object in this interpreter's {@link #getDefaultSnapshot() default snapshot} but does not load the * equality-relevant links for this object yet. */ @Override protected AbstractValueObject<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> createValueObjectWithoutEqualityRelevantLinks( ClassTypeDefinition type, Map<AssociationEnd, Collection<ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>>> propertyValues) { assert type.getClazz().isValueType(); ValueObject result = new ValueObject(type, propertyValues, getUpdatingTag(), this); loadEqualityRelevantLinksOfValue(result); return result; } @Override public ValueObject createValueObject( ClassTypeDefinition type, Map<AssociationEnd, Collection<ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>>> propertyValues) { return (ValueObject) super.createValueObject(type, propertyValues); } @Override public RunletInterpreter[] getRunningChildren() { return super.getRunningChildren(); } }