Fix parsing of [] in various cases - closes #36

* Array shapes
* Generics
* $this
* Nullables
This commit is contained in:
Ilija Tovilo 2020-01-23 17:37:46 +01:00 committed by Ondřej Mirtes
parent 1a80f73d97
commit 928179efc5
2 changed files with 107 additions and 3 deletions

View File

@ -37,10 +37,12 @@ class TypeParser
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
$type = $this->tryParseArray($tokens, $type); $type = $this->tryParseArray($tokens, $type);
} }
} elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_THIS_VARIABLE)) { } elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_THIS_VARIABLE)) {
return new Ast\Type\ThisTypeNode(); $type = new Ast\Type\ThisTypeNode();
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
$type = $this->tryParseArray($tokens, $type);
}
} else { } else {
$type = new Ast\Type\IdentifierTypeNode($tokens->currentTokenValue()); $type = new Ast\Type\IdentifierTypeNode($tokens->currentTokenValue());
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
@ -48,6 +50,9 @@ class TypeParser
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) { if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {
$type = $this->parseGeneric($tokens, $type); $type = $this->parseGeneric($tokens, $type);
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
$type = $this->tryParseArray($tokens, $type);
}
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) { } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
$type = $this->tryParseCallable($tokens, $type); $type = $this->tryParseCallable($tokens, $type);
@ -56,6 +61,10 @@ class TypeParser
} elseif ($type->name === 'array' && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) { } elseif ($type->name === 'array' && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) {
$type = $this->parseArrayShape($tokens, $type); $type = $this->parseArrayShape($tokens, $type);
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
$type = $this->tryParseArray($tokens, $type);
}
} }
} }
@ -101,6 +110,10 @@ class TypeParser
$type = $this->parseArrayShape($tokens, $type); $type = $this->parseArrayShape($tokens, $type);
} }
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
$type = $this->tryParseArray($tokens, $type);
}
return new Ast\Type\NullableTypeNode($type); return new Ast\Type\NullableTypeNode($type);
} }
@ -179,6 +192,10 @@ class TypeParser
} }
} }
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
$type = $this->tryParseArray($tokens, $type);
}
return $type; return $type;
} }
@ -218,7 +235,7 @@ class TypeParser
} }
private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type): Ast\Type\TypeNode private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type): Ast\Type\ArrayShapeNode
{ {
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET); $tokens->consumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET);
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);

View File

@ -711,6 +711,93 @@ class TypeParserTest extends \PHPUnit\Framework\TestCase
new IdentifierTypeNode("\xA009") new IdentifierTypeNode("\xA009")
), ),
], ],
[
'Collection<array-key, int>[]',
new ArrayTypeNode(
new GenericTypeNode(
new IdentifierTypeNode('Collection'),
[
new IdentifierTypeNode('array-key'),
new IdentifierTypeNode('int'),
]
)
),
],
[
'int | Collection<array-key, int>[]',
new UnionTypeNode([
new IdentifierTypeNode('int'),
new ArrayTypeNode(
new GenericTypeNode(
new IdentifierTypeNode('Collection'),
[
new IdentifierTypeNode('array-key'),
new IdentifierTypeNode('int'),
]
)
),
]),
],
[
'array{foo: int}[]',
new ArrayTypeNode(
new ArrayShapeNode([
new ArrayShapeItemNode(
new IdentifierTypeNode('foo'),
false,
new IdentifierTypeNode('int')
),
])
),
],
[
'int | array{foo: int}[]',
new UnionTypeNode([
new IdentifierTypeNode('int'),
new ArrayTypeNode(
new ArrayShapeNode([
new ArrayShapeItemNode(
new IdentifierTypeNode('foo'),
false,
new IdentifierTypeNode('int')
),
])
),
]),
],
[
'$this[]',
new ArrayTypeNode(
new ThisTypeNode()
),
],
[
'int | $this[]',
new UnionTypeNode([
new IdentifierTypeNode('int'),
new ArrayTypeNode(
new ThisTypeNode()
),
]),
],
[
'callable(): int[]',
new CallableTypeNode(
new IdentifierTypeNode('callable'),
[],
new ArrayTypeNode(
new IdentifierTypeNode('int')
)
),
],
[
'?int[]',
new NullableTypeNode(
new ArrayTypeNode(
new IdentifierTypeNode('int')
)
),
],
]; ];
} }