2003/07/07 01:47:37
[org.ibex.core.git] / src / org / xwt / js / Parser.java
index 10159b7..9183c94 100644 (file)
@@ -111,13 +111,13 @@ class Parser extends Lexer implements ByteCodes {
             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;
@@ -194,9 +194,14 @@ class Parser extends Lexer implements ByteCodes {
         }
         case INC: case DEC: {  // prefix (not postfix)
             startExpr(b, precedence[tok]);
-            if (b.get(b.size() - 1) != GET)
+            int prev = b.size() - 1;
+            if (b.get(prev) == GET && b.getArg(prev) != null)
+                b.set(prev, LITERAL, b.getArg(prev));
+            else if(b.get(prev) == GET)
+                b.pop();
+            else
                 throw pe("prefixed increment/decrement can only be performed on a valid assignment target");
-            b.set(b.size() - 1, tok, new Boolean(true));
+            b.add(parserLine, tok, Boolean.TRUE);
             break;
         }
         case BANG: case BITNOT: case TYPEOF: {
@@ -236,38 +241,26 @@ class Parser extends Lexer implements ByteCodes {
             b.add(parserLine, NEWFUNCTION, b2);
 
             // function prelude; arguments array is already on the stack
-            b2.add(parserLine, TOPSCOPE);                                                // push the scope onto the stack
-            b2.add(parserLine, SWAP);                                                    // swap 'this' and 'arguments'
-
-            b2.add(parserLine, LITERAL, "arguments");                                    // declare arguments (equivalent to 'var arguments;')
-            b2.add(parserLine, DECLARE);
-
-            b2.add(parserLine, LITERAL, "arguments");                                    // set this.arguments and leave the value 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, SWAP);                                     // set this.arguments and leave the value on the stack
             b2.add(parserLine, PUT);
-            b2.add(parserLine, SWAP);
-            b2.add(parserLine, POP);
 
             while(peekToken() != RP) {                                    // run through the list of argument names
                 if (peekToken() == NAME) {
                     consume(NAME);                                        // a named argument
+                    String varName = string;
                     
-                    b2.add(parserLine, LITERAL, string);                  // declare the name
-                    b2.add(parserLine, DECLARE);
-                    
-                    b2.add(parserLine, LITERAL, new Integer(numArgs));    // retrieve it from the arguments array
-                    b2.add(parserLine, GET_PRESERVE);
+                    b2.add(parserLine, DUP);                              // dup the args array 
+                    b2.add(parserLine, GET, new Integer(numArgs));   // retrieve it from the arguments array
+                    b2.add(parserLine, TOPSCOPE);
                     b2.add(parserLine, SWAP);
-                    b2.add(parserLine, POP);
-                    
-                    b2.add(parserLine, TOPSCOPE);                         // put it to the current scope
-                    b2.add(parserLine, SWAP);
-                    b2.add(parserLine, LITERAL, string);
+                    b2.add(parserLine, DECLARE, varName);                  // declare the name
                     b2.add(parserLine, SWAP);
-                    b2.add(parserLine, PUT);
-                    
-                    b2.add(parserLine, POP);                              // clean the stack
-                    b2.add(parserLine, POP);
+                    b2.add(parserLine, PUT); 
+                    b2.add(parserLine, POP);                               // pop the value
+                    b2.add(parserLine, POP);                               // pop the scope                  
                 }
                 if (peekToken() == RP) break;
                 consume(COMMA);
@@ -276,11 +269,17 @@ class Parser extends Lexer implements ByteCodes {
             consume(RP);
 
             b2.add(parserLine, POP);                                      // pop off the arguments array
+            b2.add(parserLine, POP);                                      // pop off TOPSCOPE
+            
+           if(peekToken() != LC)
+                throw pe("Functions must have a block surrounded by curly brackets");
+                
+            parseBlock(b2, null);                                   // the function body
 
-            parseStatement(b2, null);                                     // the function body
-
-            b2.add(parserLine, LITERAL, null);                            // in case we "fall out the bottom", return NULL
-            b2.add(parserLine, RETURN);
+            if(b2.get(b2.size()-1) != RETURN) {
+                b2.add(parserLine, LITERAL, null);                        // in case we "fall out the bottom", return NULL
+                b2.add(parserLine, RETURN);
+            }
 
             break;
         }
@@ -336,9 +335,17 @@ class Parser extends Lexer implements ByteCodes {
             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);
+            if(b.get(b.size()-1) == LITERAL && b.getArg(b.size()-1) != null)
+                b.set(b.size()-1,GET,b.getArg(b.size()-1));
+            else
+                b.add(parserLine, GET);
             return;
         }
         }
@@ -372,17 +379,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:
@@ -435,6 +433,21 @@ 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(CompiledFunctionImpl b) throws IOException { parseBlock(b, null); }
     void parseBlock(CompiledFunctionImpl b, String label) throws IOException {
@@ -482,16 +495,15 @@ class Parser extends Lexer implements ByteCodes {
             b.add(parserLine, TOPSCOPE);                         // push the current scope
             while(true) {
                 consume(NAME);
-                String name = string;
-                b.add(parserLine, LITERAL, name);                // push the name to be declared
-                b.add(parserLine, DECLARE);                      // declare it
+                b.add(parserLine, DECLARE, string);               // declare it
                 if (peekToken() == ASSIGN) {                     // if there is an '=' after the variable name
-                    b.add(parserLine, LITERAL, name);            // put the var name back on the stack
                     consume(ASSIGN);
                     startExpr(b, -1);
                     b.add(parserLine, PUT);                      // assign it
                     b.add(parserLine, POP);                      // clean the stack
-                }
+                } else {
+                    b.add(parserLine, POP);                      // pop the string pushed by declare
+                }   
                 if (peekToken() != COMMA) break;
                 consume(COMMA);
             }
@@ -585,37 +597,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;
         }