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) {


 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         return new GenericSignatureFormatError("Signature Parse error: " + errorMsg +
 124                                                "\n\tRemaining input: " + remainder());
 125     }
 126 
 127     /**
 128      * Verify the parse has made forward progress; throw an exception
 129      * if no progress.
 130      */
 131     private void progress(int startingPosition) {
 132         if (index <= startingPosition)
 133             throw error("Failure to make progress!");
 134     }
 135 
 136     /**
 137      * Static factory method. Produces a parser instance.
 138      * @return an instance of <tt>SignatureParser</tt>
 139      */
 140     public static SignatureParser make() {
 141         return new SignatureParser();
 142     }
 143 
 144     /**
 145      * Parses a class signature (as defined in the JVMS, chapter 4)
 146      * and produces an abstract syntax tree representing it.
 147      * @param s a string representing the input class signature
 148      * @return An abstract syntax tree for a class signature
 149      * corresponding to the input string
 150      * @throws GenericSignatureFormatError if the input is not a valid
 151      * class signature
 152      */
 153     public ClassSignature parseClassSig(String s) {


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

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

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

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

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

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

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

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

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






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

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

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