X-Git-Url: http://git.megacz.com/?p=org.ibex.js.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fjs%2FJS.java;h=a7270482ea2ed6e323f2abf7ab18ae9d48dc23c2;hp=0a3843c0e662a123ad080de7593306465335012b;hb=aaf060ff38871512d80f1bbf04a6596648b284c7;hpb=2d38cf96f2ac17fe1961aadb8bf4f02e5a1b5294 diff --git a/src/org/ibex/js/JS.java b/src/org/ibex/js/JS.java index 0a3843c..a727048 100644 --- a/src/org/ibex/js/JS.java +++ b/src/org/ibex/js/JS.java @@ -41,9 +41,6 @@ public interface JS extends Pausable { * 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. * @@ -92,20 +89,19 @@ public interface JS extends Pausable { 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( @@ -149,8 +145,6 @@ public interface JS extends Pausable { 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 { @@ -165,21 +159,21 @@ public interface JS extends Pausable { public String coerceToString() { return clonee.coerceToString(); } } - public static class Obj extends LinearStore implements JS { + public static class Obj extends Basket.Hash implements JS { 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( @@ -192,13 +186,24 @@ public interface JS extends Pausable { 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 { - // FEATURE: replicate some code from a superclass to avoid double object creation - return new Enumeration.JavaIterator(null, new LinearStore.IndexIterator() { - public Object next() { return entries[nextIndex()]; } }); + return new Enumeration(null) { + private int dest = -1, next = -1; + public boolean _hasNext() { + for (int i = Math.max(0, dest); i < usedslots; i++) + if (i > 0 ? entries[i * indexmultiple] != null : true && + entries[i * indexmultiple] != this) { next = i; return true; } + return false; + } + public JS _next() throws JSExn { + if (next < 0 && !hasNext()) throw new NoSuchElementException(); + int index = next; dest = next; next = -1; + return (JS)entries[index * indexmultiple]; + } + }; } public JS get(JS key) throws JSExn { int i = indexOf(key); return i < 0 ? null : entries[i + 1] instanceof Placeholder ? null : (JS)entries[i + 1]; } @@ -208,7 +213,6 @@ public interface JS extends Pausable { 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) { @@ -223,13 +227,15 @@ public interface JS extends Pausable { 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); } @@ -240,15 +246,13 @@ public interface JS extends Pausable { 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 { @@ -329,8 +333,8 @@ public interface JS extends Pausable { } 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);