return this;
}
- public Object eval(final JS.Scope s) throws ControlTransferException, JS.Exn { return eval(s, new Vec()); }
public Object eval(final JS.Scope s, Vec t) throws ControlTransferException {
for(int i=0; i<size; i++) switch(op[i]) {
case LABEL: break;
case POP: t.pop(); break;
case SWAP: { Object o1 = t.pop(); Object o2 = t.pop(); t.push(o1); t.push(o2); break; }
case DUP: t.push(t.peek()); break;
- case SCOPE: t.push(((ByteCodeBlock)arg[i]).eval(new JS.Scope(s))); break;
+
+ // FIXME: shouldn't need its own stack
+ case SCOPE: t.push(((ByteCodeBlock)arg[i]).eval(new JS.Scope(s), new Vec())); break;
+
case ASSERT: if (!JS.toBoolean(t.pop())) throw new EvaluatorException(line, sourceName, "assertion failed"); break;
case RETURN: throw new ReturnException(t.pop());
case THROW: throw new JS.Exn(t.pop());
case TRY: break;
+
+ // FIXME: implement
case TYPEOF: break;
+
case BREAK: return Boolean.FALSE;
case CONTINUE: return Boolean.TRUE;
case BITNOT: t.push(new Long(~JS.toLong(t.pop()))); break;
case BANG: t.push(new Boolean(!JS.toBoolean(t.pop()))); break;
+ case NEWFUNCTION: {
+ ByteCodeBlock bytes = (ByteCodeBlock)arg[i];
+ t.push(new JS.Function(bytes.line, bytes.sourceName, bytes, s));
+ break;
+ }
+
case PUSHKEYS: {
Object o = t.peek();
Object[] keys = ((JS)o).keys();
stack2.push(Boolean.TRUE);
while (true) {
Boolean result;
- try { result = (Boolean)loop.eval(new JS.Scope(s), stack2);
+ try { result = (Boolean)loop.eval(new JS.Scope(s), stack2);
} catch (ContinueException c) { result = Boolean.TRUE;
} catch (BreakException b) { result = Boolean.FALSE; }
if (result == Boolean.FALSE) break;
Object val = t.pop();
Object key = t.pop();
JS target = (JS)t.peek();
- if (target == null) throw new JS.Exn("tried to put a value to the " + key + " property on the null value");
+ if (target == null)
+ throw new EvaluatorException(line, sourceName, "tried to put a value to the " + key + " property on the null value");
target.put(key, val);
t.push(val);
break;
break;
}
- case NEWFUNCTION: {
- final ByteCodeBlock myBytes = (ByteCodeBlock)arg[i];
- t.push(new JS.Function() {
- public String getSourceName() throws JS.Exn { return sourceName; }
- public int getLine() throws JS.Exn { return line; }
- public Object _call(final JS.Array args) throws JS.Exn, ControlTransferException {
- JS.Scope scope = new JS.Scope(s) {
- public String getSourceName() { return sourceName; }
- public Object get(Object key) throws JS.Exn {
- if (key.equals("trapee")) return org.xwt.Trap.currentTrapee();
- else if (key.equals("cascade")) return org.xwt.Trap.cascadeFunction;
- return super.get(key);
- }
- };
- Vec stack = new Vec();
- stack.push(args);
- return myBytes.eval(scope, stack);
- }
- });
- break;
- }
-
case INC: case DEC: {
boolean isPrefix = JS.toBoolean(arg[i]);
Object key = t.pop();
}
/** Anything that is callable */
- public static abstract class Function extends Obj {
- public String getSourceName() throws JS.Exn { return "unknown"; }
- public int getLine() throws JS.Exn { return -1; }
- public abstract Object _call(JS.Array args) throws JS.Exn, ByteCodeBlock.ControlTransferException;
+ public static class Function extends Obj {
+ ByteCodeBlock bytecodes;
+ int line;
+ String sourceName;
+ Scope parentScope;
+ public Function() { this(-1, "unknown", null, null); }
+ public Function(int line, String sourceName, ByteCodeBlock bytecodes, Scope parentScope) {
+ this.sourceName = sourceName;
+ this.line = line;
+ this.bytecodes = bytecodes;
+ this.parentScope = parentScope;
+ }
+ public String getSourceName() throws JS.Exn { return sourceName; }
+ public int getLine() throws JS.Exn { return line; }
+ public Object _call(JS.Array args) throws JS.Exn, ByteCodeBlock.ControlTransferException {
+ if (bytecodes == null) throw new Error("tried to call() a JS.Function with bytecodes == null");
+ Vec stack = new Vec();
+ stack.push(args);
+ return bytecodes.eval(new FunctionScope(sourceName, parentScope), stack);
+ }
public final Object call(JS.Array args) throws JS.Exn {
Function saved = (Function)currentFunction.get(Thread.currentThread());
currentFunction.put(Thread.currentThread(), this);
public String getSourceName() throws JS.Exn { return ((ByteCodeBlock)e.elementAt(0)).getSourceName(); }
public Object _call(JS.Array args) throws JS.Exn, ByteCodeBlock.ControlTransferException {
Scope rootScope = (Scope)args.elementAt(0);
- for(int i=0; i<e.size(); i++) ((ByteCodeBlock)e.elementAt(i)).eval(rootScope);
+ for(int i=0; i<e.size(); i++) ((ByteCodeBlock)e.elementAt(i)).eval(rootScope, new Vec());
return null;
}
public static Script parse(Reader r, String sourceName, int line) throws IOException {
}
}
-
+ private class FunctionScope extends JS.Scope {
+ String sourceName;
+ public FunctionScope(String sourceName, Scope parentScope) { super(parentScope); this.sourceName = sourceName; }
+ public String getSourceName() { return sourceName; }
+ public Object get(Object key) throws JS.Exn {
+ if (key.equals("trapee")) return org.xwt.Trap.currentTrapee();
+ else if (key.equals("cascade")) return org.xwt.Trap.cascadeFunction;
+ return super.get(key);
+ }
+ }
}
}
class LexerException extends IOException {
- public LexerException(String s) { super(sourceName + ":" + line + "," + col + " " + s); }
+ public LexerException(String s) { super(sourceName + ":" + line + "," + col + ": " + s); }
}
}
/** gets a token and throws an exception if it is not <tt>code</tt> */
public void consume(int code) throws IOException {
if (getToken() != code)
- throw new ParserException("expected " + codeToString[code] + ", got " + (op == -1 ? "EOL" : codeToString[op]));
+ throw new ParserException("expected " + codeToString[code] + ", got " + (op == -1 ? "EOF" : codeToString[op]));
}
/** append the largest expression beginning with prefix containing no operators of precedence below <tt>minPrecedence</tt> */
// Token Constants //////////////////////////////////////////////////////////
- public static final int EOL = -1; // end of line
-
// arithmetic operations; also valid as bytecodes
public static final int BITOR = 0; // |
public static final int ASSIGN_BITOR = 1; // |=