X-Git-Url: http://git.megacz.com/?p=org.ibex.core.git;a=blobdiff_plain;f=src%2Forg%2Fxwt%2Fjs%2FParser.java;h=b7456fef3781acb6686e9fb5eb8b77b68b324d65;hp=ba343cf65a38fb23bbf35a5334ea43a06e10e4b2;hb=4c0fde245156c0b57d95934b9b1a2ec0fd1aa849;hpb=b3a4877fe48d36d1eb82b3fa33f2b3a1d5be718c
diff --git a/src/org/xwt/js/Parser.java b/src/org/xwt/js/Parser.java
index ba343cf..b7456fe 100644
--- a/src/org/xwt/js/Parser.java
+++ b/src/org/xwt/js/Parser.java
@@ -16,6 +16,7 @@ public class Parser extends Lexer {
this.line = line;
}
+ /** for debugging */
public static void main(String[] s) throws Exception {
Parser p = new Parser(new InputStreamReader(System.in), "stdin", 0);
while(true) {
@@ -57,94 +58,13 @@ public class Parser extends Lexer {
// Parsing Logic /////////////////////////////////////////////////////////
- /** a block is either a single statement or a list of statements surrounded by curly braces; all expressions are also statements */
- public Expr parseBlock(boolean requireBraces) throws IOException {
- Expr ret = null;
- int tok = peekToken();
- if (tok == -1) return null;
- boolean braced = tok == LC;
- if (requireBraces && !braced) throw new ParserException("expected {");
- if (braced) getToken();
- Expr head = null;
- Expr tail = null;
- int curLine = line;
- OUTER: while(true) {
- Expr smt;
-
- switch(tok = peekToken()) {
- case -1: break OUTER;
- case LC: smt = parseBlock(true); break;
- case THROW: case RETURN: case ASSERT:
- getToken();
- if (peekToken() == SEMI) {
- getToken();
- smt = new Expr(curLine, tok);
- break;
- }
- smt = new Expr(curLine, tok, parseMaximalExpr());
- if (getToken() != SEMI) throw new ParserException("expected ;");
- break;
-
- /*
- FIXME
- case NAME: {
- getToken();
- String str = string;
- if (getToken() != COLON) throw new ParserException("expected COLON after label");
- Expr labeledBlock = parseBlock(false);
- if (labeledBlock.code != WHILE && labeledBlock.code != FOR && labeledBlock.code != SWITCH)
- throw new ParserException("you can only label a WHILE, FOR, or SWITCH block");
- labeledBlock.string = str;
- return labeledBlock;
- }
- */
-
- case GOTO: case BREAK: case CONTINUE: {
- getToken();
- int t = peekToken();
- if (t == NAME) {
- getToken();
- smt = new Expr(curLine, tok, new Expr(curLine, string));
- } else if (t == GOTO) {
- throw new ParserException("goto must be followed by a label");
- } else if (t == SEMI) {
- getToken();
- smt = new Expr(curLine, tok);
- } else {
- throw new ParserException(codeToString[tok] + " followed by a " + codeToString[t] + "; expected NAME or SEMI");
- }
- break;
- }
-
- case RC:
- if (braced) getToken();
- break OUTER;
-
- case SEMI:
- getToken();
- if (!braced) break OUTER;
- continue;
-
- default:
- smt = parseMaximalExpr();
- if (smt == null) {
- if (head == null) return null;
- break OUTER;
- }
- if (peekToken() == SEMI) getToken();
- break;
- }
- if (!braced) return smt;
- if (head == null) head = tail = smt; else tail = (tail.next = smt);
- }
- return new Expr(curLine, LC, head);
+ 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]));
}
-
- /** throws an error if the next token is not code */
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 (got != code) throw new ParserException("expected " + codeToString[code] + ", got " + (got == -1 ? "EOL" : codeToString[got]));
}
/** parses the largest possible expression */
@@ -238,54 +158,56 @@ public class Parser extends Lexer {
return r;
} else { // invocation
+ ExprList list = new ExprList(curLine, LP);
while(peekToken() != RP) {
- Expr e = parseMaximalExpr();
- if (head == null) head = tail = e; else tail = tail.next = e;
- tok = getToken();
- if (tok == RP) { pushBackToken(); break; }
- if (tok != COMMA) throw new ParserException("expected comma or right paren, got " + codeToString[tok]);
+ list.add(parseMaximalExpr());
+ if (peekToken() == RP) break;
+ consume(COMMA);
}
getToken();
- return new Expr(curLine, LP, prefix, head);
+ return new Expr(curLine, LP, prefix, list);
}
case LB:
- if (prefix != null) {
- // subscripting
- e1 = parseMaximalExpr();
- if (getToken() != RB) throw new ParserException("expected a right brace");
- return new Expr(curLine, DOT, prefix, e1);
- } else {
+ if (prefix == null) {
// array ctor
+ ExprList list = new ExprList(curLine, LB);
while(true) {
- if (peekToken() == RB) { getToken(); return new Expr(curLine, LB, prefix, head); }
- Expr eee = parseMaximalExpr();
- if (eee != null) {
- if (head == null) head = tail = eee;
- else tail.next = tail = eee;
+ Expr e = parseMaximalExpr();
+ if (e != null) {
+ list.add(e);
+ } else {
+ if (peekToken() == COMMA) list.add(new Expr(curLine, NULL));
}
- tok = getToken();
- if (tok == RB) return new Expr(curLine, LB, prefix, head);
- if (tok != COMMA) throw new ParserException("expected right bracket or comma");
+ if (peekToken() == RB) { consume(RB); return list; }
+ consume(COMMA);
}
+ } else {
+ // subscripting
+ e1 = parseMaximalExpr();
+ if (getToken() != RB) throw new ParserException("expected a right brace");
+ return new Expr(curLine, DOT, prefix, e1);
}
- case LC:
+ case LC: {
+ // object ctor
if (prefix != null) { pushBackToken(); return prefix; }
tok = getToken();
- if (tok == RC) return new Expr(curLine, RC, head);
+ ExprList list = new ExprList(curLine, RC);
+ if (tok == RC) return list;
while(true) {
if (tok != NAME && tok != STRING) throw new ParserException("expecting name, got " + codeToString[tok]);
Expr name = new Expr(curLine, NAME, string);
if (getToken() != COLON) throw new ParserException("expecting colon");
e1 = new Expr(curLine, COLON, name, parseMaximalExpr());
- if (head == null) head = tail = e1; else tail = tail.next = e1;
+ list.add(e1);
tok = getToken();
if (tok != COMMA && tok != RC) throw new ParserException("expected right curly or comma, got " + codeToString[tok]);
- if (tok == RC) return new Expr(curLine, RC, head);
+ if (tok == RC) return list;
tok = getToken();
- if (tok == RC) return new Expr(curLine, RC, head);
+ if (tok == RC) return list;
}
+ }
case HOOK:
e2 = parseMaximalExpr();
@@ -299,52 +221,48 @@ public class Parser extends Lexer {
Expr switchExpr = parseMaximalExpr();
if (getToken() != RP) throw new ParserException("expected left paren");
if (getToken() != LC) throw new ParserException("expected left brace");
- Expr firstExpr = null;
- Expr lastExpr = null;
+ ExprList toplevel = new ExprList(curLine, LC);
while(true) {
tok = getToken();
Expr caseExpr;
- if (tok == DEFAULT) {
- caseExpr = null;
- } else if (tok == CASE) {
- // FIXME: we don't support non-brace-enclosed CASE blocks
- caseExpr = parseMaximalExpr();
- } else {
- throw new ParserException("expected CASE");
- }
- expect(COLON); getToken();
- head = tail = null;
+ if (tok == DEFAULT) caseExpr = null;
+ else if (tok == CASE) caseExpr = parseMaximalExpr();
+ else throw new ParserException("expected CASE or DEFAULT");
+ consume(COLON);
+ // FIXME: we shouldn't be creating a scope here
+ ExprList list = new ExprList(curLine, LC);
while(peekToken() != CASE && peekToken() != DEFAULT && peekToken() != RC) {
- e1 = parseBlock(false);
- if (e1 == null) break;
- if (head == null) head = tail = e1; else tail = tail.next = e1;
+ if ((e1 = parseBlock(false)) == null) break;
+ list.add(e1);
}
- e1 = new Expr(curLine, tok, caseExpr, new Expr(curLine, LC, head));
- if (lastExpr == null) firstExpr = e1; else lastExpr.next = e1;
- lastExpr = e1;
- if (peekToken() == RC) {getToken(); return new Expr(curLine, SWITCH, switchExpr, firstExpr); }
+ toplevel.add(new Expr(curLine, tok, caseExpr, list));
+ if (peekToken() == RC) { consume(RC); return new Expr(curLine, SWITCH, switchExpr, toplevel); }
}
}
case FUNCTION: {
if (prefix != null) { pushBackToken(); return prefix; }
- if (getToken() != LP) throw new ParserException("function keyword must be followed by a left paren");
- Expr formalArgs = null, cur = null;
- tok = getToken();
- while(tok != RP) {
- if (tok != NAME) throw new ParserException("expected a variable name");
- if (cur == null) { formalArgs = cur = new Expr(curLine, string); }
- else { cur.next = new Expr(curLine, NAME, string); cur = cur.next; }
- tok = getToken();
- if (tok == RP) break;
- if (tok != COMMA) throw new ParserException("function argument list must consist of alternating NAMEs and COMMAs");
- tok = getToken();
+ consume(LP);
+ ExprList list = new ExprList(curLine, LC);
+ if (peekToken() == RP) consume(RP);
+ else while(true) {
+ tok = peekToken();
+ if (tok == COMMA) {
+ consume(COMMA);
+ list.add(new Expr(curLine, NULL));
+ } else {
+ consume(NAME);
+ list.add(new Expr(curLine, NAME, string));
+ if (peekToken() == RP) { consume(RP); break; }
+ consume(COMMA);
+ }
}
- return new Expr(curLine, FUNCTION, formalArgs, parseBlock(true));
+ return new Expr(curLine, FUNCTION, list, parseBlock(true));
}
- case VAR:
+ case VAR: {
if (prefix != null) { pushBackToken(); return prefix; }
+ ExprList list = new ExprList(curLine, VAR);
while(true) {
if (getToken() != NAME) throw new ParserException("variable declarations must start with a variable name");
String name = string;
@@ -363,11 +281,12 @@ public class Parser extends Lexer {
} else {
e = new Expr(curLine, VAR, new Expr(curLine, name));
}
- if (head == null) head = tail = e; else tail = tail.next = e;
+ list.add(e);
if (tok != COMMA) break;
getToken();
}
- return new Expr(curLine, VAR, head);
+ return list;
+ }
case TRY: {
// We deliberately allow you to omit braces in catch{}/finally{} if they are single statements...
@@ -375,23 +294,23 @@ public class Parser extends Lexer {
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 )");
- head = tail = new Expr(curLine, CATCH, name, parseBlock(false));
+ list.add(new Expr(curLine, CATCH, name, parseBlock(false)));
tok = peekToken();
}
if (tok == FINALLY) {
getToken();
- e1 = new Expr(curLine, FINALLY, parseBlock(false));
- if (head == null) head = tail = e1; else tail = tail.next = e1;
+ list.add(new Expr(curLine, FINALLY, parseBlock(false)));
}
- if (head == null) throw new ParserException("try without catch or finally");
- return new Expr(curLine, TRY, tryBlock, head);
+ if (list.size() == 0) throw new ParserException("try without catch or finally");
+ return new Expr(curLine, TRY, tryBlock, list);
}
case IF: case WHILE: {
@@ -405,7 +324,14 @@ public class Parser extends Lexer {
getToken();
return new Expr(curLine, tok, parenExpr, new Expr(curLine, ELSE, firstBlock, parseBlock(false)));
} else {
- return new Expr(curLine, tok, parenExpr, firstBlock);
+ if (tok == IF) return new Expr(curLine, tok, parenExpr, firstBlock);
+ if (tok == WHILE) {
+ ExprList list = new ExprList(curLine, WHILE);
+ list.add(parenExpr);
+ list.add(firstBlock);
+ list.add(new Expr(curLine, NULL));
+ return list;
+ }
}
}
@@ -423,27 +349,36 @@ public class Parser extends Lexer {
} else {
Expr initExpr = e1;
+ if (initExpr == null) initExpr = new Expr(curLine, NULL);
expect(SEMI); getToken();
Expr whileExpr = parseMaximalExpr();
expect(SEMI); getToken();
Expr incExpr = parseMaximalExpr();
expect(RP); getToken();
Expr body = parseBlock(false);
- body.next = incExpr;
Expr loop = new Expr(curLine, WHILE, whileExpr, body);
- if (initExpr == null) initExpr = loop; else initExpr.next = loop;
- return new Expr(curLine, LC, initExpr);
+ ExprList list = new ExprList(curLine, LC);
+ list.add(initExpr);
+ ExprList list2 = new ExprList(curLine, WHILE);
+ list.add(list2);
+ list2.add(whileExpr);
+ list2.add(body);
+ list2.add(incExpr);
+ return list;
}
case DO: {
if (prefix != null) { pushBackToken(); return prefix; }
- Expr firstBlock = parseBlock(false);
- if (getToken() != WHILE) throw new ParserException("expecting WHILE");
- if (getToken() != LP) throw new ParserException("expected left paren");
- Expr whileExpr = parseMaximalExpr();
- if (getToken() != RP) throw new ParserException("expected right paren");
- if (getToken() != SEMI) throw new ParserException("semicolon");
- return new Expr(curLine, DO, firstBlock, whileExpr);
+ 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;
}
default:
@@ -454,13 +389,163 @@ public class Parser extends Lexer {
// Expr //////////////////////////////////////////////////////////////////////
+ class ExprList extends Expr {
+ Vec v = new Vec();
+ public ExprList(int curLine, int code) { super(curLine, code); }
+ public void add(Expr e) { v.addElement(e); }
+ public int numExprs() { return v.size(); }
+ public int size() { return v.size(); }
+ public Expr elementAt(int i) { return (Expr)v.elementAt(i); }
+ public Object eval(final JS.Scope s) throws ControlTransferException, JS.Exn {
+ switch(code) {
+ case LC: {
+ // Block
+ JS.Scope scope = new JS.Scope(s);
+ for(int i=0; i