Compare commits

..

9 Commits

Author SHA1 Message Date
dholle 523452f437 Write back classes
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 1m30s
2026-05-20 18:33:09 +02:00
dholle 7051b4335a Test ordering
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 1m12s
2026-05-20 13:36:10 +02:00
dholle 7daec0a291 Create bridge method
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 1m15s
2026-05-19 11:34:53 +02:00
dholle 653f704265 Deduplicate methods earlier
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 1m7s
2026-05-15 18:21:29 +02:00
dholle b36ba5e128 Group methods
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 1m9s
2026-05-15 17:30:11 +02:00
dholle a43f49cadb Make append example work again
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 1m48s
2026-05-15 16:47:20 +02:00
dholle 69292c37fc Keep working on it
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 1m48s
2026-05-15 15:32:37 +02:00
dholle 218e704272 Merge branch 'master' of ssh://gitea.hb.dhbw-stuttgart.de:2222/JavaTX/JavaCompilerCore 2026-05-15 14:01:55 +02:00
dholle e83e9a041c Work on pattern matching
SonarQube Scan / SonarQube Trigger (push) Failing after 1m45s
2026-05-14 20:48:13 +02:00
24 changed files with 465 additions and 753 deletions
@@ -1,19 +0,0 @@
import java.util.stream.Stream;
import Pair;
import java.util.function.Function;
public class Kombinatoren_After {
after (fst, snd) { //System.out.println("after2");
return () -> Stream.of(
toks -> {
return fst.apply().flatMap(x ->
x.apply(toks).flatMap(p1 ->
snd.apply().flatMap(y -> y.apply(p1.snd()).map(p2 ->
new Pair<>(new Pair<>(p1.fst(), p2.fst()), p2.snd()))))); } );
}
}
@@ -1,17 +0,0 @@
import java.util.stream.Stream;
import Pair;
import java.util.function.Function;
public class Kombinatoren_After_Lazy {
afterP (fst, snd) {
return toks -> {
return fst.apply(toks).flatMap(p1 ->
snd.apply(p1.snd()).map(p2 ->
new Pair<>(new Pair<>(p1.fst(), p2.fst()), p2.snd())));
};
}
}
@@ -1,30 +0,0 @@
import java.util.stream.Stream;
import Pair;
import java.util.function.Function;
public class Kombinatoren_Or {
orP (p1, p2) {
return ()-> Stream.concat(p1.apply(), p2.apply());
}
/*
after (fst, snd) { //System.out.println("after2");
return () -> Stream.of(
toks -> {
return fst.apply().flatMap(x ->
x.apply(toks).flatMap(p1 ->
snd.apply().flatMap(y -> y.apply(p1.snd()).map(p2 ->
new Pair<>(new Pair<>(p1.fst(), p2.fst()), p2.snd()))))); } );
}
trans (p, f) {
return () -> p.apply().map(x -> (toks -> x.apply(toks).map(pr -> new Pair<>(f.apply(pr.fst()), pr.snd() ) ) ) );
}
*/
}
@@ -1,70 +0,0 @@
import java.util.stream.Stream;
//import java.util.List;
import java.util.ArrayList;
import java.io.PrintStream;
import java.lang.System;
//import java.lang.String;
import java.lang.Boolean;
import java.util.function.Function;
import Pair;
import Kombinatoren_failure;
public class Kombinatoren_Satisfy {
kb = new Kombinatoren_failure();
satisfy(cond) {
// return () -> Stream.of (newToks -> new Kombinatoren_failure().failure().apply().map(x -> x.apply(newToks)));
//}
return () -> Stream.of (toks -> {
if(toks.isEmpty()) {
return new ArrayList<>().stream();
}
else
{
var fst = toks.getFirst();
if (cond.apply(fst))
{
//var newToks = List.copyOf(toks.subList(1, toks.size()));
var newToks = new ArrayList<>(toks);
return newToks.removeFirst();
kb.getContent(
kb.succeed(fst).apply().map(x -> x.apply(newToks))
);
// ;
}
}
}
);
}
/* () -> Stream.of (toks -> {
//System.out.println(toks);
if(toks.isEmpty())
{
return new ArrayList<>().stream();
}
else {
var fst = toks.getFirst();
if (cond.apply(fst))
{
var newToks = List.copyOf(toks.subList(1, toks.size()));
//System.out.println("satisfy ok " + fst.toString());
//return get(succeed(fst).apply().map(x -> x.apply(newToks)));
}
else {
//System.out.println("satisfy failure " + fst.toString());
//return get(failure().apply()).apply(toks);
}
return new ArrayList<>().stream();
} } ) ;
}
*/
}
@@ -1,13 +0,0 @@
import java.util.stream.Stream;
import Pair;
//import java.util.function.Function;
public class Kombinatoren_Trans {
trans (p, f) {
return () -> p.apply().map(x -> (toks -> x.apply(toks).map(pr -> new Pair<>(f.apply(pr.fst()), pr.snd() ) ) ) );
}
}
@@ -1,73 +0,0 @@
import java.util.stream.Stream;
import java.util.stream.IntStream;
import java.util.List;
import java.util.ArrayList;
import java.io.PrintStream;
import java.lang.System;
import java.util.Optional;
import java.lang.String;
import java.lang.Boolean;
import java.util.function.Function;
import Pair;
public class Kombinatoren_failure {
public getContent(s) {
return s.toList().getFirst();
}
public failure() {
return () -> Stream.of(
toks -> new ArrayList<>().stream());
}
public succeed( value) {
return () -> Stream.of(toks -> {
//System.out.println("succeed");
var al = new ArrayList<>();
al.add(new Pair<>(value, toks));
//al.forEach(x -> { System.out.println(x.toString());});
return al.stream();});
}
parser(p, inp) {
return p.map(y -> y.apply(
inp.chars().mapToObj(c -> (char) c)
.collect(Collectors.toList())))
.flatMap(x -> x)
.filter(x -> x.snd().isEmpty())
.findFirst()
.get()
.fst();
}
}
/*
satisfy(cond) {
return newToks -> failure().apply().map(x -> x.apply(newToks));
/*
return () -> Stream.of (toks -> {
if(toks.isEmpty()) {
return new ArrayList<>().stream();
}
else {
var fst = toks.getFirst();
if (cond.apply(fst)) {
var newToks = List.copyOf(toks.subList(1, toks.size()));
this.getContent(
succeed(fst)
.apply().map(x -> x.apply(newToks))
)
;
}
}
}
);
*/
}
}
*/
-27
View File
@@ -1,27 +0,0 @@
import java.util.*;
public class Pair<T, U> {
T a;
U b;
public Pair() { }
public Pair(T a, U b) {
System.out.println("Pair a; " + a + " b: " + b);
this.a = a;
this.b = b;
}
public T fst () {
return a;
}
public U snd () {
System.out.println("snd b: " + b);
return b;
}
public String toString() {
return "Pair<"+a.toString()+","+b.toString()+">";
}
}
-82
View File
@@ -1,82 +0,0 @@
import java.util.stream.Stream;
//import java.util.stream.IntStream;
//import java.util.List;
import java.util.ArrayList;
import java.io.PrintStream;
import java.lang.System;
import java.util.Optional;
import java.lang.Character;
import java.lang.String;
import java.lang.Boolean;
import java.lang.Integer;
import java.util.function.Function;
import java.util.function.Predicate;
//import java.util.function.IntFunction;
import Pair;
public class Parser {
strToList(s) {
var al;
al = new ArrayList<>();
var i = 0;
while (i < s.length()) {
al.add(s.charAt(i));
i=i+1;
}
return al;
}
/*
parser(p, inp) {
return p.map(y -> y.apply(
strToList(inp)//chars().mapToObj(c -> (Character) c)
//.toList()
))
//.flatMap(x -> x)
//.filter(x -> x.snd().isEmpty())
;
/*
.findFirst()
.get()
.fst()
;
}
*/
}
/*
satisfy(cond) {
return newToks -> failure().apply().map(x -> x.apply(newToks));
/*
return () -> Stream.of (toks -> {
if(toks.isEmpty()) {
return new ArrayList<>().stream();
}
else {
var fst = toks.getFirst();
if (cond.apply(fst)) {
var newToks = List.copyOf(toks.subList(1, toks.size()));
this.getContent(
succeed(fst)
.apply().map(x -> x.apply(newToks))
)
;
}
}
}
);
*/
}
}
*/
@@ -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; }
}
@@ -1499,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) {
@@ -1567,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);
@@ -1669,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) {
@@ -686,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>();
@@ -697,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) {
@@ -709,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);
@@ -719,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);
@@ -753,11 +770,88 @@ 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();
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);
@@ -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,19 @@ 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.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,7 +64,7 @@ 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));
}
@@ -156,190 +159,168 @@ 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())));
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 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 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;
}
return true;
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();
};
}
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);
private static Optional<TargetType> unify(TargetType a, TargetType b) {
if (Objects.equals(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()));
}
@Override
public int hashCode() {
return Objects.hashCode(a) + Objects.hashCode(b);
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) {
if (a.equals(b)) return Optional.empty();
var res = unify(a.parameters(), b.parameters());
if (res.isEmpty()) return Optional.empty();
var returnType = unify(a.returnType(), b.returnType());
if (returnType.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);
}
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);
assert txunified.isPresent();
var unifiedSignature = new Signature(junified.get(), txunified.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 List<MethodGroup> groupOverloads(ClassOrInterface input, List<Method> methods) {
var a = new HashSet<MethodGroup>();
for (var i = 0; i < methods.size(); i++) {
var method = methods.get(i);
// 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.stream().toList();
}
public TargetStructure convert(ClassOrInterface input) {
@@ -373,13 +354,29 @@ 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)
@@ -557,38 +554,117 @@ public class ASTToTargetAST {
return new TargetSwitch(switchExpr, cases, null, true);
}
private List<TargetMethod> generatePatternOverloads(ClassOrInterface clazz, List<MethodWithTphs> overloadedMethods) {
if (overloadedMethods.isEmpty()) return List.of();
// Check if we have a pattern as a parameter
var firstMethod = convert(overloadedMethods.getFirst(), overloadedMethods.getFirst().generics.javaGenerics);
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();
// 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()));
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));
// 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<MethodParameter>(Collections.nCopies(firstMethod.signature().parameters().size(), null));
TargetType resRet = null;
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)) {
resParams.set(i, pa);
continue;
}
var common = commonSealedInterface(ta, tb);
if (common.isPresent()) {
resParams.set(i, pa.withType(common.get()));
continue;
}
return Optional.empty();
}
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));
var ra = firstMethod.signature().returnType();
var rb = m.signature().returnType();
if (Objects.equals(ra, rb)) {
resRet = ra;
continue;
}
var common = commonSealedInterface(ra, rb);
if (common.isPresent()) resRet = common.get();
else return Optional.empty();
}
// Rename existing methods
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
sortBySpecificity(overloadedMethods);
var firstMethod = convert(overloadedMethods.getFirst());
if (overloadedMethods.size() == 1) return List.of(firstMethod);
var signatureParams = group.signature.java.parameters();
var res = new ArrayList<TargetMethod>();
for (var method : overloadedMethods) {
@@ -607,12 +683,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());
@@ -622,9 +692,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;
}
@@ -670,6 +738,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) {
@@ -684,14 +761,30 @@ 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);
}
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<>();
@@ -716,7 +809,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());
//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));
@@ -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;
}
}
@@ -736,12 +736,12 @@ public class TYPEStmt implements StatementVisitor {
for (int i = 0; i < foMethod.arglist.getArguments().size(); i++) {
// Zuordnung von MethoCall.signature (Argumenttypen) zu der Argumenttypen der ausgewaehlten Methode (assumption.params)
ret.add(new Pair(resolver.resolve(foMethod.signature.get(i)), resolver.resolve(assumption.getArgTypes().get(i)), PairOperator.EQUALSDOT));
ret.add(new Pair(foMethod.signature.get(i), assumption.getArgTypes().get(i), PairOperator.EQUALSDOT));
}
// Zuordnung von MethodCall.signature(ReturnType) zu dem ReturnType der ausgewaehlten Methode (assumption.returnType)
ret.add(new Pair(resolver.resolve(foMethod.signature.getLast()), resolver.resolve(assumption.getReturnType()), PairOperator.EQUALSDOT));
ret.add(new Pair(foMethod.signature.getLast(), assumption.getReturnType(), PairOperator.EQUALSDOT));
return ret;
}
@@ -755,7 +755,7 @@ public class RuleSet implements IRuleSet{
UnifyType lhsType = pair.getLhsType();
UnifyType rhsType = pair.getRhsType();
if((!(lhsType instanceof ReferenceType) && !(lhsType instanceof FunNType)) || !(rhsType instanceof ExtendsType))
if(!(lhsType instanceof ReferenceType) || !(rhsType instanceof ExtendsType))
return Optional.empty();
return Optional.of(new UnifyPair(lhsType, ((ExtendsType) rhsType).getExtendedType(), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair()));
@@ -781,7 +781,7 @@ public class RuleSet implements IRuleSet{
UnifyType lhsType = pair.getLhsType();
UnifyType rhsType = pair.getRhsType();
if((!(lhsType instanceof ReferenceType) && !(lhsType instanceof FunNType)) || !(rhsType instanceof SuperType))
if(!(lhsType instanceof ReferenceType) || !(rhsType instanceof SuperType))
return Optional.empty();
return Optional.of(new UnifyPair(((SuperType) rhsType).getSuperedType(), lhsType, PairOperator.SMALLERDOTWC, pair.getSubstitution(), pair.getBasePair()));
@@ -904,7 +904,7 @@ public class RuleSet implements IRuleSet{
var fiArgs = intf.getFunctionalInterfaceTypeArguments(refType);
var retType = fiArgs.getFirst();
var lhsArgs = intf.getFunctionalInterfaceTypeArguments(lhsType); //FALSCHRUM????
var lhsArgs = intf.getFunctionalInterfaceTypeArguments(lhsType);
var lhsRet = lhsArgs.getFirst();
Set<UnifyPair> result = new HashSet<>();
@@ -972,65 +972,15 @@ public class RuleSet implements IRuleSet{
}
@Override
public Optional<Set<UnifyPair>> smallerFunN(UnifyPair pair, IFiniteClosure fc) {
public Optional<Set<UnifyPair>> smallerFunN(UnifyPair pair) {
if(pair.getPairOp() != PairOperator.SMALLERDOT)
return Optional.empty();
UnifyType lhsType = pair.getLhsType();
UnifyType rhsType = pair.getRhsType();
if(!(rhsType instanceof FunNType))
if(!(lhsType instanceof PlaceholderType) || !(rhsType instanceof FunNType))
return Optional.empty();
/* muss nach angepasst werden */
//FunN$$<...> <. FunctinalInterface<...> wird umgewandelt in FunN$$<...> <. FunN$$<... args aus FuntionalInterface ...>
if (lhsType instanceof ReferenceType) {
UnifyType typeFI = pair.getLhsType();
Optional<UnifyType> opt = fc.getRightHandedFunctionalInterfaceType(typeFI.getName());
if(!opt.isPresent())
return Optional.empty();
if (!(typeFI instanceof ReferenceType refType) || !(refType instanceof FunInterfaceType intf))
return Optional.empty();
var fiArgs = intf.getFunctionalInterfaceTypeArguments(refType);
var retType = fiArgs.getFirst();
var rhsArgs = intf.getFunctionalInterfaceTypeArguments(rhsType);
var rhsRet = rhsArgs.getFirst();
Set<UnifyPair> result = new HashSet<>();
//if (retType instanceof ExtendsType) {
result.add(new UnifyPair(retType, rhsRet, PairOperator.SMALLER));
//} else if (retType instanceof SuperType) {
// return Optional.empty();
//} else {
// result.add(new UnifyPair(lhsRet, retType, PairOperator.EQUALSDOT));
//}
for (var i = 1; i < fiArgs.size(); i++) {
var rh = rhsArgs.get(i);
var lh = fiArgs.get(i);
//if (rh instanceof SuperType) {
result.add(new UnifyPair(rh, lh, PairOperator.SMALLER));
//} else if (rh instanceof ExtendsType) {
// return Optional.empty();
//} else {
// result.add(new UnifyPair(lh, rh, PairOperator.EQUALSDOT));
//}
}
return Optional.of(result);
}
else {
if(!(lhsType instanceof PlaceholderType))
return Optional.empty();
}
FunNType funNRhsType = (FunNType) rhsType;
@@ -1067,122 +1017,7 @@ public class RuleSet implements IRuleSet{
return Optional.of(result);
}
@Override
public Optional<Set<UnifyPair>> reduceFIFunN(UnifyPair pair, IFiniteClosure fc) {
if(pair.getPairOp() != PairOperator.EQUALSDOT)
return Optional.empty();
UnifyType lhsType = pair.getLhsType();
UnifyType rhsType = pair.getRhsType();
if(!(rhsType instanceof FunNType))
return Optional.empty();
/* muss nach angepasst werden */
//FunN$$<...> <. FunctinalInterface<...> wird umgewandelt in FunN$$<...> <. FunN$$<... args aus FuntionalInterface ...>
if (lhsType instanceof ReferenceType) {
UnifyType typeFI = pair.getLhsType();
Optional<UnifyType> opt = fc.getRightHandedFunctionalInterfaceType(typeFI.getName());
if(!opt.isPresent())
return Optional.empty();
if (!(typeFI instanceof ReferenceType refType) || !(refType instanceof FunInterfaceType intf))
return Optional.empty();
var fiArgs = intf.getFunctionalInterfaceTypeArguments(refType);
var retType = fiArgs.getFirst();
var rhsArgs = intf.getFunctionalInterfaceTypeArguments(rhsType);
var rhsRet = rhsArgs.getFirst();
Set<UnifyPair> result = new HashSet<>();
//if (retType instanceof ExtendsType) {
result.add(new UnifyPair(retType, rhsRet, PairOperator.EQUALSDOT));
//} else if (retType instanceof SuperType) {
// return Optional.empty();
//} else {
// result.add(new UnifyPair(lhsRet, retType, PairOperator.EQUALSDOT));
//}
for (var i = 1; i < fiArgs.size(); i++) {
var rh = rhsArgs.get(i);
var lh = fiArgs.get(i);
//if (rh instanceof SuperType) {
result.add(new UnifyPair(rh, lh, PairOperator.EQUALSDOT));
//} else if (rh instanceof ExtendsType) {
// return Optional.empty();
//} else {
// result.add(new UnifyPair(lh, rh, PairOperator.EQUALSDOT));
//}
}
return Optional.of(result);
}
else {
return Optional.empty();
}
}
@Override
public Optional<Set<UnifyPair>> reduceFunNFi(UnifyPair pair, IFiniteClosure fc) {
if(pair.getPairOp() != PairOperator.EQUALSDOT)
return Optional.empty();
UnifyType lhsType = pair.getLhsType();
UnifyType rhsType = pair.getRhsType();
if(!(lhsType instanceof FunNType))
return Optional.empty();
//FunN$$<...> <. FunctinalInterface<...> wird umgewandelt in FunN$$<...> <. FunN$$<... args aus FuntionalInterface ...>
if (rhsType instanceof ReferenceType) {
UnifyType typeFI = pair.getRhsType();
Optional<UnifyType> opt = fc.getRightHandedFunctionalInterfaceType(typeFI.getName());
if(!opt.isPresent())
return Optional.empty();
if (!(typeFI instanceof ReferenceType refType) || !(refType instanceof FunInterfaceType intf))
return Optional.empty();
var fiArgs = intf.getFunctionalInterfaceTypeArguments(refType);
var retType = fiArgs.getFirst();
var lhsArgs = intf.getFunctionalInterfaceTypeArguments(lhsType);
var lhsRet = lhsArgs.getFirst();
Set<UnifyPair> result = new HashSet<>();
//if (retType instanceof ExtendsType) {
// result.add(new UnifyPair(lhsRet, retType, PairOperator.SMALLERDOTWC));
//} else if (retType instanceof SuperType) {
// return Optional.empty();
//} else {
result.add(new UnifyPair(lhsRet, retType, PairOperator.EQUALSDOT));
//}
for (var i = 1; i < fiArgs.size(); i++) {
var lh = lhsArgs.get(i);
var rh = fiArgs.get(i);
//if (rh instanceof SuperType) {
// result.add(new UnifyPair(lh, rh, PairOperator.SMALLERDOTWC));
//} else if (rh instanceof ExtendsType) {
// return Optional.empty();
//} else {
result.add(new UnifyPair(lh, rh, PairOperator.EQUALSDOT));
//}
}
return Optional.of(result);
}
else {
return Optional.empty();
}
}
@Override
public Optional<UnifyPair> reduceTph(UnifyPair pair) {
if(pair.getPairOp() != PairOperator.SMALLERDOTWC)
@@ -1190,7 +1025,7 @@ public class RuleSet implements IRuleSet{
UnifyType lhsType = pair.getLhsType();
UnifyType rhsType = pair.getRhsType();
if(!(lhsType instanceof PlaceholderType) || (!(rhsType instanceof ReferenceType) && !(rhsType instanceof FunNType)))
if(!(lhsType instanceof PlaceholderType) || !(rhsType instanceof ReferenceType))
return Optional.empty();
return Optional.of(new UnifyPair(lhsType, rhsType, PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair()));
@@ -1239,7 +1239,7 @@ public class TypeUnifyTask extends CancellableTask<CompletableFuture<Set<Set<Uni
// FunN Rules
optSet = optSet.isPresent() ? optSet : rules.reduceFunN(pair);
optSet = optSet.isPresent() ? optSet : rules.greaterFunN(pair, fc);
optSet = optSet.isPresent() ? optSet : rules.smallerFunN(pair, fc);
optSet = optSet.isPresent() ? optSet : rules.smallerFunN(pair);
// One of the rules has been applied
if (optSet.isPresent()) {
@@ -61,9 +61,7 @@ public interface IRuleSet {
*/
public Optional<Set<UnifyPair>> reduceFunN(UnifyPair pair);
public Optional<Set<UnifyPair>> greaterFunN(UnifyPair pair, IFiniteClosure fc);
public Optional<Set<UnifyPair>> smallerFunN(UnifyPair pair, IFiniteClosure fc);
public Optional<Set<UnifyPair>> reduceFIFunN(UnifyPair pair, IFiniteClosure fc);
public Optional<Set<UnifyPair>> reduceFunNFi(UnifyPair pair, IFiniteClosure fc);
public Optional<Set<UnifyPair>> smallerFunN(UnifyPair pair);
/**
* Checks whether the erase1-Rule applies to the pair.
@@ -684,7 +684,6 @@ public class FiniteClosure //extends Ordering<UnifyType> //entfernt PL 2018-12-1
return Optional.empty();
}
@Override
public Set<UnifyType> getAncestors(UnifyType t) {
+2 -8
View File
@@ -14,9 +14,7 @@ import org.junit.jupiter.api.Test;
import com.google.common.collect.Lists;
import de.dhbwstuttgart.core.ConsoleInterface;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.util.Logger.LogLevel;
public class AllgemeinTest {
@@ -31,7 +29,6 @@ public class AllgemeinTest {
@Test
public void test() throws Exception {
ConsoleInterface.logLevel = LogLevel.DEBUG;
//String className = "GenTest";
//String className = "Overloading_Generics";
//String className = "Generics";
@@ -66,14 +63,11 @@ public class AllgemeinTest {
//String className = "Cycle";
//String className = "TripleTest";
//String className = "WildcardList";
//String className = "List";
String className = "List";
//String className = "Box";
//String className = "GenBox";
//String className = "InnerInf";
//String className = "Foo";
String className = "Kombinatoren_failure";
//String className = "Parser";
//PL 2019-10-24: genutzt fuer unterschiedliche Tests
path = System.getProperty("user.dir")+"/resources/AllgemeinTest/" + className + ".jav";
//path = System.getProperty("user.dir")+"/src/test/resources/AllgemeinTest/Overloading_Generics.jav";
@@ -82,7 +76,7 @@ public class AllgemeinTest {
///*
compiler = new JavaTXCompiler(
Lists.newArrayList(new File(path)),
Lists.newArrayList(new File(System.getProperty("user.dir")+"/resources/AllgemeinTest/")),
Lists.newArrayList(new File(System.getProperty("user.dir")+"/resources/bytecode/classFiles/")),
new File(System.getProperty("user.dir")+"/resources/bytecode/classFiles/"), true);
//*/
compiler.generateBytecode();
+25 -6
View File
@@ -1,8 +1,6 @@
import de.dhbwstuttgart.core.ConsoleInterface;
import de.dhbwstuttgart.util.Logger;
import de.dhbwstuttgart.util.Logger.LogLevel;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -955,14 +953,29 @@ 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 = LogLevel.DEBUG;
var classFiles = generateClassFiles(createClassLoader(), false,"PatternMatchingJava2.jav", "PatternMatching.jav");
//ConsoleInterface.logLevel = Logger.LogLevel.DEBUG;
var classFiles = generateClassFiles(createClassLoader(), "PatternMatching.jav");
var clazz = classFiles.get("PatternMatching");
var instance = clazz.getDeclaredConstructor().newInstance();
}
@@ -1390,7 +1403,6 @@ public class TestComplete {
}
@Test
@Disabled("too slow")
public void testBug325() throws Exception {
var classFiles = generateClassFiles(createClassLoader(), "Bug325.jav");
var clazz = classFiles.get("Bug325");
@@ -1552,4 +1564,11 @@ public class TestComplete {
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());
}
}
+1 -4
View File
@@ -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++) {
+1
View File
@@ -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);