X-Git-Url: http://git.megacz.com/?p=org.ibex.core.git;a=blobdiff_plain;f=src%2Forg%2Fxwt%2Fjs%2FParser.java;h=9aed73a501a3a21586d88b91df7e999697d8e928;hp=d4a27531baa733b57a0c3aca38f94c8d3c834656;hb=ec3ce7739bc84c0641fc57efc8da9af89372013f;hpb=9835d9bbac931f8e76ad377674fb47a7f0da01e3 diff --git a/src/org/xwt/js/Parser.java b/src/org/xwt/js/Parser.java index d4a2753..9aed73a 100644 --- a/src/org/xwt/js/Parser.java +++ b/src/org/xwt/js/Parser.java @@ -4,7 +4,7 @@ package org.xwt.js; import org.xwt.util.*; import java.io.*; -/** Parses a stream of lexed tokens into a tree of ByteCodeBlock's */ +/** Parses a stream of lexed tokens into a tree of CompiledFunction's */ class Parser extends Lexer implements ByteCodes { @@ -14,14 +14,9 @@ class Parser extends Lexer implements ByteCodes { /** for debugging */ public static void main(String[] s) throws Exception { - Parser p = new Parser(new InputStreamReader(System.in), "stdin", 0); - while(true) { - ByteCodeBlock block = new ByteCodeBlock(0, "stdin"); - p.parseStatement(false, block); - if (block == null) return; - System.out.println(block); - if (p.peekToken() == -1) return; - } + CompiledFunction block = new CompiledFunction("stdin", 0, new InputStreamReader(System.in), null); + if (block == null) return; + System.out.println(block); } @@ -56,7 +51,8 @@ class Parser extends Lexer implements ByteCodes { // Parsing Logic ///////////////////////////////////////////////////////// - private ByteCodeBlock newbb(int line) { return new ByteCodeBlock(line, sourceName); } + /** the label for the current statement */ + private String label = null; /** gets a token and throws an exception if it is not code */ public void consume(int code) throws IOException { @@ -65,47 +61,45 @@ class Parser extends Lexer implements ByteCodes { } /** append the largest expression beginning with prefix containing no operators of precedence below minPrecedence */ - public void startExpr(ByteCodeBlock block) throws IOException { startExpr(-1, block); } + public void startExpr(CompiledFunction block) throws IOException { startExpr(-1, block); } /* - public ByteCodeBlock startExpr(int minPrecedence) throws IOException { - ByteCodeBlock ret = new ByteCodeBlock(line, sourceName); + public CompiledFunction startExpr(int minPrecedence) throws IOException { + CompiledFunction ret = new CompiledFunction(line, sourceName); startExpr(minPrecedence, ret); return ret.size() == 0 ? null : ret; } */ - public void startExpr(int minPrecedence, ByteCodeBlock appendTo) throws IOException { + public void startExpr(int minPrecedence, CompiledFunction appendTo) throws IOException { int tok = getToken(); - int curLine = line; - if (tok == -1) return; - - ByteCodeBlock b = appendTo; - + int line = this.line; + CompiledFunction b = appendTo; switch (tok) { - case NUMBER: continueExpr(b.add(ByteCodeBlock.LITERAL, number), minPrecedence); return; - case STRING: continueExpr(b.add(ByteCodeBlock.LITERAL, string), minPrecedence); return; - case THIS: continueExpr(b.add(TOPSCOPE, null), minPrecedence); return; - case NULL: continueExpr(b.add(ByteCodeBlock.LITERAL, null), minPrecedence); return; - case TRUE: case FALSE: continueExpr(b.add(ByteCodeBlock.LITERAL, new Boolean(tok == TRUE)), minPrecedence); return; + case -1: return; + case NUMBER: continueExpr(b.add(line, CompiledFunction.LITERAL, number), minPrecedence); return; + case STRING: continueExpr(b.add(line, CompiledFunction.LITERAL, string), minPrecedence); return; + case THIS: continueExpr(b.add(line, TOPSCOPE, null), minPrecedence); return; + case NULL: continueExpr(b.add(line, CompiledFunction.LITERAL, null), minPrecedence); return; + case TRUE: case FALSE: continueExpr(b.add(line, CompiledFunction.LITERAL, new Boolean(tok == TRUE)), minPrecedence); return; case LB: { - b.add(ARRAY, new Integer(0)); + b.add(line, ARRAY, new Integer(0)); int i = 0; while(true) { int size = b.size(); startExpr(b); if (size == b.size()) if (peekToken() == RB) { consume(RB); continueExpr(b, minPrecedence); return; } - b.add(LITERAL, new Integer(i++)); - if (size == b.size()) b.add(LITERAL, null); - b.add(PUT); - b.add(POP); + b.add(line, LITERAL, new Integer(i++)); + if (size == b.size()) b.add(line, LITERAL, null); + b.add(line, PUT); + b.add(line, POP); if (peekToken() == RB) { consume(RB); continueExpr(b, minPrecedence); return; } consume(COMMA); } } case SUB: { consume(NUMBER); - b.add(ByteCodeBlock.LITERAL, new Double(number.doubleValue() * -1)); + b.add(line, CompiledFunction.LITERAL, new Double(number.doubleValue() * -1)); continueExpr(b, minPrecedence); return; } @@ -124,20 +118,20 @@ class Parser extends Lexer implements ByteCodes { } case BANG: case BITNOT: case TYPEOF: { startExpr(precedence[tok], b); - b.add(tok); + b.add(line, tok); continueExpr(b, minPrecedence); return; } case LC: { - b.add(OBJECT, null); + b.add(line, OBJECT, null); if (peekToken() != RC) while(true) { if (peekToken() != NAME && peekToken() != STRING) throw new Error("expected NAME or STRING"); getToken(); - b.add(LITERAL, string); + b.add(line, LITERAL, string); consume(COLON); startExpr(b); - b.add(PUT); - b.add(POP); + b.add(line, PUT); + b.add(line, POP); if (peekToken() == RC) break; consume(COMMA); if (peekToken() == RC) break; @@ -150,16 +144,16 @@ class Parser extends Lexer implements ByteCodes { String name = string; if (peekToken() == ASSIGN) { consume(ASSIGN); - b.add(TOPSCOPE); - b.add(ByteCodeBlock.LITERAL, name); + b.add(line, TOPSCOPE); + b.add(line, CompiledFunction.LITERAL, name); startExpr(minPrecedence, b); - b.add(ByteCodeBlock.PUT); - b.add(ByteCodeBlock.SWAP); - b.add(ByteCodeBlock.POP); + b.add(line, CompiledFunction.PUT); + b.add(line, CompiledFunction.SWAP); + b.add(line, CompiledFunction.POP); } else { - b.add(TOPSCOPE); - b.add(ByteCodeBlock.LITERAL, name); - b.add(ByteCodeBlock.GET); + b.add(line, TOPSCOPE); + b.add(line, CompiledFunction.LITERAL, name); + b.add(line, CompiledFunction.GET); } continueExpr(b, minPrecedence); return; @@ -167,16 +161,16 @@ class Parser extends Lexer implements ByteCodes { case FUNCTION: { consume(LP); int numArgs = 0; - ByteCodeBlock b2 = newbb(curLine); - b2.add(TOPSCOPE); - b2.add(SWAP); - b2.add(LITERAL, "arguments"); - b2.add(LITERAL, "arguments"); - b2.add(DECLARE); - b2.add(SWAP); - b2.add(PUT); - b2.add(SWAP); - b2.add(POP); + CompiledFunction b2 = new CompiledFunction(sourceName, line, null); + b2.add(line, TOPSCOPE); + b2.add(line, SWAP); + b2.add(line, LITERAL, "arguments"); + b2.add(line, LITERAL, "arguments"); + b2.add(line, DECLARE); + b2.add(line, SWAP); + b2.add(line, PUT); + b2.add(line, SWAP); + b2.add(line, POP); if (peekToken() == RP) consume(RP); else while(true) { if (peekToken() == COMMA) { @@ -186,25 +180,25 @@ class Parser extends Lexer implements ByteCodes { consume(NAME); // declare the name - b2.add(LITERAL, string); - b2.add(DECLARE); + b2.add(line, LITERAL, string); + b2.add(line, DECLARE); // retrieve it from the arguments array - b2.add(LITERAL, new Integer(numArgs)); - b2.add(GET_PRESERVE); - b2.add(SWAP); - b2.add(POP); + b2.add(line, LITERAL, new Integer(numArgs)); + b2.add(line, GET_PRESERVE); + b2.add(line, SWAP); + b2.add(line, POP); // put it to the current scope - b2.add(TOPSCOPE); - b2.add(SWAP); - b2.add(LITERAL, string); - b2.add(SWAP); - b2.add(PUT); + b2.add(line, TOPSCOPE); + b2.add(line, SWAP); + b2.add(line, LITERAL, string); + b2.add(line, SWAP); + b2.add(line, PUT); // clean the stack - b2.add(POP); - b2.add(POP); + b2.add(line, POP); + b2.add(line, POP); if (peekToken() == RP) { consume(RP); break; } consume(COMMA); @@ -212,27 +206,25 @@ class Parser extends Lexer implements ByteCodes { numArgs++; } // pop off the arguments array - b2.add(POP); + b2.add(line, POP); parseStatement(true, b2); - b2.add(LITERAL, null); - b2.add(RETURN); - continueExpr(b.add(NEWFUNCTION, b2), minPrecedence); + b2.add(line, LITERAL, null); + b2.add(line, RETURN); + continueExpr(b.add(line, NEWFUNCTION, b2), minPrecedence); return; } default: pushBackToken(); return; } } - public void continueExpr(ByteCodeBlock prefix, int minPrecedence) throws IOException { + public void continueExpr(CompiledFunction prefix, int minPrecedence) throws IOException { int tok = getToken(); - int curLine = line; if (tok == -1) return; if (minPrecedence > 0 && precedence[tok] != 0) if (precedence[tok] < minPrecedence || (precedence[tok] == minPrecedence && !isRightAssociative[tok])) { pushBackToken(); return; } - if (prefix == null) throw new Error("got null prefix"); - ByteCodeBlock b = prefix; + CompiledFunction b = prefix; switch (tok) { @@ -240,10 +232,10 @@ class Parser extends Lexer implements ByteCodes { case ASSIGN_ADD: case ASSIGN_SUB: case ASSIGN_MUL: case ASSIGN_DIV: case ASSIGN_MOD: { prefix.set(prefix.size() - 1, b.GET_PRESERVE, new Boolean(true)); startExpr(precedence[tok - 1], b); - prefix.add(tok - 1); - prefix.add(PUT); - prefix.add(SWAP); - prefix.add(POP); + prefix.add(line, tok - 1); + prefix.add(line, PUT); + prefix.add(line, SWAP); + prefix.add(line, POP); continueExpr(b, minPrecedence); return; } @@ -265,7 +257,7 @@ class Parser extends Lexer implements ByteCodes { consume(COMMA); } consume(RP); - b.add(CALL, new Integer(i)); + b.add(line, CALL, new Integer(i)); continueExpr(b, minPrecedence); return; } @@ -274,18 +266,18 @@ class Parser extends Lexer implements ByteCodes { case RSH: case URSH: case ADD: case MUL: case DIV: case MOD: case GT: case GE: case EQ: case NE: case LT: case LE: case SUB: { startExpr(precedence[tok], b); - b.add(tok); + b.add(line, tok); continueExpr(b, minPrecedence); return; } case OR: case AND: { - b.add(tok == AND ? b.JF : b.JT, new Integer(0)); + b.add(line, tok == AND ? b.JF : b.JT, new Integer(0)); int size = b.size(); startExpr(precedence[tok], b); b.set(size - 1, new Integer(b.size() - size + 2)); - b.add(JMP, new Integer(2)); - b.add(LITERAL, tok == AND ? new Boolean(false) : new Boolean(true)); + b.add(line, JMP, new Integer(2)); + b.add(line, LITERAL, tok == AND ? new Boolean(false) : new Boolean(true)); continueExpr(b, minPrecedence); return; } @@ -295,14 +287,14 @@ class Parser extends Lexer implements ByteCodes { String target = string; if (peekToken() == ASSIGN) { consume(ASSIGN); - b.add(LITERAL, target); + b.add(line, LITERAL, target); startExpr(b); - b.add(PUT); - b.add(SWAP); - b.add(POP); + b.add(line, PUT); + b.add(line, SWAP); + b.add(line, POP); } else { - b.add(LITERAL, target); - b.add(GET); + b.add(line, LITERAL, target); + b.add(line, GET); } continueExpr(b, minPrecedence); return; @@ -314,22 +306,22 @@ class Parser extends Lexer implements ByteCodes { if (peekToken() == ASSIGN) { consume(ASSIGN); startExpr(b); - b.add(PUT); - b.add(SWAP); - b.add(POP); + b.add(line, PUT); + b.add(line, SWAP); + b.add(line, POP); } else { - b.add(GET); + b.add(line, GET); } continueExpr(b, minPrecedence); return; } case HOOK: { - b.add(JF, new Integer(0)); + b.add(line, JF, new Integer(0)); int size = b.size(); startExpr(b); b.set(size - 1, new Integer(b.size() - size + 2)); - b.add(JMP, new Integer(0)); + b.add(line, JMP, new Integer(0)); consume(COLON); size = b.size(); startExpr(b); @@ -342,67 +334,70 @@ class Parser extends Lexer implements ByteCodes { } } - /** a block is either a single statement or a list of statements surrounded by curly braces; all expressions are also statements */ - - public ByteCodeBlock parseStatement() throws IOException { - ByteCodeBlock ret = new ByteCodeBlock(line, sourceName); - ret.add(ret.LITERAL, null); + /** + * a block is either a single statement or a list of statements surrounded by curly braces; + * all expressions are also statements + */ + public CompiledFunction parseStatement() throws IOException { + CompiledFunction ret = new CompiledFunction(sourceName, line, null); + ret.add(line, ret.LITERAL, null); parseStatement(false, ret); if (ret.size() == 1) return null; return ret; } - public void parseStatement(boolean requireBraces, ByteCodeBlock b) throws IOException { + public void parseStatement(boolean requireBraces, CompiledFunction b) throws IOException { int tok = peekToken(); if (tok == -1) return; + int line = this.line; boolean braced = tok == LC; if (requireBraces && !braced) throw new ParserException("expected {, got " + codeToString[tok]); if (braced) consume(LC); - int curLine = line; while(true) { switch(tok = peekToken()) { case THROW: case RETURN: case ASSERT: { getToken(); - if (tok == RETURN && peekToken() == SEMI) b.add(LITERAL, null); + if (tok == RETURN && peekToken() == SEMI) b.add(line, LITERAL, null); else startExpr(b); consume(SEMI); - b.add(tok); + b.add(line, tok); break; } case BREAK: case CONTINUE: { getToken(); if (peekToken() == NAME) consume(NAME); - b.add(tok, string); + b.add(line, tok, string); consume(SEMI); break; } - case SEMI: + case SEMI: { consume(SEMI); if (!braced) return; break; + } case VAR: { consume(VAR); - b.add(TOPSCOPE); // push the current scope + b.add(line, TOPSCOPE); // push the current scope while(true) { consume(NAME); String name = string; - b.add(LITERAL, name); // push the name to be declared - b.add(DECLARE); // declare it + b.add(line, LITERAL, name); // push the name to be declared + b.add(line, DECLARE); // declare it if (peekToken() == ASSIGN) { // if there is an '=' after the variable name - b.add(LITERAL, name); // put the var name back on the stack + b.add(line, LITERAL, name); // put the var name back on the stack consume(ASSIGN); startExpr(b); - b.add(PUT); - b.add(POP); + b.add(line, PUT); + b.add(line, POP); } if (peekToken() != COMMA) break; consume(COMMA); } - b.add(POP); + b.add(line, POP); if (peekToken() == SEMI) consume(SEMI); break; } @@ -413,14 +408,14 @@ class Parser extends Lexer implements ByteCodes { startExpr(b); consume(RP); - b.add(JF, new Integer(0)); + b.add(line, JF, new Integer(0)); int size = b.size(); parseStatement(false, b); if (peekToken() == ELSE) { consume(ELSE); b.set(size - 1, new Integer(2 + b.size() - size)); - b.add(JMP, new Integer(0)); + b.add(line, JMP, new Integer(0)); size = b.size(); parseStatement(false, b); } @@ -431,15 +426,16 @@ class Parser extends Lexer implements ByteCodes { case WHILE: { consume(WHILE); consume(LP); - b.add(LOOP); + if (label != null) b.add(line, LABEL, label); + b.add(line, LOOP); int size = b.size(); - b.add(POP); + b.add(line, POP); startExpr(b); - b.add(JT, new Integer(2)); - b.add(BREAK); + b.add(line, JT, new Integer(2)); + b.add(line, BREAK); consume(RP); parseStatement(false, b); - b.add(CONTINUE); // if we fall out of the end, definately continue + b.add(line, CONTINUE); // if we fall out of the end, definately continue b.set(size - 1, new Integer(b.size() - size + 1)); // end of the loop break; } @@ -447,7 +443,8 @@ class Parser extends Lexer implements ByteCodes { case SWITCH: { consume(SWITCH); consume(LP); - b.add(LOOP); + if (label != null) b.add(line, LABEL, label); + b.add(line, LOOP); int size0 = b.size(); startExpr(b); consume(RP); @@ -455,11 +452,11 @@ class Parser extends Lexer implements ByteCodes { while(true) if (peekToken() == CASE) { consume(CASE); - b.add(DUP); + b.add(line, DUP); startExpr(b); consume(COLON); - b.add(EQ); - b.add(JF, new Integer(0)); + b.add(line, EQ); + b.add(line, JF, new Integer(0)); int size = b.size(); while(peekToken() != CASE && peekToken() != DEFAULT && peekToken() != RC) { int size2 = b.size(); @@ -477,27 +474,28 @@ class Parser extends Lexer implements ByteCodes { } } else if (peekToken() == RC) { consume(RC); - b.add(BREAK); + b.add(line, BREAK); break; } else { throw new ParserException("expected CASE, DEFAULT, or RC; got " + codeToString[peekToken()]); } - b.add(BREAK); + b.add(line, BREAK); b.set(size0 - 1, new Integer(b.size() - size0 + 1)); // end of the loop break; } case DO: { consume(DO); - b.add(LOOP); + if (label != null) b.add(line, LABEL, label); + b.add(line, LOOP); int size = b.size(); parseStatement(false, b); consume(WHILE); consume(LP); startExpr(b); - b.add(JT, new Integer(2)); - b.add(BREAK); - b.add(CONTINUE); + b.add(line, JT, new Integer(2)); + b.add(line, BREAK); + b.add(line, CONTINUE); consume(RP); consume(SEMI); b.set(size - 1, new Integer(b.size() - size + 1)); // end of the loop @@ -507,16 +505,33 @@ class Parser extends Lexer implements ByteCodes { case TRY: { // We deliberately allow you to omit braces in catch{}/finally{} if they are single statements... consume(TRY); + b.add(line, TRY); + int size = b.size(); parseStatement(true, b); + b.add(line, POP); // pop the TryMarker + b.add(line, JMP); // jump forward to the end of the catch block + int size2 = b.size(); + b.set(size - 1, new Integer(b.size() - size + 1));// the TRY argument points at the start of the CATCH block if (peekToken() == CATCH) { getToken(); consume(LP); consume(NAME); consume(RP); - parseStatement(); // just discard the catchblock + // FIXME, we need an extra scope here + b.add(line, TOPSCOPE); // the exception is on top of the stack; put it to the variable + b.add(line, SWAP); + b.add(line, LITERAL); + b.add(line, SWAP); + b.add(line, PUT); + b.add(line, POP); + b.add(line, POP); + parseStatement(false, b); } + b.set(size2 - 1, new Integer(b.size() - size2 + 1)); // jump here if no exception was thrown + + // FIXME: not implemented correctly if (peekToken() == FINALLY) { consume(FINALLY); parseStatement(false, b); @@ -524,88 +539,92 @@ class Parser extends Lexer implements ByteCodes { break; } - case FOR: { - consume(FOR); - consume(LP); - - tok = getToken(); - boolean hadVar = false; - if (tok == VAR) { hadVar = true; tok = getToken(); } - String varName = string; - boolean forIn = peekToken() == IN; - pushBackToken(tok, varName); - - if (forIn) { - // FIXME: break needs to work in here - consume(NAME); - consume(IN); - startExpr(b); - b.add(PUSHKEYS); - b.add(LITERAL, "length"); - b.add(GET); - consume(RP); - ByteCodeBlock b2 = newbb(curLine); - - b.add(PUSHSCOPE); - - b.add(LITERAL, new Integer(1)); - b.add(SUB); - b.add(DUP); - b.add(LITERAL, new Integer(0)); - b.add(LT); - b.add(JT, new Integer(7)); - b.add(GET_PRESERVE); - b.add(LITERAL, varName); - b.add(LITERAL, varName); - b.add(DECLARE); - b.add(PUT); - parseStatement(false, b); - - b.add(POPSCOPE); - - break; + case FOR: { + consume(FOR); + consume(LP); - } else { - if (hadVar) pushBackToken(VAR, null); - b.add(PUSHSCOPE); - - parseStatement(false, b); - ByteCodeBlock e2 = new ByteCodeBlock(line, sourceName); - startExpr(e2); - consume(SEMI); - if (e2 == null) e2 = newbb(curLine).add(b.LITERAL, Boolean.TRUE); - - b.add(LOOP); - int size2 = b.size(); - - b.add(JT, new Integer(0)); - int size = b.size(); - startExpr(b); - if (b.size() > size) b.add(POP); - b.set(size - 1, new Integer(b.size() - size + 1)); - consume(RP); - - b.paste(e2); - b.add(JT, new Integer(2)); - b.add(BREAK); - parseStatement(false, b); - b.add(CONTINUE); - b.set(size2 - 1, new Integer(b.size() - size2 + 1)); // end of the loop - - b.add(POPSCOPE); - break; + tok = getToken(); + boolean hadVar = false; + if (tok == VAR) { hadVar = true; tok = getToken(); } + String varName = string; + boolean forIn = peekToken() == IN; + pushBackToken(tok, varName); + + if (forIn) { + // FIXME: break needs to work in here + consume(NAME); + consume(IN); + startExpr(b); + b.add(line, PUSHKEYS); + b.add(line, LITERAL, "length"); + b.add(line, GET); + consume(RP); + CompiledFunction b2 = new CompiledFunction(sourceName, line, null); + + b.add(line, NEWSCOPE); + + b.add(line, LITERAL, new Integer(1)); + b.add(line, SUB); + b.add(line, DUP); + b.add(line, LITERAL, new Integer(0)); + b.add(line, LT); + b.add(line, JT, new Integer(7)); + b.add(line, GET_PRESERVE); + b.add(line, LITERAL, varName); + b.add(line, LITERAL, varName); + b.add(line, DECLARE); + b.add(line, PUT); + parseStatement(false, b); + + b.add(line, OLDSCOPE); + + break; + + } else { + if (hadVar) pushBackToken(VAR, null); + b.add(line, NEWSCOPE); + + parseStatement(false, b); + CompiledFunction e2 = new CompiledFunction(sourceName, line, null); + startExpr(e2); + consume(SEMI); + if (e2 == null) e2 = new CompiledFunction(sourceName, line, null).add(line, b.LITERAL, Boolean.TRUE); + + if (label != null) b.add(line, LABEL, label); + b.add(line, LOOP); + int size2 = b.size(); + + b.add(line, JT, new Integer(0)); + int size = b.size(); + startExpr(b); + if (b.size() > size) b.add(line, POP); + b.set(size - 1, new Integer(b.size() - size + 1)); + consume(RP); + + b.paste(e2); + b.add(line, JT, new Integer(2)); + b.add(line, BREAK); + parseStatement(false, b); + b.add(line, CONTINUE); + b.set(size2 - 1, new Integer(b.size() - size2 + 1)); // end of the loop + + b.add(line, OLDSCOPE); + break; + } } - } - + case NAME: { consume(NAME); - String name = string; + String oldlabel = label; + label = string; if (peekToken() == COLON) { consume(COLON); - b.add(ByteCodeBlock.LABEL, string); + parseStatement(false, b); + label = oldlabel; break; } else { - pushBackToken(NAME, name); + pushBackToken(NAME, label); + label = oldlabel; // fall through to default case } } @@ -617,7 +636,7 @@ class Parser extends Lexer implements ByteCodes { int size = b.size(); startExpr(b); if (size == b.size()) return; - b.add(POP); + b.add(line, POP); if (peekToken() == SEMI) consume(SEMI); break; } @@ -627,7 +646,7 @@ class Parser extends Lexer implements ByteCodes { } } - class ParserException extends RuntimeException { + private class ParserException extends RuntimeException { public ParserException(String s) { super(sourceName + ":" + line + " " + s); } }