mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-16 00:38:56 +00:00
fixed endless recursion in context analysis
when context analysis is needed and an element in context has multiple cardinality and contains empty paths (e.g. ?-quantified) the quantified element will be recursed endlessly without the token analysis path even being done (since there is always an empty path) - this also applies to unordered groups. recognizing empty paths is not trivial because of recursive rules. solution: save "call stack" (actually just a set of visited elements) during recursions in context analysis. if an element is seen multiple times we check if there is any progress in the analysis paths. if not this is an endless recursion -> throw exception
This commit is contained in:
parent
a1b9bb9a59
commit
623f4b69ae
2 changed files with 59 additions and 1 deletions
org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting
|
@ -0,0 +1,47 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2022 itemis AG (http://www.itemis.eu) and others.
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions;
|
||||
|
||||
import org.eclipse.xtext.AbstractRule;
|
||||
|
||||
/**
|
||||
* @author overflow - Initial contribution and API
|
||||
*/
|
||||
public class EmptyRecursionPathInContextAnalysisException extends HoistingException {
|
||||
private static final long serialVersionUID = 3820353828411603508L;
|
||||
|
||||
public EmptyRecursionPathInContextAnalysisException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public EmptyRecursionPathInContextAnalysisException(String message, AbstractRule rule) {
|
||||
super(message, rule);
|
||||
}
|
||||
|
||||
public EmptyRecursionPathInContextAnalysisException(String message, Throwable cause, AbstractRule rule) {
|
||||
super(message, cause, rule);
|
||||
}
|
||||
|
||||
public EmptyRecursionPathInContextAnalysisException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public EmptyRecursionPathInContextAnalysisException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public EmptyRecursionPathInContextAnalysisException(Throwable cause, AbstractRule rule) {
|
||||
super(cause, rule);
|
||||
}
|
||||
|
||||
public EmptyRecursionPathInContextAnalysisException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
|
@ -36,6 +36,7 @@ import org.eclipse.xtext.RuleCall;
|
|||
import org.eclipse.xtext.UnorderedGroup;
|
||||
import org.eclipse.xtext.util.XtextSwitch;
|
||||
import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.HoistingConfiguration;
|
||||
import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.EmptyRecursionPathInContextAnalysisException;
|
||||
import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.NestedPrefixAlternativesException;
|
||||
import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.SymbolicAnalysisFailedException;
|
||||
import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.TokenAnalysisAbortedException;
|
||||
|
@ -153,6 +154,10 @@ public class TokenAnalysis {
|
|||
}
|
||||
|
||||
private TokenAnalysisPaths getTokenPathsContext(AbstractElement last, TokenAnalysisPaths prefix, boolean shortcutEndlessLoops) {
|
||||
return getTokenPathsContext(last, prefix, shortcutEndlessLoops, new HashSet<>());
|
||||
}
|
||||
|
||||
private TokenAnalysisPaths getTokenPathsContext(AbstractElement last, TokenAnalysisPaths prefix, boolean shortcutEndlessLoops, Set<AbstractElement> callStack) {
|
||||
log.info("get context for: " + abstractElementToShortString(last));
|
||||
|
||||
List<AbstractElement> context = getNextElementsInContext(last);
|
||||
|
@ -170,9 +175,15 @@ public class TokenAnalysis {
|
|||
for (AbstractElement element : context) {
|
||||
log.info("context element: " + abstractElementToShortString(element));
|
||||
TokenAnalysisPaths path = new TokenAnalysisPaths(prefix);
|
||||
path.resetProgress();
|
||||
path = getTokenPaths(element, path, false, false, shortcutEndlessLoops);
|
||||
if (!path.isDone() && element != null) {
|
||||
path = getTokenPathsContext(element, path, shortcutEndlessLoops);
|
||||
if (callStack.contains(element) && !path.hasProgress()) {
|
||||
throw new EmptyRecursionPathInContextAnalysisException("no progress in recursion");
|
||||
}
|
||||
Set<AbstractElement> localCallStack = new HashSet<>(callStack);
|
||||
localCallStack.add(element);
|
||||
path = getTokenPathsContext(element, path, shortcutEndlessLoops, localCallStack);
|
||||
}
|
||||
if (path.isDone()) {
|
||||
result = result.merge(path);
|
||||
|
|
Loading…
Reference in a new issue