in src/org/intellij/grammar/generator/RuleGraphHelper.java [351:475]
private Map<PsiElement, Cardinality> collectMembersInner(BnfRule rule, BnfExpression tree, Set<Object> visited) {
boolean firstNonTrivial = tree == Rule.firstNotTrivial(rule);
boolean outerLeft = (firstNonTrivial || rule.getExpression() == tree) &&
Rule.isLeft(rule) && !isPrivateOrNoType(rule) && !Rule.isInner(rule);
boolean tryCollapse = firstNonTrivial && !outerLeft && !isPrivateOrNoType(rule) && !Rule.isFake(rule);
Map<PsiElement, Cardinality> result;
if (tree instanceof BnfReferenceOrToken) {
BnfRule targetRule = ((BnfReferenceOrToken)tree).resolveRule();
if (targetRule != null) {
if (Rule.isExternal(targetRule)) {
result = psiMap(newExternalPsi(targetRule.getName()), REQUIRED);
}
else if (Rule.isLeft(targetRule)) {
if (!Rule.isInner(targetRule) && !isPrivateOrNoType(targetRule)) {
result = psiMap();
result.put(getSynonymTargetOrSelf(targetRule), REQUIRED);
result.put(LEFT_MARKER, REQUIRED);
}
else {
result = Collections.emptyMap();
}
}
else if (isPrivateOrNoType(targetRule)) {
result = collectMembers(targetRule, visited);
}
else if (Rule.isUpper(targetRule)) {
result = Collections.emptyMap();
}
else {
result = psiMap(getSynonymTargetOrSelf(targetRule), REQUIRED);
}
}
else {
result = psiMap(tree, REQUIRED);
}
if (tryCollapse && willCollapse(rule, result)) {
result = Collections.emptyMap();
}
}
else if (tree instanceof BnfExternalExpression) {
BnfExternalExpression expression = (BnfExternalExpression)tree;
List<BnfExpression> arguments = expression.getArguments();
if (arguments.isEmpty() && Rule.isMeta(rule)) {
result = psiMap(newExternalPsi(tree.getText()), REQUIRED);
}
else {
BnfExpression ruleRef = expression.getRefElement();
BnfRule metaRule = ((BnfReferenceOrToken)ruleRef).resolveRule();
if (metaRule == null) {
result = psiMap(newExternalPsi("#" + ruleRef.getText()), REQUIRED);
}
else if (isPrivateOrNoType(metaRule)) {
result = psiMap();
Map<PsiElement, Cardinality> metaResults = collectMembers(metaRule, visited);
List<String> params = null;
for (PsiElement member : metaResults.keySet()) {
Cardinality cardinality = metaResults.get(member);
if (!isExternalPsi(member)) {
result.put(member, cardinality);
}
else {
if (params == null) {
params = collectMetaParameters(metaRule, metaRule.getExpression());
}
int idx = params.indexOf(member.getText());
if (idx > -1 && idx < arguments.size()) {
Map<PsiElement, Cardinality> argMap = collectMembers(rule, arguments.get(idx), visited);
for (PsiElement element : argMap.keySet()) {
Cardinality existing = ObjectUtils.notNull(result.get(element), NONE);
result.put(element, existing.or(cardinality.and(argMap.get(element))));
}
}
}
}
}
else {
result = psiMap(metaRule, REQUIRED);
}
}
if (tryCollapse && willCollapse(rule, result)) {
result = Collections.emptyMap();
}
}
else {
List<BnfExpression> pinned = new ArrayList<>();
GrammarUtil.processPinnedExpressions(rule, new CommonProcessors.CollectProcessor<>(pinned));
boolean pinApplied = false;
IElementType type = getEffectiveType(tree);
List<Map<PsiElement, Cardinality>> list = new ArrayList<>();
List<BnfExpression> childExpressions = getChildExpressions(tree);
for (BnfExpression child : childExpressions) {
Map<PsiElement, Cardinality> nextMap = collectMembers(rule, child, visited);
if (pinApplied) {
nextMap = joinMaps(rule, false, BnfTypes.BNF_OP_OPT, Collections.singletonList(nextMap));
}
list.add(nextMap);
if (!pinApplied && pinned.contains(child)) {
pinApplied = true;
}
}
result = joinMaps(rule, tryCollapse, type, list);
result = type == BnfTypes.BNF_SEQUENCE && visited.contains(RECURSION_MARKER) && result.remove(rule.getExpression()) != null ?
joinMaps(rule, false, type, Arrays.asList(result, result)) : result;
}
if (outerLeft && rule.getExpression() == tree) {
List<Map<PsiElement, Cardinality>> list = new ArrayList<>();
Map<BnfRule, Cardinality> rulesToTheLeft = getRulesToTheLeft(rule);
for (BnfRule r : rulesToTheLeft.keySet()) {
Cardinality cardinality = rulesToTheLeft.get(r);
Map<PsiElement, Cardinality> leftMap = psiMap(r, REQUIRED);
if (cardinality.many()) {
list.add(joinMaps(rule, false, BnfTypes.BNF_CHOICE, Arrays.asList(leftMap, psiMap(rule, REQUIRED))));
}
else {
list.add(leftMap);
}
}
Map<PsiElement, Cardinality> combinedLeftMap = joinMaps(rule, false, BnfTypes.BNF_CHOICE, list);
result = joinMaps(rule, true, BnfTypes.BNF_SEQUENCE, Arrays.asList(result, combinedLeftMap));
}
return result;
}