Compare commits

...

23 Commits

Author SHA1 Message Date
Ruben
96eb504174 test & fix: add Testcase for Heritage-detection and removed unnecessary creation of Constraints.
All checks were successful
Build and Test with Maven / Build-and-test-with-Maven (push) Successful in 5m42s
2024-08-06 18:44:52 +02:00
Ruben
4f0162ba64 Merge branch 'targetBytecode' into patternMatching 2024-08-05 15:42:48 +02:00
Ruben
6e1198ab3d test: reverted TestCodegen 2024-08-05 15:40:05 +02:00
7785c2d0aa Fix equals method of ClassOrInterface
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 6m48s
2024-08-05 11:54:13 +02:00
a654f55deb Fix yTest
All checks were successful
Build and Test with Maven / Build-and-test-with-Maven (push) Successful in 4m45s
2024-07-25 17:05:27 +02:00
pl@gohorb.ba-horb.de
7037bdf9ef modified: src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java
All checks were successful
Build and Test with Maven / Build-and-test-with-Maven (push) Successful in 5m16s
2024-07-24 23:31:13 +02:00
pl@gohorb.ba-horb.de
d9860497df Merge branch 'targetBytecode' of ssh://gitea.hb.dhbw-stuttgart.de:2222/JavaTX/JavaCompilerCore into targetBytecode
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 5m38s
src/test/java/AllgemeinTest.java
2024-07-24 23:25:07 +02:00
pl@gohorb.ba-horb.de
fdffc11580 modified: resources/AllgemeinTest/Box.jav
deleted:    resources/bytecode/javFiles/Box.java
	modified:   src/test/java/AllgemeinTest.java
2024-07-24 23:23:39 +02:00
pl@gohorb.ba-horb.de
c10de35ca2 new file: resources/AllgemeinTest/Bar.java
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 5m25s
2024-07-24 18:28:07 +02:00
pl@gohorb.ba-horb.de
56b73332c0 modified: pom.xml
new file:   resources/AllgemeinTest/Foo.jav
	modified:   src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java
2024-07-24 18:27:32 +02:00
pl@gohorb.ba-horb.de
bdcd5ea3cf Merge branch 'targetBytecode' of https://gitea.hb.dhbw-stuttgart.de/JavaTX/JavaCompilerCore into targetBytecode 2024-07-24 12:35:43 +02:00
edafbbc5a0 Fix #340
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 44s
2024-07-23 15:33:09 +02:00
ba8810e5df I don't know why isFunctionalInterface returns true on things that aren't even interfaces but here we go
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 1m0s
2024-07-19 18:04:33 +02:00
63493ed0f7 Make lambdas castable
Some checks are pending
Build and Test with Maven / Build-and-test-with-Maven (push) Waiting to run
2024-07-19 17:26:39 +02:00
pl@gohorb.ba-horb.de
4dba867f9e Merge branch 'targetBytecode' of ssh://gitea.hb.dhbw-stuttgart.de:2222/JavaTX/JavaCompilerCore into targetBytecode 2024-06-14 11:28:05 +02:00
pl@gohorb.ba-horb.de
06caf0ff66 Merge branch 'targetBytecode' of ssh://gohorb.ba-horb.de/bahome/projekt/git/JavaCompilerCore into targetBytecode 2024-06-14 11:27:14 +02:00
ec92b5d5e1 Work on Bug #332
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 46s
2024-06-13 17:23:19 +02:00
091a6b8f1f Fix merge conflict
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 43s
2024-06-07 12:16:03 +02:00
60a1f3b220 Merge branch 'targetBytecode' of https://gitea.hb.dhbw-stuttgart.de/JavaTX/JavaCompilerCore into targetBytecode
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 47s
2024-06-07 12:04:01 +02:00
7e6aeaf728 Make Function Types implement others to allow Subtyping, fixes #337 2024-06-07 12:03:16 +02:00
pl@gohorb.ba-horb.de
5d03995f10 Merge branch 'targetBytecode' of https://gitea.hb.dhbw-stuttgart.de/JavaTX/JavaCompilerCore into targetBytecode 2024-05-27 17:44:29 +02:00
pl@gohorb.ba-horb.de
1bc58573c7 modified: src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java
modified:   src/test/java/AllgemeinTest.java
2024-05-27 17:35:59 +02:00
Pluemicke Martin
3d2b935c60 Merge branch 'targetBytecode' of https://gitea.hb.dhbw-stuttgart.de/JavaTX/JavaCompilerCore into targetBytecode 2024-05-14 22:53:08 +02:00
25 changed files with 596 additions and 306 deletions

View File

@ -0,0 +1,10 @@
public class Bar{
void visit(Object o){
System.out.println("Object");
}
void visit(Bla f){
System.out.println("Foo");
}
}

View File

@ -1,8 +1,9 @@
class Box<A> { public class Box<A> {
A a; A a;
public Box() { }
public Box(A a) { public Box(A a) {
this.a = a; //this.a = a;
} }
} }

View File

@ -0,0 +1,6 @@
public class Foo{
public accept(Bar b){
b.visit(this);
}
}

View File

@ -1,3 +0,0 @@
class Box<A> {
void m(A a) { }
}

View File

@ -0,0 +1,15 @@
import java.lang.Object;
interface Visitor {
public void visit(Object obj);
public void visit(ClassA a);
}
class ClassA {
void accept(Visitor v) {
v.visit(this);
}
}
public class Bug332 {
}

View File

@ -0,0 +1,10 @@
import java.lang.Integer;
import java.lang.Number;
import java.lang.Object;
public class Bug337 {
public void main() {
Fun1$$<Object, Integer> fun1 = x -> x.hashCode() + 1;
Fun1$$<Number, Number> fun2 = fun1;
}
}

View File

@ -1,16 +0,0 @@
import java.lang.Runnable;
import java.lang.System;
import java.lang.String;
import java.io.PrintStream;
public class LamRunnable {
public LamRunnable() {
Runnable lam = () -> {
System.out.println("lambda");
};
lam.run();
}
}

View File

@ -0,0 +1,22 @@
import java.lang.Integer;
import java.lang.Object;
import java.lang.Float;
import java.lang.String;
public class NumberOrText{}
public class Text extends NumberOrText{};
public class Number extends NumberOrText{};
public record Cons(Integer a, NumberOrText l){}
public class SwitchCaseHeritageDetection {
public main(o) {
return switch(o) {
case Cons(a, Text b) -> "Second Element is a Text";
case Cons(a, Number b) -> "Second Element is a Number";
default -> "None of the above cases";
};
}
}

View File

@ -10,8 +10,8 @@ public record Rec(Object a, Object b) {}
public class SwitchInfered { public class SwitchInfered {
public main(o) { public main(o) {
return switch (o) { return switch (o) {
case Rec(a, b) -> a; case Rec(a, b) -> "asd";
default -> 0; default -> "cde";
}; };
} }
} }

View File

@ -1,15 +0,0 @@
sealed interface List<A> permits Cons, Nil {}
record Cons(A a, List<A> l) implements List<A> {}
record Nil()implements List<A> {
void m(x) {
switch(x) {
case Cons(a, Cons(b, List<A> l)) -> System.out.println(a);
case Cons(a, Nil()) -> System.out.println(a);
case Nil() -> System.out.println("Nil");
}
}
}

View File

@ -5,6 +5,8 @@ import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.parser.NullToken; import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.scope.JavaClassName; import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface; import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.Method;
import de.dhbwstuttgart.syntaxtree.Pattern;
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.generate.StatementToTargetExpression; import de.dhbwstuttgart.target.generate.StatementToTargetExpression;
@ -31,15 +33,21 @@ public class Codegen {
private final JavaTXCompiler compiler; private final JavaTXCompiler compiler;
private final ASTToTargetAST converter; private final ASTToTargetAST converter;
private class CustomClassWriter extends ClassWriter {
public CustomClassWriter() {
super(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
}
@Override
protected ClassLoader getClassLoader() {
return compiler.getClassLoader();
}
}
public Codegen(TargetStructure clazz, JavaTXCompiler compiler, ASTToTargetAST converter) { public Codegen(TargetStructure clazz, JavaTXCompiler compiler, ASTToTargetAST converter) {
this.clazz = clazz; this.clazz = clazz;
this.className = clazz.qualifiedName().getClassName(); this.className = clazz.qualifiedName().getClassName();
this.cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) { this.cw = new CustomClassWriter();
@Override
protected ClassLoader getClassLoader() {
return compiler.getClassLoader();
}
};
this.compiler = compiler; this.compiler = compiler;
this.converter = converter; this.converter = converter;
} }
@ -82,8 +90,6 @@ public class Codegen {
int localCounter; int localCounter;
MethodVisitor mv; MethodVisitor mv;
TargetType returnType; TargetType returnType;
// This is used to remember the type from lambda expressions
TargetType contextType;
Stack<BreakEnv> breakStack = new Stack<>(); Stack<BreakEnv> breakStack = new Stack<>();
Stack<Integer> switchResultValue = new Stack<>(); Stack<Integer> switchResultValue = new Stack<>();
@ -270,13 +276,43 @@ public class Codegen {
mv.visitInsn(I2F); mv.visitInsn(I2F);
else if (dest.equals(TargetType.Double)) else if (dest.equals(TargetType.Double))
mv.visitInsn(I2D); mv.visitInsn(I2D);
} else if (isFunctionalInterface(source) && isFunctionalInterface(dest) &&
!(source instanceof TargetFunNType && dest instanceof TargetFunNType)) {
boxFunctionalInterface(state, source, dest);
} else if (!(dest instanceof TargetGenericType)) { } else if (!(dest instanceof TargetGenericType)) {
boxPrimitive(state, source); //boxPrimitive(state, source);
mv.visitTypeInsn(CHECKCAST, dest.getInternalName()); mv.visitTypeInsn(CHECKCAST, dest.getInternalName());
unboxPrimitive(state, dest); unboxPrimitive(state, dest);
} }
} }
record TypePair(TargetType from, TargetType to) {}
private Map<TypePair, String> funWrapperClasses = new HashMap<>();
private void boxFunctionalInterface(State state, TargetType source, TargetType dest) {
var mv = state.mv;
var className = "FunWrapper$$" +
source.name().replaceAll("\\.", "\\$") +
"$_$" +
dest.name().replaceAll("\\.", "\\$");
funWrapperClasses.put(new TypePair(source, dest), className);
mv.visitTypeInsn(NEW, className);
mv.visitInsn(DUP_X1);
mv.visitInsn(SWAP);
mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "(" + source.toDescriptor() + ")V", false);
}
private boolean isFunctionalInterface(TargetType type) {
if (type instanceof TargetFunNType) return true;
if (type instanceof TargetRefType) {
var clazz = compiler.getClass(new JavaClassName(type.name()));
return (clazz.getModifiers() & Modifier.INTERFACE) != 0 && clazz.isFunctionalInterface();
}
return false;
}
private TargetType largerType(TargetType left, TargetType right) { private TargetType largerType(TargetType left, TargetType right) {
if (left.equals(TargetType.String) || right.equals(TargetType.String)) { if (left.equals(TargetType.String) || right.equals(TargetType.String)) {
return TargetType.String; return TargetType.String;
@ -727,41 +763,15 @@ public class Codegen {
var mv = state.mv; var mv = state.mv;
String methodName = "apply"; String methodName = "apply";
TargetMethod.Signature signature = null; TargetMethod.Signature signature = new TargetMethod.Signature(Set.of(),
lambda.signature().parameters().stream().map(
if (!(state.contextType instanceof TargetFunNType ctx)) { par -> par.withType(TargetType.Object)).toList(),
var intf = compiler.getClass(new JavaClassName(state.contextType.name())); lambda.signature().returnType() != null ? TargetType.Object : null);
if (intf != null) {
var method = intf.getMethods().stream().filter(m -> Modifier.isAbstract(m.modifier)).findFirst().orElseThrow();
methodName = method.getName();
var methodParams = new ArrayList<MethodParameter>();
for (var i = 0; i < lambda.signature().parameters().size(); i++) {
var param = lambda.signature().parameters().get(i);
var tpe = converter.convert(method.getParameterList().getParameterAt(i).getType());
methodParams.add(param.withType(tpe));
}
var retType = converter.convert(method.getReturnType());
signature = new TargetMethod.Signature(Set.of(), methodParams, retType);
}
}
if (signature == null) {
signature = new TargetMethod.Signature(Set.of(), lambda.signature().parameters().stream().map(par -> par.withType(TargetType.Object)).toList(), TargetType.Object);
}
signature = new TargetMethod.Signature(
signature.generics(),
signature.parameters().stream().map(par ->
par.withType(par.pattern().type() instanceof TargetGenericType ? TargetType.Object : par.pattern().type())
).toList(),
signature.returnType() instanceof TargetGenericType ? TargetType.Object : signature.returnType()
);
var parameters = new ArrayList<>(lambda.captures()); var parameters = new ArrayList<>(lambda.captures());
parameters.addAll(signature.parameters()); parameters.addAll(signature.parameters());
var implSignature = new TargetMethod.Signature(Set.of(), parameters, lambda.signature().returnType()); var implSignature = new TargetMethod.Signature(Set.of(), parameters, lambda.signature().returnType());
// Normalize
TargetMethod impl; TargetMethod impl;
if (lambdas.containsKey(lambda)) { if (lambdas.containsKey(lambda)) {
impl = lambdas.get(lambda); impl = lambdas.get(lambda);
@ -782,7 +792,6 @@ public class Codegen {
params.add(new TargetRefType(clazz.qualifiedName().getClassName())); params.add(new TargetRefType(clazz.qualifiedName().getClassName()));
params.addAll(lambda.captures().stream().map(mp -> mp.pattern().type()).toList()); params.addAll(lambda.captures().stream().map(mp -> mp.pattern().type()).toList());
var descriptor = TargetMethod.getDescriptor(state.contextType, params.toArray(TargetType[]::new));
mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0);
for (var index = 0; index < lambda.captures().size(); index++) { for (var index = 0; index < lambda.captures().size(); index++) {
var capture = lambda.captures().get(index); var capture = lambda.captures().get(index);
@ -792,9 +801,42 @@ public class Codegen {
mv.visitTypeInsn(CHECKCAST, capture.pattern().type().getInternalName()); mv.visitTypeInsn(CHECKCAST, capture.pattern().type().getInternalName());
} }
var descriptor = TargetMethod.getDescriptor(lambda.type(), params.toArray(TargetType[]::new));
mv.visitInvokeDynamicInsn(methodName, descriptor, bootstrap, Type.getType(signature.getSignature()), handle, Type.getType(signature.getDescriptor())); mv.visitInvokeDynamicInsn(methodName, descriptor, bootstrap, Type.getType(signature.getSignature()), handle, Type.getType(signature.getDescriptor()));
} }
private int findReturnCode(TargetType returnType) {
if (returnType.equals(TargetType.boolean_)
|| returnType.equals(TargetType.char_)
|| returnType.equals(TargetType.int_)
|| returnType.equals(TargetType.short_)
|| returnType.equals(TargetType.byte_))
return IRETURN;
else if (returnType.equals(TargetType.long_))
return LRETURN;
else if (returnType.equals(TargetType.float_))
return FRETURN;
else if (returnType.equals(TargetType.double_))
return DRETURN;
return ARETURN;
}
private int findLoadCode(TargetType loadType) {
if (loadType.equals(TargetType.boolean_)
|| loadType.equals(TargetType.char_)
|| loadType.equals(TargetType.int_)
|| loadType.equals(TargetType.short_)
|| loadType.equals(TargetType.byte_))
return ILOAD;
else if (loadType.equals(TargetType.long_))
return LLOAD;
else if (loadType.equals(TargetType.float_))
return FLOAD;
else if (loadType.equals(TargetType.double_))
return DLOAD;
return ALOAD;
}
private void generate(State state, TargetExpression expr) { private void generate(State state, TargetExpression expr) {
var mv = state.mv; var mv = state.mv;
switch (expr) { switch (expr) {
@ -819,10 +861,7 @@ public class Codegen {
break; break;
} }
case TargetCast cast: case TargetCast cast:
var ctx = state.contextType;
state.contextType = cast.type();
generate(state, cast.expr()); generate(state, cast.expr());
state.contextType = ctx;
convertTo(state, cast.expr().type(), cast.type()); convertTo(state, cast.expr().type(), cast.type());
break; break;
case TargetInstanceOf instanceOf: case TargetInstanceOf instanceOf:
@ -867,10 +906,7 @@ public class Codegen {
case TargetAssign assign: { case TargetAssign assign: {
switch (assign.left()) { switch (assign.left()) {
case TargetLocalVar localVar -> { case TargetLocalVar localVar -> {
var ctype = state.contextType;
state.contextType = localVar.type();
generate(state, assign.right()); generate(state, assign.right());
state.contextType = ctype;
convertTo(state, assign.right().type(), localVar.type()); convertTo(state, assign.right().type(), localVar.type());
boxPrimitive(state, localVar.type()); boxPrimitive(state, localVar.type());
@ -883,10 +919,7 @@ public class Codegen {
if (!(dot.left() instanceof TargetThis && dot.isStatic())) if (!(dot.left() instanceof TargetThis && dot.isStatic()))
generate(state, dot.left()); generate(state, dot.left());
var ctype = state.contextType;
state.contextType = fieldType;
generate(state, assign.right()); generate(state, assign.right());
state.contextType = ctype;
convertTo(state, assign.right().type(), fieldType); convertTo(state, assign.right().type(), fieldType);
boxPrimitive(state, fieldType); boxPrimitive(state, fieldType);
@ -1016,29 +1049,12 @@ public class Codegen {
case TargetReturn ret: { case TargetReturn ret: {
if (ret.expression() != null && state.returnType != null) { if (ret.expression() != null && state.returnType != null) {
if (state.returnType instanceof TargetPrimitiveType) { if (state.returnType instanceof TargetPrimitiveType) {
var ctype = state.contextType;
state.contextType = state.returnType;
generate(state, ret.expression()); generate(state, ret.expression());
state.contextType = ctype;
unboxPrimitive(state, state.returnType); unboxPrimitive(state, state.returnType);
if (state.returnType.equals(TargetType.boolean_) mv.visitInsn(findReturnCode(state.returnType));
|| state.returnType.equals(TargetType.char_)
|| state.returnType.equals(TargetType.int_)
|| state.returnType.equals(TargetType.short_)
|| state.returnType.equals(TargetType.byte_))
mv.visitInsn(IRETURN);
else if (state.returnType.equals(TargetType.long_))
mv.visitInsn(LRETURN);
else if (state.returnType.equals(TargetType.float_))
mv.visitInsn(FRETURN);
else if (state.returnType.equals(TargetType.double_))
mv.visitInsn(DRETURN);
} else { } else {
var ctype = state.contextType;
state.contextType = state.returnType;
generate(state, ret.expression()); generate(state, ret.expression());
state.contextType = ctype;
boxPrimitive(state, ret.expression().type()); boxPrimitive(state, ret.expression().type());
convertTo(state, ret.expression().type(), state.returnType); convertTo(state, ret.expression().type(), state.returnType);
mv.visitInsn(ARETURN); mv.visitInsn(ARETURN);
@ -1089,12 +1105,10 @@ public class Codegen {
for (var i = 0; i < call.args().size(); i++) { for (var i = 0; i < call.args().size(); i++) {
var e = call.args().get(i); var e = call.args().get(i);
var arg = call.parameterTypes().get(i); var arg = call.parameterTypes().get(i);
var ctype = state.contextType;
state.contextType = arg;
generate(state, e); generate(state, e);
convertTo(state, e.type(), arg);
if (!(arg instanceof TargetPrimitiveType)) if (!(arg instanceof TargetPrimitiveType))
boxPrimitive(state, e.type()); boxPrimitive(state, e.type());
state.contextType = ctype;
} }
var descriptor = call.getDescriptor(); var descriptor = call.getDescriptor();
if (call.owner() instanceof TargetFunNType) // Decay FunN if (call.owner() instanceof TargetFunNType) // Decay FunN
@ -1600,6 +1614,85 @@ public class Codegen {
if (clazz instanceof TargetRecord) if (clazz instanceof TargetRecord)
generateRecordMethods(); generateRecordMethods();
// Generate wrapper classes for function types
for (var pair : funWrapperClasses.keySet()) {
var className = funWrapperClasses.get(pair);
ClassWriter cw2 = new CustomClassWriter();
cw2.visit(V1_8, ACC_PUBLIC, className, null, "java/lang/Object", new String[] { pair.to.getInternalName() });
cw2.visitField(ACC_PRIVATE, "wrapped", pair.from.toDescriptor(), null, null).visitEnd();
// Generate constructor
var ctor = cw2.visitMethod(ACC_PUBLIC, "<init>", "(" + pair.from.toDescriptor() + ")V", null, null);
ctor.visitVarInsn(ALOAD, 0);
ctor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
ctor.visitVarInsn(ALOAD, 0);
ctor.visitVarInsn(ALOAD, 1);
ctor.visitFieldInsn(PUTFIELD, className, "wrapped", pair.from.toDescriptor());
ctor.visitInsn(RETURN);
ctor.visitMaxs(0, 0);
ctor.visitEnd();
String methodName = "apply";
String fromDescriptor = null;
TargetType fromReturn = null;
if (!(pair.from instanceof TargetFunNType funNType)) {
var fromClass = compiler.getClass(new JavaClassName(pair.from.name()));
var fromMethod = fromClass.getMethods().stream().filter(m -> (m.modifier & ACC_ABSTRACT) != 0).findFirst().orElseThrow();
methodName = fromMethod.name;
fromReturn = converter.convert(fromMethod.getReturnType());
var fromParams = converter.convert(fromMethod.getParameterList(), converter.generics.javaGenerics()).stream().map(m -> m.pattern().type()).toArray(TargetType[]::new);
fromDescriptor = TargetMethod.getDescriptor(fromReturn, fromParams);
} else {
fromReturn = funNType.returnArguments() > 0 ? TargetType.Object : null;
fromDescriptor = funNType.toMethodDescriptor();
}
var toClass = compiler.getClass(new JavaClassName(pair.to.name()));
var toMethod = toClass.getMethods().stream().filter(m -> (m.modifier & ACC_ABSTRACT) != 0).findFirst().orElseThrow();
var toReturn = converter.convert(toMethod.getReturnType());
var toParams = converter.convert(toMethod.getParameterList(), converter.generics.javaGenerics()).stream().map(m -> m.pattern().type()).toArray(TargetType[]::new);
var toDescriptor = TargetMethod.getDescriptor(toReturn, toParams);
// Generate wrapper method
var mv = cw2.visitMethod(ACC_PUBLIC, toMethod.name, toDescriptor, null, null);
var state = new State(null, mv, 0);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, className, "wrapped", pair.from.toDescriptor());
for (var i = 0; i < toParams.length; i++) {
var arg = toParams[i];
mv.visitVarInsn(findLoadCode(arg), i + 1);
}
mv.visitMethodInsn(INVOKEINTERFACE, pair.from.getInternalName(), methodName, fromDescriptor, true);
if (fromReturn != null) {
if (toReturn instanceof TargetPrimitiveType) {
convertTo(state, fromReturn, TargetType.toWrapper(toReturn));
} else convertTo(state, fromReturn, toReturn);
}
if (toReturn != null)
mv.visitInsn(findReturnCode(toReturn));
else mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
cw2.visitEnd();
var bytes = cw2.toByteArray();
converter.auxiliaries.put(className, bytes);
// TODO These class loading shenanigans happen in a few places, the tests load the classes individually.
// Instead we should just look at the folder.
try {
converter.classLoader.findClass(className);
} catch (ClassNotFoundException e) {
try {
converter.classLoader.loadClass(bytes);
} catch (LinkageError ignored) {}
}
}
cw.visitEnd(); cw.visitEnd();
return cw.toByteArray(); return cw.toByteArray();
} }

View File

@ -1,11 +1,13 @@
package de.dhbwstuttgart.bytecode; package de.dhbwstuttgart.bytecode;
import de.dhbwstuttgart.syntaxtree.statement.Break;
import de.dhbwstuttgart.target.tree.TargetGeneric; import de.dhbwstuttgart.target.tree.TargetGeneric;
import de.dhbwstuttgart.target.tree.type.*; import de.dhbwstuttgart.target.tree.type.*;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import java.sql.Array;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -33,6 +35,36 @@ public class FunNGenerator {
public static class GenericParameters { public static class GenericParameters {
int start; int start;
public List<TargetType> parameters = new ArrayList<>(); public List<TargetType> parameters = new ArrayList<>();
final String descriptor;
public final List<TargetType> inParams;
public final List<TargetType> realParams;
public GenericParameters(List<TargetType> params, int numReturns) {
this.realParams = params;
this.inParams = flattenTypeParams(params);
var type = new TargetRefType(FunNGenerator.getSuperClassName(params.size() - 1, numReturns), params);
descriptor = applyDescriptor(type, this);
}
private static List<TargetType> flattenTypeParams(List<TargetType> params) {
var res = new ArrayList<TargetType>();
for (var param : params) {
if (param instanceof TargetSpecializedType tspec) {
res.addAll(flattenTypeParams(tspec.params()));
} else {
res.add(param);
}
}
return res;
}
public TargetType getReturnType() {
return FunNGenerator.getReturnType(realParams);
}
public List<TargetType> getArguments() {
return FunNGenerator.getArguments(realParams);
}
} }
private static String applyDescriptor(TargetType type, GenericParameters gep) { private static String applyDescriptor(TargetType type, GenericParameters gep) {
@ -69,7 +101,7 @@ public class FunNGenerator {
return applyNameDescriptor(type).replace("/", "$").replace(";", "$_$"); return applyNameDescriptor(type).replace("/", "$").replace(";", "$_$");
} }
public static byte[] generateSuperBytecode(int numberArguments) { public static byte[] generateSuperBytecode(int numberArguments, int numReturnTypes) {
StringBuilder superFunNClassSignature = new StringBuilder("<"); StringBuilder superFunNClassSignature = new StringBuilder("<");
StringBuilder superFunNMethodSignature = new StringBuilder("("); StringBuilder superFunNMethodSignature = new StringBuilder("(");
StringBuilder superFunNMethodDescriptor = new StringBuilder("("); StringBuilder superFunNMethodDescriptor = new StringBuilder("(");
@ -80,30 +112,34 @@ public class FunNGenerator {
superFunNMethodDescriptor.append(objectSignature); superFunNMethodDescriptor.append(objectSignature);
} }
superFunNClassSignature.append(String.format("%s:%s>%s", returnGeneric, objectSignature, objectSignature)); superFunNClassSignature.append(String.format("%s:%s>%s", returnGeneric, objectSignature, objectSignature));
superFunNMethodSignature.append(String.format(")T%s;", returnGeneric)); if (numReturnTypes > 0) {
superFunNMethodDescriptor.append(String.format(")%s", objectSignature)); superFunNMethodSignature.append(String.format(")T%s;", returnGeneric));
superFunNMethodDescriptor.append(String.format(")%s", objectSignature));
} else {
superFunNMethodSignature.append(")V");
superFunNMethodDescriptor.append(")V");
}
System.out.println(superFunNMethodSignature); System.out.println(superFunNMethodSignature);
ClassWriter classWriter = new ClassWriter(0); ClassWriter classWriter = new ClassWriter(0);
MethodVisitor methodVisitor; MethodVisitor methodVisitor;
classWriter.visit(bytecodeVersion, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, getSuperClassName(numberArguments), superFunNClassSignature.toString(), objectSuperType, null); classWriter.visit(bytecodeVersion, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, getSuperClassName(numberArguments, numReturnTypes), superFunNClassSignature.toString(), objectSuperType, null);
methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, methodName, superFunNMethodDescriptor.toString(), superFunNMethodSignature.toString(), null); methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, methodName, superFunNMethodDescriptor.toString(), superFunNMethodSignature.toString(), null);
methodVisitor.visitEnd(); methodVisitor.visitEnd();
classWriter.visitEnd(); classWriter.visitEnd();
return classWriter.toByteArray(); return classWriter.toByteArray();
} }
public static String getSuperClassName(int numberArguments) { public static String getSuperClassName(int numberArguments, int returnArguments) {
return String.format("Fun%d$$", numberArguments); return returnArguments > 0 ? String.format("Fun%d$$", numberArguments) : String.format("FunVoid%d$$", numberArguments);
} }
public static byte[] generateSpecializedBytecode(List<TargetType> argumentTypes, TargetType returnType, GenericParameters gep) { public static byte[] generateSpecializedBytecode(GenericParameters gep, List<String> superInterfaces) {
List<TargetType> parameters = Stream var argumentTypes = gep.getArguments();
.concat(argumentTypes.stream(), Stream.of(returnType)) var returnType = gep.getReturnType();
.toList();
StringBuilder funNClassSignature = new StringBuilder(objectSignature + applyDescriptor(new TargetRefType(getSuperClassName(argumentTypes.size()), parameters), gep)); StringBuilder funNClassSignature = new StringBuilder(objectSignature + gep.descriptor);
boolean containsGeneric = false; boolean containsGeneric = false;
String genericSignature = "<"; String genericSignature = "<";
@ -114,10 +150,18 @@ public class FunNGenerator {
genericSignature += ">"; genericSignature += ">";
if (containsGeneric) funNClassSignature.insert(0, genericSignature); if (containsGeneric) funNClassSignature.insert(0, genericSignature);
System.out.println(funNClassSignature.toString());
for (var superInterface : superInterfaces) {
funNClassSignature.append('L');
funNClassSignature.append(superInterface);
funNClassSignature.append(';');
}
var interfaces = new ArrayList<>(superInterfaces);
interfaces.add(getSuperClassName(argumentTypes.size(), returnType != null ? 1 : 0));
ClassWriter classWriter = new ClassWriter(0); ClassWriter classWriter = new ClassWriter(0);
classWriter.visit(bytecodeVersion, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, getSpecializedClassName(argumentTypes, returnType), funNClassSignature.toString(), objectSuperType, new String[]{getSuperClassName(argumentTypes.size())}); classWriter.visit(bytecodeVersion, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, getSpecializedClassName(argumentTypes, returnType), funNClassSignature.toString(), objectSuperType, interfaces.toArray(String[]::new));
classWriter.visitEnd(); classWriter.visitEnd();
return classWriter.toByteArray(); return classWriter.toByteArray();
} }
@ -133,14 +177,24 @@ public class FunNGenerator {
} }
} }
public static String getSpecializedClassName(GenericParameters gep) {
return getSpecializedClassName(gep.getArguments(), gep.getReturnType());
}
public static String getSpecializedClassName(List<TargetType> argumentTypes, TargetType returnType) { public static String getSpecializedClassName(List<TargetType> argumentTypes, TargetType returnType) {
return String.format("Fun%d$$%s%s", var arguments = argumentTypes
.stream()
.map(FunNGenerator::encodeType)
.collect(Collectors.joining());
if (returnType != null)
return String.format("Fun%d$$%s%s",
argumentTypes.size(),
arguments,
encodeType(returnType));
else return String.format("FunVoidImpl%d$$%s",
argumentTypes.size(), argumentTypes.size(),
argumentTypes arguments);
.stream()
.map(FunNGenerator::encodeType)
.collect(Collectors.joining()),
encodeType(returnType));
} }
public static List<TargetType> getArguments(List<TargetType> list) { public static List<TargetType> getArguments(List<TargetType> list) {
@ -151,8 +205,8 @@ public class FunNGenerator {
} }
public static TargetType getReturnType(List<TargetType> list) { public static TargetType getReturnType(List<TargetType> list) {
if(list.size() == 0) if(list.isEmpty())
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
return list.get(list.size() - 1); return list.getLast();
} }
} }

View File

@ -66,7 +66,7 @@ public class JavaTXCompiler {
Boolean resultmodel = true; Boolean resultmodel = true;
public final Map<File, SourceFile> sourceFiles = new HashMap<>(); public final Map<File, SourceFile> sourceFiles = new HashMap<>();
Boolean log = true; //gibt an ob ein Log-File nach System.getProperty("user.dir")+""/logFiles/"" geschrieben werden soll? Boolean log = false; //gibt an ob ein Log-File nach System.getProperty("user.dir")+""/logFiles/"" geschrieben werden soll?
public volatile UnifyTaskModel usedTasks = new UnifyTaskModel(); public volatile UnifyTaskModel usedTasks = new UnifyTaskModel();
public final DirectoryClassLoader classLoader; public final DirectoryClassLoader classLoader;
@ -783,6 +783,7 @@ public class JavaTXCompiler {
}); });
} }
generatedGenerics.put(sf, converter.javaGenerics()); generatedGenerics.put(sf, converter.javaGenerics());
converter.generateFunNTypes();
return generatedClasses; return generatedClasses;
} }

View File

@ -158,7 +158,8 @@ public class FCGenerator {
} }
/** /**
* Tauscht die GTVs in einem Typ gegen die entsprechenden Typen in der übergebenen Map aus. * Tauscht die GTVs in einem Typ gegen die entsprechenden Typen in der übergebenen Map aus auf der direkten Argumentebene.
* Hier sind keine Wildcards zulässig
*/ */
private static class TypeExchanger implements TypeVisitor<RefTypeOrTPHOrWildcardOrGeneric>{ private static class TypeExchanger implements TypeVisitor<RefTypeOrTPHOrWildcardOrGeneric>{
@ -172,7 +173,7 @@ public class FCGenerator {
public RefTypeOrTPHOrWildcardOrGeneric visit(RefType refType) { public RefTypeOrTPHOrWildcardOrGeneric visit(RefType refType) {
List<RefTypeOrTPHOrWildcardOrGeneric> params = new ArrayList<>(); List<RefTypeOrTPHOrWildcardOrGeneric> params = new ArrayList<>();
for(RefTypeOrTPHOrWildcardOrGeneric param : refType.getParaList()){ for(RefTypeOrTPHOrWildcardOrGeneric param : refType.getParaList()){
params.add(param.acceptTV(this)); params.add(param.acceptTV(new TypeExchangerInner(gtvs)));
} }
RefTypeOrTPHOrWildcardOrGeneric ret = new RefType(refType.getName(), params, new NullToken()); RefTypeOrTPHOrWildcardOrGeneric ret = new RefType(refType.getName(), params, new NullToken());
return ret; return ret;
@ -201,4 +202,51 @@ public class FCGenerator {
} }
} }
/**
* Tauscht die GTVs in einem Typ gegen die entsprechenden Typen in der übergebenen Map aus auf den Argumenten der Argumente.
* Hier sind Wildcards zulässig
*/
private static class TypeExchangerInner implements TypeVisitor<RefTypeOrTPHOrWildcardOrGeneric>{
private final HashMap<String, RefTypeOrTPHOrWildcardOrGeneric> gtvs;
TypeExchangerInner(HashMap<String, RefTypeOrTPHOrWildcardOrGeneric> gtvs){
this.gtvs = gtvs;
}
@Override
public RefTypeOrTPHOrWildcardOrGeneric visit(RefType refType) {
List<RefTypeOrTPHOrWildcardOrGeneric> params = new ArrayList<>();
for(RefTypeOrTPHOrWildcardOrGeneric param : refType.getParaList()){
params.add(param.acceptTV(this));
}
RefTypeOrTPHOrWildcardOrGeneric ret = new RefType(refType.getName(), params, new NullToken());
return ret;
}
@Override
public RefTypeOrTPHOrWildcardOrGeneric visit(SuperWildcardType superWildcardType) {
return superWildcardType;
}
@Override
public RefTypeOrTPHOrWildcardOrGeneric visit(TypePlaceholder typePlaceholder) {
throw new DebugException("Dieser Fall darf nicht auftreten");
}
@Override
public RefTypeOrTPHOrWildcardOrGeneric visit(ExtendsWildcardType extendsWildcardType) {
return extendsWildcardType;
}
@Override
public RefTypeOrTPHOrWildcardOrGeneric visit(GenericRefType genericRefType) {
if(! gtvs.containsKey(genericRefType.getParsedName()))
throw new DebugException("Dieser Fall darf nicht auftreten");
return gtvs.get(genericRefType.getParsedName());
}
}
} }

View File

@ -188,9 +188,8 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (!(o instanceof ClassOrInterface other)) return false;
ClassOrInterface that = (ClassOrInterface) o; return Objects.equals(name, other.name);
return Objects.equals(name, that.name);
} }
@Override @Override

View File

@ -34,6 +34,7 @@ public class ASTFactory {
private static final HashMap<java.lang.Class, ClassOrInterface> cache = new HashMap<>(); 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) {
System.out.println(jreClass);
if (cache.containsKey(jreClass)) if (cache.containsKey(jreClass))
return cache.get(jreClass); return cache.get(jreClass);
@ -173,6 +174,7 @@ public class ASTFactory {
superClass = (RefType) createType(java.lang.Object.class); superClass = (RefType) createType(java.lang.Object.class);
} }
List<RefType> implementedInterfaces = new ArrayList<>(); List<RefType> implementedInterfaces = new ArrayList<>();
System.out.println(jreClass);
for (Type jreInterface : jreClass.getGenericInterfaces()) { for (Type jreInterface : jreClass.getGenericInterfaces()) {
implementedInterfaces.add((RefType) createType(jreInterface)); implementedInterfaces.add((RefType) createType(jreInterface));
} }

View File

@ -5,7 +5,6 @@ import de.dhbwstuttgart.bytecode.FunNGenerator;
import de.dhbwstuttgart.core.JavaTXCompiler; import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.environment.ByteArrayClassLoader; import de.dhbwstuttgart.environment.ByteArrayClassLoader;
import de.dhbwstuttgart.environment.IByteArrayClassLoader; import de.dhbwstuttgart.environment.IByteArrayClassLoader;
import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.parser.NullToken; import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.scope.JavaClassName; import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.*; import de.dhbwstuttgart.syntaxtree.*;
@ -18,23 +17,25 @@ import de.dhbwstuttgart.target.tree.expression.*;
import de.dhbwstuttgart.target.tree.type.*; import de.dhbwstuttgart.target.tree.type.*;
import de.dhbwstuttgart.typeinference.result.*; import de.dhbwstuttgart.typeinference.result.*;
import javax.sql.rowset.RowSetWarning;
import java.lang.annotation.Target;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/** /**
* @author dholle * @author dholle
*/ */
public class ASTToTargetAST { public class ASTToTargetAST {
record SignaturePair(TypePlaceholder signature, RefTypeOrTPHOrWildcardOrGeneric parameter) {};
record SignaturePairTarget(TargetType signature, TargetType parameter) {}
public static RefType OBJECT = ASTFactory.createObjectType(); // TODO It would be better if I could call this directly but the hashcode seems to change public static RefType OBJECT = ASTFactory.createObjectType(); // TODO It would be better if I could call this directly but the hashcode seems to change
protected List<Generics> all; protected List<Generics> all;
public Generics generics; public Generics generics;
final Map<ClassOrInterface, Set<GenericTypeVar>> userDefinedGenerics = new HashMap<>(); final Map<ClassOrInterface, Set<GenericTypeVar>> userDefinedGenerics = new HashMap<>();
final Map<Method, Set<SignaturePair>> tphsInMethods = new HashMap<>();
private Method currentMethod;
public final JavaTXCompiler compiler; public final JavaTXCompiler compiler;
@ -56,7 +57,7 @@ public class ASTToTargetAST {
} }
protected IByteArrayClassLoader classLoader; public IByteArrayClassLoader classLoader;
protected SourceFile sourceFile; protected SourceFile sourceFile;
public ASTToTargetAST(List<ResultSet> resultSets) { public ASTToTargetAST(List<ResultSet> resultSets) {
@ -78,6 +79,12 @@ public class ASTToTargetAST {
this.generics = all.get(0); this.generics = all.get(0);
} }
public void addSignaturePair(TypePlaceholder signature, RefTypeOrTPHOrWildcardOrGeneric parameter) {
var set = tphsInMethods.getOrDefault(currentMethod, new HashSet<>());
set.add(new SignaturePair(signature, parameter));
tphsInMethods.put(currentMethod, set);
}
Optional<Method> findMethod(ClassOrInterface owner, String name, List<TargetType> argumentList) { Optional<Method> findMethod(ClassOrInterface owner, String name, List<TargetType> argumentList) {
Optional<Method> method = Optional.empty(); Optional<Method> method = Optional.empty();
while (method.isEmpty()) { while (method.isEmpty()) {
@ -131,6 +138,40 @@ public class ASTToTargetAST {
return ret; return ret;
} }
public List<List<TargetMethod>> groupOverloads(ClassOrInterface input, List<Method> methods) {
var res = new ArrayList<List<TargetMethod>>();
for (var method : methods) {
// Convert all methods
var methodsWithTphs = convert(input, method);
// Then check for methods with the same signature
var mapOfSignatures = new HashMap<TargetMethod.Signature, List<MethodWithTphs>>();
for (var m : methodsWithTphs) {
var methodsWithSameSignature = mapOfSignatures.getOrDefault(m.method.signature(), new ArrayList<>());
methodsWithSameSignature.add(m);
mapOfSignatures.put(m.method.signature(), methodsWithSameSignature);
}
var resMethods = new HashSet<TargetMethod>();
for (var methodsWithSignature : mapOfSignatures.values()) {
outer: for (var m1 : methodsWithSignature) {
for (var m2 : methodsWithSignature) {
for (var i = 0; i < m1.args.size(); i++) {
var arg1 = m1.args.get(i);
var arg2 = m2.args.get(i);
if (arg1.parameter.equals(arg2.parameter)) {
if (isSupertype(arg1.signature, arg2.signature) &&
!arg1.signature.equals(arg2.signature)) continue outer;
}
}
}
resMethods.add(m1.method);
}
}
res.add(resMethods.stream().toList());
}
return res;
}
public TargetStructure convert(ClassOrInterface input) { public TargetStructure convert(ClassOrInterface input) {
Set<TargetGeneric> javaGenerics = new HashSet<>(); Set<TargetGeneric> javaGenerics = new HashSet<>();
Set<TargetGeneric> txGenerics = new HashSet<>(); Set<TargetGeneric> txGenerics = new HashSet<>();
@ -161,11 +202,11 @@ public class ASTToTargetAST {
var superInterfaces = input.getSuperInterfaces().stream().map(clazz -> convert(clazz, generics.javaGenerics)).toList(); var superInterfaces = input.getSuperInterfaces().stream().map(clazz -> convert(clazz, generics.javaGenerics)).toList();
var constructors = input.getConstructors().stream().map(constructor -> this.convert(input, constructor, finalFieldInitializer)).flatMap(List::stream).toList(); var constructors = input.getConstructors().stream().map(constructor -> this.convert(input, constructor, finalFieldInitializer)).flatMap(List::stream).toList();
var fields = input.getFieldDecl().stream().map(this::convert).toList(); var fields = input.getFieldDecl().stream().map(this::convert).toList();
var methods = groupOverloads(input.getMethods()).stream().map(m -> convert(input, m)).flatMap(Set::stream).toList(); var methods = groupOverloads(input, input.getMethods()).stream().flatMap(List::stream).toList();
TargetMethod staticConstructor = null; TargetMethod staticConstructor = null;
if (input.getStaticInitializer().isPresent()) if (input.getStaticInitializer().isPresent())
staticConstructor = this.convert(input, input.getStaticInitializer().get()).stream().findFirst().orElseThrow(); staticConstructor = this.convert(input, input.getStaticInitializer().get()).stream().findFirst().orElseThrow().method;
if (input instanceof Record) if (input instanceof Record)
return new TargetRecord(input.getModifiers(), input.getClassName(), javaGenerics, txGenerics, superInterfaces, constructors, staticConstructor, fields, methods); return new TargetRecord(input.getModifiers(), input.getClassName(), javaGenerics, txGenerics, superInterfaces, constructors, staticConstructor, fields, methods);
@ -206,6 +247,7 @@ public class ASTToTargetAST {
generics = all.get(0); generics = all.get(0);
List<TargetConstructor> result = new ArrayList<>(); List<TargetConstructor> result = new ArrayList<>();
Set<List<MethodParameter>> parameterSet = new HashSet<>(); Set<List<MethodParameter>> parameterSet = new HashSet<>();
this.currentMethod = input;
for (var s : all) { for (var s : all) {
generics = s; generics = s;
@ -225,56 +267,6 @@ public class ASTToTargetAST {
return result; return result;
} }
/**
* This only considers type patterns, all other methods aren't grouped together
* @param a
* @param b
* @return
*/
private boolean signatureEquals(Method a, Method b) {
if (!a.name.equals(b.name)) return false;
var para = a.getParameterList().getFormalparalist();
var parb = b.getParameterList().getFormalparalist();
if (para.size() != parb.size()) return false;
for (var i = 0; i < para.size(); i++) {
var pa = para.get(i);
var pb = parb.get(i);
if (pa instanceof RecordPattern rpa) {
if (pb instanceof RecordPattern rpb) {
if (rpa.getType().equals(rpb.getType())) continue;
}
return false;
} else if (pa.getType().equals(pb.getType())) {
continue;
}
return false;
}
return true;
}
// TODO Nested patterns
private List<List<Method>> groupOverloads(List<Method> input) {
var done = new HashSet<Method>();
var res = new ArrayList<List<Method>>();
for (var method : input) {
if (done.contains(method)) continue;
var overloads = new ArrayList<Method>();
overloads.add(method);
done.add(method);
for (var method2 : input) {
if (!done.contains(method2) && signatureEquals(method, method2)) {
done.add(method2);
overloads.add(method2);
}
}
res.add(overloads);
}
return res;
}
private String encodeName(String name, ParameterList params) { private String encodeName(String name, ParameterList params) {
var res = new StringBuilder(); var res = new StringBuilder();
res.append(name); res.append(name);
@ -290,9 +282,9 @@ public class ASTToTargetAST {
return res.toString(); return res.toString();
} }
private Set<TargetMethod> convert(ClassOrInterface clazz, List<Method> overloadedMethods) { private List<TargetMethod> convert(ClassOrInterface clazz, List<Method> overloadedMethods) {
if (overloadedMethods.size() == 1) { if (overloadedMethods.size() == 1) {
return convert(clazz, overloadedMethods.getFirst()); return convert(clazz, overloadedMethods.getFirst()).stream().map(m -> m.method()).toList();
} }
var methods = new ArrayList<Method>(); var methods = new ArrayList<Method>();
for (var method : overloadedMethods) { for (var method : overloadedMethods) {
@ -329,10 +321,11 @@ public class ASTToTargetAST {
var entryPoint = new Method(template.modifier, template.name, template.getReturnType(), params, block, template.getGenerics(), new NullToken()); var entryPoint = new Method(template.modifier, template.name, template.getReturnType(), params, block, template.getGenerics(), new NullToken());
res.add(entryPoint); // TODO*/ res.add(entryPoint); // TODO*/
var res = new HashSet<TargetMethod>(); var res = new ArrayList<TargetMethod>();
for (var method : methods) { for (var method : methods) {
var overloads = convert(clazz, method); var overloads = convert(clazz, method);
for (var overload : overloads) { for (var m : overloads) {
var overload = m.method;
if (res.contains(overload)) throw new CodeGenException("Duplicate method found: " + overload.name() + " with signature " + overload.signature().getSignature()); if (res.contains(overload)) throw new CodeGenException("Duplicate method found: " + overload.name() + " with signature " + overload.signature().getSignature());
res.add(overload); res.add(overload);
} }
@ -381,10 +374,12 @@ public class ASTToTargetAST {
}).findFirst(); }).findFirst();
} }
private Set<TargetMethod> convert(ClassOrInterface currentClass, Method method) { record MethodWithTphs(TargetMethod method, List<SignaturePairTarget> args) {}
generics = all.get(0);
Set<TargetMethod> result = new HashSet<>(); private List<MethodWithTphs> convert(ClassOrInterface currentClass, Method method) {
Set<List<MethodParameter>> parameterSet = new HashSet<>(); generics = all.getFirst();
List<MethodWithTphs> result = new ArrayList<>();
this.currentMethod = method;
for (var s : all) { for (var s : all) {
generics = s; generics = s;
@ -402,19 +397,18 @@ public class ASTToTargetAST {
} }
} }
List<MethodParameter> finalParams = params; List<MethodParameter> txParams = convert(method.getParameterList(), this.generics.txGenerics);
if (parameterSet.stream().noneMatch(p -> p.equals(finalParams))) {
List<MethodParameter> txParams = convert(method.getParameterList(), this.generics.txGenerics);
var javaMethodGenerics = collectMethodGenerics(currentClass, generics.javaGenerics(), javaGenerics, method); var javaMethodGenerics = collectMethodGenerics(currentClass, generics.javaGenerics(), javaGenerics, method);
var txMethodGenerics = collectMethodGenerics(currentClass, generics.txGenerics(), txGenerics, method); var txMethodGenerics = collectMethodGenerics(currentClass, generics.txGenerics(), txGenerics, method);
var javaSignature = new TargetMethod.Signature(javaMethodGenerics, params, returnType); var javaSignature = new TargetMethod.Signature(javaMethodGenerics, params, returnType);
var txSignature = new TargetMethod.Signature(txMethodGenerics, txParams, convert(method.getReturnType(), this.generics.txGenerics)); var txSignature = new TargetMethod.Signature(txMethodGenerics, txParams, convert(method.getReturnType(), this.generics.txGenerics));
var newMethod = new TargetMethod(method.modifier, method.name, convert(method.block), javaSignature, txSignature); var newMethod = new TargetMethod(method.modifier, method.name, convert(method.block), javaSignature, txSignature);
result.add(newMethod);
parameterSet.add(params); var concreteParams = tphsInMethods.getOrDefault(method, new HashSet<>()).stream().map(sig -> new SignaturePairTarget(convert(sig.signature), convert(sig.parameter))).toList();
}
result.add(new MethodWithTphs(newMethod, concreteParams));
} }
return result; return result;
@ -486,10 +480,59 @@ public class ASTToTargetAST {
} }
var filteredParams = new ArrayList<TargetType>(); var filteredParams = new ArrayList<TargetType>();
for (var i = 0; i < newParams.size(); i++) { for (var i = 0; i < newParams.size(); i++) {
if (gep.parameters.get(i) != null) if (i < gep.inParams.size() && gep.inParams.get(i) != null)
filteredParams.add(newParams.get(i)); filteredParams.add(newParams.get(i));
} }
return TargetFunNType.fromParams(params, filteredParams); return TargetFunNType.fromParams(params, filteredParams, gep.getReturnType() != null ? 1 : 0);
}
private boolean isSubtype(TargetType test, TargetType other) {
var testClass = compiler.getClass(new JavaClassName(test.name()));
var otherClass = compiler.getClass(new JavaClassName(other.name()));
if (testClass == null) return false;
while (testClass != null) {
if (testClass.equals(otherClass)) return true;
if (testClass.getClassName().equals(new JavaClassName("java.lang.Object"))) break;
testClass = compiler.getClass(testClass.getSuperClass().getName());
}
return false;
}
private boolean isSupertype(TargetType test, TargetType other) {
return isSubtype(other, test);
}
private boolean isSubtype(FunNGenerator.GenericParameters test, FunNGenerator.GenericParameters other) {
if (test.getArguments().size() != other.getArguments().size()) return false;
if (!isSubtype(test.getReturnType(), other.getReturnType())) return false;
for (int i = 0; i < test.getArguments().size(); i++) {
var arg1 = test.getArguments().get(i);
var arg2 = other.getArguments().get(i);
if (!isSupertype(arg1, arg2)) return false;
}
return true;
}
public void generateFunNTypes() {
for (var entry : usedFunN.entrySet()) {
var gep = entry.getValue();
var superInterfaces = usedFunN.values().stream()
.filter(g -> !g.equals(gep))
.filter(genericParameters -> isSubtype(gep, genericParameters))
.map(FunNGenerator::getSpecializedClassName)
.toList();
var code = FunNGenerator.generateSpecializedBytecode(gep, superInterfaces);
try {
classLoader.findClass(entry.getKey());
} catch (ClassNotFoundException e) {
try {
classLoader.loadClass(code);
} catch (LinkageError ignored) {}
}
auxiliaries.put(entry.getKey(), code);
}
} }
protected TargetType convert(RefTypeOrTPHOrWildcardOrGeneric input, GenerateGenerics generics) { protected TargetType convert(RefTypeOrTPHOrWildcardOrGeneric input, GenerateGenerics generics) {
@ -504,17 +547,16 @@ public class ASTToTargetAST {
} }
var params = refType.getParaList().stream().map(type -> { var params = refType.getParaList().stream().map(type -> {
var res = convert(type, generics); return convert(type, generics);
if (res == null) res = new TargetRefType("java.lang.Void");
return res;
}).toList(); }).toList();
if (name.matches("Fun\\d+\\$\\$")) { // TODO This seems like a bad idea if (name.matches("Fun\\d+\\$\\$")) { // TODO This seems like a bad idea
var className = FunNGenerator.getSpecializedClassName(FunNGenerator.getArguments(params), FunNGenerator.getReturnType(params)); var returnType = FunNGenerator.getReturnType(params);
var className = FunNGenerator.getSpecializedClassName(FunNGenerator.getArguments(params), returnType);
if (!usedFunNSuperTypes.contains(params.size())) { if (!usedFunNSuperTypes.contains(params.size())) {
usedFunNSuperTypes.add(params.size()); usedFunNSuperTypes.add(params.size());
var code = FunNGenerator.generateSuperBytecode(params.size() - 1); var code = FunNGenerator.generateSuperBytecode(params.size() - 1, returnType != null ? 1 : 0);
var superClassName = FunNGenerator.getSuperClassName(params.size() - 1); var superClassName = FunNGenerator.getSuperClassName(params.size() - 1, returnType != null ? 1 : 0);
try { try {
classLoader.findClass(superClassName); classLoader.findClass(superClassName);
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
@ -526,17 +568,8 @@ public class ASTToTargetAST {
} }
FunNGenerator.GenericParameters gep = null; FunNGenerator.GenericParameters gep = null;
if (!usedFunN.containsKey(className)) { if (!usedFunN.containsKey(className)) {
gep = new FunNGenerator.GenericParameters(); gep = new FunNGenerator.GenericParameters(params, returnType != null ? 1 : 0);
var code = FunNGenerator.generateSpecializedBytecode(FunNGenerator.getArguments(params), FunNGenerator.getReturnType(params), gep);
try {
classLoader.findClass(className);
} catch (ClassNotFoundException e) {
try {
classLoader.loadClass(code);
} catch (LinkageError ignored) {}
}
usedFunN.put(className, gep); usedFunN.put(className, gep);
auxiliaries.put(className, code);
} else { } else {
gep = usedFunN.get(className); gep = usedFunN.get(className);
} }

View File

@ -652,14 +652,12 @@ public abstract class GenerateGenerics {
} }
void normalize(Set<Pair> result, Set<Pair> classGenerics, Set<TPH> usedTphs) { void normalize(Set<Pair> result, Set<Pair> classGenerics, Set<TPH> usedTphs) {
outer: for (var p1 : new HashSet<>(result)) {
for (var tph : usedTphs) { if (p1 instanceof PairLT ptph && ptph.left.resolve().equals(ptph.right.resolve()))
for (var p1 : new HashSet<>(result)) { result.remove(p1); // TODO This is a bit strange
if (p1 instanceof PairLT ptph && ptph.left.equals(ptph.right)) }
result.remove(p1); // TODO This is a bit strange
if (p1.left.equals(tph)) continue outer;
}
for (var tph : usedTphs) {
if (classGenerics == null || classGenerics.stream().noneMatch((pair) -> pair.left.equals(tph))) if (classGenerics == null || classGenerics.stream().noneMatch((pair) -> pair.left.equals(tph)))
addToPairs(result, new PairEQ(tph, ASTToTargetAST.OBJECT)); addToPairs(result, new PairEQ(tph, ASTToTargetAST.OBJECT));
} }

View File

@ -208,6 +208,11 @@ public class StatementToTargetExpression implements ASTVisitor {
var isPrivate = false; var isPrivate = false;
var signature = methodCall.signatureArguments().stream().map(converter::convert).toList(); var signature = methodCall.signatureArguments().stream().map(converter::convert).toList();
// Add used TPHs to containing method
for (var i = 0; i < methodCall.signatureArguments().size(); i++) {
converter.addSignaturePair(methodCall.signatureArguments().get(i), methodCall.arglist.getArguments().get(i).getType());
}
var receiverClass = converter.compiler.getClass(receiverName); var receiverClass = converter.compiler.getClass(receiverName);
if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver && expressionReceiver.expr instanceof This) { if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver && expressionReceiver.expr instanceof This) {
if (receiverClass == null) throw new DebugException("Class " + receiverName + " does not exist!"); if (receiverClass == null) throw new DebugException("Class " + receiverName + " does not exist!");

View File

@ -4,15 +4,29 @@ import de.dhbwstuttgart.bytecode.FunNGenerator;
import java.util.List; import java.util.List;
public record TargetFunNType(String name, List<TargetType> params) implements TargetSpecializedType { public record TargetFunNType(String name, List<TargetType> funNParams, List<TargetType> params, int returnArguments) implements TargetSpecializedType {
public static TargetFunNType fromParams(List<TargetType> params) { public static TargetFunNType fromParams(List<TargetType> params, int returnArguments) {
return fromParams(params, params); return fromParams(params, params, returnArguments);
} }
public static TargetFunNType fromParams(List<TargetType> params, List<TargetType> realParams) { public static TargetFunNType fromParams(List<TargetType> params, List<TargetType> realParams, int returnArguments) {
var name = FunNGenerator.getSpecializedClassName(FunNGenerator.getArguments(params), FunNGenerator.getReturnType(params)); var name = FunNGenerator.getSpecializedClassName(FunNGenerator.getArguments(params), FunNGenerator.getReturnType(params));
return new TargetFunNType(name, realParams); return new TargetFunNType(name, params, realParams, returnArguments);
}
public String toMethodDescriptor() {
var res = "(";
for (var i = 0; i < funNParams.size() - 1; i++) {
res += "Ljava/lang/Object;";
}
res += ")";
if (returnArguments > 0) {
res += "Ljava/lang/Object;";
} else {
res += "V";
}
return res;
} }
@Override @Override

View File

@ -53,19 +53,17 @@ public sealed interface TargetType
}; };
} }
static TargetType toTargetType(Class<?> clazz) { static TargetType toWrapper(TargetType f) {
if (clazz.isPrimitive()) { if (f.equals(boolean_)) return Boolean;
if (clazz.equals(boolean.class)) return boolean_; if (f.equals(char_)) return Char;
if (clazz.equals(char.class)) return char_; if (f.equals(byte_)) return Byte;
if (clazz.equals(byte.class)) return byte_; if (f.equals(short_)) return Short;
if (clazz.equals(short.class)) return short_; if (f.equals(int_)) return Integer;
if (clazz.equals(int.class)) return int_; if (f.equals(long_)) return Long;
if (clazz.equals(long.class)) return long_; if (f.equals(float_)) return Float;
if (clazz.equals(float.class)) return float_; if (f.equals(double_)) return Double;
if (clazz.equals(double.class)) return double_;
} return f;
if (clazz.equals(void.class)) return null;
return new TargetRefType(clazz.getName());
} }
String toSignature(); String toSignature();

View File

@ -877,8 +877,6 @@ public class TYPEStmt implements StatementVisitor {
var clazz = interestingClasses.get(j); var clazz = interestingClasses.get(j);
for (int k = 0; k < clazz.getConstructors().size(); k++) { for (int k = 0; k < clazz.getConstructors().size(); k++) {
var constructor = clazz.getConstructors().get(k); var constructor = clazz.getConstructors().get(k);
//Erster Constraint wahrscheinlich unnötig.
constraintsSet.addUndConstraint(new Pair( clazz.getFieldDecl().get(i).getType(), constructor.getParameterList().getParameterAt(i).getType(), PairOperator.SMALLERDOT, loc(constructor.getParameterList().getParameterAt(i).getOffset())));
constraintsSet.addUndConstraint(new Pair(supPattern.getType(), constructor.getParameterList().getParameterAt(i).getType(), PairOperator.SMALLERDOT, loc(constructor.getParameterList().getParameterAt(i).getOffset()))); constraintsSet.addUndConstraint(new Pair(supPattern.getType(), constructor.getParameterList().getParameterAt(i).getType(), PairOperator.SMALLERDOT, loc(constructor.getParameterList().getParameterAt(i).getOffset())));
} }

View File

@ -66,7 +66,9 @@ public class AllgemeinTest {
//String className = "WildcardList"; //String className = "WildcardList";
//String className = "List"; //String className = "List";
//String className = "Box"; //String className = "Box";
String className = "GenBox"; //String className = "GenBox";
//String className = "InnerInf";
String className = "Foo";
//PL 2019-10-24: genutzt fuer unterschiedliche Tests //PL 2019-10-24: genutzt fuer unterschiedliche Tests
path = System.getProperty("user.dir")+"/resources/AllgemeinTest/" + className + ".jav"; path = System.getProperty("user.dir")+"/resources/AllgemeinTest/" + className + ".jav";
//path = System.getProperty("user.dir")+"/src/test/resources/AllgemeinTest/Overloading_Generics.jav"; //path = System.getProperty("user.dir")+"/src/test/resources/AllgemeinTest/Overloading_Generics.jav";

View File

@ -696,18 +696,25 @@ public class TestComplete {
@Ignore("Not implemented") @Ignore("Not implemented")
@Test @Test
public void testRecordList() throws Exception { public void testRecordList() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "recordList.jav"); var classFiles = generateClassFiles(new ByteArrayClassLoader(), "SwitchCaseHeritageDetection.jav");
var clazz = classFiles.get("Nil"); var clazz = classFiles.get("SwitchCaseHeritageDetection");
var clazzAbst = classFiles.get("NumberOrText");
var clazzStringer = classFiles.get("Text");
var clazzNumber = classFiles.get("Number");
var instance = clazz.getDeclaredConstructor().newInstance(); var instance = clazz.getDeclaredConstructor().newInstance();
var swtch = clazz.getDeclaredMethod("m", Object.class); var swtch = clazz.getDeclaredMethod("main", Object.class);
//var record = classFiles.get("Rec"); var record = classFiles.get("Cons");
//var ctor = record.getDeclaredConstructor(Object.class, Object.class);
//var r1 = ctor.newInstance(1, 1);
assertEquals(swtch.invoke(instance, null), 2);
var ctor = record.getDeclaredConstructor(Integer.class, clazzAbst.getConstructor().newInstance().getClass());
var r1 = ctor.newInstance(1, clazzStringer.getConstructor().newInstance());
var r2 = ctor.newInstance(1, clazzNumber.getConstructor().newInstance());
assertEquals(swtch.invoke(instance, r1), "Second Element is a Text");
assertEquals(swtch.invoke(instance, r2), "Second Element is a Number");
} }
@Ignore("Not implemented") @Ignore("Not implemented")
@ -898,13 +905,6 @@ public class TestComplete {
var instance = clazz.getDeclaredConstructor().newInstance(); var instance = clazz.getDeclaredConstructor().newInstance();
} }
@Test
public void testLamRunnable() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "LamRunnable.jav");
var clazz = classFiles.get("LamRunnable");
var instance = clazz.getDeclaredConstructor().newInstance();
}
@Test @Test
public void testAccess() throws Exception { public void testAccess() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Access.jav"); var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Access.jav");
@ -1164,6 +1164,13 @@ public class TestComplete {
var instance = clazz.getDeclaredConstructor().newInstance(); var instance = clazz.getDeclaredConstructor().newInstance();
} }
@Test
public void testBug332() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug332.jav");
var clazz = classFiles.get("Bug332");
var instance = clazz.getDeclaredConstructor().newInstance();
}
@Test @Test
public void testBug333() throws Exception { public void testBug333() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug333.jav"); var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug333.jav");
@ -1171,6 +1178,14 @@ public class TestComplete {
var instance = clazz.getDeclaredConstructor().newInstance(); var instance = clazz.getDeclaredConstructor().newInstance();
} }
@Test
public void testBug337() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug337.jav");
var clazz = classFiles.get("Bug337");
var instance = clazz.getDeclaredConstructor().newInstance();
clazz.getDeclaredMethod("main").invoke(instance);
}
@Test @Test
public void testBug338() throws Exception { public void testBug338() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug338.jav"); var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug338.jav");

View File

@ -22,7 +22,6 @@ import static org.junit.Assert.*;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import java.io.File; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -61,6 +60,8 @@ public class TestCodegen {
} }
}).collect(Collectors.toMap(Class::getName, Function.identity()))); }).collect(Collectors.toMap(Class::getName, Function.identity())));
converter.generateFunNTypes();
for (var entry : converter.auxiliaries.entrySet()) { for (var entry : converter.auxiliaries.entrySet()) {
writeClassFile(entry.getKey(), entry.getValue()); writeClassFile(entry.getKey(), entry.getValue());
} }
@ -84,9 +85,6 @@ public class TestCodegen {
public static Class<?> generateClass(TargetStructure clazz, IByteArrayClassLoader classLoader, ASTToTargetAST converter) throws IOException { public static Class<?> generateClass(TargetStructure clazz, IByteArrayClassLoader classLoader, ASTToTargetAST converter) throws IOException {
Codegen codegen = new Codegen(clazz, converter.compiler, converter); Codegen codegen = new Codegen(clazz, converter.compiler, converter);
var code = codegen.generate(); var code = codegen.generate();
try (FileOutputStream fos = new FileOutputStream("C:\\Users\\ruben\\Desktop\\asd\\test.class")) {
fos.write(code);
}
writeClassFile(clazz.qualifiedName().getClassName(), code); writeClassFile(clazz.qualifiedName().getClassName(), code);
return classLoader.loadClass(code); return classLoader.loadClass(code);
} }
@ -108,6 +106,8 @@ public class TestCodegen {
} }
}).collect(Collectors.toMap(Class::getName, Function.identity())); }).collect(Collectors.toMap(Class::getName, Function.identity()));
converter.generateFunNTypes();
for (var entry : converter.auxiliaries.entrySet()) { for (var entry : converter.auxiliaries.entrySet()) {
writeClassFile(entry.getKey(), entry.getValue()); writeClassFile(entry.getKey(), entry.getValue());
} }
@ -220,19 +220,19 @@ public class TestCodegen {
public void testClassicSwitch() throws Exception { public void testClassicSwitch() throws Exception {
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC , new JavaClassName("SwitchClassic")); var targetClass = new TargetClass(Opcodes.ACC_PUBLIC , new JavaClassName("SwitchClassic"));
targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "switchClassic", List.of(new MethodParameter(TargetType.Integer, "i")), TargetType.Integer, new TargetBlock(List.of( targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "switchClassic", List.of(new MethodParameter(TargetType.Integer, "i")), TargetType.Integer, new TargetBlock(List.of(
new TargetVarDecl(TargetType.Integer, "res", null), new TargetVarDecl(TargetType.Integer, "res", null),
new TargetSwitch(new TargetLocalVar(TargetType.Integer, "i"), List.of( new TargetSwitch(new TargetLocalVar(TargetType.Integer, "i"), List.of(
new TargetSwitch.Case(List.of(new TargetLiteral.IntLiteral(10)), new TargetBlock( new TargetSwitch.Case(List.of(new TargetLiteral.IntLiteral(10)), new TargetBlock(
List.of(new TargetAssign(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "res"), new TargetLiteral.IntLiteral(0)), new TargetBreak()) List.of(new TargetAssign(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "res"), new TargetLiteral.IntLiteral(0)), new TargetBreak())
)), )),
new TargetSwitch.Case(List.of(new TargetLiteral.IntLiteral(15), new TargetLiteral.IntLiteral(20)), new TargetBlock(List.of())), new TargetSwitch.Case(List.of(new TargetLiteral.IntLiteral(15), new TargetLiteral.IntLiteral(20)), new TargetBlock(List.of())),
new TargetSwitch.Case(List.of(new TargetLiteral.IntLiteral(30)), new TargetBlock( new TargetSwitch.Case(List.of(new TargetLiteral.IntLiteral(30)), new TargetBlock(
List.of(new TargetAssign(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "res"), new TargetLiteral.IntLiteral(1)), new TargetBreak()) List.of(new TargetAssign(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "res"), new TargetLiteral.IntLiteral(1)), new TargetBreak())
)) ))
), new TargetSwitch.Case(new TargetBlock( ), new TargetSwitch.Case(new TargetBlock(
List.of(new TargetAssign(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "res"), new TargetLiteral.IntLiteral(2)), new TargetBreak()) List.of(new TargetAssign(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "res"), new TargetLiteral.IntLiteral(2)), new TargetBreak())
), false)), ), false)),
new TargetReturn(new TargetLocalVar(TargetType.Integer, "res")) new TargetReturn(new TargetLocalVar(TargetType.Integer, "res"))
))); )));
var clazz = generateClass(targetClass, new ByteArrayClassLoader()); var clazz = generateClass(targetClass, new ByteArrayClassLoader());
@ -248,22 +248,22 @@ public class TestCodegen {
public void testTypeSwitch() throws Exception { public void testTypeSwitch() throws Exception {
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, new JavaClassName("SwitchEnhanced")); var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, new JavaClassName("SwitchEnhanced"));
targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "switchType", List.of(new MethodParameter(TargetType.Object, "obj")), TargetType.Integer, new TargetBlock(List.of( targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "switchType", List.of(new MethodParameter(TargetType.Object, "obj")), TargetType.Integer, new TargetBlock(List.of(
new TargetReturn(new TargetSwitch(new TargetLocalVar(TargetType.Object, "obj"), List.of( new TargetReturn(new TargetSwitch(new TargetLocalVar(TargetType.Object, "obj"), List.of(
new TargetSwitch.Case(List.of(new TargetTypePattern(TargetType.String, "aString")), new TargetBlock( new TargetSwitch.Case(List.of(new TargetTypePattern(TargetType.String, "aString")), new TargetBlock(
List.of(new TargetYield(new TargetLiteral.IntLiteral(0))) List.of(new TargetYield(new TargetLiteral.IntLiteral(0)))
), false), ), false),
new TargetSwitch.Case(List.of( new TargetSwitch.Case(List.of(
new TargetGuard(new TargetTypePattern(TargetType.Integer, "i"), new TargetBinaryOp.Less(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "i"), new TargetLiteral.IntLiteral(10))) new TargetGuard(new TargetTypePattern(TargetType.Integer, "i"), new TargetBinaryOp.Less(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "i"), new TargetLiteral.IntLiteral(10)))
), new TargetBlock( ), new TargetBlock(
List.of(new TargetLiteral.IntLiteral(3)) List.of(new TargetLiteral.IntLiteral(3))
), true), ), true),
new TargetSwitch.Case(List.of(new TargetTypePattern(TargetType.Integer, "anInteger")), new TargetBlock( new TargetSwitch.Case(List.of(new TargetTypePattern(TargetType.Integer, "anInteger")), new TargetBlock(
List.of(new TargetLiteral.IntLiteral(1)) List.of(new TargetLiteral.IntLiteral(1))
), true) ), true)
), new TargetSwitch.Case(new TargetBlock( ), new TargetSwitch.Case(new TargetBlock(
List.of(new TargetLiteral.IntLiteral(2)) List.of(new TargetLiteral.IntLiteral(2))
), true), TargetType.Integer) ), true), TargetType.Integer)
)))); ))));
var clazz = generateClass(targetClass, new ByteArrayClassLoader()); var clazz = generateClass(targetClass, new ByteArrayClassLoader());
var m = clazz.getDeclaredMethod("switchType", Object.class); var m = clazz.getDeclaredMethod("switchType", Object.class);
assertEquals(m.invoke(null, "String"), 0); assertEquals(m.invoke(null, "String"), 0);
@ -277,7 +277,7 @@ public class TestCodegen {
public void testLambda() throws Exception { public void testLambda() throws Exception {
var classLoader = new ByteArrayClassLoader(); var classLoader = new ByteArrayClassLoader();
// var fun = classLoader.loadClass(Path.of(System.getProperty("user.dir"), "src/test/java/targetast/Fun1$$.class")); // var fun = classLoader.loadClass(Path.of(System.getProperty("user.dir"), "src/test/java/targetast/Fun1$$.class"));
var interfaceType = TargetFunNType.fromParams(List.of(TargetType.Integer)); var interfaceType = TargetFunNType.fromParams(List.of(TargetType.Integer), 1);
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, new JavaClassName("CGLambda")); var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, new JavaClassName("CGLambda"));
targetClass.addConstructor(Opcodes.ACC_PUBLIC, List.of(), new TargetBlock(List.of(new TargetMethodCall(null, new TargetSuper(TargetType.Object), List.of(), TargetType.Object, "<init>", false, false, false)))); targetClass.addConstructor(Opcodes.ACC_PUBLIC, List.of(), new TargetBlock(List.of(new TargetMethodCall(null, new TargetSuper(TargetType.Object), List.of(), TargetType.Object, "<init>", false, false, false))));