generateRuleBypassTransition method
void
generateRuleBypassTransition(
- ATN atn,
- int idx
)
Implementation
void generateRuleBypassTransition(ATN atn, int idx) {
final bypassStart = BasicBlockStartState(idx);
atn.addState(bypassStart);
final bypassStop = BlockEndState(idx);
atn.addState(bypassStop);
bypassStart.endState = bypassStop;
atn.defineDecisionState(bypassStart);
bypassStop.startState = bypassStart;
ATNState? endState;
Transition? excludeTransition;
if (atn.ruleToStartState[idx].isLeftRecursiveRule) {
// wrap from the beginning of the rule to the StarLoopEntryState
endState = null;
for (var state in atn.states) {
if (state == null) {
continue;
}
if (state.ruleIndex != idx) {
continue;
}
if (state is! StarLoopEntryState) {
continue;
}
final maybeLoopEndState =
state.transition(state.numberOfTransitions - 1).target;
if (maybeLoopEndState is! LoopEndState) {
continue;
}
if (maybeLoopEndState.epsilonOnlyTransitions &&
maybeLoopEndState.transition(0).target is RuleStopState) {
endState = state;
break;
}
}
if (endState == null) {
throw UnsupportedError(
"Couldn't identify final state of the precedence rule prefix section.",
);
}
excludeTransition =
(endState as StarLoopEntryState).loopBackState!.transition(0);
} else {
endState = atn.ruleToStopState[idx];
}
// all non-excluded transitions that currently target end state need to target blockEnd instead
for (var state in atn.states) {
if (state == null) {
continue;
}
for (var transition in state.transitions) {
if (transition == excludeTransition) {
continue;
}
if (transition.target == endState) {
transition.target = bypassStop;
}
}
}
// all transitions leaving the rule start state need to leave blockStart instead
while (atn.ruleToStartState[idx].numberOfTransitions > 0) {
final transition = atn.ruleToStartState[idx]
.removeTransition(atn.ruleToStartState[idx].numberOfTransitions - 1);
bypassStart.addTransition(transition);
}
// link the new states
atn.ruleToStartState[idx].addTransition(EpsilonTransition(bypassStart));
bypassStop.addTransition(EpsilonTransition(endState));
ATNState matchState = BasicState(idx);
atn.addState(matchState);
matchState.addTransition(AtomTransition(
bypassStop,
atn.ruleToTokenType[idx],
));
bypassStart.addTransition(EpsilonTransition(matchState));
}