Skip to content

Commit d31c085

Browse files
TysonAndredantleech
authored andcommitted
Support parsing php 8.3 typed class constants
https://wiki.php.net/rfc/typed_class_constants#inheritance_and_variance As of php 8.3, class constants can have the same types as parameters (including union, intersection, and DNF types) Start testing with php 8.3
1 parent 4fd2db9 commit d31c085

22 files changed

+296
-6
lines changed

.github/workflows/main.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ jobs:
3131
- PHP_VERSION: '7.4'
3232
- PHP_VERSION: '8.0'
3333
- PHP_VERSION: '8.1'
34-
- PHP_VERSION: '8.2.0beta2'
34+
- PHP_VERSION: '8.2'
35+
- PHP_VERSION: '8.3'
3536

3637
# Steps represent a sequence of tasks that will be executed as part of the job
3738
steps:

src/Node/ClassConstDeclaration.php

+5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Microsoft\PhpParser\ModifiedTypeInterface;
1010
use Microsoft\PhpParser\ModifiedTypeTrait;
1111
use Microsoft\PhpParser\Node;
12+
use Microsoft\PhpParser\Node\DelimitedList\QualifiedNameList;
1213
use Microsoft\PhpParser\Token;
1314

1415
class ClassConstDeclaration extends Node implements ModifiedTypeInterface {
@@ -23,6 +24,9 @@ class ClassConstDeclaration extends Node implements ModifiedTypeInterface {
2324
/** @var Token */
2425
public $constKeyword;
2526

27+
/** @var QualifiedNameList|null */
28+
public $typeDeclarationList;
29+
2630
/** @var DelimitedList\ConstElementList */
2731
public $constElements;
2832

@@ -33,6 +37,7 @@ class ClassConstDeclaration extends Node implements ModifiedTypeInterface {
3337
'attributes',
3438
'modifiers',
3539
'constKeyword',
40+
'typeDeclarationList',
3641
'constElements',
3742
'semicolon'
3843
];

src/Parser.php

+11-5
Original file line numberDiff line numberDiff line change
@@ -1417,7 +1417,7 @@ private function parseStringLiteralExpression2($parentNode): StringLiteral {
14171417
case TokenKind::DollarOpenBraceToken:
14181418
case TokenKind::OpenBraceDollarToken:
14191419
$expression->children[] = $this->eat(TokenKind::DollarOpenBraceToken, TokenKind::OpenBraceDollarToken);
1420-
/**
1420+
/**
14211421
* @phpstan-ignore-next-line "Strict comparison using
14221422
* === between 403|404 and 408 will always evaluate to
14231423
* false" is wrong because those tokens were eaten above
@@ -2802,10 +2802,6 @@ private function parseListIntrinsicExpression($parentNode) {
28022802
return $listExpression;
28032803
}
28042804

2805-
private function isArrayElementStart($token) {
2806-
return ($this->isArrayElementStartFn())($token);
2807-
}
2808-
28092805
private function isArrayElementStartFn() {
28102806
return function ($token) {
28112807
return $token->kind === TokenKind::AmpersandToken || $token->kind === TokenKind::DotDotDotToken || $this->isExpressionStart($token);
@@ -3370,6 +3366,16 @@ private function parseClassConstDeclaration($parentNode, $modifiers) {
33703366

33713367
$classConstDeclaration->modifiers = $modifiers;
33723368
$classConstDeclaration->constKeyword = $this->eat1(TokenKind::ConstKeyword);
3369+
// Handle class constant declarations such as `const X|Y Z = 123;` or `const X = 123;`.
3370+
// This is similar to lookahead().
3371+
$startPos = $this->lexer->getCurrentPosition();
3372+
$startToken = $this->token;
3373+
$classConstDeclaration->typeDeclarationList = $this->tryParseParameterTypeDeclarationList($classConstDeclaration);
3374+
if (in_array($this->token->kind, [TokenKind::EqualsToken, TokenKind::CommaToken, TokenKind::SemicolonToken]) && $this->lexer->getCurrentPosition() <= $startPos + 1) {
3375+
$classConstDeclaration->typeDeclarationList = null;
3376+
$this->lexer->setCurrentPosition($startPos);
3377+
$this->token = $startToken;
3378+
}
33733379
$classConstDeclaration->constElements = $this->parseConstElements($classConstDeclaration);
33743380
$classConstDeclaration->semicolon = $this->eat1(TokenKind::SemicolonToken);
33753381

tests/cases/parser/classConstDeclaration1.php.tree

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"kind": "ConstKeyword",
4242
"textLength": 5
4343
},
44+
"typeDeclarationList": null,
4445
"constElements": {
4546
"ConstElementList": {
4647
"children": [

tests/cases/parser/classConstDeclaration10.php.tree

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"kind": "ConstKeyword",
4747
"textLength": 5
4848
},
49+
"typeDeclarationList": null,
4950
"constElements": {
5051
"ConstElementList": {
5152
"children": [
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?php
2+
class A {
3+
const int|string a = 3;
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
{
2+
"SourceFileNode": {
3+
"statementList": [
4+
{
5+
"InlineHtml": {
6+
"scriptSectionEndTag": null,
7+
"text": null,
8+
"scriptSectionStartTag": {
9+
"kind": "ScriptSectionStartTag",
10+
"textLength": 6
11+
}
12+
}
13+
},
14+
{
15+
"ClassDeclaration": {
16+
"attributes": null,
17+
"abstractOrFinalModifier": null,
18+
"modifiers": [],
19+
"classKeyword": {
20+
"kind": "ClassKeyword",
21+
"textLength": 5
22+
},
23+
"name": {
24+
"kind": "Name",
25+
"textLength": 1
26+
},
27+
"classBaseClause": null,
28+
"classInterfaceClause": null,
29+
"classMembers": {
30+
"ClassMembersNode": {
31+
"openBrace": {
32+
"kind": "OpenBraceToken",
33+
"textLength": 1
34+
},
35+
"classMemberDeclarations": [
36+
{
37+
"ClassConstDeclaration": {
38+
"attributes": null,
39+
"modifiers": [],
40+
"constKeyword": {
41+
"kind": "ConstKeyword",
42+
"textLength": 5
43+
},
44+
"typeDeclarationList": {
45+
"QualifiedNameList": {
46+
"children": [
47+
{
48+
"kind": "IntReservedWord",
49+
"textLength": 3
50+
},
51+
{
52+
"kind": "BarToken",
53+
"textLength": 1
54+
},
55+
{
56+
"kind": "StringReservedWord",
57+
"textLength": 6
58+
}
59+
]
60+
}
61+
},
62+
"constElements": {
63+
"ConstElementList": {
64+
"children": [
65+
{
66+
"ConstElement": {
67+
"name": {
68+
"kind": "Name",
69+
"textLength": 1
70+
},
71+
"equalsToken": {
72+
"kind": "EqualsToken",
73+
"textLength": 1
74+
},
75+
"assignment": {
76+
"NumericLiteral": {
77+
"children": {
78+
"kind": "IntegerLiteralToken",
79+
"textLength": 1
80+
}
81+
}
82+
}
83+
}
84+
}
85+
]
86+
}
87+
},
88+
"semicolon": {
89+
"kind": "SemicolonToken",
90+
"textLength": 1
91+
}
92+
}
93+
}
94+
],
95+
"closeBrace": {
96+
"kind": "CloseBraceToken",
97+
"textLength": 1
98+
}
99+
}
100+
}
101+
}
102+
}
103+
],
104+
"endOfFileToken": {
105+
"kind": "EndOfFileToken",
106+
"textLength": 0
107+
}
108+
}
109+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?php
2+
class A {
3+
const int| a = 3;
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[
2+
{
3+
"kind": 0,
4+
"message": "';' expected.",
5+
"start": 32,
6+
"length": 0
7+
},
8+
{
9+
"kind": 0,
10+
"message": "Unexpected '='",
11+
"start": 33,
12+
"length": 1
13+
},
14+
{
15+
"kind": 0,
16+
"message": "'}' expected.",
17+
"start": 34,
18+
"length": 0
19+
},
20+
{
21+
"kind": 0,
22+
"message": "Unexpected '}'",
23+
"start": 38,
24+
"length": 1
25+
}
26+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
{
2+
"SourceFileNode": {
3+
"statementList": [
4+
{
5+
"InlineHtml": {
6+
"scriptSectionEndTag": null,
7+
"text": null,
8+
"scriptSectionStartTag": {
9+
"kind": "ScriptSectionStartTag",
10+
"textLength": 6
11+
}
12+
}
13+
},
14+
{
15+
"ClassDeclaration": {
16+
"attributes": null,
17+
"abstractOrFinalModifier": null,
18+
"modifiers": [],
19+
"classKeyword": {
20+
"kind": "ClassKeyword",
21+
"textLength": 5
22+
},
23+
"name": {
24+
"kind": "Name",
25+
"textLength": 1
26+
},
27+
"classBaseClause": null,
28+
"classInterfaceClause": null,
29+
"classMembers": {
30+
"ClassMembersNode": {
31+
"openBrace": {
32+
"kind": "OpenBraceToken",
33+
"textLength": 1
34+
},
35+
"classMemberDeclarations": [
36+
{
37+
"ClassConstDeclaration": {
38+
"attributes": null,
39+
"modifiers": [],
40+
"constKeyword": {
41+
"kind": "ConstKeyword",
42+
"textLength": 5
43+
},
44+
"typeDeclarationList": {
45+
"QualifiedNameList": {
46+
"children": [
47+
{
48+
"kind": "IntReservedWord",
49+
"textLength": 3
50+
},
51+
{
52+
"kind": "BarToken",
53+
"textLength": 1
54+
},
55+
{
56+
"QualifiedName": {
57+
"globalSpecifier": null,
58+
"relativeSpecifier": null,
59+
"nameParts": [
60+
{
61+
"kind": "Name",
62+
"textLength": 1
63+
}
64+
]
65+
}
66+
}
67+
]
68+
}
69+
},
70+
"constElements": null,
71+
"semicolon": {
72+
"error": "MissingToken",
73+
"kind": "SemicolonToken",
74+
"textLength": 0
75+
}
76+
}
77+
},
78+
{
79+
"error": "SkippedToken",
80+
"kind": "EqualsToken",
81+
"textLength": 1
82+
}
83+
],
84+
"closeBrace": {
85+
"error": "MissingToken",
86+
"kind": "CloseBraceToken",
87+
"textLength": 0
88+
}
89+
}
90+
}
91+
}
92+
},
93+
{
94+
"ExpressionStatement": {
95+
"expression": {
96+
"NumericLiteral": {
97+
"children": {
98+
"kind": "IntegerLiteralToken",
99+
"textLength": 1
100+
}
101+
}
102+
},
103+
"semicolon": {
104+
"kind": "SemicolonToken",
105+
"textLength": 1
106+
}
107+
}
108+
},
109+
{
110+
"error": "SkippedToken",
111+
"kind": "CloseBraceToken",
112+
"textLength": 1
113+
}
114+
],
115+
"endOfFileToken": {
116+
"kind": "EndOfFileToken",
117+
"textLength": 0
118+
}
119+
}
120+
}

tests/cases/parser/classConstDeclaration2.php.tree

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"kind": "ConstKeyword",
4242
"textLength": 5
4343
},
44+
"typeDeclarationList": null,
4445
"constElements": {
4546
"ConstElementList": {
4647
"children": [

tests/cases/parser/classConstDeclaration4.php.tree

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"kind": "ConstKeyword",
4747
"textLength": 5
4848
},
49+
"typeDeclarationList": null,
4950
"constElements": {
5051
"ConstElementList": {
5152
"children": [

tests/cases/parser/classConstDeclaration5.php.tree

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"kind": "ConstKeyword",
5151
"textLength": 5
5252
},
53+
"typeDeclarationList": null,
5354
"constElements": {
5455
"ConstElementList": {
5556
"children": [

tests/cases/parser/classConstDeclaration7.php.tree

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"kind": "ConstKeyword",
4242
"textLength": 5
4343
},
44+
"typeDeclarationList": null,
4445
"constElements": {
4546
"ConstElementList": {
4647
"children": [

0 commit comments

Comments
 (0)