blob: 5f71d5d71725c1430a96269ad65a797ab2ecf19a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 Christian Pontesegger and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Christian Pontesegger - initial API and implementation
* Bernhard Wedl - added Nativ
*******************************************************************************/
package org.eclipse.ease.lang.javascript.rhino.debugger;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import org.eclipse.ease.IDebugEngine;
import org.eclipse.ease.IScriptEngine;
import org.eclipse.ease.Script;
import org.eclipse.ease.debugging.AbstractScriptDebugger;
import org.eclipse.ease.debugging.IScriptDebugFrame;
import org.eclipse.ease.debugging.ScriptDebugFrame;
import org.eclipse.ease.lang.javascript.rhino.RhinoScriptEngine;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.NativeArray;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.debug.DebugFrame;
import org.mozilla.javascript.debug.DebuggableScript;
import org.mozilla.javascript.debug.Debugger;
public class RhinoDebugger extends AbstractScriptDebugger implements Debugger {
public class RhinoDebugFrame extends ScriptDebugFrame implements DebugFrame, IScriptDebugFrame {
private final String fFunctionName;
private Scriptable fScope;
public RhinoDebugFrame(final DebuggableScript fnOrScript) {
super(RhinoDebugger.this.getScript(fnOrScript), 0, fnOrScript.isFunction() ? TYPE_FUNCTION : TYPE_FILE);
fFunctionName = fnOrScript.getFunctionName();
}
@Override
public void onEnter(final Context cx, final Scriptable activation, final Scriptable thisObj, final Object[] args) {
// nothing to do
fScope = activation;
}
@Override
public void onLineChange(final Context cx, final int lineNumber) {
setLineNumber(lineNumber);
if (isTrackedScript(getScript())) {
// static code or dynamic code activated
// TODO in future we should not add stuff to the stack we do not track anyway, so we can get rid of the "if" statement
processLine(getScript(), lineNumber);
}
}
@Override
public void onExceptionThrown(final Context cx, final Throwable ex) {
setExceptionStacktrace(getStacktrace().clone());
// we do not need the scope any longer
fScope = null;
}
@Override
public void onExit(final Context cx, final boolean byThrow, final Object resultOrException) {
getStacktrace().remove(this);
// we do not need the scope any longer
fScope = null;
}
@Override
public void onDebuggerStatement(final Context cx) {
// nothing to do
}
@Override
public String getName() {
if (getType() == IScriptDebugFrame.TYPE_FUNCTION) {
String title = getScript().getTitle();
if (title == null)
title = "";
return title + ":" + fFunctionName + "()";
} else {
String title = getScript().getTitle();
if (title == null)
title = "(Dynamic)";
return title;
}
}
@Override
public Map<String, Object> getVariables() {
final Map<String, Object> result = RhinoScriptEngine.getVariables(fScope);
return result;
}
@Override
public Map<String, Object> getVariables(final Object parent) {
if (parent instanceof NativeObject) {
final Map<String, Object> children = new TreeMap<>();
for (final Object key : ((NativeObject) parent).getIds())
children.put(key.toString(), ((NativeObject) parent).get(key));
return children;
} else if (parent instanceof NativeArray) {
final Map<String, Object> children = new LinkedHashMap<>();
for (final Object key : ((NativeArray) parent).getIds())
children.put("[" + key + "]", ((NativeArray) parent).get(key));
return children;
}
return super.getVariables(parent);
}
}
private final Map<Integer, Script> fFrameToSource = new HashMap<>();
private Script fLastScript = null;
public RhinoDebugger(final IDebugEngine engine, final boolean showDynamicCode) {
super(engine, showDynamicCode);
}
@Override
public void handleCompilationDone(final Context cx, final DebuggableScript fnOrScript, final String source) {
}
@Override
public DebugFrame getFrame(final Context cx, final DebuggableScript fnOrScript) {
Script script = getScript(fnOrScript);
if (script == null)
script = fLastScript;
if (script == null)
return null;
// register script source
final DebuggableScript parentScript = getParentScript(fnOrScript);
if (!fFrameToSource.containsKey(parentScript.hashCode()))
fFrameToSource.put(parentScript.hashCode(), script);
// create debug frame
final RhinoDebugFrame debugFrame = new RhinoDebugFrame(fnOrScript);
// mDebugFrames.add(0, debugFrame);
getStacktrace().add(0, debugFrame);
return debugFrame;
}
@Override
public void notify(final IScriptEngine engine, final Script script, final int status) {
switch (status) {
case SCRIPT_START:
// fall through
case SCRIPT_INJECTION_START:
fLastScript = script;
break;
case ENGINE_END:
fFrameToSource.clear();
fLastScript = null;
break;
default:
// unknown event
break;
}
super.notify(engine, script, status);
}
private Script getScript(final DebuggableScript rhinoScript) {
return fFrameToSource.get(getParentScript(rhinoScript).hashCode());
}
private static DebuggableScript getParentScript(DebuggableScript rhinoScript) {
while (rhinoScript.getParent() != null)
rhinoScript = rhinoScript.getParent();
return rhinoScript;
}
}