16
16
use ArrayIterator ;
17
17
use InvalidArgumentException ;
18
18
use phpDocumentor \Reflection \Types \Array_ ;
19
+ use phpDocumentor \Reflection \Types \Expression_ ;
19
20
use phpDocumentor \Reflection \Types \ClassString ;
20
21
use phpDocumentor \Reflection \Types \Collection ;
21
22
use phpDocumentor \Reflection \Types \Compound ;
@@ -134,9 +135,9 @@ public function resolve(string $type, ?Context $context = null) : Type
134
135
$ context = new Context ('' );
135
136
}
136
137
137
- // split the type string into tokens `|`, `?`, `<`, `>`, `,`, `(`, `)[]`, '<', '>' and type names
138
+ // split the type string into tokens `|`, `?`, `<`, `>`, `,`, `(`, `)`, ` []`, '<', '>' and type names
138
139
$ tokens = preg_split (
139
- '/( \\|| \\?|<|>|, ?| \\(| \\)(?: \\[ \\]) +)/ ' ,
140
+ '/( \\|| \\?|<|>|&| , ?| \\(| \\)| \\[ \\]+)/ ' ,
140
141
$ type ,
141
142
-1 ,
142
143
PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE
@@ -163,6 +164,7 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser
163
164
{
164
165
$ types = [];
165
166
$ token = '' ;
167
+ $ compoundToken = '| ' ;
166
168
while ($ tokens ->valid ()) {
167
169
$ token = $ tokens ->current ();
168
170
if ($ token === null ) {
@@ -171,7 +173,7 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser
171
173
);
172
174
}
173
175
174
- if ($ token === '| ' ) {
176
+ if ($ token === '| ' || $ token === ' & ' ) {
175
177
if (count ($ types ) === 0 ) {
176
178
throw new RuntimeException (
177
179
'A type is missing before a type separator '
@@ -189,6 +191,7 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser
189
191
);
190
192
}
191
193
194
+ $ compoundToken = $ token ;
192
195
$ tokens ->next ();
193
196
} elseif ($ token === '? ' ) {
194
197
if (!in_array ($ parserContext , [
@@ -209,22 +212,16 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser
209
212
$ tokens ->next ();
210
213
$ type = $ this ->parseTypes ($ tokens , $ context , self ::PARSER_IN_ARRAY_EXPRESSION );
211
214
212
- $ resolvedType = new Array_ ($ type );
213
-
214
215
$ token = $ tokens ->current ();
215
- // Someone did not properly close their array expression ..
216
- if ($ token === null ) {
216
+ if ($ token === null ) { // Someone did not properly close their array expression ..
217
217
break ;
218
218
}
219
219
220
- // we generate arrays corresponding to the number of '[]' after the ')'
221
- $ numberOfArrays = (strlen ($ token ) - 1 ) / 2 ;
222
- for ($ i = 0 ; $ i < $ numberOfArrays - 1 ; ++$ i ) {
223
- $ resolvedType = new Array_ ($ resolvedType );
224
- }
220
+ $ tokens ->next ();
221
+
222
+ $ resolvedType = new Expression_ ($ type );
225
223
226
224
$ types [] = $ resolvedType ;
227
- $ tokens ->next ();
228
225
} elseif ($ parserContext === self ::PARSER_IN_ARRAY_EXPRESSION && $ token [0 ] === ') ' ) {
229
226
break ;
230
227
} elseif ($ token === '< ' ) {
@@ -248,6 +245,16 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser
248
245
&& ($ token === '> ' || trim ($ token ) === ', ' )
249
246
) {
250
247
break ;
248
+ } elseif ($ token === self ::OPERATOR_ARRAY ) {
249
+ end ($ types );
250
+ $ last = key ($ types );
251
+ $ lastItem = $ types [$ last ];
252
+ if ($ lastItem instanceof Expression_) {
253
+ $ lastItem = $ lastItem ->getValueType ();
254
+ }
255
+ $ types [$ last ] = new Array_ ($ lastItem );
256
+
257
+ $ tokens ->next ();
251
258
} else {
252
259
$ type = $ this ->resolveSingleType ($ token , $ context );
253
260
$ tokens ->next ();
@@ -259,7 +266,7 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser
259
266
}
260
267
}
261
268
262
- if ($ token === '| ' ) {
269
+ if ($ token === '| ' || $ token === ' & ' ) {
263
270
throw new RuntimeException (
264
271
'A type is missing after a type separator '
265
272
);
@@ -287,7 +294,7 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser
287
294
return $ types [0 ];
288
295
}
289
296
290
- return new Compound ($ types );
297
+ return new Compound ($ types, $ compoundToken );
291
298
}
292
299
293
300
/**
@@ -304,8 +311,6 @@ private function resolveSingleType(string $type, Context $context) : object
304
311
switch (true ) {
305
312
case $ this ->isKeyword ($ type ):
306
313
return $ this ->resolveKeyword ($ type );
307
- case $ this ->isTypedArray ($ type ):
308
- return $ this ->resolveTypedArray ($ type , $ context );
309
314
case $ this ->isFqsen ($ type ):
310
315
return $ this ->resolveTypedObject ($ type );
311
316
case $ this ->isPartialStructuralElementName ($ type ):
@@ -345,18 +350,6 @@ public function addKeyword(string $keyword, string $typeClassName) : void
345
350
$ this ->keywords [$ keyword ] = $ typeClassName ;
346
351
}
347
352
348
- /**
349
- * Detects whether the given type represents an array.
350
- *
351
- * @param string $type A relative or absolute type as defined in the phpDocumentor documentation.
352
- *
353
- * @psalm-pure
354
- */
355
- private function isTypedArray (string $ type ) : bool
356
- {
357
- return substr ($ type , -2 ) === self ::OPERATOR_ARRAY ;
358
- }
359
-
360
353
/**
361
354
* Detects whether the given type represents a PHPDoc keyword.
362
355
*
@@ -391,16 +384,6 @@ private function isFqsen(string $type) : bool
391
384
return strpos ($ type , self ::OPERATOR_NAMESPACE ) === 0 ;
392
385
}
393
386
394
- /**
395
- * Resolves the given typed array string (i.e. `string[]`) into an Array object with the right types set.
396
- *
397
- * @psalm-pure
398
- */
399
- private function resolveTypedArray (string $ type , Context $ context ) : Array_
400
- {
401
- return new Array_ ($ this ->resolveSingleType (substr ($ type , 0 , -2 ), $ context ));
402
- }
403
-
404
387
/**
405
388
* Resolves the given keyword (such as `string`) into a Type object representing that keyword.
406
389
*
0 commit comments