Path: blob/master/src/java.base/share/classes/sun/reflect/generics/parser/SignatureParser.java
41161 views
/*1* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.reflect.generics.parser;2627import java.lang.reflect.GenericSignatureFormatError;28import java.util.*;29import sun.reflect.generics.tree.*;3031/**32* Parser for type signatures, as defined in the Java Virtual33* Machine Specification (JVMS) chapter 4.34* Converts the signatures into an abstract syntax tree (AST) representation.35* See the package sun.reflect.generics.tree for details of the AST.36*/37public class SignatureParser {38// The input is conceptually a character stream (though currently it's39// a string). This is slightly different than traditional parsers,40// because there is no lexical scanner performing tokenization.41// Having a separate tokenizer does not fit with the nature of the42// input format.43// Other than the absence of a tokenizer, this parser is a classic44// recursive descent parser. Its structure corresponds as closely45// as possible to the grammar in the JVMS.46//47// A note on asserts vs. errors: The code contains assertions48// in situations that should never occur. An assertion failure49// indicates a failure of the parser logic. A common pattern50// is an assertion that the current input is a particular51// character. This is often paired with a separate check52// that this is the case, which seems redundant. For example:53//54// assert(current() != x);55// if (current != x {error("expected an x");56//57// where x is some character constant.58// The assertion indicates, that, as currently written,59// the code should never reach this point unless the input is an60// x. On the other hand, the test is there to check the legality61// of the input wrt to a given production. It may be that at a later62// time the code might be called directly, and if the input is63// invalid, the parser should flag an error in accordance64// with its logic.6566private String input; // the input signature67private int index; // index into the input68private int mark; // index of mark69// used to mark end of input70private static final char EOI = ':';71private static final boolean DEBUG = false;7273// private constructor - enforces use of static factory74private SignatureParser(){}7576// prepares parser for new parsing session77private void init(String s) {78input = s;79mark = index = 0;80}8182// Utility methods.8384// Most parsing routines use the following routines to access the85// input stream, and advance it as necessary.86// This makes it easy to adapt the parser to operate on streams87// of various kinds as well as strings.8889// returns current element of the input90private char current(){91assert(index <= input.length());92return index < input.length() ? input.charAt(index) : EOI;93}9495// advance the input96private void advance(){97assert(index <= input.length());98if (index < input.length()) index++;99}100101// mark current position102private void mark() {103mark = index;104}105106// For debugging, prints current character to the end of the input.107private String remainder() {108return input.substring(index);109}110111// returns a substring of input from mark (inclusive)112// to current position (exclusive)113private String markToCurrent() {114return input.substring(mark, index);115}116117// Error handling routine. Encapsulates error handling.118// Takes a string error message as argument.119// Currently throws a GenericSignatureFormatError.120121private Error error(String errorMsg) {122return new GenericSignatureFormatError("Signature Parse error: " + errorMsg +123"\n\tRemaining input: " + remainder());124}125126/**127* Verify the parse has made forward progress; throw an exception128* if no progress.129*/130private void progress(int startingPosition) {131if (index <= startingPosition)132throw error("Failure to make progress!");133}134135/**136* Static factory method. Produces a parser instance.137* @return an instance of {@code SignatureParser}138*/139public static SignatureParser make() {140return new SignatureParser();141}142143/**144* Parses a class signature (as defined in the JVMS, chapter 4)145* and produces an abstract syntax tree representing it.146* @param s a string representing the input class signature147* @return An abstract syntax tree for a class signature148* corresponding to the input string149* @throws GenericSignatureFormatError if the input is not a valid150* class signature151*/152public ClassSignature parseClassSig(String s) {153if (DEBUG) System.out.println("Parsing class sig:" + s);154init(s);155return parseClassSignature();156}157158/**159* Parses a method signature (as defined in the JVMS, chapter 4)160* and produces an abstract syntax tree representing it.161* @param s a string representing the input method signature162* @return An abstract syntax tree for a method signature163* corresponding to the input string164* @throws GenericSignatureFormatError if the input is not a valid165* method signature166*/167public MethodTypeSignature parseMethodSig(String s) {168if (DEBUG) System.out.println("Parsing method sig:" + s);169init(s);170return parseMethodTypeSignature();171}172173174/**175* Parses a type signature176* and produces an abstract syntax tree representing it.177*178* @param s a string representing the input type signature179* @return An abstract syntax tree for a type signature180* corresponding to the input string181* @throws GenericSignatureFormatError if the input is not a valid182* type signature183*/184public TypeSignature parseTypeSig(String s) {185if (DEBUG) System.out.println("Parsing type sig:" + s);186init(s);187return parseTypeSignature();188}189190// Parsing routines.191// As a rule, the parsing routines access the input using the192// utilities current() and advance().193// The convention is that when a parsing routine is invoked194// it expects the current input to be the first character it should parse195// and when it completes parsing, it leaves the input at the first196// character after the input parses.197198/*199* Note on grammar conventions: a trailing "*" matches zero or200* more occurrences, a trailing "+" matches one or more occurrences,201* "_opt" indicates an optional component.202*/203204/**205* ClassSignature:206* FormalTypeParameters_opt SuperclassSignature SuperinterfaceSignature*207*/208private ClassSignature parseClassSignature() {209// parse a class signature based on the implicit input.210assert(index == 0);211return ClassSignature.make(parseZeroOrMoreFormalTypeParameters(),212parseClassTypeSignature(), // Only rule for SuperclassSignature213parseSuperInterfaces());214}215216private FormalTypeParameter[] parseZeroOrMoreFormalTypeParameters(){217if (current() == '<') {218return parseFormalTypeParameters();219} else {220return new FormalTypeParameter[0];221}222}223224/**225* FormalTypeParameters:226* "<" FormalTypeParameter+ ">"227*/228private FormalTypeParameter[] parseFormalTypeParameters(){229List<FormalTypeParameter> ftps = new ArrayList<>(3);230assert(current() == '<'); // should not have been called at all231if (current() != '<') { throw error("expected '<'");}232advance();233ftps.add(parseFormalTypeParameter());234while (current() != '>') {235int startingPosition = index;236ftps.add(parseFormalTypeParameter());237progress(startingPosition);238}239advance();240return ftps.toArray(new FormalTypeParameter[ftps.size()]);241}242243/**244* FormalTypeParameter:245* Identifier ClassBound InterfaceBound*246*/247private FormalTypeParameter parseFormalTypeParameter(){248String id = parseIdentifier();249FieldTypeSignature[] bs = parseBounds();250return FormalTypeParameter.make(id, bs);251}252253private String parseIdentifier() {254mark();255skipIdentifier();256return markToCurrent();257}258259private void skipIdentifier() {260char c = current();261while (c != ';' && c != '.' && c != '/' &&262c != '[' && c != ':' && c != '>' &&263c != '<' && !Character.isWhitespace(c)) {264advance();265c = current();266}267}268269/**270* FieldTypeSignature:271* ClassTypeSignature272* ArrayTypeSignature273* TypeVariableSignature274*/275private FieldTypeSignature parseFieldTypeSignature() {276return parseFieldTypeSignature(true);277}278279private FieldTypeSignature parseFieldTypeSignature(boolean allowArrays) {280switch(current()) {281case 'L':282return parseClassTypeSignature();283case 'T':284return parseTypeVariableSignature();285case '[':286if (allowArrays)287return parseArrayTypeSignature();288else289throw error("Array signature not allowed here.");290default: throw error("Expected Field Type Signature");291}292}293294/**295* ClassTypeSignature:296* "L" PackageSpecifier_opt SimpleClassTypeSignature ClassTypeSignatureSuffix* ";"297*/298private ClassTypeSignature parseClassTypeSignature(){299assert(current() == 'L');300if (current() != 'L') { throw error("expected a class type");}301advance();302List<SimpleClassTypeSignature> scts = new ArrayList<>(5);303scts.add(parsePackageNameAndSimpleClassTypeSignature());304305parseClassTypeSignatureSuffix(scts);306if (current() != ';')307throw error("expected ';' got '" + current() + "'");308309advance();310return ClassTypeSignature.make(scts);311}312313/**314* PackageSpecifier:315* Identifier "/" PackageSpecifier*316*/317private SimpleClassTypeSignature parsePackageNameAndSimpleClassTypeSignature() {318// Parse both any optional leading PackageSpecifier as well as319// the following SimpleClassTypeSignature.320321mark();322skipIdentifier();323while (current() == '/') {324advance();325skipIdentifier();326}327String id = markToCurrent().replace('/', '.');328329switch (current()) {330case ';':331return SimpleClassTypeSignature.make(id, false, new TypeArgument[0]); // all done!332case '<':333if (DEBUG) System.out.println("\t remainder: " + remainder());334return SimpleClassTypeSignature.make(id, false, parseTypeArguments());335default:336throw error("expected '<' or ';' but got " + current());337}338}339340/**341* SimpleClassTypeSignature:342* Identifier TypeArguments_opt343*/344private SimpleClassTypeSignature parseSimpleClassTypeSignature(boolean dollar){345String id = parseIdentifier();346char c = current();347348switch (c) {349case ';':350case '.':351return SimpleClassTypeSignature.make(id, dollar, new TypeArgument[0]) ;352case '<':353return SimpleClassTypeSignature.make(id, dollar, parseTypeArguments());354default:355throw error("expected '<' or ';' or '.', got '" + c + "'.");356}357}358359/**360* ClassTypeSignatureSuffix:361* "." SimpleClassTypeSignature362*/363private void parseClassTypeSignatureSuffix(List<SimpleClassTypeSignature> scts) {364while (current() == '.') {365advance();366scts.add(parseSimpleClassTypeSignature(true));367}368}369370/**371* TypeArguments:372* "<" TypeArgument+ ">"373*/374private TypeArgument[] parseTypeArguments() {375List<TypeArgument> tas = new ArrayList<>(3);376assert(current() == '<');377if (current() != '<') { throw error("expected '<'");}378advance();379tas.add(parseTypeArgument());380while (current() != '>') {381//(matches(current(), '+', '-', 'L', '[', 'T', '*')) {382tas.add(parseTypeArgument());383}384advance();385return tas.toArray(new TypeArgument[tas.size()]);386}387388/**389* TypeArgument:390* WildcardIndicator_opt FieldTypeSignature391* "*"392*/393private TypeArgument parseTypeArgument() {394FieldTypeSignature[] ub, lb;395ub = new FieldTypeSignature[1];396lb = new FieldTypeSignature[1];397TypeArgument[] ta = new TypeArgument[0];398char c = current();399switch (c) {400case '+': {401advance();402ub[0] = parseFieldTypeSignature();403lb[0] = BottomSignature.make(); // bottom404return Wildcard.make(ub, lb);405}406case '*':{407advance();408ub[0] = SimpleClassTypeSignature.make("java.lang.Object", false, ta);409lb[0] = BottomSignature.make(); // bottom410return Wildcard.make(ub, lb);411}412case '-': {413advance();414lb[0] = parseFieldTypeSignature();415ub[0] = SimpleClassTypeSignature.make("java.lang.Object", false, ta);416return Wildcard.make(ub, lb);417}418default:419return parseFieldTypeSignature();420}421}422423/**424* TypeVariableSignature:425* "T" Identifier ";"426*/427private TypeVariableSignature parseTypeVariableSignature() {428assert(current() == 'T');429if (current() != 'T') { throw error("expected a type variable usage");}430advance();431TypeVariableSignature ts = TypeVariableSignature.make(parseIdentifier());432if (current() != ';') {433throw error("; expected in signature of type variable named" +434ts.getIdentifier());435}436advance();437return ts;438}439440/**441* ArrayTypeSignature:442* "[" TypeSignature443*/444private ArrayTypeSignature parseArrayTypeSignature() {445if (current() != '[') {throw error("expected array type signature");}446advance();447return ArrayTypeSignature.make(parseTypeSignature());448}449450/**451* TypeSignature:452* FieldTypeSignature453* BaseType454*/455private TypeSignature parseTypeSignature() {456switch (current()) {457case 'B':458case 'C':459case 'D':460case 'F':461case 'I':462case 'J':463case 'S':464case 'Z':465return parseBaseType();466467default:468return parseFieldTypeSignature();469}470}471472private BaseType parseBaseType() {473switch(current()) {474case 'B':475advance();476return ByteSignature.make();477case 'C':478advance();479return CharSignature.make();480case 'D':481advance();482return DoubleSignature.make();483case 'F':484advance();485return FloatSignature.make();486case 'I':487advance();488return IntSignature.make();489case 'J':490advance();491return LongSignature.make();492case 'S':493advance();494return ShortSignature.make();495case 'Z':496advance();497return BooleanSignature.make();498default: {499assert(false);500throw error("expected primitive type");501}502}503}504505/**506* ClassBound:507* ":" FieldTypeSignature_opt508*509* InterfaceBound:510* ":" FieldTypeSignature511*/512private FieldTypeSignature[] parseBounds() {513List<FieldTypeSignature> fts = new ArrayList<>(3);514515if (current() == ':') {516advance();517switch(current()) {518case ':': // empty class bound519break;520521default: // parse class bound522fts.add(parseFieldTypeSignature());523}524525// zero or more interface bounds526while (current() == ':') {527advance();528fts.add(parseFieldTypeSignature());529}530} else531error("Bound expected");532533return fts.toArray(new FieldTypeSignature[fts.size()]);534}535536/**537* SuperclassSignature:538* ClassTypeSignature539*/540private ClassTypeSignature[] parseSuperInterfaces() {541List<ClassTypeSignature> cts = new ArrayList<>(5);542while(current() == 'L') {543cts.add(parseClassTypeSignature());544}545return cts.toArray(new ClassTypeSignature[cts.size()]);546}547548549/**550* MethodTypeSignature:551* FormalTypeParameters_opt "(" TypeSignature* ")" ReturnType ThrowsSignature*552*/553private MethodTypeSignature parseMethodTypeSignature() {554// Parse a method signature based on the implicit input.555FieldTypeSignature[] ets;556557assert(index == 0);558return MethodTypeSignature.make(parseZeroOrMoreFormalTypeParameters(),559parseFormalParameters(),560parseReturnType(),561parseZeroOrMoreThrowsSignatures());562}563564// "(" TypeSignature* ")"565private TypeSignature[] parseFormalParameters() {566if (current() != '(') {throw error("expected '('");}567advance();568TypeSignature[] pts = parseZeroOrMoreTypeSignatures();569if (current() != ')') {throw error("expected ')'");}570advance();571return pts;572}573574// TypeSignature*575private TypeSignature[] parseZeroOrMoreTypeSignatures() {576List<TypeSignature> ts = new ArrayList<>();577boolean stop = false;578while (!stop) {579switch(current()) {580case 'B':581case 'C':582case 'D':583case 'F':584case 'I':585case 'J':586case 'S':587case 'Z':588case 'L':589case 'T':590case '[': {591ts.add(parseTypeSignature());592break;593}594default: stop = true;595}596}597return ts.toArray(new TypeSignature[ts.size()]);598}599600/**601* ReturnType:602* TypeSignature603* VoidDescriptor604*/605private ReturnType parseReturnType(){606if (current() == 'V') {607advance();608return VoidDescriptor.make();609} else610return parseTypeSignature();611}612613// ThrowSignature*614private FieldTypeSignature[] parseZeroOrMoreThrowsSignatures(){615List<FieldTypeSignature> ets = new ArrayList<>(3);616while( current() == '^') {617ets.add(parseThrowsSignature());618}619return ets.toArray(new FieldTypeSignature[ets.size()]);620}621622/**623* ThrowsSignature:624* "^" ClassTypeSignature625* "^" TypeVariableSignature626*/627private FieldTypeSignature parseThrowsSignature() {628assert(current() == '^');629if (current() != '^') { throw error("expected throws signature");}630advance();631return parseFieldTypeSignature(false);632}633}634635636