Changes from Christopher Oliver:

Hi Norris,

Would you mind checking in the attached changes to the debugger. The
attached files include the following changes:

1) Use ScriptableObject.getAllIds to obtain an object's properties (if
the object extends ScriptableObject).  This makes non-enumerable
properties visible in the debugger for ScriptableObject's.
2) Made the coding style more consistent with the rest of Rhino.
3) Better support for displaying and stepping through eval-ed code.

As Igor suggested to me once, it might be a good idea to define a new
interface to similarly support debugging host objects that don't extend
ScriptableObject, something like the following:

public interface Debuggable extends Scriptable {
    public Object[] getAllIds();
}

The debugger could check for this interface and if a host object chose
to implement it, the debugger would be able to display its
non-enumerable properties.

Chris


git-svn-id: svn://10.0.0.236/trunk@117520 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
nboyd%atg.com 2002-03-26 23:02:43 +00:00
parent 028a31b09c
commit d1eb87d2d8
2 changed files with 537 additions and 530 deletions

View File

@ -13,10 +13,10 @@
* The Original Code is Rhino JavaScript Debugger code, released
* November 21, 2000.
*
* The Initial Developer of the Original Code is See Beyond Corporation.
* The Initial Developer of the Original Code is SeeBeyond Corporation.
* Portions created by See Beyond are
* Copyright (C) 2000 See Beyond Communications Corporation. All
* Portions created by SeeBeyond are
* Copyright (C) 2000 SeeBeyond Technology Corporation. All
* Rights Reserved.
*
* Contributor(s):
@ -44,11 +44,11 @@ public class VariableModel extends AbstractTreeTableModel
implements TreeTableModel {
// Names of the columns.
//static protected String[] cNames = {"Name", "Type", "Value"};
static protected String[] cNames = { " Name", " Value"};
// Types of the columns.
//static protected Class[] cTypes = {TreeTableModel.class, String.class, String.class};
static protected Class[] cTypes = {TreeTableModel.class, String.class};
@ -62,7 +62,7 @@ public class VariableModel extends AbstractTreeTableModel
protected Object getObject(Object node) {
VariableNode varNode = ((VariableNode)node);
if(varNode == null) return null;
if (varNode == null) return null;
return varNode.getObject();
}
@ -86,10 +86,10 @@ public class VariableModel extends AbstractTreeTableModel
// The superclass's implementation would work, but this is more efficient.
public boolean isLeaf(Object node) {
if(node == null) return true;
if (node == null) return true;
VariableNode varNode = (VariableNode)node;
Object[] children = varNode.getChildren();
if(children != null && children.length > 0) {
if (children != null && children.length > 0) {
return false;
}
return true;
@ -116,46 +116,51 @@ public class VariableModel extends AbstractTreeTableModel
}
public Object getValueAt(Object node, int column) {
Object value = getObject(node);
Context cx = Context.enter();
try {
switch(column) {
Object value = getObject(node);
switch (column) {
case 0: // Name
VariableNode varNode = (VariableNode)node;
String name = "";
if(varNode.name != null) {
if (varNode.name != null) {
return name + varNode.name;
}
return name + "[" + varNode.index + "]";
case 1: // value
if(value == Undefined.instance ||
case 1: // Value
if (value == Undefined.instance ||
value == ScriptableObject.NOT_FOUND) {
return "undefined";
}
if(value == null) {
if (value == null) {
return "null";
}
if(value instanceof NativeCall) {
if (value instanceof NativeCall) {
return "[object Call]";
}
String result;
try {
result = Context.toString(value);
} catch(RuntimeException exc) {
result = value.toString();
if (value instanceof BaseFunction) {
result = ((BaseFunction)value).decompile(cx, 0,
false);
} else {
result = Context.toString(value);
}
} catch (RuntimeException exc) {
result = exc.getMessage();
}
StringBuffer buf = new StringBuffer();
int len = result.length();
for(int i = 0; i < len; i++) {
for (int i = 0; i < len; i++) {
char ch = result.charAt(i);
if(Character.isISOControl(ch)) {
if (Character.isISOControl(ch)) {
ch = ' ';
}
buf.append(ch);
}
return buf.toString();
}
} catch(Exception exc) {
} catch (Exception exc) {
//exc.printStackTrace();
} finally {
cx.exit();
@ -199,151 +204,119 @@ class VariableNode {
public Object getObject() {
try {
if(scope == null) return null;
if(name != null) {
if(name.equals("this")) {
if (scope == null) return null;
if (name != null) {
if (name.equals("this")) {
return scope;
}
Object result;
if(name.equals("__proto__")) {
Object result = ScriptableObject.NOT_FOUND;
if (name.equals("__proto__")) {
result = scope.getPrototype();
} else if(name.equals("__parent__")) {
} else if (name.equals("__parent__")) {
result = scope.getParentScope();
} else {
result = scope.get(name, scope);
try {
result = ScriptableObject.getProperty(scope, name);
} catch (Exception e) {
result = e.getMessage();
}
}
if(result == ScriptableObject.NOT_FOUND) {
if (result == ScriptableObject.NOT_FOUND) {
result = Undefined.instance;
}
return result;
}
Object result = scope.get(index, scope);
if(result == ScriptableObject.NOT_FOUND) {
Object result = ScriptableObject.getProperty(scope, index);
if (result == ScriptableObject.NOT_FOUND) {
result = Undefined.instance;
}
return result;
} catch(Exception exc) {
} catch (Exception exc) {
return "undefined";
}
}
Object[] children;
/**
* Loads the children, caching the results in the children ivar.
*/
static final Object[] empty = new Object[0];
static Scriptable builtin[];
protected Object[] getChildren() {
if(children != null) return children;
if (children != null) return children;
Context cx = Context.enter();
try {
Object value = getObject();
if(value == null) return children = empty;
if(value == ScriptableObject.NOT_FOUND ||
if (value == null) return children = empty;
if (value == ScriptableObject.NOT_FOUND ||
value == Undefined.instance) {
return children = empty;
}
if(value instanceof Scriptable) {
if (value instanceof Scriptable) {
Scriptable scrip = (Scriptable)value;
Scriptable proto = scrip.getPrototype();
Scriptable parent = scrip.getParentScope();
if(value instanceof NativeCall) {
if(name != null && name.equals("this")) {
// this is the local variables table root
// don't show the __parent__ property
parent = null;
} else if(!(parent instanceof NativeCall)) {
// don't bother showing [object Global] as
// the __parent__ property which just creates
// more noise
parent = null;
}
}
if(proto != null) {
if(builtin == null) {
builtin = new Scriptable[6];
builtin[0] =
ScriptableObject.getObjectPrototype(scrip);
builtin[1] =
ScriptableObject.getFunctionPrototype(scrip);
builtin[2] =
ScriptableObject.getClassPrototype(scrip,
"String");
builtin[3] =
ScriptableObject.getClassPrototype(scrip,
"Boolean");
builtin[4] =
ScriptableObject.getClassPrototype(scrip,
"Array");
builtin[5] =
ScriptableObject.getClassPrototype(scrip,
"Number");
}
for(int i = 0; i < builtin.length; i++) {
if(proto == builtin[i]) {
proto = null;
break;
}
}
}
if(scrip.has(0, scrip)) {
if (scrip.has(0, scrip)) {
int len = 0;
try {
Scriptable start = scrip;
Scriptable obj = start;
Object result = Undefined.instance;
do {
if(obj.has("length", start)) {
if (obj.has("length", start)) {
result = obj.get("length", start);
if (result != Scriptable.NOT_FOUND)
break;
}
obj = obj.getPrototype();
} while (obj != null);
if(result instanceof Number) {
if (result instanceof Number) {
len = ((Number)result).intValue();
}
} catch(Exception exc) {
} catch (Exception exc) {
}
if(parent != null) {
if (parent != null) {
len++;
}
if(proto != null) {
if (proto != null) {
len++;
}
children = new VariableNode[len];
int i = 0;
int j = 0;
if(proto != null) {
children[i++] = new VariableNode(scrip, "__proto__");
j++;
}
if(parent != null) {
if (parent != null) {
children[i++] = new VariableNode(scrip, "__parent__");
j++;
}
for(; i < len; i++) {
if (proto != null) {
children[i++] = new VariableNode(scrip, "__proto__");
j++;
}
for (; i < len; i++) {
children[i] = new VariableNode(scrip, i-j);
}
} else {
int len = 0;
Hashtable t = new Hashtable();
Object[] ids = scrip.getIds();
if(proto != null) t.put("__proto__", "__proto__");
if(parent != null) t.put("__parent__", "__parent__");
if(ids.length > 0) {
for(int j = 0; j < ids.length; j++) {
Object[] ids;
if (scrip instanceof ScriptableObject) {
ids = ((ScriptableObject)scrip).getAllIds();
} else {
ids = scrip.getIds();
}
if (ids == null) ids = empty;
if (proto != null) t.put("__proto__", "__proto__");
if (parent != null) t.put("__parent__", "__parent__");
if (ids.length > 0) {
for (int j = 0; j < ids.length; j++) {
t.put(ids[j], ids[j]);
}
}
ids = new Object[t.size()];
Enumeration e = t.keys();
int j = 0;
while(e.hasMoreElements()) {
while (e.hasMoreElements()) {
ids[j++] = e.nextElement().toString();
}
if(ids != null && ids.length > 0) {
if (ids != null && ids.length > 0) {
java.util.Arrays.sort(ids, new java.util.Comparator() {
public int compare(Object l, Object r) {
return l.toString().compareToIgnoreCase(r.toString());
@ -353,10 +326,10 @@ class VariableNode {
len = ids.length;
}
children = new VariableNode[len];
for(int i = 0; i < len; i++) {
for (int i = 0; i < len; i++) {
Object id = ids[i];
children[i] =
new VariableNode(scrip, id.toString());
children[i] = new
VariableNode(scrip, id.toString());
}
}
}