X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Fxwt%2Fjs%2FParser.java;h=1914cc7e3226acaa6f8f57fe9ae85373515ed1de;hb=de378041d5ca2aca1a2b5a31ef15ae90a86c977f;hp=3f61832a0c44c3011f75b9a5350afc793f9710c5;hpb=47f708e9d75f65e097c5968653139859047ec5a0;p=org.ibex.core.git diff --git a/src/org/xwt/js/Parser.java b/src/org/xwt/js/Parser.java index 3f61832..1914cc7 100644 --- a/src/org/xwt/js/Parser.java +++ b/src/org/xwt/js/Parser.java @@ -1,4 +1,4 @@ -// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt.js; import org.xwt.util.*; @@ -73,7 +73,7 @@ class Parser extends Lexer implements ByteCodes { /** for debugging */ public static void main(String[] s) throws Exception { - JSFunction block = JSFunction.fromReader("stdin", 0, new InputStreamReader(System.in)); + JS block = JS.fromReader("stdin", 0, new InputStreamReader(System.in)); if (block == null) return; System.out.println(block); } @@ -97,7 +97,10 @@ class Parser extends Lexer implements ByteCodes { isRightAssociative[ASSIGN_SUB] = isRightAssociative[ASSIGN_MUL] = isRightAssociative[ASSIGN_DIV] = - isRightAssociative[ASSIGN_MOD] = true; + isRightAssociative[ASSIGN_MOD] = + isRightAssociative[ADD_TRAP] = + isRightAssociative[DEL_TRAP] = + true; precedence[COMMA] = 1; // 2 is intentionally left unassigned. we use minPrecedence==2 for comma separated lists @@ -112,6 +115,8 @@ class Parser extends Lexer implements ByteCodes { precedence[ASSIGN_SUB] = precedence[ASSIGN_MUL] = precedence[ASSIGN_DIV] = + precedence[ADD_TRAP] = + precedence[DEL_TRAP] = precedence[ASSIGN_MOD] = 3; precedence[HOOK] = 4; precedence[OR] = 5; @@ -133,7 +138,16 @@ class Parser extends Lexer implements ByteCodes { /** gets a token and throws an exception if it is not code */ private void consume(int code) throws IOException { - if (getToken() != code) throw pe("expected " + codeToString[code] + ", got " + (op == -1 ? "EOF" : codeToString[op])); + if (getToken() != code) { + if(code == NAME) switch(op) { + case RETURN: case TYPEOF: case BREAK: case CONTINUE: case TRY: case THROW: + case ASSERT: case NULL: case TRUE: case FALSE: case IN: case IF: case ELSE: + case SWITCH: case CASE: case DEFAULT: case WHILE: case VAR: case WITH: + case CATCH: case FINALLY: + throw pe("Bad variable name; '" + codeToString[op].toLowerCase() + "' is a javascript keyword"); + } + throw pe("expected " + codeToString[code] + ", got " + (op == -1 ? "EOF" : codeToString[op])); + } } /** @@ -160,6 +174,18 @@ class Parser extends Lexer implements ByteCodes { case NULL: b.add(parserLine, LITERAL, null); break; case TRUE: case FALSE: b.add(parserLine, LITERAL, JS.B(tok == TRUE)); break; + // (.foo) syntax + case DOT: { + consume(NAME); + b.add(parserLine, TOPSCOPE); + b.add(parserLine, LITERAL, ""); + b.add(parserLine, GET); + b.add(parserLine, LITERAL, string); + b.add(parserLine, GET); + continueExpr(b, minPrecedence); + break; + } + case LB: { b.add(parserLine, ARRAY, JS.ZERO); // push an array onto the stack int size0 = b.size; @@ -293,6 +319,36 @@ class Parser extends Lexer implements ByteCodes { continueExpr(b, minPrecedence); } + private Grammar parseGrammar(Grammar g) throws IOException { + int tok = getToken(); + if (g != null) + switch(tok) { + case BITOR: return new Grammar.Alternative(g, parseGrammar(null)); + case ADD: return parseGrammar(new Grammar.Repetition(g, 1, Integer.MAX_VALUE)); + case MUL: return parseGrammar(new Grammar.Repetition(g, 0, Integer.MAX_VALUE)); + case HOOK: return parseGrammar(new Grammar.Repetition(g, 0, 1)); + } + Grammar g0 = null; + switch(tok) { + //case NUMBER: g0 = new Grammar.Literal(number); break; + case NAME: g0 = new Grammar.Reference(string); break; + case STRING: + g0 = new Grammar.Literal(string); + if (peekToken() == DOT) { + String old = string; + consume(DOT); + consume(DOT); + consume(STRING); + if (old.length() != 1 || string.length() != 1) throw pe("literal ranges must be single-char strings"); + g0 = new Grammar.Range(old.charAt(0), string.charAt(0)); + } + break; + case LP: g0 = parseGrammar(null); consume(RP); break; + default: pushBackToken(); return g; + } + if (g == null) return parseGrammar(g0); + return parseGrammar(new Grammar.Juxtaposition(g, g0)); + } /** * Assuming that a complete assignable (lvalue) has just been @@ -313,20 +369,38 @@ class Parser extends Lexer implements ByteCodes { // force the default case tok = -1; switch(tok) { - case ASSIGN_BITOR: case ASSIGN_BITXOR: case ASSIGN_BITAND: case ASSIGN_LSH: case ASSIGN_RSH: case ASSIGN_URSH: - case ASSIGN_MUL: case ASSIGN_DIV: case ASSIGN_MOD: case ASSIGN_ADD: case ASSIGN_SUB: { + + case GRAMMAR: { b.add(parserLine, GET_PRESERVE); + Grammar g = parseGrammar(null); + if (peekToken() == LC) { + g.action = new JSFunction(sourceName, parserLine, null); + parseBlock((JSFunction)g.action); + ((JSFunction)g.action).add(parserLine, LITERAL, null); // in case we "fall out the bottom", return NULL + ((JSFunction)g.action).add(parserLine, RETURN); + } + b.add(parserLine, MAKE_GRAMMAR, g); + b.add(parserLine, PUT); + break; + } + + case ASSIGN_BITOR: case ASSIGN_BITXOR: case ASSIGN_BITAND: case ASSIGN_LSH: case ASSIGN_RSH: case ASSIGN_URSH: + case ASSIGN_MUL: case ASSIGN_DIV: case ASSIGN_MOD: case ASSIGN_ADD: case ASSIGN_SUB: case ADD_TRAP: case DEL_TRAP: { + if (tok != ADD_TRAP && tok != DEL_TRAP) b.add(parserLine, GET_PRESERVE); + startExpr(b, precedence[tok]); + int size = b.size; - if (tok == ASSIGN_ADD || tok == ASSIGN_SUB) { + + if (tok != ADD_TRAP && tok != DEL_TRAP) { + // tok-1 is always s/^ASSIGN_// (0 is BITOR, 1 is ASSIGN_BITOR, etc) + b.add(parserLine, tok - 1, tok-1==ADD ? JS.N(2) : null); + b.add(parserLine, PUT); + b.add(parserLine, SWAP); + b.add(parserLine, POP); + } else { b.add(parserLine, tok); } - // tok-1 is always s/^ASSIGN_// (0 is BITOR, 1 is ASSIGN_BITOR, etc) - b.add(parserLine, tok - 1, tok-1==ADD ? JS.N(2) : null); - b.add(parserLine, PUT); - b.add(parserLine, SWAP); - b.add(parserLine, POP); - if (tok == ASSIGN_ADD || tok == ASSIGN_SUB) b.set(size, tok, JS.N(b.size - size)); break; } case INC: case DEC: { // postfix @@ -654,26 +728,88 @@ class Parser extends Lexer implements ByteCodes { int catchJMPDistance = -1; if (peekToken() == CATCH) { + Vec catchEnds = new Vec(); + boolean catchAll = false; + catchJMPDistance = b.size - tryInsn; - String exceptionVar; - getToken(); - consume(LP); - consume(NAME); - exceptionVar = string; - consume(RP); - b.add(parserLine, TOPSCOPE); // the exception is on top of the stack; put it to the chosen name - b.add(parserLine, SWAP); - b.add(parserLine, LITERAL,exceptionVar); - b.add(parserLine, SWAP); - b.add(parserLine, PUT); - b.add(parserLine, POP); - b.add(parserLine, POP); - parseStatement(b, null); + + while(peekToken() == CATCH && !catchAll) { + String exceptionVar; + getToken(); + consume(LP); + consume(NAME); + exceptionVar = string; + int[] writebacks = new int[] { -1, -1, -1 }; + if (peekToken() != RP) { + // extended XWT catch block: catch(e faultCode "foo.bar.baz") + consume(NAME); + String propName = string; + b.add(parserLine, DUP); + b.add(parserLine, LITERAL, string); + b.add(parserLine, GET); + b.add(parserLine, DUP); + b.add(parserLine, LITERAL, null); + b.add(parserLine, EQ); + b.add(parserLine, JT); + writebacks[0] = b.size - 1; + if (peekToken() == STRING) { + consume(STRING); + b.add(parserLine, DUP); + b.add(parserLine, LITERAL, string); + b.add(parserLine, LT); + b.add(parserLine, JT); + writebacks[1] = b.size - 1; + b.add(parserLine, DUP); + b.add(parserLine, LITERAL, string + "/"); // (slash is ASCII after dot) + b.add(parserLine, GE); + b.add(parserLine, JT); + writebacks[2] = b.size - 1; + } else { + consume(NUMBER); + b.add(parserLine, DUP); + b.add(parserLine, LITERAL, number); + b.add(parserLine, EQ); + b.add(parserLine, JF); + writebacks[1] = b.size - 1; + } + b.add(parserLine, POP); // pop the element thats on the stack from the compare + } else { + catchAll = true; + } + consume(RP); + // the exception is on top of the stack; put it to the chosen name + b.add(parserLine, NEWSCOPE); + b.add(parserLine, TOPSCOPE); + b.add(parserLine, SWAP); + b.add(parserLine, LITERAL,exceptionVar); + b.add(parserLine, DECLARE); + b.add(parserLine, SWAP); + b.add(parserLine, PUT); + b.add(parserLine, POP); + b.add(parserLine, POP); + parseBlock(b, null); + b.add(parserLine, OLDSCOPE); + + b.add(parserLine, JMP); + catchEnds.addElement(new Integer(b.size-1)); + + for(int i=0; i<3; i++) if (writebacks[i] != -1) b.set(writebacks[i], JS.N(b.size-writebacks[i])); + b.add(parserLine, POP); // pop the element thats on the stack from the compare + } + + if(!catchAll) + b.add(parserLine, THROW); + + for(int i=0;i