2003/06/03 23:21:28
authormegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:00:40 +0000 (07:00 +0000)
committermegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:00:40 +0000 (07:00 +0000)
darcs-hash:20040130070040-2ba56-bbd1af048813eabe1fbeae3febc777578e594450.gz

src/org/xwt/js/Parser.java

index e99eaa7..c99ff71 100644 (file)
@@ -104,13 +104,67 @@ public class Parser extends Lexer {
        // these case arms match the precedence of operators; each arm is a precedence level.
        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:
-           return new Expr(curLine, ASSIGN, prefix, new Expr(curLine, tok - 1, prefix, parseMaximalExpr(null, precedence[ASSIGN])));
+       case VAR: {
+           if (prefix != null) { pushBackToken(); return prefix; }
+           ByteCode b = new ByteCode(curLine);
+           b.add(b.THIS, NO_ARG);
+           while(true) {
+               consume(NAME);
+               String name = string;
+               b.add(b.DECLARE, name);
+               if (peekToken() == ASSIGN) {
+                   b.add(b.LITERAL, name);
+                   consume(ASSIGN);
+                   b.add(b.EXPR, parseMaximalExpr());
+                   b.add(b.PUT, NO_ARG);
+                   b.add(b.POP, NO_ARG);
+               }
+               if (peekToken() != COMMA) break;
+               consume(COMMA);
+           }
+           return b;
+       }
 
-           // DONE //
+       case IN: pushBackToken(); return prefix;
+
+       case IF: {
+           if (prefix != null) { pushBackToken(); return prefix; }
+           ByteCode b = new ByteCode(curLine);
+           consume(LP);
+           b.add(b.EXPR, parseMaximalExpr());
+           consume(RP);
+           b.add(b.JF, new Integer(3));
+           b.add(b.EXPR, parseBlock(false));
+           b.add(b.JMP, new Integer(2));
+           if (peekToken() != ELSE) return b.add(b.LITERAL, null);
+           consume(ELSE);
+           b.add(b.EXPR, parseBlock(false));
+           return b;
+       }
 
            // FIXME: ugly hack!!
+        case ASSIGN_BITOR: if (tok == ASSIGN_BITOR) tok = BITOR;
+       case ASSIGN_BITXOR: if (tok == ASSIGN_BITXOR) tok = BITXOR;
+       case ASSIGN_BITAND: if (tok == ASSIGN_BITAND) tok = BITAND;
+       case ASSIGN_LSH: if (tok == ASSIGN_LSH) tok = LSH;
+       case ASSIGN_RSH: if (tok == ASSIGN_RSH) tok = RSH;
+       case ASSIGN_URSH: if (tok == ASSIGN_URSH) tok = URSH;
+       case ASSIGN_ADD: if (tok == ASSIGN_ADD) tok = ADD;
+       case ASSIGN_SUB: if (tok == ASSIGN_SUB) tok = SUB;
+       case ASSIGN_MUL: if (tok == ASSIGN_MUL) tok = MUL;
+       case ASSIGN_DIV: if (tok == ASSIGN_DIV) tok = DIV;
+       case ASSIGN_MOD: if (tok == ASSIGN_MOD) tok = MOD;
+           {
+               ByteCode b = (ByteCode)prefix;
+               b.set(b.size() - 1, b.GET_PRESERVE, new Boolean(true));
+               b.add(b.EXPR, parseMaximalExpr(null, precedence[tok]));
+               b.add(tok, NO_ARG);
+               b.add(b.PUT, NO_ARG);
+               b.add(b.SWAP, NO_ARG);
+               b.add(b.POP, NO_ARG);
+               return b;
+           }
+
        case INC: case DEC:
            if (prefix == null) {
                // prefix
@@ -265,9 +319,9 @@ public class Parser extends Lexer {
                while(true) {
                    Expr e = parseMaximalExpr();
                    if (e == null && peekToken() == RB) { consume(RB); return b; }
-                   if (e == null) e = new Expr(curLine, NULL);
                    b.add(b.LITERAL, new Integer(i++));
-                   b.add(b.EXPR, e);
+                   if (e == null) b.add(b.LITERAL, null);
+                   else b.add(b.EXPR, e);
                    b.add(b.PUT, NO_ARG);
                    b.add(b.POP, NO_ARG);
                    if (peekToken() == RB) { consume(RB); return b; }
@@ -324,69 +378,64 @@ public class Parser extends Lexer {
        case FUNCTION: {
            if (prefix != null) { pushBackToken(); return prefix; }
            consume(LP);
-           ExprList list = new ExprList(curLine, LC);
+           ByteCode b = new ByteCode(curLine);
+           int numArgs = 0;
+           b.add(b.THIS, NO_ARG);
+           b.add(b.SWAP, NO_ARG);
+           b.add(b.LITERAL, "arguments");
+           b.add(b.LITERAL, "arguments");
+           b.add(b.DECLARE, NO_ARG);
+           b.add(b.SWAP, NO_ARG);
+           b.add(b.PUT, NO_ARG);
+           b.add(b.SWAP, NO_ARG);
+           b.add(b.POP, NO_ARG);
            if (peekToken() == RP) consume(RP);
            else while(true) {
-               tok = peekToken();
-               if (tok == COMMA) {
+               if (peekToken() == COMMA) {
                    consume(COMMA);
-                   list.add(new Expr(curLine, NULL));
                } else {
                    consume(NAME);
-                   list.add(new Expr(curLine, NAME, string));
+
+                   // declare the name
+                   b.add(b.LITERAL, string);
+                   b.add(b.DECLARE, NO_ARG);
+
+                   // retrieve it from the arguments array
+                   b.add(b.LITERAL, new Integer(numArgs));
+                   b.add(b.GET_PRESERVE, NO_ARG);
+                   b.add(b.SWAP, NO_ARG);
+                   b.add(b.POP, NO_ARG);
+
+                   // put it to the current scope
+                   b.add(b.THIS, NO_ARG);
+                   b.add(b.SWAP, NO_ARG);
+                   b.add(b.LITERAL, string);
+                   b.add(b.SWAP, NO_ARG);
+                   b.add(b.PUT, NO_ARG);
+
+                   // clean the stack
+                   b.add(b.POP, NO_ARG);
+                   b.add(b.POP, NO_ARG);
+
                    if (peekToken() == RP) { consume(RP); break; }
                    consume(COMMA);
                }
+               numArgs++;
            }
-           return new Expr(curLine, FUNCTION, list, parseBlock(true));
+           // pop off the arguments array
+           b.add(b.POP, NO_ARG);
+           parseBlock(true, b);
+           return new ByteCode(curLine, b.FUNCTION, b);
        }
            
-       case VAR: {
-           if (prefix != null) { pushBackToken(); return prefix; }
-           ByteCode b = new ByteCode(curLine);
-           b.add(b.THIS, NO_ARG);
-           while(true) {
-               consume(NAME);
-               String name = string;
-               b.add(b.DECLARE, name);
-               if (peekToken() == ASSIGN) {
-                   b.add(b.LITERAL, name);
-                   consume(ASSIGN);
-                   b.add(b.EXPR, parseMaximalExpr());
-                   b.add(b.PUT, NO_ARG);
-                   b.add(b.POP, NO_ARG);
-               }
-               if (peekToken() != COMMA) break;
-               consume(COMMA);
-           }
-           return b;
-       }
-
-       case IN: pushBackToken(); return prefix;
-
-       case IF: {
-           if (prefix != null) { pushBackToken(); return prefix; }
-           ByteCode b = new ByteCode(curLine);
-           consume(LP);
-           b.add(b.EXPR, parseMaximalExpr());
-           consume(RP);
-           b.add(b.JF, new Integer(3));
-           b.add(b.EXPR, parseBlock(false));
-           b.add(b.JMP, new Integer(2));
-           if (peekToken() != ELSE) return b.add(b.LITERAL, null);
-           consume(ELSE);
-           b.add(b.EXPR, parseBlock(false));
-           return b;
-       }
-
            // Needs break //
 
        case SWITCH: {
            if (prefix != null) { pushBackToken(); return prefix; }
-           if (getToken() != LP) throw new ParserException("expected left paren");
+           consume(LP);
            Expr switchExpr = parseMaximalExpr();
-           if (getToken() != RP) throw new ParserException("expected left paren");
-           if (getToken() != LC) throw new ParserException("expected left brace");
+           consume(RP);
+           consume(LC);
            ExprList toplevel = new ExprList(curLine, LC);
            while(true) {
                tok = getToken();
@@ -519,6 +568,7 @@ public class Parser extends Lexer {
        public static final byte DECLARE = -6;     // < name >                      -- declare <name> in the current scope
        public static final byte THIS = -7;        //                               -- push the topmost non-transparent scope onto the stack
        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
@@ -562,7 +612,7 @@ public class Parser extends Lexer {
        public Object eval(final JS.Scope s) throws ControlTransferException, JS.Exn {
            return eval(s, new Parser.Thread());
        }
-       public Object eval(JS.Scope s, Parser.Thread t) throws ControlTransferException {
+       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;
@@ -595,6 +645,13 @@ public class Parser extends Lexer {
                    t.push(doGet(o, v));
                    break;
                }
+               case GET_PRESERVE: {
+                   Object v = t.pop();
+                   Object o = t.peek();
+                   t.push(v);
+                   t.push(doGet(o, v));
+                   break;
+               }
                case NOP: break;
                    
                case EXPR: t.push(((Expr)arg[i]).eval(s)); break;
@@ -610,7 +667,40 @@ public class Parser extends Lexer {
                    t.push(f.call(arguments));
                    break;
 
-               case FUNCTION: break;
+               case FUNCTION: {
+                   final ByteCode myBytes = (ByteCode)arg[i];
+                   t.push(new JS.Function() {
+                       public String toString() { return sourceName + ":" + line; }
+                       public String getSourceName() throws JS.Exn { return sourceName; }
+                       public Object _call(final JS.Array args) throws JS.Exn {
+                           Function save = JS.getCurrentFunction();
+                           JS.currentFunction.put(java.lang.Thread.currentThread(), this);
+                           JS.Scope scope = new JS.Scope(s) {
+                                   // FIXME
+                                   public String getSourceName() { return sourceName; }
+                                   public Object get(Object key) throws JS.Exn {
+                                       if (key.equals("trapee")) return org.xwt.Trap.currentTrapee();
+                                       else if (key.equals("cascade")) return org.xwt.Trap.cascadeFunction;
+                                       return super.get(key);
+                                   }
+                               };
+                           Parser.Thread t0 = new Parser.Thread();
+                           t0.push(args);
+                           try {
+                               return myBytes.eval(scope, t0);
+                           } catch (ReturnException r) {
+                               return r.retval;
+                           } catch (ControlTransferException c) {
+                               throw new EvaluatorException("error, ControlTransferException tried to leave a function: " + c);
+                           } finally {
+                               if (save == null) JS.currentFunction.remove(java.lang.Thread.currentThread());
+                               else JS.currentFunction.put(java.lang.Thread.currentThread(), save);
+                           }
+                       }
+                   });
+                   break;
+               }
+
                case RETURN: break;
                case TRY: break;
                case INSTANCEOF: break;
@@ -728,7 +818,7 @@ public class Parser extends Lexer {
                            if (args.length() != 1) return null;
                            return new Integer(((String)o).indexOf(args.elementAt(0).toString()));
                        } };
-               throw new Error("Not Implemented: properties on String objects");
+               throw new Error("Not Implemented: propery " + v + " on String objects");
            } else if (o instanceof Boolean) {
                throw new Error("Not Implemented: properties on Boolean objects");
            } else if (o instanceof Number) {
@@ -821,7 +911,8 @@ public class Parser extends Lexer {
     }
     
     /** a block is either a single statement or a list of statements surrounded by curly braces; all expressions are also statements */
-    public Expr parseBlock(boolean requireBraces) throws IOException {
+    public Expr parseBlock(boolean requireBraces) throws IOException { return parseBlock(requireBraces, null); }
+    public Expr parseBlock(boolean requireBraces, ByteCode b) throws IOException {
        Expr smt = null;
        int tok = peekToken();
        if (tok == -1) return null;
@@ -830,7 +921,7 @@ public class Parser extends Lexer {
        if (braced) consume(LC);
        int curLine = line;
        ByteCode ret = new ByteCode(curLine);
-       ByteCode block = new ByteCode(curLine);
+       ByteCode block = b == null ? new ByteCode(curLine) : b;
        block.add(ret.LITERAL, Boolean.TRUE);
        ret.add(block.SCOPE, block);
        while(true) {
@@ -950,6 +1041,7 @@ public class Parser extends Lexer {
        public Object eval(final JS.Scope s) throws ControlTransferException, JS.Exn {
            switch(code) {
 
+           case Lexer.NULL: return null;
            case Lexer.TYPEOF: {
                Object o = left.eval(s);
                if (o == null) return "null";
@@ -961,38 +1053,7 @@ public class Parser extends Lexer {
                throw new EvaluatorException("typeof " + o.getClass().getName() + " unknown");
            }
 
-           case Lexer.NUMBER: return number;
-           case Lexer.STRING: return string;
-
-           case Lexer.ASSIGN: {
-               Object v = (code == Lexer.ASSIGN) ? right.eval(s) : new Double(toDouble(left.eval(s)) + (code == Lexer.INC ? 1 : -1));
-               if (left.code == Lexer.DOT) {
-                   Object o = left.left.eval(s);
-                   if (o instanceof String) {
-                       throw new EvaluatorException("can't set properties on a String");
-                   } else if (o instanceof Number) {
-                       throw new EvaluatorException("can't set properties on a Number");
-                   } else if (o instanceof Boolean) {
-                       throw new EvaluatorException("can't set properties on a Boolean");
-                   } else {
-                       JS target = (JS)o;
-                       if (target == null) throw new JS.Exn(new EvaluatorException("attempted to put to the null value"));
-                       target.put(left.right.eval(s), v);
-                       return v;
-                   }
-               } else {
-                   s.put(left.string, v);
-                   return v;
-               }
-           }
-
-           case Lexer.NULL: return null;
-           case Lexer.FALSE: return Boolean.FALSE;
-           case Lexer.TRUE: return Boolean.TRUE;
-           case Lexer.ASSERT: if (!toBoolean(left.eval(s))) throw new EvaluatorException("assertion failed");
            case Lexer.THROW: throw new JS.Exn(left.eval(s));
-           case Lexer.NAME: return s.get(string);
-           case Lexer.THIS: return s.isTransparent() ? s : this.eval(s.getParentScope());
 
            case Lexer.TRY: {
                boolean safeToExit = false;
@@ -1019,43 +1080,6 @@ public class Parser extends Lexer {
                return null;
            }
 
-           case Lexer.FUNCTION:
-               return new JS.Function() {
-                       public String toString() { return right.sourceName + ":" + right.line; }
-                       public String getSourceName() throws JS.Exn { return right.sourceName; }
-                       public Object _call(final JS.Array args) throws JS.Exn {
-                           Function save = JS.getCurrentFunction();
-                           JS.currentFunction.put(java.lang.Thread.currentThread(), this);
-                           JS.Scope scope = new JS.Scope(s) {
-                                   // FIXME
-                                   public String getSourceName() { return sourceName; }
-                                   public Object get(Object key) throws JS.Exn {
-                                       if (key.equals("trapee")) return org.xwt.Trap.currentTrapee();
-                                       else if (key.equals("cascade")) return org.xwt.Trap.cascadeFunction;
-                                       else if (key.equals("arguments")) return args;
-                                       return super.get(key);
-                                   }
-                               };
-                           int i = 0;
-                           ExprList list = (ExprList)left;
-                           for(i=0; i<list.size(); i++) {
-                               scope.declare(list.elementAt(i).string);
-                               scope.put(list.elementAt(i).string, args.get(new Integer(i)));
-                           }
-                           try {
-                               return right.eval(scope);
-                           } catch (ReturnException r) {
-                               return r.retval;
-                           } catch (ControlTransferException c) {
-                               throw new EvaluatorException("error, ControlTransferException tried to leave a function: "
-                                                            + c);
-                           } finally {
-                               if (save == null) JS.currentFunction.remove(java.lang.Thread.currentThread());
-                               else JS.currentFunction.put(java.lang.Thread.currentThread(), save);
-                           }
-                       }
-                   };
-               
            case Lexer.FOR:
                Object[] keys = ((JS)left.right.eval(s)).keys();
                for(int i=0; i<keys.length; i++) {