forked from JavaTX/JavaCompilerCore
Filter out cycles and infima
This commit is contained in:
parent
d7380c6cb7
commit
560f0c5a6f
@ -717,9 +717,8 @@ public class Codegen {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TargetReturn ret: {
|
case TargetReturn ret: {
|
||||||
generate(state, ret.expression());
|
|
||||||
|
|
||||||
if (ret.expression() != null) {
|
if (ret.expression() != null) {
|
||||||
|
generate(state, ret.expression());
|
||||||
boxPrimitive(state, ret.expression().type());
|
boxPrimitive(state, ret.expression().type());
|
||||||
mv.visitInsn(ARETURN);
|
mv.visitInsn(ARETURN);
|
||||||
} else mv.visitInsn(RETURN);
|
} else mv.visitInsn(RETURN);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package de.dhbwstuttgart.target.generate;
|
package de.dhbwstuttgart.target.generate;
|
||||||
|
|
||||||
|
import de.dhbwstuttgart.parser.NullToken;
|
||||||
import de.dhbwstuttgart.syntaxtree.*;
|
import de.dhbwstuttgart.syntaxtree.*;
|
||||||
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
|
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
|
||||||
import de.dhbwstuttgart.syntaxtree.statement.*;
|
import de.dhbwstuttgart.syntaxtree.statement.*;
|
||||||
@ -226,6 +227,7 @@ public class ASTToTargetAST {
|
|||||||
result.add(new PairTPHequalRefTypeOrWildcardType(pair.right, OBJECT));
|
result.add(new PairTPHequalRefTypeOrWildcardType(pair.right, OBJECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eliminateCyclesAndInfima(result);
|
||||||
System.out.println(method.name + ": " + result);
|
System.out.println(method.name + ": " + result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -265,9 +267,53 @@ public class ASTToTargetAST {
|
|||||||
findAllBounds(field.getType(), result);
|
findAllBounds(field.getType(), result);
|
||||||
}
|
}
|
||||||
computedGenericsOfClasses.put(classOrInterface, result);
|
computedGenericsOfClasses.put(classOrInterface, result);
|
||||||
|
eliminateCyclesAndInfima(result);
|
||||||
|
System.out.println("Class " + classOrInterface.getClassName().getClassName() + ": " + result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void eliminateCyclesAndInfima(Set<ResultPair<?, ?>> input) {
|
||||||
|
// Eliminate cycles
|
||||||
|
var cycles = findCycles(input);
|
||||||
|
for (var cycle : cycles) {
|
||||||
|
var newTph = TypePlaceholder.fresh(new NullToken());
|
||||||
|
input.add(new PairTPHequalRefTypeOrWildcardType(newTph, OBJECT));
|
||||||
|
cycle.add(cycle.get(0)); // Make it a complete cycle
|
||||||
|
for (var i = 0; i < cycle.size() - 1; i++) {
|
||||||
|
var left = cycle.get(i);
|
||||||
|
var right = cycle.get(i + 1);
|
||||||
|
var pair = new PairTPHsmallerTPH(left, right);
|
||||||
|
input.remove(pair);
|
||||||
|
equality.put(left, newTph);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Eliminate infima
|
||||||
|
var foundInfima = false;
|
||||||
|
do {
|
||||||
|
foundInfima = false;
|
||||||
|
for (var constraint : new HashSet<>(input)) {
|
||||||
|
var left = (TypePlaceholder) constraint.getLeft();
|
||||||
|
Set<PairTPHsmallerTPH> infima = new HashSet<>();
|
||||||
|
for (var pair : input) {
|
||||||
|
if (pair instanceof PairTPHsmallerTPH stph)
|
||||||
|
if (pair.getLeft().equals(constraint.getLeft()))
|
||||||
|
infima.add(stph);
|
||||||
|
}
|
||||||
|
if (infima.size() > 1) {
|
||||||
|
foundInfima = true;
|
||||||
|
var newTph = TypePlaceholder.fresh(new NullToken());
|
||||||
|
input.add(new PairTPHsmallerTPH(left, newTph));
|
||||||
|
input.add(new PairTPHequalRefTypeOrWildcardType(newTph, OBJECT));
|
||||||
|
input.removeAll(infima);
|
||||||
|
for (var infimum : infima) {
|
||||||
|
equality.put(infimum.right, newTph);
|
||||||
|
input.removeIf(pair -> pair.getLeft().equals(infimum.right));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (foundInfima);
|
||||||
|
}
|
||||||
|
|
||||||
TargetType get(TypePlaceholder tph) {
|
TargetType get(TypePlaceholder tph) {
|
||||||
if (equality.containsKey(tph)) {
|
if (equality.containsKey(tph)) {
|
||||||
return get(equality.get(tph));
|
return get(equality.get(tph));
|
||||||
@ -286,6 +332,92 @@ public class ASTToTargetAST {
|
|||||||
this.sigma = all.get(0);
|
this.sigma = all.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Set<TypePlaceholder> allNodes(Set<ResultPair<?, ?>> input) {
|
||||||
|
return input.stream().map(pair -> (TypePlaceholder) pair.getLeft()).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
static Set<TypePlaceholder> outgoingEdgesOf(TypePlaceholder tph, Set<ResultPair<?, ?>> input) {
|
||||||
|
return input.stream()
|
||||||
|
.filter(pair -> pair instanceof PairTPHsmallerTPH && pair.getLeft().equals(tph))
|
||||||
|
.map(pair -> (TypePlaceholder) pair.getRight()).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean containsEdge(TypePlaceholder a, TypePlaceholder b, Set<ResultPair<?, ?>> input) {
|
||||||
|
return input.stream().anyMatch(pair -> pair.getLeft().equals(a) && pair.getRight().equals(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tiernan simple cycles algorithm
|
||||||
|
static Set<List<TypePlaceholder>> findCycles(Set<ResultPair<?, ?>> input) {
|
||||||
|
Map<TypePlaceholder, Integer> indices = new HashMap<>();
|
||||||
|
List<TypePlaceholder> path = new ArrayList<>();
|
||||||
|
Set<TypePlaceholder> pathSet = new HashSet<>();
|
||||||
|
Map<TypePlaceholder, Set<TypePlaceholder>> blocked = new HashMap<>();
|
||||||
|
Set<List<TypePlaceholder>> cycles = new HashSet<>();
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
for (var tph : allNodes(input)) {
|
||||||
|
blocked.put(tph, new HashSet<>());
|
||||||
|
indices.put(tph, index++);
|
||||||
|
}
|
||||||
|
|
||||||
|
var vertexIterator = allNodes(input).iterator();
|
||||||
|
if (!vertexIterator.hasNext()) return cycles;
|
||||||
|
|
||||||
|
TypePlaceholder startOfPath = null;
|
||||||
|
TypePlaceholder endOfPath = vertexIterator.next();
|
||||||
|
TypePlaceholder temp = null;
|
||||||
|
int endIndex = 0;
|
||||||
|
boolean extensionFound = false;
|
||||||
|
path.add(endOfPath);
|
||||||
|
pathSet.add(endOfPath);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
do {
|
||||||
|
extensionFound = false;
|
||||||
|
for (TypePlaceholder n : outgoingEdgesOf(endOfPath, input)) {
|
||||||
|
int cmp = indices.get(n).compareTo(indices.get(path.get(0)));
|
||||||
|
if ((cmp > 0) && !pathSet.contains(n) && !blocked.get(endOfPath).contains(n)) {
|
||||||
|
path.add(n);
|
||||||
|
pathSet.add(n);
|
||||||
|
endOfPath = n;
|
||||||
|
extensionFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (extensionFound);
|
||||||
|
|
||||||
|
startOfPath = path.get(0);
|
||||||
|
if (containsEdge(endOfPath, startOfPath, input)) {
|
||||||
|
List<TypePlaceholder> cycle = new ArrayList<>(path);
|
||||||
|
cycles.add(cycle);
|
||||||
|
}
|
||||||
|
if (path.size() > 1) {
|
||||||
|
blocked.get(endOfPath).clear();
|
||||||
|
endIndex = path.size() - 1;
|
||||||
|
path.remove(endIndex);
|
||||||
|
pathSet.remove(endOfPath);
|
||||||
|
--endIndex;
|
||||||
|
temp = endOfPath;
|
||||||
|
endOfPath = path.get(endIndex);
|
||||||
|
blocked.get(endOfPath).add(temp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (vertexIterator.hasNext()) {
|
||||||
|
path.clear();
|
||||||
|
pathSet.clear();
|
||||||
|
endOfPath = vertexIterator.next();
|
||||||
|
path.add(endOfPath);
|
||||||
|
pathSet.add(endOfPath);
|
||||||
|
for (TypePlaceholder tph : blocked.keySet()) {
|
||||||
|
blocked.get(tph).clear();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return cycles;
|
||||||
|
}
|
||||||
|
|
||||||
Set<TargetGeneric> convert(Set<ResultPair<?, ?>> result) {
|
Set<TargetGeneric> convert(Set<ResultPair<?, ?>> result) {
|
||||||
return result.stream().map(p -> {
|
return result.stream().map(p -> {
|
||||||
if (p instanceof PairTPHsmallerTPH pair) {
|
if (p instanceof PairTPHsmallerTPH pair) {
|
||||||
@ -321,9 +453,10 @@ public class ASTToTargetAST {
|
|||||||
|
|
||||||
for (var s : all) {
|
for (var s : all) {
|
||||||
sigma = s;
|
sigma = s;
|
||||||
|
var generics = sigma.generics(owner, input);
|
||||||
List<MethodParameter> params = convert(input.getParameterList());
|
List<MethodParameter> params = convert(input.getParameterList());
|
||||||
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
|
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
|
||||||
result.add(new TargetConstructor(input.modifier, convert(sigma.generics(owner, input)), params, convert(input.block)));
|
result.add(new TargetConstructor(input.modifier, convert(generics), params, convert(input.block)));
|
||||||
parameterSet.add(params);
|
parameterSet.add(params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -339,11 +472,12 @@ public class ASTToTargetAST {
|
|||||||
|
|
||||||
for (var s : all) {
|
for (var s : all) {
|
||||||
sigma = s;
|
sigma = s;
|
||||||
|
var generics = sigma.generics(owner, input);
|
||||||
List<MethodParameter> params = convert(input.getParameterList());
|
List<MethodParameter> params = convert(input.getParameterList());
|
||||||
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
|
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
|
||||||
result.add(new TargetMethod(
|
result.add(new TargetMethod(
|
||||||
input.modifier,
|
input.modifier,
|
||||||
input.name, convert(sigma.generics(owner, input)), params,
|
input.name, convert(generics), params,
|
||||||
convert(input.getReturnType()),
|
convert(input.getReturnType()),
|
||||||
convert(input.block)
|
convert(input.block)
|
||||||
));
|
));
|
||||||
|
@ -62,4 +62,25 @@ public class ASTToTypedTargetAST {
|
|||||||
var tphAndGenerics = TestCodegen.generateClass(converter.convert(classes.get(0)));
|
var tphAndGenerics = TestCodegen.generateClass(converter.convert(classes.get(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cycles() throws Exception {
|
||||||
|
var file = Path.of(System.getProperty("user.dir"), "/src/test/resources/bytecode/javFiles/Cycle.jav").toFile();
|
||||||
|
var compiler = new JavaTXCompiler(file);
|
||||||
|
var resultSet = compiler.typeInference();
|
||||||
|
var converter = new ASTToTargetAST(resultSet);
|
||||||
|
var classes = compiler.sourceFiles.get(file).getClasses();
|
||||||
|
|
||||||
|
var cycle = TestCodegen.generateClass(converter.convert(classes.get(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void infimum() throws Exception {
|
||||||
|
var file = Path.of(System.getProperty("user.dir"), "/src/test/resources/bytecode/javFiles/Infimum.jav").toFile();
|
||||||
|
var compiler = new JavaTXCompiler(file);
|
||||||
|
var resultSet = compiler.typeInference();
|
||||||
|
var converter = new ASTToTargetAST(resultSet);
|
||||||
|
var classes = compiler.sourceFiles.get(file).getClasses();
|
||||||
|
|
||||||
|
var infimum = TestCodegen.generateClass(converter.convert(classes.get(0)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
6
src/test/resources/bytecode/javFiles/Cycle.jav
Normal file
6
src/test/resources/bytecode/javFiles/Cycle.jav
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
class Cycle {
|
||||||
|
m(x, y) {
|
||||||
|
y = x;
|
||||||
|
x = y;
|
||||||
|
}
|
||||||
|
}
|
6
src/test/resources/bytecode/javFiles/Infimum.jav
Normal file
6
src/test/resources/bytecode/javFiles/Infimum.jav
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
class Infimum {
|
||||||
|
m(x, y, z) {
|
||||||
|
y = x;
|
||||||
|
z = x;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user