mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-15 00:08:55 +00:00
removed loop progress exceptions and endless loop shortcut
there is no need to throw an exception if a loop has no progress -> it can be skipped fixed bug with merge() in TokenAnalysisPaths: merging with empty path is an identity operation but further merged with the same path cause problems because of concurrent modifications in the LinkedHashSet
This commit is contained in:
parent
3af9fd0c4a
commit
e00d86eb1c
2 changed files with 37 additions and 69 deletions
|
@ -196,7 +196,7 @@ public class TokenAnalysis {
|
|||
path.resetProgress();
|
||||
|
||||
// shortcut endless loops instead of throwing exception
|
||||
path = getTokenPaths(element, path, false, false, true);
|
||||
path = getTokenPaths(element, path, false, false);
|
||||
|
||||
if (!path.isDone() && element != null) {
|
||||
boolean _considerCardinalities = considerCardinalities;
|
||||
|
@ -238,11 +238,11 @@ public class TokenAnalysis {
|
|||
return result;
|
||||
}
|
||||
|
||||
private TokenAnalysisPaths getTokenPathsTrivial(Group path, TokenAnalysisPaths prefix, boolean shortcutEndlessLoops) {
|
||||
private TokenAnalysisPaths getTokenPathsTrivial(Group path, TokenAnalysisPaths prefix) {
|
||||
TokenAnalysisPaths result = new TokenAnalysisPaths(prefix);
|
||||
|
||||
for(AbstractElement element : path.getElements()) {
|
||||
result = getTokenPaths(element, result, false, false, shortcutEndlessLoops);
|
||||
result = getTokenPaths(element, result, false, false);
|
||||
if (result.isDone()) {
|
||||
break;
|
||||
}
|
||||
|
@ -250,16 +250,16 @@ public class TokenAnalysis {
|
|||
|
||||
return result;
|
||||
}
|
||||
private TokenAnalysisPaths getTokenPathsTrivial(Alternatives path, TokenAnalysisPaths prefix, boolean shortcutEndlessLoops) {
|
||||
private TokenAnalysisPaths getTokenPathsTrivial(Alternatives path, TokenAnalysisPaths prefix) {
|
||||
TokenAnalysisPaths result = TokenAnalysisPaths.empty(prefix);
|
||||
|
||||
for(AbstractElement element : path.getElements()) {
|
||||
result = result.merge(getTokenPaths(element, prefix, false, false, shortcutEndlessLoops));
|
||||
result = result.merge(getTokenPaths(element, prefix, false, false));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
private TokenAnalysisPaths getTokenPathsTrivial(UnorderedGroup path, TokenAnalysisPaths prefix, boolean shortcutEndlessLoops) {
|
||||
private TokenAnalysisPaths getTokenPathsTrivial(UnorderedGroup path, TokenAnalysisPaths prefix) {
|
||||
TokenAnalysisPaths result;
|
||||
TokenAnalysisPaths current;
|
||||
|
||||
|
@ -272,53 +272,36 @@ public class TokenAnalysis {
|
|||
do {
|
||||
current = TokenAnalysisPaths.empty(result);
|
||||
current.resetProgress();
|
||||
int currentPosition = current.getMinPosition();
|
||||
|
||||
for (AbstractElement element : path.getElements()) {
|
||||
current = current.merge(getTokenPaths(element, result, false, false, shortcutEndlessLoops));
|
||||
current = current.merge(getTokenPaths(element, result, false, false));
|
||||
}
|
||||
|
||||
result.resetProgress();
|
||||
result = result.merge(current);
|
||||
|
||||
if (current.getMinPosition() == currentPosition) {
|
||||
// endless loop
|
||||
// current will never be done since there is no progress to the shortest path
|
||||
if (shortcutEndlessLoops) {
|
||||
if (!result.hasProgress()) {
|
||||
// no progress
|
||||
// abort endless loop
|
||||
break;
|
||||
} else {
|
||||
// there is still some progress done
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
throw new TokenAnalysisAbortedException("no progress in loop");
|
||||
}
|
||||
}
|
||||
} while(!current.isDone());
|
||||
} while(result.hasProgress());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private TokenAnalysisPaths getTokenPathsTrivial(AbstractElement path, TokenAnalysisPaths prefix, boolean shortcutEndlessLoops) {
|
||||
private TokenAnalysisPaths getTokenPathsTrivial(AbstractElement path, TokenAnalysisPaths prefix) {
|
||||
return new XtextSwitch<TokenAnalysisPaths>() {
|
||||
@Override
|
||||
public TokenAnalysisPaths caseGroup(Group group) {
|
||||
return getTokenPathsTrivial(group, prefix, shortcutEndlessLoops);
|
||||
return getTokenPathsTrivial(group, prefix);
|
||||
};
|
||||
@Override
|
||||
public TokenAnalysisPaths caseAlternatives(Alternatives alternatives) {
|
||||
return getTokenPathsTrivial(alternatives, prefix, shortcutEndlessLoops);
|
||||
return getTokenPathsTrivial(alternatives, prefix);
|
||||
};
|
||||
@Override
|
||||
public TokenAnalysisPaths caseUnorderedGroup(UnorderedGroup unorderedGroup) {
|
||||
return getTokenPathsTrivial(unorderedGroup, prefix, shortcutEndlessLoops);
|
||||
return getTokenPathsTrivial(unorderedGroup, prefix);
|
||||
};
|
||||
@Override
|
||||
public TokenAnalysisPaths caseAssignment(Assignment assignment) {
|
||||
return getTokenPaths(assignment.getTerminal(), prefix, false, false, shortcutEndlessLoops);
|
||||
return getTokenPaths(assignment.getTerminal(), prefix, false, false);
|
||||
};
|
||||
@Override
|
||||
public TokenAnalysisPaths caseRuleCall(RuleCall call) {
|
||||
|
@ -326,7 +309,7 @@ public class TokenAnalysis {
|
|||
isParserRuleCall(call) ||
|
||||
isEnumRuleCall(call)
|
||||
) {
|
||||
return getTokenPaths(call.getRule().getAlternatives(), prefix, false, false, shortcutEndlessLoops);
|
||||
return getTokenPaths(call.getRule().getAlternatives(), prefix, false, false);
|
||||
} else {
|
||||
// probably terminal rule call -> go to default case
|
||||
return null;
|
||||
|
@ -358,7 +341,7 @@ public class TokenAnalysis {
|
|||
}
|
||||
|
||||
private TokenAnalysisPaths getTokenPaths(
|
||||
AbstractElement path, TokenAnalysisPaths prefix, boolean analyseContext, boolean needsLength, boolean shortcutEndlessLoops
|
||||
AbstractElement path, TokenAnalysisPaths prefix, boolean analyseContext, boolean needsLength
|
||||
) {
|
||||
if (prefix.isDone()) {
|
||||
return prefix;
|
||||
|
@ -373,11 +356,11 @@ public class TokenAnalysis {
|
|||
}
|
||||
|
||||
// use actual cardinality from path
|
||||
return getTokenPaths(path, path.getCardinality(), prefix, analyseContext, needsLength, shortcutEndlessLoops);
|
||||
return getTokenPaths(path, path.getCardinality(), prefix, analyseContext, needsLength);
|
||||
}
|
||||
|
||||
private TokenAnalysisPaths getTokenPaths(
|
||||
AbstractElement path, String cardinality, TokenAnalysisPaths prefix, boolean analyseContext, boolean needsLength, boolean shortcutEndlessLoops
|
||||
AbstractElement path, String cardinality, TokenAnalysisPaths prefix, boolean analyseContext, boolean needsLength
|
||||
) {
|
||||
// analyseContext implies needsLength
|
||||
|
||||
|
@ -409,10 +392,9 @@ public class TokenAnalysis {
|
|||
boolean loop = isVirtualMultipleCardinality(cardinality);
|
||||
|
||||
do {
|
||||
int currentMinPosition = result.getMinPosition();
|
||||
result.resetProgress();
|
||||
|
||||
TokenAnalysisPaths tokenPaths = getTokenPathsTrivial(path, result, shortcutEndlessLoops);
|
||||
TokenAnalysisPaths tokenPaths = getTokenPathsTrivial(path, result);
|
||||
|
||||
if (tokenPaths.isDone()) {
|
||||
result = result.merge(tokenPaths);
|
||||
|
@ -426,45 +408,21 @@ public class TokenAnalysis {
|
|||
result = result.merge(tokenPaths);
|
||||
}
|
||||
|
||||
if (loop) {
|
||||
if (result.getMinPosition() == currentMinPosition) {
|
||||
// endless loop
|
||||
// result will never be done since there is no progress to the shortest path
|
||||
if (shortcutEndlessLoops) {
|
||||
if (!result.hasProgress()) {
|
||||
// no progress
|
||||
// abort endless loop
|
||||
break;
|
||||
} else {
|
||||
// there is still some progress done
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
throw new TokenAnalysisAbortedException("no progress in loop");
|
||||
}
|
||||
} else {
|
||||
currentMinPosition = result.getMinPosition();
|
||||
}
|
||||
}
|
||||
} while (loop);
|
||||
} while (loop && result.hasProgress());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private TokenAnalysisPaths getTokenPaths(AbstractElement path, List<Integer> indexes, boolean analyseContext, boolean needsLength, boolean shortcutEndlessLoops) {
|
||||
return getTokenPaths(path, new TokenAnalysisPaths(indexes), analyseContext, needsLength, shortcutEndlessLoops);
|
||||
}
|
||||
|
||||
private TokenAnalysisPaths getTokenPathsNoLength(AbstractElement path, List<Integer> indexes) {
|
||||
return getTokenPaths(path, new TokenAnalysisPaths(indexes), false, false, false);
|
||||
return getTokenPaths(path, new TokenAnalysisPaths(indexes), false, false);
|
||||
}
|
||||
|
||||
private TokenAnalysisPaths getTokenPathsContext(AbstractElement path, List<Integer> indexes) {
|
||||
return getTokenPaths(path, new TokenAnalysisPaths(indexes), true, true, false);
|
||||
return getTokenPaths(path, new TokenAnalysisPaths(indexes), true, true);
|
||||
}
|
||||
|
||||
private TokenAnalysisPaths getTokenPaths(AbstractElement path, String virtualCardinality, List<Integer> indexes, boolean analyseContext, boolean needsLength, boolean shortcutEndlessLoops) {
|
||||
return getTokenPaths(path, virtualCardinality, new TokenAnalysisPaths(indexes), analyseContext, needsLength, shortcutEndlessLoops);
|
||||
private TokenAnalysisPaths getTokenPaths(AbstractElement path, String virtualCardinality, List<Integer> indexes, boolean analyseContext, boolean needsLength) {
|
||||
return getTokenPaths(path, virtualCardinality, new TokenAnalysisPaths(indexes), analyseContext, needsLength);
|
||||
}
|
||||
|
||||
private TokenAnalysisPaths getTokenPathsContextOnly(AbstractElement path, List<Integer> indexes) throws TokenAnalysisAbortedException {
|
||||
|
@ -583,7 +541,7 @@ public class TokenAnalysis {
|
|||
tokenCombinations(indexList -> {
|
||||
|
||||
// no context analysis // TODO why?
|
||||
List<List<Token>> tokenListsForPath = getTokenPaths(element, virtualCardinality, indexList, false, true, false)
|
||||
List<List<Token>> tokenListsForPath = getTokenPaths(element, virtualCardinality, indexList, false, true)
|
||||
.getTokenPaths();
|
||||
List<List<Token>> tokenListForContext = getTokenPathsContextOnly(element, indexList)
|
||||
.getTokenPaths();
|
||||
|
@ -658,7 +616,7 @@ public class TokenAnalysis {
|
|||
|
||||
public List<List<AbstractElement>> getAllPossiblePaths(AbstractElement path) {
|
||||
// token limit + 2 so identity analysis will recognize paths that are identical up to the token limit on the flattened tree
|
||||
return getTokenPaths(path, range(0, config.getTokenLimit() + 2), false, false, true)
|
||||
return getTokenPathsNoLength(path, range(0, config.getTokenLimit() + 2))
|
||||
.getTokenPaths()
|
||||
.stream()
|
||||
.map(l -> l.stream()
|
||||
|
|
|
@ -10,6 +10,7 @@ package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.pathAnalysis;
|
|||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
|
@ -20,7 +21,7 @@ import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.utils.StreamUtils
|
|||
* @author overflow - Initial contribution and APILinkedHashSet
|
||||
*/
|
||||
public class TokenAnalysisPaths {
|
||||
private LinkedHashSet<TokenAnalysisPath> tokenPaths = new LinkedHashSet<>();
|
||||
private Set<TokenAnalysisPath> tokenPaths = new LinkedHashSet<>();
|
||||
private boolean isEmpty = false;
|
||||
private boolean hasProgress = false;
|
||||
|
||||
|
@ -60,7 +61,9 @@ public class TokenAnalysisPaths {
|
|||
|
||||
public TokenAnalysisPaths merge(TokenAnalysisPaths other) {
|
||||
if (isEmpty) {
|
||||
return other;
|
||||
return other.clone();
|
||||
} else if (other.isEmpty) {
|
||||
return this.clone();
|
||||
} else {
|
||||
// set hasProgress if other has progress and progress is merged
|
||||
if (this.tokenPaths.addAll(other.tokenPaths)) {
|
||||
|
@ -98,4 +101,11 @@ public class TokenAnalysisPaths {
|
|||
+ "\n)";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenAnalysisPaths clone() {
|
||||
TokenAnalysisPaths clone = new TokenAnalysisPaths(this);
|
||||
clone.isEmpty = this.isEmpty;
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue