001 /* Copyright 2000, 2001, Compaq Computer Corporation */
002
003 package javafe.parser;
004
005 import javafe.ast.*;
006 import javafe.util.StackVector;
007 import javafe.util.Location;
008 import javafe.util.ErrorSet;
009 import javafe.Tool;
010
011 /**
012 * <code>Parse</code> objects parse Java statements, creating AST
013 * structures for the parsed input using the static
014 * <code>make*()</code> methods of the classes in the
015 * <code>javafe.ast</code> package.
016 *
017 * <p> The concrete grammar for statements is as follows:
018 * <pre>
019 * Statement:
020 * ';'
021 * | (Modifier | ModifierPragma)* ClassDeclaration
022 * | (Modifier | ModifierPragma)* Type { Idn [ '=' InitExpr ] },+ ';'
023 * | Idn ':' Stmt
024 * | Expr ';'
025 * | '{' BlockStmt* '}'
026 * // In an assert, BoolExpr must be of type boolean, NonVoidExpr must
027 * // not be of type void
028 * | 'assert' BoolExpr [ ':' NonVoidExpr ] ';'
029 * | 'break' [ Idn ] ';'
030 * | 'continue' [ Idn ] ';'
031 * | 'return' [ Expr ] ';'
032 * | 'throw' Expr ';'
033 * | 'if' '(' Expr ')' Stmt [ 'else' Stmt ]
034 * | 'do' Stmt 'while' '(' Expr ')' ';'
035 * | 'while' '(' Expr ')' Stmt
036 * | 'for' '(' [ VDeclInit | StmtExpr,* ] ';' Expr ';' StmtExpr,* ')' Stmt
037 * | 'switch' '(' Expr ')'
038 * '{' { {'case' Expr ':' | 'default:'}* BlockStmt* }* '}'
039 * | 'synchronized' '(' Expr ')' '{' BlockStmt* '}'
040 * | 'try' '{' BlockStmt* '}' { 'catch' '(' VDecl,* ')' '{' BlockStmt* '}' }*
041 * [ 'finally' '{' BlockStmt* '}' ]
042 * | StmtPragma
043 * </pre>
044 *
045 * <p> Currently, there is no error recovery. Upon detection of a
046 * syntax error, all methods in this class throw a {@link
047 * RuntimeException} with a (weak) error message.
048 *
049 * <p> Although the class as a whole is thread-safe, that is,
050 * different threads can be calling methods of different instances of
051 * <code>ParseStmt</code> at the same time, individual instances are
052 * not.
053 *
054 * @see javafe.ast.ASTNode
055 */
056
057 public abstract class ParseStmt extends ParseExpr
058 {
059 public ParseStmt() {
060 //@ set seqStmt.elementType = \type(Stmt);
061 //@ set seqStmt.owner = this;
062
063 //@ set seqCatchClause.elementType = \type(CatchClause);
064 //@ set seqCatchClause.owner = this;
065 }
066
067 /**
068 * Internal working storage for many <code>ParseStmt</code>
069 * functions.
070 */
071 //@ invariant seqStmt.elementType == \type(Stmt);
072 //@ invariant seqStmt.owner == this;
073 protected final /*@ non_null @*/ StackVector seqStmt
074 = new StackVector();
075
076 //* Internal working storage for parseCatches function.
077 //@ invariant seqCatchClause.elementType == \type(CatchClause);
078 //@ invariant seqCatchClause.owner == this;
079 protected final /*@ non_null @*/ StackVector seqCatchClause
080 = new StackVector();
081
082 /**
083 * Parse a type declaration stating at the class/interface
084 * keyword. A declaration of this method is needed because class
085 * declarations can be in statements. However, the body (and more
086 * documentation) lives in Parse.java.
087 */
088 //@ requires l != null && l.m_in != null;
089 //@ requires loc != Location.NULL;
090 //@ modifies l.ttype;
091 //@ ensures \result != null;
092 //@ ensures \old(l.ttype)==TagConstants.CLASS ==> \result instanceof ClassDecl;
093 abstract TypeDecl parseTypeDeclTail(Lex l, boolean specOnly, int loc,
094 int modifiers,
095 ModifierPragmaVec modifierPragmas);
096
097 /**
098 * Method for parsing a <code>Stmt</code>.
099 *
100 * <p> Effects: Parses a single <code>Stmt</code> according to the
101 * grammar at the top of this file, <em>except</em> that it does
102 * not accept variable-declaration statements. If no syntax
103 * errors are encountered, it adds one or more <code>Stmt</code>
104 * to <code>seqStmt</code>, leaving <code>l</code> at the token
105 * just after the trailing <code>}</code> of the statement. More
106 * than one statement is added only in the case of variable
107 * declarations that declare more than one variable.
108 */
109 //@ requires l != null && l.m_in != null;
110 //@ ensures \result != null;
111 public Stmt parseStatement(Lex l) {
112 if (l.ttype == TagConstants.LBRACE) // As an optimization, handle specially
113 return parseBlock(l, false);
114 else {
115 seqStmt.push();
116 int loc = l.startingLoc;
117 addStmt(l);
118 Stmt result = (Stmt)seqStmt.elementAt(0);
119 if (seqStmt.size() != 1 || result instanceof VarDeclStmt) {
120 fail(loc,
121 "Variable declarations are not legal in this context.");
122 }
123 if (result instanceof StmtPragma) {
124 fail(loc,
125 "Statement pragmas are not legal in this context.");
126 }
127
128 seqStmt.pop();
129 return result;
130 }
131 }
132
133 /**
134 * Internal method for parsing a <code>Stmt</code>.
135 *
136 * <p> Effects: Parses a single <code>Stmt</code> according to the
137 * grammar at the top of this file. If no syntax errors are
138 * encountered, it adds one or more <code>Stmt</code> to
139 * <code>seqStmt</code>, leaving <code>l</code> at the token just
140 * after the trailing <code>}</code> of the statement. More than
141 * one statement is added only in the case of variable
142 * declarations that declare more than one variable.
143 */
144 //@ requires l != null && l.m_in != null;
145 //-@ modifies seqStmt.elementCount, seqStmt.currentStackBottom;
146 /*@ ensures (seqStmt.elementCount - seqStmt.currentStackBottom) >
147 (\old(seqStmt.elementCount) - \old(seqStmt.currentStackBottom)); @*/
148 protected void addStmt(Lex l) {
149 int ttype = l.ttype;
150
151 // Stmt ::= ';'
152 if (ttype == TagConstants.SEMICOLON) {
153 int loc = l.startingLoc;
154 l.getNextToken(); // Discard ';'
155 seqStmt.addElement( SkipStmt.make(loc) );
156 return;
157 }
158
159 // Stmt ::= Idn ':' Stmt
160 // | Idn { '[' ']' }* { Idn ['=' InitExpr] },+
161 // | Expr ';'
162 if (ttype == TagConstants.IDENT) {
163 // FIXME @ assert !l.toString().equals("assert");
164 Expr e = parseExpression(l);
165 if (e.getTag() == TagConstants.AMBIGUOUSVARIABLEACCESS) {
166 Name n = ((AmbiguousVariableAccess)e).name;
167
168 // Check to see if we have a labeled expr...
169 if (l.ttype == TagConstants.COLON) {
170 l.getNextToken(); // Discard ':'
171 if (n.size() != 1)
172 fail(l.startingLoc, "Can't have qualified name in this context");
173 Identifier id = n.identifierAt(0);
174 int locId = n.locIdAt(0);
175 seqStmt.addElement( LabelStmt.make(id, parseStatement(l), locId) );
176 return;
177 }
178
179 // Assume we have a variable declaration
180 // first, look for modifiers on type name
181 TypeModifierPragmaVec tmodifiers = null;
182 tmodifiers = parseTypeModifierPragmas(l);
183 Type basetype = TypeName.make(tmodifiers, n);
184
185 basetype = parseBracketPairs(l, basetype);
186 //alx: dw need to reset universeArray because in this case,
187 // parseModifiers wasn't called (which would have reseted
188 // universeArray)
189 universeArray[0]=0;
190 universeArray[1]=0;
191 //alx-end
192
193 addVarDeclStmts(l, Modifiers.NONE, null, basetype);
194 expect(l, TagConstants.SEMICOLON);
195 return;
196 } else {
197 expect(l, TagConstants.SEMICOLON);
198 // TODO: make sure e is a statement expr
199 seqStmt.addElement( EvalStmt.make(e) );
200 return;
201 }
202 }
203
204 // Stmt ::= '{' ... '}' (that is, a Block)
205 if (ttype == TagConstants.LBRACE) {
206 seqStmt.addElement( parseBlock(l, false) );
207 return;
208 }
209
210 // Stmt ::= <keyword> ...
211 int keywordloc = l.startingLoc;
212 switch (ttype) {
213 case TagConstants.ASSERT: { // 'assert' BoolExpr [ ':' NonVoidExpr ] ';'
214
215 int loc = l.startingLoc;
216 l.getNextToken(); // Discard the keyword
217 Expr predicate = parseExpression(l);
218 Expr label = null;
219 if (l.ttype == TagConstants.COLON) {
220 l.getNextToken();
221 label = parseExpression(l);
222 }
223 expect(l, TagConstants.SEMICOLON);
224 // Only process if assert *is* a keyword.
225 if (Tool.options != null && !Tool.options.assertIsKeyword) {
226 ErrorSet.error(loc, "Java keyword \"assert\" is only supported if the" +
227 " -source 1.4 option is provided.");
228 } else
229 seqStmt.addElement(AssertStmt.make(predicate, label, keywordloc));
230 return;
231 }
232
233 case TagConstants.BREAK: // 'break' [ Idn ] ';'
234 case TagConstants.CONTINUE: { // 'continue' [ Idn ] ';'
235 l.getNextToken(); // Discard the keyword
236 Identifier label = null;
237 if (l.ttype == TagConstants.IDENT) {
238 label = l.identifierVal;
239 l.getNextToken(); // Discard IDENT
240 }
241 expect(l, TagConstants.SEMICOLON);
242 seqStmt.addElement(ttype == TagConstants.BREAK ?
243 (Stmt)BreakStmt.make(label, keywordloc)
244 : (Stmt)ContinueStmt.make(label, keywordloc));
245 return;
246 }
247
248 case TagConstants.RETURN: // 'return' Expr ';'
249 l.getNextToken(); // Discard the keyword
250 if (l.ttype == TagConstants.SEMICOLON) {
251 l.getNextToken(); // Discard ';'
252 seqStmt.addElement( ReturnStmt.make(null, keywordloc) );
253 } else {
254 Expr expr = parseExpression(l);
255 expect(l, TagConstants.SEMICOLON);
256 seqStmt.addElement(ReturnStmt.make(expr, keywordloc));
257 }
258 return;
259
260 case TagConstants.THROW: { // 'throw' Expr ';'
261 l.getNextToken(); // Discard the keyword
262 Expr expr = parseExpression(l);
263 expect(l, TagConstants.SEMICOLON);
264 seqStmt.addElement(ThrowStmt.make(expr, keywordloc));
265 return;
266 }
267
268 case TagConstants.IF: { // 'if' '(' Expr ')' Stmt [ 'else' Stmt ]
269 l.getNextToken(); // Discard the keyword
270 expect(l, TagConstants.LPAREN);
271 Expr test = parseExpression(l);
272 expect(l, TagConstants.RPAREN);
273 Stmt consequence = parseStatement(l);
274 Stmt alternative;
275 if (l.ttype == TagConstants.ELSE) {
276 l.getNextToken(); // Discard 'else'
277 alternative = parseStatement(l);
278 } else
279 // set the location of the implicit Skip to be that of the If
280 alternative = SkipStmt.make(keywordloc);
281 seqStmt.addElement(IfStmt.make(test, consequence, alternative,
282 keywordloc));
283 return;
284 }
285
286 case TagConstants.DO: { // 'do' Stmt 'while' '(' Expr ')' ';'
287 l.getNextToken(); // Discard the keyword
288 Stmt body = parseStatement(l);
289 expect(l, TagConstants.WHILE);
290 expect(l, TagConstants.LPAREN);
291 Expr test = parseExpression(l);
292 expect(l, TagConstants.RPAREN);
293 expect(l, TagConstants.SEMICOLON);
294 seqStmt.addElement( DoStmt.make(test, body, keywordloc) );
295 return;
296 }
297
298 case TagConstants.WHILE: { // 'while' '(' Expr ')' Stmt
299 l.getNextToken(); // Discard the keyword
300 int locGuardOpenParen = l.startingLoc;
301 expect(l, TagConstants.LPAREN);
302 Expr test = parseExpression(l);
303 expect(l, TagConstants.RPAREN);
304 Stmt body = parseStatement(l);
305 seqStmt.addElement( WhileStmt.make(test, body, keywordloc,
306 locGuardOpenParen) );
307 return;
308 }
309
310 case TagConstants.FOR: {
311 l.getNextToken(); // Discard the keyword
312 seqStmt.addElement( parseForStmt(l, keywordloc) );
313 return;
314 }
315
316 case TagConstants.SWITCH: {
317 l.getNextToken(); // Discard the keyword
318 seqStmt.addElement( parseSwitchStmt(l, keywordloc) );
319 return;
320 }
321
322 case TagConstants.SYNCHRONIZED: { // 'synchronized' '(' Expr ')' '{' BlockStmt* '}'
323 l.getNextToken(); // Discard the keyword
324 int locOpenParen = l.startingLoc;
325 expect(l, TagConstants.LPAREN);
326 Expr value = parseExpression(l);
327 expect(l, TagConstants.RPAREN);
328 BlockStmt body = parseBlock(l, false);
329 seqStmt.addElement( SynchronizeStmt.make(value, body, keywordloc,
330 locOpenParen));
331 return;
332 }
333
334 case TagConstants.TRY: { //'try' '{' BlockStmt* '}' Catches ['finally' '{'BlockStmt*'}']
335 l.getNextToken(); // Discard the keyword
336 int openloc = l.startingLoc;
337 Stmt body = parseBlock(l, false);
338
339 CatchClauseVec catches = parseCatches(l);
340
341 if (l.ttype == TagConstants.FINALLY) {
342 int finloc = l.startingLoc;
343 l.getNextToken(); // Discard 'finally'
344 Stmt fbody = parseBlock(l, false);
345 if (catches != null) {
346 Stmt s = TryCatchStmt.make(body, catches, keywordloc);
347 seqStmt.addElement( TryFinallyStmt.make(s, fbody, keywordloc,
348 finloc) );
349 } else seqStmt.addElement( TryFinallyStmt.make(body, fbody,
350 keywordloc, finloc) );
351 return;
352 } else {
353 if (catches == null)
354 fail(l.startingLoc, "Missing handlers in try statement");
355 seqStmt.addElement( TryCatchStmt.make(body, catches, keywordloc) );
356 return;
357 }
358 }
359 }
360
361 // Stmt ::= ClassDecl | VarDeclInit (Except those starting with IDENT)
362 {
363 int modifiers = parseModifiers(l);
364 ModifierPragmaVec pmodifiers = this.modifierPragmas;
365 //alx: dw handle universes
366 int[] localUniverseArray = (int[]) this.universeArray.clone();
367 //alx-end
368
369 // This is rather a hack, because some pragmas that are allowed
370 // are not statement pragmas (because they are indistinguishable
371 // from other pragmas).
372 if (l.ttype == TagConstants.TYPEDECLELEMPRAGMA) {
373 do {
374 TypeDeclElemPragma tdp = (TypeDeclElemPragma)l.auxVal;
375 tdp.decorate(pmodifiers);
376 FieldDecl fd = l.pragmaParser.isPragmaDecl(l);
377 if (modifiers != Modifiers.NONE) {
378 ErrorSet.caution(tdp.getStartLoc(),
379 "Misplaced Java modifiers prior to this point");
380 }
381 if (fd != null) {
382 LocalVarDecl d
383 = LocalVarDecl.make(fd.modifiers, fd.pmodifiers,
384 fd.id, fd.type, fd.locId, fd.init, fd.locAssignOp);
385 seqStmt.addElement( VarDeclStmt.make(d) );
386 l.getNextToken();
387 // There might be more than one variable declared in
388 // the one declaration. We could simply let the
389 // parser handle it by returning here, but then we
390 // lose the pmodifiers information up above.
391 if (l.ttype == TagConstants.TYPEDECLELEMPRAGMA)
392 continue;
393 break;
394 } else {
395 l.getNextToken();
396 break;
397 }
398 } while(true);
399 return;
400 } else if (l.ttype == TagConstants.CLASS) {
401 ClassDecl cd = (ClassDecl)parseTypeDeclTail(l, false, keywordloc,
402 modifiers, pmodifiers);
403 seqStmt.addElement(ClassDeclStmt.make(cd));
404 return;
405 } else if (modifiers != Modifiers.NONE || pmodifiers != null ||
406 //alx: dw universe modifiers are also in this case
407 localUniverseArray[0]!=0 ||
408 //alx-end
409 isPrimitiveKeywordTag(ttype)) {
410 //alx: dw save universes to our field, addVarDeclStmts expects
411 // it there
412 universeArray=localUniverseArray;
413 //alx-end
414
415 addVarDeclStmts(l, modifiers, pmodifiers, parseType(l));
416 expect(l, TagConstants.SEMICOLON);
417 return;
418 }
419 }
420
421 // Check for StmtPragma
422 if( ttype == TagConstants.STMTPRAGMA ) {
423 StmtPragma pragma = (StmtPragma)l.auxVal;
424 seqStmt.addElement( (Stmt)pragma );
425 l.getNextToken();
426 return;
427 }
428
429 // Assume it's a statement expression...
430 Expr e = parseExpression(l);
431 if (! isStatementExpression(e))
432 fail(l.startingLoc, "Statement expression expected");
433 seqStmt.addElement( EvalStmt.make(e) );
434 expect(l, TagConstants.SEMICOLON);
435 return;
436 }
437
438 /**
439 * Method for parsing a <code>ConstructorBody</code>.
440 *
441 * <p> Effects: Parses the following grammar:
442 * <pre>
443 * Block ::=
444 * '{' [ { 'this' | 'super' ] '(' ArgumentList ')' ] { VarDeclInit | Stmt }* '}'
445 * </pre>
446 *
447 * <p> If no syntax errors are encountered, it returns a parse
448 * tree for the parsed input, leaving <code>l</code> at the token
449 * just after the trailing <code>}</code> of the statement.
450 */
451 //@ requires l != null && l.m_in != null;
452 //@ ensures \result != null;
453 public BlockStmt parseConstructorBody(Lex l) {
454 int openloc = l.startingLoc;
455 expect(l, TagConstants.LBRACE);
456 seqStmt.push();
457
458 // Handle leading constructor invocation;
459 // make one up if missing and the class being declared in not object
460
461 if (((l.ttype == TagConstants.THIS || l.ttype == TagConstants.SUPER)
462 && l.lookahead(1) == TagConstants.LPAREN)) {
463 boolean superCall = (l.ttype == TagConstants.SUPER);
464 int loc = l.startingLoc;
465 l.getNextToken();
466 // Next, parse the argument list, which should start with an open
467 // parenthesis. As a check that "parseArgumentList" doesn't accept
468 // any other first token than an open parenthesis, the tag of the next
469 // token is stored in "tagShouldBeLParen", and it is assert that
470 // *if* "parseArgumentList" returns normally, then the tag recorded
471 // is indeed an open parenthesis.
472 int locOpenParen = l.startingLoc;
473 int tagShouldBeLParen = l.ttype;
474 ExprVec args = parseArgumentList(l);
475 expect( l, TagConstants.SEMICOLON );
476 seqStmt.addElement( ConstructorInvocation.make( superCall,
477 null, Location.NULL,
478 loc, locOpenParen,
479 args ) );
480 } else {
481 // Look for Primary '.' 'super' '(' ArgumentList ')' ';'
482 boolean foundDotSuper = false;
483 for (int i = 0; ; i++) {
484 switch (l.lookahead(i)) {
485 case TagConstants.EOF:
486 break;
487 case TagConstants.LBRACE:
488 for(int braceDepth = 1; 0 < braceDepth; i++) {
489 if (l.lookahead(i) == TagConstants.RBRACE) braceDepth--;
490 }
491 continue;
492 case TagConstants.SEMICOLON:
493 case TagConstants.RBRACE:
494 break;
495 case TagConstants.FIELD:
496 if (l.lookahead(i+1) == TagConstants.SUPER) {
497 foundDotSuper = true;
498 break;
499 } else continue;
500 default: continue;
501 }
502 break;
503 }
504 if (foundDotSuper) {
505 int loc = l.startingLoc;
506 Expr e = parsePrimaryExpression(l);
507 int locDot = l.startingLoc;
508 expect(l, TagConstants.FIELD);
509 expect(l, TagConstants.SUPER);
510 int locOpenParen = l.startingLoc;
511 ExprVec args = parseArgumentList(l);
512 expect(l, TagConstants.SEMICOLON);
513 seqStmt.addElement(ConstructorInvocation.make(true, e, locDot,
514 loc, locOpenParen,
515 args));
516 }
517 }
518
519 // No explicit constructor invocation. We do not know if this
520 // class is java.lang.Object, so we cannot add a constructor
521 // invocation here; we will do it in type checking.
522
523 // Handle rest of body
524 {
525 int ttype = l.ttype;
526 while (ttype != TagConstants.RBRACE && ttype != TagConstants.EOF) {
527 addStmt(l);
528 ttype = l.ttype;
529 }
530 if (ttype == TagConstants.EOF)
531 fail(l.startingLoc, "End of input in block");
532 }
533 StmtVec body = StmtVec.popFromStackVector(seqStmt);
534 int closeloc = l.startingLoc;
535 l.getNextToken(); // Discard '}'
536 return BlockStmt.make(body, openloc, closeloc);
537 }
538
539 /**
540 * Method for parsing a <code>Block</code>.
541 *
542 * <p> Effects: Parses the following grammar:
543 * <pre>
544 * Block ::=
545 * '{' { VarDeclInit | Stmt }* '}'
546 * </pre>
547 *
548 * <p> If no syntax errors are encountered, it returns a parse
549 * tree for the parsed input, leaving <code>l</code> at the token
550 * just after the trailing <code>}</code> of the statement.
551 */
552 //@ requires l != null && l.m_in != null;
553 //@ ensures \result != null;
554 public BlockStmt parseBlock(Lex l, boolean specOnly) {
555 int openloc = l.startingLoc;
556 expect(l, TagConstants.LBRACE);
557 seqStmt.push();
558 {
559 int ttype = l.ttype;
560 while (ttype != TagConstants.RBRACE && ttype != TagConstants.EOF) {
561 if (!specOnly)
562 addStmt(l);
563 else {
564 if (ttype==TagConstants.LBRACE)
565 parseBlock(l, true);
566 else
567 l.getNextToken();
568 }
569 ttype = l.ttype;
570 }
571 if (ttype == TagConstants.EOF)
572 fail(l.startingLoc, "End of input in block");
573 }
574 StmtVec body = StmtVec.popFromStackVector(seqStmt);
575 int closeloc = l.startingLoc;
576 l.getNextToken(); // Discard '}'
577 return specOnly ? null : BlockStmt.make(body, openloc, closeloc);
578 }
579
580 /**
581 * Internal method for parsing a switch statement.
582 *
583 * <p> Effects: Parses the following grammar:
584 * <pre>
585 * ForStmtRemainder ::=
586 * '(' [VDeclInit | StmtExpr,* ] ';' Expr ';' StmtExpr,* ')' Stmt
587 * </pre>
588 *
589 * <p> Note that it assumes the leading <code>for</code> has
590 * already been parsed; <code>keywordloc</code> is the location
591 * assumed for the <code>for</code> token.
592 *
593 * <p> If no syntax errors are encountered, it returns a parse
594 * tree for the parsed input, leaving <code>l</code> at the token
595 * just after the trailing <code>}</code> of the statement.
596 */
597 //@ requires l != null && l.m_in != null;
598 //@ requires keywordloc != Location.NULL;
599 //@ ensures \result != null;
600 private ForStmt parseForStmt(Lex l, int keywordloc) {
601 int parenloc = l.startingLoc;
602 expect(l, TagConstants.LPAREN);
603
604 // Parse ForInit ::= [VDeclInit | StmtExpr,* ] ';'
605 StmtVec forInit;
606 int locFirstSemi;
607 { // Parse ForInit part
608 seqStmt.push();
609
610 Type basetype = null;
611 int modifiers = Modifiers.NONE;
612 ModifierPragmaVec pmodifiers = null;
613 switch (l.ttype) {
614 case TagConstants.SEMICOLON:
615 break;
616
617 default:
618 modifiers = parseModifiers(l);
619 pmodifiers = this.modifierPragmas;
620
621 if (modifiers != Modifiers.NONE || pmodifiers != null ||
622 isPrimitiveKeywordTag(l.ttype)) {
623 basetype = parseType(l);
624 break;
625 }
626
627 Expr e = parseExpression(l);
628 if (e.getTag() == TagConstants.AMBIGUOUSVARIABLEACCESS) {
629 // Assume a var declaration
630 // look for type modifier pragmas
631 TypeModifierPragmaVec tmodifiers = null;
632 tmodifiers = parseTypeModifierPragmas(l);
633 basetype = TypeName.make(tmodifiers, ((AmbiguousVariableAccess)e).name);
634
635 break;
636 } else {
637 for(;;) {
638 if (! isStatementExpression(e))
639 fail(l.startingLoc, "Statement expression expected");
640 seqStmt.addElement( EvalStmt.make(e) );
641 if (l.ttype != TagConstants.COMMA) break;
642 l.getNextToken(); // Discard the COMMA
643 e = parseExpression(l);
644 }
645 }
646 }
647
648 if (basetype != null) {
649 basetype = parseBracketPairs(l, basetype);
650 addVarDeclStmts(l, modifiers, pmodifiers, basetype);
651 }
652
653 locFirstSemi = l.startingLoc;
654 expect(l, TagConstants.SEMICOLON);
655 forInit = StmtVec.popFromStackVector(seqStmt);
656 }
657
658 // Parse <pre> Test ::= [ Expr ] ';' </pre>
659 Expr test;
660 if (l.ttype != TagConstants.SEMICOLON)
661 test = parseExpression(l);
662 else test = LiteralExpr.make(TagConstants.BOOLEANLIT,
663 Boolean.TRUE,
664 l.startingLoc );
665 expect(l, TagConstants.SEMICOLON);
666
667 // Parse <pre> ForUpdate ::= StmtExpr,* ')' </pre>
668 ExprVec forUpdate;
669 {
670 seqExpr.push();
671
672 if (l.ttype != TagConstants.RPAREN) {
673 for(;;) {
674 Expr e = parseExpression(l);
675 if (! isStatementExpression(e))
676 fail(l.startingLoc, "Statement expression expected.");
677 seqExpr.addElement(e);
678 if (l.ttype != TagConstants.COMMA) break;
679 l.getNextToken(); // Discard COMMA
680 }
681 }
682 expect(l, TagConstants.RPAREN);
683 forUpdate = ExprVec.popFromStackVector(seqExpr);
684 }
685
686 Stmt body = parseStatement(l);
687 return ForStmt.make(forInit, test, forUpdate, body, keywordloc,
688 locFirstSemi);
689 }
690
691 /**
692 * Internal method for parsing a switch statement.
693 *
694 * <p> Effects: Parses the following grammar:
695 * <pre>
696 * SwitchStmtRemainder ::=
697 * '(' Expr ')' '{' { 'case' Expr ':' | 'default ':' | Stmt }* '}'
698 * </pre>
699 *
700 * <p> Note that it assumes the trailing <code>switch</code> has
701 * already been parsed; <code>keywordLoc</code> is the location
702 * assumed for the <code>switch</code> token.
703 *
704 * <p> If no syntax errors are encountered, it returns a parse
705 * tree for the parsed input, leaving <code>l</code> at the token
706 * just after the trailing <code>}</code> of the statement.
707 */
708 //@ requires l != null && l.m_in != null;
709 //@ requires keywordloc != Location.NULL;
710 //@ ensures \result != null;
711 private SwitchStmt parseSwitchStmt(Lex l, int keywordloc) {
712 // Read value to be tested
713 expect(l, TagConstants.LPAREN);
714 Expr value = parseExpression(l);
715 expect(l, TagConstants.RPAREN);
716
717 // Read body
718 int openloc = l.startingLoc;
719 expect(l, TagConstants.LBRACE);
720 boolean atStart=true;
721 boolean hasDefault = false;
722 seqStmt.push();
723 while (l.ttype != TagConstants.RBRACE && l.ttype != TagConstants.EOF) {
724 if (l.ttype == TagConstants.CASE || l.ttype == TagConstants.DEFAULT) {
725 if (l.ttype == TagConstants.DEFAULT) {
726 hasDefault = true;
727 }
728 int loc = l.startingLoc;
729 int ttype = l.ttype;
730 l.getNextToken(); // Discard CASE TagConstants.or DEFAULT
731 Expr e = (ttype == TagConstants.CASE ? parseExpression(l) : null);
732 expect(l, TagConstants.COLON);
733 seqStmt.addElement( SwitchLabel.make(e, loc) );
734 }
735 else {
736 if (atStart) fail(l.startingLoc,"Switch body must start with a label");
737 addStmt(l);
738 }
739 atStart = false;
740 }
741 if (l.ttype == TagConstants.EOF)
742 fail(l.startingLoc, "End of input in switch body");
743 int closeloc = l.startingLoc;
744 l.getNextToken(); // Discard '}'
745
746 if (!hasDefault) {
747 seqStmt.addElement(SwitchLabel.make(null, closeloc));
748 seqStmt.addElement(BreakStmt.make(null, closeloc));
749 }
750 StmtVec body = StmtVec.popFromStackVector(seqStmt);
751 return SwitchStmt.make(body, openloc, closeloc, value, keywordloc);
752 }
753
754 /**
755 * Internal routine for parsing zero or more catch clauses.
756 *
757 * <p> Effects: Parses the following grammar:
758 * <pre> Catches ::= { 'catch' '(' [Modifiers] Type Idn ')' Block }* </pre>
759 *
760 * At the start of each iteration (including the first), if the
761 * first token is not <code>catch</code>, it stops trying to
762 * parse, returning the (possibly empty) sequence of catch clauses
763 * parsed already and leaving the token at the first token
764 * following the last catch clause parsed. If the first token is
765 * <code>catch</code>, then it tries to parse a catch clause,
766 * throwing an exception if a syntax error is found.
767 */
768 //@ requires l != null && l.m_in != null;
769 private CatchClauseVec parseCatches(Lex l) {
770 if (l.ttype != TagConstants.CATCH) return null;
771 seqCatchClause.push();
772
773 do {
774 int loc = l.startingLoc;
775 l.getNextToken(); // Discard CATCH
776 expect(l, TagConstants.LPAREN);
777 FormalParaDecl arg = parseFormalParaDecl(l);
778 //alx: dw in catchclauses the default is readonly
779 if (useUniverses && getUniverse(arg)==TagConstants.IMPL_PEER)
780 setUniverse(arg,TagConstants.READONLY);
781 else if (useUniverses && getUniverse(arg)!=TagConstants.READONLY) {
782 setUniverse(arg,TagConstants.READONLY);
783 if (universeLevel%5!=0)
784 ErrorSet.error(arg.getStartLoc(),
785 "only readonly allowed for catch clauses");
786 }
787 //alx-end
788
789 expect(l, TagConstants.RPAREN);
790 seqCatchClause.addElement( CatchClause.make(arg, parseBlock(l,false),
791 loc) );
792 } while (l.ttype == TagConstants.CATCH);
793 return CatchClauseVec.popFromStackVector(seqCatchClause);
794 }
795
796 /**
797 * Internal routine for parsing variable declarations
798 * <em>after</em> the leading type has been parsed.
799 *
800 * <p>Effects: Parses the following grammar:
801 * <pre>
802 * VarDeclRemainder ::=
803 * { Idn { '[' ']' }* [ '=' VariableInitializer ] },*
804 * </pre>
805 *
806 * <p> Each <code>VarDeclRemainder</code> found is combined with
807 * <code>basetype</code> to create a <code>VarDeclStmt</code>
808 * which is added to the end of <code>seqStmt</code>.
809 *
810 * <p> On entry, it assumes at least one
811 * <code>VarDeclRemainder</code> is available, and throws an
812 * exception if one isn't. At the end of each iteration, it stops
813 * trying to parse if the comma is not present, leaving the token
814 * at the first token following the last
815 * <code>VarDeclRemainder</code> parsed. If a comma is found,
816 * then it tries to parse the next <code>VarDeclRemainder</code>,
817 * throwing an exception if a syntax error is found.
818 */
819 //@ requires l != null && basetype != null && l.m_in != null;
820 //@ requires basetype.syntax;
821 private void addVarDeclStmts(Lex l, int modifiers,
822 ModifierPragmaVec modifierPragmas,
823 Type basetype)
824 {
825 // make modifierPragmas non-null, so can retroactively extend
826 if( modifierPragmas == null )
827 modifierPragmas = ModifierPragmaVec.make();
828
829 //alx: dw needed because init can have more modifiers!
830 int[] localUniverseArray=null;
831 if (useUniverses)
832 localUniverseArray = (int[]) universeArray.clone();
833 //alx-end
834
835 for(;;) {
836 // Get identifier and any [] pairs trailing it
837 Identifier id = l.identifierVal;
838 int locId = l.startingLoc;
839 expect(l, TagConstants.IDENT);
840 Type vartype = parseBracketPairs(l, basetype);
841
842 // Get initializer if there is one
843 VarInit init = null;
844 int locAssignOp = Location.NULL;
845 if (l.ttype == TagConstants.ASSIGN) {
846 locAssignOp = l.startingLoc;
847 l.getNextToken();
848 init = parseVariableInitializer(l, false);
849 }
850
851 LocalVarDecl d
852 = LocalVarDecl.make(modifiers, modifierPragmas,
853 id, vartype, locId, init, locAssignOp);
854 //alx: dw set universe modifiers
855 if (useUniverses)
856 setUniverse(d,localUniverseArray);
857 //alx-end
858 seqStmt.addElement( VarDeclStmt.make(d) );
859
860 // check if end of declaration
861
862 if(l.ttype == TagConstants.MODIFIERPRAGMA ) {
863 // if modifier pragma, retroactively add to modifierPragmas
864 parseMoreModifierPragmas( l, modifierPragmas );
865 return;
866 } else if(l.ttype != TagConstants.COMMA ) {
867 // all done - do not swallow following semicolon
868 return;
869 }
870
871 expect( l, TagConstants.COMMA );
872 /* And go around loop again */
873 }
874 }
875
876
877 /**
878 * Routine for parsing a single formal parameter declarations.
879 *
880 * <p> Effects: Parses the following grammar:
881 * <pre> FormalParaDecl ::= { [Modifiers] Type Idn ModifierPragma* } </pre>
882 * returning an ASTNode representing the result. Leaves
883 * <code>l</code> pointing to the token just after the
884 * <code>FormalParaDecl</code>.
885 */
886 //@ requires l != null && l.m_in != null;
887 //@ ensures \result != null;
888 public FormalParaDecl parseFormalParaDecl(Lex l) {
889 int modifiers = parseModifiers(l);
890 //alx: dw save the universe modifiers
891 int[] localUniverseArray=null;
892 if (useUniverses)
893 localUniverseArray = (int[]) this.universeArray.clone();
894 //alx-end
895 ModifierPragmaVec modifierPragmas = this.modifierPragmas;
896 Type paratype = parseType(l);
897 Identifier idn = l.identifierVal;
898 int locId = l.startingLoc;
899 expect(l, TagConstants.IDENT);
900
901 // allow more modifier pragmas
902 modifierPragmas = parseMoreModifierPragmas( l, modifierPragmas );
903
904 FormalParaDecl fpd = FormalParaDecl.make(modifiers, modifierPragmas,
905 idn, paratype, locId);
906 //alx: dw attatch universe modifiers to the formal parameter
907 if (useUniverses)
908 setUniverse(fpd,localUniverseArray);
909 //alx-end
910 return fpd;
911 }
912
913 /**
914 * @return true iff <code>e</code> is a Java
915 * <code>StatementExpression</code> as defined in the grammar
916 * given in the language spec.
917 */
918 //@ requires e != null;
919 public static boolean isStatementExpression(Expr e) {
920 switch (e.getTag()) {
921 case TagConstants.ASSIGN:
922 case TagConstants.ASGMUL: case TagConstants.ASGDIV:
923 case TagConstants.ASGREM:
924 case TagConstants.ASGADD: case TagConstants.ASGSUB:
925 case TagConstants.ASGLSHIFT: case TagConstants.ASGRSHIFT:
926 case TagConstants.ASGURSHIFT:
927 case TagConstants.ASGBITAND:
928 case TagConstants.ASGBITOR: case TagConstants.ASGBITXOR:
929 case TagConstants.INC: case TagConstants.DEC:
930 case TagConstants.POSTFIXINC: case TagConstants.POSTFIXDEC:
931 case TagConstants.METHODINVOCATION:
932 case TagConstants.NEWINSTANCEEXPR:
933 return true;
934 default:
935 return true; // TODO return false;
936 }
937 }
938 }