From d8ee388b316dd92acb255bb297d82811cb55188d Mon Sep 17 00:00:00 2001 From: overflowerror Date: Fri, 10 Dec 2021 17:33:28 +0100 Subject: [PATCH] basic support for context analysis in unordered groups --- .../antlr/hoisting/HoistingProcessor.java | 62 ++++--------------- .../hoisting/pathAnalysis/TokenAnalysis.java | 16 ++++- 2 files changed, 26 insertions(+), 52 deletions(-) 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 3d8c05739..f95266dd4 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 @@ -26,7 +26,6 @@ import org.eclipse.xtext.Alternatives; import org.eclipse.xtext.Assignment; import org.eclipse.xtext.CompoundElement; import org.eclipse.xtext.Grammar; -import org.eclipse.xtext.GrammarUtil; import org.eclipse.xtext.Group; import org.eclipse.xtext.JavaAction; import org.eclipse.xtext.RuleCall; @@ -180,28 +179,15 @@ public class HoistingProcessor { } } - private List rewriteUnorderedGroupsAndGetElements(Group group) { - List elements = new ArrayList<>(group.getElements()); + private HoistingGuard findGuardForUnorderedGroup(UnorderedGroup element, AbstractRule currentRule) { + // Unordered group (A & B) is the same as (A | B)+ or (A | B)* (is A and B are optional) + // but the cardinality doesn't matter for hoisting + // if A and B are optional the guard for the alternatives need to check the context + // if not the alternatives are actual alternatives - int size = elements.size(); - for (int i = 0; i < size; i++) { - AbstractElement element = elements.get(i); - if (element instanceof UnorderedGroup) { - // Unordered group (A & B) is the same as (A | B)+ or (A | B)* (is A and B are optional) - // -> create virtual element - - Alternatives virtualAlternatives = XtextFactory.eINSTANCE.createAlternatives(); - addElementsToCompoundElement(virtualAlternatives, ((UnorderedGroup) element).getElements()); - - // if A and B are optional the cardinality would be * - // but it doesn't matter for hoisting - virtualAlternatives.setCardinality("+"); - - elements.set(i, virtualAlternatives); - } - } + // TODO: check if hasTerminal is valid - return elements; + return findGuardForAlternatives(element, currentRule); } private HoistingGuard findGuardForGroup(Group group, AbstractRule currentRule) { @@ -209,7 +195,7 @@ public class HoistingProcessor { GroupGuard groupGuard = new GroupGuard(); - Iterator iterator = rewriteUnorderedGroupsAndGetElements(group).iterator(); + Iterator iterator = group.getElements().iterator(); while (iterator.hasNext()) { AbstractElement element = iterator.next(); @@ -231,6 +217,8 @@ public class HoistingProcessor { } } else if (cardinality.equals("?") || cardinality.equals("*")) { + // though not technically necessary, rewrite tree to context checks are not needed + // rewrite cardinality to alternatives // A? B -> A B | B // A* B -> A+ B | B -> A B (see above) @@ -404,35 +392,7 @@ public class HoistingProcessor { } else if (element instanceof JavaAction) { return HoistingGuard.action(); } else if (element instanceof UnorderedGroup) { - if (((UnorderedGroup) element).getElements().stream().allMatch(GrammarUtil::isOptionalCardinality)) { - if (pathHasTokenOrAction(element)) { - 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 - return HoistingGuard.unguarded(); - } - } else { - if (pathHasTokenOrAction(element)) { - // there is no context but it might still be possible to find a guard for this group - // only works if none of the paths is empty or optional - return findGuardForAlternatives((CompoundElement) element, currentRule); - } else { - // the path is accessible whether or not any guard is satisfied - // -> assume it's unguarded - return HoistingGuard.unguarded(); - } - } + return findGuardForUnorderedGroup((UnorderedGroup) element, currentRule); } else if (element instanceof Assignment) { return findGuardForElement(((Assignment) element).getTerminal(), currentRule); } else { 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 1b9c7d2bb..ba8bcb15e 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 @@ -37,6 +37,7 @@ import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.HoistingConfigura 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.token.Token; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.utils.DebugUtils; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.utils.MutablePrimitiveWrapper; import static org.eclipse.xtext.GrammarUtil.*; @@ -92,9 +93,16 @@ public class TokenAnalysis { container = getCompoundContainer(last); } + log.info("getNext: " + abstractElementToShortString(last)); + log.info("container: " + abstractElementToShortString(container)); + + final AbstractElement finalLast = last; + if (container instanceof UnorderedGroup) { List result = new ArrayList<>(); - result.addAll(container.getElements()); + result.addAll(container.getElements().stream() + .filter(e -> e != finalLast).collect(Collectors.toList()) + ); result.addAll(getNextElementsInContext(container)); return result; } else if (container instanceof Group) { @@ -135,7 +143,12 @@ public class TokenAnalysis { private TokenAnalysisPaths getTokenPathsContext(AbstractElement last, TokenAnalysisPaths prefix) { + log.info("get context for: " + abstractElementToShortString(last)); + List context = getNextElementsInContext(last); + + log.info(context.size()); + log.info(context.stream().map(DebugUtils::abstractElementToShortString).collect(Collectors.toList())); TokenAnalysisPaths result = TokenAnalysisPaths.empty(prefix); @@ -157,6 +170,7 @@ public class TokenAnalysis { } } + log.info("done"); return result; }