forked from JavaTX/JavaCompilerCore
Some changes in how overload resolution works
This commit is contained in:
parent
1be27746e3
commit
4654ecacaf
@ -2,12 +2,12 @@ import java.lang.Runnable;
|
|||||||
import java.lang.String;
|
import java.lang.String;
|
||||||
import java.lang.System;
|
import java.lang.System;
|
||||||
|
|
||||||
public class LamRunnable{
|
public class LambdaRunnable {
|
||||||
|
|
||||||
public LamRunnable(){
|
public LambdaRunnable(){
|
||||||
|
|
||||||
|
|
||||||
Runnable lam = () -> {var a;};
|
Runnable lam = () -> {var a;};
|
||||||
lam.run();
|
lam.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,8 @@ 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<>();
|
||||||
@ -747,14 +749,19 @@ 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(lambda.type(), params.toArray(TargetType[]::new));
|
var descriptor = TargetMethod.getDescriptor(state.contextType, params.toArray(TargetType[]::new));
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
for (var capture : lambda.captures()) {
|
for (var capture : lambda.captures()) {
|
||||||
var pattern = (TargetTypePattern) capture.pattern();
|
var pattern = (TargetTypePattern) capture.pattern();
|
||||||
mv.visitVarInsn(ALOAD, state.scope.get(pattern.name()).index);
|
mv.visitVarInsn(ALOAD, state.scope.get(pattern.name()).index);
|
||||||
}
|
}
|
||||||
|
|
||||||
mv.visitInvokeDynamicInsn("apply", descriptor, bootstrap, Type.getType(desugared), handle, Type.getType(TargetMethod.getDescriptor(impl.signature().returnType(), lambda.params().stream().map(mp -> mp.pattern().type()).toArray(TargetType[]::new))));
|
String methodName;
|
||||||
|
var intf = compiler.getClass(new JavaClassName(state.contextType.name()));
|
||||||
|
if (intf == null) methodName = "apply"; // TODO Weird fallback logic here
|
||||||
|
else methodName = intf.getMethods().stream().filter(m -> Modifier.isAbstract(m.modifier)).findFirst().orElseThrow().getName();
|
||||||
|
|
||||||
|
mv.visitInvokeDynamicInsn(methodName, descriptor, bootstrap, Type.getType(desugared), handle, Type.getType(TargetMethod.getDescriptor(impl.signature().returnType(), lambda.params().stream().map(mp -> mp.pattern().type()).toArray(TargetType[]::new))));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generate(State state, TargetExpression expr) {
|
private void generate(State state, TargetExpression expr) {
|
||||||
@ -781,7 +788,10 @@ 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:
|
||||||
@ -825,7 +835,11 @@ 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());
|
||||||
var local = state.scope.get(localVar.name());
|
var local = state.scope.get(localVar.name());
|
||||||
@ -836,7 +850,12 @@ public class Codegen {
|
|||||||
var fieldType = dot.type();
|
var fieldType = dot.type();
|
||||||
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);
|
||||||
if (dot.isStatic())
|
if (dot.isStatic())
|
||||||
@ -934,7 +953,10 @@ public class Codegen {
|
|||||||
}
|
}
|
||||||
case TargetReturn ret: {
|
case TargetReturn ret: {
|
||||||
if (ret.expression() != null && state.returnType != null) {
|
if (ret.expression() != null && state.returnType != null) {
|
||||||
|
var ctype = state.contextType;
|
||||||
|
state.contextType = state.returnType;
|
||||||
generate(state, ret.expression());
|
generate(state, ret.expression());
|
||||||
|
state.contextType = ctype;
|
||||||
convertTo(state, ret.expression().type(), state.returnType);
|
convertTo(state, ret.expression().type(), state.returnType);
|
||||||
boxPrimitive(state, state.returnType);
|
boxPrimitive(state, state.returnType);
|
||||||
mv.visitInsn(ARETURN);
|
mv.visitInsn(ARETURN);
|
||||||
@ -981,9 +1003,12 @@ 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);
|
||||||
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
|
||||||
|
@ -742,7 +742,7 @@ public class JavaTXCompiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized Map<JavaClassName, byte[]> generateBytecode(SourceFile sf, List<ResultSet> typeInferenceResult) {
|
public synchronized Map<JavaClassName, byte[]> generateBytecode(SourceFile sf, List<ResultSet> typeInferenceResult) {
|
||||||
var converter = new ASTToTargetAST(typeInferenceResult, sf, classLoader);
|
var converter = new ASTToTargetAST(this, typeInferenceResult, sf, classLoader);
|
||||||
var generatedClasses = new HashMap<JavaClassName, byte[]>();
|
var generatedClasses = new HashMap<JavaClassName, byte[]>();
|
||||||
for (var clazz : sf.getClasses()) {
|
for (var clazz : sf.getClasses()) {
|
||||||
var codegen = new Codegen(converter.convert(clazz), this);
|
var codegen = new Codegen(converter.convert(clazz), this);
|
||||||
|
@ -8,6 +8,7 @@ public class ThisCall extends MethodCall
|
|||||||
{
|
{
|
||||||
public ThisCall(Receiver receiver, ArgumentList arglist, int offset)
|
public ThisCall(Receiver receiver, ArgumentList arglist, int offset)
|
||||||
{
|
{
|
||||||
|
// TODO What is this?
|
||||||
super(null, null, null, null, null, null, null);
|
super(null, null, null, null, null, null, null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package de.dhbwstuttgart.target.generate;
|
package de.dhbwstuttgart.target.generate;
|
||||||
|
|
||||||
import de.dhbwstuttgart.bytecode.FunNGenerator;
|
import de.dhbwstuttgart.bytecode.FunNGenerator;
|
||||||
|
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.exceptions.NotImplementedException;
|
||||||
@ -31,6 +32,8 @@ public class ASTToTargetAST {
|
|||||||
protected Generics generics;
|
protected Generics generics;
|
||||||
final Map<ClassOrInterface, Set<GenericTypeVar>> userDefinedGenerics = new HashMap<>();
|
final Map<ClassOrInterface, Set<GenericTypeVar>> userDefinedGenerics = new HashMap<>();
|
||||||
|
|
||||||
|
public final JavaTXCompiler compiler;
|
||||||
|
|
||||||
protected ClassOrInterface currentClass; // TODO This is only needed because of SuperCall, maybe there's
|
protected ClassOrInterface currentClass; // TODO This is only needed because of SuperCall, maybe there's
|
||||||
|
|
||||||
public List<GenericsResult> txGenerics() {
|
public List<GenericsResult> txGenerics() {
|
||||||
@ -55,10 +58,14 @@ public class ASTToTargetAST {
|
|||||||
protected SourceFile sourceFile;
|
protected SourceFile sourceFile;
|
||||||
|
|
||||||
public ASTToTargetAST(List<ResultSet> resultSets) {
|
public ASTToTargetAST(List<ResultSet> resultSets) {
|
||||||
this(resultSets, null, new ByteArrayClassLoader());
|
this(null, resultSets);
|
||||||
|
}
|
||||||
|
public ASTToTargetAST(JavaTXCompiler compiler, List<ResultSet> resultSets) {
|
||||||
|
this(compiler, resultSets, null, new ByteArrayClassLoader());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ASTToTargetAST(List<ResultSet> resultSets, SourceFile sourceFile, IByteArrayClassLoader classLoader) {
|
public ASTToTargetAST(JavaTXCompiler compiler, List<ResultSet> resultSets, SourceFile sourceFile, IByteArrayClassLoader classLoader) {
|
||||||
|
this.compiler = compiler;
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
this.sourceFile = sourceFile;
|
this.sourceFile = sourceFile;
|
||||||
|
|
||||||
@ -82,7 +89,7 @@ public class ASTToTargetAST {
|
|||||||
for (var i = 0; i < pars.size(); i++) {
|
for (var i = 0; i < pars.size(); i++) {
|
||||||
var type1 = convert(pars.get(i).getType(), generics.javaGenerics);
|
var type1 = convert(pars.get(i).getType(), generics.javaGenerics);
|
||||||
var type2 = convert(arguments.get(i).getType(), generics.javaGenerics);
|
var type2 = convert(arguments.get(i).getType(), generics.javaGenerics);
|
||||||
if (type2 instanceof TargetGenericType && type1 instanceof TargetGenericType)
|
if (type1 instanceof TargetGenericType)
|
||||||
return true;
|
return true;
|
||||||
if (!type1.equals(type2))
|
if (!type1.equals(type2))
|
||||||
return false;
|
return false;
|
||||||
|
@ -4,13 +4,15 @@ import de.dhbwstuttgart.exceptions.NotImplementedException;
|
|||||||
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
|
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
|
||||||
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
||||||
import de.dhbwstuttgart.syntaxtree.*;
|
import de.dhbwstuttgart.syntaxtree.*;
|
||||||
|
import de.dhbwstuttgart.syntaxtree.factory.PrimitiveMethodsGenerator;
|
||||||
import de.dhbwstuttgart.syntaxtree.statement.*;
|
import de.dhbwstuttgart.syntaxtree.statement.*;
|
||||||
import de.dhbwstuttgart.syntaxtree.type.*;
|
import de.dhbwstuttgart.syntaxtree.type.*;
|
||||||
import de.dhbwstuttgart.target.tree.MethodParameter;
|
import de.dhbwstuttgart.target.tree.MethodParameter;
|
||||||
import de.dhbwstuttgart.target.tree.expression.*;
|
import de.dhbwstuttgart.target.tree.expression.*;
|
||||||
import de.dhbwstuttgart.target.tree.type.*;
|
import de.dhbwstuttgart.target.tree.type.*;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import javax.swing.text.html.Option;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import java.util.stream.StreamSupport;
|
import java.util.stream.StreamSupport;
|
||||||
@ -169,67 +171,34 @@ public class StatementToTargetExpression implements ASTVisitor {
|
|||||||
return to.equals(from);
|
return to.equals(from);
|
||||||
}
|
}
|
||||||
|
|
||||||
Method findMethod(JavaClassName className, String name, List<TargetType> args) {
|
Optional<Method> findMethod(JavaClassName className, String name, ArgumentList args) {
|
||||||
if (converter.sourceFile != null /*&& converter.sourceFile.imports.contains(className)*/) {
|
return converter.findMethod(converter.compiler.getClass(className), name, args);
|
||||||
try {
|
|
||||||
var clazz = converter.classLoader.loadClass(className.toString());
|
|
||||||
|
|
||||||
outer: for (var method : clazz.getMethods()) {
|
|
||||||
if (method.getParameterTypes().length != args.size())
|
|
||||||
continue;
|
|
||||||
if (!method.getName().equals(name))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (var i = 0; i < method.getParameterTypes().length; i++) {
|
|
||||||
var param = method.getParameterTypes()[i];
|
|
||||||
var arg = args.get(i);
|
|
||||||
if (param.isPrimitive()) {
|
|
||||||
arg = TargetType.toPrimitive(arg);
|
|
||||||
}
|
|
||||||
if (!convertsTo(arg, Objects.requireNonNull(TargetType.toTargetType(param))))
|
|
||||||
continue outer;
|
|
||||||
}
|
|
||||||
return method;
|
|
||||||
}
|
|
||||||
} catch (ClassNotFoundException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (converter.sourceFile != null) { // TODO Multiple source files
|
|
||||||
var thisClass = converter.sourceFile.KlassenVektor.stream().filter(classOrInterface -> classOrInterface.getClassName().equals(className)).findFirst();
|
|
||||||
|
|
||||||
if (thisClass.isPresent()) {
|
|
||||||
var superClass = thisClass.get().getSuperClass().getName();
|
|
||||||
return findMethod(superClass, name, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(MethodCall methodCall) {
|
public void visit(MethodCall methodCall) {
|
||||||
var receiverType = converter.convert(methodCall.receiver.getType());
|
var receiverType = converter.convert(methodCall.receiver.getType());
|
||||||
var isFunNType = receiverType instanceof TargetFunNType;
|
var isFunNType = receiverType instanceof TargetFunNType;
|
||||||
|
|
||||||
var returnType = isFunNType ? TargetType.Object : converter.convert(methodCall.signature.get(methodCall.signature.size() - 1));
|
var returnType = isFunNType ? TargetType.Object : converter.convert(methodCall.signature.get(methodCall.signature.size() - 1));
|
||||||
var receiverName = new JavaClassName(converter.convert(methodCall.receiver.getType()).name());
|
var receiverName = new JavaClassName(converter.convert(methodCall.receiver.getType()).name());
|
||||||
var argList = methodCall.signature.stream().map(converter::convert).toList();
|
var argList = methodCall.signature.stream().map(converter::convert).toList();
|
||||||
argList = argList.subList(0, argList.size() - 1);
|
argList = argList.subList(0, argList.size() - 1);
|
||||||
|
|
||||||
Method foundMethod = null;
|
Method foundMethod;
|
||||||
|
var receiverClass = converter.currentClass;
|
||||||
if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver && expressionReceiver.expr instanceof This) {
|
if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver && expressionReceiver.expr instanceof This) {
|
||||||
var thisMethod = converter.findMethod(converter.currentClass, methodCall.name, methodCall.arglist);
|
var thisMethod = converter.findMethod(converter.currentClass, methodCall.name, methodCall.arglist);
|
||||||
if (thisMethod.isEmpty()) {
|
foundMethod = thisMethod.orElseGet(() -> findMethod(converter.currentClass.getSuperClass().getName(), methodCall.name, methodCall.arglist).orElseThrow());
|
||||||
foundMethod = findMethod(converter.currentClass.getSuperClass().getName(), methodCall.name, argList);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
foundMethod = findMethod(receiverName, methodCall.name, argList);
|
receiverClass = converter.compiler.getClass(receiverName);
|
||||||
|
foundMethod = findMethod(receiverName, methodCall.name, methodCall.arglist).orElseThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (foundMethod != null) {
|
returnType = converter.convert(foundMethod.getReturnType());
|
||||||
returnType = TargetType.toTargetType(foundMethod.getReturnType());
|
argList = foundMethod.getParameterList().getFormalparalist().stream().map(e -> converter.convert(e.getType())).toList();
|
||||||
argList = Stream.of(foundMethod.getParameterTypes()).map(TargetType::toTargetType).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
result = new TargetMethodCall(converter.convert(methodCall.getType()), returnType, argList, converter.convert(methodCall.receiver), methodCall.getArgumentList().getArguments().stream().map(converter::convert).toList(), receiverType, methodCall.name, false, isFunNType);
|
result = new TargetMethodCall(converter.convert(methodCall.getType()), returnType, argList, converter.convert(methodCall.receiver), methodCall.getArgumentList().getArguments().stream().map(converter::convert).toList(), receiverType, methodCall.name, Modifier.isStatic(foundMethod.modifier), receiverClass.isInterface());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -47,7 +47,7 @@ public class TestCodegen {
|
|||||||
var result = new HashMap<String, Class<?>>();
|
var result = new HashMap<String, Class<?>>();
|
||||||
for (var file : filenames) {
|
for (var file : filenames) {
|
||||||
var sourceFile = compiler.sourceFiles.get(file);
|
var sourceFile = compiler.sourceFiles.get(file);
|
||||||
var converter = new ASTToTargetAST(resultSet, sourceFile, classLoader);
|
var converter = new ASTToTargetAST(compiler, resultSet, sourceFile, classLoader);
|
||||||
var classes = compiler.sourceFiles.get(file).getClasses();
|
var classes = compiler.sourceFiles.get(file).getClasses();
|
||||||
|
|
||||||
result.putAll(classes.stream().map(cli -> {
|
result.putAll(classes.stream().map(cli -> {
|
||||||
@ -86,7 +86,7 @@ public class TestCodegen {
|
|||||||
var resultSet = compiler.typeInference();
|
var resultSet = compiler.typeInference();
|
||||||
|
|
||||||
var sourceFile = compiler.sourceFiles.get(file);
|
var sourceFile = compiler.sourceFiles.get(file);
|
||||||
var converter = new ASTToTargetAST(resultSet, sourceFile, classLoader);
|
var converter = new ASTToTargetAST(compiler, resultSet, sourceFile, classLoader);
|
||||||
var classes = compiler.sourceFiles.get(file).getClasses();
|
var classes = compiler.sourceFiles.get(file).getClasses();
|
||||||
|
|
||||||
var result = classes.stream().map(cli -> {
|
var result = classes.stream().map(cli -> {
|
||||||
|
Loading…
Reference in New Issue
Block a user