Add generics to the generated class file
This commit is contained in:
parent
7e259e2597
commit
a8be387dd9
@ -617,9 +617,11 @@ public class Codegen {
|
||||
break;
|
||||
case TargetVarDecl varDecl: {
|
||||
var local = state.createVariable(varDecl.name(), varDecl.varType());
|
||||
generate(state, varDecl.value());
|
||||
boxPrimitive(state, varDecl.varType());
|
||||
mv.visitVarInsn(ASTORE, local.index());
|
||||
if (varDecl.value() != null) {
|
||||
generate(state, varDecl.value());
|
||||
boxPrimitive(state, varDecl.varType());
|
||||
mv.visitVarInsn(ASTORE, local.index());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TargetBinaryOp op:
|
||||
@ -737,12 +739,8 @@ public class Codegen {
|
||||
generate(state, e);
|
||||
boxPrimitive(state, e.type());
|
||||
}
|
||||
if (call.expr() instanceof TargetThis)
|
||||
mv.visitMethodInsn(INVOKESPECIAL, clazz.getName(), "<init>", call.getDescriptor(), false);
|
||||
else if (call.expr() instanceof TargetSuper)
|
||||
mv.visitMethodInsn(INVOKESPECIAL, clazz.superType().getName(), "<init>", call.getDescriptor(), false);
|
||||
else mv.visitMethodInsn(call.isInterface() ? INVOKEINTERFACE : call.isStatic() ? INVOKESTATIC: INVOKEVIRTUAL,
|
||||
call.owner().getName(), call.name(), call.getDescriptor(), call.isInterface());
|
||||
mv.visitMethodInsn(call.isInterface() ? INVOKEINTERFACE : call.isStatic() ? INVOKESTATIC: call.name() == "<init>" ? INVOKESPECIAL : INVOKEVIRTUAL,
|
||||
call.owner().getName(), call.name(), call.getDescriptor(), call.isInterface());
|
||||
if (call.type() != null)
|
||||
unboxPrimitive(state, call.type());
|
||||
break;
|
||||
@ -766,29 +764,15 @@ public class Codegen {
|
||||
}
|
||||
|
||||
private void generateField(TargetField field) {
|
||||
cw.visitField(field.access(), field.name(), field.getDescriptor(), null, null);
|
||||
}
|
||||
|
||||
private boolean hasThisOrSuperCall(TargetBlock block) {
|
||||
if (block.statements().size() == 0) return false;
|
||||
TargetExpression first = block.statements().get(0);
|
||||
if (!(first instanceof TargetMethodCall)) return false;
|
||||
var methodCall = (TargetMethodCall) first;
|
||||
if (methodCall.expr() instanceof TargetThis || methodCall.expr() instanceof TargetSuper)
|
||||
return true;
|
||||
return false;
|
||||
cw.visitField(field.access(), field.name(), field.type().toSignature(), field.type().toGenericSignature(), null);
|
||||
}
|
||||
|
||||
private void generateConstructor(TargetConstructor constructor) {
|
||||
MethodVisitor mv = cw.visitMethod(constructor.access(), "<init>", constructor.getDescriptor(), null, null);
|
||||
MethodVisitor mv = cw.visitMethod(constructor.access(), "<init>", constructor.getDescriptor(), constructor.getSignature(), null);
|
||||
mv.visitCode();
|
||||
var state = new State(mv, 1);
|
||||
for (var param: constructor.parameters())
|
||||
state.createVariable(param.name(), param.type());
|
||||
if (!hasThisOrSuperCall(constructor.block())) {
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, clazz.superType().getName(), "<init>", "()V", false);
|
||||
}
|
||||
generate(state, constructor.block());
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
@ -796,7 +780,7 @@ public class Codegen {
|
||||
}
|
||||
|
||||
private void generateMethod(TargetMethod method) {
|
||||
MethodVisitor mv = cw.visitMethod(method.access(), method.name(), method.getDescriptor(), null, null);
|
||||
MethodVisitor mv = cw.visitMethod(method.access(), method.name(), method.getDescriptor(), method.getSignature(), null);
|
||||
mv.visitCode();
|
||||
var state = new State(mv, method.isStatic() ? 0 : 1);
|
||||
for (var param: method.parameters())
|
||||
@ -808,9 +792,20 @@ public class Codegen {
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private static String generateSignature(TargetClass clazz) {
|
||||
String ret = "<";
|
||||
for (var generic : clazz.generics()) {
|
||||
ret += generic.name() + ":" + generic.bound().toGenericSignature();
|
||||
}
|
||||
ret += ">";
|
||||
ret += clazz.superType().toGenericSignature();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public byte[] generate() {
|
||||
cw.visit(V1_8, clazz.modifiers(), clazz.qualifiedName(),
|
||||
null, clazz.superType() != null ? clazz.superType().getName(): "java/lang/Object",
|
||||
generateSignature(clazz), clazz.superType() != null ? clazz.superType().getName(): "java/lang/Object",
|
||||
clazz.implementingInterfaces().stream().map(TargetType::toSignature).toArray(String[]::new)
|
||||
);
|
||||
clazz.fields().forEach(this::generateField);
|
||||
|
@ -15,6 +15,7 @@ public class ASTToTargetAST {
|
||||
|
||||
protected List<Sigma> all;
|
||||
protected Sigma sigma;
|
||||
protected ClassOrInterface currentClass; // TODO This is only needed because of SuperCall, maybe there's a better way?
|
||||
|
||||
private class Sigma {
|
||||
Map<Method, HashSet<TargetGeneric>> computedGenericsOfMethods = new HashMap<>();
|
||||
@ -294,6 +295,7 @@ public class ASTToTargetAST {
|
||||
}
|
||||
|
||||
private List<TargetConstructor> convert(ClassOrInterface owner, Constructor input) {
|
||||
currentClass = owner;
|
||||
sigma = all.get(0);
|
||||
List<TargetConstructor> result = new ArrayList<>();
|
||||
Set<List<MethodParameter>> parameterSet = new HashSet<>();
|
||||
@ -311,6 +313,7 @@ public class ASTToTargetAST {
|
||||
}
|
||||
|
||||
private List<TargetMethod> convert(ClassOrInterface owner, Method input) {
|
||||
currentClass = owner;
|
||||
sigma = all.get(0);
|
||||
List<TargetMethod> result = new ArrayList<>();
|
||||
Set<List<MethodParameter>> parameterSet = new HashSet<>();
|
||||
|
@ -127,13 +127,12 @@ public class StatementToTargetExpression implements StatementVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(MethodCall methodCall) {
|
||||
var receiver = methodCall.receiver;
|
||||
result = new TargetMethodCall(
|
||||
converter.convert(methodCall.getType()),
|
||||
methodCall.argTypes == null ? List.of() : methodCall.argTypes.stream().map(converter::convert).toList(),
|
||||
converter.convert(receiver),
|
||||
converter.convert(methodCall.receiver),
|
||||
methodCall.getArgumentList().getArguments().stream().map(converter::convert).toList(),
|
||||
converter.convert(receiver.getType()),
|
||||
converter.convert(methodCall.receiver.getType()),
|
||||
methodCall.name, false, false
|
||||
);
|
||||
}
|
||||
@ -200,12 +199,13 @@ public class StatementToTargetExpression implements StatementVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(SuperCall superCall) {
|
||||
var aSuper = converter.convert(converter.currentClass.getSuperClass());
|
||||
result = new TargetMethodCall(
|
||||
converter.convert(superCall.getType()),
|
||||
superCall.argTypes == null ? List.of() : superCall.argTypes.stream().map(converter::convert).toList(),
|
||||
new TargetSuper(null),
|
||||
new TargetSuper(aSuper),
|
||||
superCall.getArgumentList().getArguments().stream().map(converter::convert).toList(),
|
||||
null,
|
||||
aSuper,
|
||||
superCall.name, false, false
|
||||
);
|
||||
}
|
||||
|
@ -11,5 +11,9 @@ public record TargetConstructor(int access, Set<TargetGeneric> generics, List<Me
|
||||
public String getDescriptor() {
|
||||
return TargetMethod.getDescriptor(null, parameters.stream().map(MethodParameter::type).toArray(TargetType[]::new));
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return TargetMethod.getSignature(generics, parameters, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,10 +4,6 @@ import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
public record TargetField(int access, TargetType type, String name) {
|
||||
public String getDescriptor() {
|
||||
return type.toSignature();
|
||||
}
|
||||
|
||||
public boolean isStatic() {
|
||||
return (access & Opcodes.ACC_STATIC) != 0;
|
||||
}
|
||||
|
@ -14,11 +14,23 @@ public record TargetMethod(int access, String name, Set<TargetGeneric> generics,
|
||||
ret += parameterType.toSignature();
|
||||
}
|
||||
ret += ")";
|
||||
if (returnType == null) {
|
||||
ret += "V";
|
||||
} else {
|
||||
ret += returnType.toSignature();
|
||||
if (returnType == null) ret += "V";
|
||||
else ret += returnType.toSignature();
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static String getSignature(Set<TargetGeneric> generics, List<MethodParameter> parameters, TargetType returnType) {
|
||||
String ret = "<";
|
||||
for (var generic : generics) {
|
||||
ret += generic.name() + ":" + generic.bound().toGenericSignature();
|
||||
}
|
||||
ret += ">(";
|
||||
for (var param : parameters) {
|
||||
ret += param.type().toGenericSignature();
|
||||
}
|
||||
ret += ")";
|
||||
if (returnType == null) ret += "V";
|
||||
else ret += returnType.toGenericSignature();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -26,6 +38,10 @@ public record TargetMethod(int access, String name, Set<TargetGeneric> generics,
|
||||
return getDescriptor(returnType, parameters.stream().map(MethodParameter::type).toArray(TargetType[]::new));
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return getSignature(generics, parameters, returnType);
|
||||
}
|
||||
|
||||
public boolean isStatic() {
|
||||
return (access & Opcodes.ACC_STATIC) != 0;
|
||||
}
|
||||
|
@ -6,6 +6,11 @@ public record TargetExtendsWildcard(TargetType innerType) implements TargetType
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toGenericSignature() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return null;
|
||||
|
@ -3,11 +3,16 @@ package de.dhbwstuttgart.target.tree.type;
|
||||
public record TargetGenericType(String name) implements TargetType {
|
||||
@Override
|
||||
public String toSignature() {
|
||||
return null;
|
||||
return "Ljava/lang/Object;"; // TODO Use bounds for this?
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toGenericSignature() {
|
||||
return "T" + getName() + ";";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return null;
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
@ -4,4 +4,18 @@ import java.util.List;
|
||||
|
||||
public sealed interface TargetSpecializedType extends TargetType permits TargetFunNType, TargetRefType {
|
||||
List<TargetType> params();
|
||||
|
||||
@Override
|
||||
default String toGenericSignature() {
|
||||
String ret = "L" + getName();
|
||||
if (params().size() > 0) {
|
||||
ret += "<";
|
||||
for (var param : params()) {
|
||||
ret += param.toGenericSignature();
|
||||
}
|
||||
ret += ">";
|
||||
}
|
||||
ret += ";";
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,11 @@ public record TargetSuperWildcard(TargetType innerType) implements TargetType {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toGenericSignature() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return null;
|
||||
|
@ -18,5 +18,6 @@ public sealed interface TargetType
|
||||
TargetRefType Object = new TargetRefType("java.lang.Object");
|
||||
|
||||
String toSignature();
|
||||
String toGenericSignature();
|
||||
String getName();
|
||||
}
|
||||
|
@ -59,6 +59,6 @@ public class ASTToTypedTargetAST {
|
||||
var converter = new ASTToTargetAST(resultSet);
|
||||
var classes = compiler.sourceFiles.get(file).getClasses();
|
||||
|
||||
converter.convert(classes.get(0));
|
||||
var tphAndGenerics = TestCodegen.generateClass(converter.convert(classes.get(0)));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user