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 341f095ae..835348fb1 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 @@ -287,6 +287,23 @@ public class HoistingProcessorTest extends AbstractXtextTests { Grammar grammar = ((Grammar) resource.getContents().get(0)); AbstractRule rule = getRule(grammar, "S"); + HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); + assertFalse(guard.isTrivial()); + assertTrue(guard.hasTerminal()); + assertEquals("((" + getSyntaxForKeywordToken("a", 1) + " || (p0)) && (" + getSyntaxForKeywordToken("b", 1) + " || (p1)))", guard.render()); + } + + //@Test + public void testUnorderedGroupsWithoutMandatoryContent() throws Exception { + // @formatter:off + String model = + MODEL_PREAMBLE + + "S: (($$ p0 $$?=> 'a')? & ($$ p1 $$?=> 'b')?) $$ p2 $$?=> 's';"; + // @formatter:off + XtextResource resource = getResourceFromString(model); + Grammar grammar = ((Grammar) resource.getContents().get(0)); + AbstractRule rule = getRule(grammar, "S"); + HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); @@ -307,7 +324,7 @@ public class HoistingProcessorTest extends AbstractXtextTests { HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives()); assertFalse(guard.isTrivial()); assertTrue(guard.hasTerminal()); - assertEquals("((" + getSyntaxForKeywordToken("s", 1) + " || (p2)) && (" + getSyntaxForKeywordToken("a", 1) + " || (p0)) && (" + getSyntaxForKeywordToken("b", 1) + " || (p1)))", guard.render()); + assertEquals("((" + getSyntaxForKeywordToken("a", 1) + " || (p0)) && (" + getSyntaxForKeywordToken("b", 1) + " || (p1)))", guard.render()); // check sizes of groups in unordered group Group group = (Group) rule.getAlternatives(); 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 594d5918d..4aa85c17a 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 @@ -25,6 +25,7 @@ import org.eclipse.xtext.Action; import org.eclipse.xtext.Alternatives; import org.eclipse.xtext.Assignment; import org.eclipse.xtext.CompoundElement; +import org.eclipse.xtext.GrammarUtil; import org.eclipse.xtext.Group; import org.eclipse.xtext.JavaAction; import org.eclipse.xtext.RuleCall; @@ -152,7 +153,12 @@ public class HoistingProcessor { Alternatives virtualAlternatives = XtextFactory.eINSTANCE.createAlternatives(); addElementsToCompoundElement(virtualAlternatives, ((UnorderedGroup) element).getElements()); - virtualAlternatives.setCardinality("*"); + if (((UnorderedGroup) element).getElements().stream().allMatch(GrammarUtil::isOptionalCardinality)) { + virtualAlternatives.setCardinality("*"); + // TODO: alternatives analysis needs special case + } else { + virtualAlternatives.setCardinality("+"); + } elements.set(i, virtualAlternatives); }