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 }