src/share/classes/sun/reflect/generics/parser/SignatureParser.java
Print this page
@@ -1,7 +1,7 @@
/*
- * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+ * 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,21 +23,19 @@
* 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.
+ * 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.
+ * 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,21 +54,21 @@
//
// 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
+ // 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
+ // 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,10 +100,15 @@
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,15 +118,26 @@
// 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);
+ if (DEBUG)
+ System.out.println("Signature Parse error: " + errorMsg +
+ "\n\tRemaining input: " + remainder());
return new GenericSignatureFormatError();
}
/**
+ * 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>
*/
public static SignatureParser make() {
return new SignatureParser();
@@ -161,10 +175,11 @@
/**
* 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,42 +196,62 @@
// 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.
+ /*
+ * 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(),
+ parseClassTypeSignature(), // Only rule for SuperclassSignature
parseSuperInterfaces());
}
private FormalTypeParameter[] parseZeroOrMoreFormalTypeParameters(){
- if (current() == '<') { return parseFormalTypeParameters();}
- else {return new FormalTypeParameter[0];}
+ if (current() == '<') {
+ return parseFormalTypeParameters();
+ } else {
+ return new FormalTypeParameter[0];
+ }
}
-
+ /**
+ * FormalTypeParameters:
+ * "<" FormalTypeParameter+ ">"
+ */
private FormalTypeParameter[] parseFormalTypeParameters(){
- Collection<FormalTypeParameter> ftps =
- new ArrayList<FormalTypeParameter>(3);
+ List<FormalTypeParameter> ftps = new ArrayList<>(3);
assert(current() == '<'); // should not have been called at all
- if (current() != '<') { throw error("expected <");}
+ if (current() != '<') { throw error("expected '<'");}
advance();
ftps.add(parseFormalTypeParameter());
while (current() != '>') {
+ int startingPosition = index;
ftps.add(parseFormalTypeParameter());
+ progress(startingPosition);
}
advance();
- FormalTypeParameter[] ftpa = new FormalTypeParameter[ftps.size()];
- return ftps.toArray(ftpa);
+ return ftps.toArray(new FormalTypeParameter[ftps.size()]);
}
+ /**
+ * FormalTypeParameter:
+ * Identifier ClassBound InterfaceBound*
+ */
private FormalTypeParameter parseFormalTypeParameter(){
String id = parseIdentifier();
- FieldTypeSignature[] bs = parseZeroOrMoreBounds();
+ FieldTypeSignature[] bs = parseBounds();
return FormalTypeParameter.make(id, bs);
}
private String parseIdentifier(){
StringBuilder result = new StringBuilder();
@@ -227,90 +262,155 @@
case '.':
case '/':
case '[':
case ':':
case '>':
- case '<': return result.toString();
+ 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<SimpleClassTypeSignature>(5);
- scts.add(parseSimpleClassTypeSignature(false));
+ 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 '/':
+ case '.':
return SimpleClassTypeSignature.make(id, dollar, new TypeArgument[0]) ;
- case '<': {
+ case '<':
return SimpleClassTypeSignature.make(id, dollar, parseTypeArguments());
- }
- default: {throw error("expected < or ; or /");}
+ default:
+ throw error("expected '<' or ';' or '.', got '" + c + "'.");
}
}
+ /**
+ * ClassTypeSignatureSuffix:
+ * "." SimpleClassTypeSignature
+ */
private void parseClassTypeSignatureSuffix(List<SimpleClassTypeSignature> scts) {
- while (current() == '/' || current() == '.') {
- boolean dollar = (current() == '.');
+ while (current() == '.') {
advance();
- scts.add(parseSimpleClassTypeSignature(dollar));
+ scts.add(parseSimpleClassTypeSignature(true));
}
}
private TypeArgument[] parseTypeArgumentsOpt() {
if (current() == '<') {return parseTypeArguments();}
else {return new TypeArgument[0];}
}
+ /**
+ * TypeArguments:
+ * "<" TypeArgument+ ">"
+ */
private TypeArgument[] parseTypeArguments() {
- Collection<TypeArgument> tas = new ArrayList<TypeArgument>(3);
+ List<TypeArgument> tas = new ArrayList<>(3);
assert(current() == '<');
- if (current() != '<') { throw error("expected <");}
+ 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);
+ 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,51 +432,61 @@
advance();
lb[0] = parseFieldTypeSignature();
ub[0] = SimpleClassTypeSignature.make("java.lang.Object", false, ta);
return Wildcard.make(ub, lb);
}
- default: return parseFieldTypeSignature();
+ default:
+ return parseFieldTypeSignature();
}
}
- // TypeVariableSignature -> T identifier
-
- private TypeVariableSignature parseTypeVariableSignature(){
+ /**
+ * 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());
+ TypeVariableSignature ts = TypeVariableSignature.make(parseIdentifier());
if (current() != ';') {
throw error("; expected in signature of type variable named" +
ts.getIdentifier());
}
advance();
return ts;
}
- // ArrayTypeSignature -> [ TypeSignature
-
+ /**
+ * ArrayTypeSignature:
+ * "[" TypeSignature
+ */
private ArrayTypeSignature parseArrayTypeSignature() {
if (current() != '[') {throw error("expected array type signature");}
advance();
return ArrayTypeSignature.make(parseTypeSignature());
}
- // TypeSignature -> BaseType | FieldTypeSignature
-
+ /**
+ * 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();
+ case 'Z':
+ return parseBaseType();
+
+ default:
+ return parseFieldTypeSignature();
}
}
private BaseType parseBaseType() {
switch(current()) {
@@ -409,13 +519,19 @@
throw error("expected primitive type");
}
}
}
- private FieldTypeSignature[] parseZeroOrMoreBounds() {
- Collection<FieldTypeSignature> fts =
- new ArrayList<FieldTypeSignature>(3);
+ /**
+ * ClassBound:
+ * ":" FieldTypeSignature_opt
+ *
+ * InterfaceBound:
+ * ":" FieldTypeSignature
+ */
+ private FieldTypeSignature[] parseBounds() {
+ List<FieldTypeSignature> fts = new ArrayList<>(3);
if (current() == ':') {
advance();
switch(current()) {
case ':': // empty class bound
@@ -428,50 +544,57 @@
// zero or more interface bounds
while (current() == ':') {
advance();
fts.add(parseFieldTypeSignature());
}
- }
+ } else
+ error("Bound expected");
- FieldTypeSignature[] fta = new FieldTypeSignature[fts.size()];
- return fts.toArray(fta);
+ return fts.toArray(new FieldTypeSignature[fts.size()]);
}
+ /**
+ * SuperclassSignature:
+ * ClassTypeSignature
+ */
private ClassTypeSignature[] parseSuperInterfaces() {
- Collection<ClassTypeSignature> cts =
- new ArrayList<ClassTypeSignature>(5);
+ List<ClassTypeSignature> cts = new ArrayList<>(5);
while(current() == 'L') {
cts.add(parseClassTypeSignature());
}
- ClassTypeSignature[] cta = new ClassTypeSignature[cts.size()];
- return cts.toArray(cta);
+ return cts.toArray(new ClassTypeSignature[cts.size()]);
}
- // parse a method signature based on the implicit input.
+
+ /**
+ * 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*)
+ // "(" TypeSignature* ")"
private TypeSignature[] parseFormalParameters() {
- if (current() != '(') {throw error("expected (");}
+ if (current() != '(') {throw error("expected '('");}
advance();
TypeSignature[] pts = parseZeroOrMoreTypeSignatures();
- if (current() != ')') {throw error("expected )");}
+ if (current() != ')') {throw error("expected ')'");}
advance();
return pts;
}
// TypeSignature*
private TypeSignature[] parseZeroOrMoreTypeSignatures() {
- Collection<TypeSignature> ts = new ArrayList<TypeSignature>();
+ List<TypeSignature> ts = new ArrayList<>();
boolean stop = false;
while (!stop) {
switch(current()) {
case 'B':
case 'C':
@@ -488,43 +611,42 @@
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);
+ return ts.toArray(new TypeSignature[ts.size()]);
}
- // ReturnType -> V | TypeSignature
-
+ /**
+ * ReturnType:
+ * TypeSignature
+ * VoidDescriptor
+ */
private ReturnType parseReturnType(){
if (current() == 'V') {
advance();
return VoidDescriptor.make();
- } else return parseTypeSignature();
+ } else
+ return parseTypeSignature();
}
// ThrowSignature*
private FieldTypeSignature[] parseZeroOrMoreThrowsSignatures(){
- Collection<FieldTypeSignature> ets =
- new ArrayList<FieldTypeSignature>(3);
+ List<FieldTypeSignature> ets = new ArrayList<>(3);
while( current() == '^') {
ets.add(parseThrowsSignature());
}
- FieldTypeSignature[] eta = new FieldTypeSignature[ets.size()];
- return ets.toArray(eta);
+ return ets.toArray(new FieldTypeSignature[ets.size()]);
}
- // ThrowSignature -> ^ FieldTypeSignature
-
+ /**
+ * ThrowsSignature:
+ * "^" ClassTypeSignature
+ * "^" TypeVariableSignature
+ */
private FieldTypeSignature parseThrowsSignature() {
assert(current() == '^');
if (current() != '^') { throw error("expected throws signature");}
advance();
- return parseFieldTypeSignature();
+ return parseFieldTypeSignature(false);
}
}