aboutsummaryrefslogtreecommitdiffstats
path: root/util/src
diff options
context:
space:
mode:
authoraclement <aclement>2008-10-20 18:31:31 +0000
committeraclement <aclement>2008-10-20 18:31:31 +0000
commit22c9c825e93a8ad85904462499fcd0b7ca5f7845 (patch)
treeffec158574f784a090ece1d76d40938d31a12d4f /util/src
parent83fad50ca5effa81e73b6fa8f159d175fcaab599 (diff)
downloadaspectj-22c9c825e93a8ad85904462499fcd0b7ca5f7845.tar.gz
aspectj-22c9c825e93a8ad85904462499fcd0b7ca5f7845.zip
246125: promoted generic sig parsing code to util
Diffstat (limited to 'util/src')
-rw-r--r--util/src/org/aspectj/util/GenericSignature.java249
-rw-r--r--util/src/org/aspectj/util/GenericSignatureParser.java410
2 files changed, 659 insertions, 0 deletions
diff --git a/util/src/org/aspectj/util/GenericSignature.java b/util/src/org/aspectj/util/GenericSignature.java
new file mode 100644
index 000000000..0e2433abd
--- /dev/null
+++ b/util/src/org/aspectj/util/GenericSignature.java
@@ -0,0 +1,249 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 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
+ *
+ * ******************************************************************/
+package org.aspectj.util;
+
+/**
+ * Encapsulate generic signature parsing
+ *
+ * @author Adrian Colyer
+ * @author Andy Clement
+ */
+public class GenericSignature {
+
+ /**
+ * structure holding a parsed class signature
+ */
+ public static class ClassSignature {
+ public FormalTypeParameter[] formalTypeParameters = new FormalTypeParameter[0];
+ public ClassTypeSignature superclassSignature;
+ public ClassTypeSignature[] superInterfaceSignatures = new ClassTypeSignature[0];
+
+ public String toString() {
+ StringBuffer ret = new StringBuffer();
+ ret.append(formalTypeParameters.toString());
+ ret.append(superclassSignature.toString());
+ for (int i = 0; i < superInterfaceSignatures.length; i++) {
+ ret.append(superInterfaceSignatures[i].toString());
+ }
+ return ret.toString();
+ }
+ }
+
+ public static class MethodTypeSignature {
+ public FormalTypeParameter[] formalTypeParameters = new FormalTypeParameter[0];
+ public TypeSignature[] parameters = new TypeSignature[0];
+ public TypeSignature returnType;
+ public FieldTypeSignature[] throwsSignatures = new FieldTypeSignature[0];
+
+ public MethodTypeSignature(FormalTypeParameter[] aFormalParameterList, TypeSignature[] aParameterList,
+ TypeSignature aReturnType, FieldTypeSignature[] aThrowsSignatureList) {
+ this.formalTypeParameters = aFormalParameterList;
+ this.parameters = aParameterList;
+ this.returnType = aReturnType;
+ this.throwsSignatures = aThrowsSignatureList;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ if (formalTypeParameters.length > 0) {
+ sb.append("<");
+ for (int i = 0; i < formalTypeParameters.length; i++) {
+ sb.append(formalTypeParameters[i].toString());
+ }
+ sb.append(">");
+ }
+ sb.append("(");
+ for (int i = 0; i < parameters.length; i++) {
+ sb.append(parameters[i].toString());
+ }
+ sb.append(")");
+ sb.append(returnType.toString());
+ for (int i = 0; i < throwsSignatures.length; i++) {
+ sb.append("^");
+ sb.append(throwsSignatures[i].toString());
+ }
+ return sb.toString();
+ }
+ }
+
+ /**
+ * structure capturing a FormalTypeParameter from the Signature grammar
+ */
+ public static class FormalTypeParameter {
+ public String identifier;
+ public FieldTypeSignature classBound;
+ public FieldTypeSignature[] interfaceBounds;
+
+ public String toString() {
+ StringBuffer ret = new StringBuffer();
+ ret.append("T");
+ ret.append(identifier);
+ ret.append(":");
+ ret.append(classBound.toString());
+ for (int i = 0; i < interfaceBounds.length; i++) {
+ ret.append(":");
+ ret.append(interfaceBounds[i].toString());
+ }
+ return ret.toString();
+ }
+ }
+
+ public static abstract class TypeSignature {
+ public boolean isBaseType() {
+ return false;
+ }
+ }
+
+ public static class BaseTypeSignature extends TypeSignature {
+ private final String sig;
+
+ public BaseTypeSignature(String aPrimitiveType) {
+ sig = aPrimitiveType;
+ }
+
+ public boolean isBaseType() {
+ return true;
+ }
+
+ public String toString() {
+ return sig;
+ }
+ }
+
+ public static abstract class FieldTypeSignature extends TypeSignature {
+ public boolean isClassTypeSignature() {
+ return false;
+ }
+
+ public boolean isTypeVariableSignature() {
+ return false;
+ }
+
+ public boolean isArrayTypeSignature() {
+ return false;
+ }
+ }
+
+ public static class ClassTypeSignature extends FieldTypeSignature {
+ public String classSignature;
+ public SimpleClassTypeSignature outerType;
+ public SimpleClassTypeSignature[] nestedTypes;
+
+ public ClassTypeSignature(String sig, String identifier) {
+ this.classSignature = sig;
+ this.outerType = new SimpleClassTypeSignature(identifier);
+ this.nestedTypes = new SimpleClassTypeSignature[0];
+ }
+
+ public ClassTypeSignature(String sig, SimpleClassTypeSignature outer, SimpleClassTypeSignature[] inners) {
+ this.classSignature = sig;
+ this.outerType = outer;
+ this.nestedTypes = inners;
+ }
+
+ public boolean isClassTypeSignature() {
+ return true;
+ }
+
+ public String toString() {
+ return classSignature;
+ }
+ }
+
+ public static class TypeVariableSignature extends FieldTypeSignature {
+ public String typeVariableName;
+
+ public TypeVariableSignature(String typeVarToken) {
+ this.typeVariableName = typeVarToken.substring(1);
+ }
+
+ public boolean isTypeVariableSignature() {
+ return true;
+ }
+
+ public String toString() {
+ return "T" + typeVariableName + ";";
+ }
+ }
+
+ public static class ArrayTypeSignature extends FieldTypeSignature {
+ public TypeSignature typeSig;
+
+ public ArrayTypeSignature(TypeSignature aTypeSig) {
+ this.typeSig = aTypeSig;
+ }
+
+ public boolean isArrayTypeSignature() {
+ return true;
+ }
+
+ public String toString() {
+ return "[" + typeSig.toString();
+ }
+ }
+
+ public static class SimpleClassTypeSignature {
+ public String identifier;
+ public TypeArgument[] typeArguments;
+
+ public SimpleClassTypeSignature(String identifier) {
+ this.identifier = identifier;
+ this.typeArguments = new TypeArgument[0];
+ }
+
+ public SimpleClassTypeSignature(String identifier, TypeArgument[] args) {
+ this.identifier = identifier;
+ this.typeArguments = args;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(identifier);
+ if (typeArguments.length > 0) {
+ sb.append("<");
+ for (int i = 0; i < typeArguments.length; i++) {
+ sb.append(typeArguments[i].toString());
+ }
+ sb.append(">");
+ }
+ return sb.toString();
+ }
+ }
+
+ public static class TypeArgument {
+ public boolean isWildcard = false;
+ public boolean isPlus = false;
+ public boolean isMinus = false;
+ public FieldTypeSignature signature; // null if isWildcard
+
+ public TypeArgument() {
+ isWildcard = true;
+ }
+
+ public TypeArgument(boolean plus, boolean minus, FieldTypeSignature aSig) {
+ this.isPlus = plus;
+ this.isMinus = minus;
+ this.signature = aSig;
+ }
+
+ public String toString() {
+ if (isWildcard)
+ return "*";
+ StringBuffer sb = new StringBuffer();
+ if (isPlus)
+ sb.append("+");
+ if (isMinus)
+ sb.append("-");
+ sb.append(signature.toString());
+ return sb.toString();
+ }
+ }
+}
diff --git a/util/src/org/aspectj/util/GenericSignatureParser.java b/util/src/org/aspectj/util/GenericSignatureParser.java
new file mode 100644
index 000000000..d8e5bd073
--- /dev/null
+++ b/util/src/org/aspectj/util/GenericSignatureParser.java
@@ -0,0 +1,410 @@
+/* *******************************************************************
+ * Copyright (c) 2005-2008 Contributors.
+ * 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://eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.aspectj.util.GenericSignature.ArrayTypeSignature;
+import org.aspectj.util.GenericSignature.BaseTypeSignature;
+import org.aspectj.util.GenericSignature.ClassTypeSignature;
+import org.aspectj.util.GenericSignature.FieldTypeSignature;
+import org.aspectj.util.GenericSignature.FormalTypeParameter;
+import org.aspectj.util.GenericSignature.MethodTypeSignature;
+import org.aspectj.util.GenericSignature.SimpleClassTypeSignature;
+import org.aspectj.util.GenericSignature.TypeArgument;
+import org.aspectj.util.GenericSignature.TypeSignature;
+import org.aspectj.util.GenericSignature.TypeVariableSignature;
+
+/**
+ * Parses the generic signature attribute as defined in the JVM spec.
+ *
+ * @author Adrian Colyer
+ * @author Andy Clement
+ */
+public class GenericSignatureParser {
+
+ private String inputString;
+ private String[] tokenStream; // for parse in flight
+ private int tokenIndex = 0;
+
+ /**
+ * AMC. Parse the signature string interpreting it as a ClassSignature according to the grammar defined in Section 4.4.4 of the
+ * JVM specification.
+ */
+ public GenericSignature.ClassSignature parseAsClassSignature(String sig) {
+ this.inputString = sig;
+ tokenStream = tokenize(sig);
+ tokenIndex = 0;
+ GenericSignature.ClassSignature classSig = new GenericSignature.ClassSignature();
+ // FormalTypeParameters-opt
+ if (maybeEat("<")) {
+ List formalTypeParametersList = new ArrayList();
+ do {
+ formalTypeParametersList.add(parseFormalTypeParameter());
+ } while (!maybeEat(">"));
+ classSig.formalTypeParameters = new FormalTypeParameter[formalTypeParametersList.size()];
+ formalTypeParametersList.toArray(classSig.formalTypeParameters);
+ }
+ classSig.superclassSignature = parseClassTypeSignature();
+ List superIntSigs = new ArrayList();
+ while (tokenIndex < tokenStream.length) {
+ superIntSigs.add(parseClassTypeSignature());
+ }
+ classSig.superInterfaceSignatures = new ClassTypeSignature[superIntSigs.size()];
+ superIntSigs.toArray(classSig.superInterfaceSignatures);
+ return classSig;
+ }
+
+ /**
+ * AMC. Parse the signature string interpreting it as a MethodTypeSignature according to the grammar defined in Section 4.4.4 of
+ * the JVM specification.
+ */
+ public MethodTypeSignature parseAsMethodSignature(String sig) {
+ this.inputString = sig;
+ tokenStream = tokenize(sig);
+ tokenIndex = 0;
+ FormalTypeParameter[] formals = new FormalTypeParameter[0];
+ TypeSignature returnType = null;
+ // FormalTypeParameters-opt
+ if (maybeEat("<")) {
+ List formalTypeParametersList = new ArrayList();
+ do {
+ formalTypeParametersList.add(parseFormalTypeParameter());
+ } while (!maybeEat(">"));
+ formals = new FormalTypeParameter[formalTypeParametersList.size()];
+ formalTypeParametersList.toArray(formals);
+ }
+ // Parameters
+ eat("(");
+ List paramList = new ArrayList();
+ while (!maybeEat(")")) {
+ FieldTypeSignature fsig = parseFieldTypeSignature(true);
+ if (fsig != null) {
+ paramList.add(fsig);
+ } else {
+ paramList.add(new GenericSignature.BaseTypeSignature(eatIdentifier()));
+ }
+ }
+ TypeSignature[] params = new TypeSignature[paramList.size()];
+ paramList.toArray(params);
+ // return type
+ returnType = parseFieldTypeSignature(true);
+ if (returnType == null)
+ returnType = new GenericSignature.BaseTypeSignature(eatIdentifier());
+ // throws
+ List throwsList = new ArrayList();
+ while (maybeEat("^")) {
+ FieldTypeSignature fsig = parseFieldTypeSignature(false);
+ throwsList.add(fsig);
+ }
+ FieldTypeSignature[] throwsSigs = new FieldTypeSignature[throwsList.size()];
+ throwsList.toArray(throwsSigs);
+ return new GenericSignature.MethodTypeSignature(formals, params, returnType, throwsSigs);
+ }
+
+ /**
+ * AMC. Parse the signature string interpreting it as a FieldTypeSignature according to the grammar defined in Section 4.4.4 of
+ * the JVM specification.
+ */
+ public FieldTypeSignature parseAsFieldSignature(String sig) {
+ this.inputString = sig;
+ tokenStream = tokenize(sig);
+ tokenIndex = 0;
+ return parseFieldTypeSignature(false);
+ }
+
+ private FormalTypeParameter parseFormalTypeParameter() {
+ FormalTypeParameter ftp = new FormalTypeParameter();
+ // Identifier
+ ftp.identifier = eatIdentifier();
+ // ClassBound
+ eat(":");
+ ftp.classBound = parseFieldTypeSignature(true);
+ if (ftp.classBound == null) {
+ ftp.classBound = new ClassTypeSignature("Ljava/lang/Object;", "Ljava/lang/Object");
+ }
+ // Optional InterfaceBounds
+ List optionalBounds = new ArrayList();
+ while (maybeEat(":")) {
+ optionalBounds.add(parseFieldTypeSignature(false));
+ }
+ ftp.interfaceBounds = new FieldTypeSignature[optionalBounds.size()];
+ optionalBounds.toArray(ftp.interfaceBounds);
+ return ftp;
+ }
+
+ private FieldTypeSignature parseFieldTypeSignature(boolean isOptional) {
+ if (isOptional) {
+ // anything other than 'L', 'T' or '[' and we're out of here
+ if (!tokenStream[tokenIndex].startsWith("L") && !tokenStream[tokenIndex].startsWith("T")
+ && !tokenStream[tokenIndex].startsWith("[")) {
+ return null;
+ }
+ }
+ if (maybeEat("[")) {
+ return parseArrayTypeSignature();
+ } else if (tokenStream[tokenIndex].startsWith("L")) {
+ return parseClassTypeSignature();
+ } else if (tokenStream[tokenIndex].startsWith("T")) {
+ return parseTypeVariableSignature();
+ } else {
+ throw new IllegalStateException("Expecting [,L, or T, but found " + tokenStream[tokenIndex] + " while unpacking "
+ + inputString);
+ }
+ }
+
+ private ArrayTypeSignature parseArrayTypeSignature() {
+ // opening [ already eaten
+ FieldTypeSignature fieldType = parseFieldTypeSignature(true);
+ if (fieldType != null) {
+ return new ArrayTypeSignature(fieldType);
+ } else {
+ // must be BaseType array
+ return new ArrayTypeSignature(new BaseTypeSignature(eatIdentifier()));
+ }
+ }
+
+ // L PackageSpecifier* SimpleClassTypeSignature ClassTypeSignature* ;
+ private ClassTypeSignature parseClassTypeSignature() {
+ SimpleClassTypeSignature outerType = null;
+ SimpleClassTypeSignature[] nestedTypes = new SimpleClassTypeSignature[0];
+ StringBuffer ret = new StringBuffer();
+ String identifier = eatIdentifier();
+ ret.append(identifier);
+ while (maybeEat("/")) {
+ ret.append("/"); // dont forget this...
+ ret.append(eatIdentifier());
+ }
+ identifier = ret.toString();
+ // now we have either a "." indicating the start of a nested type,
+ // or a "<" indication type arguments, or ";" and we are done.
+ while (!maybeEat(";")) {
+ if (maybeEat(".")) {
+ // outer type completed
+ outerType = new SimpleClassTypeSignature(identifier);
+ List nestedTypeList = new ArrayList();
+ do {
+ ret.append(".");
+ SimpleClassTypeSignature sig = parseSimpleClassTypeSignature();
+ ret.append(sig.toString());
+ nestedTypeList.add(sig);
+ } while (maybeEat("."));
+ nestedTypes = new SimpleClassTypeSignature[nestedTypeList.size()];
+ nestedTypeList.toArray(nestedTypes);
+ } else if (tokenStream[tokenIndex].equals("<")) {
+ ret.append("<");
+ TypeArgument[] tArgs = maybeParseTypeArguments();
+ for (int i = 0; i < tArgs.length; i++) {
+ ret.append(tArgs[i].toString());
+ }
+ ret.append(">");
+ outerType = new SimpleClassTypeSignature(identifier, tArgs);
+ // now parse possible nesteds...
+ List nestedTypeList = new ArrayList();
+ while (maybeEat(".")) {
+ ret.append(".");
+ SimpleClassTypeSignature sig = parseSimpleClassTypeSignature();
+ ret.append(sig.toString());
+ nestedTypeList.add(sig);
+ }
+ nestedTypes = new SimpleClassTypeSignature[nestedTypeList.size()];
+ nestedTypeList.toArray(nestedTypes);
+ } else {
+ throw new IllegalStateException("Expecting .,<, or ;, but found " + tokenStream[tokenIndex] + " while unpacking "
+ + inputString);
+ }
+ }
+ ret.append(";");
+ if (outerType == null)
+ outerType = new SimpleClassTypeSignature(ret.toString());
+ return new ClassTypeSignature(ret.toString(), outerType, nestedTypes);
+ }
+
+ private SimpleClassTypeSignature parseSimpleClassTypeSignature() {
+ String identifier = eatIdentifier();
+ TypeArgument[] tArgs = maybeParseTypeArguments();
+ if (tArgs != null) {
+ return new SimpleClassTypeSignature(identifier, tArgs);
+ } else {
+ return new SimpleClassTypeSignature(identifier);
+ }
+ }
+
+ private TypeArgument parseTypeArgument() {
+ boolean isPlus = false;
+ boolean isMinus = false;
+ if (maybeEat("*")) {
+ return new TypeArgument();
+ } else if (maybeEat("+")) {
+ isPlus = true;
+ } else if (maybeEat("-")) {
+ isMinus = true;
+ }
+ FieldTypeSignature sig = parseFieldTypeSignature(false);
+ return new TypeArgument(isPlus, isMinus, sig);
+ }
+
+ private TypeArgument[] maybeParseTypeArguments() {
+ if (maybeEat("<")) {
+ List typeArgs = new ArrayList();
+ do {
+ TypeArgument arg = parseTypeArgument();
+ typeArgs.add(arg);
+ } while (!maybeEat(">"));
+ TypeArgument[] tArgs = new TypeArgument[typeArgs.size()];
+ typeArgs.toArray(tArgs);
+ return tArgs;
+ } else {
+ return null;
+ }
+ }
+
+ private TypeVariableSignature parseTypeVariableSignature() {
+ TypeVariableSignature tv = new TypeVariableSignature(eatIdentifier());
+ eat(";");
+ return tv;
+ }
+
+ private boolean maybeEat(String token) {
+ if (tokenStream.length <= tokenIndex)
+ return false;
+ if (tokenStream[tokenIndex].equals(token)) {
+ tokenIndex++;
+ return true;
+ }
+ return false;
+ }
+
+ private void eat(String token) {
+ if (!tokenStream[tokenIndex].equals(token)) {
+ throw new IllegalStateException("Expecting " + token + " but found " + tokenStream[tokenIndex] + " while unpacking "
+ + inputString);
+ }
+ tokenIndex++;
+ }
+
+ private String eatIdentifier() {
+ return tokenStream[tokenIndex++];
+ }
+
+ /**
+ * non-private for test visibility Splits a string containing a generic signature into tokens for consumption by the parser.
+ */
+ public String[] tokenize(String signatureString) {
+ char[] chars = signatureString.toCharArray();
+ int index = 0;
+ List tokens = new ArrayList();
+ StringBuffer identifier = new StringBuffer();
+ boolean inParens = false;
+ boolean inArray = false;
+ boolean couldSeePrimitive = false;
+ do {
+ switch (chars[index]) {
+ case '<':
+ if (identifier.length() > 0)
+ tokens.add(identifier.toString());
+ identifier = new StringBuffer();
+ tokens.add("<");
+ break;
+ case '>':
+ if (identifier.length() > 0)
+ tokens.add(identifier.toString());
+ identifier = new StringBuffer();
+ tokens.add(">");
+ break;
+ case ':':
+ if (identifier.length() > 0)
+ tokens.add(identifier.toString());
+ identifier = new StringBuffer();
+ tokens.add(":");
+ break;
+ case '/':
+ if (identifier.length() > 0)
+ tokens.add(identifier.toString());
+ identifier = new StringBuffer();
+ tokens.add("/");
+ couldSeePrimitive = false;
+ break;
+ case ';':
+ if (identifier.length() > 0)
+ tokens.add(identifier.toString());
+ identifier = new StringBuffer();
+ tokens.add(";");
+ couldSeePrimitive = true;
+ inArray = false;
+ break;
+ case '^':
+ if (identifier.length() > 0)
+ tokens.add(identifier.toString());
+ identifier = new StringBuffer();
+ tokens.add("^");
+ break;
+ case '+':
+ tokens.add("+");
+ break;
+ case '-':
+ tokens.add("-");
+ break;
+ case '*':
+ tokens.add("*");
+ break;
+ case '.':
+ if (identifier.length() > 0)
+ tokens.add(identifier.toString());
+ identifier = new StringBuffer();
+ couldSeePrimitive = false;
+ tokens.add(".");
+ break;
+ case '(':
+ tokens.add("(");
+ inParens = true;
+ couldSeePrimitive = true;
+ break;
+ case ')':
+ tokens.add(")");
+ inParens = false;
+ break;
+ case '[':
+ tokens.add("[");
+ couldSeePrimitive = true;
+ inArray = true;
+ break;
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'F':
+ case 'I':
+ case 'J':
+ case 'S':
+ case 'V':
+ case 'Z':
+ if ((inParens || inArray) && couldSeePrimitive && identifier.length() == 0) {
+ tokens.add(new String("" + chars[index]));
+ } else {
+ identifier.append(chars[index]);
+ }
+ inArray = false;
+ break;
+ case 'L':
+ couldSeePrimitive = false;
+ // deliberate fall-through
+ default:
+ identifier.append(chars[index]);
+ }
+ } while ((++index) < chars.length);
+ if (identifier.length() > 0)
+ tokens.add(identifier.toString());
+ String[] tokenArray = new String[tokens.size()];
+ tokens.toArray(tokenArray);
+ return tokenArray;
+ }
+
+}