mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04:10 -08:00
Adds annotation parsing. Adds native method generation
This commit is contained in:
parent
df05104e3c
commit
d63171e935
|
@ -3,12 +3,8 @@ package org.teavm.classlibgen;
|
|||
import org.teavm.codegen.DefaultAliasProvider;
|
||||
import org.teavm.codegen.DefaultNamingStrategy;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.javascript.MethodDecompiler;
|
||||
import org.teavm.javascript.Optimizer;
|
||||
import org.teavm.javascript.Renderer;
|
||||
import org.teavm.javascript.ast.RenderableMethod;
|
||||
import org.teavm.javascript.Decompiler;
|
||||
import org.teavm.model.ClassHolder;
|
||||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.model.resource.ClasspathClassHolderSource;
|
||||
|
||||
/**
|
||||
|
@ -18,18 +14,12 @@ import org.teavm.model.resource.ClasspathClassHolderSource;
|
|||
public class ClasslibTestGenerator {
|
||||
public static void main(String[] args) {
|
||||
ClasspathClassHolderSource source = new ClasspathClassHolderSource();
|
||||
MethodDecompiler decompiler = new MethodDecompiler(source);
|
||||
DefaultAliasProvider aliasProvider = new DefaultAliasProvider();
|
||||
DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, source);
|
||||
SourceWriter writer = new SourceWriter(naming);
|
||||
Renderer renderer = new Renderer(writer, source);
|
||||
Optimizer optimizer = new Optimizer();
|
||||
Decompiler decompiler = new Decompiler(source, naming, writer);
|
||||
ClassHolder cls = source.getClassHolder("java.lang.Object");
|
||||
for (MethodHolder method : cls.getMethods()) {
|
||||
RenderableMethod renderableMethod = decompiler.decompile(method);
|
||||
optimizer.optimize(renderableMethod);
|
||||
renderer.render(renderableMethod);
|
||||
}
|
||||
decompiler.decompile(cls);
|
||||
System.out.println(writer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
149
teavm-core/src/main/java/org/teavm/javascript/Decompiler.java
Normal file
149
teavm-core/src/main/java/org/teavm/javascript/Decompiler.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package org.teavm.javascript;
|
||||
|
||||
import java.util.Set;
|
||||
import org.teavm.codegen.NamingStrategy;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.javascript.ast.*;
|
||||
|
@ -37,88 +36,12 @@ public class Renderer implements ExprVisitor, StatementVisitor {
|
|||
this.classSource = classSource;
|
||||
}
|
||||
|
||||
public void render(RenderableClass cls) {
|
||||
ClassHolder metadata = cls.getMetadata();
|
||||
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);
|
||||
}
|
||||
public SourceWriter getWriter() {
|
||||
return writer;
|
||||
}
|
||||
|
||||
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;
|
||||
public NamingStrategy getNaming() {
|
||||
return naming;
|
||||
}
|
||||
|
||||
private void renderInitializer(RenderableMethod method) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -1,9 +1,13 @@
|
|||
package org.teavm.javascript.ni;
|
||||
|
||||
import org.teavm.codegen.NamingStrategy;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public interface GeneratorContext {
|
||||
String getParameterName(int index);
|
||||
|
||||
NamingStrategy getNaming();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -24,7 +24,7 @@ import java.util.Map;
|
|||
*/
|
||||
public class AnnotationHolder {
|
||||
private String type;
|
||||
private Map<String, AnnotationValueHolder> values = new HashMap<>();
|
||||
private Map<String, AnnotationValue> values = new HashMap<>();
|
||||
|
||||
public AnnotationHolder(String type) {
|
||||
this.type = type;
|
||||
|
@ -34,7 +34,7 @@ public class AnnotationHolder {
|
|||
return type;
|
||||
}
|
||||
|
||||
public Map<String, AnnotationValueHolder> getValues() {
|
||||
public Map<String, AnnotationValue> getValues() {
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
|
184
teavm-core/src/main/java/org/teavm/model/AnnotationValue.java
Normal file
184
teavm-core/src/main/java/org/teavm/model/AnnotationValue.java
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -16,8 +16,6 @@
|
|||
package org.teavm.model;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -25,7 +23,7 @@ import java.util.Map;
|
|||
*/
|
||||
public abstract class ElementHolder {
|
||||
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 String name;
|
||||
|
||||
|
@ -49,7 +47,7 @@ public abstract class ElementHolder {
|
|||
return name;
|
||||
}
|
||||
|
||||
public Map<String, AnnotationHolder> getAnnotations() {
|
||||
public AnnotationContainer getAnnotations() {
|
||||
return annotations;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
package org.teavm.parsing;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import java.util.List;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.*;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.model.util.ListingBuilder;
|
||||
import org.teavm.optimization.UnreachableBasicBlockEliminator;
|
||||
|
||||
/**
|
||||
|
@ -28,6 +23,7 @@ public class Parser {
|
|||
SSATransformer ssaProducer = new SSATransformer();
|
||||
ssaProducer.transformToSSA(program, method.getParameterTypes());
|
||||
method.setProgram(program);
|
||||
parseAnnotations(method.getAnnotations(), node);
|
||||
return method;
|
||||
}
|
||||
|
||||
|
@ -50,6 +46,7 @@ public class Parser {
|
|||
MethodNode methodNode = (MethodNode)obj;
|
||||
cls.addMethod(parseMethod(methodNode));
|
||||
}
|
||||
parseAnnotations(cls.getAnnotations(), node);
|
||||
return cls;
|
||||
}
|
||||
|
||||
|
@ -58,6 +55,7 @@ public class Parser {
|
|||
field.setType(ValueType.parse(node.desc));
|
||||
field.setInitialValue(node.value);
|
||||
parseModifiers(node.access, field);
|
||||
parseAnnotations(field.getAnnotations(), node);
|
||||
return field;
|
||||
}
|
||||
|
||||
|
@ -120,59 +118,77 @@ public class Parser {
|
|||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
Class<?>[] classesToParse = { Object.class, String.class, ArrayList.class,
|
||||
StringBuilder.class, HashMap.class };
|
||||
ClassLoader classLoader = Parser.class.getClassLoader();
|
||||
for (Class<?> cls : classesToParse) {
|
||||
try (InputStream input = classLoader.getResourceAsStream(cls.getName().replace('.', '/') + ".class")) {
|
||||
ClassReader reader = new ClassReader(input);
|
||||
ClassNode node = new ClassNode();
|
||||
reader.accept(node, 0);
|
||||
display(parseClass(node));
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void parseAnnotations(AnnotationContainer annotations, MemberNode node) {
|
||||
List<Object> annotNodes = new ArrayList<>();
|
||||
if (node.visibleAnnotations != null) {
|
||||
annotNodes.addAll(node.visibleAnnotations);
|
||||
}
|
||||
if (node.invisibleAnnotations != null) {
|
||||
annotNodes.addAll(node.invisibleAnnotations);
|
||||
}
|
||||
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) {
|
||||
System.out.print(cls.getLevel());
|
||||
for (ElementModifier modifier : cls.getModifiers()) {
|
||||
System.out.print(" " + modifier);
|
||||
private static void parseAnnotationValues(AnnotationHolder annot, List<Object> values) {
|
||||
if (values == null) {
|
||||
return;
|
||||
}
|
||||
System.out.print(" class " + cls.getName());
|
||||
if (cls.getParent() != null) {
|
||||
System.out.print(" extends " + cls.getParent());
|
||||
for (int i = 0; i < values.size(); i += 2) {
|
||||
String key = (String)values.get(i);
|
||||
Object value = values.get(i + 1);
|
||||
annot.getValues().put(key, parseAnnotationValue(value));
|
||||
}
|
||||
if (!cls.getInterfaces().isEmpty()) {
|
||||
System.out.print(" implements ");
|
||||
boolean first = true;
|
||||
for (String iface : cls.getInterfaces()) {
|
||||
if (!first) {
|
||||
System.out.print(", ");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
System.out.print(iface);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static AnnotationValue parseAnnotationValue(Object value) {
|
||||
if (value instanceof String[]) {
|
||||
String[] enumInfo = (String[])value;
|
||||
return new AnnotationValue(new FieldReference(enumInfo[0], enumInfo[1]));
|
||||
} else if (value instanceof Type) {
|
||||
Type cls = (Type)value;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user