mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-15 08:18:55 +00:00
optimized alternative collapsing
only collapse alternative if the result is smaller than the uncollapsed version
This commit is contained in:
parent
4a9667ec4e
commit
8970ef67d4
3 changed files with 53 additions and 3 deletions
|
@ -802,7 +802,25 @@ public class HoistingProcessorTest extends AbstractXtextTests {
|
||||||
assertFalse(guard.isTrivial());
|
assertFalse(guard.isTrivial());
|
||||||
assertTrue(guard.hasTerminal());
|
assertTrue(guard.hasTerminal());
|
||||||
|
|
||||||
assertEquals("(" + keyword("a", 2) + " || " + keyword("b", 1) + " || ((p0) && (p2))) && (" + keyword("b", 2) + " || " + keyword("b", 1) + " || ((p0) && (p3))) && (" + keyword("a", 1) + " || (p1))", guard.render());
|
// collapsed version is actually not optimal
|
||||||
|
//assertEquals("(" + keyword("a", 2) + " || " + keyword("b", 1) + " || ((p0) && (p2))) && (" + keyword("b", 2) + " || " + keyword("b", 1) + " || ((p0) && (p3))) && (" + keyword("a", 1) + " || (p1))", guard.render());
|
||||||
|
assertEquals(
|
||||||
|
"(" +
|
||||||
|
keyword("b", 1) + " || " +
|
||||||
|
"(" +
|
||||||
|
"(p0) && (" +
|
||||||
|
keyword("a", 2) + " || " +
|
||||||
|
"(p2)" +
|
||||||
|
") && (" +
|
||||||
|
keyword("b", 2) + " || " +
|
||||||
|
"(p3)" +
|
||||||
|
")" +
|
||||||
|
")" +
|
||||||
|
") && (" +
|
||||||
|
keyword("a", 1) + " || " +
|
||||||
|
"(p1)" +
|
||||||
|
")",
|
||||||
|
guard.render());
|
||||||
}
|
}
|
||||||
|
|
||||||
// currently not able to find optimal solution
|
// currently not able to find optimal solution
|
||||||
|
@ -833,7 +851,27 @@ public class HoistingProcessorTest extends AbstractXtextTests {
|
||||||
//assertEquals("(" + keyword("a", 1) + " || (" + keyword("c", 3) + " && " + eof(3) + ") || ((p0) && (p2))) && (" + keyword("c", 1) + " || ((p0) && (p3))) && (" + keyword("d", 3) + " || (p1))", guard.render());
|
//assertEquals("(" + keyword("a", 1) + " || (" + keyword("c", 3) + " && " + eof(3) + ") || ((p0) && (p2))) && (" + keyword("c", 1) + " || ((p0) && (p3))) && (" + keyword("d", 3) + " || (p1))", guard.render());
|
||||||
|
|
||||||
// still valid but non-optimal
|
// still valid but non-optimal
|
||||||
assertEquals("(" + keyword("a", 1) + " || (" + keyword("a", 3)+ " && " + keyword("b", 3) + " && " + keyword("c", 3) + " && " + eof(3) + ") || ((p0) && (p2))) && (" + keyword("b", 1) + " || (" + keyword("a", 3)+ " && " + keyword("b", 3) + " && " + keyword("c", 3) + " && " + eof(3) + ") || ((p0) && (p3))) && (" + keyword("d", 3) + " || (p1))", guard.render());
|
assertEquals(
|
||||||
|
"(" +
|
||||||
|
"(" +
|
||||||
|
keyword("a", 3) + " && " +
|
||||||
|
keyword("b", 3) + " && " +
|
||||||
|
keyword("c", 3) + " && " +
|
||||||
|
eof(3) +
|
||||||
|
") || (" +
|
||||||
|
"(p0) && (" +
|
||||||
|
keyword("a", 1) + " || " +
|
||||||
|
"(p2)" +
|
||||||
|
") && (" +
|
||||||
|
keyword("b", 1) + " || " +
|
||||||
|
"(p3)" +
|
||||||
|
")" +
|
||||||
|
")" +
|
||||||
|
") && (" +
|
||||||
|
keyword("d", 3) + " || " +
|
||||||
|
"(p1)" +
|
||||||
|
")",
|
||||||
|
guard.render());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -31,9 +31,19 @@ public class AlternativesGuard implements HoistingGuard {
|
||||||
}
|
}
|
||||||
|
|
||||||
public AlternativesGuard(List<PathGuard> paths) {
|
public AlternativesGuard(List<PathGuard> paths) {
|
||||||
|
// collapsing nested alternatives might reduce output size
|
||||||
|
// -> try both and use smaller one
|
||||||
|
|
||||||
|
this.paths = paths;
|
||||||
|
int lengthWithoutCollapse = render().length();
|
||||||
this.paths = PathGuard.collapse(paths);
|
this.paths = PathGuard.collapse(paths);
|
||||||
|
int lengthWithCollapse = render().length();
|
||||||
|
|
||||||
|
if (lengthWithoutCollapse < lengthWithCollapse)
|
||||||
|
this.paths = paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// package private so PathGuard can access this method
|
// package private so PathGuard can access this method
|
||||||
List<PathGuard> getPaths() {
|
List<PathGuard> getPaths() {
|
||||||
return paths;
|
return paths;
|
||||||
|
|
|
@ -28,8 +28,10 @@ public class TokenSequenceGuard implements TokenGuard {
|
||||||
|
|
||||||
public TokenSequenceGuard(Collection<? extends TokenGuard> sequence) {
|
public TokenSequenceGuard(Collection<? extends TokenGuard> sequence) {
|
||||||
Set<Integer> checkedPositions = new HashSet<>();
|
Set<Integer> checkedPositions = new HashSet<>();
|
||||||
|
// remove all guards from sequences who's positions are already in the sequence
|
||||||
this.sequence = sequence.stream()
|
this.sequence = sequence.stream()
|
||||||
.flatMap(g -> {
|
.flatMap(g -> {
|
||||||
|
// special case: reduce TokenSequenceGuards
|
||||||
if (g instanceof TokenSequenceGuard) {
|
if (g instanceof TokenSequenceGuard) {
|
||||||
return ((TokenSequenceGuard) g).sequence.stream()
|
return ((TokenSequenceGuard) g).sequence.stream()
|
||||||
.filter(s -> !s.getPositions().stream()
|
.filter(s -> !s.getPositions().stream()
|
||||||
|
@ -65,7 +67,7 @@ public class TokenSequenceGuard implements TokenGuard {
|
||||||
@Override
|
@Override
|
||||||
public String render() {
|
public String render() {
|
||||||
if (sequence.size() == 1) {
|
if (sequence.size() == 1) {
|
||||||
return sequence.stream().findAny().get().render();
|
return sequence.stream().findAny().get().render();
|
||||||
} else {
|
} else {
|
||||||
return render(ContextConnective.DISJUNCTION);
|
return render(ContextConnective.DISJUNCTION);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue