pausecount++;
switch(f.op[pc]) {
case Tokens.RETURN: case ByteCodes.PUT: get = false; break;
- case ByteCodes.GET: case ByteCodes.CALL: get = true; break;
+ case ByteCodes.GET: case ByteCodes.GET_PRESERVE: case ByteCodes.CALLMETHOD: case ByteCodes.CALL: get = true; break;
default: throw new Error("paused on unexpected bytecode: " + f.op[pc]);
}
}
case BREAK:
case CONTINUE:
while(!stack.empty()) {
- JS o = (JS)stack.pop();
+ Object o = stack.pop();
if (o instanceof CallMarker) je("break or continue not within a loop");
if (o instanceof TryMarker) {
if(((TryMarker)o).finallyLoc < 0) continue; // no finally block, keep going
TrapMarker tm = (TrapMarker) o;
JS key = tm.t.key();
JS target = tm.t.target();
- if(tm.t.isWriteTrap() != write) throw new JSExn("tried to do a " + (write?"write":"read") + " cascade in a " + (write?"read":"write") + " trap");
+ if(tm.t.isWriteTrap() != write)
+ throw new JSExn("tried to do a "+(write?"write":"read") + " cascade in a " + (write?"read":"write") + " trap");
JS.Trap t = write ? tm.t.nextWrite() : tm.t.nextRead();
- // FIXME: Doesn't handle multiple levels of clone's (probably can just make this a while loop)
- if(t == null && target instanceof JS.Clone) {
+ while (t == null && target instanceof JS.Clone) {
target = ((JS.Clone)target).clonee;
t = target.getTrap(key);
if(t != null) t = write ? t.write() : t.read();
}
case CALL: case CALLMETHOD: {
- // FIXME: can a lot of simple cases in Parser be
- // reduced so creating a new JS[] is not necessary?
JS[] jsargs;
if (arg instanceof JSNumber.I) {
+ // FIXME: we should be able to recycle JS[]'s here
jsargs = new JS[((JSNumber.I)arg).toInt()];
for (int i=0; i < jsargs.length; i++) jsargs[i] = (JS)stack.pop();
} else jsargs = (JS[])arg;
if (object instanceof JSFunction) {
stack.push(new CallMarker(this));
- stack.push(jsargs);
f = (JSFunction)object;
+ stack.push(new JSArgs(jsargs, f));
scope = f.parentScope;
pc = -1;
break;
} else {
JS c = (JS)object;
- ret = method == null ? c.call(jsargs) : c.call(method, jsargs);
+ ret = c.call(method, jsargs);
}
if (pausecount > initialPauseCount) { pc++; return null; }
case THROW:
throw new JSExn((JS)stack.pop(), this);
- /* FIXME GRAMMAR
- case MAKE_GRAMMAR: {
- final Grammar r = (Grammar)arg;
- final JSScope final_scope = scope;
- Grammar r2 = new Grammar() {
- public int match(String s, int start, Map v, JSScope scope) throws JSExn {
- return r.match(s, start, v, final_scope);
- }
- public int matchAndWrite(String s, int start, Map v, JSScope scope, String key) throws JSExn {
- return r.matchAndWrite(s, start, v, final_scope, key);
- }
- public Object call(Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
- Map v = new Map();
- r.matchAndWrite((String)a0, 0, v, final_scope, "foo");
- return v.get("foo");
- }
- };
- Object obj = stack.pop();
- if (obj != null && obj instanceof Grammar) r2 = new Grammar.Alternative((Grammar)obj, r2);
- stack.push(r2);
- break;
- }
- */
case ADD_TRAP: case DEL_TRAP: {
JS val = (JS)stack.pop();
JS key = (JS)stack.pop();
JS js = (JS)stack.peek();
// A trap addition/removal
- if(!(val instanceof JSFunction)) throw new JSExn("tried to add/remove a non-function trap"); // FIXME
+ if(!(val instanceof JSFunction)) throw new JSExn("tried to add/remove a non-function trap");
if(op == ADD_TRAP) js.addTrap(key, val);
else js.delTrap(key, val);
break;
case RSH: stack.push(JSU.N(JSU.toLong(left) >> JSU.toLong(right))); break;
case URSH: stack.push(JSU.N(JSU.toLong(left) >>> JSU.toLong(right))); break;
- //#repeat </<=/>/>= LT/LE/GT/GE
- case LT: {
+ case LT: case LE: case GT: case GE: {
+ int cmp = 0;
if(left instanceof JSString && right instanceof JSString)
- stack.push(JSU.B(JSU.toString(left).compareTo(JSU.toString(right)) < 0));
+ cmp = JSU.toString(left).compareTo(JSU.toString(right));
else
- stack.push(JSU.B(JSU.toDouble(left) < JSU.toDouble(right)));
+ cmp = (int)(100 * (JSU.toDouble(left) - JSU.toDouble(right)));
+ switch(op) {
+ case LE: stack.push(JSU.B(cmp <= 0)); break;
+ case LT: stack.push(JSU.B(cmp < 0)); break;
+ case GE: stack.push(JSU.B(cmp >= 0)); break;
+ case GT: stack.push(JSU.B(cmp > 0)); break;
+ default: throw new RuntimeException("impossible");
+ }
+ break;
}
- //#end
case EQ:
case NE: {
void setupTrap(JS.Trap t, JS val, CallMarker cm) throws JSExn {
stack.push(cm);
stack.push(new TrapArgs(t, val));
- f = (JSFunction)t.function(); // FIXME
+ f = (JSFunction)t.function();
scope = f.parentScope;
pc = 0;
}
public JSArgs(JS[] args, JS callee) { this.args = args; this.callee = callee; }
public JS get(JS key) throws JSExn {
- if(JSU.isInt(key)) return args[JSU.toInt(key)];
+ if(JSU.isInt(key)) {
+ int i = JSU.toInt(key);
+ return i>=args.length ? null : args[i];
+ }
//#switch(JSU.toString(key))
case "callee": return callee;
case "length": return JSU.N(args.length);
private JS method;
JS obj;
public Stub(JS obj, JS method) { this.obj = obj; this.method = method; }
- public JS call(JS[] args) throws JSExn { return obj.call(method, args); }
+ public JS call(JS method, JS[] args) throws JSExn {
+ if (method==null) return obj.call(this.method, args);
+ return super.call(method, args);
+ }
}
static final class Stack {