2003/06/04 05:29:39
authormegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:00:43 +0000 (07:00 +0000)
committermegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:00:43 +0000 (07:00 +0000)
darcs-hash:20040130070043-2ba56-d12a8a751fe6c6dd84d7441afdaa645fc6df1ac3.gz

src/org/xwt/js/Parser.java

index 9af090f..6f55b50 100644 (file)
@@ -60,7 +60,7 @@ public class Parser extends Lexer {
 
     public void consume(int code) throws IOException {
        if (getToken() != code)
-           throw new ParserException("expected " + codeToString[op] + ", got " + (op == -1 ? "EOL" : codeToString[op]));
+           throw new ParserException("expected " + codeToString[code] + ", got " + (op == -1 ? "EOL" : codeToString[op]));
     }
 
     /** parses the largest possible expression */
@@ -489,63 +489,82 @@ public class Parser extends Lexer {
            return r;
        }
 
-           // Needs break //
-
-       case FOR:
-           if (prefix != null) { pushBackToken(); return prefix; }
-           if (getToken() != LP) throw new ParserException("expected left paren");
-           e1 = parseMaximalExpr();
-           if (peekToken() == IN) {
-               getToken();
-               e2 = parseMaximalExpr();
-               if (getToken() != RP) throw new ParserException("expected right paren");
-               return new Expr(curLine, FOR, new Expr(curLine, IN, e1.left, e2), parseBlock(false));
-               
-           } else {
-               Expr initExpr = e1;
-               if (initExpr == null) initExpr = new Expr(curLine, NULL);
-               consume(SEMI);
-               Expr whileExpr = parseMaximalExpr();
-               consume(SEMI);
-               Expr incExpr = parseMaximalExpr();
-               consume(RP);
-               Expr body = parseBlock(false);
-               Expr loop = new Expr(curLine, WHILE, whileExpr, body);
-               ExprList list = new ExprList(curLine, LC);
-               list.add(initExpr);
-               ExprList list2 = new ExprList(curLine, WHILE);
-               list.add(list2);
-               list2.add(whileExpr);
-               list2.add(body);
-               list2.add(incExpr);
-               return list;
-           }
-           
        case TRY: {
+           // FIXME: don't just ignore this!
            // We deliberately allow you to omit braces in catch{}/finally{} if they are single statements...
            if (prefix != null) { pushBackToken(); return prefix; }
            Expr tryBlock = parseBlock(true);
            
            tok = peekToken();
-           ExprList list = new ExprList(curLine, TRY);
            if (tok == CATCH) {
                getToken();
                if (getToken() != LP) throw new ParserException("expected (");
                if (getToken() != NAME) throw new ParserException("expected name");
-               Expr name = new Expr(curLine, NAME, string);
                if (getToken() != RP) throw new ParserException("expected )");
-               list.add(new Expr(curLine, CATCH, name, parseBlock(false)));
                tok = peekToken();
            }
-           if (tok == FINALLY) {
-               getToken();
-               list.add(new Expr(curLine, FINALLY, parseBlock(false)));
-           }
+           if (tok == FINALLY) getToken();
 
-           if (list.size() == 0) throw new ParserException("try without catch or finally");
-           return new Expr(curLine, TRY, tryBlock, list);
+           return tryBlock;
        }
 
+       case FOR: {
+           if (prefix != null) { pushBackToken(); return prefix; }
+           if (getToken() != LP) throw new ParserException("expected left paren");
+
+           tok = getToken();
+           if (tok == VAR) tok = getToken();
+           String varName = string;
+           boolean forIn = peekToken() == IN;
+           pushBackToken(tok, varName);
+
+           ByteCode b = new ByteCode(curLine);
+           if (forIn) {
+               consume(NAME);
+               consume(IN);
+               b.add(b.EXPR, parseMaximalExpr());
+               b.add(b.PUSHKEYS, NO_ARG);
+               b.add(b.LITERAL, "length");
+               b.add(b.GET, NO_ARG);
+               consume(RP);
+               ByteCode b2 = new ByteCode(curLine);
+               b.add(b.SCOPE, b2);
+               b2.add(b.LITERAL, new Integer(1));
+               b2.add(SUB, NO_ARG);
+               b2.add(b.DUP, NO_ARG);
+               b2.add(b.LITERAL, new Integer(0));
+               b2.add(LT, NO_ARG);
+               b2.add(b.JT, new Integer(7));
+               b2.add(b.GET_PRESERVE, NO_ARG);
+               b2.add(b.LITERAL, varName);
+               b2.add(b.LITERAL, varName);
+               b2.add(b.DECLARE, NO_ARG);
+               b2.add(b.PUT, NO_ARG);
+               b2.add(b.EXPR, parseBlock(false));
+               b2.add(b.LITERAL, null);
+               return b;
+               
+           } else {
+               ByteCode b2 = new ByteCode(curLine);
+               b.add(b.SCOPE, b2);
+               b2.add(b.EXPR, parseMaximalExpr());
+               b2.add(b.POP, NO_ARG);
+               consume(SEMI);
+               ByteCode b3 = new ByteCode(curLine);
+               b2.add(b.LOOP, b3);
+               b2.add(b.LITERAL, null);
+               b3.add(b.EXPR, parseMaximalExpr());
+               consume(SEMI);
+               b3.add(b.JT, new Integer(2));
+               b3.add(BREAK, NO_ARG);
+               b3.add(b.JT, new Integer(2));
+               b3.add(b.EXPR, parseMaximalExpr());
+               consume(RP);
+               parseBlock(false, b3);
+               return b;
+           }
+       }
+           
        default:
            pushBackToken();
            return prefix;
@@ -577,26 +596,20 @@ public class Parser extends Lexer {
        public static final byte GET = -8;         //                               -- get stack[0] from stack[1]
        public static final byte GET_PRESERVE = -80;         //                               -- get stack[0] from stack[1]
        public static final byte PUT = -9;         //                               -- put stack[1] to key stack[0] on stack[2]; leaves object on the stack
-       public static final byte THROW = -10;      //                               -- throw topmost element
-       public static final byte RETURN = -11;     //                               -- return the topmost value on the stack
-       public static final byte ASSERT = -12;     //                               -- fail if topmost element is not true
        public static final byte JT = -13;         // < relative_address >          -- pop the stack; if true, jump to <relative_address>
        public static final byte JF = -21;         // < relative_address >          -- pop the stack; if false, jump to <relative_address>
        public static final byte JMP = -22;        // < relative_address >          -- jump to <relative_address>
         static public final byte POP = -14;        //                               -- discard the top element on the stack
 
        public static final byte CALL = -15;       // < numargs >                   -- call stack[0] with the topmost <numargs> values as arguments
-       public static final byte TRY = -16;        // < bytecode_block >            -- run the block pointed to; returns with thrown exn on top of stack
-
-       public static final byte INSTANCEOF = -17; //                               -- ??
-       public static final byte TYPEOF = -18;     //                               --
 
-       public static final byte FOR__IN = -19;    //                               -- ??
+       public static final byte PUSHKEYS = -19;    //                               -- ??
        public static final byte EXPR = -20;       //                               -- transitional
        public static final byte SWAP = -23;       //                               -- transitional
        public static final byte SCOPE = -30;       //                               -- transitional
        public static final byte LOOP = -40;       //                               -- transitional
        public static final byte DUP = -50;       //                               -- transitional
+       public static final byte LABEL = -60;       //                               -- transitional
 
        int[] op = new int[10];
        Object[] arg = new Object[10];
@@ -624,22 +637,41 @@ public class Parser extends Lexer {
        public Object eval(final JS.Scope s, Parser.Thread t) throws ControlTransferException {
            for(int i=0; i<size; i++)
                switch(op[i]) {
-               case arithmetic: break;
-               case LITERAL:
-                   t.push(arg[i]);
-                   break;
+               case LABEL: break; // FIXME
+               case LITERAL: t.push(arg[i]); break;
                case OBJECT: t.push(new JS.Obj()); break;
                case ARRAY: t.push(new JS.Array(toNumber(arg[i]).intValue())); break;
                case DECLARE: s.declare(arg[i] == NO_ARG ? (String)t.pop() : (String)arg[i]); break;
                case THIS: t.push(s); break;   // FIXME: transparents
-               case ASSERT: if (!toBoolean(t.pop())) throw new EvaluatorException("assertion failed"); break;
-               case THROW: throw new JS.Exn(t.pop());
                case JT: if (toBoolean(t.pop())) i += toNumber(arg[i]).intValue() - 1; break;
                case JF: if (!toBoolean(t.pop())) i += toNumber(arg[i]).intValue() - 1; break;
                case JMP: i += toNumber(arg[i]).intValue() - 1; break;
                case POP: t.pop(); break;
                case SWAP: t.swap(); break;
                case DUP: t.push(t.peek()); break;
+               case NOP: break;
+               case EXPR: t.push(((Expr)arg[i]).eval(s)); break;
+               case SCOPE: t.push(((ByteCode)arg[i]).eval(new JS.Scope(s), t)); break;
+
+               case ASSERT: if (!toBoolean(t.pop())) throw new EvaluatorException("assertion failed"); break;
+               case RETURN: throw new ReturnException(t.pop());
+               case THROW: throw new JS.Exn(t.pop());
+
+               case TRY: break;
+               case INSTANCEOF: break;
+               case TYPEOF: break;
+               case PUSHKEYS: {
+                   Object o = t.peek();
+                   Object[] keys = ((JS)o).keys();
+                   JS.Array a = new JS.Array();
+                   a.setSize(keys.length);
+                   for(int j=0; j<keys.length; j++) a.setElementAt(keys[j], j);
+                   t.push(a);
+                   break;
+               }
+
+               case Lexer.BITNOT: t.push(new Long(~toLong(t.pop()))); break;
+               case Lexer.BANG: t.push(new Boolean(!toBoolean(t.pop()))); break;
                    
                case Lexer.BREAK: {
                    // FIXME: make sure this can only appear in proper places
@@ -683,6 +715,7 @@ public class Parser extends Lexer {
                    t.push(doGet(o, v));
                    break;
                }
+
                case GET_PRESERVE: {
                    Object v = t.pop();
                    Object o = t.peek();
@@ -690,12 +723,8 @@ public class Parser extends Lexer {
                    t.push(doGet(o, v));
                    break;
                }
-               case NOP: break;
                    
-               case EXPR: t.push(((Expr)arg[i]).eval(s)); break;
-               case SCOPE: t.push(((Expr)arg[i]).eval(new JS.Scope(s))); break;
-                   
-               case CALL:
+               case CALL: {
                    JS.Array arguments = new JS.Array();
                    int numArgs = toNumber(arg[i]).intValue();
                    arguments.setSize(numArgs);
@@ -704,6 +733,7 @@ public class Parser extends Lexer {
                    if (f == null) throw new JS.Exn(new EvaluatorException("attempted to call null"));
                    t.push(f.call(arguments));
                    break;
+               }
 
                case FUNCTION: {
                    final ByteCode myBytes = (ByteCode)arg[i];
@@ -739,15 +769,6 @@ public class Parser extends Lexer {
                    break;
                }
 
-               case RETURN: break;
-               case TRY: break;
-               case INSTANCEOF: break;
-               case TYPEOF: break;
-               case FOR__IN: break;
-
-               case Lexer.BITNOT: t.push(new Long(~toLong(t.pop()))); break;
-               case Lexer.BANG: t.push(new Boolean(!toBoolean(t.pop()))); break;
-
                case Lexer.INC: case Lexer.DEC: {
                    boolean isPrefix = toBoolean(arg[i]);
                    Object key = t.pop();
@@ -876,9 +897,7 @@ public class Parser extends Lexer {
        public void push(Object o) {
            os[size++] = o;
        }
-       public Object pop() {
-           return os[--size];
-       }
+       public Object pop() { return os[--size]; }
        public Object peek() { return os[size - 1]; }
        public void swap() { Object temp = os[size - 1]; os[size - 1] = os[size - 2]; os[size - 2] = temp; }
        public int size() { return size; }
@@ -969,31 +988,24 @@ public class Parser extends Lexer {
        while(true) {
            switch(tok = peekToken()) {
 
-           case LC:
-               smt = parseBlock(true); break;
+           case LC: smt = parseBlock(true); break;
+           case GOTO: throw new ParserException("goto not supported");
 
-           case THROW: case RETURN: case ASSERT:
+           case THROW: case RETURN: case ASSERT: {
                getToken();
-               if (peekToken() == SEMI) {
-                   if (tok == THROW || tok == ASSERT) throw new ParserException(codeToString[tok] + " requires an argument");
-                   consume(SEMI);
-                   smt = new Expr(curLine, tok);
-               } else {
-                   smt = new Expr(curLine, tok, parseMaximalExpr());
-                   consume(SEMI);
-               }
+               ByteCode r = new ByteCode(curLine);
+               if (tok == RETURN && peekToken() == SEMI) r.add(b.LITERAL, null);
+               else r.add(b.EXPR, parseMaximalExpr());
+               consume(SEMI);
+               r.add(tok, NO_ARG);
+               smt = r;
                break;
+           }
 
-           case GOTO: case BREAK: case CONTINUE: {
+           case BREAK: case CONTINUE: {
                getToken();
-               int t = peekToken();
-               if (t == NAME) {
-                   getToken();
-                   smt = new Expr(curLine, tok, new Expr(curLine, string));
-               } else if (tok == GOTO) {
-                   throw new ParserException("goto must be followed by a label");
-               }
-               smt = new Expr(curLine, tok, new Expr(curLine, string));
+               if (peekToken() == NAME) consume(NAME);
+               smt = new ByteCode(curLine, tok, string);
                consume(SEMI);
                break;
            }
@@ -1012,7 +1024,7 @@ public class Parser extends Lexer {
                consume(NAME);
                if (peekToken() == COLON) {
                    consume(COLON);
-                   smt = new Expr(curLine, COLON, new Expr(curLine, name), parseBlock(false));
+                   smt = new ByteCode(curLine, ByteCode.LABEL, string);
                    break;
                } else {
                    pushBackToken(NAME, name);
@@ -1095,8 +1107,6 @@ public class Parser extends Lexer {
                throw new EvaluatorException("typeof " + o.getClass().getName() + " unknown");
            }
 
-           case Lexer.THROW: throw new JS.Exn(left.eval(s));
-
            case Lexer.TRY: {
                boolean safeToExit = false;
                try {
@@ -1139,26 +1149,6 @@ public class Parser extends Lexer {
                }
                return null;
 
-           case Lexer.SWITCH:
-               Object switchVal = left.eval(s);
-               boolean go = false;
-               try {
-                   ExprList list = (ExprList)right;
-                   for(int i=0; i<list.size(); i++) {
-                       Expr e = list.elementAt(i);
-                       if (go || e.code == Lexer.DEFAULT || e.left.eval(s).equals(switchVal)) go = true;
-                       if (go) e.right.eval(s);
-                   }
-               } catch (BreakException b) {
-                   if (b.label == null || b.label.equals(string)) return null;
-                   throw (BreakException)b.fillInStackTrace();
-               }
-               return null;
-
-           case Lexer.BREAK: throw new BreakException(string);
-           case Lexer.CONTINUE: throw new ContinueException(string);
-           case Lexer.RETURN: throw new ReturnException(left == null ? null : left.eval(s));
-
            default: throw new EvaluatorException("don't know how to eval an Expr with code " + Lexer.codeToString[code] + "\n" + this);
            }
        }