    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.Tool;
    008
    009    /**
    010     * Parses Java types.
    011     * Extended by {@link javafe.parser.ParseExpr}.
    012     *
    013     * @see javafe.ast.ASTNode
    014     * @see javafe.parser.ParseUtil
    015     * @see javafe.parser.ParseExpr
    016     */
    017
    018    public class ParseType extends ParseUtil
    019    {
    020        public ParseType() {
    021            //@ set seqIdentifier.elementType = \type(Identifier);
    022            //@ set seqIdentifier.owner = this;
    023
    024            //@ set nameIdLocs.owner = this;
    025            //@ set nameDotLocs.owner = this;
    026        }
    027
    028        //* Internal working storage for parseName function.
    029        //@ invariant seqIdentifier.elementType == \type(Identifier);
    030        //@ invariant seqIdentifier.owner == this;
    031        protected final /*@ non_null @*/ StackVector seqIdentifier
    032                = new StackVector();
    033
    034        /**
    035         * Parse an {@link Identifier}.
    036         */
    037        //@ requires l.m_in != null;
    038        //@ ensures \result != null;
    039        public Identifier parseIdentifier(/*@ non_null @*/ Lex l) {
    040            if (l.ttype != TagConstants.IDENT) {
    041                if (l.ttype == TagConstants.UNKNOWN_KEYWORD)
    042                    fail(l.startingLoc,
    043                         "Expected an identifier; Unrecognized keyword");
    044                else
    045                    if (TagConstants.toString(l.ttype).equals("assert")) {
    046                        // If the next identifier is "assert", we need to
    047                        // handle it in a special fashion.  Tool.options
    048                        // can be null if we are not running in a "real"
    049                        // tool, as is the case during testing with
    050                        // javafe.parser.test.TestParse.
    051                        if ((Tool.options == null) || (Tool.options.assertIsKeyword)) {
    052                            // if "assert" is a keyword, then it cannot be
    053                            // used as an identifier.
    054                            fail(l.startingLoc,
    055                                 "Expected an identifier, but found the \"assert\" keyword used as an identifier.");
    056                        } else {
    057                            // if "assert" is NOT a keyword, then it is ok
    058                            // to use it as an identifier.
    059                            Identifier r = l.identifierVal;
    060                            l.getNextToken();
    061                            return r;
    062                        }
    063                    }
    064                // Otherwise, we have seen something that is not an
    065                // identifier and is not the twofaced "assert", so fail.
    066                fail(l.startingLoc, "Expected an identifier, found " +
    067                     TagConstants.toString(l.ttype) );
    068            }
    069            Identifier r = l.identifierVal;
    070            l.getNextToken();
    071            return r;
    072        }
    073
    074        /**
    075         * The following private ivars are used in parseName.  They cannot
    076         * be defined inside parseName because they would be reallocated
    077         * at each invocation.  They cannot be defined as static variables
    078         * inside parseName because then the code would not be
    079         * thread-safe.
    080         */
    081        //@ private invariant nameIdLocs.length >= 10;
    082        //@ private invariant nameIdLocs.owner == this;
    083        private /*@ non_null @*/ int nameIdLocs[]  = new int[10];
    084        //@ private invariant nameDotLocs.length == nameIdLocs.length;
    085        //@ private invariant nameDotLocs.owner == this;
    086        private /*@ non_null @*/ int nameDotLocs[] = new int[nameIdLocs.length];
    087
    088        /**
    089         * Parse a {@link Name}.
    090         * <pre>
    091         * Name:
    092         * Identifier ( . Identifier ) *
    093         * </pre>
    094         */
    095        //@ requires l != null && l.m_in != null;
    096        //@ ensures \result != null;
    097        public Name parseName(Lex l) {
    098            Identifier id = null;
    099            final Identifier assertIdentifier = Identifier.intern("assert");
    100            final boolean parsingPreAssertJava =
    101                Tool.options != null && !Tool.options.assertIsKeyword;
    102
    103            // If we are parsing pre-1.4 Java code and we see an assert
    104            // keyword, then we must convert it into a Name.
    105            if (parsingPreAssertJava && l.ttype == TagConstants.ASSERT) {
    106                id = assertIdentifier;
    107            } else {
    108                // Otherwise, if we saw something that is not an identifier,
    109                // then it is an error.
    110                if (l.ttype != TagConstants.IDENT) {
    111                    if (l.ttype == TagConstants.UNKNOWN_KEYWORD)
    112                        fail(l.startingLoc,
    113                             "Expected a Name, got '"+PrettyPrint.inst.toString(l.ttype)+"'" +
    114                             "; Unrecognized keyword");
    115                    else
    116                        fail(l.startingLoc,
    117                             "Expected a Name, got '"+PrettyPrint.inst.toString(l.ttype)+"'");
    118                }
    119                id = l.identifierVal;
    120            }
    121            int loc = l.startingLoc;
    122            l.getNextToken();
    123            if (l.ttype != TagConstants.FIELD || l.lookahead(1) != TagConstants.IDENT ||
    124                (l.lookahead (1) == TagConstants.ASSERT && !parsingPreAssertJava))
    125                return SimpleName.make(id, loc);
    126
    127            // Deal with less common, multiple-name case...
    128            seqIdentifier.push();
    129            seqIdentifier.addElement(id);
    130            int stkPtr = 0;
    131            nameIdLocs[stkPtr] = loc;
    132            /*@ loop_invariant stkPtr < nameIdLocs.length &&
    133              @                stkPtr == (seqIdentifier.elementCount -
    134              @                seqIdentifier.currentStackBottom) - 1;
    135              @*/
    136            while (l.ttype == TagConstants.FIELD &&
    137                   (l.lookahead(1) == TagConstants.IDENT ||
    138                    (parsingPreAssertJava && l.lookahead(1) == TagConstants.ASSERT))) {
    139                // need to use lookahead for "import Name . *" case
    140                nameDotLocs[stkPtr++] = l.startingLoc;
    141                l.getNextToken();  // swallow the FIELD
    142
    143                if (l.ttype != TagConstants.IDENT ||
    144                    (!parsingPreAssertJava && l.ttype == TagConstants.ASSERT)) {
    145                    if (l.ttype == TagConstants.UNKNOWN_KEYWORD)
    146                        fail(l.startingLoc, ("Expected an identifier, got '"
    147                                             +PrettyPrint.inst.toString(l.ttype)+"'" +
    148                                             "; Unrecognized keyword"));
    149                    else
    150                        fail(l.startingLoc, ("Expected an identifier, got '"
    151                                             +PrettyPrint.inst.toString(l.ttype)+"'"));
    152                }
    153                if (l.ttype == TagConstants.ASSERT)
    154                    seqIdentifier.addElement (assertIdentifier);
    155                else
    156                    seqIdentifier.addElement (l.identifierVal);
    157
    158                // Check for resizing
    159                if (stkPtr == nameIdLocs.length) {
    160                    // Extend it
    161                    int nuid[] = new int[2*nameIdLocs.length];
    162                    //@ set nuid.owner = this;
    163                    System.arraycopy(nameIdLocs, 0, nuid, 0, nameIdLocs.length);
    164                    int nudot[] = new int[2*nameIdLocs.length];
    165                    //@ set nudot.owner = this;
    166                    System.arraycopy(nameDotLocs, 0, nudot, 0, nameIdLocs.length-1);
    167                    nameDotLocs = nudot;
    168                    nameIdLocs = nuid;
    169                }
    170                nameIdLocs[stkPtr] = l.startingLoc;
    171                l.getNextToken();
    172            }
    173            //@ assume stkPtr > 0;   // loop always runs at least once
    174
    175            // Id locations in nameIdLocs[0 .. stkPtr inclusive]
    176            // Dot locations in nameIdLocs[0 .. stkPtr-1 inclusive]
    177
    178            // Copy arrays
    179            int ids[] = new int[stkPtr+1];
    180            System.arraycopy(nameIdLocs, 0, ids, 0, stkPtr+1);
    181            int dots[] = new int[stkPtr];
    182            System.arraycopy(nameDotLocs, 0, dots, 0, stkPtr);
    183            return CompoundName.make(IdentifierVec.popFromStackVector(seqIdentifier),
    184                                     ids, dots);
    185        }
    186
    187        /**
    188         * Parse a {@link TypeName}.
    189         * <pre>
    190         * TypeName:
    191         * Name [TypeModifierPragmas]
    192         * </pre>
    193         */
    194        //@ requires l != null && l.m_in != null;
    195        //@ ensures \result != null;
    196        //@ ensures \result.syntax;
    197        public TypeName parseTypeName(Lex l) {
    198            Name name = parseName(l);
    199            TypeModifierPragmaVec modifiers = parseTypeModifierPragmas(l);
    200            return TypeName.make( modifiers, name );
    201        }
    202
    203        /**
    204         * Parse square bracket pairs.  Wraps argument <code>type</code> in
    205         * {@link ArrayType} objects accordingly.
    206         *
    207         * <pre>
    208         * BracketPairs:
    209         * (LSQBRACKET RSQBRACKET)*
    210         * </pre>
    211         *
    212         * <p> Warning: when this method sees "{'[' ']'}* {'[' not-']'}",
    213         * it returns with "l" pointing to the '[' just before the
    214         * not-']'.
    215         */
    216        //@ requires l != null && type != null && l.m_in != null;
    217        //@ requires type.syntax;
    218        //@ ensures \result != null;
    219        //@ ensures \result.syntax;
    220        public Type parseBracketPairs(Lex l, Type type) {
    221            // most of this code is to preserve the warning in comment
    222            // above.  also, it is now recursive to put the annotations on
    223            // the current dimensions.
    224            if (l.ttype == TagConstants.LSQBRACKET) {
    225                int loc=l.startingLoc;
    226                int i = 1;
    227                boolean done = false;
    228                while (!done) {
    229                    switch (l.lookahead(i)) {
    230                        case TagConstants.TYPEMODIFIERPRAGMA:
    231                            i++;
    232                            break;
    233                        case TagConstants.RSQBRACKET:
    234                            done=true;
    235                            break;
    236                        default:
    237                            return type;
    238                    }
    239                }
    240                l.getNextToken();
    241                TypeModifierPragmaVec modifiers     = parseTypeModifierPragmas(l);
    242                expect( l, TagConstants.RSQBRACKET );
    243                type = ArrayType.make( modifiers,
    244                                       parseBracketPairs(l,type), loc);
    245            }
    246    //      old impl:
    247    //      while(l.ttype == TagConstants.LSQBRACKET
    248    //            && l.lookahead(1) == TagConstants.RSQBRACKET ) {
    249    //        type = ArrayType.make( type, l.startingLoc );
    250    //        l.getNextToken();
    251    //        expect( l, TagConstants.RSQBRACKET );
    252    //      }
    253
    254            return type;
    255        }
    256
    257        //@ requires l != null && l.m_in != null;
    258        public TypeModifierPragmaVec parseTypeModifierPragmas(/*@ non_null @*/ Lex l) {
    259            if (l.ttype != TagConstants.TYPEMODIFIERPRAGMA) return null;
    260            TypeModifierPragmaVec seq = TypeModifierPragmaVec.make();
    261            do {
    262                seq.addElement((TypeModifierPragma)l.auxVal);
    263                l.getNextToken();
    264            } while (l.ttype == TagConstants.TYPEMODIFIERPRAGMA);
    265            return seq;
    266        }
    267
    268        /**
    269         * @return is a tag a {@link PrimitiveType} keyword?
    270         */
    271        public boolean isPrimitiveKeywordTag(int tag) {
    272            switch (tag) {
    273                case TagConstants.BOOLEAN:
    274                case TagConstants.BYTE:
    275                case TagConstants.SHORT:
    276                case TagConstants.INT:
    277                case TagConstants.LONG:
    278                case TagConstants.CHAR:
    279                case TagConstants.FLOAT:
    280                case TagConstants.DOUBLE:
    281                case TagConstants.VOID:
    282                    return true;
    283
    284                default:
    285                    return false;
    286            }
    287        }
    288
    289        /**
    290         * Parses a {@link PrimitiveType}.  Returns <code>null</code> on
    291         * failure.
    292         *
    293         * <pre>
    294         * PrimitiveType: one of
    295         * boolean byte short int long char float double void
    296         * </PRE>
    297         */
    298        //@ requires l != null && l.m_in != null;
    299        //@ ensures \result != null ==> \result.syntax;
    300        public PrimitiveType parsePrimitiveType(Lex l) {
    301
    302            int tag;
    303
    304            switch( l.ttype ) {
    305                case TagConstants.BOOLEAN: tag = TagConstants.BOOLEANTYPE; break;
    306                case TagConstants.BYTE:    tag = TagConstants.BYTETYPE;    break;
    307                case TagConstants.SHORT:   tag = TagConstants.SHORTTYPE;   break;
    308                case TagConstants.INT:     tag = TagConstants.INTTYPE;     break;
    309                case TagConstants.LONG:    tag = TagConstants.LONGTYPE;    break;
    310                case TagConstants.CHAR:    tag = TagConstants.CHARTYPE;    break;
    311                case TagConstants.FLOAT:   tag = TagConstants.FLOATTYPE;   break;
    312                case TagConstants.DOUBLE:  tag = TagConstants.DOUBLETYPE;  break;
    313                case TagConstants.VOID:    tag = TagConstants.VOIDTYPE;    break;
    314                default: return null;       // Fail!
    315            }
    316            // get here => tag is defined
    317
    318            int loc = l.startingLoc;
    319            l.getNextToken();
    320            return PrimitiveType.make( tag, loc );
    321        }
    322
    323        /**
    324         * Parse a type, either a primitive type, a type name, but not an
    325         * array type.
    326         *
    327         * <pre>
    328         * PrimitiveTypeOrTypeName:
    329         * PrimitiveType
    330         * TypeName
    331         * </pre>
    332         */
    333        //@ requires l != null && l.m_in != null;
    334        //@ ensures \result != null;
    335        //@ ensures \result.syntax;
    336        public Type parsePrimitiveTypeOrTypeName(Lex l) {
    337            Type type = parsePrimitiveType(l);
    338            if( type != null )
    339                return type;
    340            else
    341                return parseTypeName(l);
    342        }
    343
    344        /**
    345         * Parse a {@link Type}, either a primitive type, a type name, or
    346         * an array type.
    347         *
    348         * <pre>
    349         * Type:
    350         * PrimitiveTypeOrTypeName BracketPairs
    351         * </pre>
    352         */
    353        //@ requires l != null && l.m_in != null;
    354        //@ ensures \result != null;
    355        //@ ensures \result.syntax;
    356        public Type parseType(Lex l) {
    357            Type type = parsePrimitiveTypeOrTypeName(l);
    358
    359            // Allow for brackets on end
    360            return parseBracketPairs(l, type);
    361        }
    362    }