import java.util.*;
/** The minimum set of functionality required for objects which are manipulated by JavaScript */
-public class JS extends org.ibex.util.BalancedTree {
+public abstract class JS {
public static boolean checkAssertions = false;
public static final Object METHOD = new Object() { public String toString() { return "JS.METHOD"; } };
public final JS unclone() { return _unclone(); }
public final JS jsclone() throws JSExn { return new Clone(this); }
- public Enumeration keys() throws JSExn { return entries == null ? emptyEnumeration : entries.keys(); }
- public Object get(Object key) throws JSExn { return entries == null ? null : entries.get(key, null); }
- public void put(Object key, Object val) throws JSExn { (entries==null?entries=new Hash():entries).put(key,null,val); }
+
+ public Enumeration keys() throws JSExn { throw new JSExn("you can't enumerate the keys of this object (class=" + this.getClass().getName() +")"); }
+ public Object get(Object key) throws JSExn { return null; }
+ public void put(Object key, Object val) throws JSExn { throw new JSExn("this object is read only (class=" + this.getClass().getName() +")"); }
+
+ public final boolean hasTrap(Object key) { return getTrap(key) != null; }
+
public Object callMethod(Object method, Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
- throw new JSExn("you cannot call this object (class=" + this.getClass().getName() +")");
+ throw new JSExn("method not found (" + method + ")");
}
+
// FIXME: JSArgs objects, pointers into stack frame
public Object call(Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
throw new JSExn("you cannot call this object (class=" + this.getClass().getName() +")");
}
+ Trap getTrap(Object key) { return null; }
+ void putTrap(Object key, Trap value) throws JSExn { throw new JSExn("traps cannot be placed on this object (class=" + this.getClass().getName() +")"); }
+
+ public static class O extends JS {
+ private Hash entries;
+
+ public Enumeration keys() throws JSExn { return entries == null ? emptyEnumeration : entries.keys(); }
+ public Object get(Object key) throws JSExn { return entries == null ? null : entries.get(key, null); }
+ public void put(Object key, Object val) throws JSExn { (entries==null?entries=new Hash():entries).put(key,null,val); }
+
+ /** retrieve a trap from the entries hash */
+ final Trap getTrap(Object key) {
+ return entries == null ? null : (Trap)entries.get(key, Trap.class);
+ }
+
+ /** retrieve a trap from the entries hash */
+ final void putTrap(Object key, Trap value) {
+ if (entries == null) entries = new Hash();
+ entries.put(key, Trap.class, value);
+ }
+ }
+
+ public static class BT extends O {
+ private BalancedTree bt;
+ private final BalancedTree bt() { if(bt != null) return bt; return bt = new BalancedTree(); }
+ public final void insertNode(int index, Object o) { bt().insertNode(index,o); }
+ public final void clear() { bt().clear(); }
+ public final Object getNode(int i) { return bt().getNode(i); }
+ public final int treeSize() { return bt().treeSize(); }
+ public final Object deleteNode(int i) { return bt().deleteNode(i); }
+ public final void replaceNode(int index, Object o) { bt().replaceNode(index,o); }
+ public final int indexNode(Object o) { return bt().indexNode(o); }
+ }
+
JS _unclone() { return this; }
public interface Cloneable { }
- public static class Clone extends JS implements Cloneable {
+ public static class Clone extends JS.O implements Cloneable {
protected JS clonee;
JS _unclone() { return clonee.unclone(); }
public JS getClonee() { return clonee; }
public Object nextElement() { throw new NoSuchElementException(); }
};
- private Hash entries = null;
-
public static JS fromReader(String sourceName, int firstLine, Reader sourceCode) throws IOException {
return JSFunction._fromReader(sourceName, firstLine, sourceCode);
}
// Trap support //////////////////////////////////////////////////////////////////////////////
- /** override and return true to allow placing traps on this object.
- * if isRead true, this is a read trap, otherwise write trap
- **/
- protected boolean isTrappable(Object name, boolean isRead) { return true; }
-
/** performs a put, triggering traps if present; traps are run in an unpauseable interpreter */
public void putAndTriggerTraps(Object key, Object value) throws JSExn {
Trap t = getTrap(key);
else return get(key);
}
- /** retrieve a trap from the entries hash */
- protected final Trap getTrap(Object key) {
- return entries == null ? null : (Trap)entries.get(key, Trap.class);
- }
-
- /** retrieve a trap from the entries hash */
- protected final void putTrap(Object key, Trap value) {
- if (entries == null) entries = new Hash();
- entries.put(key, Trap.class, value);
- }
-
/** adds a trap, avoiding duplicates */
protected final void addTrap(Object name, JSFunction f) throws JSExn {
if (f.numFormalArgs > 1) throw new JSExn("traps must take either one argument (write) or no arguments (read)");
boolean isRead = f.numFormalArgs == 0;
- if (!isTrappable(name, isRead)) throw new JSExn("not allowed "+(isRead?"read":"write")+" trap on property: "+name);
for(Trap t = getTrap(name); t != null; t = t.next) if (t.f == f) return;
putTrap(name, new Trap(this, name.toString(), f, (Trap)getTrap(name)));
}
/** deletes a trap, if present */
- protected final void delTrap(Object name, JSFunction f) {
+ protected final void delTrap(Object name, JSFunction f) throws JSExn {
Trap t = (Trap)getTrap(name);
if (t == null) return;
if (t.f == f) { putTrap(t.name, t.next); return; }