mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Adds more metadata usecases
This commit is contained in:
parent
b9d6e29ca2
commit
da2a26fb4f
|
@ -61,5 +61,44 @@ public class MetadataGeneratorTest {
|
||||||
assertEquals("baz", res.getArrayB().get(0).getBar());
|
assertEquals("baz", res.getArrayB().get(0).getBar());
|
||||||
assertNull(res.getArrayC());
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,8 @@ public class TestResourceGenerator implements MetadataGenerator {
|
||||||
return createInt(context, 23);
|
return createInt(context, 23);
|
||||||
case "getResource":
|
case "getResource":
|
||||||
return getResource(context);
|
return getResource(context);
|
||||||
|
case "getEmptyResource":
|
||||||
|
return context.createResource(TestResource.class);
|
||||||
default:
|
default:
|
||||||
throw new RuntimeException("Unsupported method: " + method);
|
throw new RuntimeException("Unsupported method: " + method);
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ class BuildTimeResourceProxyBuilder {
|
||||||
Map<Method, BuildTimeResourceMethod> methods = new HashMap<>();
|
Map<Method, BuildTimeResourceMethod> methods = new HashMap<>();
|
||||||
private Map<String, Integer> propertyIndexes = new HashMap<>();
|
private Map<String, Integer> propertyIndexes = new HashMap<>();
|
||||||
private Object[] initialData;
|
private Object[] initialData;
|
||||||
|
private Map<String, Class<?>> propertyTypes = new HashMap<>();
|
||||||
|
|
||||||
public ProxyFactoryCreation(Class<?> iface) {
|
public ProxyFactoryCreation(Class<?> iface) {
|
||||||
this.rootIface = iface;
|
this.rootIface = iface;
|
||||||
|
@ -73,12 +74,24 @@ class BuildTimeResourceProxyBuilder {
|
||||||
" that is not an interface");
|
" that is not an interface");
|
||||||
}
|
}
|
||||||
scanIface(rootIface);
|
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;
|
Method writeMethod;
|
||||||
try {
|
try {
|
||||||
writeMethod = ResourceWriter.class.getMethod("write", SourceWriter.class);
|
writeMethod = ResourceWriter.class.getMethod("write", SourceWriter.class);
|
||||||
} catch (NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
throw new AssertionError("Method must exist", e);
|
throw new AssertionError("Method must exist", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create factory
|
||||||
String[] properties = new String[propertyIndexes.size()];
|
String[] properties = new String[propertyIndexes.size()];
|
||||||
for (Map.Entry<String, Integer> entry : propertyIndexes.entrySet()) {
|
for (Map.Entry<String, Integer> entry : propertyIndexes.entrySet()) {
|
||||||
properties[entry.getValue()] = entry.getKey();
|
properties[entry.getValue()] = entry.getKey();
|
||||||
|
@ -129,18 +142,19 @@ class BuildTimeResourceProxyBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify types of properties and fill default values
|
// Verify types of properties
|
||||||
initialData = new Object[propertyIndexes.size()];
|
|
||||||
for (Map.Entry<String, Class<?>> property : getters.entrySet()) {
|
for (Map.Entry<String, Class<?>> property : getters.entrySet()) {
|
||||||
String propertyName = property.getKey();
|
String propertyName = property.getKey();
|
||||||
Class<?> propertyType = property.getValue();
|
Class<?> propertyType = property.getValue();
|
||||||
if (!allowedPropertyTypes.contains(propertyType)) {
|
if (!allowedPropertyTypes.contains(propertyType)) {
|
||||||
if (!propertyType.isInterface() || !Resource.class.isAssignableFrom(propertyType)) {
|
if (!propertyType.isInterface() || !Resource.class.isAssignableFrom(propertyType)) {
|
||||||
throw new IllegalArgumentException("Property " + iface.getName() + "." + propertyName +
|
throw new IllegalArgumentException("Property " + rootIface.getName() + "." + propertyName +
|
||||||
" has an illegal type " + propertyType.getName());
|
" has an illegal type " + propertyType.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initialData[propertyIndexes.get(propertyName)] = defaultValues.get(propertyType);
|
if (!propertyTypes.containsKey(propertyName)) {
|
||||||
|
propertyTypes.put(propertyName, propertyType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan superinterfaces
|
// Scan superinterfaces
|
||||||
|
|
|
@ -52,7 +52,7 @@ class ResourceAccessorGenerator implements Injector {
|
||||||
context.writeExpr(context.getArgument(0));
|
context.writeExpr(context.getArgument(0));
|
||||||
writePropertyAccessor(context, context.getArgument(1));
|
writePropertyAccessor(context, context.getArgument(1));
|
||||||
}
|
}
|
||||||
context.getWriter().append(']').ws().append('=').ws();
|
context.getWriter().ws().append('=').ws();
|
||||||
context.writeExpr(context.getArgument(2));
|
context.writeExpr(context.getArgument(2));
|
||||||
context.getWriter().append(')');
|
context.getWriter().append(')');
|
||||||
break;
|
break;
|
||||||
|
@ -87,14 +87,20 @@ class ResourceAccessorGenerator implements Injector {
|
||||||
context.writeExpr(context.getArgument(0));
|
context.writeExpr(context.getArgument(0));
|
||||||
break;
|
break;
|
||||||
case "castToString":
|
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.getWriter().append("$rt_str(");
|
||||||
context.writeExpr(context.getArgument(0));
|
context.writeExpr(context.getArgument(0));
|
||||||
context.getWriter().append(")");
|
context.getWriter().append(")").ws().append(':').ws().append("null)");
|
||||||
break;
|
break;
|
||||||
case "castFromString":
|
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.getWriter().append("$rt_ustr(");
|
||||||
context.writeExpr(context.getArgument(0));
|
context.writeExpr(context.getArgument(0));
|
||||||
context.getWriter().append(")");
|
context.getWriter().append(")").ws().append(':').ws().append("null)");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,9 +191,88 @@ class ResourceProgramTransformer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Instruction> transformSetterInvocation(InvokeInstruction insn, String property) {
|
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;
|
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) {
|
private String getPropertyName(String name) {
|
||||||
if (name.length() == 1) {
|
if (name.length() == 1) {
|
||||||
return name.toLowerCase();
|
return name.toLowerCase();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user