xref: /plugin/combo/vendor/antlr/antlr4-php-runtime/src/ParserRuleContext.php (revision 37748cd8654635afbeca80942126742f0f4cc346)
1*37748cd8SNickeau<?php
2*37748cd8SNickeau
3*37748cd8SNickeaudeclare(strict_types=1);
4*37748cd8SNickeau
5*37748cd8SNickeaunamespace Antlr\Antlr4\Runtime;
6*37748cd8SNickeau
7*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Error\Exceptions\RecognitionException;
8*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Tree\ErrorNode;
9*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Tree\ParseTree;
10*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Tree\ParseTreeListener;
11*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Tree\TerminalNode;
12*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Tree\Tree;
13*37748cd8SNickeau
14*37748cd8SNickeau/**
15*37748cd8SNickeau * A rule invocation record for parsing.
16*37748cd8SNickeau *
17*37748cd8SNickeau * Contains all of the information about the current rule not stored
18*37748cd8SNickeau * in the RuleContext. It handles parse tree children list, any ATN state
19*37748cd8SNickeau * tracing, and the default values available for rule invocations: start, stop,
20*37748cd8SNickeau * rule index, current alt number.
21*37748cd8SNickeau *
22*37748cd8SNickeau * Subclasses made for each rule and grammar track the parameters, return values,
23*37748cd8SNickeau * locals, and labels specific to that rule. These are the objects
24*37748cd8SNickeau * that are returned from rules.
25*37748cd8SNickeau *
26*37748cd8SNickeau * Note text is not an actual field of a rule return value; it is computed
27*37748cd8SNickeau * from start and stop using the input stream's toString() method. I could
28*37748cd8SNickeau * add a ctor to this so that we can pass in and store the input stream,
29*37748cd8SNickeau * but I'm not sure we want to do that. It would seem to be undefined to get
30*37748cd8SNickeau * the `text` property anyway if the rule matches tokens from multiple
31*37748cd8SNickeau * input streams.
32*37748cd8SNickeau *
33*37748cd8SNickeau * I do not use getters for fields of objects that are used simply to group
34*37748cd8SNickeau * values such as this aggregate. The getters/setters are there to satisfy
35*37748cd8SNickeau * the superclass interface.
36*37748cd8SNickeau */
37*37748cd8SNickeauclass ParserRuleContext extends RuleContext
38*37748cd8SNickeau{
39*37748cd8SNickeau    /**
40*37748cd8SNickeau     * If we are debugging or building a parse tree for a visitor,
41*37748cd8SNickeau     * we need to track all of the tokens and rule invocations associated
42*37748cd8SNickeau     * with this rule's context. This is empty for parsing w/o tree constr.
43*37748cd8SNickeau     * operation because we don't the need to track the details about
44*37748cd8SNickeau     * how we parse this rule.
45*37748cd8SNickeau     *
46*37748cd8SNickeau     * @var array<ParseTree>|null
47*37748cd8SNickeau     */
48*37748cd8SNickeau    public $children;
49*37748cd8SNickeau
50*37748cd8SNickeau    /** @var Token|null */
51*37748cd8SNickeau    public $start;
52*37748cd8SNickeau
53*37748cd8SNickeau    /** @var Token|null */
54*37748cd8SNickeau    public $stop;
55*37748cd8SNickeau
56*37748cd8SNickeau    /**
57*37748cd8SNickeau     * The exception that forced this rule to return. If the rule successfully
58*37748cd8SNickeau     * completed, this is `null`.
59*37748cd8SNickeau     *
60*37748cd8SNickeau     * @var RecognitionException|null
61*37748cd8SNickeau     */
62*37748cd8SNickeau    public $exception;
63*37748cd8SNickeau
64*37748cd8SNickeau    /**
65*37748cd8SNickeau     * COPY a context (I'm deliberately not using copy constructor) to avoid
66*37748cd8SNickeau     * confusion with creating node with parent. Does not copy children
67*37748cd8SNickeau     * (except error leaves).
68*37748cd8SNickeau     *
69*37748cd8SNickeau     * This is used in the generated parser code to flip a generic XContext
70*37748cd8SNickeau     * node for rule X to a YContext for alt label Y. In that sense, it is
71*37748cd8SNickeau     * not really a generic copy function.
72*37748cd8SNickeau     *
73*37748cd8SNickeau     * If we do an error sync() at start of a rule, we might add error nodes
74*37748cd8SNickeau     * to the generic XContext so this function must copy those nodes to
75*37748cd8SNickeau     * the YContext as well else they are lost!
76*37748cd8SNickeau     */
77*37748cd8SNickeau    public function copyFrom(ParserRuleContext $ctx) : void
78*37748cd8SNickeau    {
79*37748cd8SNickeau        // from RuleContext
80*37748cd8SNickeau        $this->parentCtx = $ctx->parentCtx;
81*37748cd8SNickeau        $this->invokingState = $ctx->invokingState;
82*37748cd8SNickeau        $this->children = null;
83*37748cd8SNickeau        $this->start = $ctx->start;
84*37748cd8SNickeau        $this->stop = $ctx->stop;
85*37748cd8SNickeau
86*37748cd8SNickeau        // copy any error nodes to alt label node
87*37748cd8SNickeau        if ($ctx->children) {
88*37748cd8SNickeau            $this->children = [];
89*37748cd8SNickeau
90*37748cd8SNickeau            // reset parent pointer for any error nodes
91*37748cd8SNickeau            foreach ($ctx->children as $child) {
92*37748cd8SNickeau                if ($child instanceof ErrorNode) {
93*37748cd8SNickeau                    $this->addErrorNode($child);
94*37748cd8SNickeau                }
95*37748cd8SNickeau            }
96*37748cd8SNickeau        }
97*37748cd8SNickeau    }
98*37748cd8SNickeau
99*37748cd8SNickeau    public function enterRule(ParseTreeListener $listener) : void
100*37748cd8SNickeau    {
101*37748cd8SNickeau    }
102*37748cd8SNickeau
103*37748cd8SNickeau    public function exitRule(ParseTreeListener $listener) : void
104*37748cd8SNickeau    {
105*37748cd8SNickeau    }
106*37748cd8SNickeau
107*37748cd8SNickeau    public function addTerminalNode(TerminalNode $t) : ParseTree
108*37748cd8SNickeau    {
109*37748cd8SNickeau        $t->setParent($this);
110*37748cd8SNickeau
111*37748cd8SNickeau        return $this->addChild($t);
112*37748cd8SNickeau    }
113*37748cd8SNickeau
114*37748cd8SNickeau    public function addErrorNode(ErrorNode $errorNode) : ParseTree
115*37748cd8SNickeau    {
116*37748cd8SNickeau        $errorNode->setParent($this);
117*37748cd8SNickeau
118*37748cd8SNickeau        return $this->addChild($errorNode);
119*37748cd8SNickeau    }
120*37748cd8SNickeau
121*37748cd8SNickeau    /**
122*37748cd8SNickeau     * Add a parse tree node to this as a child. Works for
123*37748cd8SNickeau     * internal and leaf nodes. Does not set parent link;
124*37748cd8SNickeau     * other add methods must do that. Other addChild methods
125*37748cd8SNickeau     * call this.
126*37748cd8SNickeau     *
127*37748cd8SNickeau     * We cannot set the parent pointer of the incoming node
128*37748cd8SNickeau     * because the existing interfaces do not have a `setParent()`
129*37748cd8SNickeau     * method and I don't want to break backward compatibility for this.
130*37748cd8SNickeau     */
131*37748cd8SNickeau    public function addChild(ParseTree $child) : ParseTree
132*37748cd8SNickeau    {
133*37748cd8SNickeau        if ($this->children === null) {
134*37748cd8SNickeau            $this->children = [];
135*37748cd8SNickeau        }
136*37748cd8SNickeau
137*37748cd8SNickeau        $this->children[] = $child;
138*37748cd8SNickeau
139*37748cd8SNickeau        return $child;
140*37748cd8SNickeau    }
141*37748cd8SNickeau
142*37748cd8SNickeau    /**
143*37748cd8SNickeau     * Used by enterOuterAlt to toss out a RuleContext previously added as
144*37748cd8SNickeau     * we entered a rule. If we have # label, we will need to remove
145*37748cd8SNickeau     * generic `ruleContext` object.
146*37748cd8SNickeau     */
147*37748cd8SNickeau    public function removeLastChild() : void
148*37748cd8SNickeau    {
149*37748cd8SNickeau        if ($this->children !== null) {
150*37748cd8SNickeau            \array_pop($this->children);
151*37748cd8SNickeau        }
152*37748cd8SNickeau    }
153*37748cd8SNickeau
154*37748cd8SNickeau    /**
155*37748cd8SNickeau     * @return RuleContext|null
156*37748cd8SNickeau     */
157*37748cd8SNickeau    public function getParent() : ?Tree
158*37748cd8SNickeau    {
159*37748cd8SNickeau        return $this->parentCtx;
160*37748cd8SNickeau    }
161*37748cd8SNickeau
162*37748cd8SNickeau    /**
163*37748cd8SNickeau     * @return ParseTree|null
164*37748cd8SNickeau     */
165*37748cd8SNickeau    public function getChild(int $i, ?string $type = null) : ?Tree
166*37748cd8SNickeau    {
167*37748cd8SNickeau        if ($this->children === null || $i < 0 || $i >= \count($this->children)) {
168*37748cd8SNickeau            return null;
169*37748cd8SNickeau        }
170*37748cd8SNickeau
171*37748cd8SNickeau        if ($type === null) {
172*37748cd8SNickeau            return $this->children[$i];
173*37748cd8SNickeau        }
174*37748cd8SNickeau
175*37748cd8SNickeau        foreach ($this->children as $child) {
176*37748cd8SNickeau            if ($child instanceof $type) {
177*37748cd8SNickeau                if ($i === 0) {
178*37748cd8SNickeau                    return $child;
179*37748cd8SNickeau                }
180*37748cd8SNickeau
181*37748cd8SNickeau                $i--;
182*37748cd8SNickeau            }
183*37748cd8SNickeau        }
184*37748cd8SNickeau
185*37748cd8SNickeau        return null;
186*37748cd8SNickeau    }
187*37748cd8SNickeau
188*37748cd8SNickeau    public function getToken(int $ttype, int $i) : ?TerminalNode
189*37748cd8SNickeau    {
190*37748cd8SNickeau        if ($this->children === null || $i < 0 || $i >= \count($this->children)) {
191*37748cd8SNickeau            return null;
192*37748cd8SNickeau        }
193*37748cd8SNickeau
194*37748cd8SNickeau        foreach ($this->children as $child) {
195*37748cd8SNickeau            if ($child instanceof TerminalNode && $child->getSymbol()->getType() === $ttype) {
196*37748cd8SNickeau                if ($i === 0) {
197*37748cd8SNickeau                    return $child;
198*37748cd8SNickeau                }
199*37748cd8SNickeau
200*37748cd8SNickeau                $i--;
201*37748cd8SNickeau            }
202*37748cd8SNickeau        }
203*37748cd8SNickeau
204*37748cd8SNickeau        return null;
205*37748cd8SNickeau    }
206*37748cd8SNickeau
207*37748cd8SNickeau    /**
208*37748cd8SNickeau     * @return array<TerminalNode>
209*37748cd8SNickeau     */
210*37748cd8SNickeau    public function getTokens(int $ttype) : array
211*37748cd8SNickeau    {
212*37748cd8SNickeau        if ($this->children === null) {
213*37748cd8SNickeau            return [];
214*37748cd8SNickeau        }
215*37748cd8SNickeau
216*37748cd8SNickeau        $tokens = [];
217*37748cd8SNickeau        foreach ($this->children as $child) {
218*37748cd8SNickeau            if ($child instanceof TerminalNode && $child->getSymbol()->getType() === $ttype) {
219*37748cd8SNickeau                $tokens[] = $child;
220*37748cd8SNickeau            }
221*37748cd8SNickeau        }
222*37748cd8SNickeau
223*37748cd8SNickeau        return $tokens;
224*37748cd8SNickeau    }
225*37748cd8SNickeau
226*37748cd8SNickeau    public function getTypedRuleContext(string $ctxType, int $i) : ?ParseTree
227*37748cd8SNickeau    {
228*37748cd8SNickeau        return $this->getChild($i, $ctxType);
229*37748cd8SNickeau    }
230*37748cd8SNickeau
231*37748cd8SNickeau    /**
232*37748cd8SNickeau     * @return array<ParseTree>
233*37748cd8SNickeau     */
234*37748cd8SNickeau    public function getTypedRuleContexts(string $ctxType) : array
235*37748cd8SNickeau    {
236*37748cd8SNickeau        if ($this->children=== null) {
237*37748cd8SNickeau            return [];
238*37748cd8SNickeau        }
239*37748cd8SNickeau
240*37748cd8SNickeau        $contexts = [];
241*37748cd8SNickeau        foreach ($this->children as $child) {
242*37748cd8SNickeau            if ($child instanceof $ctxType) {
243*37748cd8SNickeau                $contexts[] = $child;
244*37748cd8SNickeau            }
245*37748cd8SNickeau        }
246*37748cd8SNickeau
247*37748cd8SNickeau        return $contexts;
248*37748cd8SNickeau    }
249*37748cd8SNickeau
250*37748cd8SNickeau    public function getChildCount() : int
251*37748cd8SNickeau    {
252*37748cd8SNickeau        return $this->children !== null ? \count($this->children) : 0;
253*37748cd8SNickeau    }
254*37748cd8SNickeau
255*37748cd8SNickeau    public function getSourceInterval() : Interval
256*37748cd8SNickeau    {
257*37748cd8SNickeau        if ($this->start === null || $this->stop === null) {
258*37748cd8SNickeau            return Interval::invalid();
259*37748cd8SNickeau        }
260*37748cd8SNickeau
261*37748cd8SNickeau        return new Interval($this->start->getTokenIndex(), $this->stop->getTokenIndex());
262*37748cd8SNickeau    }
263*37748cd8SNickeau
264*37748cd8SNickeau    /**
265*37748cd8SNickeau     * Get the initial token in this context.
266*37748cd8SNickeau     *
267*37748cd8SNickeau     * Note that the range from start to stop is inclusive, so for rules that
268*37748cd8SNickeau     * do not consume anything (for example, zero length or error productions)
269*37748cd8SNickeau     * this token may exceed stop.
270*37748cd8SNickeau     */
271*37748cd8SNickeau    public function getStart() : ?Token
272*37748cd8SNickeau    {
273*37748cd8SNickeau        return $this->start;
274*37748cd8SNickeau    }
275*37748cd8SNickeau
276*37748cd8SNickeau    /**
277*37748cd8SNickeau     * Get the final token in this context.
278*37748cd8SNickeau     *
279*37748cd8SNickeau     * Note that the range from start to stop is inclusive, so for rules that
280*37748cd8SNickeau     * do not consume anything (for example, zero length or error productions)
281*37748cd8SNickeau     * this token may precede start.
282*37748cd8SNickeau     */
283*37748cd8SNickeau    public function getStop() : ?Token
284*37748cd8SNickeau    {
285*37748cd8SNickeau        return $this->stop;
286*37748cd8SNickeau    }
287*37748cd8SNickeau}
288