diff --git a/pom.xml b/pom.xml
index d9dbc114..120f4204 100644
--- a/pom.xml
+++ b/pom.xml
@@ -54,8 +54,8 @@ http://maven.apache.org/maven-v4_0_0.xsd">
3.11.0
--enable-preview
-
- 22
+
+ 21
diff --git a/resources/AllgemeinTest/Bar.java b/resources/AllgemeinTest/Bar.java
new file mode 100644
index 00000000..5d82fbb2
--- /dev/null
+++ b/resources/AllgemeinTest/Bar.java
@@ -0,0 +1,10 @@
+public class Bar{
+
+ void visit(Object o){
+ System.out.println("Object");
+ }
+
+ void visit(Bla f){
+ System.out.println("Foo");
+ }
+}
\ No newline at end of file
diff --git a/resources/AllgemeinTest/Foo.jav b/resources/AllgemeinTest/Foo.jav
new file mode 100644
index 00000000..d8195c0f
--- /dev/null
+++ b/resources/AllgemeinTest/Foo.jav
@@ -0,0 +1,6 @@
+public class Foo{
+
+ public accept(Bar b){
+ b.visit(this);
+ }
+}
\ No newline at end of file
diff --git a/resources/bytecode/javFiles/LamRunnable.jav b/resources/bytecode/javFiles/LamRunnable.jav
deleted file mode 100644
index d0da84cc..00000000
--- a/resources/bytecode/javFiles/LamRunnable.jav
+++ /dev/null
@@ -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();
- }
-}
-
\ No newline at end of file
diff --git a/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java b/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java
index 8df566b9..578e2821 100644
--- a/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java
+++ b/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java
@@ -5,6 +5,8 @@ import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
+import de.dhbwstuttgart.syntaxtree.Method;
+import de.dhbwstuttgart.syntaxtree.Pattern;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.target.generate.ASTToTargetAST;
import de.dhbwstuttgart.target.generate.StatementToTargetExpression;
@@ -31,15 +33,21 @@ public class Codegen {
private final JavaTXCompiler compiler;
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) {
this.clazz = clazz;
this.className = clazz.qualifiedName().getClassName();
- this.cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) {
- @Override
- protected ClassLoader getClassLoader() {
- return compiler.getClassLoader();
- }
- };
+ this.cw = new CustomClassWriter();
this.compiler = compiler;
this.converter = converter;
}
@@ -82,8 +90,6 @@ public class Codegen {
int localCounter;
MethodVisitor mv;
TargetType returnType;
- // This is used to remember the type from lambda expressions
- TargetType contextType;
Stack breakStack = new Stack<>();
Stack switchResultValue = new Stack<>();
@@ -270,13 +276,43 @@ public class Codegen {
mv.visitInsn(I2F);
else if (dest.equals(TargetType.Double))
mv.visitInsn(I2D);
+ } else if (isFunctionalInterface(source) && isFunctionalInterface(dest) &&
+ !(source instanceof TargetFunNType && dest instanceof TargetFunNType)) {
+ boxFunctionalInterface(state, source, dest);
} else if (!(dest instanceof TargetGenericType)) {
- boxPrimitive(state, source);
+ //boxPrimitive(state, source);
mv.visitTypeInsn(CHECKCAST, dest.getInternalName());
unboxPrimitive(state, dest);
}
}
+ record TypePair(TargetType from, TargetType to) {}
+ private Map 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, "", "(" + 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) {
if (left.equals(TargetType.String) || right.equals(TargetType.String)) {
return TargetType.String;
@@ -727,41 +763,15 @@ public class Codegen {
var mv = state.mv;
String methodName = "apply";
- TargetMethod.Signature signature = null;
-
- if (!(state.contextType instanceof TargetFunNType ctx)) {
- var intf = compiler.getClass(new JavaClassName(state.contextType.name()));
- if (intf != null) {
- var method = intf.getMethods().stream().filter(m -> Modifier.isAbstract(m.modifier)).findFirst().orElseThrow();
- methodName = method.getName();
- var methodParams = new ArrayList();
- 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()
- );
+ TargetMethod.Signature signature = new TargetMethod.Signature(Set.of(),
+ lambda.signature().parameters().stream().map(
+ par -> par.withType(TargetType.Object)).toList(),
+ lambda.signature().returnType() != null ? TargetType.Object : null);
var parameters = new ArrayList<>(lambda.captures());
parameters.addAll(signature.parameters());
var implSignature = new TargetMethod.Signature(Set.of(), parameters, lambda.signature().returnType());
- // Normalize
-
TargetMethod impl;
if (lambdas.containsKey(lambda)) {
impl = lambdas.get(lambda);
@@ -782,7 +792,6 @@ public class Codegen {
params.add(new TargetRefType(clazz.qualifiedName().getClassName()));
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);
for (var index = 0; index < lambda.captures().size(); index++) {
var capture = lambda.captures().get(index);
@@ -792,9 +801,42 @@ public class Codegen {
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()));
}
+ 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) {
var mv = state.mv;
switch (expr) {
@@ -819,10 +861,7 @@ public class Codegen {
break;
}
case TargetCast cast:
- var ctx = state.contextType;
- state.contextType = cast.type();
generate(state, cast.expr());
- state.contextType = ctx;
convertTo(state, cast.expr().type(), cast.type());
break;
case TargetInstanceOf instanceOf:
@@ -867,10 +906,7 @@ public class Codegen {
case TargetAssign assign: {
switch (assign.left()) {
case TargetLocalVar localVar -> {
- var ctype = state.contextType;
- state.contextType = localVar.type();
generate(state, assign.right());
- state.contextType = ctype;
convertTo(state, assign.right().type(), localVar.type());
boxPrimitive(state, localVar.type());
@@ -883,10 +919,7 @@ public class Codegen {
if (!(dot.left() instanceof TargetThis && dot.isStatic()))
generate(state, dot.left());
- var ctype = state.contextType;
- state.contextType = fieldType;
generate(state, assign.right());
- state.contextType = ctype;
convertTo(state, assign.right().type(), fieldType);
boxPrimitive(state, fieldType);
@@ -1016,29 +1049,12 @@ public class Codegen {
case TargetReturn ret: {
if (ret.expression() != null && state.returnType != null) {
if (state.returnType instanceof TargetPrimitiveType) {
- var ctype = state.contextType;
- state.contextType = state.returnType;
generate(state, ret.expression());
- state.contextType = ctype;
unboxPrimitive(state, state.returnType);
- if (state.returnType.equals(TargetType.boolean_)
- || 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);
+ mv.visitInsn(findReturnCode(state.returnType));
} else {
- var ctype = state.contextType;
- state.contextType = state.returnType;
generate(state, ret.expression());
- state.contextType = ctype;
boxPrimitive(state, ret.expression().type());
convertTo(state, ret.expression().type(), state.returnType);
mv.visitInsn(ARETURN);
@@ -1089,12 +1105,10 @@ public class Codegen {
for (var i = 0; i < call.args().size(); i++) {
var e = call.args().get(i);
var arg = call.parameterTypes().get(i);
- var ctype = state.contextType;
- state.contextType = arg;
generate(state, e);
+ convertTo(state, e.type(), arg);
if (!(arg instanceof TargetPrimitiveType))
boxPrimitive(state, e.type());
- state.contextType = ctype;
}
var descriptor = call.getDescriptor();
if (call.owner() instanceof TargetFunNType) // Decay FunN
@@ -1597,6 +1611,85 @@ public class Codegen {
if (clazz instanceof TargetRecord)
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, "", "(" + pair.from.toDescriptor() + ")V", null, null);
+ ctor.visitVarInsn(ALOAD, 0);
+ ctor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()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();
return cw.toByteArray();
}
diff --git a/src/main/java/de/dhbwstuttgart/bytecode/FunNGenerator.java b/src/main/java/de/dhbwstuttgart/bytecode/FunNGenerator.java
index 819f5a3e..9b6bd15f 100644
--- a/src/main/java/de/dhbwstuttgart/bytecode/FunNGenerator.java
+++ b/src/main/java/de/dhbwstuttgart/bytecode/FunNGenerator.java
@@ -34,13 +34,12 @@ public class FunNGenerator {
int start;
public List parameters = new ArrayList<>();
final String descriptor;
- final List inParams;
+ public final List inParams;
- public GenericParameters(List params) {
+ public GenericParameters(List params, int numReturns) {
this.inParams = params;
- var type = new TargetRefType(FunNGenerator.getSuperClassName(params.size() - 1), params);
+ var type = new TargetRefType(FunNGenerator.getSuperClassName(params.size() - 1, numReturns), params);
descriptor = applyDescriptor(type, this);
- System.out.println(this.parameters);
}
public TargetType getReturnType() {
@@ -86,7 +85,7 @@ public class FunNGenerator {
return applyNameDescriptor(type).replace("/", "$").replace(";", "$_$");
}
- public static byte[] generateSuperBytecode(int numberArguments) {
+ public static byte[] generateSuperBytecode(int numberArguments, int numReturnTypes) {
StringBuilder superFunNClassSignature = new StringBuilder("<");
StringBuilder superFunNMethodSignature = new StringBuilder("(");
StringBuilder superFunNMethodDescriptor = new StringBuilder("(");
@@ -97,22 +96,27 @@ public class FunNGenerator {
superFunNMethodDescriptor.append(objectSignature);
}
superFunNClassSignature.append(String.format("%s:%s>%s", returnGeneric, objectSignature, objectSignature));
- superFunNMethodSignature.append(String.format(")T%s;", returnGeneric));
- superFunNMethodDescriptor.append(String.format(")%s", objectSignature));
+ if (numReturnTypes > 0) {
+ superFunNMethodSignature.append(String.format(")T%s;", returnGeneric));
+ superFunNMethodDescriptor.append(String.format(")%s", objectSignature));
+ } else {
+ superFunNMethodSignature.append(")V");
+ superFunNMethodDescriptor.append(")V");
+ }
System.out.println(superFunNMethodSignature);
ClassWriter classWriter = new ClassWriter(0);
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.visitEnd();
classWriter.visitEnd();
return classWriter.toByteArray();
}
- public static String getSuperClassName(int numberArguments) {
- return String.format("Fun%d$$", numberArguments);
+ public static String getSuperClassName(int numberArguments, int returnArguments) {
+ return returnArguments > 0 ? String.format("Fun%d$$", numberArguments) : String.format("FunVoid%d$$", numberArguments);
}
public static byte[] generateSpecializedBytecode(GenericParameters gep, List superInterfaces) {
@@ -138,7 +142,7 @@ public class FunNGenerator {
}
var interfaces = new ArrayList<>(superInterfaces);
- interfaces.add(getSuperClassName(argumentTypes.size()));
+ interfaces.add(getSuperClassName(argumentTypes.size(), returnType != null ? 1 : 0));
ClassWriter classWriter = new ClassWriter(0);
classWriter.visit(bytecodeVersion, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, getSpecializedClassName(argumentTypes, returnType), funNClassSignature.toString(), objectSuperType, interfaces.toArray(String[]::new));
@@ -162,13 +166,19 @@ public class FunNGenerator {
}
public static String getSpecializedClassName(List 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
- .stream()
- .map(FunNGenerator::encodeType)
- .collect(Collectors.joining()),
- encodeType(returnType));
+ arguments);
}
public static List getArguments(List list) {
@@ -179,8 +189,8 @@ public class FunNGenerator {
}
public static TargetType getReturnType(List list) {
- if(list.size() == 0)
+ if(list.isEmpty())
throw new IndexOutOfBoundsException();
- return list.get(list.size() - 1);
+ return list.getLast();
}
}
diff --git a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java
index ed11515c..3e477142 100644
--- a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java
+++ b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java
@@ -66,7 +66,7 @@ public class JavaTXCompiler {
Boolean resultmodel = true;
public final Map 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 final DirectoryClassLoader classLoader;
diff --git a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java
index 4f4474a5..37df41fa 100644
--- a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java
+++ b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java
@@ -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{
@@ -172,6 +173,7 @@ public class FCGenerator {
public RefTypeOrTPHOrWildcardOrGeneric visit(RefType refType) {
List params = new ArrayList<>();
for(RefTypeOrTPHOrWildcardOrGeneric param : refType.getParaList()){
+ //params.add(param.acceptTV(new TypeExchangerInner(gtvs)));
params.add(param.acceptTV(this));
}
RefTypeOrTPHOrWildcardOrGeneric ret = new RefType(refType.getName(), params, new NullToken());
@@ -201,4 +203,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{
+
+ private final HashMap gtvs;
+
+ TypeExchangerInner(HashMap gtvs){
+ this.gtvs = gtvs;
+ }
+
+ @Override
+ public RefTypeOrTPHOrWildcardOrGeneric visit(RefType refType) {
+ List 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());
+ }
+
+ }
+
}
diff --git a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java
index d6e73ba7..36fa146b 100644
--- a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java
+++ b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java
@@ -57,7 +57,7 @@ public class ASTToTargetAST {
}
- protected IByteArrayClassLoader classLoader;
+ public IByteArrayClassLoader classLoader;
protected SourceFile sourceFile;
public ASTToTargetAST(List resultSets) {
@@ -480,10 +480,10 @@ public class ASTToTargetAST {
}
var filteredParams = new ArrayList();
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));
}
- return TargetFunNType.fromParams(params, filteredParams);
+ return TargetFunNType.fromParams(params, filteredParams, gep.getReturnType() != null ? 1 : 0);
}
private boolean isSubtype(TargetType test, TargetType other) {
@@ -547,17 +547,16 @@ public class ASTToTargetAST {
}
var params = refType.getParaList().stream().map(type -> {
- var res = convert(type, generics);
- if (res == null) res = new TargetRefType("java.lang.Void");
- return res;
+ return convert(type, generics);
}).toList();
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())) {
usedFunNSuperTypes.add(params.size());
- var code = FunNGenerator.generateSuperBytecode(params.size() - 1);
- var superClassName = FunNGenerator.getSuperClassName(params.size() - 1);
+ var code = FunNGenerator.generateSuperBytecode(params.size() - 1, returnType != null ? 1 : 0);
+ var superClassName = FunNGenerator.getSuperClassName(params.size() - 1, returnType != null ? 1 : 0);
try {
classLoader.findClass(superClassName);
} catch (ClassNotFoundException e) {
@@ -569,7 +568,7 @@ public class ASTToTargetAST {
}
FunNGenerator.GenericParameters gep = null;
if (!usedFunN.containsKey(className)) {
- gep = new FunNGenerator.GenericParameters(params);
+ gep = new FunNGenerator.GenericParameters(params, returnType != null ? 1 : 0);
usedFunN.put(className, gep);
} else {
gep = usedFunN.get(className);
diff --git a/src/main/java/de/dhbwstuttgart/target/tree/type/TargetFunNType.java b/src/main/java/de/dhbwstuttgart/target/tree/type/TargetFunNType.java
index f35f1043..db6343de 100644
--- a/src/main/java/de/dhbwstuttgart/target/tree/type/TargetFunNType.java
+++ b/src/main/java/de/dhbwstuttgart/target/tree/type/TargetFunNType.java
@@ -4,15 +4,29 @@ import de.dhbwstuttgart.bytecode.FunNGenerator;
import java.util.List;
-public record TargetFunNType(String name, List params) implements TargetSpecializedType {
+public record TargetFunNType(String name, List funNParams, List params, int returnArguments) implements TargetSpecializedType {
- public static TargetFunNType fromParams(List params) {
- return fromParams(params, params);
+ public static TargetFunNType fromParams(List params, int returnArguments) {
+ return fromParams(params, params, returnArguments);
}
- public static TargetFunNType fromParams(List params, List realParams) {
+ public static TargetFunNType fromParams(List params, List realParams, int returnArguments) {
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
diff --git a/src/main/java/de/dhbwstuttgart/target/tree/type/TargetType.java b/src/main/java/de/dhbwstuttgart/target/tree/type/TargetType.java
index 1cb57f90..f34e84ef 100644
--- a/src/main/java/de/dhbwstuttgart/target/tree/type/TargetType.java
+++ b/src/main/java/de/dhbwstuttgart/target/tree/type/TargetType.java
@@ -53,19 +53,17 @@ public sealed interface TargetType
};
}
- static TargetType toTargetType(Class> clazz) {
- if (clazz.isPrimitive()) {
- if (clazz.equals(boolean.class)) return boolean_;
- if (clazz.equals(char.class)) return char_;
- if (clazz.equals(byte.class)) return byte_;
- if (clazz.equals(short.class)) return short_;
- if (clazz.equals(int.class)) return int_;
- if (clazz.equals(long.class)) return long_;
- if (clazz.equals(float.class)) return float_;
- if (clazz.equals(double.class)) return double_;
- }
- if (clazz.equals(void.class)) return null;
- return new TargetRefType(clazz.getName());
+ static TargetType toWrapper(TargetType f) {
+ if (f.equals(boolean_)) return Boolean;
+ if (f.equals(char_)) return Char;
+ if (f.equals(byte_)) return Byte;
+ if (f.equals(short_)) return Short;
+ if (f.equals(int_)) return Integer;
+ if (f.equals(long_)) return Long;
+ if (f.equals(float_)) return Float;
+ if (f.equals(double_)) return Double;
+
+ return f;
}
String toSignature();
diff --git a/src/test/java/AllgemeinTest.java b/src/test/java/AllgemeinTest.java
index 461dd557..428d9623 100644
--- a/src/test/java/AllgemeinTest.java
+++ b/src/test/java/AllgemeinTest.java
@@ -67,7 +67,8 @@ public class AllgemeinTest {
//String className = "List";
//String className = "Box";
//String className = "GenBox";
- String className = "InnerInf";
+ //String className = "InnerInf";
+ String className = "Foo";
//PL 2019-10-24: genutzt fuer unterschiedliche Tests
path = System.getProperty("user.dir")+"/resources/AllgemeinTest/" + className + ".jav";
//path = System.getProperty("user.dir")+"/src/test/resources/AllgemeinTest/Overloading_Generics.jav";
diff --git a/src/test/java/TestComplete.java b/src/test/java/TestComplete.java
index 5638e64a..c4599e02 100644
--- a/src/test/java/TestComplete.java
+++ b/src/test/java/TestComplete.java
@@ -860,13 +860,6 @@ public class TestComplete {
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
public void testAccess() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Access.jav");
diff --git a/src/test/java/targetast/TestCodegen.java b/src/test/java/targetast/TestCodegen.java
index fb901776..e83c2f95 100644
--- a/src/test/java/targetast/TestCodegen.java
+++ b/src/test/java/targetast/TestCodegen.java
@@ -277,7 +277,7 @@ public class TestCodegen {
public void testLambda() throws Exception {
var classLoader = new ByteArrayClassLoader();
// 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"));
targetClass.addConstructor(Opcodes.ACC_PUBLIC, List.of(), new TargetBlock(List.of(new TargetMethodCall(null, new TargetSuper(TargetType.Object), List.of(), TargetType.Object, "", false, false, false))));