Skip to content

Commit 39ab8fc

Browse files
authored
Merge pull request #102 from greg0ire/templatable-value
2 parents c7b693a + abac4f6 commit 39ab8fc

10 files changed

+43
-21
lines changed

docs/en/simple-parser-example.rst

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ It tokenizes a string to ``T_UPPER``, ``T_LOWER`` and``T_NUMBER`` tokens:
1111
1212
use Doctrine\Common\Lexer\AbstractLexer;
1313
14+
/**
15+
* @extends AbstractLexer<CharacterTypeLexer::T_*, string>
16+
*/
1417
class CharacterTypeLexer extends AbstractLexer
1518
{
1619
const T_UPPER = 1;

phpstan.neon.dist

+8
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,11 @@ parameters:
33
paths:
44
- %rootDir%/../../../src
55
- %rootDir%/../../../tests
6+
7+
ignoreErrors:
8+
-
9+
message: '#^Property Doctrine\\Common\\Lexer\\AbstractLexer\<T of int\|string\|UnitEnum,V of int\|string\>\:\:\$tokens \(array\<int, Doctrine\\Common\\Lexer\\Token\<T of int\|string\|UnitEnum, V of int\|string\>\>\) does not accept non\-empty\-array\<int, Doctrine\\Common\\Lexer\\Token\<T of int\|string\|UnitEnum, int\|string\>\>\.$#'
10+
path: src/AbstractLexer.php
11+
-
12+
message: '#^Method Doctrine\\Tests\\Common\\Lexer\\AbstractLexerTest\:\:dataProvider\(\) should return array\<int, array\{string, array\<int, Doctrine\\Common\\Lexer\\Token\<string, int\|string\>\>\}\> but returns array\{array\{''price\=10'', array\{Doctrine\\Common\\Lexer\\Token\<string, string\>, Doctrine\\Common\\Lexer\\Token\<string, string\>, Doctrine\\Common\\Lexer\\Token\<string, int\>\}\}\}\.$#'
13+
path: tests/AbstractLexerTest.php

psalm.xml

+6
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@
5252
<file name="src/Token.php" />
5353
</errorLevel>
5454
</MixedReturnStatement>
55+
<ReferenceConstraintViolation>
56+
<errorLevel type="suppress">
57+
<!-- https://github.com/vimeo/psalm/issues/8891 -->
58+
<file name="src/AbstractLexer.php" />
59+
</errorLevel>
60+
</ReferenceConstraintViolation>
5561
<RedundantConditionGivenDocblockType>
5662
<errorLevel type="suppress">
5763
<!-- that test checks non-obvious things guaranteed by static analysis, just in case -->

src/AbstractLexer.php

+11-7
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
* Base class for writing simple lexers, i.e. for creating small DSLs.
2222
*
2323
* @template T of UnitEnum|string|int
24+
* @template V of string|int
2425
*/
2526
abstract class AbstractLexer
2627
{
@@ -34,7 +35,7 @@ abstract class AbstractLexer
3435
/**
3536
* Array of scanned tokens.
3637
*
37-
* @var list<Token<T>>
38+
* @var list<Token<T, V>>
3839
*/
3940
private $tokens = [];
4041

@@ -56,15 +57,15 @@ abstract class AbstractLexer
5657
* The next token in the input.
5758
*
5859
* @var mixed[]|null
59-
* @psalm-var Token<T>|null
60+
* @psalm-var Token<T, V>|null
6061
*/
6162
public $lookahead;
6263

6364
/**
6465
* The last matched/seen token.
6566
*
6667
* @var mixed[]|null
67-
* @psalm-var Token<T>|null
68+
* @psalm-var Token<T, V>|null
6869
*/
6970
public $token;
7071

@@ -217,7 +218,7 @@ public function isA($value, $token)
217218
* Moves the lookahead token forward.
218219
*
219220
* @return mixed[]|null The next token or NULL if there are no more tokens ahead.
220-
* @psalm-return Token<T>|null
221+
* @psalm-return Token<T, V>|null
221222
*/
222223
public function peek()
223224
{
@@ -232,7 +233,7 @@ public function peek()
232233
* Peeks at the next token, returns it and immediately resets the peek.
233234
*
234235
* @return mixed[]|null The next token or NULL if there are no more tokens ahead.
235-
* @psalm-return Token<T>|null
236+
* @psalm-return Token<T, V>|null
236237
*/
237238
public function glimpse()
238239
{
@@ -270,10 +271,11 @@ protected function scan($input)
270271

271272
foreach ($matches as $match) {
272273
// Must remain before 'value' assignment since it can change content
273-
$type = $this->getType($match[0]);
274+
$firstMatch = $match[0];
275+
$type = $this->getType($firstMatch);
274276

275277
$this->tokens[] = new Token(
276-
$match[0],
278+
$firstMatch,
277279
$type,
278280
$match[1]
279281
);
@@ -337,6 +339,8 @@ abstract protected function getNonCatchablePatterns();
337339
* @param string $value
338340
*
339341
* @return T|null
342+
*
343+
* @param-out V $value
340344
*/
341345
abstract protected function getType(&$value);
342346
}

src/Token.php

+5-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
/**
1515
* @template T of UnitEnum|string|int
16+
* @template V of string|int
1617
* @implements ArrayAccess<string,mixed>
1718
*/
1819
final class Token implements ArrayAccess
@@ -21,7 +22,7 @@ final class Token implements ArrayAccess
2122
* The string value of the token in the input string
2223
*
2324
* @readonly
24-
* @var string|int
25+
* @var V
2526
*/
2627
public $value;
2728

@@ -42,8 +43,8 @@ final class Token implements ArrayAccess
4243
public $position;
4344

4445
/**
45-
* @param string|int $value
46-
* @param T|null $type
46+
* @param V $value
47+
* @param T|null $type
4748
*/
4849
public function __construct($value, $type, int $position)
4950
{
@@ -83,7 +84,7 @@ public function offsetExists($offset): bool
8384
* @return mixed
8485
* @psalm-return (
8586
* O is 'value'
86-
* ? string|int
87+
* ? V
8788
* : (
8889
* O is 'type'
8990
* ? T|null

tests/AbstractLexerTest.php

+6-6
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public function tearDown(): void
3030
}
3131

3232
/**
33-
* @psalm-return list<array{string, list<Token<string>>}>
33+
* @psalm-return list<array{string, list<Token<string, string|int>>}>
3434
*/
3535
public function dataProvider(): array
3636
{
@@ -86,7 +86,7 @@ public function testResetPosition(): void
8686
}
8787

8888
/**
89-
* @psalm-param list<Token<string>> $expectedTokens
89+
* @psalm-param list<Token<string, string|int>> $expectedTokens
9090
*
9191
* @dataProvider dataProvider
9292
*/
@@ -130,7 +130,7 @@ public function testUtf8Mismatch(): void
130130
}
131131

132132
/**
133-
* @psalm-param list<Token<string>> $expectedTokens
133+
* @psalm-param list<Token<string, string|int>> $expectedTokens
134134
*
135135
* @dataProvider dataProvider
136136
*/
@@ -150,7 +150,7 @@ public function testPeek(string $input, array $expectedTokens): void
150150
}
151151

152152
/**
153-
* @psalm-param list<Token<string>> $expectedTokens
153+
* @psalm-param list<Token<string, string|int>> $expectedTokens
154154
*
155155
* @dataProvider dataProvider
156156
*/
@@ -196,7 +196,7 @@ public function testGetInputUntilPosition(
196196
}
197197

198198
/**
199-
* @psalm-param list<Token<string>> $expectedTokens
199+
* @psalm-param list<Token<string, string|int>> $expectedTokens
200200
*
201201
* @dataProvider dataProvider
202202
*/
@@ -213,7 +213,7 @@ public function testIsNextToken(string $input, array $expectedTokens): void
213213
}
214214

215215
/**
216-
* @psalm-param list<Token<string>> $expectedTokens
216+
* @psalm-param list<Token<string, string|int>> $expectedTokens
217217
*
218218
* @dataProvider dataProvider
219219
*/

tests/ConcreteLexer.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use function in_array;
1010
use function is_numeric;
1111

12-
/** @extends AbstractLexer<string> */
12+
/** @extends AbstractLexer<string, string|int> */
1313
class ConcreteLexer extends AbstractLexer
1414
{
1515
public const INT = 'int';

tests/EnumLexer.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use function in_array;
1010
use function is_numeric;
1111

12-
/** @extends AbstractLexer<TokenType> */
12+
/** @extends AbstractLexer<TokenType, string|int> */
1313
class EnumLexer extends AbstractLexer
1414
{
1515
/**

tests/MutableLexer.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use Doctrine\Common\Lexer\AbstractLexer;
88

9-
/** @extends AbstractLexer<int> */
9+
/** @extends AbstractLexer<int, string> */
1010
class MutableLexer extends AbstractLexer
1111
{
1212
/** @var string[] */

tests/TokenTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ final class TokenTest extends TestCase
1414

1515
public function testIsA(): void
1616
{
17-
/** @var Token<'string'|'int'> $token */
17+
/** @var Token<'string'|'int', string> $token */
1818
$token = new Token('foo', 'string', 1);
1919

2020
self::assertTrue($token->isA('string'));

0 commit comments

Comments
 (0)