mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-15 08:18:55 +00:00
collapse nested alternatives to reduce generated code
doesn't work if nested alternative is in nested group doesn't work if nested alternative is in merged path
This commit is contained in:
parent
2dc2b23ad9
commit
5aba8ab724
5 changed files with 90 additions and 3 deletions
|
@ -441,7 +441,7 @@ public class HoistingProcessorTest extends AbstractXtextTests {
|
|||
HoistingGuard guard = hoistingProcessor.findGuardForElement(rule.getAlternatives());
|
||||
assertFalse(guard.isTrivial());
|
||||
assertTrue(guard.hasTerminal());
|
||||
assertEquals("((" + getSyntaxForKeywordToken("c", 3) + " || ((p0) && ((" + getSyntaxForKeywordToken("b", 2) + " || (p2)) && (" + getSyntaxForKeywordToken("c", 2) + " || (p3))))) && (" + getSyntaxForKeywordToken("d", 3) + " || (p1)))", guard.render());
|
||||
assertEquals("((" + getSyntaxForKeywordToken("b", 2) + " || ((p0) && (p2))) && (" + getSyntaxForKeywordToken("c", 2) + " || ((p0) && (p3))) && (" + getSyntaxForKeywordToken("d", 3) + " || (p1)))", guard.render());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -21,7 +21,12 @@ public class AlternativesGuard implements HoistingGuard {
|
|||
private List<PathGuard> paths;
|
||||
|
||||
private AlternativesGuard(List<PathGuard> paths) {
|
||||
this.paths = paths;
|
||||
this.paths = PathGuard.collapse(paths);
|
||||
}
|
||||
|
||||
// package private so PathGuard can access this method
|
||||
List<PathGuard> getPaths() {
|
||||
return paths;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,10 +8,14 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.xtext.util.Pair;
|
||||
import org.eclipse.xtext.util.Tuples;
|
||||
|
||||
/**
|
||||
* @author overflow - Initial contribution and API
|
||||
*/
|
||||
|
@ -19,6 +23,13 @@ public class GroupGuard implements HoistingGuard {
|
|||
private List<Guard> elementGuards = new LinkedList<>();
|
||||
private boolean hasTerminal = false;
|
||||
|
||||
public GroupGuard() {
|
||||
}
|
||||
|
||||
GroupGuard(Collection<Guard> guards) {
|
||||
guards.forEach(g -> add(g));
|
||||
}
|
||||
|
||||
public void add(Guard guard) {
|
||||
if (!guard.isTrivial())
|
||||
elementGuards.add(guard);
|
||||
|
@ -28,6 +39,23 @@ public class GroupGuard implements HoistingGuard {
|
|||
hasTerminal = true;
|
||||
}
|
||||
|
||||
Pair<List<Guard>, AlternativesGuard> deconstructPaths() {
|
||||
// there can be at most 1 AlternativesGuard since they always have tokens
|
||||
// if alternatives don't have token the result will be a MergedPathGuard
|
||||
if (!elementGuards.stream().anyMatch(g -> g instanceof AlternativesGuard)) {
|
||||
return null;
|
||||
} else {
|
||||
return Tuples.pair(
|
||||
elementGuards.stream()
|
||||
.filter(g -> !(g instanceof AlternativesGuard))
|
||||
.collect(Collectors.toList()),
|
||||
elementGuards.stream()
|
||||
.filter(g -> g instanceof AlternativesGuard)
|
||||
.map(g -> (AlternativesGuard) g)
|
||||
.findAny().get());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrivial() {
|
||||
return elementGuards.isEmpty();
|
||||
|
@ -50,5 +78,5 @@ public class GroupGuard implements HoistingGuard {
|
|||
public boolean hasTerminal() {
|
||||
return hasTerminal;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -30,6 +30,14 @@ public class MergedPathGuard implements HoistingGuard {
|
|||
pathGuards.addAll(mergedPathGuard.pathGuards);
|
||||
}
|
||||
|
||||
HoistingGuard simplify() {
|
||||
if (pathGuards.size() == 1) {
|
||||
return pathGuards.get(0);
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrivial() {
|
||||
return pathGuards.stream().anyMatch(Guard::isTrivial);
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.xtext.util.Pair;
|
||||
|
||||
/**
|
||||
* @author overflow - Initial contribution and API
|
||||
*/
|
||||
|
@ -37,4 +42,45 @@ public class PathGuard implements HoistingGuard {
|
|||
// parentheses needed since tokenGuard is never empty
|
||||
return "(" + tokenGuard.render() + " || " + hoistngGuard.render() + ")";
|
||||
}
|
||||
|
||||
public static List<PathGuard> collapse(List<PathGuard> paths) {
|
||||
// we can collapse all paths of alternatives in paths
|
||||
// because the direct paths of this alternatives instance are already token-guarded
|
||||
// against all other paths (otherwise the token guard wouldn't be distinct)
|
||||
|
||||
List<PathGuard> result = new LinkedList<>();
|
||||
|
||||
for (PathGuard path : paths) {
|
||||
HoistingGuard guard = path.hoistngGuard;
|
||||
|
||||
// TODO: allow merged paths
|
||||
if (guard instanceof MergedPathGuard) {
|
||||
guard = ((MergedPathGuard) guard).simplify();
|
||||
}
|
||||
|
||||
if (guard instanceof AlternativesGuard) {
|
||||
result.addAll(((AlternativesGuard) guard).getPaths());
|
||||
} else if (guard instanceof GroupGuard) {
|
||||
// TODO: maybe allow nested groups?
|
||||
|
||||
Pair<List<Guard>, AlternativesGuard> destructedPaths = ((GroupGuard) guard).deconstructPaths();
|
||||
if (destructedPaths == null) {
|
||||
result.add(path);
|
||||
} else {
|
||||
destructedPaths.getSecond().getPaths().stream()
|
||||
.forEach(p -> {
|
||||
// combine hoisting guards of current sub path with destructed path guards
|
||||
// construct new path guard and add to result
|
||||
GroupGuard groupGuard = new GroupGuard(destructedPaths.getFirst());
|
||||
groupGuard.add(p.hoistngGuard);
|
||||
result.add(new PathGuard(p.tokenGuard, groupGuard));
|
||||
});
|
||||
}
|
||||
} else {
|
||||
result.add(path);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue