|  | 
| 15 | 15 | 
 | 
| 16 | 16 | use ArrayIterator; | 
| 17 | 17 | use InvalidArgumentException; | 
|  | 18 | +use phpDocumentor\Reflection\PseudoTypes\IntegerRange; | 
| 18 | 19 | use phpDocumentor\Reflection\PseudoTypes\List_; | 
| 19 | 20 | use phpDocumentor\Reflection\Types\Array_; | 
| 20 | 21 | use phpDocumentor\Reflection\Types\ArrayKey; | 
|  | 
| 40 | 41 | use function count; | 
| 41 | 42 | use function end; | 
| 42 | 43 | use function in_array; | 
|  | 44 | +use function is_numeric; | 
| 43 | 45 | use function key; | 
| 44 | 46 | use function preg_split; | 
| 45 | 47 | use function strpos; | 
| @@ -82,10 +84,12 @@ final class TypeResolver | 
| 82 | 84 |         'non-empty-lowercase-string' => PseudoTypes\NonEmptyLowercaseString::class, | 
| 83 | 85 |         'non-empty-string' => PseudoTypes\NonEmptyString::class, | 
| 84 | 86 |         'numeric-string' => PseudoTypes\NumericString::class, | 
|  | 87 | +        'numeric' => Types\Numeric::class, | 
| 85 | 88 |         'trait-string' => PseudoTypes\TraitString::class, | 
| 86 | 89 |         'int' => Types\Integer::class, | 
| 87 | 90 |         'integer' => Types\Integer::class, | 
| 88 | 91 |         'positive-int' => PseudoTypes\PositiveInteger::class, | 
|  | 92 | +        'negative-int' => PseudoTypes\NegativeInteger::class, | 
| 89 | 93 |         'bool' => Types\Boolean::class, | 
| 90 | 94 |         'boolean' => Types\Boolean::class, | 
| 91 | 95 |         'real' => Types\Float_::class, | 
| @@ -257,6 +261,8 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser | 
| 257 | 261 |                 if ($classType !== null) { | 
| 258 | 262 |                     if ((string) $classType === 'class-string') { | 
| 259 | 263 |                         $types[] = $this->resolveClassString($tokens, $context); | 
|  | 264 | +                    } elseif ((string) $classType === 'int') { | 
|  | 265 | +                        $types[] = $this->resolveIntRange($tokens, $context); | 
| 260 | 266 |                     } elseif ((string) $classType === 'interface-string') { | 
| 261 | 267 |                         $types[] = $this->resolveInterfaceString($tokens, $context); | 
| 262 | 268 |                     } else { | 
| @@ -479,6 +485,75 @@ private function resolveClassString(ArrayIterator $tokens, Context $context): Ty | 
| 479 | 485 |         return new ClassString($classType->getFqsen()); | 
| 480 | 486 |     } | 
| 481 | 487 | 
 | 
|  | 488 | +    /** | 
|  | 489 | +     * Resolves integer ranges | 
|  | 490 | +     * | 
|  | 491 | +     * @param ArrayIterator<int, (string|null)> $tokens | 
|  | 492 | +     */ | 
|  | 493 | +    private function resolveIntRange(ArrayIterator $tokens, Context $context): Type | 
|  | 494 | +    { | 
|  | 495 | +        $tokens->next(); | 
|  | 496 | + | 
|  | 497 | +        $token = ''; | 
|  | 498 | +        $minValue = null; | 
|  | 499 | +        $maxValue = null; | 
|  | 500 | +        $commaFound = false; | 
|  | 501 | +        $tokenCounter = 0; | 
|  | 502 | +        while ($tokens->valid()) { | 
|  | 503 | +            $tokenCounter++; | 
|  | 504 | +            $token = $tokens->current(); | 
|  | 505 | +            if ($token === null) { | 
|  | 506 | +                throw new RuntimeException( | 
|  | 507 | +                    'Unexpected nullable character' | 
|  | 508 | +                ); | 
|  | 509 | +            } | 
|  | 510 | + | 
|  | 511 | +            $token = trim($token); | 
|  | 512 | + | 
|  | 513 | +            if ($token === '>') { | 
|  | 514 | +                break; | 
|  | 515 | +            } | 
|  | 516 | + | 
|  | 517 | +            if ($token === ',') { | 
|  | 518 | +                $commaFound = true; | 
|  | 519 | +            } | 
|  | 520 | + | 
|  | 521 | +            if ($commaFound === false && $minValue === null) { | 
|  | 522 | +                if (is_numeric($token) || $token === 'max' || $token === 'min') { | 
|  | 523 | +                    $minValue = $token; | 
|  | 524 | +                } | 
|  | 525 | +            } | 
|  | 526 | + | 
|  | 527 | +            if ($commaFound === true && $maxValue === null) { | 
|  | 528 | +                if (is_numeric($token) || $token === 'max' || $token === 'min') { | 
|  | 529 | +                    $maxValue = $token; | 
|  | 530 | +                } | 
|  | 531 | +            } | 
|  | 532 | + | 
|  | 533 | +            $tokens->next(); | 
|  | 534 | +        } | 
|  | 535 | + | 
|  | 536 | +        if ($token !== '>') { | 
|  | 537 | +            if (empty($token)) { | 
|  | 538 | +                throw new RuntimeException( | 
|  | 539 | +                    'interface-string: ">" is missing' | 
|  | 540 | +                ); | 
|  | 541 | +            } | 
|  | 542 | + | 
|  | 543 | +            throw new RuntimeException( | 
|  | 544 | +                'Unexpected character "' . $token . '", ">" is missing' | 
|  | 545 | +            ); | 
|  | 546 | +        } | 
|  | 547 | + | 
|  | 548 | +        if (!$minValue || !$maxValue || $tokenCounter > 4) { | 
|  | 549 | +            throw new RuntimeException( | 
|  | 550 | +                'int<min,max> has not the correct format' | 
|  | 551 | +            ); | 
|  | 552 | +        } | 
|  | 553 | + | 
|  | 554 | +        return new IntegerRange($minValue, $maxValue); | 
|  | 555 | +    } | 
|  | 556 | + | 
| 482 | 557 |     /** | 
| 483 | 558 |      * Resolves class string | 
| 484 | 559 |      * | 
|  | 
0 commit comments