Skip to content

Commit 9bf6637

Browse files
authored
Merge pull request microsoft#368 from TysonAndre/php8.2-features
Support php 8.2 readonly classes, constants in traits, `true` type
2 parents e42180c + 7ff8145 commit 9bf6637

File tree

77 files changed

+459
-22
lines changed

Some content is hidden

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

77 files changed

+459
-22
lines changed

src/Node/Statement/ClassDeclaration.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@ class ClassDeclaration extends StatementNode implements NamespacedNameInterface,
2222
/** @var AttributeGroup[]|null */
2323
public $attributes;
2424

25-
/** @var Token */
25+
/** @var Token abstract/final/readonly modifier */
2626
public $abstractOrFinalModifier;
2727

28+
/** @var Token[] additional abstract/final/readonly modifiers */
29+
public $modifiers;
30+
2831
/** @var Token */
2932
public $classKeyword;
3033

@@ -43,6 +46,7 @@ class ClassDeclaration extends StatementNode implements NamespacedNameInterface,
4346
const CHILD_NAMES = [
4447
'attributes',
4548
'abstractOrFinalModifier',
49+
'modifiers',
4650
'classKeyword',
4751
'name',
4852
'classBaseClause',

src/Parser.php

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,9 @@ public function __construct() {
144144
[TokenKind::ArrayKeyword, TokenKind::CallableKeyword, TokenKind::BoolReservedWord,
145145
TokenKind::FloatReservedWord, TokenKind::IntReservedWord, TokenKind::StringReservedWord,
146146
TokenKind::ObjectReservedWord, TokenKind::NullReservedWord, TokenKind::FalseReservedWord,
147+
TokenKind::TrueReservedWord,
147148
TokenKind::IterableReservedWord, TokenKind::MixedReservedWord]; // TODO update spec
148-
$this->returnTypeDeclarationTokens = \array_merge([TokenKind::VoidReservedWord, TokenKind::NullReservedWord, TokenKind::FalseReservedWord, TokenKind::StaticKeyword], $this->parameterTypeDeclarationTokens);
149+
$this->returnTypeDeclarationTokens = \array_merge([TokenKind::VoidReservedWord, TokenKind::NullReservedWord, TokenKind::FalseReservedWord, TokenKind::TrueReservedWord, TokenKind::StaticKeyword], $this->parameterTypeDeclarationTokens);
149150
}
150151

151152
/**
@@ -557,10 +558,8 @@ private function parseStatementFn() {
557558
// class-declaration
558559
case TokenKind::FinalKeyword:
559560
case TokenKind::AbstractKeyword:
560-
if (!$this->lookahead(TokenKind::ClassKeyword)) {
561-
$this->advanceToken();
562-
return new SkippedToken($token);
563-
}
561+
case TokenKind::ReadonlyKeyword:
562+
// fallthrough
564563
case TokenKind::ClassKeyword:
565564
return $this->parseClassDeclaration($parentNode);
566565

@@ -657,10 +656,20 @@ private function parseClassElementFn() {
657656
};
658657
}
659658

659+
/** @return Token[] */
660+
private function parseClassModifiers(): array {
661+
$modifiers = [];
662+
while ($token = $this->eatOptional(TokenKind::AbstractKeyword, TokenKind::FinalKeyword, TokenKind::ReadonlyKeyword)) {
663+
$modifiers[] = $token;
664+
}
665+
return $modifiers;
666+
}
667+
660668
private function parseClassDeclaration($parentNode) : Node {
661669
$classNode = new ClassDeclaration(); // TODO verify not nested
662670
$classNode->parent = $parentNode;
663-
$classNode->abstractOrFinalModifier = $this->eatOptional(TokenKind::AbstractKeyword, TokenKind::FinalKeyword);
671+
$classNode->abstractOrFinalModifier = $this->eatOptional(TokenKind::AbstractKeyword, TokenKind::FinalKeyword, TokenKind::ReadonlyKeyword);
672+
$classNode->modifiers = $this->parseClassModifiers();
664673
$classNode->classKeyword = $this->eat1(TokenKind::ClassKeyword);
665674
$classNode->name = $this->eat($this->nameOrReservedWordTokens); // TODO should be any
666675
$classNode->name->kind = TokenKind::Name;
@@ -1036,6 +1045,7 @@ private function isStatementStart(Token $token) {
10361045
case TokenKind::ClassKeyword:
10371046
case TokenKind::AbstractKeyword:
10381047
case TokenKind::FinalKeyword:
1048+
case TokenKind::ReadonlyKeyword:
10391049

10401050
// interface-declaration
10411051
case TokenKind::InterfaceKeyword:
@@ -3531,6 +3541,7 @@ private function isTraitMemberDeclarationStart($token) {
35313541
case TokenKind::AbstractKeyword:
35323542
case TokenKind::FinalKeyword:
35333543
case TokenKind::ReadonlyKeyword:
3544+
case TokenKind::ConstKeyword:
35343545

35353546
// method-declaration
35363547
case TokenKind::FunctionKeyword:
@@ -3551,6 +3562,9 @@ private function parseTraitElementFn() {
35513562

35523563
$token = $this->getCurrentToken();
35533564
switch ($token->kind) {
3565+
case TokenKind::ConstKeyword:
3566+
return $this->parseClassConstDeclaration($parentNode, $modifiers);
3567+
35543568
case TokenKind::FunctionKeyword:
35553569
return $this->parseMethodDeclaration($parentNode, $modifiers);
35563570

tests/cases/parser/abstractMethodDeclaration1.php.tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"kind": "AbstractKeyword",
1919
"textLength": 8
2020
},
21+
"modifiers": [],
2122
"classKeyword": {
2223
"kind": "ClassKeyword",
2324
"textLength": 5

tests/cases/parser/abstractMethodDeclaration2.php.tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"ClassDeclaration": {
1616
"attributes": null,
1717
"abstractOrFinalModifier": null,
18+
"modifiers": [],
1819
"classKeyword": {
1920
"kind": "ClassKeyword",
2021
"textLength": 5

tests/cases/parser/abstractMethodDeclaration3.php.tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"kind": "AbstractKeyword",
1919
"textLength": 8
2020
},
21+
"modifiers": [],
2122
"classKeyword": {
2223
"kind": "ClassKeyword",
2324
"textLength": 5

tests/cases/parser/abstractMethodDeclaration5.php.tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"kind": "AbstractKeyword",
1919
"textLength": 8
2020
},
21+
"modifiers": [],
2122
"classKeyword": {
2223
"kind": "ClassKeyword",
2324
"textLength": 5

tests/cases/parser/abstractMethodDeclaration6.php.tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"kind": "AbstractKeyword",
2424
"textLength": 8
2525
},
26+
"modifiers": [],
2627
"classKeyword": {
2728
"kind": "ClassKeyword",
2829
"textLength": 5
Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1 @@
1-
[
2-
{
3-
"kind": 0,
4-
"message": "Unexpected 'abstract'",
5-
"start": 29,
6-
"length": 8
7-
}
8-
]
1+
[]

tests/cases/parser/abstractMethodDeclaration7.php.tree

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,19 @@
1111
}
1212
}
1313
},
14-
{
15-
"error": "SkippedToken",
16-
"kind": "AbstractKeyword",
17-
"textLength": 8
18-
},
1914
{
2015
"ClassDeclaration": {
2116
"attributes": null,
2217
"abstractOrFinalModifier": {
23-
"kind": "FinalKeyword",
24-
"textLength": 5
18+
"kind": "AbstractKeyword",
19+
"textLength": 8
2520
},
21+
"modifiers": [
22+
{
23+
"kind": "FinalKeyword",
24+
"textLength": 5
25+
}
26+
],
2627
"classKeyword": {
2728
"kind": "ClassKeyword",
2829
"textLength": 5

tests/cases/parser/classBaseClause1.php.tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"ClassDeclaration": {
1616
"attributes": null,
1717
"abstractOrFinalModifier": null,
18+
"modifiers": [],
1819
"classKeyword": {
1920
"kind": "ClassKeyword",
2021
"textLength": 5

0 commit comments

Comments
 (0)