Merge pull request #349 from TysonAndre/v1-refactor

Proposed changes for 0.1.0
This commit is contained in:
Rob Lourens 2021-06-10 17:44:41 -07:00 коммит произвёл GitHub
Родитель 35646d5501 56f2603a0d
Коммит 769b9d9b7a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
316 изменённых файлов: 3555 добавлений и 3723 удалений

Просмотреть файл

@ -1,13 +1,10 @@
language: php
php:
- 7.0
- 7.1
- 7.2
- 7.3
- 7.4
# Should be changed to 8.0 once travis officially provides that label.
- nightly
- '7.2'
- '7.3'
- '7.4'
- '8.0'
env:
- VALIDATION=false
@ -30,12 +27,7 @@ cache:
before_script:
- if [[ $STATIC_ANALYSIS = true ]]; then composer require phpstan/phpstan --no-update; fi
- |
if php -r 'exit(PHP_MAJOR_VERSION < 8 ? 0 : 1);';
then composer install
else
composer install --ignore-platform-reqs
fi
- composer install
- set -e # Stop on first error.
- phpenv config-rm xdebug.ini || true
- if find . -name "*.php" -path "./src/*" -path "./experiments/*" -path "./tools/*" -path "./syntax-visualizer/server/src/*" -exec php -l {} 2>&1 \; | grep "syntax error, unexpected"; then exit 1; fi

Просмотреть файл

@ -2,13 +2,15 @@
[![Build Status](https://travis-ci.org/Microsoft/tolerant-php-parser.svg?branch=master)](https://travis-ci.org/Microsoft/tolerant-php-parser)
This is an early-stage PHP parser designed, from the beginning, for IDE usage scenarios (see [Design Goals](#design-goals) for more details). There is
still a ton of work to be done, so at this point, this repo mostly serves as
still a ton of work to be done, so at this point, this repo mostly serves as
an experiment and the start of a conversation.
![image](https://cloud.githubusercontent.com/assets/762848/19023070/4ab01c92-889a-11e6-9bb5-ec1a6816aba2.png)
This is the v0.1 branch, which changes data structures to support syntax added after the initial 0.0.x release line.
## Get Started
After you've [configured your machine](docs/GettingStarted.md), you can use the parser to generate and work
After you've [configured your machine](docs/GettingStarted.md), you can use the parser to generate and work
with the Abstract Syntax Tree (AST) via a friendly API.
```php
<?php
@ -38,17 +40,17 @@ foreach ($astNode->getDescendantNodes() as $descendant) {
// All Nodes link back to their parents, so it's easy to navigate the tree.
$grandParent = $descendant->getParent()->getParent();
var_dump($grandParent->getNodeKindName());
// The AST is fully-representative, and round-trippable to the original source.
// This enables consumers to build reliable formatting and refactoring tools.
var_dump($grandParent->getLeadingCommentAndWhitespaceText());
}
// In addition to retrieving all children or descendants of a Node,
// Nodes expose properties specific to the Node type.
if ($descendant instanceof Node\Expression\EchoExpression) {
$echoKeywordStartPosition = $descendant->echoKeyword->getStartPosition();
// To cut down on memory consumption, positions are represented as a single integer
// To cut down on memory consumption, positions are represented as a single integer
// index into the document, but their line and character positions are easily retrieved.
$lineCharacterPosition = PositionUtilities::getLineCharacterPositionFromPosition(
$echoKeywordStartPosition,
@ -59,15 +61,15 @@ foreach ($astNode->getDescendantNodes() as $descendant) {
}
```
> Note: [the API](docs/ApiDocumentation.md) is not yet finalized, so please file issues let us know what functionality you want exposed,
> Note: [the API](docs/ApiDocumentation.md) is not yet finalized, so please file issues let us know what functionality you want exposed,
and we'll see what we can do! Also please file any bugs with unexpected behavior in the parse tree. We're still
in our early stages, and any feedback you have is much appreciated :smiley:.
## Design Goals
* Error tolerant design - in IDE scenarios, code is, by definition, incomplete. In the case that invalid code is entered, the
parser should still be able to recover and produce a valid + complete tree, as well as relevant diagnostics.
parser should still be able to recover and produce a valid + complete tree, as well as relevant diagnostics.
* Fast and lightweight (should be able to parse several MB of source code per second,
to leave room for other features).
to leave room for other features).
* Memory-efficient data structures
* Allow for incremental parsing in the future
* Adheres to [PHP language spec](https://github.com/php/php-langspec),
@ -83,34 +85,34 @@ so each language server operation should be < 50 ms to leave room for all the
confusing, really fast, so readability and debug-ability is high priority.
* Testable - the parser should produce provably valid parse trees. We achieve this by defining and continuously testing
a set of invariants about the tree.
* Friendly and descriptive API to make it easy for others to build on.
* Friendly and descriptive API to make it easy for others to build on.
* Written in PHP - make it as easy as possible for the PHP community to consume and contribute.
## Current Status and Approach
To ensure a sufficient level of correctness at every step of the way, the
parser is being developed using the following incremental approach:
* [x] **Phase 1:** Write lexer that does not support PHP grammar, but supports EOF
* [x] **Phase 1:** Write lexer that does not support PHP grammar, but supports EOF
and Unknown tokens. Write tests for all invariants.
* [x] **Phase 2:** Support PHP lexical grammar, lots of tests
* [x] **Phase 3:** Write a parser that does not support PHP grammar, but produces tree of
* [x] **Phase 3:** Write a parser that does not support PHP grammar, but produces tree of
Error Nodes. Write tests for all invariants.
* [x] **Phase 4:** Support PHP syntactic grammar, lots of tests
* [ ] **Phase 5 (in progress :running:):** Real-world validation and optimization
* [ ] _**Correctness:**_ validate that there are no errors produced on sample codebases, benchmark against other parsers (investigate any instance of disagreement), fuzz-testing
* [ ] _**Performance:**_ profile, benchmark against large PHP applications
* [ ] **Phase 6:** Finalize API to make it as easy as possible for people to consume.
* [ ] **Phase 6:** Finalize API to make it as easy as possible for people to consume.
### Additional notes
A few of the PHP grammatical constructs (namely yield-expression, and template strings)
are not yet supported and there are also other miscellaneous bugs. However, because the parser is error-tolerant,
these errors are handled gracefully, and the resulting tree is otherwise complete. To get a more holistic sense for
where we are, you can run the "validation" test suite (see [Contributing Guidelines](Contributing.md) for more info
where we are, you can run the "validation" test suite (see [Contributing Guidelines](Contributing.md) for more info
on running tests). Or simply, take a look at the current [validation test results](https://travis-ci.org/Microsoft/tolerant-php-parser).
Even though we haven't yet begun the performance optimization stage, we have seen promising results so far,
and have plenty more room for improvement. See [How It Works](docs/HowItWorks.md) for details on our current
approach, and run the [Performance Tests](Contributing.md#running-performance-tests) on your
Even though we haven't yet begun the performance optimization stage, we have seen promising results so far,
and have plenty more room for improvement. See [How It Works](docs/HowItWorks.md) for details on our current
approach, and run the [Performance Tests](Contributing.md#running-performance-tests) on your
own machine to see for yourself.
## Learn more
@ -119,7 +121,7 @@ own machine to see for yourself.
**:book: [Documentation](docs/GettingStarted.md#getting-started)** - learn how to reference the parser from your project, and how to perform
operations on the AST to answer questions about your code.
**:eyes: [Syntax Visualizer Tool](syntax-visualizer/client#php-parser-syntax-visualizer-tool)** - get a more tangible feel for the AST. Get creative - see if you can break it!
**:eyes: [Syntax Visualizer Tool](syntax-visualizer/client#php-parser-syntax-visualizer-tool)** - get a more tangible feel for the AST. Get creative - see if you can break it!
**:chart_with_upwards_trend: [Current Status and Approach](#current-status-and-approach)** - how much of the grammar is supported? Performance? Memory? API stability?
@ -131,10 +133,10 @@ operations on the AST to answer questions about your code.
* [Validation Strategy](docs/HowItWorks.md#validation-strategy)
**:sparkling_heart: [Contribute!](Contributing.md)** - learn how to get involved, check out some pointers to educational commits that'll
help you ramp up on the codebase (even if you've never worked on a parser before),
help you ramp up on the codebase (even if you've never worked on a parser before),
and recommended workflows that make it easier to iterate.
---
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact
[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

Просмотреть файл

@ -3,10 +3,10 @@
"description": "Tolerant PHP-to-AST parser designed for IDE usage scenarios",
"type": "library",
"require": {
"php": ">=7.0"
"php": ">=7.2"
},
"require-dev": {
"phpunit/phpunit": "^6.4|^7.5.20"
"phpunit/phpunit": "^8.5.15"
},
"license": "MIT",
"authors": [

Просмотреть файл

@ -10,15 +10,15 @@
```php
public function getNodeKindName ( ) : string
```
### Node::getStart
### Node::getStartPosition
Gets start position of Node, not including leading comments and whitespace.
```php
public function getStart ( ) : int
public function getStartPosition ( ) : int
```
### Node::getFullStart
### Node::getFullStartPosition
Gets start position of Node, including leading comments and whitespace
```php
public function getFullStart ( ) : int
public function getFullStartPosition ( ) : int
```
### Node::getParent
Gets parent of current node (returns null if has no parent)
@ -198,11 +198,11 @@ public function getFullText ( string & $document ) : string
```php
public function getStartPosition ( )
```
### Token::getFullStart
### Token::getFullStartPosition
> TODO: add doc comment
```php
public function getFullStart ( )
public function getFullStartPosition ( )
```
### Token::getWidth
> TODO: add doc comment

Просмотреть файл

@ -34,33 +34,11 @@ class FilePositionMap {
$this->lineForCurrentOffset = 1;
}
/**
* @param Node $node the node to get the start line for.
* TODO deprecate and merge this and getTokenStartLine into getStartLine
* if https://github.com/Microsoft/tolerant-php-parser/issues/166 is fixed,
* (i.e. if there is a consistent way to get the start offset)
*/
public function getNodeStartLine(Node $node) : int {
return $this->getLineNumberForOffset($node->getStart());
}
/**
* @param Token $token the token to get the start line for.
*/
public function getTokenStartLine(Token $token) : int {
return $this->getLineNumberForOffset($token->start);
}
/**
* @param Node|Token $node
*/
public function getStartLine($node) : int {
if ($node instanceof Token) {
$offset = $node->start;
} else {
$offset = $node->getStart();
}
return $this->getLineNumberForOffset($offset);
return $this->getLineNumberForOffset($node->getStartPosition());
}
/**
@ -68,12 +46,7 @@ class FilePositionMap {
* Similar to getStartLine but includes the column
*/
public function getStartLineCharacterPositionForOffset($node) : LineCharacterPosition {
if ($node instanceof Token) {
$offset = $node->start;
} else {
$offset = $node->getStart();
}
return $this->getLineCharacterPositionForOffset($offset);
return $this->getLineCharacterPositionForOffset($node->getStartPosition());
}
/** @param Node|Token $node */

Просмотреть файл

@ -6,11 +6,14 @@
namespace Microsoft\PhpParser;
use ReturnTypeWillChange;
class MissingToken extends Token {
public function __construct(int $kind, int $fullStart) {
parent::__construct($kind, $fullStart, $fullStart, 0);
}
#[ReturnTypeWillChange]
public function jsonSerialize() {
return array_merge(
["error" => $this->getTokenKindNameFromValue(TokenKind::MissingToken)],

Просмотреть файл

@ -11,6 +11,7 @@ use Microsoft\PhpParser\Node\NamespaceUseGroupClause;
use Microsoft\PhpParser\Node\SourceFileNode;
use Microsoft\PhpParser\Node\Statement\NamespaceDefinition;
use Microsoft\PhpParser\Node\Statement\NamespaceUseDeclaration;
use ReturnTypeWillChange;
abstract class Node implements \JsonSerializable {
const CHILD_NAMES = [];
@ -31,14 +32,8 @@ abstract class Node implements \JsonSerializable {
* @return int
* @throws \Exception
*/
public function getStart() : int {
$child = $this->getChildNodesAndTokens()->current();
if ($child instanceof Node) {
return $child->getStart();
} elseif ($child instanceof Token) {
return $child->start;
}
throw new \Exception("Unknown type in AST");
public function getStartPosition() : int {
return $this->getChildNodesAndTokens()->current()->getStartPosition();
}
/**
@ -46,7 +41,7 @@ abstract class Node implements \JsonSerializable {
* @return int
* @throws \Exception
*/
public function getFullStart() : int {
public function getFullStartPosition() : int {
foreach($this::CHILD_NAMES as $name) {
if (($child = $this->$name) !== null) {
@ -58,15 +53,7 @@ abstract class Node implements \JsonSerializable {
$child = $child[0];
}
if ($child instanceof Node) {
return $child->getFullStart();
}
if ($child instanceof Token) {
return $child->fullStart;
}
throw new \Exception("Unknown type in AST: " . \gettype($child));
return $child->getFullStartPosition();
}
};
@ -330,7 +317,7 @@ abstract class Node implements \JsonSerializable {
* @return int
*/
public function getWidth() : int {
$first = $this->getStart();
$first = $this->getStartPosition();
$last = $this->getEndPosition();
return $last - $first;
@ -342,7 +329,7 @@ abstract class Node implements \JsonSerializable {
* @return int
*/
public function getFullWidth() : int {
$first = $this->getFullStart();
$first = $this->getFullStartPosition();
$last = $this->getEndPosition();
return $last - $first;
@ -353,7 +340,7 @@ abstract class Node implements \JsonSerializable {
* @return string
*/
public function getText() : string {
$start = $this->getStart();
$start = $this->getStartPosition();
$end = $this->getEndPosition();
$fileContents = $this->getFileContents();
@ -365,7 +352,7 @@ abstract class Node implements \JsonSerializable {
* @return string
*/
public function getFullText() : string {
$start = $this->getFullStart();
$start = $this->getFullStartPosition();
$end = $this->getEndPosition();
$fileContents = $this->getFileContents();
@ -387,13 +374,14 @@ abstract class Node implements \JsonSerializable {
}
protected function getChildrenKvPairs() {
$result = array();
$result = [];
foreach ($this::CHILD_NAMES as $name) {
$result[$name] = $this->$name;
}
return $result;
}
#[ReturnTypeWillChange]
public function jsonSerialize() {
$kindName = $this->getNodeKindName();
return ["$kindName" => $this->getChildrenKvPairs()];
@ -463,7 +451,7 @@ abstract class Node implements \JsonSerializable {
* @return bool
*/
private function containsPosition(int $pos): bool {
return $this->getStart() <= $pos && $pos <= $this->getEndPosition();
return $this->getStartPosition() <= $pos && $pos <= $this->getEndPosition();
}
/**
@ -476,7 +464,7 @@ abstract class Node implements \JsonSerializable {
public function getDocCommentText() {
$leadingTriviaText = $this->getLeadingCommentAndWhitespaceText();
$leadingTriviaTokens = PhpTokenizer::getTokensArrayFromContent(
$leadingTriviaText, ParseContext::SourceElements, $this->getFullStart(), false
$leadingTriviaText, ParseContext::SourceElements, $this->getFullStartPosition(), false
);
for ($i = \count($leadingTriviaTokens) - 1; $i >= 0; $i--) {
$token = $leadingTriviaTokens[$i];
@ -509,13 +497,13 @@ abstract class Node implements \JsonSerializable {
$topLevelNamespaceStatements = $namespaceDefinition->compoundStatementOrSemicolon instanceof Token
? $namespaceDefinition->parent->statementList // we need to start from the namespace definition.
: $namespaceDefinition->compoundStatementOrSemicolon->statements;
$namespaceFullStart = $namespaceDefinition->getFullStart();
$namespaceFullStart = $namespaceDefinition->getFullStartPosition();
} else {
$topLevelNamespaceStatements = $this->getRoot()->statementList;
$namespaceFullStart = 0;
}
$nodeFullStart = $this->getFullStart();
$nodeFullStart = $this->getFullStartPosition();
// TODO optimize performance
// Currently we rebuild the import tables on every call (and therefore every name resolution operation)
@ -535,10 +523,10 @@ abstract class Node implements \JsonSerializable {
$contents = $this->getFileContents();
foreach ($topLevelNamespaceStatements as $useDeclaration) {
if ($useDeclaration->getFullStart() <= $namespaceFullStart) {
if ($useDeclaration->getFullStartPosition() <= $namespaceFullStart) {
continue;
}
if ($useDeclaration->getFullStart() > $nodeFullStart) {
if ($useDeclaration->getFullStartPosition() > $nodeFullStart) {
break;
} elseif (!($useDeclaration instanceof NamespaceUseDeclaration)) {
continue;
@ -609,11 +597,11 @@ abstract class Node implements \JsonSerializable {
throw new \Exception("Invalid tree - SourceFileNode must always exist at root of tree.");
}
$fullStart = $this->getFullStart();
$fullStart = $this->getFullStartPosition();
$lastNamespaceDefinition = null;
if ($namespaceDefinition instanceof SourceFileNode) {
foreach ($namespaceDefinition->getChildNodes() as $childNode) {
if ($childNode instanceof NamespaceDefinition && $childNode->getFullStart() < $fullStart) {
if ($childNode instanceof NamespaceDefinition && $childNode->getFullStartPosition() < $fullStart) {
$lastNamespaceDefinition = $childNode;
}
}
@ -662,7 +650,7 @@ abstract class Node implements \JsonSerializable {
* Add the alias and resolved name to the corresponding namespace, function, or const import table.
* If the alias already exists, it will get replaced by the most recent using.
*
* TODO - worth throwing an error here in stead?
* TODO - worth throwing an error here instead?
*/
private function addToImportTable($alias, $functionOrConst, $namespaceNameParts, $contents, & $namespaceImportTable, & $functionImportTable, & $constImportTable):array
{
@ -671,20 +659,20 @@ abstract class Node implements \JsonSerializable {
// namespaces are case-insensitive
// $alias = \strtolower($alias);
$namespaceImportTable[$alias] = ResolvedName::buildName($namespaceNameParts, $contents);
return array($namespaceImportTable, $functionImportTable, $constImportTable);
return [$namespaceImportTable, $functionImportTable, $constImportTable];
} elseif ($functionOrConst->kind === TokenKind::FunctionKeyword) {
// functions are case-insensitive
// $alias = \strtolower($alias);
$functionImportTable[$alias] = ResolvedName::buildName($namespaceNameParts, $contents);
return array($namespaceImportTable, $functionImportTable, $constImportTable);
return [$namespaceImportTable, $functionImportTable, $constImportTable];
} elseif ($functionOrConst->kind === TokenKind::ConstKeyword) {
// constants are case-sensitive
$constImportTable[$alias] = ResolvedName::buildName($namespaceNameParts, $contents);
return array($namespaceImportTable, $functionImportTable, $constImportTable);
return [$namespaceImportTable, $functionImportTable, $constImportTable];
}
return array($namespaceImportTable, $functionImportTable, $constImportTable);
return [$namespaceImportTable, $functionImportTable, $constImportTable];
}
return array($namespaceImportTable, $functionImportTable, $constImportTable);
return [$namespaceImportTable, $functionImportTable, $constImportTable];
}
/**

Просмотреть файл

@ -7,6 +7,8 @@
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node\DelimitedList\QualifiedNameList;
use Microsoft\PhpParser\MissingToken;
use Microsoft\PhpParser\Token;
class CatchClause extends Node {
@ -14,16 +16,8 @@ class CatchClause extends Node {
public $catch;
/** @var Token */
public $openParen;
/** @var QualifiedName */
public $qualifiedName;
/**
* @var QualifiedName[]|Token[] Remaining tokens and qualified names in the catch clause
* (e.g. `catch (FirstException|SecondException $x)` would contain
* the representation of `|SecondException`)
*
* TODO: In the next backwards incompatible release, replace qualifiedName with qualifiedNameList?
*/
public $otherQualifiedNameList;
/** @var QualifiedNameList[]|MissingToken */
public $qualifiedNameList;
/** @var Token|null */
public $variableName;
/** @var Token */
@ -34,8 +28,7 @@ class CatchClause extends Node {
const CHILD_NAMES = [
'catch',
'openParen',
'qualifiedName',
'otherQualifiedNameList',
'qualifiedNameList',
'variableName',
'closeParen',
'compoundStatement'

Просмотреть файл

@ -38,8 +38,7 @@ class AnonymousFunctionCreationExpression extends Expression implements Function
// FunctionReturnType
'colonToken',
'questionToken',
'returnType',
'otherReturnTypes',
'returnTypeList',
// FunctionBody
'compoundStatementOrSemicolon'

Просмотреть файл

@ -10,15 +10,12 @@ use Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\Token;
class ArgumentExpression extends Expression {
/** @var Token|null for php named arguments. If this is set, byRefToken and dotDotDotToken will not be set. */
/** @var Token|null for php named arguments. If this is set, dotDotDotToken will not be set. */
public $name;
/** @var Token|null */
public $colonToken;
/** @var Token|null */
public $byRefToken; // TODO removed in newer versions of PHP. Also only accept variable, not expression if byRef
/** @var Token|null */
public $dotDotDotToken;
@ -28,7 +25,6 @@ class ArgumentExpression extends Expression {
const CHILD_NAMES = [
'name',
'colonToken',
'byRefToken',
'dotDotDotToken',
'expression'
];

Просмотреть файл

@ -40,8 +40,7 @@ class ArrowFunctionCreationExpression extends Expression implements FunctionLike
// FunctionReturnType
'colonToken',
'questionToken',
'returnType',
'otherReturnTypes',
'returnTypeList',
// body
'arrowToken',

Просмотреть файл

@ -11,10 +11,9 @@ use Microsoft\PhpParser\Token;
trait FunctionReturnType {
/** @var Token */
public $colonToken;
// TODO: This may be the wrong choice if ?type can ever be mixed with other types in union types
/** @var Token|null */
public $questionToken;
/** @var Token|QualifiedName */
public $returnType;
/** @var DelimitedList\QualifiedNameList|null TODO: Merge with returnType in a future backwards incompatible release */
public $otherReturnTypes;
/** @var DelimitedList\QualifiedNameList|null */
public $returnTypeList;
}

Просмотреть файл

@ -34,8 +34,7 @@ class MethodDeclaration extends Node implements FunctionLike, ModifiedTypeInterf
// FunctionReturnType
'colonToken',
'questionToken',
'returnType',
'otherReturnTypes',
'returnTypeList',
// FunctionBody
'compoundStatementOrSemicolon'

Просмотреть файл

@ -20,17 +20,13 @@ class MissingMemberDeclaration extends Node implements ModifiedTypeInterface {
/** @var Token|null needed along with typeDeclaration for what looked like typed property declarations but was missing VariableName */
public $questionToken;
/** @var QualifiedName|Token|null */
public $typeDeclaration;
/** @var DelimitedList\QualifiedNameList|null */
public $otherTypeDeclarations;
public $typeDeclarationList;
const CHILD_NAMES = [
'attributes',
'modifiers',
'questionToken',
'typeDeclaration',
'otherTypeDeclarations',
'typeDeclarationList',
];
}

Просмотреть файл

@ -6,6 +6,7 @@
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\MissingToken;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
@ -16,13 +17,8 @@ class Parameter extends Node {
public $visibilityToken;
/** @var Token|null */
public $questionToken;
/** @var QualifiedName|Token|null */
public $typeDeclaration;
/**
* @var DelimitedList\QualifiedNameList a list of other types, to support php 8 union types while remaining backwards compatible.
* TODO: Merge with typeDeclaration in a future backwards incompatible release.
*/
public $otherTypeDeclarations;
/** @var DelimitedList\QualifiedNameList|MissingToken|null */
public $typeDeclarationList;
/** @var Token|null */
public $byRefToken;
/** @var Token|null */
@ -38,8 +34,7 @@ class Parameter extends Node {
'attributes',
'visibilityToken',
'questionToken',
'typeDeclaration',
'otherTypeDeclarations',
'typeDeclarationList',
'byRefToken',
'dotDotDotToken',
'variableName',

Просмотреть файл

@ -6,9 +6,11 @@
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\MissingToken;
use Microsoft\PhpParser\ModifiedTypeInterface;
use Microsoft\PhpParser\ModifiedTypeTrait;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node\DelimitedList\QualifiedNameList;
use Microsoft\PhpParser\Token;
class PropertyDeclaration extends Node implements ModifiedTypeInterface {
@ -20,14 +22,8 @@ class PropertyDeclaration extends Node implements ModifiedTypeInterface {
/** @var Token|null question token for PHP 7.4 type declaration */
public $questionToken;
/** @var QualifiedName|Token|null */
public $typeDeclaration;
/**
* @var DelimitedList\QualifiedNameList|null
* TODO: Unify with typeDeclaration in a future backwards incompatible release
*/
public $otherTypeDeclarations;
/** @var QualifiedNameList|MissingToken|null */
public $typeDeclarationList;
/** @var DelimitedList\ExpressionList */
public $propertyElements;
@ -39,8 +35,7 @@ class PropertyDeclaration extends Node implements ModifiedTypeInterface {
'attributes',
'modifiers',
'questionToken',
'typeDeclaration',
'otherTypeDeclarations',
'typeDeclarationList',
'propertyElements',
'semicolon'
];

Просмотреть файл

@ -81,7 +81,7 @@ class QualifiedName extends Node implements NamespacedNameInterface {
*/
public function getResolvedName($namespaceDefinition = null) {
// Name resolution not applicable to constructs that define symbol names or aliases.
if (($this->parent instanceof Node\Statement\NamespaceDefinition && $this->parent->name->getStart() === $this->getStart()) ||
if (($this->parent instanceof Node\Statement\NamespaceDefinition && $this->parent->name->getStartPosition() === $this->getStartPosition()) ||
$this->parent instanceof Node\Statement\NamespaceUseDeclaration ||
$this->parent instanceof Node\NamespaceUseClause ||
$this->parent instanceof Node\NamespaceUseGroupClause ||
@ -110,7 +110,7 @@ class QualifiedName extends Node implements NamespacedNameInterface {
return $this->getNamespacedName();
}
list($namespaceImportTable, $functionImportTable, $constImportTable) = $this->getImportTablesForCurrentScope();
[$namespaceImportTable, $functionImportTable, $constImportTable] = $this->getImportTablesForCurrentScope();
// QUALIFIED NAMES
// - first segment of the name is translated according to the current class/namespace import table.

Просмотреть файл

@ -60,12 +60,7 @@ class BreakOrContinueStatement extends StatementNode {
}
}
if ($breakoutLevel instanceof Token) {
$start = $breakoutLevel->getStartPosition();
}
else {
$start = $breakoutLevel->getStart();
}
$start = $breakoutLevel->getStartPosition();
$end = $breakoutLevel->getEndPosition();
return new Diagnostic(

Просмотреть файл

@ -6,7 +6,7 @@
namespace Microsoft\PhpParser\Node\Statement;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\MissingToken;
use Microsoft\PhpParser\Node\DelimitedList;
use Microsoft\PhpParser\Node\StatementNode;
use Microsoft\PhpParser\Token;
@ -16,10 +16,9 @@ class DeclareStatement extends StatementNode {
public $declareKeyword;
/** @var Token */
public $openParen;
/** @var Node */
public $declareDirective;
/** @var DelimitedList\DeclareDirectiveList|null TODO: Merge with $declareDirective in a future backwards incompatible release. */
public $otherDeclareDirectives;
// TODO Maybe create a delimited list with a missing token instead? Probably more consistent.
/** @var DelimitedList\DeclareDirectiveList|MissingToken */
public $declareDirectiveList;
/** @var Token */
public $closeParen;
/** @var Token|null */
@ -34,8 +33,7 @@ class DeclareStatement extends StatementNode {
const CHILD_NAMES = [
'declareKeyword',
'openParen',
'declareDirective',
'otherDeclareDirectives',
'declareDirectiveList',
'closeParen',
'colon',
'statements',

Просмотреть файл

@ -4,20 +4,17 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\Expression;
namespace Microsoft\PhpParser\Node\Statement;
use Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\Node\StatementNode;
use Microsoft\PhpParser\Node\DelimitedList\ExpressionList;
use Microsoft\PhpParser\Token;
/**
* This represents either a literal echo expression (`echo expr`)
* This represents either a literal echo statement (`echo expr`)
* or a short echo tag (`<?= expr...`)
*
* TODO: An echo statement cannot be used as an expression.
* Consider refactoring this to become EchoStatement in a future backwards incompatible release.
*/
class EchoExpression extends Expression {
class EchoStatement extends StatementNode {
/**
* @var Token|null this is null if generated from `<?=`
@ -27,8 +24,12 @@ class EchoExpression extends Expression {
/** @var ExpressionList */
public $expressions;
/** @var Token */
public $semicolon;
const CHILD_NAMES = [
'echoKeyword',
'expressions'
'expressions',
'semicolon',
];
}

Просмотреть файл

@ -31,8 +31,7 @@ class FunctionDeclaration extends StatementNode implements NamespacedNameInterfa
// FunctionReturnType
'colonToken',
'questionToken',
'returnType',
'otherReturnTypes',
'returnTypeList',
// FunctionBody
'compoundStatementOrSemicolon'

Просмотреть файл

@ -14,15 +14,9 @@ class NamedLabelStatement extends StatementNode {
public $name;
/** @var Token */
public $colon;
/**
* @var null this is always null as of 0.0.23
* TODO: Clean this up in the next major release.
*/
public $statement;
const CHILD_NAMES = [
'name',
'colon',
'statement'
];
}

Просмотреть файл

@ -1,27 +0,0 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\Statement;
use Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\Node\StatementNode;
use Microsoft\PhpParser\Token;
// TODO: Remove this and replace with ThrowExpression in a backwards incompatible major release
class ThrowStatement extends StatementNode {
/** @var Token */
public $throwKeyword;
/** @var Expression */
public $expression;
/** @var Token */
public $semicolon;
const CHILD_NAMES = [
'throwKeyword',
'expression',
'semicolon'
];
}

Просмотреть файл

@ -4,13 +4,13 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\Expression;
namespace Microsoft\PhpParser\Node\Statement;
use Microsoft\PhpParser\Node\DelimitedList;
use Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\Token;
class UnsetIntrinsicExpression extends Expression {
class UnsetStatement extends Expression {
/** @var Token */
public $unsetKeyword;
@ -24,10 +24,14 @@ class UnsetIntrinsicExpression extends Expression {
/** @var Token */
public $closeParen;
/** @var Token */
public $semicolon;
const CHILD_NAMES = [
'unsetKeyword',
'openParen',
'expressions',
'closeParen'
'closeParen',
'semicolon',
];
}

Просмотреть файл

@ -9,6 +9,7 @@ namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\ModifiedTypeInterface;
use Microsoft\PhpParser\ModifiedTypeTrait;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node\DelimitedList\QualifiedNameList;
use Microsoft\PhpParser\Token;
class TraitSelectOrAliasClause extends Node implements ModifiedTypeInterface {
@ -20,29 +21,15 @@ class TraitSelectOrAliasClause extends Node implements ModifiedTypeInterface {
/** @var Token */
public $asOrInsteadOfKeyword;
/** @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`
* @var QualifiedNameList|QualifiedName depends on the keyword
*/
public $remainingTargetNames;
public $targetNameList;
const CHILD_NAMES = [
'name',
'asOrInsteadOfKeyword',
'modifiers',
'targetName',
'remainingTargetNames',
'targetNameList',
];
}

Просмотреть файл

@ -40,7 +40,6 @@ use Microsoft\PhpParser\Node\Expression\{
ParenthesizedExpression,
PrefixUpdateExpression,
PrintIntrinsicExpression,
EchoExpression,
ListIntrinsicExpression,
ObjectCreationExpression,
ScriptInclusionExpression,
@ -51,7 +50,6 @@ use Microsoft\PhpParser\Node\Expression\{
ThrowExpression,
UnaryExpression,
UnaryOpExpression,
UnsetIntrinsicExpression,
Variable,
YieldExpression
};
@ -89,6 +87,7 @@ use Microsoft\PhpParser\Node\Statement\{
BreakOrContinueStatement,
DeclareStatement,
DoStatement,
EchoStatement,
EmptyStatement,
EnumDeclaration,
ExpressionStatement,
@ -104,9 +103,9 @@ use Microsoft\PhpParser\Node\Statement\{
NamedLabelStatement,
ReturnStatement,
SwitchStatementNode,
ThrowStatement,
TraitDeclaration,
TryStatement,
UnsetStatement,
WhileStatement
};
use Microsoft\PhpParser\Node\TraitMembers;
@ -180,7 +179,7 @@ class Parser {
$this->sourceFile = $sourceFile;
$sourceFile->fileContents = $fileContents;
$sourceFile->uri = $uri;
$sourceFile->statementList = array();
$sourceFile->statementList = [];
if ($this->getCurrentToken()->kind !== TokenKind::EndOfFileToken) {
$inlineHTML = $this->parseInlineHtml($sourceFile);
$sourceFile->statementList[] = $inlineHTML;
@ -222,7 +221,7 @@ class Parser {
$this->currentParseContext |= 1 << $listParseContext;
$parseListElementFn = $this->getParseListElementFn($listParseContext);
$nodeArray = array();
$nodeArray = [];
while (!$this->isListTerminator($listParseContext)) {
if ($this->isValidListElement($listParseContext, $this->getCurrentToken())) {
$element = $parseListElementFn($parentNode);
@ -534,8 +533,6 @@ class Parser {
return $this->parseBreakOrContinueStatement($parentNode);
case TokenKind::ReturnKeyword: // return-statement
return $this->parseReturnStatement($parentNode);
case TokenKind::ThrowKeyword: // throw-statement
return $this->parseThrowStatement($parentNode);
// try-statement
case TokenKind::TryKeyword:
@ -830,13 +827,10 @@ class Parser {
}
$parameter->visibilityToken = $this->eatOptional([TokenKind::PublicKeyword, TokenKind::ProtectedKeyword, TokenKind::PrivateKeyword]);
$parameter->questionToken = $this->eatOptional1(TokenKind::QuestionToken);
$typeDeclarationList = $this->tryParseParameterTypeDeclarationList($parameter);
if ($typeDeclarationList) {
$parameter->typeDeclaration = array_shift($typeDeclarationList->children);
$parameter->typeDeclaration->parent = $parameter;
if ($typeDeclarationList->children) {
$parameter->otherTypeDeclarations = $typeDeclarationList;
}
$parameter->typeDeclarationList = $this->tryParseParameterTypeDeclarationList($parameter);
if ($parameter->questionToken && !$parameter->typeDeclarationList) {
// TODO ParameterType?
$parameter->typeDeclarationList = new MissingToken(TokenKind::PropertyType, $this->token->fullStart);
}
$parameter->byRefToken = $this->eatOptional1(TokenKind::AmpersandToken);
// TODO add post-parse rule that prevents assignment
@ -858,15 +852,10 @@ class Parser {
private function parseAndSetReturnTypeDeclarationList($parentNode) {
$returnTypeList = $this->parseReturnTypeDeclarationList($parentNode);
if (!$returnTypeList) {
$parentNode->returnType = new MissingToken(TokenKind::ReturnType, $this->token->fullStart);
$parentNode->returnTypeList = new MissingToken(TokenKind::ReturnType, $this->token->fullStart);
return;
}
$returnType = array_shift($returnTypeList->children);
$parentNode->returnType = $returnType;
$returnType->parent = $parentNode;
if ($returnTypeList->children) {
$parentNode->otherReturnTypes = $returnTypeList;
}
$parentNode->returnTypeList = $returnTypeList;
}
/**
@ -1304,7 +1293,7 @@ class Parser {
$expression = new StringLiteral();
$expression->parent = $parentNode;
$expression->startQuote = $this->eat(TokenKind::SingleQuoteToken, TokenKind::DoubleQuoteToken, TokenKind::HeredocStart, TokenKind::BacktickToken);
$expression->children = array();
$expression->children = [];
while (true) {
switch ($this->getCurrentToken()->kind) {
@ -1460,7 +1449,7 @@ class Parser {
}
private function parseModifiers() {
$modifiers = array();
$modifiers = [];
$token = $this->getCurrentToken();
while ($this->isModifier($token)) {
$modifiers[] = $token;
@ -1974,12 +1963,12 @@ class Parser {
private function parseBinaryExpressionOrHigher($precedence, $parentNode) {
$leftOperand = $this->parseUnaryExpressionOrHigher($parentNode);
list($prevNewPrecedence, $prevAssociativity) = self::UNKNOWN_PRECEDENCE_AND_ASSOCIATIVITY;
[$prevNewPrecedence, $prevAssociativity] = self::UNKNOWN_PRECEDENCE_AND_ASSOCIATIVITY;
while (true) {
$token = $this->getCurrentToken();
list($newPrecedence, $associativity) = $this->getBinaryOperatorPrecedenceAndAssociativity($token);
[$newPrecedence, $associativity] = $this->getBinaryOperatorPrecedenceAndAssociativity($token);
// Expressions using operators w/o associativity (equality, relational, instanceof)
// cannot reference identical expression types within one of their operands.
@ -2410,17 +2399,7 @@ class Parser {
return $returnStatement;
}
private function parseThrowStatement($parentNode) {
$throwStatement = new ThrowStatement();
$throwStatement->parent = $parentNode;
$throwStatement->throwKeyword = $this->eat1(TokenKind::ThrowKeyword);
// TODO error for failures to parse expressions when not optional
$throwStatement->expression = $this->parseExpression($throwStatement);
$throwStatement->semicolon = $this->eatSemicolonOrAbortStatement();
return $throwStatement;
}
/** @return ThrowExpression */
private function parseThrowExpression($parentNode) {
$throwExpression = new ThrowExpression();
$throwExpression->parent = $parentNode;
@ -2437,7 +2416,7 @@ class Parser {
$tryStatement->tryKeyword = $this->eat1(TokenKind::TryKeyword);
$tryStatement->compoundStatement = $this->parseCompoundStatement($tryStatement); // TODO verifiy this is only compound
$tryStatement->catchClauses = array(); // TODO - should be some standard for empty arrays vs. null?
$tryStatement->catchClauses = []; // TODO - should be some standard for empty arrays vs. null?
while ($this->checkToken(TokenKind::CatchKeyword)) {
$tryStatement->catchClauses[] = $this->parseCatchClause($tryStatement);
}
@ -2454,9 +2433,7 @@ class Parser {
$catchClause->parent = $parentNode;
$catchClause->catch = $this->eat1(TokenKind::CatchKeyword);
$catchClause->openParen = $this->eat1(TokenKind::OpenParenToken);
$qualifiedNameList = $this->parseQualifiedNameCatchList($catchClause)->children ?? [];
$catchClause->qualifiedName = $qualifiedNameList[0] ?? null; // TODO generate missing token or error if null
$catchClause->otherQualifiedNameList = array_slice($qualifiedNameList, 1); // TODO: Generate error if the name list has missing tokens
$catchClause->qualifiedNameList = $this->parseQualifiedNameCatchList($catchClause) ?? new MissingToken(TokenKind::QualifiedName, $this->token->fullStart); // TODO generate missing token or error if null
$catchClause->variableName = $this->eatOptional1(TokenKind::VariableName);
$catchClause->closeParen = $this->eat1(TokenKind::CloseParenToken);
$catchClause->compoundStatement = $this->parseCompoundStatement($catchClause);
@ -2501,27 +2478,7 @@ class Parser {
private function parseAndSetDeclareDirectiveList($parentNode) {
$declareDirectiveList = $this->parseDeclareDirectiveList($parentNode);
if (!$declareDirectiveList) {
$declareDirective = new DeclareDirective();
$declareDirective->parent = $parentNode;
$declareDirective->name = new MissingToken(TokenKind::Name, $this->token->fullStart);
$declareDirective->equals = new MissingToken(TokenKind::EqualsToken, $this->token->fullStart);
// TODO: This is matching the first token in $this::parseDeclareDirectiveFn.
// Probably best to emit a more general "literal error".
$declareDirective->literal = new MissingToken(TokenKind::FloatingLiteralToken, $this->token->fullStart);
$parentNode->declareDirective = $declareDirective;
return;
}
$declareDirective = array_shift($declareDirectiveList->children);
$parentNode->declareDirective = $declareDirective;
$declareDirective->parent = $parentNode;
if ($declareDirectiveList->children) {
$parentNode->otherDeclareDirectives = $declareDirectiveList;
}
$parentNode->declareDirectiveList = $declareDirectiveList ?? new MissingToken(TokenKind::Name, $this->token->fullStart);
}
/**
@ -2645,34 +2602,15 @@ class Parser {
return $scriptInclusionExpression;
}
/** @return EchoStatement */
private function parseEchoStatement($parentNode) {
$expressionStatement = new ExpressionStatement();
// TODO: Could flatten into EchoStatement instead?
$echoExpression = new EchoExpression();
$echoExpression->parent = $expressionStatement;
$echoExpression->echoKeyword = $this->eat1(TokenKind::EchoKeyword);
$echoExpression->expressions =
$this->parseExpressionList($echoExpression);
$expressionStatement->parent = $parentNode;
$expressionStatement->expression = $echoExpression;
$expressionStatement->semicolon = $this->eatSemicolonOrAbortStatement();
return $expressionStatement;
}
private function parseUnsetStatement($parentNode) {
$expressionStatement = new ExpressionStatement();
// TODO: Could flatten into UnsetStatement instead?
$unsetExpression = $this->parseUnsetIntrinsicExpression($expressionStatement);
$expressionStatement->parent = $parentNode;
$expressionStatement->expression = $unsetExpression;
$expressionStatement->semicolon = $this->eatSemicolonOrAbortStatement();
return $expressionStatement;
$echoStatement = new EchoStatement();
$echoStatement->parent = $parentNode;
$echoStatement->echoKeyword = $this->eat1(TokenKind::EchoKeyword);
$echoStatement->expressions =
$this->parseExpressionList($echoStatement);
$echoStatement->semicolon = $this->eatSemicolonOrAbortStatement();
return $echoStatement;
}
private function parseListIntrinsicExpression($parentNode) {
@ -2739,16 +2677,16 @@ class Parser {
);
}
private function parseUnsetIntrinsicExpression($parentNode) {
$unsetExpression = new UnsetIntrinsicExpression();
$unsetExpression->parent = $parentNode;
private function parseUnsetStatement($parentNode) {
$unsetStatement = new UnsetStatement();
$unsetStatement->parent = $parentNode;
$unsetExpression->unsetKeyword = $this->eat1(TokenKind::UnsetKeyword);
$unsetExpression->openParen = $this->eat1(TokenKind::OpenParenToken);
$unsetExpression->expressions = $this->parseExpressionList($unsetExpression);
$unsetExpression->closeParen = $this->eat1(TokenKind::CloseParenToken);
return $unsetExpression;
$unsetStatement->unsetKeyword = $this->eat1(TokenKind::UnsetKeyword);
$unsetStatement->openParen = $this->eat1(TokenKind::OpenParenToken);
$unsetStatement->expressions = $this->parseExpressionList($unsetStatement);
$unsetStatement->closeParen = $this->eat1(TokenKind::CloseParenToken);
$unsetStatement->semicolon = $this->eatSemicolonOrAbortStatement();
return $unsetStatement;
}
private function parseArrayCreationExpression($parentNode) {
@ -3003,7 +2941,6 @@ class Parser {
$argumentExpression->name = $name;
$argumentExpression->colonToken = $this->eat1(TokenKind::ColonToken);
} else {
$argumentExpression->byRefToken = $this->eatOptional1(TokenKind::AmpersandToken);
$argumentExpression->dotDotDotToken = $this->eatOptional1(TokenKind::DotDotDotToken);
}
$argumentExpression->expression = $this->parseExpression($argumentExpression);
@ -3261,18 +3198,10 @@ class Parser {
$propertyDeclaration->modifiers = $modifiers;
$propertyDeclaration->questionToken = $questionToken;
if ($typeDeclarationList) {
/** $typeDeclarationList is a Node or a Token (e.g. IntKeyword) */
$typeDeclaration = \array_shift($typeDeclarationList->children);
$propertyDeclaration->typeDeclaration = $typeDeclaration;
if ($typeDeclaration instanceof Node) {
$typeDeclaration->parent = $propertyDeclaration;
}
if ($typeDeclarationList->children) {
$propertyDeclaration->otherTypeDeclarations = $typeDeclarationList;
$typeDeclarationList->parent = $propertyDeclaration;
}
$propertyDeclaration->typeDeclarationList = $typeDeclarationList;
$typeDeclarationList->parent = $propertyDeclaration;
} elseif ($questionToken) {
$propertyDeclaration->typeDeclaration = new MissingToken(TokenKind::PropertyType, $this->token->fullStart);
$propertyDeclaration->typeDeclarationList = new MissingToken(TokenKind::PropertyType, $this->token->fullStart);
}
$propertyDeclaration->propertyElements = $this->parseExpressionList($propertyDeclaration);
$propertyDeclaration->semicolon = $this->eat1(TokenKind::SemicolonToken);
@ -3664,14 +3593,10 @@ class Parser {
$missingTraitMemberDeclaration->modifiers = $modifiers;
$missingTraitMemberDeclaration->questionToken = $questionToken;
if ($typeDeclarationList) {
$missingTraitMemberDeclaration->typeDeclaration = \array_shift($typeDeclarationList->children);
$missingTraitMemberDeclaration->typeDeclaration->parent = $missingTraitMemberDeclaration;
if ($typeDeclarationList->children) {
$missingTraitMemberDeclaration->otherTypeDeclarations = $typeDeclarationList;
$typeDeclarationList->parent = $missingTraitMemberDeclaration;
}
$missingTraitMemberDeclaration->typeDeclarationList = $typeDeclarationList;
$missingTraitMemberDeclaration->typeDeclarationList->parent = $missingTraitMemberDeclaration;
} elseif ($questionToken) {
$missingTraitMemberDeclaration->typeDeclaration = new MissingToken(TokenKind::PropertyType, $this->token->fullStart);
$missingTraitMemberDeclaration->typeDeclarationList = new MissingToken(TokenKind::PropertyType, $this->token->fullStart);
}
return $missingTraitMemberDeclaration;
}
@ -3713,15 +3638,10 @@ class Parser {
$traitSelectAndAliasClause->modifiers = $this->parseModifiers(); // TODO accept all modifiers, verify later
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] ?? new MissingToken(TokenKind::BarToken, $this->token->fullStart);
$traitSelectAndAliasClause->remainingTargetNames = array_slice($interfaceNameList, 1);
$traitSelectAndAliasClause->targetNameList = $this->parseQualifiedNameList($traitSelectAndAliasClause);
} else {
$traitSelectAndAliasClause->targetName =
$traitSelectAndAliasClause->targetNameList =
$this->parseQualifiedNameOrScopedPropertyAccessExpression($traitSelectAndAliasClause);
$traitSelectAndAliasClause->remainingTargetNames = [];
}
// TODO errors for insteadof/as
@ -4033,14 +3953,10 @@ class Parser {
// This is the easiest way to represent `<?= "expr", "other" `
if (($inlineHtml->scriptSectionStartTag->kind ?? null) === TokenKind::ScriptSectionStartWithEchoTag) {
$echoStatement = new ExpressionStatement();
$echoStatement = new EchoStatement();
$expressionList = $this->parseExpressionList($echoStatement) ?? (new MissingToken(TokenKind::Expression, $this->token->fullStart));
$echoStatement->expressions = $expressionList;
$echoExpression = new EchoExpression();
$expressionList = $this->parseExpressionList($echoExpression) ?? (new MissingToken(TokenKind::Expression, $this->token->fullStart));
$echoExpression->expressions = $expressionList;
$echoExpression->parent = $echoStatement;
$echoStatement->expression = $echoExpression;
$echoStatement->semicolon = $this->eatSemicolonOrAbortStatement();
$echoStatement->parent = $inlineHtml;
// Deliberately leave echoKeyword as null instead of MissingToken

Просмотреть файл

@ -82,7 +82,7 @@ class PhpTokenizer implements TokenStreamProviderInterface {
$tokens = static::tokenGetAll($content, $parseContext);
$arr = array();
$arr = [];
$fullStart = $start = $pos = $initialPos;
if ($parseContext !== null) {
// If needed, skip over the prefix we added for token_get_all and remove those tokens.

Просмотреть файл

@ -6,11 +6,14 @@
namespace Microsoft\PhpParser;
use ReturnTypeWillChange;
class SkippedToken extends Token {
public function __construct(Token $token) {
parent::__construct($token->kind, $token->fullStart, $token->start, $token->length);
}
#[ReturnTypeWillChange]
public function jsonSerialize() {
return array_merge(
["error" => $this->getTokenKindNameFromValue(TokenKind::SkippedToken)],

Просмотреть файл

@ -6,6 +6,8 @@
namespace Microsoft\PhpParser;
use ReturnTypeWillChange;
use function substr;
class Token implements \JsonSerializable {
@ -61,7 +63,7 @@ class Token implements \JsonSerializable {
/**
* @return int
*/
public function getFullStart() {
public function getFullStartPosition() {
return $this->fullStart;
}
@ -110,6 +112,7 @@ class Token implements \JsonSerializable {
return $mapToKindName[$kind] ?? $kind;
}
#[ReturnTypeWillChange]
public function jsonSerialize() {
$kindName = $this->getTokenKindNameFromValue($this->kind);

Просмотреть файл

@ -9,7 +9,7 @@ namespace Microsoft\PhpParser;
use Microsoft\PhpParser\TokenKind;
class TokenStringMaps {
const KEYWORDS = array(
const KEYWORDS = [
"abstract" => TokenKind::AbstractKeyword,
"and" => TokenKind::AndKeyword,
"array" => TokenKind::ArrayKeyword,
@ -82,7 +82,7 @@ class TokenStringMaps {
// TODO soft reserved words?
);
];
const RESERVED_WORDS = [
// http://php.net/manual/en/reserved.constants.php
@ -109,7 +109,7 @@ class TokenStringMaps {
"mixed" => TokenKind::MixedReservedWord,
];
const OPERATORS_AND_PUNCTUATORS = array(
const OPERATORS_AND_PUNCTUATORS = [
"[" => TokenKind::OpenBracketToken,
"]" => TokenKind::CloseBracketToken,
"(" => TokenKind::OpenParenToken,
@ -182,7 +182,7 @@ class TokenStringMaps {
"?>\r" => TokenKind::ScriptSectionEndTag, // TODO, technically not an operator
"@" => TokenKind::AtSymbolToken, // TODO not in spec
"`" => TokenKind::BacktickToken
);
];
// TODO add new tokens
}

Просмотреть файл

@ -9,28 +9,13 @@ use PHPUnit\Framework\TestListener;
use PHPUnit\Framework\TestListenerDefaultImplementation;
use PHPUnit\Framework\AssertionFailedError;
if (PHP_VERSION_ID >= 70100) {
// PHPUnit 7 requires a return type of void, which is impossible in php 7.0
class CallbackTestListener implements TestListener {
private $cb;
public function __construct(Closure $cb) {
$this->cb = $cb;
}
use TestListenerDefaultImplementation;
// php 7.1 does not support param type widening.
function addFailure(Test $test, AssertionFailedError $e, float $time): void {
($this->cb)($test);
}
class CallbackTestListener implements TestListener {
private $cb;
public function __construct(Closure $cb) {
$this->cb = $cb;
}
} else {
class CallbackTestListener implements TestListener {
private $cb;
public function __construct(Closure $cb) {
$this->cb = $cb;
}
use TestListenerDefaultImplementation;
function addFailure(Test $test, AssertionFailedError $e, $time) {
($this->cb)($test);
}
use TestListenerDefaultImplementation;
function addFailure(Test $test, AssertionFailedError $e, float $time): void {
($this->cb)($test);
}
}

Просмотреть файл

@ -10,13 +10,13 @@ use PHPUnit\Framework\TestCase;
use Microsoft\PhpParser\TokenKind;
class LexerInvariantsTest extends TestCase {
const FILENAMES = array(
const FILENAMES = [
__dir__ . "/cases/testfile.php",
__dir__ . "/cases/commentsFile.php"
);
];
public static function tokensArrayProvider() {
$fileToTokensMap = array();
$fileToTokensMap = [];
foreach (self::FILENAMES as $filename) {
$lexer = \Microsoft\PhpParser\TokenStreamProviderFactory::GetTokenStreamProvider(file_get_contents($filename));
$fileToTokensMap[basename($filename)] = [$filename, $lexer->getTokensArray()];

Просмотреть файл

@ -57,7 +57,7 @@ class LexicalGrammarTest extends TestCase {
$skipped = json_decode(file_get_contents(__DIR__ . "/skipped.json"));
$testProviderArray = array();
$testProviderArray = [];
foreach ($testCases as $testCase) {
if (in_array(basename($testCase), $skipped)) {
continue;
@ -90,7 +90,7 @@ class LexicalGrammarTest extends TestCase {
public function lexicalSpecProvider() {
$testCases = glob(__dir__ . "/cases/php-langspec/**/*.php");
$testProviderArray = array();
$testProviderArray = [];
foreach ($testCases as $testCase) {
$testProviderArray[basename($testCase)] = [$testCase, $testCase . ".tree"];
}

Просмотреть файл

@ -12,7 +12,7 @@ class ParserFrameworkValidationTests extends TestCase {
$totalSize = 0;
$frameworks = glob(__DIR__ . "/../validation/frameworks/*", GLOB_ONLYDIR);
$testProviderArray = array();
$testProviderArray = [];
foreach ($frameworks as $frameworkDir) {
$frameworkName = basename($frameworkDir);
$iterator = new RecursiveDirectoryIterator(__DIR__ . "/../validation/frameworks/" . $frameworkName);

Просмотреть файл

@ -88,7 +88,7 @@ class ParserGrammarTest extends TestCase {
$testCases = glob(self::FILE_PATTERN . ".php");
$skipped = json_decode(file_get_contents(__DIR__ . "/skipped.json"));
$testProviderArray = array();
$testProviderArray = [];
foreach ($testCases as $testCase) {
if (in_array(basename($testCase), $skipped)) {
continue;
@ -124,7 +124,7 @@ class ParserGrammarTest extends TestCase {
$testCases = glob(__DIR__ . "/cases/php-langspec/**/*.php");
$skipped = json_decode(file_get_contents(__DIR__ . "/skipped.json"));
$testProviderArray = array();
$testProviderArray = [];
foreach ($testCases as $case) {
if (in_array(basename($case), $skipped)) {
continue;

Просмотреть файл

@ -13,7 +13,7 @@ class ParserInvariantsTest extends LexerInvariantsTest {
const FILENAME_PATTERN = __dir__ . "/cases/{parser,parser74,}/*.php";
public static function sourceFileNodeProvider() {
$testFiles = array();
$testFiles = [];
$testCases = glob(self::FILENAME_PATTERN, GLOB_BRACE);
foreach ($testCases as $filename) {
@ -24,13 +24,13 @@ class ParserInvariantsTest extends LexerInvariantsTest {
}
public static function tokensArrayProvider() {
$testFiles = array();
$testFiles = [];
$testCases = glob(self::FILENAME_PATTERN, GLOB_BRACE);
foreach ($testCases as $filename) {
$parser = new \Microsoft\PhpParser\Parser();
$sourceFileNode = $parser->parseSourceFile(file_get_contents($filename));
$tokensArray = array();
$tokensArray = [];
foreach ($sourceFileNode->getDescendantNodesAndTokens() as $child) {
if ($child instanceof \Microsoft\PhpParser\Token) {
$tokensArray[] = $child;

Просмотреть файл

@ -25,7 +25,7 @@ PHP;
public static $sourceFileNode;
public static function setUpBeforeClass() {
public static function setUpBeforeClass(): void {
$parser = new Parser();
self::$sourceFileNode = $parser->parseSourceFile(self::FILE_CONTENTS);
parent::setUpBeforeClass();

Просмотреть файл

@ -52,26 +52,22 @@
}
},
{
"ExpressionStatement": {
"expression": {
"EchoExpression": {
"echoKeyword": null,
"expressions": {
"ExpressionList": {
"children": [
{
"StringLiteral": {
"startQuote": null,
"children": {
"kind": "StringLiteralToken",
"textLength": 3
},
"endQuote": null
}
}
]
"EchoStatement": {
"echoKeyword": null,
"expressions": {
"ExpressionList": {
"children": [
{
"StringLiteral": {
"startQuote": null,
"children": {
"kind": "StringLiteralToken",
"textLength": 3
},
"endQuote": null
}
}
}
]
}
},
"semicolon": null

Просмотреть файл

@ -68,8 +68,7 @@
},
"colonToken": null,
"questionToken": null,
"returnType": null,
"otherReturnTypes": null,
"returnTypeList": null,
"compoundStatementOrSemicolon": {
"kind": "SemicolonToken",
"textLength": 1

Просмотреть файл

@ -65,8 +65,7 @@
},
"colonToken": null,
"questionToken": null,
"returnType": null,
"otherReturnTypes": null,
"returnTypeList": null,
"compoundStatementOrSemicolon": {
"kind": "SemicolonToken",
"textLength": 1

Просмотреть файл

@ -68,8 +68,7 @@
},
"colonToken": null,
"questionToken": null,
"returnType": null,
"otherReturnTypes": null,
"returnTypeList": null,
"compoundStatementOrSemicolon": {
"CompoundStatementNode": {
"openBrace": {

Просмотреть файл

@ -34,8 +34,7 @@
},
"colonToken": null,
"questionToken": null,
"returnType": null,
"otherReturnTypes": null,
"returnTypeList": null,
"compoundStatementOrSemicolon": {
"CompoundStatementNode": {
"openBrace": {

Просмотреть файл

@ -67,11 +67,16 @@
"textLength": 1
},
"questionToken": null,
"returnType": {
"kind": "BoolReservedWord",
"textLength": 4
"returnTypeList": {
"QualifiedNameList": {
"children": [
{
"kind": "BoolReservedWord",
"textLength": 4
}
]
}
},
"otherReturnTypes": null,
"compoundStatementOrSemicolon": {
"kind": "SemicolonToken",
"textLength": 1

Просмотреть файл

@ -72,11 +72,16 @@
"textLength": 1
},
"questionToken": null,
"returnType": {
"kind": "BoolReservedWord",
"textLength": 4
"returnTypeList": {
"QualifiedNameList": {
"children": [
{
"kind": "BoolReservedWord",
"textLength": 4
}
]
}
},
"otherReturnTypes": null,
"compoundStatementOrSemicolon": {
"kind": "SemicolonToken",
"textLength": 1

Просмотреть файл

@ -64,8 +64,7 @@
},
"colonToken": null,
"questionToken": null,
"returnType": null,
"otherReturnTypes": null,
"returnTypeList": null,
"compoundStatementOrSemicolon": {
"CompoundStatementNode": {
"openBrace": {

Просмотреть файл

@ -41,8 +41,7 @@
"anonymousFunctionUseClause": null,
"colonToken": null,
"questionToken": null,
"returnType": null,
"otherReturnTypes": null,
"returnTypeList": null,
"compoundStatementOrSemicolon": {
"CompoundStatementNode": {
"openBrace": {
@ -51,29 +50,25 @@
},
"statements": [
{
"ExpressionStatement": {
"expression": {
"EchoExpression": {
"echoKeyword": {
"kind": "EchoKeyword",
"textLength": 4
},
"expressions": {
"ExpressionList": {
"children": [
{
"StringLiteral": {
"startQuote": null,
"children": {
"kind": "StringLiteralToken",
"textLength": 7
},
"endQuote": null
}
}
]
"EchoStatement": {
"echoKeyword": {
"kind": "EchoKeyword",
"textLength": 4
},
"expressions": {
"ExpressionList": {
"children": [
{
"StringLiteral": {
"startQuote": null,
"children": {
"kind": "StringLiteralToken",
"textLength": 7
},
"endQuote": null
}
}
}
]
}
},
"semicolon": {

Просмотреть файл

@ -84,11 +84,16 @@
"textLength": 1
},
"questionToken": null,
"returnType": {
"kind": "VoidReservedWord",
"textLength": 4
"returnTypeList": {
"QualifiedNameList": {
"children": [
{
"kind": "VoidReservedWord",
"textLength": 4
}
]
}
},
"otherReturnTypes": null,
"compoundStatementOrSemicolon": {
"CompoundStatementNode": {
"openBrace": {

Просмотреть файл

@ -55,8 +55,7 @@
},
"colonToken": null,
"questionToken": null,
"returnType": null,
"otherReturnTypes": null,
"returnTypeList": null,
"compoundStatementOrSemicolon": {
"CompoundStatementNode": {
"openBrace": {

Просмотреть файл

@ -38,8 +38,7 @@
"anonymousFunctionUseClause": null,
"colonToken": null,
"questionToken": null,
"returnType": null,
"otherReturnTypes": null,
"returnTypeList": null,
"compoundStatementOrSemicolon": {
"CompoundStatementNode": {
"openBrace": {

Просмотреть файл

@ -35,8 +35,7 @@
"anonymousFunctionUseClause": null,
"colonToken": null,
"questionToken": null,
"returnType": null,
"otherReturnTypes": null,
"returnTypeList": null,
"compoundStatementOrSemicolon": {
"CompoundStatementNode": {
"openBrace": {

Просмотреть файл

@ -42,8 +42,7 @@
"anonymousFunctionUseClause": null,
"colonToken": null,
"questionToken": null,
"returnType": null,
"otherReturnTypes": null,
"returnTypeList": null,
"compoundStatementOrSemicolon": {
"CompoundStatementNode": {
"openBrace": {

Просмотреть файл

@ -55,8 +55,7 @@
"anonymousFunctionUseClause": null,
"colonToken": null,
"questionToken": null,
"returnType": null,
"otherReturnTypes": null,
"returnTypeList": null,
"compoundStatementOrSemicolon": {
"CompoundStatementNode": {
"openBrace": {

Просмотреть файл

@ -55,8 +55,7 @@
"anonymousFunctionUseClause": null,
"colonToken": null,
"questionToken": null,
"returnType": null,
"otherReturnTypes": null,
"returnTypeList": null,
"compoundStatementOrSemicolon": {
"CompoundStatementNode": {
"openBrace": {

Просмотреть файл

@ -94,8 +94,7 @@
},
"colonToken": null,
"questionToken": null,
"returnType": null,
"otherReturnTypes": null,
"returnTypeList": null,
"compoundStatementOrSemicolon": {
"CompoundStatementNode": {
"openBrace": {

Просмотреть файл

@ -38,7 +38,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"UnaryOpExpression": {

Просмотреть файл

@ -38,7 +38,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"ReservedWord": {
@ -58,7 +57,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"ReservedWord": {
@ -78,7 +76,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"ReservedWord": {

Просмотреть файл

@ -38,7 +38,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"MemberAccessExpression": {

Просмотреть файл

@ -73,7 +73,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"NumericLiteral": {

Просмотреть файл

@ -0,0 +1,4 @@
<?php
// This is a syntax error in php 7.0+.
// Using a call-time pass-by-reference was deprecated in php 5.3 and prohibited since 5.4.
foo(&$a);

Просмотреть файл

@ -0,0 +1,20 @@
[
{
"kind": 0,
"message": "')' expected.",
"start": 140,
"length": 0
},
{
"kind": 0,
"message": "';' expected.",
"start": 143,
"length": 0
},
{
"kind": 0,
"message": "Unexpected ')'",
"start": 143,
"length": 1
}
]

Просмотреть файл

@ -0,0 +1,85 @@
{
"SourceFileNode": {
"statementList": [
{
"InlineHtml": {
"scriptSectionEndTag": null,
"text": null,
"scriptSectionStartTag": {
"kind": "ScriptSectionStartTag",
"textLength": 6
}
}
},
{
"ExpressionStatement": {
"expression": {
"BinaryExpression": {
"leftOperand": {
"CallExpression": {
"callableExpression": {
"QualifiedName": {
"globalSpecifier": null,
"relativeSpecifier": null,
"nameParts": [
{
"kind": "Name",
"textLength": 3
}
]
}
},
"openParen": {
"kind": "OpenParenToken",
"textLength": 1
},
"argumentExpressionList": null,
"closeParen": {
"error": "MissingToken",
"kind": "CloseParenToken",
"textLength": 0
}
}
},
"operator": {
"kind": "AmpersandToken",
"textLength": 1
},
"rightOperand": {
"Variable": {
"dollar": null,
"name": {
"kind": "VariableName",
"textLength": 2
}
}
}
}
},
"semicolon": {
"error": "MissingToken",
"kind": "SemicolonToken",
"textLength": 0
}
}
},
{
"error": "SkippedToken",
"kind": "CloseParenToken",
"textLength": 1
},
{
"EmptyStatement": {
"semicolon": {
"kind": "SemicolonToken",
"textLength": 1
}
}
}
],
"endOfFileToken": {
"kind": "EndOfFileToken",
"textLength": 0
}
}
}

Просмотреть файл

@ -35,7 +35,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"Variable": {

Просмотреть файл

@ -35,7 +35,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"AssignmentExpression": {

Просмотреть файл

@ -35,7 +35,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"AssignmentExpression": {
@ -73,7 +72,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"Variable": {

Просмотреть файл

@ -35,7 +35,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"AssignmentExpression": {
@ -73,7 +72,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"Variable": {

Просмотреть файл

@ -35,7 +35,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"AssignmentExpression": {
@ -73,7 +72,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": {
"kind": "DotDotDotToken",
"textLength": 3

Просмотреть файл

@ -47,7 +47,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"Variable": {

Просмотреть файл

@ -60,7 +60,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"Variable": {

Просмотреть файл

@ -38,7 +38,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"NumericLiteral": {

Просмотреть файл

@ -110,43 +110,39 @@
}
},
{
"ExpressionStatement": {
"expression": {
"EchoExpression": {
"echoKeyword": {
"kind": "EchoKeyword",
"textLength": 4
},
"expressions": {
"ExpressionList": {
"children": [
{
"ScopedPropertyAccessExpression": {
"scopeResolutionQualifier": {
"QualifiedName": {
"globalSpecifier": null,
"relativeSpecifier": null,
"nameParts": [
{
"kind": "Name",
"textLength": 1
}
]
"EchoStatement": {
"echoKeyword": {
"kind": "EchoKeyword",
"textLength": 4
},
"expressions": {
"ExpressionList": {
"children": [
{
"ScopedPropertyAccessExpression": {
"scopeResolutionQualifier": {
"QualifiedName": {
"globalSpecifier": null,
"relativeSpecifier": null,
"nameParts": [
{
"kind": "Name",
"textLength": 1
}
},
"doubleColon": {
"kind": "ColonColonToken",
"textLength": 2
},
"memberName": {
"kind": "Name",
"textLength": 1
}
]
}
},
"doubleColon": {
"kind": "ColonColonToken",
"textLength": 2
},
"memberName": {
"kind": "Name",
"textLength": 1
}
]
}
}
}
]
}
},
"semicolon": {

Просмотреть файл

@ -65,8 +65,7 @@
},
"colonToken": null,
"questionToken": null,
"returnType": null,
"otherReturnTypes": null,
"returnTypeList": null,
"compoundStatementOrSemicolon": {
"CompoundStatementNode": {
"openBrace": {

Просмотреть файл

@ -62,8 +62,7 @@
"attributes": null,
"visibilityToken": null,
"questionToken": null,
"typeDeclaration": null,
"otherTypeDeclarations": null,
"typeDeclarationList": null,
"byRefToken": null,
"dotDotDotToken": null,
"variableName": {
@ -83,8 +82,7 @@
"attributes": null,
"visibilityToken": null,
"questionToken": null,
"typeDeclaration": null,
"otherTypeDeclarations": null,
"typeDeclarationList": null,
"byRefToken": null,
"dotDotDotToken": null,
"variableName": {
@ -104,8 +102,7 @@
},
"colonToken": null,
"questionToken": null,
"returnType": null,
"otherReturnTypes": null,
"returnTypeList": null,
"compoundStatementOrSemicolon": {
"CompoundStatementNode": {
"openBrace": {

Просмотреть файл

@ -62,8 +62,7 @@
"attributes": null,
"visibilityToken": null,
"questionToken": null,
"typeDeclaration": null,
"otherTypeDeclarations": null,
"typeDeclarationList": null,
"byRefToken": null,
"dotDotDotToken": null,
"variableName": {
@ -83,8 +82,7 @@
"attributes": null,
"visibilityToken": null,
"questionToken": null,
"typeDeclaration": null,
"otherTypeDeclarations": null,
"typeDeclarationList": null,
"byRefToken": null,
"dotDotDotToken": null,
"variableName": {
@ -107,11 +105,16 @@
"textLength": 1
},
"questionToken": null,
"returnType": {
"kind": "IntReservedWord",
"textLength": 3
"returnTypeList": {
"QualifiedNameList": {
"children": [
{
"kind": "IntReservedWord",
"textLength": 3
}
]
}
},
"otherReturnTypes": null,
"compoundStatementOrSemicolon": {
"CompoundStatementNode": {
"openBrace": {

Просмотреть файл

@ -61,8 +61,7 @@
},
"colonToken": null,
"questionToken": null,
"returnType": null,
"otherReturnTypes": null,
"returnTypeList": null,
"compoundStatementOrSemicolon": {
"CompoundStatementNode": {
"openBrace": {
@ -108,8 +107,7 @@
},
"colonToken": null,
"questionToken": null,
"returnType": null,
"otherReturnTypes": null,
"returnTypeList": null,
"compoundStatementOrSemicolon": {
"CompoundStatementNode": {
"openBrace": {

Просмотреть файл

@ -116,7 +116,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"Variable": {

Просмотреть файл

@ -118,7 +118,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"Variable": {

Просмотреть файл

@ -134,7 +134,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"Variable": {
@ -155,7 +154,6 @@
"ArgumentExpression": {
"name": null,
"colonToken": null,
"byRefToken": null,
"dotDotDotToken": null,
"expression": {
"Variable": {

Просмотреть файл

@ -64,8 +64,7 @@
},
"colonToken": null,
"questionToken": null,
"returnType": null,
"otherReturnTypes": null,
"returnTypeList": null,
"compoundStatementOrSemicolon": {
"CompoundStatementNode": {
"openBrace": {

Просмотреть файл

@ -21,23 +21,28 @@
"kind": "OpenParenToken",
"textLength": 1
},
"declareDirective": {
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
"declareDirectiveList": {
"DeclareDirectiveList": {
"children": [
{
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
}
}
]
}
},
"otherDeclareDirectives": null,
"closeParen": {
"kind": "CloseParenToken",
"textLength": 1

Просмотреть файл

@ -21,23 +21,28 @@
"kind": "OpenParenToken",
"textLength": 1
},
"declareDirective": {
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "FloatingLiteralToken",
"textLength": 3
}
"declareDirectiveList": {
"DeclareDirectiveList": {
"children": [
{
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "FloatingLiteralToken",
"textLength": 3
}
}
}
]
}
},
"otherDeclareDirectives": null,
"closeParen": {
"kind": "CloseParenToken",
"textLength": 1

Просмотреть файл

@ -21,23 +21,28 @@
"kind": "OpenParenToken",
"textLength": 1
},
"declareDirective": {
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "FloatingLiteralToken",
"textLength": 3
}
"declareDirectiveList": {
"DeclareDirectiveList": {
"children": [
{
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "FloatingLiteralToken",
"textLength": 3
}
}
}
]
}
},
"otherDeclareDirectives": null,
"closeParen": {
"kind": "CloseParenToken",
"textLength": 1

Просмотреть файл

@ -4,17 +4,5 @@
"message": "'Name' expected.",
"start": 16,
"length": 0
},
{
"kind": 0,
"message": "'=' expected.",
"start": 16,
"length": 0
},
{
"kind": 0,
"message": "'FloatingLiteralToken' expected.",
"start": 16,
"length": 0
}
]

Просмотреть файл

@ -21,26 +21,11 @@
"kind": "OpenParenToken",
"textLength": 1
},
"declareDirective": {
"DeclareDirective": {
"name": {
"error": "MissingToken",
"kind": "Name",
"textLength": 0
},
"equals": {
"error": "MissingToken",
"kind": "EqualsToken",
"textLength": 0
},
"literal": {
"error": "MissingToken",
"kind": "FloatingLiteralToken",
"textLength": 0
}
}
"declareDirectiveList": {
"error": "MissingToken",
"kind": "Name",
"textLength": 0
},
"otherDeclareDirectives": null,
"closeParen": {
"kind": "CloseParenToken",
"textLength": 1

Просмотреть файл

@ -21,23 +21,28 @@
"kind": "OpenParenToken",
"textLength": 1
},
"declareDirective": {
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
"declareDirectiveList": {
"DeclareDirectiveList": {
"children": [
{
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
}
}
]
}
},
"otherDeclareDirectives": null,
"closeParen": {
"kind": "CloseParenToken",
"textLength": 1

Просмотреть файл

@ -21,25 +21,25 @@
"kind": "OpenParenToken",
"textLength": 1
},
"declareDirective": {
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 12
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
}
},
"otherDeclareDirectives": {
"declareDirectiveList": {
"DeclareDirectiveList": {
"children": [
{
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 12
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
}
},
{
"kind": "CommaToken",
"textLength": 1

Просмотреть файл

@ -21,25 +21,25 @@
"kind": "OpenParenToken",
"textLength": 1
},
"declareDirective": {
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 12
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
}
},
"otherDeclareDirectives": {
"declareDirectiveList": {
"DeclareDirectiveList": {
"children": [
{
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 12
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
}
},
{
"kind": "CommaToken",
"textLength": 1

Просмотреть файл

@ -21,23 +21,28 @@
"kind": "OpenParenToken",
"textLength": 1
},
"declareDirective": {
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 14
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
"declareDirectiveList": {
"DeclareDirectiveList": {
"children": [
{
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 14
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
}
}
]
}
},
"otherDeclareDirectives": null,
"closeParen": {
"kind": "CloseParenToken",
"textLength": 1

Просмотреть файл

@ -21,23 +21,28 @@
"kind": "OpenParenToken",
"textLength": 1
},
"declareDirective": {
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
"declareDirectiveList": {
"DeclareDirectiveList": {
"children": [
{
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
}
}
]
}
},
"otherDeclareDirectives": null,
"closeParen": {
"kind": "CloseParenToken",
"textLength": 1

Просмотреть файл

@ -21,23 +21,28 @@
"kind": "OpenParenToken",
"textLength": 1
},
"declareDirective": {
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
"declareDirectiveList": {
"DeclareDirectiveList": {
"children": [
{
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
}
}
]
}
},
"otherDeclareDirectives": null,
"closeParen": {
"kind": "CloseParenToken",
"textLength": 1

Просмотреть файл

@ -21,23 +21,28 @@
"kind": "OpenParenToken",
"textLength": 1
},
"declareDirective": {
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 2
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
"declareDirectiveList": {
"DeclareDirectiveList": {
"children": [
{
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 2
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
}
}
]
}
},
"otherDeclareDirectives": null,
"closeParen": {
"kind": "CloseParenToken",
"textLength": 1

Просмотреть файл

@ -21,23 +21,28 @@
"kind": "OpenParenToken",
"textLength": 1
},
"declareDirective": {
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
"declareDirectiveList": {
"DeclareDirectiveList": {
"children": [
{
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
}
}
]
}
},
"otherDeclareDirectives": null,
"closeParen": {
"kind": "CloseParenToken",
"textLength": 1

Просмотреть файл

@ -21,23 +21,28 @@
"kind": "OpenParenToken",
"textLength": 1
},
"declareDirective": {
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
"declareDirectiveList": {
"DeclareDirectiveList": {
"children": [
{
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 1
}
}
}
]
}
},
"otherDeclareDirectives": null,
"closeParen": {
"kind": "CloseParenToken",
"textLength": 1

Просмотреть файл

@ -21,24 +21,29 @@
"kind": "OpenParenToken",
"textLength": 1
},
"declareDirective": {
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"error": "MissingToken",
"kind": "FloatingLiteralToken",
"textLength": 0
}
"declareDirectiveList": {
"DeclareDirectiveList": {
"children": [
{
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"error": "MissingToken",
"kind": "FloatingLiteralToken",
"textLength": 0
}
}
}
]
}
},
"otherDeclareDirectives": null,
"closeParen": {
"kind": "CloseParenToken",
"textLength": 1

Просмотреть файл

@ -21,23 +21,28 @@
"kind": "OpenParenToken",
"textLength": 1
},
"declareDirective": {
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "StringLiteralToken",
"textLength": 2
}
"declareDirectiveList": {
"DeclareDirectiveList": {
"children": [
{
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"kind": "EqualsToken",
"textLength": 1
},
"literal": {
"kind": "StringLiteralToken",
"textLength": 2
}
}
}
]
}
},
"otherDeclareDirectives": null,
"closeParen": {
"kind": "CloseParenToken",
"textLength": 1

Просмотреть файл

@ -21,24 +21,29 @@
"kind": "OpenParenToken",
"textLength": 1
},
"declareDirective": {
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"error": "MissingToken",
"kind": "EqualsToken",
"textLength": 0
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 3
}
"declareDirectiveList": {
"DeclareDirectiveList": {
"children": [
{
"DeclareDirective": {
"name": {
"kind": "Name",
"textLength": 5
},
"equals": {
"error": "MissingToken",
"kind": "EqualsToken",
"textLength": 0
},
"literal": {
"kind": "IntegerLiteralToken",
"textLength": 3
}
}
}
]
}
},
"otherDeclareDirectives": null,
"closeParen": {
"kind": "CloseParenToken",
"textLength": 1

Просмотреть файл

@ -12,42 +12,38 @@
}
},
{
"ExpressionStatement": {
"expression": {
"EchoExpression": {
"echoKeyword": {
"kind": "EchoKeyword",
"textLength": 4
},
"expressions": {
"ExpressionList": {
"children": [
{
"StringLiteral": {
"startQuote": null,
"children": {
"kind": "StringLiteralToken",
"textLength": 7
},
"endQuote": null
}
"EchoStatement": {
"echoKeyword": {
"kind": "EchoKeyword",
"textLength": 4
},
"expressions": {
"ExpressionList": {
"children": [
{
"StringLiteral": {
"startQuote": null,
"children": {
"kind": "StringLiteralToken",
"textLength": 7
},
{
"kind": "CommaToken",
"textLength": 1
},
{
"Variable": {
"dollar": null,
"name": {
"kind": "VariableName",
"textLength": 2
}
}
"endQuote": null
}
},
{
"kind": "CommaToken",
"textLength": 1
},
{
"Variable": {
"dollar": null,
"name": {
"kind": "VariableName",
"textLength": 2
}
]
}
}
}
]
}
},
"semicolon": {

Просмотреть файл

@ -12,28 +12,24 @@
}
},
{
"ExpressionStatement": {
"expression": {
"EchoExpression": {
"echoKeyword": {
"kind": "EchoKeyword",
"textLength": 4
},
"expressions": {
"ExpressionList": {
"children": [
{
"Variable": {
"dollar": null,
"name": {
"kind": "VariableName",
"textLength": 2
}
}
"EchoStatement": {
"echoKeyword": {
"kind": "EchoKeyword",
"textLength": 4
},
"expressions": {
"ExpressionList": {
"children": [
{
"Variable": {
"dollar": null,
"name": {
"kind": "VariableName",
"textLength": 2
}
]
}
}
}
]
}
},
"semicolon": {

Просмотреть файл

@ -12,16 +12,12 @@
}
},
{
"ExpressionStatement": {
"expression": {
"EchoExpression": {
"echoKeyword": {
"kind": "EchoKeyword",
"textLength": 4
},
"expressions": null
}
"EchoStatement": {
"echoKeyword": {
"kind": "EchoKeyword",
"textLength": 4
},
"expressions": null,
"semicolon": {
"kind": "SemicolonToken",
"textLength": 1

Просмотреть файл

@ -12,28 +12,24 @@
}
},
{
"ExpressionStatement": {
"expression": {
"EchoExpression": {
"echoKeyword": {
"kind": "EchoKeyword",
"textLength": 4
},
"expressions": {
"ExpressionList": {
"children": [
{
"Variable": {
"dollar": null,
"name": {
"kind": "VariableName",
"textLength": 3
}
}
"EchoStatement": {
"echoKeyword": {
"kind": "EchoKeyword",
"textLength": 4
},
"expressions": {
"ExpressionList": {
"children": [
{
"Variable": {
"dollar": null,
"name": {
"kind": "VariableName",
"textLength": 3
}
]
}
}
}
]
}
},
"semicolon": {

Просмотреть файл

@ -12,55 +12,51 @@
}
},
{
"ExpressionStatement": {
"expression": {
"EchoExpression": {
"echoKeyword": {
"kind": "EchoKeyword",
"textLength": 4
},
"expressions": {
"ExpressionList": {
"children": [
{
"Variable": {
"dollar": null,
"name": {
"kind": "VariableName",
"textLength": 3
}
}
},
{
"kind": "CommaToken",
"textLength": 1
},
{
"Variable": {
"dollar": null,
"name": {
"kind": "VariableName",
"textLength": 6
}
}
},
{
"kind": "CommaToken",
"textLength": 1
},
{
"StringLiteral": {
"startQuote": null,
"children": {
"kind": "StringLiteralToken",
"textLength": 2
},
"endQuote": null
}
"EchoStatement": {
"echoKeyword": {
"kind": "EchoKeyword",
"textLength": 4
},
"expressions": {
"ExpressionList": {
"children": [
{
"Variable": {
"dollar": null,
"name": {
"kind": "VariableName",
"textLength": 3
}
]
}
},
{
"kind": "CommaToken",
"textLength": 1
},
{
"Variable": {
"dollar": null,
"name": {
"kind": "VariableName",
"textLength": 6
}
}
},
{
"kind": "CommaToken",
"textLength": 1
},
{
"StringLiteral": {
"startQuote": null,
"children": {
"kind": "StringLiteralToken",
"textLength": 2
},
"endQuote": null
}
}
}
]
}
},
"semicolon": {

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше