* This function must never return a null object. */
public String[] getFormalArgs();
- /** Returns true if the specific key is found in this object. */
- public boolean hasKey(JS key);
-
/** Put a value to the given key, calling any write traps that have
* been placed on the key.
*
public InputStream getInputStream() throws IOException, JSExn { throw new JSExn(
"object has not associated stream, class ["+ getClass().getName() +"]"); }
- public boolean hasKey(JS key) { return false; }
-
public Object run(Object o) throws Exception { throw new JSExn(
"object cannot be called, class ["+ getClass().getName() +"]"); }
public void pause() { throw new NotPausableException(); }
- public JS call(JS[] args) throws JSExn { throw new JSExn(
- "object cannot be called, class ["+ getClass().getName() +"]"); }
- public JS call(JS method, JS[] args) throws JSExn { throw new JSExn(
- "method not found: " + Script.str(method)); }
+ public JS call(JS[] args) throws JSExn { throw new JSExn( "object cannot be called, class ["+ getClass().getName() +"]"); }
+ public JS call(JS method, JS[] args) throws JSExn {
+ if (method == null) return call(args);
+ throw new JSExn("method not found: " + JSU.str(method) + " class="+this.getClass().getName());
+ }
public String[] getFormalArgs() { return emptystr; }
public void declare(JS key) throws JSExn { throw new JSExn(
- "object cannot declare key: "+ Script.str(key)); }
+ "object cannot declare key: "+ JSU.str(key)); }
public void undeclare(JS key) throws JSExn { } // FIXME throw error?
public JS putAndTriggerTraps(JS key, JS val) throws JSExn { throw new JSExn(
public JS call(JS[] a) throws JSExn { return clonee.call(a); }
public String[] getFormalArgs() { return clonee.getFormalArgs(); }
- public boolean hasKey(JS k) { return clonee.hasKey(k); }
-
public JS putAndTriggerTraps(JS k, JS v) throws JSExn {
return clonee.putAndTriggerTraps(k, v); }
public JS getAndTriggerTraps(JS k) throws JSExn {
private static final String[] emptystr = new String[0];
private static final Placeholder holder = new Placeholder();
+ // HACK: this is hideously, disgustingly ugly.... we need N-ary Hash classes
/** entries[index + 0] // key
* entries[index + 1] // value
* entries[index + 2] // trap
*/
- protected final int indexmultiple = 3;
protected void entryAdded(int p) {}
protected void entryUpdated(int p) {}
protected void entryRemoved(int p) {}
- public Obj() { super(4, 0.75F); }
+ public Obj() { super(3, 4, 0.75F); }
public JS unclone() { return this; }
public InputStream getInputStream() throws IOException, JSExn { throw new JSExn(
public JS call(JS[] args) throws JSExn { throw new JSExn(
"object cannot be called, class ["+ getClass().getName() +"]"); }
public JS call(JS method, JS[] args) throws JSExn { throw new JSExn(
- "method not found: " + Script.str(method)); }
+ "method not found: " + JSU.str(method)); }
public String[] getFormalArgs() { return emptystr; }
public Enumeration keys() throws JSExn {
if (val == null) entries[dest + 1] = holder;
else entries[dest + 1] = val; }
- public boolean hasKey(JS key) { return indexOf(key) >= 0; }
/*public boolean hasValue(JS key, JS value) {
int i = indexOf(key); return i >= 0 && entries[i + 1] != null; }
public boolean hasTrap(JS key, JS trap) {
if (t != null && (t = t.write()) != null) {
val = (JS)new Interpreter(t, val, false).run(null);
}
+ put(key, val); // HACK: necessary for subclasses overriding put()
+ /*if (i < 0) i = put(i, key);
if (val == null) entries[i + 1] = holder;
- else entries[i + 1] = val;
+ else entries[i + 1] = val;*/
return val;
}
public JS getAndTriggerTraps(JS key) throws JSExn {
Trap t = null; int i = indexOf(key);
- if (i < 0) return null;
+ if (i < 0) return get(key); // HACK: necessary for subclasses overriding get()
t = (Trap)entries[i + 2];
return t == null ? (JS)entries[i + 1] : (JS)new Interpreter(t, null, false).run(null);
}
return (JS)new Interpreter(t, val, true).run(null);
}
- /** returns a callback which will restart the context; expects a value to be pushed onto the stack when unpaused */
- public static UnpauseCallback pause() throws NotPauseableException {
- Interpreter i = Interpreter.current();
- if (i.pausecount == -1) throw new NotPauseableException();
- boolean get;
- switch(i.f.op[i.pc]) {
- case Tokens.RETURN: case ByteCodes.PUT: get = false; break;
- case ByteCodes.GET: case ByteCodes.CALL: get = true; break;
- default: throw new Error("should never happen");
+ public void addTrap(JS key, JS f) throws JSExn {
+ if (f.getFormalArgs() == null || f.getFormalArgs().length > 1) throw new JSExn(
+ "traps must take either one argument (write) or no arguments (read)");
+ int i = indexOf(key); if (i < 0) i = put(i, key);
+ for (Trap t = (Trap)entries[i + 2]; t != null; t = t.next())
+ if (t.function().equals(f)) return;
+ entries[i + 2] = new TrapHolder(this, key, f, (Trap)entries[i + 2]);
}
public void delTrap(JS key, JS f) throws JSExn {
}
public JS get(JS key) throws JSExn {
- //#switch(Script.str(key))
- case "hasNext": return Script.B(hasNext());
+ //#switch(JSU.str(key))
+ case "hasNext": return JSU.B(hasNext());
case "next": return next();
//#end
return super.get(key);