Skip to content

Commit 869dc7f

Browse files
committed
Support parsing php 8.0 named arguments
Adding to the properties in ArgumentExpression keeps this working in older applications. And modify unaryExpression11 to avoid conflict with attributes syntax Fixes microsoft#334
1 parent be9cfce commit 869dc7f

34 files changed

+671
-4
lines changed

src/Node/Expression/ArgumentExpression.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@
1010
use Microsoft\PhpParser\Token;
1111

1212
class ArgumentExpression extends Expression {
13+
/** @var Token|null for php named arguments. If this is set, byRefToken and dotDotDotToken will not be set. */
14+
public $name;
15+
16+
/** @var Token|null */
17+
public $colonToken;
18+
1319
/** @var Token|null */
1420
public $byRefToken; // TODO removed in newer versions of PHP. Also only accept variable, not expression if byRef
1521

@@ -20,6 +26,8 @@ class ArgumentExpression extends Expression {
2026
public $expression;
2127

2228
const CHILD_NAMES = [
29+
'name',
30+
'colonToken',
2331
'byRefToken',
2432
'dotDotDotToken',
2533
'expression'

src/Parser.php

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,17 @@ class Parser {
121121
private $nameOrStaticOrReservedWordTokens;
122122
private $reservedWordTokens;
123123
private $keywordTokens;
124+
private $argumentStartTokensSet;
124125
// TODO consider validating parameter and return types on post-parse instead so we can be more permissive
125126
private $parameterTypeDeclarationTokens;
126127
private $returnTypeDeclarationTokens;
127128

128129
public function __construct() {
129130
$this->reservedWordTokens = \array_values(TokenStringMaps::RESERVED_WORDS);
130131
$this->keywordTokens = \array_values(TokenStringMaps::KEYWORDS);
132+
$this->argumentStartTokensSet = \array_flip(TokenStringMaps::KEYWORDS);
133+
unset($this->argumentStartTokensSet[TokenKind::YieldFromKeyword]);
134+
$this->argumentStartTokensSet[TokenKind::DotDotDotToken] = '...';
131135
$this->nameOrKeywordOrReservedWordTokens = \array_merge([TokenKind::Name], $this->keywordTokens, $this->reservedWordTokens);
132136
$this->nameOrReservedWordTokens = \array_merge([TokenKind::Name], $this->reservedWordTokens);
133137
$this->nameOrStaticOrReservedWordTokens = \array_merge([TokenKind::Name, TokenKind::StaticKeyword], $this->reservedWordTokens);
@@ -2762,16 +2766,30 @@ private function parseMemberName($parentNode) {
27622766
private function isArgumentExpressionStartFn() {
27632767
return function ($token) {
27642768
return
2765-
$token->kind === TokenKind::DotDotDotToken ? true : $this->isExpressionStart($token);
2769+
isset($this->argumentStartTokensSet[$token->kind]) || $this->isExpressionStart($token);
27662770
};
27672771
}
27682772

27692773
private function parseArgumentExpressionFn() {
27702774
return function ($parentNode) {
27712775
$argumentExpression = new ArgumentExpression();
27722776
$argumentExpression->parent = $parentNode;
2773-
$argumentExpression->byRefToken = $this->eatOptional1(TokenKind::AmpersandToken);
2774-
$argumentExpression->dotDotDotToken = $this->eatOptional1(TokenKind::DotDotDotToken);
2777+
2778+
$nextToken = $this->lexer->getTokensArray()[$this->lexer->getCurrentPosition()] ?? null;
2779+
if ($nextToken && $nextToken->kind === TokenKind::ColonToken) {
2780+
$name = $this->token;
2781+
$this->advanceToken();
2782+
if ($name->kind === TokenKind::YieldFromKeyword || !\in_array($name->kind, $this->nameOrKeywordOrReservedWordTokens)) {
2783+
$name = new SkippedToken($name);
2784+
} else {
2785+
$name->kind = TokenKind::Name;
2786+
}
2787+
$argumentExpression->name = $name;
2788+
$argumentExpression->colonToken = $this->eat1(TokenKind::ColonToken);
2789+
} else {
2790+
$argumentExpression->byRefToken = $this->eatOptional1(TokenKind::AmpersandToken);
2791+
$argumentExpression->dotDotDotToken = $this->eatOptional1(TokenKind::DotDotDotToken);
2792+
}
27752793
$argumentExpression->expression = $this->parseExpression($argumentExpression);
27762794
return $argumentExpression;
27772795
};

tests/cases/parser/binaryAssignmentExpressions6.php.tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
"children": [
3737
{
3838
"ArgumentExpression": {
39+
"name": null,
40+
"colonToken": null,
3941
"byRefToken": null,
4042
"dotDotDotToken": null,
4143
"expression": {

tests/cases/parser/callExpression10.php.tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
"children": [
3737
{
3838
"ArgumentExpression": {
39+
"name": null,
40+
"colonToken": null,
3941
"byRefToken": null,
4042
"dotDotDotToken": null,
4143
"expression": {
@@ -54,6 +56,8 @@
5456
},
5557
{
5658
"ArgumentExpression": {
59+
"name": null,
60+
"colonToken": null,
5761
"byRefToken": null,
5862
"dotDotDotToken": null,
5963
"expression": {
@@ -72,6 +76,8 @@
7276
},
7377
{
7478
"ArgumentExpression": {
79+
"name": null,
80+
"colonToken": null,
7581
"byRefToken": null,
7682
"dotDotDotToken": null,
7783
"expression": {

tests/cases/parser/callExpression12.php.tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
"children": [
3737
{
3838
"ArgumentExpression": {
39+
"name": null,
40+
"colonToken": null,
3941
"byRefToken": null,
4042
"dotDotDotToken": null,
4143
"expression": {

tests/cases/parser/callExpression15.php.tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@
7171
"children": [
7272
{
7373
"ArgumentExpression": {
74+
"name": null,
75+
"colonToken": null,
7476
"byRefToken": null,
7577
"dotDotDotToken": null,
7678
"expression": {

tests/cases/parser/callExpression2.php.tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
"children": [
3434
{
3535
"ArgumentExpression": {
36+
"name": null,
37+
"colonToken": null,
3638
"byRefToken": null,
3739
"dotDotDotToken": null,
3840
"expression": {

tests/cases/parser/callExpression3.php.tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
"children": [
3434
{
3535
"ArgumentExpression": {
36+
"name": null,
37+
"colonToken": null,
3638
"byRefToken": null,
3739
"dotDotDotToken": null,
3840
"expression": {

tests/cases/parser/callExpression4.php.tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
"children": [
3434
{
3535
"ArgumentExpression": {
36+
"name": null,
37+
"colonToken": null,
3638
"byRefToken": null,
3739
"dotDotDotToken": null,
3840
"expression": {
@@ -69,6 +71,8 @@
6971
},
7072
{
7173
"ArgumentExpression": {
74+
"name": null,
75+
"colonToken": null,
7276
"byRefToken": null,
7377
"dotDotDotToken": null,
7478
"expression": {

tests/cases/parser/callExpression5.php.tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
"children": [
3434
{
3535
"ArgumentExpression": {
36+
"name": null,
37+
"colonToken": null,
3638
"byRefToken": null,
3739
"dotDotDotToken": null,
3840
"expression": {
@@ -69,6 +71,8 @@
6971
},
7072
{
7173
"ArgumentExpression": {
74+
"name": null,
75+
"colonToken": null,
7276
"byRefToken": null,
7377
"dotDotDotToken": null,
7478
"expression": {

0 commit comments

Comments
 (0)