@@ -39,12 +39,37 @@ public function parse(TokenIterator $tokens): Ast\Type\TypeNode
39
39
return $ type ;
40
40
}
41
41
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
+
42
67
43
68
/** @phpstan-impure */
44
69
private function parseAtomic (TokenIterator $ tokens ): Ast \Type \TypeNode
45
70
{
46
71
if ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_OPEN_PARENTHESES )) {
47
- $ type = $ this ->parse ($ tokens );
72
+ $ type = $ this ->subParse ($ tokens );
48
73
$ tokens ->consumeTokenType (Lexer::TOKEN_CLOSE_PARENTHESES );
49
74
50
75
if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_OPEN_SQUARE_BRACKET )) {
@@ -157,6 +182,56 @@ private function parseIntersection(TokenIterator $tokens, Ast\Type\TypeNode $typ
157
182
}
158
183
159
184
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
+
160
235
/** @phpstan-impure */
161
236
private function parseNullable (TokenIterator $ tokens ): Ast \Type \TypeNode
162
237
{
0 commit comments