From af9c364c5c91adbd4488def989eee3211324e323 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Tue, 13 Dec 2011 18:28:49 +0400 Subject: [PATCH] JetSignatureVisitor and subclasses --- .../jet/codegen/BothSignatureWriter.java | 4 + .../codegen/signature/JetSignatureReader.java | 161 ++++++++++++++ .../signature/JetSignatureVisitor.java | 141 ++++++++++++ .../codegen/signature/JetSignatureWriter.java | 201 ++++++++++++++++++ 4 files changed, 507 insertions(+) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureReader.java create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureVisitor.java create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureWriter.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java b/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java index e63487fc198..f2cb8838b1d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.codegen; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.codegen.signature.JetSignatureWriter; import org.objectweb.asm.Type; import org.objectweb.asm.signature.SignatureVisitor; import org.objectweb.asm.signature.SignatureWriter; @@ -29,6 +30,9 @@ public class BothSignatureWriter { private final SignatureWriter signatureWriter = new SignatureWriter(); private final SignatureVisitor signatureVisitor; + + private final JetSignatureWriter jetSignatureWriter = new JetSignatureWriter(); + private final Mode mode; public BothSignatureWriter(Mode mode) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureReader.java b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureReader.java new file mode 100644 index 00000000000..6485efde6bf --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureReader.java @@ -0,0 +1,161 @@ +package org.jetbrains.jet.codegen.signature; + +import org.objectweb.asm.signature.SignatureReader; +import org.objectweb.asm.signature.SignatureVisitor; + +/** + * @author Stepan Koltsov + * + * @see SignatureReader + */ +public class JetSignatureReader { + + private final String signature; + + public JetSignatureReader(String signature) { + this.signature = signature; + } + + + public void accept(final JetSignatureVisitor v) { + String signature = this.signature; + int len = signature.length(); + int pos; + char c; + + if (signature.charAt(0) == '<') { + pos = 2; + do { + int end = signature.indexOf(':', pos); + v.visitFormalTypeParameter(signature.substring(pos - 1, end)); + pos = end + 1; + + c = signature.charAt(pos); + if (c == 'L' || c == '[' || c == 'T') { + pos = parseType(signature, pos, v.visitClassBound()); + } + + while ((c = signature.charAt(pos++)) == ':') { + pos = parseType(signature, pos, v.visitInterfaceBound()); + } + } while (c != '>'); + } else { + pos = 0; + } + + if (signature.charAt(pos) == '(') { + pos++; + while (signature.charAt(pos) != ')') { + pos = parseType(signature, pos, v.visitParameterType()); + } + pos = parseType(signature, pos + 1, v.visitReturnType()); + while (pos < len) { + pos = parseType(signature, pos + 1, v.visitExceptionType()); + } + } else { + pos = parseType(signature, pos, v.visitSuperclass()); + while (pos < len) { + pos = parseType(signature, pos, v.visitInterface()); + } + } + } + + + private static int parseType( + final String signature, + int pos, + final JetSignatureVisitor v) + { + char c; + int start, end; + boolean visited, inner; + String name; + + boolean nullable = false; + if (signature.charAt(pos) == '?') { + nullable = true; + pos++; + } + + switch (c = signature.charAt(pos++)) { + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + case 'F': + case 'J': + case 'D': + case 'V': + v.visitBaseType(c, nullable); + return pos; + + case '[': + return parseType(signature, pos, v.visitArrayType(nullable)); + + case 'T': + end = signature.indexOf(';', pos); + v.visitTypeVariable(signature.substring(pos, end), nullable); + return end + 1; + + default: // case 'L': + start = pos; + visited = false; + inner = false; + for (;;) { + switch (c = signature.charAt(pos++)) { + case '.': + case ';': + if (!visited) { + name = signature.substring(start, pos - 1); + if (inner) { + v.visitInnerClassType(name, nullable); + } else { + v.visitClassType(name, nullable); + } + } + if (c == ';') { + v.visitEnd(); + return pos; + } + start = pos; + visited = false; + inner = true; + break; + + case '<': + name = signature.substring(start, pos - 1); + if (inner) { + v.visitInnerClassType(name, nullable); + } else { + v.visitClassType(name, nullable); + } + visited = true; + top: for (;;) { + switch (c = signature.charAt(pos)) { + case '>': + break top; + case '*': + ++pos; + v.visitTypeArgument(); + break; + case '+': + case '-': + pos = parseType(signature, + pos + 1, + v.visitTypeArgument(c)); + break; + default: + pos = parseType(signature, + pos, + v.visitTypeArgument('=')); + break; + } + } + } + } + } + } + + +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureVisitor.java b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureVisitor.java new file mode 100644 index 00000000000..04e1319dd03 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureVisitor.java @@ -0,0 +1,141 @@ +package org.jetbrains.jet.codegen.signature; + +import org.objectweb.asm.signature.SignatureVisitor; + +/** + * @author Stepan Koltsov + * + * @see SignatureVisitor + * @url http://confluence.jetbrains.net/display/JET/Jet+Signatures + */ +public interface JetSignatureVisitor { + + /** + * Wildcard for an "extends" type argument. + */ + char EXTENDS = '+'; + + /** + * Wildcard for a "super" type argument. + */ + char SUPER = '-'; + + /** + * Wildcard for a normal type argument. + */ + char INSTANCEOF = '='; + + /** + * Visits a formal type parameter. + * + * @param name the name of the formal parameter. + */ + void visitFormalTypeParameter(String name); + + /** + * Visits the class bound of the last visited formal type parameter. + * + * @return a non null visitor to visit the signature of the class bound. + */ + JetSignatureVisitor visitClassBound(); + + /** + * Visits an interface bound of the last visited formal type parameter. + * + * @return a non null visitor to visit the signature of the interface bound. + */ + JetSignatureVisitor visitInterfaceBound(); + + /** + * Visits the type of the super class. + * + * @return a non null visitor to visit the signature of the super class + * type. + */ + JetSignatureVisitor visitSuperclass(); + + /** + * Visits the type of an interface implemented by the class. + * + * @return a non null visitor to visit the signature of the interface type. + */ + JetSignatureVisitor visitInterface(); + + /** + * Visits the type of a method parameter. + * + * @return a non null visitor to visit the signature of the parameter type. + */ + JetSignatureVisitor visitParameterType(); + + /** + * Visits the return type of the method. + * + * @return a non null visitor to visit the signature of the return type. + */ + JetSignatureVisitor visitReturnType(); + + /** + * Visits the type of a method exception. + * + * @return a non null visitor to visit the signature of the exception type. + */ + JetSignatureVisitor visitExceptionType(); + + /** + * Visits a signature corresponding to a primitive type. + * + * @param descriptor the descriptor of the primitive type, or 'V' for + * void. + */ + void visitBaseType(char descriptor, boolean nullable); + + /** + * Visits a signature corresponding to a type variable. + * + * @param name the name of the type variable. + */ + void visitTypeVariable(String name, boolean nullable); + + /** + * Visits a signature corresponding to an array type. + * + * @return a non null visitor to visit the signature of the array element + * type. + */ + JetSignatureVisitor visitArrayType(boolean nullable); + + /** + * Starts the visit of a signature corresponding to a class or interface + * type. + * + * @param name the internal name of the class or interface. + */ + void visitClassType(String name, boolean nullable); + + /** + * Visits an inner class. + * + * @param name the local name of the inner class in its enclosing class. + */ + void visitInnerClassType(String name, boolean nullable); + + /** + * Visits an unbounded type argument of the last visited class or inner + * class type. + */ + void visitTypeArgument(); + + /** + * Visits a type argument of the last visited class or inner class type. + * + * @param wildcard '+', '-' or '='. + * @return a non null visitor to visit the signature of the type argument. + */ + JetSignatureVisitor visitTypeArgument(char wildcard); + + /** + * Ends the visit of a signature corresponding to a class or interface type. + */ + void visitEnd(); +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureWriter.java b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureWriter.java new file mode 100644 index 00000000000..b85d48b3ecc --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureWriter.java @@ -0,0 +1,201 @@ +package org.jetbrains.jet.codegen.signature; + +import org.objectweb.asm.signature.SignatureWriter; + +/** + * @author Stepan Koltsov + * + * @see SignatureWriter + */ +public class JetSignatureWriter implements JetSignatureVisitor { + + /** + * Buffer used to construct the signature. + */ + private final StringBuffer buf = new StringBuffer(); + + /** + * Indicates if the signature contains formal type parameters. + */ + private boolean hasFormals; + + /** + * Indicates if the signature contains method parameter types. + */ + private boolean hasParameters; + + /** + * Stack used to keep track of class types that have arguments. Each element + * of this stack is a boolean encoded in one bit. The top of the stack is + * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping = + * /2. + */ + private int argumentStack; + + /** + * Constructs a new {@link SignatureWriter} object. + */ + public JetSignatureWriter() { + } + + // ------------------------------------------------------------------------ + // Implementation of the SignatureVisitor interface + // ------------------------------------------------------------------------ + + @Override + public void visitFormalTypeParameter(final String name) { + if (!hasFormals) { + hasFormals = true; + buf.append('<'); + } + buf.append(name); + buf.append(':'); + } + + @Override + public JetSignatureWriter visitClassBound() { + return this; + } + + @Override + public JetSignatureWriter visitInterfaceBound() { + buf.append(':'); + return this; + } + + @Override + public JetSignatureWriter visitSuperclass() { + endFormals(); + return this; + } + + @Override + public JetSignatureWriter visitInterface() { + return this; + } + + @Override + public JetSignatureWriter visitParameterType() { + endFormals(); + if (!hasParameters) { + hasParameters = true; + buf.append('('); + } + return this; + } + + @Override + public JetSignatureWriter visitReturnType() { + endFormals(); + if (!hasParameters) { + buf.append('('); + } + buf.append(')'); + return this; + } + + @Override + public JetSignatureWriter visitExceptionType() { + buf.append('^'); + return this; + } + + private void visitNullabe(boolean nullable) { + if (nullable) { + buf.append('?'); + } + } + + @Override + public void visitBaseType(final char descriptor, boolean nullable) { + visitNullabe(nullable); + buf.append(descriptor); + } + + @Override + public void visitTypeVariable(final String name, boolean nullable) { + visitNullabe(nullable); + buf.append('T'); + buf.append(name); + buf.append(';'); + } + + @Override + public JetSignatureWriter visitArrayType(boolean nullable) { + visitNullabe(nullable); + buf.append('['); + return this; + } + + @Override + public void visitClassType(final String name, boolean nullable) { + visitNullabe(nullable); + buf.append('L'); + buf.append(name); + argumentStack *= 2; + } + + @Override + public void visitInnerClassType(final String name, boolean nullable) { + endArguments(); + visitNullabe(nullable); + buf.append('.'); + buf.append(name); + argumentStack *= 2; + } + + @Override + public void visitTypeArgument() { + if (argumentStack % 2 == 0) { + ++argumentStack; + buf.append('<'); + } + buf.append('*'); + } + + @Override + public JetSignatureWriter visitTypeArgument(final char wildcard) { + if (argumentStack % 2 == 0) { + ++argumentStack; + buf.append('<'); + } + if (wildcard != '=') { + buf.append(wildcard); + } + return this; + } + + @Override + public void visitEnd() { + endArguments(); + buf.append(';'); + } + + public String toString() { + return buf.toString(); + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + /** + * Ends the formal type parameters section of the signature. + */ + private void endFormals() { + if (hasFormals) { + hasFormals = false; + buf.append('>'); + } + } + + /** + * Ends the type arguments of a class or inner class type. + */ + private void endArguments() { + if (argumentStack % 2 != 0) { + buf.append('>'); + } + argumentStack /= 2; + } +}