From: acolyer Date: Sun, 26 Jun 2005 20:29:23 +0000 (+0000) Subject: -- here be dragons -- X-Git-Tag: PRE_ANDY~114 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=6b94951b62cb77823ce164a512294b13450a7b82;p=aspectj.git -- here be dragons -- this is an early check-in for handover to Andy. I've added code to parse the generic signature attributes, but only completed parsing for class signature so far, method and field to do although these will reuse many of the same building blocks. Needs test cases and probably some more rework. Would not normally check-in at this stage. -- end of dragons -- --- diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/Signature.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/Signature.java index c55a00919..f05726596 100644 --- a/bcel-builder/src/org/aspectj/apache/bcel/classfile/Signature.java +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/Signature.java @@ -52,22 +52,31 @@ package org.aspectj.apache.bcel.classfile; * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . + * + * Extended by Adrian Colyer, June 2005 to support unpacking of Signature + * attribute */ + import org.aspectj.apache.bcel.Constants; + +import sun.reflect.generics.tree.SimpleClassTypeSignature; + import java.io.*; +import java.util.ArrayList; +import java.util.List; /** * This class is derived from Attribute and represents a reference * to a GJ attribute. * - * @version $Id: Signature.java,v 1.2 2004/11/19 16:45:18 aclement Exp $ + * @version $Id: Signature.java,v 1.3 2005/06/26 20:29:23 acolyer Exp $ * @author M. Dahm * @see Attribute */ public final class Signature extends Attribute { private int signature_index; - + /** * Initialize from another object. Note that both objects use the same * references (shallow copy). Use clone() for a physical copy. @@ -293,4 +302,410 @@ public final class Signature extends Attribute { public Attribute copy(ConstantPool constant_pool) { return (Signature)clone(); } + + // ============================================= + // AMC extensions + + /** + * structure capturing a FormalTypeParameter from the Signature grammar + */ + static class FormalTypeParameter { + String identifier; + FieldTypeSignature classBound; + FieldTypeSignature[] interfaceBounds; + } + + static abstract class FieldTypeSignature { + boolean isClassTypeSignature() { return false; } + boolean isTypeVariableSignature() { return false; } + boolean isArrayTypeSignature() { return false; } + } + + 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; + } + boolean isClassTypeSignature() { return true; } + } + + static class TypeVariableSignature extends FieldTypeSignature { + public String typeVariableName; + public TypeVariableSignature(String typeVarToken) { + this.typeVariableName = typeVarToken.substring(1); + } + boolean isTypeVariableSignature() { return true; } + } + + static class ArrayTypeSignature extends FieldTypeSignature { + public FieldTypeSignature fieldTypeSig; + public String baseTypeSig; + public boolean isBaseTypeArray; + public ArrayTypeSignature(FieldTypeSignature aFieldSig) { + this.fieldTypeSig = aFieldSig; + isBaseTypeArray = false; + } + public ArrayTypeSignature(String aBaseType) { + this.baseTypeSig = aBaseType; + isBaseTypeArray = true; + } + boolean isArrayTypeSignature() { return true; } + } + + 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(); + } + } + + 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; + } + + } + + /** + * can't ask questions of signature content until it has been parsed. + */ + private boolean isParsed = false; + + private FormalTypeParameter[] formalTypeParameters; + private ClassTypeSignature superclassSignature; + private ClassTypeSignature[] superInterfaceSignatures; + + private String[] tokenStream; // for parse in flight + private int tokenIndex = 0; + + public FormalTypeParameter[] getFormalTypeParameters() { + if (!isParsed) throw new IllegalStateException("Must parse signature attribute first"); + return formalTypeParameters; + } + + public ClassTypeSignature getSuperclassSignature() { + if (!isParsed) throw new IllegalStateException("Must parse signature attribute first"); + return superclassSignature; + } + + public ClassTypeSignature[] getSuperInterfaceSignatures() { + if (!isParsed) throw new IllegalStateException("Must parse signature attribute first"); + return superInterfaceSignatures; + } + + /** + * 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 void parseAsClassSignature() { + tokenStream = tokenize(getSignature()); + tokenIndex = 0; + // FormalTypeParameters-opt + if (maybeEat("<")) { + List formalTypeParametersList = new ArrayList(); + do { + formalTypeParametersList.add(parseFormalTypeParameter()); + } while (!maybeEat(">")); + formalTypeParameters = new FormalTypeParameter[formalTypeParametersList.size()]; + formalTypeParametersList.toArray(formalTypeParameters); + } + superclassSignature = parseClassTypeSignature(); + List superIntSigs = new ArrayList(); + while (tokenIndex < tokenStream.length) { + superIntSigs.add(parseClassTypeSignature()); + } + superInterfaceSignatures = new ClassTypeSignature[superIntSigs.size()]; + superIntSigs.toArray(superInterfaceSignatures); + isParsed = true; + } + + /** + * 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 void parseAsMethodSignature() { + isParsed = true; + } + + /** + * 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 void parseAsFieldSignature() { + isParsed = true; + } + + 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;","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("Expection [,L, or T, but found " + + tokenStream[tokenIndex]); + } + } + + private ArrayTypeSignature parseArrayTypeSignature() { + // opening [ already eaten + eat("["); // grammar adds another one! + FieldTypeSignature fieldType = parseFieldTypeSignature(true); + if (fieldType != null) { + return new ArrayTypeSignature(fieldType); + } else { + // must be BaseType array + return new ArrayTypeSignature(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(eatIdentifier()); + } + // 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(ret); + } 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(ret); + } + nestedTypes = new SimpleClassTypeSignature[nestedTypeList.size()]; + nestedTypeList.toArray(nestedTypes); + } else { + throw new IllegalStateException("Expecting .,<, or ;, but found " + tokenStream[tokenIndex]); + } + } + ret.append(";"); + 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[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]); + } + tokenIndex++; + } + + private String eatIdentifier() { + return tokenStream[tokenIndex++]; + } + + private String[] tokenize(String signatureString) { + char[] chars = signatureString.toCharArray(); + int index = 0; + List tokens = new ArrayList(); + StringBuffer identifier = new StringBuffer(); + do { + switch (chars[index]) { + case '<' : + tokens.add("<"); + break; + case '>' : + 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(";"); + break; + case '^': + tokens.add("^"); + break; + case '+': + tokens.add("+"); + break; + case '-': + tokens.add("-"); + break; + case '*': + tokens.add("*"); + case '.' : + if (identifier.length() > 0) tokens.add(identifier.toString()); + identifier = new StringBuffer(); + tokens.add("."); + break; + case '(' : + tokens.add("("); + break; + case ')' : + tokens.add(")"); + case '[' : + break; + 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; + } + }