@@ -210,6 +210,7 @@ final class TypeExpression
210
210
211
211
private bool $ isUnionType ;
212
212
213
+ /** @var '&'|'|' */
213
214
private string $ typesGlue ;
214
215
215
216
/** @var list<array{start_index: int, expression: self}> */
@@ -257,6 +258,9 @@ public function isUnionType(): bool
257
258
return $ this ->isUnionType ;
258
259
}
259
260
261
+ /**
262
+ * @return '&'|'|'
263
+ */
260
264
public function getTypesGlue (): string
261
265
{
262
266
return $ this ->typesGlue ;
@@ -392,12 +396,13 @@ public function allowsNull(): bool
392
396
393
397
private function parse (): void
394
398
{
395
- $ typesGlue = null ;
399
+ $ seenGlues = null ;
400
+ $ innerValues = [];
396
401
397
402
$ index = 0 ;
398
403
while (true ) {
399
404
Preg::match (
400
- '{\G ' .self ::REGEX_TYPE .'(?: \h*(?<glue>[|&])\h*|$)} ' ,
405
+ '{\G ' .self ::REGEX_TYPE .'(?<glue_raw> \h*(?<glue>[|&])\h*(?!$) |$)} ' ,
401
406
$ this ->value ,
402
407
$ matches ,
403
408
PREG_OFFSET_CAPTURE ,
@@ -408,17 +413,24 @@ private function parse(): void
408
413
throw new \Exception ('Unable to parse phpdoc type ' .var_export ($ this ->value , true ));
409
414
}
410
415
411
- if (null === $ typesGlue ) {
416
+ if (null === $ seenGlues ) {
412
417
if (($ matches ['glue ' ][0 ] ?? '' ) === '' ) {
413
418
break ;
414
419
}
415
420
416
- $ typesGlue = $ matches [ ' glue ' ][ 0 ];
421
+ $ seenGlues = [ ' | ' => false , ' & ' => false ];
417
422
}
418
423
419
- $ this ->innerTypeExpressions [] = [
424
+ if (($ matches ['glue ' ][0 ] ?? '' ) !== '' ) {
425
+ \assert (isset ($ seenGlues [$ matches ['glue ' ][0 ]]));
426
+ $ seenGlues [$ matches ['glue ' ][0 ]] = true ;
427
+ }
428
+
429
+ $ innerValues [] = [
420
430
'start_index ' => $ index ,
421
- 'expression ' => $ this ->inner ($ matches ['type ' ][0 ]),
431
+ 'value ' => $ matches ['type ' ][0 ],
432
+ 'next_glue ' => $ matches ['glue ' ][0 ] ?? null ,
433
+ 'next_glue_raw ' => $ matches ['glue_raw ' ][0 ] ?? null ,
422
434
];
423
435
424
436
$ consumedValueLength = \strlen ($ matches [0 ][0 ]);
@@ -427,8 +439,41 @@ private function parse(): void
427
439
if (\strlen ($ this ->value ) <= $ index ) {
428
440
\assert (\strlen ($ this ->value ) === $ index );
429
441
442
+ $ seenGlues = array_filter ($ seenGlues );
443
+ \assert ([] !== $ seenGlues );
444
+
430
445
$ this ->isUnionType = true ;
431
- $ this ->typesGlue = $ typesGlue ;
446
+ $ this ->typesGlue = array_key_first ($ seenGlues );
447
+
448
+ if (1 === \count ($ seenGlues )) {
449
+ foreach ($ innerValues as $ innerValue ) {
450
+ $ this ->innerTypeExpressions [] = [
451
+ 'start_index ' => $ innerValue ['start_index ' ],
452
+ 'expression ' => $ this ->inner ($ innerValue ['value ' ]),
453
+ ];
454
+ }
455
+ } else {
456
+ for ($ i = 0 ; $ i < \count ($ innerValues ); ++$ i ) {
457
+ $ innerStartIndex = $ innerValues [$ i ]['start_index ' ];
458
+ $ innerValue = '' ;
459
+ while (true ) {
460
+ $ innerValue .= $ innerValues [$ i ]['value ' ];
461
+
462
+ if (($ innerValues [$ i ]['next_glue ' ] ?? $ this ->typesGlue ) === $ this ->typesGlue ) {
463
+ break ;
464
+ }
465
+
466
+ $ innerValue .= $ innerValues [$ i ]['next_glue_raw ' ];
467
+
468
+ ++$ i ;
469
+ }
470
+
471
+ $ this ->innerTypeExpressions [] = [
472
+ 'start_index ' => $ innerStartIndex ,
473
+ 'expression ' => $ this ->inner ($ innerValue ),
474
+ ];
475
+ }
476
+ }
432
477
433
478
return ;
434
479
}
0 commit comments