Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\CssSelector\Parser; Chris@0: Chris@0: use Symfony\Component\CssSelector\Exception\InternalErrorException; Chris@0: use Symfony\Component\CssSelector\Exception\SyntaxErrorException; Chris@0: Chris@0: /** Chris@0: * CSS selector token stream. Chris@0: * Chris@0: * This component is a port of the Python cssselect library, Chris@0: * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. Chris@0: * Chris@0: * @author Jean-François Simon Chris@0: * Chris@0: * @internal Chris@0: */ Chris@0: class TokenStream Chris@0: { Chris@0: /** Chris@0: * @var Token[] Chris@0: */ Chris@17: private $tokens = []; Chris@0: Chris@0: /** Chris@0: * @var Token[] Chris@0: */ Chris@17: private $used = []; Chris@0: Chris@0: /** Chris@0: * @var int Chris@0: */ Chris@0: private $cursor = 0; Chris@0: Chris@0: /** Chris@0: * @var Token|null Chris@0: */ Chris@14: private $peeked; Chris@0: Chris@0: /** Chris@0: * @var bool Chris@0: */ Chris@0: private $peeking = false; Chris@0: Chris@0: /** Chris@0: * Pushes a token. Chris@0: * Chris@0: * @return $this Chris@0: */ Chris@0: public function push(Token $token) Chris@0: { Chris@0: $this->tokens[] = $token; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Freezes stream. Chris@0: * Chris@0: * @return $this Chris@0: */ Chris@0: public function freeze() Chris@0: { Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns next token. Chris@0: * Chris@0: * @return Token Chris@0: * Chris@0: * @throws InternalErrorException If there is no more token Chris@0: */ Chris@0: public function getNext() Chris@0: { Chris@0: if ($this->peeking) { Chris@0: $this->peeking = false; Chris@0: $this->used[] = $this->peeked; Chris@0: Chris@0: return $this->peeked; Chris@0: } Chris@0: Chris@0: if (!isset($this->tokens[$this->cursor])) { Chris@0: throw new InternalErrorException('Unexpected token stream end.'); Chris@0: } Chris@0: Chris@0: return $this->tokens[$this->cursor++]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns peeked token. Chris@0: * Chris@0: * @return Token Chris@0: */ Chris@0: public function getPeek() Chris@0: { Chris@0: if (!$this->peeking) { Chris@0: $this->peeked = $this->getNext(); Chris@0: $this->peeking = true; Chris@0: } Chris@0: Chris@0: return $this->peeked; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns used tokens. Chris@0: * Chris@0: * @return Token[] Chris@0: */ Chris@0: public function getUsed() Chris@0: { Chris@0: return $this->used; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns nex identifier token. Chris@0: * Chris@0: * @return string The identifier token value Chris@0: * Chris@0: * @throws SyntaxErrorException If next token is not an identifier Chris@0: */ Chris@0: public function getNextIdentifier() Chris@0: { Chris@0: $next = $this->getNext(); Chris@0: Chris@0: if (!$next->isIdentifier()) { Chris@0: throw SyntaxErrorException::unexpectedToken('identifier', $next); Chris@0: } Chris@0: Chris@0: return $next->getValue(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns nex identifier or star delimiter token. Chris@0: * Chris@17: * @return string|null The identifier token value or null if star found Chris@0: * Chris@0: * @throws SyntaxErrorException If next token is not an identifier or a star delimiter Chris@0: */ Chris@0: public function getNextIdentifierOrStar() Chris@0: { Chris@0: $next = $this->getNext(); Chris@0: Chris@0: if ($next->isIdentifier()) { Chris@0: return $next->getValue(); Chris@0: } Chris@0: Chris@17: if ($next->isDelimiter(['*'])) { Chris@0: return; Chris@0: } Chris@0: Chris@0: throw SyntaxErrorException::unexpectedToken('identifier or "*"', $next); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Skips next whitespace if any. Chris@0: */ Chris@0: public function skipWhitespace() Chris@0: { Chris@0: $peek = $this->getPeek(); Chris@0: Chris@0: if ($peek->isWhitespace()) { Chris@0: $this->getNext(); Chris@0: } Chris@0: } Chris@0: }