Skip to content

Commit f116b6b

Browse files
committed
Use list<T> in ArrayBuffer instead of custom keys (possibly keys duplication fix).
1 parent 4962698 commit f116b6b

File tree

15 files changed

+207
-75
lines changed

15 files changed

+207
-75
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
strategy:
1717
fail-fast: false
1818
matrix:
19-
php: [ '7.4', '8.0', '8.1', '8.2', '8.3', '8.4' ]
19+
php: [ '8.1', '8.2', '8.3', '8.4' ]
2020
os: [ ubuntu-latest, macos-latest, windows-latest ]
2121
stability: [ prefer-lowest, prefer-stable ]
2222
steps:

composer.json

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,18 @@
2121
"ext-pcre": "*",
2222
"ext-json": "*",
2323
"ext-mbstring": "*",
24-
"phplrt/source": "^4.0",
25-
"phplrt/lexer-contracts": "^4.0",
26-
"phplrt/exception": "^4.0"
24+
"phplrt/source": "^3.7",
25+
"phplrt/lexer-contracts": "^3.7",
26+
"phplrt/exception": "^3.7",
27+
"symfony/deprecation-contracts": "^2.5|^3.0"
2728
},
2829
"autoload": {
2930
"psr-4": {
3031
"Phplrt\\Lexer\\": "src"
31-
}
32+
},
33+
"files": [
34+
"src/polyfill.php"
35+
]
3236
},
3337
"require-dev": {
3438
"phpunit/phpunit": "^10.5|^11.0",
@@ -42,16 +46,19 @@
4246
}
4347
},
4448
"provide": {
45-
"phplrt/lexer-contracts-implementation": "^4.0"
49+
"phplrt/lexer-contracts-implementation": "^3.7"
4650
},
4751
"extra": {
4852
"branch-alias": {
49-
"dev-master": "4.x-dev",
50-
"dev-main": "4.x-dev"
53+
"dev-master": "3.x-dev",
54+
"dev-main": "3.x-dev"
5155
}
5256
},
5357
"config": {
54-
"sort-packages": true
58+
"sort-packages": true,
59+
"allow-plugins": {
60+
"phpstan/extension-installer": true
61+
}
5562
},
5663
"minimum-stability": "dev",
5764
"prefer-stable": true

resources/.deprecations.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace Phplrt\Lexer\Buffer {
4+
5+
/**
6+
* @deprecated since phplrt 3.2 and will be removed in 4.0, use {@see \Phplrt\Buffer\ArrayBuffer} instead.
7+
*/
8+
class ArrayBuffer extends \Phplrt\Buffer\ArrayBuffer
9+
{
10+
}
11+
12+
/**
13+
* @deprecated since phplrt 3.2 and will be removed in 4.0, use {@see \Phplrt\Buffer\ExtrusiveBuffer} instead.
14+
*/
15+
class ExtrusiveBuffer extends \Phplrt\Buffer\ExtrusiveBuffer
16+
{
17+
}
18+
19+
/**
20+
* @deprecated since phplrt 3.2 and will be removed in 4.0, use {@see \Phplrt\Buffer\LazyBuffer} instead.
21+
*/
22+
class LazyBuffer extends \Phplrt\Buffer\LazyBuffer
23+
{
24+
}
25+
26+
/**
27+
* @deprecated since phplrt 3.2 and will be removed in 4.0, use {@see \Phplrt\Buffer\Buffer} instead.
28+
*/
29+
abstract class Buffer extends \Phplrt\Buffer\Buffer
30+
{
31+
}
32+
33+
}

src/Compiler/Markers.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@ class Markers extends PCRECompiler
2626
* @param array<array-key, string> $chunks
2727
*
2828
* @return non-empty-string
29-
*
30-
* @psalm-suppress MoreSpecificReturnType
31-
* @psalm-suppress LessSpecificReturnStatement
3229
*/
3330
protected function buildTokens(array $chunks): string
3431
{

src/Compiler/PCRECompiler.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@ abstract class PCRECompiler implements CompilerInterface
175175
*/
176176
public function __construct(?array $flags = null, ?bool $debug = null)
177177
{
178-
/** @psalm-suppress PropertyTypeCoercion */
179178
$this->flags = $flags ?? self::DEFAULT_FLAGS;
180179

181180
if ($debug === null) {
@@ -269,7 +268,7 @@ protected function test(string $pattern, ?string $original = null): void
269268

270269
@\preg_match_all($this->wrap($pattern), '', $matches, $flags);
271270

272-
if ($error = \error_get_last()) {
271+
if (($error = \error_get_last()) !== null) {
273272
throw new CompilationException($this->formatException($error['message'], $original));
274273
}
275274
}
@@ -291,8 +290,8 @@ protected function formatException(string $message, ?string $token = null): stri
291290

292291
$message = \str_replace('Compilation failed: ', '', $message);
293292
$message = \preg_replace('/([\w_]+\(\):\h+)/', '', $message);
294-
$message = \preg_replace('/\h*at\h+offset\h+\d+/', '', $message);
293+
$message = \preg_replace('/\h*at\h+offset\h+\d+/', '', (string) $message);
295294

296-
return \ucfirst($message) . (\is_string($token) ? $suffix : '');
295+
return \ucfirst((string) $message) . (\is_string($token) ? $suffix : '');
297296
}
298297
}

src/Driver/Markers.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class Markers extends Driver
2626

2727
public function __construct(
2828
?MarkersCompiler $compiler = null,
29-
private readonly string $unknown = self::UNKNOWN_TOKEN_NAME
29+
private readonly string $unknown = self::UNKNOWN_TOKEN_NAME,
3030
) {
3131
parent::__construct($compiler ?? new MarkersCompiler());
3232
}
@@ -50,7 +50,6 @@ public function run(array $tokens, ReadableInterface $source, int $offset = 0):
5050
/** @var non-empty-string $name */
5151
$name = \array_pop($payload);
5252

53-
/** @psalm-suppress InvalidArgument */
5453
yield $this->make($name, $payload);
5554
}
5655
}

src/Exception/EndlessRecursionException.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,12 @@
99

1010
class EndlessRecursionException extends UnexpectedStateException
1111
{
12-
public static function fromState(mixed $state, ReadableInterface $src, ?TokenInterface $tok, ?\Throwable $e = null): self
13-
{
12+
public static function fromState(
13+
mixed $state,
14+
ReadableInterface $src,
15+
?TokenInterface $tok,
16+
?\Throwable $e = null,
17+
): self {
1418
$message = \vsprintf('An unsolvable infinite lexer state transitions was found at %s', [
1519
$state,
1620
]);

src/Exception/UnexpectedStateException.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ public static function fromEmptyStates(ReadableInterface $src, ?\Throwable $e =
1616
return new static($message, $src, null, $e);
1717
}
1818

19+
/**
20+
* @param array-key $state
21+
*/
1922
public static function fromState(string|int $state, ReadableInterface $src, ?TokenInterface $tok, ?\Throwable $e = null): self
2023
{
2124
$message = \sprintf('Unrecognized token state #%s', $state);

src/Lexer.php

Lines changed: 86 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,15 @@ class Lexer implements PositionalLexerInterface, MutableLexerInterface
3131
* Default token name for unidentified tokens.
3232
*
3333
* @var non-empty-string
34-
*
35-
* @final
3634
*/
37-
public const DEFAULT_UNKNOWN_TOKEN_NAME = UnknownToken::DEFAULT_TOKEN_NAME;
35+
final public const DEFAULT_UNKNOWN_TOKEN_NAME = UnknownToken::DEFAULT_TOKEN_NAME;
3836

3937
/**
4038
* Default token name for end of input.
4139
*
4240
* @var non-empty-string
43-
*
44-
* @final
4541
*/
46-
public const DEFAULT_EOI_TOKEN_NAME = EndOfInput::DEFAULT_TOKEN_NAME;
42+
final public const DEFAULT_EOI_TOKEN_NAME = EndOfInput::DEFAULT_TOKEN_NAME;
4743

4844
private DriverInterface $driver;
4945

@@ -53,17 +49,9 @@ class Lexer implements PositionalLexerInterface, MutableLexerInterface
5349

5450
private HandlerInterface $onEndOfInput;
5551

56-
/**
57-
* @var non-empty-string
58-
*/
59-
private readonly string $unknown;
60-
6152
private readonly SourceFactoryInterface $sources;
6253

6354
/**
64-
* @param array<array-key, non-empty-string> $tokens list of
65-
* token names/identifiers and its patterns
66-
* @param list<array-key> $skip list of hidden token names/identifiers
6755
* @param HandlerInterface $onUnknownToken This setting is responsible for
6856
* the behavior of the lexer in case of detection of unrecognized
6957
* tokens.
@@ -87,37 +75,61 @@ class Lexer implements PositionalLexerInterface, MutableLexerInterface
8775
*
8876
* Note that you can also define your own {@see HandlerInterface} to
8977
* override behavior.
90-
* @param non-empty-string $unknown The identifier that marks each unknown
91-
* token inside the executor (internal runtime). This parameter only
92-
* needs to be changed if the name is already in use in the user's
93-
* token set (in the {@see $tokens} parameter), otherwise it makes
94-
* no sense.
95-
* @param non-empty-string $eoi
9678
*/
9779
public function __construct(
80+
/**
81+
* List of token names/identifiers and its patterns.
82+
*
83+
* @var array<array-key, non-empty-string>
84+
*/
9885
protected array $tokens = [],
86+
/**
87+
* List of hidden token names/identifiers.
88+
*
89+
* @var list<array-key>
90+
*/
9991
protected array $skip = [],
10092
?DriverInterface $driver = null,
10193
?HandlerInterface $onHiddenToken = null,
10294
?HandlerInterface $onUnknownToken = null,
10395
?HandlerInterface $onEndOfInput = null,
104-
string $unknown = Lexer::DEFAULT_UNKNOWN_TOKEN_NAME,
10596
/**
106-
* @readonly
97+
* The identifier that marks each unknown token inside the executor
98+
* (internal runtime). This parameter only needs to be changed if the
99+
* name is already in use in the user's token set (in the {@see $tokens}
100+
* parameter), otherwise it makes no sense.
101+
*
102+
* @var non-empty-string
103+
*/
104+
private readonly string $unknown = Lexer::DEFAULT_UNKNOWN_TOKEN_NAME,
105+
/**
106+
* @var non-empty-string
107107
*/
108-
private string $eoi = Lexer::DEFAULT_EOI_TOKEN_NAME,
109-
?SourceFactoryInterface $sources = null
108+
private readonly string $eoi = Lexer::DEFAULT_EOI_TOKEN_NAME,
109+
?SourceFactoryInterface $sources = null,
110110
) {
111111
$this->driver = $driver ?? new Markers(new MarkersCompiler(), $unknown);
112-
$this->unknown = $unknown;
113-
114112
$this->onHiddenToken = $onHiddenToken ?? new NullHandler();
115113
$this->onUnknownToken = $onUnknownToken ?? new ThrowErrorHandler();
116114
$this->onEndOfInput = $onEndOfInput ?? new PassthroughHandler();
117-
118115
$this->sources = $sources ?? new SourceFactory();
119116
}
120117

118+
/**
119+
* @deprecated since phplrt 3.6 and will be removed in 4.0. Please use
120+
* "$onUnknownToken" argument of the {@see __construct()}
121+
* or {@see Lexer::withUnknownTokenHandler()} method instead.
122+
*/
123+
public function disableUnrecognizedTokenException(): void
124+
{
125+
trigger_deprecation('phplrt/lexer', '3.6', <<<'MSG'
126+
Using "%s::disableUnrecognizedTokenException()" is deprecated.
127+
Please use %1$s::withUnknownTokenHandler() instead.
128+
MSG, static::class);
129+
130+
$this->onUnknownToken = new PassthroughHandler();
131+
}
132+
121133
/**
122134
* @psalm-immutable This method returns a new {@see LexerInterface} instance
123135
* and does not change the current state of the lexer.
@@ -169,6 +181,36 @@ public function withEndOfInputHandler(HandlerInterface $handler): self
169181
return $self;
170182
}
171183

184+
/**
185+
* @deprecated since phplrt 3.6 and will be removed in 4.0.
186+
*
187+
* @api
188+
*/
189+
public function getDriver(): DriverInterface
190+
{
191+
trigger_deprecation('phplrt/lexer', '3.6', <<<'MSG'
192+
Using "%s::getDriver()" is deprecated.
193+
MSG, static::class);
194+
195+
return $this->driver;
196+
}
197+
198+
/**
199+
* @deprecated since phplrt 3.6 and will be removed in 4.0.
200+
*
201+
* @api
202+
*/
203+
public function setDriver(DriverInterface $driver): self
204+
{
205+
trigger_deprecation('phplrt/lexer', '3.6', <<<'MSG'
206+
Using "%s::setDriver(DriverInterface $driver)" is deprecated.
207+
MSG, static::class);
208+
209+
$this->driver = $driver;
210+
211+
return $this;
212+
}
213+
172214
public function skip(string ...$tokens): self
173215
{
174216
$this->skip = \array_merge($this->skip, $tokens);
@@ -277,9 +319,13 @@ public function lex(mixed $source, int $offset = 0): iterable
277319
continue;
278320
}
279321

280-
if ($unknown !== [] && ($result = $this->handleUnknownToken($source, $unknown))) {
281-
yield $result;
282-
$unknown = [];
322+
if ($unknown !== []) {
323+
$result = $this->handleUnknownToken($source, $unknown);
324+
325+
if ($result !== null) {
326+
yield $result;
327+
$unknown = [];
328+
}
283329
}
284330

285331
yield $token;
@@ -288,11 +334,17 @@ public function lex(mixed $source, int $offset = 0): iterable
288334
throw LexerException::fromInternalError($e);
289335
}
290336

291-
if ($unknown !== [] && $result = $this->handleUnknownToken($source, $unknown)) {
292-
yield $token = $result;
337+
if ($unknown !== []) {
338+
$result = $this->handleUnknownToken($source, $unknown);
339+
340+
if ($result !== null) {
341+
yield $token = $result;
342+
}
293343
}
294344

295-
if (($eoi = $this->handleEoiToken($source, $token ?? null)) !== null) {
345+
$eoi = $this->handleEoiToken($source, $token ?? null);
346+
347+
if ($eoi !== null) {
296348
yield $eoi;
297349
}
298350
}
@@ -317,9 +369,7 @@ private function handleEoiToken(ReadableInterface $source, ?TokenInterface $last
317369
*/
318370
private function reduceUnknownToken(array $tokens): TokenInterface
319371
{
320-
$concat = static function (string $data, TokenInterface $token): string {
321-
return $data . $token->getValue();
322-
};
372+
$concat = static fn(string $data, TokenInterface $token): string => $data . $token->getValue();
323373

324374
$value = \array_reduce($tokens, $concat, '');
325375

0 commit comments

Comments
 (0)