Issues (67)

src/ParserRuleContext.php (2 issues)

Severity
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Antlr\Antlr4\Runtime;
6
7
use Antlr\Antlr4\Runtime\Error\Exceptions\RecognitionException;
8
use Antlr\Antlr4\Runtime\Tree\ErrorNode;
9
use Antlr\Antlr4\Runtime\Tree\ParseTree;
10
use Antlr\Antlr4\Runtime\Tree\ParseTreeListener;
11
use Antlr\Antlr4\Runtime\Tree\TerminalNode;
12
use Antlr\Antlr4\Runtime\Tree\Tree;
13
14
/**
15
 * A rule invocation record for parsing.
16
 *
17
 * Contains all of the information about the current rule not stored
18
 * in the RuleContext. It handles parse tree children list, any ATN state
19
 * tracing, and the default values available for rule invocations: start, stop,
20
 * rule index, current alt number.
21
 *
22
 * Subclasses made for each rule and grammar track the parameters, return values,
23
 * locals, and labels specific to that rule. These are the objects
24
 * that are returned from rules.
25
 *
26
 * Note text is not an actual field of a rule return value; it is computed
27
 * from start and stop using the input stream's toString() method. I could
28
 * add a ctor to this so that we can pass in and store the input stream,
29
 * but I'm not sure we want to do that. It would seem to be undefined to get
30
 * the `text` property anyway if the rule matches tokens from multiple
31
 * input streams.
32
 *
33
 * I do not use getters for fields of objects that are used simply to group
34
 * values such as this aggregate. The getters/setters are there to satisfy
35
 * the superclass interface.
36
 */
37
class ParserRuleContext extends RuleContext
38
{
39
    /**
40
     * If we are debugging or building a parse tree for a visitor,
41
     * we need to track all of the tokens and rule invocations associated
42
     * with this rule's context. This is empty for parsing w/o tree constr.
43
     * operation because we don't the need to track the details about
44
     * how we parse this rule.
45
     *
46
     * @var array<ParseTree>|null
47
     */
48
    public $children;
49
50
    /** @var Token|null */
51
    public $start;
52
53
    /** @var Token|null */
54
    public $stop;
55
56
    /**
57
     * The exception that forced this rule to return. If the rule successfully
58
     * completed, this is `null`.
59
     *
60
     * @var RecognitionException|null
61
     */
62
    public $exception;
63
64
    /**
65
     * COPY a context (I'm deliberately not using copy constructor) to avoid
66
     * confusion with creating node with parent. Does not copy children
67
     * (except error leaves).
68
     *
69
     * This is used in the generated parser code to flip a generic XContext
70
     * node for rule X to a YContext for alt label Y. In that sense, it is
71
     * not really a generic copy function.
72
     *
73
     * If we do an error sync() at start of a rule, we might add error nodes
74
     * to the generic XContext so this function must copy those nodes to
75
     * the YContext as well else they are lost!
76
     */
77 4
    public function copyFrom(ParserRuleContext $ctx) : void
78
    {
79
        // from RuleContext
80 4
        $this->parentCtx = $ctx->parentCtx;
81 4
        $this->invokingState = $ctx->invokingState;
82 4
        $this->children = null;
83 4
        $this->start = $ctx->start;
84 4
        $this->stop = $ctx->stop;
85
86
        // copy any error nodes to alt label node
87 4
        if ($ctx->children) {
88
            $this->children = [];
89
90
            // reset parent pointer for any error nodes
91
            foreach ($ctx->children as $child) {
92
                if ($child instanceof ErrorNode) {
93
                    $this->addErrorNode($child);
94
                }
95
            }
96
        }
97 4
    }
98
99
    public function enterRule(ParseTreeListener $listener) : void
0 ignored issues
show
The parameter $listener is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

99
    public function enterRule(/** @scrutinizer ignore-unused */ ParseTreeListener $listener) : void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
100
    {
101
    }
102
103
    public function exitRule(ParseTreeListener $listener) : void
0 ignored issues
show
The parameter $listener is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

103
    public function exitRule(/** @scrutinizer ignore-unused */ ParseTreeListener $listener) : void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
104
    {
105
    }
106
107 4
    public function addTerminalNode(TerminalNode $t) : ParseTree
108
    {
109 4
        $t->setParent($this);
110
111 4
        return $this->addChild($t);
112
    }
113
114 1
    public function addErrorNode(ErrorNode $errorNode) : ParseTree
115
    {
116 1
        $errorNode->setParent($this);
117
118 1
        return $this->addChild($errorNode);
119
    }
120
121
    /**
122
     * Add a parse tree node to this as a child. Works for
123
     * internal and leaf nodes. Does not set parent link;
124
     * other add methods must do that. Other addChild methods
125
     * call this.
126
     *
127
     * We cannot set the parent pointer of the incoming node
128
     * because the existing interfaces do not have a `setParent()`
129
     * method and I don't want to break backward compatibility for this.
130
     */
131 5
    public function addChild(ParseTree $child) : ParseTree
132
    {
133 5
        if ($this->children === null) {
134 5
            $this->children = [];
135
        }
136
137 5
        $this->children[] = $child;
138
139 5
        return $child;
140
    }
141
142
    /**
143
     * Used by enterOuterAlt to toss out a RuleContext previously added as
144
     * we entered a rule. If we have # label, we will need to remove
145
     * generic `ruleContext` object.
146
     */
147 4
    public function removeLastChild() : void
148
    {
149 4
        if ($this->children !== null) {
150 4
            \array_pop($this->children);
151
        }
152 4
    }
153
154
    /**
155
     * @return RuleContext|null
156
     */
157 7
    public function getParent() : ?Tree
158
    {
159 7
        return $this->parentCtx;
160
    }
161
162
    /**
163
     * @return ParseTree|null
164
     */
165 5
    public function getChild(int $i, ?string $type = null) : ?Tree
166
    {
167 5
        if ($this->children === null || $i < 0 || $i >= \count($this->children)) {
168
            return null;
169
        }
170
171 5
        if ($type === null) {
172 5
            return $this->children[$i];
173
        }
174
175 4
        foreach ($this->children as $child) {
176 4
            if ($child instanceof $type) {
177 4
                if ($i === 0) {
178 4
                    return $child;
179
                }
180
181
                $i--;
182
            }
183
        }
184
185 4
        return null;
186
    }
187
188 2
    public function getToken(int $ttype, int $i) : ?TerminalNode
189
    {
190 2
        if ($this->children === null || $i < 0 || $i >= \count($this->children)) {
191
            return null;
192
        }
193
194 2
        foreach ($this->children as $child) {
195 2
            if ($child instanceof TerminalNode && $child->getSymbol()->getType() === $ttype) {
196 2
                if ($i === 0) {
197 2
                    return $child;
198
                }
199
200
                $i--;
201
            }
202
        }
203
204
        return null;
205
    }
206
207
    /**
208
     * @return array<TerminalNode>
209
     */
210
    public function getTokens(int $ttype) : array
211
    {
212
        if ($this->children === null) {
213
            return [];
214
        }
215
216
        $tokens = [];
217
        foreach ($this->children as $child) {
218
            if ($child instanceof TerminalNode && $child->getSymbol()->getType() === $ttype) {
219
                $tokens[] = $child;
220
            }
221
        }
222
223
        return $tokens;
224
    }
225
226 4
    public function getTypedRuleContext(string $ctxType, int $i) : ?ParseTree
227
    {
228 4
        return $this->getChild($i, $ctxType);
229
    }
230
231
    /**
232
     * @return array<ParseTree>
233
     */
234
    public function getTypedRuleContexts(string $ctxType) : array
235
    {
236
        if ($this->children=== null) {
237
            return [];
238
        }
239
240
        $contexts = [];
241
        foreach ($this->children as $child) {
242
            if ($child instanceof $ctxType) {
243
                $contexts[] = $child;
244
            }
245
        }
246
247
        return $contexts;
248
    }
249
250 7
    public function getChildCount() : int
251
    {
252 7
        return $this->children !== null ? \count($this->children) : 0;
253
    }
254
255
    public function getSourceInterval() : Interval
256
    {
257
        if ($this->start === null || $this->stop === null) {
258
            return Interval::invalid();
259
        }
260
261
        return new Interval($this->start->getTokenIndex(), $this->stop->getTokenIndex());
262
    }
263
264
    /**
265
     * Get the initial token in this context.
266
     *
267
     * Note that the range from start to stop is inclusive, so for rules that
268
     * do not consume anything (for example, zero length or error productions)
269
     * this token may exceed stop.
270
     */
271
    public function getStart() : ?Token
272
    {
273
        return $this->start;
274
    }
275
276
    /**
277
     * Get the final token in this context.
278
     *
279
     * Note that the range from start to stop is inclusive, so for rules that
280
     * do not consume anything (for example, zero length or error productions)
281
     * this token may precede start.
282
     */
283
    public function getStop() : ?Token
284
    {
285
        return $this->stop;
286
    }
287
}
288