2004/01/08 05:32:44
[org.ibex.core.git] / src / org / xwt / js / Parser.java
index 3f61832..ee04b7e 100644 (file)
@@ -133,7 +133,16 @@ 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 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 +169,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 +314,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,19 +364,40 @@ class Parser extends Lexer implements ByteCodes {
             // force the default case
             tok = -1;
         switch(tok) {
+
+        case GRAMMAR: {
+            b.add(parserLine, GET_PRESERVE);
+            Grammar g = parseGrammar(null);
+            if (peekToken() == LC) {
+                g.action = new JSFunction(sourceName, parserLine, null);
+                parseBlock(g.action);
+                g.action.add(parserLine, LITERAL, null);         // in case we "fall out the bottom", return NULL              
+                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: {
-            b.add(parserLine, GET_PRESERVE);
+            if (tok != ASSIGN_ADD && tok != ASSIGN_SUB) b.add(parserLine, GET_PRESERVE);
+            
             startExpr(b,  precedence[tok]);
+            
             int size = b.size;
             if (tok == ASSIGN_ADD || tok == ASSIGN_SUB) {
                 b.add(parserLine, tok);
+                b.add(parserLine, GET);
+                b.add(parserLine, SWAP);
             }
+            
             // 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;
         }