Antlr4.Runtime.Atn.ParserATNSimulator.CanDropLoopEntryEdgeInLeftRecursiveRule C# (CSharp) Method

CanDropLoopEntryEdgeInLeftRecursiveRule() protected method

protected CanDropLoopEntryEdgeInLeftRecursiveRule ( ATNConfig config ) : bool
config ATNConfig
return bool
        protected bool CanDropLoopEntryEdgeInLeftRecursiveRule(ATNConfig config)
        {
            ATNState p = config.state;
            // First check to see if we are in StarLoopEntryState generated during
            // left-recursion elimination. For efficiency, also check if
            // the context has an empty stack case. If so, it would mean
            // global FOLLOW so we can't perform optimization
            if (p.StateType != StateType.StarLoopEntry ||
                !((StarLoopEntryState)p).isPrecedenceDecision || // Are we the special loop entry/exit state?
                 config.context.IsEmpty ||                      // If SLL wildcard
                 config.context.HasEmptyPath)
            {
                return false;
            }

            // Require all return states to return back to the same rule
            // that p is in.
            int numCtxs = config.context.Size;
            for (int i = 0; i < numCtxs; i++)
            { // for each stack context
                ATNState returnState = atn.states[config.context.GetReturnState(i)];
                if (returnState.ruleIndex != p.ruleIndex) return false;
            }

            BlockStartState decisionStartState = (BlockStartState)p.Transition(0).target;
            int blockEndStateNum = decisionStartState.endState.stateNumber;
            BlockEndState blockEndState = (BlockEndState)atn.states[blockEndStateNum];

            // Verify that the top of each stack context leads to loop entry/exit
            // state through epsilon edges and w/o leaving rule.
            for (int i = 0; i < numCtxs; i++)
            {                           // for each stack context
                int returnStateNumber = config.context.GetReturnState(i);
                ATNState returnState = atn.states[returnStateNumber];
                // all states must have single outgoing epsilon edge
                if (returnState.NumberOfTransitions != 1 ||
                    !returnState.Transition(0).IsEpsilon)
                {
                    return false;
                }
                // Look for prefix op case like 'not expr', (' type ')' expr
                ATNState returnStateTarget = returnState.Transition(0).target;
                if (returnState.StateType == StateType.BlockEnd && returnStateTarget == p)
                {
                    continue;
                }
                // Look for 'expr op expr' or case where expr's return state is block end
                // of (...)* internal block; the block end points to loop back
                // which points to p but we don't need to check that
                if (returnState == blockEndState)
                {
                    continue;
                }
                // Look for ternary expr ? expr : expr. The return state points at block end,
                // which points at loop entry state
                if (returnStateTarget == blockEndState)
                {
                    continue;
                }
                // Look for complex prefix 'between expr and expr' case where 2nd expr's
                // return state points at block end state of (...)* internal block
                if (returnStateTarget.StateType == StateType.BlockEnd &&
                     returnStateTarget.NumberOfTransitions == 1 &&
                     returnStateTarget.Transition(0).IsEpsilon &&
                     returnStateTarget.Transition(0).target == p)
                {
                    continue;
                }

                // anything else ain't conforming
                return false;
            }

            return true;
        }