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