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 JavafePrimitiveType.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 }