2003/07/06 13:42:15
[org.ibex.core.git] / src / org / xwt / js / Parser.java
index 76f223b..49b5d34 100644 (file)
@@ -5,7 +5,7 @@ import org.xwt.util.*;
 import java.io.*;
 
 /**
- *  Parses a stream of lexed tokens into a tree of CompiledFunction's.
+ *  Parses a stream of lexed tokens into a tree of CompiledFunctionImpl's.
  *
  *  There are three kinds of things we parse: blocks, statements, and
  *  expressions.
@@ -73,7 +73,7 @@ class Parser extends Lexer implements ByteCodes {
 
     /** for debugging */
     public static void main(String[] s) throws Exception {
-        CompiledFunction block = new CompiledFunction("stdin", 0, new InputStreamReader(System.in), null);
+        CompiledFunctionImpl block = new JS.CompiledFunction("stdin", 0, new InputStreamReader(System.in), null);
         if (block == null) return;
         System.out.println(block);
     }
@@ -85,39 +85,39 @@ class Parser extends Lexer implements ByteCodes {
     static boolean[] isRightAssociative = new boolean[MAX_TOKEN + 1];
     static {
         isRightAssociative[ASSIGN] =
-           isRightAssociative[ASSIGN_BITOR] =
-           isRightAssociative[ASSIGN_BITXOR] =
-           isRightAssociative[ASSIGN_BITAND] =
-           isRightAssociative[ASSIGN_LSH] =
-           isRightAssociative[ASSIGN_RSH] =
-           isRightAssociative[ASSIGN_URSH] =
-           isRightAssociative[ASSIGN_ADD] =
-           isRightAssociative[ASSIGN_SUB] =
-           isRightAssociative[ASSIGN_MUL] =
-           isRightAssociative[ASSIGN_DIV] =
-           isRightAssociative[ASSIGN_MOD] = true;
+            isRightAssociative[ASSIGN_BITOR] =
+            isRightAssociative[ASSIGN_BITXOR] =
+            isRightAssociative[ASSIGN_BITAND] =
+            isRightAssociative[ASSIGN_LSH] =
+            isRightAssociative[ASSIGN_RSH] =
+            isRightAssociative[ASSIGN_URSH] =
+            isRightAssociative[ASSIGN_ADD] =
+            isRightAssociative[ASSIGN_SUB] =
+            isRightAssociative[ASSIGN_MUL] =
+            isRightAssociative[ASSIGN_DIV] =
+            isRightAssociative[ASSIGN_MOD] = true;
 
         precedence[ASSIGN] =
-           precedence[ASSIGN_BITOR] =
-           precedence[ASSIGN_BITXOR] =
-           precedence[ASSIGN_BITAND] =
-           precedence[ASSIGN_LSH] =
-           precedence[ASSIGN_RSH] =
-           precedence[ASSIGN_URSH] =
-           precedence[ASSIGN_ADD] =
-           precedence[ASSIGN_SUB] =
-           precedence[ASSIGN_MUL] =
-           precedence[ASSIGN_DIV] =
-           precedence[ASSIGN_MOD] = 1;
+            precedence[ASSIGN_BITOR] =
+            precedence[ASSIGN_BITXOR] =
+            precedence[ASSIGN_BITAND] =
+            precedence[ASSIGN_LSH] =
+            precedence[ASSIGN_RSH] =
+            precedence[ASSIGN_URSH] =
+            precedence[ASSIGN_ADD] =
+            precedence[ASSIGN_SUB] =
+            precedence[ASSIGN_MUL] =
+            precedence[ASSIGN_DIV] =
+            precedence[ASSIGN_MOD] = 1;
         precedence[HOOK] = 2;
         precedence[COMMA] = 3;
-        precedence[OR] = precedence[AND] = 4;
+        precedence[OR] = precedence[AND] = precedence[BANG] = 4;
         precedence[GT] = precedence[GE] = 5;
         precedence[BITOR] = 6;
         precedence[BITXOR] = 7;
         precedence[BITAND] = 8;
         precedence[EQ] = precedence[NE] = 9;
-        precedence[LT] = precedence[LE] = 10;
+        precedence[LT] = precedence[LE] = precedence[TYPEOF] = 10;
         precedence[SHEQ] = precedence[SHNE] = 11;
         precedence[LSH] = precedence[RSH] = precedence[URSH] = 12;
         precedence[ADD] = precedence[SUB] = 13;
@@ -133,7 +133,7 @@ class Parser extends Lexer implements ByteCodes {
 
     /** gets a token and throws an exception if it is not <tt>code</tt> */
     private void consume(int code) throws IOException {
-        if (getToken() != code) throw new ParserException("expected " + codeToString[code] + ", got " + (op == -1 ? "EOF" : codeToString[op]));
+        if (getToken() != code) throw pe("expected " + codeToString[code] + ", got " + (op == -1 ? "EOF" : codeToString[op]));
     }
 
     /**
@@ -142,17 +142,17 @@ class Parser extends Lexer implements ByteCodes {
      *  bytecodes for that expression to <tt>appendTo</tt>; the
      *  appended bytecodes MUST grow the stack by exactly one element.
      */ 
-    private void startExpr(CompiledFunction appendTo, int minPrecedence) throws IOException {
-       int saveParserLine = parserLine;
-       _startExpr(appendTo, minPrecedence);
-       parserLine = saveParserLine;
+    private void startExpr(CompiledFunctionImpl appendTo, int minPrecedence) throws IOException {
+        int saveParserLine = parserLine;
+        _startExpr(appendTo, minPrecedence);
+        parserLine = saveParserLine;
     }
-    private void _startExpr(CompiledFunction appendTo, int minPrecedence) throws IOException {
+    private void _startExpr(CompiledFunctionImpl appendTo, int minPrecedence) throws IOException {
         int tok = getToken();
-        CompiledFunction b = appendTo;
+        CompiledFunctionImpl b = appendTo;
 
         switch (tok) {
-        case -1: throw new ParserException("expected expression");
+        case -1: throw pe("expected expression");
 
         // all of these simply push values onto the stack
         case NUMBER: b.add(parserLine, LITERAL, number); break;
@@ -168,11 +168,11 @@ class Parser extends Lexer implements ByteCodes {
             if (peekToken() != RB)
                 while(true) {                                               // iterate over the initialization values
                     int size = b.size();
+                    b.add(parserLine, LITERAL, new Integer(i++));           // push the index in the array to place it into
                     if (peekToken() == COMMA || peekToken() == RB)
                         b.add(parserLine, LITERAL, null);                   // for stuff like [1,,2,]
                     else
                         startExpr(b, -1);                                   // push the value onto the stack
-                    b.add(parserLine, LITERAL, new Integer(i++));           // push the index in the array to place it into
                     b.add(parserLine, PUT);                                 // put it into the array
                     b.add(parserLine, POP);                                 // discard the value remaining on the stack
                     if (peekToken() == RB) break;
@@ -194,8 +194,8 @@ class Parser extends Lexer implements ByteCodes {
         }
         case INC: case DEC: {  // prefix (not postfix)
             startExpr(b, precedence[tok]);
-           if (b.get(b.size() - 1) != GET)
-               throw new ParserException("prefixed increment/decrement can only be performed on a valid assignment target");
+            if (b.get(b.size() - 1) != GET)
+                throw pe("prefixed increment/decrement can only be performed on a valid assignment target");
             b.set(b.size() - 1, tok, new Boolean(true));
             break;
         }
@@ -209,7 +209,7 @@ class Parser extends Lexer implements ByteCodes {
             if (peekToken() != RC)
                 while(true) {
                     if (peekToken() != NAME && peekToken() != STRING)
-                        throw new ParserException("expected NAME or STRING");
+                        throw pe("expected NAME or STRING");
                     getToken();
                     b.add(parserLine, LITERAL, string);                          // grab the key
                     consume(COLON);
@@ -224,15 +224,15 @@ class Parser extends Lexer implements ByteCodes {
             break;
         }
         case NAME: {
-           b.add(parserLine, TOPSCOPE);
-           b.add(parserLine, LITERAL, string);
-           continueExprAfterAssignable(b);
-           break;
+            b.add(parserLine, TOPSCOPE);
+            b.add(parserLine, LITERAL, string);
+            continueExprAfterAssignable(b);
+            break;
         }
         case FUNCTION: {
             consume(LP);
             int numArgs = 0;
-            CompiledFunction b2 = new CompiledFunction(sourceName, parserLine, null);
+            CompiledFunctionImpl b2 = new JS.CompiledFunction(sourceName, parserLine, null, null);
             b.add(parserLine, NEWFUNCTION, b2);
 
             // function prelude; arguments array is already on the stack
@@ -284,7 +284,7 @@ class Parser extends Lexer implements ByteCodes {
 
             break;
         }
-        default: throw new ParserException("expected expression, found " + codeToString[tok] + ", which cannot start an expression");
+        default: throw pe("expected expression, found " + codeToString[tok] + ", which cannot start an expression");
         }
 
         // attempt to continue the expression
@@ -299,18 +299,18 @@ class Parser extends Lexer implements ByteCodes {
      *  expression that modifies the assignable.  This method always
      *  decreases the stack depth by exactly one element.
      */
-    private void continueExprAfterAssignable(CompiledFunction b) throws IOException {
-       int saveParserLine = parserLine;
-       _continueExprAfterAssignable(b);
-       parserLine = saveParserLine;
+    private void continueExprAfterAssignable(CompiledFunctionImpl b) throws IOException {
+        int saveParserLine = parserLine;
+        _continueExprAfterAssignable(b);
+        parserLine = saveParserLine;
     }
-    private void _continueExprAfterAssignable(CompiledFunction b) throws IOException {
+    private void _continueExprAfterAssignable(CompiledFunctionImpl b) throws IOException {
         if (b == null) throw new Error("got null b; this should never happen");
         int tok = getToken();
-       switch(tok) {
+        switch(tok) {
         case ASSIGN_BITOR: case ASSIGN_BITXOR: case ASSIGN_BITAND: case ASSIGN_LSH: case ASSIGN_RSH: case ASSIGN_URSH:
         case ASSIGN_ADD: case ASSIGN_SUB: case ASSIGN_MUL: case ASSIGN_DIV: case ASSIGN_MOD: {
-           b.add(parserLine, GET_PRESERVE);
+            b.add(parserLine, GET_PRESERVE);
             startExpr(b, -1);
             b.add(parserLine, tok - 1);
             b.add(parserLine, PUT);
@@ -319,29 +319,34 @@ class Parser extends Lexer implements ByteCodes {
             break;
         }
         case INC: case DEC: { // postfix
-           b.add(parserLine, GET_PRESERVE);
-           b.add(parserLine, LITERAL, new Integer(1));
-           b.add(parserLine, tok == INC ? ADD : SUB);
-           b.add(parserLine, PUT);
-           b.add(parserLine, SWAP);
-           b.add(parserLine, POP);
-           b.add(parserLine, LITERAL, new Integer(1));
-           b.add(parserLine, tok == INC ? SUB : ADD);
-           break;
-        }
-       case ASSIGN: {
+            b.add(parserLine, GET_PRESERVE);
+            b.add(parserLine, LITERAL, new Integer(1));
+            b.add(parserLine, tok == INC ? ADD : SUB);
+            b.add(parserLine, PUT);
+            b.add(parserLine, SWAP);
+            b.add(parserLine, POP);
+            b.add(parserLine, LITERAL, new Integer(1));
+            b.add(parserLine, tok == INC ? SUB : ADD);
+            break;
+        }
+        case ASSIGN: {
             startExpr(b, -1);
-           b.add(parserLine, PUT);
-           b.add(parserLine, SWAP);
-           b.add(parserLine, POP);
-           break;
-       }
-       default: {
-           pushBackToken();
-           b.add(parserLine, GET);
-           return;
-       }
-       }
+            b.add(parserLine, PUT);
+            b.add(parserLine, SWAP);
+            b.add(parserLine, POP);
+            break;
+        }
+        case LP: {
+            int n = parseArgs(b);
+            b.add(parserLine,CALLMETHOD,new Integer(n));
+            break;
+        }
+        default: {
+            pushBackToken();
+            b.add(parserLine, GET);
+            return;
+        }
+        }
     }
 
 
@@ -356,12 +361,12 @@ class Parser extends Lexer implements ByteCodes {
      *  If any bytecodes are appended, they will not alter the stack
      *  depth.
      */
-    private void continueExpr(CompiledFunction b, int minPrecedence) throws IOException {
-       int saveParserLine = parserLine;
-       _continueExpr(b, minPrecedence);
-       parserLine = saveParserLine;
+    private void continueExpr(CompiledFunctionImpl b, int minPrecedence) throws IOException {
+        int saveParserLine = parserLine;
+        _continueExpr(b, minPrecedence);
+        parserLine = saveParserLine;
     }
-    private void _continueExpr(CompiledFunction b, int minPrecedence) throws IOException {
+    private void _continueExpr(CompiledFunctionImpl b, int minPrecedence) throws IOException {
         if (b == null) throw new Error("got null b; this should never happen");
         int tok = getToken();
         if (tok == -1) return;
@@ -372,17 +377,8 @@ class Parser extends Lexer implements ByteCodes {
 
         switch (tok) {
         case LP: {  // invocation (not grouping)
-            int i = 0;
-            while(peekToken() != RP) {
-                i++;
-                if (peekToken() != COMMA) {
-                    startExpr(b, -1);
-                    if (peekToken() == RP) break;
-                }
-                consume(COMMA);
-            }
-            consume(RP);
-            b.add(parserLine, CALL, new Integer(i));
+            int n = parseArgs(b);
+            b.add(parserLine, CALL, new Integer(n));
             break;
         }
         case BITOR: case BITXOR: case BITAND: case SHEQ: case SHNE: case LSH:
@@ -398,21 +394,21 @@ class Parser extends Lexer implements ByteCodes {
             startExpr(b, precedence[tok]);                                     // otherwise check the second value
             b.add(parserLine, JMP, new Integer(2));                            // leave the second value on the stack and jump to the end
             b.add(parserLine, LITERAL, tok == AND ?
-                 new Boolean(false) : new Boolean(true));                     // target of the short-circuit jump is here
+                  new Boolean(false) : new Boolean(true));                     // target of the short-circuit jump is here
             b.set(size - 1, new Integer(b.size() - size));                     // write the target of the short-circuit jump
             break;
         }
         case DOT: {
             consume(NAME);
-           b.add(parserLine, LITERAL, string);
-           continueExprAfterAssignable(b);
-           break;
+            b.add(parserLine, LITERAL, string);
+            continueExprAfterAssignable(b);
+            break;
         }
         case LB: { // subscripting (not array constructor)
             startExpr(b, -1);
             consume(RB);
-           continueExprAfterAssignable(b);
-           break;
+            continueExprAfterAssignable(b);
+            break;
         }
         case HOOK: {
             b.add(parserLine, JF, new Integer(0));                // jump to the if-false expression
@@ -435,14 +431,29 @@ class Parser extends Lexer implements ByteCodes {
         continueExpr(b, minPrecedence);                           // try to continue the expression
     }
     
+    // parse a set of comma separated function arguments, assume LP has already been consumed
+    private int parseArgs(CompiledFunctionImpl b) throws IOException {
+        int i = 0;
+        while(peekToken() != RP) {
+            i++;
+            if (peekToken() != COMMA) {
+                startExpr(b, -1);
+                if (peekToken() == RP) break;
+            }
+            consume(COMMA);
+        }
+        consume(RP);
+        return i;
+    }
+    
     /** Parse a block of statements which must be surrounded by LC..RC. */
-    void parseBlock(CompiledFunction b) throws IOException { parseBlock(b, null); }
-    void parseBlock(CompiledFunction b, String label) throws IOException {
-       int saveParserLine = parserLine;
-       _parseBlock(b, label);
-       parserLine = saveParserLine;
+    void parseBlock(CompiledFunctionImpl b) throws IOException { parseBlock(b, null); }
+    void parseBlock(CompiledFunctionImpl b, String label) throws IOException {
+        int saveParserLine = parserLine;
+        _parseBlock(b, label);
+        parserLine = saveParserLine;
     }
-    void _parseBlock(CompiledFunction b, String label) throws IOException {
+    void _parseBlock(CompiledFunctionImpl b, String label) throws IOException {
         if (peekToken() == -1) return;
         else if (peekToken() != LC) parseStatement(b, null);
         else {
@@ -453,12 +464,12 @@ class Parser extends Lexer implements ByteCodes {
     }
 
     /** Parse a single statement, consuming the RC or SEMI which terminates it. */
-    void parseStatement(CompiledFunction b, String label) throws IOException {
-       int saveParserLine = parserLine;
-       _parseStatement(b, label);
-       parserLine = saveParserLine;
+    void parseStatement(CompiledFunctionImpl b, String label) throws IOException {
+        int saveParserLine = parserLine;
+        _parseStatement(b, label);
+        parserLine = saveParserLine;
     }
-    void _parseStatement(CompiledFunction b, String label) throws IOException {
+    void _parseStatement(CompiledFunctionImpl b, String label) throws IOException {
         int tok = peekToken();
         if (tok == -1) return;
         switch(tok = getToken()) {
@@ -496,7 +507,7 @@ class Parser extends Lexer implements ByteCodes {
                 consume(COMMA);
             }
             b.add(parserLine, POP);                              // pop off the topscope
-            if ((mostRecentlyReadToken != RC || peekToken() == SEMI) && peekToken() != -1) consume(SEMI);
+            if ((mostRecentlyReadToken != RC || peekToken() == SEMI) && peekToken() != -1 && mostRecentlyReadToken != SEMI) consume(SEMI);
             break;
         }
         case IF: {
@@ -523,7 +534,7 @@ class Parser extends Lexer implements ByteCodes {
             if (label != null) b.add(parserLine, LABEL, label);
             b.add(parserLine, LOOP);
             int size = b.size();
-           b.add(parserLine, POP);                                   // discard the first-iteration indicator
+            b.add(parserLine, POP);                                   // discard the first-iteration indicator
             startExpr(b, -1);
             b.add(parserLine, JT, new Integer(2));                    // if the while() clause is true, jump over the BREAK
             b.add(parserLine, BREAK);
@@ -561,7 +572,7 @@ class Parser extends Lexer implements ByteCodes {
                     b.add(parserLine, BREAK);                      // break out of the loop if we 'fall through'
                     break;
                 } else {
-                    throw new ParserException("expected CASE, DEFAULT, or RC; got " + codeToString[peekToken()]);
+                    throw pe("expected CASE, DEFAULT, or RC; got " + codeToString[peekToken()]);
                 }
             b.set(size0 - 1, new Integer(b.size() - size0 + 1));      // end of the loop
             break;
@@ -585,37 +596,56 @@ class Parser extends Lexer implements ByteCodes {
         }
             
         case TRY: {
-            b.add(parserLine, TRY);
-            int size = b.size();
-            parseStatement(b, null);                                 // parse the expression to be TRYed
-            b.add(parserLine, POP);                                  // pop the TryMarker
-            b.add(parserLine, 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
+            b.add(parserLine, TRY); // try bytecode causes a TryMarker to be pushed
+            int tryInsn = b.size() - 1;
+            // parse the expression to be TRYed
+            parseStatement(b, null); 
+            // pop the try  marker. this is pushed when the TRY bytecode is executed                              
+            b.add(parserLine, POP);
+            // jump forward to the end of the catch block, start of the finally block                             
+            b.add(parserLine, JMP);                                  
+            int successJMPInsn = b.size() - 1;
             
+            if (peekToken() != CATCH && peekToken() != FINALLY)
+                throw pe("try without catch or finally");
+            
+            int catchJMPDistance = -1;
             if (peekToken() == CATCH) {
+                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);
+                b.add(parserLine, LITERAL,exceptionVar);
                 b.add(parserLine, SWAP);
                 b.add(parserLine, PUT);
                 b.add(parserLine, POP);
                 b.add(parserLine, POP);
                 parseStatement(b, null);
+                // pop the try and catch markers
+                b.add(parserLine,POP);
+                b.add(parserLine,POP);
             }
             
             // jump here if no exception was thrown
-            b.set(size2 - 1, new Integer(b.size() - size2 + 1)); 
-            
-            // FIXME: not implemented correctly
+            b.set(successJMPInsn, new Integer(b.size() - successJMPInsn)); 
+                        
+            int finallyJMPDistance = -1;
             if (peekToken() == FINALLY) {
+                b.add(parserLine, LITERAL, null); // null FinallyData
+                finallyJMPDistance = b.size() - tryInsn;
                 consume(FINALLY);
                 parseStatement(b, null);
+                b.add(parserLine,FINALLY_DONE); 
             }
+            
+            // setup the TRY arguments
+            b.set(tryInsn, new int[] { catchJMPDistance, finallyJMPDistance });
+            
             break;
         }
             
@@ -666,8 +696,8 @@ class Parser extends Lexer implements ByteCodes {
                 b.add(parserLine, NEWSCOPE);                             // grab a fresh scope
                     
                 parseStatement(b, null);                                 // initializer
-                CompiledFunction e2 =                                    // we need to put the incrementor before the test
-                    new CompiledFunction(sourceName, parserLine, null);  // so we save the test here
+                CompiledFunctionImpl e2 =                                    // we need to put the incrementor before the test
+                    new JS.CompiledFunction(sourceName, parserLine, null, null);  // so we save the test here
                 if (peekToken() != SEMI)
                     startExpr(e2, -1);
                 else
@@ -708,7 +738,7 @@ class Parser extends Lexer implements ByteCodes {
                 pushBackToken(NAME, possiblyTheLabel);  
                 startExpr(b, -1);
                 b.add(parserLine, POP);
-                if ((mostRecentlyReadToken != RC || peekToken() == SEMI) && peekToken() != -1) consume(SEMI);
+                if ((mostRecentlyReadToken != RC || peekToken() == SEMI) && peekToken() != -1 && mostRecentlyReadToken != SEMI) consume(SEMI);
                 break;
             }
         }
@@ -717,9 +747,9 @@ class Parser extends Lexer implements ByteCodes {
 
         case LC: {  // blocks are statements too
             pushBackToken();
-           b.add(parserLine, NEWSCOPE);
+            b.add(parserLine, NEWSCOPE);
             parseBlock(b, label);
-           b.add(parserLine, OLDSCOPE);
+            b.add(parserLine, OLDSCOPE);
             break;
         }
 
@@ -727,7 +757,7 @@ class Parser extends Lexer implements ByteCodes {
             pushBackToken();
             startExpr(b, -1);
             b.add(parserLine, POP);
-            if ((mostRecentlyReadToken != RC || peekToken() == SEMI) && peekToken() != -1) consume(SEMI);
+            if ((mostRecentlyReadToken != RC || peekToken() == SEMI) && peekToken() != -1 && mostRecentlyReadToken != SEMI) consume(SEMI);
             break;
         }
         }
@@ -735,8 +765,7 @@ class Parser extends Lexer implements ByteCodes {
 
 
     // ParserException //////////////////////////////////////////////////////////////////////
-    
-    private class ParserException extends IOException { public ParserException(String s) { super(sourceName + ":" + parserLine + " " + s); } }
+    private IOException pe(String s) { return new IOException(sourceName + ":" + parserLine + " " + s); }
     
 }