package com.sap.runlet.interpreter.statements; import java.lang.reflect.InvocationTargetException; import behavioral.actions.Block; import behavioral.actions.Foreach; import behavioral.actions.Iterator; import behavioral.actions.Statement; import com.sap.runlet.abstractinterpreter.Interpreter; import com.sap.runlet.abstractinterpreter.objects.EmptyObject; import com.sap.runlet.abstractinterpreter.objects.RunletObject; import com.sap.runlet.interpreter.RunletInterpreter; import com.sap.runlet.interpreter.RunletStackFrame; 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; /** * Note that the iterator variable is defined in the scope of the {@link Block} * that contains the {@link Foreach} statement and <em>not</em> in the {@link Block} * that contains the body. This in particular means that after the {@link Foreach} * statement has finished, the iterator is still in scope.<p> * * @author D043530 */ public class ForeachInterpreter implements Interpreter<Foreach, SapClass, TypeDefinition, ClassTypeDefinition, Association, AssociationEnd, Statement, Expression, SignatureImplementation, RunletStackFrame, NativeImpl, RunletInterpreter> { private Foreach foreach; public ForeachInterpreter(Foreach foreach) { this.foreach = foreach; } @Override public RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> evaluate(RunletInterpreter interpreter) throws SecurityException, IllegalArgumentException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> result = null; RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> coll = interpreter.evaluate(foreach.getCollection()); Iterator it = foreach.getForVariable(); // make the iterator variable visible only to the enclosed block RunletStackFrame stackFrame = new RunletStackFrame(/* parent */ interpreter.getCallstack().peek()); interpreter.push(stackFrame); stackFrame.enterValue(it, new EmptyObject<AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>( it.getType(), interpreter.getModelAdapter())); if (coll != null) { for (RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> o : coll.flatten()) { stackFrame.setValue(it, interpreter.convert(o, it.getType())); result = interpreter.evaluateSignatureImplementation(foreach.getNestedBlocks().get(0)); if (result instanceof ReturnInterpreter.ReturnResult) { return result; } } } interpreter.pop(); // TODO decide if it's useful to return the result of the last statement in a foreach, if any return result; } }