xref: /plugin/combo/vendor/antlr/antlr4-php-runtime/src/Dfa/DFAState.php (revision 37748cd8654635afbeca80942126742f0f4cc346)
1*37748cd8SNickeau<?php
2*37748cd8SNickeau
3*37748cd8SNickeaudeclare(strict_types=1);
4*37748cd8SNickeau
5*37748cd8SNickeaunamespace Antlr\Antlr4\Runtime\Dfa;
6*37748cd8SNickeau
7*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\ATNConfigSet;
8*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\LexerActionExecutor;
9*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Comparison\Equality;
10*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Comparison\Hashable;
11*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Comparison\Hasher;
12*37748cd8SNickeau
13*37748cd8SNickeau/**
14*37748cd8SNickeau * A DFA state represents a set of possible ATN configurations.
15*37748cd8SNickeau * As Aho, Sethi, Ullman p. 117 says "The DFA uses its state
16*37748cd8SNickeau * to keep track of all possible states the ATN can be in after
17*37748cd8SNickeau * reading each input symbol. That is to say, after reading
18*37748cd8SNickeau * input a1a2..an, the DFA is in a state that represents the
19*37748cd8SNickeau * subset T of the states of the ATN that are reachable from the
20*37748cd8SNickeau * ATN's start state along some path labeled a1a2..an."
21*37748cd8SNickeau * In conventional NFA&rarr;DFA conversion, therefore, the subset T
22*37748cd8SNickeau * would be a bitset representing the set of states the
23*37748cd8SNickeau * ATN could be in. We need to track the alt predicted by each
24*37748cd8SNickeau * state as well, however. More importantly, we need to maintain
25*37748cd8SNickeau * a stack of states, tracking the closure operations as they
26*37748cd8SNickeau * jump from rule to rule, emulating rule invocations (method calls).
27*37748cd8SNickeau * I have to add a stack to simulate the proper lookahead sequences for
28*37748cd8SNickeau * the underlying LL grammar from which the ATN was derived.
29*37748cd8SNickeau *
30*37748cd8SNickeau * I use a set of ATNConfig objects not simple states. An ATNConfig
31*37748cd8SNickeau * is both a state (ala normal conversion) and a RuleContext describing
32*37748cd8SNickeau * the chain of rules (if any) followed to arrive at that state.
33*37748cd8SNickeau *
34*37748cd8SNickeau * A DFA state may have multiple references to a particular state,
35*37748cd8SNickeau * but with different ATN contexts (with same or different alts)
36*37748cd8SNickeau * meaning that state was reached via a different set of rule invocations.
37*37748cd8SNickeau */
38*37748cd8SNickeaufinal class DFAState implements Hashable
39*37748cd8SNickeau{
40*37748cd8SNickeau    /** @var int */
41*37748cd8SNickeau    public $stateNumber;
42*37748cd8SNickeau
43*37748cd8SNickeau    /** @var ATNConfigSet */
44*37748cd8SNickeau    public $configs;
45*37748cd8SNickeau
46*37748cd8SNickeau    /**
47*37748cd8SNickeau     * `edges[symbol]` points to target of symbol. Shift up by 1 so (-1)
48*37748cd8SNickeau     * {@see Token::EOF} maps to `edges[0]`.
49*37748cd8SNickeau     *
50*37748cd8SNickeau     * @var \SplFixedArray<DFAState>|null
51*37748cd8SNickeau     */
52*37748cd8SNickeau    public $edges;
53*37748cd8SNickeau
54*37748cd8SNickeau    /** @var bool */
55*37748cd8SNickeau    public $isAcceptState = false;
56*37748cd8SNickeau
57*37748cd8SNickeau    /**
58*37748cd8SNickeau     * If accept state, what ttype do we match or alt do we predict?
59*37748cd8SNickeau     * This is set to {@see ATN::INVALID_ALT_NUMBER)} when
60*37748cd8SNickeau     * `{@see DFAState::$predicates} !== null` or {@see DFAState::$requiresFullContext}.
61*37748cd8SNickeau     *
62*37748cd8SNickeau     * @var int
63*37748cd8SNickeau     */
64*37748cd8SNickeau    public $prediction = 0;
65*37748cd8SNickeau
66*37748cd8SNickeau    /** @var LexerActionExecutor|null */
67*37748cd8SNickeau    public $lexerActionExecutor;
68*37748cd8SNickeau
69*37748cd8SNickeau    /**
70*37748cd8SNickeau     * Indicates that this state was created during SLL prediction that
71*37748cd8SNickeau     * discovered a conflict between the configurations in the state. Future
72*37748cd8SNickeau     * {@see ParserATNSimulator::execATN()} invocations immediately jumped doing
73*37748cd8SNickeau     * full context prediction if this field is true.
74*37748cd8SNickeau     *
75*37748cd8SNickeau     * @var bool
76*37748cd8SNickeau     */
77*37748cd8SNickeau    public $requiresFullContext = false;
78*37748cd8SNickeau
79*37748cd8SNickeau    /**
80*37748cd8SNickeau     * During SLL parsing, this is a list of predicates associated with the
81*37748cd8SNickeau     * ATN configurations of the DFA state. When we have predicates,
82*37748cd8SNickeau     * {@see DFAState::$requiresFullContext} is `false` since full context
83*37748cd8SNickeau     * prediction evaluates predicates on-the-fly. If this is not null, then
84*37748cd8SNickeau     * {@see DFAState::$prediction} is {@see ATN::INVALID_ALT_NUMBER}.
85*37748cd8SNickeau     *
86*37748cd8SNickeau     * We only use these for non-{@see DFAState::$requiresFullContext} bu
87*37748cd8SNickeau     * conflicting states. That means we know from the context (it's $ or we
88*37748cd8SNickeau     * don't dip into outer context) that it's an ambiguity not a conflict.
89*37748cd8SNickeau     *
90*37748cd8SNickeau     * This list is computed by {@see ParserATNSimulator::predicateDFAState()}.
91*37748cd8SNickeau     *
92*37748cd8SNickeau     * @var array<PredPrediction>|null
93*37748cd8SNickeau     */
94*37748cd8SNickeau    public $predicates;
95*37748cd8SNickeau
96*37748cd8SNickeau    public function __construct(?ATNConfigSet $configs = null, int $stateNumber = -1)
97*37748cd8SNickeau    {
98*37748cd8SNickeau        $this->configs = $configs ?? new ATNConfigSet();
99*37748cd8SNickeau        $this->stateNumber = $stateNumber;
100*37748cd8SNickeau    }
101*37748cd8SNickeau
102*37748cd8SNickeau    /**
103*37748cd8SNickeau     * Two {@see DFAState} instances are equal if their ATN configuration sets
104*37748cd8SNickeau     * are the same. This method is used to see if a state already exists.
105*37748cd8SNickeau     *
106*37748cd8SNickeau     * Because the number of alternatives and number of ATN configurations are
107*37748cd8SNickeau     * finite, there is a finite number of DFA states that can be processed.
108*37748cd8SNickeau     * This is necessary to show that the algorithm terminates.
109*37748cd8SNickeau     *
110*37748cd8SNickeau     * Cannot test the DFA state numbers here because in
111*37748cd8SNickeau     * {@see ParserATNSimulator::addDFAState()} we need to know if any other state
112*37748cd8SNickeau     * exists that has this exact set of ATN configurations. The
113*37748cd8SNickeau     * {@see DFAState::$stateNumber} is irrelevant.
114*37748cd8SNickeau     */
115*37748cd8SNickeau    public function equals(object $other) : bool
116*37748cd8SNickeau    {
117*37748cd8SNickeau        if ($this === $other) {
118*37748cd8SNickeau            return true;
119*37748cd8SNickeau        }
120*37748cd8SNickeau
121*37748cd8SNickeau        if (!$other instanceof self) {
122*37748cd8SNickeau            return false;
123*37748cd8SNickeau        }
124*37748cd8SNickeau
125*37748cd8SNickeau        // Compare set of ATN configurations in this set with other
126*37748cd8SNickeau        return Equality::equals($this->configs, $other->configs);
127*37748cd8SNickeau    }
128*37748cd8SNickeau
129*37748cd8SNickeau    public function __toString() : string
130*37748cd8SNickeau    {
131*37748cd8SNickeau        $s = \sprintf('%d:%s', $this->stateNumber, (string) $this->configs);
132*37748cd8SNickeau
133*37748cd8SNickeau        if ($this->isAcceptState) {
134*37748cd8SNickeau            $s .= '=>';
135*37748cd8SNickeau
136*37748cd8SNickeau            if ($this->predicates !== null) {
137*37748cd8SNickeau                $s .= \sprintf('[%s]', \implode(', ', $this->predicates));
138*37748cd8SNickeau            } else {
139*37748cd8SNickeau                $s .= $this->prediction;
140*37748cd8SNickeau            }
141*37748cd8SNickeau        }
142*37748cd8SNickeau
143*37748cd8SNickeau        return $s;
144*37748cd8SNickeau    }
145*37748cd8SNickeau
146*37748cd8SNickeau    public function hashCode() : int
147*37748cd8SNickeau    {
148*37748cd8SNickeau        return Hasher::hash($this->configs);
149*37748cd8SNickeau    }
150*37748cd8SNickeau}
151