package com.sap.runlet.expressionpad.launch; import java.util.LinkedList; import java.util.List; import java.util.Stack; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.model.DebugElement; import org.eclipse.debug.core.model.IBreakpoint; import org.eclipse.debug.core.model.IStackFrame; import org.eclipse.debug.core.model.IThread; import com.sap.runlet.abstractinterpreter.AbstractObjectFormatter; import com.sap.runlet.abstractinterpreter.AbstractRunletInterpreter; import com.sap.runlet.abstractinterpreter.DebugListener; import com.sap.runlet.abstractinterpreter.StackFrame; import com.sap.runlet.expressionpad.Activator; public abstract class AbstractRunletThread extends DebugElement implements IThread { private final ILaunch launch; private final AbstractRunletInterpreter<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> interpreter; private final AbstractObjectFormatter<?, ?, ?, ?> formatter; protected AbstractObjectFormatter<?, ?, ?, ?> getFormatter() { return formatter; } public AbstractRunletThread(AbstractRunletInterpreter<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> interpreter, ILaunch launch, RunletDebugTarget debugTarget, AbstractObjectFormatter<?, ?, ?, ?> formatter) { super(debugTarget); this.interpreter = interpreter; this.launch = launch; this.formatter = formatter; } public int hashCode() { return getInterpreter().hashCode(); } public boolean equals(Object o) { boolean result = false; if (o instanceof AbstractRunletThread) { result = getInterpreter().equals(((AbstractRunletThread) o).getInterpreter()); } return result; } @Override public IBreakpoint[] getBreakpoints() { // TODO Auto-generated method stub return new IBreakpoint[0]; } @Override public String getName() { return toString(); } @Override public int getPriority() { return 0; } @SuppressWarnings("unchecked") @Override public IStackFrame[] getStackFrames() { IStackFrame[] result; if (!isSuspended()) { result = new IStackFrame[0]; } else { List<AbstractRunletStackFrame<?, ?, ?, ?>> runletStackFrames = new LinkedList<AbstractRunletStackFrame<?, ?, ?, ?>>(); Stack<StackFrame<?, ?, ?, ?>> stack = (Stack<StackFrame<?, ?, ?, ?>>) getInterpreter().getCallstack(); // frames on the interpreter stack can be nested; only add innermost frames boolean innermost = true; for (int i=stack.size()-1; i>=0; i--) { StackFrame<?, ?, ?, ?> frame = stack.get(i); if (innermost) { runletStackFrames.add(createStackFrame(frame)); } // the next frame is an innermost frame if it is not the current frame's scope parent innermost = frame.getScopeParent() == null; } result = runletStackFrames.toArray(new IStackFrame[runletStackFrames.size()]); } return result; } @Override public IStackFrame getTopStackFrame() { if (getInterpreter().getCallstack().isEmpty()) { return null; } else { StackFrame<?, ?, ?, ?> frame = getInterpreter().getCallstack().peek(); IStackFrame result = null; if (frame != null) { result = createStackFrame(frame); } return result; } } protected abstract RunletStackFrame createStackFrame(StackFrame<?, ?, ?, ?> frame); @Override public boolean hasStackFrames() { return !getInterpreter().getCallstack().isEmpty(); } @Override public RunletDebugTarget getDebugTarget() { return (RunletDebugTarget) super.getDebugTarget(); } @Override public ILaunch getLaunch() { return launch; } @Override public String getModelIdentifier() { return Activator.PLUGIN_ID; } @Override public boolean canResume() { return !isTerminated() && isSuspended(); } @Override public boolean canSuspend() { return !isTerminated() && !isSuspended(); } @Override public boolean isSuspended() { return getDebugTarget().getDebugSession().isSuspended(getInterpreter()); } @Override public void resume() { getDebugTarget().getDebugSession().resume(getInterpreter(), DebugListener.ResumeReason.CLIENT_REQUEST); } @Override public void suspend() { getDebugTarget().getDebugSession().suspend(getInterpreter()); } /** * Can step into if not suspended and at the bottom of the call hierarchy (top of the call stack) */ @SuppressWarnings("unchecked") @Override public boolean canStepInto() { return isSuspended() && ( getInterpreter().getCallstack().isEmpty() || ((AbstractRunletInterpreter<?, ?, ?, ?, ?, ?, ?, ?, StackFrame<?,?,?,?>, ?, ?>) getInterpreter()).oneDown(getInterpreter().getCallstack().peek()) == null); } @Override public boolean canStepOver() { return isSuspended(); } @Override public boolean canStepReturn() { return isSuspended(); } @Override public boolean isStepping() { return !isTerminated() && !isSuspended(); } @Override public void stepInto() { getDebugTarget().getDebugSession().stepInto(getInterpreter()); } @Override public void stepOver() { getDebugTarget().getDebugSession().stepOver(getInterpreter()); } @Override public void stepReturn() { getDebugTarget().getDebugSession().stepReturn(getInterpreter()); } @Override public boolean canTerminate() { return !isTerminated() && getLaunch().canTerminate(); } @Override public boolean isTerminated() { return getInterpreter().isTerminated(); } @Override public void terminate() { getInterpreter().terminate(); } protected AbstractRunletInterpreter<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> getInterpreter() { return interpreter; } }