| package org.eclipse.e4.languages.javascript.rhino.jsdi; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.e4.languages.javascript.debug.JSONConstants; |
| import org.eclipse.e4.languages.javascript.debug.connect.DisconnectException; |
| import org.eclipse.e4.languages.javascript.debug.connect.Request; |
| import org.eclipse.e4.languages.javascript.debug.connect.Response; |
| import org.eclipse.e4.languages.javascript.debug.connect.TimeoutException; |
| import org.eclipse.e4.languages.javascript.jsdi.Location; |
| import org.eclipse.e4.languages.javascript.jsdi.StackFrame; |
| import org.eclipse.e4.languages.javascript.jsdi.Value; |
| import org.eclipse.e4.languages.javascript.jsdi.Variable; |
| |
| /** |
| * Rhino implementation of {@link StackFrame} |
| * |
| * @since 1.0 |
| */ |
| public class StackFrameImpl extends MirrorImpl implements StackFrame { |
| |
| private final Number frameId; |
| private final Number threadId; |
| private final Number contextId; |
| private final Number ref; |
| private final Location location; |
| private List variables; |
| private VariableImpl thisVariable; |
| |
| /** |
| * Constructor |
| * |
| * @param vm |
| * @param jsonFrame |
| */ |
| public StackFrameImpl(VirtualMachineImpl vm, Map jsonFrame) { |
| super(vm); |
| this.threadId = (Number) jsonFrame.get(JSONConstants.THREAD_ID); |
| this.frameId = (Number) jsonFrame.get(JSONConstants.FRAME_ID); |
| this.contextId = (Number) jsonFrame.get(JSONConstants.CONTEXT_ID); |
| this.ref = (Number) jsonFrame.get(JSONConstants.REF); |
| |
| Long scriptId = new Long(((Number) jsonFrame.get(JSONConstants.SCRIPT_ID)).longValue()); |
| ScriptReferenceImpl script = vm.script(scriptId); |
| |
| String function = (String) jsonFrame.get(JSONConstants.FUNCTION); |
| if (function != null) { |
| this.location = script.functionLocation(function); |
| } else { |
| Number line = (Number) jsonFrame.get(JSONConstants.LINE); |
| this.location = script.lineLocation(line.intValue()); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.e4.languages.javascript.jsdi.StackFrame#evaluate(java.lang.String) |
| */ |
| public Value evaluate(String expression) { |
| Request request = new Request(JSONConstants.EVALUATE); |
| request.getArguments().put(JSONConstants.THREAD_ID, threadId); |
| request.getArguments().put(JSONConstants.FRAME_ID, frameId); |
| request.getArguments().put(JSONConstants.EXPRESSION, expression); |
| try { |
| Response response = vm.sendRequest(request, 30000); |
| return createValue(response.getBody()); |
| } catch (DisconnectException e) { |
| e.printStackTrace(); |
| } catch (TimeoutException e) { |
| e.printStackTrace(); |
| } |
| return null; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.e4.languages.javascript.jsdi.StackFrame#getValue(org.eclipse.e4.languages.javascript.jsdi.Variable) |
| */ |
| public Value getValue(Variable variable) { |
| VariableImpl variableImpl = (VariableImpl) variable; |
| return lookupValue(variableImpl.getRef()); |
| } |
| |
| /** |
| * @param ref |
| * @return |
| */ |
| public Value lookupValue(Number ref) { |
| Request request = new Request(JSONConstants.LOOKUP); |
| request.getArguments().put(JSONConstants.THREAD_ID, threadId); |
| request.getArguments().put(JSONConstants.FRAME_ID, frameId); |
| request.getArguments().put(JSONConstants.HANDLE, ref); |
| try { |
| Response response = vm.sendRequest(request, 30000); |
| return createValue(response.getBody()); |
| } catch (DisconnectException e) { |
| e.printStackTrace(); |
| } catch (TimeoutException e) { |
| e.printStackTrace(); |
| } |
| return null; |
| } |
| |
| /** |
| * Creates a new type value for the given type description in the map |
| * |
| * @param body |
| * @return the new type |
| * @throws IllegalStateException |
| * if the type description in the map is unknown |
| */ |
| private Value createValue(Map body) throws IllegalStateException { |
| String type = (String) body.get(JSONConstants.TYPE); |
| // "undefined", "null", "boolean", "number", "string", "object", "function" |
| |
| if (type.equals(JSONConstants.UNDEFINED)) |
| return vm.undefinedValue; |
| else if (type.equals(JSONConstants.NULL)) |
| return vm.nullValue; |
| else if (type.equals(JSONConstants.BOOLEAN)) |
| return new BooleanValueImpl(vm, body); |
| else if (type.equals(JSONConstants.NUMBER)) |
| return new NumberValueImpl(vm, body); |
| else if (type.equals(JSONConstants.STRING)) |
| return new StringValueImpl(vm, body); |
| else if (type.equals(JSONConstants.OBJECT)) |
| return new ObjectReferenceImpl(vm, body, this); |
| else if (type.equals(JSONConstants.FUNCTION)) |
| return new FunctionReferenceImpl(vm, body, this); |
| else if (type.equals(JSONConstants.ARRAY)) |
| return new ArrayReferenceImpl(vm, body, this); |
| else |
| throw new IllegalStateException(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.e4.languages.javascript.jsdi.StackFrame#location() |
| */ |
| public Location location() { |
| return location; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.e4.languages.javascript.jsdi.StackFrame#thisObject() |
| */ |
| public synchronized Variable thisObject() { |
| initializeVariables(); |
| return thisVariable; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.e4.languages.javascript.jsdi.StackFrame#variables() |
| */ |
| public synchronized List variables() { |
| initializeVariables(); |
| return variables; |
| } |
| |
| /** |
| * Initializes and caches the live set of variables |
| */ |
| private void initializeVariables() { |
| if (variables != null) { |
| return; |
| } |
| Request request = new Request(JSONConstants.LOOKUP); |
| request.getArguments().put(JSONConstants.THREAD_ID, threadId); |
| request.getArguments().put(JSONConstants.FRAME_ID, threadId); |
| request.getArguments().put(JSONConstants.HANDLE, ref); |
| try { |
| Response response = vm.sendRequest(request, 30000); |
| List properties = (List) response.getBody().get(JSONConstants.PROPERTIES); |
| variables = new ArrayList(); |
| for (Iterator iterator = properties.iterator(); iterator.hasNext();) { |
| Map property = (Map) iterator.next(); |
| String name = (String) property.get(JSONConstants.NAME); |
| Number ref = (Number) property.get(JSONConstants.REF); |
| VariableImpl variable = new VariableImpl(vm, name, ref); |
| if (name.equals(JSONConstants.THIS)) |
| thisVariable = variable; |
| else |
| variables.add(variable); |
| } |
| } catch (DisconnectException e) { |
| e.printStackTrace(); |
| } catch (TimeoutException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| /** |
| * Returns if this stack frame is visible |
| * |
| * @param variable |
| * @return true if this frame is visible, false otherwise |
| */ |
| public synchronized boolean isVisible(VariableImpl variable) { |
| return variables != null && (thisVariable == variable || variables.contains(variable)); |
| } |
| |
| /** |
| * @return the context id for this frame |
| */ |
| public Number getContextId() { |
| return contextId; |
| } |
| } |