src/TokenStream.php
5420a5e3
 <?php
 
037ee672
 /*
  * This file is part of Twig.
  *
  * (c) Fabien Potencier
  * (c) Armin Ronacher
  *
  * For the full copyright and license information, please view the LICENSE
  * file that was distributed with this source code.
  */
 
5420a5e3
 namespace Twig;
 
037ee672
 use Twig\Error\SyntaxError;
 
 /**
  * Represents a token stream.
  *
  * @author Fabien Potencier <fabien@symfony.com>
  */
 final class TokenStream
 {
     private $tokens;
     private $current = 0;
     private $source;
 
     public function __construct(array $tokens, Source $source = null)
     {
         $this->tokens = $tokens;
         $this->source = $source ?: new Source('', '');
     }
 
     public function __toString()
     {
         return implode("\n", $this->tokens);
     }
 
     public function injectTokens(array $tokens)
     {
         $this->tokens = array_merge(\array_slice($this->tokens, 0, $this->current), $tokens, \array_slice($this->tokens, $this->current));
     }
 
     /**
      * Sets the pointer to the next token and returns the old one.
      */
6c91803a
     public function next(): Token
037ee672
     {
         if (!isset($this->tokens[++$this->current])) {
             throw new SyntaxError('Unexpected end of template.', $this->tokens[$this->current - 1]->getLine(), $this->source);
         }
 
         return $this->tokens[$this->current - 1];
     }
 
     /**
      * Tests a token, sets the pointer to the next one and returns it or throws a syntax error.
      *
      * @return Token|null The next token if the condition is true, null otherwise
      */
     public function nextIf($primary, $secondary = null)
     {
         if ($this->tokens[$this->current]->test($primary, $secondary)) {
             return $this->next();
         }
     }
 
     /**
      * Tests a token and returns it or throws a syntax error.
      */
6c91803a
     public function expect($type, $value = null, string $message = null): Token
037ee672
     {
         $token = $this->tokens[$this->current];
         if (!$token->test($type, $value)) {
             $line = $token->getLine();
19164de7
             throw new SyntaxError(sprintf('%sUnexpected token "%s"%s ("%s" expected%s).',
037ee672
                 $message ? $message.'. ' : '',
19164de7
                 Token::typeToEnglish($token->getType()),
                 $token->getValue() ? sprintf(' of value "%s"', $token->getValue()) : '',
037ee672
                 Token::typeToEnglish($type), $value ? sprintf(' with value "%s"', $value) : ''),
                 $line,
                 $this->source
             );
         }
         $this->next();
 
         return $token;
     }
 
     /**
      * Looks at the next token.
      */
6c91803a
     public function look(int $number = 1): Token
037ee672
     {
         if (!isset($this->tokens[$this->current + $number])) {
             throw new SyntaxError('Unexpected end of template.', $this->tokens[$this->current + $number - 1]->getLine(), $this->source);
         }
 
         return $this->tokens[$this->current + $number];
     }
 
     /**
      * Tests the current token.
      */
6c91803a
     public function test($primary, $secondary = null): bool
037ee672
     {
         return $this->tokens[$this->current]->test($primary, $secondary);
     }
 
     /**
      * Checks if end of stream was reached.
      */
6c91803a
     public function isEOF(): bool
037ee672
     {
         return /* Token::EOF_TYPE */ -1 === $this->tokens[$this->current]->getType();
     }
5420a5e3
 
6c91803a
     public function getCurrent(): Token
5420a5e3
     {
037ee672
         return $this->tokens[$this->current];
     }
 
     /**
      * Gets the source associated with this stream.
      *
      * @internal
      */
6c91803a
     public function getSourceContext(): Source
037ee672
     {
         return $this->source;
5420a5e3
     }
 }