public function testMarkerAnnotation() { $lexer = new DocLexer(); $lexer->setInput("@Name"); $this->assertNull($lexer->token); $this->assertNull($lexer->lookahead); $this->assertTrue($lexer->moveNext()); $this->assertNull($lexer->token); $this->assertEquals('@', $lexer->lookahead['value']); $this->assertTrue($lexer->moveNext()); $this->assertEquals('@', $lexer->token['value']); $this->assertEquals('Name', $lexer->lookahead['value']); $this->assertFalse($lexer->moveNext()); }
public function testScannerTokenizesDocBlockWhitInvalidIdentifier() { $lexer = new DocLexer(); $docblock = '@Foo\\3.42'; $tokens = array(array('value' => '@', 'position' => 0, 'type' => DocLexer::T_AT), array('value' => 'Foo', 'position' => 1, 'type' => DocLexer::T_IDENTIFIER), array('value' => '\\', 'position' => 4, 'type' => DocLexer::T_NAMESPACE_SEPARATOR), array('value' => 3.42, 'position' => 5, 'type' => DocLexer::T_FLOAT)); $lexer->setInput($docblock); foreach ($tokens as $expected) { $lexer->moveNext(); $lookahead = $lexer->lookahead; $this->assertEquals($expected['value'], $lookahead['value']); $this->assertEquals($expected['type'], $lookahead['type']); $this->assertEquals($expected['position'], $lookahead['position']); } $this->assertFalse($lexer->moveNext()); }
/** * @group 44 */ public function testRecognizesDoubleQuotesEscapeSequence() { $lexer = new DocLexer(); $docblock = '@Foo("""' . "\n" . '""")'; $tokens = array(array('value' => '@', 'position' => 0, 'type' => DocLexer::T_AT), array('value' => 'Foo', 'position' => 1, 'type' => DocLexer::T_IDENTIFIER), array('value' => '(', 'position' => 4, 'type' => DocLexer::T_OPEN_PARENTHESIS), array('value' => "\"\n\"", 'position' => 5, 'type' => DocLexer::T_STRING), array('value' => ')', 'position' => 12, 'type' => DocLexer::T_CLOSE_PARENTHESIS)); $lexer->setInput($docblock); foreach ($tokens as $expected) { $lexer->moveNext(); $lookahead = $lexer->lookahead; $this->assertEquals($expected['value'], $lookahead['value']); $this->assertEquals($expected['type'], $lookahead['type']); $this->assertEquals($expected['position'], $lookahead['position']); } $this->assertFalse($lexer->moveNext()); }
public function parse($comment, $context) { $annotations = ['params' => [], 'returns' => [], 'vars' => []]; $lexer = new DocLexer(); $lexer->setInput($comment); while (true) { $lexer->moveNext(); $lexer->skipUntil(DocLexer::T_AT); if ($lexer->lookahead === null) { break; } if ($a = $this->parseReturnComment($lexer, $context)) { $annotations['returns'][] = $a; } if ($a = $this->parseParamComment($lexer, $context)) { $annotations['params'][] = $a; } if ($a = $this->parseVarComment($lexer, $context)) { $annotations['vars'][] = $a; } } if (count($annotations['returns']) > 1) { throw AnnotationException::semanticalError("Duplicated return: {$context}"); } if (count($annotations['vars']) > 1) { throw AnnotationException::semanticalError("Duplicated var: {$context}"); } return $annotations; }
/** * Attempts to match the current lookahead token with any of the given tokens. * * If any of them matches, this method updates the lookahead token; otherwise * a syntax error is raised. * * @param array $tokens * * @return boolean */ private function matchAny(array $tokens) { if (!$this->lexer->isNextTokenAny($tokens)) { $this->syntaxError(implode(' or ', array_map(array($this->lexer, 'getLiteral'), $tokens))); } return $this->lexer->moveNext(); }
/** * Matches any one of the tokens and advances. * * @param array $tokens The list of tokens. * * @return boolean TRUE if the next token matches, FALSE if not. * * @throws Exception * @throws SyntaxException If a syntax error is found. */ private function matchAny(array $tokens) { if (!$this->lexer->isNextTokenAny($tokens)) { throw SyntaxException::expectedToken(implode(' or ', array_map(array($this->lexer, 'getLiteral'), $tokens)), null, $this->lexer); } return $this->lexer->moveNext(); }
/** * Identifier ::= string * * @return string */ private function Identifier() { // check if we have an annotation if (!$this->lexer->isNextTokenAny(self::$classIdentifiers)) { $this->syntaxError('namespace separator or identifier'); } $this->lexer->moveNext(); $className = $this->lexer->token['value']; while ($this->lexer->lookahead['position'] === $this->lexer->token['position'] + strlen($this->lexer->token['value']) && $this->lexer->isNextToken(DocLexer::T_NAMESPACE_SEPARATOR)) { $this->match(DocLexer::T_NAMESPACE_SEPARATOR); $this->matchAny(self::$classIdentifiers); $className .= '\\' . $this->lexer->token['value']; } return $className; }