diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 41b615f..17e894e 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -26,4 +26,4 @@ jobs: name: "PHPUnit" uses: "doctrine/.github/.github/workflows/continuous-integration.yml@3.0.0" with: - php-versions: '["7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2"]' + php-versions: '["8.1", "8.2"]' diff --git a/UPGRADE.md b/UPGRADE.md index 79d5bc8..1933fcb 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -9,6 +9,10 @@ awareness about deprecated code. # Upgrade to 3.0.0 `Doctrine\Common\Lexer\Token` no longer implements `ArrayAccess`. +Parameter type declarations have been added to +`Doctrine\Common\Lexer\AbstractLexer` and `Doctrine\Common\Lexer\Token`. +You should add both parameter type declarations and return type declarations to +your lexers, based on the `@return` phpdoc. # Upgrade to 2.0.0 diff --git a/composer.json b/composer.json index 78bf961..8a61afe 100644 --- a/composer.json +++ b/composer.json @@ -26,14 +26,14 @@ ], "homepage": "https://www.doctrine-project.org/projects/lexer.html", "require": { - "php": "^7.1 || ^8.0" + "php": "^8.1" }, "require-dev": { - "doctrine/coding-standard": "^9 || ^10", - "phpstan/phpstan": "^1.3", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "doctrine/coding-standard": "^10", + "phpstan/phpstan": "^1.9", + "phpunit/phpunit": "^9.5", "psalm/plugin-phpunit": "^0.18.3", - "vimeo/psalm": "^4.11 || ^5.0" + "vimeo/psalm": "^5.0" }, "autoload": { "psr-4": { diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 54a9e54..b7b6083 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -6,7 +6,7 @@ - + @@ -15,21 +15,10 @@ tests - - - - - - - - - - tests/* - diff --git a/psalm.xml b/psalm.xml index dfb8bc6..fa14053 100644 --- a/psalm.xml +++ b/psalm.xml @@ -37,6 +37,7 @@ + @@ -44,6 +45,7 @@ + diff --git a/src/AbstractLexer.php b/src/AbstractLexer.php index eed4c51..7c31935 100644 --- a/src/AbstractLexer.php +++ b/src/AbstractLexer.php @@ -7,7 +7,6 @@ use ReflectionClass; use UnitEnum; -use function get_class; use function implode; use function preg_split; use function sprintf; @@ -27,31 +26,25 @@ abstract class AbstractLexer { /** * Lexer original input string. - * - * @var string */ - private $input; + private string $input; /** * Array of scanned tokens. * * @var list> */ - private $tokens = []; + private array $tokens = []; /** * Current lexer position in input string. - * - * @var int */ - private $position = 0; + private int $position = 0; /** * Current peek of current lexer position. - * - * @var int */ - private $peek = 0; + private int $peek = 0; /** * The next token in the input. @@ -59,7 +52,7 @@ abstract class AbstractLexer * @var mixed[]|null * @psalm-var Token|null */ - public $lookahead; + public Token|null $lookahead; /** * The last matched/seen token. @@ -67,14 +60,12 @@ abstract class AbstractLexer * @var mixed[]|null * @psalm-var Token|null */ - public $token; + public Token|null $token; /** * Composed regex for input parsing. - * - * @var string|null */ - private $regex; + private string|null $regex = null; /** * Sets the input data to be tokenized. @@ -86,7 +77,7 @@ abstract class AbstractLexer * * @return void */ - public function setInput($input) + public function setInput(string $input) { $this->input = $input; $this->tokens = []; @@ -125,7 +116,7 @@ public function resetPeek() * * @return void */ - public function resetPosition($position = 0) + public function resetPosition(int $position = 0) { $this->position = $position; } @@ -133,11 +124,9 @@ public function resetPosition($position = 0) /** * Retrieve the original lexer's input until a given position. * - * @param int $position - * * @return string */ - public function getInputUntilPosition($position) + public function getInputUntilPosition(int $position) { return substr($this->input, 0, $position); } @@ -151,7 +140,7 @@ public function getInputUntilPosition($position) * * @psalm-assert-if-true !=null $this->lookahead */ - public function isNextToken($type) + public function isNextToken(int|string|UnitEnum $type) { return $this->lookahead !== null && $this->lookahead->isA($type); } @@ -194,7 +183,7 @@ public function moveNext() * * @return void */ - public function skipUntil($type) + public function skipUntil(int|string|UnitEnum $type) { while ($this->lookahead !== null && ! $this->lookahead->isA($type)) { $this->moveNext(); @@ -204,12 +193,9 @@ public function skipUntil($type) /** * Checks if given value is identical to the given token. * - * @param string $value - * @param int|string $token - * * @return bool */ - public function isA($value, $token) + public function isA(string $value, int|string|UnitEnum $token) { return $this->getType($value) === $token; } @@ -250,14 +236,14 @@ public function glimpse() * * @return void */ - protected function scan($input) + protected function scan(string $input) { if (! isset($this->regex)) { $this->regex = sprintf( '/(%s)|%s/%s', implode(')|(', $this->getCatchablePatterns()), implode('|', $this->getNonCatchablePatterns()), - $this->getModifiers() + $this->getModifiers(), ); } @@ -277,7 +263,7 @@ protected function scan($input) $this->tokens[] = new Token( $firstMatch, $type, - $match[1] + $match[1], ); } } @@ -289,10 +275,10 @@ protected function scan($input) * * @return int|string */ - public function getLiteral($token) + public function getLiteral(int|string|UnitEnum $token) { if ($token instanceof UnitEnum) { - return get_class($token) . '::' . $token->name; + return $token::class . '::' . $token->name; } $className = static::class; @@ -336,11 +322,9 @@ abstract protected function getNonCatchablePatterns(); /** * Retrieve token type. Also processes the token value if necessary. * - * @param string $value - * * @return T|null * * @param-out V $value */ - abstract protected function getType(&$value); + abstract protected function getType(string &$value); } diff --git a/src/Token.php b/src/Token.php index 68a9fa8..b6df694 100644 --- a/src/Token.php +++ b/src/Token.php @@ -20,7 +20,7 @@ final class Token * @readonly * @var V */ - public $value; + public string|int $value; /** * The type of the token (identifier, numeric, string, input parameter, none) @@ -34,15 +34,14 @@ final class Token * The position of the token in the input string * * @readonly - * @var int */ - public $position; + public int $position; /** * @param V $value * @param T|null $type */ - public function __construct($value, $type, int $position) + public function __construct(string|int $value, $type, int $position) { $this->value = $value; $this->type = $type; diff --git a/tests/AbstractLexerTest.php b/tests/AbstractLexerTest.php index 7050914..4a74a9d 100644 --- a/tests/AbstractLexerTest.php +++ b/tests/AbstractLexerTest.php @@ -16,8 +16,7 @@ class AbstractLexerTest extends TestCase { - /** @var ConcreteLexer */ - private $concreteLexer; + private ConcreteLexer $concreteLexer; public function setUp(): void { @@ -29,9 +28,7 @@ public function tearDown(): void setlocale(LC_ALL, null); } - /** - * @psalm-return list>}> - */ + /** @psalm-return list>}> */ public function dataProvider(): array { return [ @@ -113,7 +110,7 @@ public function testSkipUntil(): void $this->assertEquals( new Token('=', 'operator', 5), - $this->concreteLexer->lookahead + $this->concreteLexer->lookahead, ); } @@ -125,7 +122,7 @@ public function testUtf8Mismatch(): void $this->assertEquals( new Token("\xE9=10", 'string', 0), - $this->concreteLexer->lookahead + $this->concreteLexer->lookahead, ); } @@ -172,9 +169,7 @@ public function testGlimpse(string $input, array $expectedTokens): void $this->assertNull($this->concreteLexer->peek()); } - /** - * @psalm-return list - */ + /** @psalm-return list */ public function inputUntilPositionDataProvider(): array { return [ @@ -182,13 +177,11 @@ public function inputUntilPositionDataProvider(): array ]; } - /** - * @dataProvider inputUntilPositionDataProvider - */ + /** @dataProvider inputUntilPositionDataProvider */ public function testGetInputUntilPosition( string $input, int $position, - string $expectedInput + string $expectedInput, ): void { $this->concreteLexer->setInput($input); @@ -242,15 +235,12 @@ public function testGetLiteral(): void $this->assertSame('fake_token', $this->concreteLexer->getLiteral('fake_token')); } - /** - * @requires PHP 8.1 - */ public function testGetLiteralWithEnumLexer(): void { $enumLexer = new EnumLexer(); $this->assertSame( 'Doctrine\Tests\Common\Lexer\TokenType::OPERATOR', - $enumLexer->getLiteral(TokenType::OPERATOR) + $enumLexer->getLiteral(TokenType::OPERATOR), ); } diff --git a/tests/ConcreteLexer.php b/tests/ConcreteLexer.php index 62fc2db..989bae3 100644 --- a/tests/ConcreteLexer.php +++ b/tests/ConcreteLexer.php @@ -12,7 +12,7 @@ /** @extends AbstractLexer */ class ConcreteLexer extends AbstractLexer { - public const INT = 'int'; + final public const INT = 'int'; /** * {@inheritDoc} @@ -37,10 +37,7 @@ protected function getNonCatchablePatterns(): array ]; } - /** - * {@inheritDoc} - */ - protected function getType(&$value): string + protected function getType(string|int|float &$value): string { if (is_numeric($value)) { $value = (int) $value; diff --git a/tests/EnumLexer.php b/tests/EnumLexer.php index 083d0a2..1aebbe1 100644 --- a/tests/EnumLexer.php +++ b/tests/EnumLexer.php @@ -35,10 +35,7 @@ protected function getNonCatchablePatterns(): array ]; } - /** - * {@inheritDoc} - */ - protected function getType(&$value): TokenType + protected function getType(string &$value): TokenType { if (is_numeric($value)) { $value = (int) $value; diff --git a/tests/MutableLexer.php b/tests/MutableLexer.php index 5530b29..b8b706d 100644 --- a/tests/MutableLexer.php +++ b/tests/MutableLexer.php @@ -10,7 +10,7 @@ class MutableLexer extends AbstractLexer { /** @var string[] */ - private $catchablePatterns = []; + private array $catchablePatterns = []; public function addCatchablePattern(string $pattern): void { @@ -33,10 +33,7 @@ protected function getNonCatchablePatterns(): array return ['[\s,]+']; } - /** - * {@inheritDoc} - */ - protected function getType(&$value): int + protected function getType(string &$value): int { return 1; }