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