From 918a2cc04dce8861cdc549a672ded0a5997689d7 Mon Sep 17 00:00:00 2001 From: Etienne Zink Date: Mon, 21 Mar 2022 08:42:50 +0100 Subject: [PATCH] =?UTF-8?q?Implementierung=20in=20FunN=20von=20getSuperByt?= =?UTF-8?q?ecode()=20und=20Hinzuf=C3=BCgen=20entsprechender=20Test.=20Umbe?= =?UTF-8?q?nennung=20in=20IntermediateRefType:=20getTypParameter()=20->=20?= =?UTF-8?q?getTypArgument()=20und=20getTypParameterSize()=20->=20getTypArg?= =?UTF-8?q?umentSize().?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../intermediate/generation/FunN.java | 48 +++++++++++++++-- .../types/IntermediateRefType.java | 12 ++--- .../intermediate/generation/FunNTest.java | 54 +++++++++++++++++++ 3 files changed, 103 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/dhbwstuttgart/intermediate/generation/FunN.java b/src/main/java/de/dhbwstuttgart/intermediate/generation/FunN.java index fc55efcb2..0312de3a9 100644 --- a/src/main/java/de/dhbwstuttgart/intermediate/generation/FunN.java +++ b/src/main/java/de/dhbwstuttgart/intermediate/generation/FunN.java @@ -1,13 +1,20 @@ package de.dhbwstuttgart.intermediate.generation; +import de.dhbwstuttgart.intermediate.types.IntermediateGenericType; import de.dhbwstuttgart.intermediate.types.IntermediateRefType; import de.dhbwstuttgart.intermediate.types.IntermediateType; import de.dhbwstuttgart.parser.scope.JavaClassName; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Type; +import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.objectweb.asm.Opcodes.*; + /** * Class which represents a function type. * Offers different methods to generate or interact with this real function type. @@ -17,16 +24,23 @@ import java.util.stream.Stream; */ public final class FunN extends IntermediateRefType { - /** - * Caches the bytecode after first computation. - */ - private byte[] bytecode; + private final String superFunNName; + private final String argumentGenericBase = "T"; + private final String returnGeneric = "R"; + private final String methodName = "apply"; /** * Caches the superBytecode after first computation. */ private byte[] superBytecode; + /** + * Caches the bytecode after first computation. + */ + private byte[] bytecode; + + public FunN(IntermediateType returnType){ this(Collections.emptyList(), returnType); } + public FunN(List typArguments, IntermediateType returnType) { super(new JavaClassName( String.format("Fun%d$$%s%s", @@ -39,6 +53,7 @@ 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()); } /** @@ -47,7 +62,30 @@ public final class FunN extends IntermediateRefType { public byte[] getSuperBytecode(){ byte[] superBytecode = this.superBytecode; if (superBytecode == null){ - //ToDo + String superType = Type.getInternalName(Object.class).replace('.','/'); + String objectSignature = new IntermediateRefType(new JavaClassName(Type.getInternalName(Object.class))).getSignature(); + + String superFunNClassSignature = "<"; + String superFunNMethodSignature = "("; + String superFunNMethodDescriptor = "("; + + //currentParameter < getTypArgumentSize() because the return type is stored in the typArguments as well + for (int currentParameter = 1; currentParameter < getTypArgumentSize(); currentParameter++){ + superFunNClassSignature += String.format("%s%d:%s",argumentGenericBase, currentParameter, objectSignature); + superFunNMethodSignature += new IntermediateGenericType(argumentGenericBase + currentParameter).getSignature(); + superFunNMethodDescriptor += objectSignature; + } + superFunNClassSignature += String.format("%s:%s>%s", returnGeneric, objectSignature, objectSignature); + superFunNMethodSignature += String.format(")%s", new IntermediateGenericType(returnGeneric).getSignature()); + superFunNMethodDescriptor += String.format(")%s", objectSignature); + + ClassWriter classWriter = new ClassWriter(0); + MethodVisitor methodVisitor; + classWriter.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, superFunNName, superFunNClassSignature, superType, null); + methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, methodName, superFunNMethodDescriptor, superFunNMethodSignature , null); + methodVisitor.visitEnd(); + classWriter.visitEnd(); + superBytecode = classWriter.toByteArray(); this.superBytecode = superBytecode; } return superBytecode; diff --git a/src/main/java/de/dhbwstuttgart/intermediate/types/IntermediateRefType.java b/src/main/java/de/dhbwstuttgart/intermediate/types/IntermediateRefType.java index eea0ff807..be32f8601 100644 --- a/src/main/java/de/dhbwstuttgart/intermediate/types/IntermediateRefType.java +++ b/src/main/java/de/dhbwstuttgart/intermediate/types/IntermediateRefType.java @@ -31,9 +31,7 @@ public class IntermediateRefType extends IntermediateInnerType{ */ private String descriptor = ""; - public IntermediateRefType(JavaClassName className) { - this(className, new ArrayList<>()); - } + public IntermediateRefType(JavaClassName className) { this(className, Collections.emptyList()); } public IntermediateRefType(JavaClassName className, List typArguments){ this.className = className; @@ -100,16 +98,18 @@ public class IntermediateRefType extends IntermediateInnerType{ public boolean isParametrized() { return typArguments.size() > 0; } - public int getTypParameterSize(){ return typArguments.size(); } + public int getTypArgumentSize(){ return typArguments.size(); } /** * @param index * @return the typ parameter at {@code index} or {@code null}, iff {@code |typ parameters| < index} */ - public IntermediateType getTypParameter(int index) { + public IntermediateType getTypArgument(int index) { if(typArguments.size() < index) return null; return typArguments.get(index); } - private String getFullyQualifiedName(){ return className.toString(); } + public String getClassName(){ return className.getClassName(); } + public String getPackageName(){ return className.getPackageName(); } + public String getFullyQualifiedName(){ return className.toString(); } } diff --git a/src/test/java/intermediate/generation/FunNTest.java b/src/test/java/intermediate/generation/FunNTest.java index c244ae5a0..dba3f2a6f 100644 --- a/src/test/java/intermediate/generation/FunNTest.java +++ b/src/test/java/intermediate/generation/FunNTest.java @@ -1,30 +1,45 @@ package intermediate.generation; import de.dhbwstuttgart.intermediate.generation.FunN; +import de.dhbwstuttgart.intermediate.types.IntermediateGenericType; import de.dhbwstuttgart.intermediate.types.IntermediateRefType; import de.dhbwstuttgart.parser.scope.JavaClassName; import org.junit.BeforeClass; import org.junit.Test; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Type; import java.util.Arrays; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.objectweb.asm.Opcodes.*; public class FunNTest { + + private static FunN fun0T; + private static String fun1IntIntSignature; private static String fun1IntIntDescriptor; private static FunN fun1IntInt; + 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))); + IntermediateRefType string = new IntermediateRefType(new JavaClassName(Type.getInternalName(String.class))); + + fun0T = new FunN(new IntermediateGenericType("T")); fun1IntIntSignature = "LFun1$$Ljava$lang$Integer$_$Ljava$lang$Integer$_$;"; fun1IntIntDescriptor = "LFun1$$Ljava$lang$Integer$_$Ljava$lang$Integer$_$;"; fun1IntInt = new FunN(Arrays.asList(integer), integer); + + fun2IntIntString = new FunN(Arrays.asList(integer, integer), string); } @Test @@ -32,4 +47,43 @@ public class FunNTest { @Test public void DescriptorTest_Fun1IntegerInteger(){ assertEquals(fun1IntIntDescriptor, fun1IntInt.getDescriptor()); } + + @Test + public void BytecodeTest_Super0(){ assertArrayEquals(generatedASMFun0(), fun0T.getSuperBytecode()) ;} + + @Test + public void BytecodeTest_Super1(){ assertArrayEquals(generatedASMFun1(), fun1IntInt.getSuperBytecode()) ;} + + @Test + public void BytecodeTest_Super2(){ assertArrayEquals(generatedASMFun2(), fun2IntIntString.getSuperBytecode()) ;} + + private byte[] generatedASMFun0() { + ClassWriter classWriter = new ClassWriter(0); + MethodVisitor methodVisitor; + classWriter.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "Fun0$$", "Ljava/lang/Object;", "java/lang/Object", null); + methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, "apply", "()Ljava/lang/Object;", "()TR;", null); + methodVisitor.visitEnd(); + classWriter.visitEnd(); + return classWriter.toByteArray(); + } + + private byte[] generatedASMFun1() { + ClassWriter classWriter = new ClassWriter(0); + MethodVisitor methodVisitor; + classWriter.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "Fun1$$", "Ljava/lang/Object;", "java/lang/Object", null); + methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, "apply", "(Ljava/lang/Object;)Ljava/lang/Object;", "(TT1;)TR;", null); + methodVisitor.visitEnd(); + classWriter.visitEnd(); + return classWriter.toByteArray(); + } + + private byte[] generatedASMFun2() { + ClassWriter classWriter = new ClassWriter(0); + MethodVisitor methodVisitor; + classWriter.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "Fun2$$", "Ljava/lang/Object;", "java/lang/Object", null); + methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, "apply", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", "(TT1;TT2;)TR;", null); + methodVisitor.visitEnd(); + classWriter.visitEnd(); + return classWriter.toByteArray(); + } }