/** * When the given token is the next token then move * to it, otherwise throw a syntax error exception. * * @param int $token The token code to check. * @return AnnotationToken The next token. */ private function next($token) { /* @var \com\mohiva\common\lang\AnnotationToken $lookahead */ $lookahead = $this->stream->getLookahead(); if ($lookahead && $lookahead->getCode() !== $token || !$lookahead) { $this->syntaxError(array($token), $lookahead); } $this->stream->next(); return $this->stream->current(); }
/** * Create an array from the token stream which contains only the tokens and the operators/values. * * @param TokenStream $stream The stream containing the lexer tokens. * @return array The actual list with tokens and operators/values. */ private function buildActualTokens(TokenStream $stream) { $actual = array(); while ($stream->valid()) { /* @var \com\mohiva\pyramid\Token $current */ $current = $stream->current(); $stream->next(); $actual[] = array($current->getCode() => $current->getValue()); } return $actual; }
/** * Parse the operand. * * This example shows how you should parse sub expressions. You must only create a * new parser with the passed grammar and token stream. * * @param Grammar $grammar The grammar of the parser. * @param TokenStream $stream The token stream to parse. * @return Node The node between the parentheses. * @throws SyntaxErrorException if an unexpected token was found. */ public function parse(Grammar $grammar, TokenStream $stream) { $stream->next(); $parser = new Parser($grammar); $node = $parser->parse($stream); $stream->expect(array(Lexer::T_CLOSE_PARENTHESIS), function (Token $current = null) { if ($current) { $message = "Expected `)`; got `{$current->getValue()}`"; } else { $message = "Expected `)` but end of stream reached"; } throw new SyntaxErrorException($message); }); return $node; }
/** * Parse the ternary operator. * * @param Node $node The expression node. * @param int $precedence The precedence level. * @return Node The ternary operator node or the given expression node. * @throws SyntaxErrorException if no ternary else can be found after a ternary if. */ private function parseTernary(Node $node, $precedence) { /* @var Token $token */ while (($token = $this->stream->current()) && $this->operatorTable->isTernary($token)) { $operator = $this->operatorTable->getTernaryOperator($token); if ($operator->getIfCode() != $token->getCode() || $operator->getPrecedence() < $precedence) { break; } $operatorNode = $operator->getNode(); $subPrecedence = $operator->isRightAssociative() ? $operator->getPrecedence() : $operator->getPrecedence() + 1; // Parse the if expression if ($operator->isShorthandAllowed() && $this->stream->getLookaheadCode() == $operator->getElseCode()) { $this->stream->next(); $if = null; } else { $this->stream->next(); $if = $this->parseExpression($subPrecedence); } // Parse the else expression $this->stream->expect([$operator->getElseCode()], function (Token $current = null) { if ($current) { $near = substr($this->stream->getSource(), 0, $current->getOffset()); $message = "Ternary else expected; got `{$current->getValue()}`; near: " . $near; } else { $near = substr($this->stream->getSource(), 0, strlen($this->stream->getSource())); $message = "Ternary else expected but end of stream reached; near: " . $near; } throw new SyntaxErrorException($message); }); $this->stream->next(); $else = $this->parseExpression($subPrecedence); // Create the ternary operator node $node = $operatorNode($node, $if, $else); } return $node; }
/** * Test if a specified token is the next token. * * @param \com\mohiva\common\parser\TokenStream $stream The token stream to use for this test. * @dataProvider tokenStreamProvider */ public function testIsNext(TokenStream $stream) { // user.name.split(" ").join("-") $this->assertTrue($stream->isNext(self::T_POINT)); $stream->next(); $this->assertTrue($stream->isNext(self::T_NAME)); $stream->next(); $this->assertTrue($stream->isNext(self::T_POINT)); $stream->next(); $this->assertTrue($stream->isNext(self::T_NAME)); $stream->next(); $this->assertTrue($stream->isNext(self::T_OPEN_PARENTHESIS)); $stream->next(); $this->assertTrue($stream->isNext(self::T_VALUE)); $this->assertTrue($stream->isNext(self::T_CLOSE_PARENTHESIS, 2)); $this->assertTrue($stream->isNext(self::T_POINT, 3)); $this->assertTrue($stream->isNext(self::T_NAME, 4)); $this->assertTrue($stream->isNext(self::T_OPEN_PARENTHESIS, 5)); $this->assertTrue($stream->isNext(self::T_VALUE, 6)); $this->assertTrue($stream->isNext(self::T_CLOSE_PARENTHESIS, 7)); $this->assertFalse($stream->isNext(self::T_NAME, 8)); }