diff --git a/org.eclipse.xtext.tests/src/org/eclipse/xtext/xtext/generator/hoisting/HoistingGeneratorTest.xtend b/org.eclipse.xtext.tests/src/org/eclipse/xtext/xtext/generator/hoisting/HoistingGeneratorTest.xtend index 1f58ba950..1a7169994 100644 --- a/org.eclipse.xtext.tests/src/org/eclipse/xtext/xtext/generator/hoisting/HoistingGeneratorTest.xtend +++ b/org.eclipse.xtext.tests/src/org/eclipse/xtext/xtext/generator/hoisting/HoistingGeneratorTest.xtend @@ -105,7 +105,7 @@ class HoistingGeneratorTest extends AbstractXtextTests { leaveRule(); }: ( - {(p0)}?=> + {p0}?=> ( ( ) @@ -115,7 +115,7 @@ class HoistingGeneratorTest extends AbstractXtextTests { } ) | - {(p1)}?=> + {p1}?=> ( ( ) @@ -202,7 +202,7 @@ class HoistingGeneratorTest extends AbstractXtextTests { leaveRule(); }: ( - {(p0)}?=> + {p0}?=> ( ) otherlv_1='a' @@ -376,7 +376,7 @@ class HoistingGeneratorTest extends AbstractXtextTests { int stackSize = keepStackSize(); } : - {(p0)}?=>( + {p0}?=>( { before(grammarAccess.getSAccess().getGroup_0()); } ( rule__S__Group_0__0 @@ -384,7 +384,7 @@ class HoistingGeneratorTest extends AbstractXtextTests { { after(grammarAccess.getSAccess().getGroup_0()); } ) | - {(p1)}?=>( + {p1}?=>( { before(grammarAccess.getSAccess().getGroup_1()); } ( rule__S__Group_1__0 @@ -571,7 +571,7 @@ class HoistingGeneratorTest extends AbstractXtextTests { ( { before(grammarAccess.getSAccess().getGroup()); } ( - {(p0)}?=> + {p0}?=> rule__S__Group__0 ) * diff --git a/org.eclipse.xtext.tests/src/org/eclipse/xtext/xtext/generator/hoisting/HoistingProcessorTest.java b/org.eclipse.xtext.tests/src/org/eclipse/xtext/xtext/generator/hoisting/HoistingProcessorTest.java index dc1c5fb0c..3202986ef 100644 --- a/org.eclipse.xtext.tests/src/org/eclipse/xtext/xtext/generator/hoisting/HoistingProcessorTest.java +++ b/org.eclipse.xtext.tests/src/org/eclipse/xtext/xtext/generator/hoisting/HoistingProcessorTest.java @@ -22,7 +22,7 @@ import org.eclipse.xtext.testing.GlobalRegistries; import org.eclipse.xtext.tests.AbstractXtextTests; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.HoistingProcessor; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.TokenAnalysisAbortedException; -import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.HoistingGuard; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.hoistingGuards.HoistingGuard; import org.junit.After; import org.junit.Before; import org.junit.Ignore; @@ -108,7 +108,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertFalse(guard.hasTerminal()); - assertEquals("(p0)", guard.render()); + assertEquals("p0", guard.render()); } @Test @@ -126,7 +126,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("(p0)", guard.render()); + assertEquals("p0", guard.render()); } @Test @@ -180,7 +180,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("(p0)", guard.render()); + assertEquals("p0", guard.render()); } @Test @@ -198,7 +198,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("((p0) && (p1))", guard.render()); + assertEquals("(p0) && (p1)", guard.render()); } @Test @@ -217,7 +217,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("(p0)", guard.render()); + assertEquals("p0", guard.render()); } @Test @@ -253,7 +253,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("((p0) && (p1) && (p2))", guard.render()); + assertEquals("(p0) && (p1) && (p2)", guard.render()); } @Test @@ -271,7 +271,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("(p0)", guard.render()); + assertEquals("p0", guard.render()); } @Test @@ -289,7 +289,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("(" + keyword("a", 1) + " || (p0))", guard.render()); + assertEquals(keyword("a", 1) + " || (p0)", guard.render()); } @Test @@ -307,7 +307,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("(" + keyword("a", 1) + " || (p0))", guard.render()); + assertEquals(keyword("a", 1) + " || (p0)", guard.render()); } @Test @@ -327,7 +327,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("(" + keyword("a", 1) + " || (p0))", guard.render()); + assertEquals(keyword("a", 1) + " || (p0)", guard.render()); } @Test @@ -345,7 +345,8 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("(" + keyword("a", 1) + " || (p0))", guard.render()); + System.out.println(guard); + assertEquals(keyword("a", 1) + " || (p0)", guard.render()); } @Test @@ -382,7 +383,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("(" + keyword("a", 1) + " || (p0))", guard.render()); + assertEquals(keyword("a", 1) + " || (p0)", guard.render()); } @@ -401,7 +402,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("((" + keyword("a", 1) + " || (p0)) && (" + keyword("b", 1) + " || (p1)))", guard.render()); + assertEquals("(" + keyword("a", 1) + " || (p0)) && (" + keyword("b", 1) + " || (p1))", guard.render()); } @Test @@ -436,7 +437,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("((" + keyword("a", 1) + " || (p0)) && (" + keyword("b", 1) + " || (p1)))", guard.render()); + assertEquals("(" + keyword("a", 1) + " || (p0)) && (" + keyword("b", 1) + " || (p1))", guard.render()); } // predicates in unordered group with optional paths are currently not supported by the algorithm @@ -457,7 +458,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("((" + keyword("a", 1) + " || (p0)) && (" + keyword("b", 1) + " || (p1)))", guard.render()); + assertEquals("(" + keyword("a", 1) + " || (p0)) && (" + keyword("b", 1) + " || (p1))", guard.render()); } // predicates in unordered group with optional paths are currently not supported by the algorithm @@ -478,7 +479,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("((" + keyword("a", 1) + " || (p0)) && (" + keyword("b", 1) + " || (p1)))", guard.render()); + assertEquals("(" + keyword("a", 1) + " || (p0)) && (" + keyword("b", 1) + " || (p1))", guard.render()); } // predicates in unordered group with optional paths are currently not supported by the algorithm @@ -501,7 +502,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); System.out.println(guard.toString()); - assertEquals("((" + keyword("a", 1) + " || (p0)) && (" + keyword("b", 1) + " || (p1)))", guard.render()); + assertEquals("(" + keyword("a", 1) + " || (p0)) && (" + keyword("b", 1) + " || (p1))", guard.render()); } @Test @@ -519,7 +520,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("((" + keyword("a", 1) + " || (p0)) && (" + keyword("b", 1) + " || (p1)))", guard.render()); + assertEquals("(" + keyword("a", 1) + " || (p0)) && (" + keyword("b", 1) + " || (p1))", guard.render()); // check sizes of groups in unordered group Group group = (Group) rule.getAlternatives(); @@ -548,7 +549,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertFalse(guard.hasTerminal()); - assertEquals("((p0) || (p1))", guard.render()); + assertEquals("(p0) || (p1)", guard.render()); } @Test @@ -567,7 +568,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("((" + keyword("a", 1) + " || (p0)) && (" + keyword("b", 1) + " || (p1)))", guard.render()); + assertEquals("(" + keyword("a", 1) + " || (p0)) && (" + keyword("b", 1) + " || (p1))", guard.render()); } @Test @@ -588,7 +589,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); System.out.println(guard.toString()); - assertEquals("((" + keyword("s", 2) + " || (p0)) && (" + keyword("b", 2) + " || (p1)))", guard.render()); + assertEquals("(" + keyword("s", 2) + " || (p0)) && (" + keyword("b", 2) + " || (p1))", guard.render()); } @Test @@ -609,7 +610,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("(((" + keyword("a", 1) + " && " + keyword("b", 1) + ") || (p0)) && ((" + keyword("c", 1) + " && " + keyword("d", 1) + ") || (p1)))", guard.render()); + assertEquals("((" + keyword("a", 1) + " && " + keyword("b", 1) + ") || (p0)) && ((" + keyword("c", 1) + " && " + keyword("d", 1) + ") || (p1))", guard.render()); } @Test @@ -629,7 +630,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("((" + keyword("a", 2) + " || (p0)) && (" + keyword("b", 2) + " || (p1)))", guard.render()); + assertEquals("(" + keyword("a", 2) + " || (p0)) && (" + keyword("b", 2) + " || (p1))", guard.render()); } @Test @@ -650,7 +651,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("((" + keyword("j", 10) + " || (p0) || (p1)) && (" + keyword("k", 10) + " || (p2)))", guard.render()); + assertEquals("(" + keyword("j", 10) + " || (p0) || (p1)) && (" + keyword("k", 10) + " || (p2))", guard.render()); } @Test @@ -671,7 +672,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("((" + keyword("a", 1) + " || (p0) || (p1)) && (" + keyword("b", 1) + " || (p2)))", guard.render()); + assertEquals("(" + keyword("a", 1) + " || (p0) || (p1)) && (" + keyword("b", 1) + " || (p2))", guard.render()); // number of elements in Alternatives object has to stay the same // even though the identical paths are collapsed during the hoisting process @@ -712,7 +713,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("((" + keyword("a", 1) + " || (p0)) && ((" + keyword("b", 1) + " && " + keyword("c", 1) + ") || (p1)))", guard.render()); + assertEquals("(" + keyword("a", 1) + " || (p0)) && ((" + keyword("b", 1) + " && " + keyword("c", 1) + ") || (p1))", guard.render()); } @Test @@ -731,7 +732,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("(" + keyword("a", 1) + " || (p0))", guard.render()); + assertEquals(keyword("a", 1) + " || (p0)", guard.render()); } @Test @@ -755,8 +756,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - - assertEquals("((((" + keyword("b", 2) + " || " + keyword("b", 3) + ") && (" + keyword("c", 2) + " || " + keyword("c", 3) + ")) || (p0)) && (((" + keyword("b", 2) + " || " + keyword("c", 3) + ") && (" + keyword("c", 2) + " || " + keyword("b", 3) + ")) || (p1)))", guard.render()); + assertEquals("(((" + keyword("b", 2) + " || " + keyword("b", 3) + ") && (" + keyword("c", 2) + " || " + keyword("c", 3) + ")) || (p0)) && (((" + keyword("b", 2) + " || " + keyword("c", 3) + ") && (" + keyword("c", 2) + " || " + keyword("b", 3) + ")) || (p1))", guard.render()); } @Test @@ -779,7 +779,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("((" + keyword("b", 3) + " || ((p0) && (p2))) && (" + keyword("c", 3) + " || ((p0) && (p3))) && (" + keyword("d", 3) + " || (p1)))", guard.render()); + assertEquals("(" + keyword("b", 3) + " || ((p0) && (p2))) && (" + keyword("c", 3) + " || ((p0) && (p3))) && (" + keyword("d", 3) + " || (p1))", guard.render()); } @Test @@ -802,7 +802,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { assertFalse(guard.isTrivial()); 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()); + assertEquals("(" + keyword("a", 2) + " || " + keyword("b", 1) + " || ((p0) && (p2))) && (" + keyword("b", 2) + " || " + keyword("b", 1) + " || ((p0) && (p3))) && (" + keyword("a", 1) + " || (p1))", guard.render()); } // currently not able to find optimal solution @@ -830,10 +830,10 @@ public class HoistingProcessorTest extends AbstractXtextTests { // algorithm is not optimal // optimal result - //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 - 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", 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()); } @Test @@ -850,7 +850,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { AbstractRule rule = getRule(grammar, "S"); HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); - assertEquals("((" + keyword("a", 1) + " || (p0)) && (" + eof(1) + " || (p1)))", guard.render()); + assertEquals("(" + keyword("a", 1) + " || (p0)) && (" + eof(1) + " || (p1))", guard.render()); } @Test @@ -867,7 +867,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { AbstractRule rule = getRule(grammar, "S"); HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); - assertEquals("((" + eof(3) + " || (p0)) && (" + keyword("c", 3) + " || (p1)))", guard.render()); + assertEquals("(" + eof(3) + " || (p0)) && (" + keyword("c", 3) + " || (p1))", guard.render()); } @Test @@ -885,7 +885,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { AbstractRule rule = getRule(grammar, "A"); HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); - assertEquals("((" + keyword("d", 4) + " || (p0)) && (" + keyword("c", 4) + " || (p1)))", guard.render()); + assertEquals("(" + keyword("d", 4) + " || (p0)) && (" + keyword("c", 4) + " || (p1))", guard.render()); } @Test @@ -904,7 +904,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { AbstractRule rule = getRule(grammar, "A"); HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); - assertEquals("(((" + keyword("c", 2) + " && " + keyword("d", 2) + ") || (p0)) && (" + keyword("b", 2) + " || (p1)))", guard.render()); + assertEquals("((" + keyword("c", 2) + " && " + keyword("d", 2) + ") || (p0)) && (" + keyword("b", 2) + " || (p1))", guard.render()); } @Test(expected = TokenAnalysisAbortedException.class) @@ -968,12 +968,10 @@ public class HoistingProcessorTest extends AbstractXtextTests { assertTrue(guard.hasTerminal()); System.out.println(guard.toString()); assertEquals( - "(" + - "(" + keyword("a", 1) + " || " + eof(2) + " || (p0) || (p1)) && " + - "(" + keyword("b", 2) + " || (p0)) && " + - "(" + keyword("c", 2) + " || (p1)) && " + - "(" + keyword("d", 1) + " || (p2))" + - ")", + "(" + keyword("a", 1) + " || " + eof(2) + " || (p0) || (p1)) && " + + "(" + keyword("b", 2) + " || (p0)) && " + + "(" + keyword("c", 2) + " || (p1)) && " + + "(" + keyword("d", 1) + " || (p2))", guard.render() ); } @@ -996,11 +994,9 @@ public class HoistingProcessorTest extends AbstractXtextTests { assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); assertEquals( - "(" + - "(" + eof(1) + " || (p0) || (p1)) && " + - "(" + keyword("a", 1) + " || (p0)) && " + - "(" + keyword("b", 1) + " || (p1))" + - ")", + "(" + eof(1) + " || (p0) || (p1)) && " + + "(" + keyword("a", 1) + " || (p0)) && " + + "(" + keyword("b", 1) + " || (p1))", guard.render() ); @@ -1055,7 +1051,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("(((" + keyword("a", 2) + " && " + eof(2) + ") || (p0)) && (" + keyword("b", 2) + " || (p1)))", guard.render()); + assertEquals("((" + keyword("a", 2) + " && " + eof(2) + ") || (p0)) && (" + keyword("b", 2) + " || (p1))", guard.render()); } @Test @@ -1075,7 +1071,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("(((" + keyword("a", 2) + " && " + eof(2) + ") || (p0)) && (" + keyword("b", 2) + " || (p1)))", guard.render()); + assertEquals("((" + keyword("a", 2) + " && " + eof(2) + ") || (p0)) && (" + keyword("b", 2) + " || (p1))", guard.render()); } @Test @@ -1095,7 +1091,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("(((" + keyword("a", 2) + " && " + eof(2) + ") || (p0)) && (" + keyword("b", 2) + " || (p1)))", guard.render()); + assertEquals("((" + keyword("a", 2) + " && " + eof(2) + ") || (p0)) && (" + keyword("b", 2) + " || (p1))", guard.render()); } @Test @@ -1115,7 +1111,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("((" + eof(2) + " || (p0)) && (" + keyword("a", 2) + " || (p1)))", guard.render()); + assertEquals("(" + eof(2) + " || (p0)) && (" + keyword("a", 2) + " || (p1))", guard.render()); } @Test @@ -1134,7 +1130,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("((" + eof(2) + " || (p0)) && (" + keyword("a", 2) + " || (p1)))", guard.render()); + assertEquals("(" + eof(2) + " || (p0)) && (" + keyword("a", 2) + " || (p1))", guard.render()); } @Test @@ -1155,7 +1151,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("(((" + eof(2) + " && " + keyword("c", 2) + ") || (p0)) && (" + keyword("b", 2) + " || (p1)))", guard.render()); + assertEquals("((" + eof(2) + " && " + keyword("c", 2) + ") || (p0)) && (" + keyword("b", 2) + " || (p1))", guard.render()); } @Test @@ -1177,7 +1173,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("(((" + eof(2) + " && " + keyword("c", 2) + ") || (p0)) && (" + keyword("b", 2) + " || (p1)))", guard.render()); + assertEquals("((" + eof(2) + " && " + keyword("c", 2) + ") || (p0)) && (" + keyword("b", 2) + " || (p1))", guard.render()); } @Test @@ -1201,6 +1197,6 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("(((" + eof(2) + " && " + keyword("c", 2) + ") || (p0)) && (" + keyword("a", 2) + " || (p1)))", guard.render()); + assertEquals("((" + eof(2) + " && " + keyword("c", 2) + ") || (p0)) && (" + keyword("a", 2) + " || (p1))", guard.render()); } } diff --git a/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/xtext/generator/hoisting/HoistingGeneratorTest.java b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/xtext/generator/hoisting/HoistingGeneratorTest.java index 0f17d2c18..a095e0597 100644 --- a/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/xtext/generator/hoisting/HoistingGeneratorTest.java +++ b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/xtext/generator/hoisting/HoistingGeneratorTest.java @@ -212,7 +212,7 @@ public class HoistingGeneratorTest extends AbstractXtextTests { _builder_1.append("("); _builder_1.newLine(); _builder_1.append("\t\t"); - _builder_1.append("{(p0)}?=>"); + _builder_1.append("{p0}?=>"); _builder_1.newLine(); _builder_1.append("\t\t\t"); _builder_1.append("("); @@ -242,7 +242,7 @@ public class HoistingGeneratorTest extends AbstractXtextTests { _builder_1.append("|"); _builder_1.newLine(); _builder_1.append("\t\t"); - _builder_1.append("{(p1)}?=>"); + _builder_1.append("{p1}?=>"); _builder_1.newLine(); _builder_1.append("\t\t\t"); _builder_1.append("("); @@ -431,7 +431,7 @@ public class HoistingGeneratorTest extends AbstractXtextTests { _builder_1.append("("); _builder_1.newLine(); _builder_1.append("\t\t"); - _builder_1.append("{(p0)}?=>"); + _builder_1.append("{p0}?=>"); _builder_1.newLine(); _builder_1.append("\t\t"); _builder_1.append("("); @@ -809,7 +809,7 @@ public class HoistingGeneratorTest extends AbstractXtextTests { _builder_1.append(":"); _builder_1.newLine(); _builder_1.append("\t"); - _builder_1.append("{(p0)}?=>("); + _builder_1.append("{p0}?=>("); _builder_1.newLine(); _builder_1.append("\t\t"); _builder_1.append("{ before(grammarAccess.getSAccess().getGroup_0()); }"); @@ -833,7 +833,7 @@ public class HoistingGeneratorTest extends AbstractXtextTests { _builder_1.append("|"); _builder_1.newLine(); _builder_1.append("\t"); - _builder_1.append("{(p1)}?=>("); + _builder_1.append("{p1}?=>("); _builder_1.newLine(); _builder_1.append("\t\t"); _builder_1.append("{ before(grammarAccess.getSAccess().getGroup_1()); }"); @@ -1262,7 +1262,7 @@ public class HoistingGeneratorTest extends AbstractXtextTests { _builder_1.append("("); _builder_1.newLine(); _builder_1.append("\t\t\t"); - _builder_1.append("{(p0)}?=>"); + _builder_1.append("{p0}?=>"); _builder_1.newLine(); _builder_1.append("\t\t\t"); _builder_1.append("rule__S__Group__0"); diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/JavaCodeUtils.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/JavaCodeUtils.java index 44dc9033f..c751b89b6 100644 --- a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/JavaCodeUtils.java +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/JavaCodeUtils.java @@ -25,10 +25,7 @@ public class JavaCodeUtils { } static public String formatPredicateForGrammar(String predicate) { - return formatCodeForGrammar( - // remove parentheses - predicate.substring(1, predicate.length() - 1) - ); + return formatCodeForGrammar(predicate); } static public String formatGuardForGrammar(Guard guard) { diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/HoistingProcessor.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/HoistingProcessor.java index 8ac460ff8..db128f4a7 100644 --- a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/HoistingProcessor.java +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/HoistingProcessor.java @@ -42,20 +42,20 @@ import org.eclipse.xtext.util.Tuples; import static org.eclipse.xtext.GrammarUtil.*; import org.eclipse.xtext.xtext.generator.parser.antlr.JavaCodeUtils; -import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.NestedPrefixAlternativesException; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.NestedIdenticalPathException; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.TokenAnalysisAbortedException; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.UnsupportedConstructException; -import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.AlternativeTokenSequenceGuard; -import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.AlternativesGuard; -import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.GroupGuard; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.Guard; -import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.HoistingGuard; -import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.MergedPathGuard; -import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.PathGuard; -import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.PredicateGuard; -import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.SingleTokenGuard; -import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.TokenGuard; -import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.TokenSequenceGuard; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.hoistingGuards.AlternativesGuard; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.hoistingGuards.GroupGuard; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.hoistingGuards.HoistingGuard; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.hoistingGuards.MergedPathGuard; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.hoistingGuards.PathGuard; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.hoistingGuards.PredicateGuard; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.tokenGuards.AlternativeTokenSequenceGuard; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.tokenGuards.SingleTokenGuard; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.tokenGuards.TokenGuard; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.tokenGuards.TokenSequenceGuard; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.pathAnalysis.TokenAnalysis; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.token.Token; import static org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.utils.DebugUtils.*; @@ -292,11 +292,11 @@ public class HoistingProcessor { (TokenGuard tokenGuard, MergedPathGuard pathGuard) -> Tuples.pair(tokenGuard, pathGuard) ).map(p -> new PathGuard(p.getFirst(), p.getSecond())) .collect(AlternativesGuard.collector()); - } catch(NestedPrefixAlternativesException e) { - // nested prefix alternatives + } catch(NestedIdenticalPathException e) { + // nested identical paths // -> flatten paths to alternative and try again // this is very inefficient - log.warn("nested prefix alternatives detected"); + log.warn("nested identical paths detected"); log.warn("avoid these since they can't be handled efficiently"); if (config.isDebug()) @@ -310,7 +310,7 @@ public class HoistingProcessor { log.info(flattened.getElements().size()); // TODO: value configurable? if (flattened.getElements().size() > 100) { - throw new NestedPrefixAlternativesException("nested prefix alternatives can't be analysed because of too many paths"); + throw new NestedIdenticalPathException("nested identical paths can't be analysed because of too many paths"); } return findGuardForAlternatives(flattened, currentRule, true); diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/exceptions/NestedIdenticalPathException.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/exceptions/NestedIdenticalPathException.java new file mode 100644 index 000000000..4f67e00dc --- /dev/null +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/exceptions/NestedIdenticalPathException.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2021 itemis AG (http://www.itemis.eu) and others. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions; + +import org.eclipse.xtext.AbstractRule; + +/** + * @author overflow - Initial contribution and API + */ +public class NestedIdenticalPathException extends TokenAnalysisAbortedException { + private static final long serialVersionUID = -1309434841547765441L; + + public NestedIdenticalPathException() { + super(); + } + + public NestedIdenticalPathException(String message, AbstractRule rule) { + super(message, rule); + } + + public NestedIdenticalPathException(String message, Throwable cause, AbstractRule rule) { + super(message, cause, rule); + } + + public NestedIdenticalPathException(String message, Throwable cause) { + super(message, cause); + } + + public NestedIdenticalPathException(String message) { + super(message); + } + + public NestedIdenticalPathException(Throwable cause, AbstractRule rule) { + super(cause, rule); + } + + public NestedIdenticalPathException(Throwable cause) { + super(cause); + } +} diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/exceptions/NestedPrefixAlternativesException.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/exceptions/NestedPrefixAlternativesException.java deleted file mode 100644 index aa5f8db97..000000000 --- a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/exceptions/NestedPrefixAlternativesException.java +++ /dev/null @@ -1,53 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2021 itemis AG (http://www.itemis.eu) and others. - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0. - * - * SPDX-License-Identifier: EPL-2.0 - *******************************************************************************/ -package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions; - -import org.eclipse.xtext.AbstractRule; - -/** - * @author overflow - Initial contribution and API - */ -public class NestedPrefixAlternativesException extends TokenAnalysisAbortedException { - private static final long serialVersionUID = -1309434841547765441L; - - public NestedPrefixAlternativesException() { - super(); - // TODO Auto-generated constructor stub - } - - public NestedPrefixAlternativesException(String message, AbstractRule rule) { - super(message, rule); - // TODO Auto-generated constructor stub - } - - public NestedPrefixAlternativesException(String message, Throwable cause, AbstractRule rule) { - super(message, cause, rule); - // TODO Auto-generated constructor stub - } - - public NestedPrefixAlternativesException(String message, Throwable cause) { - super(message, cause); - // TODO Auto-generated constructor stub - } - - public NestedPrefixAlternativesException(String message) { - super(message); - // TODO Auto-generated constructor stub - } - - public NestedPrefixAlternativesException(Throwable cause, AbstractRule rule) { - super(cause, rule); - // TODO Auto-generated constructor stub - } - - public NestedPrefixAlternativesException(Throwable cause) { - super(cause); - // TODO Auto-generated constructor stub - } -} diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/token/NotATokenException.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/exceptions/NotATokenException.java similarity index 98% rename from org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/token/NotATokenException.java rename to org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/exceptions/NotATokenException.java index 6b8d58e7a..96e6a0757 100644 --- a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/token/NotATokenException.java +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/exceptions/NotATokenException.java @@ -6,7 +6,7 @@ * * SPDX-License-Identifier: EPL-2.0 *******************************************************************************/ -package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.token; +package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions; /** * @author overflow - Initial contribution and API diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/ContextConnective.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/ContextConnective.java new file mode 100644 index 000000000..757f01792 --- /dev/null +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/ContextConnective.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2022 itemis AG (http://www.itemis.eu) and others. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards; + +/** + * @author overflow - Initial contribution and API + */ +public enum ContextConnective { + DISJUNCTION, CONJUNCTION; + + public String addParenthesesIfNot(String str, ContextConnective connective) { + if (this != connective) { + return "(" + str + ")"; + } else { + return str; + } + } +} diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/Guard.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/Guard.java index 3dec906da..b2706b459 100644 --- a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/Guard.java +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/Guard.java @@ -13,5 +13,15 @@ package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards; */ public interface Guard { boolean isTrivial(); + /** + * should only be used for the root guard when rendering. + * + * assume context connective matches inner connective + */ String render(); + + /** + * don't render parentheses if inner connective matches context + */ + String render(ContextConnective connective); } diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/HoistingGuard.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/HoistingGuard.java deleted file mode 100644 index aa5bb3847..000000000 --- a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/HoistingGuard.java +++ /dev/null @@ -1,75 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2021 itemis AG (http://www.itemis.eu) and others. - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0. - * - * SPDX-License-Identifier: EPL-2.0 - *******************************************************************************/ -package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards; - -/** - * @author overflow - Initial contribution and API - */ -public interface HoistingGuard extends Guard { - default String renderPredicate() { - if (isTrivial()) { - return ""; - } else { - return "{" + render() + "}?=>"; - } - } - - default String renderDescription() { - if (isTrivial()) { - return "trivial"; - } else { - return render(); - } - } - - boolean hasTerminal(); - - static public HoistingGuard unguarded() { - return new HoistingGuard() { - @Override - public String render() { - return "true"; - } - - @Override - public boolean isTrivial() { - return true; - } - - @Override - public boolean hasTerminal() { - return false; - } - }; - } - - static public HoistingGuard terminal() { - return new HoistingGuard() { - @Override - public String render() { - return "true"; - } - - @Override - public boolean isTrivial() { - return true; - } - - @Override - public boolean hasTerminal() { - return true; - } - }; - } - - static HoistingGuard action() { - // technically not a terminal, but it behaves the same - return terminal(); - } -} diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/AlternativesGuard.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/hoistingGuards/AlternativesGuard.java similarity index 56% rename from org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/AlternativesGuard.java rename to org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/hoistingGuards/AlternativesGuard.java index 4ed076500..313659e1c 100644 --- a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/AlternativesGuard.java +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/hoistingGuards/AlternativesGuard.java @@ -6,7 +6,7 @@ * * SPDX-License-Identifier: EPL-2.0 *******************************************************************************/ -package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards; +package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.hoistingGuards; import java.util.Arrays; import java.util.LinkedList; @@ -15,8 +15,13 @@ import java.util.function.Predicate; import java.util.stream.Collector; import java.util.stream.Collectors; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.ContextConnective; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.Guard; + /** * @author overflow - Initial contribution and API + * + * AlternativesGuards are the guard conditions of non-empty alternatives. */ public class AlternativesGuard implements HoistingGuard { private List paths; @@ -36,29 +41,49 @@ public class AlternativesGuard implements HoistingGuard { @Override public boolean isTrivial() { + // should never be true, otherwise findAlternativeGuard would + // produce unguarded path hoisting guard return paths.stream().allMatch(Guard::isTrivial); } + @Override + public String render(ContextConnective connective) { + // there is at least one path that is not trivial + List relevantGuards = paths.stream() + .filter(Predicate.not(Guard::isTrivial)) + .collect(Collectors.toList()); + + if (relevantGuards.size() == 1) { + return paths.get(0).render(connective); + } else { + String result = relevantGuards.stream() + .map(g -> g.render(ContextConnective.CONJUNCTION)) + .collect(Collectors.joining(" && ")); + return connective.addParenthesesIfNot(result, ContextConnective.CONJUNCTION); + } + } + @Override public String render() { - List renderedGuards = paths.stream() - .filter(Predicate.not(Guard::isTrivial)) - .map(Guard::render) - .collect(Collectors.toList()); - - if (renderedGuards.size() == 1) { + // there is at least one path that is not trivial + List relevantGuards = paths.stream() + .filter(Predicate.not(Guard::isTrivial)) + .collect(Collectors.toList()); + + if (relevantGuards.size() == 1) { return paths.get(0).render(); - } else { - return "(" + - String.join(" && ", renderedGuards) + - ")"; + } else { + return render(ContextConnective.CONJUNCTION); } } @Override public boolean hasTerminal() { - // empty paths are only allowed when all paths are empty - // in that case a MergedPathGuard is returned. + // using the current method there is no way of handling predicates + // after alternatives with empty paths the same way antlr does + // => assume that the alternative always contains tokens + // the only case that works is when all paths are empty + // => a MergedPathGuard is returned by findGuardForAlternatives return true; } diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/GroupGuard.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/hoistingGuards/GroupGuard.java similarity index 77% rename from org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/GroupGuard.java rename to org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/hoistingGuards/GroupGuard.java index ed6c9da61..ce9ffdc45 100644 --- a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/GroupGuard.java +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/hoistingGuards/GroupGuard.java @@ -6,7 +6,7 @@ * * SPDX-License-Identifier: EPL-2.0 *******************************************************************************/ -package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards; +package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.hoistingGuards; import java.util.Arrays; import java.util.Collection; @@ -16,9 +16,14 @@ import java.util.stream.Collectors; import org.eclipse.xtext.util.Pair; import org.eclipse.xtext.util.Tuples; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.ContextConnective; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.Guard; /** * @author overflow - Initial contribution and API + * + * GroupGuards represent the conditions for group elements. + * */ public class GroupGuard implements HoistingGuard { private List elementGuards = new LinkedList<>(); @@ -50,6 +55,7 @@ public class GroupGuard implements HoistingGuard { Pair, 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 { @@ -60,7 +66,7 @@ public class GroupGuard implements HoistingGuard { elementGuards.stream() .filter(g -> g instanceof AlternativesGuard) .map(g -> (AlternativesGuard) g) - .findAny().get()); + .findFirst().get()); } } @@ -74,11 +80,19 @@ public class GroupGuard implements HoistingGuard { if (elementGuards.size() == 1) { return elementGuards.get(0).render(); } else { - return "(" + - elementGuards.stream() - .map(Guard::render) - .collect(Collectors.joining(" && ")) + - ")"; + return render(ContextConnective.CONJUNCTION); + } + } + + @Override + public String render(ContextConnective connective) { + if (elementGuards.size() == 1) { + return elementGuards.get(0).render(connective); + } else { + String result = elementGuards.stream() + .map(g -> g.render(ContextConnective.CONJUNCTION)) + .collect(Collectors.joining(" && ")); + return connective.addParenthesesIfNot(result, ContextConnective.CONJUNCTION); } } diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/hoistingGuards/HoistingGuard.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/hoistingGuards/HoistingGuard.java new file mode 100644 index 000000000..59172c969 --- /dev/null +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/hoistingGuards/HoistingGuard.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2021 itemis AG (http://www.itemis.eu) and others. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.hoistingGuards; + +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.ContextConnective; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.Guard; + +/** + * @author overflow - Initial contribution and API + * + * A HoistingGuard is a condition that has to be true for a certain path to accessible. + * + */ +public interface HoistingGuard extends Guard { + default String renderPredicate() { + if (isTrivial()) { + return ""; + } else { + return "{" + render() + "}?=>"; + } + } + + default String renderDescription() { + if (isTrivial()) { + return "trivial"; + } else { + return render(); + } + } + + boolean hasTerminal(); + + static public HoistingGuard unguarded() { + return new UnguardedPathHoistingGuard(); + } + + static public HoistingGuard terminal() { + return new TerminalHoistingGuard(); + } + + static class UnguardedPathHoistingGuard implements HoistingGuard { + @Override + public String render() { + return "true"; + } + + @Override + public String render(ContextConnective connective) { + return render(); + } + + @Override + public boolean isTrivial() { + return true; + } + + @Override + public boolean hasTerminal() { + return false; + } + } + + static class TerminalHoistingGuard implements HoistingGuard { + @Override + public String render() { + return "true"; + } + + @Override + public String render(ContextConnective connective) { + return render(); + } + + @Override + public boolean isTrivial() { + return true; + } + + @Override + public boolean hasTerminal() { + return true; + } + } + + static HoistingGuard action() { + // technically not a terminal, but it behaves the same + return new TerminalHoistingGuard(); + } +} diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/MergedPathGuard.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/hoistingGuards/MergedPathGuard.java similarity index 71% rename from org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/MergedPathGuard.java rename to org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/hoistingGuards/MergedPathGuard.java index 1e1fb293c..d9323fd5d 100644 --- a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/MergedPathGuard.java +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/hoistingGuards/MergedPathGuard.java @@ -6,15 +6,21 @@ * * SPDX-License-Identifier: EPL-2.0 *******************************************************************************/ -package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards; +package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.hoistingGuards; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.ContextConnective; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.Guard; + /** * @author overflow - Initial contribution and API + * + * MergedPathGuards are used to combine identical paths in alternatives. + * This class is also used for alternatives that only have empty paths. */ public class MergedPathGuard implements HoistingGuard { private List pathGuards = new LinkedList<>(); @@ -49,19 +55,26 @@ public class MergedPathGuard implements HoistingGuard { if (pathGuards.size() == 1) { return pathGuards.get(0).render(); } else { - return "(" + renderWithoutParentheses() + ")"; + return render(ContextConnective.DISJUNCTION); } } - String renderWithoutParentheses() { - return pathGuards.stream() - .map(Guard::render) + @Override + public String render(ContextConnective connective) { + if (pathGuards.size() == 1) { + return pathGuards.get(0).render(connective); + } else { + String result = pathGuards.stream() + .map(g -> g.render(ContextConnective.DISJUNCTION)) .collect(Collectors.joining(" || ")); + return connective.addParenthesesIfNot(result, ContextConnective.DISJUNCTION); + } } @Override public boolean hasTerminal() { - // only need to check first element since all paths should be identical + // only need to check first element since all paths should be + // identical with regards to tokens. return pathGuards.get(0).hasTerminal(); } diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/PathGuard.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/hoistingGuards/PathGuard.java similarity index 72% rename from org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/PathGuard.java rename to org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/hoistingGuards/PathGuard.java index 039de7ba6..a17c13652 100644 --- a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/PathGuard.java +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/hoistingGuards/PathGuard.java @@ -6,7 +6,7 @@ * * SPDX-License-Identifier: EPL-2.0 *******************************************************************************/ -package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards; +package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.hoistingGuards; import java.util.Arrays; import java.util.LinkedList; @@ -14,9 +14,16 @@ import java.util.List; import java.util.stream.Collectors; import org.eclipse.xtext.util.Pair; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.ContextConnective; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.Guard; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.tokenGuards.TokenGuard; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.tokenGuards.TokenSequenceGuard; /** * @author overflow - Initial contribution and API + * + * PathGuards represent that conditions for single paths in alternatives. + * */ public class PathGuard implements HoistingGuard { private TokenGuard tokenGuard; @@ -34,32 +41,28 @@ public class PathGuard implements HoistingGuard { @Override public boolean hasTerminal() { - // empty paths are only allowed when all paths are empty - // in that case a MergedPathGuard is returned by findGuardForAlternatives. + // using the current method there is no way of handling predicates + // after alternatives with empty paths the same way antlr does + // => assume that alternative paths always contain tokens + // the only case that works is when all paths are empty + // => a MergedPathGuard is returned by findGuardForAlternatives return true; } @Override public String render() { - // parentheses needed since tokenGuard is never empty - String result = "("; - - if (tokenGuard instanceof TokenSequenceGuard) { - result += ((TokenSequenceGuard) tokenGuard).renderWithoutParenthesis(); - } else { - result += tokenGuard.render(); - } + return render(ContextConnective.DISJUNCTION); + } + + @Override + public String render(ContextConnective connective) { + String result = ""; + result += tokenGuard.render(ContextConnective.DISJUNCTION); result += " || "; + result += hoistngGuard.render(ContextConnective.DISJUNCTION); - if (hoistngGuard instanceof MergedPathGuard) { - result += ((MergedPathGuard) hoistngGuard).renderWithoutParentheses(); - } else { - result += hoistngGuard.render(); - } - - result += ")"; - return result; + return connective.addParenthesesIfNot(result, ContextConnective.DISJUNCTION); } public static List collapse(List paths) { diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/PredicateGuard.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/hoistingGuards/PredicateGuard.java similarity index 75% rename from org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/PredicateGuard.java rename to org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/hoistingGuards/PredicateGuard.java index 70410dfda..b654124b8 100644 --- a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/PredicateGuard.java +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/hoistingGuards/PredicateGuard.java @@ -6,13 +6,17 @@ * * SPDX-License-Identifier: EPL-2.0 *******************************************************************************/ -package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards; +package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.hoistingGuards; import org.eclipse.xtext.AbstractSemanticPredicate; import org.eclipse.xtext.xtext.generator.parser.antlr.JavaCodeUtils; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.ContextConnective; /** * @author overflow - Initial contribution and API + * + * PredicateGuards represent the atomic guard condition of a predicate. + * */ public class PredicateGuard implements HoistingGuard { @@ -29,8 +33,15 @@ public class PredicateGuard implements HoistingGuard { @Override public String render() { - return "(" + JavaCodeUtils.getSource(element.getCode()) + ")"; + // no parentheses if this is the root element + return JavaCodeUtils.getSource(element.getCode()); } + + @Override + public String render(ContextConnective connective) { + return "(" + render() + ")"; + } + @Override public boolean hasTerminal() { diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/AlternativeTokenSequenceGuard.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/tokenGuards/AlternativeTokenSequenceGuard.java similarity index 72% rename from org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/AlternativeTokenSequenceGuard.java rename to org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/tokenGuards/AlternativeTokenSequenceGuard.java index 531e873ef..5ae12bb18 100644 --- a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/AlternativeTokenSequenceGuard.java +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/tokenGuards/AlternativeTokenSequenceGuard.java @@ -6,7 +6,7 @@ * * SPDX-License-Identifier: EPL-2.0 *******************************************************************************/ -package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards; +package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.tokenGuards; import java.util.Arrays; import java.util.Collection; @@ -14,8 +14,13 @@ import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.ContextConnective; + /** * @author overflow - Initial contribution and API + * + * An AlternativeTokenSequenceGuard represents alternative token paths as a TokenGuard. + * */ public class AlternativeTokenSequenceGuard implements TokenGuard { private Collection alternatives; @@ -26,7 +31,7 @@ public class AlternativeTokenSequenceGuard implements TokenGuard { public TokenGuard reduce() { if (alternatives.size() == 1) { - return alternatives.stream().findAny().get(); + return alternatives.stream().findFirst().get(); } else { return this; } @@ -34,14 +39,22 @@ public class AlternativeTokenSequenceGuard implements TokenGuard { @Override public String render() { - if (alternatives.size() != 1) { - return "(" + - alternatives.stream() - .map(TokenGuard::render) - .collect(Collectors.joining(" && ")) + - ")"; - } else { + if (alternatives.size() == 1) { return alternatives.stream().findAny().get().render(); + } else { + return render(ContextConnective.CONJUNCTION); + } + } + + @Override + public String render(ContextConnective connective) { + if (alternatives.size() == 1) { + return alternatives.stream().findAny().get().render(connective); + } else { + String result = alternatives.stream() + .map(g -> g.render(ContextConnective.CONJUNCTION)) + .collect(Collectors.joining(" && ")); + return connective.addParenthesesIfNot(result, ContextConnective.CONJUNCTION); } } diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/SingleTokenGuard.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/tokenGuards/SingleTokenGuard.java similarity index 86% rename from org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/SingleTokenGuard.java rename to org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/tokenGuards/SingleTokenGuard.java index 75c2528c8..23190cd3e 100644 --- a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/SingleTokenGuard.java +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/tokenGuards/SingleTokenGuard.java @@ -6,12 +6,13 @@ * * SPDX-License-Identifier: EPL-2.0 *******************************************************************************/ -package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards; +package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.tokenGuards; import java.util.Arrays; import java.util.HashSet; import java.util.Set; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.ContextConnective; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.token.Token; /** @@ -34,6 +35,11 @@ public class SingleTokenGuard implements TokenGuard { return token.negatedCondition(); } + @Override + public String render(ContextConnective connective) { + return render(); + } + @Override public String toString() { return "SingleTokenGuard (\n" + diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/TokenGuard.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/tokenGuards/TokenGuard.java similarity index 73% rename from org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/TokenGuard.java rename to org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/tokenGuards/TokenGuard.java index 250511461..b78be3aad 100644 --- a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/TokenGuard.java +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/tokenGuards/TokenGuard.java @@ -6,12 +6,18 @@ * * SPDX-License-Identifier: EPL-2.0 *******************************************************************************/ -package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards; +package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.tokenGuards; import java.util.Set; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.Guard; + /** * @author overflow - Initial contribution and API + * + * TokenGuards represent the tokens necessary for the given path. + * Usually only tokens that distinguish the current path from other alternative paths are used. + * */ public interface TokenGuard extends Guard { @Override diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/TokenSequenceGuard.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/tokenGuards/TokenSequenceGuard.java similarity index 79% rename from org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/TokenSequenceGuard.java rename to org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/tokenGuards/TokenSequenceGuard.java index 3144790d8..1fc2cfd1e 100644 --- a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/TokenSequenceGuard.java +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/guards/tokenGuards/TokenSequenceGuard.java @@ -6,7 +6,7 @@ * * SPDX-License-Identifier: EPL-2.0 *******************************************************************************/ -package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards; +package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.tokenGuards; import java.util.Arrays; import java.util.Collection; @@ -15,10 +15,13 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.guards.ContextConnective; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.utils.StreamUtils; /** * @author overflow - Initial contribution and API + * + * A TokenSequenceGuard represents a sequence of tokens as a TokenGuard. */ public class TokenSequenceGuard implements TokenGuard { private Collection sequence; @@ -61,26 +64,23 @@ public class TokenSequenceGuard implements TokenGuard { @Override public String render() { - boolean addParentheses = sequence.size() != 1; - String result = ""; - - if (addParentheses) { - result += "("; + if (sequence.size() == 1) { + return sequence.stream().findAny().get().render(); + } else { + return render(ContextConnective.DISJUNCTION); } - - result += renderWithoutParenthesis(); - - if (addParentheses) { - result += ")"; - } - - return result; } - public String renderWithoutParenthesis() { - return sequence.stream() - .map(TokenGuard::render) + @Override + public String render(ContextConnective connective) { + if (sequence.size() == 1) { + return sequence.stream().findAny().get().render(connective); + } else { + String result = sequence.stream() + .map(g -> g.render(ContextConnective.DISJUNCTION)) .collect(Collectors.joining(" || ")); + return connective.addParenthesesIfNot(result, ContextConnective.DISJUNCTION); + } } @Override diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/pathAnalysis/TokenAnalysis.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/pathAnalysis/TokenAnalysis.java index 4ac3068e7..89dc064fe 100644 --- a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/pathAnalysis/TokenAnalysis.java +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/pathAnalysis/TokenAnalysis.java @@ -38,7 +38,7 @@ import org.eclipse.xtext.RuleCall; import org.eclipse.xtext.UnorderedGroup; import org.eclipse.xtext.util.XtextSwitch; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.HoistingConfiguration; -import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.NestedPrefixAlternativesException; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.NestedIdenticalPathException; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.TokenAnalysisAbortedException; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.UnsupportedConstructException; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.token.Token; @@ -486,8 +486,8 @@ public class TokenAnalysis { throw new TokenAnalysisAbortedException("token limit exhausted while searching for minimal differences"); } else { // path length exhausted while searching for minimal differences - // this indicates nested prefix alternatives - throw new NestedPrefixAlternativesException(); + // this indicates the presence of nested identical paths + throw new NestedIdenticalPathException(); } } private boolean tokenCombinations(long prefix, int prefixLength, int ones, Function, Boolean> callback, MutableWrapper limit) { diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/token/Token.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/token/Token.java index b6965f444..db0b73afb 100644 --- a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/token/Token.java +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/token/Token.java @@ -14,6 +14,7 @@ import org.eclipse.xtext.EnumLiteralDeclaration; import org.eclipse.xtext.Keyword; import org.eclipse.xtext.RuleCall; import org.eclipse.xtext.TerminalRule; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.NotATokenException; /** * @author overflow - Initial contribution and API @@ -23,6 +24,8 @@ public interface Token { AbstractElement getElement(); + int getPosition(); + static boolean isToken(AbstractElement element) { if (element == null) { return true; @@ -53,6 +56,4 @@ public interface Token { throw new NotATokenException(element.eClass().getName()); } - - int getPosition(); }