Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 654c8d6df8 | |||
| 30dd045a7c | |||
| 9b762470b5 | |||
| 85ee805a3f | |||
| 523452f437 | |||
| 7051b4335a | |||
| 7daec0a291 | |||
| 653f704265 | |||
| b36ba5e128 | |||
| a43f49cadb | |||
| 69292c37fc | |||
| 218e704272 | |||
| e83e9a041c | |||
| 2f7e4fc1e4 | |||
| 433dcf83c2 |
@@ -0,0 +1,10 @@
|
||||
import java.lang.String;
|
||||
|
||||
public class Bug389 {
|
||||
public swap(f) {
|
||||
return x -> y -> f.apply(y).apply(x);
|
||||
}
|
||||
public swap(f) {
|
||||
return x -> y -> z -> f.apply(z).apply(x).apply(y);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import Bug389;
|
||||
import java.util.List;
|
||||
import java.lang.String;
|
||||
import java.lang.Integer;
|
||||
|
||||
public class Bug389Main {
|
||||
public static main(args) {
|
||||
var func = x -> y -> z -> x + y + z;
|
||||
var swap = new Bug389();
|
||||
swap.swap(func).apply(1).apply(2).apply(3);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
sealed interface List<T> permits Cons, Empty {}
|
||||
public sealed interface List<T> permits Cons, Empty {}
|
||||
|
||||
public record Cons<T>(T a, List<T> l) implements List<T> {}
|
||||
public record Empty<T>() implements List<T> {}
|
||||
public record Tuple<T1, T2>(T1 a, T2 b) {}
|
||||
public record Pair<T1, T2>(T1 a, T2 b) {}
|
||||
|
||||
public class PatternMatching {
|
||||
public zip(Cons(x, xs), Cons(y, ys)) {
|
||||
return new Cons(new Tuple(x, y), zip(xs, ys));
|
||||
return new Cons<>(new Pair<>(x, y), zip(xs, ys));
|
||||
}
|
||||
public zip(Empty x, Empty y) { return new Empty(); }
|
||||
public zip(Empty(), Empty()) { return new Empty<>(); }
|
||||
|
||||
/*public zip(Empty x, Cons y) { return new Empty(); }
|
||||
public zip(Cons x, Empty y) { return new Empty(); }
|
||||
|
||||
@@ -2,18 +2,24 @@ import java.lang.Object;
|
||||
import List;
|
||||
import Cons;
|
||||
import Empty;
|
||||
import Tuple;
|
||||
import Pair;
|
||||
|
||||
public class PatternMatchingJava {
|
||||
public zip(a, b) {
|
||||
public <A, B> Cons<Pair<A, B>> zip(Cons<A> a, Cons<B> b) {
|
||||
switch (a) {
|
||||
case Cons(x, Cons xs) -> {
|
||||
switch (b) {
|
||||
case Cons(y, Cons ys) -> { return new Cons<>(new Tuple<>(x, y), zip(xs, ys)); }
|
||||
case Cons(y, Empty()) -> { return new Empty<>(); }
|
||||
case Cons(y, Cons ys) -> { return new Cons<>(new Pair<>(x, y), zip(xs, ys)); }
|
||||
};
|
||||
}
|
||||
case Cons(x, Empty()) -> { return new Empty<>(); }
|
||||
case Cons(x, Empty xs) -> {
|
||||
switch (b) {
|
||||
case Cons(y, Empty ys) -> { return new Cons<>(new Pair<>(x, y), zip(xs, ys)); }
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
public <A, B> Empty<Pair<A, B>> zip(Empty<A> a, Empty<B>) {
|
||||
return new Empty<>();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
sealed interface List<T> permits Cons, Empty {}
|
||||
public sealed interface List<T> permits Cons, Empty {}
|
||||
|
||||
public record Cons<T>(T a, List<T> l) implements List<T> {}
|
||||
public record Empty<T>() implements List<T> {}
|
||||
public record Tuple<T1, T2>(T1 a, T2 b) {}
|
||||
public record Pair<T1, T2>(T1 a, T2 b) {}
|
||||
@@ -1,7 +1,7 @@
|
||||
import java.lang.Boolean;
|
||||
import java.lang.Object;
|
||||
|
||||
sealed interface List<T> permits Cons, Empty {}
|
||||
public sealed interface List<T> permits Cons, Empty {}
|
||||
|
||||
public record Cons<T>(T a, List<T> l) implements List<T> {}
|
||||
public record Empty<T>() implements List<T> {}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import java.lang.Integer;
|
||||
import java.lang.Number;
|
||||
|
||||
public record R(Number n) {}
|
||||
|
||||
public class PatternMatchingSpecificity {
|
||||
public m(R(Number n)) { return 0; }
|
||||
public m(R(Integer i)) { return 1; }
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import de.dhbwstuttgart.core.JavaTXCompiler;
|
||||
import de.dhbwstuttgart.exceptions.NotImplementedException;
|
||||
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
||||
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
|
||||
import de.dhbwstuttgart.syntaxtree.Pattern;
|
||||
import de.dhbwstuttgart.target.generate.ASTToTargetAST;
|
||||
import de.dhbwstuttgart.target.tree.*;
|
||||
import de.dhbwstuttgart.target.tree.expression.*;
|
||||
@@ -1498,12 +1499,13 @@ public class Codegen {
|
||||
state.exitScope();
|
||||
}
|
||||
|
||||
private void extractField(State state, TargetType type, int i, ClassOrInterface clazz) {
|
||||
private void extractField(State state, TargetType ret, TargetType type, int i, ClassOrInterface clazz) {
|
||||
if (i >= clazz.getFieldDecl().size())
|
||||
throw new CodeGenException("Couldn't find suitable field accessor for '" + type.name() + "'");
|
||||
var field = clazz.getFieldDecl().get(i);
|
||||
var fieldType = converter.convert(field.getType());
|
||||
state.mv.visitMethodInsn(INVOKEVIRTUAL, type.getInternalName(), field.getName(), "()" + fieldType.toDescriptor(), false);
|
||||
if (ret != null) convertTo(state, fieldType, ret);
|
||||
}
|
||||
|
||||
private void bindPattern(State state, TargetType type, TargetPattern pat, Label start, int index, int depth) {
|
||||
@@ -1566,7 +1568,7 @@ public class Codegen {
|
||||
var subPattern = cp.subPatterns().get(i);
|
||||
|
||||
state.mv.visitInsn(DUP);
|
||||
extractField(state, cp.type(), i, clazz);
|
||||
extractField(state, null, cp.type(), i, clazz);
|
||||
|
||||
if (subPattern.type() instanceof TargetRefType || subPattern.type() instanceof TargetExtendsWildcard) {
|
||||
state.mv.visitInsn(DUP);
|
||||
@@ -1668,7 +1670,7 @@ public class Codegen {
|
||||
if (i < cp.subPatterns().size() - 1)
|
||||
state.mv.visitInsn(DUP);
|
||||
|
||||
extractField(state, cp.type(), i, clazz);
|
||||
extractField(state, subPattern.type(), cp.type(), i, clazz);
|
||||
if (subPattern.type() instanceof TargetRefType)
|
||||
state.mv.visitTypeInsn(CHECKCAST, subPattern.type().getInternalName());
|
||||
offset = state.createVariable(subPattern.name(), subPattern.type()).index;
|
||||
|
||||
@@ -20,14 +20,11 @@ import de.dhbwstuttgart.server.SocketFuture;
|
||||
import de.dhbwstuttgart.server.packet.SetAutoclosePacket;
|
||||
import de.dhbwstuttgart.server.packet.UnifyRequestPacket;
|
||||
import de.dhbwstuttgart.server.packet.UnifyResultPacket;
|
||||
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
|
||||
import de.dhbwstuttgart.syntaxtree.GenericTypeVar;
|
||||
import de.dhbwstuttgart.syntaxtree.Method;
|
||||
import de.dhbwstuttgart.syntaxtree.ParameterList;
|
||||
import de.dhbwstuttgart.syntaxtree.SourceFile;
|
||||
import de.dhbwstuttgart.syntaxtree.GenericDeclarationList;
|
||||
import de.dhbwstuttgart.syntaxtree.*;
|
||||
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
|
||||
import de.dhbwstuttgart.syntaxtree.factory.UnifyTypeFactory;
|
||||
import de.dhbwstuttgart.syntaxtree.statement.Block;
|
||||
import de.dhbwstuttgart.syntaxtree.statement.Statement;
|
||||
import de.dhbwstuttgart.syntaxtree.type.ExtendsWildcardType;
|
||||
import de.dhbwstuttgart.syntaxtree.type.GenericRefType;
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefType;
|
||||
@@ -35,9 +32,12 @@ import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||
import de.dhbwstuttgart.syntaxtree.type.SuperWildcardType;
|
||||
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||
import de.dhbwstuttgart.syntaxtree.type.TypeVisitor;
|
||||
import de.dhbwstuttgart.syntaxtree.type.Void;
|
||||
import de.dhbwstuttgart.syntaxtree.visual.ASTTypePrinter;
|
||||
import de.dhbwstuttgart.target.generate.ASTToTargetAST;
|
||||
import de.dhbwstuttgart.target.generate.GenericsResult;
|
||||
import de.dhbwstuttgart.target.tree.*;
|
||||
import de.dhbwstuttgart.target.tree.type.*;
|
||||
import de.dhbwstuttgart.typeinference.constraints.Constraint;
|
||||
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
|
||||
import de.dhbwstuttgart.typeinference.constraints.Pair;
|
||||
@@ -62,6 +62,7 @@ import de.dhbwstuttgart.typeinference.unify.UnifyTaskModel;
|
||||
|
||||
import de.dhbwstuttgart.util.Logger;
|
||||
import java.io.*;
|
||||
import java.lang.Record;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.file.Path;
|
||||
import java.sql.Array;
|
||||
@@ -82,7 +83,9 @@ public class JavaTXCompiler {
|
||||
// public static JavaTXCompiler INSTANCE;
|
||||
final CompilationEnvironment environment;
|
||||
Boolean resultmodel = true;
|
||||
public final Map<File, SourceFile> sourceFiles = new HashMap<>();
|
||||
|
||||
private final List<File> sources;
|
||||
public final Map<File, SourceFile> sourceFiles = new LinkedHashMap<>();
|
||||
public final Set<JavaClassName> input = new HashSet<>();
|
||||
|
||||
public volatile UnifyTaskModel usedTasks = new UnifyTaskModel();
|
||||
@@ -124,7 +127,11 @@ public class JavaTXCompiler {
|
||||
environment = new CompilationEnvironment(sources, classLoader);
|
||||
classPath = path;
|
||||
this.outputPath = outputPath;
|
||||
this.sources = sources;
|
||||
// INSTANCE = this;
|
||||
}
|
||||
|
||||
private List<SourceFileContext> generateSources(List<File> sources) throws IOException, ClassNotFoundException {
|
||||
// TODO This should maybe be moved elsewhere
|
||||
var treeList = new ArrayList<SourceFileContext>(sources.size());
|
||||
for (var s : sources) {
|
||||
@@ -154,11 +161,7 @@ public class JavaTXCompiler {
|
||||
input.add(classRegistry.getName(className));
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < sources.size(); i++) {
|
||||
parse(treeList.get(i), sources.get(i));
|
||||
}
|
||||
// INSTANCE = this;
|
||||
return treeList;
|
||||
}
|
||||
|
||||
private void addSourceFile(File file, SourceFile sf) {
|
||||
@@ -422,43 +425,6 @@ public class JavaTXCompiler {
|
||||
return typeInference(List.of(file));
|
||||
}
|
||||
|
||||
public static String constraintSetToDot(ConstraintSet<Pair> c){
|
||||
|
||||
Iterator<String> colors = List.of(
|
||||
"#FF0000", "#FF7F00", "#FFFF00", "#7FFF00", "#00FF00", "#00FF7F", "#00FFFF", "#007FFF",
|
||||
"#0000FF", "#7F00FF", "#FF00FF", "#FF007F", "#BF0000", "#BF5F00", "#BFBF00", "#5FBF00",
|
||||
"#00BF00", "#00BF5F", "#00BFBF", "#005FBF", "#0000BF", "#5F00BF", "#BF00BF", "#BF005F",
|
||||
"#800000", "#804000", "#808000", "#408000", "#008000", "#008040", "#008080", "#004080",
|
||||
"#000080", "#400080", "#800080", "#800040", "#FF4040", "#FF8040", "#FFFF40", "#80FF40",
|
||||
"#40FF40", "#40FF80", "#40FFFF", "#4080FF", "#4040FF", "#8040FF", "#FF40FF", "#FF4080",
|
||||
"#BF4040", "#BF8040", "#BFBF40", "#80BF40", "#40BF40", "#40BF80", "#40BFBF", "#4080BF",
|
||||
"#4040BF", "#8040BF", "#BF40BF", "#BF4080", "#FF8080", "#FFBF80", "#FFFF80", "#BFFF80",
|
||||
"#80FF80", "#80FFBF", "#80FFFF", "#80BFFF", "#8080FF", "#BF80FF", "#FF80FF", "#FF80BF").iterator();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("diagraph G{");
|
||||
|
||||
//and constraints to dot
|
||||
sb.append(c.getUndConstraints().stream().map(Pair::toDot).collect(Collectors.joining("\n")));
|
||||
|
||||
//or constraints to dot
|
||||
for (var orConstSet : c.getOderConstraints()){
|
||||
for(var cons : orConstSet){
|
||||
String color = colors.next();
|
||||
sb.append(cons.stream().map(x -> x.toDot(color)).collect(Collectors.joining("\n")));
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("}");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String q(String s) {
|
||||
return "\"" + s.replace("\"", "\\\"") + "\"";
|
||||
}
|
||||
|
||||
public List<ResultSet> typeInference(List<File> files) throws ClassNotFoundException, IOException {
|
||||
Set<ClassOrInterface> allClasses = new HashSet<>();
|
||||
|
||||
@@ -475,36 +441,6 @@ public class JavaTXCompiler {
|
||||
TYPE ty = new TYPE(definedClasses, allClasses);
|
||||
var cons = ty.getConstraints();
|
||||
|
||||
var ANDconstraints = cons.getUndConstraints();
|
||||
var ORConstraints = cons.getOderConstraints();
|
||||
|
||||
var orIterator = ORConstraints.iterator();
|
||||
|
||||
while(orIterator.hasNext()){
|
||||
Set<Constraint<Pair>> y = orIterator.next();
|
||||
if (y.isEmpty()) orIterator.remove();
|
||||
else if (y.size() == 1){
|
||||
ANDconstraints.addAll(y.iterator().next()); // add the OR constraint to the AND constraint since we only have one option
|
||||
orIterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
String dot = constraintSetToDot(cons);
|
||||
|
||||
|
||||
ANDconstraints.forEach(System.out::println);
|
||||
|
||||
for (var orc : ORConstraints){
|
||||
System.out.println();
|
||||
System.out.println("------");
|
||||
System.out.println();
|
||||
for(var hashs : orc){
|
||||
System.out.print(hashs);
|
||||
System.out.print("\n | \n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Set<Set<UnifyPair>> results = new HashSet<>();
|
||||
PlaceholderRegistry placeholderRegistry = new PlaceholderRegistry();
|
||||
|
||||
@@ -753,7 +689,7 @@ public class JavaTXCompiler {
|
||||
|
||||
public final JavaClassRegistry classRegistry = new JavaClassRegistry();
|
||||
|
||||
private void parse(SourceFileContext tree, File sourceFile) throws IOException, java.lang.ClassNotFoundException {
|
||||
private void parse(SourceFileContext tree, File sourceFile) throws IOException, ClassNotFoundException {
|
||||
SyntaxTreeGenerator generator = new SyntaxTreeGenerator(this, classRegistry, new GenericsRegistry(null), sourceFile.getName());
|
||||
environment.addClassesToRegistry(classRegistry, tree, sourceFile, this);
|
||||
var classes = new ArrayList<ClassOrInterface>();
|
||||
@@ -764,8 +700,18 @@ public class JavaTXCompiler {
|
||||
sf.imports.addAll(generator.imports);
|
||||
}
|
||||
|
||||
public void parseAll() throws IOException, ClassNotFoundException {
|
||||
var treeList = generateSources(sources);
|
||||
for (var i = 0; i < sources.size(); i++) {
|
||||
parse(treeList.get(i), sources.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
public void generateBytecode() throws ClassNotFoundException, IOException {
|
||||
// The compiler has two modes, one is to infer all files together and the other one is to do them in sequence
|
||||
if (inferTogether) {
|
||||
parseAll();
|
||||
|
||||
var files = sourceFiles.keySet().stream().toList();
|
||||
var typeinferenceResult = this.typeInference(files);
|
||||
for (var file : files) {
|
||||
@@ -776,7 +722,11 @@ public class JavaTXCompiler {
|
||||
writeClassFile(classes, outputPath == null ? file.getParentFile() : outputPath, outputPath == null);
|
||||
}
|
||||
} else {
|
||||
for (var file : sourceFiles.keySet()) {
|
||||
var treeList = generateSources(sources);
|
||||
for (var i = 0; i < sources.size(); i++) {
|
||||
var file = sources.get(i);
|
||||
parse(treeList.get(i), file);
|
||||
|
||||
var sf = sourceFiles.get(file);
|
||||
if (sf.isGenerated()) continue;
|
||||
var classes = generateBytecode(file);
|
||||
@@ -786,7 +736,7 @@ public class JavaTXCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
public Map<JavaClassName, byte[]> generateBytecode(File sourceFile) throws ClassNotFoundException, IOException {
|
||||
private Map<JavaClassName, byte[]> generateBytecode(File sourceFile) throws ClassNotFoundException, IOException {
|
||||
var sf = sourceFiles.get(sourceFile);
|
||||
if (sf.isGenerated()) return null;
|
||||
List<ResultSet> typeinferenceResult = this.typeInference(sourceFile);
|
||||
@@ -820,11 +770,91 @@ public class JavaTXCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Maybe move this elsewhere it doesn't really belong here
|
||||
private static RefTypeOrTPHOrWildcardOrGeneric toRefType(TargetType type) {
|
||||
return switch(type) {
|
||||
case TargetExtendsWildcard targetExtendsWildcard ->
|
||||
new ExtendsWildcardType(toRefType(targetExtendsWildcard.innerType()), new NullToken());
|
||||
case TargetSuperWildcard targetSuperWildcard ->
|
||||
new SuperWildcardType(toRefType(targetSuperWildcard.innerType()), new NullToken());
|
||||
case TargetGenericType targetGenericType -> new GenericRefType(targetGenericType.name(), new NullToken());
|
||||
case TargetPrimitiveType targetPrimitiveType -> toRefType(TargetType.toWrapper(targetPrimitiveType));
|
||||
case TargetSpecializedType targetSpecializedType ->
|
||||
new RefType(new JavaClassName(targetSpecializedType.name()),
|
||||
targetSpecializedType.params().stream().map(JavaTXCompiler::toRefType).toList(), new NullToken()
|
||||
);
|
||||
case null -> new Void(new NullToken());
|
||||
};
|
||||
}
|
||||
|
||||
private static ParameterList toParameterList(List<MethodParameter> params) {
|
||||
return new ParameterList(params.stream().map(mp
|
||||
-> (Pattern) new FormalParameter(mp.pattern().name(), toRefType(mp.pattern().type()), new NullToken())).toList(),
|
||||
new NullToken()
|
||||
);
|
||||
}
|
||||
|
||||
private static GenericDeclarationList toGenerics(Set<TargetGeneric> generics) {
|
||||
return new GenericDeclarationList(
|
||||
generics.stream().map(g
|
||||
-> new GenericTypeVar(g.name(), List.of(toRefType(g.bound())), new NullToken(), new NullToken())
|
||||
).toList(), new NullToken()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This writes back the compiled target structure into the loadedClasses map so that it can be used
|
||||
* as an input in further processing
|
||||
* @param target
|
||||
*/
|
||||
private void writeBackToClass(TargetStructure target) {
|
||||
var fielddecl = new ArrayList<Field>();
|
||||
for (var field : target.fields()) {
|
||||
fielddecl.add(new Field(field.name(), toRefType(field.type()), field.access(), new NullToken()));
|
||||
}
|
||||
|
||||
var methods = new ArrayList<Method>();
|
||||
for (var method : target.methods()) {
|
||||
methods.add(new Method(method.access(), method.name(), toRefType(method.signature().returnType()),
|
||||
toParameterList(method.signature().parameters()), new Block(new ArrayList<>(), new NullToken()), toGenerics(method.signature().generics()), new NullToken())
|
||||
);
|
||||
}
|
||||
|
||||
var constructors = new ArrayList<Constructor>();
|
||||
for (var ctor : target.constructors()) {
|
||||
constructors.add(new Constructor(ctor.access(), target.getName(), new RefType(target.qualifiedName(), new NullToken()),
|
||||
toParameterList(ctor.parameters()), new Block(new ArrayList<>(), new NullToken()), toGenerics(ctor.generics()), new NullToken())
|
||||
);
|
||||
}
|
||||
|
||||
var generics = new GenericDeclarationList(toGenerics(target.generics()), new NullToken());
|
||||
var superClass = (RefType) toRefType(target.superType());
|
||||
var isInterface = target instanceof TargetInterface;
|
||||
var isFunctionalInterface = false; // TODO We might actually want to generate those
|
||||
var implementedInterfaces = target.implementingInterfaces().stream()
|
||||
.map(t -> (RefType) toRefType(t)).toList();
|
||||
var permittedSubtypes = List.<RefType>of();
|
||||
if (target instanceof TargetInterface tinf) {
|
||||
permittedSubtypes = tinf.permittedSubtypes().stream().map(t -> (RefType) toRefType(t)).toList();
|
||||
}
|
||||
|
||||
var clazz = new ClassOrInterface(
|
||||
target.modifiers(), target.qualifiedName(),
|
||||
fielddecl, Optional.empty(), Optional.empty(),
|
||||
methods, constructors, generics, superClass,
|
||||
isInterface, isFunctionalInterface, implementedInterfaces,
|
||||
permittedSubtypes, new NullToken(), ""
|
||||
);
|
||||
loadedClasses.put(target.qualifiedName(), clazz);
|
||||
}
|
||||
|
||||
public synchronized Map<JavaClassName, byte[]> generateBytecode(SourceFile sf, List<ResultSet> typeInferenceResult) {
|
||||
var converter = new ASTToTargetAST(this, typeInferenceResult, sf, classLoader);
|
||||
var generatedClasses = new HashMap<JavaClassName, byte[]>();
|
||||
for (var clazz : sf.getClasses()) {
|
||||
var codegen = new Codegen(converter.convert(clazz), this, converter);
|
||||
var target = converter.convert(clazz);
|
||||
writeBackToClass(target);
|
||||
var codegen = new Codegen(target, this, converter);
|
||||
var code = codegen.generate();
|
||||
generatedClasses.put(clazz.getClassName(), code);
|
||||
}
|
||||
|
||||
@@ -58,14 +58,11 @@ public class LanguageServerInterface {
|
||||
var file = path.toFile();
|
||||
Files.createDirectories(path.getParent().resolve("out"));
|
||||
var compiler = new JavaTXCompiler(List.of(file), List.of(path.getParent().toFile()), path.getParent().resolve("out").toFile(), false);
|
||||
compiler.generateBytecode();
|
||||
|
||||
var parsedSource = compiler.sourceFiles.get(file);
|
||||
var tiResults = compiler.typeInference(file);
|
||||
|
||||
Map<JavaClassName, byte[]> bytecode = compiler.generateBytecode(parsedSource, tiResults);
|
||||
Files.createDirectories(path.getParent().resolve("out"));
|
||||
compiler.writeClassFile(bytecode, path.getParent().resolve("out").toFile(), false);
|
||||
|
||||
return new LanguageServerTransferObject(tiResults, parsedSource, "", compiler.getGeneratedGenerics());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
|
||||
@@ -700,7 +700,7 @@ public class StatementGenerator {
|
||||
case ConditionalassignexpressionContext condassign:
|
||||
return convert(condassign);
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
throw new NotImplementedException(expression.getClass().toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,8 @@ public class TypeGenerator {
|
||||
switch (typeContext.primitiveType().getText()) {
|
||||
case "boolean":
|
||||
return new RefType(ASTFactory.createClass(Boolean.class).getClassName(), typeContext.getStart());
|
||||
case "char":
|
||||
return new RefType(ASTFactory.createClass(Character.class).getClassName(), typeContext.getStart());
|
||||
case "int":
|
||||
return new RefType(ASTFactory.createClass(Integer.class).getClassName(), typeContext.getStart());
|
||||
case "double":
|
||||
@@ -71,7 +73,7 @@ public class TypeGenerator {
|
||||
case "float":
|
||||
return new RefType(ASTFactory.createClass(Float.class).getClassName(), typeContext.getStart());
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
throw new NotImplementedException(typeContext.primitiveType().getText());
|
||||
}
|
||||
} else if (!typeContext.LBRACK().isEmpty()) { // ArrayType über eckige Klammer prüfen
|
||||
// JavaTXParser.logger.info(unannTypeContext.getText());
|
||||
|
||||
@@ -229,9 +229,6 @@ public class ASTFactory {
|
||||
public static Method createMethod(java.lang.reflect.Method jreMethod, String signature, java.lang.Class inClass, Boolean isInherited, Boolean isImplemented) {
|
||||
String name = jreMethod.getName();
|
||||
RefTypeOrTPHOrWildcardOrGeneric returnType;
|
||||
if (inClass.getName().equals("Swap")){
|
||||
System.out.println();
|
||||
}
|
||||
Type jreRetType;
|
||||
if (jreMethod.getGenericReturnType() != null) {
|
||||
jreRetType = jreMethod.getGenericReturnType();
|
||||
|
||||
@@ -28,6 +28,7 @@ public class MethodCall extends Statement
|
||||
|
||||
//sind Tphs, repraesentieren im Resultset die Signatur der aufgerufenen Methoden, letztes Element ist der Returntyp
|
||||
public final ArrayList<TypePlaceholder> signature;
|
||||
public int modifiers;
|
||||
|
||||
public MethodCall(RefTypeOrTPHOrWildcardOrGeneric retType, Receiver receiver, String methodName, ArgumentList argumentList,
|
||||
RefTypeOrTPHOrWildcardOrGeneric receiverType, ArrayList<TypePlaceholder> signature, Token offset){
|
||||
|
||||
@@ -4,6 +4,7 @@ import de.dhbwstuttgart.bytecode.FunNGenerator;
|
||||
import de.dhbwstuttgart.core.JavaTXCompiler;
|
||||
import de.dhbwstuttgart.environment.IByteArrayClassLoader;
|
||||
import de.dhbwstuttgart.exceptions.DebugException;
|
||||
import de.dhbwstuttgart.exceptions.NotImplementedException;
|
||||
import de.dhbwstuttgart.parser.NullToken;
|
||||
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
||||
import de.dhbwstuttgart.syntaxtree.*;
|
||||
@@ -11,17 +12,20 @@ import de.dhbwstuttgart.syntaxtree.Record;
|
||||
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
|
||||
import de.dhbwstuttgart.syntaxtree.statement.*;
|
||||
import de.dhbwstuttgart.syntaxtree.type.*;
|
||||
import de.dhbwstuttgart.syntaxtree.visual.ASTPrinter;
|
||||
import de.dhbwstuttgart.syntaxtree.visual.OutputGenerator;
|
||||
import de.dhbwstuttgart.target.Target;
|
||||
import de.dhbwstuttgart.target.tree.*;
|
||||
import de.dhbwstuttgart.target.tree.expression.*;
|
||||
import de.dhbwstuttgart.target.tree.type.*;
|
||||
import de.dhbwstuttgart.typeinference.result.*;
|
||||
import de.dhbwstuttgart.typeinference.unify.MartelliMontanariUnify;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.*;
|
||||
|
||||
import java.lang.annotation.Target;
|
||||
import javax.swing.text.html.Option;
|
||||
import java.sql.Array;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
/**
|
||||
* @author dholle
|
||||
@@ -61,10 +65,14 @@ public class ASTToTargetAST {
|
||||
return converter.result;
|
||||
}
|
||||
|
||||
public record Generics(JavaGenerics javaGenerics, TxGenerics txGenerics) {
|
||||
public record Generics(IGenerics javaGenerics, IGenerics txGenerics) {
|
||||
public Generics(JavaTXCompiler compiler, ResultSet set) {
|
||||
this(new JavaGenerics(compiler, set), new TxGenerics(compiler, set));
|
||||
}
|
||||
|
||||
public static Generics nullGenerics() {
|
||||
return new Generics(null, new ResultSet(Set.of()));
|
||||
}
|
||||
}
|
||||
|
||||
public IByteArrayClassLoader classLoader;
|
||||
@@ -94,10 +102,15 @@ public class ASTToTargetAST {
|
||||
tphsInMethods.put(currentMethod, set);
|
||||
}
|
||||
|
||||
public static Optional<Method> findMethod(ClassOrInterface owner, String name, List<TargetType> argumentList, JavaTXCompiler compiler) {
|
||||
return findMethod(owner, name, argumentList, Generics.nullGenerics().javaGenerics(), compiler);
|
||||
}
|
||||
|
||||
public static Optional<Method> findMethod(ClassOrInterface owner, String name, List<TargetType> argumentList, IGenerics generics, JavaTXCompiler compiler) {
|
||||
Optional<Method> method = Optional.empty();
|
||||
while (method.isEmpty()) {
|
||||
method = owner.getMethods().stream().filter(m -> m.name.equals(name) && parameterEquals(m.getParameterList(), argumentList, generics)).findFirst();
|
||||
method = owner.getMethods().stream().filter(m -> m.name.equals(name) &&
|
||||
parameterEquals(m.getParameterList().getFormalparalist().stream().map(p -> generics.getTargetType(p.getType())).toList(), argumentList)).findFirst();
|
||||
if (owner.getClassName().toString().equals("java.lang.Object")) break;
|
||||
owner = compiler.getClass(owner.getSuperClass().getName());
|
||||
}
|
||||
@@ -105,16 +118,16 @@ public class ASTToTargetAST {
|
||||
}
|
||||
|
||||
Optional<Constructor> findConstructor(ClassOrInterface owner, List<TargetType> argumentList, IGenerics generics) {
|
||||
return owner.getConstructors().stream().filter(c -> parameterEquals(c.getParameterList(), argumentList, generics)).findFirst();
|
||||
return owner.getConstructors().stream().filter(c ->
|
||||
parameterEquals(c.getParameterList().getFormalparalist().stream().map(p -> generics.getTargetType(p.getType())).toList(), argumentList)).findFirst();
|
||||
}
|
||||
|
||||
static boolean parameterEquals(ParameterList parameterList, List<TargetType> arguments, IGenerics generics) {
|
||||
var pars = parameterList.getFormalparalist();
|
||||
static boolean parameterEquals(List<TargetType> pars, List<TargetType> arguments) {
|
||||
if (pars.size() != arguments.size())
|
||||
return false;
|
||||
|
||||
for (var i = 0; i < pars.size(); i++) {
|
||||
var type1 = generics.getTargetType(pars.get(i).getType());
|
||||
var type1 = pars.get(i);
|
||||
var type2 = arguments.get(i);
|
||||
if (type1 instanceof TargetGenericType)
|
||||
return true;
|
||||
@@ -147,190 +160,182 @@ public class ASTToTargetAST {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// This finds a common sealed interface type to group together methods that use different records
|
||||
// This function should do matching or unification
|
||||
private List<ClassOrInterface> commonSuperInterfaceTypes(TargetType a, TargetType b) {
|
||||
if (a instanceof TargetGenericType && b instanceof TargetGenericType) return List.of(ASTFactory.createObjectClass());
|
||||
if (a instanceof TargetRefType ta && b instanceof TargetGenericType)
|
||||
return List.of(compiler.getClass(new JavaClassName(ta.name())));
|
||||
if (b instanceof TargetRefType tb && a instanceof TargetGenericType)
|
||||
return List.of(compiler.getClass(new JavaClassName(tb.name())));
|
||||
private static UnifyType toUnifyType(TargetType a) {
|
||||
return switch(a) {
|
||||
case TargetExtendsWildcard targetExtendsWildcard -> new ExtendsType(toUnifyType(targetExtendsWildcard.innerType()));
|
||||
case TargetSuperWildcard targetSuperWildcard -> new SuperType(toUnifyType(targetSuperWildcard.innerType()));
|
||||
case TargetGenericType targetGenericType -> new PlaceholderType(targetGenericType.name(), JavaTXCompiler.defaultClientPlaceholderRegistry);
|
||||
case TargetPrimitiveType _ -> throw new NotImplementedException();
|
||||
case TargetFunNType targetFunNType -> FunNType.getFunNType(new TypeParams(targetFunNType.params().stream().map(ASTToTargetAST::toUnifyType).toList()));
|
||||
case TargetRefType targetRefType -> new ReferenceType(targetRefType.name(), new TypeParams(targetRefType.params().stream().map(ASTToTargetAST::toUnifyType).toList()));
|
||||
};
|
||||
}
|
||||
|
||||
private static TargetType toTargetType(UnifyType a) {
|
||||
return switch (a) {
|
||||
case ExtendsType extendType -> new TargetExtendsWildcard(toTargetType(extendType.getExtendedType()));
|
||||
case SuperType superType -> new TargetSuperWildcard(toTargetType(superType.getSuperedType()));
|
||||
case PlaceholderType placeholderType -> new TargetGenericType(placeholderType.getName());
|
||||
case FunNType funNType -> TargetFunNType.fromParams(StreamSupport.stream(funNType.getTypeParams().spliterator(), false).map(ASTToTargetAST::toTargetType).toList(), 1); // FIXME How does this work with Fun0??
|
||||
case ReferenceType referenceType -> new TargetRefType(referenceType.getName(), StreamSupport.stream(referenceType.getTypeParams().spliterator(), false).map(ASTToTargetAST::toTargetType).toList());
|
||||
default -> throw new NotImplementedException();
|
||||
};
|
||||
}
|
||||
|
||||
// TODO This should be moved elsewhere
|
||||
private static boolean typesStrictlyEqual(TargetType a, TargetType b) {
|
||||
if (a instanceof TargetRefType ta && b instanceof TargetRefType tb) {
|
||||
var res = new HashSet<ClassOrInterface>();
|
||||
|
||||
var cla = compiler.getClass(new JavaClassName(ta.name()));
|
||||
var clb = compiler.getClass(new JavaClassName(tb.name()));
|
||||
|
||||
if (cla.equals(clb)) return List.of(cla);
|
||||
|
||||
while (!cla.equals(ASTFactory.createObjectClass())) {
|
||||
var clb2 = clb;
|
||||
while (!clb2.equals(ASTFactory.createObjectClass())) {
|
||||
for (var intfa : cla.getSuperInterfaces()) {
|
||||
for (var intfb : clb.getSuperInterfaces()) {
|
||||
if (intfa.equals(intfb)) {
|
||||
var clintf = compiler.getClass(intfa.getName());
|
||||
if (clintf.isSealed()) {
|
||||
res.add(clintf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
clb2 = compiler.getClass(clb2.getSuperClass().getName());
|
||||
}
|
||||
cla = compiler.getClass(cla.getSuperClass().getName());
|
||||
}
|
||||
return res.stream().toList();
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
|
||||
private boolean canCombine(Signature m1, Signature m2) {
|
||||
var pl1 = m1.java.parameters();
|
||||
var pl2 = m2.java.parameters();
|
||||
if (pl1.size() != pl2.size()) return false;
|
||||
if (pl1.isEmpty()) return false;
|
||||
for (var i = 0; i < pl1.size(); i++) {
|
||||
var p1 = pl1.get(i).pattern();
|
||||
var p2 = pl2.get(i).pattern();
|
||||
// TPH <> RefType sind nicht unterscheidbar
|
||||
if (p1.type() instanceof TargetGenericType || p2.type() instanceof TargetGenericType) continue;
|
||||
// Pattern(X) <> Pattern(Y) ist nicht unterscheidbar
|
||||
if (p1 instanceof TargetComplexPattern pc1 && p2 instanceof TargetComplexPattern pc2 &&
|
||||
pc1.type().equals(pc2.type())) continue;
|
||||
if (!p1.equals(p2)) return false;
|
||||
if (!Objects.equals(ta.name(), tb.name())) return false;
|
||||
if (ta.params().size() != tb.params().size()) return false;
|
||||
for (var i = 0; i < ta.params().size(); i++) {
|
||||
if (!typesStrictlyEqual(ta.params().get(i), tb.params().get(i)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private record Combination(MethodWithTphs a, MethodWithTphs b) {
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Combination(MethodWithTphs a1, MethodWithTphs b1))) return false;
|
||||
return this.a.equals(a1) && this.b.equals(b1) ||
|
||||
this.a.equals(b1) && this.b.equals(a1);
|
||||
// Generics are considered equal
|
||||
if (a instanceof TargetGenericType && b instanceof TargetGenericType)
|
||||
return true;
|
||||
return Objects.equals(a, b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(a) + Objects.hashCode(b);
|
||||
private static Optional<TargetType> unify(TargetType a, TargetType b) {
|
||||
if (typesStrictlyEqual(a, b)) return Optional.of(a);
|
||||
var unify = new MartelliMontanariUnify();
|
||||
var ua = toUnifyType(a);
|
||||
var unifier = unify.unify(Set.of(ua, toUnifyType(b)));
|
||||
if (unifier.isEmpty()) return Optional.empty();
|
||||
return Optional.of(toTargetType(unifier.get().apply(ua)));
|
||||
}
|
||||
|
||||
private static Optional<List<MethodParameter>> unify(List<MethodParameter> a, List<MethodParameter> b) {
|
||||
if (a.size() != b.size()) return Optional.empty();
|
||||
var result = new ArrayList<MethodParameter>();
|
||||
for (var i = 0; i < a.size(); i++) {
|
||||
var u = unify(a.get(i).pattern().type(), b.get(i).pattern().type());
|
||||
if (u.isEmpty()) return Optional.empty();
|
||||
// Strip off patterns, we don't need them for merged methods, they do a switch case
|
||||
result.add(new MethodParameter(u.get(), a.get(i).pattern().name()));
|
||||
}
|
||||
|
||||
return Optional.of(result);
|
||||
}
|
||||
|
||||
private static Set<String> findUsedGenerics(TargetType type) {
|
||||
if (type instanceof TargetSpecializedType tspec) {
|
||||
return tspec.params().stream().map(ASTToTargetAST::findUsedGenerics).flatMap(Set::stream).collect(Collectors.toSet());
|
||||
} else if (type instanceof TargetGenericType(String name)) {
|
||||
var set = new HashSet<String>();
|
||||
set.add(name);
|
||||
return set;
|
||||
}
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
// When unifying types we need to keep the generics that are still used in the signature
|
||||
// This is done in an extra step after all generics have been combined into one list
|
||||
private static void correctGenerics(TargetMethod.Signature signature, List<TargetGeneric> generics) {
|
||||
var outGenerics = signature.generics();
|
||||
outGenerics.addAll(generics);
|
||||
var foundGenerics = signature.parameters().stream().map(p -> findUsedGenerics(p.pattern().type()))
|
||||
.flatMap(Set::stream)
|
||||
.collect(Collectors.toSet());
|
||||
foundGenerics.addAll(findUsedGenerics(signature.returnType()));
|
||||
|
||||
for (var generic : new HashSet<>(outGenerics)) {
|
||||
if (!foundGenerics.contains(generic.name())) outGenerics.remove(generic);
|
||||
}
|
||||
}
|
||||
|
||||
private List<List<MethodWithTphs>> groupOverloads(ClassOrInterface input, List<Method> methods) {
|
||||
var mapOfTargetMethods = new HashMap<Generics, MethodWithTphs[]>();
|
||||
for (var gen : all) {
|
||||
mapOfTargetMethods.put(gen, new MethodWithTphs[methods.size()]);
|
||||
private static Optional<TargetMethod.Signature> unify(TargetMethod.Signature a, TargetMethod.Signature b) {
|
||||
var returnType = unify(a.returnType(), b.returnType());
|
||||
if (returnType.isEmpty()) return Optional.empty();
|
||||
var res = unify(a.parameters(), b.parameters());
|
||||
if (res.isEmpty()) return Optional.empty();
|
||||
var generics = new ArrayList<>(a.generics());
|
||||
generics.addAll(b.generics());
|
||||
var signature = new TargetMethod.Signature(new HashSet<>(), res.get(), returnType.get());
|
||||
correctGenerics(signature, generics);
|
||||
return Optional.of(signature);
|
||||
}
|
||||
|
||||
for (var i = 0; i < methods.size(); i++) {
|
||||
var method = methods.get(i);
|
||||
private static Optional<MethodGroup> unify(MethodGroup a, MethodGroup b) {
|
||||
var junified = unify(a.signature.java, b.signature.java);
|
||||
if (junified.isEmpty()) return Optional.empty();
|
||||
var txunified = unify(a.signature.tx, b.signature.tx);
|
||||
|
||||
var unifiedSignature = new Signature(junified.get(), txunified.orElseGet(junified::get), a.signature().generics);
|
||||
|
||||
var concat = new HashSet<>(a.methods);
|
||||
concat.addAll(b.methods);
|
||||
return Optional.of(new MethodGroup(unifiedSignature, concat));
|
||||
}
|
||||
|
||||
private record NameAndParameters(String name, int parameters) {}
|
||||
|
||||
private List<List<Method>> groupMethods(ClassOrInterface input, List<Method> methods) {
|
||||
var groups = new HashMap<NameAndParameters, List<Method>>();
|
||||
for (var m : methods) {
|
||||
var nameAndParameters = new NameAndParameters(m.name, m.getParameterList().getFormalparalist().size());
|
||||
var l = groups.getOrDefault(nameAndParameters, new ArrayList<>());
|
||||
l.add(m);
|
||||
groups.put(nameAndParameters, l);
|
||||
}
|
||||
|
||||
return groups.values().stream().toList();
|
||||
}
|
||||
|
||||
private Set<MethodGroup> groupOverloads(ClassOrInterface input, List<Method> methods) {
|
||||
var a = new HashSet<MethodGroup>();
|
||||
|
||||
for (Method method : methods) {
|
||||
// Convert all methods
|
||||
var methodsWithTphs = convert(input, method);
|
||||
for (var m : methodsWithTphs) {
|
||||
var resultMethods = mapOfTargetMethods.get(m.generics);
|
||||
resultMethods[i] = new MethodWithTphs(m.method, m.generics, m.signature);
|
||||
var mtph = new MethodWithTphs(m.method, m.generics, m.signature);
|
||||
a.add(new MethodGroup(m.signature, Set.of(mtph)));
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("============== INPUT ==============");
|
||||
for (var m : mapOfTargetMethods.values()) {
|
||||
for (var v : m) if (v != null) System.out.println(v.signature.java.returnType() + " " + v.method.name + " " + v.signature.java().parameters());
|
||||
System.out.println();
|
||||
for (var m : a) {
|
||||
System.out.println(m);
|
||||
}
|
||||
|
||||
var allCombinations = new HashSet<Set<Combination>>();
|
||||
// Combine methods based on their signature and position in the result set
|
||||
for (var g1 : all) {
|
||||
var resMeth1 = mapOfTargetMethods.get(g1);
|
||||
for (var i = 0; i < methods.size(); i++) {
|
||||
var m1 = resMeth1[i];
|
||||
if (m1 == null) continue;
|
||||
// Algorithm
|
||||
|
||||
for (var g2 : all) {
|
||||
if (g1 == g2) continue; // No need to combine the same method
|
||||
var resMeth2 = mapOfTargetMethods.get(g2);
|
||||
var m2 = resMeth2[i];
|
||||
if (m2 == null) continue;
|
||||
var R = new HashSet<MethodGroup>();
|
||||
var i = new HashSet<>(a);
|
||||
|
||||
var combinations = new HashSet<Combination>();
|
||||
|
||||
if (canCombine(m1.signature, m2.signature)) {
|
||||
//System.out.println(" Combining " + m1.signature.java.getSignature() + " and " + m2.signature.java.getSignature());
|
||||
combinations.add(new Combination(m1, m2));
|
||||
for (var j = 0; j < methods.size(); j++) {
|
||||
if (j == i) continue;
|
||||
var m3 = resMeth2[j];
|
||||
if (m3 == null) continue;
|
||||
var m4 = resMeth1[j];
|
||||
if (m4 == null) continue;
|
||||
combinations.add(new Combination(m4, m3));
|
||||
//System.out.println("Also Combining " + m4.signature.java.getSignature() + " and " + m3.signature.java.getSignature());
|
||||
}
|
||||
} else {
|
||||
//System.out.println(" Not Combining " + m1.signature.java.getSignature() + " and " + m2.signature.java.getSignature());
|
||||
}
|
||||
if (!combinations.isEmpty()) allCombinations.add(combinations);
|
||||
while (!i.isEmpty()) {
|
||||
var m = i.iterator().next();
|
||||
i.remove(m);
|
||||
R.add(m);
|
||||
var a1 = new HashSet<>(a);
|
||||
for (var m1 : a1) {
|
||||
if (m1 != m) {
|
||||
var u_opt = unify(m, m1);
|
||||
if (u_opt.isPresent()) {
|
||||
var u = u_opt.get();
|
||||
//System.out.println("Unified " + m + " AND " + m1 + "\n\t" + u);
|
||||
i.remove(m1);
|
||||
R.remove(m);
|
||||
R.remove(m1);
|
||||
R.add(u);
|
||||
a.add(u);
|
||||
} /*else {
|
||||
System.out.println("Couldn't unify " + m + " AND " + m1);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allCombinations.isEmpty()) allCombinations.add(new HashSet<>());
|
||||
|
||||
// Combine back into output format
|
||||
var r0 = new HashSet<Set<MethodWithTphs>>();
|
||||
for (var combinations : allCombinations) {
|
||||
var r1 = new HashSet<Set<MethodWithTphs>>();
|
||||
// This is used to weed out duplicates
|
||||
var uniqued = new HashSet<MethodWithTphs>();
|
||||
// We go over all methods in the result
|
||||
for (var g : all) for (var i = 0; i < methods.size(); i++) {
|
||||
var r2 = new HashSet<MethodWithTphs>();
|
||||
var m = mapOfTargetMethods.get(g)[i];
|
||||
if (m == null) continue;
|
||||
if (!uniqued.contains(m)) {
|
||||
// Add the method to r2
|
||||
r2.add(m);
|
||||
uniqued.add(m);
|
||||
} else continue;
|
||||
// Find all combinations that contain the method and add them to the result
|
||||
// if not filtered out by uniqued
|
||||
for (var c : combinations) {
|
||||
if (c.a.equals(m) || c.b.equals(m)) {
|
||||
if (!uniqued.contains(c.a)) {
|
||||
r2.add(c.a);
|
||||
uniqued.add(c.a);
|
||||
}
|
||||
if (!uniqued.contains(c.b)) {
|
||||
r2.add(c.b);
|
||||
uniqued.add(c.b);
|
||||
}
|
||||
}
|
||||
}
|
||||
r1.add(r2);
|
||||
}
|
||||
outer: for (var s1 : r1) {
|
||||
for (var s2 : new HashSet<>(r0)) {
|
||||
if (s2.containsAll(s1)) {
|
||||
continue outer;
|
||||
} else if (s1.containsAll(s2)) {
|
||||
r0.remove(s2);
|
||||
r0.add(s1);
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
r0.add(s1);
|
||||
}
|
||||
System.out.println("============== OUTPUT ==============");
|
||||
for (var mg : R) {
|
||||
System.out.println(mg.methods.size() + " " + mg);
|
||||
}
|
||||
|
||||
var result = r0.stream().map(l -> l.stream().toList()).toList();
|
||||
|
||||
//System.out.println("============== OUTPUT ==============");
|
||||
//for (var l : result) {
|
||||
// for (var m : l) System.out.println(m.method.name + " " + m.signature.java.getSignature());
|
||||
// System.out.println();
|
||||
//}
|
||||
return result;
|
||||
return R;
|
||||
}
|
||||
|
||||
public TargetStructure convert(ClassOrInterface input) {
|
||||
@@ -364,25 +369,48 @@ public class ASTToTargetAST {
|
||||
var superInterfaces = input.getSuperInterfaces().stream().map(clazz -> convert(clazz, generics.javaGenerics, compiler)).toList();
|
||||
var constructors = input.getConstructors().stream().map(constructor -> this.convert(input, constructor, finalFieldInitializer, generics)).flatMap(List::stream).toList();
|
||||
var fields = input.getFieldDecl().stream().map(f -> convert(f, generics.javaGenerics)).toList();
|
||||
var methods = groupOverloads(input, input.getMethods()).stream().map(m -> generatePatternOverloads(input, m)).flatMap(List::stream)
|
||||
.collect(Collectors.toSet()).stream().toList(); // Unique generated methods
|
||||
var m0 = groupMethods(input, input.getMethods());
|
||||
|
||||
var m1 = new ArrayList<TargetMethod>();
|
||||
for (var group : m0) {
|
||||
var overloads = groupOverloads(input, group);
|
||||
// This contains the merged pattern overloads
|
||||
var genMethods = new ArrayList<TargetMethod>();
|
||||
for (var o : overloads) {
|
||||
var pOverloads = generatePatternOverloads(input, o);
|
||||
m1.addAll(pOverloads);
|
||||
if (!pOverloads.isEmpty()) {
|
||||
genMethods.add(pOverloads.getLast());
|
||||
}
|
||||
}
|
||||
var bridge = generateBridgeMethod(input, genMethods);
|
||||
bridge.map(m1::add);
|
||||
}
|
||||
var methods = new HashSet<>(m1).stream().toList();
|
||||
|
||||
TargetMethod staticConstructor = null;
|
||||
if (input.getStaticInitializer().isPresent()) {
|
||||
var init = this.convert(input, input.getStaticInitializer().get()).stream().findFirst().orElseThrow();
|
||||
staticConstructor = this.convert(init, init.generics.javaGenerics);
|
||||
staticConstructor = this.convert(init);
|
||||
}
|
||||
|
||||
if (input instanceof Record)
|
||||
return new TargetRecord(input.getModifiers(), input.getClassName(), javaGenerics, txGenerics, superInterfaces, constructors, staticConstructor, fields, methods);
|
||||
else if (input.isInterface())
|
||||
return new TargetInterface(input.getModifiers(), input.getClassName(), javaGenerics, txGenerics, methods, superInterfaces, staticConstructor);
|
||||
return new TargetInterface(input.getModifiers(), input.getClassName(), javaGenerics, txGenerics, methods, superInterfaces, staticConstructor,
|
||||
input.getPermittedSubtypes().stream().map(t -> (TargetRefType) convert(t)).toList());
|
||||
else return new TargetClass(input.getModifiers(), input.getClassName(), convert(input.getSuperClass(), generics.javaGenerics, compiler), javaGenerics, txGenerics, superInterfaces, constructors, staticConstructor, fields, methods);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public List<MethodParameter> convert(ParameterList input) {
|
||||
return convert(input, all.getFirst().javaGenerics);
|
||||
var res = new ArrayList<MethodParameter>();
|
||||
for (var i = 0; i < input.getFormalparalist().size(); i++) {
|
||||
var param = input.getFormalparalist().get(i);
|
||||
var pattern = (TargetPattern) convert(param, Generics.nullGenerics().javaGenerics);
|
||||
if (pattern instanceof TargetComplexPattern) pattern = pattern.withName("__var" + i);
|
||||
res.add(new MethodParameter(pattern));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public List<MethodParameter> convert(ParameterList input, IGenerics generics) {
|
||||
@@ -466,17 +494,7 @@ public class ASTToTargetAST {
|
||||
}
|
||||
}
|
||||
|
||||
private TargetType unwrap(TargetType type) {
|
||||
if (type instanceof TargetRefType ref) {
|
||||
if (!ref.params().isEmpty()) return new TargetRefType(ref.name());
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
private TargetExpression generatePatternOverloadsRec(int offset, TargetExpression switchExpr, List<TargetLocalVar> params, List<TargetPattern> patterns, List<TargetMethod> methods, TargetType classType) {
|
||||
if (methods.isEmpty()) throw new DebugException("Couldn't find a candidate for switch overloading");
|
||||
if (methods.size() == 1) {
|
||||
var method = methods.getFirst();
|
||||
private static TargetExpression generateCall(TargetMethod method, List<TargetLocalVar> params, TargetType classType) {
|
||||
var mParams = new ArrayList<TargetExpression>();
|
||||
for (var i = 0; i < params.size(); i++) {
|
||||
var tpe = method.signature().parameters().get(i).pattern().type();
|
||||
@@ -496,6 +514,13 @@ public class ASTToTargetAST {
|
||||
return caseBody;
|
||||
}
|
||||
|
||||
private static TargetExpression generatePatternOverloadsRec(int offset, TargetExpression switchExpr, List<TargetLocalVar> params, List<TargetPattern> patterns, List<TargetMethod> methods, TargetType classType) {
|
||||
if (methods.isEmpty()) throw new DebugException("Couldn't find a candidate for switch overloading");
|
||||
if (methods.size() == 1) {
|
||||
var method = methods.getFirst();
|
||||
return generateCall(method, params, classType);
|
||||
}
|
||||
|
||||
var cases = new ArrayList<TargetSwitch.Case>();
|
||||
var usedPatterns = new HashSet<TargetPattern>();
|
||||
|
||||
@@ -527,10 +552,13 @@ public class ASTToTargetAST {
|
||||
if (!patternsRec.get(j).equals(param.pattern())) return false;
|
||||
j++;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}).toList();
|
||||
|
||||
//System.out.println(offset + " -> " + lastPattern);
|
||||
if (candidates.isEmpty()) {
|
||||
var body = new TargetBlock(List.of(generateCall(method, params, classType)));
|
||||
cases.add(new TargetSwitch.Case(List.of(lastPattern), body));
|
||||
} else {
|
||||
//candidates.forEach(m -> System.out.println(m.getSignature()));
|
||||
var caseBody = generatePatternOverloadsRec(offset + 1, expr, params, patternsRec, candidates, classType);
|
||||
var body = new TargetBlock(List.of(caseBody));
|
||||
@@ -538,42 +566,116 @@ public class ASTToTargetAST {
|
||||
|
||||
cases.add(case_);
|
||||
}
|
||||
}
|
||||
|
||||
return new TargetSwitch(switchExpr, cases, null, true);
|
||||
}
|
||||
|
||||
private List<TargetMethod> generatePatternOverloads(ClassOrInterface clazz, List<MethodWithTphs> overloadedMethods) {
|
||||
// TODO What happens if a record implements two sealed interfaces?
|
||||
private Optional<TargetType> commonSealedInterface(TargetType a, TargetType b) {
|
||||
if (!(a instanceof TargetRefType ar && b instanceof TargetRefType ab)) return Optional.empty();
|
||||
var cla = compiler.getClass(new JavaClassName(ar.name()));
|
||||
var clb = compiler.getClass(new JavaClassName(ab.name()));
|
||||
|
||||
// TODO This only goes one layer deep, this is fine for records as they can't extend anything but fails for complex hierarchies
|
||||
var intersection = new HashSet<>(cla.getSuperInterfaces());
|
||||
intersection.retainAll(clb.getSuperInterfaces());
|
||||
|
||||
if (intersection.size() != 1) return Optional.empty();
|
||||
return Optional.of(new TargetRefType(intersection.stream().findFirst().get().getName().toString()));
|
||||
}
|
||||
|
||||
private Optional<TargetMethod> generateBridgeMethod(ClassOrInterface clazz, List<TargetMethod> methods) {
|
||||
// If there's only one method we don't need a bridge
|
||||
if (methods.size() <= 1) return Optional.empty();
|
||||
var firstMethod = methods.getFirst();
|
||||
|
||||
// Check if all parameters are either the same or implement a sealed interface
|
||||
var resParams = new ArrayList<>(firstMethod.signature().parameters());
|
||||
TargetType resRet = firstMethod.signature().returnType();
|
||||
|
||||
for (var m : methods.subList(1, methods.size())) {
|
||||
for (var i = 0; i < m.signature().parameters().size(); i++) {
|
||||
var pa = firstMethod.signature().parameters().get(i);
|
||||
var pb = m.signature().parameters().get(i);
|
||||
|
||||
var ta = pa.pattern().type();
|
||||
var tb = pb.pattern().type();
|
||||
//System.out.println(ta + " " + tb);
|
||||
|
||||
if (Objects.equals(ta, tb)) continue;
|
||||
var common = commonSealedInterface(ta, tb);
|
||||
if (common.isPresent()) {
|
||||
resParams.set(i, pa.withType(common.get()));
|
||||
continue;
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
var ra = firstMethod.signature().returnType();
|
||||
var rb = m.signature().returnType();
|
||||
|
||||
if (Objects.equals(ra, rb)) continue;
|
||||
var common = commonSealedInterface(ra, rb);
|
||||
if (common.isPresent()) resRet = common.get();
|
||||
else return Optional.empty();
|
||||
}
|
||||
|
||||
var parameters = resParams.stream().map( p -> new TargetLocalVar(p.pattern().type(), p.pattern().name())).toList();
|
||||
|
||||
var classType = new TargetRefType(clazz.getClassName().getClassName());
|
||||
var stmt = generatePatternOverloadsRec(0, new TargetLocalVar(resParams.getFirst().pattern().type(), resParams.getFirst().pattern().name()), parameters, List.of(), methods, classType);
|
||||
var block = new TargetBlock(List.of(stmt));
|
||||
|
||||
var resSig = new TargetMethod.Signature(firstMethod.signature().generics(), resParams, resRet);
|
||||
var bridgeMethod = new TargetMethod(firstMethod.access(), firstMethod.name(), block, resSig, resSig);
|
||||
return Optional.of(bridgeMethod);
|
||||
}
|
||||
|
||||
private int comparePattern(TargetPattern a, TargetPattern b) {
|
||||
if (a instanceof TargetComplexPattern cpa
|
||||
&& b instanceof TargetComplexPattern cpb
|
||||
&& Objects.equals(cpa.type(), cpb.type())) {
|
||||
|
||||
assert cpa.subPatterns().size() == cpb.subPatterns().size();
|
||||
for (var i = 0; i < cpa.subPatterns().size(); i++) {
|
||||
var c = comparePattern(cpa.subPatterns().get(i), cpb.subPatterns().get(i));
|
||||
if (c != 0) return c;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isSubtype(a.type(), b.type())) return -1;
|
||||
if (isSubtype(b.type(), a.type())) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
private class CompareBySpecificity implements Comparator<MethodWithTphs> {
|
||||
@Override
|
||||
public int compare(MethodWithTphs o1, MethodWithTphs o2) {
|
||||
var p1 = o1.signature.java.parameters();
|
||||
var p2 = o2.signature.java.parameters();
|
||||
if (p1.size() != p2.size()) return 0;
|
||||
for (var i = 0; i < p1.size(); i++) {
|
||||
var c = comparePattern(p1.get(i).pattern(), p2.get(i).pattern());
|
||||
if (c != 0) return c;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void sortBySpecificity(List<MethodWithTphs> methods) {
|
||||
methods.sort(new CompareBySpecificity());
|
||||
}
|
||||
|
||||
private List<TargetMethod> generatePatternOverloads(ClassOrInterface clazz, MethodGroup group) {
|
||||
var overloadedMethods = new ArrayList<>(group.methods);
|
||||
if (overloadedMethods.isEmpty()) return List.of();
|
||||
// Check if we have a pattern as a parameter
|
||||
var firstMethod = convert(overloadedMethods.getFirst(), overloadedMethods.getFirst().generics.javaGenerics);
|
||||
sortBySpecificity(overloadedMethods);
|
||||
var firstMethod = convert(overloadedMethods.getFirst());
|
||||
if (overloadedMethods.size() == 1) return List.of(firstMethod);
|
||||
var secondMethod = convert(overloadedMethods.get(1), overloadedMethods.get(1).generics.javaGenerics);
|
||||
if (firstMethod.signature().parameters().stream().noneMatch(mp -> mp.pattern() instanceof TargetComplexPattern))
|
||||
return overloadedMethods.stream().map(m -> convert(m, m.generics.javaGenerics)).toList();
|
||||
|
||||
var signatureParams = new ArrayList<MethodParameter>();
|
||||
for (var i = 0; i < firstMethod.signature().parameters().size(); i++) {
|
||||
var p1 = firstMethod.signature().parameters().get(i).pattern();
|
||||
var t1 = p1.type();
|
||||
var t2 = secondMethod.signature().parameters().get(i).pattern().type();
|
||||
var commonSubTypes = new HashSet<>(commonSuperInterfaceTypes(t1, t2));
|
||||
for (var m : overloadedMethods.subList(2, overloadedMethods.size())) {
|
||||
var t3 = m.signature().java.parameters().get(i).pattern().type();
|
||||
commonSubTypes.retainAll(commonSuperInterfaceTypes(t1, t3));
|
||||
}
|
||||
if (commonSubTypes.size() > 1) throw new DebugException("Invalid overload");
|
||||
// TODO accept multiple types
|
||||
var superType = ASTFactory.createObjectClass();
|
||||
if (!commonSubTypes.isEmpty())
|
||||
superType = commonSubTypes.iterator().next();
|
||||
|
||||
String name;
|
||||
if (p1 instanceof TargetComplexPattern) name = "__var" + i;
|
||||
else name = p1.name();
|
||||
signatureParams.add(new MethodParameter(new TargetRefType(superType.getClassName().toString()), name));
|
||||
}
|
||||
|
||||
// Rename existing methods
|
||||
var signatureParams = group.signature.java.parameters();
|
||||
|
||||
var res = new ArrayList<TargetMethod>();
|
||||
for (var method : overloadedMethods) {
|
||||
@@ -592,12 +694,6 @@ public class ASTToTargetAST {
|
||||
res.add(new TargetMethod(tMethod.access(), name, tMethod.block(), tMethod.signature(), tMethod.txSignature()));
|
||||
}
|
||||
|
||||
var commonSubTypes = new HashSet<>(commonSuperInterfaceTypes(firstMethod.signature().returnType(), secondMethod.signature().returnType()));
|
||||
for (var m : overloadedMethods.subList(2, overloadedMethods.size())) {
|
||||
commonSubTypes.retainAll(commonSuperInterfaceTypes(firstMethod.signature().returnType(), m.signature().java.returnType()));
|
||||
}
|
||||
var returnType = commonSubTypes.isEmpty() ? TargetType.Object : new TargetRefType(commonSubTypes.iterator().next().getClassName().toString());
|
||||
|
||||
var parameters = signatureParams.stream().map( p -> new TargetLocalVar(p.pattern().type(), p.pattern().name())).toList();
|
||||
//var patterns = List.of((TargetComplexPattern) firstMethod.signature().parameters().stream()
|
||||
// .filter(p -> p.pattern() instanceof TargetComplexPattern).findFirst().orElseThrow().pattern());
|
||||
@@ -607,9 +703,7 @@ public class ASTToTargetAST {
|
||||
var stmt = generatePatternOverloadsRec(0, new TargetLocalVar(signatureParams.getFirst().pattern().type(), signatureParams.getFirst().pattern().name()), parameters, List.of(), res, classType);
|
||||
var block = new TargetBlock(List.of(stmt));
|
||||
|
||||
var signature = new TargetMethod.Signature(Set.of(), signatureParams, returnType);
|
||||
var bridgeMethod = new TargetMethod(firstMethod.access(), firstMethod.name(), block, signature, firstMethod.txSignature());
|
||||
|
||||
var bridgeMethod = new TargetMethod(firstMethod.access(), firstMethod.name(), block, group.signature.java, group.signature.tx);
|
||||
res.add(bridgeMethod);
|
||||
return res;
|
||||
}
|
||||
@@ -655,6 +749,15 @@ public class ASTToTargetAST {
|
||||
}).findFirst();
|
||||
}
|
||||
|
||||
record MethodGroup(Signature signature, Set<MethodWithTphs> methods) {
|
||||
@Override
|
||||
public String toString() {
|
||||
assert !methods.isEmpty();
|
||||
var first = methods.iterator().next();
|
||||
return signature.java.returnType() + " " + first.method.name + " " + signature.java.generics() + " " + signature.java.parameters();
|
||||
}
|
||||
}
|
||||
|
||||
record MethodWithTphs(Method method, Generics generics, Signature signature) {
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
@@ -669,14 +772,31 @@ public class ASTToTargetAST {
|
||||
}
|
||||
}
|
||||
|
||||
private TargetMethod convert(MethodWithTphs mtph) {
|
||||
return convert(mtph, mtph.generics.javaGenerics);
|
||||
}
|
||||
|
||||
private TargetMethod convert(MethodWithTphs mtph, IGenerics generics) {
|
||||
return new TargetMethod(mtph.method.modifier, mtph.method.name, convert(mtph.method.block, generics), mtph.signature.java(), mtph.signature.tx());
|
||||
}
|
||||
|
||||
record Signature(TargetMethod.Signature java, TargetMethod.Signature tx, Generics generics) {}
|
||||
record Signature(TargetMethod.Signature java, TargetMethod.Signature tx, Generics generics) {
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) return true;
|
||||
if (!(other instanceof Signature that)) return false;
|
||||
return Objects.equals(this.java, that.java) && Objects.equals(this.tx, that.tx)
|
||||
&& typesStrictlyEqual(this.java.returnType(), that.java.returnType()) && typesStrictlyEqual(this.tx.returnType(), that.tx.returnType());
|
||||
}
|
||||
|
||||
private List<MethodWithTphs> convert(ClassOrInterface currentClass, Method method) {
|
||||
List<MethodWithTphs> result = new ArrayList<>();
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(java, tx);
|
||||
}
|
||||
}
|
||||
|
||||
private Set<MethodWithTphs> convert(ClassOrInterface currentClass, Method method) {
|
||||
Set<MethodWithTphs> result = new HashSet<>();
|
||||
this.currentMethod = method;
|
||||
|
||||
List<Signature> signatures = new ArrayList<>();
|
||||
@@ -701,6 +821,7 @@ public class ASTToTargetAST {
|
||||
var txMethodGenerics = collectMethodGenerics(currentClass, generics.txGenerics(), txGenerics, method);
|
||||
|
||||
var javaSignature = new TargetMethod.Signature(javaMethodGenerics, params, returnType);
|
||||
//System.out.println(javaSignature.getDescriptor());
|
||||
var txSignature = new TargetMethod.Signature(txMethodGenerics, txParams, convert(method.getReturnType(), generics.txGenerics, compiler));
|
||||
|
||||
signatures.add(new Signature(javaSignature, txSignature, generics));
|
||||
@@ -754,7 +875,7 @@ public class ASTToTargetAST {
|
||||
for (var i = 0; i < tspec.params().size(); i++) {
|
||||
var param = tspec.params().get(i);
|
||||
if (param instanceof TargetSpecializedType fn) {
|
||||
collectArguments(tspec, newParams);
|
||||
collectArguments(fn, newParams);
|
||||
} else {
|
||||
newParams.add(param);
|
||||
}
|
||||
|
||||
@@ -216,6 +216,10 @@ public class StatementToTargetExpression implements ASTVisitor {
|
||||
return ASTToTargetAST.findMethod(converter.compiler.getClass(className), name, args, generics, compiler);
|
||||
}
|
||||
|
||||
Optional<Method> findMethod(JavaClassName className, String name, List<TargetType> args, JavaTXCompiler compiler) {
|
||||
return ASTToTargetAST.findMethod(converter.compiler.getClass(className), name, args, compiler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MethodCall methodCall) {
|
||||
var receiverType = converter.convert(methodCall.receiver.getType(), generics);
|
||||
@@ -246,7 +250,7 @@ public class StatementToTargetExpression implements ASTVisitor {
|
||||
} else if (!isFunNType) {
|
||||
receiverClass = converter.compiler.getClass(receiverName);
|
||||
if (receiverClass == null) throw new DebugException("Class " + receiverName + " does not exist!");
|
||||
foundMethod = findMethod(receiverName, methodCall.name, signature, generics, converter.compiler).orElseThrow();
|
||||
foundMethod = findMethod(receiverName, methodCall.name, signature, converter.compiler).orElseThrow();
|
||||
}
|
||||
|
||||
if (!isFunNType) {
|
||||
|
||||
@@ -3,4 +3,9 @@ package de.dhbwstuttgart.target.tree;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetGeneric(String name, TargetType bound) {
|
||||
@Override
|
||||
public String toString() {
|
||||
if (bound.equals(TargetType.Object)) return "'" + name;
|
||||
else return "'" + name + " < " + bound;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package de.dhbwstuttgart.target.tree;
|
||||
|
||||
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetRefType;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public record TargetInterface(int modifiers, JavaClassName qualifiedName, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<TargetMethod> methods, List<TargetType> implementingInterfaces, TargetMethod staticConstructor) implements TargetStructure {
|
||||
public record TargetInterface(int modifiers, JavaClassName qualifiedName, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<TargetMethod> methods, List<TargetType> implementingInterfaces, TargetMethod staticConstructor, List<TargetRefType> permittedSubtypes) implements TargetStructure {
|
||||
@Override
|
||||
public TargetType superType() {
|
||||
return null;
|
||||
|
||||
@@ -85,12 +85,11 @@ public class Constraint<A extends IConstraintElement> extends HashSet<A> impleme
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString();
|
||||
// + "\nisInherited = " + isInherited
|
||||
// + " isOveridden = " + isImplemented
|
||||
// + " msc[" + methodSignatureConstraint.size() + "] = " + methodSignatureConstraint
|
||||
// //" + extendsContraint: " + (extendConstraint != null ? extendConstraint.toStringBase() : "null" )
|
||||
// + "\n";
|
||||
return super.toString() + "\nisInherited = " + isInherited
|
||||
+ " isOveridden = " + isImplemented
|
||||
+ " msc[" + methodSignatureConstraint.size() + "] = " + methodSignatureConstraint
|
||||
//" + extendsContraint: " + (extendConstraint != null ? extendConstraint.toStringBase() : "null" )
|
||||
+ "\n";
|
||||
}
|
||||
|
||||
public String toStringBase() {
|
||||
|
||||
@@ -4,7 +4,6 @@ import de.dhbwstuttgart.server.packet.dataContainers.ISerializableData;
|
||||
import de.dhbwstuttgart.server.packet.dataContainers.KeyStorage;
|
||||
import de.dhbwstuttgart.server.packet.dataContainers.serialized.SerialMap;
|
||||
import de.dhbwstuttgart.typeinference.unify.UnifyContext;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -14,8 +13,6 @@ import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
|
||||
|
||||
import static de.dhbwstuttgart.core.JavaTXCompiler.q;
|
||||
|
||||
|
||||
public class Pair implements Serializable, IConstraintElement, ISerializableData {
|
||||
public final RefTypeOrTPHOrWildcardOrGeneric TA1;
|
||||
@@ -176,27 +173,5 @@ public class Pair implements Serializable, IConstraintElement, ISerializableData
|
||||
if (location != null) pair.location = SourceLoc.fromSerial(location);
|
||||
return pair;
|
||||
}
|
||||
|
||||
public String toDot(String color) {
|
||||
|
||||
return q(this.TA1.toString()) +
|
||||
" -> " +
|
||||
q(this.TA2.toString()) +
|
||||
" [label=" +
|
||||
q(this.GetOperator().toString()) +
|
||||
",color=" + q(color) + "]" +
|
||||
";\n";
|
||||
}
|
||||
|
||||
public String toDot() {
|
||||
|
||||
return q(this.TA1.toString()) +
|
||||
" -> " +
|
||||
q(this.TA2.toString()) +
|
||||
" [label=" +
|
||||
q(this.GetOperator().toString()) +
|
||||
"]" +
|
||||
";\n";
|
||||
}
|
||||
}
|
||||
// ino.end
|
||||
|
||||
@@ -35,8 +35,8 @@ public class TYPE {
|
||||
this.definedClasses = definedClasses;
|
||||
}
|
||||
|
||||
public ConstraintSet<Pair> getConstraints() {
|
||||
ConstraintSet<Pair> ret = new ConstraintSet<>();
|
||||
public ConstraintSet getConstraints() {
|
||||
ConstraintSet ret = new ConstraintSet();
|
||||
for (ClassOrInterface cl : definedClasses) {
|
||||
Set<ClassOrInterface> allClasses = TypeUnifyTaskHelper.getPresizedHashSet(allAvailableClasses.size());
|
||||
allClasses.addAll(allAvailableClasses);
|
||||
@@ -45,9 +45,9 @@ public class TYPE {
|
||||
return ret;
|
||||
}
|
||||
|
||||
private ConstraintSet<Pair> getConstraintsClass(ClassOrInterface cl, TypeInferenceInformation info) {
|
||||
ConstraintSet<Pair> ret = new ConstraintSet<>();
|
||||
ConstraintSet<Pair> methConstrains;
|
||||
private ConstraintSet getConstraintsClass(ClassOrInterface cl, TypeInferenceInformation info) {
|
||||
ConstraintSet ret = new ConstraintSet();
|
||||
ConstraintSet methConstrains;
|
||||
for(Method m : cl.getMethods()){
|
||||
ret.addAll(methConstrains = getConstraintsMethod(m,info, cl));
|
||||
m.constraints.addAll(methConstrains);
|
||||
@@ -86,11 +86,11 @@ public class TYPE {
|
||||
}
|
||||
*/
|
||||
|
||||
private ConstraintSet<Pair> getConstraintsMethod(Method m, TypeInferenceInformation info, ClassOrInterface currentClass) {
|
||||
if(m.block == null)return new ConstraintSet<Pair>(); //Abstrakte Methoden generieren keine Constraints
|
||||
private ConstraintSet getConstraintsMethod(Method m, TypeInferenceInformation info, ClassOrInterface currentClass) {
|
||||
if(m.block == null)return new ConstraintSet(); //Abstrakte Methoden generieren keine Constraints
|
||||
TypeInferenceBlockInformation blockInfo = new TypeInferenceBlockInformation(info.getAvailableClasses(), currentClass, m);
|
||||
TYPEStmt methodScope = new TYPEStmt(blockInfo);
|
||||
ConstraintSet<Pair> constraintSet = new ConstraintSet<>();
|
||||
ConstraintSet constraintSet = new ConstraintSet();
|
||||
|
||||
if (m.name.equals("main") && Modifier.isStatic(m.modifier) && m.getParameterList().getFormalparalist().size() == 1) {
|
||||
// Add constraint for main method
|
||||
|
||||
@@ -953,20 +953,48 @@ public class TestComplete {
|
||||
var list1 = ConsCtor.newInstance(1, ConsCtor.newInstance(2, ConsCtor.newInstance(3, EmptyCtor.newInstance())));
|
||||
var list2 = ConsCtor.newInstance(4, ConsCtor.newInstance(5, ConsCtor.newInstance(6, EmptyCtor.newInstance())));
|
||||
|
||||
var append = clazz.getDeclaredMethod("append", Cons, Cons);
|
||||
var append = clazz.getDeclaredMethod("append", List, List);
|
||||
System.out.println(append.invoke(instance, list1, list2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPatternMatchingSpecificity() throws Exception {
|
||||
var classFiles = generateClassFiles(createClassLoader(), "PatternMatchingSpecificity.jav");
|
||||
|
||||
var clazz = classFiles.get("PatternMatchingSpecificity");
|
||||
var instance = clazz.getDeclaredConstructor().newInstance();
|
||||
var R = classFiles.get("R");
|
||||
|
||||
Integer i = 20;
|
||||
var r = R.getDeclaredConstructor(Number.class).newInstance(i);
|
||||
|
||||
var m = clazz.getDeclaredMethod("m", R);
|
||||
assertEquals(1, m.invoke(instance, r));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPatternMatchingZip() throws Exception {
|
||||
//ConsoleInterface.logLevel = Logger.LogLevel.DEBUG;
|
||||
var classFiles = generateClassFiles(createClassLoader(), "PatternMatching.jav");
|
||||
var clazz = classFiles.get("PatternMatching");
|
||||
var instance = clazz.getDeclaredConstructor().newInstance();
|
||||
|
||||
var Cons = classFiles.get("Cons");
|
||||
var Empty = classFiles.get("Empty");
|
||||
var List = classFiles.get("List");
|
||||
|
||||
var ConsCtor = Cons.getDeclaredConstructor(Object.class, List);
|
||||
var EmptyCtor = Empty.getDeclaredConstructor();
|
||||
|
||||
var list1 = ConsCtor.newInstance(1, ConsCtor.newInstance(2, ConsCtor.newInstance(3, EmptyCtor.newInstance())));
|
||||
var list2 = ConsCtor.newInstance(4, ConsCtor.newInstance(5, ConsCtor.newInstance(6, EmptyCtor.newInstance())));
|
||||
|
||||
var zip = clazz.getDeclaredMethod("zip", List, List);
|
||||
System.out.println(zip.invoke(instance, list1, list2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPatternMatchingZipJava() throws Exception {
|
||||
ConsoleInterface.logLevel = Logger.LogLevel.DEBUG;
|
||||
var classFiles = generateClassFiles(createClassLoader(), false, "PatternMatchingJava.jav", "PatternMatchingJava2.jav");
|
||||
var clazz = classFiles.get("PatternMatchingJava");
|
||||
var instance = clazz.getDeclaredConstructor().newInstance();
|
||||
@@ -1536,10 +1564,24 @@ public class TestComplete {
|
||||
// TODO This logs output that we should validate
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug389() throws Exception {
|
||||
var classFiles = generateClassFiles(createClassLoader(), false, "Bug389.jav", "Bug389Main.jav");
|
||||
var clazz = classFiles.get("Bug389Main");
|
||||
clazz.getDeclaredMethod("main", List.class).invoke(null, List.of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug390() throws Exception {
|
||||
var classFiles = generateClassFiles(createClassLoader(), "Bug390.jav");
|
||||
var clazz = classFiles.get("Bug390");
|
||||
clazz.getDeclaredMethod("main", List.class).invoke(null, List.of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug392() throws Exception {
|
||||
var classFiles = generateClassFiles(createClassLoader(), "Bug392.jav");
|
||||
var clazz = classFiles.get("Bug392");
|
||||
clazz.getDeclaredMethod("main", List.class).invoke(null, List.of());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,14 +19,11 @@ public class TestTypeDeployment {
|
||||
var path = Path.of(System.getProperty("user.dir"), "/resources/bytecode/javFiles/Cycle.jav");
|
||||
var file = path.toFile();
|
||||
var compiler = new JavaTXCompiler(file);
|
||||
compiler.parseAll();
|
||||
var parsedSource = compiler.sourceFiles.get(file);
|
||||
var tiResults = compiler.typeInference(file);
|
||||
Set<TypeInsert> tips = new HashSet<>();
|
||||
|
||||
for (var sf : compiler.sourceFiles.values()) {
|
||||
Map<JavaClassName, byte[]> bytecode = compiler.generateBytecode(sf, tiResults);
|
||||
}
|
||||
|
||||
System.out.println(compiler.getGeneratedGenerics());
|
||||
|
||||
for (int i = 0; i < tiResults.size(); i++) {
|
||||
|
||||
@@ -59,6 +59,7 @@ public class ServerTest {
|
||||
|
||||
// get information from the compiler
|
||||
JavaTXCompiler compiler = new JavaTXCompiler(List.of(file));
|
||||
compiler.parseAll();
|
||||
|
||||
// NOW: simulate the call to method typeInference. Once via server and once locally
|
||||
// if everything works, they should neither interfere with each other nor differ in their result
|
||||
|
||||
@@ -49,6 +49,7 @@ public class TestGenerics {
|
||||
private static Result computeGenerics(String filename) throws IOException, ClassNotFoundException {
|
||||
var file = Path.of(rootDirectory + filename).toFile();
|
||||
var compiler = new JavaTXCompiler(List.of(file), List.of(file.getParentFile()), new File(bytecodeDirectory), true);
|
||||
compiler.parseAll();
|
||||
var inference = compiler.typeInference(file);
|
||||
compiler.generateBytecode(new File(bytecodeDirectory), inference);
|
||||
var sf = compiler.sourceFiles.get(file);
|
||||
|
||||
Reference in New Issue
Block a user