ParserUtils.java
/* $Id$
*****************************************************************************
* Copyright (c) 2009-2012 Contributors - see below
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* lepekhine
*****************************************************************************
*
* Some portions of this file was previously release using the BSD License:
*/
// Rights Reserved. Permission to use, copy, modify, and distribute this
// software and its documentation without fee, and without a written
// agreement is hereby granted, provided that the above copyright notice
// and this paragraph appear in all copies. This software program and
// documentation are copyrighted by The Regents of the University of
// California. The software program and documentation are supplied "AS
// IS", without any accompanying services from The Regents. The Regents
// does not warrant that the operation of the program will be
// uninterrupted or error-free. The end-user understands that the program
// was developed for research purposes and is advised not to rely
// exclusively on the program for any reason. IN NO EVENT SHALL THE
// UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
// SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
// THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
// PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
// CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
// UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
package org.argouml.language.java.reveng.classfile;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Contains methods used in Classfile.g to parse descriptors and signatures.
*
* @author Alexander Lepekhin
*/
public class ParserUtils {
/**
* Convert a classfile field descriptor.
*
* @param desc The descriptor as a string.
* @return The descriptor as it would appear in a Java sourcefile.
*/
public static String convertFieldDescriptor(String desc) {
return convertFieldDescriptor(new FieldDescriptorLexer(desc).parse());
}
/**
* Convert a method descriptor.
*
* @param desc The method descriptor as a String.
* @return The method descriptor as a array of Strings, that holds Java
* types.
*/
public static String[] convertMethodDescriptor(String desc) {
List<String> buf = new LinkedList<String>();
MethodDescriptorLexer lexer = new MethodDescriptorLexer(desc);
for (Token t : lexer.parse()) {
buf.add(t.getValue());
}
return buf.toArray(new String[] {});
}
/**
*
* Convert a field type signature.
*
* @param desc The signature as a string.
* @return The signature as it would appear in a Java sourcefile.
*/
public static String convertFieldTypeSignature(String desc) {
List<Token> lexer = new FieldTypeSignatureLexer(desc).parse();
return convertFieldTypeSignature(lexer);
}
/**
*
* Convert class type signature.
*
* @param desc The signature as a string.
* @return The signature as it would appear in a Java sourcefile.
*/
public static String convertClassTypeSignature(String desc) {
List<Token> lexer = new ClassTypeSignatureLexer(desc).parse();
return convertClassTypeSignature(lexer);
}
/**
*
* Convert class signature.
*
* @param desc The signature as a string.
* @return The signature as it would appear in a Java sourcefile.
*/
public static String convertClassSignature(String desc) {
return convertClassSignature(new ClassSignatureLexer(desc).parse());
}
/**
*
* Convert class signature.
*
* @param desc The signature as a string in a java source .
* @return A list of type parameters.
*/
public static List<String> extractTypeParameters(String desc) {
List<String> result = new LinkedList<String>();
if (desc.startsWith("<")) {
int endIndex =
AbstractLexer.balancedBracketPosition(desc, '<', '>');
desc = desc.substring(1, endIndex);
while (desc.length() > 0) {
int index =
AbstractLexer.firstIndexNotInside(',', '<', '>', desc);
if (index == 0 || index == desc.length()) {
result.add(desc.trim());
desc = "";
} else {
result.add(desc.substring(0, index).trim());
desc = desc.substring(index + 1);
}
}
}
return result;
}
public static List<Token> parseClassSignature(String s) {
return new ClassSignatureLexer(s).parse();
}
/**
* Convert a method type signature.
*
* @param desc The signature as a string.
* @return The signature as it would appear in a Java sourcefile.
*/
public static String convertMethodTypeSignature(String desc) {
return convertMethodTypeSignature(new MethodTypeSignatureLexer(desc)
.parse());
}
protected static String convertFieldDescriptor(List<Token> tokens) {
String brackets = "";
for (Token t : tokens) {
if (t.getType() == Token.BASE_TYPE) {
return convertBaseType(t.getValue()) + brackets;
} else if (t.getType() == Token.CLASS_NAME) {
return t.getValue().replaceAll("/", ".") + brackets;
} else if (t.getType() == Token.ARRAY_BRACKET) {
brackets += t.getValue();
}
}
throw new IllegalArgumentException("Can not parse field descriptor");
}
protected static String convertClassTypeSignature(List<Token> tokens) {
StringBuilder buf = new StringBuilder();
for (Token t : tokens) {
buf.append(t.getValue());
}
return buf.toString();
}
protected static String convertFieldTypeSignature(List<Token> tokens) {
StringBuilder buf = new StringBuilder();
for (Token t : tokens) {
buf.append(t.getValue());
}
return buf.toString();
}
protected static String convertClassSignature(List<Token> tokens) {
StringBuilder buf = new StringBuilder();
for (Token t : tokens) {
buf.append(t.getValue());
}
return buf.toString();
}
protected static String convertMethodTypeSignature(List<Token> tokens) {
StringBuilder buf = new StringBuilder();
for (Token t : tokens) {
buf.append(t.getValue());
}
return buf.toString();
}
protected static String convertBaseType(String s) {
switch (s.charAt(0)) {
case 'B':
return "byte";
case 'C':
return "char";
case 'D':
return "double";
case 'F':
return "float";
case 'I':
return "int";
case 'J':
return "long";
case 'S':
return "short";
case 'Z':
return "boolean";
}
throw new IllegalArgumentException(s + " is not a base type");
}
/**
* Tokens.
*/
/**
*
* @author Linus
*/
public static class Token {
/**
* B|C|D
*/
public static final int BASE_TYPE = 0; // B|C|D...
/**
* V
*/
public static final int VOID_TYPE = 1; // V
/**
* with slashes
*/
public static final int CLASS_NAME = 2; // with slashes
/**
* [
*/
public static final int ARRAY_BRACKET = 3; // [
/**
* method parameter
*/
public static final int FIELD_DESCRIPTOR = 4; // method parameter
/**
* as a.b.c
*/
public static final int PACKAGE = 5; // as a.b.c
/**
* identifier
*/
public static final int IDENTIFIER = 6; //
/**
* <
*/
public static final int LABRACKET = 7; // <
/**
* >
*/
public static final int RABRACKET = 8; // >
/**
* +-*
*/
public static final int WILDCARD = 9; // +-*
/**
* ,
*/
public static final int COMMA = 10; // ,
/**
* .
*/
public static final int POINT = 11; // .
/**
* :
*/
public static final int COLON = 12; // .
/**
* extends
*/
public static final int SUPERCLASS = 13; // extends
/**
* implements
*/
public static final int SUPERINTERFACE = 15; // implements
/**
* (
*/
public static final int LBRACKET = 16; // (
/**
* )
*/
public static final int RBRACKET = 17; // )
/**
* throws
*/
public static final int THROWS = 18; // throws
/**
* return
*/
public static final int RETURN = 19; // return
/**
* &
*/
public static final int AMPERSAND = 20; // &
private String value;
private int type;
public Token(int t, String v) {
type = t;
value = v;
}
public int getType() {
return type;
}
public String getValue() {
return value;
}
@Override
public String toString() {
return type + ":" + value;
}
}
/**
* Lexer for the a field descriptor.
*/
protected static class FieldDescriptorLexer
extends AbstractLexer {
public FieldDescriptorLexer(String desc) {
super(desc);
}
/**
* Parse field descriptor according the grammar:
*
* <pre>
* FieldDescriptor:=BaseType|ObjectType|ArrayType
* BaseType:=B|C|D|F|J|S|Z
* ObjectType:=L Classname;
* ArrayType:=[FieldDescriptor
* </pre>
*
* @return a List of matched Token.
*/
public List<Token> parse() {
List<Token> result = new LinkedList<Token>();
// Object type?
Matcher m = Pattern.compile("^(L)(.+)(;)").matcher(desc);
if (m.matches()) {
// Classname
result.add(new Token(Token.CLASS_NAME, m.group(2)));
desc = desc.substring(m.group(0).length()); // the rest after ;
return result;
}
// Array type?
m = Pattern.compile("^(\\[)((.+))").matcher(desc);
if (m.matches()) {
result.add(new Token(Token.ARRAY_BRACKET, "[]"));
desc = desc.substring(1);
result.addAll(parse());
return result;
}
// Base type?
m = Pattern.compile("^(B|C|D|F|I|J|S|Z)((.*))").matcher(desc);
if (m.matches()) {
result.add(new Token(Token.BASE_TYPE, m.group(1)));
desc = desc.substring(1);
return result;
}
if (desc.length() == 0) {
return result;
}
throw new IllegalArgumentException(desc
+ " is not a FieldDescriptor");
}
}
/**
* Lexer for the method descriptor.
*/
protected static class MethodDescriptorLexer
extends AbstractLexer {
public MethodDescriptorLexer(String desc) {
super(desc);
}
/**
* Parse method descriptor according the grammar:
*
* <pre>
* MethodDescriptor:= ( FieldDescriptor* ) ReturnDescriptor
* ReturnDescriptor:=FieldDescriptor|V
*
* </pre>
*
* @return a List of matched Token.
*/
public List<Token> parse() {
List<Token> result = new LinkedList<Token>();
// Object type?
Matcher m = Pattern.compile("^(\\()(.*)(\\))((.+))").matcher(desc);
if (m.matches()) {
String returnDescriptor = m.group(4);
String parameters = m.group(2);
while (parameters.length() > 0) {
FieldDescriptorLexer lexer = new FieldDescriptorLexer(
parameters);
result.add(new Token(Token.FIELD_DESCRIPTOR,
convertFieldDescriptor(lexer.parse())));
parameters = lexer.getRest();
}
if (returnDescriptor.equals("V")) {
result.add(new Token(Token.VOID_TYPE, "void"));
} else {
FieldDescriptorLexer lexer = new FieldDescriptorLexer(
returnDescriptor);
result.add(new Token(Token.FIELD_DESCRIPTOR,
convertFieldDescriptor(lexer.parse())));
}
return result;
}
throw new IllegalArgumentException(desc
+ " is not a MethodDescriptor");
}
}
/**
* Lexer for the signature of a field type.
*/
protected static class FieldTypeSignatureLexer extends AbstractLexer {
public FieldTypeSignatureLexer(String desc) {
super(desc);
}
/**
* Parse FieldTypeSignature according the grammar:
*
* <pre>
* FieldTypeSignature: ClassTypeSignature
* |ArrayTypeSignature
* |TypeVariableSignature
* </pre>
*
* @return a List of matched Token.
*/
@Override
public List<Token> parse() {
List<Token> result = new LinkedList<Token>();
// while (desc.length() > 0) {
AbstractLexer lexer = null;
switch (desc.charAt(0)) {
case 'L':
lexer = new ClassTypeSignatureLexer(desc);
break;
case '[':
lexer = new ArrayTypeSignatureLexer(desc);
break;
case 'T':
lexer = new TypeVariableSignatureLexer(desc);
break;
default:
throw new IllegalArgumentException(desc
+ " is not a field type signature");
}
result.addAll(lexer.parse());
desc = lexer.getRest();
// }
return result;
}
}
/**
* Lexer for the signature of a variable declaration.
*/
protected static class TypeVariableSignatureLexer extends AbstractLexer {
public TypeVariableSignatureLexer(String desc) {
super(desc);
}
/**
* Parse type variable signature according the grammar:
*
* <pre>
* TypeVariableSignature: T Identifer ;
* </pre>
*
* @return a List of matched Token.
*/
@Override
public List<Token> parse() {
List<Token> result = new LinkedList<Token>();
Matcher m = Pattern.compile("T([^;]*);((.*))").matcher(desc);
if (m.matches()) {
result.add(new Token(Token.IDENTIFIER, m.group(1)));
desc = m.group(2);
} else {
new IllegalArgumentException(desc
+ " is not a type variable signature");
}
return result;
}
}
/**
* Lexer for the signature of an array type.
*/
protected static class ArrayTypeSignatureLexer extends AbstractLexer {
public ArrayTypeSignatureLexer(String desc) {
super(desc);
}
/**
* Parse array type signature according the grammar:
*
* <pre>
* ArrayTypeSignature: [TypeSignature
* TypeSignature: FieldTypeSignature|BaseType
* </pre>
*
* @return a List of matched Token.
*/
@Override
public List<Token> parse() {
List<Token> result = new LinkedList<Token>();
if (desc.charAt(0) == '[') {
desc = desc.substring(1);
TypeSignatureLexer l = new TypeSignatureLexer(desc);
result.addAll(l.parse());
desc = l.getRest();
result.add(new Token(Token.ARRAY_BRACKET, "[]"));
return result;
} else {
throw new IllegalArgumentException(desc
+ " is not an array type signature");
}
}
}
/**
* Lexer for the signature of a type.
*/
protected static class TypeSignatureLexer extends AbstractLexer {
public TypeSignatureLexer(String desc) {
super(desc);
}
/**
* Parse type signature according the grammar:
*
* <pre>
* TypeSignature: FieldTypeSignature|BaseType
* </pre>
*
* @return a List of matched Token.
*/
@Override
public List<Token> parse() {
List<Token> result = new LinkedList<Token>();
Matcher m = Pattern.compile("^(B|C|D|F|I|J|S|Z)((.*))").matcher(
desc);
if (m.matches()) {
result.add(new Token(Token.BASE_TYPE, convertBaseType(m
.group(1))));
desc = desc.substring(1);
} else {
AbstractLexer l = new FieldTypeSignatureLexer(desc);
result.addAll(l.parse());
desc = l.getRest();
}
return result;
}
}
/**
* Lexer for the signature of a simple class type.
*/
protected static class SimpleClassTypeSignatureLexer extends AbstractLexer {
public SimpleClassTypeSignatureLexer(String desc) {
super(desc);
}
/**
* Parse simple class type signature according the grammar:
*
* <pre>
* SimpleClassTypeSignature:=Identifier TypeArgumentsopt
* TypeArguments:<TypeArgument+>
* TypeArgument:WildcardIndicatoropt FieldTypeSignature|*
* WildcardIndicator:+|-
* </pre>
*
* @return a List of matched Token.
*/
@Override
public List<Token> parse() {
List<Token> result = new LinkedList<Token>();
Matcher m = Pattern.compile("([^<.]*)(<.*>)?((.*))").matcher(desc);
if (m.matches()) {
String identifier = m.group(1);
String typeArguments = m.group(2);
if (identifier != null && identifier.length() > 0) {
result.add(new Token(Token.IDENTIFIER, identifier));
} else {
throw new IllegalArgumentException(desc
+ " is not a SimpleClassTypeSignature");
}
if (typeArguments != null && typeArguments.length() > 0) {
result.add(new Token(Token.LABRACKET, "<"));
String arguments = typeArguments.substring(1, typeArguments
.length() - 1);
if (arguments.charAt(0) == '*') {
result.add(new Token(Token.WILDCARD, "?"));
} else {
if (arguments.charAt(0) == '+') {
result.add(new Token(Token.WILDCARD, "? extends "));
arguments = arguments.substring(1);
} else if (arguments.charAt(0) == '-') {
result.add(new Token(Token.WILDCARD, "? super "));
arguments = arguments.substring(1);
}
while (arguments.length() > 0) {
FieldTypeSignatureLexer l =
new FieldTypeSignatureLexer(arguments);
result.addAll(l.parse());
arguments = l.getRest();
if (arguments.length() > 0) {
result.add(new Token(Token.COMMA, ","));
}
}
}
result.add(new Token(Token.RABRACKET, ">"));
}
}
desc = m.group(3);
return result;
}
}
/**
* Lexer for the signature of a class type.
*/
protected static class ClassTypeSignatureLexer extends AbstractLexer {
public ClassTypeSignatureLexer(String desc) {
super(desc);
}
/**
* Parse class type signature according the grammar:
*
* <pre>
* ClassTypeSignature:=L PackageSpecifier* SimpleClassTypeSignature ClassTypeSignatureSuffix* ;
* PackageSpecifier:=Identifier / PackageSpecifier*
* ClassTypeSignatureSuffix:=. SimpleClassTypeSignature
* </pre>
*
* @return a List of matched Token.
*/
@Override
public List<Token> parse() {
List<Token> result = new LinkedList<Token>();
// find signature in desc
int index = firstIndexNotInside(';', '<', '>', desc);
String classTypeSignature = desc.substring(0, index + 1);
desc = desc.substring(index + 1);
Matcher m = Pattern.compile("L([^<\\.;]*/)*([^<\\.;]*)((.*));$")
.matcher(classTypeSignature);
if (m.matches()) {
String packageSpecifier = m.group(1);
String identifier = m.group(2);
String other = m.group(3);
String arguments = "";
String suffixes = "";
if (other != null && other.length() > 0) {
if (other.charAt(0) == '<') {
// this is type arguments
arguments = other.substring(0, balancedBracketPosition(
other, '<', '>') + 1);
}
suffixes = other.substring(arguments.length());
}
if (packageSpecifier != null && packageSpecifier.length() > 0) {
result.add(new Token(Token.PACKAGE, packageSpecifier
.replaceAll("/", ".")));
}
SimpleClassTypeSignatureLexer sl =
new SimpleClassTypeSignatureLexer(
identifier + arguments);
result.addAll(sl.parse());
// parse suffixes
while (suffixes.length() > 0) {
// find suffix in suffixes
suffixes = suffixes.substring(1);
index = firstIndexNotInside('.', '<', '>', suffixes);
String suffix = suffixes.substring(0, index);
result.add(new Token(Token.POINT, "."));
result.addAll(new SimpleClassTypeSignatureLexer(suffix)
.parse());
suffixes = suffixes.substring(index);
}
}
return result;
}
}
/**
* Lexer for a signature of a class.
*/
protected static class ClassSignatureLexer extends AbstractLexer {
public ClassSignatureLexer(String desc) {
super(desc);
}
/**
* Parse class signature according the grammar:
*
* <pre>
* ClassSignature: FormalTypeParametersopt SuperclassSignature SuperinterfaceSignature*
* FormalTypeParameters: <FormalTypeParameter+>
* FormalTypeParameter: Identifier ClassBound InterfaceBound*
* ClassBound: : FieldTypeSignatureopt
* InterfaceBound: : FieldTypeSignature
* SuperclassSignature: ClassTypeSignature
* SuperinterfaceSignature: ClassTypeSignature
* </pre>
*
* @return a List of matched Token.
*/
@Override
public List<Token> parse() {
List<Token> result = new LinkedList<Token>();
if (desc.charAt(0) == '<') {
result.add(new Token(Token.LABRACKET, "<"));
int formalTypeParametersEndIndex = balancedBracketPosition(
desc, '<', '>');
String formalTypeParameters = desc.substring(1,
formalTypeParametersEndIndex);
desc = desc.substring(formalTypeParametersEndIndex + 1);
FormalTypeParameterLexer l = new FormalTypeParameterLexer(
formalTypeParameters);
result.addAll(l.parse());
Pattern.compile("([^:]*):((.*))").matcher(formalTypeParameters);
result.add(new Token(Token.RABRACKET, ">"));
}
// parse super type
ClassTypeSignatureLexer l = new ClassTypeSignatureLexer(desc);
result.add(new Token(Token.SUPERCLASS, " extends "));
result.addAll(l.parse());
String interfaces = l.getRest();
if (interfaces.length() > 0) {
// parse super interfaces
result.add(new Token(Token.SUPERCLASS, " implements "));
ClassTypeSignatureLexer l2 = new ClassTypeSignatureLexer(
interfaces);
result.addAll(l2.parse());
String others = l2.getRest();
while (others.length() > 0) {
l2 = new ClassTypeSignatureLexer(others);
result.add(new Token(Token.COMMA, ","));
result.addAll(l2.parse());
others = l2.getRest();
}
}
return result;
}
}
/**
* Lexer for the formal type parameter.
*/
protected static class FormalTypeParameterLexer extends AbstractLexer {
public FormalTypeParameterLexer(String desc) {
super(desc);
}
/**
* Parse formal type parameters according the grammar:
*
* <pre>
* FormalTypeParameters: <FormalTypeParameter+>
* FormalTypeParameter: Identifier ClassBound InterfaceBound*
* ClassBound: : FieldTypeSignatureopt
* InterfaceBound: : FieldTypeSignature
* </pre>
*
* @return a List of matched Token.
*/
@Override
public List<Token> parse() {
List<Token> result = new LinkedList<Token>();
Matcher m = Pattern.compile("([^:]*):((.*))").matcher(desc);
if (m.matches()) {
String identifier = m.group(1);
String other = m.group(2);
result.add(new Token(Token.IDENTIFIER, identifier));
result.add(new Token(Token.SUPERCLASS, " extends "));
// other begins with ":" if ClassBound is absent
// that is parameter extends interface, not a class
if (other.charAt(0) == ':') {
other = other.substring(1);
}
FieldTypeSignatureLexer f = new FieldTypeSignatureLexer(other);
result.addAll(f.parse());
other = f.getRest();
if (other.length() > 0) {
if (other.startsWith(":")) {
// interface bounds begins here
while (other.startsWith(":")) {
result.add(new Token(Token.AMPERSAND, " & "));
FieldTypeSignatureLexer l =
new FieldTypeSignatureLexer(
other.substring(1));
result.addAll(l.parse());
other = l.getRest();
}
}
}
if (other.length() > 0) {
// new FormalTypeParameter begins here
result.add(new Token(Token.COMMA, ","));
FormalTypeParameterLexer l = new FormalTypeParameterLexer(
other);
result.addAll(l.parse());
}
desc = other;
}
return result;
}
}
/**
* Lexer for the signature of the method type.
*/
protected static class MethodTypeSignatureLexer extends AbstractLexer {
public MethodTypeSignatureLexer(String desc) {
super(desc);
}
/**
* Parse method type signature according the grammar:
*
* <pre>
* MethodTypeSignature: FormalTypeParametersopt (TypeSignature*) ReturnType ThrowsSignature*
* ReturnType: TypeSignature VoidDescriptor
* ThrowsSignature: ˆClassTypeSignature ˆTypeVariableSignature
* </pre>
*
* @return a List of matched Token.
*/
@Override
public List<Token> parse() {
List<Token> result = new LinkedList<Token>();
if (desc.charAt(0) == '<') {
result.add(new Token(Token.LABRACKET, "<"));
int formalTypeParametersEndIndex = balancedBracketPosition(
desc, '<', '>');
String formalTypeParameters = desc.substring(1,
formalTypeParametersEndIndex);
desc = desc.substring(formalTypeParametersEndIndex + 1);
FormalTypeParameterLexer l = new FormalTypeParameterLexer(
formalTypeParameters);
result.addAll(l.parse());
Pattern.compile("([^:]*):((.*))")
.matcher(formalTypeParameters);
result.add(new Token(Token.RABRACKET, ">"));
}
// parse type signatures
result.add(new Token(Token.LBRACKET, "("));
int typeSignaturesEndIndex =
balancedBracketPosition(desc, '(', ')');
String typeSignatures = desc.substring(1, typeSignaturesEndIndex);
desc = desc.substring(typeSignaturesEndIndex + 1);
if (typeSignatures.length() > 0) {
TypeSignatureLexer t = new TypeSignatureLexer(typeSignatures);
result.addAll(t.parse());
typeSignatures = t.getRest();
while (typeSignatures.length() > 0) {
result.add(new Token(Token.COMMA, ","));
TypeSignatureLexer t2 = new TypeSignatureLexer(
typeSignatures);
result.addAll(t2.parse());
typeSignatures = t2.getRest();
}
}
result.add(new Token(Token.RBRACKET, ")"));
// parse return type
result.add(new Token(Token.RETURN, " return "));
if (desc.charAt(0) == 'V') {
result.add(new Token(Token.VOID_TYPE, "void"));
desc = desc.substring(1);
} else {
TypeSignatureLexer t3 = new TypeSignatureLexer(desc);
result.addAll(t3.parse());
desc = t3.getRest();
}
// parse throws signatures
if (desc.length() > 0) {
result.add(new Token(Token.THROWS, " throws "));
ThrowsSignatureLexer t4 = new ThrowsSignatureLexer(desc);
result.addAll(t4.parse());
desc = t4.getRest();
while (desc.length() > 0) {
result.add(new Token(Token.COMMA, ","));
ThrowsSignatureLexer t2 = new ThrowsSignatureLexer(desc);
result.addAll(t2.parse());
desc = t2.getRest();
}
}
return result;
}
}
/**
* Lexer for the throws signature.
*/
protected static class ThrowsSignatureLexer extends AbstractLexer {
public ThrowsSignatureLexer(String desc) {
super(desc);
}
/**
* Parse throws signature according the grammar:
*
* <pre>
* ThrowsSignature: ˆClassTypeSignature ˆTypeVariableSignature
* </pre>
*
* @return a List of matched Token.
*/
@Override
public List<Token> parse() {
List<Token> result = new LinkedList<Token>();
if (desc.charAt(0) == '^') {
desc = desc.substring(1);
if (desc.charAt(0) == 'T') {
TypeVariableSignatureLexer l =
new TypeVariableSignatureLexer(desc);
result.addAll(l.parse());
desc = l.getRest();
} else {
ClassTypeSignatureLexer l = new ClassTypeSignatureLexer(
desc);
result.addAll(l.parse());
desc = l.getRest();
}
} else {
throw new IllegalArgumentException(desc
+ " is not a throws signature");
}
return result;
}
}
/**
* The abstract lexer.
*/
protected abstract static class AbstractLexer {
/**
* Description of the lexer.
*/
protected String desc;
public AbstractLexer(String d) {
desc = d;
}
public abstract List<Token> parse();
public String getRest() {
return desc;
}
/**
* Find the index of the first occurrence of symbol in text outside of
* brackets.
*
* @param symbol
* @param openBracket
* @param closeBracket
* @param text
* @return index
*/
protected static int firstIndexNotInside(char symbol, char openBracket,
char closeBracket, String text) {
int count = 0;
int index = 0;
for (char c : text.toCharArray()) {
if (c == symbol && count == 0) {
break;
}
if (c == openBracket) {
count++;
}
if (c == closeBracket) {
count--;
}
index++;
}
return index;
}
protected static int balancedBracketPosition(String text,
char openBracket, char closeBracket) {
if (text.charAt(0) != openBracket) {
throw new IllegalArgumentException(text
+ " does not start with open bracket ");
}
if (text.indexOf(closeBracket) == -1) {
throw new IllegalArgumentException(text
+ " does not contain close bracket ");
}
int count = -1;
char[] chars = text.toCharArray();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
if (c == openBracket) {
count++;
} else if (c == closeBracket) {
if (count == 0) {
return i;
} else {
count--;
}
}
}
throw new IllegalArgumentException(text
+ " has no balanced bracket for " + openBracket);
}
}
}