Skip to content

Commit 2ab3f72

Browse files
committed
TASK: Refactor TypeReferenceParser
1 parent 2e86dca commit 2ab3f72

4 files changed

Lines changed: 76 additions & 37 deletions

File tree

src/Language/Parser/ParserException.php

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,9 @@ abstract class ParserException extends \Exception
2929
protected function __construct(
3030
int $code,
3131
string $message,
32-
public readonly Range $affectedRangeInSource,
32+
public readonly ?Range $affectedRangeInSource = null,
3333
?\Exception $cause = null
3434
) {
35-
$message = sprintf(
36-
'[%s] %s',
37-
$affectedRangeInSource->start->toDebugString(),
38-
$message
39-
);
40-
4135
parent::__construct($message, $code, $cause);
4236
}
4337
}

src/Language/Parser/TypeReference/TypeReferenceCouldNotBeParsed.php

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,36 @@
2222

2323
namespace PackageFactory\ComponentEngine\Language\Parser\TypeReference;
2424

25+
use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeNameNodes;
2526
use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeReferenceNode;
2627
use PackageFactory\ComponentEngine\Language\Parser\ParserException;
27-
use PackageFactory\ComponentEngine\Parser\Source\Range;
2828

2929
final class TypeReferenceCouldNotBeParsed extends ParserException
3030
{
3131
public static function becauseOfInvalidTypeReferenceNode(
32-
InvalidTypeReferenceNode $cause,
33-
Range $affectedRangeInSource
32+
InvalidTypeReferenceNode $cause
3433
): self {
3534
return new self(
3635
code: 1690542466,
3736
message: sprintf(
3837
'TypeReferenceNode could not be parsed, because the result would be invalid: %s',
3938
$cause->getMessage()
4039
),
41-
affectedRangeInSource: $affectedRangeInSource,
40+
affectedRangeInSource: $cause->attributesOfAffectedNode?->rangeInSource ?? null,
41+
cause: $cause
42+
);
43+
}
44+
45+
public static function becauseOfInvalidTypeTypeNameNodes(
46+
InvalidTypeNameNodes $cause
47+
): self {
48+
return new self(
49+
code: 1690833898,
50+
message: sprintf(
51+
'TypeReferenceNode could not be parsed, because the list of type names was invalid: %s',
52+
$cause->getMessage()
53+
),
54+
affectedRangeInSource: $cause->attributesOfAffectedNode?->rangeInSource ?? null,
4255
cause: $cause
4356
);
4457
}

src/Language/Parser/TypeReference/TypeReferenceParser.php

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
namespace PackageFactory\ComponentEngine\Language\Parser\TypeReference;
2424

2525
use PackageFactory\ComponentEngine\Domain\TypeName\TypeName;
26+
use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeNameNodes;
2627
use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeReferenceNode;
2728
use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode;
2829
use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes;
@@ -66,10 +67,7 @@ public function parse(\Iterator $tokens): TypeReferenceNode
6667
isOptional: $isOptional
6768
);
6869
} catch (InvalidTypeReferenceNode $e) {
69-
throw TypeReferenceCouldNotBeParsed::becauseOfInvalidTypeReferenceNode(
70-
cause: $e,
71-
affectedRangeInSource: $rangeInSource
72-
);
70+
throw TypeReferenceCouldNotBeParsed::becauseOfInvalidTypeReferenceNode($e);
7371
}
7472
}
7573

@@ -97,31 +95,40 @@ public function parseTypeNames(\Iterator $tokens): TypeNameNodes
9795
{
9896
$items = [];
9997
while (true) {
100-
Scanner::assertType($tokens, TokenType::STRING);
101-
102-
$typeNameToken = $tokens->current();
103-
$items[] = new TypeNameNode(
104-
attributes: new NodeAttributes(
105-
rangeInSource: $typeNameToken->boundaries
106-
),
107-
value: TypeName::from($typeNameToken->value)
108-
);
98+
$items[] = $this->parseTypeName($tokens);
10999

110-
Scanner::skipOne($tokens);
111-
112-
if (Scanner::isEnd($tokens)) {
100+
if (Scanner::isEnd($tokens) || Scanner::type($tokens) !== TokenType::PIPE) {
113101
break;
114102
}
115103

116-
if (Scanner::type($tokens) === TokenType::PIPE) {
117-
Scanner::skipOne($tokens);
118-
continue;
119-
}
104+
Scanner::skipOne($tokens);
105+
}
120106

121-
break;
107+
try {
108+
return new TypeNameNodes(...$items);
109+
} catch (InvalidTypeNameNodes $e) {
110+
throw TypeReferenceCouldNotBeParsed::becauseOfInvalidTypeTypeNameNodes($e);
122111
}
112+
}
113+
114+
/**
115+
* @param \Iterator<mixed,Token> $tokens
116+
* @return TypeNameNode
117+
*/
118+
public function parseTypeName(\Iterator $tokens): TypeNameNode
119+
{
120+
Scanner::assertType($tokens, TokenType::STRING);
121+
122+
$typeNameToken = $tokens->current();
123123

124-
return new TypeNameNodes(...$items);
124+
Scanner::skipOne($tokens);
125+
126+
return new TypeNameNode(
127+
attributes: new NodeAttributes(
128+
rangeInSource: $typeNameToken->boundaries
129+
),
130+
value: TypeName::from($typeNameToken->value)
131+
);
125132
}
126133

127134
/**

test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
use PackageFactory\ComponentEngine\Domain\TypeName\TypeName;
2626
use PackageFactory\ComponentEngine\Domain\TypeName\TypeNames;
27+
use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeNameNodes;
2728
use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeReferenceNode;
2829
use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode;
2930
use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes;
@@ -221,10 +222,34 @@ public function throwsParserExceptionWhenInvalidTypeReferenceOccurs(): void
221222
new Position(0, 4)
222223
)
223224
),
224-
),
225-
affectedRangeInSource: Range::from(
226-
new Position(0, 0),
227-
new Position(0, 4)
225+
)
226+
)
227+
);
228+
229+
$typeReferenceParser->parse($tokens);
230+
}
231+
232+
/**
233+
* @test
234+
*/
235+
public function throwsParserExceptionWhenDuplicatesOccur(): void
236+
{
237+
$typeReferenceParser = new TypeReferenceParser();
238+
$tokens = Tokenizer::fromSource(Source::fromString('Foo|Bar|Foo|Baz'))->getIterator();
239+
240+
$this->expectException(ParserException::class);
241+
$this->expectExceptionObject(
242+
TypeReferenceCouldNotBeParsed::becauseOfInvalidTypeTypeNameNodes(
243+
cause: InvalidTypeNameNodes::becauseTheyContainDuplicates(
244+
duplicateTypeNameNode: new TypeNameNode(
245+
attributes: new NodeAttributes(
246+
rangeInSource: Range::from(
247+
new Position(0, 9),
248+
new Position(0, 11)
249+
)
250+
),
251+
value: TypeName::from('Foo')
252+
)
228253
)
229254
)
230255
);

0 commit comments

Comments
 (0)