in src/org/intellij/grammar/analysis/BnfFirstNextAnalyzer.java [99:168]
private Map<BnfExpression, BnfExpression> calcNextInner(@NotNull BnfExpression targetExpression,
Map<BnfExpression, BnfExpression> result,
Set<BnfExpression> visited) {
Map<BnfExpression, BnfExpression> cached = myNextCache.get(targetExpression);
if (cached != null) return cached;
LinkedList<BnfExpression> stack = new LinkedList<>();
HashSet<BnfRule> totalVisited = new HashSet<>();
Set<BnfExpression> curResult = new HashSet<>();
stack.add(targetExpression);
main: while (!stack.isEmpty()) {
PsiElement cur = stack.removeLast();
BnfExpression startingExpr = cur instanceof BnfReferenceOrToken? (BnfExpression)cur : null;
PsiElement parent = cur.getParent();
while (parent instanceof BnfExpression && (myParentFilter == null || myParentFilter.value(parent))) {
curResult.clear();
PsiElement grandPa = parent.getParent();
if (grandPa instanceof BnfRule && ParserGeneratorUtil.Rule.isExternal((BnfRule)grandPa) ||
grandPa instanceof BnfExternalExpression /*todo support meta rules*/) {
result.put(BNF_MATCHES_ANY, startingExpr);
break;
}
else if (parent instanceof BnfSequence) {
List<BnfExpression> children = ((BnfSequence)parent).getExpressionList();
int idx = children.indexOf(cur);
List<BnfExpression> sublist = myBackward? children.subList(0, idx) : children.subList(idx + 1, children.size());
calcSequenceFirstInner(sublist, curResult, visited);
boolean skipResolve = !curResult.contains(BNF_MATCHES_EOF);
for (BnfExpression e : curResult) {
result.put(e, startingExpr);
}
if (skipResolve) continue main;
}
else if (parent instanceof BnfQuantified) {
IElementType effectiveType = ParserGeneratorUtil.getEffectiveType(parent);
if (effectiveType == BnfTypes.BNF_OP_ZEROMORE || effectiveType == BnfTypes.BNF_OP_ONEMORE) {
calcFirstInner((BnfExpression)parent, curResult, visited);
for (BnfExpression e : curResult) {
result.put(e, startingExpr);
}
}
}
cur = parent;
parent = grandPa;
}
if (parent instanceof BnfRule &&
(myParentFilter == null || myParentFilter.value(parent)) &&
totalVisited.add((BnfRule)parent)) {
BnfRule rule = (BnfRule)parent;
for (PsiReference reference : ReferencesSearch.search(rule, rule.getUseScope()).findAll()) {
PsiElement element = reference.getElement();
if (element instanceof BnfExpression && PsiTreeUtil.getParentOfType(element, BnfPredicate.class) == null) {
BnfAttr attr = PsiTreeUtil.getParentOfType(element, BnfAttr.class);
if (attr != null) {
if (KnownAttribute.getCompatibleAttribute(attr.getName()) == KnownAttribute.RECOVER_WHILE) {
result.put(BNF_MATCHES_ANY, startingExpr);
}
}
else {
stack.add((BnfExpression)element);
}
}
}
}
}
if (result.isEmpty()) result.put(BNF_MATCHES_EOF, null);
myNextCache.put(targetExpression, result);
return result;
}