src/share/classes/sun/reflect/generics/parser/SignatureParser.java

Print this page


   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();


 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  }
   1 /*
   2  * Copyright (c) 2003, 2011, 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 import java.lang.reflect.GenericSignatureFormatError;
  29 import java.util.*;
  30 import sun.reflect.generics.tree.*;
  31 

  32 /**
  33  * Parser for type signatures, as defined in the Java Virtual
  34  * Machine Specification (JVMS) chapter 4.
  35  * Converts the signatures into an abstract syntax tree (AST) representation.
  36  * See the package sun.reflect.generics.tree for details of the AST.
  37  */
  38 public class SignatureParser {
  39     // The input is conceptually a character stream (though currently it's
  40     // a string). This is slightly different than traditional parsers,
  41     // because there is no lexical scanner performing tokenization.
  42     // Having a separate tokenizer does not fit with the nature of the
  43     // input format.
  44     // Other than the absence of a tokenizer, this parser is a classic
  45     // recursive descent parser. Its structure corresponds as closely
  46     // as possible to the grammar in the JVMS.
  47     //
  48     // A note on asserts vs. errors: The code contains assertions
  49     // in situations that should never occur. An assertion failure
  50     // indicates a failure of the parser logic. A common pattern
  51     // is an assertion that the current input is a particular
  52     // character. This is often paired with a separate check
  53     // that this is the case, which seems redundant. For example:
  54     //
  55     // assert(current() != x);
  56     // if (current != x {error("expected an x");
  57     //
  58     // where x is some character constant.
  59     // The assertion indicates, that, as currently written,
  60     // the code should never reach this point unless the input is an
  61     // x. On the other hand, the test is there to check the legality
  62     // of the input wrt to a given production. It may be that at a later
  63     // time the code might be called directly, and if the input is
  64     // invalid, the parser should flag an error in accordance
  65     // with its logic.
  66 
  67     private char[] input; // the input signature
  68     private int index = 0; // index into the input
  69     // used to mark end of input
  70     private static final char EOI = ':';
  71     private static final boolean DEBUG = false;
  72 
  73     // private constructor - enforces use of static factory
  74     private SignatureParser(){}
  75 
  76     // Utility methods.
  77 
  78     // Most parsing routines use the following routines to access the
  79     // input stream, and advance it as necessary.
  80     // This makes it easy to adapt the parser to operate on streams
  81     // of various kinds as well as strings.
  82 
  83     // returns current element of the input and advances the input
  84     private char getNext(){
  85         assert(index <= input.length);
  86         try {
  87             return input[index++];
  88         } catch (ArrayIndexOutOfBoundsException e) { return EOI;}
  89     }
  90 
  91     // returns current element of the input
  92     private char current(){
  93         assert(index <= input.length);
  94         try {
  95             return input[index];
  96         } catch (ArrayIndexOutOfBoundsException e) { return EOI;}
  97     }
  98 
  99     // advance the input
 100     private void advance(){
 101         assert(index <= input.length);
 102         index++;
 103     }
 104 
 105     // For debugging, prints current character to the end of the input.
 106     private String remainder() {
 107         return new String(input, index, input.length-index);
 108     }
 109 
 110     // Match c against a "set" of characters
 111     private boolean matches(char c, char... set) {
 112         for (char e : set) {
 113             if (c == e) return true;
 114         }
 115         return false;
 116     }
 117 
 118     // Error handling routine. Encapsulates error handling.
 119     // Takes a string error message as argument.
 120     // Currently throws a GenericSignatureFormatError.
 121 
 122     private Error error(String errorMsg) {
 123         if (DEBUG)
 124             System.out.println("Signature Parse error: " + errorMsg +
 125                                "\n\tRemaining input: " + remainder());
 126         return new GenericSignatureFormatError();
 127     }
 128 
 129     /**
 130      * Verify the parse has made forward progress; throw an exception
 131      * if no progress.
 132      */
 133     private void progress(int startingPosition) {
 134         if (index <= startingPosition)
 135             throw error("Failure to make progress!");
 136     }
 137 
 138     /**
 139      * Static factory method. Produces a parser instance.
 140      * @return an instance of <tt>SignatureParser</tt>
 141      */
 142     public static SignatureParser make() {
 143         return new SignatureParser();
 144     }
 145 
 146     /**
 147      * Parses a class signature (as defined in the JVMS, chapter 4)
 148      * and produces an abstract syntax tree representing it.
 149      * @param s a string representing the input class signature
 150      * @return An abstract syntax tree for a class signature
 151      * corresponding to the input string
 152      * @throws GenericSignatureFormatError if the input is not a valid
 153      * class signature
 154      */
 155     public ClassSignature parseClassSig(String s) {
 156         if (DEBUG) System.out.println("Parsing class sig:" + s);
 157         input = s.toCharArray();
 158         return parseClassSignature();


 160 
 161     /**
 162      * Parses a method signature (as defined in the JVMS, chapter 4)
 163      * and produces an abstract syntax tree representing it.
 164      * @param s a string representing the input method signature
 165      * @return An abstract syntax tree for a method signature
 166      * corresponding to the input string
 167      * @throws GenericSignatureFormatError if the input is not a valid
 168      * method signature
 169      */
 170     public MethodTypeSignature parseMethodSig(String s) {
 171         if (DEBUG) System.out.println("Parsing method sig:" + s);
 172         input = s.toCharArray();
 173         return parseMethodTypeSignature();
 174     }
 175 
 176 
 177     /**
 178      * Parses a type signature
 179      * and produces an abstract syntax tree representing it.
 180      *
 181      * @param s a string representing the input type signature
 182      * @return An abstract syntax tree for a type signature
 183      * corresponding to the input string
 184      * @throws GenericSignatureFormatError if the input is not a valid
 185      * type signature
 186      */
 187     public TypeSignature parseTypeSig(String s) {
 188         if (DEBUG) System.out.println("Parsing type sig:" + s);
 189         input = s.toCharArray();
 190         return parseTypeSignature();
 191     }
 192 
 193     // Parsing routines.
 194     // As a rule, the parsing routines access the input using the
 195     // utilities current(), getNext() and/or advance().
 196     // The convention is that when a parsing routine is invoked
 197     // it expects the current input to be the first character it should parse
 198     // and when it completes parsing, it leaves the input at the first
 199     // character after the input parses.
 200 
 201     /*
 202      * Note on grammar conventions: a trailing "*" matches zero or
 203      * more occurrences, a trailing "+" matches one or more occurrences,
 204      * "_opt" indicates an optional component.
 205      */
 206 
 207     /**
 208      * ClassSignature:
 209      *     FormalTypeParameters_opt SuperclassSignature SuperinterfaceSignature*
 210      */
 211     private ClassSignature parseClassSignature() {
 212         // parse a class signature based on the implicit input.
 213         assert(index == 0);
 214         return ClassSignature.make(parseZeroOrMoreFormalTypeParameters(),
 215                                    parseClassTypeSignature(), // Only rule for SuperclassSignature
 216                                    parseSuperInterfaces());
 217     }
 218 
 219     private FormalTypeParameter[] parseZeroOrMoreFormalTypeParameters(){
 220         if (current() == '<') {
 221             return parseFormalTypeParameters();
 222         } else {
 223             return new FormalTypeParameter[0];
 224         }
 225     }
 226 
 227     /**
 228      * FormalTypeParameters:
 229      *     "<" FormalTypeParameter+ ">"
 230      */
 231     private FormalTypeParameter[] parseFormalTypeParameters(){
 232         List<FormalTypeParameter> ftps =  new ArrayList<>(3);

 233         assert(current() == '<'); // should not have been called at all
 234         if (current() != '<') { throw error("expected '<'");}
 235         advance();
 236         ftps.add(parseFormalTypeParameter());
 237         while (current() != '>') {
 238             int startingPosition = index;
 239             ftps.add(parseFormalTypeParameter());
 240             progress(startingPosition);
 241         }
 242         advance();
 243         return ftps.toArray(new FormalTypeParameter[ftps.size()]);

 244     }
 245 
 246     /**
 247      * FormalTypeParameter:
 248      *     Identifier ClassBound InterfaceBound*
 249      */
 250     private FormalTypeParameter parseFormalTypeParameter(){
 251         String id = parseIdentifier();
 252         FieldTypeSignature[] bs = parseBounds();
 253         return FormalTypeParameter.make(id, bs);
 254     }
 255 
 256     private String parseIdentifier(){
 257         StringBuilder result = new StringBuilder();
 258         while (!Character.isWhitespace(current())) {
 259             char c = current();
 260             switch(c) {
 261             case ';':
 262             case '.':
 263             case '/':
 264             case '[':
 265             case ':':
 266             case '>':
 267             case '<':
 268                 return result.toString();
 269             default:{
 270                 result.append(c);
 271                 advance();
 272             }
 273 
 274             }
 275         }
 276         return result.toString();
 277     }
 278     /**
 279      * FieldTypeSignature:
 280      *     ClassTypeSignature
 281      *     ArrayTypeSignature
 282      *     TypeVariableSignature
 283      */
 284     private FieldTypeSignature parseFieldTypeSignature() {
 285         return parseFieldTypeSignature(true);
 286     }
 287 
 288     private FieldTypeSignature parseFieldTypeSignature(boolean allowArrays) {
 289         switch(current()) {
 290         case 'L':
 291            return parseClassTypeSignature();
 292         case 'T':
 293             return parseTypeVariableSignature();
 294         case '[':
 295             if (allowArrays)
 296                 return parseArrayTypeSignature();
 297             else
 298                 throw error("Array signature not allowed here.");
 299         default: throw error("Expected Field Type Signature");
 300         }
 301     }
 302 
 303     /**
 304      * ClassTypeSignature:
 305      *     "L" PackageSpecifier_opt SimpleClassTypeSignature ClassTypeSignatureSuffix* ";"
 306      */
 307     private ClassTypeSignature parseClassTypeSignature(){
 308         assert(current() == 'L');
 309         if (current() != 'L') { throw error("expected a class type");}
 310         advance();
 311         List<SimpleClassTypeSignature> scts = new ArrayList<>(5);
 312         scts.add(parsePackageNameAndSimpleClassTypeSignature());
 313 
 314         parseClassTypeSignatureSuffix(scts);
 315         if (current() != ';')
 316             throw error("expected ';' got '" + current() + "'");
 317 
 318         advance();
 319         return ClassTypeSignature.make(scts);
 320     }
 321 
 322     /**
 323      * PackageSpecifier:
 324      *     Identifier "/" PackageSpecifier*
 325      */
 326     private SimpleClassTypeSignature parsePackageNameAndSimpleClassTypeSignature() {
 327         // Parse both any optional leading PackageSpecifier as well as
 328         // the following SimpleClassTypeSignature.
 329 
 330         String id = parseIdentifier();
 331 
 332         if (current() == '/') { // package name
 333             StringBuilder idBuild = new StringBuilder(id);
 334 
 335             while(current() == '/') {
 336                 advance();
 337                 idBuild.append(".");
 338                 idBuild.append(parseIdentifier());
 339             }
 340             id = idBuild.toString();
 341         }
 342 
 343         switch (current()) {
 344         case ';':
 345             return SimpleClassTypeSignature.make(id, false, new TypeArgument[0]); // all done!
 346         case '<':
 347             if (DEBUG) System.out.println("\t remainder: " + remainder());
 348             return SimpleClassTypeSignature.make(id, false, parseTypeArguments());
 349         default:
 350             throw error("expected '<' or ';' but got " + current());
 351         }
 352     }
 353 
 354     /**
 355      * SimpleClassTypeSignature:
 356      *     Identifier TypeArguments_opt
 357      */
 358     private SimpleClassTypeSignature parseSimpleClassTypeSignature(boolean dollar){
 359         String id = parseIdentifier();
 360         char c = current();
 361 
 362         switch (c) {
 363         case ';':
 364         case '.':
 365             return SimpleClassTypeSignature.make(id, dollar, new TypeArgument[0]) ;
 366         case '<':
 367             return SimpleClassTypeSignature.make(id, dollar, parseTypeArguments());
 368         default:
 369             throw error("expected '<' or ';' or '.', got '" + c + "'.");
 370         }
 371     }
 372 
 373     /**
 374      * ClassTypeSignatureSuffix:
 375      *     "." SimpleClassTypeSignature
 376      */
 377     private void parseClassTypeSignatureSuffix(List<SimpleClassTypeSignature> scts) {
 378         while (current() == '.') {

 379             advance();
 380             scts.add(parseSimpleClassTypeSignature(true));
 381         }
 382     }
 383 
 384     private TypeArgument[] parseTypeArgumentsOpt() {
 385         if (current() == '<') {return parseTypeArguments();}
 386         else {return new TypeArgument[0];}
 387     }
 388 
 389     /**
 390      * TypeArguments:
 391      *     "<" TypeArgument+ ">"
 392      */
 393     private TypeArgument[] parseTypeArguments() {
 394         List<TypeArgument> tas = new ArrayList<>(3);
 395         assert(current() == '<');
 396         if (current() != '<') { throw error("expected '<'");}
 397         advance();
 398         tas.add(parseTypeArgument());
 399         while (current() != '>') {
 400                 //(matches(current(),  '+', '-', 'L', '[', 'T', '*')) {
 401             tas.add(parseTypeArgument());
 402         }
 403         advance();
 404         return tas.toArray(new TypeArgument[tas.size()]);

 405     }
 406 
 407     /**
 408      * TypeArgument:
 409      *     WildcardIndicator_opt FieldTypeSignature
 410      *     "*"
 411      */
 412     private TypeArgument parseTypeArgument() {
 413         FieldTypeSignature[] ub, lb;
 414         ub = new FieldTypeSignature[1];
 415         lb = new FieldTypeSignature[1];
 416         TypeArgument[] ta = new TypeArgument[0];
 417         char c = current();
 418         switch (c) {
 419         case '+': {
 420             advance();
 421             ub[0] = parseFieldTypeSignature();
 422             lb[0] = BottomSignature.make(); // bottom
 423             return Wildcard.make(ub, lb);
 424         }
 425         case '*':{
 426             advance();
 427             ub[0] = SimpleClassTypeSignature.make("java.lang.Object", false, ta);
 428             lb[0] = BottomSignature.make(); // bottom
 429             return Wildcard.make(ub, lb);
 430         }
 431         case '-': {
 432             advance();
 433             lb[0] = parseFieldTypeSignature();
 434             ub[0] = SimpleClassTypeSignature.make("java.lang.Object", false, ta);
 435             return Wildcard.make(ub, lb);
 436         }
 437         default:
 438             return parseFieldTypeSignature();
 439         }
 440     }
 441 
 442     /**
 443      * TypeVariableSignature:
 444      *     "T" Identifier ";"
 445      */
 446     private TypeVariableSignature parseTypeVariableSignature() {
 447         assert(current() == 'T');
 448         if (current() != 'T') { throw error("expected a type variable usage");}
 449         advance();
 450         TypeVariableSignature ts = TypeVariableSignature.make(parseIdentifier());

 451         if (current() != ';') {
 452             throw error("; expected in signature of type variable named" +
 453                   ts.getIdentifier());
 454         }
 455         advance();
 456         return ts;
 457     }
 458 
 459     /**
 460      * ArrayTypeSignature:
 461      *     "[" TypeSignature
 462      */
 463     private ArrayTypeSignature parseArrayTypeSignature() {
 464         if (current() != '[') {throw error("expected array type signature");}
 465         advance();
 466         return ArrayTypeSignature.make(parseTypeSignature());
 467     }
 468 
 469     /**
 470      * TypeSignature:
 471      *     FieldTypeSignature
 472      *     BaseType
 473      */
 474     private TypeSignature parseTypeSignature() {
 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             return parseBaseType();
 485 
 486         default:
 487             return parseFieldTypeSignature();
 488         }
 489     }
 490 
 491     private BaseType parseBaseType() {
 492         switch(current()) {
 493         case 'B':
 494             advance();
 495             return ByteSignature.make();
 496         case 'C':
 497             advance();
 498             return CharSignature.make();
 499         case 'D':
 500             advance();
 501             return DoubleSignature.make();
 502         case 'F':
 503             advance();
 504             return FloatSignature.make();
 505         case 'I':
 506             advance();
 507             return IntSignature.make();
 508         case 'J':
 509             advance();
 510             return LongSignature.make();
 511         case 'S':
 512             advance();
 513             return ShortSignature.make();
 514         case 'Z':
 515             advance();
 516             return BooleanSignature.make();
 517         default: {
 518             assert(false);
 519             throw error("expected primitive type");
 520         }
 521         }
 522     }
 523 
 524     /**
 525      * ClassBound:
 526      *     ":" FieldTypeSignature_opt
 527      *
 528      * InterfaceBound:
 529      *     ":" FieldTypeSignature
 530      */
 531     private FieldTypeSignature[] parseBounds() {
 532         List<FieldTypeSignature> fts = new ArrayList<>(3);
 533 
 534         if (current() == ':') {
 535             advance();
 536             switch(current()) {
 537             case ':': // empty class bound
 538                 break;
 539 
 540             default: // parse class bound
 541                 fts.add(parseFieldTypeSignature());
 542             }
 543 
 544             // zero or more interface bounds
 545             while (current() == ':') {
 546                 advance();
 547                 fts.add(parseFieldTypeSignature());
 548             }
 549         } else
 550             error("Bound expected");
 551 
 552         return fts.toArray(new FieldTypeSignature[fts.size()]);

 553     }
 554 
 555     /**
 556      * SuperclassSignature:
 557      *     ClassTypeSignature
 558      */
 559     private ClassTypeSignature[] parseSuperInterfaces() {
 560         List<ClassTypeSignature> cts = new ArrayList<>(5);

 561         while(current() == 'L') {
 562             cts.add(parseClassTypeSignature());
 563         }
 564         return cts.toArray(new ClassTypeSignature[cts.size()]);

 565     }
 566 
 567 
 568     /**
 569      * MethodTypeSignature:
 570      *     FormalTypeParameters_opt "(" TypeSignature* ")" ReturnType ThrowsSignature*
 571      */
 572     private MethodTypeSignature parseMethodTypeSignature() {
 573         // Parse a method signature based on the implicit input.
 574         FieldTypeSignature[] ets;
 575 
 576         assert(index == 0);
 577         return MethodTypeSignature.make(parseZeroOrMoreFormalTypeParameters(),
 578                                         parseFormalParameters(),
 579                                         parseReturnType(),
 580                                         parseZeroOrMoreThrowsSignatures());
 581     }
 582 
 583     // "(" TypeSignature* ")"
 584     private TypeSignature[] parseFormalParameters() {
 585         if (current() != '(') {throw error("expected '('");}
 586         advance();
 587         TypeSignature[] pts = parseZeroOrMoreTypeSignatures();
 588         if (current() != ')') {throw error("expected ')'");}
 589         advance();
 590         return pts;
 591     }
 592 
 593     // TypeSignature*
 594     private TypeSignature[] parseZeroOrMoreTypeSignatures() {
 595         List<TypeSignature> ts = new ArrayList<>();
 596         boolean stop = false;
 597         while (!stop) {
 598             switch(current()) {
 599             case 'B':
 600             case 'C':
 601             case 'D':
 602             case 'F':
 603             case 'I':
 604             case 'J':
 605             case 'S':
 606             case 'Z':
 607             case 'L':
 608             case 'T':
 609             case '[': {
 610                 ts.add(parseTypeSignature());
 611                 break;
 612             }
 613             default: stop = true;
 614             }
 615         }
 616         return ts.toArray(new TypeSignature[ts.size()]);






 617     }
 618 
 619     /**
 620      * ReturnType:
 621      *     TypeSignature
 622      *     VoidDescriptor
 623      */
 624     private ReturnType parseReturnType(){
 625         if (current() == 'V') {
 626             advance();
 627             return VoidDescriptor.make();
 628         } else
 629             return parseTypeSignature();
 630     }
 631 
 632     // ThrowSignature*
 633     private FieldTypeSignature[] parseZeroOrMoreThrowsSignatures(){
 634         List<FieldTypeSignature> ets = new ArrayList<>(3);

 635         while( current() == '^') {
 636             ets.add(parseThrowsSignature());
 637         }
 638         return ets.toArray(new FieldTypeSignature[ets.size()]);

 639     }
 640 
 641     /**
 642      * ThrowsSignature:
 643      *     "^" ClassTypeSignature
 644      *     "^" TypeVariableSignature
 645      */
 646     private FieldTypeSignature parseThrowsSignature() {
 647         assert(current() == '^');
 648         if (current() != '^') { throw error("expected throws signature");}
 649         advance();
 650         return parseFieldTypeSignature(false);
 651     }
 652  }