@@ -39,12 +39,37 @@ public function parse(TokenIterator $tokens): Ast\Type\TypeNode
3939 return $ type ;
4040 }
4141
42+ /** @phpstan-impure */
43+ private function subParse (TokenIterator $ tokens ): Ast \Type \TypeNode
44+ {
45+ if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_NULLABLE )) {
46+ $ type = $ this ->parseNullable ($ tokens );
47+
48+ } elseif ($ tokens ->isCurrentTokenType (Lexer::TOKEN_VARIABLE )) {
49+ $ type = $ this ->parseConditionalForParameter ($ tokens , $ tokens ->currentTokenValue ());
50+
51+ } else {
52+ $ type = $ this ->parseAtomic ($ tokens );
53+
54+ if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_UNION )) {
55+ $ type = $ this ->parseUnion ($ tokens , $ type );
56+
57+ } elseif ($ tokens ->isCurrentTokenType (Lexer::TOKEN_INTERSECTION )) {
58+ $ type = $ this ->parseIntersection ($ tokens , $ type );
59+ } elseif ($ tokens ->isCurrentTokenValue ('is ' )) {
60+ $ type = $ this ->parseConditional ($ tokens , $ type );
61+ }
62+ }
63+
64+ return $ type ;
65+ }
66+
4267
4368 /** @phpstan-impure */
4469 private function parseAtomic (TokenIterator $ tokens ): Ast \Type \TypeNode
4570 {
4671 if ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_OPEN_PARENTHESES )) {
47- $ type = $ this ->parse ($ tokens );
72+ $ type = $ this ->subParse ($ tokens );
4873 $ tokens ->consumeTokenType (Lexer::TOKEN_CLOSE_PARENTHESES );
4974
5075 if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_OPEN_SQUARE_BRACKET )) {
@@ -157,6 +182,56 @@ private function parseIntersection(TokenIterator $tokens, Ast\Type\TypeNode $typ
157182 }
158183
159184
185+ /** @phpstan-impure */
186+ private function parseConditional (TokenIterator $ tokens , Ast \Type \TypeNode $ subjectType ): Ast \Type \TypeNode
187+ {
188+ $ tokens ->consumeTokenType (Lexer::TOKEN_IDENTIFIER );
189+
190+ $ negated = false ;
191+ if ($ tokens ->isCurrentTokenValue ('not ' )) {
192+ $ negated = true ;
193+ $ tokens ->consumeTokenType (Lexer::TOKEN_IDENTIFIER );
194+ }
195+
196+ $ targetType = $ this ->parseAtomic ($ tokens );
197+
198+ $ tokens ->consumeTokenType (Lexer::TOKEN_NULLABLE );
199+
200+ $ ifType = $ this ->parseAtomic ($ tokens );
201+
202+ $ tokens ->consumeTokenType (Lexer::TOKEN_COLON );
203+
204+ $ elseType = $ this ->parseAtomic ($ tokens );
205+
206+ return new Ast \Type \ConditionalTypeNode ($ subjectType , $ targetType , $ ifType , $ elseType , $ negated );
207+ }
208+
209+ /** @phpstan-impure */
210+ private function parseConditionalForParameter (TokenIterator $ tokens , string $ parameterName ): Ast \Type \TypeNode
211+ {
212+ $ tokens ->consumeTokenType (Lexer::TOKEN_VARIABLE );
213+ $ tokens ->consumeTokenValue (Lexer::TOKEN_IDENTIFIER , 'is ' );
214+
215+ $ negated = false ;
216+ if ($ tokens ->isCurrentTokenValue ('not ' )) {
217+ $ negated = true ;
218+ $ tokens ->consumeTokenType (Lexer::TOKEN_IDENTIFIER );
219+ }
220+
221+ $ targetType = $ this ->parseAtomic ($ tokens );
222+
223+ $ tokens ->consumeTokenType (Lexer::TOKEN_NULLABLE );
224+
225+ $ ifType = $ this ->parseAtomic ($ tokens );
226+
227+ $ tokens ->consumeTokenType (Lexer::TOKEN_COLON );
228+
229+ $ elseType = $ this ->parseAtomic ($ tokens );
230+
231+ return new Ast \Type \ConditionalTypeForParameterNode ($ parameterName , $ targetType , $ ifType , $ elseType , $ negated );
232+ }
233+
234+
160235 /** @phpstan-impure */
161236 private function parseNullable (TokenIterator $ tokens ): Ast \Type \TypeNode
162237 {
0 commit comments