Issues (67)

src/CommonToken.php (1 issue)

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Antlr\Antlr4\Runtime;
6
7
use Antlr\Antlr4\Runtime\Utils\Pair;
8
use Antlr\Antlr4\Runtime\Utils\StringUtils;
9
10
final class CommonToken implements WritableToken
11
{
12
    /**
13
     * This is the backing field for {@see CommonToken::getType()} and
14
     * {@see CommonToken::setType()}.
15
     *
16
     * @var int
17
     */
18
    protected $type;
19
20
    /**
21
     * This is the backing field for {@see CommonToken::getLine()} and
22
     * {@see CommonToken::setLine()}.
23
     *
24
     * @var int
25
     */
26
    protected $line = 0;
27
28
    /**
29
     * This is the backing field for {@see CommonToken::getCharPositionInLine()}
30
     * and {@see CommonToken::setCharPositionInLine()}.
31
     *
32
     * @var int
33
     */
34
    protected $charPositionInLine = -1;
35
36
    /**
37
     * This is the backing field for {@see CommonToken::getChannel()} and
38
     * {@see CommonToken::setChannel()}.
39
     *
40
     * @var int
41
     */
42
    protected $channel = Token::DEFAULT_CHANNEL;
43
44
    /**
45
     * This is the backing field for {@see CommonToken::getTokenSource()} and
46
     * {@see CommonToken::getInputStream()}.
47
     *
48
     *
49
     * These properties share a field to reduce the memory footprint of
50
     * {@see CommonToken}. Tokens created by a {@see CommonTokenFactory} from
51
     * the same source and input stream share a reference to the same
52
     * {@see Pair} containing these values.
53
     *
54
     * @var Pair
55
     */
56
    protected $source;
57
58
    /**
59
     * This is the backing field for {@see CommonToken::getText()} when the token
60
     * text is explicitly set in the constructor or via {@see CommonToken::setText()}.
61
     *
62
     * @see CommonToken::getText()
63
     *
64
     * @var string|null
65
     */
66
    protected $text;
67
68
    /**
69
     * This is the backing field for {@see CommonToken::getTokenIndex()} and
70
     * {@see CommonToken::setTokenIndex()}.
71
     *
72
     * @var int
73
     */
74
    protected $index = -1;
75
76
    /**
77
     * This is the backing field for {@see CommonToken::getStartIndex()} and
78
     * {@see CommonToken::setStartIndex()}.
79
     *
80
     * @var int
81
     */
82
    protected $start;
83
84
    /**
85
     * This is the backing field for {@see CommonToken::getStopIndex()} and
86
     * {@see CommonToken::setStopIndex()}.
87
     *
88
     * @var int
89
     */
90
    protected $stop;
91
92 7
    public function __construct(
93
        int $type,
94
        ?Pair $source = null,
95
        ?int $channel = null,
96
        int $start = -1,
97
        int $stop = -1
98
    ) {
99 7
        if ($source !== null && !$source->a instanceof TokenSource) {
100
            throw new \RuntimeException('Unexpected token source type.');
101
        }
102
103 7
        if ($source !== null && !$source->b instanceof CharStream) {
104
            throw new \RuntimeException('Unexpected stream type.');
105
        }
106
107 7
        $this->source = $source ?? self::emptySource();
108 7
        $this->type = $type;
109 7
        $this->channel = $channel ?? Token::DEFAULT_CHANNEL;
110 7
        $this->start = $start;
111 7
        $this->stop = $stop;
112
113 7
        $tokenSource = $this->source->a;
114
115 7
        if ($tokenSource instanceof TokenSource) {
116 7
            $this->line = $tokenSource->getLine();
117 7
            $this->charPositionInLine = $tokenSource->getCharPositionInLine();
118
        }
119 7
    }
120
121
    /**
122
     * An empty {@see Pair}, which is used as the default value of
123
     * {@see CommonToken::source()} for tokens that do not have a source.
124
     */
125
    public static function emptySource() : Pair
126
    {
127
        static $source;
128
129
        return $source = $source ?? new Pair(null, null);
130
    }
131
132
    /**
133
     * Constructs a new {@see CommonToken} as a copy of another {@see Token}.
134
     *
135
     * If `oldToken` is also a {@see CommonToken} instance, the newly constructed
136
     * token will share a reference to the {@see CommonToken::text()} field and
137
     * the {@see Pair} stored in {@see CommonToken::source()}. Otherwise,
138
     * {@see CommonToken::text()} will be assigned the result of calling
139
     * {@see CommonToken::getText()}, and {@see CommonToken::source()} will be
140
     * constructed from the result of {@see Token::getTokenSource()} and
141
     * {@see Token::getInputStream()}.
142
     */
143
    public function clone() : CommonToken
144
    {
145
        $token = new self($this->type, $this->source, $this->channel, $this->start, $this->stop);
146
147
        $token->index = $this->index;
148
        $token->line = $this->line;
149
        $token->charPositionInLine = $this->charPositionInLine;
150
151
        $token->setText($this->text);
152
153
        return $token;
154
    }
155
156 7
    public function getType() : int
157
    {
158 7
        return $this->type;
159
    }
160
161
    public function setType(int $type) : void
162
    {
163
        $this->type = $type;
164
    }
165
166 4
    public function getLine() : int
167
    {
168 4
        return $this->line;
169
    }
170
171 7
    public function setLine(int $line) : void
172
    {
173 7
        $this->line = $line;
174 7
    }
175
176 5
    public function getText() : ?string
177
    {
178 5
        if ($this->text !== null) {
179
            return $this->text;
180
        }
181
182 5
        $input = $this->getInputStream();
183
184 5
        if ($input === null) {
0 ignored issues
show
The condition $input === null is always true.
Loading history...
185
            return null;
186
        }
187
188 5
        $n = $input->getLength();
189
190 5
        if ($this->start < $n && $this->stop < $n) {
191 3
            return $input->getText($this->start, $this->stop);
192
        }
193
194 3
        return '<EOF>';
195
    }
196
197
    /**
198
     * Explicitly set the text for this token. If `text` is not `null`, then
199
     * {@see CommonToken::getText()} will return this value rather than
200
     * extracting the text from the input.
201
     *
202
     * @param string $text The explicit text of the token, or `null`
203
     *                     if the text should be obtained from the input
204
     *                     along with the start and stop indexes of the token.
205
     */
206
    public function setText(?string $text) : void
207
    {
208
        $this->text = $text;
209
    }
210
211 4
    public function getCharPositionInLine() : int
212
    {
213 4
        return $this->charPositionInLine;
214
    }
215
216 7
    public function setCharPositionInLine(int $charPositionInLine) : void
217
    {
218 7
        $this->charPositionInLine = $charPositionInLine;
219 7
    }
220
221 7
    public function getChannel() : int
222
    {
223 7
        return $this->channel;
224
    }
225
226
    public function setChannel(int $channel) : void
227
    {
228
        $this->channel = $channel;
229
    }
230
231
    public function getStartIndex() : int
232
    {
233
        return $this->start;
234
    }
235
236
    public function setStartIndex(int $index) : void
237
    {
238
        $this->start = $index;
239
    }
240
241
    public function getStopIndex() : int
242
    {
243
        return $this->stop;
244
    }
245
246
    public function setStopIndex(int $index) : void
247
    {
248
        $this->stop = $index;
249
    }
250
251 1
    public function getTokenIndex() : int
252
    {
253 1
        return $this->index;
254
    }
255
256 7
    public function setTokenIndex(int $tokenIndex) : void
257
    {
258 7
        $this->index = $tokenIndex;
259 7
    }
260
261
    public function getTokenSource() : ?TokenSource
262
    {
263
        $source = $this->source->a;
264
265
        if ($source !== null && !$source instanceof TokenSource) {
266
            throw new \RuntimeException('Unexpected token source type.');
267
        }
268
269
        return $source;
270
    }
271
272 5
    public function getInputStream() : ?CharStream
273
    {
274 5
        $stream = $this->source->b;
275
276 5
        if ($stream !== null && !$stream instanceof CharStream) {
277
            throw new \RuntimeException('Unexpected token source type.');
278
        }
279
280 5
        return $stream;
281
    }
282
283
    public function getSource() : Pair
284
    {
285
        return $this->source;
286
    }
287
288
    public function __toString() : string
289
    {
290
        return \sprintf(
291
            '[@%d,%d:%d=\'%s\',<%d>%s,%d:%d]',
292
            $this->getTokenIndex(),
293
            $this->start,
294
            $this->stop,
295
            StringUtils::escapeWhitespace($this->getText() ?? ''),
296
            $this->type,
297
            $this->channel > 0 ? ',channel=' . $this->channel : '',
298
            $this->line,
299
            $this->charPositionInLine
300
        );
301
    }
302
}
303