Skip to content

Commit fde6cca

Browse files
committed
ConstFetchNode - supports all constants wildcard
1 parent cfd8285 commit fde6cca

File tree

5 files changed

+80
-19
lines changed

5 files changed

+80
-19
lines changed

src/Parser/ConstExprParser.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,18 @@ public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\Con
5353
}
5454

5555
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
56-
$classConstantName = $tokens->currentTokenValue();
57-
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
56+
$classConstantName = '';
57+
if ($tokens->currentTokenType() === Lexer::TOKEN_IDENTIFIER) {
58+
$classConstantName .= $tokens->currentTokenValue();
59+
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
60+
if ($tokens->tryConsumeTokenValue('*')) {
61+
$classConstantName .= '*';
62+
}
63+
} else {
64+
$tokens->consumeTokenValue('*');
65+
$classConstantName .= '*';
66+
}
67+
5868
return new Ast\ConstExpr\ConstFetchNode($identifier, $classConstantName);
5969

6070
}

src/Parser/ParserException.php

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,43 @@ class ParserException extends \Exception
1919
/** @var int */
2020
private $expectedTokenType;
2121

22+
/** @var string */
23+
private $expectedTokenValue;
24+
2225
public function __construct(
2326
string $currentTokenValue,
2427
int $currentTokenType,
2528
int $currentOffset,
26-
int $expectedTokenType
29+
?int $expectedTokenType,
30+
?string $expectedTokenValue = null
2731
)
2832
{
2933
$this->currentTokenValue = $currentTokenValue;
3034
$this->currentTokenType = $currentTokenType;
3135
$this->currentOffset = $currentOffset;
3236
$this->expectedTokenType = $expectedTokenType;
37+
$this->expectedTokenValue = $expectedTokenValue;
3338

3439
$json = json_encode($currentTokenValue, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
3540
assert($json !== false);
3641

37-
parent::__construct(sprintf(
38-
'Unexpected token %s, expected %s at offset %d',
39-
$json,
40-
Lexer::TOKEN_LABELS[$expectedTokenType],
41-
$currentOffset
42-
));
42+
if ($expectedTokenType !== null) {
43+
parent::__construct(sprintf(
44+
'Unexpected token %s, expected %s at offset %d',
45+
$json,
46+
Lexer::TOKEN_LABELS[$expectedTokenType],
47+
$currentOffset
48+
));
49+
} elseif ($expectedTokenValue !== null) {
50+
parent::__construct(sprintf(
51+
'Unexpected token value %s, expected value %s at offset %d',
52+
$json,
53+
$expectedTokenValue,
54+
$currentOffset
55+
));
56+
} else {
57+
throw new \LogicException();
58+
}
4359
}
4460

4561

@@ -66,4 +82,9 @@ public function getExpectedTokenType(): int
6682
return $this->expectedTokenType;
6783
}
6884

85+
public function getExpectedTokenValue(): string
86+
{
87+
return $this->expectedTokenValue;
88+
}
89+
6990
}

src/Parser/TokenIterator.php

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,25 @@ public function isPrecededByHorizontalWhitespace(): bool
6969
return ($this->tokens[$this->index - 1][Lexer::TYPE_OFFSET] ?? -1) === Lexer::TOKEN_HORIZONTAL_WS;
7070
}
7171

72+
/**
73+
* @param string $tokenValue
74+
* @throws \PHPStan\PhpDocParser\Parser\ParserException
75+
*/
76+
public function consumeTokenValue(string $tokenValue): void
77+
{
78+
if ($this->tokens[$this->index][Lexer::VALUE_OFFSET] !== $tokenValue) {
79+
$this->throwError(null, $tokenValue);
80+
}
81+
82+
$this->index++;
83+
84+
if (($this->tokens[$this->index][Lexer::TYPE_OFFSET] ?? -1) !== Lexer::TOKEN_HORIZONTAL_WS) {
85+
return;
86+
}
87+
88+
$this->index++;
89+
}
90+
7291

7392
/**
7493
* @param int $tokenType
@@ -77,7 +96,7 @@ public function isPrecededByHorizontalWhitespace(): bool
7796
public function consumeTokenType(int $tokenType): void
7897
{
7998
if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== $tokenType) {
80-
$this->throwError($tokenType);
99+
$this->throwError($tokenType, null);
81100
}
82101

83102
$this->index++;
@@ -175,16 +194,18 @@ public function rollback(): void
175194

176195

177196
/**
178-
* @param int $expectedTokenType
197+
* @param int|null $expectedTokenType
198+
* @param string|null $expectedTokenValue
179199
* @throws \PHPStan\PhpDocParser\Parser\ParserException
180200
*/
181-
private function throwError(int $expectedTokenType): void
201+
private function throwError(?int $expectedTokenType, ?string $expectedTokenValue): void
182202
{
183203
throw new \PHPStan\PhpDocParser\Parser\ParserException(
184204
$this->currentTokenValue(),
185205
$this->currentTokenType(),
186206
$this->currentTokenOffset(),
187-
$expectedTokenType
207+
$expectedTokenType,
208+
$expectedTokenValue
188209
);
189210
}
190211

src/Parser/TypeParser.php

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,7 @@ private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode
108108
if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
109109
throw $exception;
110110
}
111-
if ($constExpr instanceof Ast\ConstExpr\ConstFetchNode) {
112-
if ($tokens->currentTokenValue() === '*') {
113-
$tokens->consumeTokenType($tokens->currentTokenType());
114-
$constExpr = new Ast\ConstExpr\ConstFetchNode($constExpr->className, $constExpr->name . '*');
115-
}
116-
}
111+
117112
return new Ast\Type\ConstTypeNode($constExpr);
118113
} catch (\LogicException $e) {
119114
throw $exception;

tests/PHPStan/Parser/TypeParserTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,20 @@ public function provideParseData(): array
858858
'Foo::FOO_*',
859859
new ConstTypeNode(new ConstFetchNode('Foo', 'FOO_*')),
860860
],
861+
[
862+
'Foo::*',
863+
new ConstTypeNode(new ConstFetchNode('Foo', '*')),
864+
],
865+
[
866+
'Foo::**',
867+
new \PHPStan\PhpDocParser\Parser\ParserException(
868+
'**',
869+
Lexer::TOKEN_END,
870+
5,
871+
null,
872+
'*'
873+
),
874+
],
861875
[
862876
'( "foo" | Foo::FOO_* )',
863877
new UnionTypeNode([

0 commit comments

Comments
 (0)