fixed problem with unsupported constructs in unguarded rules

This commit is contained in:
overflowerror 2021-12-04 18:30:02 +01:00
parent 62e9d44a64
commit 13aef9e99b
2 changed files with 64 additions and 16 deletions

View file

@ -20,7 +20,6 @@ import org.eclipse.xtext.resource.XtextResource;
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.HoistingException;
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.HoistingGuard;
@ -291,6 +290,22 @@ public class HoistingProcessorTest extends AbstractXtextTests {
assertEquals("((" + getSyntaxForKeywordToken("s", 1) + " || (p1)) && (" + getSyntaxForKeywordToken("a", 1) + " || (p0)))", guard.render());
}
@Test
public void testCardinalityStarWithoutContextWithoutPredicates_expectUnguarded() throws Exception {
// @formatter:off
String model =
MODEL_PREAMBLE +
"S: ('a')*;";
// @formatter:off
XtextResource resource = getResourceFromString(model);
Grammar grammar = ((Grammar) resource.getContents().get(0));
AbstractRule rule = getRule(grammar, "S");
HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives());
assertTrue(guard.isTrivial());
assertFalse(guard.hasTerminal());
}
@Test(expected = UnsupportedConstructException.class)
public void testCardinalityStarWithoutContext_expectUnsupporedConstruct() throws Exception {
// @formatter:off
@ -323,6 +338,22 @@ public class HoistingProcessorTest extends AbstractXtextTests {
assertEquals("((" + getSyntaxForKeywordToken("a", 1) + " || (p0)) && (" + getSyntaxForKeywordToken("b", 1) + " || (p1)))", guard.render());
}
@Test
public void testUnorderedGroupWithEmptyPathsWithoutContextWithoutPredicates_expectUnguarded() throws Exception {
// @formatter:off
String model =
MODEL_PREAMBLE +
"S: ('a')? & ('b');";
// @formatter:off
XtextResource resource = getResourceFromString(model);
Grammar grammar = ((Grammar) resource.getContents().get(0));
AbstractRule rule = getRule(grammar, "S");
HoistingGuard guard = hoistingProcessor.findHoistingGuard(rule.getAlternatives());
assertTrue(guard.isTrivial());
assertFalse(guard.hasTerminal());
}
@Test
public void testUnorderedGroupWithNoEmptyPathsWithoutContext() throws Exception {
// @formatter:off

View file

@ -329,18 +329,24 @@ public class HoistingProcessor {
}
private HoistingGuard findGuardForElement(AbstractElement element, AbstractRule currentRule) {
if (isTrivialCardinality(element)) {
return findGuardForElementWithTrivialCardinality(element, currentRule);
} else if (isOneOrMoreCardinality(element)) {
if (isTrivialCardinality(element) ||
isOneOrMoreCardinality(element)
) {
return findGuardForElementWithTrivialCardinality(element, currentRule);
} else if (isOptionalCardinality(element)) {
if (pathHasTokenOrAction(element)) {
// there might be a token in this element
// no context accessible to construct guard
// this does only work when analyzing group
// TODO: maybe generate warning and return terminal()
throw new OptionalCardinalityWithoutContextException("optional cardinality is only supported in groups", currentRule);
if (!pathHasHoistablePredicate(currentRule.getAlternatives())) {
// unsupported construct doesn't matter since there is no
// hoistable predicate in the rule anyway.
return HoistingGuard.unguarded();
} else {
// there might be a token in this element
// no context accessible to construct guard
// this does only work when analyzing group
// TODO: maybe generate warning and return terminal()
throw new OptionalCardinalityWithoutContextException("optional cardinality is only supported in groups", currentRule);
}
} else {
// element with cardinality ? or * has no token or action
// -> the path is accessible whether or not this element is guarded
@ -379,11 +385,17 @@ public class HoistingProcessor {
} else if (element instanceof UnorderedGroup) {
if (((UnorderedGroup) element).getElements().stream().allMatch(GrammarUtil::isOptionalCardinality)) {
if (pathHasTokenOrAction(element)) {
// if unordered group has tokens or actions we need the context which is not available here
// only works when analyzing groups
// TODO: maybe add warning and return unguarded
throw new UnsupportedConstructException("unordered groups with hoisting-relevant elements and optional cardinalities are only supported in groups", currentRule);
if (!pathHasHoistablePredicate(currentRule.getAlternatives())) {
// unsupported construct but rule doesn't contain hoistable predicates
return HoistingGuard.unguarded();
} else {
// if unordered group has tokens or actions we need the context which is
// not available here
// only works when analyzing groups
// TODO: maybe add warning and return unguarded
throw new UnsupportedConstructException("unordered groups with hoisting-relevant elements and optional cardinalities are only supported in groups", currentRule);
}
} else {
// the path is accessible whether or not any guard is satisfied
// -> assume it's unguarded
@ -403,7 +415,12 @@ public class HoistingProcessor {
} else if (element instanceof Assignment) {
return findGuardForElement(((Assignment) element).getTerminal(), currentRule);
} else {
throw new UnsupportedConstructException("element not supported: " + element.toString(), currentRule);
if (!pathHasHoistablePredicate(currentRule.getAlternatives())) {
// unsupported construct but rule doesn't contain hoistable predicates
return HoistingGuard.unguarded();
} else {
throw new UnsupportedConstructException("element not supported: " + element.toString(), currentRule);
}
}
}
}