xref: /plugin/combo/vendor/antlr/antlr4-php-runtime/src/Atn/ATNConfig.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\SemanticContexts\SemanticContext;
8*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\States\ATNState;
9*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Comparison\Equality;
10*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Comparison\Hashable;
11*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Comparison\Hasher;
12*37748cd8SNickeauuse Antlr\Antlr4\Runtime\PredictionContexts\PredictionContext;
13*37748cd8SNickeau
14*37748cd8SNickeau/**
15*37748cd8SNickeau * A tuple: (ATN state, predicted alt, syntactic, semantic context).
16*37748cd8SNickeau * The syntactic context is a graph-structured stack node whose path(s)
17*37748cd8SNickeau * to the root is the rule invocation(s) chain used to arrive at the state.
18*37748cd8SNickeau * The semantic context is the tree of semantic predicates encountered
19*37748cd8SNickeau * before reaching an ATN state.
20*37748cd8SNickeau */
21*37748cd8SNickeauclass ATNConfig implements Hashable
22*37748cd8SNickeau{
23*37748cd8SNickeau    /**
24*37748cd8SNickeau     * This field stores the bit mask for implementing the
25*37748cd8SNickeau     * {@see ATNConfig::isPrecedenceFilterSuppressed()} property as a bit within
26*37748cd8SNickeau     * the existing {@see ATNConfig::$reachesIntoOuterContext} field.
27*37748cd8SNickeau     */
28*37748cd8SNickeau    private const SUPPRESS_PRECEDENCE_FILTER = 0x40000000;
29*37748cd8SNickeau
30*37748cd8SNickeau    /**
31*37748cd8SNickeau     * The ATN state associated with this configuration.
32*37748cd8SNickeau     *
33*37748cd8SNickeau     * @var ATNState
34*37748cd8SNickeau     */
35*37748cd8SNickeau    public $state;
36*37748cd8SNickeau
37*37748cd8SNickeau    /**
38*37748cd8SNickeau     * What alt (or lexer rule) is predicted by this configuration.
39*37748cd8SNickeau     *
40*37748cd8SNickeau     * @var int
41*37748cd8SNickeau     */
42*37748cd8SNickeau    public $alt;
43*37748cd8SNickeau
44*37748cd8SNickeau    /**
45*37748cd8SNickeau     * The stack of invoking states leading to the rule/states associated
46*37748cd8SNickeau     * with this config. We track only those contexts pushed during
47*37748cd8SNickeau     * execution of the ATN simulator.
48*37748cd8SNickeau     *
49*37748cd8SNickeau     * @var PredictionContext|null
50*37748cd8SNickeau     */
51*37748cd8SNickeau    public $context;
52*37748cd8SNickeau
53*37748cd8SNickeau    /**
54*37748cd8SNickeau     * We cannot execute predicates dependent upon local context unless
55*37748cd8SNickeau     * we know for sure we are in the correct context. Because there is
56*37748cd8SNickeau     * no way to do this efficiently, we simply cannot evaluate
57*37748cd8SNickeau     * dependent predicates unless we are in the rule that initially
58*37748cd8SNickeau     * invokes the ATN simulator.
59*37748cd8SNickeau     *
60*37748cd8SNickeau     * closure() tracks the depth of how far we dip into the outer context:
61*37748cd8SNickeau     * `depth > 0`. Note that it may not be totally accurate depth since I
62*37748cd8SNickeau     * don't ever decrement. TODO: make it a boolean then
63*37748cd8SNickeau     *
64*37748cd8SNickeau     * For memory efficiency, {@see ATNConfig::isPrecedenceFilterSuppressed()}
65*37748cd8SNickeau     * is also backed by this field. Since the field is publicly accessible, the
66*37748cd8SNickeau     * highest bit which would not cause the value to become negative is used to
67*37748cd8SNickeau     * store this field. This choice minimizes the risk that code which only
68*37748cd8SNickeau     * compares this value to 0 would be affected by the new purpose of the
69*37748cd8SNickeau     * flag. It also ensures the performance of the existing {@see ATNConfig}
70*37748cd8SNickeau     * constructors as well as certain operations like
71*37748cd8SNickeau     * {@see ATNConfigSet::add()} method are completely unaffected by the change.
72*37748cd8SNickeau     *
73*37748cd8SNickeau     * @var int
74*37748cd8SNickeau     */
75*37748cd8SNickeau    public $reachesIntoOuterContext;
76*37748cd8SNickeau
77*37748cd8SNickeau    /** @var SemanticContext */
78*37748cd8SNickeau    public $semanticContext;
79*37748cd8SNickeau
80*37748cd8SNickeau    public function __construct(
81*37748cd8SNickeau        ?self $oldConfig,
82*37748cd8SNickeau        ?ATNState $state,
83*37748cd8SNickeau        ?PredictionContext $context = null,
84*37748cd8SNickeau        ?SemanticContext $semanticContext = null,
85*37748cd8SNickeau        ?int $alt = null
86*37748cd8SNickeau    ) {
87*37748cd8SNickeau        if ($oldConfig === null) {
88*37748cd8SNickeau            if ($state === null) {
89*37748cd8SNickeau                throw new \RuntimeException('ATN State cannot be null.');
90*37748cd8SNickeau            }
91*37748cd8SNickeau
92*37748cd8SNickeau            $this->state = $state;
93*37748cd8SNickeau            $this->alt = $alt ?? 0;
94*37748cd8SNickeau            $this->context = $context;
95*37748cd8SNickeau            $this->semanticContext = $semanticContext ?? SemanticContext::none();
96*37748cd8SNickeau        } else {
97*37748cd8SNickeau            $this->state = $state ?? $oldConfig->state;
98*37748cd8SNickeau            $this->alt = $alt ?? $oldConfig->alt;
99*37748cd8SNickeau            $this->context = $context ?? $oldConfig->context;
100*37748cd8SNickeau            $this->semanticContext = $semanticContext ?? $oldConfig->semanticContext;
101*37748cd8SNickeau            $this->reachesIntoOuterContext = $oldConfig->reachesIntoOuterContext;
102*37748cd8SNickeau        }
103*37748cd8SNickeau    }
104*37748cd8SNickeau
105*37748cd8SNickeau    /**
106*37748cd8SNickeau     * This method gets the value of the {@see ATNConfig::$reachesIntoOuterContext}
107*37748cd8SNickeau     * field as it existed prior to the introduction of the
108*37748cd8SNickeau     * {@see ATNConfig::isPrecedenceFilterSuppressed()} method.
109*37748cd8SNickeau     */
110*37748cd8SNickeau    public function getOuterContextDepth() : int
111*37748cd8SNickeau    {
112*37748cd8SNickeau        return $this->reachesIntoOuterContext & ~self::SUPPRESS_PRECEDENCE_FILTER;
113*37748cd8SNickeau    }
114*37748cd8SNickeau
115*37748cd8SNickeau    public function isPrecedenceFilterSuppressed() : bool
116*37748cd8SNickeau    {
117*37748cd8SNickeau        return ($this->reachesIntoOuterContext & self::SUPPRESS_PRECEDENCE_FILTER) !== 0;
118*37748cd8SNickeau    }
119*37748cd8SNickeau
120*37748cd8SNickeau    public function setPrecedenceFilterSuppressed(bool $value) : void
121*37748cd8SNickeau    {
122*37748cd8SNickeau        if ($value) {
123*37748cd8SNickeau            $this->reachesIntoOuterContext |= self::SUPPRESS_PRECEDENCE_FILTER;
124*37748cd8SNickeau        } else {
125*37748cd8SNickeau            $this->reachesIntoOuterContext &= ~self::SUPPRESS_PRECEDENCE_FILTER;
126*37748cd8SNickeau        }
127*37748cd8SNickeau    }
128*37748cd8SNickeau
129*37748cd8SNickeau    /**
130*37748cd8SNickeau     * An ATN configuration is equal to another if both have the same state, they
131*37748cd8SNickeau     * predict the same alternative, and syntactic/semantic contexts are the same.
132*37748cd8SNickeau     */
133*37748cd8SNickeau    public function equals(object $other) : bool
134*37748cd8SNickeau    {
135*37748cd8SNickeau        if ($this === $other) {
136*37748cd8SNickeau            return true;
137*37748cd8SNickeau        }
138*37748cd8SNickeau
139*37748cd8SNickeau        return $other instanceof self
140*37748cd8SNickeau            && $this->alt === $other->alt
141*37748cd8SNickeau            && $this->isPrecedenceFilterSuppressed() === $other->isPrecedenceFilterSuppressed()
142*37748cd8SNickeau            && $this->semanticContext->equals($other->semanticContext)
143*37748cd8SNickeau            && Equality::equals($this->state, $other->state)
144*37748cd8SNickeau            && Equality::equals($this->context, $other->context);
145*37748cd8SNickeau    }
146*37748cd8SNickeau
147*37748cd8SNickeau    public function hashCode() : int
148*37748cd8SNickeau    {
149*37748cd8SNickeau        return Hasher::hash(
150*37748cd8SNickeau            $this->state->stateNumber,
151*37748cd8SNickeau            $this->alt,
152*37748cd8SNickeau            $this->context,
153*37748cd8SNickeau            $this->semanticContext
154*37748cd8SNickeau        );
155*37748cd8SNickeau    }
156*37748cd8SNickeau
157*37748cd8SNickeau    public function toString(bool $showAlt) : string
158*37748cd8SNickeau    {
159*37748cd8SNickeau        $buf = '(' . $this->state;
160*37748cd8SNickeau
161*37748cd8SNickeau        if ($showAlt) {
162*37748cd8SNickeau            $buf .= ',' . $this->alt;
163*37748cd8SNickeau        }
164*37748cd8SNickeau
165*37748cd8SNickeau        if ($this->context !== null) {
166*37748cd8SNickeau            $buf .= ',[' . $this->context . ']';
167*37748cd8SNickeau        }
168*37748cd8SNickeau
169*37748cd8SNickeau        if ($this->semanticContext->equals(SemanticContext::none())) {
170*37748cd8SNickeau            $buf .= ',' . $this->semanticContext;
171*37748cd8SNickeau        }
172*37748cd8SNickeau
173*37748cd8SNickeau        if ($this->getOuterContextDepth() > 0) {
174*37748cd8SNickeau            $buf .= ',up=' . $this->getOuterContextDepth();
175*37748cd8SNickeau        }
176*37748cd8SNickeau
177*37748cd8SNickeau        $buf .= ')';
178*37748cd8SNickeau
179*37748cd8SNickeau        return $buf;
180*37748cd8SNickeau    }
181*37748cd8SNickeau
182*37748cd8SNickeau    public function __toString() : string
183*37748cd8SNickeau    {
184*37748cd8SNickeau        return \sprintf(
185*37748cd8SNickeau            '(%s,%d%s%s%s)',
186*37748cd8SNickeau            $this->state,
187*37748cd8SNickeau            $this->alt,
188*37748cd8SNickeau            $this->context !== null ? ',[' . $this->context . ']' : '',
189*37748cd8SNickeau            $this->semanticContext !== null && $this->semanticContext->equals(SemanticContext::none()) ?
190*37748cd8SNickeau                ',' . $this->semanticContext :
191*37748cd8SNickeau                '',
192*37748cd8SNickeau            $this->reachesIntoOuterContext > 0 ? ',up=' . $this->reachesIntoOuterContext : ''
193*37748cd8SNickeau        );
194*37748cd8SNickeau    }
195*37748cd8SNickeau}
196