2003/06/03 00:53:07
authormegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:00:37 +0000 (07:00 +0000)
committermegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:00:37 +0000 (07:00 +0000)
darcs-hash:20040130070037-2ba56-a60521fd8558545921a99e6e7bac2f6a6a3791b2.gz

src/org/xwt/js/Lexer.java
src/org/xwt/js/Parser.java

index e8cd2d4..d7a5725 100644 (file)
@@ -29,21 +29,18 @@ class Lexer {
            System.out.println(codeToString[tok]);
     }
 
-    private SmartReader in;
-    private boolean pushedBack = false;
-
     public int op;
-    public int twoBack;
+    public Number number = null;
+    public String string = null;
+
     public int line = 0;
     public int col = 0;
+
+    private SmartReader in;
     public String sourceName = "unknown";
-    public Number number;
-    public String string;
 
     public Lexer(Reader r) throws IOException { in = new SmartReader(r); }
-    public int peekToken() throws IOException { int ret = getToken(); pushBackToken(); return ret; }
-    public void pushBackToken() { pushBackToken(op); }
-    public void pushBackToken(int i) { if (pushedBack) throw new Error("can't push back twice"); pushedBack = true; op = i; }
+
 
     // Token Constants //////////////////////////////////////////////////////////
 
@@ -389,16 +386,6 @@ class Lexer {
         return STRING;
     }
 
-    public int getToken() throws IOException {
-       if (pushedBack) { pushedBack = false; return op; }
-       do {
-           if (op != EOL) twoBack = op;
-           op = _getToken();
-           if (op == EOL) { line++; col = 0; }
-       } while (op == EOL);
-       return op;
-    }
-
     public int _getToken() throws IOException {
         int c;
         do { if ((c = in.read()) == '\n') break; } while (isWhiteSpace(c) || c == '\n');
@@ -488,4 +475,50 @@ class Lexer {
         }
     }
 
+
+    // PushBack Stuff ////////////////////////////////////////////////////////////
+
+    int pushBackDepth = 0;
+    int[] pushBackInts = new int[10];
+    Object[] pushBackObjects = new Object[10];
+
+    public void pushBackToken() {
+       if (pushBackDepth >= pushBackInts.length - 1) {
+           int[] newInts = new int[pushBackInts.length * 2];
+           System.arraycopy(pushBackInts, 0, newInts, 0, pushBackInts.length);
+           pushBackInts = newInts;
+           Object[] newObjects = new Object[pushBackObjects.length * 2];
+           System.arraycopy(pushBackObjects, 0, newObjects, 0, pushBackObjects.length);
+           pushBackObjects = newObjects;
+       }
+       pushBackInts[pushBackDepth] = op;
+       pushBackObjects[pushBackDepth] = number != null ? (Object)number : (Object)string;
+       pushBackDepth++;
+    }
+
+    public int peekToken() throws IOException {
+       int ret = getToken();
+       pushBackToken();
+       return ret;
+    }
+
+    public int getToken() throws IOException {
+       number = null;
+       string = null;
+       if (pushBackDepth > 0) {
+           pushBackDepth--;
+           op = pushBackInts[pushBackDepth];
+           if (pushBackObjects[pushBackDepth] != null) {
+               number = pushBackObjects[pushBackDepth] instanceof Number ? (Number)pushBackObjects[pushBackDepth] : null;
+               string = pushBackObjects[pushBackDepth] instanceof String ? (String)pushBackObjects[pushBackDepth] : null;
+           }
+       } else {
+           do {
+               op = _getToken();
+               if (op == EOL) { line++; col = 0; }
+           } while (op == EOL);
+       }
+       return op;
+    }
+
 }
index ba343cf..b7456fe 100644 (file)
@@ -16,6 +16,7 @@ public class Parser extends Lexer {
        this.line = line;
     }
 
+    /** for debugging */
     public static void main(String[] s) throws Exception {
        Parser p = new Parser(new InputStreamReader(System.in), "stdin", 0);
        while(true) {
@@ -57,94 +58,13 @@ public class Parser extends Lexer {
 
     // Parsing Logic /////////////////////////////////////////////////////////
 
-    /** 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 {
-       Expr ret = null;
-       int tok = peekToken();
-       if (tok == -1) return null;
-       boolean braced = tok == LC;
-       if (requireBraces && !braced) throw new ParserException("expected {");
-       if (braced) getToken();
-       Expr head = null;
-       Expr tail = null;
-       int curLine = line;
-       OUTER: while(true) {
-           Expr smt;
-
-           switch(tok = peekToken()) {
-           case -1: break OUTER;
-           case LC: smt = parseBlock(true); break;
-           case THROW: case RETURN: case ASSERT:
-               getToken();
-               if (peekToken() == SEMI) {
-                   getToken();
-                   smt = new Expr(curLine, tok);
-                   break;
-               }
-               smt = new Expr(curLine, tok, parseMaximalExpr());
-               if (getToken() != SEMI) throw new ParserException("expected ;");
-               break;
-
-               /*
-                 FIXME
-           case NAME: {
-               getToken();
-               String str = string;
-               if (getToken() != COLON) throw new ParserException("expected COLON after label");
-               Expr labeledBlock = parseBlock(false);
-               if (labeledBlock.code != WHILE && labeledBlock.code != FOR && labeledBlock.code != SWITCH) 
-                   throw new ParserException("you can only label a WHILE, FOR, or SWITCH block");
-               labeledBlock.string = str;
-               return labeledBlock;
-           }
-               */
-
-           case GOTO: case BREAK: case CONTINUE: {
-               getToken();
-               int t = peekToken();
-               if (t == NAME) {
-                   getToken();
-                   smt = new Expr(curLine, tok, new Expr(curLine, string));
-               } else if (t == GOTO) {
-                   throw new ParserException("goto must be followed by a label");
-               } else if (t == SEMI) {
-                   getToken();
-                   smt = new Expr(curLine, tok);
-               } else {
-                   throw new ParserException(codeToString[tok] + " followed by a " + codeToString[t] + "; expected NAME or SEMI");
-               }
-               break;
-           }
-
-           case RC:
-               if (braced) getToken();
-               break OUTER;
-
-           case SEMI:
-               getToken();
-               if (!braced) break OUTER;
-               continue;
-
-           default:
-               smt = parseMaximalExpr();
-               if (smt == null) {
-                   if (head == null) return null;
-                   break OUTER;
-               }
-               if (peekToken() == SEMI) getToken();
-               break;
-           }
-           if (!braced) return smt;
-           if (head == null) head = tail = smt; else tail = (tail.next = smt);
-       }
-       return new Expr(curLine, LC, head);
+    public void consume(int code) throws IOException {
+       int got = getToken();
+       if (got != code) throw new ParserException("expected " + codeToString[code] + ", got " + (got == -1 ? "EOL" : codeToString[got]));
     }
-
-    /** throws an error if the next token is not <tt>code</tt> */
     public void expect(int code) throws IOException {
        int got = peekToken();
-       if (got != code)
-           throw new ParserException("expected " + codeToString[code] + ", got " + (got == -1 ? "EOL" : codeToString[got]));
+       if (got != code) throw new ParserException("expected " + codeToString[code] + ", got " + (got == -1 ? "EOL" : codeToString[got]));
     }
 
     /** parses the largest possible expression */
@@ -238,54 +158,56 @@ public class Parser extends Lexer {
                return r;
 
            } else {  // invocation
+               ExprList list = new ExprList(curLine, LP);
                while(peekToken() != RP) {
-                   Expr e = parseMaximalExpr();
-                   if (head == null) head = tail = e; else tail = tail.next = e;
-                   tok = getToken();
-                   if (tok == RP) { pushBackToken(); break; }
-                   if (tok != COMMA) throw new ParserException("expected comma or right paren, got " + codeToString[tok]);
+                   list.add(parseMaximalExpr());
+                   if (peekToken() == RP) break;
+                   consume(COMMA);
                }
                getToken();
-               return new Expr(curLine, LP, prefix, head);
+               return new Expr(curLine, LP, prefix, list);
            }
 
        case LB:
-           if (prefix != null) {
-               // subscripting
-               e1 = parseMaximalExpr();
-               if (getToken() != RB) throw new ParserException("expected a right brace");
-               return new Expr(curLine, DOT, prefix, e1);
-           } else {
+           if (prefix == null) {
                // array ctor
+               ExprList list = new ExprList(curLine, LB);
                while(true) {
-                   if (peekToken() == RB) { getToken(); return new Expr(curLine, LB, prefix, head); }
-                   Expr eee = parseMaximalExpr();
-                   if (eee != null) {
-                       if (head == null) head = tail = eee;
-                       else tail.next = tail = eee;
+                   Expr e = parseMaximalExpr();
+                   if (e != null) {
+                       list.add(e);
+                   } else {
+                       if (peekToken() == COMMA) list.add(new Expr(curLine, NULL));
                    }
-                   tok = getToken();
-                   if (tok == RB) return new Expr(curLine, LB, prefix, head);
-                   if (tok != COMMA) throw new ParserException("expected right bracket or comma");
+                   if (peekToken() == RB) { consume(RB); return list; }
+                   consume(COMMA);
                }
+           } else {
+               // subscripting
+               e1 = parseMaximalExpr();
+               if (getToken() != RB) throw new ParserException("expected a right brace");
+               return new Expr(curLine, DOT, prefix, e1);
            }
            
-       case LC:
+       case LC: {
+           // object ctor
            if (prefix != null) { pushBackToken(); return prefix; }
            tok = getToken();
-           if (tok == RC) return new Expr(curLine, RC, head);
+           ExprList list = new ExprList(curLine, RC);
+           if (tok == RC) return list;
            while(true) {
                if (tok != NAME && tok != STRING) throw new ParserException("expecting name, got " + codeToString[tok]);
                Expr name = new Expr(curLine, NAME, string);
                if (getToken() != COLON) throw new ParserException("expecting colon");          
                e1 = new Expr(curLine, COLON, name, parseMaximalExpr());
-               if (head == null) head = tail = e1; else tail = tail.next = e1;
+               list.add(e1);
                tok = getToken();
                if (tok != COMMA && tok != RC) throw new ParserException("expected right curly or comma, got " + codeToString[tok]);
-               if (tok == RC) return new Expr(curLine, RC, head);
+               if (tok == RC) return list;
                tok = getToken();
-               if (tok == RC) return new Expr(curLine, RC, head);
+               if (tok == RC) return list;
            }
+       }
            
        case HOOK:
            e2 = parseMaximalExpr();
@@ -299,52 +221,48 @@ public class Parser extends Lexer {
            Expr switchExpr = parseMaximalExpr();
            if (getToken() != RP) throw new ParserException("expected left paren");
            if (getToken() != LC) throw new ParserException("expected left brace");
-           Expr firstExpr = null;
-           Expr lastExpr = null;
+           ExprList toplevel = new ExprList(curLine, LC);
            while(true) {
                tok = getToken();
                Expr caseExpr;
-               if (tok == DEFAULT) {
-                   caseExpr = null;
-               } else if (tok == CASE) {
-                   // FIXME: we don't support non-brace-enclosed CASE blocks
-                   caseExpr = parseMaximalExpr();
-               } else {
-                   throw new ParserException("expected CASE");
-               }
-               expect(COLON); getToken();
-               head = tail = null;
+               if (tok == DEFAULT) caseExpr = null;
+               else if (tok == CASE) caseExpr = parseMaximalExpr();
+               else throw new ParserException("expected CASE or DEFAULT");
+               consume(COLON);
+               // FIXME: we shouldn't be creating a scope here
+               ExprList list = new ExprList(curLine, LC);
                while(peekToken() != CASE && peekToken() != DEFAULT && peekToken() != RC) {
-                   e1 = parseBlock(false);
-                   if (e1 == null) break;
-                   if (head == null) head = tail = e1; else tail = tail.next = e1;
+                   if ((e1 = parseBlock(false)) == null) break;
+                   list.add(e1);
                }
-               e1 = new Expr(curLine, tok, caseExpr, new Expr(curLine, LC, head));
-               if (lastExpr == null) firstExpr = e1; else lastExpr.next = e1;
-               lastExpr = e1;
-               if (peekToken() == RC) {getToken(); return new Expr(curLine, SWITCH, switchExpr, firstExpr); }
+               toplevel.add(new Expr(curLine, tok, caseExpr, list));
+               if (peekToken() == RC) { consume(RC); return new Expr(curLine, SWITCH, switchExpr, toplevel); }
            }
        }
            
        case FUNCTION: {
            if (prefix != null) { pushBackToken(); return prefix; }
-           if (getToken() != LP) throw new ParserException("function keyword must be followed by a left paren");
-           Expr formalArgs = null, cur = null;
-           tok = getToken();
-           while(tok != RP) {
-               if (tok != NAME) throw new ParserException("expected a variable name");
-               if (cur == null) { formalArgs = cur = new Expr(curLine, string); }
-               else { cur.next = new Expr(curLine, NAME, string); cur = cur.next; }
-               tok = getToken();
-               if (tok == RP) break;
-               if (tok != COMMA) throw new ParserException("function argument list must consist of alternating NAMEs and COMMAs");
-               tok = getToken();
+           consume(LP);
+           ExprList list = new ExprList(curLine, LC);
+           if (peekToken() == RP) consume(RP);
+           else while(true) {
+               tok = peekToken();
+               if (tok == COMMA) {
+                   consume(COMMA);
+                   list.add(new Expr(curLine, NULL));
+               } else {
+                   consume(NAME);
+                   list.add(new Expr(curLine, NAME, string));
+                   if (peekToken() == RP) { consume(RP); break; }
+                   consume(COMMA);
+               }
            }
-           return new Expr(curLine, FUNCTION, formalArgs, parseBlock(true));
+           return new Expr(curLine, FUNCTION, list, parseBlock(true));
        }
            
-       case VAR:
+       case VAR: {
            if (prefix != null) { pushBackToken(); return prefix; }
+           ExprList list = new ExprList(curLine, VAR);
            while(true) {
                if (getToken() != NAME) throw new ParserException("variable declarations must start with a variable name");
                String name = string;
@@ -363,11 +281,12 @@ public class Parser extends Lexer {
                } else {
                    e = new Expr(curLine, VAR, new Expr(curLine, name));
                }
-               if (head == null) head = tail = e; else tail = tail.next = e;
+               list.add(e);
                if (tok != COMMA) break;
                getToken();
            }
-           return new Expr(curLine, VAR, head);
+           return list;
+       }
 
        case TRY: {
            // We deliberately allow you to omit braces in catch{}/finally{} if they are single statements...
@@ -375,23 +294,23 @@ public class Parser extends Lexer {
            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 )");
-               head = tail = new Expr(curLine, CATCH, name, parseBlock(false));
+               list.add(new Expr(curLine, CATCH, name, parseBlock(false)));
                tok = peekToken();
            }
            if (tok == FINALLY) {
                getToken();
-               e1 = new Expr(curLine, FINALLY, parseBlock(false));
-               if (head == null) head = tail = e1; else tail = tail.next = e1;
+               list.add(new Expr(curLine, FINALLY, parseBlock(false)));
            }
 
-           if (head == null) throw new ParserException("try without catch or finally");
-           return new Expr(curLine, TRY, tryBlock, head);
+           if (list.size() == 0) throw new ParserException("try without catch or finally");
+           return new Expr(curLine, TRY, tryBlock, list);
        }
 
        case IF: case WHILE: {
@@ -405,7 +324,14 @@ public class Parser extends Lexer {
                getToken();
                return new Expr(curLine, tok, parenExpr, new Expr(curLine, ELSE, firstBlock, parseBlock(false)));
            } else {
-               return new Expr(curLine, tok, parenExpr, firstBlock);
+               if (tok == IF) return new Expr(curLine, tok, parenExpr, firstBlock);
+               if (tok == WHILE) {
+                   ExprList list = new ExprList(curLine, WHILE);
+                   list.add(parenExpr);
+                   list.add(firstBlock);
+                   list.add(new Expr(curLine, NULL));
+                   return list;
+               }
            }
        }
 
@@ -423,27 +349,36 @@ public class Parser extends Lexer {
                
            } else {
                Expr initExpr = e1;
+               if (initExpr == null) initExpr = new Expr(curLine, NULL);
                expect(SEMI); getToken();
                Expr whileExpr = parseMaximalExpr();
                expect(SEMI); getToken();
                Expr incExpr = parseMaximalExpr();
                expect(RP); getToken();
                Expr body = parseBlock(false);
-               body.next = incExpr;
                Expr loop = new Expr(curLine, WHILE, whileExpr, body);
-               if (initExpr == null) initExpr = loop; else initExpr.next = loop;
-               return new Expr(curLine, LC, initExpr);
+               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 DO: {
            if (prefix != null) { pushBackToken(); return prefix; }
-           Expr firstBlock = parseBlock(false);
-           if (getToken() != WHILE) throw new ParserException("expecting WHILE");
-           if (getToken() != LP) throw new ParserException("expected left paren");
-           Expr whileExpr = parseMaximalExpr();
-           if (getToken() != RP) throw new ParserException("expected right paren");
-           if (getToken() != SEMI) throw new ParserException("semicolon");
-           return new Expr(curLine, DO, firstBlock, whileExpr);
+           ExprList list = new ExprList(curLine, DO);
+           Expr body = parseBlock(false);
+           consume(WHILE);
+           consume(LP);
+           list.add(parseMaximalExpr());
+           list.add(body);
+           list.add(new Expr(curLine, NULL));
+           consume(RP);
+           consume(SEMI);
+           return list;
        }
            
        default:
@@ -454,13 +389,163 @@ public class Parser extends Lexer {
     
     // Expr //////////////////////////////////////////////////////////////////////
 
+    class ExprList extends Expr {
+       Vec v = new Vec();
+       public ExprList(int curLine, int code) { super(curLine, code); }
+       public void add(Expr e) { v.addElement(e); }
+       public int numExprs() { return v.size(); }
+       public int size() { return v.size(); }
+       public Expr elementAt(int i) { return (Expr)v.elementAt(i); }
+       public Object eval(final JS.Scope s) throws ControlTransferException, JS.Exn {
+           switch(code) {
+           case LC: {
+               // Block
+               JS.Scope scope = new JS.Scope(s);
+               for(int i=0; i<v.size(); i++) ((Expr)v.elementAt(i)).eval(scope);
+               return null;
+           }
+           case Lexer.LB: {
+               // Array ctor
+               JS.Array ret = new JS.Array();
+               for(int i=0; i<numExprs(); i++) ret.addElement(elementAt(i).eval(s));
+               return ret;
+           }
+           case Lexer.RC: {
+               // Object ctor
+               JS.Obj ret = new JS.Obj();
+               for(int i=0; i<numExprs(); i++) {
+                   Expr e = elementAt(i);
+                   Object key = e.left.string;
+                   Object val = e.right.eval(s);
+                   ret.put(key, val);
+               }
+               return ret;
+           }
+           case Lexer.WHILE:
+           case Lexer.DO:
+               try {
+                   boolean first = true;
+                   Object bogus = null;
+                   ExprList list = this;
+                   Expr whileExpr = list.elementAt(0);
+                   Expr bodyExpr = list.elementAt(1);
+                   Expr incExpr = list.elementAt(2);
+                   for(;(first && code == Lexer.DO) || toBoolean(whileExpr.eval(s)); bogus = incExpr.eval(s)) {
+                       first = false;
+                       try { bodyExpr.eval(s);
+                       } catch (ContinueException c) {
+                           if (c.label == null || c.label.equals(string)) continue;
+                       } catch (BreakException b) {
+                           if (b.label == null || b.label.equals(string)) return null;
+                           throw (BreakException)b.fillInStackTrace();
+                       }
+                   }
+               } catch (BreakException e) {
+                   if (e.label != null && !e.label.equals(string)) throw e;
+               }
+               return null;
+           case Lexer.VAR:
+               for(int i=0; i<size(); i++) {
+                   Expr e = elementAt(i);
+                   s.declare(e.left.string);
+                   if (e.right != null) e.right.eval(s);
+               }
+               return null;
+           default: throw new Error("augh!");
+           }
+       }
+    }
+    
+    /** 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 {
+       Expr smt = null;
+       int tok = peekToken();
+       if (tok == -1) return null;
+       boolean braced = tok == LC;
+       if (requireBraces && !braced) throw new ParserException("expected {, got " + codeToString[tok]);
+       if (braced) getToken();
+       int curLine = line;
+       ExprList block = new ExprList(curLine, LC);
+       while(true) {
+           switch(tok = peekToken()) {
+
+           case -1:
+               return block;
+
+           case LC:
+               smt = parseBlock(true); break;
+
+           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);
+               }
+               break;
+
+           case GOTO: 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));
+               consume(SEMI);
+               break;
+           }
+               
+           case RC:
+               if (braced) consume(RC);
+               return block;
+               
+           case SEMI:
+               consume(SEMI);
+               if (!braced) return block;
+               continue;
+               
+/*  FIXME: LL(2)
+           case NAME: {
+               String name = string;
+               getToken();
+               if (peekToken() == COLON) {
+                   smt = new Expr(curLine, COLON, new Expr(curLine, name), parseBlock(false));
+                   break;
+               } else {
+                   pushBackToken(tok);
+                   string = name;
+                   // fall through to default case
+               }
+           }
+*/             
+           default:
+               smt = parseMaximalExpr();
+               if (smt == null) {
+                   if (block.numExprs() == 0) return null;
+                   return block;
+               }
+               if (peekToken() == SEMI) getToken();
+               break;
+           }
+
+           if (!braced) return smt;
+           block.add(smt);
+       }
+    }
+    
+
     /** sorta like gcc trees */
     class Expr {
        int code = -1;
     
        final Expr left;
        final Expr right;
-       Expr next = null;   // if this expr is part of a list
        int line = -1;
        String sourceName = "unknown";
     
@@ -477,7 +562,6 @@ public class Parser extends Lexer {
            ret += "\n";
            if (left != null) ret += left.toString(indent + 2);
            if (right != null) ret += right.toString(indent + 2);
-           if (next != null) ret += next.toString(indent);
            return ret;
        }
     
@@ -669,12 +753,13 @@ public class Parser extends Lexer {
                    safeToExit = true;
                    return ret;
                } catch (JS.Exn e) {
-                   Expr c = right;
+                   ExprList list = (ExprList)right;
+                   Expr c = list.elementAt(0);
                    if (c.code == Lexer.CATCH) {
                        JS.Scope scope = new JS.Scope(s);
                        s.put(c.left.string, e);
                        c.right.eval(scope);
-                       c = c.next;
+                       c = list.elementAt(1);
                    }
                    if (c.code == Lexer.FINALLY) {
                        JS.Scope scope = new JS.Scope(s);
@@ -689,7 +774,7 @@ public class Parser extends Lexer {
            case Lexer.LP:
                JS.Function f = (JS.Function)left.eval(s);
                JS.Array arguments = new JS.Array();
-               for(Expr e = right; e != null; e = e.next) arguments.addElement(e.eval(s));
+               for(int i=0; i<((ExprList)right).numExprs(); i++) arguments.addElement(((ExprList)right).elementAt(i).eval(s));
                if (f == null) throw new JS.Exn(new EvaluatorException("attempted to call null"));
                return f.call(arguments);
            
@@ -711,9 +796,10 @@ public class Parser extends Lexer {
                                    }
                                };
                            int i = 0;
-                           for(Expr e = left; e != null; e = e.next) {
-                               scope.declare(e.string);
-                               scope.put(e.string, args.get(new Integer(i++)));
+                           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);
@@ -750,7 +836,9 @@ public class Parser extends Lexer {
                Object switchVal = left.eval(s);
                boolean go = false;
                try {
-                   for(Expr e = right; e != null; e = e.next) {
+                   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);
                    }
@@ -760,34 +848,6 @@ public class Parser extends Lexer {
                }
                return null;
 
-           case Lexer.LB: {
-               JS.Array ret = new JS.Array();
-               for(Expr e = left; e != null; e = e.next) ret.addElement(e.eval(s));
-               return ret;
-           }
-           
-           case Lexer.LC: // block
-               JS.Scope scope = new JS.Scope(s);
-               for(Expr e = left; e != null; e = e.next) e.eval(scope);
-               return null;
-           
-           case Lexer.RC: {   // Object ctor
-               JS.Obj ret = new JS.Obj();
-               for(Expr e = left; e != null; e = e.next) {
-                   Object key = e.left.string;
-                   Object val = e.right.eval(s);
-                   ret.put(key, val);
-               }
-               return ret;
-           }
-           
-           case Lexer.VAR:
-               for(Expr e = this.left; e != null; e = e.next) {
-                   s.declare(e.left.string);
-                   if (e.right != null) e.right.eval(s);
-               }
-               return null;
-
            case Lexer.HOOK: return toBoolean(left.eval(s)) ? right.left.eval(s) : right.right.eval(s);
            case Lexer.IF:
                if (right.code == ELSE) {
@@ -802,26 +862,6 @@ public class Parser extends Lexer {
            case Lexer.CONTINUE: throw new ContinueException(string);
            case Lexer.RETURN: throw new ReturnException(left == null ? null : left.eval(s));
 
-           case Lexer.WHILE:
-           case Lexer.DO:
-               try {
-                   boolean first = true;
-                   Object bogus = null;
-                   for(;(first && code == Lexer.DO) || toBoolean(left.eval(s)); bogus = (right.next == null ? null : right.next.eval(s))) {
-                       first = false;
-                       try { right.eval(s);
-                       } catch (ContinueException c) {
-                           if (c.label == null || c.label.equals(string)) continue;
-                       } catch (BreakException b) {
-                           if (b.label == null || b.label.equals(string)) return null;
-                           throw (BreakException)b.fillInStackTrace();
-                       }
-                   }
-               } catch (BreakException e) {
-                   if (e.label != null && !e.label.equals(string)) throw e;
-               }
-               return null;
-
            default: throw new EvaluatorException("don't know how to eval an Expr with code " + Lexer.codeToString[code] + "\n" + this);
            }
        }