throw je("tried to assign \"" + (val==null?"(null)":val.toString()) + "\" to the null key");
Trap t = null;
- if (target instanceof Trap.TrapScope && key.equals("cascade")) {
- Trap.TrapScope ts = (Trap.TrapScope)target;
- t = ts.t.next;
- ts.cascadeHappened = true;
+ if (target instanceof JSScope && key.equals("cascade")) {
+ Trap.TrapScope ts = null;
+ JSScope p = (JSScope)target; // search the scope-path for the trap
+ if (target instanceof Trap.TrapScope) {
+ ts = (Trap.TrapScope)target;
+ }
+ else {
+ while (ts == null && p.getParentScope() != null) {
+ p = p.getParentScope();
+ if (p instanceof Trap.TrapScope) {
+ ts = (Trap.TrapScope)p;
+ }
+ }
+ }
+ t = ts.t.next;
+ ts.cascadeHappened = true;
while (t != null && t.f.numFormalArgs == 0) t = t.next;
if (t == null) { target = ts.t.trapee; key = ts.t.name; }
} else {
t = ((JS)target).getTrap(key);
}
-
while (t != null && t.f.numFormalArgs == 0) t = t.next; // find the first write trap
- if (t != null) {
- stack.push(new CallMarker(this));
- JSArray args = new JSArray();
- args.addElement(val);
- stack.push(args);
- }
}
if (t != null) {
+ stack.push(new CallMarker(this));
+ JSArray args = new JSArray();
+ args.addElement(val);
+ stack.push(args);
f = t.f;
scope = new Trap.TrapScope(f.parentScope, t, val);
pc = -1;
} else {
t = ((JS)o).getTrap(v);
}
-
while (t != null && t.f.numFormalArgs != 0) t = t.next; // get first read trap
- if (t != null) {
- stack.push(new CallMarker(this));
- JSArray args = new JSArray();
- stack.push(args);
- }
}
if (t != null) {
+ stack.push(new CallMarker(this));
+ JSArray args = new JSArray();
+ stack.push(args);
f = t.f;
scope = new Trap.TrapScope(f.parentScope, t, null);
((Trap.TrapScope)scope).cascadeHappened = true;
}
case THROW:
- throw new JSExn(stack.pop());
+ throw new JSExn(stack.pop(), stack, f, pc, scope);
+ /* FIXME
case MAKE_GRAMMAR: {
final Grammar r = (Grammar)arg;
final JSScope final_scope = scope;
stack.push(r2);
break;
}
-
+ */
case ADD_TRAP: case DEL_TRAP: {
Object val = stack.pop();
Object key = stack.pop();
Object obj = stack.peek();
// A trap addition/removal
- JS js = obj instanceof JSScope ? ((JSScope)obj).top() : (JS) obj;
+ JS js = (JS) obj;
+ if(js instanceof JSScope) {
+ JSScope s = (JSScope) js;
+ while(s.getParentScope() != null) {
+ if(s.has(key)) throw new JSExn("cannot trap a variable that isn't at the top level scope");
+ s = s.getParentScope();
+ }
+ js = s;
+ }
+ // might want this?
+ // if(!js.has(key)) throw new JSExn("tried to add/remove a trap from an uninitialized variable");
if(op == ADD_TRAP) js.addTrap(key, (JSFunction)val);
else js.delTrap(key, (JSFunction)val);
break;
if (right == null) right = JS.N(0);
int result = 0;
if (left instanceof String || right instanceof String) {
- result = left.toString().compareTo(right.toString());
+ result = JS.toString(left).compareTo(JS.toString(right));
} else {
result = (int)java.lang.Math.ceil(JS.toDouble(left) - JS.toDouble(right));
}
case EQ:
case NE: {
+ // FIXME: This is not correct, see ECMA-262 11.9.3
Object l = left;
Object r = right;
boolean ret;
else if (r == null) ret = false; // l != null, so its false
else if (l instanceof Boolean) ret = JS.B(JS.toBoolean(r)).equals(l);
else if (l instanceof Number) ret = JS.toNumber(r).doubleValue() == JS.toNumber(l).doubleValue();
- else if (l instanceof String) ret = r != null && l.equals(r.toString());
+ else if (l instanceof String) ret = r != null && l.equals(JS.toString(r));
else ret = l.equals(r);
stack.push(JS.B(op == EQ ? ret : !ret)); break;
}
}
} catch(JSExn e) {
- if(f.op[pc] != FINALLY_DONE) e.addBacktrace(f.sourceName,f.line[pc]);
while(stack.size() > 0) {
Object o = stack.pop();
if (o instanceof CatchMarker || o instanceof TryMarker) {
pc = ((TryMarker)o).finallyLoc - 1;
continue OUTER;
}
- } else if(o instanceof CallMarker) {
- CallMarker cm = (CallMarker) o;
- if(cm.f == null)
- e.addBacktrace("<java>",0); // This might not even be worth mentioning
- else
- e.addBacktrace(cm.f.sourceName,cm.f.line[cm.pc-1]);
}
}
throw e;
return sb.toString();
}
case "indexOf": {
- String search = alength >= 1 ? arg0.toString() : "null";
+ String search = alength >= 1 ? JS.toString(arg0) : "null";
int start = alength >= 2 ? JS.toInt(arg1) : 0;
// Java's indexOf handles an out of bounds start index, it'll return -1
return JS.N(s.indexOf(search,start));
}
case "lastIndexOf": {
- String search = alength >= 1 ? arg0.toString() : "null";
+ String search = alength >= 1 ? JS.toString(arg0) : "null";
int start = alength >= 2 ? JS.toInt(arg1) : 0;
// Java's indexOf handles an out of bounds start index, it'll return -1
return JS.N(s.lastIndexOf(search,start));
static Object getFromPrimitive(Object o, Object key) throws JSExn {
boolean returnJS = false;
if (o instanceof Boolean) {
- throw new JSExn("cannot call methods on Booleans");
+ throw new JSExn("Booleans do not have properties");
} else if (o instanceof Number) {
if (key.equals("toPrecision") || key.equals("toExponential") || key.equals("toFixed"))
returnJS = true;
}
if (!returnJS) {
// the string stuff applies to everything
- String s = o.toString();
+ String s = JS.toString(o);
// this is sort of ugly, but this list should never change
// These should provide a complete (enough) implementation of the ECMA-262 String object
case "lastIndexOf": returnJS = true; break;
case "match": returnJS = true; break;
case "replace": returnJS = true; break;
- case "seatch": returnJS = true; break;
+ case "search": returnJS = true; break;
case "slice": returnJS = true; break;
case "split": returnJS = true; break;
case "toLowerCase": returnJS = true; break;
}
if (returnJS) {
final Object target = o;
- final String method = key.toString();
+ final String method = JS.toString(o);
return new JS() {
public Object call(Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
if (nargs > 2) throw new JSExn("cannot call that method with that many arguments");