2004/01/11 01:43:16
[org.ibex.core.git] / src / org / xwt / js / Parser.java
index 4bf273d..0583202 100644 (file)
@@ -314,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
@@ -334,6 +364,21 @@ 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: {
             if (tok != ASSIGN_ADD && tok != ASSIGN_SUB) b.add(parserLine, GET_PRESERVE);
@@ -682,20 +727,57 @@ class Parser extends Lexer implements ByteCodes {
             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,exceptionVar);
-                b.add(parserLine, SWAP);
-                b.add(parserLine, PUT);
-                b.add(parserLine, POP);
-                b.add(parserLine, POP);
-                parseStatement(b, null);
+                while(peekToken() == CATCH) {
+                    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, 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, LITERAL, number);
+                            b.add(parserLine, EQ);
+                            b.add(parserLine, JF);
+                            writebacks[1] = b.size - 1;
+                        }
+                    }
+                    consume(RP);
+                    // the exception is on top of the stack; put it to the chosen name
+                    b.add(parserLine, TOPSCOPE);
+                    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);
+                    b.add(parserLine, LITERAL, null);   // so we have something to pop
+                    for(int i=0; i<3; i++) if (writebacks[i] != -1) b.set(i, JS.N(b.size - i));
+                }
                 // pop the try and catch markers
                 b.add(parserLine,POP);
                 b.add(parserLine,POP);