mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-15 08:18:55 +00:00
fixed problem with unsupported constructs in unguarded rules
This commit is contained in:
parent
62e9d44a64
commit
13aef9e99b
2 changed files with 64 additions and 16 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue