package com.sap.runlet.interpreter.objects;
import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import com.sap.runlet.abstractinterpreter.objects.ClassTypedObject;
import com.sap.runlet.abstractinterpreter.objects.RunletObject;
import com.sap.runlet.interpreter.RunletInterpreter;
import data.classes.AssociationEnd;
import data.classes.ClassTypeDefinition;
import data.classes.FunctionSignatureTypeDefinition;
import data.classes.Parameter;
import data.classes.SignatureImplementation;
import data.classes.TypeDefinition;
/**
* Represents an object that is a callable function. Its {@link #getType() type} therefore is a
* {@link FunctionSignatureTypeDefinition}. The object holds a reference to the function
* implementation.
*
* @author Axel Uhl (D043530)
*/
public class FunctionFromMethodObject extends FunctionObject {
/**
* The object on which to call the method specified by the {@link #getType() FunctionSignatureTypeDefinition}.
*/
private ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> thiz;
/**
* Ensures that the <tt>type</tt> is really a {@link FunctionSignatureTypeDefinition}.
* It is assumed that the resolution of the <tt>implementation</tt> has been performed
* considering the definitions of polymorphic method calls, based on the runtime type of
* <tt>thiz</tt>.
*/
public FunctionFromMethodObject(TypeDefinition type, SignatureImplementation implementation,
ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> thiz) {
super(type, implementation);
this.thiz = thiz;
}
@Override
public RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> evaluate(RunletInterpreter interpreter)
throws SecurityException, IllegalArgumentException,
NoSuchMethodException, InstantiationException,
IllegalAccessException, InvocationTargetException {
// Note that the stack frame is expected to have been added particularly for the purpose
// of this call; therefore, no other "this" pointer is overwritten by this; it is just an
// enrichment over what a non-method function call would put on the stack frame
interpreter.getCallstack().peek().setThis(thiz);
addObjectParametersToStackFrame(interpreter);
return super.evaluate(interpreter);
}
/**
* If {@link #thiz}'s class has {@link ClassTypeDefinition#getObjectParameters() object parameters},
* those will be added to the interpreter's current stack frame.
*/
private void addObjectParametersToStackFrame(RunletInterpreter interpreter) {
if (thiz instanceof ValueObject) {
ValueObject value = (ValueObject) thiz;
Iterator<Parameter> aop = thiz.getType().getClazz().getFormalObjectParameters().iterator();
for (RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> actualObjectParameterValue : value.getActualObjectParameters()) {
// TODO consider using a separate StackFrame for object parameters so that method parameters can hide them
interpreter.getCallstack().peek().enterValue(aop.next(), actualObjectParameterValue);
}
}
}
}