vendor/twig/twig/src/TokenStream.php line 53

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of Twig.
  4. *
  5. * (c) Fabien Potencier
  6. * (c) Armin Ronacher
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace Twig;
  12. use Twig\Error\SyntaxError;
  13. /**
  14. * Represents a token stream.
  15. *
  16. * @author Fabien Potencier <fabien@symfony.com>
  17. */
  18. final class TokenStream
  19. {
  20. private $current = 0;
  21. public function __construct(
  22. private array $tokens,
  23. private ?Source $source = null,
  24. ) {
  25. if (null === $this->source) {
  26. trigger_deprecation('twig/twig', '3.16', \sprintf('Not passing a "%s" object to "%s" constructor is deprecated.', Source::class, __CLASS__));
  27. $this->source = new Source('', '');
  28. }
  29. }
  30. public function __toString(): string
  31. {
  32. return implode("\n", $this->tokens);
  33. }
  34. /**
  35. * @return void
  36. */
  37. public function injectTokens(array $tokens)
  38. {
  39. $this->tokens = array_merge(\array_slice($this->tokens, 0, $this->current), $tokens, \array_slice($this->tokens, $this->current));
  40. }
  41. /**
  42. * Sets the pointer to the next token and returns the old one.
  43. */
  44. public function next(): Token
  45. {
  46. if (!isset($this->tokens[++$this->current])) {
  47. throw new SyntaxError('Unexpected end of template.', $this->tokens[$this->current - 1]->getLine(), $this->source);
  48. }
  49. return $this->tokens[$this->current - 1];
  50. }
  51. /**
  52. * Tests a token, sets the pointer to the next one and returns it or throws a syntax error.
  53. *
  54. * @return Token|null The next token if the condition is true, null otherwise
  55. */
  56. public function nextIf($primary, $secondary = null)
  57. {
  58. return $this->tokens[$this->current]->test($primary, $secondary) ? $this->next() : null;
  59. }
  60. /**
  61. * Tests a token and returns it or throws a syntax error.
  62. */
  63. public function expect($type, $value = null, ?string $message = null): Token
  64. {
  65. $token = $this->tokens[$this->current];
  66. if (!$token->test($type, $value)) {
  67. $line = $token->getLine();
  68. throw new SyntaxError(\sprintf('%sUnexpected token "%s"%s ("%s" expected%s).',
  69. $message ? $message.'. ' : '',
  70. $token->toEnglish(),
  71. $token->getValue() ? \sprintf(' of value "%s"', $token->getValue()) : '',
  72. Token::typeToEnglish($type), $value ? \sprintf(' with value "%s"', $value) : ''),
  73. $line,
  74. $this->source
  75. );
  76. }
  77. $this->next();
  78. return $token;
  79. }
  80. /**
  81. * Looks at the next token.
  82. */
  83. public function look(int $number = 1): Token
  84. {
  85. if (!isset($this->tokens[$this->current + $number])) {
  86. throw new SyntaxError('Unexpected end of template.', $this->tokens[$this->current + $number - 1]->getLine(), $this->source);
  87. }
  88. return $this->tokens[$this->current + $number];
  89. }
  90. /**
  91. * Tests the current token.
  92. */
  93. public function test($primary, $secondary = null): bool
  94. {
  95. return $this->tokens[$this->current]->test($primary, $secondary);
  96. }
  97. /**
  98. * Checks if end of stream was reached.
  99. */
  100. public function isEOF(): bool
  101. {
  102. return $this->tokens[$this->current]->test(Token::EOF_TYPE);
  103. }
  104. public function getCurrent(): Token
  105. {
  106. return $this->tokens[$this->current];
  107. }
  108. public function getSourceContext(): Source
  109. {
  110. return $this->source;
  111. }
  112. }