| 
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' => PseudoTypes\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);  | 
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): 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