Skip to content

Commit 3b36546

Browse files
committed
Add parser attributes
1 parent 43def08 commit 3b36546

17 files changed

+179
-57
lines changed

resources/grammar.php

+39-23
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@
135135
new \Phplrt\Parser\Grammar\Concatenation([59]),
136136
new \Phplrt\Parser\Grammar\Optional(54),
137137
new \Phplrt\Parser\Grammar\Alternation([55, 56]),
138-
new \Phplrt\Parser\Grammar\Concatenation([144]),
138+
new \Phplrt\Parser\Grammar\Concatenation([154]),
139139
new \Phplrt\Parser\Grammar\Concatenation([67, 71, 72]),
140140
new \Phplrt\Parser\Grammar\Concatenation([86, 59]),
141141
new \Phplrt\Parser\Grammar\Lexeme('T_PARENTHESIS_OPEN', false),
@@ -194,7 +194,7 @@
194194
new \Phplrt\Parser\Grammar\Alternation([53, 99]),
195195
new \Phplrt\Parser\Grammar\Optional(115),
196196
new \Phplrt\Parser\Grammar\Concatenation([2, 116]),
197-
new \Phplrt\Parser\Grammar\Concatenation([145]),
197+
new \Phplrt\Parser\Grammar\Concatenation([155]),
198198
new \Phplrt\Parser\Grammar\Optional(121),
199199
new \Phplrt\Parser\Grammar\Concatenation([118, 119]),
200200
new \Phplrt\Parser\Grammar\Concatenation([124, 125, 126, 59, 127, 59]),
@@ -216,32 +216,42 @@
216216
new \Phplrt\Parser\Grammar\Lexeme('T_ATTR_OPEN', false),
217217
new \Phplrt\Parser\Grammar\Optional(136),
218218
new \Phplrt\Parser\Grammar\Lexeme('T_SQUARE_BRACKET_CLOSE', false),
219-
new \Phplrt\Parser\Grammar\Concatenation([2]),
219+
new \Phplrt\Parser\Grammar\Concatenation([2, 145]),
220220
new \Phplrt\Parser\Grammar\Lexeme('T_COMMA', false),
221221
new \Phplrt\Parser\Grammar\Concatenation([141, 140]),
222222
new \Phplrt\Parser\Grammar\Repetition(142, 0, INF),
223+
new \Phplrt\Parser\Grammar\Concatenation([150, 146, 151, 152, 153]),
224+
new \Phplrt\Parser\Grammar\Optional(144),
225+
new \Phplrt\Parser\Grammar\Concatenation([59]),
226+
new \Phplrt\Parser\Grammar\Lexeme('T_COMMA', false),
227+
new \Phplrt\Parser\Grammar\Concatenation([147, 146]),
228+
new \Phplrt\Parser\Grammar\Lexeme('T_COMMA', false),
229+
new \Phplrt\Parser\Grammar\Lexeme('T_PARENTHESIS_OPEN', false),
230+
new \Phplrt\Parser\Grammar\Repetition(148, 0, INF),
231+
new \Phplrt\Parser\Grammar\Optional(149),
232+
new \Phplrt\Parser\Grammar\Lexeme('T_PARENTHESIS_CLOSE', false),
223233
new \Phplrt\Parser\Grammar\Concatenation([123]),
224-
new \Phplrt\Parser\Grammar\Concatenation([146, 149]),
225-
new \Phplrt\Parser\Grammar\Concatenation([150, 153]),
234+
new \Phplrt\Parser\Grammar\Concatenation([156, 159]),
235+
new \Phplrt\Parser\Grammar\Concatenation([160, 163]),
226236
new \Phplrt\Parser\Grammar\Lexeme('T_OR', false),
227-
new \Phplrt\Parser\Grammar\Concatenation([147, 145]),
228-
new \Phplrt\Parser\Grammar\Optional(148),
229-
new \Phplrt\Parser\Grammar\Concatenation([154]),
237+
new \Phplrt\Parser\Grammar\Concatenation([157, 155]),
238+
new \Phplrt\Parser\Grammar\Optional(158),
239+
new \Phplrt\Parser\Grammar\Concatenation([164]),
230240
new \Phplrt\Parser\Grammar\Lexeme('T_AMP', false),
231-
new \Phplrt\Parser\Grammar\Concatenation([151, 146]),
232-
new \Phplrt\Parser\Grammar\Optional(152),
233-
new \Phplrt\Parser\Grammar\Alternation([157, 155]),
234-
new \Phplrt\Parser\Grammar\Concatenation([158, 162]),
241+
new \Phplrt\Parser\Grammar\Concatenation([161, 156]),
242+
new \Phplrt\Parser\Grammar\Optional(162),
243+
new \Phplrt\Parser\Grammar\Alternation([167, 165]),
244+
new \Phplrt\Parser\Grammar\Concatenation([168, 172]),
235245
new \Phplrt\Parser\Grammar\Lexeme('T_QMARK', true),
236-
new \Phplrt\Parser\Grammar\Concatenation([156, 155]),
237-
new \Phplrt\Parser\Grammar\Alternation([165, 29, 20, 66, 117]),
246+
new \Phplrt\Parser\Grammar\Concatenation([166, 165]),
247+
new \Phplrt\Parser\Grammar\Alternation([175, 29, 20, 66, 117]),
238248
new \Phplrt\Parser\Grammar\Lexeme('T_SQUARE_BRACKET_OPEN', true),
239249
new \Phplrt\Parser\Grammar\Lexeme('T_SQUARE_BRACKET_CLOSE', false),
240-
new \Phplrt\Parser\Grammar\Concatenation([159, 160]),
241-
new \Phplrt\Parser\Grammar\Repetition(161, 0, INF),
250+
new \Phplrt\Parser\Grammar\Concatenation([169, 170]),
251+
new \Phplrt\Parser\Grammar\Repetition(171, 0, INF),
242252
new \Phplrt\Parser\Grammar\Lexeme('T_PARENTHESIS_OPEN', false),
243253
new \Phplrt\Parser\Grammar\Lexeme('T_PARENTHESIS_CLOSE', false),
244-
new \Phplrt\Parser\Grammar\Concatenation([163, 59, 164]),
254+
new \Phplrt\Parser\Grammar\Concatenation([173, 59, 174]),
245255
],
246256
'reducers' => [
247257
0 => static function (\Phplrt\Parser\Context $ctx, $children) {
@@ -363,7 +373,7 @@
363373
$hint = \reset($children);
364374
}
365375

366-
return new Node\Stmt\Template\ArgumentNode(
376+
return new Node\Stmt\Template\TemplateArgumentNode(
367377
$type,
368378
$hint,
369379
$attributes,
@@ -377,7 +387,7 @@
377387
throw FeatureNotAllowedException::fromFeature('template arguments', $offset);
378388
}
379389

380-
return new Node\Stmt\Template\ArgumentsListNode($children);
390+
return new Node\Stmt\Template\TemplateArgumentsListNode($children);
381391
},
382392
54 => static function (\Phplrt\Parser\Context $ctx, $children) {
383393
return new Node\Stmt\Attribute\AttributeGroupsListNode($children);
@@ -618,7 +628,13 @@
618628
$children[0],
619629
);
620630
},
621-
145 => function (\Phplrt\Parser\Context $ctx, $children) {
631+
144 => static function (\Phplrt\Parser\Context $ctx, $children) {
632+
return new Node\Stmt\Attribute\AttributeArgumentsListNode($children);
633+
},
634+
146 => static function (\Phplrt\Parser\Context $ctx, $children) {
635+
return new Node\Stmt\Attribute\AttributeArgumentNode($children[0]);
636+
},
637+
155 => function (\Phplrt\Parser\Context $ctx, $children) {
622638
// The "$offset" variable is an auto-generated
623639
$offset = $ctx->lastProcessedToken->getOffset();
624640

@@ -632,7 +648,7 @@
632648

633649
return $children;
634650
},
635-
146 => function (\Phplrt\Parser\Context $ctx, $children) {
651+
156 => function (\Phplrt\Parser\Context $ctx, $children) {
636652
// The "$offset" variable is an auto-generated
637653
$offset = $ctx->lastProcessedToken->getOffset();
638654

@@ -646,14 +662,14 @@
646662

647663
return $children;
648664
},
649-
154 => static function (\Phplrt\Parser\Context $ctx, $children) {
665+
164 => static function (\Phplrt\Parser\Context $ctx, $children) {
650666
if (\is_array($children)) {
651667
return new Node\Stmt\NullableTypeNode($children[1]);
652668
}
653669

654670
return $children;
655671
},
656-
155 => function (\Phplrt\Parser\Context $ctx, $children) {
672+
165 => function (\Phplrt\Parser\Context $ctx, $children) {
657673
// The "$offset" variable is an auto-generated
658674
$offset = $ctx->lastProcessedToken->getOffset();
659675

resources/grammar/attribute.pp2

+17-1
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,21 @@ Attribute -> {
2424
$children[0],
2525
);
2626
}
27-
: Name()
27+
: Name() AttributeArguments()?
28+
;
29+
30+
AttributeArguments -> {
31+
return new Node\Stmt\Attribute\AttributeArgumentsListNode($children);
32+
}
33+
: ::T_PARENTHESIS_OPEN::
34+
AttributeArgument() (
35+
::T_COMMA:: AttributeArgument()
36+
)* ::T_COMMA::?
37+
::T_PARENTHESIS_CLOSE::
38+
;
39+
40+
AttributeArgument -> {
41+
return new Node\Stmt\Attribute\AttributeArgumentNode($children[0]);
42+
}
43+
: Type()
2844
;

resources/grammar/template-arguments.pp2

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ TemplateArguments -> {
44
throw FeatureNotAllowedException::fromFeature('template arguments', $offset);
55
}
66

7-
return new Node\Stmt\Template\ArgumentsListNode($children);
7+
return new Node\Stmt\Template\TemplateArgumentsListNode($children);
88
}
99
: ::T_ANGLE_BRACKET_OPEN::
1010
TemplateArgument() (
@@ -34,7 +34,7 @@ TemplateArgument -> {
3434
$hint = \reset($children);
3535
}
3636

37-
return new Node\Stmt\Template\ArgumentNode(
37+
return new Node\Stmt\Template\TemplateArgumentNode(
3838
$type,
3939
$hint,
4040
$attributes,

src/Exception/FeatureNotAllowedException.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class FeatureNotAllowedException extends SemanticException
1414
*/
1515
public static function fromFeature(string $name, int $offset = 0): self
1616
{
17-
$message = \sprintf('%s not allowed', $name);
17+
$message = \sprintf('%s not allowed', \ucfirst($name));
1818

1919
return new static($offset, $message);
2020
}

src/Exception/ParseException.php

+6-7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace TypeLang\Parser\Exception;
66

7+
use Phplrt\Contracts\Source\ReadableInterface;
78
use Phplrt\Contracts\Source\SourceExceptionInterface;
89

910
class ParseException extends \LogicException implements ParserExceptionInterface
@@ -78,19 +79,17 @@ public static function fromUnrecognizedSyntaxError(string $statement, int $offse
7879
}
7980

8081
/**
81-
* @param int<0, max> $offset
82-
*
8382
* @throws SourceExceptionInterface
8483
*/
85-
public static function fromSemanticError(string $message, string $statement, int $offset, int $code = 0): static
84+
public static function fromSemanticError(SemanticException $e, ReadableInterface $source): static
8685
{
8786
$message = \vsprintf('%s in %s %s', [
88-
\ucfirst($message),
89-
Formatter::source($statement),
90-
Formatter::suffix($statement, $offset),
87+
\ucfirst($e->getMessage()),
88+
Formatter::source($source->getContents()),
89+
Formatter::suffix($source->getContents(), $e->getOffset()),
9190
]);
9291

93-
return new static($message, self::ERROR_CODE_SEMANTIC_ERROR_BASE + $code);
92+
return new static($message, self::ERROR_CODE_SEMANTIC_ERROR_BASE + $e->getCode());
9493
}
9594

9695
public static function fromInternalError(string $statement, \Throwable $e): static

src/Node/NodeList.php

+46-1
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@
77
/**
88
* @template TNode of Node
99
* @template-implements \IteratorAggregate<array-key, TNode>
10+
* @template-implements \ArrayAccess<int<0, max>, TNode>
1011
*/
11-
abstract class NodeList extends Node implements \IteratorAggregate, \Countable
12+
abstract class NodeList extends Node implements
13+
\IteratorAggregate,
14+
\ArrayAccess,
15+
\Countable
1216
{
1317
/**
1418
* @param list<TNode> $items
@@ -37,6 +41,47 @@ public function last(): ?Node
3741
return $last instanceof Node ? $last : null;
3842
}
3943

44+
public function offsetExists(mixed $offset): bool
45+
{
46+
// @phpstan-ignore-next-line
47+
assert(\is_int($offset) && $offset >= 0);
48+
49+
return isset($this->items[$offset]);
50+
}
51+
52+
public function offsetGet(mixed $offset): ?Node
53+
{
54+
// @phpstan-ignore-next-line
55+
assert(\is_int($offset) && $offset >= 0);
56+
57+
return $this->items[$offset] ?? null;
58+
}
59+
60+
public function offsetSet(mixed $offset, mixed $value): void
61+
{
62+
// @phpstan-ignore-next-line
63+
assert(\is_int($offset) && $offset >= 0);
64+
// @phpstan-ignore-next-line
65+
assert($value instanceof Node);
66+
67+
// @phpstan-ignore-next-line
68+
$this->items[$offset] = $value;
69+
70+
if (!\array_is_list($this->items)) {
71+
$this->items = \array_values($this->items);
72+
}
73+
}
74+
75+
public function offsetUnset(mixed $offset): void
76+
{
77+
// @phpstan-ignore-next-line
78+
assert(\is_int($offset) && $offset >= 0);
79+
80+
$items = $this->items;
81+
unset($items[$offset]);
82+
$this->items = \array_values($items);
83+
}
84+
4085
public function getIterator(): \Traversable
4186
{
4287
return new \ArrayIterator($this->items);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TypeLang\Parser\Node\Stmt\Attribute;
6+
7+
use TypeLang\Parser\Node\Node;
8+
use TypeLang\Parser\Node\Stmt\TypeStatement;
9+
10+
class AttributeArgumentNode extends Node
11+
{
12+
public function __construct(
13+
public TypeStatement $value,
14+
public ?AttributeGroupsListNode $attributes = null,
15+
) {}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TypeLang\Parser\Node\Stmt\Attribute;
6+
7+
use TypeLang\Parser\Node\NodeList;
8+
9+
/**
10+
* @template-extends NodeList<AttributeArgumentNode>
11+
*/
12+
class AttributeArgumentsListNode extends NodeList {}

src/Node/Stmt/Attribute/AttributeGroupsListNode.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44

55
namespace TypeLang\Parser\Node\Stmt\Attribute;
66

7-
use PhpParser\Node\AttributeGroup;
87
use TypeLang\Parser\Node\NodeList;
98

109
/**
11-
* @template-extends NodeList<AttributeGroup>
10+
* @template-extends NodeList<AttributeGroupNode>
1211
*/
1312
final class AttributeGroupsListNode extends NodeList {}

src/Node/Stmt/Attribute/AttributeNode.php

+1
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ final class AttributeNode extends Statement
1111
{
1212
public function __construct(
1313
public Name $name,
14+
public ?AttributeArgumentsListNode $arguments = null,
1415
) {}
1516
}

src/Node/Stmt/NamedTypeNode.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use TypeLang\Parser\Node\Identifier;
88
use TypeLang\Parser\Node\Name;
99
use TypeLang\Parser\Node\Stmt\Shape\FieldsListNode;
10-
use TypeLang\Parser\Node\Stmt\Template\ArgumentsListNode;
10+
use TypeLang\Parser\Node\Stmt\Template\TemplateArgumentsListNode;
1111

1212
class NamedTypeNode extends TypeStatement
1313
{
@@ -18,7 +18,7 @@ class NamedTypeNode extends TypeStatement
1818
*/
1919
public function __construct(
2020
Name|Identifier|string $name,
21-
public ?ArgumentsListNode $arguments = null,
21+
public ?TemplateArgumentsListNode $arguments = null,
2222
public ?FieldsListNode $fields = null,
2323
) {
2424
$this->name = $name instanceof Name ? $name : new Name($name);

src/Node/Stmt/Template/ArgumentNode.php

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
use TypeLang\Parser\Node\Stmt\Attribute\AttributeGroupsListNode;
1010
use TypeLang\Parser\Node\Stmt\TypeStatement;
1111

12+
/**
13+
* @deprecated Since 1.1, please use {@see TemplateArgumentNode} instead.
14+
*/
1215
class ArgumentNode extends Node
1316
{
1417
public ?Identifier $hint;

src/Node/Stmt/Template/ArgumentsListNode.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
use TypeLang\Parser\Node\NodeList;
88

99
/**
10-
* @template-extends NodeList<ArgumentNode>
10+
* @template T of ArgumentNode
11+
* @template-extends NodeList<T>
12+
*
13+
* @deprecated Since 1.1, please use {@see TemplateArgumentsListNode} instead.
1114
*/
1215
class ArgumentsListNode extends NodeList {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TypeLang\Parser\Node\Stmt\Template;
6+
7+
class TemplateArgumentNode extends ArgumentNode {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TypeLang\Parser\Node\Stmt\Template;
6+
7+
/**
8+
* @template-extends ArgumentsListNode<TemplateArgumentNode>
9+
*/
10+
class TemplateArgumentsListNode extends ArgumentsListNode {}

0 commit comments

Comments
 (0)