Skip to content

Commit 17cadd3

Browse files
committed
Improve exceptions
1 parent cccfd69 commit 17cadd3

14 files changed

Lines changed: 345 additions & 93 deletions

src/Exception/Definition/Template/MissingTemplateArgumentsException.php

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@
1111
*/
1212
class MissingTemplateArgumentsException extends TemplateArgumentsCountException
1313
{
14+
public const ERROR_CODE_COUNT = 0x01;
15+
public const ERROR_CODE_GREATER_THAN = 0x02;
16+
1417
/**
1518
* @param int<0, max> $minArgumentsCount
1619
*/
17-
public static function becauseNoRequiredArgument(
20+
public static function becauseArgumentsCountRequired(
1821
int $minArgumentsCount,
1922
NamedTypeNode $type,
2023
?\Throwable $previous = null,
@@ -33,6 +36,34 @@ public static function becauseNoRequiredArgument(
3336
expectedArgumentsCount: $minArgumentsCount,
3437
type: $type,
3538
template: $template,
39+
code: self::ERROR_CODE_COUNT,
40+
previous: $previous,
41+
);
42+
}
43+
44+
/**
45+
* @param int<0, max> $minArgumentsCount
46+
*/
47+
public static function becauseArgumentsCountLessThan(
48+
int $minArgumentsCount,
49+
NamedTypeNode $type,
50+
?\Throwable $previous = null,
51+
): self {
52+
$passedArgumentsCount = $type->arguments?->count() ?? 0;
53+
54+
assert($passedArgumentsCount > $minArgumentsCount, new \InvalidArgumentException(
55+
'Semantic Violation: Passed type`s argument count should be less than min bound',
56+
));
57+
58+
$template = 'Type "{{type}}" accepts no more than {{expectedArgumentsCount}}'
59+
. ' template argument(s), but {{passedArgumentsCount}} were passed';
60+
61+
return new self(
62+
passedArgumentsCount: $passedArgumentsCount,
63+
expectedArgumentsCount: $minArgumentsCount,
64+
type: $type,
65+
template: $template,
66+
code: self::ERROR_CODE_GREATER_THAN,
3667
previous: $previous,
3768
);
3869
}

src/Exception/Definition/Template/MissingTemplateArgumentsInRangeException.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class MissingTemplateArgumentsInRangeException extends TemplateArgumentsInRangeE
1515
* @param int<0, max> $minArgumentsCount
1616
* @param int<1, max> $maxArgumentsCount
1717
*/
18-
public static function becauseNoRequiredArgument(
18+
public static function becauseArgumentsCountRequired(
1919
int $minArgumentsCount,
2020
int $maxArgumentsCount,
2121
NamedTypeNode $type,

src/Exception/Definition/Template/OneOfTemplateArgumentsCountException.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public static function becauseArgumentsCountDoesNotMatch(
4141
NamedTypeNode $type,
4242
?\Throwable $previous = null,
4343
): self {
44+
/** @phpstan-ignore-next-line : Additional DbC precondition */
4445
assert(\count($variants) !== 0, new \InvalidArgumentException(
4546
'Semantic Violation: Argument variants should be greater than 0',
4647
));

src/Exception/Definition/Template/TooManyTemplateArgumentsException.php

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,59 @@
1111
*/
1212
class TooManyTemplateArgumentsException extends TemplateArgumentsCountException
1313
{
14+
public const ERROR_CODE_COUNT = 0x01;
15+
public const ERROR_CODE_LESS_THAN = 0x02;
16+
17+
/**
18+
* @param int<0, max> $expectedArgumentsCount
19+
*/
20+
public static function becauseArgumentsCountRequired(
21+
int $expectedArgumentsCount,
22+
NamedTypeNode $type,
23+
?\Throwable $previous = null,
24+
): self {
25+
$passedArgumentsCount = $type->arguments?->count() ?? 0;
26+
27+
assert($passedArgumentsCount > $expectedArgumentsCount, new \InvalidArgumentException(
28+
'Semantic Violation: Passed type`s argument count should be greater than expected',
29+
));
30+
31+
$template = 'Type "{{type}}" only accepts {{expectedArgumentsCount}}'
32+
. ' template argument(s), but {{passedArgumentsCount}} were passed';
33+
34+
return new self(
35+
passedArgumentsCount: $passedArgumentsCount,
36+
expectedArgumentsCount: $expectedArgumentsCount,
37+
type: $type,
38+
template: $template,
39+
code: self::ERROR_CODE_COUNT,
40+
previous: $previous,
41+
);
42+
}
43+
1444
/**
1545
* @param int<0, max> $maxArgumentsCount
1646
*/
17-
public static function becauseHasRedundantArgument(
47+
public static function becauseArgumentsCountLessThan(
1848
int $maxArgumentsCount,
1949
NamedTypeNode $type,
2050
?\Throwable $previous = null,
2151
): self {
2252
$passedArgumentsCount = $type->arguments?->count() ?? 0;
2353

24-
assert($passedArgumentsCount > $maxArgumentsCount, new \InvalidArgumentException(
54+
assert($passedArgumentsCount < $maxArgumentsCount, new \InvalidArgumentException(
2555
'Semantic Violation: Passed type`s argument count should be greater than max bound',
2656
));
2757

28-
$template = 'Type "{{type}}" only accepts {{expectedArgumentsCount}}'
58+
$template = 'Type "{{type}}" accepts at least {{expectedArgumentsCount}}'
2959
. ' template argument(s), but {{passedArgumentsCount}} were passed';
3060

3161
return new self(
3262
passedArgumentsCount: $passedArgumentsCount,
3363
expectedArgumentsCount: $maxArgumentsCount,
3464
type: $type,
3565
template: $template,
66+
code: self::ERROR_CODE_LESS_THAN,
3667
previous: $previous,
3768
);
3869
}

src/Exception/Definition/Template/TooManyTemplateArgumentsInRangeException.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,11 @@
1111
*/
1212
class TooManyTemplateArgumentsInRangeException extends TemplateArgumentsInRangeException
1313
{
14-
public const ERROR_CODE_IN_RANGE = 0x01;
15-
1614
/**
1715
* @param int<0, max> $minArgumentsCount
1816
* @param int<1, max> $maxArgumentsCount
1917
*/
20-
public static function becauseHasRedundantArgument(
18+
public static function becauseArgumentsCountRequired(
2119
int $minArgumentsCount,
2220
int $maxArgumentsCount,
2321
NamedTypeNode $type,
@@ -43,7 +41,6 @@ public static function becauseHasRedundantArgument(
4341
maxArgumentsCount: $maxArgumentsCount,
4442
type: $type,
4543
template: $template,
46-
code: self::ERROR_CODE_IN_RANGE,
4744
previous: $previous,
4845
);
4946
}

src/Type/Builder/Assert.php

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TypeLang\Mapper\Type\Builder;
6+
7+
use TypeLang\Mapper\Exception\Definition\Template\Hint\TemplateArgumentHintsNotSupportedException;
8+
use TypeLang\Mapper\Exception\Definition\Template\MissingTemplateArgumentsException;
9+
use TypeLang\Mapper\Exception\Definition\Template\MissingTemplateArgumentsInRangeException;
10+
use TypeLang\Mapper\Exception\Definition\Template\TemplateArgumentsNotSupportedException;
11+
use TypeLang\Mapper\Exception\Definition\Template\TooManyTemplateArgumentsException;
12+
use TypeLang\Mapper\Exception\Definition\Template\TooManyTemplateArgumentsInRangeException;
13+
use TypeLang\Parser\Node\Stmt\NamedTypeNode;
14+
use TypeLang\Parser\Node\Stmt\Template\TemplateArgumentNode;
15+
16+
final class Assert
17+
{
18+
/**
19+
* @throws TemplateArgumentsNotSupportedException
20+
*/
21+
public static function expectNoTemplateArguments(NamedTypeNode $stmt): void
22+
{
23+
if ($stmt->arguments === null) {
24+
return;
25+
}
26+
27+
throw TemplateArgumentsNotSupportedException::becauseTooManyArguments($stmt);
28+
}
29+
30+
/**
31+
* @throws TooManyTemplateArgumentsException
32+
* @throws MissingTemplateArgumentsException
33+
* @throws TemplateArgumentsNotSupportedException
34+
* @throws TooManyTemplateArgumentsInRangeException
35+
* @throws MissingTemplateArgumentsInRangeException
36+
*/
37+
public static function expectTemplateArgumentsCountInRange(NamedTypeNode $stmt, int $from, int $to): void
38+
{
39+
$from = \max(0, $from);
40+
$to = \max(0, $to);
41+
42+
if ($from === $to) {
43+
self::expectTemplateArgumentsCount($stmt, $from);
44+
45+
return;
46+
}
47+
48+
if ($from > $to) {
49+
[$from, $to] = [$to, $from];
50+
}
51+
52+
if ($from < 1) {
53+
self::expectTemplateArgumentsCountLessOrEqualThan($stmt, $to);
54+
55+
return;
56+
}
57+
58+
$actualArgumentsCount = $stmt->arguments?->count() ?? 0;
59+
60+
/** @var int<1, max> $to */
61+
if ($actualArgumentsCount > $to) {
62+
throw TooManyTemplateArgumentsInRangeException::becauseArgumentsCountRequired($from, $to, $stmt);
63+
}
64+
65+
if ($actualArgumentsCount < $from) {
66+
throw MissingTemplateArgumentsInRangeException::becauseArgumentsCountRequired($from, $to, $stmt);
67+
}
68+
}
69+
70+
/**
71+
* @throws TooManyTemplateArgumentsException
72+
* @throws MissingTemplateArgumentsException
73+
* @throws TemplateArgumentsNotSupportedException
74+
*/
75+
public static function expectTemplateArgumentsCount(NamedTypeNode $stmt, int $count): void
76+
{
77+
if ($count < 1) {
78+
self::expectNoTemplateArguments($stmt);
79+
80+
return;
81+
}
82+
83+
if (($stmt->arguments?->count() ?? 0) > $count) {
84+
throw TooManyTemplateArgumentsException::becauseArgumentsCountRequired($count, $stmt);
85+
}
86+
87+
throw MissingTemplateArgumentsException::becauseArgumentsCountRequired($count, $stmt);
88+
}
89+
90+
/**
91+
* @throws TooManyTemplateArgumentsException
92+
*/
93+
public static function expectTemplateArgumentsCountGreaterThan(NamedTypeNode $stmt, int $count): void
94+
{
95+
self::expectTemplateArgumentsCountGreaterOrEqualThan($stmt, $count + 1);
96+
}
97+
98+
/**
99+
* @throws TooManyTemplateArgumentsException
100+
*/
101+
public static function expectTemplateArgumentsCountGreaterOrEqualThan(NamedTypeNode $stmt, int $count): void
102+
{
103+
$actualArgumentsCount = $stmt->arguments?->count() ?? 0;
104+
105+
if ($count <= $actualArgumentsCount) {
106+
return;
107+
}
108+
109+
throw TooManyTemplateArgumentsException::becauseArgumentsCountLessThan($count, $stmt);
110+
}
111+
112+
/**
113+
* @throws MissingTemplateArgumentsException
114+
*/
115+
public static function expectTemplateArgumentsCountLessThan(NamedTypeNode $stmt, int $count): void
116+
{
117+
self::expectTemplateArgumentsCountLessOrEqualThan($stmt, $count - 1);
118+
}
119+
120+
/**
121+
* @throws MissingTemplateArgumentsException
122+
* @throws TemplateArgumentsNotSupportedException
123+
*/
124+
public static function expectTemplateArgumentsCountLessOrEqualThan(NamedTypeNode $stmt, int $count): void
125+
{
126+
if ($count < 1) {
127+
self::expectNoTemplateArguments($stmt);
128+
129+
return;
130+
}
131+
132+
$actualArgumentsCount = $stmt->arguments?->count() ?? 0;
133+
134+
if ($count >= $actualArgumentsCount) {
135+
return;
136+
}
137+
138+
throw MissingTemplateArgumentsException::becauseArgumentsCountLessThan($count, $stmt);
139+
}
140+
141+
/**
142+
* @throws TemplateArgumentHintsNotSupportedException
143+
*/
144+
public static function expectNoTemplateArgumentHints(NamedTypeNode $stmt, TemplateArgumentNode $argument): void
145+
{
146+
// Skip in case of argument is not a part of type
147+
if (!\in_array($argument, $stmt->arguments->items ?? [], true)) {
148+
return;
149+
}
150+
151+
if ($argument->hint === null) {
152+
return;
153+
}
154+
155+
throw TemplateArgumentHintsNotSupportedException::becauseTooManyHints(
156+
argument: $argument,
157+
type: $stmt,
158+
);
159+
}
160+
161+
/**
162+
* @throws TemplateArgumentHintsNotSupportedException
163+
*/
164+
public static function expectNoAnyTemplateArgumentsHints(NamedTypeNode $stmt): void
165+
{
166+
foreach ($stmt->arguments->items ?? [] as $argument) {
167+
self::expectNoTemplateArgumentHints($stmt, $argument);
168+
}
169+
}
170+
}

0 commit comments

Comments
 (0)