X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Fibex%2Fjs%2FParser.java;h=dce9a240a6f8d1d9c9d24a891f2d9cc4efa81188;hb=2d6763644359578428d56d004b998edd10463a84;hp=ded25567416be9b486397bfd9c9793d39c820af8;hpb=2fecdbcb19c71c09b252e1ecdb30f1d8e28cd845;p=org.ibex.core.git diff --git a/src/org/ibex/js/Parser.java b/src/org/ibex/js/Parser.java index ded2556..dce9a24 100644 --- a/src/org/ibex/js/Parser.java +++ b/src/org/ibex/js/Parser.java @@ -169,18 +169,18 @@ class Parser extends Lexer implements ByteCodes { case -1: throw pe("expected expression"); // all of these simply push values onto the stack - case NUMBER: b.add(parserLine, LITERAL, number); break; - case STRING: b.add(parserLine, LITERAL, string); break; + case NUMBER: b.add(parserLine, LITERAL, JS.N(number)); break; + case STRING: b.add(parserLine, LITERAL, JSString.intern(string)); break; case NULL: b.add(parserLine, LITERAL, null); break; - case TRUE: case FALSE: b.add(parserLine, LITERAL, JS.B(tok == TRUE)); break; + case TRUE: case FALSE: b.add(parserLine, LITERAL, tok == TRUE ? JS.T : JS.F); break; // (.foo) syntax case DOT: { consume(NAME); b.add(parserLine, TOPSCOPE); - b.add(parserLine, LITERAL, ""); + b.add(parserLine, LITERAL, JSString.intern("")); b.add(parserLine, GET); - b.add(parserLine, LITERAL, string); + b.add(parserLine, LITERAL, JSString.intern(string)); b.add(parserLine, GET); continueExpr(b, minPrecedence); break; @@ -206,9 +206,17 @@ class Parser extends Lexer implements ByteCodes { consume(RB); break; } - case SUB: { // negative literal (like "3 * -1") - consume(NUMBER); - b.add(parserLine, LITERAL, JS.N(number.doubleValue() * -1)); + case SUB: case ADD: { + if(peekToken() == NUMBER) { // literal + consume(NUMBER); + b.add(parserLine, LITERAL, JS.N(number.doubleValue() * (tok == SUB ? -1 : 1))); + } else { // unary +/- operator + if(tok == SUB) b.add(parserLine, LITERAL, JS.ZERO); + // BITNOT has the same precedence as the unary +/- operators + startExpr(b,precedence[BITNOT]); + if(tok == ADD) b.add(parserLine, LITERAL, JS.ZERO); // HACK to force expr into a numeric context + b.add(parserLine, SUB); + } break; } case LP: { // grouping (not calling) @@ -245,7 +253,7 @@ class Parser extends Lexer implements ByteCodes { if (peekToken() != NAME && peekToken() != STRING) throw pe("expected NAME or STRING"); getToken(); - b.add(parserLine, LITERAL, string); // grab the key + b.add(parserLine, LITERAL, JSString.intern(string)); // grab the key consume(COLON); startExpr(b, NO_COMMA); // grab the value b.add(parserLine, PUT); // put the value into the object @@ -259,7 +267,7 @@ class Parser extends Lexer implements ByteCodes { } case NAME: { b.add(parserLine, TOPSCOPE); - b.add(parserLine, LITERAL, string); + b.add(parserLine, LITERAL, JSString.intern(string)); continueExprAfterAssignable(b,minPrecedence); break; } @@ -272,7 +280,7 @@ class Parser extends Lexer implements ByteCodes { // function prelude; arguments array is already on the stack b2.add(parserLine, TOPSCOPE); b2.add(parserLine, SWAP); - b2.add(parserLine, DECLARE, "arguments"); // declare arguments (equivalent to 'var arguments;') + b2.add(parserLine, DECLARE, JSString.intern("arguments")); // declare arguments (equivalent to 'var arguments;') b2.add(parserLine, SWAP); // set this.arguments and leave the value on the stack b2.add(parserLine, PUT); @@ -280,7 +288,7 @@ class Parser extends Lexer implements ByteCodes { numArgs++; if (peekToken() == NAME) { consume(NAME); // a named argument - String varName = string; + JS varName = JSString.intern(string); b2.add(parserLine, DUP); // dup the args array b2.add(parserLine, GET, JS.N(numArgs - 1)); // retrieve it from the arguments array @@ -408,7 +416,7 @@ class Parser extends Lexer implements ByteCodes { b.add(parserLine, SWAP, null); b.add(parserLine, POP, null); b.add(parserLine, LITERAL, JS.N(1)); - b.add(parserLine, tok == INC ? SUB : ADD, null); // undo what we just did, since this is postfix + b.add(parserLine, tok == INC ? SUB : ADD, JS.N(2)); // undo what we just did, since this is postfix break; } case ASSIGN: { @@ -423,8 +431,8 @@ class Parser extends Lexer implements ByteCodes { // Method calls are implemented by doing a GET_PRESERVE // first. If the object supports method calls, it will // return JS.METHOD - int n = parseArgs(b, 2); b.add(parserLine, GET_PRESERVE); + int n = parseArgs(b); b.add(parserLine, CALLMETHOD, JS.N(n)); break; } @@ -467,7 +475,7 @@ class Parser extends Lexer implements ByteCodes { switch (tok) { case LP: { // invocation (not grouping) - int n = parseArgs(b, 1); + int n = parseArgs(b); b.add(parserLine, CALL, JS.N(n)); break; } @@ -507,7 +515,7 @@ class Parser extends Lexer implements ByteCodes { } else { consume(NAME); } - b.add(parserLine, LITERAL, string); + b.add(parserLine, LITERAL, JSString.intern(string)); continueExprAfterAssignable(b,minPrecedence); break; } @@ -545,14 +553,12 @@ class Parser extends Lexer implements ByteCodes { } // parse a set of comma separated function arguments, assume LP has already been consumed - // if swap is true, (because the function is already on the stack) we will SWAP after each argument to keep it on top - private int parseArgs(JSFunction b, int pushdown) throws IOException { + private int parseArgs(JSFunction b) throws IOException { int i = 0; while(peekToken() != RP) { i++; if (peekToken() != COMMA) { startExpr(b, NO_COMMA); - b.add(parserLine, SWAP, JS.N(pushdown)); if (peekToken() == RP) break; } consume(COMMA); @@ -608,7 +614,7 @@ class Parser extends Lexer implements ByteCodes { b.add(parserLine, TOPSCOPE); // push the current scope while(true) { consume(NAME); - b.add(parserLine, DECLARE, string); // declare it + b.add(parserLine, DECLARE, JSString.intern(string)); // declare it if (peekToken() == ASSIGN) { // if there is an '=' after the variable name consume(ASSIGN); startExpr(b, NO_COMMA); @@ -741,7 +747,7 @@ class Parser extends Lexer implements ByteCodes { // extended Ibex catch block: catch(e faultCode "foo.bar.baz") consume(NAME); b.add(parserLine, DUP); - b.add(parserLine, LITERAL, string); + b.add(parserLine, LITERAL, JSString.intern(string)); b.add(parserLine, GET); b.add(parserLine, DUP); b.add(parserLine, LITERAL, null); @@ -777,7 +783,7 @@ class Parser extends Lexer implements ByteCodes { b.add(parserLine, NEWSCOPE); b.add(parserLine, TOPSCOPE); b.add(parserLine, SWAP); - b.add(parserLine, LITERAL,exceptionVar); + b.add(parserLine, LITERAL,JSString.intern(exceptionVar)); b.add(parserLine, DECLARE); b.add(parserLine, SWAP); b.add(parserLine, PUT); @@ -835,37 +841,47 @@ class Parser extends Lexer implements ByteCodes { pushBackToken(tok, varName); if (forIn) { - b.add(parserLine, NEWSCOPE); // for-loops always create new scopes - b.add(parserLine, LITERAL, varName); // declare the new variable - b.add(parserLine, DECLARE); - - b.add(parserLine, LOOP); // we actually only add this to ensure that BREAK works - b.add(parserLine, POP); // discard the first-iteration indicator - int size = b.size; consume(NAME); consume(IN); - startExpr(b, -1); - b.add(parserLine, PUSHKEYS); // push the keys as an array; check the length - b.add(parserLine, LITERAL, "length"); - b.add(parserLine, GET); + startExpr(b,-1); consume(RP); - - b.add(parserLine, LITERAL, JS.N(1)); // decrement the length - b.add(parserLine, SUB); - b.add(parserLine, DUP); - b.add(parserLine, LITERAL, JS.ZERO); // see if we've exhausted all the elements - b.add(parserLine, LT); - b.add(parserLine, JF, JS.N(2)); - b.add(parserLine, BREAK); // if we have, then BREAK - b.add(parserLine, GET_PRESERVE); // get the key out of the keys array - b.add(parserLine, LITERAL, varName); - b.add(parserLine, PUT); // write it to this[varName] - parseStatement(b, null); // do some stuff - b.add(parserLine, CONTINUE); // continue if we fall out the bottom - - b.set(size - 1, JS.N(b.size - size + 1)); // BREAK to here - b.add(parserLine, OLDSCOPE); // restore the scope - + + b.add(parserLine, PUSHKEYS); + + int size = b.size; + b.add(parserLine, LOOP); + b.add(parserLine, POP); + + b.add(parserLine,SWAP); // get the keys enumeration object on top + b.add(parserLine,DUP); + b.add(parserLine,GET,JS.S("hasMoreElements")); + int size2 = b.size; + b.add(parserLine,JT); + b.add(parserLine,SWAP); + b.add(parserLine,BREAK); + b.set(size2, JS.N(b.size - size2)); + b.add(parserLine,DUP); + b.add(parserLine,GET,JS.S("nextElement")); + + b.add(parserLine, NEWSCOPE); + + b.add(parserLine,TOPSCOPE); + b.add(parserLine,SWAP); + b.add(parserLine, hadVar ? DECLARE : LITERAL, JSString.intern(varName)); + b.add(parserLine,SWAP); + b.add(parserLine,PUT); + b.add(parserLine,POP); + b.add(parserLine,POP); + b.add(parserLine,SWAP); + + parseStatement(b, null); + + b.add(parserLine, OLDSCOPE); + b.add(parserLine, CONTINUE); + // jump here on break + b.set(size, JS.N(b.size - size)); + + b.add(parserLine, POP); } else { if (hadVar) pushBackToken(VAR, null); // yeah, this actually matters b.add(parserLine, NEWSCOPE); // grab a fresh scope @@ -876,7 +892,7 @@ class Parser extends Lexer implements ByteCodes { if (peekToken() != SEMI) startExpr(e2, -1); else - e2.add(parserLine, JSFunction.LITERAL, Boolean.TRUE); // handle the for(foo;;foo) case + e2.add(parserLine, JSFunction.LITERAL, JS.T); // handle the for(foo;;foo) case consume(SEMI); if (label != null) b.add(parserLine, LABEL, label); b.add(parserLine, LOOP);