1 /* 2 * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.reflect.generics.parser; 27 28 29 import java.lang.reflect.GenericSignatureFormatError; 30 import java.util.*; 31 import sun.reflect.generics.tree.*; 32 33 34 /** 35 * Parser for type signatures, as defined in the Java Virtual 36 // Machine Specification (JVMS) chapter 4. 37 * Converts the signatures into an abstract syntax tree (AST) representation. 38 // See the package sun.reflect.generics.tree for details of the AST. 39 */ 40 public class SignatureParser { 41 // The input is conceptually a character stream (though currently it's 42 // a string). This is slightly different than traditional parsers, 43 // because there is no lexical scanner performing tokenization. 44 // Having a separate tokenizer does not fit with the nature of the 45 // input format. 46 // Other than the absence of a tokenizer, this parser is a classic 47 // recursive descent parser. Its structure corresponds as closely 48 // as possible to the grammar in the JVMS. 49 // 50 // A note on asserts vs. errors: The code contains assertions 51 // in situations that should never occur. An assertion failure 52 // indicates a failure of the parser logic. A common pattern 53 // is an assertion that the current input is a particular 54 // character. This is often paired with a separate check 55 // that this is the case, which seems redundant. For example: 56 // 57 // assert(current() != x); 58 // if (current != x {error("expected an x"); 59 // 60 // where x is some character constant. 61 // The assertion inidcates, that, as currently written, 62 // the code should nver reach this point unless the input is an 63 // x. On the other hand, the test is there to check the legality 64 // of the input wrt to a given production. It may be that at a later 65 // time the code might be called directly, and if the input is 66 // invalid, the parser should flag an error in accordance 67 // with its logic. 68 69 private char[] input; // the input signature 70 private int index = 0; // index into the input 71 // used to mark end of input 72 private static final char EOI = ':'; 73 private static final boolean DEBUG = false; 74 75 // private constructor - enforces use of static factory 76 private SignatureParser(){} 77 78 // Utility methods. 79 80 // Most parsing routines use the following routines to access the 81 // input stream, and advance it as necessary. 82 // This makes it easy to adapt the parser to operate on streams 83 // of various kinds as well as strings. 84 85 // returns current element of the input and advances the input 86 private char getNext(){ 87 assert(index <= input.length); 88 try { 89 return input[index++]; 90 } catch (ArrayIndexOutOfBoundsException e) { return EOI;} 91 } 92 93 // returns current element of the input 94 private char current(){ 95 assert(index <= input.length); 96 try { 97 return input[index]; 98 } catch (ArrayIndexOutOfBoundsException e) { return EOI;} 99 } 100 101 // advance the input 102 private void advance(){ 103 assert(index <= input.length); 104 index++; 105 } 106 107 // Match c against a "set" of characters 108 private boolean matches(char c, char... set) { 109 for (char e : set) { 110 if (c == e) return true; 111 } 112 return false; 113 } 114 115 // Error handling routine. Encapsulates error handling. 116 // Takes a string error message as argument. 117 // Currently throws a GenericSignatureFormatError. 118 119 private Error error(String errorMsg) { 120 if (DEBUG) System.out.println("Parse error:" + errorMsg); 121 return new GenericSignatureFormatError(); 122 } 123 124 /** 125 * Static factory method. Produces a parser instance. 126 * @return an instance of <tt>SignatureParser</tt> 127 */ 128 public static SignatureParser make() { 129 return new SignatureParser(); 130 } 131 132 /** 133 * Parses a class signature (as defined in the JVMS, chapter 4) 134 * and produces an abstract syntax tree representing it. 135 * @param s a string representing the input class signature 136 * @return An abstract syntax tree for a class signature 137 * corresponding to the input string 138 * @throws GenericSignatureFormatError if the input is not a valid 139 * class signature 140 */ 141 public ClassSignature parseClassSig(String s) { 142 if (DEBUG) System.out.println("Parsing class sig:" + s); 143 input = s.toCharArray(); 144 return parseClassSignature(); 145 } 146 147 /** 148 * Parses a method signature (as defined in the JVMS, chapter 4) 149 * and produces an abstract syntax tree representing it. 150 * @param s a string representing the input method signature 151 * @return An abstract syntax tree for a method signature 152 * corresponding to the input string 153 * @throws GenericSignatureFormatError if the input is not a valid 154 * method signature 155 */ 156 public MethodTypeSignature parseMethodSig(String s) { 157 if (DEBUG) System.out.println("Parsing method sig:" + s); 158 input = s.toCharArray(); 159 return parseMethodTypeSignature(); 160 } 161 162 163 /** 164 * Parses a type signature 165 * and produces an abstract syntax tree representing it. 166 * @param s a string representing the input type signature 167 * @return An abstract syntax tree for a type signature 168 * corresponding to the input string 169 * @throws GenericSignatureFormatError if the input is not a valid 170 * type signature 171 */ 172 public TypeSignature parseTypeSig(String s) { 173 if (DEBUG) System.out.println("Parsing type sig:" + s); 174 input = s.toCharArray(); 175 return parseTypeSignature(); 176 } 177 178 // Parsing routines. 179 // As a rule, the parsing routines access the input using the 180 // utilities current(), getNext() and/or advance(). 181 // The convention is that when a parsing routine is invoked 182 // it expects the current input to be the first character it should parse 183 // and when it completes parsing, it leaves the input at the first 184 // character after the input parses. 185 186 // parse a class signature based on the implicit input. 187 private ClassSignature parseClassSignature() { 188 assert(index == 0); 189 return ClassSignature.make(parseZeroOrMoreFormalTypeParameters(), 190 parseClassTypeSignature(), 191 parseSuperInterfaces()); 192 } 193 194 private FormalTypeParameter[] parseZeroOrMoreFormalTypeParameters(){ 195 if (current() == '<') { return parseFormalTypeParameters();} 196 else {return new FormalTypeParameter[0];} 197 } 198 199 200 private FormalTypeParameter[] parseFormalTypeParameters(){ 201 Collection<FormalTypeParameter> ftps = 202 new ArrayList<FormalTypeParameter>(3); 203 assert(current() == '<'); // should not have been called at all 204 if (current() != '<') { throw error("expected <");} 205 advance(); 206 ftps.add(parseFormalTypeParameter()); 207 while (current() != '>') { 208 ftps.add(parseFormalTypeParameter()); 209 } 210 advance(); 211 FormalTypeParameter[] ftpa = new FormalTypeParameter[ftps.size()]; 212 return ftps.toArray(ftpa); 213 } 214 215 private FormalTypeParameter parseFormalTypeParameter(){ 216 String id = parseIdentifier(); 217 FieldTypeSignature[] bs = parseZeroOrMoreBounds(); 218 return FormalTypeParameter.make(id, bs); 219 } 220 221 private String parseIdentifier(){ 222 StringBuilder result = new StringBuilder(); 223 while (!Character.isWhitespace(current())) { 224 char c = current(); 225 switch(c) { 226 case ';': 227 case '.': 228 case '/': 229 case '[': 230 case ':': 231 case '>': 232 case '<': return result.toString(); 233 default:{ 234 result.append(c); 235 advance(); 236 } 237 238 } 239 } 240 return result.toString(); 241 } 242 243 private FieldTypeSignature parseFieldTypeSignature() { 244 switch(current()) { 245 case 'L': 246 return parseClassTypeSignature(); 247 case 'T': 248 return parseTypeVariableSignature(); 249 case '[': 250 return parseArrayTypeSignature(); 251 default: throw error("Expected Field Type Signature"); 252 } 253 } 254 255 private ClassTypeSignature parseClassTypeSignature(){ 256 assert(current() == 'L'); 257 if (current() != 'L') { throw error("expected a class type");} 258 advance(); 259 List<SimpleClassTypeSignature> scts = 260 new ArrayList<SimpleClassTypeSignature>(5); 261 scts.add(parseSimpleClassTypeSignature(false)); 262 parseClassTypeSignatureSuffix(scts); 263 if (current() != ';') 264 throw error("expected ';' got '" + current() + "'"); 265 266 advance(); 267 return ClassTypeSignature.make(scts); 268 } 269 270 private SimpleClassTypeSignature parseSimpleClassTypeSignature(boolean dollar){ 271 String id = parseIdentifier(); 272 char c = current(); 273 switch (c) { 274 case ';': 275 case '/': 276 return SimpleClassTypeSignature.make(id, dollar, new TypeArgument[0]) ; 277 case '<': { 278 return SimpleClassTypeSignature.make(id, dollar, parseTypeArguments()); 279 } 280 default: {throw error("expected < or ; or /");} 281 } 282 } 283 284 private void parseClassTypeSignatureSuffix(List<SimpleClassTypeSignature> scts) { 285 while (current() == '/' || current() == '.') { 286 boolean dollar = (current() == '.'); 287 advance(); 288 scts.add(parseSimpleClassTypeSignature(dollar)); 289 } 290 } 291 292 private TypeArgument[] parseTypeArgumentsOpt() { 293 if (current() == '<') {return parseTypeArguments();} 294 else {return new TypeArgument[0];} 295 } 296 297 private TypeArgument[] parseTypeArguments() { 298 Collection<TypeArgument> tas = new ArrayList<TypeArgument>(3); 299 assert(current() == '<'); 300 if (current() != '<') { throw error("expected <");} 301 advance(); 302 tas.add(parseTypeArgument()); 303 while (current() != '>') { 304 //(matches(current(), '+', '-', 'L', '[', 'T', '*')) { 305 tas.add(parseTypeArgument()); 306 } 307 advance(); 308 TypeArgument[] taa = new TypeArgument[tas.size()]; 309 return tas.toArray(taa); 310 } 311 312 private TypeArgument parseTypeArgument() { 313 FieldTypeSignature[] ub, lb; 314 ub = new FieldTypeSignature[1]; 315 lb = new FieldTypeSignature[1]; 316 TypeArgument[] ta = new TypeArgument[0]; 317 char c = current(); 318 switch (c) { 319 case '+': { 320 advance(); 321 ub[0] = parseFieldTypeSignature(); 322 lb[0] = BottomSignature.make(); // bottom 323 return Wildcard.make(ub, lb); 324 } 325 case '*':{ 326 advance(); 327 ub[0] = SimpleClassTypeSignature.make("java.lang.Object", false, ta); 328 lb[0] = BottomSignature.make(); // bottom 329 return Wildcard.make(ub, lb); 330 } 331 case '-': { 332 advance(); 333 lb[0] = parseFieldTypeSignature(); 334 ub[0] = SimpleClassTypeSignature.make("java.lang.Object", false, ta); 335 return Wildcard.make(ub, lb); 336 } 337 default: return parseFieldTypeSignature(); 338 } 339 } 340 341 // TypeVariableSignature -> T identifier 342 343 private TypeVariableSignature parseTypeVariableSignature(){ 344 assert(current() == 'T'); 345 if (current() != 'T') { throw error("expected a type variable usage");} 346 advance(); 347 TypeVariableSignature ts = 348 TypeVariableSignature.make(parseIdentifier()); 349 if (current() != ';') { 350 throw error("; expected in signature of type variable named" + 351 ts.getIdentifier()); 352 } 353 advance(); 354 return ts; 355 } 356 357 // ArrayTypeSignature -> [ TypeSignature 358 359 private ArrayTypeSignature parseArrayTypeSignature() { 360 if (current() != '[') {throw error("expected array type signature");} 361 advance(); 362 return ArrayTypeSignature.make(parseTypeSignature()); 363 } 364 365 // TypeSignature -> BaseType | FieldTypeSignature 366 367 private TypeSignature parseTypeSignature() { 368 switch (current()) { 369 case 'B': 370 case 'C': 371 case 'D': 372 case 'F': 373 case 'I': 374 case 'J': 375 case 'S': 376 case 'Z':return parseBaseType(); 377 default: return parseFieldTypeSignature(); 378 } 379 } 380 381 private BaseType parseBaseType() { 382 switch(current()) { 383 case 'B': 384 advance(); 385 return ByteSignature.make(); 386 case 'C': 387 advance(); 388 return CharSignature.make(); 389 case 'D': 390 advance(); 391 return DoubleSignature.make(); 392 case 'F': 393 advance(); 394 return FloatSignature.make(); 395 case 'I': 396 advance(); 397 return IntSignature.make(); 398 case 'J': 399 advance(); 400 return LongSignature.make(); 401 case 'S': 402 advance(); 403 return ShortSignature.make(); 404 case 'Z': 405 advance(); 406 return BooleanSignature.make(); 407 default: { 408 assert(false); 409 throw error("expected primitive type"); 410 } 411 } 412 } 413 414 private FieldTypeSignature[] parseZeroOrMoreBounds() { 415 Collection<FieldTypeSignature> fts = 416 new ArrayList<FieldTypeSignature>(3); 417 418 if (current() == ':') { 419 advance(); 420 switch(current()) { 421 case ':': // empty class bound 422 break; 423 424 default: // parse class bound 425 fts.add(parseFieldTypeSignature()); 426 } 427 428 // zero or more interface bounds 429 while (current() == ':') { 430 advance(); 431 fts.add(parseFieldTypeSignature()); 432 } 433 } 434 435 FieldTypeSignature[] fta = new FieldTypeSignature[fts.size()]; 436 return fts.toArray(fta); 437 } 438 439 private ClassTypeSignature[] parseSuperInterfaces() { 440 Collection<ClassTypeSignature> cts = 441 new ArrayList<ClassTypeSignature>(5); 442 while(current() == 'L') { 443 cts.add(parseClassTypeSignature()); 444 } 445 ClassTypeSignature[] cta = new ClassTypeSignature[cts.size()]; 446 return cts.toArray(cta); 447 } 448 449 // parse a method signature based on the implicit input. 450 private MethodTypeSignature parseMethodTypeSignature() { 451 FieldTypeSignature[] ets; 452 453 assert(index == 0); 454 return MethodTypeSignature.make(parseZeroOrMoreFormalTypeParameters(), 455 parseFormalParameters(), 456 parseReturnType(), 457 parseZeroOrMoreThrowsSignatures()); 458 } 459 460 // (TypeSignature*) 461 private TypeSignature[] parseFormalParameters() { 462 if (current() != '(') {throw error("expected (");} 463 advance(); 464 TypeSignature[] pts = parseZeroOrMoreTypeSignatures(); 465 if (current() != ')') {throw error("expected )");} 466 advance(); 467 return pts; 468 } 469 470 // TypeSignature* 471 private TypeSignature[] parseZeroOrMoreTypeSignatures() { 472 Collection<TypeSignature> ts = new ArrayList<TypeSignature>(); 473 boolean stop = false; 474 while (!stop) { 475 switch(current()) { 476 case 'B': 477 case 'C': 478 case 'D': 479 case 'F': 480 case 'I': 481 case 'J': 482 case 'S': 483 case 'Z': 484 case 'L': 485 case 'T': 486 case '[': { 487 ts.add(parseTypeSignature()); 488 break; 489 } 490 default: stop = true; 491 } 492 } 493 /* while( matches(current(), 494 'B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z', 'L', 'T', '[') 495 ) { 496 ts.add(parseTypeSignature()); 497 }*/ 498 TypeSignature[] ta = new TypeSignature[ts.size()]; 499 return ts.toArray(ta); 500 } 501 502 // ReturnType -> V | TypeSignature 503 504 private ReturnType parseReturnType(){ 505 if (current() == 'V') { 506 advance(); 507 return VoidDescriptor.make(); 508 } else return parseTypeSignature(); 509 } 510 511 // ThrowSignature* 512 private FieldTypeSignature[] parseZeroOrMoreThrowsSignatures(){ 513 Collection<FieldTypeSignature> ets = 514 new ArrayList<FieldTypeSignature>(3); 515 while( current() == '^') { 516 ets.add(parseThrowsSignature()); 517 } 518 FieldTypeSignature[] eta = new FieldTypeSignature[ets.size()]; 519 return ets.toArray(eta); 520 } 521 522 // ThrowSignature -> ^ FieldTypeSignature 523 524 private FieldTypeSignature parseThrowsSignature() { 525 assert(current() == '^'); 526 if (current() != '^') { throw error("expected throws signature");} 527 advance(); 528 return parseFieldTypeSignature(); 529 } 530 }