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;
|
||||
}
|
||||
case TargetReturn ret: {
|
||||
generate(state, ret.expression());
|
||||
|
||||
if (ret.expression() != null) {
|
||||
generate(state, ret.expression());
|
||||
boxPrimitive(state, ret.expression().type());
|
||||
mv.visitInsn(ARETURN);
|
||||
} else mv.visitInsn(RETURN);
|
||||
|
@ -1,5 +1,6 @@
|
||||
package de.dhbwstuttgart.target.generate;
|
||||
|
||||
import de.dhbwstuttgart.parser.NullToken;
|
||||
import de.dhbwstuttgart.syntaxtree.*;
|
||||
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
|
||||
import de.dhbwstuttgart.syntaxtree.statement.*;
|
||||
@ -226,6 +227,7 @@ public class ASTToTargetAST {
|
||||
result.add(new PairTPHequalRefTypeOrWildcardType(pair.right, OBJECT));
|
||||
}
|
||||
|
||||
eliminateCyclesAndInfima(result);
|
||||
System.out.println(method.name + ": " + result);
|
||||
|
||||
return result;
|
||||
@ -265,9 +267,53 @@ public class ASTToTargetAST {
|
||||
findAllBounds(field.getType(), result);
|
||||
}
|
||||
computedGenericsOfClasses.put(classOrInterface, result);
|
||||
eliminateCyclesAndInfima(result);
|
||||
System.out.println("Class " + classOrInterface.getClassName().getClassName() + ": " + 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) {
|
||||
if (equality.containsKey(tph)) {
|
||||
return get(equality.get(tph));
|
||||
@ -286,6 +332,92 @@ public class ASTToTargetAST {
|
||||
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) {
|
||||
return result.stream().map(p -> {
|
||||
if (p instanceof PairTPHsmallerTPH pair) {
|
||||
@ -321,9 +453,10 @@ public class ASTToTargetAST {
|
||||
|
||||
for (var s : all) {
|
||||
sigma = s;
|
||||
var generics = sigma.generics(owner, input);
|
||||
List<MethodParameter> params = convert(input.getParameterList());
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -339,11 +472,12 @@ public class ASTToTargetAST {
|
||||
|
||||
for (var s : all) {
|
||||
sigma = s;
|
||||
var generics = sigma.generics(owner, input);
|
||||
List<MethodParameter> params = convert(input.getParameterList());
|
||||
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
|
||||
result.add(new TargetMethod(
|
||||
input.modifier,
|
||||
input.name, convert(sigma.generics(owner, input)), params,
|
||||
input.name, convert(generics), params,
|
||||
convert(input.getReturnType()),
|
||||
convert(input.block)
|
||||
));
|
||||
|
@ -62,4 +62,25 @@ public class ASTToTypedTargetAST {
|
||||
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