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    }