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