/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* 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.
// Having a separate tokenizer does not fit with the nature of the
// input format.
// Other than the absence of a tokenizer, this parser is a classic
// recursive descent parser. Its structure corresponds as closely
// as possible to the grammar in the JVMS.
//
// A note on asserts vs. errors: The code contains assertions
// in situations that should never occur. An assertion failure
// indicates a failure of the parser logic. A common pattern
// is an assertion that the current input is a particular
// character. This is often paired with a separate check
// that this is the case, which seems redundant. For example:
//
// 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.
// used to mark end of input
private static final boolean DEBUG = false;
// private constructor - enforces use of static factory
private SignatureParser(){}
// Utility methods.
// Most parsing routines use the following routines to access the
// input stream, and advance it as necessary.
// This makes it easy to adapt the parser to operate on streams
// of various kinds as well as strings.
// returns current element of the input and advances the input
private char getNext(){
try {
} catch (ArrayIndexOutOfBoundsException e) { return EOI;}
}
// returns current element of the input
private char current(){
try {
} catch (ArrayIndexOutOfBoundsException e) { return EOI;}
}
// advance the input
private void advance(){
index++;
}
// For debugging, prints current character to the end of the input.
}
// Match c against a "set" of characters
for (char e : set) {
if (c == e) return true;
}
return false;
}
// Error handling routine. Encapsulates error handling.
// Takes a string error message as argument.
// Currently throws a GenericSignatureFormatError.
if (DEBUG)
"\n\tRemaining input: " + remainder());
return new GenericSignatureFormatError();
}
/**
* Verify the parse has made forward progress; throw an exception
* if no progress.
*/
if (index <= startingPosition)
throw error("Failure to make progress!");
}
/**
* Static factory method. Produces a parser instance.
* @return an instance of <tt>SignatureParser</tt>
*/
return new SignatureParser();
}
/**
* Parses a class signature (as defined in the JVMS, chapter 4)
* and produces an abstract syntax tree representing it.
* @param s a string representing the input class signature
* @return An abstract syntax tree for a class signature
* corresponding to the input string
* @throws GenericSignatureFormatError if the input is not a valid
* class signature
*/
input = s.toCharArray();
return parseClassSignature();
}
/**
* Parses a method signature (as defined in the JVMS, chapter 4)
* and produces an abstract syntax tree representing it.
* @param s a string representing the input method signature
* @return An abstract syntax tree for a method signature
* corresponding to the input string
* @throws GenericSignatureFormatError if the input is not a valid
* method signature
*/
input = s.toCharArray();
return parseMethodTypeSignature();
}
/**
* 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
*/
input = s.toCharArray();
return parseTypeSignature();
}
// Parsing routines.
// As a rule, the parsing routines access the input using the
// 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*
*/
// parse a class signature based on the implicit input.
assert(index == 0);
parseClassTypeSignature(), // Only rule for SuperclassSignature
}
if (current() == '<') {
return parseFormalTypeParameters();
} else {
return new FormalTypeParameter[0];
}
}
/**
* FormalTypeParameters:
* "<" FormalTypeParameter+ ">"
*/
advance();
while (current() != '>') {
int startingPosition = index;
}
advance();
}
/**
* FormalTypeParameter:
* Identifier ClassBound InterfaceBound*
*/
}
char c = current();
switch(c) {
case ';':
case '.':
case '/':
case '[':
case ':':
case '>':
case '<':
default:{
advance();
}
}
}
}
/**
* FieldTypeSignature:
* ClassTypeSignature
* ArrayTypeSignature
* TypeVariableSignature
*/
return parseFieldTypeSignature(true);
}
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* ";"
*/
assert(current() == 'L');
advance();
if (current() != ';')
advance();
}
/**
* PackageSpecifier:
* Identifier "/" PackageSpecifier*
*/
// Parse both any optional leading PackageSpecifier as well as
// the following SimpleClassTypeSignature.
while(current() == '/') {
advance();
}
}
switch (current()) {
case ';':
case '<':
default:
}
}
/**
* SimpleClassTypeSignature:
* Identifier TypeArguments_opt
*/
char c = current();
switch (c) {
case ';':
case '.':
case '<':
default:
}
}
/**
* ClassTypeSignatureSuffix:
* "." SimpleClassTypeSignature
*/
while (current() == '.') {
advance();
}
}
else {return new TypeArgument[0];}
}
/**
* TypeArguments:
* "<" TypeArgument+ ">"
*/
assert(current() == '<');
advance();
while (current() != '>') {
//(matches(current(), '+', '-', 'L', '[', 'T', '*')) {
}
advance();
}
/**
* TypeArgument:
* WildcardIndicator_opt FieldTypeSignature
* "*"
*/
char c = current();
switch (c) {
case '+': {
advance();
}
case '*':{
advance();
}
case '-': {
advance();
}
default:
return parseFieldTypeSignature();
}
}
/**
* TypeVariableSignature:
* "T" Identifier ";"
*/
assert(current() == 'T');
advance();
if (current() != ';') {
throw error("; expected in signature of type variable named" +
ts.getIdentifier());
}
advance();
return ts;
}
/**
* ArrayTypeSignature:
* "[" TypeSignature
*/
advance();
}
/**
* TypeSignature:
* FieldTypeSignature
* BaseType
*/
switch (current()) {
case 'B':
case 'C':
case 'D':
case 'F':
case 'I':
case 'J':
case 'S':
case 'Z':
return parseBaseType();
default:
return parseFieldTypeSignature();
}
}
switch(current()) {
case 'B':
advance();
return ByteSignature.make();
case 'C':
advance();
return CharSignature.make();
case 'D':
advance();
return DoubleSignature.make();
case 'F':
advance();
return FloatSignature.make();
case 'I':
advance();
return IntSignature.make();
case 'J':
advance();
return LongSignature.make();
case 'S':
advance();
return ShortSignature.make();
case 'Z':
advance();
return BooleanSignature.make();
default: {
assert(false);
throw error("expected primitive type");
}
}
}
/**
* ClassBound:
* ":" FieldTypeSignature_opt
*
* InterfaceBound:
* ":" FieldTypeSignature
*/
if (current() == ':') {
advance();
switch(current()) {
case ':': // empty class bound
break;
default: // parse class bound
}
// zero or more interface bounds
while (current() == ':') {
advance();
}
} else
error("Bound expected");
}
/**
* SuperclassSignature:
* ClassTypeSignature
*/
while(current() == 'L') {
}
}
/**
* MethodTypeSignature:
* FormalTypeParameters_opt "(" TypeSignature* ")" ReturnType ThrowsSignature*
*/
// Parse a method signature based on the implicit input.
assert(index == 0);
}
// "(" TypeSignature* ")"
advance();
advance();
return pts;
}
// TypeSignature*
boolean stop = false;
while (!stop) {
switch(current()) {
case 'B':
case 'C':
case 'D':
case 'F':
case 'I':
case 'J':
case 'S':
case 'Z':
case 'L':
case 'T':
case '[': {
break;
}
default: stop = true;
}
}
}
/**
* ReturnType:
* TypeSignature
* VoidDescriptor
*/
if (current() == 'V') {
advance();
return VoidDescriptor.make();
} else
return parseTypeSignature();
}
// ThrowSignature*
while( current() == '^') {
}
}
/**
* ThrowsSignature:
* "^" ClassTypeSignature
* "^" TypeVariableSignature
*/
assert(current() == '^');
advance();
return parseFieldTypeSignature(false);
}
}