Skip to content

Commit 41172b8

Browse files
committed
Improve exceptions and add exception tests
1 parent 3df5e99 commit 41172b8

55 files changed

Lines changed: 1427 additions & 168 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/Exception/Definition/Shape/ShapeFieldException.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
namespace TypeLang\Mapper\Exception\Definition\Shape;
66

7+
use TypeLang\Parser\Node\Stmt\NamedTypeNode;
78
use TypeLang\Parser\Node\Stmt\Shape\FieldNode;
8-
use TypeLang\Parser\Node\Stmt\TypeStatement;
99

1010
/**
1111
* An exception associated with ONE specific shape field.
@@ -14,7 +14,7 @@ abstract class ShapeFieldException extends ShapeFieldsException
1414
{
1515
public function __construct(
1616
public readonly FieldNode $field,
17-
TypeStatement $type,
17+
NamedTypeNode $type,
1818
string $template,
1919
int $code = 0,
2020
?\Throwable $previous = null,

src/Exception/Definition/Shape/ShapeFieldsException.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,15 @@
55
namespace TypeLang\Mapper\Exception\Definition\Shape;
66

77
use TypeLang\Mapper\Exception\Definition\DefinitionException;
8+
use TypeLang\Parser\Node\Stmt\NamedTypeNode;
89

910
/**
1011
* An exception associated with ALL possible shape fields.
1112
*/
12-
abstract class ShapeFieldsException extends DefinitionException {}
13+
abstract class ShapeFieldsException extends DefinitionException
14+
{
15+
public function __construct(NamedTypeNode $type, string $template, int $code = 0, ?\Throwable $previous = null)
16+
{
17+
parent::__construct($type, $template, $code, $previous);
18+
}
19+
}

src/Exception/Definition/Shape/ShapeFieldsNotSupportedException.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44

55
namespace TypeLang\Mapper\Exception\Definition\Shape;
66

7-
use TypeLang\Parser\Node\Stmt\TypeStatement;
7+
use TypeLang\Parser\Node\Stmt\NamedTypeNode;
88

99
class ShapeFieldsNotSupportedException extends ShapeFieldsException
1010
{
11-
public static function becauseShapeFieldsNotSupported(
12-
TypeStatement $type,
11+
public static function becauseTooManyShapeFields(
12+
NamedTypeNode $type,
1313
?\Throwable $previous = null
1414
): self {
1515
$template = 'Type "{{type}}" does not support shape fields';

src/Exception/Definition/Template/Hint/TemplateArgumentHintException.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
namespace TypeLang\Mapper\Exception\Definition\Template\Hint;
66

77
use TypeLang\Parser\Node\Identifier;
8+
use TypeLang\Parser\Node\Stmt\NamedTypeNode;
89
use TypeLang\Parser\Node\Stmt\Template\TemplateArgumentNode;
9-
use TypeLang\Parser\Node\Stmt\TypeStatement;
1010

1111
/**
1212
* An exception associated with ONE specific template argument hint.
@@ -17,7 +17,7 @@ abstract class TemplateArgumentHintException extends TemplateArgumentHintsExcept
1717

1818
public function __construct(
1919
TemplateArgumentNode $argument,
20-
TypeStatement $type,
20+
NamedTypeNode $type,
2121
string $template,
2222
int $code = 0,
2323
?\Throwable $previous = null,

src/Exception/Definition/Template/Hint/TemplateArgumentHintsNotSupportedException.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,26 @@
44

55
namespace TypeLang\Mapper\Exception\Definition\Template\Hint;
66

7+
use TypeLang\Parser\Node\Stmt\NamedTypeNode;
78
use TypeLang\Parser\Node\Stmt\Template\TemplateArgumentNode;
8-
use TypeLang\Parser\Node\Stmt\TypeStatement;
99

1010
/**
11-
* Occurs when a type's template argument does not hints
11+
* Occurs when a type's template argument does not support hints
1212
*/
1313
class TemplateArgumentHintsNotSupportedException extends TemplateArgumentHintException
1414
{
15-
public static function becauseTemplateArgumentHintsNotSupported(
15+
public static function becauseTooManyHints(
1616
TemplateArgumentNode $argument,
17-
TypeStatement $type,
17+
NamedTypeNode $type,
1818
?\Throwable $previous = null
1919
): self {
2020
$template = 'Template argument #{{index}} ({{argument}}) of "{{type}}" does not support any hints, '
2121
. 'but "{{hint}}" were passed';
2222

23+
assert($argument->hint !== null, new \InvalidArgumentException(
24+
'Incorrect exception usage',
25+
));
26+
2327
return new self(
2428
argument: $argument,
2529
type: $type,

src/Exception/Definition/Template/InvalidTemplateArgumentException.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace TypeLang\Mapper\Exception\Definition\Template;
66

7+
use TypeLang\Parser\Node\Stmt\NamedTypeNode;
78
use TypeLang\Parser\Node\Stmt\Template\TemplateArgumentNode;
89
use TypeLang\Parser\Node\Stmt\TypeStatement;
910

@@ -23,7 +24,7 @@ public function __construct(
2324
*/
2425
public readonly TypeStatement $expected,
2526
TemplateArgumentNode $argument,
26-
TypeStatement $type,
27+
NamedTypeNode $type,
2728
string $template,
2829
int $code = 0,
2930
?\Throwable $previous = null,
@@ -39,10 +40,10 @@ public function __construct(
3940
);
4041
}
4142

42-
public static function becauseTemplateArgumentIsInvalid(
43-
TypeStatement $expected,
43+
public static function becauseTemplateArgumentMustBe(
4444
TemplateArgumentNode $argument,
45-
TypeStatement $type,
45+
TypeStatement $expected,
46+
NamedTypeNode $type,
4647
?\Throwable $previous = null,
4748
): self {
4849
$template = 'Passed template argument #{{index}} of type {{type}} must '

src/Exception/Definition/Template/MissingTemplateArgumentsException.php

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,28 @@
99
/**
1010
* Occurs when a type requires more template arguments to be specified than required
1111
*/
12-
class MissingTemplateArgumentsException extends TemplateArgumentsRangeException
12+
class MissingTemplateArgumentsException extends TemplateArgumentsCountException
1313
{
1414
/**
15-
* @param int<0, max> $minSupportedArgumentsCount
16-
* @param int<0, max> $maxSupportedArgumentsCount
15+
* @param int<0, max> $minArgumentsCount
1716
*/
18-
public static function becauseTemplateArgumentsRangeRequired(
19-
int $minSupportedArgumentsCount,
20-
int $maxSupportedArgumentsCount,
17+
public static function becauseNoRequiredArgument(
18+
int $minArgumentsCount,
2119
NamedTypeNode $type,
22-
?\Throwable $previous = null
20+
?\Throwable $previous = null,
2321
): self {
24-
$template = 'Type "{{type}}" expects at least %s template argument(s), '
25-
. 'but {{passedArgumentsCount}} were passed';
22+
$passedArgumentsCount = $type->arguments?->count() ?? 0;
2623

27-
$template = $minSupportedArgumentsCount === $maxSupportedArgumentsCount
28-
? \sprintf($template, '{{minSupportedArgumentsCount}}')
29-
: \sprintf($template, 'from {{minSupportedArgumentsCount}} to {{maxSupportedArgumentsCount}}');
24+
assert($passedArgumentsCount < $minArgumentsCount, new \InvalidArgumentException(
25+
'Incorrect exception usage',
26+
));
27+
28+
$template = 'Type "{{type}}" expects at least {{expectedArgumentsCount}}'
29+
. ' template argument(s), but {{passedArgumentsCount}} were passed';
3030

3131
return new self(
3232
passedArgumentsCount: $type->arguments?->count() ?? 0,
33-
minSupportedArgumentsCount: $minSupportedArgumentsCount,
34-
maxSupportedArgumentsCount: $maxSupportedArgumentsCount,
33+
expectedArgumentsCount: $minArgumentsCount,
3534
type: $type,
3635
template: $template,
3736
previous: $previous,
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TypeLang\Mapper\Exception\Definition\Template;
6+
7+
use TypeLang\Parser\Node\Stmt\NamedTypeNode;
8+
9+
/**
10+
* Occurs when a type requires more template arguments to be specified than required
11+
*
12+
* @deprecated TODO
13+
*/
14+
class MissingTemplateArgumentsInRangeException extends TemplateArgumentsInRangeException
15+
{
16+
/**
17+
* @param int<0, max> $minSupportedArgumentsCount
18+
* @param int<1, max> $maxSupportedArgumentsCount
19+
*/
20+
public static function becauseTemplateArgumentsRequired(
21+
int $minSupportedArgumentsCount,
22+
int $maxSupportedArgumentsCount,
23+
NamedTypeNode $type,
24+
?\Throwable $previous = null
25+
): self {
26+
$template = 'Type "{{type}}" expects at least %s template argument(s), '
27+
. 'but {{passedArgumentsCount}} were passed';
28+
29+
$template = $minSupportedArgumentsCount === $maxSupportedArgumentsCount
30+
? \sprintf($template, '{{minSupportedArgumentsCount}}')
31+
: \sprintf($template, 'from {{minSupportedArgumentsCount}} to {{maxSupportedArgumentsCount}}');
32+
33+
return new self(
34+
passedArgumentsCount: $type->arguments?->count() ?? 0,
35+
minSupportedArgumentsCount: $minSupportedArgumentsCount,
36+
maxSupportedArgumentsCount: $maxSupportedArgumentsCount,
37+
type: $type,
38+
template: $template,
39+
previous: $previous,
40+
);
41+
}
42+
43+
/**
44+
* @param int<1, max> $maxSupportedArgumentsCount
45+
*/
46+
public static function becauseNoMoreTemplateArguments(
47+
int $maxSupportedArgumentsCount,
48+
NamedTypeNode $type,
49+
?\Throwable $previous = null,
50+
): self {
51+
$template = 'Type "{{type}}" only accepts {{maxSupportedArgumentsCount}} template argument(s), '
52+
. 'but {{passedArgumentsCount}} were passed';
53+
54+
return new self(
55+
passedArgumentsCount: $type->arguments?->count() ?? 0,
56+
minSupportedArgumentsCount: 0,
57+
maxSupportedArgumentsCount: $maxSupportedArgumentsCount,
58+
type: $type,
59+
template: $template,
60+
previous: $previous,
61+
);
62+
}
63+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TypeLang\Mapper\Exception\Definition\Template;
6+
7+
use TypeLang\Parser\Node\Stmt\NamedTypeNode;
8+
9+
/**
10+
* Occurs when the number of arguments does not match one of the required
11+
*/
12+
class OneOfTemplateArgumentsCountException extends TemplateArgumentsException
13+
{
14+
public function __construct(
15+
/**
16+
* @var int<0, max>
17+
*/
18+
public readonly int $passedArgumentsCount,
19+
/**
20+
* @var list<int<0, max>>
21+
*/
22+
public readonly array $expectedArgumentCountVariants,
23+
NamedTypeNode $type,
24+
string $template,
25+
int $code = 0,
26+
?\Throwable $previous = null,
27+
) {
28+
parent::__construct(
29+
type: $type,
30+
template: $template,
31+
code: $code,
32+
previous: $previous,
33+
);
34+
}
35+
36+
/**
37+
* @param array<array-key, int<0, max>> $variants
38+
*/
39+
public static function becauseArgumentsCountDoesNotMatch(
40+
array $variants,
41+
NamedTypeNode $type,
42+
?\Throwable $previous = null,
43+
): self|TemplateArgumentsException {
44+
$passedArgumentsCount = $type->arguments?->count() ?? 0;
45+
46+
assert(!\in_array($passedArgumentsCount, $variants, true), new \InvalidArgumentException(
47+
'Incorrect exception usage',
48+
));
49+
50+
$simplified = self::simplifyException($variants, $type, $previous);
51+
52+
if ($simplified !== null) {
53+
return $simplified;
54+
}
55+
56+
$template = 'Type "{{type}}" only accepts {{expectedArgumentCountVariants}}'
57+
. ' template argument(s), but {{passedArgumentsCount}} were passed';
58+
59+
return new self(
60+
passedArgumentsCount: $passedArgumentsCount,
61+
expectedArgumentCountVariants: \array_values($variants),
62+
type: $type,
63+
template: $template,
64+
previous: $previous,
65+
);
66+
}
67+
68+
/**
69+
* @param array<array-key, int<0, max>> $variants
70+
*/
71+
private static function simplifyException(
72+
array $variants,
73+
NamedTypeNode $type,
74+
?\Throwable $previous = null,
75+
): ?TemplateArgumentsException {
76+
return match (\count($variants)) {
77+
0 => TemplateArgumentsNotSupportedException::becauseTooManyArguments($type),
78+
1 => ($expectedArgumentsCount = \reset($variants)) < ($type->arguments?->count() ?? 0)
79+
? TooManyTemplateArgumentsException::becauseHasRedundantArgument($expectedArgumentsCount, $type, $previous)
80+
: MissingTemplateArgumentsException::becauseNoRequiredArgument($expectedArgumentsCount, $type, $previous),
81+
default => null,
82+
};
83+
}
84+
}

src/Exception/Definition/Template/TemplateArgumentException.php

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
use TypeLang\Parser\Node\Stmt\NamedTypeNode;
88
use TypeLang\Parser\Node\Stmt\Template\TemplateArgumentNode;
9-
use TypeLang\Parser\Node\Stmt\TypeStatement;
109

1110
/**
1211
* An exception associated with ONE specific template argument.
@@ -20,27 +19,23 @@ abstract class TemplateArgumentException extends TemplateArgumentsException
2019

2120
public function __construct(
2221
public readonly TemplateArgumentNode $argument,
23-
TypeStatement $type,
22+
NamedTypeNode $type,
2423
string $template,
2524
int $code = 0,
2625
?\Throwable $previous = null,
2726
) {
28-
$this->index = self::fetchArgumentIndex($argument, $type);
27+
$this->index = self::getArgumentIndex($argument, $type);
2928

3029
parent::__construct($type, $template, $code, $previous);
3130
}
3231

3332
/**
3433
* @return int<0, max>
3534
*/
36-
private static function fetchArgumentIndex(TemplateArgumentNode $argument, TypeStatement $type): int
35+
private static function getArgumentIndex(TemplateArgumentNode $argument, NamedTypeNode $type): int
3736
{
3837
$index = 0;
3938

40-
if (!$type instanceof NamedTypeNode) {
41-
return $index;
42-
}
43-
4439
foreach ($type->arguments ?? [] as $actual) {
4540
if ($actual === $argument) {
4641
return $index + 1;

0 commit comments

Comments
 (0)