    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                    addVarDeclStmts(l, Modifiers.NONE, null, basetype);
    187                    expect(l, TagConstants.SEMICOLON);
    188                    return;
    189                } else {
    190                    expect(l, TagConstants.SEMICOLON);
    191                    // TODO: make sure e is a statement expr
    192                    seqStmt.addElement( EvalStmt.make(e) );
    193                    return;
    194                }
    195            }
    196
    197            // Stmt ::= '{' ... '}'  (that is, a Block)
    198            if (ttype == TagConstants.LBRACE) {
    199                seqStmt.addElement( parseBlock(l, false) );
    200                return;
    201            }
    202
    203            // Stmt ::= <keyword> ...
    204            int keywordloc = l.startingLoc;
    205            switch (ttype) {
    206                case TagConstants.ASSERT: { // 'assert' BoolExpr [ ':' NonVoidExpr ] ';'
    207
    208                    int loc = l.startingLoc;
    209                    l.getNextToken(); // Discard the keyword
    210                    Expr predicate = parseExpression(l);
    211                    Expr label = null;
    212                    if (l.ttype == TagConstants.COLON) {
    213                        l.getNextToken();
    214                        label = parseExpression(l);
    215                    }
    216                    expect(l, TagConstants.SEMICOLON);
    217                    // Only process if assert *is* a keyword.
    218                    if (Tool.options != null && !Tool.options.assertIsKeyword) {
    219                        ErrorSet.error(loc, "Java keyword \"assert\" is only supported if the" +
    220                             " -source 1.4 option is provided.");
    221                    } else
    222                        seqStmt.addElement(AssertStmt.make(predicate, label, keywordloc));
    223                    return;
    224                }
    225
    226                case TagConstants.BREAK: // 'break' [ Idn ] ';'
    227                case TagConstants.CONTINUE: { // 'continue' [ Idn ] ';'
    228                    l.getNextToken(); // Discard the keyword
    229                    Identifier label = null;
    230                    if (l.ttype == TagConstants.IDENT) {
    231                        label = l.identifierVal;
    232                        l.getNextToken(); // Discard IDENT
    233                    }
    234                    expect(l, TagConstants.SEMICOLON);
    235                    seqStmt.addElement(ttype == TagConstants.BREAK ?
    236                                       (Stmt)BreakStmt.make(label, keywordloc)
    237                                       : (Stmt)ContinueStmt.make(label, keywordloc));
    238                    return;
    239                }
    240
    241                case TagConstants.RETURN: // 'return' Expr ';'
    242                    l.getNextToken(); // Discard the keyword
    243                    if (l.ttype == TagConstants.SEMICOLON) {
    244                        l.getNextToken(); // Discard ';'
    245                        seqStmt.addElement( ReturnStmt.make(null, keywordloc) );
    246                    } else {
    247                        Expr expr = parseExpression(l);
    248                        expect(l, TagConstants.SEMICOLON);
    249                        seqStmt.addElement(ReturnStmt.make(expr, keywordloc));
    250                    }
    251                    return;
    252
    253                case TagConstants.THROW: { // 'throw' Expr ';'
    254                    l.getNextToken(); // Discard the keyword
    255                    Expr expr = parseExpression(l);
    256                    expect(l, TagConstants.SEMICOLON);
    257                    seqStmt.addElement(ThrowStmt.make(expr, keywordloc));
    258                    return;
    259                }
    260
    261                case TagConstants.IF: { // 'if' '(' Expr ')' Stmt [ 'else' Stmt ]
    262                    l.getNextToken(); // Discard the keyword
    263                    expect(l, TagConstants.LPAREN);
    264                    Expr test = parseExpression(l);
    265                    expect(l, TagConstants.RPAREN);
    266                    Stmt consequence = parseStatement(l);
    267                    Stmt alternative;
    268                    if (l.ttype == TagConstants.ELSE) {
    269                        l.getNextToken(); // Discard 'else'
    270                        alternative = parseStatement(l);
    271                    } else
    272                        // set the location of the implicit Skip to be that of the If
    273                        alternative = SkipStmt.make(keywordloc);
    274                    seqStmt.addElement(IfStmt.make(test, consequence, alternative,
    275                                                   keywordloc));
    276                    return;
    277                }
    278
    279                case TagConstants.DO: { // 'do' Stmt 'while' '(' Expr ')' ';'
    280                    l.getNextToken(); // Discard the keyword
    281                    Stmt body = parseStatement(l);
    282                    expect(l, TagConstants.WHILE);
    283                    expect(l, TagConstants.LPAREN);
    284                    Expr test = parseExpression(l);
    285                    expect(l, TagConstants.RPAREN);
    286                    expect(l, TagConstants.SEMICOLON);
    287                    seqStmt.addElement( DoStmt.make(test, body, keywordloc) );
    288                    return;
    289                }
    290
    291                case TagConstants.WHILE: { // 'while' '(' Expr ')' Stmt
    292                    l.getNextToken(); // Discard the keyword
    293                    int locGuardOpenParen = l.startingLoc;
    294                    expect(l, TagConstants.LPAREN);
    295                    Expr test = parseExpression(l);
    296                    expect(l, TagConstants.RPAREN);
    297                    Stmt body = parseStatement(l);
    298                    seqStmt.addElement( WhileStmt.make(test, body, keywordloc,
    299                                                       locGuardOpenParen) );
    300                    return;
    301                }
    302
    303                case TagConstants.FOR: {
    304                    l.getNextToken(); // Discard the keyword
    305                    seqStmt.addElement( parseForStmt(l, keywordloc) );
    306                    return;
    307                }
    308
    309                case TagConstants.SWITCH: {
    310                    l.getNextToken(); // Discard the keyword
    311                    seqStmt.addElement( parseSwitchStmt(l, keywordloc) );
    312                    return;
    313                }
    314
    315                case TagConstants.SYNCHRONIZED: { // 'synchronized' '(' Expr ')' '{' BlockStmt* '}'
    316                    l.getNextToken(); // Discard the keyword
    317                    int locOpenParen = l.startingLoc;
    318                    expect(l, TagConstants.LPAREN);
    319                    Expr value = parseExpression(l);
    320                    expect(l, TagConstants.RPAREN);
    321                    BlockStmt body = parseBlock(l, false);
    322                    seqStmt.addElement( SynchronizeStmt.make(value, body, keywordloc,
    323                                                             locOpenParen));
    324                    return;
    325                }
    326
    327                case TagConstants.TRY: { //'try' '{' BlockStmt* '}' Catches ['finally' '{'BlockStmt*'}']
    328                    l.getNextToken(); // Discard the keyword
    329                    int openloc = l.startingLoc;
    330                    Stmt body = parseBlock(l, false);
    331
    332                    CatchClauseVec catches = parseCatches(l);
    333
    334                    if (l.ttype == TagConstants.FINALLY) {
    335                        int finloc = l.startingLoc;
    336                        l.getNextToken(); // Discard 'finally'
    337                        Stmt fbody = parseBlock(l, false);
    338                        if (catches != null) {
    339                            Stmt s = TryCatchStmt.make(body, catches, keywordloc);
    340                            seqStmt.addElement( TryFinallyStmt.make(s, fbody, keywordloc,
    341                                                                    finloc) );
    342                        } else seqStmt.addElement( TryFinallyStmt.make(body, fbody,
    343                                                                       keywordloc, finloc) );
    344                        return;
    345                    } else {
    346                        if (catches == null)
    347                            fail(l.startingLoc, "Missing handlers in try statement");
    348                        seqStmt.addElement( TryCatchStmt.make(body, catches, keywordloc) );
    349                        return;
    350                    }
    351                }
    352            }
    353
    354            // Stmt ::= ClassDecl | VarDeclInit   (Except those starting with IDENT)
    355            {
    356                int modifiers = parseModifiers(l);
    357                ModifierPragmaVec pmodifiers = this.modifierPragmas;
    358
    359                // This is rather a hack, because some pragmas that are allowed
    360                // are not statement pragmas (because they are indistinguishable
    361                // from other pragmas).
    362                if (l.ttype == TagConstants.TYPEDECLELEMPRAGMA) {
    363                    do {
    364                        TypeDeclElemPragma tdp = (TypeDeclElemPragma)l.auxVal;
    365                        tdp.decorate(pmodifiers);
    366                        FieldDecl fd = l.pragmaParser.isPragmaDecl(l);
    367                        if (modifiers != Modifiers.NONE) {
    368                            ErrorSet.caution(tdp.getStartLoc(),
    369                                "Misplaced Java modifiers prior to this point");
    370                        }
    371                        if (fd != null) {
    372                            LocalVarDecl d
    373                                = LocalVarDecl.make(fd.modifiers, fd.pmodifiers,
    374                                        fd.id, fd.type, fd.locId, fd.init, fd.locAssignOp);
    375                            seqStmt.addElement( VarDeclStmt.make(d) );
    376                            l.getNextToken();
    377                            // There might be more than one variable declared in
    378                            // the one declaration.  We could simply let the
    379                            // parser handle it by returning here, but then we
    380                            // lose the pmodifiers information up above.
    381                            if (l.ttype == TagConstants.TYPEDECLELEMPRAGMA)
    382                                    continue;
    383                            break;
    384                        } else {
    385                            l.getNextToken();
    386                            break;
    387                        }
    388                    } while(true);
    389                    return;
    390                } else if (l.ttype == TagConstants.CLASS) {
    391                    ClassDecl cd = (ClassDecl)parseTypeDeclTail(l, false, keywordloc,
    392                                                                modifiers, pmodifiers);
    393                    seqStmt.addElement(ClassDeclStmt.make(cd));
    394                    return;
    395                } else if (modifiers != Modifiers.NONE || pmodifiers != null ||
    396                           isPrimitiveKeywordTag(ttype)) {
    397                    addVarDeclStmts(l, modifiers, pmodifiers, parseType(l));
    398                    expect(l, TagConstants.SEMICOLON);
    399                    return;
    400                }
    401            }
    402
    403            // Check for StmtPragma
    404            if( ttype == TagConstants.STMTPRAGMA ) {
    405                StmtPragma pragma = (StmtPragma)l.auxVal;
    406                seqStmt.addElement( (Stmt)pragma );
    407                l.getNextToken();
    408                return;
    409            }
    410
    411            // Assume it's a statement expression...
    412            Expr e = parseExpression(l);
    413            if (! isStatementExpression(e))
    414                fail(l.startingLoc, "Statement expression expected");
    415            seqStmt.addElement( EvalStmt.make(e) );
    416            expect(l, TagConstants.SEMICOLON);
    417            return;
    418        }
    419
    420        /**
    421         * Method for parsing a <code>ConstructorBody</code>.
    422         *
    423         * <p> Effects: Parses the following grammar:
    424         * <pre>
    425         * Block ::=
    426         * '{' [ { 'this' | 'super' ] '(' ArgumentList ')' ] { VarDeclInit | Stmt }* '}'
    427         * </pre>
    428         *
    429         * <p> If no syntax errors are encountered, it returns a parse
    430         * tree for the parsed input, leaving <code>l</code> at the token
    431         * just after the trailing <code>}</code> of the statement.
    432         */
    433        //@ requires l != null && l.m_in != null;
    434        //@ ensures \result != null;
    435        public BlockStmt parseConstructorBody(Lex l) {
    436            int openloc = l.startingLoc;
    437            expect(l, TagConstants.LBRACE);
    438            seqStmt.push();
    439
    440            // Handle leading constructor invocation;
    441            // make one up if missing and the class being declared in not object
    442
    443            if (((l.ttype == TagConstants.THIS || l.ttype == TagConstants.SUPER)
    444                 && l.lookahead(1) == TagConstants.LPAREN)) {
    445                boolean superCall = (l.ttype == TagConstants.SUPER);
    446                int loc = l.startingLoc;
    447                l.getNextToken();
    448                // Next, parse the argument list, which should start with an open
    449                // parenthesis.  As a check that "parseArgumentList" doesn't accept
    450                // any other first token than an open parenthesis, the tag of the next
    451                // token is stored in "tagShouldBeLParen", and it is assert that
    452                // *if* "parseArgumentList" returns normally, then the tag recorded
    453                // is indeed an open parenthesis.
    454                int locOpenParen = l.startingLoc;
    455                int tagShouldBeLParen = l.ttype;
    456                ExprVec args = parseArgumentList(l);
    457                expect( l, TagConstants.SEMICOLON );
    458                seqStmt.addElement( ConstructorInvocation.make( superCall,
    459                                                                null, Location.NULL,
    460                                                                loc, locOpenParen,
    461                                                                args ) );
    462            } else {
    463                // Look for Primary '.' 'super' '(' ArgumentList ')' ';'
    464                boolean foundDotSuper = false;
    465                for (int i = 0; ; i++) {
    466                    switch (l.lookahead(i)) {
    467                        case TagConstants.EOF:
    468                            break;
    469                        case TagConstants.LBRACE:
    470                            for(int braceDepth = 1; 0 < braceDepth; i++) {
    471                                if (l.lookahead(i) == TagConstants.RBRACE) braceDepth--;
    472                            }
    473                            continue;
    474                        case TagConstants.SEMICOLON:
    475                        case TagConstants.RBRACE:
    476                            break;
    477                        case TagConstants.FIELD:
    478                            if (l.lookahead(i+1) == TagConstants.SUPER) {
    479                                foundDotSuper = true;
    480                                break;
    481                            } else continue;
    482                        default: continue;
    483                    }
    484                    break;
    485                }
    486                if (foundDotSuper) {
    487                    int loc = l.startingLoc;
    488                    Expr e = parsePrimaryExpression(l);
    489                    int locDot = l.startingLoc;
    490                    expect(l, TagConstants.FIELD);
    491                    expect(l, TagConstants.SUPER);
    492                    int locOpenParen = l.startingLoc;
    493                    ExprVec args = parseArgumentList(l);
    494                    expect(l, TagConstants.SEMICOLON);
    495                    seqStmt.addElement(ConstructorInvocation.make(true, e, locDot,
    496                                                                  loc, locOpenParen,
    497                                                                  args));
    498                }
    499            }
    500
    501            // No explicit constructor invocation.  We do not know if this
    502            // class is java.lang.Object, so we cannot add a constructor
    503            // invocation here; we will do it in type checking.
    504
    505            // Handle rest of body
    506            {
    507                int ttype = l.ttype;
    508                while (ttype != TagConstants.RBRACE && ttype != TagConstants.EOF) {
    509                    addStmt(l);
    510                    ttype = l.ttype;
    511                }
    512                if (ttype == TagConstants.EOF)
    513                    fail(l.startingLoc, "End of input in block");
    514            }
    515            StmtVec body = StmtVec.popFromStackVector(seqStmt);
    516            int closeloc = l.startingLoc;
    517            l.getNextToken(); // Discard '}'
    518            return BlockStmt.make(body, openloc, closeloc);
    519        }
    520
    521        /**
    522         * Method for parsing a <code>Block</code>.
    523         *
    524         * <p> Effects: Parses the following grammar:
    525         * <pre>
    526         * Block ::=
    527         * '{' { VarDeclInit | Stmt }* '}'
    528         * </pre>
    529         *
    530         * <p> If no syntax errors are encountered, it returns a parse
    531         * tree for the parsed input, leaving <code>l</code> at the token
    532         * just after the trailing <code>}</code> of the statement.
    533         */
    534        //@ requires l != null && l.m_in != null;
    535        //@ ensures \result != null;
    536        public BlockStmt parseBlock(Lex l, boolean specOnly) {
    537            int openloc = l.startingLoc;
    538            expect(l, TagConstants.LBRACE);
    539            seqStmt.push();
    540            {
    541                int ttype = l.ttype;
    542                while (ttype != TagConstants.RBRACE && ttype != TagConstants.EOF) {
    543                    if (!specOnly)
    544                        addStmt(l);
    545                    else {
    546                        if (ttype==TagConstants.LBRACE)
    547                            parseBlock(l, true);
    548                        else
    549                            l.getNextToken();
    550                    }
    551                    ttype = l.ttype;
    552                }
    553                if (ttype == TagConstants.EOF)
    554                    fail(l.startingLoc, "End of input in block");
    555            }
    556            StmtVec body = StmtVec.popFromStackVector(seqStmt);
    557            int closeloc = l.startingLoc;
    558            l.getNextToken(); // Discard '}'
    559            return specOnly ? null : BlockStmt.make(body, openloc, closeloc);
    560        }
    561
    562        /**
    563         * Internal method for parsing a switch statement.
    564         *
    565         * <p> Effects: Parses the following grammar:
    566         * <pre>
    567         * ForStmtRemainder ::=
    568         * '(' [VDeclInit | StmtExpr,* ] ';' Expr ';' StmtExpr,* ')' Stmt
    569         * </pre>
    570         *
    571         * <p> Note that it assumes the leading <code>for</code> has
    572         * already been parsed; <code>keywordloc</code> is the location
    573         * assumed for the <code>for</code> token.
    574         *
    575         * <p> If no syntax errors are encountered, it returns a parse
    576         * tree for the parsed input, leaving <code>l</code> at the token
    577         * just after the trailing <code>}</code> of the statement.
    578         */
    579        //@ requires l != null && l.m_in != null;
    580        //@ requires keywordloc != Location.NULL;
    581        //@ ensures \result != null;
    582        private ForStmt parseForStmt(Lex l, int keywordloc) {
    583            int parenloc = l.startingLoc;
    584            expect(l, TagConstants.LPAREN);
    585
    586            // Parse ForInit ::= [VDeclInit | StmtExpr,* ] ';'
    587            StmtVec forInit;
    588            int locFirstSemi;
    589            { // Parse ForInit part
    590                seqStmt.push();
    591
    592                Type basetype = null;
    593                int modifiers = Modifiers.NONE;
    594                ModifierPragmaVec pmodifiers = null;
    595                switch (l.ttype) {
    596                    case TagConstants.SEMICOLON:
    597                        break;
    598
    599                    default:
    600                        modifiers = parseModifiers(l);
    601                        pmodifiers = this.modifierPragmas;
    602
    603                        if (modifiers != Modifiers.NONE || pmodifiers != null ||
    604                            isPrimitiveKeywordTag(l.ttype)) {
    605                            basetype = parseType(l);
    606                            break;
    607                        }
    608
    609                        Expr e = parseExpression(l);
    610                        if (e.getTag() == TagConstants.AMBIGUOUSVARIABLEACCESS) {
    611                            // Assume a var declaration
    612                            // look for type modifier pragmas
    613                            TypeModifierPragmaVec tmodifiers = null;
    614                            tmodifiers = parseTypeModifierPragmas(l);
    615                            basetype = TypeName.make(tmodifiers, ((AmbiguousVariableAccess)e).name);
    616
    617                            break;
    618                        } else {
    619                            for(;;) {
    620                                if (! isStatementExpression(e))
    621                                    fail(l.startingLoc, "Statement expression expected");
    622                                seqStmt.addElement( EvalStmt.make(e) );
    623                                if (l.ttype != TagConstants.COMMA) break;
    624                                l.getNextToken(); // Discard the COMMA
    625                                e = parseExpression(l);
    626                            }
    627                        }
    628                }
    629
    630                if (basetype != null) {
    631                    basetype = parseBracketPairs(l, basetype);
    632                    addVarDeclStmts(l, modifiers, pmodifiers, basetype);
    633                }
    634
    635                locFirstSemi = l.startingLoc;
    636                expect(l, TagConstants.SEMICOLON);
    637                forInit = StmtVec.popFromStackVector(seqStmt);
    638            }
    639
    640            // Parse <pre> Test ::= [ Expr ] ';' </pre>
    641            Expr test;
    642            if (l.ttype != TagConstants.SEMICOLON)
    643                test = parseExpression(l);
    644            else test = LiteralExpr.make(TagConstants.BOOLEANLIT,
    645                                         Boolean.TRUE,
    646                                         l.startingLoc );
    647            expect(l, TagConstants.SEMICOLON);
    648
    649            // Parse <pre> ForUpdate ::= StmtExpr,* ')' </pre>
    650            ExprVec forUpdate;
    651            {
    652                seqExpr.push();
    653
    654                if (l.ttype != TagConstants.RPAREN) {
    655                    for(;;) {
    656                        Expr e = parseExpression(l);
    657                        if (! isStatementExpression(e))
    658                            fail(l.startingLoc, "Statement expression expected.");
    659                        seqExpr.addElement(e);
    660                        if (l.ttype != TagConstants.COMMA) break;
    661                        l.getNextToken(); // Discard COMMA
    662                    }
    663                }
    664                expect(l, TagConstants.RPAREN);
    665                forUpdate = ExprVec.popFromStackVector(seqExpr);
    666            }
    667
    668            Stmt body = parseStatement(l);
    669            return ForStmt.make(forInit, test, forUpdate, body, keywordloc,
    670                                locFirstSemi);
    671        }
    672
    673        /**
    674         * Internal method for parsing a switch statement.
    675         *
    676         * <p> Effects: Parses the following grammar:
    677         * <pre>
    678         * SwitchStmtRemainder ::=
    679         * '(' Expr ')' '{' { 'case' Expr ':' | 'default ':' | Stmt }* '}'
    680         * </pre>
    681         *
    682         * <p> Note that it assumes the trailing <code>switch</code> has
    683         * already been parsed; <code>keywordLoc</code> is the location
    684         * assumed for the <code>switch</code> token.
    685         *
    686         * <p> If no syntax errors are encountered, it returns a parse
    687         * tree for the parsed input, leaving <code>l</code> at the token
    688         * just after the trailing <code>}</code> of the statement.
    689         */
    690        //@ requires l != null && l.m_in != null;
    691        //@ requires keywordloc != Location.NULL;
    692        //@ ensures \result != null;
    693        private SwitchStmt parseSwitchStmt(Lex l, int keywordloc) {
    694            // Read value to be tested
    695            expect(l, TagConstants.LPAREN);
    696            Expr value = parseExpression(l);
    697            expect(l, TagConstants.RPAREN);
    698
    699            // Read body
    700            int openloc = l.startingLoc;
    701            expect(l, TagConstants.LBRACE);
    702            boolean atStart=true;
    703            boolean hasDefault = false;
    704            seqStmt.push();
    705            while (l.ttype != TagConstants.RBRACE && l.ttype != TagConstants.EOF) {
    706                if (l.ttype == TagConstants.CASE || l.ttype == TagConstants.DEFAULT) {
    707                    if (l.ttype == TagConstants.DEFAULT) {
    708                        hasDefault = true;
    709                    }
    710                    int loc = l.startingLoc;
    711                    int ttype = l.ttype;
    712                    l.getNextToken(); // Discard CASE TagConstants.or DEFAULT
    713                    Expr e = (ttype == TagConstants.CASE ? parseExpression(l) : null);
    714                    expect(l, TagConstants.COLON);
    715                    seqStmt.addElement( SwitchLabel.make(e, loc) );
    716                }
    717                else {
    718                    if (atStart) fail(l.startingLoc,"Switch body must start with a label");
    719                    addStmt(l);
    720                }
    721                atStart = false;
    722            }
    723            if (l.ttype == TagConstants.EOF)
    724                fail(l.startingLoc, "End of input in switch body");
    725            int closeloc = l.startingLoc;
    726            l.getNextToken(); // Discard '}'
    727
    728            if (!hasDefault) {
    729                seqStmt.addElement(SwitchLabel.make(null, closeloc));
    730                seqStmt.addElement(BreakStmt.make(null, closeloc));
    731            }
    732            StmtVec body = StmtVec.popFromStackVector(seqStmt);
    733            return SwitchStmt.make(body, openloc, closeloc, value, keywordloc);
    734        }
    735
    736        /**
    737         * Internal routine for parsing zero or more catch clauses.
    738         *
    739         * <p> Effects: Parses the following grammar:
    740         * <pre> Catches ::= { 'catch' '(' [Modifiers] Type Idn ')' Block }* </pre>
    741         *
    742         * At the start of each iteration (including the first), if the
    743         * first token is not <code>catch</code>, it stops trying to
    744         * parse, returning the (possibly empty) sequence of catch clauses
    745         * parsed already and leaving the token at the first token
    746         * following the last catch clause parsed.  If the first token is
    747         * <code>catch</code>, then it tries to parse a catch clause,
    748         * throwing an exception if a syntax error is found.
    749         */
    750        //@ requires l != null && l.m_in != null;
    751        private CatchClauseVec parseCatches(Lex l) {
    752            if (l.ttype != TagConstants.CATCH) return null;
    753            seqCatchClause.push();
    754
    755            do {
    756                int loc = l.startingLoc;
    757                l.getNextToken(); // Discard CATCH
    758                expect(l, TagConstants.LPAREN);
    759                FormalParaDecl arg = parseFormalParaDecl(l);
    760                expect(l, TagConstants.RPAREN);
    761                seqCatchClause.addElement( CatchClause.make(arg, parseBlock(l,false),
    762                                                            loc) );
    763            } while (l.ttype == TagConstants.CATCH);
    764            return CatchClauseVec.popFromStackVector(seqCatchClause);
    765        }
    766
    767        /**
    768         * Internal routine for parsing variable declarations
    769         * <em>after</em> the leading type has been parsed.
    770         *
    771         * <p>Effects: Parses the following grammar:
    772         * <pre>
    773         * VarDeclRemainder ::=
    774         * { Idn { '[' ']' }* [ '=' VariableInitializer ] },*
    775         * </pre>
    776         *
    777         * <p> Each <code>VarDeclRemainder</code> found is combined with
    778         * <code>basetype</code> to create a <code>VarDeclStmt</code>
    779         * which is added to the end of <code>seqStmt</code>.
    780         *
    781         * <p> On entry, it assumes at least one
    782         * <code>VarDeclRemainder</code> is available, and throws an
    783         * exception if one isn't.  At the end of each iteration, it stops
    784         * trying to parse if the comma is not present, leaving the token
    785         * at the first token following the last
    786         * <code>VarDeclRemainder</code> parsed.  If a comma is found,
    787         * then it tries to parse the next <code>VarDeclRemainder</code>,
    788         * throwing an exception if a syntax error is found.
    789         */
    790        //@ requires l != null && basetype != null && l.m_in != null;
    791        //@ requires basetype.syntax;
    792        private void addVarDeclStmts(Lex l, int modifiers,
    793                                     ModifierPragmaVec modifierPragmas,
    794                                     Type basetype)
    795        {
    796            // make modifierPragmas non-null, so can retroactively extend
    797            if( modifierPragmas == null )
    798                modifierPragmas = ModifierPragmaVec.make();
    799
    800            for(;;) {
    801                // Get identifier and any [] pairs trailing it
    802                Identifier id = l.identifierVal;
    803                int locId = l.startingLoc;
    804                expect(l, TagConstants.IDENT);
    805                Type vartype = parseBracketPairs(l, basetype);
    806
    807                // Get initializer if there is one
    808                VarInit init = null;
    809                int locAssignOp = Location.NULL;
    810                if (l.ttype == TagConstants.ASSIGN) {
    811                    locAssignOp = l.startingLoc;
    812                    l.getNextToken();
    813                    init = parseVariableInitializer(l, false);
    814                }
    815
    816                LocalVarDecl d
    817                    = LocalVarDecl.make(modifiers, modifierPragmas,
    818                                        id, vartype, locId, init, locAssignOp);
    819                seqStmt.addElement( VarDeclStmt.make(d) );
    820
    821                // check if end of declaration
    822
    823                if(l.ttype == TagConstants.MODIFIERPRAGMA ) {
    824                    // if modifier pragma, retroactively add to modifierPragmas
    825                    parseMoreModifierPragmas( l, modifierPragmas );
    826                    return;
    827                } else if(l.ttype != TagConstants.COMMA ) {
    828                    // all done - do not swallow following semicolon
    829                    return;
    830                }
    831
    832                expect( l, TagConstants.COMMA );
    833                /* And go around loop again */
    834            }
    835        }
    836
    837
    838        /**
    839         * Routine for parsing a single formal parameter declarations.
    840         *
    841         * <p> Effects: Parses the following grammar:
    842         * <pre> FormalParaDecl ::= { [Modifiers] Type Idn ModifierPragma* } </pre>
    843         * returning an ASTNode representing the result.  Leaves
    844         * <code>l</code> pointing to the token just after the
    845         * <code>FormalParaDecl</code>.
    846         */
    847        //@ requires l != null && l.m_in != null;
    848        //@ ensures \result != null;
    849        public FormalParaDecl parseFormalParaDecl(Lex l) {
    850            int modifiers = parseModifiers(l);
    851            ModifierPragmaVec modifierPragmas = this.modifierPragmas;
    852            Type paratype = parseType(l);
    853            Identifier idn = l.identifierVal;
    854            int locId = l.startingLoc;
    855            expect(l, TagConstants.IDENT);
    856
    857            // allow more modifier pragmas
    858            modifierPragmas = parseMoreModifierPragmas( l, modifierPragmas );
    859
    860            return FormalParaDecl.make(modifiers, modifierPragmas,
    861                                       idn, paratype, locId);
    862        }
    863
    864        /**
    865         * @return true iff <code>e</code> is a Java
    866         * <code>StatementExpression</code> as defined in the grammar
    867         * given in the language spec.
    868         */
    869        //@ requires e != null;
    870        public static boolean isStatementExpression(Expr e) {
    871            switch (e.getTag()) {
    872                case TagConstants.ASSIGN:
    873                case TagConstants.ASGMUL: case TagConstants.ASGDIV:
    874                case TagConstants.ASGREM:
    875                case TagConstants.ASGADD: case TagConstants.ASGSUB:
    876                case TagConstants.ASGLSHIFT: case TagConstants.ASGRSHIFT:
    877                case TagConstants.ASGURSHIFT:
    878                case TagConstants.ASGBITAND:
    879                case TagConstants.ASGBITOR: case TagConstants.ASGBITXOR:
    880                case TagConstants.INC: case TagConstants.DEC:
    881                case TagConstants.POSTFIXINC: case TagConstants.POSTFIXDEC:
    882                case TagConstants.METHODINVOCATION:
    883                case TagConstants.NEWINSTANCEEXPR:
    884                    return true;
    885                default:
    886                    return true; // TODO return false;
    887            }
    888        }
    889    }