diff --git a/docs/en/simple-parser-example.rst b/docs/en/simple-parser-example.rst index 23becdb..c663ee3 100644 --- a/docs/en/simple-parser-example.rst +++ b/docs/en/simple-parser-example.rst @@ -11,6 +11,9 @@ It tokenizes a string to ``T_UPPER``, ``T_LOWER`` and``T_NUMBER`` tokens: use Doctrine\Common\Lexer\AbstractLexer; + /** + * @extends AbstractLexer + */ class CharacterTypeLexer extends AbstractLexer { const T_UPPER = 1; diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 6d0fc0d..fc208bf 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -3,3 +3,11 @@ parameters: paths: - %rootDir%/../../../src - %rootDir%/../../../tests + + ignoreErrors: + - + message: '#^Property Doctrine\\Common\\Lexer\\AbstractLexer\\:\:\$tokens \(array\\>\) does not accept non\-empty\-array\\>\.$#' + path: src/AbstractLexer.php + - + message: '#^Method Doctrine\\Tests\\Common\\Lexer\\AbstractLexerTest\:\:dataProvider\(\) should return array\\>\}\> but returns array\{array\{''price\=10'', array\{Doctrine\\Common\\Lexer\\Token\, Doctrine\\Common\\Lexer\\Token\, Doctrine\\Common\\Lexer\\Token\\}\}\}\.$#' + path: tests/AbstractLexerTest.php diff --git a/psalm.xml b/psalm.xml index 8f1224a..daebf3a 100644 --- a/psalm.xml +++ b/psalm.xml @@ -52,6 +52,12 @@ + + + + + + diff --git a/src/AbstractLexer.php b/src/AbstractLexer.php index 218e08a..eed4c51 100644 --- a/src/AbstractLexer.php +++ b/src/AbstractLexer.php @@ -21,6 +21,7 @@ * Base class for writing simple lexers, i.e. for creating small DSLs. * * @template T of UnitEnum|string|int + * @template V of string|int */ abstract class AbstractLexer { @@ -34,7 +35,7 @@ abstract class AbstractLexer /** * Array of scanned tokens. * - * @var list> + * @var list> */ private $tokens = []; @@ -56,7 +57,7 @@ abstract class AbstractLexer * The next token in the input. * * @var mixed[]|null - * @psalm-var Token|null + * @psalm-var Token|null */ public $lookahead; @@ -64,7 +65,7 @@ abstract class AbstractLexer * The last matched/seen token. * * @var mixed[]|null - * @psalm-var Token|null + * @psalm-var Token|null */ public $token; @@ -217,7 +218,7 @@ public function isA($value, $token) * Moves the lookahead token forward. * * @return mixed[]|null The next token or NULL if there are no more tokens ahead. - * @psalm-return Token|null + * @psalm-return Token|null */ public function peek() { @@ -232,7 +233,7 @@ public function peek() * Peeks at the next token, returns it and immediately resets the peek. * * @return mixed[]|null The next token or NULL if there are no more tokens ahead. - * @psalm-return Token|null + * @psalm-return Token|null */ public function glimpse() { @@ -270,10 +271,11 @@ protected function scan($input) foreach ($matches as $match) { // Must remain before 'value' assignment since it can change content - $type = $this->getType($match[0]); + $firstMatch = $match[0]; + $type = $this->getType($firstMatch); $this->tokens[] = new Token( - $match[0], + $firstMatch, $type, $match[1] ); @@ -337,6 +339,8 @@ abstract protected function getNonCatchablePatterns(); * @param string $value * * @return T|null + * + * @param-out V $value */ abstract protected function getType(&$value); } diff --git a/src/Token.php b/src/Token.php index f9743f1..4fbbf4e 100644 --- a/src/Token.php +++ b/src/Token.php @@ -13,6 +13,7 @@ /** * @template T of UnitEnum|string|int + * @template V of string|int * @implements ArrayAccess */ final class Token implements ArrayAccess @@ -21,7 +22,7 @@ final class Token implements ArrayAccess * The string value of the token in the input string * * @readonly - * @var string|int + * @var V */ public $value; @@ -42,8 +43,8 @@ final class Token implements ArrayAccess public $position; /** - * @param string|int $value - * @param T|null $type + * @param V $value + * @param T|null $type */ public function __construct($value, $type, int $position) { @@ -83,7 +84,7 @@ public function offsetExists($offset): bool * @return mixed * @psalm-return ( * O is 'value' - * ? string|int + * ? V * : ( * O is 'type' * ? T|null diff --git a/tests/AbstractLexerTest.php b/tests/AbstractLexerTest.php index 35ec673..68a6181 100644 --- a/tests/AbstractLexerTest.php +++ b/tests/AbstractLexerTest.php @@ -30,7 +30,7 @@ public function tearDown(): void } /** - * @psalm-return list>}> + * @psalm-return list>}> */ public function dataProvider(): array { @@ -86,7 +86,7 @@ public function testResetPosition(): void } /** - * @psalm-param list> $expectedTokens + * @psalm-param list> $expectedTokens * * @dataProvider dataProvider */ @@ -130,7 +130,7 @@ public function testUtf8Mismatch(): void } /** - * @psalm-param list> $expectedTokens + * @psalm-param list> $expectedTokens * * @dataProvider dataProvider */ @@ -150,7 +150,7 @@ public function testPeek(string $input, array $expectedTokens): void } /** - * @psalm-param list> $expectedTokens + * @psalm-param list> $expectedTokens * * @dataProvider dataProvider */ @@ -196,7 +196,7 @@ public function testGetInputUntilPosition( } /** - * @psalm-param list> $expectedTokens + * @psalm-param list> $expectedTokens * * @dataProvider dataProvider */ @@ -213,7 +213,7 @@ public function testIsNextToken(string $input, array $expectedTokens): void } /** - * @psalm-param list> $expectedTokens + * @psalm-param list> $expectedTokens * * @dataProvider dataProvider */ diff --git a/tests/ConcreteLexer.php b/tests/ConcreteLexer.php index 1c8601c..62fc2db 100644 --- a/tests/ConcreteLexer.php +++ b/tests/ConcreteLexer.php @@ -9,7 +9,7 @@ use function in_array; use function is_numeric; -/** @extends AbstractLexer */ +/** @extends AbstractLexer */ class ConcreteLexer extends AbstractLexer { public const INT = 'int'; diff --git a/tests/EnumLexer.php b/tests/EnumLexer.php index f6fcd5f..083d0a2 100644 --- a/tests/EnumLexer.php +++ b/tests/EnumLexer.php @@ -9,7 +9,7 @@ use function in_array; use function is_numeric; -/** @extends AbstractLexer */ +/** @extends AbstractLexer */ class EnumLexer extends AbstractLexer { /** diff --git a/tests/MutableLexer.php b/tests/MutableLexer.php index 20776b0..5530b29 100644 --- a/tests/MutableLexer.php +++ b/tests/MutableLexer.php @@ -6,7 +6,7 @@ use Doctrine\Common\Lexer\AbstractLexer; -/** @extends AbstractLexer */ +/** @extends AbstractLexer */ class MutableLexer extends AbstractLexer { /** @var string[] */ diff --git a/tests/TokenTest.php b/tests/TokenTest.php index 4ef7ccd..70b4009 100644 --- a/tests/TokenTest.php +++ b/tests/TokenTest.php @@ -14,7 +14,7 @@ final class TokenTest extends TestCase public function testIsA(): void { - /** @var Token<'string'|'int'> $token */ + /** @var Token<'string'|'int', string> $token */ $token = new Token('foo', 'string', 1); self::assertTrue($token->isA('string'));