forked from JavaTX/JavaCompilerCore
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;
|
package de.dhbwstuttgart.bytecode;
|
||||||
|
|
||||||
import de.dhbwstuttgart.exceptions.NotImplementedException;
|
import de.dhbwstuttgart.exceptions.NotImplementedException;
|
||||||
import de.dhbwstuttgart.syntaxtree.statement.Break;
|
|
||||||
import de.dhbwstuttgart.target.tree.*;
|
import de.dhbwstuttgart.target.tree.*;
|
||||||
import de.dhbwstuttgart.target.tree.expression.*;
|
import de.dhbwstuttgart.target.tree.expression.*;
|
||||||
import de.dhbwstuttgart.target.tree.type.*;
|
import de.dhbwstuttgart.target.tree.type.*;
|
||||||
import org.antlr.v4.codegen.Target;
|
|
||||||
import org.objectweb.asm.*;
|
import org.objectweb.asm.*;
|
||||||
|
|
||||||
import java.lang.invoke.CallSite;
|
import java.lang.invoke.*;
|
||||||
import java.lang.invoke.MethodHandle;
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.lang.invoke.MethodType;
|
|
||||||
import java.sql.Array;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.objectweb.asm.Opcodes.*;
|
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.*;
|
import static de.dhbwstuttgart.target.tree.expression.TargetLiteral.*;
|
||||||
|
|
||||||
public class Codegen {
|
public class Codegen {
|
||||||
private final TargetClass clazz;
|
private final TargetStructure clazz;
|
||||||
private final ClassWriter cw;
|
private final ClassWriter cw;
|
||||||
public final String className;
|
public final String className;
|
||||||
private int lambdaCounter = 0;
|
private int lambdaCounter = 0;
|
||||||
private final HashMap<TargetLambdaExpression, TargetMethod> lambdas = new HashMap<>();
|
private final HashMap<TargetLambdaExpression, TargetMethod> lambdas = new HashMap<>();
|
||||||
|
|
||||||
public Codegen(TargetClass clazz) {
|
public Codegen(TargetStructure clazz) {
|
||||||
this.clazz = clazz;
|
this.clazz = clazz;
|
||||||
this.className = clazz.qualifiedName();
|
this.className = clazz.qualifiedName();
|
||||||
this.cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
this.cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||||
@ -1148,10 +1142,13 @@ public class Codegen {
|
|||||||
|
|
||||||
if (cse.labels().size() == 1) {
|
if (cse.labels().size() == 1) {
|
||||||
var label = cse.labels().get(0);
|
var label = cse.labels().get(0);
|
||||||
if (label instanceof TargetSwitch.Guard gd)
|
if (label instanceof TargetSwitch.Guard gd){
|
||||||
bindLabel(state, tmp, aSwitch.expr().type(), gd.inner());
|
state.mv.visitVarInsn(ALOAD, tmp);
|
||||||
else if (label instanceof TargetSwitch.Pattern pat)
|
bindPattern(state, aSwitch.expr().type(), gd.inner());
|
||||||
bindLabel(state, tmp, aSwitch.expr().type(), pat);
|
} else if (label instanceof TargetSwitch.Pattern pat) {
|
||||||
|
state.mv.visitVarInsn(ALOAD, tmp);
|
||||||
|
bindPattern(state, aSwitch.expr().type(), pat);
|
||||||
|
}
|
||||||
|
|
||||||
if (label instanceof TargetSwitch.Guard gd) {
|
if (label instanceof TargetSwitch.Guard gd) {
|
||||||
generate(state, gd.expression());
|
generate(state, gd.expression());
|
||||||
@ -1191,13 +1188,13 @@ public class Codegen {
|
|||||||
state.exitScope();
|
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) {
|
if (pat instanceof TargetSwitch.SimplePattern sp) {
|
||||||
state.mv.visitVarInsn(ALOAD, tmp);
|
|
||||||
var local = state.createVariable(sp.name(), sp.type());
|
var local = state.createVariable(sp.name(), sp.type());
|
||||||
convertTo(state, type, local.type);
|
convertTo(state, type, local.type);
|
||||||
boxPrimitive(state, local.type);
|
|
||||||
state.mv.visitVarInsn(ASTORE, local.index);
|
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) {
|
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) {
|
private void generateConstructor(TargetConstructor constructor) {
|
||||||
@ -1265,7 +1266,7 @@ public class Codegen {
|
|||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String generateSignature(TargetClass clazz, Set<TargetGeneric> generics) {
|
private static String generateSignature(TargetStructure clazz, Set<TargetGeneric> generics) {
|
||||||
String ret = "";
|
String ret = "";
|
||||||
if (generics.size() > 0) {
|
if (generics.size() > 0) {
|
||||||
ret += "<";
|
ret += "<";
|
||||||
@ -1280,7 +1281,11 @@ public class Codegen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public byte[] generate() {
|
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)
|
if (clazz.txGenerics() != null)
|
||||||
cw.visitAttribute(new JavaTXSignatureAttribute(generateSignature(clazz, clazz.txGenerics())));
|
cw.visitAttribute(new JavaTXSignatureAttribute(generateSignature(clazz, clazz.txGenerics())));
|
||||||
|
|
||||||
@ -1288,7 +1293,53 @@ public class Codegen {
|
|||||||
clazz.constructors().forEach(this::generateConstructor);
|
clazz.constructors().forEach(this::generateConstructor);
|
||||||
clazz.methods().forEach(this::generateMethod);
|
clazz.methods().forEach(this::generateMethod);
|
||||||
|
|
||||||
|
if (clazz instanceof TargetRecord)
|
||||||
|
generateRecordMethods();
|
||||||
|
|
||||||
cw.visitEnd();
|
cw.visitEnd();
|
||||||
return cw.toByteArray();
|
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) {
|
void addMethods(SourceFile sf, ClassOrInterface cl, List<ClassOrInterface> importedClasses, ClassOrInterface objectClass) {
|
||||||
if (!cl.areMethodsAdded()) {
|
if (!cl.areMethodsAdded()) {
|
||||||
ClassOrInterface superclass = null;
|
ClassOrInterface superclass = null;
|
||||||
if (cl.getSuperClass().getName().equals(new JavaClassName("java.lang.Object"))) {
|
Optional<ClassOrInterface> optSuperclass = importedClasses.stream().filter(x -> x.getClassName().equals(cl.getSuperClass().getName())).findFirst();
|
||||||
superclass = objectClass;
|
if (optSuperclass.isPresent()) {
|
||||||
|
superclass = optSuperclass.get();
|
||||||
} else {
|
} 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()) {
|
if (optSuperclass.isPresent()) {
|
||||||
superclass = optSuperclass.get();
|
superclass = optSuperclass.get();
|
||||||
|
addMethods(sf, superclass, importedClasses, objectClass);
|
||||||
} else {
|
} else {
|
||||||
optSuperclass = sf.KlassenVektor.stream().filter(x -> x.getClassName().equals(cl.getSuperClass().getName())).findFirst();
|
try {
|
||||||
if (optSuperclass.isPresent()) {
|
var className = cl.getSuperClass().getName().toString();
|
||||||
superclass = optSuperclass.get();
|
superclass = ASTFactory.createClass(classLoader.loadClass(className));
|
||||||
addMethods(sf, superclass, importedClasses, objectClass);
|
} catch (ClassNotFoundException ignored) {}
|
||||||
} else {
|
// throw new ClassNotFoundException("");
|
||||||
// throw new ClassNotFoundException("");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator<RefTypeOrTPHOrWildcardOrGeneric> paraIt = cl.getSuperClass().getParaList().iterator();
|
Iterator<RefTypeOrTPHOrWildcardOrGeneric> paraIt = cl.getSuperClass().getParaList().iterator();
|
||||||
Iterator<GenericTypeVar> tvarVarIt = superclass.getGenerics().iterator();
|
Iterator<GenericTypeVar> tvarVarIt = superclass.getGenerics().iterator();
|
||||||
|
|
||||||
|
@ -87,6 +87,8 @@ import de.dhbwstuttgart.syntaxtree.type.Void;
|
|||||||
import de.dhbwstuttgart.typeinference.constraints.GenericsResolver;
|
import de.dhbwstuttgart.typeinference.constraints.GenericsResolver;
|
||||||
import javassist.compiler.SyntaxError;
|
import javassist.compiler.SyntaxError;
|
||||||
|
|
||||||
|
import javax.swing.text.html.Option;
|
||||||
|
|
||||||
public class SyntaxTreeGenerator {
|
public class SyntaxTreeGenerator {
|
||||||
private JavaClassRegistry reg;
|
private JavaClassRegistry reg;
|
||||||
private final GenericsRegistry globalGenerics;
|
private final GenericsRegistry globalGenerics;
|
||||||
@ -248,7 +250,7 @@ public class SyntaxTreeGenerator {
|
|||||||
} else {
|
} else {
|
||||||
genericClassParameters = TypeGenerator.convert(recordDeclaration.genericDeclarationList(), name, "", reg, generics);
|
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<Field> fielddecl = new ArrayList<>();
|
||||||
List<Method> methods = new ArrayList<>();
|
List<Method> methods = new ArrayList<>();
|
||||||
List<Constructor> constructors = new ArrayList<>();
|
List<Constructor> constructors = new ArrayList<>();
|
||||||
|
@ -33,7 +33,11 @@ import org.objectweb.asm.signature.SignatureVisitor;
|
|||||||
*/
|
*/
|
||||||
public class ASTFactory {
|
public class ASTFactory {
|
||||||
|
|
||||||
|
private static final HashMap<java.lang.Class, ClassOrInterface> cache = new HashMap<>();
|
||||||
|
|
||||||
public static ClassOrInterface createClass(java.lang.Class jreClass) {
|
public static ClassOrInterface createClass(java.lang.Class jreClass) {
|
||||||
|
if (cache.containsKey(jreClass))
|
||||||
|
return cache.get(jreClass);
|
||||||
|
|
||||||
// TODO Inner classes
|
// 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
|
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) {
|
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.ByteArrayClassLoader;
|
||||||
import de.dhbwstuttgart.environment.IByteArrayClassLoader;
|
import de.dhbwstuttgart.environment.IByteArrayClassLoader;
|
||||||
import de.dhbwstuttgart.syntaxtree.*;
|
import de.dhbwstuttgart.syntaxtree.*;
|
||||||
|
import de.dhbwstuttgart.syntaxtree.Record;
|
||||||
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
|
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
|
||||||
import de.dhbwstuttgart.syntaxtree.statement.*;
|
import de.dhbwstuttgart.syntaxtree.statement.*;
|
||||||
import de.dhbwstuttgart.syntaxtree.type.*;
|
import de.dhbwstuttgart.syntaxtree.type.*;
|
||||||
@ -104,7 +105,7 @@ public class ASTToTargetAST {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TargetClass convert(ClassOrInterface input) {
|
public TargetStructure convert(ClassOrInterface input) {
|
||||||
currentClass = input;
|
currentClass = input;
|
||||||
Set<TargetGeneric> javaGenerics = new HashSet<>();
|
Set<TargetGeneric> javaGenerics = new HashSet<>();
|
||||||
Set<TargetGeneric> txGenerics = new HashSet<>();
|
Set<TargetGeneric> txGenerics = new HashSet<>();
|
||||||
@ -132,7 +133,14 @@ public class ASTToTargetAST {
|
|||||||
fieldInitializer = convert(input.getfieldInitializations().get().block);
|
fieldInitializer = convert(input.getfieldInitializations().get().block);
|
||||||
TargetBlock finalFieldInitializer = fieldInitializer;
|
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) {
|
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) {
|
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 {
|
try {
|
||||||
var clazz = converter.classLoader.loadClass(className.toString());
|
var clazz = converter.classLoader.loadClass(className.toString());
|
||||||
|
|
||||||
@ -374,6 +374,7 @@ public class StatementToTargetExpression implements StatementVisitor {
|
|||||||
public void visit(RecordPattern aRecordPattern) {
|
public void visit(RecordPattern aRecordPattern) {
|
||||||
result = new TargetSwitch.ComplexPattern(
|
result = new TargetSwitch.ComplexPattern(
|
||||||
converter.convert(aRecordPattern.getType()),
|
converter.convert(aRecordPattern.getType()),
|
||||||
|
aRecordPattern.getName(),
|
||||||
aRecordPattern.getSubPattern().stream().map(x -> (TargetSwitch.Pattern) converter.convert(x)).toList()
|
aRecordPattern.getSubPattern().stream().map(x -> (TargetSwitch.Pattern) converter.convert(x)).toList()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import java.util.List;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public record TargetClass(int modifiers, String qualifiedName, TargetType superType, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<TargetType> implementingInterfaces,
|
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) {
|
public TargetClass(int modifiers, String qualifiedName) {
|
||||||
this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new HashSet<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
|
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<>());
|
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) {
|
public void addField(int access, TargetRefType type, String name) {
|
||||||
this.fields.add(new TargetField(access, type, 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 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 {}
|
public record Guard(Pattern inner, TargetExpression expression) implements Pattern {}
|
||||||
}
|
}
|
||||||
|
@ -638,4 +638,15 @@ public class TestComplete {
|
|||||||
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "OL.jav");
|
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "OL.jav");
|
||||||
var instance = classFiles.get("OL").getDeclaredConstructor().newInstance();
|
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");
|
resultingAST = resultingAST.replaceAll("TPH [A-Z]+", "TPH");
|
||||||
System.out.println("Expected:\n" + new String(expectedAST));
|
System.out.println("Expected:\n" + new String(expectedAST));
|
||||||
System.out.println("Result:\n" + new String(resultingAST));
|
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) {
|
} catch (Exception exc) {
|
||||||
exc.printStackTrace();
|
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.syntaxtree.type.RefType;
|
||||||
import de.dhbwstuttgart.target.generate.ASTToTargetAST;
|
import de.dhbwstuttgart.target.generate.ASTToTargetAST;
|
||||||
import de.dhbwstuttgart.target.tree.TargetClass;
|
import de.dhbwstuttgart.target.tree.TargetClass;
|
||||||
|
import de.dhbwstuttgart.target.tree.TargetStructure;
|
||||||
import de.dhbwstuttgart.typeinference.result.ResultSet;
|
import de.dhbwstuttgart.typeinference.result.ResultSet;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -27,7 +28,7 @@ public class ASTToTypedTargetAST {
|
|||||||
public void emptyClass() {
|
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());
|
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<>());
|
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.getName().equals("EmptyClass");
|
||||||
assert emptyTargetClass.methods().size() == 0;
|
assert emptyTargetClass.methods().size() == 0;
|
||||||
assert emptyTargetClass.fields().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.generate.ASTToTargetAST;
|
||||||
import de.dhbwstuttgart.target.tree.MethodParameter;
|
import de.dhbwstuttgart.target.tree.MethodParameter;
|
||||||
import de.dhbwstuttgart.target.tree.TargetClass;
|
import de.dhbwstuttgart.target.tree.TargetClass;
|
||||||
|
import de.dhbwstuttgart.target.tree.TargetStructure;
|
||||||
import de.dhbwstuttgart.target.tree.expression.*;
|
import de.dhbwstuttgart.target.tree.expression.*;
|
||||||
import de.dhbwstuttgart.target.tree.type.TargetFunNType;
|
import de.dhbwstuttgart.target.tree.type.TargetFunNType;
|
||||||
import de.dhbwstuttgart.target.tree.type.TargetRefType;
|
import de.dhbwstuttgart.target.tree.type.TargetRefType;
|
||||||
@ -66,7 +67,7 @@ public class TestCodegen {
|
|||||||
return result;
|
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 codegen = new Codegen(clazz);
|
||||||
var code = codegen.generate();
|
var code = codegen.generate();
|
||||||
writeClassFile(clazz.qualifiedName(), code);
|
writeClassFile(clazz.qualifiedName(), code);
|
||||||
|
Loading…
Reference in New Issue
Block a user