From e7d0960e9c0a457227ccdca5dc5b5d2e6348b0fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Mon, 28 Nov 2022 21:10:53 +0100 Subject: [PATCH] Allow using enums as a token type Enums allow to avoid having to come up with values to assign for each name (unless you use a backed enum), and will provide more type safety. --- lib/Doctrine/Common/Lexer/AbstractLexer.php | 18 +++++- lib/Doctrine/Common/Lexer/Token.php | 3 +- .../Common/Lexer/AbstractLexerTest.php | 9 +++ tests/Doctrine/Common/Lexer/EnumLexer.php | 58 +++++++++++++++++++ tests/Doctrine/Common/Lexer/TokenType.php | 12 ++++ 5 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 tests/Doctrine/Common/Lexer/EnumLexer.php create mode 100644 tests/Doctrine/Common/Lexer/TokenType.php diff --git a/lib/Doctrine/Common/Lexer/AbstractLexer.php b/lib/Doctrine/Common/Lexer/AbstractLexer.php index 44ea16b..9ea73f3 100644 --- a/lib/Doctrine/Common/Lexer/AbstractLexer.php +++ b/lib/Doctrine/Common/Lexer/AbstractLexer.php @@ -5,8 +5,13 @@ namespace Doctrine\Common\Lexer; use ReflectionClass; +use UnitEnum; +use function assert; +use function get_class; use function implode; +use function is_int; +use function is_string; use function preg_split; use function sprintf; use function substr; @@ -18,7 +23,7 @@ /** * Base class for writing simple lexers, i.e. for creating small DSLs. * - * @template T of string|int + * @template T of UnitEnum|string|int */ abstract class AbstractLexer { @@ -275,13 +280,18 @@ protected function scan($input) /** * Gets the literal for a given token. * - * @param int|string $token + * @param T $token * * @return int|string */ public function getLiteral($token) { - $className = static::class; + if ($token instanceof UnitEnum) { + $className = get_class($token); + } else { + $className = static::class; + } + $reflClass = new ReflectionClass($className); $constants = $reflClass->getConstants(); @@ -291,6 +301,8 @@ public function getLiteral($token) } } + assert(is_string($token) || is_int($token)); + return $token; } diff --git a/lib/Doctrine/Common/Lexer/Token.php b/lib/Doctrine/Common/Lexer/Token.php index 475afa1..4c6d53a 100644 --- a/lib/Doctrine/Common/Lexer/Token.php +++ b/lib/Doctrine/Common/Lexer/Token.php @@ -8,11 +8,12 @@ use Countable; use Doctrine\Deprecations\Deprecation; use ReturnTypeWillChange; +use UnitEnum; use function in_array; /** - * @template T of string|int + * @template T of UnitEnum|string|int * @implements ArrayAccess */ final class Token implements ArrayAccess, Countable diff --git a/tests/Doctrine/Common/Lexer/AbstractLexerTest.php b/tests/Doctrine/Common/Lexer/AbstractLexerTest.php index 5a8ebac..c0c5bc6 100644 --- a/tests/Doctrine/Common/Lexer/AbstractLexerTest.php +++ b/tests/Doctrine/Common/Lexer/AbstractLexerTest.php @@ -236,6 +236,15 @@ public function testGetLiteral(): void $this->assertSame('fake_token', $this->concreteLexer->getLiteral('fake_token')); } + public function testGetLiteralWithEnumLexer(): void + { + $enumLexer = new EnumLexer(); + $this->assertSame( + 'Doctrine\Tests\Common\Lexer\TokenType::OPERATOR', + $enumLexer->getLiteral(TokenType::OPERATOR) + ); + } + public function testIsA(): void { $this->assertTrue($this->concreteLexer->isA(11, 'int')); diff --git a/tests/Doctrine/Common/Lexer/EnumLexer.php b/tests/Doctrine/Common/Lexer/EnumLexer.php new file mode 100644 index 0000000..c80aaae --- /dev/null +++ b/tests/Doctrine/Common/Lexer/EnumLexer.php @@ -0,0 +1,58 @@ + */ +class EnumLexer extends AbstractLexer +{ + /** + * {@inheritDoc} + */ + protected function getCatchablePatterns() + { + return [ + '=|<|>', + '[a-z]+', + '\d+', + ]; + } + + /** + * {@inheritDoc} + */ + protected function getNonCatchablePatterns() + { + return [ + '\s+', + '(.)', + ]; + } + + /** + * {@inheritDoc} + */ + protected function getType(&$value) + { + if (is_numeric($value)) { + $value = (int) $value; + + return TokenType::INT; + } + + if (in_array($value, ['=', '<', '>'])) { + return TokenType::OPERATOR; + } + + if (is_string($value)) { + return TokenType::STRING; + } + } +} diff --git a/tests/Doctrine/Common/Lexer/TokenType.php b/tests/Doctrine/Common/Lexer/TokenType.php new file mode 100644 index 0000000..d4a7d53 --- /dev/null +++ b/tests/Doctrine/Common/Lexer/TokenType.php @@ -0,0 +1,12 @@ +