KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > aspectj > compiler > base > parser > JavaParser


1 /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * This file is part of the compiler and core tools for the AspectJ(tm)
4  * programming language; see http://aspectj.org
5  *
6  * The contents of this file are subject to the Mozilla Public License
7  * Version 1.1 (the "License"); you may not use this file except in
8  * compliance with the License. You may obtain a copy of the License at
9  * either http://www.mozilla.org/MPL/ or http://aspectj.org/MPL/.
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is AspectJ.
17  *
18  * The Initial Developer of the Original Code is Xerox Corporation. Portions
19  * created by Xerox Corporation are Copyright (C) 1999-2002 Xerox Corporation.
20  * All Rights Reserved.
21  *
22  * Contributor(s):
23  */

24
25 package org.aspectj.compiler.base.parser;
26
27 import org.aspectj.compiler.base.ast.*;
28 import org.aspectj.compiler.base.cst.*;
29 import org.aspectj.compiler.base.*;
30
31
32 import java.util.*;
33 import java.io.*;
34 import java.util.Stack JavaDoc;
35
36 public class JavaParser extends CompilerObject implements JavaConstants {
37     public boolean parseInterfaceOnly = false;
38
39     public JavaParser(JavaCompiler compiler) {
40         super(compiler);
41         if (compiler.getOptions().source.equals("1.4")) {
42             stmtParsers.put("assert", new AssertStmtParser());
43             keywords.add("assert");
44         }
45     }
46
47     public CompilationUnit interfaceParse(CompilationUnit cu) throws IOException {
48         tokenSource.setSourceInfo(cu.getSourceInfo());
49         currentCompilationUnit = cu;
50         currentIndex = 0;
51         lastValidIndex = -1;
52
53         parseCompilationUnit();
54         currentCompilationUnit.setScanned(true);
55         return currentCompilationUnit;
56     }
57
58     /* Global variable to identify that we are parsing interface */
59     protected boolean inInterface;
60     /* Interface to the Token Manager */
61     private JavaTokenizer tokenSource = new JavaTokenizer(getCompiler());
62     // this size must be a power of two
63
private static final int LOOKAHEAD_BUFFER_SIZE = 256;
64     private static final int LOOKAHEAD_MASK = LOOKAHEAD_BUFFER_SIZE-1;
65     private Token[] lookaheadBuffer = new Token[LOOKAHEAD_BUFFER_SIZE];
66     public int currentIndex = 0;
67     private int lastValidIndex = -1;
68
69     private final void initTokenSource(int offset) {
70         currentIndex = 0;
71         lastValidIndex = -1;
72         tokenSource.setOffset(offset);
73     }
74
75     public void cleanup(boolean fully) {
76         tokenSource.cleanup(fully);
77         for (int i=0; i < LOOKAHEAD_BUFFER_SIZE; i++) {
78             lookaheadBuffer[i] = null;
79         }
80         lastValidIndex = -1;
81     }
82
83     private final Token getToken(int index) {
84         while (index > lastValidIndex) {
85             lastValidIndex++;
86             Token newToken = tokenSource.getNextToken();
87             //System.err.println("t: "+newToken.startPosition+", "+newToken+", "+newToken.image+", "+newToken.isIdentifier());
88
lookaheadBuffer[lastValidIndex&LOOKAHEAD_MASK] = newToken;
89         }
90         return lookaheadBuffer[index&LOOKAHEAD_MASK];
91     }
92
93     private int savedIndex = -1;
94     //!!! this scheme needs some error checking
95
protected final void pushCurrentIndex() {
96         savedIndex = currentIndex;
97     }
98
99     protected final void popCurrentIndex() {
100         currentIndex = savedIndex;
101     }
102
103     public final void eatTopToken(int kind) {
104         if (peekToken().kind != kind) {
105             throwError(peekToken(), "expected "+JavaConstants.tokenImage[kind]+", found "+peekToken().image);
106         }
107         currentIndex++;
108     }
109
110     public final boolean maybeEatToken(int kind) {
111         if (peekToken().kind == kind) {
112             currentIndex++;
113             return true;
114         } else {
115             return false;
116         }
117     }
118
119     public final void eatTopToken() {
120         currentIndex++;
121     }
122
123     public final Token popToken(int kind) {
124         return getToken(currentIndex++);
125     }
126
127     public final Token popToken() {
128         return getToken(currentIndex++);
129     }
130
131     public final Token peekToken() {
132         return getToken(currentIndex);
133     }
134
135     public final Token peekToken(int i) {
136         return getToken(currentIndex+i);
137     }
138
139     public int scanTillMatched() {
140         Token beginToken = peekToken();
141         int kind = RBRACE;
142         if (beginToken.kind != LBRACE)
143             throwError(beginToken,"internal error: expected '{'");
144
145         // TODO: scan all lookahead tokens
146
// I don't check lookahead tokens right now, because
147
// the is no meaning to lookahead after '{' token.
148
if (currentIndex != lastValidIndex)
149             throwError(beginToken,"internal error: lookahead of '{'");
150
151         // eat the left brace
152
eatTopToken();
153
154         // ask tokenizer scan all data until matched 'kind' token
155
try {
156             Token endToken = tokenSource.scanTillMatched(kind);
157             lastValidIndex++;
158             lookaheadBuffer[lastValidIndex&LOOKAHEAD_MASK] = endToken;
159             // eat the right brace
160
eatTopToken();
161             return endToken.endPosition;
162         } catch (Exception JavaDoc e) {
163             showError(beginToken,"Unexpected end of file while looking matched close brace");
164         }
165         return beginToken.endPosition;
166     }
167
168     private Stack JavaDoc enclosingTypeDecs = new Stack JavaDoc();
169
170     public void pushEnclosingTypeDec(TypeDec dec) {
171         enclosingTypeDecs.push(dec);
172         //currentCompilationUnit.addDefinedType(dec);
173
}
174
175     public void popEnclosingTypeDec() {
176         enclosingTypeDecs.pop();
177     }
178
179     public TypeDec peekEnclosingTypeDec() {
180         if (enclosingTypeDecs.size() == 0) return null;
181         return (TypeDec)enclosingTypeDecs.peek();
182     }
183
184     protected void parseIdMatchingEnclosingTypeName(String JavaDoc where) {
185         Token beginToken = peekToken();
186         String JavaDoc id;
187         if (beginToken.kind == NEW) {
188             id = "new";
189             popToken();
190         } else {
191             id = parseId();
192         }
193         if ( id.equals(peekEnclosingTypeDec().getId())) return;
194
195         throwError(beginToken, where + " \"" + id +
196                                  "\" doesn't match enclosing type name \"" +
197                                  peekEnclosingTypeDec().getId()+"\"");
198     }
199
200
201
202
203     /* Dynamic parser stuff */
204
205     // table of all keywords from JLSv2 3.9
206
protected Set keywords = new HashSet(Arrays.asList(new String JavaDoc[]
207         { "abstract", "boolean", "break", "byte", "case", "catch",
208           "char", "class", "const", "continue",
209           "default", "do", "double", "else", "extends",
210           "final", "finally", "float", "for", "goto",
211           "if", "implements", "import", "intstanceof", "int",
212           "interface", "long", "native", "new", "package",
213           "private", "protected", "public", "return", "short",
214           "static", "strictfp", "super", "switch", "synchronized",
215           "this", "throw", "throws", "transient", "try",
216           "void", "volatile", "while",
217           "true", "false", "null", "instanceof"// technically not keywords, but not legal ids anyway
218
}));
219
220     private Map primitiveTypeNames = new HashMap();
221     {
222         primitiveTypeNames.put("int", getTypeManager().intType);
223         primitiveTypeNames.put("byte", getTypeManager().byteType);
224         primitiveTypeNames.put("short", getTypeManager().shortType);
225         primitiveTypeNames.put("long", getTypeManager().longType);
226         primitiveTypeNames.put("double", getTypeManager().doubleType);
227         primitiveTypeNames.put("float", getTypeManager().floatType);
228         primitiveTypeNames.put("char", getTypeManager().charType);
229         primitiveTypeNames.put("boolean", getTypeManager().booleanType);
230         primitiveTypeNames.put("void", getTypeManager().voidType);
231     }
232     public TypeD lookupPrimitiveTypeD(String JavaDoc name) {
233         Type type = (Type)primitiveTypeNames.get(name);
234         if (type == null) return null;
235         return type.makeTypeD();
236     }
237
238     protected static Map modifiers = new HashMap();
239     static {
240         modifiers.put("public", new Integer JavaDoc(Modifiers.PUBLIC));
241         modifiers.put("protected", new Integer JavaDoc(Modifiers.PROTECTED));
242         modifiers.put("private", new Integer JavaDoc(Modifiers.PRIVATE));
243         modifiers.put("static", new Integer JavaDoc(Modifiers.STATIC));
244         modifiers.put("final", new Integer JavaDoc(Modifiers.FINAL));
245         modifiers.put("abstract", new Integer JavaDoc(Modifiers.ABSTRACT));
246         modifiers.put("native", new Integer JavaDoc(Modifiers.NATIVE));
247         modifiers.put("synchronized", new Integer JavaDoc(Modifiers.SYNCHRONIZED));
248         modifiers.put("transient", new Integer JavaDoc(Modifiers.TRANSIENT));
249         modifiers.put("volatile", new Integer JavaDoc(Modifiers.VOLATILE));
250         modifiers.put("strictfp", new Integer JavaDoc(Modifiers.STRICT));
251     }
252     public final boolean isModifier(Token token) {
253         return getModifier(token) != null;
254     }
255
256     public final Integer JavaDoc getModifier(Token token) {
257         if (!isIdentifier(token)) return null;
258         return (Integer JavaDoc)modifiers.get(token.image);
259     }
260
261     protected Map decParsers = new HashMap();
262     {
263         decParsers.put("class", new ClassDecParser());
264         decParsers.put("interface", new InterfaceDecParser());
265     }
266
267     protected Map stmtDecParsers = new HashMap();
268     {
269         stmtDecParsers.put("class", new ClassDecParser());
270         stmtDecParsers.put("interface", new InterfaceDecParser());
271     }
272
273
274     protected Map stmtParsers = new HashMap();
275     {
276
277
278         stmtParsers.put("if", new IfStmtParser());
279         stmtParsers.put("while", new WhileStmtParser());
280         stmtParsers.put("do", new DoStmtParser());
281         stmtParsers.put("for", new ForStmtParser());
282
283         stmtParsers.put("synchronized", new SynchronizedStmtParser());
284         stmtParsers.put("try", new TryStmtParser());
285         stmtParsers.put("switch", new SwitchStmtParser());
286
287         stmtParsers.put("break", new BreakStmtParser());
288         stmtParsers.put("continue", new ContinueStmtParser());
289         stmtParsers.put("return", new ReturnStmtParser());
290         stmtParsers.put("throw", new ThrowStmtParser());
291
292         stmtParsers.put("goto", new GotoStmtParser());
293     }
294
295     protected SourceLocation dummySource = new DummySourceLocation(getCompiler());
296
297     protected class NewOperator extends PrefixOperator {
298         public NewOperator(int precedence) {
299             super("new", precedence);
300         }
301
302         private NewArrayExpr parseNewArrayExprWithInitializer(ArrayTypeD typeD) {
303             ArrayInitializer init = null;
304             if (peekToken().kind == LBRACE) {
305                 init = parseArrayInitializer();
306             } else {
307                 showError(peekToken(), "'{' expected");
308             }
309             //System.out.println("parsed new array: " + peekToken());
310
return new NewArrayExpr(dummySource, typeD, init, null);
311         }
312
313         private NewArrayExpr parseNewArrayExpr(TypeD typeD) {
314             Exprs dimExprs = null;
315             if (peekToken().kind == LBRACKET) {
316                 dimExprs = parseArrayDimExprs();
317                 for(int i=0; i<dimExprs.size(); i++) {
318                     typeD = new ArrayTypeD(dummySource,typeD);
319                 }
320             }
321             return new NewArrayExpr(dummySource,(ArrayTypeD)typeD, null, dimExprs);
322         }
323
324         public Expr parse() {
325             Token beginToken = peekToken();
326
327             eatTopToken(); //eats the 'new'
328
TypeD typeD = parseTypeD();
329             if (typeD == null) {
330                 throwError(peekToken(), "type expected");
331             }
332
333             if (maybeEatToken(LPAREN)) {
334                 Exprs args = parseExprs(RPAREN);
335                 eatTopToken(RPAREN);
336
337                 TypeDec typeDec = maybeParseClassBody(typeD);
338                 return new NewInstanceExpr(dummySource, null, (TypeD)typeD, args, typeDec, null);
339             } else if (typeD instanceof ArrayTypeD) {
340                 // already ate a bunch of [][][]...s
341
return parseNewArrayExprWithInitializer((ArrayTypeD)typeD);
342             } else if (peekToken().kind == LBRACKET) {
343                 // have yet to eat any []s.
344
return parseNewArrayExpr(typeD);
345             } else {
346                 throwError(peekToken(), "( or [ expected");
347                 return null;
348             }
349         }
350     }
351
352     TypeDec maybeParseClassBody(TypeD superTypeD) {
353         if (peekToken().kind == LBRACE) {
354             Token beginToken = peekToken();
355             Modifiers mods = new Modifiers(makeSourceLocation(beginToken), 0);
356             if (superTypeD != null) superTypeD = (TypeD)superTypeD.copy();
357             ClassDec classDec =
358                 new ClassDec(dummySource, mods,
359                              "ANONYMOUS", superTypeD,
360                              null, null);
361             classDec.setIsAnonymous();
362             classDec.setLocal();
363             Decs body = null;
364             boolean oldInInterface = inInterface;
365             try {
366                 inInterface = false;
367                 pushEnclosingTypeDec(classDec);
368                 body = parseDecs();
369             } finally {
370                 inInterface = oldInInterface;
371                 popEnclosingTypeDec(); //classDec);
372
}
373             classDec.setBody(body);
374             
375             classDec.setEnclosingTypeDec(peekEnclosingTypeDec());
376             addContext(classDec, beginToken);
377             return classDec;
378         } else {
379             return null;
380         }
381     }
382         
383
384     protected class ParenOperator extends PrefixOperator {
385         protected boolean allowCasts = false;
386
387         public ParenOperator(int precedence, boolean allowCasts) {
388             super("(", precedence);
389             this.allowCasts = allowCasts;
390         }
391         public ParenOperator(int precedence) {
392             this(precedence, false);
393         }
394
395         private boolean notPlusMinus(int kind) {
396             switch (kind) {
397                 case PLUS:
398                 case MINUS:
399                 case INCR:
400                 case DECR:
401                 //XXX I don't think these are really needed, but they can't hurt
402
case HOOK:
403                 case SEMICOLON:
404                     return false;
405                 default:
406                     return true;
407             }
408         }
409
410         // Handle's both cast op and simple parenthesized exp
411
public Expr parse() {
412             eatTopToken(); // eats the '('
413

414             if (!allowCasts) return basicParse();
415
416             // follow the language spec closely, even though I disagree with their rules
417
// if next identifier is a numerictype, then it's definately a cast
418
// otherwise, peek through a typed and a close paren, and if the next
419
// token is not a +, ++, -, or --, then it's a cast
420
int savedIndex = currentIndex; //pushCurrentIndex();
421
Token nextToken = peekToken();
422
423             // cast precedence is between unary ops and multiplicative binops
424

425             if ((nextToken.isIdentifier() && primitiveTypeNames.get(nextToken.image) != null)) {
426                 TypeD typeD = parseTypeD();
427                 eatTopToken(RPAREN);
428                 return new CastExpr(dummySource,typeD, exprParser.parse(1500));
429             } else if (eatTypeD() && popToken().kind == RPAREN &&
430                        notPlusMinus(popToken().kind)) {
431                 currentIndex = savedIndex;
432                 TypeD typeD = parseTypeD();
433                 eatTopToken(RPAREN);
434                 Expr expr = exprParser.parse(1500); // parseExpr(true);
435
if (expr != null) return new CastExpr(dummySource,typeD, expr);
436             }
437
438             currentIndex = savedIndex;
439             return basicParse();
440         }
441
442         protected Expr basicParse() {
443             Expr expr = parentParse();
444             eatTopToken(RPAREN);
445             return new ParenExpr(dummySource,expr);
446         }
447
448     }
449
450
451     abstract protected class Operator {
452         protected int precedence;
453         protected String JavaDoc image;
454         protected int tokenKind;
455
456         private ExprParser parent;
457
458         protected Operator(int tokenKind, int precedence) {
459             this.precedence = precedence;
460             this.tokenKind = tokenKind;
461             this.image = tokenImage[tokenKind];
462         }
463
464         protected Operator(String JavaDoc image, int precedence) {
465             int tokenKind = 0;
466             String JavaDoc testImage = "\"" + image + "\"";
467
468             for(;tokenKind < tokenImage.length; tokenKind++) {
469                 String JavaDoc maybeImage = tokenImage[tokenKind];
470                 if (maybeImage != null && maybeImage.equals(testImage)) {
471                     break;
472                 }
473             }
474
475             if (tokenKind == tokenImage.length) {
476                 tokenKind = tokenSource.addOperator(image);
477             }
478
479             this.tokenKind = tokenKind;
480             this.image = image;
481             this.precedence = precedence;
482         }
483
484         public int getTokenKind() {
485             return tokenKind;
486         }
487
488         public void setParent(ExprParser parent) {
489             this.parent = parent;
490         }
491
492         public Expr parentParse() {
493             Expr ret = parent.parse();
494             if (ret == null) throwError(null, "expression expected");
495             return ret;
496         }
497
498         public Expr parentParse(int precedence) {
499             Expr ret = parent.parse(precedence);
500             if (ret == null) throwError(null, "expression expected");
501             return ret;
502         }
503      }
504
505     protected class MinusOperator extends PrefixOperator {
506         public MinusOperator(int precedence) {
507             super("-", precedence);
508         }
509
510         public Expr parse() {
511             eatTopToken();
512             //!!! should be this, not image
513
if (peekToken().kind == INTEGER_LITERAL) {
514                 Token t = popToken();
515                 return t.getNegativeExpr(makeSourceLocation(peekToken(-1)));
516             } else {
517                 return new MinusOpExpr(makeSourceLocation(peekToken(-1)),
518                                        image, parentParse(precedence));
519             }
520         }
521     }
522
523     protected class PrefixOperator extends Operator {
524         protected PrefixOperator(int tokenKind, int precedence) {
525             super(tokenKind, precedence);
526         }
527
528         public PrefixOperator(String JavaDoc image, int precedence) {
529             super(image, precedence);
530         }
531
532         public Expr parse() {
533             eatTopToken();
534             //!!! should be this, not image
535
return UnopExpr.build(dummySource, image, parentParse(precedence));
536         }
537     }
538
539
540     protected abstract class LiteralOp extends PrefixOperator {
541         public LiteralOp(int tokenKind) {
542             super(tokenKind, -1);
543         }
544
545         public LiteralOp(String JavaDoc image) {
546             super(image, -1);
547         }
548
549         public Expr parse() {
550             Token token = peekToken();
551             Expr expr = parse(token.image);
552             return expr;
553         }
554
555         public abstract Expr parse(String JavaDoc image);
556     }
557
558
559     protected class TrueLiteral extends LiteralOp {
560         public TrueLiteral() { super("true"); }
561
562         public Expr parse(String JavaDoc image) {
563             eatTopToken();
564             return new BooleanLiteralExpr(dummySource,true);
565         }
566     }
567
568     protected class FalseLiteral extends LiteralOp {
569         public FalseLiteral() { super("false"); }
570
571         public Expr parse(String JavaDoc image) {
572             eatTopToken();
573             return new BooleanLiteralExpr(dummySource,false);
574         }
575     }
576
577     protected class NullLiteral extends LiteralOp {
578         public NullLiteral() { super("null"); }
579
580         public Expr parse(String JavaDoc image) {
581             eatTopToken();
582             return new NullExpr(dummySource);
583         }
584     }
585
586     protected class ThisLiteral extends LiteralOp {
587         public ThisLiteral() { super("this"); }
588
589         public Expr parse(String JavaDoc image) {
590             eatTopToken();
591             return new ThisExpr(dummySource);
592         }
593     }
594
595     protected class SuperLiteral extends LiteralOp {
596         public SuperLiteral() { super("super"); }
597
598         public Expr parse(String JavaDoc image) {
599             eatTopToken();
600             return new SuperExpr(dummySource);
601         }
602     }
603
604     public Expr parseCallExpr(Name name) {
605         //System.out.println("call name: " + name);
606

607         String JavaDoc id = name.getId();
608         Name parentName = name.getParentName();
609         Exprs args = parseExprs(RPAREN);
610         eatTopToken(RPAREN);
611         Expr expr = null;
612         if (parentName != null) {
613             parentName.clearParent();
614             expr = new UnresolvedExpr(dummySource,parentName);
615             expr.setSource(parentName);
616         }
617
618         if (id.equals("this")) {
619             if (parentName != null) throwError(null, "bad this");
620             return new ConstructorCallExpr(dummySource, null, false, args, null);
621         } else if (id.equals("super")) {
622             if (parentName != null) throwError(null, "bad super");
623             return new ConstructorCallExpr(dummySource, null, true, args, null);
624         }
625
626         return new CallExpr(dummySource,expr, id, args);
627     }
628
629
630     protected class IdentifierOp extends LiteralOp {
631         public IdentifierOp() { super(IDENTIFIER); }
632
633         public Expr parse(String JavaDoc image) {
634             TypeD typeD = lookupPrimitiveTypeD(image);
635             if (typeD != null) {
636                 eatTopToken();
637                 return new TypeExpr(dummySource, typeD);
638             }
639
640             Name name = parseExtendedName();
641
642             if (maybeEatToken(LPAREN)) {
643                 return parseCallExpr(name);
644             }
645             return new UnresolvedExpr(dummySource,name);
646         }
647     }
648
649     protected class InfixOperator extends Operator {
650         protected InfixOperator(int tokenKind, int precedence) {
651             super(tokenKind, precedence);
652         }
653
654         public InfixOperator(String JavaDoc image, int precedence) {
655             super(image, precedence);
656         }
657
658         public Expr parse(Expr lhs, int minimumPrecedence) {
659             if (precedence <= minimumPrecedence) return lhs;
660             eatTopToken();
661
662             return parse(lhs);
663         }
664
665         public Expr parse(Expr lhs) {
666             //!!! should be this, not image
667
return BinopExpr.build(dummySource,this.image, lhs, parentParse(precedence));
668         }
669     }
670
671     private Name buildName(Expr expr) {
672         if (expr instanceof UnresolvedExpr) {
673             return ((UnresolvedExpr)expr).getName();
674         } else {
675             return null;
676         }
677     }
678
679     private TypeD exprToTypeD(Expr lhs) {
680         if (lhs instanceof TypeExpr) {
681             return ((TypeExpr)lhs).getTypeD();
682         }
683
684         Name id = buildName(lhs);
685         TypeD ret = null;
686         if (id == null) return null;
687         if (id.getParentName() == null) {
688             TypeD primTypeD = lookupPrimitiveTypeD(id.getId());
689             if (primTypeD != null) ret = primTypeD;
690         }
691         id.clearParent();
692         if (ret == null) ret = new UnresolvedNameTypeD(dummySource,id);
693         ret.setSource(lhs);
694         return ret;
695     }
696
697     private TypeD exprToTypeD(Expr lhs, String JavaDoc name) {
698         TypeD ret = exprToTypeD(lhs);
699         if (ret == null) {
700             throwError(peekToken(-2), "type required before "+name);
701         }
702
703         addContext(ret, lhs);
704         return ret;
705     }
706
707     protected class DotOperator extends InfixOperator {
708         public DotOperator(int precedence) {
709             super(".", precedence);
710         }
711
712         public Expr parse(Expr lhs) {
713             // here we handle the ever popular inner constructor syntax
714
if (maybeEatKeyword("new")) {
715                 String JavaDoc innerName = parseId();
716                 eatTopToken(LPAREN);
717                 Exprs args = parseExprs(RPAREN);
718                 eatTopToken(RPAREN);
719                 TypeDec typeDec = maybeParseClassBody(null);
720                 return new NewInnerInstanceExpr(dummySource,
721                                                 lhs, null, args, typeDec,
722                                                 null, innerName);
723             }
724
725             String JavaDoc id = parseIdOrKeywords_this_super_class();
726             if (id.equals("this")) {
727                 return new QualifiedThisExpr(dummySource,exprToTypeD(lhs, ".this"));
728             } else if (id.equals("super")) {
729                 if (inConstructor() && maybeEatToken(LPAREN)) {
730                     Exprs args = parseExprs(RPAREN);
731                     eatTopToken(RPAREN);
732                     return new ConstructorCallExpr(dummySource, lhs, true, args, null);
733                 } else {
734                     return new QualifiedSuperExpr(dummySource,exprToTypeD(lhs, ".super"));
735                 }
736             } else if (id.equals("class")) {
737                 return new ClassExpr(dummySource,exprToTypeD(lhs, ".class"));
738             } else if (maybeEatToken(LPAREN)) {
739                 Exprs args = parseExprs(RPAREN);
740                 eatTopToken(RPAREN);
741                 return new CallExpr(dummySource,lhs, id, args);
742             } else {
743                 return new UnresolvedFieldAccessExpr(dummySource,lhs, id);
744             }
745         }
746     }
747
748     protected class AssignOperator extends InfixOperator {
749         public AssignOperator(String JavaDoc image, int precedence) {
750             super(image, precedence);
751         }
752
753         public Expr parse(Expr lhs) {
754             Expr rhs = parentParse(precedence-1);
755             String JavaDoc s = this.image;
756             return AssignExpr.build(dummySource,checkAssignable(lhs),
757                                     s.substring(0, s.length() - 1),
758                                     rhs);
759         }
760     }
761
762     protected class ArrayOperator extends InfixOperator {
763         public ArrayOperator(int precedence) {
764             super("[", precedence);
765         }
766
767         public Expr parse(Expr lhs) {
768             // add in a special case for an array type followed by .class
769
if (peekToken().kind == RBRACKET) {
770                 //System.out.println("lhs: "+lhs);
771
TypeD typeD = exprToTypeD(lhs, ".class");
772                 //!!! violates an abstraction, should be something like unpopToken()
773
currentIndex--;
774                 typeD = addBracketsToTypeD(typeD);
775                 eatTopToken(DOT);
776                 eatKeyword("class");
777                 return new ClassExpr(dummySource,typeD);
778             }
779
780             Expr index = parseExpr();
781             eatTopToken(RBRACKET);
782             return new ArrayExpr(dummySource,lhs, index);
783         }
784     }
785
786     protected class QuestionOperator extends InfixOperator {
787         public QuestionOperator(int precedence) {
788             super("?", precedence);
789         }
790
791         public Expr parse(Expr lhs) {
792             // parse anything up to a :
793
Expr trueExpr = parentParse(0);
794             eatTopToken(COLON);
795             Expr falseExpr = parseExpr();
796             return new TriTestExpr(dummySource,lhs, trueExpr, falseExpr);
797         }
798     }
799
800     protected class InstanceOfOperator extends InfixOperator {
801         public InstanceOfOperator(int precedence) {
802             super("instanceof", precedence);
803         }
804
805         public Expr parse(Expr lhs) {
806             TypeD typeD = parseTypeD();
807             return new InstanceofExpr(dummySource,lhs, typeD);
808         }
809     }
810
811     /**
812      * Checks to see is an expression is a legal lhs
813      * According to JLS 15.8.5 a parenthesized expression is a legal lhs
814      * if its contained expression is a legal lhs.
815      *
816      * To keep our static typing here, this will strip parens off of the
817      * returned expression. This is acceptable to all current callers, but a
818      * dangerous choice for potential future callers.
819      */

820     AssignableExpr checkAssignable(Expr expr) {
821         if (expr instanceof AssignableExpr) return (AssignableExpr)expr;
822         if (expr instanceof ParenExpr) {
823             return checkAssignable( ((ParenExpr)expr).getExpr() );
824         }
825         expr.showError("invalid lhs for assign: "+expr.getClass().getName());
826         return null;
827     }
828
829     protected class PreOperator extends PrefixOperator {
830         public PreOperator(String JavaDoc image, int precedence) {
831             super(image, precedence);
832         }
833
834         public Expr parse() {
835             eatTopToken(); // eats the '--' or the '++'
836
return new PrefixExpr(dummySource,checkAssignable(parentParse(precedence)), image);
837         }
838     }
839
840     protected class PostOperator extends InfixOperator {
841         public PostOperator(String JavaDoc image, int precedence) {
842             super(image, precedence);
843         }
844
845         public Expr parse(Expr lhs) {
846             return new PostfixExpr(dummySource,checkAssignable(lhs), image);
847         }
848     }
849
850     private static final int MAX_TOKEN_KINDS = 512;
851
852     protected class ExprParser {
853         // these should be hidden as implementation details as much as possible
854
protected PrefixOperator[] prefixOps;
855         protected InfixOperator[] infixOps;
856
857         private boolean allowLiterals = true;
858
859         public ExprParser() {
860             int tokenTypes = tokenImage.length;
861
862             prefixOps = new PrefixOperator[MAX_TOKEN_KINDS];
863             infixOps = new InfixOperator[MAX_TOKEN_KINDS];
864             //terminals = new PrefixOperator[tokenTypes];
865
}
866
867         private final void fillOps(Operator[] ops, Operator[] toArray) {
868             for(int i=0; i<ops.length; i++) {
869                 Operator op = ops[i];
870                 toArray[op.getTokenKind()] = op;
871                 op.setParent(this);
872             }
873         }
874
875         public ExprParser(PrefixOperator[] prefixes, InfixOperator[] infixes,
876                     boolean allowLiterals)
877         {
878             this(prefixes, infixes);
879             this.allowLiterals = allowLiterals;
880         }
881
882         public ExprParser(PrefixOperator[] prefixes, InfixOperator[] infixes) {
883             this();
884
885             fillOps(prefixes, prefixOps);
886             fillOps(infixes, infixOps);
887         }
888
889         public void addInfixOperator(InfixOperator op) {
890             infixOps[op.getTokenKind()] = op;
891             op.setParent(this);
892         }
893
894         public void addPrefixOperator(PrefixOperator op) {
895             prefixOps[op.getTokenKind()] = op;
896             op.setParent(this);
897         }
898
899         //public void addTerminal(PrefixOperator op) {
900
// terminals[op.getTokenKind()] = op;
901
// op.setParent(this);
902
//}
903

904
905         public Expr parseTerminal() {
906             Token token = peekToken();
907             int kind = token.kind;
908
909             Expr literalExpr = token.getExpr(makeSourceLocation(token));
910             if (literalExpr != null && allowLiterals) {
911                 eatTopToken();
912                 return literalExpr;
913             }
914
915             PrefixOperator op = prefixOps[kind];
916             if (op == null && token.isIdentifier()) {
917                 op = prefixOps[IDENTIFIER];
918             }
919
920             if (op != null) {
921                 return op.parse();
922             }
923
924             return null;
925         }
926
927         public Expr parseOperator(Expr lhs, int minimumPrecedence) {
928             Token token = peekToken();
929             int kind = token.kind;
930
931             InfixOperator op = infixOps[kind];
932             if (op != null) {
933                 return op.parse(lhs, minimumPrecedence);
934             }
935             return lhs;
936         }
937
938         public Expr parseAll(Expr lhs, int minimumPrecedence, Token beginToken) {
939             Expr ret;
940             // keep parsing until a fixed-point is reached
941
//Token beginToken = peekToken();
942
while ((ret = parseOperator(lhs, minimumPrecedence)) != lhs && ret != null) {
943                 addContext(ret, beginToken);
944                 beginToken = peekToken();
945                 lhs = ret;
946             }
947             return ret;
948         }
949
950         protected Expr parse(int minimumPrecedence) {
951             Token beginToken = peekToken();
952             Expr lhs = parseTerminal();
953             if (lhs == null) return null;
954             addContext(lhs, beginToken);
955             return parseAll(lhs, minimumPrecedence, beginToken);
956         }
957
958         public Expr parse() {
959             return parse(0);
960         }
961     }
962
963     private InfixOperator[] infixOperators = {
964         new QuestionOperator(200),
965
966         new InfixOperator("||", 300),
967         new InfixOperator("&&", 400),
968
969         new InfixOperator("|", 500),
970         new InfixOperator("^", 600),
971         new InfixOperator("&", 700),
972
973         new InfixOperator("==", 800),
974         new InfixOperator("!=", 800),
975
976         new InstanceOfOperator(900),
977
978         new InfixOperator(">", 1000),
979         new InfixOperator("<", 1000),
980         new InfixOperator("<=", 1000),
981         new InfixOperator(">=", 1000),
982
983         new InfixOperator("<<", 1100),
984         new InfixOperator(">>", 1100),
985         new InfixOperator(">>>", 1100),
986
987         new InfixOperator("+", 1200),
988         new InfixOperator("-", 1200),
989
990         new InfixOperator("*", 1300),
991         new InfixOperator("/", 1300),
992         new InfixOperator("%", 1300),
993
994         new PostOperator("++", 4000), //??? postfix is a degenerate case of infix
995
new PostOperator("--", 4000),
996
997         //new CallOperator(5000),
998
new ArrayOperator(5000),
999         new DotOperator(5000),
1000
1001        // the claim is that assignments are just infix operators
1002
new AssignOperator("=", 100),
1003        new AssignOperator("+=", 100),
1004        new AssignOperator("-=", 100),
1005        new AssignOperator("*=", 100),
1006        new AssignOperator("/=", 100),
1007        new AssignOperator("&=", 100),
1008        new AssignOperator("|=", 100),
1009        new AssignOperator("^=", 100),
1010        new AssignOperator("%=", 100),
1011        new AssignOperator("<<=", 100),
1012        new AssignOperator(">>=", 100),
1013        new AssignOperator(">>>=", 100),
1014    };
1015
1016    private PrefixOperator[] prefixOperators = {
1017        new PrefixOperator("+", 2000),
1018        new MinusOperator(2000),
1019        new PrefixOperator("!", 3000),
1020        new PrefixOperator("~", 3000),
1021
1022        new PreOperator("++", 2500),
1023        new PreOperator("--", 2500),
1024
1025        new ParenOperator(1, true),
1026        new NewOperator(1),
1027
1028        new TrueLiteral(),
1029        new FalseLiteral(),
1030        new NullLiteral(),
1031        new ThisLiteral(),
1032        new SuperLiteral(),
1033
1034        new IdentifierOp()
1035    };
1036
1037
1038    protected ExprParser exprParser = new ExprParser(prefixOperators, infixOperators);
1039
1040    /* Useful predicates */
1041    public final boolean eatKeyword(String JavaDoc keyword, boolean isMaybe) {
1042        Token topToken = peekToken();
1043        if (topToken.isIdentifier() && topToken.image.equals(keyword)) {
1044            eatTopToken();
1045            return true;
1046        } else {
1047            if (!isMaybe) {
1048                throwError(topToken, "expected keyword: '"+keyword+"'");
1049            }
1050            return false;
1051        }
1052    }
1053
1054    public final boolean peekKeyword(String JavaDoc keyword) {
1055        Token topToken = peekToken();
1056        if (topToken.isIdentifier() && topToken.image.equals(keyword)) {
1057            return true;
1058        } else {
1059            return false;
1060        }
1061    }
1062
1063    public final boolean eatKeyword(String JavaDoc keyword) {
1064        return eatKeyword(keyword, false);
1065    }
1066
1067    public final boolean maybeEatKeyword(String JavaDoc keyword) {
1068        return eatKeyword(keyword, true);
1069    }
1070
1071    public final boolean isIdentifier(Token token) {
1072        //??? make sure it's not a keyword?
1073
return token.isIdentifier() && !token.image.equals("new");
1074    }
1075
1076    public final boolean isIdentifierOrNew(Token token) {
1077        return token.isIdentifier();
1078    }
1079
1080    public final boolean isKeyword(Token token) {
1081        return keywords.contains(token.image);
1082    }
1083
1084    /* Parse different AST nodes */
1085    protected CompilationUnit currentCompilationUnit;
1086
1087    private CompilationUnit parseCompilationUnit() {
1088        Token beginToken0 = peekToken();
1089
1090        Decs decs = new Decs(dummySource);
1091        currentCompilationUnit.setDecs(decs);
1092
1093        // first check for a package
1094
if (maybeEatKeyword("package")) {
1095            String JavaDoc name = parseExtendedString(false);
1096            if (name != null) {
1097                currentCompilationUnit.setPackageName(name);
1098            } else {
1099                showError(peekToken(), "package name expected");
1100            }
1101                
1102            eatTopToken(SEMICOLON);
1103        }
1104
1105        Token beginImportsToken = peekToken();
1106        Imports imports = new Imports(dummySource);
1107        while (peekKeyword("import")) {
1108            imports.add(parseImport());
1109        }
1110        addContext(imports, beginImportsToken);
1111
1112        while (peekToken().kind != EOF) {
1113            if (peekToken().kind == SEMICOLON) {
1114                eatTopToken(); continue;
1115            }
1116            Token beginToken = peekToken();
1117            Dec dec = (Dec)parseTopDec(null);
1118            addContext(dec, beginToken);
1119
1120            if (dec instanceof TypeDec) {
1121                decs.add(dec);
1122            } else {
1123                throwError(null, "expected import, package, type or aspect declaration");
1124            }
1125        }
1126
1127        addContext(decs, beginToken0);
1128
1129        currentCompilationUnit.setImports(imports);
1130        addContext(currentCompilationUnit, beginToken0);
1131        return currentCompilationUnit;
1132    }
1133
1134    public Import parseImport() {
1135        Token beginToken = peekToken();
1136        eatKeyword("import");
1137        Name name = parseExtendedName();
1138
1139        boolean star = false;
1140        if (peekToken(0).kind == DOT && peekToken(1).kind == STAR) {
1141            eatTopToken(); eatTopToken();
1142            star = true;
1143        }
1144        eatTopToken(SEMICOLON);
1145        return new Import(makeSourceLocation(beginToken), name, star);
1146    }
1147
1148
1149    protected boolean eatModifiers() {
1150        Token token;
1151        while (isModifier(token=peekToken())) {
1152            eatTopToken();
1153        }
1154        return true;
1155    }
1156
1157    public void parseNoModifiers() {
1158        parseModifiers(0);
1159    }
1160
1161    public Modifiers parseModifiers(int legalModifiers) {
1162        Token beginToken = peekToken();
1163        int modifierValue = 0;
1164        while (true) {
1165            Integer JavaDoc ivalue = getModifier(peekToken());
1166            if (ivalue == null) break;
1167
1168            int value = ivalue.intValue();
1169            if ((legalModifiers & value) != value) {
1170                showError(peekToken(), "modifier " + peekToken().image + " not allowed here");
1171            } else if ((modifierValue & value) != 0) {
1172                showError(peekToken(), "repeated modifier");
1173            } else {
1174                modifierValue |= value;
1175            }
1176            eatTopToken();
1177        }
1178        return new Modifiers(makeSourceLocation(beginToken), modifierValue);
1179    }
1180
1181    public TypeDs parseTypeDs() {
1182        Token beginToken = peekToken();
1183        TypeD nameTypeD;
1184        List names = null;
1185        while ((nameTypeD = parseTypeD()) != null) {
1186            if (names == null) names = new ArrayList();
1187            names.add(nameTypeD);
1188            if (peekToken().kind != COMMA) break;
1189            eatTopToken();
1190        }
1191        if (names == null) {
1192            return null;
1193        } else {
1194            TypeDs ret = new TypeDs(dummySource,(TypeD[])names.toArray(new TypeD[0]));
1195            addContext(ret, beginToken);
1196            return ret;
1197        }
1198    }
1199
1200    public String JavaDoc parseIdPattern() {
1201        if (maybeEatToken(STAR)) {
1202            return "*";
1203        } else {
1204            return parseId();
1205        }
1206    }
1207
1208    protected boolean eatIdentifier(boolean onlyDec) {
1209        if (!isIdentifier(peekToken())) return false;
1210        eatTopToken();
1211        return true;
1212    }
1213
1214    public boolean lookaheadVarDes() {
1215        pushCurrentIndex();
1216        eatModifiers();
1217        boolean isVarDes = (eatModifiers() && eatTypeD() && eatIdentifier(true));
1218        popCurrentIndex();
1219        return isVarDes;
1220    }
1221
1222    public Name parseExtendedName() {
1223        if (!isSimpleIdentifier(peekToken())) return null;
1224        return parseExtendedName(null);
1225    }
1226
1227
1228    public boolean isSimpleIdentifier(Token t) {
1229        //System.out.println("t: " + t + " keyword: " + isKeyword(t));
1230
return t.isIdentifier() &&
1231            (lookupPrimitiveTypeD(t.image) != null || !isKeyword(t));
1232    }
1233
1234    //ASPECT this is a cflow aspect
1235
private boolean inConstructor = false;
1236    public boolean inConstructor() {
1237        return inConstructor;
1238    }
1239
1240
1241    public Name parseExtendedName(Name parentName) {
1242        Token beginToken = peekToken();
1243        Name name = new Name(dummySource, parentName, parseId());
1244        addContext(name, beginToken);
1245        if (peekToken(0).kind == DOT && isSimpleIdentifier(peekToken(1))) {
1246            eatTopToken();
1247            return parseExtendedName(name);
1248        } else {
1249            return name;
1250        }
1251    }
1252
1253    public String JavaDoc parseExtendedString(boolean allowStar) {
1254        if (!isIdentifier(peekToken())) return null;
1255        StringBuffer JavaDoc buf = new StringBuffer JavaDoc(parseId());
1256        while (peekToken().kind == DOT) {
1257            eatTopToken();
1258            buf.append(".");
1259            if (allowStar && peekToken().kind == STAR) {
1260                eatTopToken();
1261                buf.append("*");
1262            } else {
1263                buf.append(parseId());
1264            }
1265        }
1266        return buf.toString();
1267    }
1268
1269
1270    public TypeD parseNameTypeD() {
1271        Token beginToken = peekToken();
1272        Name name = parseExtendedName();
1273        if (name == null) {
1274            throwError(null, "name expected");
1275        }
1276        TypeD ret = new UnresolvedNameTypeD(dummySource,name);
1277        addContext(ret, beginToken);
1278        return ret;
1279    }
1280
1281    public TypeD addBracketsToTypeD(TypeD typeD) {
1282        while (peekToken().kind == LBRACKET && peekToken(1).kind == RBRACKET) {
1283            eatTopToken(); eatTopToken();
1284            TypeD oldTypeD = typeD;
1285            typeD = new ArrayTypeD(dummySource,typeD);
1286            addContext(typeD, oldTypeD);
1287        }
1288        return typeD;
1289    }
1290
1291
1292    public TypeD parseTypeD() {
1293        Token beginToken = peekToken();
1294        TypeD typeD = lookupPrimitiveTypeD(beginToken.image);
1295        if (typeD != null) {
1296            eatTopToken();
1297        } else {
1298            typeD = parseNameTypeD();
1299        }
1300
1301        addContext(typeD, beginToken);
1302        typeD = addBracketsToTypeD(typeD);
1303        return typeD;
1304    }
1305
1306    protected boolean eatTypeD() {
1307        if (!isSimpleIdentifier(peekToken())) return false;
1308        eatTopToken();
1309        while (peekToken().kind == DOT) {
1310            eatTopToken();
1311            if (peekToken().kind == DOT) continue;
1312            if (!isSimpleIdentifier(peekToken())) {
1313                currentIndex -= 1;
1314                return true;
1315            }
1316            eatTopToken();
1317        }
1318
1319        while (peekToken().kind == LBRACKET && peekToken(1).kind == RBRACKET) {
1320            eatTopToken(); eatTopToken();
1321        }
1322        return true;
1323    }
1324
1325    public FormalDec parseFormal() {
1326        Token beginToken = peekToken();
1327        Modifiers modifiers = parseModifiers(Modifiers.FINAL);
1328        TypeD typeD = parseTypeD();
1329        String JavaDoc id = parseId();
1330        //Identifier id = parseIdentifier();
1331
typeD = addBracketsToTypeD(typeD);
1332        FormalDec ret = new FormalDec(dummySource,modifiers, typeD, id, null);
1333        addContext(ret, beginToken);
1334        return ret;
1335    }
1336
1337    public Formals parseFormals() {
1338        Token beginToken = peekToken();
1339        eatTopToken(LPAREN);
1340
1341        Formals ret=new Formals(dummySource);
1342        if (peekToken().kind == RPAREN) {
1343            eatTopToken();
1344            addContext(ret, beginToken);
1345            return ret;
1346        }
1347
1348        while (true) {
1349            FormalDec formal = parseFormal();
1350            ret.add(formal);
1351
1352            Token t = popToken();
1353            if (t.kind == RPAREN) break;
1354            else if (t.kind == COMMA) continue;
1355            throwError(t, "parsing formals");
1356        }
1357        addContext(ret, beginToken);
1358        return ret;
1359    }
1360
1361    public BlockStmt parseOptionalBlockStmt() {
1362        if (peekToken().kind == SEMICOLON) {
1363            eatTopToken();
1364            return null;
1365        } else {
1366            return parseBlockStmt();
1367        }
1368    }
1369
1370    public Stmts parseStmts(int endToken) {
1371        Token beginToken = peekToken();
1372        Stmts stmts = new Stmts(dummySource);
1373        while (peekToken().kind != endToken) {
1374            stmts.add(parseStmt());
1375        }
1376        addContext(stmts, beginToken);
1377        eatTopToken(endToken);
1378        return stmts;
1379    }
1380
1381    public BlockStmt parseBlockStmt() {
1382        Token beginToken = peekToken();
1383        eatTopToken(LBRACE);
1384
1385        Stmts stmts = parseStmts(RBRACE);
1386        BlockStmt ret = new BlockStmt(dummySource,stmts);
1387        addContext(ret, beginToken);
1388        return ret;
1389    }
1390
1391
1392
1393    public CodeBody parseOptionalCodeBody() {
1394        Token beginToken = peekToken();
1395        if (maybeEatToken(SEMICOLON)) return null;
1396
1397        return parseCodeBody();
1398    }
1399
1400    public CodeBody parseCodeBodyFully() {
1401        boolean oldParseInterfaceOnly = parseInterfaceOnly;
1402        parseInterfaceOnly = false;
1403        CodeBody body = null;
1404        try {
1405            body = parseCodeBody();
1406        } finally {
1407            parseInterfaceOnly = oldParseInterfaceOnly;
1408        }
1409        return body;
1410    }
1411
1412    public CodeBody parseCodeBody() {
1413        Token beginToken = peekToken();
1414
1415        CodeBody ret;
1416// if (parseInterfaceOnly) {
1417
// ret = new CodeBody(getCompiler(),null,false);
1418
// if (beginToken.startPosition < 0)
1419
// throwError(beginToken, "wrong offset "+beginToken.startPosition);
1420
// ret.setStartPosition(beginToken.startPosition);
1421
// int endPos = scanTillMatched();
1422
// ret.setEndPosition(endPos);
1423
// ret.setParsed(false);
1424
// } else {
1425
eatTopToken(LBRACE);
1426            Stmts stmts = parseStmts(RBRACE);
1427            ret = new CodeBody(dummySource,stmts,true);
1428            ret.setParsed(true);
1429            addContext(ret, beginToken);
1430// }
1431
return ret;
1432    }
1433
1434    public ConstructorBody parseConstructorBody() {
1435        Token beginToken = peekToken();
1436        if (maybeEatToken(SEMICOLON)) {
1437            showError(beginToken, "constructor must have a body");
1438            return null;
1439        }
1440
1441        ConstructorBody ret;
1442// if (parseInterfaceOnly) {
1443
// ret = new ConstructorBody(dummySource,null, null, false);
1444
// if (beginToken.startPosition < 0)
1445
// throwError(beginToken, "wrong offset "+beginToken.startPosition);
1446
// ret.setStartPosition(beginToken.startPosition);
1447
// int endPos = scanTillMatched();
1448
// ret.setEndPosition(endPos);
1449
// ret.setParsed(false);
1450
// } else {
1451
eatTopToken(LBRACE);
1452
1453            ConstructorCallExpr constructorCall = null;
1454
1455            Token firstToken = peekToken();
1456            if (firstToken.image.equals("this") || firstToken.image.equals("super")) {
1457                boolean isSuper = firstToken.image.equals("super");
1458                if (peekToken(1).kind == LPAREN) {
1459                    eatTopToken();
1460                    constructorCall = new ConstructorCallExpr(dummySource, null, isSuper, parseParenExprs(), null);
1461                    addContext(constructorCall, firstToken);
1462                }
1463            }
1464
1465            inConstructor = true;
1466            Stmts stmts = parseStmts(RBRACE);
1467            inConstructor = false;
1468            if (constructorCall == null && stmts.size() > 0) {
1469                Stmt stmt = stmts.get(0);
1470                if (stmt instanceof ExprStmt && ((ExprStmt)stmt).getExpr() instanceof ConstructorCallExpr) {
1471                    constructorCall = (ConstructorCallExpr) ((ExprStmt)stmt).getExpr();
1472                    stmts.remove(0);
1473                }
1474            }
1475            ret = new ConstructorBody(dummySource,stmts, constructorCall, true);
1476            ret.setParsed(true);
1477            addContext(ret, beginToken);
1478// }
1479
return ret;
1480    }
1481
1482
1483
1484
1485    // too much like the above!!!
1486
public Decs parseDecs() {
1487        return parseDecs(null);
1488    }
1489
1490    public Decs parseDecs(Map extraDecParsers) {
1491        Token beginToken = peekToken();
1492        eatTopToken(LBRACE);
1493
1494        Decs decs = new Decs(dummySource);
1495        while (peekToken().kind != RBRACE) {
1496            if (peekToken().kind == SEMICOLON) {
1497                eatTopToken(); continue;
1498            }
1499            Token decBeginToken = peekToken();
1500            Stmt dec = parseStmt(extraDecParsers, true, true);
1501            addContext(dec, decBeginToken);
1502            if (dec instanceof Dec) {
1503                decs.add((Dec)dec);
1504            } else if (dec instanceof Decs) {
1505                decs.addAll((Decs)dec);
1506            } else {
1507                throwError(decBeginToken, "expected declaration");
1508                return null;
1509            }
1510        }
1511
1512        eatTopToken(RBRACE);
1513        addContext(decs, beginToken);
1514        return decs;
1515    }
1516
1517    public TypeDs parseThrows() {
1518        if (maybeEatKeyword("throws")) {
1519            return parseTypeDs();
1520        } else {
1521            return null;
1522        }
1523    }
1524
1525    public InitializerDec parseInitializerDec() {
1526        int legalModifiers = Modifiers.STATIC;
1527        Token beginToken = peekToken();
1528        Modifiers modifiers = parseModifiers(legalModifiers);
1529        Formals formals = new Formals(dummySource);
1530        addContext(formals, beginToken);
1531        TypeDs _throws = new TypeDs(dummySource);
1532        addContext(_throws, beginToken);
1533        return new InitializerDec(dummySource, modifiers, formals, _throws, parseOptionalCodeBody());
1534    }
1535
1536    public Dec parseConstructorDec() {
1537        int legalModifiers = Modifiers.PUBLIC | Modifiers.PROTECTED | Modifiers.PRIVATE;
1538
1539        Token beginToken = peekToken();
1540
1541        if (inInterface) { showError(beginToken, "constructor not allowed in interface"); }
1542
1543        Modifiers modifiers = parseModifiers(legalModifiers);
1544        parseIdMatchingEnclosingTypeName("constructor name");
1545        Formals formals = parseFormals();
1546        TypeDs _throws = parseThrows();
1547
1548        return new ConstructorDec(dummySource,modifiers, formals, _throws, parseConstructorBody());
1549    }
1550
1551    public Dec parseMethodDec() {
1552        int legalModifiers;
1553        if (inInterface) {
1554            legalModifiers = Modifiers.PUBLIC | Modifiers.ABSTRACT;
1555        } else {
1556            legalModifiers = Modifiers.PUBLIC | Modifiers.PROTECTED | Modifiers.PRIVATE |
1557                Modifiers.ABSTRACT | Modifiers.STATIC | Modifiers.FINAL |
1558                Modifiers.SYNCHRONIZED | Modifiers.NATIVE | Modifiers.STRICT;
1559        }
1560
1561        Modifiers modifiers = parseModifiers(legalModifiers);
1562        if (inInterface) {
1563            modifiers.setAbstract(true);
1564            modifiers.setPublic(true);
1565        }
1566
1567
1568        TypeD typeD = parseTypeD();
1569        String JavaDoc id = parseId();
1570
1571        Formals formals = parseFormals();
1572
1573        // handle funky "int foo()[] {" return type specifier
1574
typeD = addBracketsToTypeD(typeD);
1575
1576        TypeDs _throws = parseThrows();
1577
1578        return new MethodDec(dummySource,modifiers, typeD, id, formals, _throws,
1579                             parseOptionalCodeBody());
1580    }
1581
1582    public Stmt parseVarDec() { return parseVarDec(false); }
1583    public Stmt parseFieldDec() { return parseVarDec(true); }
1584
1585
1586    // returns either a multivardec or a vardec
1587
public Stmt parseVarDec(boolean isField) {
1588        int legalModifiers;
1589
1590        if (isField) {
1591            if (inInterface) {
1592                legalModifiers = Modifiers.PUBLIC | Modifiers.STATIC | Modifiers.FINAL;
1593            } else {
1594                legalModifiers = Modifiers.PUBLIC | Modifiers.PROTECTED | Modifiers.PRIVATE |
1595                    Modifiers.STATIC | Modifiers.FINAL |
1596                    Modifiers.TRANSIENT | Modifiers.VOLATILE;
1597            }
1598        } else {
1599            legalModifiers = Modifiers.FINAL;
1600        }
1601
1602        Token beginToken = peekToken();
1603        Modifiers modifiers = parseModifiers(legalModifiers);
1604
1605        if (inInterface) {
1606            modifiers.setPublic(true);
1607            modifiers.setStatic(true);
1608        }
1609
1610        TypeD baseTypeD = parseTypeD();
1611
1612        Decs decs = null;
1613        VarDec dec = null;
1614
1615        while (true) {
1616            String JavaDoc id = parseId();
1617            TypeD typeD = baseTypeD;
1618
1619            Expr initializer = null;
1620            typeD = addBracketsToTypeD(typeD);
1621            //VarDes des = new VarDes(modifiers, id, typeD);
1622
//??? what should the context really be for a var des in a list
1623
//addContext(des, beginToken);
1624

1625            Token endToken = popToken();
1626            if (endToken.kind == ASSIGN) {
1627                if (typeD instanceof ArrayTypeD && peekToken().kind == LBRACE) {
1628                    initializer = parseArrayInitializer();
1629                } else {
1630                    initializer = parseExpr();
1631                }
1632                endToken = popToken();
1633            }
1634
1635            if (isField) {
1636                dec = new FieldDec(dummySource,(Modifiers)modifiers.copy(), typeD, id, initializer);
1637            } else {
1638                dec = new VarDec(dummySource,(Modifiers)modifiers.copy(), typeD, id, initializer);
1639            }
1640            addContext(dec, beginToken);
1641
1642            if (endToken.kind == SEMICOLON) {
1643                if (decs != null) decs.add(dec);
1644                break;
1645            } else if (endToken.kind == COMMA) {
1646                if (decs == null) decs = new Decs(dummySource,dec);
1647                else decs.add(dec);
1648
1649                // this copy is needed to keep the AST a tree and not a graph
1650
baseTypeD = (TypeD)baseTypeD.copy();
1651                continue;
1652            } else {
1653                throwError(endToken, "expected ',' or ';'");
1654            }
1655        }
1656
1657        if (decs != null) return decs;
1658        else return dec;
1659    }
1660
1661    public String JavaDoc parseAnyId() {
1662        Token token = popToken();
1663        if (!isIdentifier(token)) {
1664            throwError(token, "identifier expected");
1665        }
1666        return token.image;
1667    }
1668
1669    public String JavaDoc parseId() {
1670        Token token = popToken();
1671        if (!isIdentifier(token) || isKeyword(token)) {
1672            throwError(token, "identifier expected");
1673        }
1674        return token.image;
1675    }
1676
1677    public String JavaDoc parseIdOrKeywords_this_super_class() {
1678        Token token = popToken();
1679        if (!isIdentifier(token) || isKeyword(token)) {
1680            if (!( token.image.equals("this")
1681                 || token.image.equals("super")
1682                 || token.image.equals("class")
1683                ))
1684            throwError(token, "identifier expected");
1685        }
1686        return token.image;
1687    }
1688
1689
1690    public FormalDec parseParenFormal() {
1691        eatTopToken(LPAREN);
1692        FormalDec formal = parseFormal();
1693        eatTopToken(RPAREN);
1694
1695        return formal;
1696    }
1697
1698    public Exprs parseExprs(int stopKind) {
1699        Token beginToken = peekToken();
1700        Exprs exprs = new Exprs(dummySource);
1701
1702        if (beginToken.kind != stopKind) {
1703            while (true) {
1704                Expr expr = parseExpr();
1705                exprs.add(expr);
1706                if (peekToken().kind != COMMA) break;
1707                eatTopToken();
1708            }
1709        }
1710        addContext(exprs, beginToken);
1711        return exprs;
1712    }
1713
1714    //public Exprs parseExprs(int stopKind) {
1715
// return new Exprs(parseExprArray(stopKind));
1716
//}
1717

1718    public Exprs parseParenExprs() {
1719        eatTopToken(LPAREN);
1720        Exprs exprs = parseExprs(RPAREN);
1721        eatTopToken(RPAREN);
1722        return exprs;
1723    }
1724
1725
1726    public ArrayInitializer parseArrayInitializer() {
1727        ArrayInitializer ret;
1728        eatTopToken(LBRACE);
1729
1730        Exprs exprs = new Exprs(dummySource);
1731
1732        if (maybeEatToken(RBRACE)) {
1733            return new ArrayInitializer(dummySource,exprs);
1734        }
1735
1736        while (true) {
1737            Expr expr;
1738            if (peekToken().kind == LBRACE) {
1739                expr = parseArrayInitializer();
1740            } else if (maybeEatToken(COMMA)) {
1741                if (exprs.size() > 0 || !getCompiler().getOptions().lenient) {
1742                    showError(peekToken(-1), "too many commas");
1743                }
1744                break;
1745            } else {
1746                expr = parseExpr();
1747            }
1748            exprs.add(expr);
1749            if (!maybeEatToken(COMMA)) break;
1750            if (peekToken().kind == RBRACE) break;
1751        }
1752        eatTopToken(RBRACE);
1753        return new ArrayInitializer(dummySource,exprs);
1754    }
1755
1756    public Exprs parseArrayDimExprs() {
1757        // check for an array type
1758
Exprs exprs = new Exprs(dummySource);
1759        while (peekToken().kind == LBRACKET) {
1760            eatTopToken();
1761            if (peekToken().kind == RBRACKET) {
1762                exprs.add(new EmptyExpr(dummySource));
1763            } else {
1764                exprs.add(parseExpr());
1765            }
1766            eatTopToken(RBRACKET);
1767        }
1768        return exprs;
1769    }
1770
1771    public Expr parseParenExpr() {
1772        eatTopToken(LPAREN);
1773        Expr expr = parseExpr();
1774        eatTopToken(RPAREN);
1775
1776        return expr;
1777    }
1778
1779    public Expr parseExpr() {
1780        return parseExpr(false);
1781    }
1782
1783    public Expr parseExpr(boolean allowNulls) {
1784        Expr ret = exprParser.parse();
1785        if (!allowNulls && ret == null) {
1786            throwError(null, "expression required");
1787        }
1788        return ret;
1789    }
1790
1791    protected String JavaDoc grabFormalComment(Token token) {
1792        while ((token = token.specialToken) != null) {
1793            if (token.kind == FORMAL_COMMENT) {
1794                return token.image;
1795            }
1796        }
1797        return null;
1798    }
1799
1800    protected void addComments(ASTObject ast, Token beginToken) {
1801        //System.out.println(ast + ": " + beginToken);
1802

1803        // we only stick formal comments on Dec's
1804
if (ast instanceof Dec) {
1805            String JavaDoc comment = grabFormalComment(beginToken);
1806            if (comment != null) ast.setFormalComment(comment);
1807        }
1808    }
1809
1810    protected SourceLocation makeSourceLocation(Token beginToken) {
1811        Token endToken = peekToken(-1);
1812        if (endToken == null) endToken = beginToken;
1813        SourceLocation ret = new TextSourceLocation(currentCompilationUnit,
1814                                                beginToken.startPosition,
1815                                                endToken.endPosition);
1816        return ret;
1817    }
1818
1819    protected SourceLocation makeSourceLocation(SourceLocation beginSourceLoc) {
1820        Token endToken = peekToken(-1);
1821        int startPosition = -1;
1822        if (beginSourceLoc != null) startPosition = beginSourceLoc.getStartPosition();
1823        SourceLocation ret = new TextSourceLocation(currentCompilationUnit,
1824                                                startPosition,
1825                                                endToken.endPosition);
1826        return ret;
1827    }
1828
1829    protected void addContext(ASTObject ast, ASTObject beginAST) {
1830        if (ast == null) return;
1831        ast.setSourceLocation(makeSourceLocation(beginAST.getSourceLocation()));
1832    }
1833
1834    protected void addContext(ASTObject ast, Token beginToken) {
1835        if (ast == null) return;
1836        ast.setSourceLocation(makeSourceLocation(beginToken));
1837        addComments(ast, beginToken);
1838    }
1839
1840    public Stmt parseStmt() {
1841        Token beginToken = peekToken();
1842        Stmt ret = parseStmt(null, false, false);
1843        addContext(ret, beginToken);
1844        return ret;
1845    }
1846
1847    public boolean lookaheadFormals() {
1848        if (peekToken().kind != LPAREN) return false;
1849        if (peekToken(1).kind == RPAREN) return true;
1850
1851        int start = currentIndex;
1852        eatTopToken();
1853
1854        if (eatModifiers() && eatTypeD() && isIdentifier(peekToken())) {
1855            currentIndex = start;
1856            return true;
1857        }
1858        currentIndex = start;
1859        return false;
1860    }
1861
1862
1863    private Stmt parseStmt(Map extraDecParsers,
1864                           boolean allowConstructors, boolean onlyDec) {
1865        Token topToken = peekToken();
1866
1867        // Step 1. check for a statement keyword or a labeled statement
1868
if (!onlyDec && isIdentifier(topToken)) {
1869            String JavaDoc keyword = topToken.image;
1870            StmtParser stmtParser = (StmtParser)stmtParsers.get(keyword);
1871            if (stmtParser != null) {
1872                eatTopToken();
1873                return stmtParser.parse();
1874            } else if (peekToken(1).kind == COLON) {
1875                if (isKeyword(popToken())) { //label
1876
showError(peekToken(-1), "keyword not allowed as label");
1877                }
1878                eatTopToken(); // :
1879
Stmt stmt = parseStmt(extraDecParsers, allowConstructors, onlyDec);
1880                return new LabeledStmt(dummySource,keyword, stmt);
1881            }
1882        }
1883
1884        // Step 2. check for the variety of possible decs
1885
// method: typed id(
1886
// constructor: id(
1887
// var: typed id
1888
// initialized: {
1889
// named: keyword ...
1890

1891        pushCurrentIndex();
1892        eatModifiers();
1893        topToken = peekToken();
1894
1895        // check for named dec
1896
if (isIdentifier(topToken)) {
1897            String JavaDoc keyword = topToken.image;
1898
1899            DecParser decParser;
1900            if (allowConstructors) {
1901                decParser = (DecParser)decParsers.get(keyword);
1902            } else {
1903                decParser = (DecParser)stmtDecParsers.get(keyword);
1904            }
1905
1906            if (extraDecParsers != null && decParser == null) {
1907                decParser = (DecParser)extraDecParsers.get(keyword);
1908            }
1909            if (decParser != null) {
1910                popCurrentIndex();
1911                return decParser.parse(onlyDec);
1912            }
1913        }
1914
1915        if (allowConstructors) {
1916            //!!! inserting some strange code here for the sake of introduction blocks
1917
if (isIdentifierOrNew(topToken)) {
1918                eatTopToken();
1919                if (lookaheadFormals()) {
1920                    popCurrentIndex();
1921                    return parseConstructorDec();
1922                } else {
1923                    currentIndex -= 1;
1924                }
1925            }
1926            if (topToken.kind == LBRACE) {
1927                popCurrentIndex();
1928                return parseInitializerDec();
1929                //return new InitializerDec(new Des[] {new InitializerDes(modifiers, null)},
1930
// parseBlockStmt());
1931
}
1932        }
1933
1934        if (eatTypeD() && eatIdentifier(onlyDec)) {
1935            if (peekToken().kind == LPAREN) {
1936                popCurrentIndex();
1937                return parseMethodDec();
1938            } else {
1939                popCurrentIndex();
1940                if (onlyDec) {
1941                    return parseFieldDec();
1942                } else {
1943                    return parseVarDec();
1944                }
1945            }
1946        }
1947
1948        // give up on looking for a dec
1949
popCurrentIndex();
1950        if (onlyDec) {
1951            return noDecFound();
1952        }
1953
1954        // Step 3. parse unnamed stmts
1955
if (topToken.kind == SEMICOLON) {
1956            eatTopToken();
1957            return new EmptyStmt(dummySource);
1958        }
1959
1960        if (topToken.kind == LBRACE) {
1961            return parseBlockStmt();
1962        }
1963
1964        Expr expr = parseExpr();
1965        eatTopToken(SEMICOLON);
1966        return new ExprStmt(dummySource,expr);
1967    }
1968
1969    protected Dec noDecFound() {
1970        throwError(peekToken(), "declaration or '}' expected");
1971        return null;
1972    }
1973
1974
1975    private Stmt parseTopDec(Map extraDecParsers) {
1976        Token topToken = peekToken();
1977
1978        pushCurrentIndex();
1979        eatModifiers();
1980        topToken = peekToken();
1981
1982        // check for named dec
1983
if (isIdentifier(topToken)) {
1984            String JavaDoc keyword = topToken.image;
1985            DecParser decParser = (DecParser)decParsers.get(keyword);
1986            if (extraDecParsers != null && decParser == null) {
1987                decParser = (DecParser)extraDecParsers.get(keyword);
1988            }
1989            if (decParser != null) {
1990                popCurrentIndex();
1991                return decParser.parse(true);
1992            }
1993        }
1994
1995        // give up on looking for a dec
1996
popCurrentIndex();
1997        throwError(topToken, "type declaration expected");
1998        return null;
1999    }
2000
2001
2002    /* error handling code */
2003    public void throwError(Token t, String JavaDoc message) {
2004        if (t == null) t = peekToken();
2005        //System.out.println(t);
2006
//if (getCompiler().getOptions().dumpstack) Thread.dumpStack();
2007
throw new ParseException(t, tokenSource.sourceInfo, message);
2008    }
2009
2010
2011    public void warnVersion(String JavaDoc version, Token t, String JavaDoc message) {
2012        getCompiler().warnVersion(version, tokenToASTObject(t), message);
2013    }
2014
2015    public void showError(Token t, String JavaDoc message) {
2016         getCompiler().showError(tokenToASTObject(t), message);
2017    }
2018
2019    // utility function for interacting with code that expects an ASTObject
2020
static class FakeASTObject extends ASTObject {
2021        public FakeASTObject(SourceLocation loc) {
2022            super(loc);
2023            //setSourceLocation(loc);
2024
//XXX should be new CompilationUnit(file);
2025
// source = new CompilationUnit(compiler,null, null, null, _sourceInfo,true);
2026
// startPosition = _startPosition;
2027
}
2028        public ASTObject copy() { return null; }
2029        public int getChildCount() { return 0; }
2030    }
2031
2032    public ASTObject tokenToASTObject(Token t) {
2033        ASTObject fake = new FakeASTObject(makeSourceLocation(t));//tokenSource.sourceInfo, t.startPosition);
2034
return fake;
2035    }
2036
2037
2038    // dec parsers
2039
public static abstract class DecParser {
2040        public Dec parse(boolean isNotMethodLocal) {
2041            // actually, boolean doesn't matter, since class/interface/etc
2042
// parsers should override parse(boolean) method
2043
return parse();
2044        }
2045        abstract public Dec parse();
2046    }
2047
2048    class InterfaceDecParser extends DecParser {
2049        public Dec parse() {
2050            // not used, we override parse(boolean)
2051
throw new RuntimeException JavaDoc();
2052        }
2053        public Dec parse(boolean isNotMethodLocal) {
2054            int legalModifiers;
2055            if (!isNotMethodLocal) {
2056                legalModifiers = Modifiers.ABSTRACT | Modifiers.STRICT;
2057            } else if (peekEnclosingTypeDec() == null) {
2058                legalModifiers = Modifiers.PUBLIC | Modifiers.ABSTRACT | Modifiers.STRICT;
2059            } else if (inInterface) {
2060                legalModifiers = Modifiers.PUBLIC | Modifiers.ABSTRACT |
2061                    Modifiers.STRICT | Modifiers.STATIC;
2062            } else {
2063                legalModifiers = Modifiers.PUBLIC | Modifiers.ABSTRACT | Modifiers.STRICT |
2064                    Modifiers.PRIVATE | Modifiers.PROTECTED | Modifiers.STATIC;
2065            }
2066
2067            Modifiers modifiers = parseModifiers(legalModifiers);
2068            if (inInterface) {
2069                modifiers.setPublic(true);
2070            }
2071            eatKeyword("interface");
2072            String JavaDoc id = parseId();
2073
2074            TypeDs _extends = null;
2075            if (maybeEatKeyword("extends")) {
2076                _extends = parseTypeDs();
2077            }
2078
2079            TypeDec ret = new InterfaceDec(dummySource, modifiers, id, _extends, null);
2080            ret.setEnclosingTypeDec(peekEnclosingTypeDec());
2081
2082            pushEnclosingTypeDec(ret);
2083            Decs body = null;
2084            boolean oldInInterface = inInterface;
2085            try {
2086                inInterface = true;
2087                body = parseDecs();
2088            } finally {
2089                inInterface = oldInInterface;
2090            }
2091            popEnclosingTypeDec();
2092            ret.setBody(body);
2093
2094            if (peekEnclosingTypeDec() == null) currentCompilationUnit.addDefinedType(ret);
2095            return ret;
2096        }
2097    }
2098
2099    class ClassDecParser extends DecParser {
2100        public Dec parse() {
2101            // not used, we override parse(boolean)
2102
throw new RuntimeException JavaDoc();
2103        }
2104        public Dec parse(boolean isNotMethodLocal) {
2105            int legalModifiers;
2106            if (!isNotMethodLocal) {
2107                legalModifiers = Modifiers.ABSTRACT | Modifiers.FINAL | Modifiers.STRICT;
2108            } else if (peekEnclosingTypeDec() == null) {
2109                legalModifiers = Modifiers.PUBLIC | Modifiers.ABSTRACT | Modifiers.FINAL |
2110                    Modifiers.STRICT;
2111            } else if (inInterface) {
2112                legalModifiers = Modifiers.PUBLIC | Modifiers.ABSTRACT | Modifiers.FINAL |
2113                    Modifiers.STRICT | Modifiers.STATIC;
2114            } else {
2115                legalModifiers = Modifiers.PUBLIC | Modifiers.ABSTRACT | Modifiers.FINAL |
2116                    Modifiers.STRICT |
2117                    Modifiers.PRIVATE | Modifiers.PROTECTED | Modifiers.STATIC;
2118            }
2119
2120            Modifiers modifiers = parseModifiers(legalModifiers);
2121            if (inInterface) {
2122                modifiers.setPublic(true);
2123            }
2124
2125            eatKeyword("class");
2126            String JavaDoc id = parseId();
2127
2128            TypeD superClass = null;
2129            if (maybeEatKeyword("extends")) {
2130                superClass = parseTypeD();
2131            }
2132            TypeDs _implements = null;
2133            if (maybeEatKeyword("implements")) {
2134                _implements = parseTypeDs();
2135            }
2136
2137            TypeDec ret =
2138                new ClassDec(dummySource, modifiers, id, superClass, _implements, null);
2139            if(!isNotMethodLocal) ret.setLocal();
2140            ret.setEnclosingTypeDec(peekEnclosingTypeDec());
2141
2142            pushEnclosingTypeDec(ret);
2143
2144            Decs body = null;
2145            boolean oldInInterface = inInterface;
2146            try {
2147                inInterface = false;
2148                body = parseDecs();
2149            } finally {
2150                inInterface = oldInInterface;
2151            }
2152            popEnclosingTypeDec();
2153
2154            ret.setBody(body);
2155            if (peekEnclosingTypeDec() == null) currentCompilationUnit.addDefinedType(ret);
2156            return ret;
2157        }
2158    }
2159
2160
2161    // stmt parsers
2162
public static abstract class StmtParser {
2163        abstract public Stmt parse();
2164    }
2165
2166    class BreakStmtParser extends StmtParser {
2167        public Stmt parse() {
2168            String JavaDoc label = null;
2169            if (peekToken().kind != SEMICOLON) {
2170                label = parseId();
2171            }
2172            eatTopToken(SEMICOLON);
2173            return new BreakStmt(dummySource,label);
2174        }
2175    }
2176
2177    class ContinueStmtParser extends StmtParser {
2178        public Stmt parse() {
2179            String JavaDoc label = null;
2180            if (peekToken().kind != SEMICOLON) {
2181                label = parseId();
2182            }
2183            eatTopToken(SEMICOLON);
2184            return new ContinueStmt(dummySource,label);
2185        }
2186    }
2187
2188    class DoStmtParser extends StmtParser {
2189        public Stmt parse() {
2190            Stmt body = parseStmt();
2191
2192            eatKeyword("while");
2193            Expr test = parseParenExpr();
2194            eatTopToken(SEMICOLON);
2195
2196            return new DoStmt(dummySource, body, test);
2197        }
2198    }
2199
2200    class AssertStmtParser extends StmtParser {
2201        public Stmt parse() {
2202            Expr test = parseExpr();
2203            Expr message = null;
2204            if (maybeEatToken(COLON)) {
2205                message = parseExpr();
2206            }
2207            eatTopToken(SEMICOLON);
2208
2209            return new AssertStmt(dummySource, test, message);
2210        }
2211    }
2212
2213    class ForStmtParser extends StmtParser {
2214        public Stmt parse() {
2215            eatTopToken(LPAREN);
2216            ASTObject init;
2217            Expr test;
2218            Exprs update;
2219
2220            // check for a var dec
2221
if (lookaheadVarDes()) {
2222                init = parseVarDec();
2223            } else {
2224                init = parseExprs(SEMICOLON);
2225                eatTopToken(SEMICOLON);
2226            }
2227
2228            test = parseExpr(true);
2229            eatTopToken(SEMICOLON);
2230            update = parseExprs(RPAREN);
2231            eatTopToken(RPAREN);
2232            Stmt body = parseStmt();
2233
2234            ForStmt forStmt = new ForStmt(dummySource,init, test, update, body);
2235            if (test == null) {
2236                forStmt.setTest((Expr)
2237                                new BooleanLiteralExpr(dummySource, true)
2238                                    .setSyntheticSource(forStmt));
2239            }
2240            return forStmt;
2241        }
2242    }
2243
2244    class IfStmtParser extends StmtParser {
2245        public Stmt parse() {
2246            Expr test = parseParenExpr();
2247            Stmt _then = parseStmt();
2248            Stmt _else = null;
2249            if (maybeEatKeyword("else")) {
2250                _else = parseStmt();
2251            }
2252            IfStmt ifStmt = new IfStmt(dummySource,test, _then, _else);
2253            if (_else == null) {
2254                ifStmt.setElse((Stmt)
2255                               new EmptyStmt(dummySource).setSyntheticSource(ifStmt));
2256            }
2257            return ifStmt;
2258        }
2259    }
2260
2261    class ReturnStmtParser extends StmtParser {
2262        public Stmt parse() {
2263            Expr expr = null;
2264            if (peekToken().kind != SEMICOLON) {
2265                expr = parseExpr();
2266            }
2267            eatTopToken(SEMICOLON);
2268            return new ReturnStmt(dummySource,expr);
2269        }
2270    }
2271
2272    class SwitchStmtParser extends StmtParser {
2273        public Stmt parse() {
2274            Expr expr = parseParenExpr();
2275
2276            eatTopToken(LBRACE);
2277            SwitchClauses clauses = new SwitchClauses(dummySource);
2278            Expr label = null;
2279            Stmts stmts = null;
2280            SwitchClause switchClause=null;
2281
2282            while (true) {
2283                if (maybeEatKeyword("case")) {
2284                    label = parseExpr();
2285                    eatTopToken(COLON);
2286                    if (switchClause != null) clauses.add(switchClause);
2287                    stmts = new Stmts(dummySource);
2288                    switchClause = new SwitchClause(dummySource,label, stmts);
2289                } else if (maybeEatKeyword("default")) {
2290                    eatTopToken(COLON);
2291                    if (switchClause != null) clauses.add(switchClause);
2292                    stmts = new Stmts(dummySource);
2293                    switchClause = new SwitchClause(dummySource,null, stmts);
2294                } else if (peekToken().kind == RBRACE) {
2295                    if (switchClause != null) clauses.add(switchClause);
2296                    eatTopToken();
2297                    break;
2298                } else {
2299                    if (stmts == null) {
2300                        throwError(peekToken(), "'case', 'default' or '}' expected");
2301                        break;
2302                    }
2303                    stmts.add(parseStmt());
2304                }
2305            }
2306
2307            return new SwitchStmt(dummySource,expr, clauses);
2308        }
2309    }
2310
2311    class SynchronizedStmtParser extends StmtParser {
2312        public Stmt parse() {
2313            Expr expr = parseParenExpr();
2314            Stmt body = parseStmt();
2315
2316            return new SynchronizedStmt(dummySource,expr, body);
2317        }
2318    }
2319
2320    class ThrowStmtParser extends StmtParser {
2321        public Stmt parse() {
2322            Expr expr = parseExpr();
2323            eatTopToken(SEMICOLON);
2324            return new ThrowStmt(dummySource,expr);
2325        }
2326    }
2327
2328    class GotoStmtParser extends StmtParser {
2329        public Stmt parse() {
2330            showError(peekToken(),"'goto' is java reserved keyword");
2331            return null;
2332        }
2333    }
2334
2335    class TryStmtParser extends StmtParser {
2336        public Stmt parse() {
2337            Stmt body = parseStmt();
2338
2339            CatchClauses catches = new CatchClauses(dummySource);
2340            Token beginToken = peekToken();
2341            while (maybeEatKeyword("catch")) {
2342                FormalDec formal = parseParenFormal();
2343                Stmt catchBody = parseStmt();
2344                CatchClause clause = new CatchClause(dummySource,formal, catchBody);
2345                addContext(clause, beginToken);
2346                catches.add(clause);
2347                beginToken = peekToken();
2348            }
2349
2350            Stmt _finally = null;
2351            if (maybeEatKeyword("finally")) {
2352                _finally = parseStmt();
2353            }
2354
2355            if (catches.size() == 0) {
2356                return new TryFinallyStmt(dummySource, body, _finally);
2357            } else if (_finally == null) {
2358                return new TryCatchStmt(dummySource, body, catches);
2359            } else {
2360                TryFinallyStmt s = new TryFinallyStmt(dummySource, null, _finally);
2361                TryCatchStmt b = new TryCatchStmt(dummySource, body, catches);
2362                b.setSyntheticSource(s);
2363                s.setBody(b);
2364                return s;
2365            }
2366        }
2367    }
2368
2369    class WhileStmtParser extends StmtParser {
2370        public Stmt parse() {
2371            Expr test = parseParenExpr();
2372            Stmt body = parseStmt();
2373            return new WhileStmt(dummySource,test, body);
2374        }
2375    }
2376
2377}
2378
2379
2380/* Thoughts on macros
2381
2382macro for (ExprList init; Expr[boolean] test; ExprList update) {Stmt @code} => {
2383  @init;
2384  while (@test) {
2385    @code;
2386    @update;
2387  }
2388}
2389
2390macro do {@code} while (@test); => {
2391  while (true) {
2392    @code;
2393    if (@test) break;
2394  }
2395}
2396
2397macro foreach (@type @var) in (@sequence) {@code} => {
2398  Collection temp = @sequence;
2399  for (Iterator iter = temp.iterator(); iter.hasNext(); ) {
2400    @type @var = (@type)iter.next();
2401    @code;
2402  }
2403}
2404
2405*/

2406
Popular Tags