Compare commits
23 Commits
cc8f36d3ec
...
96eb504174
Author | SHA1 | Date | |
---|---|---|---|
|
96eb504174 | ||
|
4f0162ba64 | ||
|
6e1198ab3d | ||
7785c2d0aa | |||
a654f55deb | |||
|
7037bdf9ef | ||
|
d9860497df | ||
|
fdffc11580 | ||
|
c10de35ca2 | ||
|
56b73332c0 | ||
|
bdcd5ea3cf | ||
edafbbc5a0 | |||
ba8810e5df | |||
63493ed0f7 | |||
|
4dba867f9e | ||
|
06caf0ff66 | ||
ec92b5d5e1 | |||
091a6b8f1f | |||
60a1f3b220 | |||
7e6aeaf728 | |||
|
5d03995f10 | ||
|
1bc58573c7 | ||
|
3d2b935c60 |
10
resources/AllgemeinTest/Bar.java
Normal file
10
resources/AllgemeinTest/Bar.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
public class Bar{
|
||||||
|
|
||||||
|
void visit(Object o){
|
||||||
|
System.out.println("Object");
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit(Bla f){
|
||||||
|
System.out.println("Foo");
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
6
resources/AllgemeinTest/Foo.jav
Normal file
6
resources/AllgemeinTest/Foo.jav
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
public class Foo{
|
||||||
|
|
||||||
|
public accept(Bar b){
|
||||||
|
b.visit(this);
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +0,0 @@
|
|||||||
class Box<A> {
|
|
||||||
void m(A a) { }
|
|
||||||
}
|
|
15
resources/bytecode/javFiles/Bug332.jav
Normal file
15
resources/bytecode/javFiles/Bug332.jav
Normal 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 {
|
||||||
|
}
|
10
resources/bytecode/javFiles/Bug337.jav
Normal file
10
resources/bytecode/javFiles/Bug337.jav
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
22
resources/bytecode/javFiles/SwitchCaseHeritageDetection.jav
Normal file
22
resources/bytecode/javFiles/SwitchCaseHeritageDetection.jav
Normal 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";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -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";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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!");
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
@ -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())));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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";
|
||||||
|
@ -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");
|
||||||
|
@ -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))));
|
||||||
|
Loading…
Reference in New Issue
Block a user