diff --git a/src/main/java/de/dhbwstuttgart/intermediate/generation/FunN.java b/src/main/java/de/dhbwstuttgart/intermediate/generation/FunN.java index 0312de3a..1d60f46a 100644 --- a/src/main/java/de/dhbwstuttgart/intermediate/generation/FunN.java +++ b/src/main/java/de/dhbwstuttgart/intermediate/generation/FunN.java @@ -1,6 +1,7 @@ package de.dhbwstuttgart.intermediate.generation; import de.dhbwstuttgart.intermediate.types.IntermediateGenericType; +import de.dhbwstuttgart.intermediate.types.IntermediateInnerType; import de.dhbwstuttgart.intermediate.types.IntermediateRefType; import de.dhbwstuttgart.intermediate.types.IntermediateType; import de.dhbwstuttgart.parser.scope.JavaClassName; @@ -24,10 +25,18 @@ import static org.objectweb.asm.Opcodes.*; */ public final class FunN extends IntermediateRefType { - private final String superFunNName; private final String argumentGenericBase = "T"; private final String returnGeneric = "R"; private final String methodName = "apply"; + private final int bytecodeVersion = V1_8; + + private final String objectSuperType = Type.getInternalName(Object.class).replace('.','/'); + private final String objectSignature = new IntermediateRefType(new JavaClassName(Type.getInternalName(Object.class))).getSignature(); + + /** + * Represents the super interface of this specialized function. + */ + private final IntermediateRefType superFunN; /** * Caches the superBytecode after first computation. @@ -39,9 +48,10 @@ public final class FunN extends IntermediateRefType { */ private byte[] bytecode; - public FunN(IntermediateType returnType){ this(Collections.emptyList(), returnType); } + public FunN(IntermediateInnerType returnType){ this(Collections.emptyList(), returnType); } - public FunN(List typArguments, IntermediateType returnType) { + public FunN(List typArguments, IntermediateInnerType returnType) { + //using stream-API for single line processing of relevant data in the super()-call super(new JavaClassName( String.format("Fun%d$$%s%s", typArguments.size(), @@ -53,7 +63,8 @@ public final class FunN extends IntermediateRefType { .replace('/', '$') .replace(";", "$_$")), Stream.concat(typArguments.stream(), Stream.of(returnType)).collect(Collectors.toList())); - superFunNName = String.format("Fun%d$$", typArguments.size()); + superFunN = new IntermediateRefType(new JavaClassName(String.format("Fun%d$$", typArguments.size())), + Stream.concat(typArguments.stream(), Stream.of(returnType)).collect(Collectors.toList())); } /** @@ -62,9 +73,6 @@ public final class FunN extends IntermediateRefType { public byte[] getSuperBytecode(){ byte[] superBytecode = this.superBytecode; if (superBytecode == null){ - String superType = Type.getInternalName(Object.class).replace('.','/'); - String objectSignature = new IntermediateRefType(new JavaClassName(Type.getInternalName(Object.class))).getSignature(); - String superFunNClassSignature = "<"; String superFunNMethodSignature = "("; String superFunNMethodDescriptor = "("; @@ -81,7 +89,7 @@ public final class FunN extends IntermediateRefType { ClassWriter classWriter = new ClassWriter(0); MethodVisitor methodVisitor; - classWriter.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, superFunNName, superFunNClassSignature, superType, null); + classWriter.visit(bytecodeVersion, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, superFunN.getClassName(), superFunNClassSignature, objectSuperType, null); methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, methodName, superFunNMethodDescriptor, superFunNMethodSignature , null); methodVisitor.visitEnd(); classWriter.visitEnd(); @@ -99,7 +107,26 @@ public final class FunN extends IntermediateRefType { public byte[] getBytecode(){ byte[] bytecode = this.bytecode; if (bytecode == null){ - //ToDo + String funNClassSignature = objectSignature + superFunN.getSignature(); + boolean containsGeneric = false; + + String genericSignature = "<"; + for (int currentTypArgumentIndex = 0; currentTypArgumentIndex < getTypArgumentSize(); currentTypArgumentIndex++) { + IntermediateType typArgument = getTypArgument(currentTypArgumentIndex); + if (typArgument == null) continue; + if (typArgument instanceof IntermediateGenericType){ + IntermediateGenericType generic = (IntermediateGenericType) typArgument; + genericSignature += String.format("%s:%s", generic.getGenericName(), generic.getDescriptor()); + containsGeneric = true; + } + } + genericSignature += ">"; + if (containsGeneric) funNClassSignature = genericSignature + funNClassSignature; + + ClassWriter classWriter = new ClassWriter(0); + classWriter.visit(bytecodeVersion, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, getClassName(), funNClassSignature, objectSuperType, new String[]{superFunN.getClassName()}); + classWriter.visitEnd(); + bytecode = classWriter.toByteArray(); this.bytecode = bytecode; } return bytecode; diff --git a/src/test/java/intermediate/generation/FunNTest.java b/src/test/java/intermediate/generation/FunNTest.java index dba3f2a6..d94595cd 100644 --- a/src/test/java/intermediate/generation/FunNTest.java +++ b/src/test/java/intermediate/generation/FunNTest.java @@ -26,8 +26,6 @@ public class FunNTest { private static FunN fun2IntIntString; - //ToDo mehr Tests und Bytecode Tests - @BeforeClass public static void SetUp(){ IntermediateRefType integer = new IntermediateRefType(new JavaClassName(Type.getInternalName(Integer.class))); @@ -51,12 +49,21 @@ public class FunNTest { @Test public void BytecodeTest_Super0(){ assertArrayEquals(generatedASMFun0(), fun0T.getSuperBytecode()) ;} + @Test + public void BytecodeTest_Fun0T(){ assertArrayEquals(generatedASMFun0T(), fun0T.getBytecode()) ;} + @Test public void BytecodeTest_Super1(){ assertArrayEquals(generatedASMFun1(), fun1IntInt.getSuperBytecode()) ;} + @Test + public void BytecodeTest_Fun1IntInt(){ assertArrayEquals(generatedASMFun1IntInt(), fun1IntInt.getBytecode()) ;} + @Test public void BytecodeTest_Super2(){ assertArrayEquals(generatedASMFun2(), fun2IntIntString.getSuperBytecode()) ;} + @Test + public void BytecodeTest_Fun2IntIntString(){ assertArrayEquals(generatedASMFun2IntIntString(), fun2IntIntString.getBytecode()) ;} + private byte[] generatedASMFun0() { ClassWriter classWriter = new ClassWriter(0); MethodVisitor methodVisitor; @@ -67,6 +74,13 @@ public class FunNTest { return classWriter.toByteArray(); } + private byte[] generatedASMFun0T() { + ClassWriter classWriter = new ClassWriter(0); + classWriter.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "Fun0$$TT$_$", "Ljava/lang/Object;LFun0$$;", "java/lang/Object", new String[]{"Fun0$$"}); + classWriter.visitEnd(); + return classWriter.toByteArray(); + } + private byte[] generatedASMFun1() { ClassWriter classWriter = new ClassWriter(0); MethodVisitor methodVisitor; @@ -77,6 +91,13 @@ public class FunNTest { return classWriter.toByteArray(); } + private byte[] generatedASMFun1IntInt() { + ClassWriter classWriter = new ClassWriter(0); + classWriter.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "Fun1$$Ljava$lang$Integer$_$Ljava$lang$Integer$_$", "Ljava/lang/Object;LFun1$$;", "java/lang/Object", new String[]{"Fun1$$"}); + classWriter.visitEnd(); + return classWriter.toByteArray(); + } + private byte[] generatedASMFun2() { ClassWriter classWriter = new ClassWriter(0); MethodVisitor methodVisitor; @@ -86,4 +107,11 @@ public class FunNTest { classWriter.visitEnd(); return classWriter.toByteArray(); } + + private byte[] generatedASMFun2IntIntString() { + ClassWriter classWriter = new ClassWriter(0); + classWriter.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "Fun2$$Ljava$lang$Integer$_$Ljava$lang$Integer$_$Ljava$lang$String$_$", "Ljava/lang/Object;LFun2$$;", "java/lang/Object", new String[]{"Fun2$$"}); + classWriter.visitEnd(); + return classWriter.toByteArray(); + } }