xref: /plugin/combo/vendor/antlr/antlr4-php-runtime/src/Atn/ATN.php (revision 37748cd8654635afbeca80942126742f0f4cc346)
1*37748cd8SNickeau<?php
2*37748cd8SNickeau
3*37748cd8SNickeaudeclare(strict_types=1);
4*37748cd8SNickeau
5*37748cd8SNickeaunamespace Antlr\Antlr4\Runtime\Atn;
6*37748cd8SNickeau
7*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\Actions\LexerAction;
8*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\States\ATNState;
9*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\States\DecisionState;
10*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\States\RuleStartState;
11*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\States\RuleStopState;
12*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\States\TokensStartState;
13*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\Transitions\RuleTransition;
14*37748cd8SNickeauuse Antlr\Antlr4\Runtime\IntervalSet;
15*37748cd8SNickeauuse Antlr\Antlr4\Runtime\LL1Analyzer;
16*37748cd8SNickeauuse Antlr\Antlr4\Runtime\ParserRuleContext;
17*37748cd8SNickeauuse Antlr\Antlr4\Runtime\RuleContext;
18*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Token;
19*37748cd8SNickeau
20*37748cd8SNickeaufinal class ATN
21*37748cd8SNickeau{
22*37748cd8SNickeau    public const INVALID_ALT_NUMBER = 0;
23*37748cd8SNickeau    public const ATN_TYPE_LEXER = 0;
24*37748cd8SNickeau    public const ATN_TYPE_PARSER = 1;
25*37748cd8SNickeau
26*37748cd8SNickeau    /** @var array<ATNState> */
27*37748cd8SNickeau    public $states = [];
28*37748cd8SNickeau
29*37748cd8SNickeau    /**
30*37748cd8SNickeau     * Each subrule/rule is a decision point and we must track them so we
31*37748cd8SNickeau     * can go back later and build DFA predictors for them. This includes
32*37748cd8SNickeau     * all the rules, subrules, optional blocks, ()+, ()* etc...
33*37748cd8SNickeau     *
34*37748cd8SNickeau     * @var array<DecisionState>
35*37748cd8SNickeau     */
36*37748cd8SNickeau    public $decisionToState = [];
37*37748cd8SNickeau
38*37748cd8SNickeau    /**
39*37748cd8SNickeau     * Maps from rule index to starting state number.
40*37748cd8SNickeau     *
41*37748cd8SNickeau     * @var array<RuleStartState>
42*37748cd8SNickeau     */
43*37748cd8SNickeau    public $ruleToStartState = [];
44*37748cd8SNickeau
45*37748cd8SNickeau    /**
46*37748cd8SNickeau     * Maps from rule index to stop state number.
47*37748cd8SNickeau     *
48*37748cd8SNickeau     * @var array<RuleStopState>
49*37748cd8SNickeau     */
50*37748cd8SNickeau    public $ruleToStopState = [];
51*37748cd8SNickeau
52*37748cd8SNickeau    /** @var array<TokensStartState> */
53*37748cd8SNickeau    public $modeNameToStartState = [];
54*37748cd8SNickeau
55*37748cd8SNickeau    /**
56*37748cd8SNickeau     * The type of the ATN.
57*37748cd8SNickeau     *
58*37748cd8SNickeau     * @var int
59*37748cd8SNickeau     */
60*37748cd8SNickeau    public $grammarType;
61*37748cd8SNickeau
62*37748cd8SNickeau    /**
63*37748cd8SNickeau     * The maximum value for any symbol recognized by a transition in the ATN.
64*37748cd8SNickeau     *
65*37748cd8SNickeau     * @var int
66*37748cd8SNickeau     */
67*37748cd8SNickeau    public $maxTokenType;
68*37748cd8SNickeau
69*37748cd8SNickeau    /**
70*37748cd8SNickeau     * For lexer ATNs, this maps the rule index to the resulting token type.
71*37748cd8SNickeau     * For parser ATNs, this maps the rule index to the generated bypass token
72*37748cd8SNickeau     * type if the
73*37748cd8SNickeau     * {@see ATNDeserializationOptions::isGenerateRuleBypassTransitions()}
74*37748cd8SNickeau     * deserialization option was specified; otherwise, this is `null`.
75*37748cd8SNickeau     *
76*37748cd8SNickeau     * @var array<int|null>
77*37748cd8SNickeau     */
78*37748cd8SNickeau    public $ruleToTokenType = [];
79*37748cd8SNickeau
80*37748cd8SNickeau    /**
81*37748cd8SNickeau     * For lexer ATNs, this is an array of {@see LexerAction} objects which may
82*37748cd8SNickeau     * be referenced by action transitions in the ATN.
83*37748cd8SNickeau     *
84*37748cd8SNickeau     * @var array<LexerAction>
85*37748cd8SNickeau     */
86*37748cd8SNickeau    public $lexerActions = [];
87*37748cd8SNickeau
88*37748cd8SNickeau    /** @var array<TokensStartState> */
89*37748cd8SNickeau    public $modeToStartState = [];
90*37748cd8SNickeau
91*37748cd8SNickeau    /**
92*37748cd8SNickeau     * Used for runtime deserialization of ATNs from strings
93*37748cd8SNickeau     */
94*37748cd8SNickeau    public function __construct(int $grammarType, int $maxTokenType)
95*37748cd8SNickeau    {
96*37748cd8SNickeau        $this->grammarType = $grammarType;
97*37748cd8SNickeau        $this->maxTokenType = $maxTokenType;
98*37748cd8SNickeau    }
99*37748cd8SNickeau
100*37748cd8SNickeau    /**
101*37748cd8SNickeau     * Compute the set of valid tokens that can occur starting in state `state`.
102*37748cd8SNickeau     * If `context` is null, the set of tokens will not include what can follow
103*37748cd8SNickeau     * the rule surrounding `state`. In other words, the set will be
104*37748cd8SNickeau     * restricted to tokens reachable staying within `state`'s rule.
105*37748cd8SNickeau     */
106*37748cd8SNickeau    public function nextTokensInContext(ATNState $state, ?RuleContext $context) : IntervalSet
107*37748cd8SNickeau    {
108*37748cd8SNickeau        return (new LL1Analyzer($this))->look($state, null, $context);
109*37748cd8SNickeau    }
110*37748cd8SNickeau
111*37748cd8SNickeau    /**
112*37748cd8SNickeau     * Compute the set of valid tokens that can occur starting in `state` and
113*37748cd8SNickeau     * staying in same rule. {@see Token::EPSILON} is in set if we reach end of
114*37748cd8SNickeau     * rule.
115*37748cd8SNickeau     */
116*37748cd8SNickeau    public function nextTokens(ATNState $state) : IntervalSet
117*37748cd8SNickeau    {
118*37748cd8SNickeau        if ($state->nextTokenWithinRule !== null) {
119*37748cd8SNickeau            return $state->nextTokenWithinRule;
120*37748cd8SNickeau        }
121*37748cd8SNickeau
122*37748cd8SNickeau        $state->nextTokenWithinRule = $this->nextTokensInContext($state, null);
123*37748cd8SNickeau        $state->nextTokenWithinRule->setReadOnly(true);
124*37748cd8SNickeau
125*37748cd8SNickeau        return $state->nextTokenWithinRule;
126*37748cd8SNickeau    }
127*37748cd8SNickeau
128*37748cd8SNickeau    public function addState(?ATNState $state) : void
129*37748cd8SNickeau    {
130*37748cd8SNickeau        if ($state === null) {
131*37748cd8SNickeau            return;
132*37748cd8SNickeau        }
133*37748cd8SNickeau
134*37748cd8SNickeau        $state->atn = $this;
135*37748cd8SNickeau        $state->stateNumber = \count($this->states);
136*37748cd8SNickeau
137*37748cd8SNickeau        $this->states[] = $state;
138*37748cd8SNickeau    }
139*37748cd8SNickeau
140*37748cd8SNickeau    public function removeState(ATNState $state) : void
141*37748cd8SNickeau    {
142*37748cd8SNickeau        // just free mem, don't shift states in list
143*37748cd8SNickeau        unset($this->states[$state->stateNumber]);
144*37748cd8SNickeau    }
145*37748cd8SNickeau
146*37748cd8SNickeau    public function defineDecisionState(DecisionState $s) : int
147*37748cd8SNickeau    {
148*37748cd8SNickeau        $this->decisionToState[] = $s;
149*37748cd8SNickeau
150*37748cd8SNickeau        $s->decision = \count($this->decisionToState) - 1;
151*37748cd8SNickeau
152*37748cd8SNickeau        return $s->decision;
153*37748cd8SNickeau    }
154*37748cd8SNickeau
155*37748cd8SNickeau    public function getDecisionState(int $decision) : ?DecisionState
156*37748cd8SNickeau    {
157*37748cd8SNickeau        if (\count($this->decisionToState) === 0) {
158*37748cd8SNickeau            return null;
159*37748cd8SNickeau        }
160*37748cd8SNickeau
161*37748cd8SNickeau        return $this->decisionToState[$decision];
162*37748cd8SNickeau    }
163*37748cd8SNickeau
164*37748cd8SNickeau    public function getNumberOfDecisions() : int
165*37748cd8SNickeau    {
166*37748cd8SNickeau        return \count($this->decisionToState);
167*37748cd8SNickeau    }
168*37748cd8SNickeau
169*37748cd8SNickeau    /**
170*37748cd8SNickeau     * Computes the set of input symbols which could follow ATN state number
171*37748cd8SNickeau     * `stateNumber` in the specified full `context`. This method
172*37748cd8SNickeau     * considers the complete parser context, but does not evaluate semantic
173*37748cd8SNickeau     * predicates (i.e. all predicates encountered during the calculation are
174*37748cd8SNickeau     * assumed true). If a path in the ATN exists from the starting state to the
175*37748cd8SNickeau     * {@see RuleStopState} of the outermost context without matching any
176*37748cd8SNickeau     * symbols, {@see Token::EOF} is added to the returned set.
177*37748cd8SNickeau     *
178*37748cd8SNickeau     * If `context` is `null`, it is treated as {@see ParserRuleContext::EMPTY}.
179*37748cd8SNickeau     *
180*37748cd8SNickeau     * @param int         $stateNumber The ATN state number
181*37748cd8SNickeau     * @param RuleContext $context     The full parse context
182*37748cd8SNickeau     *
183*37748cd8SNickeau     * @return IntervalSet The set of potentially valid input symbols which could
184*37748cd8SNickeau     *                     follow the specified state in the specified context.
185*37748cd8SNickeau     *
186*37748cd8SNickeau     * @throws \RuntimeException
187*37748cd8SNickeau     */
188*37748cd8SNickeau    public function getExpectedTokens(int $stateNumber, ?RuleContext $context) : IntervalSet
189*37748cd8SNickeau    {
190*37748cd8SNickeau        if ($stateNumber < 0 || $stateNumber >= \count($this->states)) {
191*37748cd8SNickeau            throw new \InvalidArgumentException('Invalid state number.');
192*37748cd8SNickeau        }
193*37748cd8SNickeau
194*37748cd8SNickeau        $s = $this->states[$stateNumber];
195*37748cd8SNickeau        $following = $this->nextTokens($s);
196*37748cd8SNickeau
197*37748cd8SNickeau        if (!$following->contains(Token::EPSILON)) {
198*37748cd8SNickeau            return $following;
199*37748cd8SNickeau        }
200*37748cd8SNickeau
201*37748cd8SNickeau        $expected = new IntervalSet();
202*37748cd8SNickeau
203*37748cd8SNickeau        $expected->addSet($following);
204*37748cd8SNickeau        $expected->removeOne(Token::EPSILON);
205*37748cd8SNickeau
206*37748cd8SNickeau        if ($context === null) {
207*37748cd8SNickeau            $context = ParserRuleContext::emptyContext();
208*37748cd8SNickeau        }
209*37748cd8SNickeau
210*37748cd8SNickeau        while ($context !== null && $context->invokingState >= 0 && $following->contains(Token::EPSILON)) {
211*37748cd8SNickeau            $invokingState = $this->states[$context->invokingState];
212*37748cd8SNickeau            $transition = $invokingState->getTransition(0);
213*37748cd8SNickeau
214*37748cd8SNickeau            if (!$transition instanceof RuleTransition) {
215*37748cd8SNickeau                throw new \RuntimeException('Unexpected transition type.');
216*37748cd8SNickeau            }
217*37748cd8SNickeau
218*37748cd8SNickeau            $following = $this->nextTokens($transition->followState);
219*37748cd8SNickeau
220*37748cd8SNickeau            $expected->addSet($following);
221*37748cd8SNickeau            $expected->removeOne(Token::EPSILON);
222*37748cd8SNickeau
223*37748cd8SNickeau            $context = $context->getParent();
224*37748cd8SNickeau        }
225*37748cd8SNickeau
226*37748cd8SNickeau        if ($following->contains(Token::EPSILON)) {
227*37748cd8SNickeau            $expected->addOne(Token::EOF);
228*37748cd8SNickeau        }
229*37748cd8SNickeau
230*37748cd8SNickeau        return $expected;
231*37748cd8SNickeau    }
232*37748cd8SNickeau}
233