@@ -41,49 +41,26 @@ final class TypeReferenceParser
4141 */
4242 public function parse (\Iterator $ tokens ): TypeReferenceNode
4343 {
44- $ isOptional = false ;
45- if (Scanner::type ($ tokens ) === TokenType::QUESTIONMARK ) {
46- $ startingToken = $ tokens ->current ();
47- $ isOptional = true ;
48- Scanner::skipOne ($ tokens );
49- }
50-
51- Scanner::assertType ($ tokens , TokenType::STRING );
44+ $ startingToken = $ tokens ->current ();
45+ $ questionmarkToken = $ this ->extractQuestionmarkToken ($ tokens );
46+ $ isOptional = !is_null ($ questionmarkToken );
5247
53- $ typeNameToken = $ finalToken = $ tokens ->current ();
54- $ startingToken = $ startingToken ?? $ typeNameToken ;
48+ $ typeNameNodes = $ this ->parseTypeNames ($ tokens );
5549
56- Scanner::skipOne ($ tokens );
57-
58- $ isArray = false ;
59- if (!Scanner::isEnd ($ tokens ) && Scanner::type ($ tokens ) === TokenType::BRACKET_SQUARE_OPEN ) {
60- Scanner::skipOne ($ tokens );
61- Scanner::assertType ($ tokens , TokenType::BRACKET_SQUARE_CLOSE );
62-
63- $ finalToken = $ tokens ->current ();
64- $ isArray = true ;
65-
66- Scanner::skipOne ($ tokens );
67- }
50+ $ closingArrayToken = $ this ->extractClosingArrayToken ($ tokens );
51+ $ isArray = !is_null ($ closingArrayToken );
6852
6953 try {
7054 return new TypeReferenceNode (
7155 attributes: new NodeAttributes (
7256 pathToSource: $ startingToken ->sourcePath ,
7357 rangeInSource: Range::from (
7458 $ startingToken ->boundaries ->start ,
75- $ finalToken ->boundaries ->end
76- )
77- ),
78- names: new TypeNameNodes (
79- new TypeNameNode (
80- attributes: new NodeAttributes (
81- pathToSource: $ typeNameToken ->sourcePath ,
82- rangeInSource: $ typeNameToken ->boundaries
83- ),
84- value: TypeName::from ($ typeNameToken ->value )
59+ $ closingArrayToken ?->boundaries->end
60+ ?? $ typeNameNodes ->getLast ()->attributes ->rangeInSource ->end
8561 )
8662 ),
63+ names: $ typeNameNodes ,
8764 isArray: $ isArray ,
8865 isOptional: $ isOptional
8966 );
@@ -94,4 +71,76 @@ public function parse(\Iterator $tokens): TypeReferenceNode
9471 );
9572 }
9673 }
74+
75+ /**
76+ * @param \Iterator<mixed,Token> $tokens
77+ * @return Token
78+ */
79+ public function extractQuestionmarkToken (\Iterator $ tokens ): ?Token
80+ {
81+ if (Scanner::type ($ tokens ) === TokenType::QUESTIONMARK ) {
82+ $ questionmarkToken = $ tokens ->current ();
83+ Scanner::skipOne ($ tokens );
84+
85+ return $ questionmarkToken ;
86+ }
87+
88+ return null ;
89+ }
90+
91+ /**
92+ * @param \Iterator<mixed,Token> $tokens
93+ * @return TypeNameNodes
94+ */
95+ public function parseTypeNames (\Iterator $ tokens ): TypeNameNodes
96+ {
97+ $ items = [];
98+ while (true ) {
99+ Scanner::assertType ($ tokens , TokenType::STRING );
100+
101+ $ typeNameToken = $ tokens ->current ();
102+ $ items [] = new TypeNameNode (
103+ attributes: new NodeAttributes (
104+ pathToSource: $ typeNameToken ->sourcePath ,
105+ rangeInSource: $ typeNameToken ->boundaries
106+ ),
107+ value: TypeName::from ($ typeNameToken ->value )
108+ );
109+
110+ Scanner::skipOne ($ tokens );
111+
112+ if (Scanner::isEnd ($ tokens )) {
113+ break ;
114+ }
115+
116+ if (Scanner::type ($ tokens ) === TokenType::PIPE ) {
117+ Scanner::skipOne ($ tokens );
118+ continue ;
119+ }
120+
121+ break ;
122+ }
123+
124+ return new TypeNameNodes (...$ items );
125+ }
126+
127+ /**
128+ * @param \Iterator<mixed,Token> $tokens
129+ * @return Token
130+ */
131+ public function extractClosingArrayToken (\Iterator $ tokens ): ?Token
132+ {
133+ if (!Scanner::isEnd ($ tokens ) && Scanner::type ($ tokens ) === TokenType::BRACKET_SQUARE_OPEN ) {
134+ Scanner::skipOne ($ tokens );
135+ Scanner::assertType ($ tokens , TokenType::BRACKET_SQUARE_CLOSE );
136+
137+ $ closingArrayToken = $ tokens ->current ();
138+
139+ Scanner::skipOne ($ tokens );
140+
141+ return $ closingArrayToken ;
142+ }
143+
144+ return null ;
145+ }
97146}
0 commit comments