mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -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());
|
||||
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);
|
||||
case "getResource":
|
||||
return getResource(context);
|
||||
case "getEmptyResource":
|
||||
return context.createResource(TestResource.class);
|
||||
default:
|
||||
throw new RuntimeException("Unsupported method: " + method);
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ class BuildTimeResourceProxyBuilder {
|
|||
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;
|
||||
|
@ -73,12 +74,24 @@ class BuildTimeResourceProxyBuilder {
|
|||
" 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();
|
||||
|
@ -129,18 +142,19 @@ class BuildTimeResourceProxyBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
// Verify types of properties and fill default values
|
||||
initialData = new Object[propertyIndexes.size()];
|
||||
// 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 " + iface.getName() + "." + propertyName +
|
||||
throw new IllegalArgumentException("Property " + rootIface.getName() + "." + propertyName +
|
||||
" has an illegal type " + propertyType.getName());
|
||||
}
|
||||
}
|
||||
initialData[propertyIndexes.get(propertyName)] = defaultValues.get(propertyType);
|
||||
if (!propertyTypes.containsKey(propertyName)) {
|
||||
propertyTypes.put(propertyName, propertyType);
|
||||
}
|
||||
}
|
||||
|
||||
// Scan superinterfaces
|
||||
|
|
|
@ -52,7 +52,7 @@ class ResourceAccessorGenerator implements Injector {
|
|||
context.writeExpr(context.getArgument(0));
|
||||
writePropertyAccessor(context, context.getArgument(1));
|
||||
}
|
||||
context.getWriter().append(']').ws().append('=').ws();
|
||||
context.getWriter().ws().append('=').ws();
|
||||
context.writeExpr(context.getArgument(2));
|
||||
context.getWriter().append(')');
|
||||
break;
|
||||
|
@ -87,14 +87,20 @@ class ResourceAccessorGenerator implements Injector {
|
|||
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(")");
|
||||
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(")");
|
||||
context.getWriter().append(")").ws().append(':').ws().append("null)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -191,9 +191,88 @@ class ResourceProgramTransformer {
|
|||
}
|
||||
|
||||
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();
|
||||
|
|
Loading…
Reference in New Issue
Block a user