Implement records
This commit is contained in:
parent
4f3164a48a
commit
b0f7a264c2
22
resources/bytecode/javFiles/RecordTest.jav
Normal file
22
resources/bytecode/javFiles/RecordTest.jav
Normal file
@ -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(); }
|
||||
}
|
@ -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<TargetLambdaExpression, TargetMethod> 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<TargetGeneric> generics) {
|
||||
private static String generateSignature(TargetStructure clazz, Set<TargetGeneric> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -135,22 +135,23 @@ public class JavaTXCompiler {
|
||||
void addMethods(SourceFile sf, ClassOrInterface cl, List<ClassOrInterface> importedClasses, ClassOrInterface objectClass) {
|
||||
if (!cl.areMethodsAdded()) {
|
||||
ClassOrInterface superclass = null;
|
||||
if (cl.getSuperClass().getName().equals(new JavaClassName("java.lang.Object"))) {
|
||||
superclass = objectClass;
|
||||
Optional<ClassOrInterface> optSuperclass = importedClasses.stream().filter(x -> x.getClassName().equals(cl.getSuperClass().getName())).findFirst();
|
||||
if (optSuperclass.isPresent()) {
|
||||
superclass = optSuperclass.get();
|
||||
} else {
|
||||
Optional<ClassOrInterface> 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<RefTypeOrTPHOrWildcardOrGeneric> paraIt = cl.getSuperClass().getParaList().iterator();
|
||||
Iterator<GenericTypeVar> tvarVarIt = superclass.getGenerics().iterator();
|
||||
|
||||
|
@ -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<Field> fielddecl = new ArrayList<>();
|
||||
List<Method> methods = new ArrayList<>();
|
||||
List<Constructor> constructors = new ArrayList<>();
|
||||
|
@ -33,7 +33,11 @@ import org.objectweb.asm.signature.SignatureVisitor;
|
||||
*/
|
||||
public class ASTFactory {
|
||||
|
||||
private static final HashMap<java.lang.Class, ClassOrInterface> 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) {
|
||||
|
@ -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<TargetGeneric> javaGenerics = new HashSet<>();
|
||||
Set<TargetGeneric> 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<MethodParameter> convert(ParameterList input, GenerateGenerics generics) {
|
||||
|
@ -170,7 +170,7 @@ public class StatementToTargetExpression implements StatementVisitor {
|
||||
}
|
||||
|
||||
Method findMethod(JavaClassName className, String name, List<TargetType> 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()
|
||||
);
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public record TargetClass(int modifiers, String qualifiedName, TargetType superType, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<TargetType> implementingInterfaces,
|
||||
List<TargetConstructor> constructors, List<TargetField> fields, List<TargetMethod> methods) {
|
||||
List<TargetConstructor> constructors, List<TargetField> fields, List<TargetMethod> 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<TargetGeneric> generics, List<MethodParameter> 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<MethodParameter> parameterTypes, TargetType returnType, TargetBlock block) {
|
||||
addMethod(access, name, Set.of(), parameterTypes, returnType, block);
|
||||
}
|
||||
|
||||
public void addConstructor(int access, Set<TargetGeneric> generics, List<MethodParameter> paramterTypes, TargetBlock block) {
|
||||
this.constructors.add(new TargetConstructor(access, generics, Set.of(), paramterTypes, List.of(), block, null));
|
||||
}
|
||||
|
||||
public void addConstructor(int access, List<MethodParameter> 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));
|
||||
}
|
||||
|
18
src/main/java/de/dhbwstuttgart/target/tree/TargetRecord.java
Normal file
18
src/main/java/de/dhbwstuttgart/target/tree/TargetRecord.java
Normal file
@ -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<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<TargetType> implementingInterfaces, List<TargetConstructor> constructors, List<TargetField> fields, List<TargetMethod> methods) implements TargetStructure {
|
||||
|
||||
public static final TargetType RECORD = new TargetRefType("java.lang.Record");
|
||||
|
||||
@Override
|
||||
public TargetType superType() {
|
||||
return RECORD;
|
||||
}
|
||||
}
|
@ -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<TargetGeneric> generics();
|
||||
Set<TargetGeneric> txGenerics();
|
||||
List<TargetType> implementingInterfaces();
|
||||
List<TargetConstructor> constructors();
|
||||
List<TargetField> fields();
|
||||
List<TargetMethod> 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<TargetGeneric> generics, List<MethodParameter> 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<MethodParameter> parameterTypes, TargetType returnType, TargetBlock block) {
|
||||
addMethod(access, name, Set.of(), parameterTypes, returnType, block);
|
||||
}
|
||||
|
||||
default void addConstructor(int access, Set<TargetGeneric> generics, List<MethodParameter> paramterTypes, TargetBlock block) {
|
||||
this.constructors().add(new TargetConstructor(access, generics, Set.of(), paramterTypes, List.of(), block, null));
|
||||
}
|
||||
|
||||
default void addConstructor(int access, List<MethodParameter> paramterTypes, TargetBlock block) {
|
||||
addConstructor(access, Set.of(), paramterTypes, block);
|
||||
}
|
||||
}
|
@ -27,10 +27,14 @@ public record TargetSwitch(TargetExpression expr, List<Case> 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<Pattern> subPatterns) implements Pattern {}
|
||||
public record ComplexPattern(TargetType type, String name, List<Pattern> subPatterns) implements Pattern {}
|
||||
|
||||
public record Guard(Pattern inner, TargetExpression expression) implements Pattern {}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user