Fixes #190: `insteadof` should be able to accept a name list
Do this in a way that makes it less likely that applications already using targetName will throw an exception or error. This should be revisited in a future backwards incompatible release. Add remainingTargetNames as a new property. NOTE: traits16.php is invalid php 7 code, so traits16.php.diag should be non-empty. However, tolerant-php-parser emits a slightly different error message than `php -l` would.
This commit is contained in:
Родитель
31cffdb9ab
Коммит
f297043862
|
@ -22,10 +22,26 @@ class TraitSelectOrAliasClause extends Node {
|
|||
/** @var QualifiedName|Node\Expression\ScopedPropertyAccessExpression */
|
||||
public $targetName;
|
||||
|
||||
/**
|
||||
* @var Token[]|QualifiedName[]|null
|
||||
*
|
||||
* This is set if $asOrInsteadOfKeyword is an insteadof keyword.
|
||||
* (E.g. for parsing `use T1, T2, T3{T1::foo insteadof T2, T3}`
|
||||
*
|
||||
* NOTE: This was added as a separate property to minimize
|
||||
* backwards compatibility breaks in applications using this file.
|
||||
*
|
||||
* TODO: Use a more consistent design such as either of the following:
|
||||
* 1. Combine targetName and remainingTargetNames into a DelimitedList
|
||||
* 2. Use two distinct properties for the targets of `as` and `insteadof`
|
||||
*/
|
||||
public $remainingTargetNames;
|
||||
|
||||
const CHILD_NAMES = [
|
||||
'name',
|
||||
'asOrInsteadOfKeyword',
|
||||
'modifiers',
|
||||
'targetName'
|
||||
'targetName',
|
||||
'remainingTargetNames',
|
||||
];
|
||||
}
|
||||
|
|
|
@ -2665,6 +2665,10 @@ class Parser {
|
|||
return $propertyDeclaration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node $parentNode
|
||||
* @return DelimitedList\QualifiedNameList
|
||||
*/
|
||||
private function parseQualifiedNameList($parentNode) {
|
||||
return $this->parseDelimitedList(
|
||||
DelimitedList\QualifiedNameList::class,
|
||||
|
@ -2943,8 +2947,17 @@ class Parser {
|
|||
$traitSelectAndAliasClause->asOrInsteadOfKeyword = $this->eat(TokenKind::AsKeyword, TokenKind::InsteadOfKeyword);
|
||||
$traitSelectAndAliasClause->modifiers = $this->parseModifiers(); // TODO accept all modifiers, verify later
|
||||
|
||||
$traitSelectAndAliasClause->targetName =
|
||||
$this->parseQualifiedNameOrScopedPropertyAccessExpression($traitSelectAndAliasClause);
|
||||
if ($traitSelectAndAliasClause->asOrInsteadOfKeyword->kind === TokenKind::InsteadOfKeyword) {
|
||||
// https://github.com/Microsoft/tolerant-php-parser/issues/190
|
||||
// TODO: In the next backwards incompatible release, convert targetName to a list?
|
||||
$interfaceNameList = $this->parseQualifiedNameList($traitSelectAndAliasClause)->children;
|
||||
$traitSelectAndAliasClause->targetName = $interfaceNameList[0] ?? null;
|
||||
$traitSelectAndAliasClause->remainingTargetNames = array_slice($interfaceNameList, 1);
|
||||
} else {
|
||||
$traitSelectAndAliasClause->targetName =
|
||||
$this->parseQualifiedNameOrScopedPropertyAccessExpression($traitSelectAndAliasClause);
|
||||
}
|
||||
|
||||
|
||||
// TODO errors for insteadof/as
|
||||
return $traitSelectAndAliasClause;
|
||||
|
|
|
@ -89,7 +89,8 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"remainingTargetNames": null
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -89,7 +89,8 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"remainingTargetNames": []
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -126,7 +127,8 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"remainingTargetNames": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -97,7 +97,8 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"remainingTargetNames": []
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -97,7 +97,8 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"remainingTargetNames": []
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -101,7 +101,8 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"remainingTargetNames": []
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -1 +1,32 @@
|
|||
[]
|
||||
[
|
||||
{
|
||||
"kind": 0,
|
||||
"message": "'}' expected.",
|
||||
"start": 41,
|
||||
"length": 0
|
||||
},
|
||||
{
|
||||
"kind": 0,
|
||||
"message": "Unexpected '::'",
|
||||
"start": 41,
|
||||
"length": 2
|
||||
},
|
||||
{
|
||||
"kind": 0,
|
||||
"message": "'}' expected.",
|
||||
"start": 43,
|
||||
"length": 0
|
||||
},
|
||||
{
|
||||
"kind": 0,
|
||||
"message": "Unexpected '}'",
|
||||
"start": 46,
|
||||
"length": 1
|
||||
},
|
||||
{
|
||||
"kind": 0,
|
||||
"message": "Unexpected '}'",
|
||||
"start": 48,
|
||||
"length": 1
|
||||
}
|
||||
]
|
|
@ -79,52 +79,74 @@
|
|||
},
|
||||
"modifiers": [],
|
||||
"targetName": {
|
||||
"ScopedPropertyAccessExpression": {
|
||||
"scopeResolutionQualifier": {
|
||||
"QualifiedName": {
|
||||
"globalSpecifier": null,
|
||||
"relativeSpecifier": null,
|
||||
"nameParts": [
|
||||
{
|
||||
"kind": "Name",
|
||||
"textLength": 1
|
||||
}
|
||||
]
|
||||
"QualifiedName": {
|
||||
"globalSpecifier": null,
|
||||
"relativeSpecifier": null,
|
||||
"nameParts": [
|
||||
{
|
||||
"kind": "Name",
|
||||
"textLength": 1
|
||||
}
|
||||
},
|
||||
"doubleColon": {
|
||||
"kind": "ColonColonToken",
|
||||
"textLength": 2
|
||||
},
|
||||
"memberName": {
|
||||
"kind": "Name",
|
||||
"textLength": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"remainingTargetNames": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "SemicolonToken",
|
||||
"textLength": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"closeBrace": {
|
||||
"error": "MissingToken",
|
||||
"kind": "CloseBraceToken",
|
||||
"textLength": 1
|
||||
"textLength": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"error": "SkippedToken",
|
||||
"kind": "ColonColonToken",
|
||||
"textLength": 2
|
||||
}
|
||||
],
|
||||
"closeBrace": {
|
||||
"error": "MissingToken",
|
||||
"kind": "CloseBraceToken",
|
||||
"textLength": 1
|
||||
"textLength": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ExpressionStatement": {
|
||||
"expression": {
|
||||
"QualifiedName": {
|
||||
"globalSpecifier": null,
|
||||
"relativeSpecifier": null,
|
||||
"nameParts": [
|
||||
{
|
||||
"kind": "Name",
|
||||
"textLength": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"semicolon": {
|
||||
"kind": "SemicolonToken",
|
||||
"textLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"error": "SkippedToken",
|
||||
"kind": "CloseBraceToken",
|
||||
"textLength": 1
|
||||
},
|
||||
{
|
||||
"error": "SkippedToken",
|
||||
"kind": "CloseBraceToken",
|
||||
"textLength": 1
|
||||
}
|
||||
],
|
||||
"endOfFileToken": {
|
||||
|
|
|
@ -109,7 +109,8 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"remainingTargetNames": []
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -94,7 +94,8 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"remainingTargetNames": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -98,7 +98,8 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"remainingTargetNames": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -95,7 +95,8 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"remainingTargetNames": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -155,7 +156,8 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"remainingTargetNames": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -110,7 +110,8 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"remainingTargetNames": []
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -147,7 +148,8 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"remainingTargetNames": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
// https://github.com/Microsoft/tolerant-php-parser/issues/98
|
||||
|
||||
class A {
|
||||
use X, Y, Z {
|
||||
\X::b insteadof Y, Z;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
[]
|
|
@ -0,0 +1,191 @@
|
|||
{
|
||||
"SourceFileNode": {
|
||||
"statementList": [
|
||||
{
|
||||
"InlineHtml": {
|
||||
"scriptSectionEndTag": null,
|
||||
"text": null,
|
||||
"scriptSectionStartTag": {
|
||||
"kind": "ScriptSectionStartTag",
|
||||
"textLength": 6
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ClassDeclaration": {
|
||||
"abstractOrFinalModifier": null,
|
||||
"classKeyword": {
|
||||
"kind": "ClassKeyword",
|
||||
"textLength": 5
|
||||
},
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"textLength": 1
|
||||
},
|
||||
"classBaseClause": null,
|
||||
"classInterfaceClause": null,
|
||||
"classMembers": {
|
||||
"ClassMembersNode": {
|
||||
"openBrace": {
|
||||
"kind": "OpenBraceToken",
|
||||
"textLength": 1
|
||||
},
|
||||
"classMemberDeclarations": [
|
||||
{
|
||||
"TraitUseClause": {
|
||||
"useKeyword": {
|
||||
"kind": "UseKeyword",
|
||||
"textLength": 3
|
||||
},
|
||||
"traitNameList": {
|
||||
"QualifiedNameList": {
|
||||
"children": [
|
||||
{
|
||||
"QualifiedName": {
|
||||
"globalSpecifier": null,
|
||||
"relativeSpecifier": null,
|
||||
"nameParts": [
|
||||
{
|
||||
"kind": "Name",
|
||||
"textLength": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "CommaToken",
|
||||
"textLength": 1
|
||||
},
|
||||
{
|
||||
"QualifiedName": {
|
||||
"globalSpecifier": null,
|
||||
"relativeSpecifier": null,
|
||||
"nameParts": [
|
||||
{
|
||||
"kind": "Name",
|
||||
"textLength": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "CommaToken",
|
||||
"textLength": 1
|
||||
},
|
||||
{
|
||||
"QualifiedName": {
|
||||
"globalSpecifier": null,
|
||||
"relativeSpecifier": null,
|
||||
"nameParts": [
|
||||
{
|
||||
"kind": "Name",
|
||||
"textLength": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"semicolonOrOpenBrace": {
|
||||
"kind": "OpenBraceToken",
|
||||
"textLength": 1
|
||||
},
|
||||
"traitSelectAndAliasClauses": {
|
||||
"TraitSelectOrAliasClauseList": {
|
||||
"children": [
|
||||
{
|
||||
"TraitSelectOrAliasClause": {
|
||||
"name": {
|
||||
"ScopedPropertyAccessExpression": {
|
||||
"scopeResolutionQualifier": {
|
||||
"QualifiedName": {
|
||||
"globalSpecifier": {
|
||||
"kind": "BackslashToken",
|
||||
"textLength": 1
|
||||
},
|
||||
"relativeSpecifier": null,
|
||||
"nameParts": [
|
||||
{
|
||||
"kind": "Name",
|
||||
"textLength": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"doubleColon": {
|
||||
"kind": "ColonColonToken",
|
||||
"textLength": 2
|
||||
},
|
||||
"memberName": {
|
||||
"kind": "Name",
|
||||
"textLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"asOrInsteadOfKeyword": {
|
||||
"kind": "InsteadOfKeyword",
|
||||
"textLength": 9
|
||||
},
|
||||
"modifiers": [],
|
||||
"targetName": {
|
||||
"QualifiedName": {
|
||||
"globalSpecifier": null,
|
||||
"relativeSpecifier": null,
|
||||
"nameParts": [
|
||||
{
|
||||
"kind": "Name",
|
||||
"textLength": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"remainingTargetNames": [
|
||||
{
|
||||
"kind": "CommaToken",
|
||||
"textLength": 1
|
||||
},
|
||||
{
|
||||
"QualifiedName": {
|
||||
"globalSpecifier": null,
|
||||
"relativeSpecifier": null,
|
||||
"nameParts": [
|
||||
{
|
||||
"kind": "Name",
|
||||
"textLength": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "SemicolonToken",
|
||||
"textLength": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"closeBrace": {
|
||||
"kind": "CloseBraceToken",
|
||||
"textLength": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"closeBrace": {
|
||||
"kind": "CloseBraceToken",
|
||||
"textLength": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"endOfFileToken": {
|
||||
"kind": "EndOfFileToken",
|
||||
"textLength": 0
|
||||
}
|
||||
}
|
||||
}
|
|
@ -89,7 +89,8 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"remainingTargetNames": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче