Adds annotation parsing. Adds native method generation

This commit is contained in:
konsoletyper 2013-10-28 22:59:56 +04:00
parent df05104e3c
commit d63171e935
12 changed files with 478 additions and 256 deletions

View File

@ -3,12 +3,8 @@ package org.teavm.classlibgen;
import org.teavm.codegen.DefaultAliasProvider; import org.teavm.codegen.DefaultAliasProvider;
import org.teavm.codegen.DefaultNamingStrategy; import org.teavm.codegen.DefaultNamingStrategy;
import org.teavm.codegen.SourceWriter; import org.teavm.codegen.SourceWriter;
import org.teavm.javascript.MethodDecompiler; import org.teavm.javascript.Decompiler;
import org.teavm.javascript.Optimizer;
import org.teavm.javascript.Renderer;
import org.teavm.javascript.ast.RenderableMethod;
import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolder;
import org.teavm.model.MethodHolder;
import org.teavm.model.resource.ClasspathClassHolderSource; import org.teavm.model.resource.ClasspathClassHolderSource;
/** /**
@ -18,18 +14,12 @@ import org.teavm.model.resource.ClasspathClassHolderSource;
public class ClasslibTestGenerator { public class ClasslibTestGenerator {
public static void main(String[] args) { public static void main(String[] args) {
ClasspathClassHolderSource source = new ClasspathClassHolderSource(); ClasspathClassHolderSource source = new ClasspathClassHolderSource();
MethodDecompiler decompiler = new MethodDecompiler(source);
DefaultAliasProvider aliasProvider = new DefaultAliasProvider(); DefaultAliasProvider aliasProvider = new DefaultAliasProvider();
DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, source); DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, source);
SourceWriter writer = new SourceWriter(naming); SourceWriter writer = new SourceWriter(naming);
Renderer renderer = new Renderer(writer, source); Decompiler decompiler = new Decompiler(source, naming, writer);
Optimizer optimizer = new Optimizer();
ClassHolder cls = source.getClassHolder("java.lang.Object"); ClassHolder cls = source.getClassHolder("java.lang.Object");
for (MethodHolder method : cls.getMethods()) { decompiler.decompile(cls);
RenderableMethod renderableMethod = decompiler.decompile(method);
optimizer.optimize(renderableMethod);
renderer.render(renderableMethod);
}
System.out.println(writer); System.out.println(writer);
} }
} }

View File

@ -0,0 +1,25 @@
package org.teavm.javascript;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class DecompilationException extends RuntimeException {
private static final long serialVersionUID = -1400142974526572669L;
public DecompilationException() {
super();
}
public DecompilationException(String message, Throwable cause) {
super(message, cause);
}
public DecompilationException(String message) {
super(message);
}
public DecompilationException(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,149 @@
package org.teavm.javascript;
import java.util.Set;
import org.teavm.codegen.NamingStrategy;
import org.teavm.codegen.SourceWriter;
import org.teavm.javascript.ast.RenderableMethod;
import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.model.*;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class Decompiler {
private SourceWriter writer;
private MethodDecompiler methodDecompiler;
private NamingStrategy naming;
private Renderer renderer;
public Decompiler(ClassHolderSource classSource, NamingStrategy naming, SourceWriter writer) {
this.methodDecompiler = new MethodDecompiler(classSource);
this.renderer = new Renderer(writer, classSource);
this.writer = writer;
this.naming = naming;
}
public void decompile(ClassHolder cls) {
writer.appendClass(cls.getName()).append(" = function() {\n").indent().newLine();
for (FieldHolder field : cls.getFields()) {
if (field.getModifiers().contains(ElementModifier.STATIC)) {
continue;
}
Object value = field.getInitialValue();
if (value == null) {
value = getDefaultValue(field.getType());
}
writer.append("this.").appendField(cls.getName(), field.getName()).append(" = ")
.append(renderer.constantToString(value)).append(";").newLine();
}
writer.append("this.$class = ").appendClass(cls.getName()).append(";").newLine();
writer.outdent().append("}").newLine();
for (FieldHolder field : cls.getFields()) {
if (!field.getModifiers().contains(ElementModifier.STATIC)) {
continue;
}
Object value = field.getInitialValue();
if (value == null) {
value = getDefaultValue(field.getType());
}
writer.appendClass(cls.getName()).append('.')
.appendField(cls.getName(), field.getName()).append(" = ")
.append(renderer.constantToString(value)).append(";").newLine();
}
writer.appendClass(cls.getName()).append(".prototype = new ")
.append(cls.getParent() != null ? naming.getNameFor(cls.getParent()) :
"Object").append("();").newLine();
writer.appendClass(cls.getName()).append(".$meta = { ");
writer.append("supertypes : [");
boolean first = true;
if (cls.getParent() != null) {
writer.appendClass(cls.getParent());
first = false;
}
for (String iface : cls.getInterfaces()) {
if (!first) {
writer.append(", ");
}
first = false;
writer.appendClass(iface);
}
writer.append("]");
writer.append(" };").newLine();
for (MethodHolder method : cls.getMethods()) {
Set<ElementModifier> modifiers = method.getModifiers();
if (modifiers.contains(ElementModifier.ABSTRACT)) {
continue;
}
if (modifiers.contains(ElementModifier.NATIVE)) {
AnnotationHolder annotHolder = method.getAnnotations().get(GeneratedBy.class.getName());
if (annotHolder == null) {
throw new DecompilationException("Method " + cls.getName() + "." + method.getDescriptor() +
" is native, but no " + GeneratedBy.class.getName() + " annotation found");
}
ValueType annotValue = annotHolder.getValues().get("value").getJavaClass();
String generatorClassName = ((ValueType.Object)annotValue).getClassName();
generateNativeMethod(generatorClassName, method);
} else {
RenderableMethod renderableMethod = methodDecompiler.decompile(method);
Optimizer optimizer = new Optimizer();
optimizer.optimize(renderableMethod);
renderer.render(renderableMethod);
}
}
}
private void generateNativeMethod(String generatorClassName, MethodHolder method) {
Generator generator;
try {
Class<?> generatorClass = Class.forName(generatorClassName);
generator = (Generator)generatorClass.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
throw new DecompilationException("Error instantiating generator " + generatorClassName +
" for native method " + method.getOwner().getName() + "." + method.getDescriptor());
}
MethodReference ref = new MethodReference(method.getOwner().getName(), method.getDescriptor());
generator.generate(new Context(), writer, ref);
}
private static Object getDefaultValue(ValueType type) {
if (type instanceof ValueType.Primitive) {
ValueType.Primitive primitive = (ValueType.Primitive)type;
switch (primitive.getKind()) {
case BOOLEAN:
return false;
case BYTE:
return (byte)0;
case SHORT:
return (short)0;
case INTEGER:
return 0;
case CHARACTER:
return '\0';
case LONG:
return 0L;
case FLOAT:
return 0F;
case DOUBLE:
return 0.0;
}
}
return null;
}
private class Context implements GeneratorContext {
@Override
public String getParameterName(int index) {
return renderer.variableName(index);
}
@Override
public NamingStrategy getNaming() {
return naming;
}
}
}

View File

@ -15,7 +15,6 @@
*/ */
package org.teavm.javascript; package org.teavm.javascript;
import java.util.Set;
import org.teavm.codegen.NamingStrategy; import org.teavm.codegen.NamingStrategy;
import org.teavm.codegen.SourceWriter; import org.teavm.codegen.SourceWriter;
import org.teavm.javascript.ast.*; import org.teavm.javascript.ast.*;
@ -37,88 +36,12 @@ public class Renderer implements ExprVisitor, StatementVisitor {
this.classSource = classSource; this.classSource = classSource;
} }
public void render(RenderableClass cls) { public SourceWriter getWriter() {
ClassHolder metadata = cls.getMetadata(); return writer;
writer.appendClass(metadata.getName()).append(" = function() {\n").indent().newLine();
for (FieldHolder field : cls.getFields()) {
if (field.getModifiers().contains(ElementModifier.STATIC)) {
continue;
}
Object value = field.getInitialValue();
if (value == null) {
value = getDefaultValue(field.getType());
}
writer.append("this.").appendField(metadata.getName(), field.getName()).append(" = ")
.append(constantToString(value)).append(";").newLine();
}
writer.append("this.$class = ").appendClass(metadata.getName()).append(";").newLine();
writer.outdent().append("}").newLine();
for (FieldHolder field : cls.getFields()) {
if (!field.getModifiers().contains(ElementModifier.STATIC)) {
continue;
}
Object value = field.getInitialValue();
if (value == null) {
value = getDefaultValue(field.getType());
}
writer.appendClass(metadata.getName()).append('.')
.appendField(metadata.getName(), field.getName()).append(" = ")
.append(constantToString(value)).append(";").newLine();
}
writer.appendClass(metadata.getName()).append(".prototype = new ")
.append(metadata.getParent() != null ? naming.getNameFor(metadata.getParent()) :
"Object").append("();").newLine();
writer.appendClass(metadata.getName()).append(".$meta = { ");
writer.append("supertypes : [");
boolean first = true;
if (metadata.getParent() != null) {
writer.appendClass(metadata.getParent());
first = false;
}
for (String iface : metadata.getInterfaces()) {
if (!first) {
writer.append(", ");
}
first = false;
writer.appendClass(iface);
}
writer.append("]");
writer.append(" };").newLine();
for (RenderableMethod method : cls.getMethods()) {
MethodHolder methodMetadata = method.getMetadata();
Set<ElementModifier> modifiers = methodMetadata.getModifiers();
if (modifiers.contains(ElementModifier.ABSTRACT)) {
continue;
}
render(method);
}
} }
private static Object getDefaultValue(ValueType type) { public NamingStrategy getNaming() {
if (type instanceof ValueType.Primitive) { return naming;
ValueType.Primitive primitive = (ValueType.Primitive)type;
switch (primitive.getKind()) {
case BOOLEAN:
return false;
case BYTE:
return (byte)0;
case SHORT:
return (short)0;
case INTEGER:
return 0;
case CHARACTER:
return '\0';
case LONG:
return 0L;
case FLOAT:
return 0F;
case DOUBLE:
return 0.0;
}
}
return null;
} }
private void renderInitializer(RenderableMethod method) { private void renderInitializer(RenderableMethod method) {

View File

@ -1,54 +0,0 @@
/*
* Copyright 2012 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.javascript.ast;
import java.util.List;
import org.teavm.model.ClassHolder;
import org.teavm.model.FieldHolder;
/**
*
* @author Alexey Andreev
*/
public class RenderableClass {
private ClassHolder metadata;
private List<RenderableMethod> methods;
private List<FieldHolder> fields;
public RenderableClass(ClassHolder metadata) {
this.metadata = metadata;
}
public ClassHolder getMetadata() {
return metadata;
}
public List<RenderableMethod> getMethods() {
return methods;
}
public void setMethods(List<RenderableMethod> methods) {
this.methods = methods;
}
public List<FieldHolder> getFields() {
return fields;
}
public void setFields(List<FieldHolder> fields) {
this.fields = fields;
}
}

View File

@ -1,9 +1,13 @@
package org.teavm.javascript.ni; package org.teavm.javascript.ni;
import org.teavm.codegen.NamingStrategy;
/** /**
* *
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
public interface GeneratorContext { public interface GeneratorContext {
String getParameterName(int index); String getParameterName(int index);
NamingStrategy getNaming();
} }

View File

@ -0,0 +1,35 @@
package org.teavm.model;
import java.util.Map;
import java.util.HashMap;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class AnnotationContainer {
private Map<String, AnnotationHolder> annotations = new HashMap<>();
public void add(AnnotationHolder annotation) {
if (annotations.containsKey(annotation.getType())) {
throw new IllegalArgumentException("Annotation of type " + annotation.getType() + " is already there");
}
annotations.put(annotation.getType(), annotation);
}
public AnnotationHolder get(String type) {
return annotations.get(type);
}
public void remove(AnnotationHolder annotation) {
AnnotationHolder existingAnnot = get(annotation.getType());
if (existingAnnot != annotation) {
throw new IllegalArgumentException("There is no such annotation");
}
annotations.remove(annotation.getType());
}
public void remove(String type) {
annotations.remove(type);
}
}

View File

@ -24,7 +24,7 @@ import java.util.Map;
*/ */
public class AnnotationHolder { public class AnnotationHolder {
private String type; private String type;
private Map<String, AnnotationValueHolder> values = new HashMap<>(); private Map<String, AnnotationValue> values = new HashMap<>();
public AnnotationHolder(String type) { public AnnotationHolder(String type) {
this.type = type; this.type = type;
@ -34,7 +34,7 @@ public class AnnotationHolder {
return type; return type;
} }
public Map<String, AnnotationValueHolder> getValues() { public Map<String, AnnotationValue> getValues() {
return values; return values;
} }
} }

View File

@ -0,0 +1,184 @@
/*
* Copyright 2013 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.model;
import java.util.List;
/**
*
* @author Alexey Andreev
*/
public class AnnotationValue {
private static final byte BOOLEAN = 0;
private static final byte BYTE = 1;
private static final byte SHORT = 2;
private static final byte INT = 3;
private static final byte LONG = 4;
private static final byte FLOAT = 5;
private static final byte DOUBLE = 6;
private static final byte STRING = 7;
private static final byte CLASS = 8;
private static final byte LIST = 9;
private static final byte ENUM = 10;
private static final byte ANNOTATION = 11;
private byte type;
private Object value;
public AnnotationValue(boolean value) {
this.type = BOOLEAN;
this.value = value;
}
public AnnotationValue(byte value) {
this.type = BYTE;
this.value = value;
}
public AnnotationValue(short value) {
this.type = SHORT;
this.value = value;
}
public AnnotationValue(int value) {
this.type = INT;
this.value = value;
}
public AnnotationValue(long value) {
this.type = LONG;
this.value = value;
}
public AnnotationValue(float value) {
this.type = FLOAT;
this.value = value;
}
public AnnotationValue(double value) {
this.type = DOUBLE;
this.value = value;
}
public AnnotationValue(String value) {
this.type = STRING;
this.value = value;
}
public AnnotationValue(ValueType value) {
this.type = CLASS;
this.value = value;
}
public AnnotationValue(List<AnnotationValue> value) {
this.type = LIST;
this.value = value;
}
public AnnotationValue(AnnotationHolder value) {
this.type = ANNOTATION;
this.value = value;
}
public AnnotationValue(FieldReference value) {
this.type = ENUM;
this.value = value;
}
public boolean getBoolean() {
if (type != BOOLEAN) {
throw new IllegalStateException("There is no boolean value");
}
return (Boolean)value;
}
public byte getByte() {
if (type != BYTE) {
throw new IllegalStateException("There is no byte value");
}
return (Byte)value;
}
public short getShort() {
if (type != SHORT) {
throw new IllegalStateException("There is no short value");
}
return (Short)value;
}
public int getInt() {
if (type != INT) {
throw new IllegalStateException("There is no int value");
}
return (Integer)value;
}
public long getLong() {
if (type != LONG) {
throw new IllegalStateException("There is no long value");
}
return (Long)value;
}
public float getFloat() {
if (type != FLOAT) {
throw new IllegalStateException("There is no float value");
}
return (Float)value;
}
public double getDouble() {
if (type != DOUBLE) {
throw new IllegalStateException("There is no double value");
}
return (Double)value;
}
public String getString() {
if (type != STRING) {
throw new IllegalStateException("There is no String value");
}
return (String)value;
}
public ValueType getJavaClass() {
if (type != CLASS) {
throw new IllegalStateException("There is no ValueType value");
}
return (ValueType)value;
}
@SuppressWarnings("unchecked")
public List<AnnotationValue> getList() {
if (type != LIST) {
throw new IllegalStateException("There is no List value");
}
return (List<AnnotationValue>)value;
}
public FieldReference getEnumValue() {
if (type != ENUM) {
throw new IllegalStateException("There is no enum value");
}
return (FieldReference)value;
}
public AnnotationHolder getAnnotation() {
if (type != ANNOTATION) {
throw new IllegalStateException("There is no annotation value");
}
return (AnnotationHolder)value;
}
}

View File

@ -1,48 +0,0 @@
/*
* Copyright 2013 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.model;
import java.util.List;
/**
*
* @author Alexey Andreev
*/
public interface AnnotationValueHolder {
boolean getBoolean();
byte getByte();
short getShort();
int getInteger();
long getLong();
float getFloat();
double getDouble();
String getString();
ValueType getJavaClass();
List<AnnotationValueHolder> getList();
String getEnumValue();
AnnotationHolder getAnnotation();
}

View File

@ -16,8 +16,6 @@
package org.teavm.model; package org.teavm.model;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
/** /**
* *
@ -25,7 +23,7 @@ import java.util.Map;
*/ */
public abstract class ElementHolder { public abstract class ElementHolder {
private EnumSet<ElementModifier> modifiers = EnumSet.noneOf(ElementModifier.class); private EnumSet<ElementModifier> modifiers = EnumSet.noneOf(ElementModifier.class);
private Map<String, AnnotationHolder> annotations = new HashMap<>(); private AnnotationContainer annotations = new AnnotationContainer();
private AccessLevel level = AccessLevel.PACKAGE_PRIVATE; private AccessLevel level = AccessLevel.PACKAGE_PRIVATE;
private String name; private String name;
@ -49,7 +47,7 @@ public abstract class ElementHolder {
return name; return name;
} }
public Map<String, AnnotationHolder> getAnnotations() { public AnnotationContainer getAnnotations() {
return annotations; return annotations;
} }
} }

View File

@ -1,16 +1,11 @@
package org.teavm.parsing; package org.teavm.parsing;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.List;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.Type;
import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.*;
import org.objectweb.asm.tree.MethodNode;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.model.util.ListingBuilder;
import org.teavm.optimization.UnreachableBasicBlockEliminator; import org.teavm.optimization.UnreachableBasicBlockEliminator;
/** /**
@ -28,6 +23,7 @@ public class Parser {
SSATransformer ssaProducer = new SSATransformer(); SSATransformer ssaProducer = new SSATransformer();
ssaProducer.transformToSSA(program, method.getParameterTypes()); ssaProducer.transformToSSA(program, method.getParameterTypes());
method.setProgram(program); method.setProgram(program);
parseAnnotations(method.getAnnotations(), node);
return method; return method;
} }
@ -50,6 +46,7 @@ public class Parser {
MethodNode methodNode = (MethodNode)obj; MethodNode methodNode = (MethodNode)obj;
cls.addMethod(parseMethod(methodNode)); cls.addMethod(parseMethod(methodNode));
} }
parseAnnotations(cls.getAnnotations(), node);
return cls; return cls;
} }
@ -58,6 +55,7 @@ public class Parser {
field.setType(ValueType.parse(node.desc)); field.setType(ValueType.parse(node.desc));
field.setInitialValue(node.value); field.setInitialValue(node.value);
parseModifiers(node.access, field); parseModifiers(node.access, field);
parseAnnotations(field.getAnnotations(), node);
return field; return field;
} }
@ -120,59 +118,77 @@ public class Parser {
} }
} }
public static void main(String[] args) throws IOException { @SuppressWarnings("unchecked")
Class<?>[] classesToParse = { Object.class, String.class, ArrayList.class, private static void parseAnnotations(AnnotationContainer annotations, MemberNode node) {
StringBuilder.class, HashMap.class }; List<Object> annotNodes = new ArrayList<>();
ClassLoader classLoader = Parser.class.getClassLoader(); if (node.visibleAnnotations != null) {
for (Class<?> cls : classesToParse) { annotNodes.addAll(node.visibleAnnotations);
try (InputStream input = classLoader.getResourceAsStream(cls.getName().replace('.', '/') + ".class")) { }
ClassReader reader = new ClassReader(input); if (node.invisibleAnnotations != null) {
ClassNode node = new ClassNode(); annotNodes.addAll(node.invisibleAnnotations);
reader.accept(node, 0); }
display(parseClass(node)); for (Object obj : annotNodes) {
AnnotationNode annotNode = (AnnotationNode)obj;
String desc = annotNode.desc;
if (desc.startsWith("L") && desc.endsWith(";")) {
desc = desc.substring(1, desc.length() - 1);
} }
desc = desc.replace('/', '.');
AnnotationHolder annot = new AnnotationHolder(desc);
parseAnnotationValues(annot, annotNode.values);
annotations.add(annot);
} }
} }
private static void display(ClassHolder cls) { private static void parseAnnotationValues(AnnotationHolder annot, List<Object> values) {
System.out.print(cls.getLevel()); if (values == null) {
for (ElementModifier modifier : cls.getModifiers()) { return;
System.out.print(" " + modifier);
} }
System.out.print(" class " + cls.getName()); for (int i = 0; i < values.size(); i += 2) {
if (cls.getParent() != null) { String key = (String)values.get(i);
System.out.print(" extends " + cls.getParent()); Object value = values.get(i + 1);
annot.getValues().put(key, parseAnnotationValue(value));
} }
if (!cls.getInterfaces().isEmpty()) { }
System.out.print(" implements ");
boolean first = true; @SuppressWarnings("unchecked")
for (String iface : cls.getInterfaces()) { private static AnnotationValue parseAnnotationValue(Object value) {
if (!first) { if (value instanceof String[]) {
System.out.print(", "); String[] enumInfo = (String[])value;
} else { return new AnnotationValue(new FieldReference(enumInfo[0], enumInfo[1]));
first = false; } else if (value instanceof Type) {
} Type cls = (Type)value;
System.out.print(iface); return new AnnotationValue(ValueType.parse(cls.getDescriptor()));
} else if (value instanceof List<?>) {
List<?> originalList = (List<?>)value;
List<AnnotationValue> resultList = new ArrayList<>();
for (Object item : originalList) {
resultList.add(parseAnnotationValue(item));
} }
return new AnnotationValue(resultList);
} else if (value instanceof AnnotationNode) {
AnnotationNode annotNode = (AnnotationNode)value;
AnnotationHolder annotation = new AnnotationHolder(annotNode.desc.replace('.', '/'));
parseAnnotationValues(annotation, annotNode.values);
return new AnnotationValue(annotation);
} else if (value instanceof String) {
return new AnnotationValue((String)value);
} else if (value instanceof Boolean) {
return new AnnotationValue((Boolean)value);
} else if (value instanceof Byte) {
return new AnnotationValue((Byte)value);
} else if (value instanceof Short) {
return new AnnotationValue((Short)value);
} else if (value instanceof Integer) {
return new AnnotationValue((Integer)value);
} else if (value instanceof Long) {
return new AnnotationValue((Long)value);
} else if (value instanceof Float) {
return new AnnotationValue((Float)value);
} else if (value instanceof Double) {
return new AnnotationValue((Double)value);
} else {
throw new AssertionError();
} }
System.out.println();
for (FieldHolder field : cls.getFields()) {
System.out.print(" " + field.getLevel());
for (ElementModifier modifier : field.getModifiers()) {
System.out.print(" " + modifier);
}
System.out.println(" " + field.getName() + " : " + field.getType());
}
ListingBuilder listingBuilder = new ListingBuilder();
for (MethodHolder method : cls.getMethods()) {
System.out.print(" " + method.getLevel());
for (ElementModifier modifier : method.getModifiers()) {
System.out.print(" " + modifier);
}
System.out.println(" " + method.getDescriptor());
System.out.println(listingBuilder.buildListing(method.getProgram(), " "));
}
System.out.println();
System.out.println();
} }
} }