@@ -129,6 +129,8 @@ private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode
129
129
if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_OPEN_SQUARE_BRACKET )) {
130
130
$ type = $ this ->tryParseArrayOrOffsetAccess ($ tokens , $ type );
131
131
}
132
+ } elseif ($ type ->name === 'object ' && $ tokens ->isCurrentTokenType (Lexer::TOKEN_OPEN_CURLY_BRACKET ) && !$ tokens ->isPrecededByHorizontalWhitespace ()) {
133
+ $ type = $ this ->parseObjectShape ($ tokens , $ type );
132
134
}
133
135
134
136
return $ type ;
@@ -468,53 +470,76 @@ private function tryParseArrayOrOffsetAccess(TokenIterator $tokens, Ast\Type\Typ
468
470
return $ type ;
469
471
}
470
472
471
-
472
473
/** @phpstan-impure */
473
- private function parseArrayShape (TokenIterator $ tokens , Ast \Type \TypeNode $ type ): Ast \ Type \ ArrayShapeNode
474
+ private function parseShape (TokenIterator $ tokens , Ast \Type \IdentifierTypeNode $ type ): array
474
475
{
475
476
$ tokens ->consumeTokenType (Lexer::TOKEN_OPEN_CURLY_BRACKET );
476
477
if ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_CLOSE_CURLY_BRACKET )) {
477
- return new Ast \ Type \ ArrayShapeNode ([]) ;
478
+ return [] ;
478
479
}
479
480
480
481
$ tokens ->tryConsumeTokenType (Lexer::TOKEN_PHPDOC_EOL );
481
- $ items = [$ this ->parseArrayShapeItem ($ tokens )];
482
+ $ items = [$ this ->parseShapeItem ($ tokens, $ type )];
482
483
483
484
$ tokens ->tryConsumeTokenType (Lexer::TOKEN_PHPDOC_EOL );
484
485
while ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_COMMA )) {
485
486
$ tokens ->tryConsumeTokenType (Lexer::TOKEN_PHPDOC_EOL );
486
487
if ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_CLOSE_CURLY_BRACKET )) {
487
488
// trailing comma case
488
- return new Ast \ Type \ ArrayShapeNode ( $ items) ;
489
+ return $ items ;
489
490
}
490
491
491
- $ items [] = $ this ->parseArrayShapeItem ($ tokens );
492
+ $ items [] = $ this ->parseShapeItem ($ tokens, $ type );
492
493
$ tokens ->tryConsumeTokenType (Lexer::TOKEN_PHPDOC_EOL );
493
494
}
494
495
495
496
$ tokens ->tryConsumeTokenType (Lexer::TOKEN_PHPDOC_EOL );
496
497
$ tokens ->consumeTokenType (Lexer::TOKEN_CLOSE_CURLY_BRACKET );
497
498
499
+ return $ items ;
500
+ }
501
+
502
+ /** @phpstan-impure */
503
+ private function parseArrayShape (TokenIterator $ tokens , Ast \Type \IdentifierTypeNode $ type ): Ast \Type \ArrayShapeNode
504
+ {
505
+ $ items = $ this ->parseShape ($ tokens , $ type );
506
+
498
507
return new Ast \Type \ArrayShapeNode ($ items );
499
508
}
500
509
510
+ /** @phpstan-impure */
511
+ private function parseObjectShape (TokenIterator $ tokens , Ast \Type \IdentifierTypeNode $ type ): Ast \Type \ObjectShapeNode
512
+ {
513
+ $ items = $ this ->parseShape ($ tokens , $ type );
514
+
515
+ return new Ast \Type \ObjectShapeNode ($ type , $ items );
516
+ }
517
+
501
518
502
519
/** @phpstan-impure */
503
- private function parseArrayShapeItem (TokenIterator $ tokens ): Ast \Type \ArrayShapeItemNode
520
+ private function parseShapeItem (TokenIterator $ tokens, Ast \ Type \ IdentifierTypeNode $ type ): Ast \Type \ShapeItemNode
504
521
{
505
522
try {
506
523
$ tokens ->pushSavePoint ();
507
- $ key = $ this ->parseArrayShapeKey ($ tokens );
524
+ $ key = $ this ->parseShapeKey ($ tokens );
508
525
$ optional = $ tokens ->tryConsumeTokenType (Lexer::TOKEN_NULLABLE );
509
526
$ tokens ->consumeTokenType (Lexer::TOKEN_COLON );
510
527
$ value = $ this ->parse ($ tokens );
511
528
$ tokens ->dropSavePoint ();
512
529
530
+ if ($ type ->name === 'object ' ) {
531
+ return new Ast \Type \ObjectShapeItemNode ($ key , $ optional , $ value );
532
+ }
533
+
513
534
return new Ast \Type \ArrayShapeItemNode ($ key , $ optional , $ value );
514
535
} catch (ParserException $ e ) {
515
536
$ tokens ->rollback ();
516
537
$ value = $ this ->parse ($ tokens );
517
538
539
+ if ($ type ->name === 'object ' ) {
540
+ return new Ast \Type \ObjectShapeItemNode (null , false , $ value );
541
+ }
542
+
518
543
return new Ast \Type \ArrayShapeItemNode (null , false , $ value );
519
544
}
520
545
}
@@ -523,7 +548,7 @@ private function parseArrayShapeItem(TokenIterator $tokens): Ast\Type\ArrayShape
523
548
* @phpstan-impure
524
549
* @return Ast\ConstExpr\ConstExprIntegerNode|Ast\ConstExpr\ConstExprStringNode|Ast\Type\IdentifierTypeNode
525
550
*/
526
- private function parseArrayShapeKey (TokenIterator $ tokens )
551
+ private function parseShapeKey (TokenIterator $ tokens )
527
552
{
528
553
if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_INTEGER )) {
529
554
$ key = new Ast \ConstExpr \ConstExprIntegerNode ($ tokens ->currentTokenValue ());
0 commit comments