xref: /plugin/combo/vendor/antlr/antlr4-php-runtime/src/BufferedTokenStream.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\Utils\Set;
8*37748cd8SNickeau
9*37748cd8SNickeau/**
10*37748cd8SNickeau * This implementation of {@see TokenStream} loads tokens from a
11*37748cd8SNickeau * {@see TokenSource} on-demand, and places the tokens in a buffer to provide
12*37748cd8SNickeau * access to any previous token by index.
13*37748cd8SNickeau *
14*37748cd8SNickeau * This token stream ignores the value of {@see Token::getChannel()}. If your
15*37748cd8SNickeau * parser requires the token stream filter tokens to only those on a particular
16*37748cd8SNickeau * channel, such as {@see Token::DEFAULT_CHANNEL} or
17*37748cd8SNickeau * {@see Token::HIDDEN_CHANNEL}, use a filtering token stream such a
18*37748cd8SNickeau * {@see CommonTokenStream}.
19*37748cd8SNickeau */
20*37748cd8SNickeauclass BufferedTokenStream implements TokenStream
21*37748cd8SNickeau{
22*37748cd8SNickeau    /**
23*37748cd8SNickeau     * The {@see TokenSource} from which tokens for this stream are fetched.
24*37748cd8SNickeau     *
25*37748cd8SNickeau     * @var TokenSource
26*37748cd8SNickeau     */
27*37748cd8SNickeau    protected $tokenSource;
28*37748cd8SNickeau
29*37748cd8SNickeau    /**
30*37748cd8SNickeau     * A collection of all tokens fetched from the token source. The list is
31*37748cd8SNickeau     * considered a complete view of the input once
32*37748cd8SNickeau     * {@see BufferedTokenStream::fetchedEOF()} is set to `true`.
33*37748cd8SNickeau     *
34*37748cd8SNickeau     * @var array<Token>
35*37748cd8SNickeau     */
36*37748cd8SNickeau    protected $tokens = [];
37*37748cd8SNickeau
38*37748cd8SNickeau    /**
39*37748cd8SNickeau     * The index into {@see BufferedTokenStream::tokens()} of the current token
40*37748cd8SNickeau     * (next token to {@see BufferedTokenStream::consume()}).
41*37748cd8SNickeau     * {@see BufferedTokenStream::tokens()}`[{@see BufferedTokenStream::p()}]`
42*37748cd8SNickeau     * should be {@see BufferedTokenStream::LT(1)}.
43*37748cd8SNickeau     *
44*37748cd8SNickeau     * This field is set to -1 when the stream is first constructed or when
45*37748cd8SNickeau     * {@see BufferedTokenStream::setTokenSource()} is called, indicating that
46*37748cd8SNickeau     * the first token has not yet been fetched from the token source. For
47*37748cd8SNickeau     * additional information, see the documentation of {@see IntStream} for
48*37748cd8SNickeau     * a description of Initializing Methods.
49*37748cd8SNickeau     *
50*37748cd8SNickeau     * @var int
51*37748cd8SNickeau     */
52*37748cd8SNickeau    protected $index = -1;
53*37748cd8SNickeau
54*37748cd8SNickeau    /**
55*37748cd8SNickeau     * Indicates whether the {@see Token::EOF} token has been fetched from
56*37748cd8SNickeau     * {@see BufferedTokenStream::tokenSource()} and added to
57*37748cd8SNickeau     * {@see BufferedTokenStream::tokens()}. This field improves  performance
58*37748cd8SNickeau     * for the following cases:
59*37748cd8SNickeau     *
60*37748cd8SNickeau     * - {@see BufferedTokenStream::consume()}: The lookahead check in
61*37748cd8SNickeau     *    {@see BufferedTokenStream::consume()} to prevent consuming the
62*37748cd8SNickeau     *    EOF symbol is optimized by checking the values of
63*37748cd8SNickeau     *    {@see BufferedTokenStream::fetchedEOF()} and
64*37748cd8SNickeau     *    {@see BufferedTokenStream::p()} instead of calling
65*37748cd8SNickeau     *    {@see BufferedTokenStream::LA()}.
66*37748cd8SNickeau     * - {@see BufferedTokenStream::fetch()}: The check to prevent adding multiple
67*37748cd8SNickeau     *    EOF symbols into {@see BufferedTokenStream::tokens()} is trivial with
68*37748cd8SNickeau     *    this field.
69*37748cd8SNickeau     *
70*37748cd8SNickeau     * @var bool
71*37748cd8SNickeau     */
72*37748cd8SNickeau    protected $fetchedEOF = false;
73*37748cd8SNickeau
74*37748cd8SNickeau    public function __construct(TokenSource $tokenSource)
75*37748cd8SNickeau    {
76*37748cd8SNickeau        $this->tokenSource = $tokenSource;
77*37748cd8SNickeau    }
78*37748cd8SNickeau
79*37748cd8SNickeau    public function getTokenSource() : TokenSource
80*37748cd8SNickeau    {
81*37748cd8SNickeau        return $this->tokenSource;
82*37748cd8SNickeau    }
83*37748cd8SNickeau
84*37748cd8SNickeau    public function getIndex() : int
85*37748cd8SNickeau    {
86*37748cd8SNickeau        return $this->index;
87*37748cd8SNickeau    }
88*37748cd8SNickeau
89*37748cd8SNickeau    public function mark() : int
90*37748cd8SNickeau    {
91*37748cd8SNickeau        return 0;
92*37748cd8SNickeau    }
93*37748cd8SNickeau
94*37748cd8SNickeau    public function release(int $marker) : void
95*37748cd8SNickeau    {
96*37748cd8SNickeau        // no resources to release
97*37748cd8SNickeau    }
98*37748cd8SNickeau
99*37748cd8SNickeau    public function seek(int $index) : void
100*37748cd8SNickeau    {
101*37748cd8SNickeau        $this->lazyInit();
102*37748cd8SNickeau
103*37748cd8SNickeau        $this->index = $this->adjustSeekIndex($index);
104*37748cd8SNickeau    }
105*37748cd8SNickeau
106*37748cd8SNickeau    public function getLength() : int
107*37748cd8SNickeau    {
108*37748cd8SNickeau        return \count($this->tokens);
109*37748cd8SNickeau    }
110*37748cd8SNickeau
111*37748cd8SNickeau    public function consume() : void
112*37748cd8SNickeau    {
113*37748cd8SNickeau        $skipEofCheck = false;
114*37748cd8SNickeau
115*37748cd8SNickeau        if ($this->index >= 0) {
116*37748cd8SNickeau            if ($this->fetchedEOF) {
117*37748cd8SNickeau                // the last token in tokens is EOF. skip check if p indexes any
118*37748cd8SNickeau                // fetched token except the last.
119*37748cd8SNickeau                $skipEofCheck = $this->index < \count($this->tokens) - 1;
120*37748cd8SNickeau            } else {
121*37748cd8SNickeau                // no EOF token in tokens. skip check if p indexes a fetched token.
122*37748cd8SNickeau                $skipEofCheck = $this->index < \count($this->tokens);
123*37748cd8SNickeau            }
124*37748cd8SNickeau        }
125*37748cd8SNickeau
126*37748cd8SNickeau        if (!$skipEofCheck && $this->LA(1) === Token::EOF) {
127*37748cd8SNickeau            throw new \InvalidArgumentException('Cannot consume EOF.');
128*37748cd8SNickeau        }
129*37748cd8SNickeau
130*37748cd8SNickeau        if ($this->sync($this->index + 1)) {
131*37748cd8SNickeau            $this->index = $this->adjustSeekIndex($this->index + 1);
132*37748cd8SNickeau        }
133*37748cd8SNickeau    }
134*37748cd8SNickeau
135*37748cd8SNickeau    /**
136*37748cd8SNickeau     * Make sure index `i` in tokens has a token.
137*37748cd8SNickeau     *
138*37748cd8SNickeau     * @return bool `true` if a token is located at index `i`,
139*37748cd8SNickeau     *              otherwise `false`.
140*37748cd8SNickeau     *
141*37748cd8SNickeau     * @see BufferedTokenStream::get()
142*37748cd8SNickeau     */
143*37748cd8SNickeau    public function sync(int $i) : bool
144*37748cd8SNickeau    {
145*37748cd8SNickeau        $n = $i - \count($this->tokens) + 1; // how many more elements we need?
146*37748cd8SNickeau
147*37748cd8SNickeau        if ($n > 0) {
148*37748cd8SNickeau            $fetched = $this->fetch($n);
149*37748cd8SNickeau
150*37748cd8SNickeau            return $fetched >= $n;
151*37748cd8SNickeau        }
152*37748cd8SNickeau
153*37748cd8SNickeau        return true;
154*37748cd8SNickeau    }
155*37748cd8SNickeau
156*37748cd8SNickeau    public function fetch(int $n) : int
157*37748cd8SNickeau    {
158*37748cd8SNickeau        if ($this->fetchedEOF) {
159*37748cd8SNickeau            return 0;
160*37748cd8SNickeau        }
161*37748cd8SNickeau
162*37748cd8SNickeau        for ($i = 0; $i < $n; $i++) {
163*37748cd8SNickeau            /** @var WritableToken $token */
164*37748cd8SNickeau            $token = $this->tokenSource->nextToken();
165*37748cd8SNickeau            $token->setTokenIndex(\count($this->tokens));
166*37748cd8SNickeau
167*37748cd8SNickeau            $this->tokens[] = $token;
168*37748cd8SNickeau
169*37748cd8SNickeau            if ($token->getType() === Token::EOF) {
170*37748cd8SNickeau                $this->fetchedEOF = true;
171*37748cd8SNickeau
172*37748cd8SNickeau                return $i + 1;
173*37748cd8SNickeau            }
174*37748cd8SNickeau        }
175*37748cd8SNickeau
176*37748cd8SNickeau        return $n;
177*37748cd8SNickeau    }
178*37748cd8SNickeau
179*37748cd8SNickeau    public function get(int $index) : Token
180*37748cd8SNickeau    {
181*37748cd8SNickeau        $count = \count($this->tokens);
182*37748cd8SNickeau
183*37748cd8SNickeau        if ($index < 0 || $index >= $count) {
184*37748cd8SNickeau            throw new \OutOfBoundsException(\sprintf(
185*37748cd8SNickeau                'Token index %d out of range 0..%d.',
186*37748cd8SNickeau                $index,
187*37748cd8SNickeau                $count
188*37748cd8SNickeau            ));
189*37748cd8SNickeau        }
190*37748cd8SNickeau
191*37748cd8SNickeau        $this->lazyInit();
192*37748cd8SNickeau
193*37748cd8SNickeau        return $this->tokens[$index];
194*37748cd8SNickeau    }
195*37748cd8SNickeau
196*37748cd8SNickeau    public function LA(int $i) : int
197*37748cd8SNickeau    {
198*37748cd8SNickeau        $token = $this->LT($i);
199*37748cd8SNickeau
200*37748cd8SNickeau        return $token === null ? Token::INVALID_TYPE : $token->getType();
201*37748cd8SNickeau    }
202*37748cd8SNickeau
203*37748cd8SNickeau    protected function LB(int $k) : ?Token
204*37748cd8SNickeau    {
205*37748cd8SNickeau        if ($this->index - $k < 0) {
206*37748cd8SNickeau            return null;
207*37748cd8SNickeau        }
208*37748cd8SNickeau
209*37748cd8SNickeau        return $this->tokens[$this->index - $k];
210*37748cd8SNickeau    }
211*37748cd8SNickeau
212*37748cd8SNickeau    public function LT(int $k) : ?Token
213*37748cd8SNickeau    {
214*37748cd8SNickeau        $this->lazyInit();
215*37748cd8SNickeau
216*37748cd8SNickeau        if ($k === 0) {
217*37748cd8SNickeau            return null;
218*37748cd8SNickeau        }
219*37748cd8SNickeau
220*37748cd8SNickeau        if ($k < 0) {
221*37748cd8SNickeau            return $this->LB(-$k);
222*37748cd8SNickeau        }
223*37748cd8SNickeau
224*37748cd8SNickeau        $i = $this->index + $k - 1;
225*37748cd8SNickeau
226*37748cd8SNickeau        $this->sync($i);
227*37748cd8SNickeau
228*37748cd8SNickeau        if ($i >= \count($this->tokens)) {
229*37748cd8SNickeau            // return EOF token
230*37748cd8SNickeau            // EOF must be last token
231*37748cd8SNickeau            return $this->tokens[\count($this->tokens) - 1];
232*37748cd8SNickeau        }
233*37748cd8SNickeau
234*37748cd8SNickeau        return $this->tokens[$i];
235*37748cd8SNickeau    }
236*37748cd8SNickeau
237*37748cd8SNickeau    /**
238*37748cd8SNickeau     * Allowed derived classes to modify the behavior of operations which change
239*37748cd8SNickeau     * the current stream position by adjusting the target token index of a seek
240*37748cd8SNickeau     * operation. The default implementation simply returns `i`. If an
241*37748cd8SNickeau     * exception is thrown in this method, the current stream index should not
242*37748cd8SNickeau     * be changed.
243*37748cd8SNickeau     *
244*37748cd8SNickeau     * For example, {@see CommonTokenStream} overrides this method to ensure
245*37748cd8SNickeau     * that the seek target is always an on-channel token.
246*37748cd8SNickeau     *
247*37748cd8SNickeau     * @param int $i The target token index.
248*37748cd8SNickeau     *
249*37748cd8SNickeau     * @return int The adjusted target token index.
250*37748cd8SNickeau     */
251*37748cd8SNickeau    public function adjustSeekIndex(int $i) : int
252*37748cd8SNickeau    {
253*37748cd8SNickeau        return $i;
254*37748cd8SNickeau    }
255*37748cd8SNickeau
256*37748cd8SNickeau    protected function lazyInit() : void
257*37748cd8SNickeau    {
258*37748cd8SNickeau        if ($this->index === -1) {
259*37748cd8SNickeau            $this->setup();
260*37748cd8SNickeau        }
261*37748cd8SNickeau    }
262*37748cd8SNickeau
263*37748cd8SNickeau    protected function setup() : void
264*37748cd8SNickeau    {
265*37748cd8SNickeau        $this->sync(0);
266*37748cd8SNickeau
267*37748cd8SNickeau        $this->index = $this->adjustSeekIndex(0);
268*37748cd8SNickeau    }
269*37748cd8SNickeau
270*37748cd8SNickeau    /**
271*37748cd8SNickeau     * Reset this token stream by setting its token source.
272*37748cd8SNickeau     */
273*37748cd8SNickeau    public function setTokenSource(TokenSource $tokenSource) : void
274*37748cd8SNickeau    {
275*37748cd8SNickeau        $this->tokenSource = $tokenSource;
276*37748cd8SNickeau        $this->tokens = [];
277*37748cd8SNickeau        $this->index = -1;
278*37748cd8SNickeau        $this->fetchedEOF = false;
279*37748cd8SNickeau    }
280*37748cd8SNickeau
281*37748cd8SNickeau    /**
282*37748cd8SNickeau     * @return array<Token>
283*37748cd8SNickeau     */
284*37748cd8SNickeau    public function getAllTokens() : array
285*37748cd8SNickeau    {
286*37748cd8SNickeau        return $this->tokens;
287*37748cd8SNickeau    }
288*37748cd8SNickeau
289*37748cd8SNickeau    /**
290*37748cd8SNickeau     * Get all tokens from start..stop inclusively
291*37748cd8SNickeau     *
292*37748cd8SNickeau     * @return array<Token>|null
293*37748cd8SNickeau     */
294*37748cd8SNickeau    public function getTokens(int $start, int $stop, ?Set $types = null) : ?array
295*37748cd8SNickeau    {
296*37748cd8SNickeau        if ($start < 0 || $stop < 0) {
297*37748cd8SNickeau            return null;
298*37748cd8SNickeau        }
299*37748cd8SNickeau
300*37748cd8SNickeau        $this->lazyInit();
301*37748cd8SNickeau
302*37748cd8SNickeau        $subset = [];
303*37748cd8SNickeau        if ($stop >= \count($this->tokens)) {
304*37748cd8SNickeau            $stop = \count($this->tokens) - 1;
305*37748cd8SNickeau        }
306*37748cd8SNickeau
307*37748cd8SNickeau        for ($i = $start; $i < $stop; $i++) {
308*37748cd8SNickeau            $t = $this->tokens[$i];
309*37748cd8SNickeau
310*37748cd8SNickeau            if ($t->getType() === Token::EOF) {
311*37748cd8SNickeau                break;
312*37748cd8SNickeau            }
313*37748cd8SNickeau
314*37748cd8SNickeau            if ($types === null || $types->contains($t->getType())) {
315*37748cd8SNickeau                $subset[] = $t;
316*37748cd8SNickeau            }
317*37748cd8SNickeau        }
318*37748cd8SNickeau
319*37748cd8SNickeau        return $subset;
320*37748cd8SNickeau    }
321*37748cd8SNickeau
322*37748cd8SNickeau    /**
323*37748cd8SNickeau     * Given a starting index, return the index of the next token on channel.
324*37748cd8SNickeau     * Return `i` if `tokens[i]` is on channel. Return the index of the EOF
325*37748cd8SNickeau     * token if there are no tokens on channel between `i` and EOF.
326*37748cd8SNickeau     */
327*37748cd8SNickeau    protected function nextTokenOnChannel(int $i, int $channel) : int
328*37748cd8SNickeau    {
329*37748cd8SNickeau        $this->sync($i);
330*37748cd8SNickeau
331*37748cd8SNickeau        if ($i >= \count($this->tokens)) {
332*37748cd8SNickeau            return $this->getLength() - 1;
333*37748cd8SNickeau        }
334*37748cd8SNickeau
335*37748cd8SNickeau        $token = $this->tokens[$i];
336*37748cd8SNickeau        while ($token->getChannel() !== $channel) {
337*37748cd8SNickeau            if ($token->getType() === Token::EOF) {
338*37748cd8SNickeau                return $i;
339*37748cd8SNickeau            }
340*37748cd8SNickeau
341*37748cd8SNickeau            $i++;
342*37748cd8SNickeau
343*37748cd8SNickeau            $this->sync($i);
344*37748cd8SNickeau
345*37748cd8SNickeau            $token = $this->tokens[$i];
346*37748cd8SNickeau        }
347*37748cd8SNickeau
348*37748cd8SNickeau        return $i;
349*37748cd8SNickeau    }
350*37748cd8SNickeau
351*37748cd8SNickeau    /**
352*37748cd8SNickeau     * Given a starting index, return the index of the previous token on channel.
353*37748cd8SNickeau     * Return `i` if `tokens[i]` is on channel. Return -1 if there are no tokens
354*37748cd8SNickeau     * on channel between `i` and 0.
355*37748cd8SNickeau     *
356*37748cd8SNickeau     * If `i` specifies an index at or after the EOF token, the EOF token
357*37748cd8SNickeau     * index is returned. This is due to the fact that the EOF token is treated
358*37748cd8SNickeau     * as though it were on every channel.
359*37748cd8SNickeau     */
360*37748cd8SNickeau    protected function previousTokenOnChannel(int $i, int $channel) : int
361*37748cd8SNickeau    {
362*37748cd8SNickeau        while ($i >= 0 && $this->tokens[$i]->getChannel() !== $channel) {
363*37748cd8SNickeau            $i--;
364*37748cd8SNickeau        }
365*37748cd8SNickeau
366*37748cd8SNickeau        return $i;
367*37748cd8SNickeau    }
368*37748cd8SNickeau
369*37748cd8SNickeau    /**
370*37748cd8SNickeau     * Collect all tokens on specified channel to the right of  the current token
371*37748cd8SNickeau     * up until we see a token on DEFAULT_TOKEN_CHANNEL or EOF. If channel is -1,
372*37748cd8SNickeau     * find any non default channel token.
373*37748cd8SNickeau     *
374*37748cd8SNickeau     * @return array<Token>
375*37748cd8SNickeau     */
376*37748cd8SNickeau    public function getHiddenTokensToRight(int $tokenIndex, int $channel) : ?array
377*37748cd8SNickeau    {
378*37748cd8SNickeau        $this->lazyInit();
379*37748cd8SNickeau
380*37748cd8SNickeau        if ($tokenIndex < 0 || $tokenIndex >= \count($this->tokens)) {
381*37748cd8SNickeau            throw new \RuntimeException(\sprintf('%d not in 0..%d', $tokenIndex, \count($this->tokens) - 1));
382*37748cd8SNickeau        }
383*37748cd8SNickeau
384*37748cd8SNickeau        $nextOnChannel = $this->nextTokenOnChannel($tokenIndex + 1, Lexer::DEFAULT_TOKEN_CHANNEL);
385*37748cd8SNickeau        $from_ = $tokenIndex + 1;
386*37748cd8SNickeau        // if none onchannel to right, nextOnChannel=-1 so set to = last token
387*37748cd8SNickeau        $to = $nextOnChannel === -1 ? \count($this->tokens) - 1 : $nextOnChannel;
388*37748cd8SNickeau
389*37748cd8SNickeau        return $this->filterForChannel($from_, $to, $channel);
390*37748cd8SNickeau    }
391*37748cd8SNickeau
392*37748cd8SNickeau    /**
393*37748cd8SNickeau     * Collect all tokens on specified channel to the left of the current token
394*37748cd8SNickeau     * up until we see a token on DEFAULT_TOKEN_CHANNEL. If channel is -1, find
395*37748cd8SNickeau     * any non default channel token.
396*37748cd8SNickeau     *
397*37748cd8SNickeau     * @return array<Token>
398*37748cd8SNickeau     */
399*37748cd8SNickeau    public function getHiddenTokensToLeft(int $tokenIndex, int $channel) : ?array
400*37748cd8SNickeau    {
401*37748cd8SNickeau        $this->lazyInit();
402*37748cd8SNickeau
403*37748cd8SNickeau        if ($tokenIndex < 0 || $tokenIndex >= \count($this->tokens)) {
404*37748cd8SNickeau            throw new \RuntimeException(\sprintf('%d not in 0..%d', $tokenIndex, \count($this->tokens) - 1));
405*37748cd8SNickeau        }
406*37748cd8SNickeau
407*37748cd8SNickeau        $prevOnChannel = $this->previousTokenOnChannel($tokenIndex - 1, Lexer::DEFAULT_TOKEN_CHANNEL);
408*37748cd8SNickeau
409*37748cd8SNickeau        if ($prevOnChannel === $tokenIndex - 1) {
410*37748cd8SNickeau            return null;
411*37748cd8SNickeau        }
412*37748cd8SNickeau
413*37748cd8SNickeau        // if none on channel to left, prevOnChannel=-1 then from=0
414*37748cd8SNickeau        $from = $prevOnChannel + 1;
415*37748cd8SNickeau        $to = $tokenIndex - 1;
416*37748cd8SNickeau
417*37748cd8SNickeau        return $this->filterForChannel($from, $to, $channel);
418*37748cd8SNickeau    }
419*37748cd8SNickeau
420*37748cd8SNickeau    /**
421*37748cd8SNickeau     * @return array<Token>|null
422*37748cd8SNickeau     */
423*37748cd8SNickeau    protected function filterForChannel(int $left, int $right, int $channel) : ?array
424*37748cd8SNickeau    {
425*37748cd8SNickeau        $hidden = [];
426*37748cd8SNickeau        for ($i = $left; $i < $right + 1; $i++) {
427*37748cd8SNickeau            $t = $this->tokens[$i];
428*37748cd8SNickeau
429*37748cd8SNickeau            if ($channel === -1) {
430*37748cd8SNickeau                if ($t->getChannel() !== Lexer::DEFAULT_TOKEN_CHANNEL) {
431*37748cd8SNickeau                    $hidden[] = $t;
432*37748cd8SNickeau                }
433*37748cd8SNickeau            } elseif ($t->getChannel() === $channel) {
434*37748cd8SNickeau                $hidden[] = $t;
435*37748cd8SNickeau            }
436*37748cd8SNickeau        }
437*37748cd8SNickeau
438*37748cd8SNickeau        if (\count($hidden) === 0) {
439*37748cd8SNickeau            return null;
440*37748cd8SNickeau        }
441*37748cd8SNickeau
442*37748cd8SNickeau        return $hidden;
443*37748cd8SNickeau    }
444*37748cd8SNickeau
445*37748cd8SNickeau    public function getSourceName() : string
446*37748cd8SNickeau    {
447*37748cd8SNickeau        return $this->tokenSource->getSourceName();
448*37748cd8SNickeau    }
449*37748cd8SNickeau
450*37748cd8SNickeau    /**
451*37748cd8SNickeau     * Get the text of all tokens in this buffer.
452*37748cd8SNickeau     */
453*37748cd8SNickeau    public function getTextByInterval(Interval $interval) : string
454*37748cd8SNickeau    {
455*37748cd8SNickeau        $this->lazyInit();
456*37748cd8SNickeau        $this->fill();
457*37748cd8SNickeau
458*37748cd8SNickeau        if ($interval->start < 0 || $interval->stop < 0) {
459*37748cd8SNickeau            return '';
460*37748cd8SNickeau        }
461*37748cd8SNickeau
462*37748cd8SNickeau        $stop = $interval->stop;
463*37748cd8SNickeau
464*37748cd8SNickeau        if ($stop >= \count($this->tokens)) {
465*37748cd8SNickeau            $stop = \count($this->tokens) - 1;
466*37748cd8SNickeau        }
467*37748cd8SNickeau
468*37748cd8SNickeau        $s = '';
469*37748cd8SNickeau        for ($i = $interval->start; $i <= $stop; $i++) {
470*37748cd8SNickeau            $t = $this->tokens[$i];
471*37748cd8SNickeau
472*37748cd8SNickeau            if ($t->getType() === Token::EOF) {
473*37748cd8SNickeau                break;
474*37748cd8SNickeau            }
475*37748cd8SNickeau
476*37748cd8SNickeau            $s .= $t->getText();
477*37748cd8SNickeau        }
478*37748cd8SNickeau
479*37748cd8SNickeau        return $s;
480*37748cd8SNickeau    }
481*37748cd8SNickeau
482*37748cd8SNickeau    public function getText() : string
483*37748cd8SNickeau    {
484*37748cd8SNickeau        return $this->getTextByInterval(new Interval(0, \count($this->tokens) - 1));
485*37748cd8SNickeau    }
486*37748cd8SNickeau
487*37748cd8SNickeau    public function getTextByTokens(?Token $start = null, ?Token $stop = null) : string
488*37748cd8SNickeau    {
489*37748cd8SNickeau        $startIndex = $start === null ? 0 : $start->getTokenIndex();
490*37748cd8SNickeau        $stopIndex = $stop === null ? \count($this->tokens) - 1 : $stop->getTokenIndex();
491*37748cd8SNickeau
492*37748cd8SNickeau        return $this->getTextByInterval(new Interval($startIndex, $stopIndex));
493*37748cd8SNickeau    }
494*37748cd8SNickeau
495*37748cd8SNickeau    public function getTextByContext(RuleContext $context) : string
496*37748cd8SNickeau    {
497*37748cd8SNickeau        return $this->getTextByInterval($context->getSourceInterval());
498*37748cd8SNickeau    }
499*37748cd8SNickeau
500*37748cd8SNickeau    /**
501*37748cd8SNickeau     * Get all tokens from lexer until EOF.
502*37748cd8SNickeau     */
503*37748cd8SNickeau    public function fill() : void
504*37748cd8SNickeau    {
505*37748cd8SNickeau        $this->lazyInit();
506*37748cd8SNickeau
507*37748cd8SNickeau        while ($this->fetch(1000) === 1000) {
508*37748cd8SNickeau            continue;
509*37748cd8SNickeau        }
510*37748cd8SNickeau    }
511*37748cd8SNickeau}
512