LibJF/libjf-config-compiler-plugin/src/main/java/io/gitlab/jfronny/libjf/config/plugin/asm/value/DiscoveredValue.java

97 lines
3.9 KiB
Java

package io.gitlab.jfronny.libjf.config.plugin.asm.value;
import io.gitlab.jfronny.libjf.config.plugin.asm.ConfigInjectClassTransformer;
import io.gitlab.jfronny.libjf.config.plugin.util.GeneratorAdapter2;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.Method;
import static io.gitlab.jfronny.libjf.config.plugin.asm.value.KnownTypes.*;
import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
import static org.objectweb.asm.Opcodes.ACC_STATIC;
import static org.objectweb.asm.Type.*;
public class DiscoveredValue {
private static final String PREFIX = ConfigInjectClassTransformer.PREFIX;
public final String name;
public final double min;
public final double max;
public final Type aType;
public final KnownType type;
public DiscoveredValue(String name, double min, double max, Type type) {
this.name = name;
this.min = min;
this.max = max;
this.aType = type;
this.type = KnownType.of(type);
}
public void generateRegistration(GeneratorAdapter2 m, ConfigInjectClassTransformer t) {
if (type != KnownType.OBJECT) {
m.push(name);
m.getStatic(t.current, name, aType);
if (!aType.equals(type.unboxed)) {
m.comment("Unboxing value " + name + " from " + aType + " to " + type.unboxed);
m.unbox(type.unboxed); // Unbox (as parameter is unboxed) or leave as is (if target is unboxed)
}
}
switch (type) {
case INT, LONG, FLOAT, DOUBLE -> {
m.comment("Numeric type");
m.push(min);
m.push(max);
m.supplier(t.current.getInternalName(), gName(), gDesc());
m.consumer(t.current.getInternalName(), sName(), sDesc());
t.dslInvoke(m, "value", CATEGORY_BUILDER_TYPE, STRING_TYPE, type.unboxed, DOUBLE_TYPE, DOUBLE_TYPE, SUPPLIER_TYPE, CONSUMER_TYPE);
}
case BOOLEAN, STRING -> {
m.comment("Simple one-value type");
m.supplier(t.current.getInternalName(), gName(), gDesc());
m.consumer(t.current.getInternalName(), sName(), sDesc());
t.dslInvoke(m, "value", CATEGORY_BUILDER_TYPE, STRING_TYPE, type.unboxed, SUPPLIER_TYPE, CONSUMER_TYPE);
}
case OBJECT -> {
System.err.println("WARNING: Attempted to use unsupported type in config. The entry \"" + name + "\" will fall back to reflective runtime access!");
m.comment("Reflective access due to missing compatibility for the type \"" + aType + "\"");
m.push(t.current);
m.push(name);
m.invokeIStatic(ENTRY_INFO_TYPE, new Method("ofField", ENTRY_INFO_TYPE, new Type[]{CLASS_TYPE, STRING_TYPE}));
m.invokeInterface(CATEGORY_BUILDER_TYPE, new Method("value", CATEGORY_BUILDER_TYPE, new Type[]{ENTRY_INFO_TYPE}));
}
}
}
public void generateλ(ConfigInjectClassTransformer t) {
GeneratorAdapter2 m = t.method(ACC_PRIVATE | ACC_STATIC, gName(), gDesc().getInternalName(), null, null);
m.getStatic(t.current, name, aType);
m.comment("Boxing from " + aType + " (" + aType.getSort() + ")");
m.box(aType); // Box if target field uses unboxed value
m.returnValue();
m.endMethod();
m = t.method(ACC_PRIVATE | ACC_STATIC, sName(), sDesc().getInternalName(), null, null);
m.loadArg(0);
m.unbox(aType); // Unbox to the target fields type
m.putStatic(t.current, name, aType);
m.returnValue();
m.endMethod();
}
private String gName() {
return PREFIX + "get$" + name;
}
private Type gDesc() {
return getMethodType(type.boxed);
}
private String sName() {
return PREFIX + "set$" + name;
}
private Type sDesc() {
return getMethodType(VOID_TYPE, type.boxed);
}
}