diff --git a/src/main/java/de/dhbwstuttgart/target/bytecode/Codegen.java b/src/main/java/de/dhbwstuttgart/target/bytecode/Codegen.java index 822ab6704..13514baa0 100755 --- a/src/main/java/de/dhbwstuttgart/target/bytecode/Codegen.java +++ b/src/main/java/de/dhbwstuttgart/target/bytecode/Codegen.java @@ -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(), "", call.getDescriptor(), false); - else if (call.expr() instanceof TargetSuper) - mv.visitMethodInsn(INVOKESPECIAL, clazz.superType().getName(), "", 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() == "" ? 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(), "", constructor.getDescriptor(), null, null); + MethodVisitor mv = cw.visitMethod(constructor.access(), "", 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(), "", "()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); diff --git a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java index 51e27e422..f307b3925 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java @@ -15,6 +15,7 @@ public class ASTToTargetAST { protected List 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> computedGenericsOfMethods = new HashMap<>(); @@ -294,6 +295,7 @@ public class ASTToTargetAST { } private List convert(ClassOrInterface owner, Constructor input) { + currentClass = owner; sigma = all.get(0); List result = new ArrayList<>(); Set> parameterSet = new HashSet<>(); @@ -311,6 +313,7 @@ public class ASTToTargetAST { } private List convert(ClassOrInterface owner, Method input) { + currentClass = owner; sigma = all.get(0); List result = new ArrayList<>(); Set> parameterSet = new HashSet<>(); diff --git a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java index 2bc06235f..53b690662 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java @@ -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 ); } diff --git a/src/main/java/de/dhbwstuttgart/target/tree/TargetConstructor.java b/src/main/java/de/dhbwstuttgart/target/tree/TargetConstructor.java index a0e5a3652..dc7f01ac3 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/TargetConstructor.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/TargetConstructor.java @@ -11,5 +11,9 @@ public record TargetConstructor(int access, Set generics, List 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 generics, List 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 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; } diff --git a/src/main/java/de/dhbwstuttgart/target/tree/type/TargetExtendsWildcard.java b/src/main/java/de/dhbwstuttgart/target/tree/type/TargetExtendsWildcard.java index c9d70f199..5d32fb1b4 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/type/TargetExtendsWildcard.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/type/TargetExtendsWildcard.java @@ -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; diff --git a/src/main/java/de/dhbwstuttgart/target/tree/type/TargetGenericType.java b/src/main/java/de/dhbwstuttgart/target/tree/type/TargetGenericType.java index 149ed52c1..cc9e4bb2c 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/type/TargetGenericType.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/type/TargetGenericType.java @@ -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; } } diff --git a/src/main/java/de/dhbwstuttgart/target/tree/type/TargetSpecializedType.java b/src/main/java/de/dhbwstuttgart/target/tree/type/TargetSpecializedType.java index 0dce98250..c1f4dfc9d 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/type/TargetSpecializedType.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/type/TargetSpecializedType.java @@ -4,4 +4,18 @@ import java.util.List; public sealed interface TargetSpecializedType extends TargetType permits TargetFunNType, TargetRefType { List 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; + } } diff --git a/src/main/java/de/dhbwstuttgart/target/tree/type/TargetSuperWildcard.java b/src/main/java/de/dhbwstuttgart/target/tree/type/TargetSuperWildcard.java index fee113758..3306d14db 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/type/TargetSuperWildcard.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/type/TargetSuperWildcard.java @@ -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; diff --git a/src/main/java/de/dhbwstuttgart/target/tree/type/TargetType.java b/src/main/java/de/dhbwstuttgart/target/tree/type/TargetType.java index 263c760c1..ad9c895e7 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/type/TargetType.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/type/TargetType.java @@ -18,5 +18,6 @@ public sealed interface TargetType TargetRefType Object = new TargetRefType("java.lang.Object"); String toSignature(); + String toGenericSignature(); String getName(); } diff --git a/src/test/java/targetast/ASTToTypedTargetAST.java b/src/test/java/targetast/ASTToTypedTargetAST.java index 171964703..db1c635f6 100644 --- a/src/test/java/targetast/ASTToTypedTargetAST.java +++ b/src/test/java/targetast/ASTToTypedTargetAST.java @@ -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))); } }