xref: /plugin/combo/vendor/antlr/antlr4-php-runtime/src/CommonTokenStream.php (revision 37748cd8654635afbeca80942126742f0f4cc346)
1*37748cd8SNickeau<?php
2*37748cd8SNickeau
3*37748cd8SNickeaudeclare(strict_types=1);
4*37748cd8SNickeau
5*37748cd8SNickeaunamespace Antlr\Antlr4\Runtime;
6*37748cd8SNickeau
7*37748cd8SNickeau/**
8*37748cd8SNickeau * This class extends {@see BufferedTokenStream} with functionality to filter
9*37748cd8SNickeau * token streams to tokens on a particular channel (tokens where
10*37748cd8SNickeau * {@see Token::getChannel()} returns a particular value).
11*37748cd8SNickeau *
12*37748cd8SNickeau * This token stream provides access to all tokens by index or when calling
13*37748cd8SNickeau * methods like {@see CommonTokenStream::getText()}. The channel filtering
14*37748cd8SNickeau * is only used for code accessing tokens via the lookahead methods
15*37748cd8SNickeau * {@see CommonTokenStream::LA()}, {@see CommonTokenStream::LT()}, and
16*37748cd8SNickeau * {@see CommonTokenStream::LB()}.
17*37748cd8SNickeau *
18*37748cd8SNickeau * By default, tokens are placed on the default channel
19*37748cd8SNickeau * ({@see Token::DEFAULT_CHANNEL()}), but may be reassigned by using the
20*37748cd8SNickeau * {@code CommonTokenStream::channel(HIDDEN)} lexer command, or by using an
21*37748cd8SNickeau * embedded action to call {@see Lexer::setChannel()}.
22*37748cd8SNickeau *
23*37748cd8SNickeau *
24*37748cd8SNickeau *
25*37748cd8SNickeau * Note: lexer rules which use the `$this->skip` lexer command or call
26*37748cd8SNickeau * {@see Lexer::skip()} do not produce tokens at all, so input text matched by
27*37748cd8SNickeau * such a rule will not be available as part of the token stream, regardless of
28*37748cd8SNickeau * channel.we
29*37748cd8SNickeau */
30*37748cd8SNickeaufinal class CommonTokenStream extends BufferedTokenStream
31*37748cd8SNickeau{
32*37748cd8SNickeau    /**
33*37748cd8SNickeau     * Specifies the channel to use for filtering tokens.
34*37748cd8SNickeau     *
35*37748cd8SNickeau     *
36*37748cd8SNickeau     * The default value is {@see Token::DEFAULT_CHANNEL}, which matches the
37*37748cd8SNickeau     * default channel assigned to tokens created by the lexer.
38*37748cd8SNickeau     *
39*37748cd8SNickeau     * @var int
40*37748cd8SNickeau     */
41*37748cd8SNickeau    protected $channel;
42*37748cd8SNickeau
43*37748cd8SNickeau    /**
44*37748cd8SNickeau     * Constructs a new {@see CommonTokenStream} using the specified token
45*37748cd8SNickeau     * source and filtering tokens to the specified channel. Only tokens whose
46*37748cd8SNickeau     * {@see Token::getChannel()} matches `channel` or have the
47*37748cd8SNickeau     * {@see Token::getType()} equal to {@see Token::EOF} will be returned by
48*37748cd8SNickeau     * tthe oken stream lookahead methods.
49*37748cd8SNickeau     *
50*37748cd8SNickeau     * @param TokenSource $tokenSource The token source.
51*37748cd8SNickeau     * @param int         $channel     The channel to use for filtering tokens.
52*37748cd8SNickeau     */
53*37748cd8SNickeau    public function __construct(TokenSource $tokenSource, int $channel = Token::DEFAULT_CHANNEL)
54*37748cd8SNickeau    {
55*37748cd8SNickeau        parent::__construct($tokenSource);
56*37748cd8SNickeau
57*37748cd8SNickeau        $this->channel = $channel;
58*37748cd8SNickeau    }
59*37748cd8SNickeau
60*37748cd8SNickeau    public function adjustSeekIndex(int $i) : int
61*37748cd8SNickeau    {
62*37748cd8SNickeau        return $this->nextTokenOnChannel($i, $this->channel);
63*37748cd8SNickeau    }
64*37748cd8SNickeau
65*37748cd8SNickeau    protected function LB(int $k) : ?Token
66*37748cd8SNickeau    {
67*37748cd8SNickeau        if ($k === 0 || $this->index - $k < 0) {
68*37748cd8SNickeau            return null;
69*37748cd8SNickeau        }
70*37748cd8SNickeau
71*37748cd8SNickeau        // find k good tokens looking backwards
72*37748cd8SNickeau        $i = $this->index;
73*37748cd8SNickeau        $n = 1;
74*37748cd8SNickeau        while ($n <= $k) {
75*37748cd8SNickeau            // skip off-channel tokens
76*37748cd8SNickeau            $i = $this->previousTokenOnChannel($i - 1, $this->channel);
77*37748cd8SNickeau            $n++;
78*37748cd8SNickeau        }
79*37748cd8SNickeau
80*37748cd8SNickeau        if ($i < 0) {
81*37748cd8SNickeau            return null;
82*37748cd8SNickeau        }
83*37748cd8SNickeau
84*37748cd8SNickeau        return $this->tokens[$i];
85*37748cd8SNickeau    }
86*37748cd8SNickeau
87*37748cd8SNickeau    public function LT(int $k) : ?Token
88*37748cd8SNickeau    {
89*37748cd8SNickeau        $this->lazyInit();
90*37748cd8SNickeau
91*37748cd8SNickeau        if ($k === 0) {
92*37748cd8SNickeau            return null;
93*37748cd8SNickeau        }
94*37748cd8SNickeau
95*37748cd8SNickeau        if ($k < 0) {
96*37748cd8SNickeau            return $this->LB(-$k);
97*37748cd8SNickeau        }
98*37748cd8SNickeau
99*37748cd8SNickeau        // find k good tokens
100*37748cd8SNickeau        $i = $this->index;
101*37748cd8SNickeau        $n = 1; // we know tokens[pos] is a good one
102*37748cd8SNickeau        while ($n < $k) {
103*37748cd8SNickeau            // skip off-channel tokens, but make sure to not look past EOF
104*37748cd8SNickeau            if ($this->sync($i + 1)) {
105*37748cd8SNickeau                $i = $this->nextTokenOnChannel($i + 1, $this->channel);
106*37748cd8SNickeau            }
107*37748cd8SNickeau
108*37748cd8SNickeau            $n++;
109*37748cd8SNickeau        }
110*37748cd8SNickeau
111*37748cd8SNickeau        return $this->tokens[$i];
112*37748cd8SNickeau    }
113*37748cd8SNickeau
114*37748cd8SNickeau    /**
115*37748cd8SNickeau     * Count EOF just once.
116*37748cd8SNickeau     */
117*37748cd8SNickeau    public function getNumberOfOnChannelTokens() : int
118*37748cd8SNickeau    {
119*37748cd8SNickeau        $n = 0;
120*37748cd8SNickeau
121*37748cd8SNickeau        $this->fill();
122*37748cd8SNickeau
123*37748cd8SNickeau        foreach ($this->tokens as $t) {
124*37748cd8SNickeau            if ($t->getChannel() === $this->channel) {
125*37748cd8SNickeau                $n++;
126*37748cd8SNickeau            }
127*37748cd8SNickeau
128*37748cd8SNickeau            if ($t->getType() === Token::EOF) {
129*37748cd8SNickeau                break;
130*37748cd8SNickeau            }
131*37748cd8SNickeau        }
132*37748cd8SNickeau
133*37748cd8SNickeau        return $n;
134*37748cd8SNickeau    }
135*37748cd8SNickeau}
136