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