From b0f7a264c2799239ac3c0020e116067955fc5eb5 Mon Sep 17 00:00:00 2001 From: Daniel Holle Date: Mon, 31 Jul 2023 15:11:35 +0200 Subject: [PATCH] Implement records --- resources/bytecode/javFiles/RecordTest.jav | 22 +++++ .../de/dhbwstuttgart/bytecode/Codegen.java | 89 +++++++++++++++---- .../de/dhbwstuttgart/core/JavaTXCompiler.java | 21 ++--- .../SyntaxTreeGenerator.java | 4 +- .../syntaxtree/factory/ASTFactory.java | 8 +- .../target/generate/ASTToTargetAST.java | 12 ++- .../generate/StatementToTargetExpression.java | 3 +- .../target/tree/TargetClass.java | 22 +---- .../target/tree/TargetRecord.java | 18 ++++ .../target/tree/TargetStructure.java | 40 +++++++++ .../target/tree/expression/TargetSwitch.java | 8 +- src/test/java/TestComplete.java | 11 +++ .../syntaxtreegenerator/TestNewFeatures.java | 4 +- .../java/targetast/ASTToTypedTargetAST.java | 3 +- src/test/java/targetast/TestCodegen.java | 3 +- 15 files changed, 207 insertions(+), 61 deletions(-) create mode 100644 resources/bytecode/javFiles/RecordTest.jav create mode 100644 src/main/java/de/dhbwstuttgart/target/tree/TargetRecord.java create mode 100644 src/main/java/de/dhbwstuttgart/target/tree/TargetStructure.java diff --git a/resources/bytecode/javFiles/RecordTest.jav b/resources/bytecode/javFiles/RecordTest.jav new file mode 100644 index 00000000..c64c3d94 --- /dev/null +++ b/resources/bytecode/javFiles/RecordTest.jav @@ -0,0 +1,22 @@ +import java.lang.Integer; + +record Rec(Integer a, Integer b) {} + +/*public class Rec { + x; y; + Rec(Integer a, Integer b) { + x = a; + y = b; + } +}*/ + +public class RecordTest { + a = new Rec(10, 20); + b = new Rec(10, 20); + c = new Rec(20, 40); + + doesEqual() { return a.equals(b); } + doesNotEqual() { return b.equals(c); } + hashCode() { return a.hashCode(); } + toString() { return a.toString(); } +} \ No newline at end of file diff --git a/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java b/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java index bcbe0573..a09531c1 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java @@ -1,18 +1,12 @@ package de.dhbwstuttgart.bytecode; import de.dhbwstuttgart.exceptions.NotImplementedException; -import de.dhbwstuttgart.syntaxtree.statement.Break; import de.dhbwstuttgart.target.tree.*; import de.dhbwstuttgart.target.tree.expression.*; import de.dhbwstuttgart.target.tree.type.*; -import org.antlr.v4.codegen.Target; import org.objectweb.asm.*; -import java.lang.invoke.CallSite; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.sql.Array; +import java.lang.invoke.*; import java.util.*; import static org.objectweb.asm.Opcodes.*; @@ -20,13 +14,13 @@ import static de.dhbwstuttgart.target.tree.expression.TargetBinaryOp.*; import static de.dhbwstuttgart.target.tree.expression.TargetLiteral.*; public class Codegen { - private final TargetClass clazz; + private final TargetStructure clazz; private final ClassWriter cw; public final String className; private int lambdaCounter = 0; private final HashMap lambdas = new HashMap<>(); - public Codegen(TargetClass clazz) { + public Codegen(TargetStructure clazz) { this.clazz = clazz; this.className = clazz.qualifiedName(); this.cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); @@ -1148,10 +1142,13 @@ public class Codegen { if (cse.labels().size() == 1) { var label = cse.labels().get(0); - if (label instanceof TargetSwitch.Guard gd) - bindLabel(state, tmp, aSwitch.expr().type(), gd.inner()); - else if (label instanceof TargetSwitch.Pattern pat) - bindLabel(state, tmp, aSwitch.expr().type(), pat); + if (label instanceof TargetSwitch.Guard gd){ + state.mv.visitVarInsn(ALOAD, tmp); + bindPattern(state, aSwitch.expr().type(), gd.inner()); + } else if (label instanceof TargetSwitch.Pattern pat) { + state.mv.visitVarInsn(ALOAD, tmp); + bindPattern(state, aSwitch.expr().type(), pat); + } if (label instanceof TargetSwitch.Guard gd) { generate(state, gd.expression()); @@ -1191,13 +1188,13 @@ public class Codegen { state.exitScope(); } - private void bindLabel(State state, int tmp, TargetType type, TargetSwitch.Pattern pat) { + private void bindPattern(State state, TargetType type, TargetSwitch.Pattern pat) { if (pat instanceof TargetSwitch.SimplePattern sp) { - state.mv.visitVarInsn(ALOAD, tmp); var local = state.createVariable(sp.name(), sp.type()); convertTo(state, type, local.type); - boxPrimitive(state, local.type); state.mv.visitVarInsn(ASTORE, local.index); + } else if (pat instanceof TargetSwitch.ComplexPattern cp) { + convertTo(state, type, cp.type()); } } @@ -1218,7 +1215,11 @@ public class Codegen { } private void generateField(TargetField field) { - cw.visitField(field.access() | ACC_PUBLIC, field.name(), field.type().toSignature(), field.type().toDescriptor(), null); + var access = field.access(); + if ((access & ACC_PRIVATE) == 0 && (access & ACC_PROTECTED) == 0) // TODO Implement access modifiers properly + access |= ACC_PUBLIC; + + cw.visitField(access, field.name(), field.type().toSignature(), field.type().toDescriptor(), null); } private void generateConstructor(TargetConstructor constructor) { @@ -1265,7 +1266,7 @@ public class Codegen { mv.visitEnd(); } - private static String generateSignature(TargetClass clazz, Set generics) { + private static String generateSignature(TargetStructure clazz, Set generics) { String ret = ""; if (generics.size() > 0) { ret += "<"; @@ -1280,7 +1281,11 @@ public class Codegen { } public byte[] generate() { - cw.visit(V1_8, clazz.modifiers() | ACC_PUBLIC | ACC_SUPER, clazz.qualifiedName(), generateSignature(clazz, clazz.generics()), clazz.superType() != null ? clazz.superType().getInternalName() : "java/lang/Object", clazz.implementingInterfaces().stream().map(TargetType::toSignature).toArray(String[]::new)); + var access = clazz.modifiers(); + if ((access & ACC_PRIVATE) == 0 && (access & ACC_PROTECTED) == 0) // TODO Implement access modifiers properly + access |= ACC_PUBLIC; + + cw.visit(V1_8, access | ACC_SUPER, clazz.qualifiedName(), generateSignature(clazz, clazz.generics()), clazz.superType() != null ? clazz.superType().getInternalName() : "java/lang/Object", clazz.implementingInterfaces().stream().map(TargetType::toSignature).toArray(String[]::new)); if (clazz.txGenerics() != null) cw.visitAttribute(new JavaTXSignatureAttribute(generateSignature(clazz, clazz.txGenerics()))); @@ -1288,7 +1293,53 @@ public class Codegen { clazz.constructors().forEach(this::generateConstructor); clazz.methods().forEach(this::generateMethod); + if (clazz instanceof TargetRecord) + generateRecordMethods(); + cw.visitEnd(); return cw.toByteArray(); } + + private void generateRecordMethods() { + var mt = MethodType.methodType(Object.class, MethodHandles.Lookup.class, String.class, TypeDescriptor.class, Class.class, String.class, MethodHandle[].class); + var bootstrap = new Handle(H_INVOKESTATIC, "java/lang/runtime/ObjectMethods", "bootstrap", mt.toMethodDescriptorString(), false); + var bootstrapArgs = new Object[2 + clazz.fields().size()]; + + bootstrapArgs[0] = Type.getObjectType(clazz.getName()); + bootstrapArgs[1] = String.join(";", clazz.fields().stream().map(TargetField::name).toArray(String[]::new)); + for (var i = 0; i < clazz.fields().size(); i++) { + var field = clazz.fields().get(i); + var fieldRef = new Handle(H_GETFIELD, clazz.getName(), field.name(), field.type().toDescriptor(), false); + bootstrapArgs[i + 2] = fieldRef; + } + + { // hashCode + var mv = cw.visitMethod(ACC_PUBLIC, "hashCode", "()I", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitInvokeDynamicInsn("hashCode", "(L" + clazz.getName() + ";)I", bootstrap, bootstrapArgs); + mv.visitInsn(IRETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + { // equals + var mv = cw.visitMethod(ACC_PUBLIC, "equals", "(Ljava/lang/Object;)Z", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitInvokeDynamicInsn("equals", "(L" + clazz.getName() + ";Ljava/lang/Object;)Z", bootstrap, bootstrapArgs); + mv.visitInsn(IRETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + { // toString + var mv = cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitInvokeDynamicInsn("toString", "(L" + clazz.getName() + ";)Ljava/lang/String;", bootstrap, bootstrapArgs); + mv.visitInsn(ARETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + } } diff --git a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java index 48c9bb60..b6eb211e 100644 --- a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java +++ b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java @@ -135,22 +135,23 @@ public class JavaTXCompiler { void addMethods(SourceFile sf, ClassOrInterface cl, List importedClasses, ClassOrInterface objectClass) { if (!cl.areMethodsAdded()) { ClassOrInterface superclass = null; - if (cl.getSuperClass().getName().equals(new JavaClassName("java.lang.Object"))) { - superclass = objectClass; + Optional optSuperclass = importedClasses.stream().filter(x -> x.getClassName().equals(cl.getSuperClass().getName())).findFirst(); + if (optSuperclass.isPresent()) { + superclass = optSuperclass.get(); } else { - Optional optSuperclass = importedClasses.stream().filter(x -> x.getClassName().equals(cl.getSuperClass().getName())).findFirst(); + optSuperclass = sf.KlassenVektor.stream().filter(x -> x.getClassName().equals(cl.getSuperClass().getName())).findFirst(); if (optSuperclass.isPresent()) { superclass = optSuperclass.get(); + addMethods(sf, superclass, importedClasses, objectClass); } else { - optSuperclass = sf.KlassenVektor.stream().filter(x -> x.getClassName().equals(cl.getSuperClass().getName())).findFirst(); - if (optSuperclass.isPresent()) { - superclass = optSuperclass.get(); - addMethods(sf, superclass, importedClasses, objectClass); - } else { - // throw new ClassNotFoundException(""); - } + try { + var className = cl.getSuperClass().getName().toString(); + superclass = ASTFactory.createClass(classLoader.loadClass(className)); + } catch (ClassNotFoundException ignored) {} + // throw new ClassNotFoundException(""); } } + Iterator paraIt = cl.getSuperClass().getParaList().iterator(); Iterator tvarVarIt = superclass.getGenerics().iterator(); diff --git a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java index baebce55..810a8b73 100644 --- a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java +++ b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java @@ -87,6 +87,8 @@ import de.dhbwstuttgart.syntaxtree.type.Void; import de.dhbwstuttgart.typeinference.constraints.GenericsResolver; import javassist.compiler.SyntaxError; +import javax.swing.text.html.Option; + public class SyntaxTreeGenerator { private JavaClassRegistry reg; private final GenericsRegistry globalGenerics; @@ -248,7 +250,7 @@ public class SyntaxTreeGenerator { } else { genericClassParameters = TypeGenerator.convert(recordDeclaration.genericDeclarationList(), name, "", reg, generics); } - RefType superClass = new RefType(ASTFactory.createObjectClass().getClassName(), offset); + RefType superClass = new RefType(ASTFactory.createClass(java.lang.Record.class).getClassName(), offset); List fielddecl = new ArrayList<>(); List methods = new ArrayList<>(); List constructors = new ArrayList<>(); diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java b/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java index d0faf486..ee2000b3 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java @@ -33,7 +33,11 @@ import org.objectweb.asm.signature.SignatureVisitor; */ public class ASTFactory { + private static final HashMap cache = new HashMap<>(); + public static ClassOrInterface createClass(java.lang.Class jreClass) { + if (cache.containsKey(jreClass)) + return cache.get(jreClass); // TODO Inner classes @@ -141,7 +145,9 @@ public class ASTFactory { Token offset = new NullToken(); // Braucht keinen Offset, da diese Klasse nicht aus einem Quellcode geparst wurde - return new ClassOrInterface(modifier, name, felder, Optional.empty() /* eingefuegt PL 2018-11-24 */, methoden, konstruktoren, genericDeclarationList, superClass, isInterface, implementedInterfaces, permittedSubtypes, offset); + var cinf = new ClassOrInterface(modifier, name, felder, Optional.empty() /* eingefuegt PL 2018-11-24 */, methoden, konstruktoren, genericDeclarationList, superClass, isInterface, implementedInterfaces, permittedSubtypes, offset); + cache.put(jreClass, cinf); + return cinf; } private static Field createField(java.lang.reflect.Field field, JavaClassName jreClass) { diff --git a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java index d65b5f10..377a89fd 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java @@ -4,6 +4,7 @@ import de.dhbwstuttgart.bytecode.FunNGenerator; import de.dhbwstuttgart.environment.ByteArrayClassLoader; import de.dhbwstuttgart.environment.IByteArrayClassLoader; import de.dhbwstuttgart.syntaxtree.*; +import de.dhbwstuttgart.syntaxtree.Record; import de.dhbwstuttgart.syntaxtree.factory.ASTFactory; import de.dhbwstuttgart.syntaxtree.statement.*; import de.dhbwstuttgart.syntaxtree.type.*; @@ -104,7 +105,7 @@ public class ASTToTargetAST { return ret; } - public TargetClass convert(ClassOrInterface input) { + public TargetStructure convert(ClassOrInterface input) { currentClass = input; Set javaGenerics = new HashSet<>(); Set txGenerics = new HashSet<>(); @@ -132,7 +133,14 @@ public class ASTToTargetAST { fieldInitializer = convert(input.getfieldInitializations().get().block); TargetBlock finalFieldInitializer = fieldInitializer; - return new TargetClass(input.getModifiers(), input.getClassName().toString(), convert(input.getSuperClass(), generics.javaGenerics), javaGenerics, txGenerics, input.getSuperInterfaces().stream().map(clazz -> convert(clazz, generics.javaGenerics)).toList(), input.getConstructors().stream().map(constructor -> this.convert(constructor, finalFieldInitializer)).flatMap(List::stream).toList(), input.getFieldDecl().stream().map(this::convert).toList(), input.getMethods().stream().map(this::convert).flatMap(List::stream).toList()); + var superInterfaces = input.getSuperInterfaces().stream().map(clazz -> convert(clazz, generics.javaGenerics)).toList(); + var constructors = input.getConstructors().stream().map(constructor -> this.convert(constructor, finalFieldInitializer)).flatMap(List::stream).toList(); + var fields = input.getFieldDecl().stream().map(this::convert).toList(); + var methods = input.getMethods().stream().map(this::convert).flatMap(List::stream).toList(); + + if (input instanceof Record) + return new TargetRecord(input.getModifiers(), input.getClassName().toString(), javaGenerics, txGenerics, superInterfaces, constructors, fields, methods); + else return new TargetClass(input.getModifiers(), input.getClassName().toString(), convert(input.getSuperClass(), generics.javaGenerics), javaGenerics, txGenerics, superInterfaces, constructors, fields, methods); } private List convert(ParameterList input, GenerateGenerics generics) { diff --git a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java index 5cad36bd..a5b0faf6 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java @@ -170,7 +170,7 @@ public class StatementToTargetExpression implements StatementVisitor { } Method findMethod(JavaClassName className, String name, List args) { - if (converter.sourceFile != null && converter.sourceFile.imports.contains(className)) { + if (converter.sourceFile != null /*&& converter.sourceFile.imports.contains(className)*/) { try { var clazz = converter.classLoader.loadClass(className.toString()); @@ -374,6 +374,7 @@ public class StatementToTargetExpression implements StatementVisitor { public void visit(RecordPattern aRecordPattern) { result = new TargetSwitch.ComplexPattern( converter.convert(aRecordPattern.getType()), + aRecordPattern.getName(), aRecordPattern.getSubPattern().stream().map(x -> (TargetSwitch.Pattern) converter.convert(x)).toList() ); } diff --git a/src/main/java/de/dhbwstuttgart/target/tree/TargetClass.java b/src/main/java/de/dhbwstuttgart/target/tree/TargetClass.java index 3118a1d8..8e19a362 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/TargetClass.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/TargetClass.java @@ -11,7 +11,7 @@ import java.util.List; import java.util.Set; public record TargetClass(int modifiers, String qualifiedName, TargetType superType, Set generics, Set txGenerics, List implementingInterfaces, - List constructors, List fields, List methods) { + List constructors, List fields, List methods) implements TargetStructure { public TargetClass(int modifiers, String qualifiedName) { this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new HashSet<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); @@ -20,26 +20,6 @@ public record TargetClass(int modifiers, String qualifiedName, TargetType superT this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new HashSet<>(), implementingInterfaces, new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); } - public String getName() { - return qualifiedName.replaceAll("\\.", "/"); - } - - public void addMethod(int access, String name, Set generics, List parameterTypes, TargetType returnType, TargetBlock block) { - this.methods.add(new TargetMethod(access, name, block, new TargetMethod.Signature(generics, parameterTypes, returnType), null)); - } - - public void addMethod(int access, String name, List parameterTypes, TargetType returnType, TargetBlock block) { - addMethod(access, name, Set.of(), parameterTypes, returnType, block); - } - - public void addConstructor(int access, Set generics, List paramterTypes, TargetBlock block) { - this.constructors.add(new TargetConstructor(access, generics, Set.of(), paramterTypes, List.of(), block, null)); - } - - public void addConstructor(int access, List paramterTypes, TargetBlock block) { - addConstructor(access, Set.of(), paramterTypes, block); - } - public void addField(int access, TargetRefType type, String name) { this.fields.add(new TargetField(access, type, name)); } diff --git a/src/main/java/de/dhbwstuttgart/target/tree/TargetRecord.java b/src/main/java/de/dhbwstuttgart/target/tree/TargetRecord.java new file mode 100644 index 00000000..5e02fb58 --- /dev/null +++ b/src/main/java/de/dhbwstuttgart/target/tree/TargetRecord.java @@ -0,0 +1,18 @@ +package de.dhbwstuttgart.target.tree; + +import de.dhbwstuttgart.target.tree.type.TargetRefType; +import de.dhbwstuttgart.target.tree.type.TargetType; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +public record TargetRecord(int modifiers, String qualifiedName, Set generics, Set txGenerics, List implementingInterfaces, List constructors, List fields, List methods) implements TargetStructure { + + public static final TargetType RECORD = new TargetRefType("java.lang.Record"); + + @Override + public TargetType superType() { + return RECORD; + } +} diff --git a/src/main/java/de/dhbwstuttgart/target/tree/TargetStructure.java b/src/main/java/de/dhbwstuttgart/target/tree/TargetStructure.java new file mode 100644 index 00000000..6227776f --- /dev/null +++ b/src/main/java/de/dhbwstuttgart/target/tree/TargetStructure.java @@ -0,0 +1,40 @@ +package de.dhbwstuttgart.target.tree; + +import de.dhbwstuttgart.target.tree.expression.TargetBlock; +import de.dhbwstuttgart.target.tree.type.TargetType; + +import java.util.List; +import java.util.Set; + +public interface TargetStructure { + int modifiers(); + String qualifiedName(); + TargetType superType(); + Set generics(); + Set txGenerics(); + List implementingInterfaces(); + List constructors(); + List fields(); + List methods(); + + default String getName() { + return qualifiedName().replaceAll("\\.", "/"); + } + + // These methods are only meant to be used for test cases, a Class record should be immutable! + default void addMethod(int access, String name, Set generics, List parameterTypes, TargetType returnType, TargetBlock block) { + this.methods().add(new TargetMethod(access, name, block, new TargetMethod.Signature(generics, parameterTypes, returnType), null)); + } + + default void addMethod(int access, String name, List parameterTypes, TargetType returnType, TargetBlock block) { + addMethod(access, name, Set.of(), parameterTypes, returnType, block); + } + + default void addConstructor(int access, Set generics, List paramterTypes, TargetBlock block) { + this.constructors().add(new TargetConstructor(access, generics, Set.of(), paramterTypes, List.of(), block, null)); + } + + default void addConstructor(int access, List paramterTypes, TargetBlock block) { + addConstructor(access, Set.of(), paramterTypes, block); + } +} diff --git a/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetSwitch.java b/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetSwitch.java index 44a3c394..ea3283ed 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetSwitch.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetSwitch.java @@ -27,10 +27,14 @@ public record TargetSwitch(TargetExpression expr, List cases, Case default } } - public sealed interface Pattern extends TargetExpression {} + public sealed interface Pattern extends TargetExpression { + default String name() { + return null; + } + } public record SimplePattern(TargetType type, String name) implements Pattern {} - public record ComplexPattern(TargetType type, List subPatterns) implements Pattern {} + public record ComplexPattern(TargetType type, String name, List subPatterns) implements Pattern {} public record Guard(Pattern inner, TargetExpression expression) implements Pattern {} } diff --git a/src/test/java/TestComplete.java b/src/test/java/TestComplete.java index 286e6ec6..fbf12853 100644 --- a/src/test/java/TestComplete.java +++ b/src/test/java/TestComplete.java @@ -638,4 +638,15 @@ public class TestComplete { var classFiles = generateClassFiles(new ByteArrayClassLoader(), "OL.jav"); var instance = classFiles.get("OL").getDeclaredConstructor().newInstance(); } + + @Test + public void recordTest() throws Exception { + var classFiles = generateClassFiles(new ByteArrayClassLoader(), "RecordTest.jav"); + var clazz = classFiles.get("RecordTest"); + var instance = clazz.getDeclaredConstructor().newInstance(); + assertTrue((Boolean) clazz.getDeclaredMethod("doesEqual").invoke(instance)); + assertFalse((Boolean) clazz.getDeclaredMethod("doesNotEqual").invoke(instance)); + System.out.println(clazz.getDeclaredMethod("hashCode").invoke(instance)); + System.out.println(clazz.getDeclaredMethod("toString").invoke(instance)); + } } diff --git a/src/test/java/syntaxtreegenerator/TestNewFeatures.java b/src/test/java/syntaxtreegenerator/TestNewFeatures.java index 067dc0f4..5ef7867a 100644 --- a/src/test/java/syntaxtreegenerator/TestNewFeatures.java +++ b/src/test/java/syntaxtreegenerator/TestNewFeatures.java @@ -62,10 +62,10 @@ public class TestNewFeatures { resultingAST = resultingAST.replaceAll("TPH [A-Z]+", "TPH"); System.out.println("Expected:\n" + new String(expectedAST)); System.out.println("Result:\n" + new String(resultingAST)); - assertEquals("Comparing expected and resulting AST for Record.jav", expectedAST, resultingAST); + assertEquals("Comparing expected and resulting AST for RecordTest.jav", expectedAST, resultingAST); } catch (Exception exc) { exc.printStackTrace(); - fail("An error occured while generating the AST for Record.jav"); + fail("An error occured while generating the AST for RecordTest.jav"); } } diff --git a/src/test/java/targetast/ASTToTypedTargetAST.java b/src/test/java/targetast/ASTToTypedTargetAST.java index c6e3d394..d49b61a5 100644 --- a/src/test/java/targetast/ASTToTypedTargetAST.java +++ b/src/test/java/targetast/ASTToTypedTargetAST.java @@ -9,6 +9,7 @@ import de.dhbwstuttgart.syntaxtree.*; import de.dhbwstuttgart.syntaxtree.type.RefType; import de.dhbwstuttgart.target.generate.ASTToTargetAST; import de.dhbwstuttgart.target.tree.TargetClass; +import de.dhbwstuttgart.target.tree.TargetStructure; import de.dhbwstuttgart.typeinference.result.ResultSet; import org.junit.Ignore; import org.junit.Test; @@ -27,7 +28,7 @@ public class ASTToTypedTargetAST { public void emptyClass() { ClassOrInterface emptyClass = new ClassOrInterface(0, new JavaClassName("EmptyClass"), new ArrayList<>(), java.util.Optional.empty(), new ArrayList<>(), new ArrayList<>(), new GenericDeclarationList(new ArrayList<>(), new NullToken()), new RefType(new JavaClassName("Object"), new NullToken()), false, new ArrayList<>(), new ArrayList<>(), new NullToken()); ResultSet emptyResultSet = new ResultSet(new HashSet<>()); - TargetClass emptyTargetClass = new ASTToTargetAST(List.of(emptyResultSet)).convert(emptyClass); + TargetStructure emptyTargetClass = new ASTToTargetAST(List.of(emptyResultSet)).convert(emptyClass); assert emptyTargetClass.getName().equals("EmptyClass"); assert emptyTargetClass.methods().size() == 0; assert emptyTargetClass.fields().size() == 0; diff --git a/src/test/java/targetast/TestCodegen.java b/src/test/java/targetast/TestCodegen.java index 532335db..07f1b176 100644 --- a/src/test/java/targetast/TestCodegen.java +++ b/src/test/java/targetast/TestCodegen.java @@ -7,6 +7,7 @@ import de.dhbwstuttgart.environment.IByteArrayClassLoader; import de.dhbwstuttgart.target.generate.ASTToTargetAST; import de.dhbwstuttgart.target.tree.MethodParameter; import de.dhbwstuttgart.target.tree.TargetClass; +import de.dhbwstuttgart.target.tree.TargetStructure; import de.dhbwstuttgart.target.tree.expression.*; import de.dhbwstuttgart.target.tree.type.TargetFunNType; import de.dhbwstuttgart.target.tree.type.TargetRefType; @@ -66,7 +67,7 @@ public class TestCodegen { return result; } - public static Class generateClass(TargetClass clazz, IByteArrayClassLoader classLoader) throws IOException { + public static Class generateClass(TargetStructure clazz, IByteArrayClassLoader classLoader) throws IOException { var codegen = new Codegen(clazz); var code = codegen.generate(); writeClassFile(clazz.qualifiedName(), code);