// Parsing Logic /////////////////////////////////////////////////////////
public void consume(int code) throws IOException {
- int got = getToken();
- if (got != code) throw new ParserException("expected " + codeToString[code] + ", got " + (got == -1 ? "EOL" : codeToString[got]));
- }
- public void consume(int code, int code2) throws IOException {
- int got = getToken();
- if (got != code && got != code2)
- throw new ParserException("expected " + codeToString[code] + " or " + codeToString[code2] +
- ", got " + (got == -1 ? "EOL" : codeToString[got]));
- }
- public void expect(int code) throws IOException {
- int got = peekToken();
- if (got != code) throw new ParserException("expected " + codeToString[code] + ", got " + (got == -1 ? "EOL" : codeToString[got]));
+ if (getToken() != code)
+ throw new ParserException("expected " + codeToString[op] + ", got " + (op == -1 ? "EOL" : codeToString[op]));
}
/** parses the largest possible expression */
}
}
- // end //
-
case LC: {
if (prefix != null) { pushBackToken(); return prefix; }
ByteCode b = new ByteCode(curLine);
b.add(b.OBJECT, null);
if (peekToken() == RC) { consume(RC); return b; }
while(true) {
- consume(NAME, STRING);
+ if (peekToken() != NAME && peekToken() != STRING) throw new Error("expected NAME or STRING");
+ getToken();
b.add(b.LITERAL, string);
consume(COLON);
b.add(b.EXPR, parseMaximalExpr());
return new ByteCode(curLine, b.FUNCTION, b);
}
- // Needs break //
+ case WHILE: {
+ if (prefix != null) { pushBackToken(); return prefix; }
+ consume(LP);
+ ByteCode r = new ByteCode(curLine);
+ ByteCode loop = new ByteCode(curLine);
+ r.add(loop.LOOP, loop);
+ r.add(r.LITERAL, null);
+
+ loop.add(loop.EXPR, parseMaximalExpr());
+ loop.add(loop.JT, new Integer(2));
+ loop.add(Lexer.BREAK, NO_ARG);
+ consume(RP);
+ parseBlock(false, loop);
+
+ // if we fall out of the end, definately continue
+ loop.add(CONTINUE, NO_ARG);
+ return r;
+ }
case SWITCH: {
if (prefix != null) { pushBackToken(); return prefix; }
consume(LP);
- Expr switchExpr = parseMaximalExpr();
+ ByteCode r = new ByteCode(curLine);
+ ByteCode loop = new ByteCode(curLine);
+ r.add(loop.LOOP, loop);
+ r.add(r.LITERAL, null);
+ loop.add(loop.EXPR, parseMaximalExpr());
consume(RP);
consume(LC);
- ExprList toplevel = new ExprList(curLine, LC);
while(true) {
- tok = getToken();
Expr caseExpr;
- if (tok == DEFAULT) caseExpr = null;
- else if (tok == CASE) caseExpr = parseMaximalExpr();
- else throw new ParserException("expected CASE or DEFAULT");
+ tok = getToken();
+ if (tok == CASE) {
+ loop.add(loop.DUP, NO_ARG);
+ loop.add(loop.EXPR, parseMaximalExpr());
+ loop.add(EQ, NO_ARG);
+ loop.add(loop.JF, new Integer(2));
+ } else if (tok != DEFAULT) throw new ParserException("expected CASE or DEFAULT");
consume(COLON);
- // FIXME: we shouldn't be creating a scope here
- ExprList list = new ExprList(curLine, LC);
+ ByteCode b = new ByteCode(curLine);
while(peekToken() != CASE && peekToken() != DEFAULT && peekToken() != RC) {
if ((e1 = parseBlock(false)) == null) break;
- list.add(e1);
+ b.add(b.EXPR, e1);
+ }
+ loop.add(loop.EXPR, b);
+ if (peekToken() == RC) {
+ consume(RC);
+ r.add(BREAK, NO_ARG);
+ return r;
}
- toplevel.add(new Expr(curLine, tok, caseExpr, list));
- if (peekToken() == RC) { consume(RC); return new Expr(curLine, SWITCH, switchExpr, toplevel); }
}
}
- case TRY: {
- // We deliberately allow you to omit braces in catch{}/finally{} if they are single statements...
+ case DO: {
if (prefix != null) { pushBackToken(); return prefix; }
- Expr tryBlock = parseBlock(true);
-
- tok = peekToken();
- ExprList list = new ExprList(curLine, TRY);
- if (tok == CATCH) {
- getToken();
- if (getToken() != LP) throw new ParserException("expected (");
- if (getToken() != NAME) throw new ParserException("expected name");
- Expr name = new Expr(curLine, NAME, string);
- if (getToken() != RP) throw new ParserException("expected )");
- list.add(new Expr(curLine, CATCH, name, parseBlock(false)));
- tok = peekToken();
- }
- if (tok == FINALLY) {
- getToken();
- list.add(new Expr(curLine, FINALLY, parseBlock(false)));
- }
-
- if (list.size() == 0) throw new ParserException("try without catch or finally");
- return new Expr(curLine, TRY, tryBlock, list);
- }
+ ByteCode r = new ByteCode(curLine);
+ ByteCode loop = new ByteCode(curLine);
+ r.add(loop.LOOP, loop);
+ r.add(r.LITERAL, null);
- case WHILE: {
- if (prefix != null) { pushBackToken(); return prefix; }
+ parseBlock(false, loop);
+ consume(WHILE);
consume(LP);
- Expr parenExpr = parseMaximalExpr();
- int t;
- if ((t = getToken()) != RP)
- throw new ParserException("expected right paren, but got " + codeToString[t]);
- Expr firstBlock = parseBlock(false);
- ExprList list = new ExprList(curLine, WHILE);
- list.add(parenExpr);
- list.add(firstBlock);
- list.add(new Expr(curLine, NULL));
- return list;
+ loop.add(loop.EXPR, parseMaximalExpr());
+ loop.add(loop.JT, new Integer(2));
+ loop.add(Lexer.BREAK, NO_ARG);
+ loop.add(Lexer.CONTINUE, NO_ARG);
+ consume(RP);
+ consume(SEMI);
+ return r;
}
+ // Needs break //
+
case FOR:
if (prefix != null) { pushBackToken(); return prefix; }
if (getToken() != LP) throw new ParserException("expected left paren");
} else {
Expr initExpr = e1;
if (initExpr == null) initExpr = new Expr(curLine, NULL);
- expect(SEMI); getToken();
+ consume(SEMI);
Expr whileExpr = parseMaximalExpr();
- expect(SEMI); getToken();
+ consume(SEMI);
Expr incExpr = parseMaximalExpr();
- expect(RP); getToken();
+ consume(RP);
Expr body = parseBlock(false);
Expr loop = new Expr(curLine, WHILE, whileExpr, body);
ExprList list = new ExprList(curLine, LC);
return list;
}
- case DO: {
+ case TRY: {
+ // We deliberately allow you to omit braces in catch{}/finally{} if they are single statements...
if (prefix != null) { pushBackToken(); return prefix; }
- ExprList list = new ExprList(curLine, DO);
- Expr body = parseBlock(false);
- consume(WHILE);
- consume(LP);
- list.add(parseMaximalExpr());
- list.add(body);
- list.add(new Expr(curLine, NULL));
- consume(RP);
- consume(SEMI);
- return list;
- }
+ Expr tryBlock = parseBlock(true);
+ tok = peekToken();
+ ExprList list = new ExprList(curLine, TRY);
+ if (tok == CATCH) {
+ getToken();
+ if (getToken() != LP) throw new ParserException("expected (");
+ if (getToken() != NAME) throw new ParserException("expected name");
+ Expr name = new Expr(curLine, NAME, string);
+ if (getToken() != RP) throw new ParserException("expected )");
+ list.add(new Expr(curLine, CATCH, name, parseBlock(false)));
+ tok = peekToken();
+ }
+ if (tok == FINALLY) {
+ getToken();
+ list.add(new Expr(curLine, FINALLY, parseBlock(false)));
+ }
+
+ if (list.size() == 0) throw new ParserException("try without catch or finally");
+ return new Expr(curLine, TRY, tryBlock, list);
+ }
+
default:
pushBackToken();
return prefix;
public static final byte EXPR = -20; // -- transitional
public static final byte SWAP = -23; // -- transitional
public static final byte SCOPE = -30; // -- transitional
+ public static final byte LOOP = -40; // -- transitional
+ public static final byte DUP = -50; // -- transitional
int[] op = new int[10];
Object[] arg = new Object[10];
case JMP: i += toNumber(arg[i]).intValue() - 1; break;
case POP: t.pop(); break;
case SWAP: t.swap(); break;
+ case DUP: t.push(t.peek()); break;
+ case Lexer.BREAK: {
+ // FIXME: make sure this can only appear in proper places
+ return Boolean.FALSE;
+ }
+ case Lexer.CONTINUE: {
+ // FIXME: make sure this can only appear in proper places
+ return Boolean.TRUE;
+ }
+ case LOOP: {
+ ByteCode loop = (ByteCode)arg[i];
+ Parser.Thread t2 = new Parser.Thread();
+ t2.push(Boolean.TRUE);
+ while (true) {
+ Boolean result;
+ try {
+ result = (Boolean)loop.eval(new JS.Scope(s), t2);
+ } catch (ContinueException c) {
+ result = Boolean.TRUE;
+ } catch (BreakException b) {
+ result = Boolean.FALSE;
+ }
+ if (result == Boolean.FALSE) break;
+ t2 = new Parser.Thread();
+ t2.push(Boolean.FALSE);
+ }
+ break;
+ }
+
case PUT: {
Object val = arg[i] == NO_ARG ? t.pop() : arg[i];
Object key = t.pop();
class Thread {
public Object[] os = new Object[256];
- int size = 0;
- public void push(Object o) { os[size++] = o; }
- public Object pop() { return os[--size]; }
+ private int size = 0;
+ public void push(Object o) {
+ os[size++] = o;
+ }
+ public Object pop() {
+ return os[--size];
+ }
public Object peek() { return os[size - 1]; }
public void swap() { Object temp = os[size - 1]; os[size - 1] = os[size - 2]; os[size - 2] = temp; }
public int size() { return size; }