1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package org.apache.harmony.luni.lang.reflect; 18 19import java.lang.reflect.Constructor; 20import java.lang.reflect.GenericDeclaration; 21import java.lang.reflect.GenericSignatureFormatError; 22import java.lang.reflect.Method; 23import java.lang.reflect.Type; 24import java.lang.reflect.TypeVariable; 25 26/** 27 * Implements a parser for the generics signature attribute. 28 * Uses a top-down, recursive descent parsing approach for the following grammar: 29 * <pre> 30 * ClassSignature ::= 31 * OptFormalTypeParams SuperclassSignature {SuperinterfaceSignature}. 32 * SuperclassSignature ::= ClassTypeSignature. 33 * SuperinterfaceSignature ::= ClassTypeSignature. 34 * 35 * OptFormalTypeParams ::= 36 * ["<" FormalTypeParameter {FormalTypeParameter} ">"]. 37 * 38 * FormalTypeParameter ::= Ident ClassBound {InterfaceBound}. 39 * ClassBound ::= ":" [FieldTypeSignature]. 40 * InterfaceBound ::= ":" FieldTypeSignature. 41 * 42 * FieldTypeSignature ::= 43 * ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature. 44 * ArrayTypeSignature ::= "[" TypSignature. 45 * 46 * ClassTypeSignature ::= 47 * "L" {Ident "/"} Ident OptTypeArguments {"." Ident OptTypeArguments} ";". 48 * 49 * OptTypeArguments ::= "<" TypeArgument {TypeArgument} ">". 50 * 51 * TypeArgument ::= ([WildcardIndicator] FieldTypeSignature) | "*". 52 * WildcardIndicator ::= "+" | "-". 53 * 54 * TypeVariableSignature ::= "T" Ident ";". 55 * 56 * TypSignature ::= FieldTypeSignature | BaseType. 57 * BaseType ::= "B" | "C" | "D" | "F" | "I" | "J" | "S" | "Z". 58 * 59 * MethodTypeSignature ::= 60 * OptFormalTypeParams "(" {TypeSignature} ")" ReturnType {ThrowsSignature}. 61 * ThrowsSignature ::= ("^" ClassTypeSignature) | ("^" TypeVariableSignature). 62 * 63 * ReturnType ::= TypSignature | VoidDescriptor. 64 * VoidDescriptor ::= "V". 65 * </pre> 66 */ 67public class GenericSignatureParser { 68 69 public ListOfTypes exceptionTypes; 70 public ListOfTypes parameterTypes; 71 public TypeVariable[] formalTypeParameters; 72 public Type returnType; 73 public Type fieldType; 74 public ListOfTypes interfaceTypes; 75 public Type superclassType; 76 public ClassLoader loader; 77 78 GenericDeclaration genericDecl; 79 80 /* 81 * Parser: 82 */ 83 char symbol; // 0: eof; else valid term symbol or first char of identifier. 84 String identifier; 85 86 87 /* 88 * Scanner: 89 * eof is private to the scan methods 90 * and it's set only when a scan is issued at the end of the buffer. 91 */ 92 private boolean eof; 93 94 char[] buffer; 95 int pos; 96 97 public GenericSignatureParser(ClassLoader loader) { 98 this.loader = loader; 99 } 100 101 void setInput(GenericDeclaration genericDecl, String input) { 102 if (input != null) { 103 this.genericDecl = genericDecl; 104 this.buffer = input.toCharArray(); 105 this.eof = false; 106 scanSymbol(); 107 } 108 else { 109 this.eof = true; 110 } 111 } 112 113 /** 114 * Parses the generic signature of a class and creates the data structure 115 * representing the signature. 116 * 117 * @param genericDecl the GenericDeclaration calling this method 118 * @param signature the generic signature of the class 119 */ 120 public void parseForClass(GenericDeclaration genericDecl, 121 String signature) { 122 setInput(genericDecl, signature); 123 if (!eof) { 124 parseClassSignature(); 125 } else { 126 if(genericDecl instanceof Class) { 127 Class c = (Class) genericDecl; 128 this.formalTypeParameters = ListOfVariables.EMPTY; 129 this.superclassType = c.getSuperclass(); 130 this.interfaceTypes = new ListOfTypes(c.getInterfaces()); 131 } else { 132 this.formalTypeParameters = ListOfVariables.EMPTY; 133 this.superclassType = Object.class; 134 this.interfaceTypes = ListOfTypes.EMPTY; 135 } 136 } 137 } 138 139 /** 140 * Parses the generic signature of a method and creates the data structure 141 * representing the signature. 142 * 143 * @param genericDecl the GenericDeclaration calling this method 144 * @param signature the generic signature of the class 145 */ 146 public void parseForMethod(GenericDeclaration genericDecl, 147 String signature, Class<?>[] rawExceptionTypes) { 148 setInput(genericDecl, signature); 149 if (!eof) { 150 parseMethodTypeSignature(rawExceptionTypes); 151 } else { 152 if(genericDecl instanceof Method) { 153 Method m = (Method) genericDecl; 154 this.formalTypeParameters = ListOfVariables.EMPTY; 155 this.parameterTypes = new ListOfTypes(m.getParameterTypes()); 156 this.exceptionTypes = new ListOfTypes(m.getExceptionTypes()); 157 this.returnType = m.getReturnType(); 158 } else { 159 this.formalTypeParameters = ListOfVariables.EMPTY; 160 this.parameterTypes = ListOfTypes.EMPTY; 161 this.exceptionTypes = ListOfTypes.EMPTY; 162 this.returnType = void.class; 163 } 164 } 165 } 166 167 /** 168 * Parses the generic signature of a constructor and creates the data 169 * structure representing the signature. 170 * 171 * @param genericDecl the GenericDeclaration calling this method 172 * @param signature the generic signature of the class 173 */ 174 public void parseForConstructor(GenericDeclaration genericDecl, 175 String signature, Class<?>[] rawExceptionTypes) { 176 setInput(genericDecl, signature); 177 if (!eof) { 178 parseMethodTypeSignature(rawExceptionTypes); 179 } else { 180 if(genericDecl instanceof Constructor) { 181 Constructor c = (Constructor) genericDecl; 182 this.formalTypeParameters = ListOfVariables.EMPTY; 183 this.parameterTypes = new ListOfTypes(c.getParameterTypes()); 184 this.exceptionTypes = new ListOfTypes(c.getExceptionTypes()); 185 } else { 186 this.formalTypeParameters = ListOfVariables.EMPTY; 187 this.parameterTypes = ListOfTypes.EMPTY; 188 this.exceptionTypes = ListOfTypes.EMPTY; 189 } 190 } 191 } 192 193 /** 194 * Parses the generic signature of a field and creates the data structure 195 * representing the signature. 196 * 197 * @param genericDecl the GenericDeclaration calling this method 198 * @param signature the generic signature of the class 199 */ 200 public void parseForField(GenericDeclaration genericDecl, 201 String signature) { 202 setInput(genericDecl, signature); 203 if (!eof) { 204 this.fieldType = parseFieldTypeSignature(); 205 } 206 } 207 208 209 // 210 // Parser: 211 // 212 213 void parseClassSignature() { 214 // ClassSignature ::= 215 // OptFormalTypeParameters SuperclassSignature {SuperinterfaceSignature}. 216 217 parseOptFormalTypeParameters(); 218 219 // SuperclassSignature ::= ClassTypeSignature. 220 this.superclassType = parseClassTypeSignature(); 221 222 interfaceTypes = new ListOfTypes(16); 223 while (symbol > 0) { 224 // SuperinterfaceSignature ::= ClassTypeSignature. 225 interfaceTypes.add(parseClassTypeSignature()); 226 } 227 } 228 229 void parseOptFormalTypeParameters() { 230 // OptFormalTypeParameters ::= 231 // ["<" FormalTypeParameter {FormalTypeParameter} ">"]. 232 233 ListOfVariables typeParams = new ListOfVariables(); 234 235 if (symbol == '<') { 236 scanSymbol(); 237 typeParams.add(parseFormalTypeParameter()); 238 while ((symbol != '>') && (symbol > 0)) { 239 typeParams.add(parseFormalTypeParameter()); 240 } 241 expect('>'); 242 } 243 this.formalTypeParameters = typeParams.getArray(); 244 } 245 246 ImplForVariable<GenericDeclaration> parseFormalTypeParameter() { 247 // FormalTypeParameter ::= Ident ClassBound {InterfaceBound}. 248 249 scanIdentifier(); 250 String name = identifier.intern(); // FIXME: is this o.k.? 251 252 ListOfTypes bounds = new ListOfTypes(8); 253 254 // ClassBound ::= ":" [FieldTypeSignature]. 255 expect(':'); 256 if (symbol == 'L' || symbol == '[' || symbol == 'T') { 257 bounds.add(parseFieldTypeSignature()); 258 } 259 260 while (symbol == ':') { 261 // InterfaceBound ::= ":" FieldTypeSignature. 262 scanSymbol(); 263 bounds.add(parseFieldTypeSignature()); 264 } 265 266 return new ImplForVariable<GenericDeclaration>(genericDecl, name, bounds); 267 } 268 269 Type parseFieldTypeSignature() { 270 // FieldTypeSignature ::= ClassTypeSignature | ArrayTypeSignature 271 // | TypeVariableSignature. 272 273 switch (symbol) { 274 case 'L': 275 return parseClassTypeSignature(); 276 case '[': 277 // ArrayTypeSignature ::= "[" TypSignature. 278 scanSymbol(); 279 return new ImplForArray(parseTypeSignature()); 280 case 'T': 281 return parseTypeVariableSignature(); 282 default: 283 throw new GenericSignatureFormatError(); 284 } 285 } 286 287 Type parseClassTypeSignature() { 288 // ClassTypeSignature ::= "L" {Ident "/"} Ident 289 // OptTypeArguments {"." Ident OptTypeArguments} ";". 290 291 expect('L'); 292 293 StringBuilder qualIdent = new StringBuilder(); 294 scanIdentifier(); 295 while (symbol == '/') { 296 scanSymbol(); 297 qualIdent.append(identifier).append("."); 298 scanIdentifier(); 299 } 300 301 qualIdent.append(this.identifier); 302 303 ListOfTypes typeArgs = parseOptTypeArguments(); 304 ImplForType parentType = 305 new ImplForType(null, qualIdent.toString(), typeArgs, loader); 306 ImplForType type = parentType; 307 308 while (symbol == '.') { 309 // Deal with Member Classes: 310 scanSymbol(); 311 scanIdentifier(); 312 qualIdent.append("$").append(identifier); // FIXME: is "$" correct? 313 typeArgs = parseOptTypeArguments(); 314 type = new ImplForType(parentType, qualIdent.toString(), typeArgs, 315 loader); 316 } 317 318 expect(';'); 319 320 return type; 321 } 322 323 ListOfTypes parseOptTypeArguments() { 324 // OptTypeArguments ::= "<" TypeArgument {TypeArgument} ">". 325 326 ListOfTypes typeArgs = new ListOfTypes(8); 327 if (symbol == '<') { 328 scanSymbol(); 329 330 typeArgs.add(parseTypeArgument()); 331 while ((symbol != '>') && (symbol > 0)) { 332 typeArgs.add(parseTypeArgument()); 333 } 334 expect('>'); 335 } 336 return typeArgs; 337 } 338 339 Type parseTypeArgument() { 340 // TypeArgument ::= (["+" | "-"] FieldTypeSignature) | "*". 341 ListOfTypes extendsBound = new ListOfTypes(1); 342 ListOfTypes superBound = new ListOfTypes(1); 343 if (symbol == '*') { 344 scanSymbol(); 345 extendsBound.add(Object.class); 346 return new ImplForWildcard(extendsBound, superBound); 347 } 348 else if (symbol == '+') { 349 scanSymbol(); 350 extendsBound.add(parseFieldTypeSignature()); 351 return new ImplForWildcard(extendsBound, superBound); 352 } 353 else if (symbol == '-') { 354 scanSymbol(); 355 superBound.add(parseFieldTypeSignature()); 356 extendsBound.add(Object.class); 357 return new ImplForWildcard(extendsBound, superBound); 358 } 359 else { 360 return parseFieldTypeSignature(); 361 } 362 } 363 364 ImplForVariable<GenericDeclaration> parseTypeVariableSignature() { 365 // TypeVariableSignature ::= "T" Ident ";". 366 expect('T'); 367 scanIdentifier(); 368 expect(';'); 369 // Reference to type variable: 370 // Note: we don't know the declaring GenericDeclaration yet. 371 return new ImplForVariable<GenericDeclaration>(genericDecl, identifier); 372 } 373 374 Type parseTypeSignature() { 375 switch (symbol) { 376 case 'B': scanSymbol(); return byte.class; 377 case 'C': scanSymbol(); return char.class; 378 case 'D': scanSymbol(); return double.class; 379 case 'F': scanSymbol(); return float.class; 380 case 'I': scanSymbol(); return int.class; 381 case 'J': scanSymbol(); return long.class; 382 case 'S': scanSymbol(); return short.class; 383 case 'Z': scanSymbol(); return boolean.class; 384 default: 385 // Not an elementary type, but a FieldTypeSignature. 386 return parseFieldTypeSignature(); 387 } 388 } 389 390 /** 391 * @param rawExceptionTypes the non-generic exceptions. This is necessary 392 * because the signature may omit the exceptions when none are generic. 393 * May be null for methods that declare no exceptions. 394 */ 395 void parseMethodTypeSignature(Class<?>[] rawExceptionTypes) { 396 // MethodTypeSignature ::= [FormalTypeParameters] 397 // "(" {TypeSignature} ")" ReturnType {ThrowsSignature}. 398 399 parseOptFormalTypeParameters(); 400 401 parameterTypes = new ListOfTypes(16); 402 expect('('); 403 while (symbol != ')' && (symbol > 0)) { 404 parameterTypes.add(parseTypeSignature()); 405 } 406 expect(')'); 407 408 returnType = parseReturnType(); 409 410 if (symbol == '^') { 411 exceptionTypes = new ListOfTypes(8); 412 do { 413 scanSymbol(); 414 415 // ThrowsSignature ::= ("^" ClassTypeSignature) | 416 // ("^" TypeVariableSignature). 417 if (symbol == 'T') { 418 exceptionTypes.add(parseTypeVariableSignature()); 419 } else { 420 exceptionTypes.add(parseClassTypeSignature()); 421 } 422 } while (symbol == '^'); 423 } else if (rawExceptionTypes != null) { 424 exceptionTypes = new ListOfTypes(rawExceptionTypes); 425 } else { 426 exceptionTypes = new ListOfTypes(0); 427 } 428 } 429 430 Type parseReturnType() { 431 // ReturnType ::= TypeSignature | "V". 432 if (symbol != 'V') { return parseTypeSignature(); } 433 else { scanSymbol(); return void.class; } 434 } 435 436 437 // 438 // Scanner: 439 // 440 441 void scanSymbol() { 442 if (!eof) { 443 if (pos < buffer.length) { 444 symbol = buffer[pos]; 445 pos++; 446 } else { 447 symbol = 0; 448 eof = true; 449 } 450 } else { 451 throw new GenericSignatureFormatError(); 452 } 453 } 454 455 void expect(char c) { 456 if (symbol == c) { 457 scanSymbol(); 458 } else { 459 throw new GenericSignatureFormatError(); 460 } 461 } 462 463 boolean isStopSymbol(char ch) { 464 switch (ch) { 465 case ':': 466 case '/': 467 case ';': 468 case '<': 469 case '.': 470 return true; 471 } 472 return false; 473 } 474 475 // PRE: symbol is the first char of the identifier. 476 // POST: symbol = the next symbol AFTER the identifier. 477 void scanIdentifier() { 478 if (!eof) { 479 StringBuilder identBuf = new StringBuilder(32); 480 if (!isStopSymbol(symbol)) { 481 identBuf.append(symbol); 482 do { 483 char ch = buffer[pos]; 484 if ((ch >= 'a') && (ch <= 'z') || (ch >= 'A') && (ch <= 'Z') 485 || !isStopSymbol(ch)) { 486 identBuf.append(buffer[pos]); 487 pos++; 488 } else { 489 identifier = identBuf.toString(); 490 scanSymbol(); 491 return; 492 } 493 } while (pos != buffer.length); 494 identifier = identBuf.toString(); 495 symbol = 0; 496 eof = true; 497 } else { 498 // Ident starts with incorrect char. 499 symbol = 0; 500 eof = true; 501 throw new GenericSignatureFormatError(); 502 } 503 } else { 504 throw new GenericSignatureFormatError(); 505 } 506 } 507 508} 509