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  }