mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Merge branch 'platform' into date2
Conflicts: pom.xml
This commit is contained in:
commit
c4d32fce85
6
pom.xml
6
pom.xml
|
@ -77,6 +77,7 @@
|
|||
<module>teavm-jso</module>
|
||||
<module>teavm-html4j</module>
|
||||
<module>teavm-samples</module>
|
||||
<module>teavm-platform</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
|
@ -178,6 +179,11 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.17</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
|
|
@ -30,6 +30,12 @@
|
|||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-platform</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-core</artifactId>
|
||||
|
@ -51,6 +57,13 @@
|
|||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-maven-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-platform</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>generate-javascript-tests</id>
|
||||
|
@ -96,6 +109,15 @@
|
|||
</arguments>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>org/teavm/platform/metadata/*.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
|
|
|
@ -17,7 +17,7 @@ package org.teavm.classlib.impl.unicode;
|
|||
|
||||
import java.io.IOException;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.dependency.DependencyChecker;
|
||||
import org.teavm.dependency.DependencyAgent;
|
||||
import org.teavm.dependency.DependencyPlugin;
|
||||
import org.teavm.dependency.MethodDependency;
|
||||
import org.teavm.javascript.ni.Generator;
|
||||
|
@ -30,7 +30,7 @@ import org.teavm.model.MethodReference;
|
|||
*/
|
||||
public class CLDRHelperNativeGenerator implements Generator, DependencyPlugin {
|
||||
@Override
|
||||
public void methodAchieved(DependencyChecker checker, MethodDependency method) {
|
||||
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
|
||||
switch (method.getMethod().getName()) {
|
||||
case "getLikelySubtagsImpl":
|
||||
method.getResult().propagate("java.lang.String");
|
||||
|
|
|
@ -19,7 +19,7 @@ import java.io.IOException;
|
|||
import org.teavm.classlib.impl.unicode.UnicodeHelper;
|
||||
import org.teavm.classlib.impl.unicode.UnicodeSupport;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.dependency.DependencyChecker;
|
||||
import org.teavm.dependency.DependencyAgent;
|
||||
import org.teavm.dependency.DependencyPlugin;
|
||||
import org.teavm.dependency.MethodDependency;
|
||||
import org.teavm.javascript.ni.Generator;
|
||||
|
@ -52,7 +52,7 @@ public class CharacterNativeGenerator implements Generator, DependencyPlugin {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(DependencyChecker checker, MethodDependency method) {
|
||||
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
|
||||
switch (method.getReference().getName()) {
|
||||
case "obtainDigitMapping":
|
||||
case "obtainClasses":
|
||||
|
|
|
@ -17,7 +17,7 @@ package org.teavm.classlib.java.lang;
|
|||
|
||||
import java.io.IOException;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.dependency.DependencyChecker;
|
||||
import org.teavm.dependency.DependencyAgent;
|
||||
import org.teavm.dependency.DependencyPlugin;
|
||||
import org.teavm.dependency.MethodDependency;
|
||||
import org.teavm.javascript.ni.Generator;
|
||||
|
@ -186,7 +186,7 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug
|
|||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(DependencyChecker checker, MethodDependency graph) {
|
||||
public void methodAchieved(DependencyAgent agent, MethodDependency graph) {
|
||||
switch (graph.getReference().getName()) {
|
||||
case "voidClass":
|
||||
case "booleanClass":
|
||||
|
@ -205,7 +205,7 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug
|
|||
graph.getResult().propagate("java.lang.Class");
|
||||
break;
|
||||
case "newInstance":
|
||||
checker.linkMethod(new MethodReference(InstantiationException.class.getName(), "<init>",
|
||||
agent.linkMethod(new MethodReference(InstantiationException.class.getName(), "<init>",
|
||||
ValueType.VOID), graph.getStack()).use();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -17,16 +17,12 @@ package org.teavm.classlib.java.lang;
|
|||
|
||||
import java.io.IOException;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.dependency.DependencyChecker;
|
||||
import org.teavm.dependency.DependencyPlugin;
|
||||
import org.teavm.dependency.MethodDependency;
|
||||
import org.teavm.dependency.*;
|
||||
import org.teavm.javascript.ni.Generator;
|
||||
import org.teavm.javascript.ni.GeneratorContext;
|
||||
import org.teavm.javascript.ni.Injector;
|
||||
import org.teavm.javascript.ni.InjectorContext;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -62,13 +58,13 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
|
|||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(DependencyChecker checker, MethodDependency method) {
|
||||
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
|
||||
switch (method.getReference().getName()) {
|
||||
case "clone":
|
||||
method.getVariable(0).connect(method.getResult());
|
||||
break;
|
||||
case "getClass":
|
||||
achieveGetClass(checker, method);
|
||||
achieveGetClass(agent, method);
|
||||
break;
|
||||
case "wrap":
|
||||
method.getVariable(1).connect(method.getResult());
|
||||
|
@ -87,11 +83,9 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
|
|||
writer.append(".constructor)");
|
||||
}
|
||||
|
||||
private void achieveGetClass(DependencyChecker checker, MethodDependency method) {
|
||||
String classClass = "java.lang.Class";
|
||||
MethodReference initMethod = new MethodReference(classClass, new MethodDescriptor("createNew",
|
||||
ValueType.object(classClass)));
|
||||
checker.addEntryPoint(initMethod);
|
||||
private void achieveGetClass(DependencyAgent agent, MethodDependency method) {
|
||||
MethodReference initMethod = new MethodReference(Class.class, "createNew", Class.class);
|
||||
agent.linkMethod(initMethod, method.getStack()).use();
|
||||
method.getResult().propagate("java.lang.Class");
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
package org.teavm.classlib.java.lang;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.teavm.dependency.DependencyChecker;
|
||||
import org.teavm.dependency.DependencyAgent;
|
||||
import org.teavm.dependency.DependencyPlugin;
|
||||
import org.teavm.dependency.MethodDependency;
|
||||
import org.teavm.javascript.ni.Injector;
|
||||
|
@ -29,7 +29,7 @@ import org.teavm.model.MethodReference;
|
|||
*/
|
||||
public class StringNativeGenerator implements Injector, DependencyPlugin {
|
||||
@Override
|
||||
public void methodAchieved(DependencyChecker checker, MethodDependency method) {
|
||||
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
|
||||
switch (method.getReference().getName()) {
|
||||
case "wrap":
|
||||
method.getVariable(1).connect(method.getResult());
|
||||
|
|
|
@ -54,16 +54,16 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(DependencyChecker checker, MethodDependency method) {
|
||||
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
|
||||
switch (method.getReference().getName()) {
|
||||
case "doArrayCopy":
|
||||
achieveArrayCopy(method);
|
||||
break;
|
||||
case "setOut":
|
||||
achieveSetOut(checker, method);
|
||||
achieveSetOut(agent, method);
|
||||
break;
|
||||
case "setErr":
|
||||
achieveSetErr(checker, method);
|
||||
achieveSetErr(agent, method);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -97,13 +97,13 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin {
|
|||
src.getArrayItem().connect(dest.getArrayItem());
|
||||
}
|
||||
|
||||
private void achieveSetErr(DependencyChecker checker, MethodDependency method) {
|
||||
FieldDependency fieldDep = checker.linkField(new FieldReference("java.lang.System", "err"), method.getStack());
|
||||
private void achieveSetErr(DependencyAgent agent, MethodDependency method) {
|
||||
FieldDependency fieldDep = agent.linkField(new FieldReference("java.lang.System", "err"), method.getStack());
|
||||
method.getVariable(1).connect(fieldDep.getValue());
|
||||
}
|
||||
|
||||
private void achieveSetOut(DependencyChecker checker, MethodDependency method) {
|
||||
FieldDependency fieldDep = checker.linkField(new FieldReference("java.lang.System", "out"), method.getStack());
|
||||
private void achieveSetOut(DependencyAgent agent, MethodDependency method) {
|
||||
FieldDependency fieldDep = agent.linkField(new FieldReference("java.lang.System", "out"), method.getStack());
|
||||
method.getVariable(1).connect(fieldDep.getValue());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,10 +17,7 @@ package org.teavm.classlib.java.lang.reflect;
|
|||
|
||||
import java.io.IOException;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.dependency.DependencyChecker;
|
||||
import org.teavm.dependency.DependencyConsumer;
|
||||
import org.teavm.dependency.DependencyPlugin;
|
||||
import org.teavm.dependency.MethodDependency;
|
||||
import org.teavm.dependency.*;
|
||||
import org.teavm.javascript.ni.Generator;
|
||||
import org.teavm.javascript.ni.GeneratorContext;
|
||||
import org.teavm.model.ClassReader;
|
||||
|
@ -41,16 +38,16 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
|
|||
ValueType.INTEGER, ValueType.LONG, ValueType.FLOAT, ValueType.DOUBLE, ValueType.BOOLEAN };
|
||||
|
||||
@Override
|
||||
public void methodAchieved(DependencyChecker checker, MethodDependency method) {
|
||||
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
|
||||
switch (method.getReference().getName()) {
|
||||
case "getLength":
|
||||
achieveGetLength(checker, method);
|
||||
achieveGetLength(agent, method);
|
||||
break;
|
||||
case "newInstanceImpl":
|
||||
method.getResult().propagate("[java.lang.Object");
|
||||
break;
|
||||
case "getImpl":
|
||||
achieveGet(checker, method);
|
||||
achieveGet(agent, method);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -81,13 +78,12 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
|
|||
writer.append("return " + array + ".data.length;").softNewLine();
|
||||
}
|
||||
|
||||
private void achieveGetLength(final DependencyChecker checker, final MethodDependency method) {
|
||||
private void achieveGetLength(final DependencyAgent agent, final MethodDependency method) {
|
||||
method.getVariable(1).addConsumer(new DependencyConsumer() {
|
||||
@Override public void consume(String type) {
|
||||
if (!type.startsWith("[")) {
|
||||
MethodReference cons = new MethodReference("java.lang.IllegalArgumentException",
|
||||
new MethodDescriptor("<init>", ValueType.VOID));
|
||||
checker.addEntryPoint(cons);
|
||||
MethodReference cons = new MethodReference(IllegalArgumentException.class, "<init>", void.class);
|
||||
agent.linkMethod(cons, method.getStack()).use();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -129,7 +125,7 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
|
|||
writer.outdent().append("}").softNewLine();
|
||||
}
|
||||
|
||||
private void achieveGet(final DependencyChecker checker, final MethodDependency method) {
|
||||
private void achieveGet(final DependencyAgent agent, final MethodDependency method) {
|
||||
method.getVariable(1).getArrayItem().connect(method.getResult());
|
||||
method.getVariable(1).addConsumer(new DependencyConsumer() {
|
||||
@Override public void consume(String type) {
|
||||
|
@ -140,7 +136,7 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
|
|||
String wrapper = "java.lang." + primitiveWrappers[i];
|
||||
MethodReference methodRef = new MethodReference(wrapper, "valueOf",
|
||||
primitiveTypes[i], ValueType.object(wrapper));
|
||||
checker.linkMethod(methodRef, method.getStack()).use();
|
||||
agent.linkMethod(methodRef, method.getStack()).use();
|
||||
method.getResult().propagate("java.lang." + primitiveWrappers[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ package org.teavm.classlib.java.util;
|
|||
|
||||
import java.io.IOException;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.dependency.DependencyChecker;
|
||||
import org.teavm.dependency.DependencyAgent;
|
||||
import org.teavm.dependency.DependencyPlugin;
|
||||
import org.teavm.dependency.MethodDependency;
|
||||
import org.teavm.javascript.ni.Generator;
|
||||
|
@ -70,7 +70,7 @@ public class DateNativeGenerator implements Generator, DependencyPlugin {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(DependencyChecker checker, MethodDependency method) {
|
||||
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
|
||||
switch (method.getMethod().getName()) {
|
||||
case "toString":
|
||||
case "toLocaleFormat":
|
||||
|
|
|
@ -17,7 +17,7 @@ package org.teavm.classlib.java.util;
|
|||
|
||||
import java.io.IOException;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.dependency.DependencyChecker;
|
||||
import org.teavm.dependency.DependencyAgent;
|
||||
import org.teavm.dependency.DependencyPlugin;
|
||||
import org.teavm.dependency.MethodDependency;
|
||||
import org.teavm.javascript.ni.Generator;
|
||||
|
@ -67,7 +67,7 @@ public class LocaleNativeGenerator implements Generator, DependencyPlugin {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(DependencyChecker checker, MethodDependency method) {
|
||||
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
|
||||
switch (method.getMethod().getName()) {
|
||||
case "getDefaultLocale":
|
||||
case "getDisplayCountry":
|
||||
|
|
|
@ -17,7 +17,7 @@ package org.teavm.classlib.java.util;
|
|||
|
||||
import java.io.IOException;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.dependency.DependencyChecker;
|
||||
import org.teavm.dependency.DependencyAgent;
|
||||
import org.teavm.dependency.DependencyPlugin;
|
||||
import org.teavm.dependency.MethodDependency;
|
||||
import org.teavm.javascript.ni.Generator;
|
||||
|
@ -34,10 +34,11 @@ public class TimerNativeGenerator implements Generator, DependencyPlugin {
|
|||
"performOnce", ValueType.VOID);
|
||||
|
||||
@Override
|
||||
public void methodAchieved(DependencyChecker checker, MethodDependency method) {
|
||||
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
|
||||
switch (method.getReference().getName()) {
|
||||
case "scheduleOnce": {
|
||||
MethodDependency performMethod = checker.linkMethod(performOnceRef, method.getStack());
|
||||
MethodDependency performMethod = agent.linkMethod(performOnceRef, method.getStack());
|
||||
performMethod.use();
|
||||
method.getVariable(1).connect(performMethod.getVariable(1));
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.metadata;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface DependentTestResource extends Resource {
|
||||
String getBar();
|
||||
|
||||
void setBar(String bar);
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.metadata;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class MetadataGeneratorTest {
|
||||
@MetadataProvider(TestResourceGenerator.class)
|
||||
private native TestResource getNull();
|
||||
|
||||
@Test
|
||||
public void nullExposed() {
|
||||
assertNull(getNull());
|
||||
}
|
||||
|
||||
@MetadataProvider(TestResourceGenerator.class)
|
||||
private native IntResource getInt();
|
||||
|
||||
@Test
|
||||
public void intExposed() {
|
||||
assertEquals(23, getInt().getValue());
|
||||
}
|
||||
|
||||
@MetadataProvider(TestResourceGenerator.class)
|
||||
private native TestResource getResource();
|
||||
|
||||
@Test
|
||||
public void resourceObjectExposed() {
|
||||
TestResource res = getResource();
|
||||
assertEquals(23, res.getA());
|
||||
assertFalse(res.getB());
|
||||
assertEquals(24, res.getD());
|
||||
assertEquals(25, res.getE());
|
||||
assertEquals(3.14, res.getF(), 0.001);
|
||||
assertEquals(2.72, res.getG(), 0.001);
|
||||
|
||||
assertEquals("qwe", res.getFoo());
|
||||
|
||||
assertEquals(2, res.getArrayA().size());
|
||||
assertEquals(2, res.getArrayA().get(0).getValue());
|
||||
assertEquals(3, res.getArrayA().get(1).getValue());
|
||||
assertEquals(1, res.getArrayB().size());
|
||||
assertEquals("baz", res.getArrayB().get(0).getBar());
|
||||
assertNull(res.getArrayC());
|
||||
}
|
||||
|
||||
@MetadataProvider(TestResourceGenerator.class)
|
||||
private native TestResource getEmptyResource();
|
||||
|
||||
@Test
|
||||
public void resourceDefaultsSet() {
|
||||
TestResource res = getEmptyResource();
|
||||
assertEquals(0, res.getA());
|
||||
assertFalse(res.getB());
|
||||
assertEquals(0, res.getD());
|
||||
assertEquals(0, res.getE());
|
||||
assertEquals(0, res.getF(), 1E-10);
|
||||
assertEquals(0, res.getG(), 1E-10);
|
||||
assertNull(res.getFoo());
|
||||
assertNull(res.getArrayA());
|
||||
assertNull(res.getArrayB());
|
||||
assertNull(res.getArrayC());
|
||||
assertNull(res.getMapA());
|
||||
assertNull(res.getMapB());
|
||||
assertNull(res.getMapC());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resourceModifiedInRunTime() {
|
||||
TestResource res = getEmptyResource();
|
||||
res.setA(23);
|
||||
res.setB(true);
|
||||
res.setD((byte)24);
|
||||
res.setE((short)25);
|
||||
res.setF(3.14f);
|
||||
res.setG(2.72);
|
||||
|
||||
assertEquals(23, res.getA());
|
||||
assertTrue(res.getB());
|
||||
assertEquals(24, res.getD());
|
||||
assertEquals(25, res.getE());
|
||||
assertEquals(3.14, res.getF(), 0.001);
|
||||
assertEquals(2.72, res.getG(), 0.001);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.metadata;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface TestResource extends Resource {
|
||||
int getA();
|
||||
|
||||
void setA(int a);
|
||||
|
||||
boolean getB();
|
||||
|
||||
void setB(boolean b);
|
||||
|
||||
byte getD();
|
||||
|
||||
void setD(byte d);
|
||||
|
||||
short getE();
|
||||
|
||||
void setE(short e);
|
||||
|
||||
float getF();
|
||||
|
||||
void setF(float f);
|
||||
|
||||
double getG();
|
||||
|
||||
void setG(double g);
|
||||
|
||||
String getFoo();
|
||||
|
||||
void setFoo(String foo);
|
||||
|
||||
ResourceArray<IntResource> getArrayA();
|
||||
|
||||
void setArrayA(ResourceArray<IntResource> arrayA);
|
||||
|
||||
ResourceArray<DependentTestResource> getArrayB();
|
||||
|
||||
void setArrayB(ResourceArray<DependentTestResource> arrayB);
|
||||
|
||||
ResourceArray<ResourceArray<StringResource>> getArrayC();
|
||||
|
||||
void setArrayC(ResourceArray<ResourceArray<StringResource>> arrayC);
|
||||
|
||||
ResourceMap<IntResource> getMapA();
|
||||
|
||||
void setMapA(ResourceMap<IntResource> mapA);
|
||||
|
||||
ResourceMap<DependentTestResource> getMapB();
|
||||
|
||||
void setMapB(ResourceMap<DependentTestResource> mapB);
|
||||
|
||||
ResourceMap<ResourceArray<StringResource>> getMapC();
|
||||
|
||||
void setMapC(ResourceMap<ResourceArray<StringResource>> mapC);
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.metadata;
|
||||
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class TestResourceGenerator implements MetadataGenerator {
|
||||
@Override
|
||||
public Resource generateMetadata(MetadataGeneratorContext context, MethodReference method) {
|
||||
switch (method.getName()) {
|
||||
case "getNull":
|
||||
return null;
|
||||
case "getInt":
|
||||
return createInt(context, 23);
|
||||
case "getResource":
|
||||
return getResource(context);
|
||||
case "getEmptyResource":
|
||||
return context.createResource(TestResource.class);
|
||||
default:
|
||||
throw new RuntimeException("Unsupported method: " + method);
|
||||
}
|
||||
}
|
||||
|
||||
private Resource getResource(MetadataGeneratorContext context) {
|
||||
TestResource resource = context.createResource(TestResource.class);
|
||||
resource.setA(23);
|
||||
resource.setB(false);
|
||||
resource.setD((byte)24);
|
||||
resource.setE((short)25);
|
||||
resource.setF(3.14f);
|
||||
resource.setG(2.72);
|
||||
resource.setFoo("qwe");
|
||||
|
||||
ResourceArray<IntResource> array = context.createResourceArray();
|
||||
array.add(createInt(context, 2));
|
||||
array.add(createInt(context, 3));
|
||||
resource.setArrayA(array);
|
||||
DependentTestResource dep = context.createResource(DependentTestResource.class);
|
||||
dep.setBar("baz");
|
||||
ResourceArray<DependentTestResource> resArray = context.createResourceArray();
|
||||
resArray.add(dep);
|
||||
resource.setArrayB(resArray);
|
||||
return resource;
|
||||
}
|
||||
|
||||
private IntResource createInt(MetadataGeneratorContext context, int value) {
|
||||
IntResource res = context.createResource(IntResource.class);
|
||||
res.setValue(value);
|
||||
return res;
|
||||
}
|
||||
}
|
|
@ -31,10 +31,13 @@ public class SourceWriter implements Appendable {
|
|||
private NamingStrategy naming;
|
||||
private boolean lineStart;
|
||||
private boolean minified;
|
||||
private int lineWidth;
|
||||
private int pos;
|
||||
|
||||
SourceWriter(NamingStrategy naming, Appendable innerWriter) {
|
||||
SourceWriter(NamingStrategy naming, Appendable innerWriter, int lineWidth) {
|
||||
this.naming = naming;
|
||||
this.innerWriter = innerWriter;
|
||||
this.lineWidth = lineWidth;
|
||||
}
|
||||
|
||||
void setMinified(boolean minified) {
|
||||
|
@ -42,8 +45,7 @@ public class SourceWriter implements Appendable {
|
|||
}
|
||||
|
||||
public SourceWriter append(String value) throws IOException {
|
||||
appendIndent();
|
||||
innerWriter.append(value);
|
||||
append((CharSequence)value);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -59,23 +61,43 @@ public class SourceWriter implements Appendable {
|
|||
public SourceWriter append(char value) throws IOException {
|
||||
appendIndent();
|
||||
innerWriter.append(value);
|
||||
if (value == '\n') {
|
||||
newLine();
|
||||
} else {
|
||||
pos++;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter append(CharSequence csq) throws IOException {
|
||||
appendIndent();
|
||||
innerWriter.append(csq);
|
||||
append(csq, 0, csq.length());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter append(CharSequence csq, int start, int end) throws IOException {
|
||||
appendIndent();
|
||||
innerWriter.append(csq, start, end);
|
||||
int last = start;
|
||||
for (int i = start; i < end; ++i) {
|
||||
if (csq.charAt(i) == '\n') {
|
||||
appendSingleLine(csq, last, i);
|
||||
newLine();
|
||||
last = i;
|
||||
}
|
||||
}
|
||||
appendSingleLine(csq, last, end);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void appendSingleLine(CharSequence csq, int start, int end) throws IOException {
|
||||
if (start == end) {
|
||||
return;
|
||||
}
|
||||
appendIndent();
|
||||
pos += end - start;
|
||||
innerWriter.append(csq, start, end);
|
||||
}
|
||||
|
||||
public SourceWriter appendClass(String cls) throws NamingException, IOException {
|
||||
return append(naming.getNameFor(cls));
|
||||
}
|
||||
|
@ -109,6 +131,7 @@ public class SourceWriter implements Appendable {
|
|||
if (lineStart) {
|
||||
for (int i = 0; i < indentSize; ++i) {
|
||||
innerWriter.append(" ");
|
||||
pos += 4;
|
||||
}
|
||||
lineStart = false;
|
||||
}
|
||||
|
@ -116,13 +139,26 @@ public class SourceWriter implements Appendable {
|
|||
|
||||
public SourceWriter newLine() throws IOException{
|
||||
innerWriter.append('\n');
|
||||
pos = 0;
|
||||
lineStart = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SourceWriter ws() throws IOException{
|
||||
if (!minified) {
|
||||
innerWriter.append(' ');
|
||||
public SourceWriter ws() throws IOException {
|
||||
if (pos >= lineWidth) {
|
||||
newLine();
|
||||
} else {
|
||||
if (!minified) {
|
||||
innerWriter.append(' ');
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public SourceWriter tokenBoundary() throws IOException {
|
||||
if (pos >= lineWidth) {
|
||||
newLine();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -130,6 +166,7 @@ public class SourceWriter implements Appendable {
|
|||
public SourceWriter softNewLine() throws IOException{
|
||||
if (!minified) {
|
||||
innerWriter.append('\n');
|
||||
pos = 0;
|
||||
lineStart = true;
|
||||
}
|
||||
return this;
|
||||
|
|
|
@ -22,6 +22,7 @@ package org.teavm.codegen;
|
|||
public class SourceWriterBuilder {
|
||||
private NamingStrategy naming;
|
||||
private boolean minified;
|
||||
private int lineWidth = 512;
|
||||
|
||||
public SourceWriterBuilder(NamingStrategy naming) {
|
||||
this.naming = naming;
|
||||
|
@ -35,8 +36,12 @@ public class SourceWriterBuilder {
|
|||
this.minified = minified;
|
||||
}
|
||||
|
||||
public void setLineWidth(int lineWidth) {
|
||||
this.lineWidth = lineWidth;
|
||||
}
|
||||
|
||||
public SourceWriter build(Appendable innerWriter) {
|
||||
SourceWriter writer = new SourceWriter(naming, innerWriter);
|
||||
SourceWriter writer = new SourceWriter(naming, innerWriter, lineWidth);
|
||||
writer.setMinified(minified);
|
||||
return writer;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2014 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.common;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface ServiceRepository {
|
||||
<T> T getService(Class<T> type);
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package org.teavm.dependency;
|
||||
|
||||
import org.teavm.common.ServiceRepository;
|
||||
import org.teavm.model.ClassHolder;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
@ -23,7 +24,7 @@ import org.teavm.model.MethodReference;
|
|||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface DependencyAgent extends DependencyInfo {
|
||||
public interface DependencyAgent extends DependencyInfo, ServiceRepository {
|
||||
DependencyNode createNode();
|
||||
|
||||
String generateClassName();
|
||||
|
|
|
@ -45,18 +45,21 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
|||
private ConcurrentMap<String, Object> achievableClasses = new ConcurrentHashMap<>();
|
||||
private ConcurrentMap<String, Object> initializedClasses = new ConcurrentHashMap<>();
|
||||
private List<DependencyListener> listeners = new ArrayList<>();
|
||||
private ServiceRepository services;
|
||||
ConcurrentMap<MethodReference, DependencyStack> missingMethods = new ConcurrentHashMap<>();
|
||||
ConcurrentMap<String, DependencyStack> missingClasses = new ConcurrentHashMap<>();
|
||||
ConcurrentMap<FieldReference, DependencyStack> missingFields = new ConcurrentHashMap<>();
|
||||
|
||||
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader) {
|
||||
this(classSource, classLoader, new SimpleFiniteExecutor());
|
||||
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services) {
|
||||
this(classSource, classLoader, services, new SimpleFiniteExecutor());
|
||||
}
|
||||
|
||||
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, FiniteExecutor executor) {
|
||||
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services,
|
||||
FiniteExecutor executor) {
|
||||
this.classSource = new DependencyClassSource(classSource);
|
||||
this.classLoader = classLoader;
|
||||
this.executor = executor;
|
||||
this.services = services;
|
||||
methodReaderCache = new ConcurrentCachedMapper<>(new Mapper<MethodReference, MethodReader>() {
|
||||
@Override public MethodReader map(MethodReference preimage) {
|
||||
return findMethodReader(preimage);
|
||||
|
@ -447,4 +450,9 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
|||
sb.append('\n');
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getService(Class<T> type) {
|
||||
return services.getService(type);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,5 +20,5 @@ package org.teavm.dependency;
|
|||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface DependencyPlugin {
|
||||
void methodAchieved(DependencyChecker checker, MethodDependency method);
|
||||
void methodAchieved(DependencyAgent checker, MethodDependency method);
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ public class Decompiler {
|
|||
private RangeTree.Node parentNode;
|
||||
private FiniteExecutor executor;
|
||||
private Map<MethodReference, Generator> generators = new HashMap<>();
|
||||
private Set<MethodReference> methodsToPass = new HashSet<>();
|
||||
|
||||
public Decompiler(ClassHolderSource classSource, ClassLoader classLoader, FiniteExecutor executor) {
|
||||
this.classSource = classSource;
|
||||
|
@ -84,6 +85,7 @@ public class Decompiler {
|
|||
@Override public void run() {
|
||||
Decompiler copy = new Decompiler(classSource, classLoader, executor);
|
||||
copy.generators = generators;
|
||||
copy.methodsToPass = methodsToPass;
|
||||
result.set(index, copy.decompile(classSource.get(className)));
|
||||
}
|
||||
});
|
||||
|
@ -96,6 +98,10 @@ public class Decompiler {
|
|||
generators.put(method, generator);
|
||||
}
|
||||
|
||||
public void addMethodToPass(MethodReference method) {
|
||||
methodsToPass.add(method);
|
||||
}
|
||||
|
||||
private void orderClasses(String className, Set<String> visited, List<String> order) {
|
||||
if (!visited.add(className)) {
|
||||
return;
|
||||
|
@ -125,7 +131,8 @@ public class Decompiler {
|
|||
if (method.getModifiers().contains(ElementModifier.ABSTRACT)) {
|
||||
continue;
|
||||
}
|
||||
if (method.getAnnotations().get(InjectedBy.class.getName()) != null) {
|
||||
if (method.getAnnotations().get(InjectedBy.class.getName()) != null ||
|
||||
methodsToPass.contains(method.getReference())) {
|
||||
continue;
|
||||
}
|
||||
MethodNode methodNode = decompile(method);
|
||||
|
@ -140,8 +147,8 @@ public class Decompiler {
|
|||
}
|
||||
|
||||
public MethodNode decompile(MethodHolder method) {
|
||||
return method.getModifiers().contains(ElementModifier.NATIVE) ?
|
||||
decompileNative(method) : decompileRegular(method);
|
||||
return method.getModifiers().contains(ElementModifier.NATIVE) ? decompileNative(method) :
|
||||
decompileRegular(method);
|
||||
}
|
||||
|
||||
public NativeMethodNode decompileNative(MethodHolder method) {
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.*;
|
|||
import org.teavm.codegen.NamingException;
|
||||
import org.teavm.codegen.NamingStrategy;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.common.ServiceRepository;
|
||||
import org.teavm.javascript.ast.*;
|
||||
import org.teavm.javascript.ni.GeneratorContext;
|
||||
import org.teavm.javascript.ni.InjectedBy;
|
||||
|
@ -43,6 +44,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
private ClassLoader classLoader;
|
||||
private boolean minifying;
|
||||
private Map<MethodReference, InjectorHolder> injectorMap = new HashMap<>();
|
||||
private Properties properties = new Properties();
|
||||
private ServiceRepository services;
|
||||
|
||||
private static class InjectorHolder {
|
||||
public final Injector injector;
|
||||
|
@ -52,11 +55,17 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
}
|
||||
}
|
||||
|
||||
public Renderer(SourceWriter writer, ListableClassHolderSource classSource, ClassLoader classLoader) {
|
||||
public void addInjector(MethodReference method, Injector injector) {
|
||||
injectorMap.put(method, new InjectorHolder(injector));
|
||||
}
|
||||
|
||||
public Renderer(SourceWriter writer, ListableClassHolderSource classSource, ClassLoader classLoader,
|
||||
ServiceRepository services) {
|
||||
this.naming = writer.getNaming();
|
||||
this.writer = writer;
|
||||
this.classSource = classSource;
|
||||
this.classLoader = classLoader;
|
||||
this.services = services;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -88,6 +97,16 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
return classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties getProperties() {
|
||||
return new Properties(properties);
|
||||
}
|
||||
|
||||
public void setProperties(Properties properties) {
|
||||
this.properties.clear();
|
||||
this.properties.putAll(properties);
|
||||
}
|
||||
|
||||
public void renderRuntime() throws RenderingException {
|
||||
try {
|
||||
renderRuntimeCls();
|
||||
|
@ -483,6 +502,21 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
public ListableClassReaderSource getClassSource() {
|
||||
return classSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties getProperties() {
|
||||
return new Properties(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getService(Class<T> type) {
|
||||
return services.getService(type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1404,5 +1438,20 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
public int argumentCount() {
|
||||
return arguments.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getService(Class<T> type) {
|
||||
return services.getService(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties getProperties() {
|
||||
return new Properties(properties);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getService(Class<T> type) {
|
||||
return services.getService(type);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,15 +15,17 @@
|
|||
*/
|
||||
package org.teavm.javascript;
|
||||
|
||||
import java.util.Properties;
|
||||
import org.teavm.codegen.NamingStrategy;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.common.ServiceRepository;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public interface RenderingContext {
|
||||
public interface RenderingContext extends ServiceRepository {
|
||||
NamingStrategy getNaming();
|
||||
|
||||
SourceWriter getWriter();
|
||||
|
@ -33,4 +35,6 @@ public interface RenderingContext {
|
|||
ListableClassReaderSource getClassSource();
|
||||
|
||||
ClassLoader getClassLoader();
|
||||
|
||||
Properties getProperties();
|
||||
}
|
||||
|
|
|
@ -15,14 +15,20 @@
|
|||
*/
|
||||
package org.teavm.javascript.ni;
|
||||
|
||||
import java.util.Properties;
|
||||
import org.teavm.common.ServiceRepository;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public interface GeneratorContext {
|
||||
public interface GeneratorContext extends ServiceRepository {
|
||||
String getParameterName(int index);
|
||||
|
||||
ListableClassReaderSource getClassSource();
|
||||
|
||||
ClassLoader getClassLoader();
|
||||
|
||||
Properties getProperties();
|
||||
}
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
package org.teavm.javascript.ni;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.common.ServiceRepository;
|
||||
import org.teavm.javascript.ast.Expr;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
|
@ -24,7 +26,7 @@ import org.teavm.model.ValueType;
|
|||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public interface InjectorContext {
|
||||
public interface InjectorContext extends ServiceRepository {
|
||||
Expr getArgument(int index);
|
||||
|
||||
int argumentCount();
|
||||
|
@ -33,6 +35,8 @@ public interface InjectorContext {
|
|||
|
||||
SourceWriter getWriter();
|
||||
|
||||
Properties getProperties();
|
||||
|
||||
void writeEscaped(String str) throws IOException;
|
||||
|
||||
void writeType(ValueType type) throws IOException;
|
||||
|
|
|
@ -34,6 +34,17 @@ public class MethodDescriptor {
|
|||
this.signature = Arrays.copyOf(signature, signature.length);
|
||||
}
|
||||
|
||||
public MethodDescriptor(String name, Class<?>... signature) {
|
||||
if (signature.length < 1) {
|
||||
throw new IllegalArgumentException("Signature must be at least 1 element length");
|
||||
}
|
||||
this.name = name;
|
||||
this.signature = new ValueType[signature.length];
|
||||
for (int i = 0; i < signature.length; ++i) {
|
||||
this.signature[i] = ValueType.parse(signature[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
|
|
@ -55,6 +55,10 @@ public class MethodReference {
|
|||
this(className, new MethodDescriptor(name, signature));
|
||||
}
|
||||
|
||||
public MethodReference(Class<?> cls, String name, Class<?>... signature) {
|
||||
this(cls.getName(), new MethodDescriptor(name, signature));
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
package org.teavm.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -25,6 +27,7 @@ import java.util.List;
|
|||
*/
|
||||
public abstract class ValueType {
|
||||
volatile String reprCache;
|
||||
private static final Map<Class<?>, ValueType> primitiveMap = new HashMap<>();
|
||||
|
||||
private ValueType() {
|
||||
}
|
||||
|
@ -166,6 +169,19 @@ public abstract class ValueType {
|
|||
|
||||
public static final Null NULL = new Null();
|
||||
|
||||
|
||||
static {
|
||||
primitiveMap.put(boolean.class, BOOLEAN);
|
||||
primitiveMap.put(char.class, CHARACTER);
|
||||
primitiveMap.put(byte.class, BYTE);
|
||||
primitiveMap.put(short.class, SHORT);
|
||||
primitiveMap.put(int.class, INTEGER);
|
||||
primitiveMap.put(long.class, LONG);
|
||||
primitiveMap.put(float.class, FLOAT);
|
||||
primitiveMap.put(double.class, DOUBLE);
|
||||
primitiveMap.put(void.class, VOID);
|
||||
}
|
||||
|
||||
public static ValueType object(String cls) {
|
||||
return new Object(cls);
|
||||
}
|
||||
|
@ -175,7 +191,26 @@ public abstract class ValueType {
|
|||
}
|
||||
|
||||
public static ValueType primitive(PrimitiveType type) {
|
||||
return new Primitive(type);
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
return BOOLEAN;
|
||||
case BYTE:
|
||||
return BYTE;
|
||||
case CHARACTER:
|
||||
return CHARACTER;
|
||||
case SHORT:
|
||||
return SHORT;
|
||||
case INTEGER:
|
||||
return INTEGER;
|
||||
case LONG:
|
||||
return LONG;
|
||||
case FLOAT:
|
||||
return FLOAT;
|
||||
case DOUBLE:
|
||||
return DOUBLE;
|
||||
default:
|
||||
throw new AssertionError("Unknown primitive type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
public static ValueType[] parseMany(String text) {
|
||||
|
@ -267,6 +302,16 @@ public abstract class ValueType {
|
|||
}
|
||||
}
|
||||
|
||||
public static ValueType parse(Class<?> cls) {
|
||||
if (cls.isPrimitive()) {
|
||||
return primitiveMap.get(cls);
|
||||
} else if (cls.getComponentType() != null) {
|
||||
return ValueType.arrayOf(ValueType.parse(cls.getComponentType()));
|
||||
} else {
|
||||
return ValueType.object(cls.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toString().hashCode();
|
||||
|
|
|
@ -19,10 +19,14 @@ import java.io.*;
|
|||
import java.util.*;
|
||||
import org.teavm.codegen.*;
|
||||
import org.teavm.common.FiniteExecutor;
|
||||
import org.teavm.common.ServiceRepository;
|
||||
import org.teavm.dependency.*;
|
||||
import org.teavm.javascript.*;
|
||||
import org.teavm.javascript.Decompiler;
|
||||
import org.teavm.javascript.Renderer;
|
||||
import org.teavm.javascript.RenderingException;
|
||||
import org.teavm.javascript.ast.ClassNode;
|
||||
import org.teavm.javascript.ni.Generator;
|
||||
import org.teavm.javascript.ni.Injector;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.model.util.ListingBuilder;
|
||||
import org.teavm.model.util.ProgramUtils;
|
||||
|
@ -62,7 +66,7 @@ import org.teavm.vm.spi.TeaVMPlugin;
|
|||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class TeaVM implements TeaVMHost {
|
||||
public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||
private ClassReaderSource classSource;
|
||||
private DependencyChecker dependencyChecker;
|
||||
private FiniteExecutor executor;
|
||||
|
@ -73,13 +77,15 @@ public class TeaVM implements TeaVMHost {
|
|||
private Map<String, TeaVMEntryPoint> entryPoints = new HashMap<>();
|
||||
private Map<String, String> exportedClasses = new HashMap<>();
|
||||
private Map<MethodReference, Generator> methodGenerators = new HashMap<>();
|
||||
private Map<MethodReference, Injector> methodInjectors = new HashMap<>();
|
||||
private List<RendererListener> rendererListeners = new ArrayList<>();
|
||||
private Map<Class<?>, Object> services = new HashMap<>();
|
||||
private Properties properties = new Properties();
|
||||
|
||||
TeaVM(ClassReaderSource classSource, ClassLoader classLoader, FiniteExecutor executor) {
|
||||
this.classSource = classSource;
|
||||
this.classLoader = classLoader;
|
||||
dependencyChecker = new DependencyChecker(this.classSource, classLoader, executor);
|
||||
dependencyChecker = new DependencyChecker(this.classSource, classLoader, this, executor);
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
|
@ -98,6 +104,11 @@ public class TeaVM implements TeaVMHost {
|
|||
methodGenerators.put(methodRef, generator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(MethodReference methodRef, Injector injector) {
|
||||
methodInjectors.put(methodRef, injector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(RendererListener listener) {
|
||||
rendererListeners.add(listener);
|
||||
|
@ -315,6 +326,9 @@ public class TeaVM implements TeaVMHost {
|
|||
for (Map.Entry<MethodReference, Generator> entry : methodGenerators.entrySet()) {
|
||||
decompiler.addGenerator(entry.getKey(), entry.getValue());
|
||||
}
|
||||
for (MethodReference injectedMethod : methodInjectors.keySet()) {
|
||||
decompiler.addMethodToPass(injectedMethod);
|
||||
}
|
||||
List<ClassNode> clsNodes = decompiler.decompile(classSet.getClassNames());
|
||||
|
||||
// Render
|
||||
|
@ -323,7 +337,10 @@ public class TeaVM implements TeaVMHost {
|
|||
SourceWriterBuilder builder = new SourceWriterBuilder(naming);
|
||||
builder.setMinified(minifying);
|
||||
SourceWriter sourceWriter = builder.build(writer);
|
||||
Renderer renderer = new Renderer(sourceWriter, classSet, classLoader);
|
||||
Renderer renderer = new Renderer(sourceWriter, classSet, classLoader, this);
|
||||
for (Map.Entry<MethodReference, Injector> entry : methodInjectors.entrySet()) {
|
||||
renderer.addInjector(entry.getKey(), entry.getValue());
|
||||
}
|
||||
try {
|
||||
for (RendererListener listener : rendererListeners) {
|
||||
listener.begin(renderer, target);
|
||||
|
@ -514,4 +531,18 @@ public class TeaVM implements TeaVMHost {
|
|||
plugin.install(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getService(Class<T> type) {
|
||||
Object service = services.get(type);
|
||||
if (service == null) {
|
||||
throw new IllegalArgumentException("Service not registered: " + type.getName());
|
||||
}
|
||||
return type.cast(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void registerService(Class<T> type, T instance) {
|
||||
services.put(type, instance);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.teavm.vm.spi;
|
|||
import java.util.Properties;
|
||||
import org.teavm.dependency.DependencyListener;
|
||||
import org.teavm.javascript.ni.Generator;
|
||||
import org.teavm.javascript.ni.Injector;
|
||||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.vm.TeaVM;
|
||||
|
@ -36,8 +37,12 @@ public interface TeaVMHost {
|
|||
|
||||
void add(MethodReference methodRef, Generator generator);
|
||||
|
||||
void add(MethodReference methodRef, Injector injector);
|
||||
|
||||
void add(RendererListener listener);
|
||||
|
||||
<T> void registerService(Class<T> type, T instance);
|
||||
|
||||
/**
|
||||
* Gets class loaded that is used by TeaVM. This class loader is usually specified by
|
||||
* {@link TeaVMBuilder#setClassLoader(ClassLoader)}
|
||||
|
|
|
@ -17,10 +17,7 @@ package org.teavm.jso;
|
|||
|
||||
import java.io.IOException;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.dependency.DependencyChecker;
|
||||
import org.teavm.dependency.DependencyConsumer;
|
||||
import org.teavm.dependency.DependencyPlugin;
|
||||
import org.teavm.dependency.MethodDependency;
|
||||
import org.teavm.dependency.*;
|
||||
import org.teavm.javascript.ast.ConstantExpr;
|
||||
import org.teavm.javascript.ast.Expr;
|
||||
import org.teavm.javascript.ast.InvocationExpr;
|
||||
|
@ -28,7 +25,10 @@ import org.teavm.javascript.ni.Generator;
|
|||
import org.teavm.javascript.ni.GeneratorContext;
|
||||
import org.teavm.javascript.ni.Injector;
|
||||
import org.teavm.javascript.ni.InjectorContext;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -115,24 +115,24 @@ public class JSNativeGenerator implements Generator, Injector, DependencyPlugin
|
|||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(final DependencyChecker checker, final MethodDependency method) {
|
||||
public void methodAchieved(final DependencyAgent agent, final MethodDependency method) {
|
||||
for (int i = 0; i < method.getReference().parameterCount(); ++i) {
|
||||
method.getVariable(i).addConsumer(new DependencyConsumer() {
|
||||
@Override public void consume(String type) {
|
||||
achieveFunctorMethods(checker, type, method);
|
||||
achieveFunctorMethods(agent, type, method);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void achieveFunctorMethods(DependencyChecker checker, String type, MethodDependency caller) {
|
||||
private void achieveFunctorMethods(DependencyAgent agent, String type, MethodDependency caller) {
|
||||
if (caller.isMissing()) {
|
||||
return;
|
||||
}
|
||||
ClassReader cls = checker.getClassSource().get(type);
|
||||
ClassReader cls = agent.getClassSource().get(type);
|
||||
if (cls != null) {
|
||||
for (MethodReader method : cls.getMethods()) {
|
||||
checker.linkMethod(method.getReference(), caller.getStack()).use();
|
||||
agent.linkMethod(method.getReference(), caller.getStack()).use();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
4
teavm-platform/.gitignore
vendored
Normal file
4
teavm-platform/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/target
|
||||
/.settings
|
||||
/.project
|
||||
/.classpath
|
24
teavm-platform/pom.xml
Normal file
24
teavm-platform/pom.xml
Normal file
|
@ -0,0 +1,24 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm</artifactId>
|
||||
<version>0.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>teavm-platform</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.metadata;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface BooleanResource extends Resource {
|
||||
boolean getValue();
|
||||
|
||||
void setValue(boolean value);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.metadata;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface ByteResource extends Resource {
|
||||
byte getValue();
|
||||
|
||||
void setValue(byte value);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.metadata;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface DoubleResource extends Resource {
|
||||
double getValue();
|
||||
|
||||
void setValue(double value);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.metadata;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface FloatResource extends Resource {
|
||||
float getValue();
|
||||
|
||||
void setValue(float value);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.metadata;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface IntResource extends Resource {
|
||||
int getValue();
|
||||
|
||||
void setValue(int value);
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.metadata;
|
||||
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
/**
|
||||
* <p>Represents a generator, that produces resources during compilation phase. User must implement this
|
||||
* interface and bind this implementation to a method that would read resources at runtime.</p>
|
||||
*
|
||||
* <p>Here is the full workflow:</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>Compiler finds a method that is marked with the {@link MetadataProvider} annotation.
|
||||
* This method must be declared as <code>native</code>, otherwise compiler should throw an exception.</li>
|
||||
* <li>Compiler instantiates the {@link MetadataGenerator} instance with the no-arg constructor
|
||||
* If no such constructor exists, compiler throws exception.</li>
|
||||
* <li>Compiler runs the {@link #generateMetadata(MetadataGeneratorContext, MethodReference)} method
|
||||
* ands gets the produced resource.</li>
|
||||
* <li>Compiler generates implementation of the method marked with {@link MetadataProvider}, that
|
||||
* will return the generated resource in run time.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Therefore, the type of the value, returned by the
|
||||
* {@link #generateMetadata(MetadataGeneratorContext, MethodReference)}
|
||||
* method must match the returning type of the appropriate method, marked with {@link MetadataProvider}.</p>
|
||||
*
|
||||
* <p>The valid resource types are the following:</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>Valid interfaces, extending the {@link Resource} annotation. Read the description of this interface
|
||||
* for detailed description about valid resources interfaces.</li>
|
||||
* <li>{@link ResourceArray} of valid resources.</li>
|
||||
* <li>{@link ResourceMap} of valid resources.</li>
|
||||
* <li>The <code>null</code> value.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>All other types are not considered to be resources and therefore are not accepted.</p>
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public interface MetadataGenerator {
|
||||
/**
|
||||
* <p>Generates resources, that will be available at runtime.</p>
|
||||
*
|
||||
* @param context context that contains useful compile-time information.
|
||||
* @param method method which will be used to access the generated resources at run time.
|
||||
*/
|
||||
Resource generateMetadata(MetadataGeneratorContext context, MethodReference method);
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.metadata;
|
||||
|
||||
import java.util.Properties;
|
||||
import org.teavm.common.ServiceRepository;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
import org.teavm.vm.TeaVM;
|
||||
|
||||
/**
|
||||
* <p>Represents context with compile-time information, that is useful for {@link MetadataGenerator}.
|
||||
* This context is provided by the compiler infrastructure.</p>
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public interface MetadataGeneratorContext extends ServiceRepository {
|
||||
/**
|
||||
* Gets the collection of all classes that were achieved by the dependency checker.
|
||||
*/
|
||||
ListableClassReaderSource getClassSource();
|
||||
|
||||
/**
|
||||
* Gets the class loader that is used by the compiler.
|
||||
*/
|
||||
ClassLoader getClassLoader();
|
||||
|
||||
/**
|
||||
* Gets properties that were specified to {@link TeaVM}.
|
||||
*/
|
||||
Properties getProperties();
|
||||
|
||||
/**
|
||||
* Creates a new resource of the given type. The description of valid resources
|
||||
* is available in documentation for {@link Resource}.
|
||||
*/
|
||||
<T extends Resource> T createResource(Class<T> resourceType);
|
||||
|
||||
/**
|
||||
* Creates a new resource array.
|
||||
*/
|
||||
<T extends Resource> ResourceArray<T> createResourceArray();
|
||||
|
||||
/**
|
||||
* Creates a new resource map.
|
||||
*/
|
||||
<T extends Resource> ResourceMap<T> createResourceMap();
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.metadata;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* <p>Binds a {@link MetadataGenerator} to a native method.</p>
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface MetadataProvider {
|
||||
Class<? extends MetadataGenerator> value();
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.metadata;
|
||||
|
||||
/**
|
||||
* <p>Marks a valid <b>resource interface</b>. Resource interface is an interface, that has get* and set* methods,
|
||||
* according the default convention for JavaBeans. Each property must have both getter and setter.
|
||||
* Also each property's must be either primitive value (except for <code>long</code>) or a valid resource.</p>
|
||||
*
|
||||
* @see MetadataGenerator
|
||||
* @see ResourceArray
|
||||
* @see ResourceMap
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public interface Resource {
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.metadata;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public interface ResourceArray<T extends Resource> extends Resource {
|
||||
int size();
|
||||
|
||||
T get(int i);
|
||||
|
||||
void add(T elem);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.metadata;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public interface ResourceMap<T extends Resource> extends Resource {
|
||||
boolean has(String key);
|
||||
|
||||
T get(String key);
|
||||
|
||||
void put(String key, T value);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.metadata;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface ShortResource extends Resource {
|
||||
short getValue();
|
||||
|
||||
void setValue(short value);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.metadata;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface StringResource extends Resource {
|
||||
String getValue();
|
||||
|
||||
void setValue(String value);
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.platform.metadata.Resource;
|
||||
import org.teavm.platform.metadata.ResourceArray;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class BuildTimeResourceArray<T extends Resource> implements ResourceArray<T>, ResourceWriter {
|
||||
private List<T> data = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return data.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(int i) {
|
||||
return data.get(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(T elem) {
|
||||
data.add(elem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(SourceWriter writer) throws IOException {
|
||||
writer.append('[').tokenBoundary();
|
||||
for (int i = 0; i < data.size(); ++i) {
|
||||
if (i > 0) {
|
||||
writer.append(',').ws();
|
||||
}
|
||||
ResourceWriterHelper.write(writer, data.get(i));
|
||||
}
|
||||
writer.append(']').tokenBoundary();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class BuildTimeResourceGetter implements BuildTimeResourceMethod {
|
||||
private int index;
|
||||
|
||||
public BuildTimeResourceGetter(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(BuildTimeResourceProxy proxy, Object[] args) throws Throwable {
|
||||
return proxy.data[index];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.platform.metadata.Resource;
|
||||
import org.teavm.platform.metadata.ResourceMap;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class BuildTimeResourceMap<T extends Resource> implements ResourceMap<T>, ResourceWriter {
|
||||
private Map<String, T> data = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean has(String key) {
|
||||
return data.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(String key) {
|
||||
return data.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String key, T value) {
|
||||
data.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(SourceWriter writer) throws IOException {
|
||||
writer.append('{');
|
||||
boolean first = true;
|
||||
for (Map.Entry<String, T> entry : data.entrySet()) {
|
||||
if (!first) {
|
||||
writer.append(",").ws();
|
||||
}
|
||||
first = false;
|
||||
ResourceWriterHelper.writeString(writer, entry.getKey());
|
||||
writer.ws().append(':').ws();
|
||||
ResourceWriterHelper.write(writer, entry.getValue());
|
||||
}
|
||||
writer.append('}').tokenBoundary();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
interface BuildTimeResourceMethod {
|
||||
Object invoke(BuildTimeResourceProxy proxy, Object[] args) throws Throwable;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
class BuildTimeResourceProxy implements InvocationHandler {
|
||||
private Map<Method, BuildTimeResourceMethod> methods;
|
||||
Object[] data;
|
||||
|
||||
public BuildTimeResourceProxy(Map<Method, BuildTimeResourceMethod> methods, Object[] initialData) {
|
||||
this.methods = methods;
|
||||
data = Arrays.copyOf(initialData, initialData.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
return methods.get(method).invoke(this, args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.platform.metadata.Resource;
|
||||
import org.teavm.platform.metadata.ResourceArray;
|
||||
import org.teavm.platform.metadata.ResourceMap;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class BuildTimeResourceProxyBuilder {
|
||||
private Map<Class<?>, BuildTimeResourceProxyFactory> factories = new HashMap<>();
|
||||
private static Set<Class<?>> allowedPropertyTypes = new HashSet<>(Arrays.<Class<?>>asList(
|
||||
boolean.class, byte.class, short.class, int.class, float.class, double.class,
|
||||
String.class, ResourceArray.class, ResourceMap.class));
|
||||
private static Map<Class<?>, Object> defaultValues = new HashMap<>();
|
||||
|
||||
static {
|
||||
defaultValues.put(boolean.class, false);
|
||||
defaultValues.put(byte.class, (byte)0);
|
||||
defaultValues.put(short.class, (short)0);
|
||||
defaultValues.put(int.class, 0);
|
||||
defaultValues.put(float.class, 0F);
|
||||
defaultValues.put(double.class, 0.0);
|
||||
}
|
||||
|
||||
public BuildTimeResourceProxy buildProxy(Class<?> iface) {
|
||||
BuildTimeResourceProxyFactory factory = factories.get(iface);
|
||||
if (factory == null) {
|
||||
factory = createFactory(iface);
|
||||
factories.put(iface, factory);
|
||||
}
|
||||
return factory.create();
|
||||
}
|
||||
|
||||
private BuildTimeResourceProxyFactory createFactory(Class<?> iface) {
|
||||
return new ProxyFactoryCreation(iface).create();
|
||||
}
|
||||
|
||||
private static class ProxyFactoryCreation {
|
||||
private Class<?> rootIface;
|
||||
Map<String, Class<?>> getters = new HashMap<>();
|
||||
Map<String, Class<?>> setters = new HashMap<>();
|
||||
Map<Method, BuildTimeResourceMethod> methods = new HashMap<>();
|
||||
private Map<String, Integer> propertyIndexes = new HashMap<>();
|
||||
private Object[] initialData;
|
||||
private Map<String, Class<?>> propertyTypes = new HashMap<>();
|
||||
|
||||
public ProxyFactoryCreation(Class<?> iface) {
|
||||
this.rootIface = iface;
|
||||
}
|
||||
|
||||
BuildTimeResourceProxyFactory create() {
|
||||
if (!rootIface.isInterface()) {
|
||||
throw new IllegalArgumentException("Error creating a new resource of type " + rootIface.getName() +
|
||||
" that is not an interface");
|
||||
}
|
||||
scanIface(rootIface);
|
||||
|
||||
// Fill default values
|
||||
initialData = new Object[propertyIndexes.size()];
|
||||
for (Map.Entry<String, Class<?>> property : propertyTypes.entrySet()) {
|
||||
String propertyName = property.getKey();
|
||||
Class<?> propertyType = property.getValue();
|
||||
initialData[propertyIndexes.get(propertyName)] = defaultValues.get(propertyType);
|
||||
}
|
||||
|
||||
// Generate write method
|
||||
Method writeMethod;
|
||||
try {
|
||||
writeMethod = ResourceWriter.class.getMethod("write", SourceWriter.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new AssertionError("Method must exist", e);
|
||||
}
|
||||
|
||||
// Create factory
|
||||
String[] properties = new String[propertyIndexes.size()];
|
||||
for (Map.Entry<String, Integer> entry : propertyIndexes.entrySet()) {
|
||||
properties[entry.getValue()] = entry.getKey();
|
||||
}
|
||||
methods.put(writeMethod, new BuildTimeResourceWriterMethod(properties));
|
||||
return new BuildTimeResourceProxyFactory(methods, initialData);
|
||||
}
|
||||
|
||||
private void scanIface(Class<?> iface) {
|
||||
if (!Resource.class.isAssignableFrom(iface)) {
|
||||
throw new IllegalArgumentException("Error creating a new resource of type " + iface.getName() +
|
||||
". This type does not implement the " + Resource.class.getName() + " interface");
|
||||
}
|
||||
|
||||
// Scan methods
|
||||
getters.clear();
|
||||
setters.clear();
|
||||
for (Method method : iface.getDeclaredMethods()) {
|
||||
if (method.getName().startsWith("get")) {
|
||||
scanGetter(method);
|
||||
} else if (method.getName().startsWith("is")) {
|
||||
scanBooleanGetter(method);
|
||||
} else if (method.getName().startsWith("set")) {
|
||||
scanSetter(method);
|
||||
} else {
|
||||
throwInvalidMethod(method);
|
||||
}
|
||||
}
|
||||
|
||||
// Verify consistency of getters and setters
|
||||
for (Map.Entry<String, Class<?>> property : getters.entrySet()) {
|
||||
String propertyName = property.getKey();
|
||||
Class<?> getterType = property.getValue();
|
||||
Class<?> setterType = setters.get(propertyName);
|
||||
if (setterType == null) {
|
||||
throw new IllegalArgumentException("Property " + iface.getName() + "." + propertyName +
|
||||
" has a getter, but does not have a setter");
|
||||
}
|
||||
if (!setterType.equals(getterType)) {
|
||||
throw new IllegalArgumentException("Property " + iface.getName() + "." + propertyName +
|
||||
" has a getter and a setter of different types");
|
||||
}
|
||||
}
|
||||
for (String propertyName : setters.keySet()) {
|
||||
if (!getters.containsKey(propertyName)) {
|
||||
throw new IllegalArgumentException("Property " + iface.getName() + "." + propertyName +
|
||||
" has a setter, but does not have a getter");
|
||||
}
|
||||
}
|
||||
|
||||
// Verify types of properties
|
||||
for (Map.Entry<String, Class<?>> property : getters.entrySet()) {
|
||||
String propertyName = property.getKey();
|
||||
Class<?> propertyType = property.getValue();
|
||||
if (!allowedPropertyTypes.contains(propertyType)) {
|
||||
if (!propertyType.isInterface() || !Resource.class.isAssignableFrom(propertyType)) {
|
||||
throw new IllegalArgumentException("Property " + rootIface.getName() + "." + propertyName +
|
||||
" has an illegal type " + propertyType.getName());
|
||||
}
|
||||
}
|
||||
if (!propertyTypes.containsKey(propertyName)) {
|
||||
propertyTypes.put(propertyName, propertyType);
|
||||
}
|
||||
}
|
||||
|
||||
// Scan superinterfaces
|
||||
for (Class<?> superIface : iface.getInterfaces()) {
|
||||
scanIface(superIface);
|
||||
}
|
||||
}
|
||||
|
||||
private void throwInvalidMethod(Method method) {
|
||||
throw new IllegalArgumentException("Method " + method.getDeclaringClass().getName() + "." +
|
||||
method.getName() + " is not likely to be either getter or setter");
|
||||
}
|
||||
|
||||
private void scanGetter(Method method) {
|
||||
String propertyName = extractPropertyName(method.getName().substring(3));
|
||||
if (propertyName == null || method.getReturnType().equals(void.class) ||
|
||||
method.getParameterTypes().length > 0) {
|
||||
throwInvalidMethod(method);
|
||||
}
|
||||
if (getters.put(propertyName, method.getReturnType()) != null) {
|
||||
throw new IllegalArgumentException("Method " + method.getDeclaringClass().getName() + "." +
|
||||
method.getName() + " is a duplicate getter for property " + propertyName);
|
||||
}
|
||||
methods.put(method, new BuildTimeResourceGetter(getPropertyIndex(propertyName)));
|
||||
}
|
||||
|
||||
private void scanBooleanGetter(Method method) {
|
||||
String propertyName = extractPropertyName(method.getName().substring(2));
|
||||
if (propertyName == null || !method.getReturnType().equals(boolean.class) ||
|
||||
method.getParameterTypes().length > 0) {
|
||||
throwInvalidMethod(method);
|
||||
}
|
||||
if (getters.put(propertyName, method.getReturnType()) != null) {
|
||||
throw new IllegalArgumentException("Method " + method.getDeclaringClass().getName() + "." +
|
||||
method.getName() + " is a duplicate getter for property " + propertyName);
|
||||
}
|
||||
methods.put(method, new BuildTimeResourceGetter(getPropertyIndex(propertyName)));
|
||||
}
|
||||
|
||||
private void scanSetter(Method method) {
|
||||
String propertyName = extractPropertyName(method.getName().substring(3));
|
||||
if (propertyName == null || !method.getReturnType().equals(void.class) ||
|
||||
method.getParameterTypes().length != 1) {
|
||||
throwInvalidMethod(method);
|
||||
}
|
||||
if (setters.put(propertyName, method.getParameterTypes()[0]) != null) {
|
||||
throw new IllegalArgumentException("Method " + method.getDeclaringClass().getName() + "." +
|
||||
method.getName() + " is a duplicate setter for property " + propertyName);
|
||||
}
|
||||
methods.put(method, new BuildTimeResourceSetter(getPropertyIndex(propertyName)));
|
||||
}
|
||||
|
||||
private String extractPropertyName(String propertyName) {
|
||||
if (propertyName.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
char c = propertyName.charAt(0);
|
||||
if (c != Character.toUpperCase(c)) {
|
||||
return null;
|
||||
}
|
||||
if (propertyName.length() == 1) {
|
||||
return propertyName.toLowerCase();
|
||||
}
|
||||
c = propertyName.charAt(1);
|
||||
if (c == Character.toUpperCase(c)) {
|
||||
return propertyName;
|
||||
} else {
|
||||
return Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
private int getPropertyIndex(String propertyName) {
|
||||
Integer index = propertyIndexes.get(propertyName);
|
||||
if (index == null) {
|
||||
index = propertyIndexes.size();
|
||||
propertyIndexes.put(propertyName, index);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class BuildTimeResourceProxyFactory {
|
||||
private Map<Method, BuildTimeResourceMethod> methods = new HashMap<>();
|
||||
private Object[] initialData;
|
||||
|
||||
public BuildTimeResourceProxyFactory(Map<Method, BuildTimeResourceMethod> methods, Object[] initialData) {
|
||||
this.methods = methods;
|
||||
this.initialData = initialData;
|
||||
}
|
||||
|
||||
BuildTimeResourceProxy create() {
|
||||
return new BuildTimeResourceProxy(methods, initialData);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class BuildTimeResourceSetter implements BuildTimeResourceMethod {
|
||||
private int index;
|
||||
|
||||
public BuildTimeResourceSetter(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(BuildTimeResourceProxy proxy, Object[] args) throws Throwable {
|
||||
proxy.data[index] = args[0];
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class BuildTimeResourceWriterMethod implements BuildTimeResourceMethod {
|
||||
private String[] propertyNames;
|
||||
|
||||
public BuildTimeResourceWriterMethod(String[] propertyNames) {
|
||||
this.propertyNames = propertyNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(BuildTimeResourceProxy proxy, Object[] args) throws Throwable {
|
||||
SourceWriter writer = (SourceWriter)args[0];
|
||||
writer.append('{');
|
||||
for (int i = 0; i < propertyNames.length; ++i) {
|
||||
if (i > 0) {
|
||||
writer.append(',').ws();
|
||||
}
|
||||
ResourceWriterHelper.writeString(writer, propertyNames[i]);
|
||||
writer.ws().append(':').ws();
|
||||
ResourceWriterHelper.write(writer, proxy.data[i]);
|
||||
}
|
||||
writer.append('}').tokenBoundary();
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Properties;
|
||||
import org.teavm.common.ServiceRepository;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
import org.teavm.platform.metadata.MetadataGeneratorContext;
|
||||
import org.teavm.platform.metadata.Resource;
|
||||
import org.teavm.platform.metadata.ResourceArray;
|
||||
import org.teavm.platform.metadata.ResourceMap;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class DefaultMetadataGeneratorContext implements MetadataGeneratorContext {
|
||||
private ListableClassReaderSource classSource;
|
||||
private ClassLoader classLoader;
|
||||
private Properties properties;
|
||||
private BuildTimeResourceProxyBuilder proxyBuilder = new BuildTimeResourceProxyBuilder();
|
||||
private ServiceRepository services;
|
||||
|
||||
public DefaultMetadataGeneratorContext(ListableClassReaderSource classSource, ClassLoader classLoader,
|
||||
Properties properties, ServiceRepository services) {
|
||||
this.classSource = classSource;
|
||||
this.classLoader = classLoader;
|
||||
this.properties = properties;
|
||||
this.services = services;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListableClassReaderSource getClassSource() {
|
||||
return classSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties getProperties() {
|
||||
return new Properties(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Resource> T createResource(Class<T> resourceType) {
|
||||
return resourceType.cast(Proxy.newProxyInstance(classLoader,
|
||||
new Class<?>[] { resourceType, ResourceWriter.class },
|
||||
proxyBuilder.buildProxy(resourceType)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Resource> ResourceArray<T> createResourceArray() {
|
||||
return new BuildTimeResourceArray<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Resource> ResourceMap<T> createResourceMap() {
|
||||
return new BuildTimeResourceMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getService(Class<T> type) {
|
||||
return services.getService(type);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.javascript.ni.Generator;
|
||||
import org.teavm.javascript.ni.GeneratorContext;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.platform.metadata.MetadataGenerator;
|
||||
import org.teavm.platform.metadata.MetadataProvider;
|
||||
import org.teavm.platform.metadata.Resource;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class MetadataProviderNativeGenerator implements Generator {
|
||||
@Override
|
||||
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
|
||||
// Validate method
|
||||
ClassReader cls = context.getClassSource().get(methodRef.getClassName());
|
||||
MethodReader method = cls.getMethod(methodRef.getDescriptor());
|
||||
AnnotationReader providerAnnot = method.getAnnotations().get(MetadataProvider.class.getName());
|
||||
if (providerAnnot == null) {
|
||||
return;
|
||||
}
|
||||
if (!method.hasModifier(ElementModifier.NATIVE)) {
|
||||
throw new IllegalStateException("Method " + method.getReference() + " was marked with " +
|
||||
MetadataProvider.class.getName() + " but it is not native");
|
||||
}
|
||||
|
||||
// Find and instantiate metadata generator
|
||||
ValueType generatorType = providerAnnot.getValue("value").getJavaClass();
|
||||
String generatorClassName = ((ValueType.Object)generatorType).getClassName();
|
||||
Class<?> generatorClass;
|
||||
try {
|
||||
generatorClass = Class.forName(generatorClassName, true, context.getClassLoader());
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException("Can't find metadata generator class: " + generatorClassName, e);
|
||||
}
|
||||
Constructor<?> cons;
|
||||
try {
|
||||
cons = generatorClass.getConstructor();
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException("Metadata generator " + generatorClassName + " does not have a public " +
|
||||
"no-arg constructor", e);
|
||||
}
|
||||
MetadataGenerator generator;
|
||||
try {
|
||||
generator = (MetadataGenerator)cons.newInstance();
|
||||
} catch (IllegalAccessException | InstantiationException e) {
|
||||
throw new RuntimeException("Error instantiating metadata generator " + generatorClassName, e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException("Error instantiating metadata generator " + generatorClassName,
|
||||
e.getTargetException());
|
||||
}
|
||||
DefaultMetadataGeneratorContext metadataContext = new DefaultMetadataGeneratorContext(context.getClassSource(),
|
||||
context.getClassLoader(), context.getProperties(), context);
|
||||
|
||||
// Generate resource loader
|
||||
Resource resource = generator.generateMetadata(metadataContext, methodRef);
|
||||
writer.append("if (!window.hasOwnProperty(\"").appendMethodBody(methodRef).append("$$resource\")) {")
|
||||
.indent().softNewLine();
|
||||
writer.appendMethodBody(methodRef).append("$$resource = ");
|
||||
ResourceWriterHelper.write(writer, resource);
|
||||
writer.append(';').softNewLine();
|
||||
writer.outdent().append('}').softNewLine();
|
||||
writer.append("return ").appendMethodBody(methodRef).append("$$resource;").softNewLine();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
import org.teavm.javascript.ni.GeneratedBy;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.platform.metadata.MetadataProvider;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class MetadataProviderTransformer implements ClassHolderTransformer {
|
||||
@Override
|
||||
public void transformClass(ClassHolder cls, ClassReaderSource innerSource) {
|
||||
for (MethodHolder method : cls.getMethods()) {
|
||||
AnnotationReader providerAnnot = method.getAnnotations().get(MetadataProvider.class.getName());
|
||||
if (providerAnnot == null) {
|
||||
continue;
|
||||
}
|
||||
AnnotationHolder genAnnot = new AnnotationHolder(GeneratedBy.class.getName());
|
||||
genAnnot.getValues().put("value", new AnnotationValue(ValueType.object(
|
||||
MetadataProviderNativeGenerator.class.getName())));
|
||||
method.getAnnotations().add(genAnnot);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
import org.teavm.vm.spi.TeaVMHost;
|
||||
import org.teavm.vm.spi.TeaVMPlugin;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public class PlatformPlugin implements TeaVMPlugin {
|
||||
@Override
|
||||
public void install(TeaVMHost host) {
|
||||
host.add(new MetadataProviderTransformer());
|
||||
host.add(new ResourceTransformer());
|
||||
host.add(new ResourceAccessorTransformer(host));
|
||||
host.add(new ResourceAccessorDependencyListener());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
import org.teavm.platform.metadata.Resource;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
final class ResourceAccessor {
|
||||
public static native Object get(Object obj, String propertyName);
|
||||
|
||||
public static native void put(Object obj, String propertyName, Object elem);
|
||||
|
||||
public static native Resource get(Object obj, int index);
|
||||
|
||||
public static native void add(Object obj, Resource elem);
|
||||
|
||||
public static native boolean has(Object obj, String key);
|
||||
|
||||
public static native int size(Object obj);
|
||||
|
||||
public static native int castToInt(Object obj);
|
||||
|
||||
public static native short castToShort(Object obj);
|
||||
|
||||
public static native byte castToByte(Object obj);
|
||||
|
||||
public static native boolean castToBoolean(Object obj);
|
||||
|
||||
public static native float castToFloat(Object obj);
|
||||
|
||||
public static native double castToDouble(Object obj);
|
||||
|
||||
public static native String castToString(Object obj);
|
||||
|
||||
public static native Object castFromInt(int value);
|
||||
|
||||
public static native Object castFromShort(short value);
|
||||
|
||||
public static native Object castFromByte(byte value);
|
||||
|
||||
public static native Object castFromBoolean(boolean value);
|
||||
|
||||
public static native Object castFromFloat(float value);
|
||||
|
||||
public static native Object castFromDouble(double value);
|
||||
|
||||
public static native Object castFromString(String value);
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
import org.teavm.dependency.DependencyAgent;
|
||||
import org.teavm.dependency.DependencyListener;
|
||||
import org.teavm.dependency.FieldDependency;
|
||||
import org.teavm.dependency.MethodDependency;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class ResourceAccessorDependencyListener implements DependencyListener {
|
||||
@Override
|
||||
public void started(DependencyAgent agent) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void classAchieved(DependencyAgent agent, String className) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
|
||||
switch (method.getReference().getName()) {
|
||||
case "castToString":
|
||||
method.getResult().propagate("java.lang.String");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fieldAchieved(DependencyAgent agent, FieldDependency field) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.teavm.javascript.ast.ConstantExpr;
|
||||
import org.teavm.javascript.ast.Expr;
|
||||
import org.teavm.javascript.ni.Injector;
|
||||
import org.teavm.javascript.ni.InjectorContext;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class ResourceAccessorGenerator implements Injector {
|
||||
@Override
|
||||
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
|
||||
switch (methodRef.getName()) {
|
||||
case "get":
|
||||
if (methodRef.getDescriptor().parameterType(1) == ValueType.INTEGER) {
|
||||
context.writeExpr(context.getArgument(0));
|
||||
context.getWriter().append('[');
|
||||
context.writeExpr(context.getArgument(1));
|
||||
context.getWriter().append(']');
|
||||
} else {
|
||||
context.writeExpr(context.getArgument(0));
|
||||
writePropertyAccessor(context, context.getArgument(1));
|
||||
}
|
||||
break;
|
||||
case "put":
|
||||
context.getWriter().append('(');
|
||||
if (methodRef.getDescriptor().parameterType(1) == ValueType.INTEGER) {
|
||||
context.writeExpr(context.getArgument(0));
|
||||
context.getWriter().append('[');
|
||||
context.writeExpr(context.getArgument(1));
|
||||
} else {
|
||||
context.writeExpr(context.getArgument(0));
|
||||
writePropertyAccessor(context, context.getArgument(1));
|
||||
}
|
||||
context.getWriter().ws().append('=').ws();
|
||||
context.writeExpr(context.getArgument(2));
|
||||
context.getWriter().append(')');
|
||||
break;
|
||||
case "add":
|
||||
context.writeExpr(context.getArgument(0));
|
||||
context.getWriter().append(".push(");
|
||||
context.writeExpr(context.getArgument(1));
|
||||
context.getWriter().append(')');
|
||||
break;
|
||||
case "has":
|
||||
context.writeExpr(context.getArgument(0));
|
||||
context.getWriter().append(".hasOwnProperty(");
|
||||
writeStringExpr(context, context.getArgument(1));
|
||||
context.getWriter().append(')');
|
||||
break;
|
||||
case "size":
|
||||
context.writeExpr(context.getArgument(0));
|
||||
context.getWriter().append(".length");
|
||||
break;
|
||||
case "castToInt":
|
||||
case "castToShort":
|
||||
case "castToByte":
|
||||
case "castToBoolean":
|
||||
case "castToFloat":
|
||||
case "castToDouble":
|
||||
case "castFromInt":
|
||||
case "castFromShort":
|
||||
case "castFromByte":
|
||||
case "castFromBoolean":
|
||||
case "castFromFloat":
|
||||
case "castFromDouble":
|
||||
context.writeExpr(context.getArgument(0));
|
||||
break;
|
||||
case "castToString":
|
||||
context.getWriter().append('(');
|
||||
context.writeExpr(context.getArgument(0));
|
||||
context.getWriter().ws().append("!==").ws().append("null").ws().append("?").ws();
|
||||
context.getWriter().append("$rt_str(");
|
||||
context.writeExpr(context.getArgument(0));
|
||||
context.getWriter().append(")").ws().append(':').ws().append("null)");
|
||||
break;
|
||||
case "castFromString":
|
||||
context.getWriter().append('(');
|
||||
context.writeExpr(context.getArgument(0));
|
||||
context.getWriter().ws().append("!==").ws().append("null").ws().append("?").ws();
|
||||
context.getWriter().append("$rt_ustr(");
|
||||
context.writeExpr(context.getArgument(0));
|
||||
context.getWriter().append(")").ws().append(':').ws().append("null)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void writePropertyAccessor(InjectorContext context, Expr property) throws IOException {
|
||||
if (property instanceof ConstantExpr) {
|
||||
String str = (String)((ConstantExpr)property).getValue();
|
||||
if (str.isEmpty()) {
|
||||
context.getWriter().append("[\"\"]");
|
||||
return;
|
||||
}
|
||||
if (isValidIndentifier(str)) {
|
||||
context.getWriter().append(".").append(str);
|
||||
return;
|
||||
}
|
||||
}
|
||||
context.getWriter().append("[$rt_ustr(");
|
||||
context.writeExpr(property);
|
||||
context.getWriter().append(")]");
|
||||
}
|
||||
|
||||
private void writeStringExpr(InjectorContext context, Expr expr) throws IOException {
|
||||
if (expr instanceof ConstantExpr) {
|
||||
String str = (String)((ConstantExpr)expr).getValue();
|
||||
context.getWriter().append('"');
|
||||
context.writeEscaped(str);
|
||||
context.getWriter().append('"');
|
||||
return;
|
||||
}
|
||||
context.getWriter().append("$rt_ustr(");
|
||||
context.writeExpr(expr);
|
||||
context.getWriter().append(")");
|
||||
}
|
||||
|
||||
private boolean isValidIndentifier(String str) {
|
||||
if (!Character.isJavaIdentifierStart(str.charAt(0))) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 1; i < str.length(); ++i) {
|
||||
if (!Character.isJavaIdentifierPart(str.charAt(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
import org.teavm.model.ClassHolder;
|
||||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.vm.spi.TeaVMHost;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class ResourceAccessorTransformer implements ClassHolderTransformer {
|
||||
private TeaVMHost vm;
|
||||
|
||||
public ResourceAccessorTransformer(TeaVMHost vm) {
|
||||
this.vm = vm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transformClass(ClassHolder cls, ClassReaderSource innerSource) {
|
||||
if (cls.getName().equals(ResourceAccessor.class.getName())) {
|
||||
ResourceAccessorGenerator generator = new ResourceAccessorGenerator();
|
||||
for (MethodHolder method : cls.getMethods()) {
|
||||
vm.add(method.getReference(), generator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,285 @@
|
|||
package org.teavm.platform.plugin;
|
||||
|
||||
import java.util.*;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.model.instructions.*;
|
||||
import org.teavm.platform.metadata.Resource;
|
||||
import org.teavm.platform.metadata.ResourceArray;
|
||||
import org.teavm.platform.metadata.ResourceMap;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class ResourceProgramTransformer {
|
||||
private ClassReaderSource innerSource;
|
||||
private Program program;
|
||||
|
||||
public ResourceProgramTransformer(ClassReaderSource innerSource, Program program) {
|
||||
this.innerSource = innerSource;
|
||||
this.program = program;
|
||||
}
|
||||
|
||||
public void transformProgram() {
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
transformBasicBlock(program.basicBlockAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
private void transformBasicBlock(BasicBlock block) {
|
||||
List<Instruction> instructions = block.getInstructions();
|
||||
for (int i = 0; i < instructions.size(); ++i) {
|
||||
Instruction insn = instructions.get(i);
|
||||
if (insn instanceof InvokeInstruction) {
|
||||
InvokeInstruction invoke = (InvokeInstruction)insn;
|
||||
List<Instruction> replacement = transformInvoke(invoke);
|
||||
if (replacement != null) {
|
||||
instructions.set(i, new EmptyInstruction());
|
||||
instructions.addAll(i, replacement);
|
||||
i += replacement.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<Instruction> transformInvoke(InvokeInstruction insn) {
|
||||
if (insn.getType() != InvocationType.VIRTUAL) {
|
||||
return null;
|
||||
}
|
||||
MethodReference method = insn.getMethod();
|
||||
if (method.getClassName().equals(ResourceArray.class.getName()) ||
|
||||
method.getClassName().equals(ResourceMap.class.getName())) {
|
||||
InvokeInstruction accessInsn = new InvokeInstruction();
|
||||
accessInsn.setType(InvocationType.SPECIAL);
|
||||
ValueType[] types = new ValueType[method.getDescriptor().parameterCount() + 2];
|
||||
types[0] = ValueType.object("java.lang.Object");
|
||||
System.arraycopy(method.getDescriptor().getSignature(), 0, types, 1,
|
||||
method.getDescriptor().parameterCount() + 1);
|
||||
accessInsn.setMethod(new MethodReference(ResourceAccessor.class.getName(), method.getName(), types));
|
||||
accessInsn.getArguments().add(insn.getInstance());
|
||||
accessInsn.getArguments().addAll(insn.getArguments());
|
||||
accessInsn.setReceiver(insn.getReceiver());
|
||||
return Arrays.<Instruction>asList(accessInsn);
|
||||
}
|
||||
ClassReader iface = innerSource.get(method.getClassName());
|
||||
if (!isSubclass(iface, Resource.class.getName())) {
|
||||
return null;
|
||||
}
|
||||
if (method.getName().startsWith("get")) {
|
||||
if (method.getName().length() > 3) {
|
||||
return transformGetterInvocation(insn, getPropertyName(method.getName().substring(3)));
|
||||
}
|
||||
} else if (method.getName().startsWith("is")) {
|
||||
if (method.getName().length() > 2) {
|
||||
return transformGetterInvocation(insn, getPropertyName(method.getName().substring(2)));
|
||||
}
|
||||
} else if (method.getName().startsWith("set")) {
|
||||
if (method.getName().length() > 3) {
|
||||
return transformSetterInvocation(insn, getPropertyName(method.getName().substring(3)));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isSubclass(ClassReader cls, String superClass) {
|
||||
if (cls.getName().equals(superClass)) {
|
||||
return true;
|
||||
}
|
||||
ClassReader parent = cls.getParent() != null ? innerSource.get(cls.getParent()) : null;
|
||||
if (parent != null && isSubclass(parent, superClass)) {
|
||||
return true;
|
||||
}
|
||||
for (String ifaceName : cls.getInterfaces()) {
|
||||
ClassReader iface = innerSource.get(ifaceName);
|
||||
if (iface != null) {
|
||||
return isSubclass(iface, superClass);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<Instruction> transformGetterInvocation(InvokeInstruction insn, String property) {
|
||||
if (insn.getReceiver() == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
ValueType type = insn.getMethod().getDescriptor().getResultType();
|
||||
List<Instruction> instructions = new ArrayList<>();
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive)type).getKind()) {
|
||||
case BOOLEAN:
|
||||
getAndCastProperty(insn, property, instructions, boolean.class);
|
||||
return instructions;
|
||||
case BYTE:
|
||||
getAndCastProperty(insn, property, instructions, byte.class);
|
||||
return instructions;
|
||||
case SHORT:
|
||||
getAndCastProperty(insn, property, instructions, short.class);
|
||||
return instructions;
|
||||
case INTEGER:
|
||||
getAndCastProperty(insn, property, instructions, int.class);
|
||||
return instructions;
|
||||
case FLOAT:
|
||||
getAndCastProperty(insn, property, instructions, float.class);
|
||||
return instructions;
|
||||
case DOUBLE:
|
||||
getAndCastProperty(insn, property, instructions, double.class);
|
||||
return instructions;
|
||||
case CHARACTER:
|
||||
case LONG:
|
||||
break;
|
||||
}
|
||||
} else if (type instanceof ValueType.Object) {
|
||||
switch (((ValueType.Object)type).getClassName()) {
|
||||
case "java.lang.String": {
|
||||
Variable resultVar = insn.getProgram().createVariable();
|
||||
getProperty(insn, property, instructions, resultVar);
|
||||
InvokeInstruction castInvoke = new InvokeInstruction();
|
||||
castInvoke.setType(InvocationType.SPECIAL);
|
||||
castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castToString",
|
||||
Object.class, String.class));
|
||||
castInvoke.getArguments().add(resultVar);
|
||||
castInvoke.setReceiver(insn.getReceiver());
|
||||
instructions.add(castInvoke);
|
||||
return instructions;
|
||||
}
|
||||
default: {
|
||||
Variable resultVar = insn.getProgram().createVariable();
|
||||
getProperty(insn, property, instructions, resultVar);
|
||||
CastInstruction castInsn = new CastInstruction();
|
||||
castInsn.setReceiver(insn.getReceiver());
|
||||
castInsn.setTargetType(type);
|
||||
castInsn.setValue(resultVar);
|
||||
instructions.add(castInsn);
|
||||
return instructions;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void getProperty(InvokeInstruction insn, String property, List<Instruction> instructions,
|
||||
Variable resultVar) {
|
||||
Variable nameVar = program.createVariable();
|
||||
StringConstantInstruction nameInsn = new StringConstantInstruction();
|
||||
nameInsn.setConstant(property);
|
||||
nameInsn.setReceiver(nameVar);
|
||||
instructions.add(nameInsn);
|
||||
InvokeInstruction accessorInvoke = new InvokeInstruction();
|
||||
accessorInvoke.setType(InvocationType.SPECIAL);
|
||||
accessorInvoke.setMethod(new MethodReference(ResourceAccessor.class, "get",
|
||||
Object.class, String.class, Object.class));
|
||||
accessorInvoke.getArguments().add(insn.getInstance());
|
||||
accessorInvoke.getArguments().add(nameVar);
|
||||
accessorInvoke.setReceiver(resultVar);
|
||||
instructions.add(accessorInvoke);
|
||||
}
|
||||
|
||||
private void getAndCastProperty(InvokeInstruction insn, String property, List<Instruction> instructions,
|
||||
Class<?> primitive) {
|
||||
Variable resultVar = program.createVariable();
|
||||
getProperty(insn, property, instructions, resultVar);
|
||||
InvokeInstruction castInvoke = new InvokeInstruction();
|
||||
castInvoke.setType(InvocationType.SPECIAL);
|
||||
String primitiveCapitalized = primitive.getName();
|
||||
primitiveCapitalized = Character.toUpperCase(primitiveCapitalized.charAt(0)) +
|
||||
primitiveCapitalized.substring(1);
|
||||
castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castTo" + primitiveCapitalized,
|
||||
Object.class, primitive));
|
||||
castInvoke.getArguments().add(resultVar);
|
||||
castInvoke.setReceiver(insn.getReceiver());
|
||||
instructions.add(castInvoke);
|
||||
}
|
||||
|
||||
private List<Instruction> transformSetterInvocation(InvokeInstruction insn, String property) {
|
||||
ValueType type = insn.getMethod().getDescriptor().parameterType(0);
|
||||
List<Instruction> instructions = new ArrayList<>();
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive)type).getKind()) {
|
||||
case BOOLEAN:
|
||||
castAndSetProperty(insn, property, instructions, boolean.class);
|
||||
return instructions;
|
||||
case BYTE:
|
||||
castAndSetProperty(insn, property, instructions, byte.class);
|
||||
return instructions;
|
||||
case SHORT:
|
||||
castAndSetProperty(insn, property, instructions, short.class);
|
||||
return instructions;
|
||||
case INTEGER:
|
||||
castAndSetProperty(insn, property, instructions, int.class);
|
||||
return instructions;
|
||||
case FLOAT:
|
||||
castAndSetProperty(insn, property, instructions, float.class);
|
||||
return instructions;
|
||||
case DOUBLE:
|
||||
castAndSetProperty(insn, property, instructions, double.class);
|
||||
return instructions;
|
||||
case CHARACTER:
|
||||
case LONG:
|
||||
break;
|
||||
}
|
||||
} else if (type instanceof ValueType.Object) {
|
||||
switch (((ValueType.Object)type).getClassName()) {
|
||||
case "java.lang.String": {
|
||||
Variable castVar = insn.getProgram().createVariable();
|
||||
InvokeInstruction castInvoke = new InvokeInstruction();
|
||||
castInvoke.setType(InvocationType.SPECIAL);
|
||||
castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castFromString",
|
||||
String.class, Object.class));
|
||||
castInvoke.getArguments().add(insn.getArguments().get(0));
|
||||
castInvoke.setReceiver(castVar);
|
||||
instructions.add(castInvoke);
|
||||
setProperty(insn, property, instructions, castVar);
|
||||
return instructions;
|
||||
}
|
||||
default: {
|
||||
setProperty(insn, property, instructions, insn.getArguments().get(0));
|
||||
return instructions;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void setProperty(InvokeInstruction insn, String property, List<Instruction> instructions,
|
||||
Variable valueVar) {
|
||||
Variable nameVar = program.createVariable();
|
||||
StringConstantInstruction nameInsn = new StringConstantInstruction();
|
||||
nameInsn.setConstant(property);
|
||||
nameInsn.setReceiver(nameVar);
|
||||
instructions.add(nameInsn);
|
||||
InvokeInstruction accessorInvoke = new InvokeInstruction();
|
||||
accessorInvoke.setType(InvocationType.SPECIAL);
|
||||
accessorInvoke.setMethod(new MethodReference(ResourceAccessor.class, "put",
|
||||
Object.class, String.class, Object.class, void.class));
|
||||
accessorInvoke.getArguments().add(insn.getInstance());
|
||||
accessorInvoke.getArguments().add(nameVar);
|
||||
accessorInvoke.getArguments().add(valueVar);
|
||||
instructions.add(accessorInvoke);
|
||||
}
|
||||
|
||||
private void castAndSetProperty(InvokeInstruction insn, String property, List<Instruction> instructions,
|
||||
Class<?> primitive) {
|
||||
Variable castVar = program.createVariable();
|
||||
InvokeInstruction castInvoke = new InvokeInstruction();
|
||||
castInvoke.setType(InvocationType.SPECIAL);
|
||||
String primitiveCapitalized = primitive.getName();
|
||||
primitiveCapitalized = Character.toUpperCase(primitiveCapitalized.charAt(0)) +
|
||||
primitiveCapitalized.substring(1);
|
||||
castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castFrom" + primitiveCapitalized,
|
||||
primitive, Object.class));
|
||||
castInvoke.getArguments().add(insn.getArguments().get(0));
|
||||
castInvoke.setReceiver(castVar);
|
||||
instructions.add(castInvoke);
|
||||
setProperty(insn, property, instructions, castVar);
|
||||
}
|
||||
|
||||
private String getPropertyName(String name) {
|
||||
if (name.length() == 1) {
|
||||
return name.toLowerCase();
|
||||
}
|
||||
if (Character.isUpperCase(name.charAt(1))) {
|
||||
return name;
|
||||
}
|
||||
return Character.toLowerCase(name.charAt(0)) + name.substring(1);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
import org.teavm.model.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class ResourceTransformer implements ClassHolderTransformer {
|
||||
@Override
|
||||
public void transformClass(ClassHolder cls, ClassReaderSource innerSource) {
|
||||
for (MethodHolder method : cls.getMethods()) {
|
||||
Program program = method.getProgram();
|
||||
if (program != null) {
|
||||
new ResourceProgramTransformer(innerSource, program).transformProgram();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface ResourceWriter {
|
||||
void write(SourceWriter writer) throws IOException;
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright 2014 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.platform.plugin;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
final class ResourceWriterHelper {
|
||||
public static void write(SourceWriter writer, Object resource) throws IOException {
|
||||
if (resource == null) {
|
||||
writer.append("null");
|
||||
} else {
|
||||
if (resource instanceof ResourceWriter) {
|
||||
((ResourceWriter)resource).write(writer);
|
||||
} else if (resource instanceof Number) {
|
||||
writer.append(resource);
|
||||
} else if (resource instanceof Boolean) {
|
||||
writer.append(resource == Boolean.TRUE ? "true" : "false");
|
||||
} else if (resource instanceof String) {
|
||||
writeString(writer, (String)resource);
|
||||
} else {
|
||||
throw new RuntimeException("Error compiling resources. Value of illegal type found: " +
|
||||
resource.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeString(SourceWriter writer, String s) throws IOException {
|
||||
writer.append('"');
|
||||
for (int i = 0; i < s.length(); ++i) {
|
||||
char c = s.charAt(i);
|
||||
switch (c) {
|
||||
case '\0':
|
||||
writer.append("\\0");
|
||||
break;
|
||||
case '\n':
|
||||
writer.append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
writer.append("\\r");
|
||||
break;
|
||||
case '\t':
|
||||
writer.append("\\t");
|
||||
break;
|
||||
default:
|
||||
if (c < 32) {
|
||||
writer.append("\\u00").append(Character.forDigit(c / 16, 16))
|
||||
.append(Character.forDigit(c % 16, 16));
|
||||
} else {
|
||||
writer.append(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
writer.append('"');
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.teavm.platform.plugin.PlatformPlugin
|
Loading…
Reference in New Issue
Block a user