1<?php
2
3declare(strict_types=1);
4
5namespace Antlr\Antlr4\Runtime;
6
7use Antlr\Antlr4\Runtime\Atn\ATN;
8use Antlr\Antlr4\Runtime\Tree\ParseTree;
9use Antlr\Antlr4\Runtime\Tree\ParseTreeVisitor;
10use Antlr\Antlr4\Runtime\Tree\RuleNode;
11use Antlr\Antlr4\Runtime\Tree\Tree;
12use Antlr\Antlr4\Runtime\Tree\Trees;
13
14/**
15 * A rule context is a record of a single rule invocation.
16 *
17 * We form a stack of these context objects using the parent pointer. A parent
18 * pointer of null indicates that the current context is the bottom of the stack.
19 * The {@see ParserRuleContext} subclass as a children list so that we can turn
20 * this data structure into a tree.
21 *
22 * The root node always has a null pointer and invokingState of -1.
23 *
24 * Upon entry to parsing, the first invoked rule function creates a context object
25 * (a subclass specialized for that rule such as SContext) and makes it the root
26 * of a parse tree, recorded by field Parser->ctx.
27 *
28 *     public final s(){
29 *         SContext _localctx = new SContext(_ctx, getState()); <-- create new node
30 *         enterRule(_localctx, 0, RULE_s);                     <-- push it
31 *         ...
32 *         exitRule();                                          <-- pop back to _localctx
33 *         return _localctx;
34 *     }
35 *
36 * A subsequent rule invocation of r from the start rule s pushes a new
37 * context object for r whose parent points at s and use invoking state is
38 * the state with r emanating as edge label.
39 *
40 * The invokingState fields from a context object to the root together
41 * form a stack of rule indication states where the root (bottom of the stack)
42 * has a -1 sentinel value. If we invoke start symbol s then call r1,
43 * which calls r2, the  would look like this:
44 *
45 *     SContext[-1]   <- root node (bottom of the stack)
46 *     R1Context[p]   <- p in rule s called r1
47 *     R2Context[q]   <- q in rule r1 called r2
48 *
49 * So the top of the stack, `_ctx`, represents a call to the current rule
50 * and it holds the return address from another rule that invoke to this rule.
51 * To invoke a rule, we must always have a current context.
52 *
53 * The parent contexts are useful for computing lookahead sets and getting
54 * error information.
55 *
56 * These objects are used during parsing and prediction. For the special case
57 * of parsers, we use the subclass {@see ParserRuleContext}.
58 */
59class RuleContext implements RuleNode
60{
61    /**
62     * The context that invoked this rule.
63     *
64     * @var RuleContext|null
65     */
66    public $parentCtx;
67
68    /**
69     * What state invoked the rule associated with this context?
70     * The "return address" is the followState of invokingState. If parent
71     * is null, this should be -1 this context object represents the start rule.
72     *
73     * @var int
74     */
75    public $invokingState = -1;
76
77    public function __construct(?RuleContext $parent, ?int $invokingState = null)
78    {
79        $this->parentCtx = $parent;
80        $this->invokingState = $invokingState ?? -1;
81    }
82
83    public static function emptyContext() : ParserRuleContext
84    {
85        static $empty;
86
87        return $empty ?? ($empty = new ParserRuleContext(null));
88    }
89
90    public function depth() : int
91    {
92        $n = 0;
93        $p = $this;
94
95        while ($p !== null) {
96            $p = $p->parentCtx;
97            $n++;
98        }
99
100        return $n;
101    }
102
103    /**
104     * A context is empty if there is no invoking state; meaning nobody call
105     * current context.
106     */
107    public function isEmpty() : bool
108    {
109        return $this->invokingState === -1;
110    }
111
112    public function getSourceInterval() : Interval
113    {
114        return Interval::invalid();
115    }
116
117    public function getRuleContext() : RuleContext
118    {
119        return $this;
120    }
121
122    public function getPayload() : RuleContext
123    {
124        return $this;
125    }
126
127    /**
128     * Return the combined text of all child nodes. This method only considers
129     * tokens which have been added to the parse tree.
130     *
131     * Since tokens on hidden channels (e.g. whitespace or comments) are not
132     * added to the parse trees, they will not appear in the output
133     * of this method.
134     */
135    public function getText() : string
136    {
137        $text = '';
138
139        for ($i = 0, $count = $this->getChildCount(); $i < $count; $i++) {
140            $child = $this->getChild($i);
141
142            if ($child !== null) {
143                $text .= $child->getText();
144            }
145        }
146
147        return $text;
148    }
149
150    public function getRuleIndex() : int
151    {
152        return -1;
153    }
154
155    /**
156     * For rule associated with this parse tree internal node, return the outer
157     * alternative number used to match the input. Default implementation
158     * does not compute nor store this alt num. Create a subclass of
159     * {@see ParserRuleContext} with backing field and set option
160     * `contextSuperClass` to set it.
161     */
162    public function getAltNumber() : int
163    {
164        return ATN::INVALID_ALT_NUMBER;
165    }
166
167    /**
168     * Set the outer alternative number for this context node. Default
169     * implementation does nothing to avoid backing field overhead for trees
170     * that don't need it. Create a subclass of {@see ParserRuleContext} with backing
171     * field and set option `contextSuperClass`.
172     */
173    public function setAltNumber(int $altNumber) : void
174    {
175    }
176
177    /**
178     * @return RuleContext|null
179     */
180    public function getParent() : ?Tree
181    {
182        return $this->parentCtx;
183    }
184
185    public function setParent(?RuleContext $ctx) : void
186    {
187        $this->parentCtx = $ctx;
188    }
189
190    /**
191     * @return ParseTree|null
192     */
193    public function getChild(int $i, ?string $type = null) : ?Tree
194    {
195        return null;
196    }
197
198    public function getChildCount() : int
199    {
200        return 0;
201    }
202
203    public function accept(ParseTreeVisitor $visitor)
204    {
205        return $visitor->visitChildren($this);
206    }
207
208    /**
209     * Print out a whole tree, not just a node, in LISP format
210     * (root child1 .. childN). Print just a node if this is a leaf.
211     *
212     * @param array<string>|null $ruleNames
213     */
214    public function toStringTree(?array $ruleNames = null) : string
215    {
216        return Trees::toStringTree($this, $ruleNames);
217    }
218
219    public function __toString() : string
220    {
221        return $this->toString();
222    }
223
224    /**
225     * @param array<string>|null $ruleNames
226     */
227    public function toString(?array $ruleNames = null, ?RuleContext $stop = null) : string
228    {
229        $p = $this;
230        $string = '[';
231
232        while ($p !== null && $p !== $stop) {
233            if ($ruleNames === null) {
234                if (!$p->isEmpty()) {
235                    $string .= $p->invokingState;
236                }
237            } else {
238                $ri = $p->getRuleIndex();
239                $ruleName = $ri >= 0 && $ri < \count($ruleNames) ? $ruleNames[$ri] : (string) $ri;
240                $string .= $ruleName;
241            }
242
243            if ($p->parentCtx !== null && ($ruleNames !== null || !$p->parentCtx->isEmpty())) {
244                $string .= ' ';
245            }
246
247            $p = $p->parentCtx;
248        }
249
250        return $string . ']';
251    }
252}
253