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

Print this page

        

*** 1,7 **** /* ! * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this --- 1,7 ---- /* ! * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this
*** 23,43 **** * questions. */ package sun.reflect.generics.parser; - import java.lang.reflect.GenericSignatureFormatError; import java.util.*; import sun.reflect.generics.tree.*; - /** * Parser for type signatures, as defined in the Java Virtual ! // Machine Specification (JVMS) chapter 4. * Converts the signatures into an abstract syntax tree (AST) representation. ! // See the package sun.reflect.generics.tree for details of the AST. */ public class SignatureParser { // The input is conceptually a character stream (though currently it's // a string). This is slightly different than traditional parsers, // because there is no lexical scanner performing tokenization. --- 23,41 ---- * questions. */ package sun.reflect.generics.parser; import java.lang.reflect.GenericSignatureFormatError; import java.util.*; import sun.reflect.generics.tree.*; /** * Parser for type signatures, as defined in the Java Virtual ! * Machine Specification (JVMS) chapter 4. * Converts the signatures into an abstract syntax tree (AST) representation. ! * See the package sun.reflect.generics.tree for details of the AST. */ public class SignatureParser { // The input is conceptually a character stream (though currently it's // a string). This is slightly different than traditional parsers, // because there is no lexical scanner performing tokenization.
*** 56,76 **** // // assert(current() != x); // if (current != x {error("expected an x"); // // where x is some character constant. ! // The assertion inidcates, that, as currently written, ! // the code should nver reach this point unless the input is an // x. On the other hand, the test is there to check the legality // of the input wrt to a given production. It may be that at a later // time the code might be called directly, and if the input is // invalid, the parser should flag an error in accordance // with its logic. private char[] input; // the input signature private int index = 0; // index into the input ! // used to mark end of input private static final char EOI = ':'; private static final boolean DEBUG = false; // private constructor - enforces use of static factory private SignatureParser(){} --- 54,74 ---- // // assert(current() != x); // if (current != x {error("expected an x"); // // where x is some character constant. ! // The assertion indicates, that, as currently written, ! // the code should never reach this point unless the input is an // x. On the other hand, the test is there to check the legality // of the input wrt to a given production. It may be that at a later // time the code might be called directly, and if the input is // invalid, the parser should flag an error in accordance // with its logic. private char[] input; // the input signature private int index = 0; // index into the input ! // used to mark end of input private static final char EOI = ':'; private static final boolean DEBUG = false; // private constructor - enforces use of static factory private SignatureParser(){}
*** 102,111 **** --- 100,114 ---- private void advance(){ assert(index <= input.length); index++; } + // For debugging, prints current character to the end of the input. + private String remainder() { + return new String(input, index, input.length-index); + } + // Match c against a "set" of characters private boolean matches(char c, char... set) { for (char e : set) { if (c == e) return true; }
*** 115,126 **** // Error handling routine. Encapsulates error handling. // Takes a string error message as argument. // Currently throws a GenericSignatureFormatError. private Error error(String errorMsg) { ! if (DEBUG) System.out.println("Parse error:" + errorMsg); ! return new GenericSignatureFormatError(); } /** * Static factory method. Produces a parser instance. * @return an instance of <tt>SignatureParser</tt> --- 118,138 ---- // Error handling routine. Encapsulates error handling. // Takes a string error message as argument. // Currently throws a GenericSignatureFormatError. private Error error(String errorMsg) { ! return new GenericSignatureFormatError("Signature Parse error: " + errorMsg + ! "\n\tRemaining input: " + remainder()); ! } ! ! /** ! * Verify the parse has made forward progress; throw an exception ! * if no progress. ! */ ! private void progress(int startingPosition) { ! if (index <= startingPosition) ! throw error("Failure to make progress!"); } /** * Static factory method. Produces a parser instance. * @return an instance of <tt>SignatureParser</tt>
*** 161,170 **** --- 173,183 ---- /** * Parses a type signature * and produces an abstract syntax tree representing it. + * * @param s a string representing the input type signature * @return An abstract syntax tree for a type signature * corresponding to the input string * @throws GenericSignatureFormatError if the input is not a valid * type signature
*** 181,222 **** // The convention is that when a parsing routine is invoked // it expects the current input to be the first character it should parse // and when it completes parsing, it leaves the input at the first // character after the input parses. ! // parse a class signature based on the implicit input. private ClassSignature parseClassSignature() { assert(index == 0); return ClassSignature.make(parseZeroOrMoreFormalTypeParameters(), ! parseClassTypeSignature(), parseSuperInterfaces()); } private FormalTypeParameter[] parseZeroOrMoreFormalTypeParameters(){ ! if (current() == '<') { return parseFormalTypeParameters();} ! else {return new FormalTypeParameter[0];} } ! private FormalTypeParameter[] parseFormalTypeParameters(){ ! Collection<FormalTypeParameter> ftps = ! new ArrayList<FormalTypeParameter>(3); assert(current() == '<'); // should not have been called at all ! if (current() != '<') { throw error("expected <");} advance(); ftps.add(parseFormalTypeParameter()); while (current() != '>') { ftps.add(parseFormalTypeParameter()); } advance(); ! FormalTypeParameter[] ftpa = new FormalTypeParameter[ftps.size()]; ! return ftps.toArray(ftpa); } private FormalTypeParameter parseFormalTypeParameter(){ String id = parseIdentifier(); ! FieldTypeSignature[] bs = parseZeroOrMoreBounds(); return FormalTypeParameter.make(id, bs); } private String parseIdentifier(){ StringBuilder result = new StringBuilder(); --- 194,255 ---- // The convention is that when a parsing routine is invoked // it expects the current input to be the first character it should parse // and when it completes parsing, it leaves the input at the first // character after the input parses. ! /* ! * Note on grammar conventions: a trailing "*" matches zero or ! * more occurrences, a trailing "+" matches one or more occurrences, ! * "_opt" indicates an optional component. ! */ ! ! /** ! * ClassSignature: ! * FormalTypeParameters_opt SuperclassSignature SuperinterfaceSignature* ! */ private ClassSignature parseClassSignature() { + // parse a class signature based on the implicit input. assert(index == 0); return ClassSignature.make(parseZeroOrMoreFormalTypeParameters(), ! parseClassTypeSignature(), // Only rule for SuperclassSignature parseSuperInterfaces()); } private FormalTypeParameter[] parseZeroOrMoreFormalTypeParameters(){ ! if (current() == '<') { ! return parseFormalTypeParameters(); ! } else { ! return new FormalTypeParameter[0]; ! } } ! /** ! * FormalTypeParameters: ! * "<" FormalTypeParameter+ ">" ! */ private FormalTypeParameter[] parseFormalTypeParameters(){ ! List<FormalTypeParameter> ftps = new ArrayList<>(3); assert(current() == '<'); // should not have been called at all ! if (current() != '<') { throw error("expected '<'");} advance(); ftps.add(parseFormalTypeParameter()); while (current() != '>') { + int startingPosition = index; ftps.add(parseFormalTypeParameter()); + progress(startingPosition); } advance(); ! return ftps.toArray(new FormalTypeParameter[ftps.size()]); } + /** + * FormalTypeParameter: + * Identifier ClassBound InterfaceBound* + */ private FormalTypeParameter parseFormalTypeParameter(){ String id = parseIdentifier(); ! FieldTypeSignature[] bs = parseBounds(); return FormalTypeParameter.make(id, bs); } private String parseIdentifier(){ StringBuilder result = new StringBuilder();
*** 227,316 **** case '.': case '/': case '[': case ':': case '>': ! case '<': return result.toString(); default:{ result.append(c); advance(); } } } return result.toString(); } ! private FieldTypeSignature parseFieldTypeSignature() { switch(current()) { case 'L': return parseClassTypeSignature(); case 'T': return parseTypeVariableSignature(); case '[': return parseArrayTypeSignature(); default: throw error("Expected Field Type Signature"); } } private ClassTypeSignature parseClassTypeSignature(){ assert(current() == 'L'); if (current() != 'L') { throw error("expected a class type");} advance(); ! List<SimpleClassTypeSignature> scts = ! new ArrayList<SimpleClassTypeSignature>(5); ! scts.add(parseSimpleClassTypeSignature(false)); parseClassTypeSignatureSuffix(scts); if (current() != ';') throw error("expected ';' got '" + current() + "'"); advance(); return ClassTypeSignature.make(scts); } private SimpleClassTypeSignature parseSimpleClassTypeSignature(boolean dollar){ String id = parseIdentifier(); char c = current(); switch (c) { case ';': ! case '/': return SimpleClassTypeSignature.make(id, dollar, new TypeArgument[0]) ; ! case '<': { return SimpleClassTypeSignature.make(id, dollar, parseTypeArguments()); ! } ! default: {throw error("expected < or ; or /");} } } private void parseClassTypeSignatureSuffix(List<SimpleClassTypeSignature> scts) { ! while (current() == '/' || current() == '.') { ! boolean dollar = (current() == '.'); advance(); ! scts.add(parseSimpleClassTypeSignature(dollar)); } } private TypeArgument[] parseTypeArgumentsOpt() { if (current() == '<') {return parseTypeArguments();} else {return new TypeArgument[0];} } private TypeArgument[] parseTypeArguments() { ! Collection<TypeArgument> tas = new ArrayList<TypeArgument>(3); assert(current() == '<'); ! if (current() != '<') { throw error("expected <");} advance(); tas.add(parseTypeArgument()); while (current() != '>') { //(matches(current(), '+', '-', 'L', '[', 'T', '*')) { tas.add(parseTypeArgument()); } advance(); ! TypeArgument[] taa = new TypeArgument[tas.size()]; ! return tas.toArray(taa); } private TypeArgument parseTypeArgument() { FieldTypeSignature[] ub, lb; ub = new FieldTypeSignature[1]; lb = new FieldTypeSignature[1]; TypeArgument[] ta = new TypeArgument[0]; --- 260,414 ---- case '.': case '/': case '[': case ':': case '>': ! case '<': ! return result.toString(); default:{ result.append(c); advance(); } } } return result.toString(); } ! /** ! * FieldTypeSignature: ! * ClassTypeSignature ! * ArrayTypeSignature ! * TypeVariableSignature ! */ private FieldTypeSignature parseFieldTypeSignature() { + return parseFieldTypeSignature(true); + } + + private FieldTypeSignature parseFieldTypeSignature(boolean allowArrays) { switch(current()) { case 'L': return parseClassTypeSignature(); case 'T': return parseTypeVariableSignature(); case '[': + if (allowArrays) return parseArrayTypeSignature(); + else + throw error("Array signature not allowed here."); default: throw error("Expected Field Type Signature"); } } + /** + * ClassTypeSignature: + * "L" PackageSpecifier_opt SimpleClassTypeSignature ClassTypeSignatureSuffix* ";" + */ private ClassTypeSignature parseClassTypeSignature(){ assert(current() == 'L'); if (current() != 'L') { throw error("expected a class type");} advance(); ! List<SimpleClassTypeSignature> scts = new ArrayList<>(5); ! scts.add(parsePackageNameAndSimpleClassTypeSignature()); ! parseClassTypeSignatureSuffix(scts); if (current() != ';') throw error("expected ';' got '" + current() + "'"); advance(); return ClassTypeSignature.make(scts); } + /** + * PackageSpecifier: + * Identifier "/" PackageSpecifier* + */ + private SimpleClassTypeSignature parsePackageNameAndSimpleClassTypeSignature() { + // Parse both any optional leading PackageSpecifier as well as + // the following SimpleClassTypeSignature. + + String id = parseIdentifier(); + + if (current() == '/') { // package name + StringBuilder idBuild = new StringBuilder(id); + + while(current() == '/') { + advance(); + idBuild.append("."); + idBuild.append(parseIdentifier()); + } + id = idBuild.toString(); + } + + switch (current()) { + case ';': + return SimpleClassTypeSignature.make(id, false, new TypeArgument[0]); // all done! + case '<': + if (DEBUG) System.out.println("\t remainder: " + remainder()); + return SimpleClassTypeSignature.make(id, false, parseTypeArguments()); + default: + throw error("expected '<' or ';' but got " + current()); + } + } + + /** + * SimpleClassTypeSignature: + * Identifier TypeArguments_opt + */ private SimpleClassTypeSignature parseSimpleClassTypeSignature(boolean dollar){ String id = parseIdentifier(); char c = current(); + switch (c) { case ';': ! case '.': return SimpleClassTypeSignature.make(id, dollar, new TypeArgument[0]) ; ! case '<': return SimpleClassTypeSignature.make(id, dollar, parseTypeArguments()); ! default: ! throw error("expected '<' or ';' or '.', got '" + c + "'."); } } + /** + * ClassTypeSignatureSuffix: + * "." SimpleClassTypeSignature + */ private void parseClassTypeSignatureSuffix(List<SimpleClassTypeSignature> scts) { ! while (current() == '.') { advance(); ! scts.add(parseSimpleClassTypeSignature(true)); } } private TypeArgument[] parseTypeArgumentsOpt() { if (current() == '<') {return parseTypeArguments();} else {return new TypeArgument[0];} } + /** + * TypeArguments: + * "<" TypeArgument+ ">" + */ private TypeArgument[] parseTypeArguments() { ! List<TypeArgument> tas = new ArrayList<>(3); assert(current() == '<'); ! if (current() != '<') { throw error("expected '<'");} advance(); tas.add(parseTypeArgument()); while (current() != '>') { //(matches(current(), '+', '-', 'L', '[', 'T', '*')) { tas.add(parseTypeArgument()); } advance(); ! return tas.toArray(new TypeArgument[tas.size()]); } + /** + * TypeArgument: + * WildcardIndicator_opt FieldTypeSignature + * "*" + */ private TypeArgument parseTypeArgument() { FieldTypeSignature[] ub, lb; ub = new FieldTypeSignature[1]; lb = new FieldTypeSignature[1]; TypeArgument[] ta = new TypeArgument[0];
*** 332,382 **** advance(); lb[0] = parseFieldTypeSignature(); ub[0] = SimpleClassTypeSignature.make("java.lang.Object", false, ta); return Wildcard.make(ub, lb); } ! default: return parseFieldTypeSignature(); } } ! // TypeVariableSignature -> T identifier ! ! private TypeVariableSignature parseTypeVariableSignature(){ assert(current() == 'T'); if (current() != 'T') { throw error("expected a type variable usage");} advance(); ! TypeVariableSignature ts = ! TypeVariableSignature.make(parseIdentifier()); if (current() != ';') { throw error("; expected in signature of type variable named" + ts.getIdentifier()); } advance(); return ts; } ! // ArrayTypeSignature -> [ TypeSignature ! private ArrayTypeSignature parseArrayTypeSignature() { if (current() != '[') {throw error("expected array type signature");} advance(); return ArrayTypeSignature.make(parseTypeSignature()); } ! // TypeSignature -> BaseType | FieldTypeSignature ! private TypeSignature parseTypeSignature() { switch (current()) { case 'B': case 'C': case 'D': case 'F': case 'I': case 'J': case 'S': ! case 'Z':return parseBaseType(); ! default: return parseFieldTypeSignature(); } } private BaseType parseBaseType() { switch(current()) { --- 430,490 ---- advance(); lb[0] = parseFieldTypeSignature(); ub[0] = SimpleClassTypeSignature.make("java.lang.Object", false, ta); return Wildcard.make(ub, lb); } ! default: ! return parseFieldTypeSignature(); } } ! /** ! * TypeVariableSignature: ! * "T" Identifier ";" ! */ ! private TypeVariableSignature parseTypeVariableSignature() { assert(current() == 'T'); if (current() != 'T') { throw error("expected a type variable usage");} advance(); ! TypeVariableSignature ts = TypeVariableSignature.make(parseIdentifier()); if (current() != ';') { throw error("; expected in signature of type variable named" + ts.getIdentifier()); } advance(); return ts; } ! /** ! * ArrayTypeSignature: ! * "[" TypeSignature ! */ private ArrayTypeSignature parseArrayTypeSignature() { if (current() != '[') {throw error("expected array type signature");} advance(); return ArrayTypeSignature.make(parseTypeSignature()); } ! /** ! * TypeSignature: ! * FieldTypeSignature ! * BaseType ! */ private TypeSignature parseTypeSignature() { switch (current()) { case 'B': case 'C': case 'D': case 'F': case 'I': case 'J': case 'S': ! case 'Z': ! return parseBaseType(); ! ! default: ! return parseFieldTypeSignature(); } } private BaseType parseBaseType() { switch(current()) {
*** 409,421 **** throw error("expected primitive type"); } } } ! private FieldTypeSignature[] parseZeroOrMoreBounds() { ! Collection<FieldTypeSignature> fts = ! new ArrayList<FieldTypeSignature>(3); if (current() == ':') { advance(); switch(current()) { case ':': // empty class bound --- 517,535 ---- throw error("expected primitive type"); } } } ! /** ! * ClassBound: ! * ":" FieldTypeSignature_opt ! * ! * InterfaceBound: ! * ":" FieldTypeSignature ! */ ! private FieldTypeSignature[] parseBounds() { ! List<FieldTypeSignature> fts = new ArrayList<>(3); if (current() == ':') { advance(); switch(current()) { case ':': // empty class bound
*** 428,477 **** // zero or more interface bounds while (current() == ':') { advance(); fts.add(parseFieldTypeSignature()); } ! } ! FieldTypeSignature[] fta = new FieldTypeSignature[fts.size()]; ! return fts.toArray(fta); } private ClassTypeSignature[] parseSuperInterfaces() { ! Collection<ClassTypeSignature> cts = ! new ArrayList<ClassTypeSignature>(5); while(current() == 'L') { cts.add(parseClassTypeSignature()); } ! ClassTypeSignature[] cta = new ClassTypeSignature[cts.size()]; ! return cts.toArray(cta); } ! // parse a method signature based on the implicit input. private MethodTypeSignature parseMethodTypeSignature() { FieldTypeSignature[] ets; assert(index == 0); return MethodTypeSignature.make(parseZeroOrMoreFormalTypeParameters(), parseFormalParameters(), parseReturnType(), parseZeroOrMoreThrowsSignatures()); } ! // (TypeSignature*) private TypeSignature[] parseFormalParameters() { ! if (current() != '(') {throw error("expected (");} advance(); TypeSignature[] pts = parseZeroOrMoreTypeSignatures(); ! if (current() != ')') {throw error("expected )");} advance(); return pts; } // TypeSignature* private TypeSignature[] parseZeroOrMoreTypeSignatures() { ! Collection<TypeSignature> ts = new ArrayList<TypeSignature>(); boolean stop = false; while (!stop) { switch(current()) { case 'B': case 'C': --- 542,598 ---- // zero or more interface bounds while (current() == ':') { advance(); fts.add(parseFieldTypeSignature()); } ! } else ! error("Bound expected"); ! return fts.toArray(new FieldTypeSignature[fts.size()]); } + /** + * SuperclassSignature: + * ClassTypeSignature + */ private ClassTypeSignature[] parseSuperInterfaces() { ! List<ClassTypeSignature> cts = new ArrayList<>(5); while(current() == 'L') { cts.add(parseClassTypeSignature()); } ! return cts.toArray(new ClassTypeSignature[cts.size()]); } ! ! /** ! * MethodTypeSignature: ! * FormalTypeParameters_opt "(" TypeSignature* ")" ReturnType ThrowsSignature* ! */ private MethodTypeSignature parseMethodTypeSignature() { + // Parse a method signature based on the implicit input. FieldTypeSignature[] ets; assert(index == 0); return MethodTypeSignature.make(parseZeroOrMoreFormalTypeParameters(), parseFormalParameters(), parseReturnType(), parseZeroOrMoreThrowsSignatures()); } ! // "(" TypeSignature* ")" private TypeSignature[] parseFormalParameters() { ! if (current() != '(') {throw error("expected '('");} advance(); TypeSignature[] pts = parseZeroOrMoreTypeSignatures(); ! if (current() != ')') {throw error("expected ')'");} advance(); return pts; } // TypeSignature* private TypeSignature[] parseZeroOrMoreTypeSignatures() { ! List<TypeSignature> ts = new ArrayList<>(); boolean stop = false; while (!stop) { switch(current()) { case 'B': case 'C':
*** 488,530 **** break; } default: stop = true; } } ! /* while( matches(current(), ! 'B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z', 'L', 'T', '[') ! ) { ! ts.add(parseTypeSignature()); ! }*/ ! TypeSignature[] ta = new TypeSignature[ts.size()]; ! return ts.toArray(ta); } ! // ReturnType -> V | TypeSignature ! private ReturnType parseReturnType(){ if (current() == 'V') { advance(); return VoidDescriptor.make(); ! } else return parseTypeSignature(); } // ThrowSignature* private FieldTypeSignature[] parseZeroOrMoreThrowsSignatures(){ ! Collection<FieldTypeSignature> ets = ! new ArrayList<FieldTypeSignature>(3); while( current() == '^') { ets.add(parseThrowsSignature()); } ! FieldTypeSignature[] eta = new FieldTypeSignature[ets.size()]; ! return ets.toArray(eta); } ! // ThrowSignature -> ^ FieldTypeSignature ! private FieldTypeSignature parseThrowsSignature() { assert(current() == '^'); if (current() != '^') { throw error("expected throws signature");} advance(); ! return parseFieldTypeSignature(); } } --- 609,650 ---- break; } default: stop = true; } } ! return ts.toArray(new TypeSignature[ts.size()]); } ! /** ! * ReturnType: ! * TypeSignature ! * VoidDescriptor ! */ private ReturnType parseReturnType(){ if (current() == 'V') { advance(); return VoidDescriptor.make(); ! } else ! return parseTypeSignature(); } // ThrowSignature* private FieldTypeSignature[] parseZeroOrMoreThrowsSignatures(){ ! List<FieldTypeSignature> ets = new ArrayList<>(3); while( current() == '^') { ets.add(parseThrowsSignature()); } ! return ets.toArray(new FieldTypeSignature[ets.size()]); } ! /** ! * ThrowsSignature: ! * "^" ClassTypeSignature ! * "^" TypeVariableSignature ! */ private FieldTypeSignature parseThrowsSignature() { assert(current() == '^'); if (current() != '^') { throw error("expected throws signature");} advance(); ! return parseFieldTypeSignature(false); } }