Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 72e51f7

Browse files
TypeParser: Allow multiple newlines and also allow multiline union and intersection types for array shapes
1 parent 81de606 commit 72e51f7

File tree

3 files changed

+309
-42
lines changed

3 files changed

+309
-42
lines changed

‎src/Parser/TokenIterator.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,19 @@ public function tryConsumeTokenType(int $tokenType): bool
205205
}
206206

207207

208+
/** @phpstan-impure */
209+
public function skipNewLineTokens(): void
210+
{
211+
if (!$this->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
212+
return;
213+
}
214+
215+
do {
216+
$foundNewLine = $this->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
217+
} while ($foundNewLine === true);
218+
}
219+
220+
208221
private function detectNewline(): void
209222
{
210223
$value = $this->currentTokenValue();

‎src/Parser/TypeParser.php

Lines changed: 72 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,44 @@ public function parse(TokenIterator $tokens): Ast\Type\TypeNode
4040
} else {
4141
$type = $this->parseAtomic($tokens);
4242

43-
if ($tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) {
44-
$type = $this->parseUnion($tokens, $type);
43+
$tokens->pushSavePoint();
44+
$tokens->skipNewLineTokens();
45+
46+
try {
47+
$enrichedType = $this->enrichTypeOnUnionOrIntersection($tokens, $type);
48+
49+
} catch (ParserException $parserException) {
50+
$enrichedType = null;
51+
}
4552

46-
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) {
47-
$type = $this->parseIntersection($tokens, $type);
53+
if ($enrichedType !== null) {
54+
$type = $enrichedType;
55+
$tokens->dropSavePoint();
56+
57+
} else {
58+
$tokens->rollback();
59+
$type = $this->enrichTypeOnUnionOrIntersection($tokens, $type) ?? $type;
4860
}
4961
}
5062

5163
return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
5264
}
5365

66+
/** @phpstan-impure */
67+
private function enrichTypeOnUnionOrIntersection(TokenIterator $tokens, Ast\Type\TypeNode $type): ?Ast\Type\TypeNode
68+
{
69+
if ($tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) {
70+
return $this->parseUnion($tokens, $type);
71+
72+
}
73+
74+
if ($tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) {
75+
return $this->parseIntersection($tokens, $type);
76+
}
77+
78+
return null;
79+
}
80+
5481
/**
5582
* @internal
5683
* @template T of Ast\Node
@@ -90,7 +117,7 @@ private function subParse(TokenIterator $tokens): Ast\Type\TypeNode
90117
if ($tokens->isCurrentTokenValue('is')) {
91118
$type = $this->parseConditional($tokens, $type);
92119
} else {
93-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
120+
$tokens->skipNewLineTokens();
94121

95122
if ($tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) {
96123
$type = $this->subParseUnion($tokens, $type);
@@ -112,9 +139,9 @@ private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode
112139
$startIndex = $tokens->currentTokenIndex();
113140

114141
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
115-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
142+
$tokens->skipNewLineTokens();
116143
$type = $this->subParse($tokens);
117-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
144+
$tokens->skipNewLineTokens();
118145

119146
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
120147

@@ -256,9 +283,9 @@ private function subParseUnion(TokenIterator $tokens, Ast\Type\TypeNode $type):
256283
$types = [$type];
257284

258285
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_UNION)) {
259-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
286+
$tokens->skipNewLineTokens();
260287
$types[] = $this->parseAtomic($tokens);
261-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
288+
$tokens->skipNewLineTokens();
262289
}
263290

264291
return new Ast\Type\UnionTypeNode($types);
@@ -284,9 +311,9 @@ private function subParseIntersection(TokenIterator $tokens, Ast\Type\TypeNode $
284311
$types = [$type];
285312

286313
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_INTERSECTION)) {
287-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
314+
$tokens->skipNewLineTokens();
288315
$types[] = $this->parseAtomic($tokens);
289-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
316+
$tokens->skipNewLineTokens();
290317
}
291318

292319
return new Ast\Type\IntersectionTypeNode($types);
@@ -306,15 +333,15 @@ private function parseConditional(TokenIterator $tokens, Ast\Type\TypeNode $subj
306333

307334
$targetType = $this->parse($tokens);
308335

309-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
336+
$tokens->skipNewLineTokens();
310337
$tokens->consumeTokenType(Lexer::TOKEN_NULLABLE);
311-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
338+
$tokens->skipNewLineTokens();
312339

313340
$ifType = $this->parse($tokens);
314341

315-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
342+
$tokens->skipNewLineTokens();
316343
$tokens->consumeTokenType(Lexer::TOKEN_COLON);
317-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
344+
$tokens->skipNewLineTokens();
318345

319346
$elseType = $this->subParse($tokens);
320347

@@ -335,15 +362,15 @@ private function parseConditionalForParameter(TokenIterator $tokens, string $par
335362

336363
$targetType = $this->parse($tokens);
337364

338-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
365+
$tokens->skipNewLineTokens();
339366
$tokens->consumeTokenType(Lexer::TOKEN_NULLABLE);
340-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
367+
$tokens->skipNewLineTokens();
341368

342369
$ifType = $this->parse($tokens);
343370

344-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
371+
$tokens->skipNewLineTokens();
345372
$tokens->consumeTokenType(Lexer::TOKEN_COLON);
346-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
373+
$tokens->skipNewLineTokens();
347374

348375
$elseType = $this->subParse($tokens);
349376

@@ -409,8 +436,11 @@ public function parseGeneric(TokenIterator $tokens, Ast\Type\IdentifierTypeNode
409436
$variances = [];
410437

411438
$isFirst = true;
412-
while ($isFirst || $tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
413-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
439+
while (
440+
$isFirst
441+
|| $tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)
442+
) {
443+
$tokens->skipNewLineTokens();
414444

415445
// trailing comma case
416446
if (!$isFirst && $tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) {
@@ -419,7 +449,7 @@ public function parseGeneric(TokenIterator $tokens, Ast\Type\IdentifierTypeNode
419449
$isFirst = false;
420450

421451
[$genericTypes[], $variances[]] = $this->parseGenericTypeArgument($tokens);
422-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
452+
$tokens->skipNewLineTokens();
423453
}
424454

425455
$type = new Ast\Type\GenericTypeNode($baseType, $genericTypes, $variances);
@@ -510,19 +540,19 @@ private function parseCallable(TokenIterator $tokens, Ast\Type\IdentifierTypeNod
510540
: [];
511541

512542
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES);
513-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
543+
$tokens->skipNewLineTokens();
514544

515545
$parameters = [];
516546
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) {
517547
$parameters[] = $this->parseCallableParameter($tokens);
518-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
548+
$tokens->skipNewLineTokens();
519549
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
520-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
550+
$tokens->skipNewLineTokens();
521551
if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) {
522552
break;
523553
}
524554
$parameters[] = $this->parseCallableParameter($tokens);
525-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
555+
$tokens->skipNewLineTokens();
526556
}
527557
}
528558

@@ -550,7 +580,7 @@ private function parseCallableTemplates(TokenIterator $tokens): array
550580

551581
$isFirst = true;
552582
while ($isFirst || $tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
553-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
583+
$tokens->skipNewLineTokens();
554584

555585
// trailing comma case
556586
if (!$isFirst && $tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) {
@@ -559,7 +589,7 @@ private function parseCallableTemplates(TokenIterator $tokens): array
559589
$isFirst = false;
560590

561591
$templates[] = $this->parseCallableTemplateArgument($tokens);
562-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
592+
$tokens->skipNewLineTokens();
563593
}
564594

565595
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
@@ -830,7 +860,7 @@ private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type,
830860
$unsealedType = null;
831861

832862
do {
833-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
863+
$tokens->skipNewLineTokens();
834864

835865
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) {
836866
return Ast\Type\ArrayShapeNode::createSealed($items, $kind);
@@ -839,14 +869,14 @@ private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type,
839869
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC)) {
840870
$sealed = false;
841871

842-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
872+
$tokens->skipNewLineTokens();
843873
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {
844874
if ($kind === Ast\Type\ArrayShapeNode::KIND_ARRAY) {
845875
$unsealedType = $this->parseArrayShapeUnsealedType($tokens);
846876
} else {
847877
$unsealedType = $this->parseListShapeUnsealedType($tokens);
848878
}
849-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
879+
$tokens->skipNewLineTokens();
850880
}
851881

852882
$tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA);
@@ -855,10 +885,10 @@ private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type,
855885

856886
$items[] = $this->parseArrayShapeItem($tokens);
857887

858-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
888+
$tokens->skipNewLineTokens();
859889
} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));
860890

861-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
891+
$tokens->skipNewLineTokens();
862892
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET);
863893

864894
if ($sealed) {
@@ -945,18 +975,18 @@ private function parseArrayShapeUnsealedType(TokenIterator $tokens): Ast\Type\Ar
945975
$startIndex = $tokens->currentTokenIndex();
946976

947977
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);
948-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
978+
$tokens->skipNewLineTokens();
949979

950980
$valueType = $this->parse($tokens);
951-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
981+
$tokens->skipNewLineTokens();
952982

953983
$keyType = null;
954984
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
955-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
985+
$tokens->skipNewLineTokens();
956986

957987
$keyType = $valueType;
958988
$valueType = $this->parse($tokens);
959-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
989+
$tokens->skipNewLineTokens();
960990
}
961991

962992
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
@@ -978,10 +1008,10 @@ private function parseListShapeUnsealedType(TokenIterator $tokens): Ast\Type\Arr
9781008
$startIndex = $tokens->currentTokenIndex();
9791009

9801010
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);
981-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
1011+
$tokens->skipNewLineTokens();
9821012

9831013
$valueType = $this->parse($tokens);
984-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
1014+
$tokens->skipNewLineTokens();
9851015

9861016
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
9871017

@@ -1003,18 +1033,18 @@ private function parseObjectShape(TokenIterator $tokens): Ast\Type\ObjectShapeNo
10031033
$items = [];
10041034

10051035
do {
1006-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
1036+
$tokens->skipNewLineTokens();
10071037

10081038
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) {
10091039
return new Ast\Type\ObjectShapeNode($items);
10101040
}
10111041

10121042
$items[] = $this->parseObjectShapeItem($tokens);
10131043

1014-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
1044+
$tokens->skipNewLineTokens();
10151045
} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));
10161046

1017-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
1047+
$tokens->skipNewLineTokens();
10181048
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET);
10191049

10201050
return new Ast\Type\ObjectShapeNode($items);

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /