fixed bug with alternatives containing unordered groups

gave exception in token analysis
-> added handling for unordered groups to token analysis

added test case
This commit is contained in:
overflowerror 2021-12-05 18:18:18 +01:00
parent 13aef9e99b
commit 83232e5a43
3 changed files with 42 additions and 5 deletions

View file

@ -579,6 +579,24 @@ public class HoistingProcessorTest extends AbstractXtextTests {
assertTrue(guard.hasTerminal()); assertTrue(guard.hasTerminal());
} }
@Test
public void testUnorderedGroupInAlternatives_bugUnknownElementInTokenAnalysis_expectNoException() throws Exception {
// @formatter:off
String model =
MODEL_PREAMBLE +
"S: {S} $$ p0 $$?=> 'a' \n" +
" | {S} $$ p1 $$?=> ('b' & 'c');";
// @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());
assertEquals("((" + getSyntaxForKeywordToken("a", 1) + " || (p0)) && ((" + getSyntaxForKeywordToken("b", 1) + " && " + getSyntaxForKeywordToken("c", 1) + ") || (p1)))", guard.render());
}
@Test @Test
public void testAlternativeUnguardedPath() throws Exception { public void testAlternativeUnguardedPath() throws Exception {
// @formatter:off // @formatter:off

View file

@ -25,12 +25,16 @@ import org.eclipse.xtext.AbstractSemanticPredicate;
import org.eclipse.xtext.Action; import org.eclipse.xtext.Action;
import org.eclipse.xtext.Alternatives; import org.eclipse.xtext.Alternatives;
import org.eclipse.xtext.Assignment; import org.eclipse.xtext.Assignment;
import org.eclipse.xtext.CompoundElement;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.Group; import org.eclipse.xtext.Group;
import org.eclipse.xtext.JavaAction; import org.eclipse.xtext.JavaAction;
import org.eclipse.xtext.RuleCall; import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.UnorderedGroup;
import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.HoistingConfiguration; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.HoistingConfiguration;
import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.SymbolicAnalysisFailedException; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.SymbolicAnalysisFailedException;
import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.TokenAnalysisAbortedException; 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; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.token.Token;
import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.utils.MutablePrimitiveWrapper; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.utils.MutablePrimitiveWrapper;
@ -48,7 +52,7 @@ public class TokenAnalysis {
this.config = config; this.config = config;
} }
private TokenAnalysisPaths getTokenForIndexesAlternatives(Alternatives path, TokenAnalysisPaths prefix, boolean needsLength) throws TokenAnalysisAbortedException { private TokenAnalysisPaths getTokenForIndexesAlternatives(CompoundElement path, TokenAnalysisPaths prefix, boolean needsLength) throws TokenAnalysisAbortedException {
if (prefix.isDone()) { if (prefix.isDone()) {
return prefix; return prefix;
} }
@ -165,7 +169,7 @@ public class TokenAnalysis {
} else if (path instanceof Assignment) { } else if (path instanceof Assignment) {
current = getTokenForIndexes(((Assignment) path).getTerminal(), current, false); current = getTokenForIndexes(((Assignment) path).getTerminal(), current, false);
} else { } else {
throw new IllegalArgumentException("unknown element: " + path.eClass().getName()); throw new UnsupportedConstructException("unknown element: " + path.eClass().getName());
} }
// add path to result // add path to result
@ -192,6 +196,23 @@ public class TokenAnalysis {
return getTokenForIndexesAlternatives((Alternatives) path, prefix, needsLength); return getTokenForIndexesAlternatives((Alternatives) path, prefix, needsLength);
} else if (path instanceof Group) { } else if (path instanceof Group) {
return getTokenForIndexesGroup((Group) path, prefix, needsLength); return getTokenForIndexesGroup((Group) path, prefix, needsLength);
} else if (path instanceof UnorderedGroup) {
// clone unordered group
// set cardinality accordingly
// use code for alternatives
CompoundElement clonedUnorderedGroup = (CompoundElement) cloneAbstractElement(path);
if (isOptionalCardinality(path) ||
((UnorderedGroup) path).getElements().stream().allMatch(GrammarUtil::isOptionalCardinality)
){
clonedUnorderedGroup.setCardinality("*");
} else {
clonedUnorderedGroup.setCardinality("+");
}
// getTokenForIndexesAlternatives only needs a CompoundElement so we can give it
// the modified unordered group
return getTokenForIndexesAlternatives(clonedUnorderedGroup, prefix, needsLength);
} else if (path instanceof Action || } else if (path instanceof Action ||
path instanceof AbstractSemanticPredicate || path instanceof AbstractSemanticPredicate ||
path instanceof JavaAction path instanceof JavaAction
@ -217,7 +238,7 @@ public class TokenAnalysis {
} }
private boolean arePathsIdenticalFallback(AbstractElement path1, AbstractElement path2) { private boolean arePathsIdenticalFallback(AbstractElement path1, AbstractElement path2) {
// + 1, because otherwise identical paths of length TOKEN_ANALYSIS_LIMIT can't be checked // + 1, because otherwise identical paths of length token limit can't be checked
for (int i = 0; i < config.getTokenLimit() + 1; i++) { for (int i = 0; i < config.getTokenLimit() + 1; i++) {
Set<List<Token>> tokenListSet1; Set<List<Token>> tokenListSet1;
Set<List<Token>> tokenListSet2; Set<List<Token>> tokenListSet2;

View file

@ -10,8 +10,6 @@ package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.utils;
import java.util.function.Function; import java.util.function.Function;
import com.google.errorprone.annotations.MustBeClosed;
/** /**
* @author overflow - Initial contribution and API * @author overflow - Initial contribution and API
*/ */