mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -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.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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
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) {
|
||||||
|
|
|
@ -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;
|
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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
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;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user