@@ -124,8 +124,12 @@ private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode
124
124
} elseif ($ tokens ->isCurrentTokenType (Lexer::TOKEN_OPEN_SQUARE_BRACKET )) {
125
125
$ type = $ this ->tryParseArrayOrOffsetAccess ($ tokens , $ type );
126
126
127
- } elseif (in_array ($ type ->name , ['array ' , 'list ' ], true ) && $ tokens ->isCurrentTokenType (Lexer::TOKEN_OPEN_CURLY_BRACKET ) && !$ tokens ->isPrecededByHorizontalWhitespace ()) {
128
- $ type = $ this ->parseArrayShape ($ tokens , $ type , $ type ->name );
127
+ } elseif (in_array ($ type ->name , ['array ' , 'list ' , 'object ' ], true ) && $ tokens ->isCurrentTokenType (Lexer::TOKEN_OPEN_CURLY_BRACKET ) && !$ tokens ->isPrecededByHorizontalWhitespace ()) {
128
+ if ($ type ->name === 'object ' ) {
129
+ $ type = $ this ->parseObjectShape ($ tokens );
130
+ } else {
131
+ $ type = $ this ->parseArrayShape ($ tokens , $ type , $ type ->name );
132
+ }
129
133
130
134
if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_OPEN_SQUARE_BRACKET )) {
131
135
$ type = $ this ->tryParseArrayOrOffsetAccess ($ tokens , $ type );
@@ -582,4 +586,64 @@ private function parseArrayShapeKey(TokenIterator $tokens)
582
586
return $ key ;
583
587
}
584
588
589
+ /**
590
+ * @phpstan-impure
591
+ */
592
+ private function parseObjectShape (TokenIterator $ tokens ): Ast \Type \ObjectShapeNode
593
+ {
594
+ $ tokens ->consumeTokenType (Lexer::TOKEN_OPEN_CURLY_BRACKET );
595
+
596
+ $ items = [];
597
+
598
+ do {
599
+ $ tokens ->tryConsumeTokenType (Lexer::TOKEN_PHPDOC_EOL );
600
+
601
+ if ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_CLOSE_CURLY_BRACKET )) {
602
+ return new Ast \Type \ObjectShapeNode ($ items );
603
+ }
604
+
605
+ $ items [] = $ this ->parseObjectShapeItem ($ tokens );
606
+
607
+ $ tokens ->tryConsumeTokenType (Lexer::TOKEN_PHPDOC_EOL );
608
+ } while ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_COMMA ));
609
+
610
+ $ tokens ->tryConsumeTokenType (Lexer::TOKEN_PHPDOC_EOL );
611
+ $ tokens ->consumeTokenType (Lexer::TOKEN_CLOSE_CURLY_BRACKET );
612
+
613
+ return new Ast \Type \ObjectShapeNode ($ items );
614
+ }
615
+
616
+ /** @phpstan-impure */
617
+ private function parseObjectShapeItem (TokenIterator $ tokens ): Ast \Type \ObjectShapeItemNode
618
+ {
619
+ $ key = $ this ->parseObjectShapeKey ($ tokens );
620
+ $ optional = $ tokens ->tryConsumeTokenType (Lexer::TOKEN_NULLABLE );
621
+ $ tokens ->consumeTokenType (Lexer::TOKEN_COLON );
622
+ $ value = $ this ->parse ($ tokens );
623
+
624
+ return new Ast \Type \ObjectShapeItemNode ($ key , $ optional , $ value );
625
+ }
626
+
627
+ /**
628
+ * @phpstan-impure
629
+ * @return Ast\ConstExpr\ConstExprStringNode|Ast\Type\IdentifierTypeNode
630
+ */
631
+ private function parseObjectShapeKey (TokenIterator $ tokens )
632
+ {
633
+ if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_SINGLE_QUOTED_STRING )) {
634
+ $ key = new Ast \ConstExpr \ConstExprStringNode (trim ($ tokens ->currentTokenValue (), "' " ));
635
+ $ tokens ->next ();
636
+
637
+ } elseif ($ tokens ->isCurrentTokenType (Lexer::TOKEN_DOUBLE_QUOTED_STRING )) {
638
+ $ key = new Ast \ConstExpr \ConstExprStringNode (trim ($ tokens ->currentTokenValue (), '" ' ));
639
+ $ tokens ->next ();
640
+
641
+ } else {
642
+ $ key = new Ast \Type \IdentifierTypeNode ($ tokens ->currentTokenValue ());
643
+ $ tokens ->consumeTokenType (Lexer::TOKEN_IDENTIFIER );
644
+ }
645
+
646
+ return $ key ;
647
+ }
648
+
585
649
}
0 commit comments