package com.sap.runlet.expressionpad.launch;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.debug.core.model.DebugElement;
import org.eclipse.debug.core.model.IValue;
import org.eclipse.debug.core.model.IVariable;
import com.sap.runlet.abstractinterpreter.AbstractObjectFormatter;
import com.sap.runlet.abstractinterpreter.objects.ClassTypedObject;
import com.sap.runlet.abstractinterpreter.objects.EmptyObject;
import com.sap.runlet.abstractinterpreter.objects.RunletObject;
import com.sap.runlet.expressionpad.Activator;
import com.sap.runlet.interpreter.RunletInterpreter;
import com.sap.runlet.interpreter.objects.FunctionFromMethodObject;
import data.classes.AssociationEnd;
import data.classes.ClassTypeDefinition;
import data.classes.LinkTraversal;
import data.classes.MethodSignature;
import data.classes.SapClass;
import data.classes.SignatureImplementation;
import data.classes.TypeDefinition;
public class RunletValue extends DebugElement implements IValue {
private RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> value;
private final AbstractObjectFormatter<AssociationEnd, TypeDefinition, ClassTypeDefinition, SignatureImplementation> formatter;
public RunletValue(RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> value,
RunletDebugTarget debugTarget,
AbstractObjectFormatter<AssociationEnd, TypeDefinition, ClassTypeDefinition, SignatureImplementation> formatter) {
super(debugTarget);
this.value = value;
this.formatter = formatter;
}
public int hashCode() {
return value.hashCode();
}
public boolean equals(Object o) {
boolean result = false;
if (o instanceof RunletValue) {
result = value.equals(((RunletValue) o).value);
}
return result;
}
@Override
public String getReferenceTypeName() {
return formatter.formatType(value);
}
@Override
public String getValueString() {
return value.toString();
}
/**
* If {@link #value} has a many-multiplicity, the "variables" are the individual objects that result
* from iterating the value. Otherwise, all attaching association ends navigable away from the
* value are determined, as well as all no-arg side effect-free operations available on the class.
*/
@Override
public IVariable[] getVariables() {
List<IVariable> result = new LinkedList<IVariable>();
TypeDefinition td = value.getType();
if (td.isMany()) {
// stable order?
int i=0; // for "naming" the variables
for (RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> single : value) {
result.add(new RunletVariable(""+i, single, getDebugTarget(), formatter));
}
} else {
if (!value.isEmpty() && td instanceof ClassTypeDefinition) {
result = getVariablesFromClassTypedObject();
}
}
return result.toArray(new IVariable[result.size()]);
}
private List<IVariable> getVariablesFromClassTypedObject() {
List<IVariable> result = new LinkedList<IVariable>();
SapClass c = ((ClassTypeDefinition) value.getType()).getClazz();
for (AssociationEnd ae : c.getConformsToAssociationEnds()) {
AssociationEnd oe = ae.otherEnd();
if (oe.isNavigable()) {
RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> endValue = ((RunletInterpreter) getDebugTarget().getInterpreter()).navigate(
(ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>) value, oe);
RunletVariable var = new RunletVariable(oe.getName() + " (from " + ae.getName()
+ ")", endValue, getDebugTarget(), formatter);
result.add(var);
}
}
for (MethodSignature sig : c.allSignatures()) {
if (sig.getInput().size() == 0 && sig.getOutput() != null && sig.isSideEffectFree() &&
// filter out the link traversals; those we have already from
// the association ends handled above
!(sig.getImplementation() instanceof LinkTraversal)) {
FunctionFromMethodObject ffmo = new FunctionFromMethodObject(
/* type definition not needed for simple invocation */null, sig
.getImplementation(), (ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>) value);
try {
RunletInterpreter methodEvalInterpreter = (RunletInterpreter) getDebugTarget().getInterpreter().spawn();
com.sap.runlet.interpreter.RunletStackFrame evalFrame = new com.sap.runlet.interpreter.RunletStackFrame();
methodEvalInterpreter.push(evalFrame);
RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> methodCallResult = ffmo.evaluate(methodEvalInterpreter);
result.add(new RunletVariable(sig.getName() + "()", methodCallResult,
getDebugTarget(), formatter));
} catch (Exception e) {
result.add(new RunletVariable(sig.getName() + "()", new EmptyObject<AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(sig
.getOutput(), ((RunletInterpreter) getDebugTarget().getInterpreter()).getModelAdapter()), getDebugTarget(), formatter));
}
}
}
return result;
}
@Override
public boolean hasVariables() {
return getVariables().length > 0;
}
@Override
public boolean isAllocated() {
return true;
}
@Override
public RunletDebugTarget getDebugTarget() {
return (RunletDebugTarget) super.getDebugTarget();
}
@Override
public String getModelIdentifier() {
return Activator.PLUGIN_ID;
}
}