package com.sap.runlet.interpreter.expressions;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import behavioral.actions.Statement;
import com.sap.runlet.abstractinterpreter.Interpreter;
import com.sap.runlet.abstractinterpreter.objects.EmptyObject;
import com.sap.runlet.abstractinterpreter.objects.MultiValuedObject;
import com.sap.runlet.abstractinterpreter.objects.RunletObject;
import com.sap.runlet.interpreter.RunletInterpreter;
import com.sap.runlet.interpreter.RunletStackFrame;
import com.sap.runlet.interpreter.objects.FunctionObject;
import data.classes.Association;
import data.classes.AssociationEnd;
import data.classes.ClassTypeDefinition;
import data.classes.NativeImpl;
import data.classes.SapClass;
import data.classes.SignatureImplementation;
import data.classes.TypeDefinition;
import dataaccess.expressions.Expression;
import dataaccess.expressions.Map;
public class MapInterpreter implements Interpreter<Map, SapClass, TypeDefinition, ClassTypeDefinition, Association, AssociationEnd, Statement, Expression, SignatureImplementation, RunletStackFrame, NativeImpl, RunletInterpreter> {
private Map mapExpr;
public MapInterpreter(Map mapExpr) {
this.mapExpr = mapExpr;
}
@Override
public RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> evaluate(RunletInterpreter interpreter) throws SecurityException,
IllegalArgumentException, NoSuchMethodException, InstantiationException,
IllegalAccessException, InvocationTargetException {
TypeDefinition mapExprType = mapExpr.getType();
RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> o = interpreter.evaluate(mapExpr.getObject());
// f is currently expected to be a single function object;
// mapping with multiple functions concurrently may be supported in the future
FunctionObject f = (FunctionObject) interpreter.evaluate(mapExpr.getArgument());
RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> result = null;
Collection<RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>> resultCollection = null;
boolean pushed = false;
try {
// TODO check use of flatten() once NestedTypeDefinition use has been finalized
// TODO parallelize
for (RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> singleO : o) {
List<RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>> parameterValues = new ArrayList<RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>>(1);
parameterValues.add(singleO);
RunletStackFrame newStackFrame =
interpreter.pushArgumentsToStackFrame(parameterValues, f);
pushed = true;
interpreter.push(newStackFrame); // TODO this must not happen before function expression has been evaluated (errr... why again?)
RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> evaluationResult = f.evaluate(interpreter);
if (result != null) {
// already a result; this is a "many" case; put previous and this result into collection
resultCollection = RunletObject.createCollection(
mapExprType.isOrdered(), mapExprType.isUnique());
resultCollection.add(result);
result = null;
resultCollection.add(evaluationResult);
} else {
result = evaluationResult;
}
}
} finally {
if (pushed) {
interpreter.pop();
}
}
if (mapExprType != null) {
if (resultCollection != null) {
result = new MultiValuedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>(
mapExprType, resultCollection, mapExprType.isOrdered(), mapExprType.isUnique());
} else {
if (result == null) {
// non-void return type; return valid EmptyObject
result = new EmptyObject<AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(mapExprType, interpreter.getModelAdapter());
}
}
} else {
// return type is void; force a null result
assert result == null;
}
return result;
}
}