Autogeneration of some IO code

This commit is contained in:
Anuken
2020-02-13 13:30:30 -05:00
parent 47f075133f
commit ad248e2e20
40 changed files with 163 additions and 74 deletions

View File

@@ -24,6 +24,12 @@ public class Annotations{
public @interface Replace{
}
/** Indicates that a component field is imported from other components. */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.SOURCE)
public @interface Import{
}
/** Indicates that a component field is read-only. */
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
@@ -70,6 +76,7 @@ public class Annotations{
Class[] value();
boolean isFinal() default true;
boolean pooled() default false;
boolean serialize() default true;
}
/** Indicates an internal interface for entity components. */

View File

@@ -0,0 +1,55 @@
package mindustry.annotations.entity;
import arc.util.*;
import com.squareup.javapoet.*;
import com.squareup.javapoet.MethodSpec.*;
import mindustry.annotations.*;
import javax.lang.model.element.*;
public class EntityIO{
final TypeElement contentElem = BaseProcessor.elementu.getTypeElement("mindustry.ctype.Content");
final MethodSpec.Builder builder;
final boolean write;
EntityIO(Builder builder, boolean write){
this.builder = builder;
this.write = write;
}
void io(TypeName type, String field) throws Exception{
TypeElement element = BaseProcessor.elementu.getTypeElement(type.toString());
if(type.isPrimitive()){
s(type.toString(), field);
}else if(type.toString().equals("java.lang.String")){
s("UTF", field);
}else if(element != null && BaseProcessor.typeu.isSubtype(element.asType(), contentElem.asType())){
if(write){
s("short", field + ".id");
}else{
st(field + " = mindustry.Vars.content.getByID(mindustry.ctype.ContentType.$L, input.readShort())", BaseProcessor.simpleName(type.toString()).toLowerCase().replace("type", ""));
}
}
}
private void cont(String text, Object... fmt){
builder.beginControlFlow(text, fmt);
}
private void cont(){
builder.endControlFlow();
}
private void st(String text, Object... args){
builder.addStatement(text, args);
}
private void s(String type, String field){
if(write){
builder.addStatement("output.write$L($L)", Strings.capitalize(type), field);
}else{
builder.addStatement("$L = input.read$L()", field, Strings.capitalize(type));
}
}
}

View File

@@ -1,4 +1,4 @@
package mindustry.annotations.impl;
package mindustry.annotations.entity;
import arc.files.*;
import arc.func.*;
@@ -118,7 +118,7 @@ public class EntityProcess extends BaseProcessor{
.build())).addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT).build());
}
for(Svar field : component.fields().select(e -> !e.is(Modifier.STATIC) && !e.is(Modifier.PRIVATE) && !e.is(Modifier.TRANSIENT))){
for(Svar field : component.fields().select(e -> !e.is(Modifier.STATIC) && !e.is(Modifier.PRIVATE) && !e.has(Import.class))){
String cname = field.name();
//getter
@@ -221,19 +221,32 @@ public class EntityProcess extends BaseProcessor{
Array<GroupDefinition> groups = groupDefs.select(g -> (!g.components.isEmpty() && !g.components.contains(s -> !components.contains(s))) || g.manualInclusions.contains(type));
ObjectMap<String, Array<Smethod>> methods = new ObjectMap<>();
ObjectMap<FieldSpec, Svar> specVariables = new ObjectMap<>();
ObjectSet<String> usedFields = new ObjectSet<>();
//add serialize() boolean
builder.addMethod(MethodSpec.methodBuilder("serialize").addModifiers(Modifier.PUBLIC, Modifier.FINAL).returns(boolean.class).addStatement("return " + ann.serialize()).build());
//add all components
for(Stype comp : components){
//write fields to the class; ignoring transient ones
Array<Svar> fields = comp.fields().select(f -> !f.is(Modifier.TRANSIENT));
Array<Svar> fields = comp.fields().select(f -> !f.has(Import.class));
for(Svar f : fields){
if(!usedFields.add(f.name())){
err("Field '" + f.name() + "' of component '" + comp.name() + "' re-defines a field in entity '" + type.name() + "'");
continue;
}
FieldSpec.Builder fbuilder = FieldSpec.builder(f.tname(), f.name());
//keep statics/finals
if(f.is(Modifier.STATIC)){
fbuilder.addModifiers(Modifier.STATIC);
if(f.is(Modifier.FINAL)) fbuilder.addModifiers(Modifier.FINAL);
}
//add transient modifier for serialization
if(f.is(Modifier.TRANSIENT)){
fbuilder.addModifiers(Modifier.TRANSIENT);
}
//add initializer if it exists
if(varInitializers.containsKey(f)){
fbuilder.initializer(varInitializers.get(f));
@@ -312,6 +325,18 @@ public class EntityProcess extends BaseProcessor{
}
}
//SPECIAL CASE: I/O code
//note that serialization is generated even for non-serializing entities for manual usage
if(first.name().equals("read") || first.name().equals("write")){
EntityIO writer = new EntityIO(mbuilder, first.name().equals("write"));
//write or read each non-transient field
for(FieldSpec spec : builder.fieldSpecs){
if(!spec.hasModifier(Modifier.TRANSIENT) && !spec.hasModifier(Modifier.STATIC) && !spec.hasModifier(Modifier.FINAL)){
writer.io(spec.type, "this." + spec.name);
}
}
}
for(Smethod elem : entry.value){
if(elem.is(Modifier.ABSTRACT) || elem.is(Modifier.NATIVE) || !methodBlocks.containsKey(elem)) continue;