Merge remote-tracking branch 'origin/master'

This commit is contained in:
Alexey Andreev 2013-11-11 19:08:47 +04:00
commit 93798a335c
13 changed files with 201 additions and 23 deletions

View File

@ -16,5 +16,10 @@
<version>0.0.1-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -15,7 +15,7 @@ public class ObjectNativeGenerator implements Generator {
@Override @Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) { public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) {
switch (methodRef.getDescriptor().getName()) { switch (methodRef.getDescriptor().getName()) {
case "init": case "<init>":
generateInit(context, writer); generateInit(context, writer);
break; break;
case "getClass": case "getClass":

View File

@ -2,17 +2,20 @@ package org.teavm.classlib.java.lang;
import org.teavm.javascript.ni.GeneratedBy; import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.javascript.ni.Rename; import org.teavm.javascript.ni.Rename;
import org.teavm.javascript.ni.Superclass;
/** /**
* *
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
@Superclass("")
public class TObject { public class TObject {
@Rename("fakeInit")
public TObject() { public TObject() {
init();
} }
@GeneratedBy(ObjectNativeGenerator.class) @GeneratedBy(ObjectNativeGenerator.class)
@Rename("<init>")
private native void init(); private native void init();
@GeneratedBy(ObjectNativeGenerator.class) @GeneratedBy(ObjectNativeGenerator.class)

View File

@ -0,0 +1,30 @@
package org.teavm.classlib.java.lang;
import static org.junit.Assert.*;
import org.junit.Test;
/**
*
* @author Alexey Andreev
*/
class TObjectTests {
@Test
public void objectCreated() {
Object a = new Object();
assertNotNull(a);
}
@Test
public void differentInstancesNotEqual() {
Object a = new Object();
Object b = new Object();
assertNotEquals(a, b);
}
@Test
public void sameInstancesAreEqual() {
Object a = new Object();
Object b = a;
assertEquals(a, b);
}
}

View File

@ -0,0 +1,8 @@
package org.teavm.classlib.java.lang.annotation;
/**
*
* @author Alexey Andreev
*/
public @interface TAnnotation {
}

View File

@ -1,12 +1,15 @@
package org.teavm.classlibgen; package org.teavm.classlibgen;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
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.Decompiler; import org.teavm.javascript.Decompiler;
import org.teavm.javascript.Renderer; import org.teavm.javascript.Renderer;
import org.teavm.javascript.ast.ClassNode; import org.teavm.javascript.ast.ClassNode;
import org.teavm.model.ClassHolder; import org.teavm.model.*;
import org.teavm.model.resource.ClasspathClassHolderSource; import org.teavm.model.resource.ClasspathClassHolderSource;
/** /**
@ -14,16 +17,77 @@ import org.teavm.model.resource.ClasspathClassHolderSource;
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
public class ClasslibTestGenerator { public class ClasslibTestGenerator {
public static void main(String[] args) { private static ClasspathClassHolderSource classSource;
ClasspathClassHolderSource source = new ClasspathClassHolderSource(); private static Decompiler decompiler;
Decompiler decompiler = new Decompiler(source); private static DefaultAliasProvider aliasProvider;
ClassHolder cls = source.getClassHolder("java.lang.Object"); private static DefaultNamingStrategy naming;
ClassNode clsNode = decompiler.decompile(cls); private static SourceWriter writer;
DefaultAliasProvider aliasProvider = new DefaultAliasProvider(); private static Renderer renderer;
DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, source);
SourceWriter writer = new SourceWriter(naming); public static void main(String[] args) throws IOException {
Renderer renderer = new Renderer(writer, source); classSource = new ClasspathClassHolderSource();
renderer.render(clsNode); decompiler = new Decompiler(classSource);
aliasProvider = new DefaultAliasProvider();
naming = new DefaultNamingStrategy(aliasProvider, classSource);
writer = new SourceWriter(naming);
renderer = new Renderer(writer, classSource);
decompileClass("java.lang.Object");
decompileClass("java.lang.ObjectTests");
decompileClass("java.lang.Class");
decompileClass("java.lang.annotation.Annotation");
decompileClass("org.junit.Assert");
decompileClass("org.junit.Test");
renderHead();
ClassLoader classLoader = ClasslibTestGenerator.class.getClassLoader();
try (InputStream input = classLoader.getResourceAsStream(
"org/teavm/classlib/junit-support.js")) {
System.out.println(IOUtils.toString(input));
}
try (InputStream input = classLoader.getResourceAsStream(
"org/teavm/javascript/runtime.js")) {
System.out.println(IOUtils.toString(input));
}
renderClassTest(classSource.getClassHolder("java.lang.ObjectTests"));
System.out.println(writer); System.out.println(writer);
renderFoot();
}
private static void decompileClass(String className) {
ClassHolder cls = classSource.getClassHolder(className);
ClassNode clsNode = decompiler.decompile(cls);
renderer.render(clsNode);
}
private static void renderHead() {
System.out.println("<!DOCTYPE html>");
System.out.println("<html>");
System.out.println(" <head>");
System.out.println(" <title>TeaVM JUnit tests</title>");
System.out.println(" <meta http-equiv=\"Content-Type\" " +
"content=\"text/html;charset=UTF-8\"/>");
System.out.println(" <title>TeaVM JUnit tests</title>");
System.out.println(" </head>");
System.out.println(" <body>");
System.out.println(" <script type=\"text/javascript\">");
}
private static void renderFoot() {
System.out.println(" </script>");
System.out.println(" </body>");
System.out.println("</html>");
}
private static void renderClassTest(ClassHolder cls) {
writer.append("testClass(\"" + cls.getName() + "\", function() {").newLine().indent();
MethodReference cons = new MethodReference(cls.getName(),
new MethodDescriptor("<init>", ValueType.VOID));
for (MethodHolder method : cls.getMethods()) {
if (method.getAnnotations().get("org.junit.Test") != null) {
MethodReference ref = new MethodReference(cls.getName(), method.getDescriptor());
writer.append("runTestCase(").appendClass(cls.getName()).append(".").appendMethod(cons)
.append("(), \"" + method.getName() + "\", \"").appendMethod(ref).append("\");").newLine();
}
}
writer.outdent().append("})").newLine();
} }
} }

View File

@ -0,0 +1,41 @@
JUnitAssertionFailure = function() {}
JUnitAssertionFailure.prototype = new Error();
currentTestReportBody = null;
runTestCase = function(instance, methodName, realMethodName) {
var row = document.createElement("tr");
currentTestReportBody.appendChild(row);
var nameCell = document.createElement("td");
row.appendChild(nameCell);
nameCell.appendChild(document.createTextNode(methodName));
var statusCell = document.createElement("td");
row.appendChild(statusCell);
var exceptionCell = document.createElement("td");
row.appendChild(exceptionCell);
try {
instance[realMethodName]();
statusCell.appendChild(document.createTextNode("ok"));
} catch (e) {
if (e instanceof JUnitAssertionFailure) {
statusCell.appendChild(document.createTextNode("assertion failed"));
exceptionCell.appendChild(document.createTextNode(e.stack));
} else {
statusCell.appendChild(document.createTextNode("unexpected exception"));
exceptionCell.appendChild(document.createTextNode(e.stack));
}
}
}
testClass = function(className, classTests) {
var table = document.createElement("table");
document.body.appendChild(table);
var caption = document.createElement("caption");
table.appendChild(caption);
caption.appendChild(document.createTextNode(className));
var tbody = document.createElement("tbody");
table.appendChild(tbody);
currentTestReportBody = tbody;
classTests();
currentTestReportBody = null;
}

View File

@ -153,7 +153,7 @@ public class Renderer implements ExprVisitor, StatementVisitor {
} }
renderWorkingMethod(method); renderWorkingMethod(method);
int startParam = 0; int startParam = 0;
if (method.getModifiers().contains(ElementModifier.STATIC)) { if (method.getModifiers().contains(NodeModifier.STATIC)) {
startParam = 1; startParam = 1;
} }
writer.appendClass(ref.getClassName()).append('.'); writer.appendClass(ref.getClassName()).append('.');
@ -186,7 +186,7 @@ public class Renderer implements ExprVisitor, StatementVisitor {
MethodReference ref = method.getReference(); MethodReference ref = method.getReference();
writer.append("function ").appendClass(ref.getClassName()).append('_').appendMethod(ref).append('('); writer.append("function ").appendClass(ref.getClassName()).append('_').appendMethod(ref).append('(');
int startParam = 0; int startParam = 0;
if (method.getModifiers().contains(ElementModifier.STATIC)) { if (method.getModifiers().contains(NodeModifier.STATIC)) {
startParam = 1; startParam = 1;
} }
for (int i = startParam; i <= ref.parameterCount(); ++i) { for (int i = startParam; i <= ref.parameterCount(); ++i) {

View File

@ -302,11 +302,11 @@ public class StatementGenerator implements InstructionVisitor {
insn.getAlternative()); insn.getAlternative());
break; break;
case NOT_NULL: case NOT_NULL:
branch(Expr.binary(BinaryOperation.STRICT_EQUALS, Expr.var(insn.getOperand().getIndex()), branch(Expr.binary(BinaryOperation.STRICT_NOT_EQUALS, Expr.var(insn.getOperand().getIndex()),
Expr.constant(null)), insn.getConsequent(), insn.getAlternative()); Expr.constant(null)), insn.getConsequent(), insn.getAlternative());
break; break;
case NULL: case NULL:
branch(Expr.binary(BinaryOperation.STRICT_NOT_EQUALS, Expr.var(insn.getOperand().getIndex()), branch(Expr.binary(BinaryOperation.STRICT_EQUALS, Expr.var(insn.getOperand().getIndex()),
Expr.constant(null)), insn.getConsequent(), insn.getAlternative()); Expr.constant(null)), insn.getConsequent(), insn.getAlternative());
break; break;
} }
@ -489,7 +489,7 @@ public class StatementGenerator implements InstructionVisitor {
public String findDeclaringClass(String className, MethodDescriptor method) { public String findDeclaringClass(String className, MethodDescriptor method) {
ClassHolder cls = classSource.getClassHolder(className); ClassHolder cls = classSource.getClassHolder(className);
while (cls != null && cls.getMethod(method) == null) { while (cls != null && cls.getMethod(method) == null) {
cls = classSource.getClassHolder(cls.getParent()); cls = cls.getParent() != null ? classSource.getClassHolder(cls.getParent()) : null;
} }
return cls != null ? cls.getName() : null; return cls != null ? cls.getName() : null;
} }

View File

@ -10,7 +10,7 @@ import java.lang.annotation.Target;
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target({ ElementType.METHOD, ElementType.CONSTRUCTOR })
public @interface Rename { public @interface Rename {
String value(); String value();
} }

View File

@ -0,0 +1,16 @@
package org.teavm.javascript.ni;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* @author Alexey Andreev
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Superclass {
String value();
}

View File

@ -3,6 +3,7 @@ package org.teavm.model.resource;
import java.util.Map; import java.util.Map;
import org.teavm.codegen.Mapper; import org.teavm.codegen.Mapper;
import org.teavm.javascript.ni.Rename; import org.teavm.javascript.ni.Rename;
import org.teavm.javascript.ni.Superclass;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.model.instructions.*; import org.teavm.model.instructions.*;
@ -21,9 +22,15 @@ class ClassRefsRenamer implements InstructionVisitor {
ClassHolder renamedCls = new ClassHolder(classNameMapper.map(cls.getName())); ClassHolder renamedCls = new ClassHolder(classNameMapper.map(cls.getName()));
renamedCls.getModifiers().addAll(cls.getModifiers()); renamedCls.getModifiers().addAll(cls.getModifiers());
renamedCls.setLevel(cls.getLevel()); renamedCls.setLevel(cls.getLevel());
if (cls.getParent() != null) { String parent = cls.getParent();
renamedCls.setParent(classNameMapper.map(cls.getParent())); AnnotationHolder superclassAnnot = cls.getAnnotations().get(Superclass.class.getName());
if (superclassAnnot != null) {
parent = superclassAnnot.getValues().get("value").getString();
if (parent.isEmpty()) {
parent = null;
}
} }
renamedCls.setParent(parent != null ? classNameMapper.map(parent) : null);
for (MethodHolder method : cls.getMethods()) { for (MethodHolder method : cls.getMethods()) {
renamedCls.addMethod(rename(method)); renamedCls.addMethod(rename(method));
} }
@ -71,7 +78,8 @@ class ClassRefsRenamer implements InstructionVisitor {
private void rename(AnnotationContainer source, AnnotationContainer target) { private void rename(AnnotationContainer source, AnnotationContainer target) {
for (AnnotationHolder annot : source.all()) { for (AnnotationHolder annot : source.all()) {
if (!annot.getType().equals(Rename.class.getName())) { if (!annot.getType().equals(Rename.class.getName()) &&
!annot.getType().equals(Superclass.class.getName())) {
target.add(rename(annot)); target.add(rename(annot));
} }
} }

View File

@ -81,7 +81,10 @@ public class ClasspathResourceMapper implements Mapper<String, ClassHolder> {
String packageName = name.substring(0, index); String packageName = name.substring(0, index);
ClassHolder classHolder = innerMapper.map(transformation.packagePrefix + "." + packageName + ClassHolder classHolder = innerMapper.map(transformation.packagePrefix + "." + packageName +
"." + transformation.classPrefix + className); "." + transformation.classPrefix + className);
return renamer.rename(classHolder); if (classHolder != null) {
classHolder = renamer.rename(classHolder);
}
return classHolder;
} }
} }
return innerMapper.map(name); return innerMapper.map(name);