mirror of
https://github.com/nikic/PHP-Parser.git
synced 2025-07-10 00:46:35 +02:00
Compare commits
40 Commits
v3.0.0beta
...
v3.0.0
Author | SHA1 | Date | |
---|---|---|---|
68973aed1e | |||
bcdfb703d5 | |||
27281e9130 | |||
098294beec | |||
b02f8ac07d | |||
e52ffc4447 | |||
c5cdd5ad73 | |||
c0630f8169 | |||
6db8d9d5a5 | |||
71438559ae | |||
c0f0edf044 | |||
fa7357b483 | |||
91cb82d3d2 | |||
7672b974ff | |||
8489364528 | |||
0d0accfa9f | |||
623bad2c8b | |||
f66cf8f0dd | |||
4e25f51581 | |||
a46b309975 | |||
f99a96e0a2 | |||
90834bff8e | |||
a910f6a247 | |||
caa5c0cc76 | |||
5e5cb86e83 | |||
2be7838fc6 | |||
f6eb341b15 | |||
b2fe43cf7a | |||
648a246be0 | |||
2e5ae28c39 | |||
5025d75160 | |||
c79ea6d1d3 | |||
e926efd62e | |||
17d1e738fa | |||
9e5d3bbe25 | |||
f3c7dc9d89 | |||
c5e0c3d7e2 | |||
ea47b6e0d6 | |||
9e1c535b1d | |||
cfd207cae5 |
56
CHANGELOG.md
56
CHANGELOG.md
@ -1,10 +1,62 @@
|
|||||||
Version 3.0.0-dev
|
Version 3.0.1-dev
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
Nothing yet.
|
Nothing yet.
|
||||||
|
|
||||||
|
Version 3.0.0 (2016-11-30)
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Added support for dumping node positions in the NodeDumper through the `dumpPositions` option.
|
||||||
|
* Added error recovery support for `$`, `new`, `Foo::`.
|
||||||
|
|
||||||
|
Version 3.0.0-beta2 (2016-10-29)
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
This release primarily improves our support for error recovery.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Added `Node::setDocComment()` method.
|
||||||
|
* Added `Error::getMessageWithColumnInfo()` method.
|
||||||
|
* Added support for recovery from lexer errors.
|
||||||
|
* Added support for recovering from "special" errors (i.e. non-syntax parse errors).
|
||||||
|
* Added precise location information for lexer errors.
|
||||||
|
* Added `ErrorHandler` interface, and `ErrorHandler\Throwing` and `ErrorHandler\Collecting` as
|
||||||
|
specific implementations. These provide a general mechanism for handling error recovery.
|
||||||
|
* Added optional `ErrorHandler` argument to `Parser::parse()`, `Lexer::startLexing()` and
|
||||||
|
`NameResolver::__construct()`.
|
||||||
|
* The `NameResolver` now adds a `namespacedName` attribute on name nodes that cannot be statically
|
||||||
|
resolved (unqualified unaliased function or constant names in namespaces).
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Fixed attribute assignment for `GroupUse` prefix and variables in interpolated strings.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
* The constants on `NameTraverserInterface` have been moved into the `NameTraverser` class.
|
||||||
|
* Due to the error handling changes, the `Parser` interface and `Lexer` API have changed.
|
||||||
|
* The emulative lexer now directly postprocesses tokens, instead of using `~__EMU__~` sequences.
|
||||||
|
This changes the protected API of the lexer.
|
||||||
|
* The `Name::slice()` method now returns `null` for empty slices, previously `new Name([])` was
|
||||||
|
used. `Name::concat()` now also supports concatenation with `null`.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
* Removed `Name::append()` and `Name::prepend()`. These mutable methods have been superseded by
|
||||||
|
the immutable `Name::concat()`.
|
||||||
|
* Removed `Error::getRawLine()` and `Error::setRawLine()`. These methods have been superseded by
|
||||||
|
`Error::getStartLine()` and `Error::setStartLine()`.
|
||||||
|
* Removed support for node cloning in the `NodeTraverser`.
|
||||||
|
* Removed `$separator` argument from `Name::toString()`.
|
||||||
|
* Removed `throw_on_error` parser option and `Parser::getErrors()` method. Use the `ErrorHandler`
|
||||||
|
mechanism instead.
|
||||||
|
|
||||||
Version 3.0.0-beta1 (2016-09-16)
|
Version 3.0.0-beta1 (2016-09-16)
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
* [7.1] Function/method and parameter builders now support PHP 7.1 type hints (void, iterable and
|
* [7.1] Function/method and parameter builders now support PHP 7.1 type hints (void, iterable and
|
||||||
@ -20,7 +72,7 @@ Version 3.0.0-beta1 (2016-09-16)
|
|||||||
The following changes are also part of PHP-Parser 2.1.1:
|
The following changes are also part of PHP-Parser 2.1.1:
|
||||||
|
|
||||||
* The PHP 7 parser will now generate a parse error for `$var =& new Obj` assignments.
|
* The PHP 7 parser will now generate a parse error for `$var =& new Obj` assignments.
|
||||||
* Comments on free-standing code blocks will no be retained as comments on the first statement in
|
* Comments on free-standing code blocks will now be retained as comments on the first statement in
|
||||||
the code block.
|
the code block.
|
||||||
|
|
||||||
Version 3.0.0-alpha1 (2016-07-25)
|
Version 3.0.0-alpha1 (2016-07-25)
|
||||||
|
@ -6,7 +6,9 @@ PHP Parser
|
|||||||
This is a PHP 5.2 to PHP 7.1 parser written in PHP. Its purpose is to simplify static code analysis and
|
This is a PHP 5.2 to PHP 7.1 parser written in PHP. Its purpose is to simplify static code analysis and
|
||||||
manipulation.
|
manipulation.
|
||||||
|
|
||||||
[**Documentation for version 2.x**][doc_master] (stable; for running on PHP >= 5.4; for parsing PHP 5.2 to PHP 7.0).
|
[**Documentation for version 3.x**][doc_master] (stable; for running on PHP >= 5.5; for parsing PHP 5.2 to PHP 7.1).
|
||||||
|
|
||||||
|
[Documentation for version 2.x][doc_2_x] (stable; for running on PHP >= 5.4; for parsing PHP 5.2 to PHP 7.0).
|
||||||
|
|
||||||
[Documentation for version 1.x][doc_1_x] (unsupported; for running on PHP >= 5.3; for parsing PHP 5.2 to PHP 5.6).
|
[Documentation for version 1.x][doc_1_x] (unsupported; for running on PHP >= 5.3; for parsing PHP 5.2 to PHP 5.6).
|
||||||
|
|
||||||
@ -89,7 +91,7 @@ Documentation
|
|||||||
|
|
||||||
Component documentation:
|
Component documentation:
|
||||||
|
|
||||||
1. [Error](doc/component/Error.markdown)
|
1. [Error handling](doc/component/Error_handling.markdown)
|
||||||
2. [Lexer](doc/component/Lexer.markdown)
|
2. [Lexer](doc/component/Lexer.markdown)
|
||||||
|
|
||||||
[doc_1_x]: https://github.com/nikic/PHP-Parser/tree/1.x/doc
|
[doc_1_x]: https://github.com/nikic/PHP-Parser/tree/1.x/doc
|
||||||
|
122
UPGRADE-3.0.md
122
UPGRADE-3.0.md
@ -1,8 +1,13 @@
|
|||||||
Upgrading from PHP-Parser 2.x to 3.0
|
Upgrading from PHP-Parser 2.x to 3.0
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
This version does not include any major API changes. Only specific details of the node
|
The backwards-incompatible changes in this release may be summarized as follows:
|
||||||
representation have changed in some cases.
|
|
||||||
|
* The specific details of the node representation have changed in some cases, primarily to
|
||||||
|
accomodate new PHP 7.1 features.
|
||||||
|
* There have been significant changes to the error recovery implementation. This may affect you,
|
||||||
|
if you used the error recovery mode or have a custom lexer implementation.
|
||||||
|
* A number of deprecated methods were removed.
|
||||||
|
|
||||||
### PHP version requirements
|
### PHP version requirements
|
||||||
|
|
||||||
@ -31,13 +36,111 @@ The following changes are unlikely to require code changes:
|
|||||||
* `void` and `iterable` types are now stored as strings if the PHP 7 parser is used. Previously
|
* `void` and `iterable` types are now stored as strings if the PHP 7 parser is used. Previously
|
||||||
these would have been represented as `Name` instances.
|
these would have been represented as `Name` instances.
|
||||||
|
|
||||||
### Removed methods
|
### Changes to error recovery mode
|
||||||
|
|
||||||
The following methods have been removed:
|
Previously, error recovery mode was enabled by setting the `throwOnError` option to `false` when
|
||||||
|
creating the parser, while collected errors were retrieved using the `getErrors()` method:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$lexer = ...;
|
||||||
|
$parser = (new ParserFactory)->create(ParserFactor::ONLY_PHP7, $lexer, [
|
||||||
|
'throwOnError' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$stmts = $parser->parse($code);
|
||||||
|
$errors = $parser->getErrors();
|
||||||
|
if ($errors) {
|
||||||
|
handleErrors($errors);
|
||||||
|
}
|
||||||
|
processAst($stmts);
|
||||||
|
```
|
||||||
|
|
||||||
|
Both the `throwOnError` option and the `getErrors()` method have been removed in PHP-Parser 3.0.
|
||||||
|
Instead an instance of `ErrorHandler\Collecting` should be passed to the `parse()` method:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$lexer = ...;
|
||||||
|
$parser = (new ParserFactory)->create(ParserFactor::ONLY_PHP7, $lexer);
|
||||||
|
|
||||||
|
$errorHandler = new ErrorHandler\Collecting;
|
||||||
|
$stmts = $parser->parse($code, $errorHandler);
|
||||||
|
if ($errorHandler->hasErrors()) {
|
||||||
|
handleErrors($errorHandler->getErrors());
|
||||||
|
}
|
||||||
|
processAst($stmts);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Multiple parser fallback in error recovery mode
|
||||||
|
|
||||||
|
As a result of this change, if a `Multiple` parser is used (e.g. through the `ParserFactory` using
|
||||||
|
`PREFER_PHP7` or `PREFER_PHP5`), it will now return the result of the first *non-throwing* parse. As
|
||||||
|
parsing never throws in error recovery mode, the result from the first parser will always be
|
||||||
|
returned.
|
||||||
|
|
||||||
|
The PHP 7 parser is a superset of the PHP 5 parser, with the exceptions that `=& new` and
|
||||||
|
`global $$foo->bar` are not supported (other differences are in representation only). The PHP 7
|
||||||
|
parser will be able to recover from the error in both cases. For this reason, this change will
|
||||||
|
likely pass unnoticed if you do not specifically test for this syntax.
|
||||||
|
|
||||||
|
It is possible to restore the precise previous behavior with the following code:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$lexer = ...;
|
||||||
|
$parser7 = new Parser\Php7($lexer);
|
||||||
|
$parser5 = new Parser\Php5($lexer);
|
||||||
|
|
||||||
|
$errors7 = new ErrorHandler\Collecting();
|
||||||
|
$stmts7 = $parser7->parse($code, $errors7);
|
||||||
|
if ($errors7->hasErrors()) {
|
||||||
|
$errors5 = new ErrorHandler\Collecting();
|
||||||
|
$stmts5 = $parser5->parse($code, $errors5);
|
||||||
|
if (!$errors5->hasErrors()) {
|
||||||
|
// If PHP 7 parse has errors but PHP 5 parse has no errors, use PHP 5 result
|
||||||
|
return [$stmts5, $errors5];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If PHP 7 succeeds or both fail use PHP 7 result
|
||||||
|
return [$stmts7, $errors7];
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Error handling in the lexer
|
||||||
|
|
||||||
|
In order to support recovery from lexer errors, the signature of the `startLexing()` method changed
|
||||||
|
to optionally accept an `ErrorHandler`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// OLD
|
||||||
|
public function startLexing($code);
|
||||||
|
// NEW
|
||||||
|
public function startLexing($code, ErrorHandler $errorHandler = null);
|
||||||
|
```
|
||||||
|
|
||||||
|
If you use a custom lexer with overriden `startLexing()` method, it needs to be changed to accept
|
||||||
|
the extra parameter. The value should be passed on to the parent method.
|
||||||
|
|
||||||
|
#### Error checks in node constructors
|
||||||
|
|
||||||
|
The constructors of certain nodes used to contain additional checks for semantic errors, such as
|
||||||
|
creating a try block without either catch or finally. These checks have been moved from the node
|
||||||
|
constructors into the parser. This allows recovery from such errors, as well as representing the
|
||||||
|
resulting (invalid) AST.
|
||||||
|
|
||||||
|
This means that certain error conditions are no longer checked for manually constructed nodes.
|
||||||
|
|
||||||
|
### Removed methods, arguments, options
|
||||||
|
|
||||||
|
The following methods, arguments or options have been removed:
|
||||||
|
|
||||||
* `Comment::setLine()`, `Comment::setText()`: Create new `Comment` instances instead.
|
* `Comment::setLine()`, `Comment::setText()`: Create new `Comment` instances instead.
|
||||||
* `Name::set()`, `Name::setFirst()`, `Name::setLast()`: Create new `Name` instances instead. For
|
* `Name::set()`, `Name::setFirst()`, `Name::setLast()`, `Name::append()`, `Name::prepend()`:
|
||||||
the latter two a combination of `Name::concat()` and `Name::slice()` can be used.
|
Use `Name::concat()` in combination with `Name::slice()` instead.
|
||||||
|
* `Error::getRawLine()`, `Error::setRawLine()`. Use `Error::getStartLine()` and
|
||||||
|
`Error::setStartLine()` instead.
|
||||||
|
* `Parser::getErrors()`. Use `ErrorHandler\Collecting` instead.
|
||||||
|
* `$separator` argument of `Name::toString()`. Use `strtr()` instead, if you really need it.
|
||||||
|
* `$cloneNodes` argument of `NodeTraverser::__construct()`. Explicitly clone nodes in the visitor
|
||||||
|
instead.
|
||||||
|
* `throwOnError` parser option. Use `ErrorHandler\Collecting` instead.
|
||||||
|
|
||||||
### Miscellaneous
|
### Miscellaneous
|
||||||
|
|
||||||
@ -45,4 +148,9 @@ The following methods have been removed:
|
|||||||
The pretty printer should only be invoked using the `prettyPrint()`, `prettyPrintFile()` and
|
The pretty printer should only be invoked using the `prettyPrint()`, `prettyPrintFile()` and
|
||||||
`prettyPrintExpr()` methods.
|
`prettyPrintExpr()` methods.
|
||||||
* The node dumper now prints numeric values that act as enums/flags in a string representation.
|
* The node dumper now prints numeric values that act as enums/flags in a string representation.
|
||||||
If node dumper results are used in tests, updates may be needed to account for this.
|
If node dumper results are used in tests, updates may be needed to account for this.
|
||||||
|
* The constants on `NameTraverserInterface` have been moved into the `NameTraverser` class.
|
||||||
|
* The emulative lexer now directly postprocesses tokens, instead of using `~__EMU__~` sequences.
|
||||||
|
This changes the protected API of the emulative lexer.
|
||||||
|
* The `Name::slice()` method now returns `null` for empty slices, previously `new Name([])` was
|
||||||
|
used. `Name::concat()` now also supports concatenation with `null`.
|
||||||
|
@ -31,8 +31,7 @@ $lexer = new PhpParser\Lexer\Emulative(array('usedAttributes' => array(
|
|||||||
)));
|
)));
|
||||||
$parser = (new PhpParser\ParserFactory)->create(
|
$parser = (new PhpParser\ParserFactory)->create(
|
||||||
PhpParser\ParserFactory::PREFER_PHP7,
|
PhpParser\ParserFactory::PREFER_PHP7,
|
||||||
$lexer,
|
$lexer
|
||||||
array('throwOnError' => !$attributes['with-recovery'])
|
|
||||||
);
|
);
|
||||||
$dumper = new PhpParser\NodeDumper(['dumpComments' => true]);
|
$dumper = new PhpParser\NodeDumper(['dumpComments' => true]);
|
||||||
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
|
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
|
||||||
@ -54,18 +53,23 @@ foreach ($files as $file) {
|
|||||||
echo "====> File $file:\n";
|
echo "====> File $file:\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if ($attributes['with-recovery']) {
|
||||||
$stmts = $parser->parse($code);
|
$errorHandler = new PhpParser\ErrorHandler\Collecting;
|
||||||
foreach ($parser->getErrors() as $error) {
|
$stmts = $parser->parse($code, $errorHandler);
|
||||||
|
foreach ($errorHandler->getErrors() as $error) {
|
||||||
$message = formatErrorMessage($error, $code, $attributes['with-column-info']);
|
$message = formatErrorMessage($error, $code, $attributes['with-column-info']);
|
||||||
echo $message . "\n";
|
echo $message . "\n";
|
||||||
}
|
}
|
||||||
if (null === $stmts) {
|
if (null === $stmts) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} catch (PhpParser\Error $error) {
|
} else {
|
||||||
$message = formatErrorMessage($error, $code, $attributes['with-column-info']);
|
try {
|
||||||
die($message . "\n");
|
$stmts = $parser->parse($code);
|
||||||
|
} catch (PhpParser\Error $error) {
|
||||||
|
$message = formatErrorMessage($error, $code, $attributes['with-column-info']);
|
||||||
|
die($message . "\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($operations as $operation) {
|
foreach ($operations as $operation) {
|
||||||
@ -90,11 +94,7 @@ foreach ($files as $file) {
|
|||||||
|
|
||||||
function formatErrorMessage(PhpParser\Error $e, $code, $withColumnInfo) {
|
function formatErrorMessage(PhpParser\Error $e, $code, $withColumnInfo) {
|
||||||
if ($withColumnInfo && $e->hasColumnInfo()) {
|
if ($withColumnInfo && $e->hasColumnInfo()) {
|
||||||
$startLine = $e->getStartLine();
|
return $e->getMessageWithColumnInfo($code);
|
||||||
$endLine = $e->getEndLine();
|
|
||||||
$startColumn = $e->getStartColumn($code);
|
|
||||||
$endColumn = $e->getEndColumn($code);
|
|
||||||
return $e->getRawMessage() . " from $startLine:$startColumn to $endLine:$endColumn";
|
|
||||||
} else {
|
} else {
|
||||||
return $e->getMessage();
|
return $e->getMessage();
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
"ext-tokenizer": "*"
|
"ext-tokenizer": "*"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "~4.0"
|
"phpunit/phpunit": "~4.0|~5.0"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
@ -8,7 +8,7 @@ Simple serialization
|
|||||||
|
|
||||||
It is possible to serialize the node tree using `serialize()` and also unserialize it using
|
It is possible to serialize the node tree using `serialize()` and also unserialize it using
|
||||||
`unserialize()`. The output is not human readable and not easily processable from anything
|
`unserialize()`. The output is not human readable and not easily processable from anything
|
||||||
but PHP, but it is compact and generates fast. The main application thus is in caching.
|
but PHP, but it is compact and generates quickly. The main application thus is in caching.
|
||||||
|
|
||||||
Human readable dumping
|
Human readable dumping
|
||||||
----------------------
|
----------------------
|
||||||
@ -86,6 +86,134 @@ array(
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
JSON encoding
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Nodes (and comments) implement the `JsonSerializable` interface. As such, it is possible to JSON
|
||||||
|
encode the AST directly using `json_encode()`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$code = <<<'CODE'
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function printLine($msg) {
|
||||||
|
echo $msg, "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
printLine('Hello World!!!');
|
||||||
|
CODE;
|
||||||
|
|
||||||
|
$parser = (new PhpParser\ParserFactory)->create(PhpParser\ParserFactory::PREFER_PHP7);
|
||||||
|
$nodeDumper = new PhpParser\NodeDumper;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmts = $parser->parse($code);
|
||||||
|
|
||||||
|
echo json_encode($stmts, JSON_PRETTY_PRINT), "\n";
|
||||||
|
} catch (PhpParser\Error $e) {
|
||||||
|
echo 'Parse Error: ', $e->getMessage();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This will result in the following output (which includes attributes):
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"nodeType": "Stmt_Function",
|
||||||
|
"byRef": false,
|
||||||
|
"name": "printLine",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"nodeType": "Param",
|
||||||
|
"type": null,
|
||||||
|
"byRef": false,
|
||||||
|
"variadic": false,
|
||||||
|
"name": "msg",
|
||||||
|
"default": null,
|
||||||
|
"attributes": {
|
||||||
|
"startLine": 3,
|
||||||
|
"endLine": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"returnType": null,
|
||||||
|
"stmts": [
|
||||||
|
{
|
||||||
|
"nodeType": "Stmt_Echo",
|
||||||
|
"exprs": [
|
||||||
|
{
|
||||||
|
"nodeType": "Expr_Variable",
|
||||||
|
"name": "msg",
|
||||||
|
"attributes": {
|
||||||
|
"startLine": 4,
|
||||||
|
"endLine": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeType": "Scalar_String",
|
||||||
|
"value": "\n",
|
||||||
|
"attributes": {
|
||||||
|
"startLine": 4,
|
||||||
|
"endLine": 4,
|
||||||
|
"kind": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"attributes": {
|
||||||
|
"startLine": 4,
|
||||||
|
"endLine": 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"attributes": {
|
||||||
|
"startLine": 3,
|
||||||
|
"endLine": 5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeType": "Expr_FuncCall",
|
||||||
|
"name": {
|
||||||
|
"nodeType": "Name",
|
||||||
|
"parts": [
|
||||||
|
"printLine"
|
||||||
|
],
|
||||||
|
"attributes": {
|
||||||
|
"startLine": 7,
|
||||||
|
"endLine": 7
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"nodeType": "Arg",
|
||||||
|
"value": {
|
||||||
|
"nodeType": "Scalar_String",
|
||||||
|
"value": "Hello World!!!",
|
||||||
|
"attributes": {
|
||||||
|
"startLine": 7,
|
||||||
|
"endLine": 7,
|
||||||
|
"kind": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"byRef": false,
|
||||||
|
"unpack": false,
|
||||||
|
"attributes": {
|
||||||
|
"startLine": 7,
|
||||||
|
"endLine": 7
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"attributes": {
|
||||||
|
"startLine": 7,
|
||||||
|
"endLine": 7
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
There is currently no mechanism to convert JSON back into a node tree. Furthermore, not all ASTs
|
||||||
|
can be JSON encoded. In particular, JSON only supports UTF-8 strings.
|
||||||
|
|
||||||
Serialization to XML
|
Serialization to XML
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
@ -35,6 +35,8 @@ the source code of the parsed file. An example for printing an error:
|
|||||||
if ($e->hasColumnInfo()) {
|
if ($e->hasColumnInfo()) {
|
||||||
echo $e->getRawMessage() . ' from ' . $e->getStartLine() . ':' . $e->getStartColumn($code)
|
echo $e->getRawMessage() . ' from ' . $e->getStartLine() . ':' . $e->getStartColumn($code)
|
||||||
. ' to ' . $e->getEndLine() . ':' . $e->getEndColumn($code);
|
. ' to ' . $e->getEndLine() . ':' . $e->getEndColumn($code);
|
||||||
|
// or:
|
||||||
|
echo $e->getMessageWithColumnInfo();
|
||||||
} else {
|
} else {
|
||||||
echo $e->getMessage();
|
echo $e->getMessage();
|
||||||
}
|
}
|
||||||
@ -46,27 +48,23 @@ file.
|
|||||||
Error recovery
|
Error recovery
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
> **EXPERIMENTAL**
|
The error behavior of the parser (and other components) is controlled by an `ErrorHandler`. Whenever an error is
|
||||||
|
encountered, `ErrorHandler::handleError()` is invoked. The default error handling strategy is `ErrorHandler\Throwing`,
|
||||||
|
which will immediately throw when an error is encountered.
|
||||||
|
|
||||||
By default the parser will throw an exception upon encountering the first error during parsing. An alternative mode is
|
To instead collect all encountered errors into an array, while trying to continue parsing the rest of the source code,
|
||||||
also supported, in which the parser will remember the error, but try to continue parsing the rest of the source code.
|
an instance of `ErrorHandler\Collecting` can be passed to the `Parser::parse()` method. A usage example:
|
||||||
|
|
||||||
To enable this mode the `throwOnError` parser option needs to be disabled. Any errors that occurred during parsing can
|
|
||||||
then be retrieved using `$parser->getErrors()`. The `$parser->parse()` method will either return a partial syntax tree
|
|
||||||
or `null` if recovery fails.
|
|
||||||
|
|
||||||
A usage example:
|
|
||||||
|
|
||||||
```php
|
```php
|
||||||
$parser = (new PhpParser\ParserFactory)->create(PhpParser\ParserFactory::PREFER_PHP7, null, array(
|
$parser = (new PhpParser\ParserFactory)->create(PhpParser\ParserFactory::ONLY_PHP7);
|
||||||
'throwOnError' => false,
|
$errorHandler = new PhpParser\ErrorHandler\Collecting;
|
||||||
));
|
|
||||||
|
|
||||||
$stmts = $parser->parse($code);
|
$stmts = $parser->parse($code, $errorHandler);
|
||||||
$errors = $parser->getErrors();
|
|
||||||
|
|
||||||
foreach ($errors as $error) {
|
if ($errorHandler->hasErrors()) {
|
||||||
// $error is an ordinary PhpParser\Error
|
foreach ($errorHandler->getErrors() as $error) {
|
||||||
|
// $error is an ordinary PhpParser\Error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $stmts) {
|
if (null !== $stmts) {
|
||||||
@ -74,4 +72,4 @@ if (null !== $stmts) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The error recovery implementation is experimental -- it currently won't be able to recover from many types of errors.
|
The `NameResolver` visitor also accepts an `ErrorHandler` as a constructor argument.
|
@ -95,13 +95,14 @@ Lexer extension
|
|||||||
|
|
||||||
A lexer has to define the following public interface:
|
A lexer has to define the following public interface:
|
||||||
|
|
||||||
void startLexing(string $code);
|
void startLexing(string $code, ErrorHandler $errorHandler = null);
|
||||||
array getTokens();
|
array getTokens();
|
||||||
string handleHaltCompiler();
|
string handleHaltCompiler();
|
||||||
int getNextToken(string &$value = null, array &$startAttributes = null, array &$endAttributes = null);
|
int getNextToken(string &$value = null, array &$startAttributes = null, array &$endAttributes = null);
|
||||||
|
|
||||||
The `startLexing()` method is invoked with the source code that is to be lexed (including the opening tag) whenever the
|
The `startLexing()` method is invoked with the source code that is to be lexed (including the opening tag) whenever the
|
||||||
`parse()` method of the parser is called. It can be used to reset state or preprocess the source code or tokens.
|
`parse()` method of the parser is called. It can be used to reset state or preprocess the source code or tokens. The
|
||||||
|
passes `ErrorHandler` should be used to report lexing errors.
|
||||||
|
|
||||||
The `getTokens()` method returns the current token array, in the usual `token_get_all()` format. This method is not
|
The `getTokens()` method returns the current token array, in the usual `token_get_all()` format. This method is not
|
||||||
used by the parser (which uses `getNextToken()`), but is useful in combination with the token position attributes.
|
used by the parser (which uses `getNextToken()`), but is useful in combination with the token position attributes.
|
||||||
@ -122,9 +123,10 @@ node and the `$endAttributes` from the last token that is part of the node.
|
|||||||
E.g. if the tokens `T_FUNCTION T_STRING ... '{' ... '}'` constitute a node, then the `$startAttributes` from the
|
E.g. if the tokens `T_FUNCTION T_STRING ... '{' ... '}'` constitute a node, then the `$startAttributes` from the
|
||||||
`T_FUNCTION` token will be taken and the `$endAttributes` from the `'}'` token.
|
`T_FUNCTION` token will be taken and the `$endAttributes` from the `'}'` token.
|
||||||
|
|
||||||
An application of custom attributes is storing the original formatting of literals: The parser does not retain
|
An application of custom attributes is storing the exact original formatting of literals: While the parser does retain
|
||||||
information about the formatting of integers (like decimal vs. hexadecimal) or strings (like used quote type or used
|
some information about the formatting of integers (like decimal vs. hexadecimal) or strings (like used quote type), it
|
||||||
escape sequences). This can be remedied by storing the original value in an attribute:
|
does not preserve the exact original formatting (e.g. leading zeros for integers or escape sequences in strings). This
|
||||||
|
can be remedied by storing the original value in an attribute:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
use PhpParser\Lexer;
|
use PhpParser\Lexer;
|
||||||
@ -135,9 +137,10 @@ class KeepOriginalValueLexer extends Lexer // or Lexer\Emulative
|
|||||||
public function getNextToken(&$value = null, &$startAttributes = null, &$endAttributes = null) {
|
public function getNextToken(&$value = null, &$startAttributes = null, &$endAttributes = null) {
|
||||||
$tokenId = parent::getNextToken($value, $startAttributes, $endAttributes);
|
$tokenId = parent::getNextToken($value, $startAttributes, $endAttributes);
|
||||||
|
|
||||||
if ($tokenId == Tokens::T_CONSTANT_ENCAPSED_STRING // non-interpolated string
|
if ($tokenId == Tokens::T_CONSTANT_ENCAPSED_STRING // non-interpolated string
|
||||||
|| $tokenId == Tokens::T_LNUMBER // integer
|
|| $tokenId == Tokens::T_ENCAPSED_AND_WHITESPACE // interpolated string
|
||||||
|| $tokenId == Tokens::T_DNUMBER // floating point number
|
|| $tokenId == Tokens::T_LNUMBER // integer
|
||||||
|
|| $tokenId == Tokens::T_DNUMBER // floating point number
|
||||||
) {
|
) {
|
||||||
// could also use $startAttributes, doesn't really matter here
|
// could also use $startAttributes, doesn't really matter here
|
||||||
$endAttributes['originalValue'] = $value;
|
$endAttributes['originalValue'] = $value;
|
||||||
|
@ -55,9 +55,12 @@ top_statement:
|
|||||||
| class_declaration_statement { $$ = $1; }
|
| class_declaration_statement { $$ = $1; }
|
||||||
| T_HALT_COMPILER
|
| T_HALT_COMPILER
|
||||||
{ $$ = Stmt\HaltCompiler[$this->lexer->handleHaltCompiler()]; }
|
{ $$ = Stmt\HaltCompiler[$this->lexer->handleHaltCompiler()]; }
|
||||||
| T_NAMESPACE namespace_name ';' { $$ = Stmt\Namespace_[$2, null]; }
|
| T_NAMESPACE namespace_name ';'
|
||||||
| T_NAMESPACE namespace_name '{' top_statement_list '}' { $$ = Stmt\Namespace_[$2, $4]; }
|
{ $$ = Stmt\Namespace_[$2, null]; $this->checkNamespace($$); }
|
||||||
| T_NAMESPACE '{' top_statement_list '}' { $$ = Stmt\Namespace_[null, $3]; }
|
| T_NAMESPACE namespace_name '{' top_statement_list '}'
|
||||||
|
{ $$ = Stmt\Namespace_[$2, $4]; $this->checkNamespace($$); }
|
||||||
|
| T_NAMESPACE '{' top_statement_list '}'
|
||||||
|
{ $$ = Stmt\Namespace_[null, $3]; $this->checkNamespace($$); }
|
||||||
| T_USE use_declarations ';' { $$ = Stmt\Use_[$2, Stmt\Use_::TYPE_NORMAL]; }
|
| T_USE use_declarations ';' { $$ = Stmt\Use_[$2, Stmt\Use_::TYPE_NORMAL]; }
|
||||||
| T_USE use_type use_declarations ';' { $$ = Stmt\Use_[$3, $2]; }
|
| T_USE use_type use_declarations ';' { $$ = Stmt\Use_[$3, $2]; }
|
||||||
| group_use_declaration ';' { $$ = $1; }
|
| group_use_declaration ';' { $$ = $1; }
|
||||||
@ -72,13 +75,13 @@ use_type:
|
|||||||
/* Using namespace_name_parts here to avoid s/r conflict on T_NS_SEPARATOR */
|
/* Using namespace_name_parts here to avoid s/r conflict on T_NS_SEPARATOR */
|
||||||
group_use_declaration:
|
group_use_declaration:
|
||||||
T_USE use_type namespace_name_parts T_NS_SEPARATOR '{' unprefixed_use_declarations '}'
|
T_USE use_type namespace_name_parts T_NS_SEPARATOR '{' unprefixed_use_declarations '}'
|
||||||
{ $$ = Stmt\GroupUse[Name[$3], $6, $2]; }
|
{ $$ = Stmt\GroupUse[new Name($3, stackAttributes(#3)), $6, $2]; }
|
||||||
| T_USE use_type T_NS_SEPARATOR namespace_name_parts T_NS_SEPARATOR '{' unprefixed_use_declarations '}'
|
| T_USE use_type T_NS_SEPARATOR namespace_name_parts T_NS_SEPARATOR '{' unprefixed_use_declarations '}'
|
||||||
{ $$ = Stmt\GroupUse[Name[$4], $7, $2]; }
|
{ $$ = Stmt\GroupUse[new Name($4, stackAttributes(#4)), $7, $2]; }
|
||||||
| T_USE namespace_name_parts T_NS_SEPARATOR '{' inline_use_declarations '}'
|
| T_USE namespace_name_parts T_NS_SEPARATOR '{' inline_use_declarations '}'
|
||||||
{ $$ = Stmt\GroupUse[Name[$2], $5, Stmt\Use_::TYPE_UNKNOWN]; }
|
{ $$ = Stmt\GroupUse[new Name($2, stackAttributes(#2)), $5, Stmt\Use_::TYPE_UNKNOWN]; }
|
||||||
| T_USE T_NS_SEPARATOR namespace_name_parts T_NS_SEPARATOR '{' inline_use_declarations '}'
|
| T_USE T_NS_SEPARATOR namespace_name_parts T_NS_SEPARATOR '{' inline_use_declarations '}'
|
||||||
{ $$ = Stmt\GroupUse[Name[$3], $6, Stmt\Use_::TYPE_UNKNOWN]; }
|
{ $$ = Stmt\GroupUse[new Name($3, stackAttributes(#3)), $6, Stmt\Use_::TYPE_UNKNOWN]; }
|
||||||
;
|
;
|
||||||
|
|
||||||
unprefixed_use_declarations:
|
unprefixed_use_declarations:
|
||||||
@ -98,8 +101,10 @@ inline_use_declarations:
|
|||||||
;
|
;
|
||||||
|
|
||||||
unprefixed_use_declaration:
|
unprefixed_use_declaration:
|
||||||
namespace_name { $$ = Stmt\UseUse[$1, null, Stmt\Use_::TYPE_UNKNOWN]; }
|
namespace_name
|
||||||
| namespace_name T_AS T_STRING { $$ = Stmt\UseUse[$1, $3, Stmt\Use_::TYPE_UNKNOWN]; }
|
{ $$ = Stmt\UseUse[$1, null, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #1); }
|
||||||
|
| namespace_name T_AS T_STRING
|
||||||
|
{ $$ = Stmt\UseUse[$1, $3, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
use_declaration:
|
use_declaration:
|
||||||
@ -179,7 +184,7 @@ non_empty_statement:
|
|||||||
{ $$ = Stmt\Foreach_[$3, $7[0], ['keyVar' => $5, 'byRef' => $7[1], 'stmts' => $9]]; }
|
{ $$ = Stmt\Foreach_[$3, $7[0], ['keyVar' => $5, 'byRef' => $7[1], 'stmts' => $9]]; }
|
||||||
| T_DECLARE '(' declare_list ')' declare_statement { $$ = Stmt\Declare_[$3, $5]; }
|
| T_DECLARE '(' declare_list ')' declare_statement { $$ = Stmt\Declare_[$3, $5]; }
|
||||||
| T_TRY '{' inner_statement_list '}' catches optional_finally
|
| T_TRY '{' inner_statement_list '}' catches optional_finally
|
||||||
{ $$ = Stmt\TryCatch[$3, $5, $6]; }
|
{ $$ = Stmt\TryCatch[$3, $5, $6]; $this->checkTryCatch($$); }
|
||||||
| T_THROW expr ';' { $$ = Stmt\Throw_[$2]; }
|
| T_THROW expr ';' { $$ = Stmt\Throw_[$2]; }
|
||||||
| T_GOTO T_STRING ';' { $$ = Stmt\Goto_[$2]; }
|
| T_GOTO T_STRING ';' { $$ = Stmt\Goto_[$2]; }
|
||||||
| T_STRING ':' { $$ = Stmt\Label[$1]; }
|
| T_STRING ':' { $$ = Stmt\Label[$1]; }
|
||||||
@ -231,9 +236,11 @@ function_declaration_statement:
|
|||||||
|
|
||||||
class_declaration_statement:
|
class_declaration_statement:
|
||||||
class_entry_type T_STRING extends_from implements_list '{' class_statement_list '}'
|
class_entry_type T_STRING extends_from implements_list '{' class_statement_list '}'
|
||||||
{ $$ = Stmt\Class_[$2, ['type' => $1, 'extends' => $3, 'implements' => $4, 'stmts' => $6]]; }
|
{ $$ = Stmt\Class_[$2, ['type' => $1, 'extends' => $3, 'implements' => $4, 'stmts' => $6]];
|
||||||
|
$this->checkClass($$, #2); }
|
||||||
| T_INTERFACE T_STRING interface_extends_list '{' class_statement_list '}'
|
| T_INTERFACE T_STRING interface_extends_list '{' class_statement_list '}'
|
||||||
{ $$ = Stmt\Interface_[$2, ['extends' => $3, 'stmts' => $5]]; }
|
{ $$ = Stmt\Interface_[$2, ['extends' => $3, 'stmts' => $5]];
|
||||||
|
$this->checkInterface($$, #2); }
|
||||||
| T_TRAIT T_STRING '{' class_statement_list '}'
|
| T_TRAIT T_STRING '{' class_statement_list '}'
|
||||||
{ $$ = Stmt\Trait_[$2, ['stmts' => $4]]; }
|
{ $$ = Stmt\Trait_[$2, ['stmts' => $4]]; }
|
||||||
;
|
;
|
||||||
@ -362,9 +369,9 @@ non_empty_parameter_list:
|
|||||||
|
|
||||||
parameter:
|
parameter:
|
||||||
optional_param_type optional_ref optional_ellipsis T_VARIABLE
|
optional_param_type optional_ref optional_ellipsis T_VARIABLE
|
||||||
{ $$ = Node\Param[parseVar($4), null, $1, $2, $3]; }
|
{ $$ = Node\Param[parseVar($4), null, $1, $2, $3]; $this->checkParam($$); }
|
||||||
| optional_param_type optional_ref optional_ellipsis T_VARIABLE '=' static_scalar
|
| optional_param_type optional_ref optional_ellipsis T_VARIABLE '=' static_scalar
|
||||||
{ $$ = Node\Param[parseVar($4), $6, $1, $2, $3]; }
|
{ $$ = Node\Param[parseVar($4), $6, $1, $2, $3]; $this->checkParam($$); }
|
||||||
;
|
;
|
||||||
|
|
||||||
type:
|
type:
|
||||||
@ -427,10 +434,12 @@ class_statement_list:
|
|||||||
;
|
;
|
||||||
|
|
||||||
class_statement:
|
class_statement:
|
||||||
variable_modifiers property_declaration_list ';' { $$ = Stmt\Property[$1, $2]; }
|
variable_modifiers property_declaration_list ';'
|
||||||
|
{ $$ = Stmt\Property[$1, $2]; $this->checkProperty($$, #1); }
|
||||||
| T_CONST class_const_list ';' { $$ = Stmt\ClassConst[$2, 0]; }
|
| T_CONST class_const_list ';' { $$ = Stmt\ClassConst[$2, 0]; }
|
||||||
| method_modifiers T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type method_body
|
| method_modifiers T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type method_body
|
||||||
{ $$ = Stmt\ClassMethod[$4, ['type' => $1, 'byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9]]; }
|
{ $$ = Stmt\ClassMethod[$4, ['type' => $1, 'byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9]];
|
||||||
|
$this->checkClassMethod($$, #1); }
|
||||||
| T_USE name_list trait_adaptations { $$ = Stmt\TraitUse[$2, $3]; }
|
| T_USE name_list trait_adaptations { $$ = Stmt\TraitUse[$2, $3]; }
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -482,7 +491,7 @@ method_modifiers:
|
|||||||
|
|
||||||
non_empty_member_modifiers:
|
non_empty_member_modifiers:
|
||||||
member_modifier { $$ = $1; }
|
member_modifier { $$ = $1; }
|
||||||
| non_empty_member_modifiers member_modifier { Stmt\Class_::verifyModifier($1, $2); $$ = $1 | $2; }
|
| non_empty_member_modifiers member_modifier { $this->checkModifier($1, $2, #2); $$ = $1 | $2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
member_modifier:
|
member_modifier:
|
||||||
@ -640,7 +649,8 @@ scalar_dereference:
|
|||||||
|
|
||||||
anonymous_class:
|
anonymous_class:
|
||||||
T_CLASS ctor_arguments extends_from implements_list '{' class_statement_list '}'
|
T_CLASS ctor_arguments extends_from implements_list '{' class_statement_list '}'
|
||||||
{ $$ = array(Stmt\Class_[null, ['type' => 0, 'extends' => $3, 'implements' => $4, 'stmts' => $6]], $2); }
|
{ $$ = array(Stmt\Class_[null, ['type' => 0, 'extends' => $3, 'implements' => $4, 'stmts' => $6]], $2);
|
||||||
|
$this->checkClass($$[0], -1); }
|
||||||
|
|
||||||
new_expr:
|
new_expr:
|
||||||
T_NEW class_name_reference ctor_arguments { $$ = Expr\New_[$2, $3]; }
|
T_NEW class_name_reference ctor_arguments { $$ = Expr\New_[$2, $3]; }
|
||||||
@ -743,7 +753,7 @@ ctor_arguments:
|
|||||||
;
|
;
|
||||||
|
|
||||||
common_scalar:
|
common_scalar:
|
||||||
T_LNUMBER { $$ = Scalar\LNumber::fromString($1, attributes(), true); }
|
T_LNUMBER { $$ = $this->parseLNumber($1, attributes(), true); }
|
||||||
| T_DNUMBER { $$ = Scalar\DNumber[Scalar\DNumber::parse($1)]; }
|
| T_DNUMBER { $$ = Scalar\DNumber[Scalar\DNumber::parse($1)]; }
|
||||||
| T_CONSTANT_ENCAPSED_STRING
|
| T_CONSTANT_ENCAPSED_STRING
|
||||||
{ $attrs = attributes(); $attrs['kind'] = strKind($1);
|
{ $attrs = attributes(); $attrs['kind'] = strKind($1);
|
||||||
@ -961,10 +971,14 @@ encaps_string_part:
|
|||||||
T_ENCAPSED_AND_WHITESPACE { $$ = Scalar\EncapsedStringPart[$1]; }
|
T_ENCAPSED_AND_WHITESPACE { $$ = Scalar\EncapsedStringPart[$1]; }
|
||||||
;
|
;
|
||||||
|
|
||||||
encaps_var:
|
encaps_base_var:
|
||||||
T_VARIABLE { $$ = Expr\Variable[parseVar($1)]; }
|
T_VARIABLE { $$ = Expr\Variable[parseVar($1)]; }
|
||||||
| T_VARIABLE '[' encaps_var_offset ']' { $$ = Expr\ArrayDimFetch[Expr\Variable[parseVar($1)], $3]; }
|
;
|
||||||
| T_VARIABLE T_OBJECT_OPERATOR T_STRING { $$ = Expr\PropertyFetch[Expr\Variable[parseVar($1)], $3]; }
|
|
||||||
|
encaps_var:
|
||||||
|
encaps_base_var { $$ = $1; }
|
||||||
|
| encaps_base_var '[' encaps_var_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
||||||
|
| encaps_base_var T_OBJECT_OPERATOR T_STRING { $$ = Expr\PropertyFetch[$1, $3]; }
|
||||||
| T_DOLLAR_OPEN_CURLY_BRACES expr '}' { $$ = Expr\Variable[$2]; }
|
| T_DOLLAR_OPEN_CURLY_BRACES expr '}' { $$ = Expr\Variable[$2]; }
|
||||||
| T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '}' { $$ = Expr\Variable[$2]; }
|
| T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '}' { $$ = Expr\Variable[$2]; }
|
||||||
| T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '[' expr ']' '}'
|
| T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '[' expr ']' '}'
|
||||||
|
@ -55,9 +55,12 @@ top_statement:
|
|||||||
| class_declaration_statement { $$ = $1; }
|
| class_declaration_statement { $$ = $1; }
|
||||||
| T_HALT_COMPILER
|
| T_HALT_COMPILER
|
||||||
{ $$ = Stmt\HaltCompiler[$this->lexer->handleHaltCompiler()]; }
|
{ $$ = Stmt\HaltCompiler[$this->lexer->handleHaltCompiler()]; }
|
||||||
| T_NAMESPACE namespace_name ';' { $$ = Stmt\Namespace_[$2, null]; }
|
| T_NAMESPACE namespace_name ';'
|
||||||
| T_NAMESPACE namespace_name '{' top_statement_list '}' { $$ = Stmt\Namespace_[$2, $4]; }
|
{ $$ = Stmt\Namespace_[$2, null]; $this->checkNamespace($$); }
|
||||||
| T_NAMESPACE '{' top_statement_list '}' { $$ = Stmt\Namespace_[null, $3]; }
|
| T_NAMESPACE namespace_name '{' top_statement_list '}'
|
||||||
|
{ $$ = Stmt\Namespace_[$2, $4]; $this->checkNamespace($$); }
|
||||||
|
| T_NAMESPACE '{' top_statement_list '}'
|
||||||
|
{ $$ = Stmt\Namespace_[null, $3]; $this->checkNamespace($$); }
|
||||||
| T_USE use_declarations ';' { $$ = Stmt\Use_[$2, Stmt\Use_::TYPE_NORMAL]; }
|
| T_USE use_declarations ';' { $$ = Stmt\Use_[$2, Stmt\Use_::TYPE_NORMAL]; }
|
||||||
| T_USE use_type use_declarations ';' { $$ = Stmt\Use_[$3, $2]; }
|
| T_USE use_type use_declarations ';' { $$ = Stmt\Use_[$3, $2]; }
|
||||||
| group_use_declaration ';' { $$ = $1; }
|
| group_use_declaration ';' { $$ = $1; }
|
||||||
@ -72,13 +75,13 @@ use_type:
|
|||||||
/* Using namespace_name_parts here to avoid s/r conflict on T_NS_SEPARATOR */
|
/* Using namespace_name_parts here to avoid s/r conflict on T_NS_SEPARATOR */
|
||||||
group_use_declaration:
|
group_use_declaration:
|
||||||
T_USE use_type namespace_name_parts T_NS_SEPARATOR '{' unprefixed_use_declarations '}'
|
T_USE use_type namespace_name_parts T_NS_SEPARATOR '{' unprefixed_use_declarations '}'
|
||||||
{ $$ = Stmt\GroupUse[Name[$3], $6, $2]; }
|
{ $$ = Stmt\GroupUse[new Name($3, stackAttributes(#3)), $6, $2]; }
|
||||||
| T_USE use_type T_NS_SEPARATOR namespace_name_parts T_NS_SEPARATOR '{' unprefixed_use_declarations '}'
|
| T_USE use_type T_NS_SEPARATOR namespace_name_parts T_NS_SEPARATOR '{' unprefixed_use_declarations '}'
|
||||||
{ $$ = Stmt\GroupUse[Name[$4], $7, $2]; }
|
{ $$ = Stmt\GroupUse[new Name($4, stackAttributes(#4)), $7, $2]; }
|
||||||
| T_USE namespace_name_parts T_NS_SEPARATOR '{' inline_use_declarations '}'
|
| T_USE namespace_name_parts T_NS_SEPARATOR '{' inline_use_declarations '}'
|
||||||
{ $$ = Stmt\GroupUse[Name[$2], $5, Stmt\Use_::TYPE_UNKNOWN]; }
|
{ $$ = Stmt\GroupUse[new Name($2, stackAttributes(#2)), $5, Stmt\Use_::TYPE_UNKNOWN]; }
|
||||||
| T_USE T_NS_SEPARATOR namespace_name_parts T_NS_SEPARATOR '{' inline_use_declarations '}'
|
| T_USE T_NS_SEPARATOR namespace_name_parts T_NS_SEPARATOR '{' inline_use_declarations '}'
|
||||||
{ $$ = Stmt\GroupUse[Name[$3], $6, Stmt\Use_::TYPE_UNKNOWN]; }
|
{ $$ = Stmt\GroupUse[new Name($3, stackAttributes(#3)), $6, Stmt\Use_::TYPE_UNKNOWN]; }
|
||||||
;
|
;
|
||||||
|
|
||||||
unprefixed_use_declarations:
|
unprefixed_use_declarations:
|
||||||
@ -98,8 +101,10 @@ inline_use_declarations:
|
|||||||
;
|
;
|
||||||
|
|
||||||
unprefixed_use_declaration:
|
unprefixed_use_declaration:
|
||||||
namespace_name { $$ = Stmt\UseUse[$1, null, Stmt\Use_::TYPE_UNKNOWN]; }
|
namespace_name
|
||||||
| namespace_name T_AS T_STRING { $$ = Stmt\UseUse[$1, $3, Stmt\Use_::TYPE_UNKNOWN]; }
|
{ $$ = Stmt\UseUse[$1, null, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #1); }
|
||||||
|
| namespace_name T_AS T_STRING
|
||||||
|
{ $$ = Stmt\UseUse[$1, $3, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
use_declaration:
|
use_declaration:
|
||||||
@ -175,7 +180,7 @@ non_empty_statement:
|
|||||||
{ $$ = Stmt\Foreach_[$3, $7[0], ['keyVar' => $5, 'byRef' => $7[1], 'stmts' => $9]]; }
|
{ $$ = Stmt\Foreach_[$3, $7[0], ['keyVar' => $5, 'byRef' => $7[1], 'stmts' => $9]]; }
|
||||||
| T_DECLARE '(' declare_list ')' declare_statement { $$ = Stmt\Declare_[$3, $5]; }
|
| T_DECLARE '(' declare_list ')' declare_statement { $$ = Stmt\Declare_[$3, $5]; }
|
||||||
| T_TRY '{' inner_statement_list '}' catches optional_finally
|
| T_TRY '{' inner_statement_list '}' catches optional_finally
|
||||||
{ $$ = Stmt\TryCatch[$3, $5, $6]; }
|
{ $$ = Stmt\TryCatch[$3, $5, $6]; $this->checkTryCatch($$); }
|
||||||
| T_THROW expr ';' { $$ = Stmt\Throw_[$2]; }
|
| T_THROW expr ';' { $$ = Stmt\Throw_[$2]; }
|
||||||
| T_GOTO T_STRING ';' { $$ = Stmt\Goto_[$2]; }
|
| T_GOTO T_STRING ';' { $$ = Stmt\Goto_[$2]; }
|
||||||
| T_STRING ':' { $$ = Stmt\Label[$1]; }
|
| T_STRING ':' { $$ = Stmt\Label[$1]; }
|
||||||
@ -232,9 +237,11 @@ function_declaration_statement:
|
|||||||
|
|
||||||
class_declaration_statement:
|
class_declaration_statement:
|
||||||
class_entry_type T_STRING extends_from implements_list '{' class_statement_list '}'
|
class_entry_type T_STRING extends_from implements_list '{' class_statement_list '}'
|
||||||
{ $$ = Stmt\Class_[$2, ['type' => $1, 'extends' => $3, 'implements' => $4, 'stmts' => $6]]; }
|
{ $$ = Stmt\Class_[$2, ['type' => $1, 'extends' => $3, 'implements' => $4, 'stmts' => $6]];
|
||||||
|
$this->checkClass($$, #2); }
|
||||||
| T_INTERFACE T_STRING interface_extends_list '{' class_statement_list '}'
|
| T_INTERFACE T_STRING interface_extends_list '{' class_statement_list '}'
|
||||||
{ $$ = Stmt\Interface_[$2, ['extends' => $3, 'stmts' => $5]]; }
|
{ $$ = Stmt\Interface_[$2, ['extends' => $3, 'stmts' => $5]];
|
||||||
|
$this->checkInterface($$, #2); }
|
||||||
| T_TRAIT T_STRING '{' class_statement_list '}'
|
| T_TRAIT T_STRING '{' class_statement_list '}'
|
||||||
{ $$ = Stmt\Trait_[$2, ['stmts' => $4]]; }
|
{ $$ = Stmt\Trait_[$2, ['stmts' => $4]]; }
|
||||||
;
|
;
|
||||||
@ -364,9 +371,9 @@ non_empty_parameter_list:
|
|||||||
|
|
||||||
parameter:
|
parameter:
|
||||||
optional_param_type optional_ref optional_ellipsis T_VARIABLE
|
optional_param_type optional_ref optional_ellipsis T_VARIABLE
|
||||||
{ $$ = Node\Param[parseVar($4), null, $1, $2, $3]; }
|
{ $$ = Node\Param[parseVar($4), null, $1, $2, $3]; $this->checkParam($$); }
|
||||||
| optional_param_type optional_ref optional_ellipsis T_VARIABLE '=' expr
|
| optional_param_type optional_ref optional_ellipsis T_VARIABLE '=' expr
|
||||||
{ $$ = Node\Param[parseVar($4), $6, $1, $2, $3]; }
|
{ $$ = Node\Param[parseVar($4), $6, $1, $2, $3]; $this->checkParam($$); }
|
||||||
;
|
;
|
||||||
|
|
||||||
type_expr:
|
type_expr:
|
||||||
@ -431,10 +438,13 @@ class_statement_list:
|
|||||||
;
|
;
|
||||||
|
|
||||||
class_statement:
|
class_statement:
|
||||||
variable_modifiers property_declaration_list ';' { $$ = Stmt\Property[$1, $2]; }
|
variable_modifiers property_declaration_list ';'
|
||||||
| method_modifiers T_CONST class_const_list ';' { $$ = Stmt\ClassConst[$3, $1]; }
|
{ $$ = Stmt\Property[$1, $2]; $this->checkProperty($$, #1); }
|
||||||
|
| method_modifiers T_CONST class_const_list ';'
|
||||||
|
{ $$ = Stmt\ClassConst[$3, $1]; $this->checkClassConst($$, #1); }
|
||||||
| method_modifiers T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type method_body
|
| method_modifiers T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type method_body
|
||||||
{ $$ = Stmt\ClassMethod[$4, ['type' => $1, 'byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9]]; }
|
{ $$ = Stmt\ClassMethod[$4, ['type' => $1, 'byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9]];
|
||||||
|
$this->checkClassMethod($$, #1); }
|
||||||
| T_USE name_list trait_adaptations { $$ = Stmt\TraitUse[$2, $3]; }
|
| T_USE name_list trait_adaptations { $$ = Stmt\TraitUse[$2, $3]; }
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -486,7 +496,7 @@ method_modifiers:
|
|||||||
|
|
||||||
non_empty_member_modifiers:
|
non_empty_member_modifiers:
|
||||||
member_modifier { $$ = $1; }
|
member_modifier { $$ = $1; }
|
||||||
| non_empty_member_modifiers member_modifier { Stmt\Class_::verifyModifier($1, $2); $$ = $1 | $2; }
|
| non_empty_member_modifiers member_modifier { $this->checkModifier($1, $2, #2); $$ = $1 | $2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
member_modifier:
|
member_modifier:
|
||||||
@ -613,7 +623,8 @@ expr:
|
|||||||
|
|
||||||
anonymous_class:
|
anonymous_class:
|
||||||
T_CLASS ctor_arguments extends_from implements_list '{' class_statement_list '}'
|
T_CLASS ctor_arguments extends_from implements_list '{' class_statement_list '}'
|
||||||
{ $$ = array(Stmt\Class_[null, ['type' => 0, 'extends' => $3, 'implements' => $4, 'stmts' => $6]], $2); }
|
{ $$ = array(Stmt\Class_[null, ['type' => 0, 'extends' => $3, 'implements' => $4, 'stmts' => $6]], $2);
|
||||||
|
$this->checkClass($$[0], -1); }
|
||||||
|
|
||||||
new_expr:
|
new_expr:
|
||||||
T_NEW class_name_reference ctor_arguments { $$ = Expr\New_[$2, $3]; }
|
T_NEW class_name_reference ctor_arguments { $$ = Expr\New_[$2, $3]; }
|
||||||
@ -656,6 +667,7 @@ name:
|
|||||||
class_name_reference:
|
class_name_reference:
|
||||||
class_name { $$ = $1; }
|
class_name { $$ = $1; }
|
||||||
| new_variable { $$ = $1; }
|
| new_variable { $$ = $1; }
|
||||||
|
| error { $$ = Expr\Error[]; $this->errorState = 2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
class_name_or_var:
|
class_name_or_var:
|
||||||
@ -684,6 +696,10 @@ constant:
|
|||||||
name { $$ = Expr\ConstFetch[$1]; }
|
name { $$ = Expr\ConstFetch[$1]; }
|
||||||
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier
|
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier
|
||||||
{ $$ = Expr\ClassConstFetch[$1, $3]; }
|
{ $$ = Expr\ClassConstFetch[$1, $3]; }
|
||||||
|
/* We interpret and isolated FOO:: as an unfinished class constant fetch. It could also be
|
||||||
|
an unfinished static property fetch or unfinished scoped call. */
|
||||||
|
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM error
|
||||||
|
{ $$ = Expr\ClassConstFetch[$1, Expr\Error[]]; $this->errorState = 2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
array_short_syntax:
|
array_short_syntax:
|
||||||
@ -703,7 +719,7 @@ dereferencable_scalar:
|
|||||||
;
|
;
|
||||||
|
|
||||||
scalar:
|
scalar:
|
||||||
T_LNUMBER { $$ = Scalar\LNumber::fromString($1, attributes()); }
|
T_LNUMBER { $$ = $this->parseLNumber($1, attributes()); }
|
||||||
| T_DNUMBER { $$ = Scalar\DNumber[Scalar\DNumber::parse($1)]; }
|
| T_DNUMBER { $$ = Scalar\DNumber[Scalar\DNumber::parse($1)]; }
|
||||||
| T_LINE { $$ = Scalar\MagicConst\Line[]; }
|
| T_LINE { $$ = Scalar\MagicConst\Line[]; }
|
||||||
| T_FILE { $$ = Scalar\MagicConst\File[]; }
|
| T_FILE { $$ = Scalar\MagicConst\File[]; }
|
||||||
@ -766,6 +782,7 @@ simple_variable:
|
|||||||
T_VARIABLE { $$ = parseVar($1); }
|
T_VARIABLE { $$ = parseVar($1); }
|
||||||
| '$' '{' expr '}' { $$ = $3; }
|
| '$' '{' expr '}' { $$ = $3; }
|
||||||
| '$' simple_variable { $$ = Expr\Variable[$2]; }
|
| '$' simple_variable { $$ = Expr\Variable[$2]; }
|
||||||
|
| '$' error { $$ = Expr\Error[]; $this->errorState = 2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
static_member:
|
static_member:
|
||||||
@ -841,10 +858,14 @@ encaps_string_part:
|
|||||||
T_ENCAPSED_AND_WHITESPACE { $$ = Scalar\EncapsedStringPart[$1]; }
|
T_ENCAPSED_AND_WHITESPACE { $$ = Scalar\EncapsedStringPart[$1]; }
|
||||||
;
|
;
|
||||||
|
|
||||||
encaps_var:
|
encaps_base_var:
|
||||||
T_VARIABLE { $$ = Expr\Variable[parseVar($1)]; }
|
T_VARIABLE { $$ = Expr\Variable[parseVar($1)]; }
|
||||||
| T_VARIABLE '[' encaps_var_offset ']' { $$ = Expr\ArrayDimFetch[Expr\Variable[parseVar($1)], $3]; }
|
;
|
||||||
| T_VARIABLE T_OBJECT_OPERATOR T_STRING { $$ = Expr\PropertyFetch[Expr\Variable[parseVar($1)], $3]; }
|
|
||||||
|
encaps_var:
|
||||||
|
encaps_base_var { $$ = $1; }
|
||||||
|
| encaps_base_var '[' encaps_var_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
||||||
|
| encaps_base_var T_OBJECT_OPERATOR T_STRING { $$ = Expr\PropertyFetch[$1, $3]; }
|
||||||
| T_DOLLAR_OPEN_CURLY_BRACES expr '}' { $$ = Expr\Variable[$2]; }
|
| T_DOLLAR_OPEN_CURLY_BRACES expr '}' { $$ = Expr\Variable[$2]; }
|
||||||
| T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '}' { $$ = Expr\Variable[$2]; }
|
| T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '}' { $$ = Expr\Variable[$2]; }
|
||||||
| T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '[' expr ']' '}'
|
| T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '[' expr ']' '}'
|
||||||
|
@ -124,6 +124,12 @@ function resolveMacros($code) {
|
|||||||
return '$this->startAttributeStack[#1] + $this->endAttributes';
|
return '$this->startAttributeStack[#1] + $this->endAttributes';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('stackAttributes' == $name) {
|
||||||
|
assertArgs(1, $args, $name);
|
||||||
|
return '$this->startAttributeStack[' . $args[0] . ']'
|
||||||
|
. ' + $this->endAttributeStack[' . $args[0] . ']';
|
||||||
|
}
|
||||||
|
|
||||||
if ('init' == $name) {
|
if ('init' == $name) {
|
||||||
return '$$ = array(' . implode(', ', $args) . ')';
|
return '$$ = array(' . implode(', ', $args) . ')';
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
namespace PhpParser\Builder;
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
use PhpParser;
|
use PhpParser;
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
|
|
||||||
abstract class Declaration extends PhpParser\BuilderAbstract
|
abstract class Declaration extends PhpParser\BuilderAbstract
|
||||||
{
|
{
|
||||||
|
@ -4,7 +4,6 @@ namespace PhpParser\Builder;
|
|||||||
|
|
||||||
use PhpParser;
|
use PhpParser;
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
|
|
||||||
abstract class FunctionLike extends Declaration
|
abstract class FunctionLike extends Declaration
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
namespace PhpParser\Builder;
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
use PhpParser;
|
use PhpParser;
|
||||||
use PhpParser\Node\Name;
|
|
||||||
use PhpParser\Node\Stmt;
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
class Trait_ extends Declaration
|
class Trait_ extends Declaration
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
namespace PhpParser;
|
namespace PhpParser;
|
||||||
|
|
||||||
use PhpParser\Node\Name;
|
|
||||||
use PhpParser\Node\Expr;
|
|
||||||
use PhpParser\Node\NullableType;
|
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
use PhpParser\Node\Scalar;
|
|
||||||
use PhpParser\Comment;
|
use PhpParser\Comment;
|
||||||
|
use PhpParser\Node\Expr;
|
||||||
|
use PhpParser\Node\Name;
|
||||||
|
use PhpParser\Node\NullableType;
|
||||||
|
use PhpParser\Node\Scalar;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
abstract class BuilderAbstract implements Builder {
|
abstract class BuilderAbstract implements Builder {
|
||||||
/**
|
/**
|
||||||
|
@ -61,6 +61,16 @@ class Error extends \RuntimeException
|
|||||||
return $this->attributes;
|
return $this->attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the attributes of the node/token the error occured at.
|
||||||
|
*
|
||||||
|
* @param array $attributes
|
||||||
|
*/
|
||||||
|
public function setAttributes(array $attributes) {
|
||||||
|
$this->attributes = $attributes;
|
||||||
|
$this->updateMessage();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the line of the PHP file the error occurred in.
|
* Sets the line of the PHP file the error occurred in.
|
||||||
*
|
*
|
||||||
@ -120,6 +130,14 @@ class Error extends \RuntimeException
|
|||||||
return $this->toColumn($code, $this->attributes['endFilePos']);
|
return $this->toColumn($code, $this->attributes['endFilePos']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getMessageWithColumnInfo($code) {
|
||||||
|
return sprintf(
|
||||||
|
'%s from %d:%d to %d:%d', $this->getRawMessage(),
|
||||||
|
$this->getStartLine(), $this->getStartColumn($code),
|
||||||
|
$this->getEndLine(), $this->getEndColumn($code)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private function toColumn($code, $pos) {
|
private function toColumn($code, $pos) {
|
||||||
if ($pos > strlen($code)) {
|
if ($pos > strlen($code)) {
|
||||||
throw new \RuntimeException('Invalid position information');
|
throw new \RuntimeException('Invalid position information');
|
||||||
@ -145,14 +163,4 @@ class Error extends \RuntimeException
|
|||||||
$this->message .= ' on line ' . $this->getStartLine();
|
$this->message .= ' on line ' . $this->getStartLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @deprecated Use getStartLine() instead */
|
|
||||||
public function getRawLine() {
|
|
||||||
return $this->getStartLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated Use setStartLine() instead */
|
|
||||||
public function setRawLine($line) {
|
|
||||||
$this->setStartLine($line);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
13
lib/PhpParser/ErrorHandler.php
Normal file
13
lib/PhpParser/ErrorHandler.php
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpParser;
|
||||||
|
|
||||||
|
interface ErrorHandler
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an error generated during lexing, parsing or some other operation.
|
||||||
|
*
|
||||||
|
* @param Error $error The error that needs to be handled
|
||||||
|
*/
|
||||||
|
public function handleError(Error $error);
|
||||||
|
}
|
46
lib/PhpParser/ErrorHandler/Collecting.php
Normal file
46
lib/PhpParser/ErrorHandler/Collecting.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpParser\ErrorHandler;
|
||||||
|
|
||||||
|
use PhpParser\Error;
|
||||||
|
use PhpParser\ErrorHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error handler that collects all errors into an array.
|
||||||
|
*
|
||||||
|
* This allows graceful handling of errors.
|
||||||
|
*/
|
||||||
|
class Collecting implements ErrorHandler
|
||||||
|
{
|
||||||
|
/** @var Error[] Collected errors */
|
||||||
|
private $errors = [];
|
||||||
|
|
||||||
|
public function handleError(Error $error) {
|
||||||
|
$this->errors[] = $error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get collected errors.
|
||||||
|
*
|
||||||
|
* @return Error[]
|
||||||
|
*/
|
||||||
|
public function getErrors() {
|
||||||
|
return $this->errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether there are any errors.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasErrors() {
|
||||||
|
return !empty($this->errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset/clear collected errors.
|
||||||
|
*/
|
||||||
|
public function clearErrors() {
|
||||||
|
$this->errors = [];
|
||||||
|
}
|
||||||
|
}
|
18
lib/PhpParser/ErrorHandler/Throwing.php
Normal file
18
lib/PhpParser/ErrorHandler/Throwing.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpParser\ErrorHandler;
|
||||||
|
|
||||||
|
use PhpParser\Error;
|
||||||
|
use PhpParser\ErrorHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error handler that handles all errors by throwing them.
|
||||||
|
*
|
||||||
|
* This is the default strategy used by all components.
|
||||||
|
*/
|
||||||
|
class Throwing implements ErrorHandler
|
||||||
|
{
|
||||||
|
public function handleError(Error $error) {
|
||||||
|
throw $error;
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace PhpParser;
|
namespace PhpParser;
|
||||||
|
|
||||||
use PhpParser\Node\Scalar\LNumber;
|
|
||||||
use PhpParser\Parser\Tokens;
|
use PhpParser\Parser\Tokens;
|
||||||
|
|
||||||
class Lexer
|
class Lexer
|
||||||
@ -49,19 +48,16 @@ class Lexer
|
|||||||
/**
|
/**
|
||||||
* Initializes the lexer for lexing the provided source code.
|
* Initializes the lexer for lexing the provided source code.
|
||||||
*
|
*
|
||||||
* @param string $code The source code to lex
|
* This function does not throw if lexing errors occur. Instead, errors may be retrieved using
|
||||||
|
* the getErrors() method.
|
||||||
*
|
*
|
||||||
* @throws Error on lexing errors (unterminated comment or unexpected character)
|
* @param string $code The source code to lex
|
||||||
|
* @param ErrorHandler|null $errorHandler Error handler to use for lexing errors. Defaults to
|
||||||
|
* ErrorHandler\Throwing
|
||||||
*/
|
*/
|
||||||
public function startLexing($code) {
|
public function startLexing($code, ErrorHandler $errorHandler = null) {
|
||||||
$scream = ini_set('xdebug.scream', '0');
|
if (null === $errorHandler) {
|
||||||
|
$errorHandler = new ErrorHandler\Throwing();
|
||||||
$this->resetErrors();
|
|
||||||
$this->tokens = @token_get_all($code);
|
|
||||||
$this->handleErrors();
|
|
||||||
|
|
||||||
if (false !== $scream) {
|
|
||||||
ini_set('xdebug.scream', $scream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->code = $code; // keep the code around for __halt_compiler() handling
|
$this->code = $code; // keep the code around for __halt_compiler() handling
|
||||||
@ -72,6 +68,16 @@ class Lexer
|
|||||||
// If inline HTML occurs without preceding code, treat it as if it had a leading newline.
|
// If inline HTML occurs without preceding code, treat it as if it had a leading newline.
|
||||||
// This ensures proper composability, because having a newline is the "safe" assumption.
|
// This ensures proper composability, because having a newline is the "safe" assumption.
|
||||||
$this->prevCloseTagHasNewline = true;
|
$this->prevCloseTagHasNewline = true;
|
||||||
|
|
||||||
|
$scream = ini_set('xdebug.scream', '0');
|
||||||
|
|
||||||
|
$this->resetErrors();
|
||||||
|
$this->tokens = @token_get_all($code);
|
||||||
|
$this->handleErrors($errorHandler);
|
||||||
|
|
||||||
|
if (false !== $scream) {
|
||||||
|
ini_set('xdebug.scream', $scream);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function resetErrors() {
|
protected function resetErrors() {
|
||||||
@ -85,32 +91,109 @@ class Lexer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handleErrors() {
|
private function handleInvalidCharacterRange($start, $end, $line, ErrorHandler $errorHandler) {
|
||||||
|
for ($i = $start; $i < $end; $i++) {
|
||||||
|
$chr = $this->code[$i];
|
||||||
|
if ($chr === 'b' || $chr === 'B') {
|
||||||
|
// HHVM does not treat b" tokens correctly, so ignore these
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($chr === "\0") {
|
||||||
|
// PHP cuts error message after null byte, so need special case
|
||||||
|
$errorMsg = 'Unexpected null byte';
|
||||||
|
} else {
|
||||||
|
$errorMsg = sprintf(
|
||||||
|
'Unexpected character "%s" (ASCII %d)', $chr, ord($chr)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$errorHandler->handleError(new Error($errorMsg, [
|
||||||
|
'startLine' => $line,
|
||||||
|
'endLine' => $line,
|
||||||
|
'startFilePos' => $i,
|
||||||
|
'endFilePos' => $i,
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isUnterminatedComment($token) {
|
||||||
|
return ($token[0] === T_COMMENT || $token[0] === T_DOC_COMMENT)
|
||||||
|
&& substr($token[1], 0, 2) === '/*'
|
||||||
|
&& substr($token[1], -2) !== '*/';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function errorMayHaveOccurred() {
|
||||||
|
if (defined('HHVM_VERSION')) {
|
||||||
|
// In HHVM token_get_all() does not throw warnings, so we need to conservatively
|
||||||
|
// assume that an error occurred
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
$error = error_get_last();
|
$error = error_get_last();
|
||||||
if (null === $error) {
|
return null !== $error
|
||||||
|
&& false === strpos($error['message'], 'Undefined variable');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleErrors(ErrorHandler $errorHandler) {
|
||||||
|
if (!$this->errorMayHaveOccurred()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (preg_match(
|
// PHP's error handling for token_get_all() is rather bad, so if we want detailed
|
||||||
'~^Unterminated comment starting line ([0-9]+)$~',
|
// error information we need to compute it ourselves. Invalid character errors are
|
||||||
$error['message'], $matches
|
// detected by finding "gaps" in the token array. Unterminated comments are detected
|
||||||
)) {
|
// by checking if a trailing comment has a "*/" at the end.
|
||||||
throw new Error('Unterminated comment', (int) $matches[1]);
|
|
||||||
|
$filePos = 0;
|
||||||
|
$line = 1;
|
||||||
|
foreach ($this->tokens as $i => $token) {
|
||||||
|
$tokenValue = \is_string($token) ? $token : $token[1];
|
||||||
|
$tokenLen = \strlen($tokenValue);
|
||||||
|
|
||||||
|
if (substr($this->code, $filePos, $tokenLen) !== $tokenValue) {
|
||||||
|
// Something is missing, must be an invalid character
|
||||||
|
$nextFilePos = strpos($this->code, $tokenValue, $filePos);
|
||||||
|
$this->handleInvalidCharacterRange(
|
||||||
|
$filePos, $nextFilePos, $line, $errorHandler);
|
||||||
|
$filePos = $nextFilePos;
|
||||||
|
}
|
||||||
|
|
||||||
|
$filePos += $tokenLen;
|
||||||
|
$line += substr_count($tokenValue, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (preg_match(
|
if ($filePos !== \strlen($this->code)) {
|
||||||
'~^Unexpected character in input: \'(.)\' \(ASCII=([0-9]+)\)~s',
|
if (substr($this->code, $filePos, 2) === '/*') {
|
||||||
$error['message'], $matches
|
// Unlike PHP, HHVM will drop unterminated comments entirely
|
||||||
)) {
|
$comment = substr($this->code, $filePos);
|
||||||
throw new Error(sprintf(
|
$errorHandler->handleError(new Error('Unterminated comment', [
|
||||||
'Unexpected character "%s" (ASCII %d)',
|
'startLine' => $line,
|
||||||
$matches[1], $matches[2]
|
'endLine' => $line + substr_count($comment, "\n"),
|
||||||
));
|
'startFilePos' => $filePos,
|
||||||
|
'endFilePos' => $filePos + \strlen($comment),
|
||||||
|
]));
|
||||||
|
|
||||||
|
// Emulate the PHP behavior
|
||||||
|
$isDocComment = isset($comment[3]) && $comment[3] === '*';
|
||||||
|
$this->tokens[] = [$isDocComment ? T_DOC_COMMENT : T_COMMENT, $comment, $line];
|
||||||
|
} else {
|
||||||
|
// Invalid characters at the end of the input
|
||||||
|
$this->handleInvalidCharacterRange(
|
||||||
|
$filePos, \strlen($this->code), $line, $errorHandler);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PHP cuts error message after null byte, so need special case
|
// Check for unterminated comment
|
||||||
if (preg_match('~^Unexpected character in input: \'$~', $error['message'])) {
|
$lastToken = $this->tokens[count($this->tokens) - 1];
|
||||||
throw new Error('Unexpected null byte');
|
if ($this->isUnterminatedComment($lastToken)) {
|
||||||
|
$errorHandler->handleError(new Error('Unterminated comment', [
|
||||||
|
'startLine' => $line - substr_count($lastToken[1], "\n"),
|
||||||
|
'endLine' => $line,
|
||||||
|
'startFilePos' => $filePos - \strlen($lastToken[1]),
|
||||||
|
'endFilePos' => $filePos,
|
||||||
|
]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,11 +2,9 @@
|
|||||||
|
|
||||||
namespace PhpParser\Lexer;
|
namespace PhpParser\Lexer;
|
||||||
|
|
||||||
|
use PhpParser\ErrorHandler;
|
||||||
use PhpParser\Parser\Tokens;
|
use PhpParser\Parser\Tokens;
|
||||||
|
|
||||||
/**
|
|
||||||
* ATTENTION: This code is WRITE-ONLY. Do not try to read it.
|
|
||||||
*/
|
|
||||||
class Emulative extends \PhpParser\Lexer
|
class Emulative extends \PhpParser\Lexer
|
||||||
{
|
{
|
||||||
protected $newKeywords;
|
protected $newKeywords;
|
||||||
@ -53,131 +51,106 @@ class Emulative extends \PhpParser\Lexer
|
|||||||
$this->tokenMap[self::T_POW_EQUAL] = Tokens::T_POW_EQUAL;
|
$this->tokenMap[self::T_POW_EQUAL] = Tokens::T_POW_EQUAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function startLexing($code) {
|
public function startLexing($code, ErrorHandler $errorHandler = null) {
|
||||||
$this->inObjectAccess = false;
|
$this->inObjectAccess = false;
|
||||||
|
|
||||||
$preprocessedCode = $this->preprocessCode($code);
|
parent::startLexing($code, $errorHandler);
|
||||||
parent::startLexing($preprocessedCode);
|
if ($this->requiresEmulation($code)) {
|
||||||
if ($preprocessedCode !== $code) {
|
$this->emulateTokens();
|
||||||
$this->postprocessTokens();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set code property back to the original code, so __halt_compiler()
|
|
||||||
// handling and (start|end)FilePos attributes use the correct offsets
|
|
||||||
$this->code = $code;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Replaces new features in the code by ~__EMU__{NAME}__{DATA}__~ sequences.
|
* Checks if the code is potentially using features that require emulation.
|
||||||
* ~LABEL~ is never valid PHP code, that's why we can (to some degree) safely
|
|
||||||
* use it here.
|
|
||||||
* Later when preprocessing the tokens these sequences will either be replaced
|
|
||||||
* by real tokens or replaced with their original content (e.g. if they occurred
|
|
||||||
* inside a string, i.e. a place where they don't have a special meaning).
|
|
||||||
*/
|
*/
|
||||||
protected function preprocessCode($code) {
|
protected function requiresEmulation($code) {
|
||||||
if (version_compare(PHP_VERSION, self::PHP_7_0, '>=')) {
|
if (version_compare(PHP_VERSION, self::PHP_7_0, '>=')) {
|
||||||
return $code;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$code = str_replace('??', '~__EMU__COALESCE__~', $code);
|
if (preg_match('(\?\?|<=>|yield[ \n\r\t]+from)', $code)) {
|
||||||
$code = str_replace('<=>', '~__EMU__SPACESHIP__~', $code);
|
return true;
|
||||||
$code = preg_replace_callback('(yield[ \n\r\t]+from)', function($matches) {
|
}
|
||||||
// Encoding $0 in order to preserve exact whitespace
|
|
||||||
return '~__EMU__YIELDFROM__' . bin2hex($matches[0]) . '__~';
|
|
||||||
}, $code);
|
|
||||||
|
|
||||||
if (version_compare(PHP_VERSION, self::PHP_5_6, '>=')) {
|
if (version_compare(PHP_VERSION, self::PHP_5_6, '>=')) {
|
||||||
return $code;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$code = str_replace('...', '~__EMU__ELLIPSIS__~', $code);
|
return preg_match('(\.\.\.|(?<!/)\*\*(?!/))', $code);
|
||||||
$code = preg_replace('((?<!/)\*\*=)', '~__EMU__POWEQUAL__~', $code);
|
|
||||||
$code = preg_replace('((?<!/)\*\*(?!/))', '~__EMU__POW__~', $code);
|
|
||||||
|
|
||||||
return $code;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Replaces the ~__EMU__...~ sequences with real tokens or their original
|
* Emulates tokens for newer PHP versions.
|
||||||
* value.
|
|
||||||
*/
|
*/
|
||||||
protected function postprocessTokens() {
|
protected function emulateTokens() {
|
||||||
// we need to manually iterate and manage a count because we'll change
|
// We need to manually iterate and manage a count because we'll change
|
||||||
// the tokens array on the way
|
// the tokens array on the way
|
||||||
|
$line = 1;
|
||||||
for ($i = 0, $c = count($this->tokens); $i < $c; ++$i) {
|
for ($i = 0, $c = count($this->tokens); $i < $c; ++$i) {
|
||||||
// first check that the following tokens are of form ~LABEL~,
|
$replace = null;
|
||||||
// then match the __EMU__... sequence.
|
if (isset($this->tokens[$i + 1])) {
|
||||||
if ('~' === $this->tokens[$i]
|
if ($this->tokens[$i] === '?' && $this->tokens[$i + 1] === '?') {
|
||||||
&& isset($this->tokens[$i + 2])
|
array_splice($this->tokens, $i, 2, array(
|
||||||
&& '~' === $this->tokens[$i + 2]
|
array(self::T_COALESCE, '??', $line)
|
||||||
&& T_STRING === $this->tokens[$i + 1][0]
|
));
|
||||||
&& preg_match('(^__EMU__([A-Z]++)__(?:([A-Za-z0-9]++)__)?$)', $this->tokens[$i + 1][1], $matches)
|
$c--;
|
||||||
) {
|
continue;
|
||||||
if ('ELLIPSIS' === $matches[1]) {
|
}
|
||||||
$replace = array(
|
if ($this->tokens[$i][0] === T_IS_SMALLER_OR_EQUAL
|
||||||
array(self::T_ELLIPSIS, '...', $this->tokens[$i + 1][2])
|
&& $this->tokens[$i + 1] === '>'
|
||||||
);
|
) {
|
||||||
} else if ('POW' === $matches[1]) {
|
array_splice($this->tokens, $i, 2, array(
|
||||||
$replace = array(
|
array(self::T_SPACESHIP, '<=>', $line)
|
||||||
array(self::T_POW, '**', $this->tokens[$i + 1][2])
|
));
|
||||||
);
|
$c--;
|
||||||
} else if ('POWEQUAL' === $matches[1]) {
|
continue;
|
||||||
$replace = array(
|
}
|
||||||
array(self::T_POW_EQUAL, '**=', $this->tokens[$i + 1][2])
|
if ($this->tokens[$i] === '*' && $this->tokens[$i + 1] === '*') {
|
||||||
);
|
array_splice($this->tokens, $i, 2, array(
|
||||||
} else if ('COALESCE' === $matches[1]) {
|
array(self::T_POW, '**', $line)
|
||||||
$replace = array(
|
));
|
||||||
array(self::T_COALESCE, '??', $this->tokens[$i + 1][2])
|
$c--;
|
||||||
);
|
continue;
|
||||||
} else if ('SPACESHIP' === $matches[1]) {
|
}
|
||||||
$replace = array(
|
if ($this->tokens[$i] === '*' && $this->tokens[$i + 1][0] === T_MUL_EQUAL) {
|
||||||
array(self::T_SPACESHIP, '<=>', $this->tokens[$i + 1][2]),
|
array_splice($this->tokens, $i, 2, array(
|
||||||
);
|
array(self::T_POW_EQUAL, '**=', $line)
|
||||||
} else if ('YIELDFROM' === $matches[1]) {
|
));
|
||||||
$content = hex2bin($matches[2]);
|
$c--;
|
||||||
$replace = array(
|
continue;
|
||||||
array(self::T_YIELD_FROM, $content, $this->tokens[$i + 1][2] - substr_count($content, "\n"))
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
throw new \RuntimeException('Invalid __EMU__ sequence');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
array_splice($this->tokens, $i, 3, $replace);
|
|
||||||
$c -= 3 - count($replace);
|
|
||||||
// for multichar tokens (e.g. strings) replace any ~__EMU__...~ sequences
|
|
||||||
// in their content with the original character sequence
|
|
||||||
} elseif (is_array($this->tokens[$i])
|
|
||||||
&& 0 !== strpos($this->tokens[$i][1], '__EMU__')
|
|
||||||
) {
|
|
||||||
$this->tokens[$i][1] = preg_replace_callback(
|
|
||||||
'(~__EMU__([A-Z]++)__(?:([A-Za-z0-9]++)__)?~)',
|
|
||||||
array($this, 'restoreContentCallback'),
|
|
||||||
$this->tokens[$i][1]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
if (isset($this->tokens[$i + 2])) {
|
||||||
* This method is a callback for restoring EMU sequences in
|
if ($this->tokens[$i][0] === T_YIELD && $this->tokens[$i + 1][0] === T_WHITESPACE
|
||||||
* multichar tokens (like strings) to their original value.
|
&& $this->tokens[$i + 2][0] === T_STRING
|
||||||
*/
|
&& !strcasecmp($this->tokens[$i + 2][1], 'from')
|
||||||
public function restoreContentCallback(array $matches) {
|
) {
|
||||||
if ('ELLIPSIS' === $matches[1]) {
|
array_splice($this->tokens, $i, 3, array(
|
||||||
return '...';
|
array(
|
||||||
} else if ('POW' === $matches[1]) {
|
self::T_YIELD_FROM,
|
||||||
return '**';
|
$this->tokens[$i][1] . $this->tokens[$i + 1][1] . $this->tokens[$i + 2][1],
|
||||||
} else if ('POWEQUAL' === $matches[1]) {
|
$line
|
||||||
return '**=';
|
)
|
||||||
} else if ('COALESCE' === $matches[1]) {
|
));
|
||||||
return '??';
|
$c -= 2;
|
||||||
} else if ('SPACESHIP' === $matches[1]) {
|
$line += substr_count($this->tokens[$i][1], "\n");
|
||||||
return '<=>';
|
continue;
|
||||||
} else if ('YIELDFROM' === $matches[1]) {
|
}
|
||||||
return hex2bin($matches[2]);
|
if ($this->tokens[$i] === '.' && $this->tokens[$i + 1] === '.'
|
||||||
} else {
|
&& $this->tokens[$i + 2] === '.'
|
||||||
return $matches[0];
|
) {
|
||||||
|
array_splice($this->tokens, $i, 3, array(
|
||||||
|
array(self::T_ELLIPSIS, '...', $line)
|
||||||
|
));
|
||||||
|
$c -= 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\is_array($this->tokens[$i])) {
|
||||||
|
$line += substr_count($this->tokens[$i][1], "\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +41,15 @@ interface Node
|
|||||||
*/
|
*/
|
||||||
public function getDocComment();
|
public function getDocComment();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the doc comment of the node.
|
||||||
|
*
|
||||||
|
* This will either replace an existing doc comment or add it to the comments array.
|
||||||
|
*
|
||||||
|
* @param Comment\Doc $docComment Doc comment to set
|
||||||
|
*/
|
||||||
|
public function setDocComment(Comment\Doc $docComment);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets an attribute on a node.
|
* Sets an attribute on a node.
|
||||||
*
|
*
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace PhpParser\Node\Expr;
|
namespace PhpParser\Node\Expr;
|
||||||
|
|
||||||
use PhpParser\Node\Name;
|
|
||||||
use PhpParser\Node\Expr;
|
use PhpParser\Node\Expr;
|
||||||
|
use PhpParser\Node\Name;
|
||||||
|
|
||||||
class ClassConstFetch extends Expr
|
class ClassConstFetch extends Expr
|
||||||
{
|
{
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace PhpParser\Node\Expr;
|
namespace PhpParser\Node\Expr;
|
||||||
|
|
||||||
use PhpParser\Node\Name;
|
|
||||||
use PhpParser\Node\Expr;
|
use PhpParser\Node\Expr;
|
||||||
|
use PhpParser\Node\Name;
|
||||||
|
|
||||||
class ConstFetch extends Expr
|
class ConstFetch extends Expr
|
||||||
{
|
{
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace PhpParser\Node\Expr;
|
namespace PhpParser\Node\Expr;
|
||||||
|
|
||||||
use PhpParser\Node\Name;
|
|
||||||
use PhpParser\Node\Expr;
|
use PhpParser\Node\Expr;
|
||||||
|
use PhpParser\Node\Name;
|
||||||
|
|
||||||
class Instanceof_ extends Expr
|
class Instanceof_ extends Expr
|
||||||
{
|
{
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace PhpParser\Node\Expr;
|
namespace PhpParser\Node\Expr;
|
||||||
|
|
||||||
use PhpParser\Node\Name;
|
|
||||||
use PhpParser\Node\Expr;
|
use PhpParser\Node\Expr;
|
||||||
|
use PhpParser\Node\Name;
|
||||||
|
|
||||||
class StaticPropertyFetch extends Expr
|
class StaticPropertyFetch extends Expr
|
||||||
{
|
{
|
||||||
|
@ -6,22 +6,21 @@ use PhpParser\NodeAbstract;
|
|||||||
|
|
||||||
class Name extends NodeAbstract
|
class Name extends NodeAbstract
|
||||||
{
|
{
|
||||||
/** @var string[] Parts of the name */
|
/**
|
||||||
|
* @var string[] Parts of the name
|
||||||
|
* @deprecated Avoid directly accessing $parts, use methods instead.
|
||||||
|
*/
|
||||||
public $parts;
|
public $parts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a name node.
|
* Constructs a name node.
|
||||||
*
|
*
|
||||||
* @param string|array $parts Parts of the name (or name as string)
|
* @param string|array|self $name Name as string, part array or Name instance (copy ctor)
|
||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct($parts, array $attributes = array()) {
|
public function __construct($name, array $attributes = array()) {
|
||||||
if (!is_array($parts)) {
|
|
||||||
$parts = explode('\\', $parts);
|
|
||||||
}
|
|
||||||
|
|
||||||
parent::__construct($attributes);
|
parent::__construct($attributes);
|
||||||
$this->parts = $parts;
|
$this->parts = self::prepareName($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSubNodeNames() {
|
public function getSubNodeNames() {
|
||||||
@ -83,14 +82,13 @@ class Name extends NodeAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a string representation of the name by imploding the namespace parts with a separator.
|
* Returns a string representation of the name by imploding the namespace parts with the
|
||||||
*
|
* namespace separator.
|
||||||
* @param string $separator The separator to use (defaults to the namespace separator \)
|
|
||||||
*
|
*
|
||||||
* @return string String representation
|
* @return string String representation
|
||||||
*/
|
*/
|
||||||
public function toString($separator = '\\') {
|
public function toString() {
|
||||||
return implode($separator, $this->parts);
|
return implode('\\', $this->parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -103,43 +101,21 @@ class Name extends NodeAbstract
|
|||||||
return implode('\\', $this->parts);
|
return implode('\\', $this->parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepends a name to this name.
|
|
||||||
*
|
|
||||||
* @deprecated Use Name::concat($name1, $name2) instead
|
|
||||||
*
|
|
||||||
* @param string|array|self $name Name to prepend
|
|
||||||
*/
|
|
||||||
public function prepend($name) {
|
|
||||||
$this->parts = array_merge(self::prepareName($name), $this->parts);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Appends a name to this name.
|
|
||||||
*
|
|
||||||
* @deprecated Use Name::concat($name1, $name2) instead
|
|
||||||
*
|
|
||||||
* @param string|array|self $name Name to append
|
|
||||||
*/
|
|
||||||
public function append($name) {
|
|
||||||
$this->parts = array_merge($this->parts, self::prepareName($name));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a slice of a name (similar to array_slice).
|
* Gets a slice of a name (similar to array_slice).
|
||||||
*
|
*
|
||||||
* This method returns a new instance of the same type as the original and with the same
|
* This method returns a new instance of the same type as the original and with the same
|
||||||
* attributes.
|
* attributes.
|
||||||
*
|
*
|
||||||
* If the slice is empty, a Name with an empty parts array is returned. While this is
|
* If the slice is empty, null is returned. The null value will be correctly handled in
|
||||||
* meaningless in itself, it works correctly in conjunction with concat().
|
* concatenations using concat().
|
||||||
*
|
*
|
||||||
* Offset and length have the same meaning as in array_slice().
|
* Offset and length have the same meaning as in array_slice().
|
||||||
*
|
*
|
||||||
* @param int $offset Offset to start the slice at (may be negative)
|
* @param int $offset Offset to start the slice at (may be negative)
|
||||||
* @param int|null $length Length of the slice (may be negative)
|
* @param int|null $length Length of the slice (may be negative)
|
||||||
*
|
*
|
||||||
* @return static Sliced name
|
* @return static|null Sliced name
|
||||||
*/
|
*/
|
||||||
public function slice($offset, $length = null) {
|
public function slice($offset, $length = null) {
|
||||||
$numParts = count($this->parts);
|
$numParts = count($this->parts);
|
||||||
@ -158,6 +134,11 @@ class Name extends NodeAbstract
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($realLength === 0) {
|
||||||
|
// Empty slice is represented as null
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return new static(array_slice($this->parts, $realOffset, $realLength), $this->attributes);
|
return new static(array_slice($this->parts, $realOffset, $realLength), $this->attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,16 +148,29 @@ class Name extends NodeAbstract
|
|||||||
* The type of the generated instance depends on which class this method is called on, for
|
* The type of the generated instance depends on which class this method is called on, for
|
||||||
* example Name\FullyQualified::concat() will yield a Name\FullyQualified instance.
|
* example Name\FullyQualified::concat() will yield a Name\FullyQualified instance.
|
||||||
*
|
*
|
||||||
* @param string|array|self $name1 The first name
|
* If one of the arguments is null, a new instance of the other name will be returned. If both
|
||||||
* @param string|array|self $name2 The second name
|
* arguments are null, null will be returned. As such, writing
|
||||||
* @param array $attributes Attributes to assign to concatenated name
|
* Name::concat($namespace, $shortName)
|
||||||
|
* where $namespace is a Name node or null will work as expected.
|
||||||
*
|
*
|
||||||
* @return static Concatenated name
|
* @param string|array|self|null $name1 The first name
|
||||||
|
* @param string|array|self|null $name2 The second name
|
||||||
|
* @param array $attributes Attributes to assign to concatenated name
|
||||||
|
*
|
||||||
|
* @return static|null Concatenated name
|
||||||
*/
|
*/
|
||||||
public static function concat($name1, $name2, array $attributes = []) {
|
public static function concat($name1, $name2, array $attributes = []) {
|
||||||
return new static(
|
if (null === $name1 && null === $name2) {
|
||||||
array_merge(self::prepareName($name1), self::prepareName($name2)), $attributes
|
return null;
|
||||||
);
|
} elseif (null === $name1) {
|
||||||
|
return new static(self::prepareName($name2), $attributes);
|
||||||
|
} else if (null === $name2) {
|
||||||
|
return new static(self::prepareName($name1), $attributes);
|
||||||
|
} else {
|
||||||
|
return new static(
|
||||||
|
array_merge(self::prepareName($name1), self::prepareName($name2)), $attributes
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -188,16 +182,16 @@ class Name extends NodeAbstract
|
|||||||
* @return array Prepared name
|
* @return array Prepared name
|
||||||
*/
|
*/
|
||||||
private static function prepareName($name) {
|
private static function prepareName($name) {
|
||||||
if (is_string($name)) {
|
if (\is_string($name)) {
|
||||||
return explode('\\', $name);
|
return explode('\\', $name);
|
||||||
} elseif (is_array($name)) {
|
} elseif (\is_array($name)) {
|
||||||
return $name;
|
return $name;
|
||||||
} elseif ($name instanceof self) {
|
} elseif ($name instanceof self) {
|
||||||
return $name->parts;
|
return $name->parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new \InvalidArgumentException(
|
throw new \InvalidArgumentException(
|
||||||
'When changing a name you need to pass either a string, an array or a Name node'
|
'Expected string, array of parts or Name instance'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace PhpParser\Node;
|
namespace PhpParser\Node;
|
||||||
|
|
||||||
use PhpParser\Error;
|
|
||||||
use PhpParser\NodeAbstract;
|
use PhpParser\NodeAbstract;
|
||||||
|
|
||||||
class Param extends NodeAbstract
|
class Param extends NodeAbstract
|
||||||
@ -35,10 +34,6 @@ class Param extends NodeAbstract
|
|||||||
$this->variadic = $variadic;
|
$this->variadic = $variadic;
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
$this->default = $default;
|
$this->default = $default;
|
||||||
|
|
||||||
if ($variadic && null !== $default) {
|
|
||||||
throw new Error('Variadic parameter cannot have a default value', $default->getAttributes());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSubNodeNames() {
|
public function getSubNodeNames() {
|
||||||
|
@ -2,11 +2,12 @@
|
|||||||
|
|
||||||
namespace PhpParser\Node\Scalar;
|
namespace PhpParser\Node\Scalar;
|
||||||
|
|
||||||
|
use PhpParser\Node\Expr;
|
||||||
use PhpParser\Node\Scalar;
|
use PhpParser\Node\Scalar;
|
||||||
|
|
||||||
class Encapsed extends Scalar
|
class Encapsed extends Scalar
|
||||||
{
|
{
|
||||||
/** @var array Encaps list */
|
/** @var Expr[] list of string parts */
|
||||||
public $parts;
|
public $parts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
namespace PhpParser\Node\Stmt;
|
namespace PhpParser\Node\Stmt;
|
||||||
|
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
use PhpParser\Error;
|
|
||||||
|
|
||||||
class ClassConst extends Node\Stmt
|
class ClassConst extends Node\Stmt
|
||||||
{
|
{
|
||||||
@ -20,16 +19,6 @@ class ClassConst extends Node\Stmt
|
|||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct(array $consts, $flags = 0, array $attributes = array()) {
|
public function __construct(array $consts, $flags = 0, array $attributes = array()) {
|
||||||
if ($flags & Class_::MODIFIER_STATIC) {
|
|
||||||
throw new Error("Cannot use 'static' as constant modifier");
|
|
||||||
}
|
|
||||||
if ($flags & Class_::MODIFIER_ABSTRACT) {
|
|
||||||
throw new Error("Cannot use 'abstract' as constant modifier");
|
|
||||||
}
|
|
||||||
if ($flags & Class_::MODIFIER_FINAL) {
|
|
||||||
throw new Error("Cannot use 'final' as constant modifier");
|
|
||||||
}
|
|
||||||
|
|
||||||
parent::__construct($attributes);
|
parent::__construct($attributes);
|
||||||
$this->flags = $flags;
|
$this->flags = $flags;
|
||||||
$this->consts = $consts;
|
$this->consts = $consts;
|
||||||
|
@ -5,7 +5,7 @@ namespace PhpParser\Node\Stmt;
|
|||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
|
|
||||||
abstract class ClassLike extends Node\Stmt {
|
abstract class ClassLike extends Node\Stmt {
|
||||||
/** @var string Name */
|
/** @var string|null Name */
|
||||||
public $name;
|
public $name;
|
||||||
/** @var Node[] Statements */
|
/** @var Node[] Statements */
|
||||||
public $stmts;
|
public $stmts;
|
||||||
|
@ -4,7 +4,6 @@ namespace PhpParser\Node\Stmt;
|
|||||||
|
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
use PhpParser\Node\FunctionLike;
|
use PhpParser\Node\FunctionLike;
|
||||||
use PhpParser\Error;
|
|
||||||
|
|
||||||
class ClassMethod extends Node\Stmt implements FunctionLike
|
class ClassMethod extends Node\Stmt implements FunctionLike
|
||||||
{
|
{
|
||||||
@ -46,17 +45,6 @@ class ClassMethod extends Node\Stmt implements FunctionLike
|
|||||||
$this->params = isset($subNodes['params']) ? $subNodes['params'] : array();
|
$this->params = isset($subNodes['params']) ? $subNodes['params'] : array();
|
||||||
$this->returnType = isset($subNodes['returnType']) ? $subNodes['returnType'] : null;
|
$this->returnType = isset($subNodes['returnType']) ? $subNodes['returnType'] : null;
|
||||||
$this->stmts = array_key_exists('stmts', $subNodes) ? $subNodes['stmts'] : array();
|
$this->stmts = array_key_exists('stmts', $subNodes) ? $subNodes['stmts'] : array();
|
||||||
|
|
||||||
if ($this->flags & Class_::MODIFIER_STATIC) {
|
|
||||||
switch (strtolower($this->name)) {
|
|
||||||
case '__construct':
|
|
||||||
throw new Error(sprintf('Constructor %s() cannot be static', $this->name));
|
|
||||||
case '__destruct':
|
|
||||||
throw new Error(sprintf('Destructor %s() cannot be static', $this->name));
|
|
||||||
case '__clone':
|
|
||||||
throw new Error(sprintf('Clone method %s() cannot be static', $this->name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSubNodeNames() {
|
public function getSubNodeNames() {
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace PhpParser\Node\Stmt;
|
namespace PhpParser\Node\Stmt;
|
||||||
|
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Error;
|
use PhpParser\Error;
|
||||||
|
use PhpParser\Node;
|
||||||
|
|
||||||
class Class_ extends ClassLike
|
class Class_ extends ClassLike
|
||||||
{
|
{
|
||||||
@ -52,26 +52,6 @@ class Class_ extends ClassLike
|
|||||||
$this->extends = isset($subNodes['extends']) ? $subNodes['extends'] : null;
|
$this->extends = isset($subNodes['extends']) ? $subNodes['extends'] : null;
|
||||||
$this->implements = isset($subNodes['implements']) ? $subNodes['implements'] : array();
|
$this->implements = isset($subNodes['implements']) ? $subNodes['implements'] : array();
|
||||||
$this->stmts = isset($subNodes['stmts']) ? $subNodes['stmts'] : array();
|
$this->stmts = isset($subNodes['stmts']) ? $subNodes['stmts'] : array();
|
||||||
|
|
||||||
if (null !== $this->name && isset(self::$specialNames[strtolower($this->name)])) {
|
|
||||||
throw new Error(sprintf('Cannot use \'%s\' as class name as it is reserved', $this->name));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset(self::$specialNames[strtolower($this->extends)])) {
|
|
||||||
throw new Error(
|
|
||||||
sprintf('Cannot use \'%s\' as class name as it is reserved', $this->extends),
|
|
||||||
$this->extends->getAttributes()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($this->implements as $interface) {
|
|
||||||
if (isset(self::$specialNames[strtolower($interface)])) {
|
|
||||||
throw new Error(
|
|
||||||
sprintf('Cannot use \'%s\' as interface name as it is reserved', $interface),
|
|
||||||
$interface->getAttributes()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSubNodeNames() {
|
public function getSubNodeNames() {
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
namespace PhpParser\Node\Stmt;
|
namespace PhpParser\Node\Stmt;
|
||||||
|
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
|
|
||||||
class Declare_ extends Node\Stmt
|
class Declare_ extends Node\Stmt
|
||||||
{
|
{
|
||||||
/** @var DeclareDeclare[] List of declares */
|
/** @var DeclareDeclare[] List of declares */
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace PhpParser\Node\Stmt;
|
namespace PhpParser\Node\Stmt;
|
||||||
|
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
use PhpParser\Node\Name;
|
use PhpParser\Node\Name;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
class GroupUse extends Stmt
|
class GroupUse extends Stmt
|
||||||
{
|
{
|
||||||
|
@ -3,19 +3,12 @@
|
|||||||
namespace PhpParser\Node\Stmt;
|
namespace PhpParser\Node\Stmt;
|
||||||
|
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
use PhpParser\Error;
|
|
||||||
|
|
||||||
class Interface_ extends ClassLike
|
class Interface_ extends ClassLike
|
||||||
{
|
{
|
||||||
/** @var Node\Name[] Extended interfaces */
|
/** @var Node\Name[] Extended interfaces */
|
||||||
public $extends;
|
public $extends;
|
||||||
|
|
||||||
protected static $specialNames = array(
|
|
||||||
'self' => true,
|
|
||||||
'parent' => true,
|
|
||||||
'static' => true,
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a class node.
|
* Constructs a class node.
|
||||||
*
|
*
|
||||||
@ -30,19 +23,6 @@ class Interface_ extends ClassLike
|
|||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
$this->extends = isset($subNodes['extends']) ? $subNodes['extends'] : array();
|
$this->extends = isset($subNodes['extends']) ? $subNodes['extends'] : array();
|
||||||
$this->stmts = isset($subNodes['stmts']) ? $subNodes['stmts'] : array();
|
$this->stmts = isset($subNodes['stmts']) ? $subNodes['stmts'] : array();
|
||||||
|
|
||||||
if (isset(self::$specialNames[strtolower($this->name)])) {
|
|
||||||
throw new Error(sprintf('Cannot use \'%s\' as class name as it is reserved', $this->name));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($this->extends as $interface) {
|
|
||||||
if (isset(self::$specialNames[strtolower($interface)])) {
|
|
||||||
throw new Error(
|
|
||||||
sprintf('Cannot use \'%s\' as interface name as it is reserved', $interface),
|
|
||||||
$interface->getAttributes()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSubNodeNames() {
|
public function getSubNodeNames() {
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
namespace PhpParser\Node\Stmt;
|
namespace PhpParser\Node\Stmt;
|
||||||
|
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
use PhpParser\Error;
|
|
||||||
|
|
||||||
class Namespace_ extends Node\Stmt
|
class Namespace_ extends Node\Stmt
|
||||||
{
|
{
|
||||||
@ -12,12 +11,6 @@ class Namespace_ extends Node\Stmt
|
|||||||
/** @var Node[] Statements */
|
/** @var Node[] Statements */
|
||||||
public $stmts;
|
public $stmts;
|
||||||
|
|
||||||
protected static $specialNames = array(
|
|
||||||
'self' => true,
|
|
||||||
'parent' => true,
|
|
||||||
'static' => true,
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a namespace node.
|
* Constructs a namespace node.
|
||||||
*
|
*
|
||||||
@ -29,21 +22,6 @@ class Namespace_ extends Node\Stmt
|
|||||||
parent::__construct($attributes);
|
parent::__construct($attributes);
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
$this->stmts = $stmts;
|
$this->stmts = $stmts;
|
||||||
|
|
||||||
if (isset(self::$specialNames[strtolower($this->name)])) {
|
|
||||||
throw new Error(
|
|
||||||
sprintf('Cannot use \'%s\' as namespace name', $this->name),
|
|
||||||
$this->name->getAttributes()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null !== $this->stmts) {
|
|
||||||
foreach ($this->stmts as $stmt) {
|
|
||||||
if ($stmt instanceof self) {
|
|
||||||
throw new Error('Namespace declarations cannot be nested', $stmt->getAttributes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSubNodeNames() {
|
public function getSubNodeNames() {
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
namespace PhpParser\Node\Stmt;
|
namespace PhpParser\Node\Stmt;
|
||||||
|
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
use PhpParser\Error;
|
|
||||||
|
|
||||||
class Property extends Node\Stmt
|
class Property extends Node\Stmt
|
||||||
{
|
{
|
||||||
@ -23,14 +22,6 @@ class Property extends Node\Stmt
|
|||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct($flags, array $props, array $attributes = array()) {
|
public function __construct($flags, array $props, array $attributes = array()) {
|
||||||
if ($flags & Class_::MODIFIER_ABSTRACT) {
|
|
||||||
throw new Error('Properties cannot be declared abstract');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($flags & Class_::MODIFIER_FINAL) {
|
|
||||||
throw new Error('Properties cannot be declared final');
|
|
||||||
}
|
|
||||||
|
|
||||||
parent::__construct($attributes);
|
parent::__construct($attributes);
|
||||||
$this->flags = $flags;
|
$this->flags = $flags;
|
||||||
$this->type = $flags;
|
$this->type = $flags;
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
namespace PhpParser\Node\Stmt;
|
namespace PhpParser\Node\Stmt;
|
||||||
|
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
use PhpParser\Error;
|
|
||||||
|
|
||||||
class TryCatch extends Node\Stmt
|
class TryCatch extends Node\Stmt
|
||||||
{
|
{
|
||||||
@ -23,10 +22,6 @@ class TryCatch extends Node\Stmt
|
|||||||
* @param array|null $attributes Additional attributes
|
* @param array|null $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct(array $stmts, array $catches, Finally_ $finally = null, array $attributes = array()) {
|
public function __construct(array $stmts, array $catches, Finally_ $finally = null, array $attributes = array()) {
|
||||||
if (empty($catches) && null === $finally) {
|
|
||||||
throw new Error('Cannot use try without catch or finally');
|
|
||||||
}
|
|
||||||
|
|
||||||
parent::__construct($attributes);
|
parent::__construct($attributes);
|
||||||
$this->stmts = $stmts;
|
$this->stmts = $stmts;
|
||||||
$this->catches = $catches;
|
$this->catches = $catches;
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
namespace PhpParser\Node\Stmt;
|
namespace PhpParser\Node\Stmt;
|
||||||
|
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
use PhpParser\Error;
|
|
||||||
|
|
||||||
class UseUse extends Node\Stmt
|
class UseUse extends Node\Stmt
|
||||||
{
|
{
|
||||||
@ -27,13 +26,6 @@ class UseUse extends Node\Stmt
|
|||||||
$alias = $name->getLast();
|
$alias = $name->getLast();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('self' == strtolower($alias) || 'parent' == strtolower($alias)) {
|
|
||||||
throw new Error(sprintf(
|
|
||||||
'Cannot use %s as %s because \'%2$s\' is a special class name',
|
|
||||||
$name, $alias
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
parent::__construct($attributes);
|
parent::__construct($attributes);
|
||||||
$this->type = $type;
|
$this->type = $type;
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
|
@ -63,6 +63,28 @@ abstract class NodeAbstract implements Node, \JsonSerializable
|
|||||||
return $lastComment;
|
return $lastComment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the doc comment of the node.
|
||||||
|
*
|
||||||
|
* This will either replace an existing doc comment or add it to the comments array.
|
||||||
|
*
|
||||||
|
* @param Comment\Doc $docComment Doc comment to set
|
||||||
|
*/
|
||||||
|
public function setDocComment(Comment\Doc $docComment) {
|
||||||
|
$comments = $this->getAttribute('comments', []);
|
||||||
|
|
||||||
|
$numComments = count($comments);
|
||||||
|
if ($numComments > 0 && $comments[$numComments - 1] instanceof Comment\Doc) {
|
||||||
|
// Replace existing doc comment
|
||||||
|
$comments[$numComments - 1] = $docComment;
|
||||||
|
} else {
|
||||||
|
// Append new comment
|
||||||
|
$comments[] = $docComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setAttribute('comments', $comments);
|
||||||
|
}
|
||||||
|
|
||||||
public function setAttribute($key, $value) {
|
public function setAttribute($key, $value) {
|
||||||
$this->attributes[$key] = $value;
|
$this->attributes[$key] = $value;
|
||||||
}
|
}
|
||||||
|
@ -11,27 +11,46 @@ use PhpParser\Node\Stmt\UseUse;
|
|||||||
class NodeDumper
|
class NodeDumper
|
||||||
{
|
{
|
||||||
private $dumpComments;
|
private $dumpComments;
|
||||||
|
private $dumpPositions;
|
||||||
|
private $code;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a NodeDumper.
|
* Constructs a NodeDumper.
|
||||||
*
|
*
|
||||||
* @param array $options Boolean option 'dumpComments' controls whether comments should be
|
* Supported options:
|
||||||
* dumped
|
* * bool dumpComments: Whether comments should be dumped.
|
||||||
|
* * bool dumpPositions: Whether line/offset information should be dumped. To dump offset
|
||||||
|
* information, the code needs to be passed to dump().
|
||||||
|
*
|
||||||
|
* @param array $options Options (see description)
|
||||||
*/
|
*/
|
||||||
public function __construct(array $options = []) {
|
public function __construct(array $options = []) {
|
||||||
$this->dumpComments = !empty($options['dumpComments']);
|
$this->dumpComments = !empty($options['dumpComments']);
|
||||||
|
$this->dumpPositions = !empty($options['dumpPositions']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dumps a node or array.
|
* Dumps a node or array.
|
||||||
*
|
*
|
||||||
* @param array|Node $node Node or array to dump
|
* @param array|Node $node Node or array to dump
|
||||||
|
* @param string|null $code Code corresponding to dumped AST. This only needs to be passed if
|
||||||
|
* the dumpPositions option is enabled and the dumping of node offsets
|
||||||
|
* is desired.
|
||||||
*
|
*
|
||||||
* @return string Dumped value
|
* @return string Dumped value
|
||||||
*/
|
*/
|
||||||
public function dump($node) {
|
public function dump($node, $code = null) {
|
||||||
|
$this->code = $code;
|
||||||
|
return $this->dumpRecursive($node);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function dumpRecursive($node) {
|
||||||
if ($node instanceof Node) {
|
if ($node instanceof Node) {
|
||||||
$r = $node->getType() . '(';
|
$r = $node->getType();
|
||||||
|
if ($this->dumpPositions && null !== $p = $this->dumpPosition($node)) {
|
||||||
|
$r .= $p;
|
||||||
|
}
|
||||||
|
$r .= '(';
|
||||||
|
|
||||||
foreach ($node->getSubNodeNames() as $key) {
|
foreach ($node->getSubNodeNames() as $key) {
|
||||||
$r .= "\n " . $key . ': ';
|
$r .= "\n " . $key . ': ';
|
||||||
@ -55,12 +74,12 @@ class NodeDumper
|
|||||||
$r .= $value;
|
$r .= $value;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$r .= str_replace("\n", "\n ", $this->dump($value));
|
$r .= str_replace("\n", "\n ", $this->dumpRecursive($value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->dumpComments && $comments = $node->getAttribute('comments')) {
|
if ($this->dumpComments && $comments = $node->getAttribute('comments')) {
|
||||||
$r .= "\n comments: " . str_replace("\n", "\n ", $this->dump($comments));
|
$r .= "\n comments: " . str_replace("\n", "\n ", $this->dumpRecursive($comments));
|
||||||
}
|
}
|
||||||
} elseif (is_array($node)) {
|
} elseif (is_array($node)) {
|
||||||
$r = 'array(';
|
$r = 'array(';
|
||||||
@ -77,7 +96,7 @@ class NodeDumper
|
|||||||
} elseif (is_scalar($value)) {
|
} elseif (is_scalar($value)) {
|
||||||
$r .= $value;
|
$r .= $value;
|
||||||
} else {
|
} else {
|
||||||
$r .= str_replace("\n", "\n ", $this->dump($value));
|
$r .= str_replace("\n", "\n ", $this->dumpRecursive($value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif ($node instanceof Comment) {
|
} elseif ($node instanceof Comment) {
|
||||||
@ -144,4 +163,34 @@ class NodeDumper
|
|||||||
}
|
}
|
||||||
return $map[$type] . ' (' . $type . ')';
|
return $map[$type] . ' (' . $type . ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function dumpPosition(Node $node) {
|
||||||
|
if (!$node->hasAttribute('startLine') || !$node->hasAttribute('endLine')) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$start = $node->getAttribute('startLine');
|
||||||
|
$end = $node->getAttribute('endLine');
|
||||||
|
if ($node->hasAttribute('startFilePos') && $node->hasAttribute('endFilePos')
|
||||||
|
&& null !== $this->code
|
||||||
|
) {
|
||||||
|
$start .= ':' . $this->toColumn($this->code, $node->getAttribute('startFilePos'));
|
||||||
|
$end .= ':' . $this->toColumn($this->code, $node->getAttribute('endFilePos'));
|
||||||
|
}
|
||||||
|
return "[$start - $end]";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copied from Error class
|
||||||
|
private function toColumn($code, $pos) {
|
||||||
|
if ($pos > strlen($code)) {
|
||||||
|
throw new \RuntimeException('Invalid position information');
|
||||||
|
}
|
||||||
|
|
||||||
|
$lineStartPos = strrpos($code, "\n", $pos - strlen($code));
|
||||||
|
if (false === $lineStartPos) {
|
||||||
|
$lineStartPos = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $pos - $lineStartPos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,23 +5,31 @@ namespace PhpParser;
|
|||||||
class NodeTraverser implements NodeTraverserInterface
|
class NodeTraverser implements NodeTraverserInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var NodeVisitor[] Visitors
|
* If NodeVisitor::enterNode() returns DONT_TRAVERSE_CHILDREN, child nodes
|
||||||
|
* of the current node will not be traversed for any visitors.
|
||||||
|
*
|
||||||
|
* For subsequent visitors enterNode() will still be called on the current
|
||||||
|
* node and leaveNode() will also be invoked for the current node.
|
||||||
*/
|
*/
|
||||||
|
const DONT_TRAVERSE_CHILDREN = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If NodeVisitor::leaveNode() returns REMOVE_NODE for a node that occurs
|
||||||
|
* in an array, it will be removed from the array.
|
||||||
|
*
|
||||||
|
* For subsequent visitors leaveNode() will still be invoked for the
|
||||||
|
* removed node.
|
||||||
|
*/
|
||||||
|
const REMOVE_NODE = false;
|
||||||
|
|
||||||
|
/** @var NodeVisitor[] Visitors */
|
||||||
protected $visitors;
|
protected $visitors;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
private $cloneNodes;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a node traverser.
|
* Constructs a node traverser.
|
||||||
*
|
|
||||||
* @param bool $cloneNodes Should the traverser clone the nodes when traversing the AST
|
|
||||||
*/
|
*/
|
||||||
public function __construct($cloneNodes = false) {
|
public function __construct() {
|
||||||
$this->visitors = array();
|
$this->visitors = array();
|
||||||
$this->cloneNodes = $cloneNodes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -73,10 +81,6 @@ class NodeTraverser implements NodeTraverserInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function traverseNode(Node $node) {
|
protected function traverseNode(Node $node) {
|
||||||
if ($this->cloneNodes) {
|
|
||||||
$node = clone $node;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($node->getSubNodeNames() as $name) {
|
foreach ($node->getSubNodeNames() as $name) {
|
||||||
$subNode =& $node->$name;
|
$subNode =& $node->$name;
|
||||||
|
|
||||||
|
@ -4,24 +4,6 @@ namespace PhpParser;
|
|||||||
|
|
||||||
interface NodeTraverserInterface
|
interface NodeTraverserInterface
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* If NodeVisitor::enterNode() returns DONT_TRAVERSE_CHILDREN, child nodes
|
|
||||||
* of the current node will not be traversed for any visitors.
|
|
||||||
*
|
|
||||||
* For subsequent visitors enterNode() will still be called on the current
|
|
||||||
* node and leaveNode() will also be invoked for the current node.
|
|
||||||
*/
|
|
||||||
const DONT_TRAVERSE_CHILDREN = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If NodeVisitor::leaveNode() returns REMOVE_NODE for a node that occurs
|
|
||||||
* in an array, it will be removed from the array.
|
|
||||||
*
|
|
||||||
* For subsequent visitors leaveNode() will still be invoked for the
|
|
||||||
* removed node.
|
|
||||||
*/
|
|
||||||
const REMOVE_NODE = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a visitor.
|
* Adds a visitor.
|
||||||
*
|
*
|
||||||
|
@ -2,13 +2,14 @@
|
|||||||
|
|
||||||
namespace PhpParser\NodeVisitor;
|
namespace PhpParser\NodeVisitor;
|
||||||
|
|
||||||
use PhpParser\NodeVisitorAbstract;
|
|
||||||
use PhpParser\Error;
|
use PhpParser\Error;
|
||||||
|
use PhpParser\ErrorHandler;
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Expr;
|
||||||
use PhpParser\Node\Name;
|
use PhpParser\Node\Name;
|
||||||
use PhpParser\Node\Name\FullyQualified;
|
use PhpParser\Node\Name\FullyQualified;
|
||||||
use PhpParser\Node\Expr;
|
|
||||||
use PhpParser\Node\Stmt;
|
use PhpParser\Node\Stmt;
|
||||||
|
use PhpParser\NodeVisitorAbstract;
|
||||||
|
|
||||||
class NameResolver extends NodeVisitorAbstract
|
class NameResolver extends NodeVisitorAbstract
|
||||||
{
|
{
|
||||||
@ -18,6 +19,18 @@ class NameResolver extends NodeVisitorAbstract
|
|||||||
/** @var array Map of format [aliasType => [aliasName => originalName]] */
|
/** @var array Map of format [aliasType => [aliasName => originalName]] */
|
||||||
protected $aliases;
|
protected $aliases;
|
||||||
|
|
||||||
|
/** @var ErrorHandler Error handler */
|
||||||
|
protected $errorHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a name resolution visitor.
|
||||||
|
*
|
||||||
|
* @param ErrorHandler|null $errorHandler Error handler
|
||||||
|
*/
|
||||||
|
public function __construct(ErrorHandler $errorHandler = null) {
|
||||||
|
$this->errorHandler = $errorHandler ?: new ErrorHandler\Throwing;
|
||||||
|
}
|
||||||
|
|
||||||
public function beforeTraverse(array $nodes) {
|
public function beforeTraverse(array $nodes) {
|
||||||
$this->resetState();
|
$this->resetState();
|
||||||
}
|
}
|
||||||
@ -132,13 +145,14 @@ class NameResolver extends NodeVisitorAbstract
|
|||||||
Stmt\Use_::TYPE_CONSTANT => 'const ',
|
Stmt\Use_::TYPE_CONSTANT => 'const ',
|
||||||
);
|
);
|
||||||
|
|
||||||
throw new Error(
|
$this->errorHandler->handleError(new Error(
|
||||||
sprintf(
|
sprintf(
|
||||||
'Cannot use %s%s as %s because the name is already in use',
|
'Cannot use %s%s as %s because the name is already in use',
|
||||||
$typeStringMap[$type], $name, $use->alias
|
$typeStringMap[$type], $name, $use->alias
|
||||||
),
|
),
|
||||||
$use->getLine()
|
$use->getAttributes()
|
||||||
);
|
));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->aliases[$type][$aliasName] = $name;
|
$this->aliases[$type][$aliasName] = $name;
|
||||||
@ -160,10 +174,10 @@ class NameResolver extends NodeVisitorAbstract
|
|||||||
// don't resolve special class names
|
// don't resolve special class names
|
||||||
if (in_array(strtolower($name->toString()), array('self', 'parent', 'static'))) {
|
if (in_array(strtolower($name->toString()), array('self', 'parent', 'static'))) {
|
||||||
if (!$name->isUnqualified()) {
|
if (!$name->isUnqualified()) {
|
||||||
throw new Error(
|
$this->errorHandler->handleError(new Error(
|
||||||
sprintf("'\\%s' is an invalid class name", $name->toString()),
|
sprintf("'\\%s' is an invalid class name", $name->toString()),
|
||||||
$name->getLine()
|
$name->getAttributes()
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $name;
|
return $name;
|
||||||
@ -181,12 +195,8 @@ class NameResolver extends NodeVisitorAbstract
|
|||||||
return FullyQualified::concat($alias, $name->slice(1), $name->getAttributes());
|
return FullyQualified::concat($alias, $name->slice(1), $name->getAttributes());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $this->namespace) {
|
// if no alias exists prepend current namespace
|
||||||
// if no alias exists prepend current namespace
|
return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
|
||||||
return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
|
|
||||||
}
|
|
||||||
|
|
||||||
return new FullyQualified($name->parts, $name->getAttributes());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function resolveOtherName(Name $name, $type) {
|
protected function resolveOtherName(Name $name, $type) {
|
||||||
@ -208,28 +218,28 @@ class NameResolver extends NodeVisitorAbstract
|
|||||||
$aliasName = $name->getFirst();
|
$aliasName = $name->getFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($this->aliases[$type][$aliasName])) {
|
if (isset($this->aliases[$type][$aliasName])) {
|
||||||
// unqualified, unaliased names cannot be resolved at compile-time
|
// resolve unqualified aliases
|
||||||
return $name;
|
return new FullyQualified($this->aliases[$type][$aliasName], $name->getAttributes());
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve unqualified aliases
|
if (null === $this->namespace) {
|
||||||
return new FullyQualified($this->aliases[$type][$aliasName], $name->getAttributes());
|
// outside of a namespace unaliased unqualified is same as fully qualified
|
||||||
|
return new FullyQualified($name, $name->getAttributes());
|
||||||
|
}
|
||||||
|
|
||||||
|
// unqualified names inside a namespace cannot be resolved at compile-time
|
||||||
|
// add the namespaced version of the name as an attribute
|
||||||
|
$name->setAttribute('namespacedName',
|
||||||
|
FullyQualified::concat($this->namespace, $name, $name->getAttributes()));
|
||||||
|
return $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $this->namespace) {
|
// if no alias exists prepend current namespace
|
||||||
// if no alias exists prepend current namespace
|
return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
|
||||||
return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
|
|
||||||
}
|
|
||||||
|
|
||||||
return new FullyQualified($name->parts, $name->getAttributes());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function addNamespacedName(Node $node) {
|
protected function addNamespacedName(Node $node) {
|
||||||
if (null !== $this->namespace) {
|
$node->namespacedName = Name::concat($this->namespace, $node->name);
|
||||||
$node->namespacedName = Name::concat($this->namespace, $node->name);
|
|
||||||
} else {
|
|
||||||
$node->namespacedName = new Name($node->name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,18 +7,11 @@ interface Parser {
|
|||||||
* Parses PHP code into a node tree.
|
* Parses PHP code into a node tree.
|
||||||
*
|
*
|
||||||
* @param string $code The source code to parse
|
* @param string $code The source code to parse
|
||||||
|
* @param ErrorHandler|null $errorHandler Error handler to use for lexer/parser errors, defaults
|
||||||
|
* to ErrorHandler\Throwing.
|
||||||
*
|
*
|
||||||
* @return Node[]|null Array of statements (or null if the 'throwOnError' option is disabled and the parser was
|
* @return Node[]|null Array of statements (or null if the 'throwOnError' option is disabled and the parser was
|
||||||
* unable to recover from an error).
|
* unable to recover from an error).
|
||||||
*/
|
*/
|
||||||
public function parse($code);
|
public function parse($code, ErrorHandler $errorHandler = null);
|
||||||
|
|
||||||
/**
|
|
||||||
* Get array of errors that occurred during the last parse.
|
|
||||||
*
|
|
||||||
* This method may only return multiple errors if the 'throwOnError' option is disabled.
|
|
||||||
*
|
|
||||||
* @return Error[]
|
|
||||||
*/
|
|
||||||
public function getErrors();
|
|
||||||
}
|
}
|
||||||
|
@ -3,61 +3,52 @@
|
|||||||
namespace PhpParser\Parser;
|
namespace PhpParser\Parser;
|
||||||
|
|
||||||
use PhpParser\Error;
|
use PhpParser\Error;
|
||||||
|
use PhpParser\ErrorHandler;
|
||||||
use PhpParser\Parser;
|
use PhpParser\Parser;
|
||||||
|
|
||||||
class Multiple implements Parser {
|
class Multiple implements Parser {
|
||||||
/** @var Parser[] List of parsers to try, in order of preference */
|
/** @var Parser[] List of parsers to try, in order of preference */
|
||||||
private $parsers;
|
private $parsers;
|
||||||
/** @var Error[] Errors collected during last parse */
|
|
||||||
private $errors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a parser which will try multiple parsers in an order of preference.
|
* Create a parser which will try multiple parsers in an order of preference.
|
||||||
*
|
*
|
||||||
* Parsers will be invoked in the order they're provided to the constructor. If one of the
|
* Parsers will be invoked in the order they're provided to the constructor. If one of the
|
||||||
* parsers runs without errors, it's output is returned. Otherwise the errors (and
|
* parsers runs without throwing, it's output is returned. Otherwise the exception that the
|
||||||
* PhpParser\Error exception) of the first parser are used.
|
* first parser generated is thrown.
|
||||||
*
|
*
|
||||||
* @param Parser[] $parsers
|
* @param Parser[] $parsers
|
||||||
*/
|
*/
|
||||||
public function __construct(array $parsers) {
|
public function __construct(array $parsers) {
|
||||||
$this->parsers = $parsers;
|
$this->parsers = $parsers;
|
||||||
$this->errors = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function parse($code) {
|
public function parse($code, ErrorHandler $errorHandler = null) {
|
||||||
list($firstStmts, $firstErrors, $firstError) = $this->tryParse($this->parsers[0], $code);
|
if (null === $errorHandler) {
|
||||||
if ($firstErrors === []) {
|
$errorHandler = new ErrorHandler\Throwing;
|
||||||
$this->errors = [];
|
}
|
||||||
|
|
||||||
|
list($firstStmts, $firstError) = $this->tryParse($this->parsers[0], $errorHandler, $code);
|
||||||
|
if ($firstError === null) {
|
||||||
return $firstStmts;
|
return $firstStmts;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ($i = 1, $c = count($this->parsers); $i < $c; ++$i) {
|
for ($i = 1, $c = count($this->parsers); $i < $c; ++$i) {
|
||||||
list($stmts, $errors) = $this->tryParse($this->parsers[$i], $code);
|
list($stmts, $error) = $this->tryParse($this->parsers[$i], $errorHandler, $code);
|
||||||
if ($errors === []) {
|
if ($error === null) {
|
||||||
$this->errors = [];
|
|
||||||
return $stmts;
|
return $stmts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->errors = $firstErrors;
|
throw $firstError;
|
||||||
if ($firstError) {
|
|
||||||
throw $firstError;
|
|
||||||
}
|
|
||||||
return $firstStmts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getErrors() {
|
private function tryParse(Parser $parser, ErrorHandler $errorHandler, $code) {
|
||||||
return $this->errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function tryParse(Parser $parser, $code) {
|
|
||||||
$stmts = null;
|
$stmts = null;
|
||||||
$error = null;
|
$error = null;
|
||||||
try {
|
try {
|
||||||
$stmts = $parser->parse($code);
|
$stmts = $parser->parse($code, $errorHandler);
|
||||||
} catch (Error $error) {}
|
} catch (Error $error) {}
|
||||||
$errors = $parser->getErrors();
|
return [$stmts, $error];
|
||||||
return [$stmts, $errors, $error];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
{
|
{
|
||||||
protected $tokenToSymbolMapSize = 392;
|
protected $tokenToSymbolMapSize = 392;
|
||||||
protected $actionTableSize = 1012;
|
protected $actionTableSize = 1012;
|
||||||
protected $gotoTableSize = 650;
|
protected $gotoTableSize = 652;
|
||||||
|
|
||||||
protected $invalidSymbol = 157;
|
protected $invalidSymbol = 157;
|
||||||
protected $errorSymbol = 1;
|
protected $errorSymbol = 1;
|
||||||
@ -235,104 +235,104 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
protected $action = array(
|
protected $action = array(
|
||||||
672, 673, 674, 675, 676,-32766, 677, 678, 679, 715,
|
672, 673, 674, 675, 676,-32766, 677, 678, 679, 715,
|
||||||
716, 216, 217, 218, 219, 220, 221, 222, 223, 224,
|
716, 216, 217, 218, 219, 220, 221, 222, 223, 224,
|
||||||
282, 225, 226, 227, 228, 229, 230, 231, 232, 233,
|
23, 225, 226, 227, 228, 229, 230, 231, 232, 233,
|
||||||
234, 235, 236,-32766,-32766,-32766,-32766,-32766,-32766,-32766,
|
234, 235, 236,-32766,-32766,-32766,-32766,-32766,-32766,-32766,
|
||||||
-32766,-32767,-32767,-32767,-32767, 440, 237, 238,-32766,-32766,
|
-32766,-32767,-32767,-32767,-32767, 460, 237, 238,-32766,-32766,
|
||||||
-32766,-32766, 680,-32766, 0,-32766,-32766,-32766,-32766,-32766,
|
-32766,-32766, 680,-32766, 0,-32766,-32766,-32766,-32766,-32766,
|
||||||
-32766,-32767,-32767,-32767,-32767,-32767, 681, 682, 683, 684,
|
-32766,-32767,-32767,-32767,-32767,-32767, 681, 682, 683, 684,
|
||||||
685, 686, 687, 1172, 204, 747,-32766,-32766,-32766,-32766,
|
685, 686, 687, 909, 204, 747,-32766,-32766,-32766,-32766,
|
||||||
-32766, 419, 688, 689, 690, 691, 692, 693, 694, 695,
|
-32766, 419, 688, 689, 690, 691, 692, 693, 694, 695,
|
||||||
696, 697, 698, 718, 719, 720, 721, 722, 710, 711,
|
696, 697, 698, 718, 719, 720, 721, 722, 710, 711,
|
||||||
712, 713, 714, 699, 700, 701, 702, 703, 704, 705,
|
712, 713, 714, 699, 700, 701, 702, 703, 704, 705,
|
||||||
741, 742, 743, 744, 745, 746, 706, 707, 708, 709,
|
741, 742, 743, 744, 745, 746, 706, 707, 708, 709,
|
||||||
739, 730, 728, 729, 725, 726, 306, 717, 723, 724,
|
739, 730, 728, 729, 725, 726, 306, 717, 723, 724,
|
||||||
731, 732, 734, 733, 735, 736, 52, 53, 420, 54,
|
731, 732, 734, 733, 735, 736, 52, 53, 420, 54,
|
||||||
55, 727, 738, 737, 447, 56, 57, 339, 58,-32766,
|
55, 727, 738, 737, 282, 56, 57, 284, 58,-32766,
|
||||||
-32766,-32766,-32766,-32766,-32766,-32766,-32766,-32766, 7,-32767,
|
-32766,-32766,-32766,-32766,-32766,-32766,-32766,-32766, 7,-32767,
|
||||||
-32767,-32767,-32767, 50, 329, 1186, 585, 945, 946, 947,
|
-32767,-32767,-32767, 50, 329, 900, 585, 945, 946, 947,
|
||||||
944, 943, 942, 937, 1212, 27, 1214, 1213, 763, 764,
|
944, 943, 942, 937, 1213, 27, 1215, 1214, 763, 764,
|
||||||
821, 59, 60,-32766,-32766,-32766, 762, 61, 1172, 62,
|
821, 59, 60,-32766,-32766,-32766, 918, 61, 1172, 62,
|
||||||
291, 292, 63, 64, 65, 66, 67, 68, 69, 70,
|
291, 292, 63, 64, 65, 66, 67, 68, 69, 70,
|
||||||
441, 24, 299, 71, 413,-32766,-32766,-32766, 1185, 1087,
|
356, 24, 299, 71, 413,-32766,-32766,-32766, 1185, 1087,
|
||||||
1088, 749, 633, 1178, 213, 214, 215, 464,-32766,-32766,
|
1088, 749, 633, 1178, 213, 214, 215, 464,-32766,-32766,
|
||||||
-32766, 822, 407, 1099, 309,-32766, 1054,-32766,-32766,-32766,
|
-32766, 822, 407, 1099, 311,-32766, 1054,-32766,-32766,-32766,
|
||||||
-32766,-32766,-32766, 1036, 200, -269, 428, 1036,-32766, 23,
|
-32766,-32766,-32766, 1036, 200, -269, 428, 1036,-32766, 447,
|
||||||
-32766,-32766,-32766,-32766,-32766, 120, 491, 945, 946, 947,
|
-32766,-32766,-32766,-32766,-32766, 120, 491, 945, 946, 947,
|
||||||
944, 943, 942, 297, 473, 474, 283, 623, 125,-32766,
|
944, 943, 942, 297, 473, 474, 283, 623, 125,-32766,
|
||||||
893, 894, 339, 477, 478,-32766, 1093, 1094, 1095, 1096,
|
893, 894, 339, 477, 478,-32766, 1093, 1094, 1095, 1096,
|
||||||
1090, 1091, 307, 492,-32766, 8, 425, 492, 1097, 1092,
|
1090, 1091, 307, 492,-32766, 8, 425, 492, 1097, 1092,
|
||||||
425, 121, -220, 869, 1182, 39, 280, 332, 321, 18,
|
425, 121, -220, 869, 1182, 39, 280, 332, 321, 1186,
|
||||||
322, 421, -122, -122, -122, -4, 822, 463, 99, 100,
|
322, 421, -122, -122, -122, -4, 822, 463, 99, 100,
|
||||||
101, 811, 301, 377, 38, 19, 422, -122, 465, -122,
|
101, 811, 301, 377, 38, 19, 422, -122, 465, -122,
|
||||||
466, -122, 467, -122, 102, 423, -122, -122, -122, 28,
|
466, -122, 467, -122, 102, 423, -122, -122, -122, 28,
|
||||||
29, 468, 424, 624, 30, 469, 425, 812, 72, 412,
|
29, 468, 424, 624, 30, 469, 425, 812, 72, 412,
|
||||||
923, 349, 350, 470, 471,-32766,-32766,-32766, 298, 472,
|
923, 349, 350, 470, 471,-32766,-32766,-32766, 298, 472,
|
||||||
1036, 809, 793, 840, 475, 476,-32767,-32767,-32767,-32767,
|
1036, 808, 793, 840, 475, 476,-32767,-32767,-32767,-32767,
|
||||||
94, 95, 96, 97, 98,-32766, 126,-32766,-32766,-32766,
|
94, 95, 96, 97, 98,-32766, 126,-32766,-32766,-32766,
|
||||||
-32766, 1137, 213, 214, 215, 295, 421, 239, 824, 638,
|
-32766, 1137, 213, 214, 215, 295, 421, 239, 824, 638,
|
||||||
-122, 1036, 463, 893, 894, 367, 811, 1036, 1204, 38,
|
-122, 1036, 463, 893, 894, 1205, 811, 1036, 1204, 38,
|
||||||
19, 422, 200, 465, 900, 466, 492, 467, 127, 425,
|
19, 422, 200, 465, 18, 466, 492, 467, 127, 425,
|
||||||
423, 213, 214, 215, 28, 29, 468, 424, 414, 30,
|
423, 213, 214, 215, 28, 29, 468, 424, 414, 30,
|
||||||
469, 1036, 870, 72, 320, 822, 349, 350, 470, 471,
|
469, 1036, 870, 72, 320, 822, 349, 350, 470, 471,
|
||||||
1036, 200, 214, 215, 472, 356, 919, 755, 840, 475,
|
1036, 200, 214, 215, 472, 441, 919, 755, 840, 475,
|
||||||
476, 213, 214, 215, 295, -216, 76, 77, 78, 47,
|
476, 213, 214, 215, 295, -216, 76, 77, 78, 47,
|
||||||
338, 200, 477, 644, 348, 438, 31, 294, 331, 460,
|
338, 200, 477, 644, 348, 438, 31, 294, 331, 440,
|
||||||
326, 200, 241, 824, 638, -4, 32, 334, 79, 80,
|
326, 200, 241, 824, 638, -4, 32, 335, 79, 80,
|
||||||
81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
|
81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
|
||||||
91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
|
91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
|
||||||
101, 1209, 301, 119, 822, 421, 801, 124,-32766,-32766,
|
101, 1210, 301, 34, 822, 421, 801, 124,-32766,-32766,
|
||||||
-32766, 463, 899, 129, 102, 811, 1178, 576, 38, 19,
|
-32766, 463, 899, 129, 102, 811, 1178, 576, 38, 19,
|
||||||
422, 545, 465, 909, 466, 34, 467, 46,-32766, 423,
|
422, 546, 465, 1172, 466, 119, 467, 49,-32766, 423,
|
||||||
-32766,-32766, 647, 28, 29, 468, 822, 803, 30, 469,
|
-32766,-32766, 647, 28, 29, 468, 822, 803, 30, 469,
|
||||||
415, 117, 72, 805, 49, 349, 350,-32766,-32766,-32766,
|
415, 117, 72, 805, 46, 349, 350,-32766,-32766,-32766,
|
||||||
-32766,-32766,-32766, 472, 200, 1036, 234, 235, 236,-32766,
|
-32766,-32766,-32766, 472, 200, 1036, 234, 235, 236,-32766,
|
||||||
-32766,-32766,-32766,-32766, 641, 1138, 124,-32766,-32766,-32766,
|
-32766,-32766,-32766,-32766, 641, 1138, 124,-32766,-32766,-32766,
|
||||||
-32766,-32766, 237, 238, 421, 96, 97, 98, 293,-32766,
|
-32766,-32766, 237, 238, 421, 231, 232, 233, 293,-32766,
|
||||||
463, 518, 856, 638, 811, 439, 808, 38, 19, 422,
|
463, 518, 856, 638, 811, 439, 809, 38, 19, 422,
|
||||||
332, 465, 650, 466, 749, 467, 1178, 284, 423, 231,
|
332, 465, 128, 466, 749, 467, 1178, 339, 423, 96,
|
||||||
232, 233, 28, 29, 468, 822, 421, 30, 469, 116,
|
97, 98, 28, 29, 468, 822, 421, 30, 469, 118,
|
||||||
918, 72, 463, 215, 349, 350, 811, 242, 1036, 38,
|
762, 72, 463, 215, 349, 350, 811, 242, 1036, 38,
|
||||||
19, 422, 472, 465, 207, 466, 118, 467, 1036, 1064,
|
19, 422, 472, 465, 206, 466, 116, 467, 1036, 1064,
|
||||||
423, 200, 833, 642, 28, 29, 468, 822, 1099, 30,
|
423, 200, 833, 642, 28, 29, 468, 822, 1099, 30,
|
||||||
469, 296, 115, 72, 205, 123, 349, 350,-32766,-32766,
|
469, 296, 207, 72, 205, 123, 349, 350,-32766,-32766,
|
||||||
492, 824, 638, 425, 472, 206, 213, 214, 215, 434,
|
492, 824, 638, 425, 472, 115, 213, 214, 215, 434,
|
||||||
492, 244, 640, 425, 243, 653, 237, 238, 429,-32766,
|
492, 244, 640, 425, 243, 653, 237, 238, 429,-32766,
|
||||||
332, 454, 591, 449, 20, 421, 200, 130, 357, 763,
|
332, 454, 591, 449, 20, 421, 200, 130, 357, 763,
|
||||||
764, 463, 646, 824, 638, 811, 922, 666, 38, 19,
|
764, 463, 820, 824, 638, 811, 922, 666, 38, 19,
|
||||||
422, 820, 465, 311, 466, 128, 467, 599, 600, 423,
|
422, 646, 465, 650, 466, 313, 467, 599, 600, 423,
|
||||||
102, 756, 643, 28, 29, 468, 822, 421, 30, 469,
|
102, 756, 643, 28, 29, 468, 822, 421, 30, 469,
|
||||||
934, 656, 72, 463, 301, 349, 350, 811, 44, 51,
|
934, 656, 72, 463, 301, 349, 350, 811, 41, 51,
|
||||||
38, 19, 422, 472, 465, 48, 466, 299, 467, 605,
|
38, 19, 422, 472, 465, 48, 466, 299, 467, 605,
|
||||||
43, 423, 41, 513, 45, 28, 29, 468, 42, 524,
|
42, 423, 43, 517, 44, 28, 29, 468, 45,-32766,
|
||||||
30, 469, 596,-32766, 72, 749, 534, 349, 350, 512,
|
30, 469, 596, 524, 72, 435, 433, 349, 350, 533,
|
||||||
435, 433, 824, 638, 1207, 472, 750, 33, 103, 104,
|
534, 749, 824, 638, 1208, 472, 776, 33, 103, 104,
|
||||||
105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
|
105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
|
||||||
776, 533, 517, 437, 632, 622, 421, 612, 1057, 602,
|
750, 513, 512, 437, 632, 602, 421, 1057, 622, 612,
|
||||||
516, 619, 463, 279, 824, 638, 811, 595, 582, 38,
|
516, 619, 463, 279, 824, 638, 811, 582, 595, 38,
|
||||||
19, 422, 330, 465, 579, 466, 240, 467, 975, 977,
|
19, 422, 330, 465, 579, 466, 240, 467, 975, 977,
|
||||||
423, 609, 327, 12, 28, 29, 468, 537, -80, 30,
|
423, 609, 334, 537, 28, 29, 468, 12, -80, 30,
|
||||||
469, 842, 432, 72, 208, 209, 349, 350, 458, 1144,
|
469, 842, 432, 72, 208, 209, 349, 350, 458, 1144,
|
||||||
210, 384, 211, 333, 472, 841, 9, 393, -398, 409,
|
210, 384, 211, 327, 472, 841, 9, 393, -398, 409,
|
||||||
328, 0, 310, 1045, 202, 477, 0, 0, 0, 208,
|
328, 0, 310, 1045, 202, 477, 0, 0, 0, 208,
|
||||||
209, 0, 1087, 1088, 0, 210,-32766, 211, -497, -498,
|
209, 0, 1087, 1088, 0, 210,-32766, 211, -497, 312,
|
||||||
1089, 308, 0, 824, 638, 0, 1098, 4, 372, 202,
|
1089, -498, 0, 824, 638, 0, 1098, 4, 372, 202,
|
||||||
3, 11, 303, 0, -407, 0, 370, 1087, 1088, -406,
|
3, 11, 303, 0, -407, 0, 370, 1087, 1088, -406,
|
||||||
-497,-32766, 434, 864, 526, 1089, 408, 385, 75, 835,
|
-497,-32766, 434, 864, 526, 1089, 408, 385, 75, 835,
|
||||||
0, 857, 863, 854, 813, 798, 819, 807, 761, 661,
|
0, 857, 863, 854, 813, 798, 819, 807, 761, 661,
|
||||||
0, 660, 37, 36, 759, 926, 810, 565, 852, 1093,
|
0, 660, 37, 36, 759, 926, 810, 565, 852, 1093,
|
||||||
1094, 1095, 1096, 1090, 1091, 383, 929, 930, 806, 760,
|
1094, 1095, 1096, 1090, 1091, 383, 929, 806, 930, 818,
|
||||||
818, 1097, 1092, 928, 804, 302, 802, 927, 212, 796,
|
760, 1097, 1092, 928, 804, 302, 802, 927, 212, 796,
|
||||||
-32766, 872, 565, 639, 1093, 1094, 1095, 1096, 1090, 1091,
|
-32766, 872, 565, 639, 1093, 1094, 1095, 1096, 1090, 1091,
|
||||||
383, 649, 651, 652, 654, 655, 1097, 1092, 658, 663,
|
383, 649, 651, 652, 654, 655, 1097, 1092, 658, 663,
|
||||||
664, 1034, 665, 212, 122,-32766, 324, 325, 405, 406,
|
664, 1034, 665, 212, 122,-32766, 324, 325, 405, 406,
|
||||||
-416, 1210, 757, 758, 839, 838, 766, 453, 1208, 1179,
|
-416, 1211, 757, 758, 839, 838, 766, 453, 1209, 1179,
|
||||||
1177, 1163, 1175, 1078, 911, 1183, 1173, 829, 836, 1038,
|
1177, 1163, 1175, 1078, 911, 1183, 1173, 829, 836, 1038,
|
||||||
1039, 827, 935, 1211, 765, 837, 794, 662, 1050, 861,
|
1039, 827, 935, 1212, 765, 837, 794, 662, 1050, 861,
|
||||||
768, 767, 862, 0, 304, 290, 289, 25, 26, 281,
|
768, 767, 862, 0, 304, 290, 289, 25, 26, 281,
|
||||||
305, 335, 203, 74, 411, 417, 35, 73,-32766, 40,
|
305, 336, 203, 74, 411, 417, 35, 73,-32766, 40,
|
||||||
22, 0, 1015, 569, -217, 1016, 1103, 1080, 901, 1040,
|
22, 0, 1015, 569, -217, 1016, 1103, 1080, 901, 1040,
|
||||||
1044, 1041, 629, 559, 461, 457, 455, 450, 378, 16,
|
1044, 1041, 629, 559, 461, 457, 455, 450, 378, 16,
|
||||||
15, 14, -216, 0, 0, 0, 603, 1157, 1104, 1206,
|
15, 14, -216, 0, 0, 0, 603, 1157, 1104, 1207,
|
||||||
1077, 1174, 1158, 1162, 1176, 1063, 1048, 1049, 1046, 1047,
|
1077, 1174, 1158, 1162, 1176, 1063, 1048, 1049, 1046, 1047,
|
||||||
0, 1143
|
0, 1143
|
||||||
);
|
);
|
||||||
@ -456,8 +456,8 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
398, 398, 398, 398, 398, 398, 398, 398, 398, 398,
|
398, 398, 398, 398, 398, 398, 398, 398, 398, 398,
|
||||||
398, 398, 398, 398, 398, 398, 398, 398, 398, 398,
|
398, 398, 398, 398, 398, 398, 398, 398, 398, 398,
|
||||||
398, 398, 398, 398, 398, 398, 398, 398, 398, 398,
|
398, 398, 398, 398, 398, 398, 398, 398, 398, 398,
|
||||||
398, 254, 179, 460, 482, 738, 736, 730, 732, 827,
|
398, 254, 179, 482, 460, 738, 736, 729, 731, 827,
|
||||||
659, 823, 778, 779, 636, 780, 781, 782, 783, 784,
|
659, 823, 778, 779, 533, 780, 781, 782, 783, 784,
|
||||||
777, 785, 841, 786, 418, 418, 418, 418, 418, 418,
|
777, 785, 841, 786, 418, 418, 418, 418, 418, 418,
|
||||||
418, 418, 418, 418, 418, -3, 354, 383, 413, 206,
|
418, 418, 418, 418, 418, -3, 354, 383, 413, 206,
|
||||||
524, 618, 618, 618, 618, 618, 618, 618, 175, 175,
|
524, 618, 618, 618, 618, 618, 618, 618, 175, 175,
|
||||||
@ -471,42 +471,42 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
327, 587, 210, 489, 197, 25, 25, 25, 25, 25,
|
327, 587, 210, 489, 197, 25, 25, 25, 25, 25,
|
||||||
17, 45, 5, 5, 5, 5, 712, 305, 305, 305,
|
17, 45, 5, 5, 5, 5, 712, 305, 305, 305,
|
||||||
305, 118, 118, 118, 118, 774, 775, 795, 798, 303,
|
305, 118, 118, 118, 118, 774, 775, 795, 798, 303,
|
||||||
303, 676, 676, 629, 765, 498, 498, 522, 522, 487,
|
303, 676, 676, 629, 765, 522, 522, 498, 498, 487,
|
||||||
487, 487, 487, 487, 487, 487, 487, 487, 487, 387,
|
487, 487, 487, 487, 487, 487, 487, 487, 487, 387,
|
||||||
156, 817, 130, 130, 130, 130, 243, 469, 207, 207,
|
156, 817, 130, 130, 130, 130, 243, 469, 650, 855,
|
||||||
207, 243, 650, 855, 248, 248, 248, 476, 476, 476,
|
207, 207, 207, 243, 248, 248, 248, 476, 476, 476,
|
||||||
76, 627, 296, 296, 547, 547, 547, 477, 477, 477,
|
76, 631, 296, 296, 547, 547, 547, 477, 477, 477,
|
||||||
477, 483, 699, 477, 477, 477, 362, 631, 97, 334,
|
477, 483, 699, 627, 477, 477, 477, 362, 97, 334,
|
||||||
662, 799, 661, 802, 508, 692, 96, 700, 653, 414,
|
661, 799, 662, 802, 508, 692, 96, 700, 653, -6,
|
||||||
680, 571, 569, 561, 656, 406, 414, 254, 532, 447,
|
680, 571, 569, 561, 656, 406, -6, 254, 532, 430,
|
||||||
630, 718, 639, 38, 716, 408, 193, 363, 523, 430,
|
630, 718, 643, 432, 716, 193, 408, 363, 523, 447,
|
||||||
-6, 137, 767, 731, 821, 820, 13, 321, 691, 630,
|
414, 232, 767, 732, 821, 820, 137, 321, 693, 630,
|
||||||
630, 630, 232, 84, 768, 769, 430, 273, 570, 570,
|
630, 630, 13, 84, 768, 769, 447, 273, 570, 570,
|
||||||
570, 570, 801, 770, 570, 570, 570, 570, 800, 794,
|
570, 570, 801, 770, 570, 570, 570, 570, 800, 794,
|
||||||
268, 432, 776, 74, 717, 638, 638, 638, 638, 638,
|
268, 38, 776, 74, 717, 644, 644, 644, 644, 644,
|
||||||
638, 567, 638, 807, 626, 819, 819, 664, 670, 567,
|
644, 567, 644, 807, 664, 819, 819, 642, 666, 567,
|
||||||
818, 818, 818, 818, 567, 638, 819, 819, 567, 629,
|
818, 818, 818, 818, 567, 644, 819, 819, 567, 629,
|
||||||
819, 168, 567, 646, 638, 667, 667, 818, 713, 711,
|
819, 168, 567, 667, 644, 646, 646, 818, 713, 711,
|
||||||
626, 671, 673, 819, 819, 819, 673, 664, 567, 818,
|
664, 671, 673, 819, 819, 819, 673, 642, 567, 818,
|
||||||
603, 702, 67, 819, 818, 634, 634, 603, 567, 634,
|
603, 702, 67, 819, 818, 636, 636, 603, 567, 636,
|
||||||
670, 634, 54, 632, 635, 815, 816, 814, 642, 744,
|
666, 636, 54, 623, 621, 815, 816, 814, 665, 744,
|
||||||
672, 658, 805, 804, 812, 665, 644, 808, 806, 698,
|
672, 658, 805, 804, 812, 626, 639, 808, 806, 698,
|
||||||
710, 709, 643, 597, 641, 633, 621, 637, 688, 628,
|
710, 709, 638, 610, 633, 635, 637, 641, 688, 628,
|
||||||
693, 680, 696, 604, 604, 604, 690, 685, 690, 604,
|
674, 680, 696, 604, 604, 604, 690, 685, 690, 604,
|
||||||
604, 604, 604, 604, 604, 604, 604, 648, 694, 697,
|
604, 604, 604, 604, 604, 604, 604, 648, 694, 697,
|
||||||
674, 657, 708, 599, 682, 683, 610, 759, 687, 698,
|
691, 657, 708, 599, 682, 679, 579, 759, 687, 698,
|
||||||
698, 796, 829, 836, 766, 757, 649, 734, 831, 690,
|
698, 796, 829, 836, 766, 757, 663, 734, 831, 690,
|
||||||
854, 715, 274, 579, 681, 797, 645, 663, 701, 690,
|
854, 715, 274, 597, 681, 797, 645, 649, 701, 690,
|
||||||
803, 690, 760, 690, 828, 647, 793, 698, 773, 604,
|
803, 690, 760, 690, 828, 793, 647, 698, 773, 604,
|
||||||
826, 853, 852, 851, 850, 849, 848, 847, 846, 622,
|
826, 853, 852, 851, 850, 849, 848, 847, 846, 622,
|
||||||
845, 707, 677, 835, 119, 811, 656, 654, 651, 706,
|
845, 707, 677, 835, 119, 811, 656, 654, 651, 706,
|
||||||
440, 844, 772, 690, 690, 761, 699, 690, 763, 743,
|
440, 844, 772, 690, 690, 761, 699, 690, 763, 743,
|
||||||
714, 839, 704, 834, 843, 687, 833, 690, 686, 842,
|
714, 839, 704, 834, 843, 687, 833, 690, 686, 842,
|
||||||
440, 623, 625, 822, 678, 695, 813, 668, 824, 810,
|
440, 632, 625, 822, 678, 695, 813, 670, 824, 810,
|
||||||
752, 572, 619, 771, 533, 741, 838, 837, 840, 703,
|
752, 572, 619, 771, 634, 741, 838, 837, 840, 703,
|
||||||
753, 754, 616, 660, 669, 666, 787, 755, 809, 705,
|
753, 754, 616, 660, 668, 669, 787, 755, 809, 705,
|
||||||
788, 789, 830, 684, 696, 689, 652, 679, 655, 756,
|
788, 789, 830, 684, 696, 689, 652, 683, 655, 756,
|
||||||
790, 832, 720, 728, 729, 791, 739, 792, 0, 0,
|
790, 832, 720, 728, 730, 791, 739, 792, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 134, 134,
|
0, 0, 0, 0, 0, 0, 0, 0, 134, 134,
|
||||||
@ -539,17 +539,17 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
-20, -20, -20, 0, 248, 248, 248, 248, -20, -20,
|
-20, -20, -20, 0, 248, 248, 248, 248, -20, -20,
|
||||||
-20, -20, 55, 55, 55, 55, 487, 487, 487, 487,
|
-20, -20, 55, 55, 55, 55, 487, 487, 487, 487,
|
||||||
487, 487, 248, 248, 476, 476, 0, 0, 0, 0,
|
487, 487, 248, 248, 476, 476, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 487, 55, 487, 638,
|
0, 0, 0, 0, 0, 0, 487, 55, 487, 644,
|
||||||
638, 638, 638, 638, 296, 407, 407, 407, 638, 296,
|
644, 644, 644, 644, 296, 296, 296, 407, 407, 407,
|
||||||
296, 0, 0, 0, 0, 0, 0, 638, 296, 0,
|
644, 0, 0, 0, 0, 0, 0, 644, 296, 0,
|
||||||
0, 638, 638, 638, 638, 638, 638, 638, 638, 407,
|
0, 644, 644, 644, 644, 644, 644, 644, 644, 407,
|
||||||
638, 638, 638, 819, 296, 0, 407, 550, 550, 550,
|
296, 644, 644, 644, 819, 0, 407, 550, 550, 550,
|
||||||
550, 440, 430, 0, 638, 638, 0, 671, 0, 0,
|
550, 440, 447, 0, 644, 644, 0, 671, 0, 0,
|
||||||
0, 819, 0, 0, 0, 0, 0, 604, 274, 734,
|
0, 819, 0, 0, 0, 0, 0, 604, 274, 734,
|
||||||
0, 427, 0, 0, 0, 0, 0, 0, 0, 649,
|
0, 427, 0, 0, 0, 0, 0, 0, 0, 663,
|
||||||
427, 246, 246, 0, 0, 622, 604, 604, 604, 0,
|
427, 246, 246, 0, 0, 622, 604, 604, 604, 0,
|
||||||
0, 649, 649, 0, 0, 0, 0, 0, 0, 433,
|
0, 663, 663, 0, 0, 0, 0, 0, 0, 433,
|
||||||
649, 0, 0, 0, 0, 433, 322, 0, 0, 322,
|
663, 0, 0, 0, 0, 433, 322, 0, 0, 322,
|
||||||
0, 440
|
0, 440
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -587,10 +587,10 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
272,32767, 228, 228, 228, 228, 228,32767,32767,32767,
|
272,32767, 228, 228, 228, 228, 228,32767,32767,32767,
|
||||||
32767,32767,32767,32767, 321, 322, 320, 448, 449, 447,
|
32767,32767,32767,32767, 321, 322, 320, 448, 449, 447,
|
||||||
32767, 415,32767, 417,32767,32767,32767,32767,32767,32767,
|
32767, 415,32767, 417,32767,32767,32767,32767,32767,32767,
|
||||||
32767,32767,32767,32767,32767,32767, 486,32767,32767,32767,
|
32767,32767,32767,32767,32767,32767,32767, 486,32767,32767,
|
||||||
32767,32767,32767,32767,32767, 499, 404,32767,32767,32767,
|
32767,32767,32767,32767,32767, 499, 404,32767,32767,32767,
|
||||||
397, 212, 214, 161, 472,32767,32767,32767,32767, 504,
|
397, 212, 214, 161, 472,32767,32767,32767,32767, 504,
|
||||||
331,32767,32767,32767,32767,32767,32767, 538,32767, 499,
|
331,32767,32767,32767,32767,32767,32767, 539,32767, 499,
|
||||||
32767,32767,32767,32767,32767,32767,32767,32767, 344, 323,
|
32767,32767,32767,32767,32767,32767,32767,32767, 344, 323,
|
||||||
324, 325,32767,32767,32767,32767, 503, 497, 456, 457,
|
324, 325,32767,32767,32767,32767, 503, 497, 456, 457,
|
||||||
458, 459,32767,32767, 450, 451, 452, 455,32767,32767,
|
458, 459,32767,32767, 450, 451, 452, 455,32767,32767,
|
||||||
@ -608,7 +608,7 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
405,32767,32767,32767, 84, 108, 247,32767, 537, 84,
|
405,32767,32767,32767, 84, 108, 247,32767, 537, 84,
|
||||||
400,32767,32767, 294, 537,32767,32767,32767,32767, 532,
|
400,32767,32767, 294, 537,32767,32767,32767,32767, 532,
|
||||||
32767,32767, 288,32767,32767,32767, 84,32767, 84, 243,
|
32767,32767, 288,32767,32767,32767, 84,32767, 84, 243,
|
||||||
32767, 163,32767, 522,32767,32767, 497, 401,32767, 328,
|
32767, 163,32767, 522,32767, 497,32767, 401,32767, 328,
|
||||||
32767,32767,32767,32767,32767,32767,32767,32767,32767, 498,
|
32767,32767,32767,32767,32767,32767,32767,32767,32767, 498,
|
||||||
32767,32767,32767,32767, 219,32767, 435,32767, 84,32767,
|
32767,32767,32767,32767, 219,32767, 435,32767, 84,32767,
|
||||||
179,32767,32767, 292, 238,32767,32767, 531,32767,32767,
|
179,32767,32767, 292, 238,32767,32767, 531,32767,32767,
|
||||||
@ -635,50 +635,49 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
549, 182, 183, 184, 185, 186, 187, 188, 189, 190,
|
549, 182, 183, 184, 185, 186, 187, 188, 189, 190,
|
||||||
191, 192, 193, 194, 145, 146, 147, 161, 148, 163,
|
191, 192, 193, 194, 145, 146, 147, 161, 148, 163,
|
||||||
149, 197, 164, 150, 151, 152, 198, 153, 131, 625,
|
149, 197, 164, 150, 151, 152, 198, 153, 131, 625,
|
||||||
567, 784, 567, 567, 567, 567, 567, 567, 567, 567,
|
567, 753, 567, 567, 567, 567, 567, 567, 567, 567,
|
||||||
567, 567, 567, 567, 567, 567, 567, 567, 567, 567,
|
567, 567, 567, 567, 567, 567, 567, 567, 567, 567,
|
||||||
567, 567, 567, 567, 567, 567, 567, 567, 567, 567,
|
567, 567, 567, 567, 567, 567, 567, 567, 567, 567,
|
||||||
567, 567, 567, 567, 567, 567, 567, 567, 567, 567,
|
567, 567, 567, 567, 567, 567, 567, 567, 567, 567,
|
||||||
567, 567, 567, 567, 567, 1100, 753, 1100, 1100, 1100,
|
567, 567, 567, 567, 567, 1100, 754, 1100, 1100, 1100,
|
||||||
1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100,
|
1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100,
|
||||||
1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100,
|
1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100,
|
||||||
1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100,
|
1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100,
|
||||||
1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100,
|
1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100,
|
||||||
885, 885, 1190, 1190, 1169, 611, 1169, 168, 617, 509,
|
885, 885, 1190, 1190, 6, 611, 784, 168, 617, 509,
|
||||||
358, 509, 171, 172, 173, 388, 389, 390, 391, 167,
|
358, 509, 171, 172, 173, 388, 389, 390, 391, 167,
|
||||||
195, 199, 201, 249, 251, 253, 260, 261, 262, 263,
|
195, 199, 201, 249, 251, 253, 260, 261, 262, 263,
|
||||||
264, 265, 271, 272, 273, 274, 287, 288, 317, 318,
|
264, 265, 271, 272, 273, 274, 287, 288, 317, 318,
|
||||||
319, 394, 395, 396, 397, 169, 174, 246, 247, 175,
|
319, 394, 395, 396, 397, 169, 174, 246, 247, 175,
|
||||||
176, 177, 497, 497, 497, 497, 497, 497, 6, 523,
|
176, 177, 497, 497, 497, 497, 497, 497, 341, 580,
|
||||||
580, 606, 497, 497, 497, 497, 497, 497, 497, 497,
|
606, 523, 497, 497, 497, 497, 497, 497, 497, 497,
|
||||||
497, 497, 508, 754, 508, 387, 608, 543, 543, 573,
|
497, 497, 508, 634, 508, 387, 608, 543, 543, 573,
|
||||||
539, 1076, 1075, 790, 752, 541, 541, 496, 498, 529,
|
539, 1076, 1075, 790, 752, 541, 541, 496, 498, 529,
|
||||||
546, 574, 577, 587, 593, 871, 510, 851, 510, 657,
|
545, 574, 577, 587, 593, 871, 1169, 851, 1169, 657,
|
||||||
634, 511, 880, 875, 566, 341, 566, 566, 566, 566,
|
815, 511, 880, 875, 566, 855, 566, 566, 566, 566,
|
||||||
566, 566, 566, 566, 566, 566, 566, 566, 566, 566,
|
566, 566, 566, 566, 566, 566, 566, 566, 566, 566,
|
||||||
566, 566, 566, 566, 566, 566, 566, 566, 566, 566,
|
566, 566, 566, 566, 566, 566, 566, 566, 566, 566,
|
||||||
566, 566, 566, 566, 566, 566, 566, 566, 566, 566,
|
566, 566, 566, 566, 566, 566, 566, 566, 566, 566,
|
||||||
566, 566, 566, 566, 566, 566, 566, 566, 566, 551,
|
566, 566, 566, 566, 566, 566, 566, 566, 566, 551,
|
||||||
552, 553, 554, 555, 556, 557, 558, 560, 589, 815,
|
552, 553, 554, 555, 556, 557, 558, 560, 589, 550,
|
||||||
548, 550, 514, 572, 855, 522, 519, 519, 519, 443,
|
323, 309, 514, 522, 1201, 1201, 519, 519, 519, 583,
|
||||||
445, 933, 636, 519, 1161, 1101, 618, 931, 522, 522,
|
586, 631, 510, 519, 510, 1161, 522, 522, 903, 1201,
|
||||||
1201, 1201, 903, 430, 430, 430, 430, 430, 430, 538,
|
590, 344, 404, 430, 430, 430, 430, 430, 430, 538,
|
||||||
519, 1201, 1058, 430, 430, 430, 430, 430, 430, 430,
|
519, 544, 1058, 430, 430, 430, 430, 430, 430, 430,
|
||||||
430, 430, 430, 1065, 544, 1065, 892, 892, 892, 892,
|
430, 430, 430, 1065, 1194, 1065, 892, 892, 892, 892,
|
||||||
892, 535, 1194, 659, 562, 892, 594, 868, 882, 613,
|
892, 361, 598, 535, 777, 659, 562, 892, 594, 868,
|
||||||
867, 616, 878, 620, 621, 628, 630, 635, 637, 777,
|
882, 613, 867, 616, 878, 620, 621, 628, 630, 635,
|
||||||
361, 849, 849, 849, 849, 598, 1081, 844, 850, 615,
|
637, 849, 849, 849, 849, 1149, 1081, 607, 844, 850,
|
||||||
583, 586, 631, 1019, 17, 13, 355, 519, 519, 536,
|
615, 777, 777, 1019, 17, 13, 355, 519, 519, 536,
|
||||||
568, 519, 519, 1149, 519, 607, 777, 777, 1187, 375,
|
568, 519, 519, 1187, 519, 443, 445, 933, 636, 375,
|
||||||
561, 369, 369, 369, 1061, 1062, 1009, 520, 1058, 1168,
|
561, 1101, 618, 931, 1061, 1062, 889, 520, 1058, 276,
|
||||||
889, 1168, 21, 1200, 1200, 347, 547, 604, 1184, 1184,
|
277, 278, 21, 1200, 1200, 548, 547, 604, 572, 342,
|
||||||
1184, 1059, 1160, 1059, 1200, 369, 362, 590, 344, 404,
|
343, 1059, 1160, 1059, 1168, 362, 1168, 1009, 1200, 527,
|
||||||
527, 1060, 386, 898, 540, 276, 277, 278, 1203, 323,
|
898, 1060, 941, 540, 347, 1184, 1184, 1184, 1203, 770,
|
||||||
313, 907, 1167, 960, 398, 368, 773, 373, 645, 1051,
|
770, 778, 778, 778, 780, 960, 769, 398, 373, 451,
|
||||||
451, 771, 402, 1056, 770, 770, 778, 778, 778, 780,
|
369, 369, 369, 773, 368, 771, 645, 1167, 907, 10,
|
||||||
10, 769, 446, 781, 578, 912, 342, 343, 859, 1146,
|
402, 1051, 1056, 446, 781, 578, 912, 859, 1146, 459,
|
||||||
459, 949, 0, 0, 0, 0, 0, 0, 0, 0,
|
949, 0, 369, 0, 0, 0, 0, 0, 0, 386,
|
||||||
0, 0, 0, 0, 0, 0, 941, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
@ -688,7 +687,9 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 528
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 528
|
||||||
);
|
);
|
||||||
|
|
||||||
protected $gotoCheck = array(
|
protected $gotoCheck = array(
|
||||||
@ -703,50 +704,49 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
|
39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
|
||||||
39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
|
39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
|
||||||
39, 39, 39, 39, 39, 39, 39, 39, 39, 53,
|
39, 39, 39, 39, 39, 39, 39, 39, 39, 53,
|
||||||
112, 25, 112, 112, 112, 112, 112, 112, 112, 112,
|
112, 11, 112, 112, 112, 112, 112, 112, 112, 112,
|
||||||
112, 112, 112, 112, 112, 112, 112, 112, 112, 112,
|
112, 112, 112, 112, 112, 112, 112, 112, 112, 112,
|
||||||
112, 112, 112, 112, 112, 112, 112, 112, 112, 112,
|
112, 112, 112, 112, 112, 112, 112, 112, 112, 112,
|
||||||
112, 112, 112, 112, 112, 112, 112, 112, 112, 112,
|
112, 112, 112, 112, 112, 112, 112, 112, 112, 112,
|
||||||
112, 112, 112, 112, 112, 119, 11, 119, 119, 119,
|
112, 112, 112, 112, 112, 119, 12, 119, 119, 119,
|
||||||
119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
|
119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
|
||||||
119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
|
119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
|
||||||
119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
|
119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
|
||||||
119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
|
119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
|
||||||
70, 70, 70, 70, 110, 57, 110, 23, 57, 112,
|
70, 70, 70, 70, 90, 57, 25, 23, 57, 112,
|
||||||
57, 112, 23, 23, 23, 23, 23, 23, 23, 23,
|
57, 112, 23, 23, 23, 23, 23, 23, 23, 23,
|
||||||
23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
|
23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
|
||||||
23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
|
23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
|
||||||
23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
|
23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
|
||||||
23, 23, 109, 109, 109, 109, 109, 109, 90, 93,
|
23, 23, 109, 109, 109, 109, 109, 109, 65, 36,
|
||||||
36, 36, 109, 109, 109, 109, 109, 109, 109, 109,
|
36, 93, 109, 109, 109, 109, 109, 109, 109, 109,
|
||||||
109, 109, 109, 12, 109, 47, 47, 47, 47, 47,
|
109, 109, 109, 5, 109, 47, 47, 47, 47, 47,
|
||||||
47, 117, 117, 10, 10, 47, 47, 47, 47, 47,
|
47, 117, 117, 10, 10, 47, 47, 47, 47, 47,
|
||||||
47, 47, 47, 47, 47, 10, 115, 10, 115, 10,
|
47, 47, 47, 47, 47, 10, 110, 10, 110, 10,
|
||||||
5, 10, 10, 10, 53, 65, 53, 53, 53, 53,
|
46, 10, 10, 10, 53, 29, 53, 53, 53, 53,
|
||||||
53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
|
53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
|
||||||
53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
|
53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
|
||||||
53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
|
53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
|
||||||
53, 53, 53, 53, 53, 53, 53, 53, 53, 102,
|
53, 53, 53, 53, 53, 53, 53, 53, 53, 102,
|
||||||
102, 102, 102, 102, 102, 102, 102, 102, 102, 46,
|
102, 102, 102, 102, 102, 102, 102, 102, 102, 40,
|
||||||
2, 40, 8, 2, 29, 40, 8, 8, 8, 7,
|
118, 118, 8, 40, 134, 134, 8, 8, 8, 56,
|
||||||
7, 7, 7, 8, 75, 7, 7, 7, 40, 40,
|
56, 56, 115, 8, 115, 75, 40, 40, 77, 134,
|
||||||
134, 134, 77, 53, 53, 53, 53, 53, 53, 8,
|
63, 63, 63, 53, 53, 53, 53, 53, 53, 8,
|
||||||
8, 134, 75, 53, 53, 53, 53, 53, 53, 53,
|
8, 101, 75, 53, 53, 53, 53, 53, 53, 53,
|
||||||
53, 53, 53, 53, 101, 53, 53, 53, 53, 53,
|
53, 53, 53, 53, 132, 53, 53, 53, 53, 53,
|
||||||
53, 28, 132, 28, 28, 53, 28, 28, 28, 28,
|
53, 43, 120, 28, 19, 28, 28, 53, 28, 28,
|
||||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 19,
|
28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||||
43, 53, 53, 53, 53, 120, 30, 53, 53, 53,
|
28, 53, 53, 53, 53, 124, 30, 45, 53, 53,
|
||||||
56, 56, 56, 30, 30, 30, 30, 8, 8, 8,
|
53, 19, 19, 30, 30, 30, 30, 8, 8, 8,
|
||||||
8, 8, 8, 124, 8, 45, 19, 19, 130, 44,
|
8, 8, 8, 130, 8, 7, 7, 7, 7, 44,
|
||||||
30, 116, 116, 116, 75, 75, 94, 8, 75, 111,
|
30, 7, 7, 7, 75, 75, 72, 8, 75, 61,
|
||||||
72, 111, 30, 133, 133, 14, 8, 30, 111, 111,
|
61, 61, 30, 133, 133, 2, 8, 30, 2, 65,
|
||||||
111, 75, 75, 75, 133, 116, 54, 63, 63, 63,
|
65, 75, 75, 75, 111, 54, 111, 94, 133, 54,
|
||||||
54, 75, 116, 74, 54, 61, 61, 61, 133, 118,
|
74, 75, 90, 54, 14, 111, 111, 111, 133, 19,
|
||||||
118, 78, 111, 93, 18, 9, 21, 13, 67, 105,
|
19, 19, 19, 19, 19, 93, 19, 18, 13, 54,
|
||||||
54, 20, 17, 107, 19, 19, 19, 19, 19, 19,
|
116, 116, 116, 21, 9, 20, 67, 111, 78, 54,
|
||||||
54, 19, 59, 22, 60, 79, 65, 65, 64, 123,
|
17, 105, 107, 59, 22, 60, 79, 64, 123, 100,
|
||||||
100, 92, -1, -1, -1, -1, -1, -1, -1, -1,
|
92, -1, 116, -1, -1, -1, -1, -1, -1, 116,
|
||||||
-1, -1, -1, -1, -1, -1, 90, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
@ -756,24 +756,26 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, 93
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, 93
|
||||||
);
|
);
|
||||||
|
|
||||||
protected $gotoBase = array(
|
protected $gotoBase = array(
|
||||||
0, 0, -280, 0, 0, 288, 0, 366, 42, 174,
|
0, 0, -165, 0, 0, 261, 0, 452, 42, 183,
|
||||||
282, 154, 271, 160, 155, 0, 0, 106, 179, 109,
|
282, 109, 154, 161, 174, 0, 0, 114, 182, 94,
|
||||||
163, 180, 83, 7, 0, 103, 0, 0, -228, 346,
|
167, 187, 84, 7, 0, 198, 0, 0, -226, 287,
|
||||||
23, 0, 0, 0, 0, 0, 224, 0, 0, -22,
|
23, 0, 0, 0, 0, 0, 223, 0, 0, -22,
|
||||||
339, 0, 0, 392, 169, 175, 343, -4, 0, 0,
|
337, 0, 0, 373, 169, 157, 284, -4, 0, 0,
|
||||||
0, 0, 0, 104, 62, 0, 137, -251, 0, 86,
|
0, 0, 0, 104, 61, 0, 66, -251, 0, 87,
|
||||||
78, -168, 0, 159, 81, -134, 0, 151, 0, 0,
|
79, -194, 0, 52, 80, -181, 0, 159, 0, 0,
|
||||||
-79, 0, 164, 0, 182, 38, 0, 359, 145, 84,
|
-79, 0, 160, 0, 177, 38, 0, 355, 162, 85,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
246, 0, 71, 220, 165, 0, 0, 0, 0, 0,
|
192, 0, 70, 222, 186, 0, 0, 0, 0, 0,
|
||||||
73, 379, 307, 0, 0, 93, 0, 94, 0, -27,
|
72, 366, 307, 0, 0, 105, 0, 103, 0, -27,
|
||||||
-95, 170, -90, 0, 0, -3, 153, -28, 178, -45,
|
-3, 185, -90, 0, 0, 73, 200, -30, 39, -45,
|
||||||
232, 0, 0, 77, 249, 0, 0, 0, 0, 0,
|
209, 0, 0, 76, 231, 0, 0, 0, 0, 0,
|
||||||
176, 0, 385, 161, 68, 0
|
171, 0, 377, 165, 56, 0, 0
|
||||||
);
|
);
|
||||||
|
|
||||||
protected $gotoDefault = array(
|
protected $gotoDefault = array(
|
||||||
@ -788,9 +790,9 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
916, 418, 401, 588, 920, 921, 5, 925, 626, 627,
|
916, 418, 401, 588, 920, 921, 5, 925, 626, 627,
|
||||||
940, 300, 948, 961, 416, 1029, 1031, 484, 485, 525,
|
940, 300, 948, 961, 416, 1029, 1031, 484, 485, 525,
|
||||||
456, 507, 530, 486, 1052, 436, 403, 1055, 487, 488,
|
456, 507, 530, 486, 1052, 436, 403, 1055, 487, 488,
|
||||||
426, 427, 1073, 1070, 346, 1154, 345, 444, 312, 1141,
|
426, 427, 1073, 1070, 346, 1154, 345, 444, 308, 1141,
|
||||||
584, 1105, 452, 1193, 1150, 336, 489, 490, 359, 376,
|
584, 1105, 452, 1193, 1150, 337, 489, 490, 359, 376,
|
||||||
1188, 431, 1195, 1202, 337, 571
|
1188, 431, 1195, 1202, 333, 367, 571
|
||||||
);
|
);
|
||||||
|
|
||||||
protected $ruleToNonTerminal = array(
|
protected $ruleToNonTerminal = array(
|
||||||
@ -847,8 +849,8 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
111, 115, 115, 110, 110, 128, 128, 128, 128, 116,
|
111, 115, 115, 110, 110, 128, 128, 128, 128, 116,
|
||||||
116, 116, 116, 102, 102, 117, 117, 117, 117, 70,
|
116, 116, 116, 102, 102, 117, 117, 117, 117, 70,
|
||||||
129, 129, 130, 130, 130, 101, 101, 131, 131, 132,
|
129, 129, 130, 130, 130, 101, 101, 131, 131, 132,
|
||||||
132, 132, 132, 118, 118, 118, 118, 134, 133, 133,
|
132, 132, 132, 118, 118, 118, 118, 134, 135, 133,
|
||||||
133, 133, 133, 133, 133, 135, 135, 135
|
133, 133, 133, 133, 133, 133, 136, 136, 136
|
||||||
);
|
);
|
||||||
|
|
||||||
protected $ruleToLength = array(
|
protected $ruleToLength = array(
|
||||||
@ -905,8 +907,8 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
2, 1, 1, 4, 1, 3, 6, 4, 4, 4,
|
2, 1, 1, 4, 1, 3, 6, 4, 4, 4,
|
||||||
4, 1, 4, 0, 1, 1, 3, 1, 1, 4,
|
4, 1, 4, 0, 1, 1, 3, 1, 1, 4,
|
||||||
3, 1, 1, 1, 0, 0, 2, 3, 1, 3,
|
3, 1, 1, 1, 0, 0, 2, 3, 1, 3,
|
||||||
1, 4, 2, 2, 2, 1, 2, 1, 1, 4,
|
1, 4, 2, 2, 2, 1, 2, 1, 1, 1,
|
||||||
3, 3, 3, 6, 3, 1, 1, 1
|
4, 3, 3, 3, 6, 3, 1, 1, 1
|
||||||
);
|
);
|
||||||
|
|
||||||
protected function reduceRule0() {
|
protected function reduceRule0() {
|
||||||
@ -1267,15 +1269,15 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule89() {
|
protected function reduceRule89() {
|
||||||
$this->semValue = new Stmt\Namespace_($this->semStack[$this->stackPos-(3-2)], null, $this->startAttributeStack[$this->stackPos-(3-1)] + $this->endAttributes);
|
$this->semValue = new Stmt\Namespace_($this->semStack[$this->stackPos-(3-2)], null, $this->startAttributeStack[$this->stackPos-(3-1)] + $this->endAttributes); $this->checkNamespace($this->semValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule90() {
|
protected function reduceRule90() {
|
||||||
$this->semValue = new Stmt\Namespace_($this->semStack[$this->stackPos-(5-2)], $this->semStack[$this->stackPos-(5-4)], $this->startAttributeStack[$this->stackPos-(5-1)] + $this->endAttributes);
|
$this->semValue = new Stmt\Namespace_($this->semStack[$this->stackPos-(5-2)], $this->semStack[$this->stackPos-(5-4)], $this->startAttributeStack[$this->stackPos-(5-1)] + $this->endAttributes); $this->checkNamespace($this->semValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule91() {
|
protected function reduceRule91() {
|
||||||
$this->semValue = new Stmt\Namespace_(null, $this->semStack[$this->stackPos-(4-3)], $this->startAttributeStack[$this->stackPos-(4-1)] + $this->endAttributes);
|
$this->semValue = new Stmt\Namespace_(null, $this->semStack[$this->stackPos-(4-3)], $this->startAttributeStack[$this->stackPos-(4-1)] + $this->endAttributes); $this->checkNamespace($this->semValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule92() {
|
protected function reduceRule92() {
|
||||||
@ -1303,19 +1305,19 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule98() {
|
protected function reduceRule98() {
|
||||||
$this->semValue = new Stmt\GroupUse(new Name($this->semStack[$this->stackPos-(7-3)], $this->startAttributeStack[$this->stackPos-(7-1)] + $this->endAttributes), $this->semStack[$this->stackPos-(7-6)], $this->semStack[$this->stackPos-(7-2)], $this->startAttributeStack[$this->stackPos-(7-1)] + $this->endAttributes);
|
$this->semValue = new Stmt\GroupUse(new Name($this->semStack[$this->stackPos-(7-3)], $this->startAttributeStack[$this->stackPos-(7-3)] + $this->endAttributeStack[$this->stackPos-(7-3)]), $this->semStack[$this->stackPos-(7-6)], $this->semStack[$this->stackPos-(7-2)], $this->startAttributeStack[$this->stackPos-(7-1)] + $this->endAttributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule99() {
|
protected function reduceRule99() {
|
||||||
$this->semValue = new Stmt\GroupUse(new Name($this->semStack[$this->stackPos-(8-4)], $this->startAttributeStack[$this->stackPos-(8-1)] + $this->endAttributes), $this->semStack[$this->stackPos-(8-7)], $this->semStack[$this->stackPos-(8-2)], $this->startAttributeStack[$this->stackPos-(8-1)] + $this->endAttributes);
|
$this->semValue = new Stmt\GroupUse(new Name($this->semStack[$this->stackPos-(8-4)], $this->startAttributeStack[$this->stackPos-(8-4)] + $this->endAttributeStack[$this->stackPos-(8-4)]), $this->semStack[$this->stackPos-(8-7)], $this->semStack[$this->stackPos-(8-2)], $this->startAttributeStack[$this->stackPos-(8-1)] + $this->endAttributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule100() {
|
protected function reduceRule100() {
|
||||||
$this->semValue = new Stmt\GroupUse(new Name($this->semStack[$this->stackPos-(6-2)], $this->startAttributeStack[$this->stackPos-(6-1)] + $this->endAttributes), $this->semStack[$this->stackPos-(6-5)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$this->stackPos-(6-1)] + $this->endAttributes);
|
$this->semValue = new Stmt\GroupUse(new Name($this->semStack[$this->stackPos-(6-2)], $this->startAttributeStack[$this->stackPos-(6-2)] + $this->endAttributeStack[$this->stackPos-(6-2)]), $this->semStack[$this->stackPos-(6-5)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$this->stackPos-(6-1)] + $this->endAttributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule101() {
|
protected function reduceRule101() {
|
||||||
$this->semValue = new Stmt\GroupUse(new Name($this->semStack[$this->stackPos-(7-3)], $this->startAttributeStack[$this->stackPos-(7-1)] + $this->endAttributes), $this->semStack[$this->stackPos-(7-6)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$this->stackPos-(7-1)] + $this->endAttributes);
|
$this->semValue = new Stmt\GroupUse(new Name($this->semStack[$this->stackPos-(7-3)], $this->startAttributeStack[$this->stackPos-(7-3)] + $this->endAttributeStack[$this->stackPos-(7-3)]), $this->semStack[$this->stackPos-(7-6)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$this->stackPos-(7-1)] + $this->endAttributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule102() {
|
protected function reduceRule102() {
|
||||||
@ -1343,11 +1345,11 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule108() {
|
protected function reduceRule108() {
|
||||||
$this->semValue = new Stmt\UseUse($this->semStack[$this->stackPos-(1-1)], null, Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$this->stackPos-(1-1)] + $this->endAttributes);
|
$this->semValue = new Stmt\UseUse($this->semStack[$this->stackPos-(1-1)], null, Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$this->stackPos-(1-1)] + $this->endAttributes); $this->checkUseUse($this->semValue, $this->stackPos-(1-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule109() {
|
protected function reduceRule109() {
|
||||||
$this->semValue = new Stmt\UseUse($this->semStack[$this->stackPos-(3-1)], $this->semStack[$this->stackPos-(3-3)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$this->stackPos-(3-1)] + $this->endAttributes);
|
$this->semValue = new Stmt\UseUse($this->semStack[$this->stackPos-(3-1)], $this->semStack[$this->stackPos-(3-3)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$this->stackPos-(3-1)] + $this->endAttributes); $this->checkUseUse($this->semValue, $this->stackPos-(3-3));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule110() {
|
protected function reduceRule110() {
|
||||||
@ -1512,7 +1514,7 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule150() {
|
protected function reduceRule150() {
|
||||||
$this->semValue = new Stmt\TryCatch($this->semStack[$this->stackPos-(6-3)], $this->semStack[$this->stackPos-(6-5)], $this->semStack[$this->stackPos-(6-6)], $this->startAttributeStack[$this->stackPos-(6-1)] + $this->endAttributes);
|
$this->semValue = new Stmt\TryCatch($this->semStack[$this->stackPos-(6-3)], $this->semStack[$this->stackPos-(6-5)], $this->semStack[$this->stackPos-(6-6)], $this->startAttributeStack[$this->stackPos-(6-1)] + $this->endAttributes); $this->checkTryCatch($this->semValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule151() {
|
protected function reduceRule151() {
|
||||||
@ -1594,10 +1596,12 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
|
|
||||||
protected function reduceRule170() {
|
protected function reduceRule170() {
|
||||||
$this->semValue = new Stmt\Class_($this->semStack[$this->stackPos-(7-2)], ['type' => $this->semStack[$this->stackPos-(7-1)], 'extends' => $this->semStack[$this->stackPos-(7-3)], 'implements' => $this->semStack[$this->stackPos-(7-4)], 'stmts' => $this->semStack[$this->stackPos-(7-6)]], $this->startAttributeStack[$this->stackPos-(7-1)] + $this->endAttributes);
|
$this->semValue = new Stmt\Class_($this->semStack[$this->stackPos-(7-2)], ['type' => $this->semStack[$this->stackPos-(7-1)], 'extends' => $this->semStack[$this->stackPos-(7-3)], 'implements' => $this->semStack[$this->stackPos-(7-4)], 'stmts' => $this->semStack[$this->stackPos-(7-6)]], $this->startAttributeStack[$this->stackPos-(7-1)] + $this->endAttributes);
|
||||||
|
$this->checkClass($this->semValue, $this->stackPos-(7-2));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule171() {
|
protected function reduceRule171() {
|
||||||
$this->semValue = new Stmt\Interface_($this->semStack[$this->stackPos-(6-2)], ['extends' => $this->semStack[$this->stackPos-(6-3)], 'stmts' => $this->semStack[$this->stackPos-(6-5)]], $this->startAttributeStack[$this->stackPos-(6-1)] + $this->endAttributes);
|
$this->semValue = new Stmt\Interface_($this->semStack[$this->stackPos-(6-2)], ['extends' => $this->semStack[$this->stackPos-(6-3)], 'stmts' => $this->semStack[$this->stackPos-(6-5)]], $this->startAttributeStack[$this->stackPos-(6-1)] + $this->endAttributes);
|
||||||
|
$this->checkInterface($this->semValue, $this->stackPos-(6-2));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule172() {
|
protected function reduceRule172() {
|
||||||
@ -1805,11 +1809,11 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule223() {
|
protected function reduceRule223() {
|
||||||
$this->semValue = new Node\Param(substr($this->semStack[$this->stackPos-(4-4)], 1), null, $this->semStack[$this->stackPos-(4-1)], $this->semStack[$this->stackPos-(4-2)], $this->semStack[$this->stackPos-(4-3)], $this->startAttributeStack[$this->stackPos-(4-1)] + $this->endAttributes);
|
$this->semValue = new Node\Param(substr($this->semStack[$this->stackPos-(4-4)], 1), null, $this->semStack[$this->stackPos-(4-1)], $this->semStack[$this->stackPos-(4-2)], $this->semStack[$this->stackPos-(4-3)], $this->startAttributeStack[$this->stackPos-(4-1)] + $this->endAttributes); $this->checkParam($this->semValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule224() {
|
protected function reduceRule224() {
|
||||||
$this->semValue = new Node\Param(substr($this->semStack[$this->stackPos-(6-4)], 1), $this->semStack[$this->stackPos-(6-6)], $this->semStack[$this->stackPos-(6-1)], $this->semStack[$this->stackPos-(6-2)], $this->semStack[$this->stackPos-(6-3)], $this->startAttributeStack[$this->stackPos-(6-1)] + $this->endAttributes);
|
$this->semValue = new Node\Param(substr($this->semStack[$this->stackPos-(6-4)], 1), $this->semStack[$this->stackPos-(6-6)], $this->semStack[$this->stackPos-(6-1)], $this->semStack[$this->stackPos-(6-2)], $this->semStack[$this->stackPos-(6-3)], $this->startAttributeStack[$this->stackPos-(6-1)] + $this->endAttributes); $this->checkParam($this->semValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule225() {
|
protected function reduceRule225() {
|
||||||
@ -1917,7 +1921,7 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule251() {
|
protected function reduceRule251() {
|
||||||
$this->semValue = new Stmt\Property($this->semStack[$this->stackPos-(3-1)], $this->semStack[$this->stackPos-(3-2)], $this->startAttributeStack[$this->stackPos-(3-1)] + $this->endAttributes);
|
$this->semValue = new Stmt\Property($this->semStack[$this->stackPos-(3-1)], $this->semStack[$this->stackPos-(3-2)], $this->startAttributeStack[$this->stackPos-(3-1)] + $this->endAttributes); $this->checkProperty($this->semValue, $this->stackPos-(3-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule252() {
|
protected function reduceRule252() {
|
||||||
@ -1926,6 +1930,7 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
|
|
||||||
protected function reduceRule253() {
|
protected function reduceRule253() {
|
||||||
$this->semValue = new Stmt\ClassMethod($this->semStack[$this->stackPos-(9-4)], ['type' => $this->semStack[$this->stackPos-(9-1)], 'byRef' => $this->semStack[$this->stackPos-(9-3)], 'params' => $this->semStack[$this->stackPos-(9-6)], 'returnType' => $this->semStack[$this->stackPos-(9-8)], 'stmts' => $this->semStack[$this->stackPos-(9-9)]], $this->startAttributeStack[$this->stackPos-(9-1)] + $this->endAttributes);
|
$this->semValue = new Stmt\ClassMethod($this->semStack[$this->stackPos-(9-4)], ['type' => $this->semStack[$this->stackPos-(9-1)], 'byRef' => $this->semStack[$this->stackPos-(9-3)], 'params' => $this->semStack[$this->stackPos-(9-6)], 'returnType' => $this->semStack[$this->stackPos-(9-8)], 'stmts' => $this->semStack[$this->stackPos-(9-9)]], $this->startAttributeStack[$this->stackPos-(9-1)] + $this->endAttributes);
|
||||||
|
$this->checkClassMethod($this->semValue, $this->stackPos-(9-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule254() {
|
protected function reduceRule254() {
|
||||||
@ -2009,7 +2014,7 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule274() {
|
protected function reduceRule274() {
|
||||||
Stmt\Class_::verifyModifier($this->semStack[$this->stackPos-(2-1)], $this->semStack[$this->stackPos-(2-2)]); $this->semValue = $this->semStack[$this->stackPos-(2-1)] | $this->semStack[$this->stackPos-(2-2)];
|
$this->checkModifier($this->semStack[$this->stackPos-(2-1)], $this->semStack[$this->stackPos-(2-2)], $this->stackPos-(2-2)); $this->semValue = $this->semStack[$this->stackPos-(2-1)] | $this->semStack[$this->stackPos-(2-2)];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule275() {
|
protected function reduceRule275() {
|
||||||
@ -2451,6 +2456,7 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
|
|
||||||
protected function reduceRule383() {
|
protected function reduceRule383() {
|
||||||
$this->semValue = array(new Stmt\Class_(null, ['type' => 0, 'extends' => $this->semStack[$this->stackPos-(7-3)], 'implements' => $this->semStack[$this->stackPos-(7-4)], 'stmts' => $this->semStack[$this->stackPos-(7-6)]], $this->startAttributeStack[$this->stackPos-(7-1)] + $this->endAttributes), $this->semStack[$this->stackPos-(7-2)]);
|
$this->semValue = array(new Stmt\Class_(null, ['type' => 0, 'extends' => $this->semStack[$this->stackPos-(7-3)], 'implements' => $this->semStack[$this->stackPos-(7-4)], 'stmts' => $this->semStack[$this->stackPos-(7-6)]], $this->startAttributeStack[$this->stackPos-(7-1)] + $this->endAttributes), $this->semStack[$this->stackPos-(7-2)]);
|
||||||
|
$this->checkClass($this->semValue[0], -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule384() {
|
protected function reduceRule384() {
|
||||||
@ -2612,7 +2618,7 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule420() {
|
protected function reduceRule420() {
|
||||||
$this->semValue = Scalar\LNumber::fromString($this->semStack[$this->stackPos-(1-1)], $this->startAttributeStack[$this->stackPos-(1-1)] + $this->endAttributes, true);
|
$this->semValue = $this->parseLNumber($this->semStack[$this->stackPos-(1-1)], $this->startAttributeStack[$this->stackPos-(1-1)] + $this->endAttributes, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule421() {
|
protected function reduceRule421() {
|
||||||
@ -3093,15 +3099,15 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule539() {
|
protected function reduceRule539() {
|
||||||
$this->semValue = new Expr\ArrayDimFetch(new Expr\Variable(substr($this->semStack[$this->stackPos-(4-1)], 1), $this->startAttributeStack[$this->stackPos-(4-1)] + $this->endAttributes), $this->semStack[$this->stackPos-(4-3)], $this->startAttributeStack[$this->stackPos-(4-1)] + $this->endAttributes);
|
$this->semValue = $this->semStack[$this->stackPos-(1-1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule540() {
|
protected function reduceRule540() {
|
||||||
$this->semValue = new Expr\PropertyFetch(new Expr\Variable(substr($this->semStack[$this->stackPos-(3-1)], 1), $this->startAttributeStack[$this->stackPos-(3-1)] + $this->endAttributes), $this->semStack[$this->stackPos-(3-3)], $this->startAttributeStack[$this->stackPos-(3-1)] + $this->endAttributes);
|
$this->semValue = new Expr\ArrayDimFetch($this->semStack[$this->stackPos-(4-1)], $this->semStack[$this->stackPos-(4-3)], $this->startAttributeStack[$this->stackPos-(4-1)] + $this->endAttributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule541() {
|
protected function reduceRule541() {
|
||||||
$this->semValue = new Expr\Variable($this->semStack[$this->stackPos-(3-2)], $this->startAttributeStack[$this->stackPos-(3-1)] + $this->endAttributes);
|
$this->semValue = new Expr\PropertyFetch($this->semStack[$this->stackPos-(3-1)], $this->semStack[$this->stackPos-(3-3)], $this->startAttributeStack[$this->stackPos-(3-1)] + $this->endAttributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule542() {
|
protected function reduceRule542() {
|
||||||
@ -3109,15 +3115,15 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule543() {
|
protected function reduceRule543() {
|
||||||
$this->semValue = new Expr\ArrayDimFetch(new Expr\Variable($this->semStack[$this->stackPos-(6-2)], $this->startAttributeStack[$this->stackPos-(6-1)] + $this->endAttributes), $this->semStack[$this->stackPos-(6-4)], $this->startAttributeStack[$this->stackPos-(6-1)] + $this->endAttributes);
|
$this->semValue = new Expr\Variable($this->semStack[$this->stackPos-(3-2)], $this->startAttributeStack[$this->stackPos-(3-1)] + $this->endAttributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule544() {
|
protected function reduceRule544() {
|
||||||
$this->semValue = $this->semStack[$this->stackPos-(3-2)];
|
$this->semValue = new Expr\ArrayDimFetch(new Expr\Variable($this->semStack[$this->stackPos-(6-2)], $this->startAttributeStack[$this->stackPos-(6-1)] + $this->endAttributes), $this->semStack[$this->stackPos-(6-4)], $this->startAttributeStack[$this->stackPos-(6-1)] + $this->endAttributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule545() {
|
protected function reduceRule545() {
|
||||||
$this->semValue = new Scalar\String_($this->semStack[$this->stackPos-(1-1)], $this->startAttributeStack[$this->stackPos-(1-1)] + $this->endAttributes);
|
$this->semValue = $this->semStack[$this->stackPos-(3-2)];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule546() {
|
protected function reduceRule546() {
|
||||||
@ -3125,6 +3131,10 @@ class Php5 extends \PhpParser\ParserAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceRule547() {
|
protected function reduceRule547() {
|
||||||
|
$this->semValue = new Scalar\String_($this->semStack[$this->stackPos-(1-1)], $this->startAttributeStack[$this->stackPos-(1-1)] + $this->endAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function reduceRule548() {
|
||||||
$this->semValue = new Expr\Variable(substr($this->semStack[$this->stackPos-(1-1)], 1), $this->startAttributeStack[$this->stackPos-(1-1)] + $this->endAttributes);
|
$this->semValue = new Expr\Variable(substr($this->semStack[$this->stackPos-(1-1)], 1), $this->startAttributeStack[$this->stackPos-(1-1)] + $this->endAttributes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -7,6 +7,16 @@ namespace PhpParser;
|
|||||||
* turn is based on work by Masato Bito.
|
* turn is based on work by Masato Bito.
|
||||||
*/
|
*/
|
||||||
use PhpParser\Node\Name;
|
use PhpParser\Node\Name;
|
||||||
|
use PhpParser\Node\Param;
|
||||||
|
use PhpParser\Node\Scalar\LNumber;
|
||||||
|
use PhpParser\Node\Stmt\Class_;
|
||||||
|
use PhpParser\Node\Stmt\ClassConst;
|
||||||
|
use PhpParser\Node\Stmt\ClassMethod;
|
||||||
|
use PhpParser\Node\Stmt\Interface_;
|
||||||
|
use PhpParser\Node\Stmt\Namespace_;
|
||||||
|
use PhpParser\Node\Stmt\Property;
|
||||||
|
use PhpParser\Node\Stmt\TryCatch;
|
||||||
|
use PhpParser\Node\Stmt\UseUse;
|
||||||
|
|
||||||
abstract class ParserAbstract implements Parser
|
abstract class ParserAbstract implements Parser
|
||||||
{
|
{
|
||||||
@ -86,13 +96,15 @@ abstract class ParserAbstract implements Parser
|
|||||||
protected $semStack;
|
protected $semStack;
|
||||||
/** @var array[] Start attribute stack */
|
/** @var array[] Start attribute stack */
|
||||||
protected $startAttributeStack;
|
protected $startAttributeStack;
|
||||||
|
/** @var array[] End attribute stack */
|
||||||
|
protected $endAttributeStack;
|
||||||
/** @var array End attributes of last *shifted* token */
|
/** @var array End attributes of last *shifted* token */
|
||||||
protected $endAttributes;
|
protected $endAttributes;
|
||||||
/** @var array Start attributes of last *read* token */
|
/** @var array Start attributes of last *read* token */
|
||||||
protected $lookaheadStartAttributes;
|
protected $lookaheadStartAttributes;
|
||||||
|
|
||||||
/** @var bool Whether to throw on first error */
|
/** @var ErrorHandler Error handler */
|
||||||
protected $throwOnError;
|
protected $errorHandler;
|
||||||
/** @var Error[] Errors collected during last parse */
|
/** @var Error[] Errors collected during last parse */
|
||||||
protected $errors;
|
protected $errors;
|
||||||
/** @var int Error state, used to avoid error floods */
|
/** @var int Error state, used to avoid error floods */
|
||||||
@ -102,38 +114,36 @@ abstract class ParserAbstract implements Parser
|
|||||||
* Creates a parser instance.
|
* Creates a parser instance.
|
||||||
*
|
*
|
||||||
* @param Lexer $lexer A lexer
|
* @param Lexer $lexer A lexer
|
||||||
* @param array $options Options array. The boolean 'throwOnError' option determines whether an exception should be
|
* @param array $options Options array. Currently no options are supported.
|
||||||
* thrown on first error, or if the parser should try to continue parsing the remaining code
|
|
||||||
* and build a partial AST.
|
|
||||||
*/
|
*/
|
||||||
public function __construct(Lexer $lexer, array $options = array()) {
|
public function __construct(Lexer $lexer, array $options = array()) {
|
||||||
$this->lexer = $lexer;
|
$this->lexer = $lexer;
|
||||||
$this->errors = array();
|
$this->errors = array();
|
||||||
$this->throwOnError = isset($options['throwOnError']) ? $options['throwOnError'] : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if (isset($options['throwOnError'])) {
|
||||||
* Get array of errors that occurred during the last parse.
|
throw new \LogicException(
|
||||||
*
|
'"throwOnError" is no longer supported, use "errorHandler" instead');
|
||||||
* This method may only return multiple errors if the 'throwOnError' option is disabled.
|
}
|
||||||
*
|
|
||||||
* @return Error[]
|
|
||||||
*/
|
|
||||||
public function getErrors() {
|
|
||||||
return $this->errors;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses PHP code into a node tree.
|
* Parses PHP code into a node tree.
|
||||||
*
|
*
|
||||||
|
* If a non-throwing error handler is used, the parser will continue parsing after an error
|
||||||
|
* occurred and attempt to build a partial AST.
|
||||||
|
*
|
||||||
* @param string $code The source code to parse
|
* @param string $code The source code to parse
|
||||||
|
* @param ErrorHandler|null $errorHandler Error handler to use for lexer/parser errors, defaults
|
||||||
|
* to ErrorHandler\Throwing.
|
||||||
*
|
*
|
||||||
* @return Node[]|null Array of statements (or null if the 'throwOnError' option is disabled and the parser was
|
* @return Node[]|null Array of statements (or null if the 'throwOnError' option is disabled and the parser was
|
||||||
* unable to recover from an error).
|
* unable to recover from an error).
|
||||||
*/
|
*/
|
||||||
public function parse($code) {
|
public function parse($code, ErrorHandler $errorHandler = null) {
|
||||||
$this->lexer->startLexing($code);
|
$this->errorHandler = $errorHandler ?: new ErrorHandler\Throwing;
|
||||||
$this->errors = array();
|
|
||||||
|
// Initialize the lexer
|
||||||
|
$this->lexer->startLexing($code, $this->errorHandler);
|
||||||
|
|
||||||
// We start off with no lookahead-token
|
// We start off with no lookahead-token
|
||||||
$symbol = self::SYMBOL_NONE;
|
$symbol = self::SYMBOL_NONE;
|
||||||
@ -145,9 +155,9 @@ abstract class ParserAbstract implements Parser
|
|||||||
$endAttributes = '*POISON';
|
$endAttributes = '*POISON';
|
||||||
$this->endAttributes = $endAttributes;
|
$this->endAttributes = $endAttributes;
|
||||||
|
|
||||||
// In order to figure out the attributes for the starting token, we have to keep
|
// Keep stack of start and end attributes
|
||||||
// them in a stack
|
|
||||||
$this->startAttributeStack = array();
|
$this->startAttributeStack = array();
|
||||||
|
$this->endAttributeStack = array($endAttributes);
|
||||||
|
|
||||||
// Start off in the initial state and keep a stack of previous states
|
// Start off in the initial state and keep a stack of previous states
|
||||||
$state = 0;
|
$state = 0;
|
||||||
@ -189,6 +199,7 @@ abstract class ParserAbstract implements Parser
|
|||||||
// This is necessary to assign some meaningful attributes to /* empty */ productions. They'll get
|
// This is necessary to assign some meaningful attributes to /* empty */ productions. They'll get
|
||||||
// the attributes of the next token, even though they don't contain it themselves.
|
// the attributes of the next token, even though they don't contain it themselves.
|
||||||
$this->startAttributeStack[$this->stackPos+1] = $startAttributes;
|
$this->startAttributeStack[$this->stackPos+1] = $startAttributes;
|
||||||
|
$this->endAttributeStack[$this->stackPos+1] = $endAttributes;
|
||||||
$this->lookaheadStartAttributes = $startAttributes;
|
$this->lookaheadStartAttributes = $startAttributes;
|
||||||
|
|
||||||
//$this->traceRead($symbol);
|
//$this->traceRead($symbol);
|
||||||
@ -215,6 +226,7 @@ abstract class ParserAbstract implements Parser
|
|||||||
$stateStack[$this->stackPos] = $state = $action;
|
$stateStack[$this->stackPos] = $state = $action;
|
||||||
$this->semStack[$this->stackPos] = $tokenValue;
|
$this->semStack[$this->stackPos] = $tokenValue;
|
||||||
$this->startAttributeStack[$this->stackPos] = $startAttributes;
|
$this->startAttributeStack[$this->stackPos] = $startAttributes;
|
||||||
|
$this->endAttributeStack[$this->stackPos] = $endAttributes;
|
||||||
$this->endAttributes = $endAttributes;
|
$this->endAttributes = $endAttributes;
|
||||||
$symbol = self::SYMBOL_NONE;
|
$symbol = self::SYMBOL_NONE;
|
||||||
|
|
||||||
@ -252,16 +264,13 @@ abstract class ParserAbstract implements Parser
|
|||||||
$e->setStartLine($startAttributes['startLine']);
|
$e->setStartLine($startAttributes['startLine']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->errors[] = $e;
|
$this->emitError($e);
|
||||||
if ($this->throwOnError) {
|
// Can't recover from this type of error
|
||||||
throw $e;
|
return null;
|
||||||
} else {
|
|
||||||
// Currently can't recover from "special" errors
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Goto - shift nonterminal */
|
/* Goto - shift nonterminal */
|
||||||
|
$lastEndAttributes = $this->endAttributeStack[$this->stackPos];
|
||||||
$this->stackPos -= $this->ruleToLength[$rule];
|
$this->stackPos -= $this->ruleToLength[$rule];
|
||||||
$nonTerminal = $this->ruleToNonTerminal[$rule];
|
$nonTerminal = $this->ruleToNonTerminal[$rule];
|
||||||
$idx = $this->gotoBase[$nonTerminal] + $stateStack[$this->stackPos];
|
$idx = $this->gotoBase[$nonTerminal] + $stateStack[$this->stackPos];
|
||||||
@ -274,16 +283,13 @@ abstract class ParserAbstract implements Parser
|
|||||||
++$this->stackPos;
|
++$this->stackPos;
|
||||||
$stateStack[$this->stackPos] = $state;
|
$stateStack[$this->stackPos] = $state;
|
||||||
$this->semStack[$this->stackPos] = $this->semValue;
|
$this->semStack[$this->stackPos] = $this->semValue;
|
||||||
|
$this->endAttributeStack[$this->stackPos] = $lastEndAttributes;
|
||||||
} else {
|
} else {
|
||||||
/* error */
|
/* error */
|
||||||
switch ($this->errorState) {
|
switch ($this->errorState) {
|
||||||
case 0:
|
case 0:
|
||||||
$msg = $this->getErrorMessage($symbol, $state);
|
$msg = $this->getErrorMessage($symbol, $state);
|
||||||
$error = new Error($msg, $startAttributes + $endAttributes);
|
$this->emitError(new Error($msg, $startAttributes + $endAttributes));
|
||||||
$this->errors[] = $error;
|
|
||||||
if ($this->throwOnError) {
|
|
||||||
throw $error;
|
|
||||||
}
|
|
||||||
// Break missing intentionally
|
// Break missing intentionally
|
||||||
case 1:
|
case 1:
|
||||||
case 2:
|
case 2:
|
||||||
@ -306,7 +312,9 @@ abstract class ParserAbstract implements Parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
//$this->traceShift($this->errorSymbol);
|
//$this->traceShift($this->errorSymbol);
|
||||||
$stateStack[++$this->stackPos] = $state = $action;
|
++$this->stackPos;
|
||||||
|
$stateStack[$this->stackPos] = $state = $action;
|
||||||
|
$this->endAttributes = $this->endAttributeStack[$this->stackPos];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
@ -333,6 +341,10 @@ abstract class ParserAbstract implements Parser
|
|||||||
throw new \RuntimeException('Reached end of parser loop');
|
throw new \RuntimeException('Reached end of parser loop');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function emitError(Error $error) {
|
||||||
|
$this->errorHandler->handleError($error);
|
||||||
|
}
|
||||||
|
|
||||||
protected function getErrorMessage($symbol, $state) {
|
protected function getErrorMessage($symbol, $state) {
|
||||||
$expectedString = '';
|
$expectedString = '';
|
||||||
if ($expected = $this->getExpectedTokens($state)) {
|
if ($expected = $this->getExpectedTokens($state)) {
|
||||||
@ -355,6 +367,7 @@ abstract class ParserAbstract implements Parser
|
|||||||
) {
|
) {
|
||||||
if ($this->action[$idx] != $this->unexpectedTokenRule
|
if ($this->action[$idx] != $this->unexpectedTokenRule
|
||||||
&& $this->action[$idx] != $this->defaultAction
|
&& $this->action[$idx] != $this->defaultAction
|
||||||
|
&& $symbol != $this->errorSymbol
|
||||||
) {
|
) {
|
||||||
if (count($expected) == 4) {
|
if (count($expected) == 4) {
|
||||||
/* Too many expected tokens */
|
/* Too many expected tokens */
|
||||||
@ -415,6 +428,7 @@ abstract class ParserAbstract implements Parser
|
|||||||
* @return Node[]
|
* @return Node[]
|
||||||
*/
|
*/
|
||||||
protected function handleNamespaces(array $stmts) {
|
protected function handleNamespaces(array $stmts) {
|
||||||
|
$hasErrored = false;
|
||||||
$style = $this->getNamespacingStyle($stmts);
|
$style = $this->getNamespacingStyle($stmts);
|
||||||
if (null === $style) {
|
if (null === $style) {
|
||||||
// not namespaced, nothing to do
|
// not namespaced, nothing to do
|
||||||
@ -425,8 +439,11 @@ abstract class ParserAbstract implements Parser
|
|||||||
foreach ($stmts as $stmt) {
|
foreach ($stmts as $stmt) {
|
||||||
if ($stmt instanceof Node\Stmt\Namespace_) {
|
if ($stmt instanceof Node\Stmt\Namespace_) {
|
||||||
$afterFirstNamespace = true;
|
$afterFirstNamespace = true;
|
||||||
} elseif (!$stmt instanceof Node\Stmt\HaltCompiler && $afterFirstNamespace) {
|
} elseif (!$stmt instanceof Node\Stmt\HaltCompiler
|
||||||
throw new Error('No code may exist outside of namespace {}', $stmt->getLine());
|
&& $afterFirstNamespace && !$hasErrored) {
|
||||||
|
$this->emitError(new Error(
|
||||||
|
'No code may exist outside of namespace {}', $stmt->getAttributes()));
|
||||||
|
$hasErrored = true; // Avoid one error for every statement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $stmts;
|
return $stmts;
|
||||||
@ -436,9 +453,15 @@ abstract class ParserAbstract implements Parser
|
|||||||
$targetStmts =& $resultStmts;
|
$targetStmts =& $resultStmts;
|
||||||
foreach ($stmts as $stmt) {
|
foreach ($stmts as $stmt) {
|
||||||
if ($stmt instanceof Node\Stmt\Namespace_) {
|
if ($stmt instanceof Node\Stmt\Namespace_) {
|
||||||
$stmt->stmts = array();
|
if ($stmt->stmts === null) {
|
||||||
$targetStmts =& $stmt->stmts;
|
$stmt->stmts = array();
|
||||||
$resultStmts[] = $stmt;
|
$targetStmts =& $stmt->stmts;
|
||||||
|
$resultStmts[] = $stmt;
|
||||||
|
} else {
|
||||||
|
// This handles the invalid case of mixed style namespaces
|
||||||
|
$resultStmts[] = $stmt;
|
||||||
|
$targetStmts =& $resultStmts;
|
||||||
|
}
|
||||||
} elseif ($stmt instanceof Node\Stmt\HaltCompiler) {
|
} elseif ($stmt instanceof Node\Stmt\HaltCompiler) {
|
||||||
// __halt_compiler() is not moved into the namespace
|
// __halt_compiler() is not moved into the namespace
|
||||||
$resultStmts[] = $stmt;
|
$resultStmts[] = $stmt;
|
||||||
@ -459,10 +482,18 @@ abstract class ParserAbstract implements Parser
|
|||||||
if (null === $style) {
|
if (null === $style) {
|
||||||
$style = $currentStyle;
|
$style = $currentStyle;
|
||||||
if ($hasNotAllowedStmts) {
|
if ($hasNotAllowedStmts) {
|
||||||
throw new Error('Namespace declaration statement has to be the very first statement in the script', $stmt->getLine());
|
$this->emitError(new Error(
|
||||||
|
'Namespace declaration statement has to be the very first statement in the script',
|
||||||
|
$stmt->getLine() // Avoid marking the entire namespace as an error
|
||||||
|
));
|
||||||
}
|
}
|
||||||
} elseif ($style !== $currentStyle) {
|
} elseif ($style !== $currentStyle) {
|
||||||
throw new Error('Cannot mix bracketed namespace declarations with unbracketed namespace declarations', $stmt->getLine());
|
$this->emitError(new Error(
|
||||||
|
'Cannot mix bracketed namespace declarations with unbracketed namespace declarations',
|
||||||
|
$stmt->getLine() // Avoid marking the entire namespace as an error
|
||||||
|
));
|
||||||
|
// Treat like semicolon style for namespace normalization
|
||||||
|
return 'semicolon';
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -502,4 +533,177 @@ abstract class ParserAbstract implements Parser
|
|||||||
$lowerName = strtolower($name->toString());
|
$lowerName = strtolower($name->toString());
|
||||||
return isset($scalarTypes[$lowerName]) ? $lowerName : $name;
|
return isset($scalarTypes[$lowerName]) ? $lowerName : $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static $specialNames = array(
|
||||||
|
'self' => true,
|
||||||
|
'parent' => true,
|
||||||
|
'static' => true,
|
||||||
|
);
|
||||||
|
|
||||||
|
protected function getAttributesAt($pos) {
|
||||||
|
return $this->startAttributeStack[$pos] + $this->endAttributeStack[$pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function parseLNumber($str, $attributes, $allowInvalidOctal = false) {
|
||||||
|
try {
|
||||||
|
return LNumber::fromString($str, $attributes, $allowInvalidOctal);
|
||||||
|
} catch (Error $error) {
|
||||||
|
$this->emitError($error);
|
||||||
|
// Use dummy value
|
||||||
|
return new LNumber(0, $attributes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function checkModifier($a, $b, $modifierPos) {
|
||||||
|
// Jumping through some hoops here because verifyModifier() is also used elsewhere
|
||||||
|
try {
|
||||||
|
Class_::verifyModifier($a, $b);
|
||||||
|
} catch (Error $error) {
|
||||||
|
$error->setAttributes($this->getAttributesAt($modifierPos));
|
||||||
|
$this->emitError($error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function checkParam(Param $node) {
|
||||||
|
if ($node->variadic && null !== $node->default) {
|
||||||
|
$this->emitError(new Error(
|
||||||
|
'Variadic parameter cannot have a default value',
|
||||||
|
$node->default->getAttributes()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function checkTryCatch(TryCatch $node) {
|
||||||
|
if (empty($node->catches) && null === $node->finally) {
|
||||||
|
$this->emitError(new Error(
|
||||||
|
'Cannot use try without catch or finally', $node->getAttributes()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function checkNamespace(Namespace_ $node) {
|
||||||
|
if (isset(self::$specialNames[strtolower($node->name)])) {
|
||||||
|
$this->emitError(new Error(
|
||||||
|
sprintf('Cannot use \'%s\' as namespace name', $node->name),
|
||||||
|
$node->name->getAttributes()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $node->stmts) {
|
||||||
|
foreach ($node->stmts as $stmt) {
|
||||||
|
if ($stmt instanceof Namespace_) {
|
||||||
|
$this->emitError(new Error(
|
||||||
|
'Namespace declarations cannot be nested', $stmt->getAttributes()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function checkClass(Class_ $node, $namePos) {
|
||||||
|
if (null !== $node->name && isset(self::$specialNames[strtolower($node->name)])) {
|
||||||
|
$this->emitError(new Error(
|
||||||
|
sprintf('Cannot use \'%s\' as class name as it is reserved', $node->name),
|
||||||
|
$this->getAttributesAt($namePos)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset(self::$specialNames[strtolower($node->extends)])) {
|
||||||
|
$this->emitError(new Error(
|
||||||
|
sprintf('Cannot use \'%s\' as class name as it is reserved', $node->extends),
|
||||||
|
$node->extends->getAttributes()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($node->implements as $interface) {
|
||||||
|
if (isset(self::$specialNames[strtolower($interface)])) {
|
||||||
|
$this->emitError(new Error(
|
||||||
|
sprintf('Cannot use \'%s\' as interface name as it is reserved', $interface),
|
||||||
|
$interface->getAttributes()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function checkInterface(Interface_ $node, $namePos) {
|
||||||
|
if (null !== $node->name && isset(self::$specialNames[strtolower($node->name)])) {
|
||||||
|
$this->emitError(new Error(
|
||||||
|
sprintf('Cannot use \'%s\' as class name as it is reserved', $node->name),
|
||||||
|
$this->getAttributesAt($namePos)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($node->extends as $interface) {
|
||||||
|
if (isset(self::$specialNames[strtolower($interface)])) {
|
||||||
|
$this->emitError(new Error(
|
||||||
|
sprintf('Cannot use \'%s\' as interface name as it is reserved', $interface),
|
||||||
|
$interface->getAttributes()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function checkClassMethod(ClassMethod $node, $modifierPos) {
|
||||||
|
if ($node->flags & Class_::MODIFIER_STATIC) {
|
||||||
|
switch (strtolower($node->name)) {
|
||||||
|
case '__construct':
|
||||||
|
$this->emitError(new Error(
|
||||||
|
sprintf('Constructor %s() cannot be static', $node->name),
|
||||||
|
$this->getAttributesAt($modifierPos)));
|
||||||
|
break;
|
||||||
|
case '__destruct':
|
||||||
|
$this->emitError(new Error(
|
||||||
|
sprintf('Destructor %s() cannot be static', $node->name),
|
||||||
|
$this->getAttributesAt($modifierPos)));
|
||||||
|
break;
|
||||||
|
case '__clone':
|
||||||
|
$this->emitError(new Error(
|
||||||
|
sprintf('Clone method %s() cannot be static', $node->name),
|
||||||
|
$this->getAttributesAt($modifierPos)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function checkClassConst(ClassConst $node, $modifierPos) {
|
||||||
|
if ($node->flags & Class_::MODIFIER_STATIC) {
|
||||||
|
$this->emitError(new Error(
|
||||||
|
"Cannot use 'static' as constant modifier",
|
||||||
|
$this->getAttributesAt($modifierPos)));
|
||||||
|
}
|
||||||
|
if ($node->flags & Class_::MODIFIER_ABSTRACT) {
|
||||||
|
$this->emitError(new Error(
|
||||||
|
"Cannot use 'abstract' as constant modifier",
|
||||||
|
$this->getAttributesAt($modifierPos)));
|
||||||
|
}
|
||||||
|
if ($node->flags & Class_::MODIFIER_FINAL) {
|
||||||
|
$this->emitError(new Error(
|
||||||
|
"Cannot use 'final' as constant modifier",
|
||||||
|
$this->getAttributesAt($modifierPos)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function checkProperty(Property $node, $modifierPos) {
|
||||||
|
if ($node->flags & Class_::MODIFIER_ABSTRACT) {
|
||||||
|
$this->emitError(new Error('Properties cannot be declared abstract',
|
||||||
|
$this->getAttributesAt($modifierPos)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($node->flags & Class_::MODIFIER_FINAL) {
|
||||||
|
$this->emitError(new Error('Properties cannot be declared final',
|
||||||
|
$this->getAttributesAt($modifierPos)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function checkUseUse(UseUse $node, $namePos) {
|
||||||
|
if ('self' == strtolower($node->alias) || 'parent' == strtolower($node->alias)) {
|
||||||
|
$this->emitError(new Error(
|
||||||
|
sprintf(
|
||||||
|
'Cannot use %s as %s because \'%2$s\' is a special class name',
|
||||||
|
$node->name, $node->alias
|
||||||
|
),
|
||||||
|
$this->getAttributesAt($namePos)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,16 +2,16 @@
|
|||||||
|
|
||||||
namespace PhpParser\PrettyPrinter;
|
namespace PhpParser\PrettyPrinter;
|
||||||
|
|
||||||
use PhpParser\PrettyPrinterAbstract;
|
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
use PhpParser\Node\Scalar;
|
|
||||||
use PhpParser\Node\Scalar\MagicConst;
|
|
||||||
use PhpParser\Node\Expr;
|
use PhpParser\Node\Expr;
|
||||||
use PhpParser\Node\Expr\AssignOp;
|
use PhpParser\Node\Expr\AssignOp;
|
||||||
use PhpParser\Node\Expr\BinaryOp;
|
use PhpParser\Node\Expr\BinaryOp;
|
||||||
use PhpParser\Node\Expr\Cast;
|
use PhpParser\Node\Expr\Cast;
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
use PhpParser\Node\Name;
|
use PhpParser\Node\Name;
|
||||||
|
use PhpParser\Node\Scalar;
|
||||||
|
use PhpParser\Node\Scalar\MagicConst;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
use PhpParser\PrettyPrinterAbstract;
|
||||||
|
|
||||||
class Standard extends PrettyPrinterAbstract
|
class Standard extends PrettyPrinterAbstract
|
||||||
{
|
{
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
namespace PhpParser\Serializer;
|
namespace PhpParser\Serializer;
|
||||||
|
|
||||||
use XMLWriter;
|
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Comment;
|
use PhpParser\Comment;
|
||||||
|
use PhpParser\Node;
|
||||||
use PhpParser\Serializer;
|
use PhpParser\Serializer;
|
||||||
|
use XMLWriter;
|
||||||
|
|
||||||
class XML implements Serializer
|
class XML implements Serializer
|
||||||
{
|
{
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
namespace PhpParser\Unserializer;
|
namespace PhpParser\Unserializer;
|
||||||
|
|
||||||
use XMLReader;
|
|
||||||
use DomainException;
|
use DomainException;
|
||||||
use PhpParser\Unserializer;
|
use PhpParser\Unserializer;
|
||||||
|
use XMLReader;
|
||||||
|
|
||||||
class XML implements Unserializer
|
class XML implements Unserializer
|
||||||
{
|
{
|
||||||
|
@ -2,9 +2,6 @@
|
|||||||
|
|
||||||
namespace PhpParser;
|
namespace PhpParser;
|
||||||
|
|
||||||
use PhpParser\Node\Expr;
|
|
||||||
use PhpParser\Node\Scalar;
|
|
||||||
|
|
||||||
/* The autoloader is already active at this point, so we only check effects here. */
|
/* The autoloader is already active at this point, so we only check effects here. */
|
||||||
|
|
||||||
class AutoloaderTest extends \PHPUnit_Framework_TestCase {
|
class AutoloaderTest extends \PHPUnit_Framework_TestCase {
|
||||||
|
@ -43,7 +43,7 @@ class ClassTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
new Stmt\Class_('Test', array(
|
new Stmt\Class_('Test', array(
|
||||||
'type' => Stmt\Class_::MODIFIER_ABSTRACT
|
'flags' => Stmt\Class_::MODIFIER_ABSTRACT
|
||||||
)),
|
)),
|
||||||
$node
|
$node
|
||||||
);
|
);
|
||||||
@ -57,7 +57,7 @@ class ClassTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
new Stmt\Class_('Test', array(
|
new Stmt\Class_('Test', array(
|
||||||
'type' => Stmt\Class_::MODIFIER_FINAL
|
'flags' => Stmt\Class_::MODIFIER_FINAL
|
||||||
)),
|
)),
|
||||||
$node
|
$node
|
||||||
);
|
);
|
||||||
|
@ -4,9 +4,9 @@ namespace PhpParser\Builder;
|
|||||||
|
|
||||||
use PhpParser\Comment;
|
use PhpParser\Comment;
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
use PhpParser\Node\Expr\Print_;
|
use PhpParser\Node\Expr\Print_;
|
||||||
use PhpParser\Node\Scalar\String_;
|
use PhpParser\Node\Scalar\String_;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
class FunctionTest extends \PHPUnit_Framework_TestCase
|
class FunctionTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
namespace PhpParser\Builder;
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
use PhpParser\Node\Scalar\DNumber;
|
|
||||||
use PhpParser\Comment;
|
use PhpParser\Comment;
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Scalar\DNumber;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
class InterfaceTest extends \PHPUnit_Framework_TestCase
|
class InterfaceTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
namespace PhpParser\Builder;
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser\Comment;
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
use PhpParser\Node\Expr\Print_;
|
use PhpParser\Node\Expr\Print_;
|
||||||
use PhpParser\Node\Scalar\String_;
|
use PhpParser\Node\Scalar\String_;
|
||||||
use PhpParser\Node\Stmt;
|
use PhpParser\Node\Stmt;
|
||||||
use PhpParser\Comment;
|
|
||||||
|
|
||||||
class MethodTest extends \PHPUnit_Framework_TestCase
|
class MethodTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
@ -24,9 +24,9 @@ class MethodTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
new Stmt\ClassMethod('test', array(
|
new Stmt\ClassMethod('test', array(
|
||||||
'type' => Stmt\Class_::MODIFIER_PUBLIC
|
'flags' => Stmt\Class_::MODIFIER_PUBLIC
|
||||||
| Stmt\Class_::MODIFIER_ABSTRACT
|
| Stmt\Class_::MODIFIER_ABSTRACT
|
||||||
| Stmt\Class_::MODIFIER_STATIC,
|
| Stmt\Class_::MODIFIER_STATIC,
|
||||||
'stmts' => null,
|
'stmts' => null,
|
||||||
)),
|
)),
|
||||||
$node
|
$node
|
||||||
@ -40,8 +40,8 @@ class MethodTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
new Stmt\ClassMethod('test', array(
|
new Stmt\ClassMethod('test', array(
|
||||||
'type' => Stmt\Class_::MODIFIER_PROTECTED
|
'flags' => Stmt\Class_::MODIFIER_PROTECTED
|
||||||
| Stmt\Class_::MODIFIER_FINAL
|
| Stmt\Class_::MODIFIER_FINAL
|
||||||
)),
|
)),
|
||||||
$node
|
$node
|
||||||
);
|
);
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
namespace PhpParser\Builder;
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
use PhpParser\Node\Name;
|
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
use PhpParser\Node\Expr;
|
|
||||||
use PhpParser\Node\Scalar;
|
|
||||||
use PhpParser\Comment;
|
use PhpParser\Comment;
|
||||||
|
use PhpParser\Node\Expr;
|
||||||
|
use PhpParser\Node\Name;
|
||||||
|
use PhpParser\Node\Scalar;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
class PropertyTest extends \PHPUnit_Framework_TestCase
|
class PropertyTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
namespace PhpParser\Builder;
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
use PhpParser\Comment;
|
use PhpParser\Comment;
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Node\Name;
|
|
||||||
use PhpParser\Node\Stmt;
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
class TraitTest extends \PHPUnit_Framework_TestCase
|
class TraitTest extends \PHPUnit_Framework_TestCase
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
namespace PhpParser;
|
namespace PhpParser;
|
||||||
|
|
||||||
use PhpParser\Comment;
|
|
||||||
|
|
||||||
require_once __DIR__ . '/CodeTestAbstract.php';
|
require_once __DIR__ . '/CodeTestAbstract.php';
|
||||||
|
|
||||||
class CodeParsingTest extends CodeTestAbstract
|
class CodeParsingTest extends CodeTestAbstract
|
||||||
@ -11,24 +9,28 @@ class CodeParsingTest extends CodeTestAbstract
|
|||||||
/**
|
/**
|
||||||
* @dataProvider provideTestParse
|
* @dataProvider provideTestParse
|
||||||
*/
|
*/
|
||||||
public function testParse($name, $code, $expected, $mode) {
|
public function testParse($name, $code, $expected, $modeLine) {
|
||||||
|
if (null !== $modeLine) {
|
||||||
|
$modes = array_fill_keys(explode(',', $modeLine), true);
|
||||||
|
} else {
|
||||||
|
$modes = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$lexer = new Lexer\Emulative(array('usedAttributes' => array(
|
$lexer = new Lexer\Emulative(array('usedAttributes' => array(
|
||||||
'startLine', 'endLine', 'startFilePos', 'endFilePos', 'comments'
|
'startLine', 'endLine', 'startFilePos', 'endFilePos', 'comments'
|
||||||
)));
|
)));
|
||||||
$parser5 = new Parser\Php5($lexer, array(
|
$parser5 = new Parser\Php5($lexer);
|
||||||
'throwOnError' => false,
|
$parser7 = new Parser\Php7($lexer);
|
||||||
));
|
|
||||||
$parser7 = new Parser\Php7($lexer, array(
|
|
||||||
'throwOnError' => false,
|
|
||||||
));
|
|
||||||
|
|
||||||
$output5 = $this->getParseOutput($parser5, $code);
|
$dumpPositions = isset($modes['positions']);
|
||||||
$output7 = $this->getParseOutput($parser7, $code);
|
$output5 = $this->getParseOutput($parser5, $code, $dumpPositions);
|
||||||
|
$output7 = $this->getParseOutput($parser7, $code, $dumpPositions);
|
||||||
|
|
||||||
if ($mode === 'php5') {
|
if (isset($modes['php5'])) {
|
||||||
$this->assertSame($expected, $output5, $name);
|
$this->assertSame($expected, $output5, $name);
|
||||||
$this->assertNotSame($expected, $output7, $name);
|
$this->assertNotSame($expected, $output7, $name);
|
||||||
} else if ($mode === 'php7') {
|
} else if (isset($modes['php7'])) {
|
||||||
$this->assertNotSame($expected, $output5, $name);
|
$this->assertNotSame($expected, $output5, $name);
|
||||||
$this->assertSame($expected, $output7, $name);
|
$this->assertSame($expected, $output7, $name);
|
||||||
} else {
|
} else {
|
||||||
@ -37,18 +39,18 @@ class CodeParsingTest extends CodeTestAbstract
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getParseOutput(Parser $parser, $code) {
|
private function getParseOutput(Parser $parser, $code, $dumpPositions) {
|
||||||
$stmts = $parser->parse($code);
|
$errors = new ErrorHandler\Collecting;
|
||||||
$errors = $parser->getErrors();
|
$stmts = $parser->parse($code, $errors);
|
||||||
|
|
||||||
$output = '';
|
$output = '';
|
||||||
foreach ($errors as $error) {
|
foreach ($errors->getErrors() as $error) {
|
||||||
$output .= $this->formatErrorMessage($error, $code) . "\n";
|
$output .= $this->formatErrorMessage($error, $code) . "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $stmts) {
|
if (null !== $stmts) {
|
||||||
$dumper = new NodeDumper(['dumpComments' => true]);
|
$dumper = new NodeDumper(['dumpComments' => true, 'dumpPositions' => $dumpPositions]);
|
||||||
$output .= $dumper->dump($stmts);
|
$output .= $dumper->dump($stmts, $code);
|
||||||
}
|
}
|
||||||
|
|
||||||
return canonicalize($output);
|
return canonicalize($output);
|
||||||
@ -60,8 +62,7 @@ class CodeParsingTest extends CodeTestAbstract
|
|||||||
|
|
||||||
private function formatErrorMessage(Error $e, $code) {
|
private function formatErrorMessage(Error $e, $code) {
|
||||||
if ($e->hasColumnInfo()) {
|
if ($e->hasColumnInfo()) {
|
||||||
return $e->getRawMessage() . ' from ' . $e->getStartLine() . ':' . $e->getStartColumn($code)
|
return $e->getMessageWithColumnInfo($code);
|
||||||
. ' to ' . $e->getEndLine() . ':' . $e->getEndColumn($code);
|
|
||||||
} else {
|
} else {
|
||||||
return $e->getMessage();
|
return $e->getMessage();
|
||||||
}
|
}
|
||||||
|
22
test/PhpParser/ErrorHandler/CollectingTest.php
Normal file
22
test/PhpParser/ErrorHandler/CollectingTest.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpParser\ErrorHandler;
|
||||||
|
|
||||||
|
use PhpParser\Error;
|
||||||
|
|
||||||
|
class CollectingTest extends \PHPUnit_Framework_TestCase {
|
||||||
|
public function testHandleError() {
|
||||||
|
$errorHandler = new Collecting();
|
||||||
|
$this->assertFalse($errorHandler->hasErrors());
|
||||||
|
$this->assertEmpty($errorHandler->getErrors());
|
||||||
|
|
||||||
|
$errorHandler->handleError($e1 = new Error('Test 1'));
|
||||||
|
$errorHandler->handleError($e2 = new Error('Test 2'));
|
||||||
|
$this->assertTrue($errorHandler->hasErrors());
|
||||||
|
$this->assertSame([$e1, $e2], $errorHandler->getErrors());
|
||||||
|
|
||||||
|
$errorHandler->clearErrors();
|
||||||
|
$this->assertFalse($errorHandler->hasErrors());
|
||||||
|
$this->assertEmpty($errorHandler->getErrors());
|
||||||
|
}
|
||||||
|
}
|
16
test/PhpParser/ErrorHandler/ThrowingTest.php
Normal file
16
test/PhpParser/ErrorHandler/ThrowingTest.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpParser\ErrorHandler;
|
||||||
|
|
||||||
|
use PhpParser\Error;
|
||||||
|
|
||||||
|
class ThrowingTest extends \PHPUnit_Framework_TestCase {
|
||||||
|
/**
|
||||||
|
* @expectedException \PhpParser\Error
|
||||||
|
* @expectedExceptionMessage Test
|
||||||
|
*/
|
||||||
|
public function testHandleError() {
|
||||||
|
$errorHandler = new Throwing();
|
||||||
|
$errorHandler->handleError(new Error('Test'));
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,6 @@ class ErrorTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertSame($attributes, $error->getAttributes());
|
$this->assertSame($attributes, $error->getAttributes());
|
||||||
$this->assertSame(10, $error->getStartLine());
|
$this->assertSame(10, $error->getStartLine());
|
||||||
$this->assertSame(11, $error->getEndLine());
|
$this->assertSame(11, $error->getEndLine());
|
||||||
$this->assertSame(10, $error->getRawLine());
|
|
||||||
$this->assertSame('Some error on line 10', $error->getMessage());
|
$this->assertSame('Some error on line 10', $error->getMessage());
|
||||||
|
|
||||||
return $error;
|
return $error;
|
||||||
@ -31,10 +30,6 @@ class ErrorTest extends \PHPUnit_Framework_TestCase
|
|||||||
$error->setStartLine(15);
|
$error->setStartLine(15);
|
||||||
$this->assertSame(15, $error->getStartLine());
|
$this->assertSame(15, $error->getStartLine());
|
||||||
$this->assertSame('Some other error on line 15', $error->getMessage());
|
$this->assertSame('Some other error on line 15', $error->getMessage());
|
||||||
|
|
||||||
$error->setRawLine(17);
|
|
||||||
$this->assertSame(17, $error->getRawLine());
|
|
||||||
$this->assertSame('Some other error on line 17', $error->getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUnknownLine() {
|
public function testUnknownLine() {
|
||||||
@ -42,7 +37,6 @@ class ErrorTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$this->assertSame(-1, $error->getStartLine());
|
$this->assertSame(-1, $error->getStartLine());
|
||||||
$this->assertSame(-1, $error->getEndLine());
|
$this->assertSame(-1, $error->getEndLine());
|
||||||
$this->assertSame(-1, $error->getRawLine());
|
|
||||||
$this->assertSame('Some error on unknown line', $error->getMessage());
|
$this->assertSame('Some error on unknown line', $error->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,28 +14,36 @@ class LexerTest extends \PHPUnit_Framework_TestCase
|
|||||||
/**
|
/**
|
||||||
* @dataProvider provideTestError
|
* @dataProvider provideTestError
|
||||||
*/
|
*/
|
||||||
public function testError($code, $message) {
|
public function testError($code, $messages) {
|
||||||
if (defined('HHVM_VERSION')) {
|
if (defined('HHVM_VERSION')) {
|
||||||
$this->markTestSkipped('HHVM does not throw warnings from token_get_all()');
|
$this->markTestSkipped('HHVM does not throw warnings from token_get_all()');
|
||||||
}
|
}
|
||||||
|
|
||||||
$lexer = $this->getLexer();
|
$errorHandler = new ErrorHandler\Collecting();
|
||||||
try {
|
$lexer = $this->getLexer(['usedAttributes' => [
|
||||||
$lexer->startLexing($code);
|
'comments', 'startLine', 'endLine', 'startFilePos', 'endFilePos'
|
||||||
} catch (Error $e) {
|
]]);
|
||||||
$this->assertSame($message, $e->getMessage());
|
$lexer->startLexing($code, $errorHandler);
|
||||||
|
$errors = $errorHandler->getErrors();
|
||||||
|
|
||||||
return;
|
$this->assertSame(count($messages), count($errors));
|
||||||
|
for ($i = 0; $i < count($messages); $i++) {
|
||||||
|
$this->assertSame($messages[$i], $errors[$i]->getMessageWithColumnInfo($code));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->fail('Expected PhpParser\Error');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function provideTestError() {
|
public function provideTestError() {
|
||||||
return array(
|
return array(
|
||||||
array('<?php /*', 'Unterminated comment on line 1'),
|
array("<?php /*", array("Unterminated comment from 1:7 to 1:9")),
|
||||||
array('<?php ' . "\1", 'Unexpected character "' . "\1" . '" (ASCII 1) on unknown line'),
|
array("<?php \1", array("Unexpected character \"\1\" (ASCII 1) from 1:7 to 1:7")),
|
||||||
array('<?php ' . "\0", 'Unexpected null byte on unknown line'),
|
array("<?php \0", array("Unexpected null byte from 1:7 to 1:7")),
|
||||||
|
// Error with potentially emulated token
|
||||||
|
array("<?php ?? \0", array("Unexpected null byte from 1:10 to 1:10")),
|
||||||
|
array("<?php\n\0\1 foo /* bar", array(
|
||||||
|
"Unexpected null byte from 2:1 to 2:1",
|
||||||
|
"Unexpected character \"\1\" (ASCII 1) from 2:2 to 2:2",
|
||||||
|
"Unterminated comment from 2:8 to 2:14"
|
||||||
|
)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,9 @@ class NameTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$name = new Name('foo\bar');
|
$name = new Name('foo\bar');
|
||||||
$this->assertSame(array('foo', 'bar'), $name->parts);
|
$this->assertSame(array('foo', 'bar'), $name->parts);
|
||||||
|
|
||||||
|
$name = new Name($name);
|
||||||
|
$this->assertSame(array('foo', 'bar'), $name->parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGet() {
|
public function testGet() {
|
||||||
@ -27,43 +30,22 @@ class NameTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$this->assertSame('foo\bar', (string) $name);
|
$this->assertSame('foo\bar', (string) $name);
|
||||||
$this->assertSame('foo\bar', $name->toString());
|
$this->assertSame('foo\bar', $name->toString());
|
||||||
$this->assertSame('foo_bar', $name->toString('_'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testAppend() {
|
|
||||||
$name = new Name('foo');
|
|
||||||
|
|
||||||
$name->append('bar');
|
|
||||||
$this->assertSame('foo\bar', $name->toString());
|
|
||||||
|
|
||||||
$name->append('bar\foo');
|
|
||||||
$this->assertSame('foo\bar\bar\foo', $name->toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testPrepend() {
|
|
||||||
$name = new Name('foo');
|
|
||||||
|
|
||||||
$name->prepend('bar');
|
|
||||||
$this->assertSame('bar\foo', $name->toString());
|
|
||||||
|
|
||||||
$name->prepend('foo\bar');
|
|
||||||
$this->assertSame('foo\bar\bar\foo', $name->toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSlice() {
|
public function testSlice() {
|
||||||
$name = new Name('foo\bar\baz');
|
$name = new Name('foo\bar\baz');
|
||||||
$this->assertEquals(new Name('foo\bar\baz'), $name->slice(0));
|
$this->assertEquals(new Name('foo\bar\baz'), $name->slice(0));
|
||||||
$this->assertEquals(new Name('bar\baz'), $name->slice(1));
|
$this->assertEquals(new Name('bar\baz'), $name->slice(1));
|
||||||
$this->assertEquals(new Name([]), $name->slice(3));
|
$this->assertNull($name->slice(3));
|
||||||
$this->assertEquals(new Name('foo\bar\baz'), $name->slice(-3));
|
$this->assertEquals(new Name('foo\bar\baz'), $name->slice(-3));
|
||||||
$this->assertEquals(new Name('bar\baz'), $name->slice(-2));
|
$this->assertEquals(new Name('bar\baz'), $name->slice(-2));
|
||||||
$this->assertEquals(new Name('foo\bar'), $name->slice(0, -1));
|
$this->assertEquals(new Name('foo\bar'), $name->slice(0, -1));
|
||||||
$this->assertEquals(new Name([]), $name->slice(0, -3));
|
$this->assertNull($name->slice(0, -3));
|
||||||
$this->assertEquals(new Name('bar'), $name->slice(1, -1));
|
$this->assertEquals(new Name('bar'), $name->slice(1, -1));
|
||||||
$this->assertEquals(new Name([]), $name->slice(1, -2));
|
$this->assertNull($name->slice(1, -2));
|
||||||
$this->assertEquals(new Name('bar'), $name->slice(-2, 1));
|
$this->assertEquals(new Name('bar'), $name->slice(-2, 1));
|
||||||
$this->assertEquals(new Name('bar'), $name->slice(-2, -1));
|
$this->assertEquals(new Name('bar'), $name->slice(-2, -1));
|
||||||
$this->assertEquals(new Name([]), $name->slice(-2, -2));
|
$this->assertNull($name->slice(-2, -2));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -111,8 +93,9 @@ class NameTest extends \PHPUnit_Framework_TestCase
|
|||||||
Name\Relative::concat(new Name\FullyQualified('foo\bar'), 'baz', $attributes)
|
Name\Relative::concat(new Name\FullyQualified('foo\bar'), 'baz', $attributes)
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals(new Name('foo'), Name::concat([], 'foo'));
|
$this->assertEquals(new Name('foo'), Name::concat(null, 'foo'));
|
||||||
$this->assertEquals(new Name([]), Name::concat([], []));
|
$this->assertEquals(new Name('foo'), Name::concat('foo', null));
|
||||||
|
$this->assertNull(Name::concat(null, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIs() {
|
public function testIs() {
|
||||||
@ -143,10 +126,9 @@ class NameTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException \InvalidArgumentException
|
* @expectedException \InvalidArgumentException
|
||||||
* @expectedExceptionMessage When changing a name you need to pass either a string, an array or a Name node
|
* @expectedExceptionMessage Expected string, array of parts or Name instance
|
||||||
*/
|
*/
|
||||||
public function testInvalidArg() {
|
public function testInvalidArg() {
|
||||||
$name = new Name('foo');
|
Name::concat('foo', new \stdClass);
|
||||||
$name->append(new \stdClass);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -70,6 +70,28 @@ class NodeAbstractTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertNull($node->getDocComment());
|
$this->assertNull($node->getDocComment());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSetDocComment() {
|
||||||
|
$node = new DummyNode(null, null, []);
|
||||||
|
|
||||||
|
// Add doc comment to node without comments
|
||||||
|
$docComment = new Comment\Doc('/** doc */');
|
||||||
|
$node->setDocComment($docComment);
|
||||||
|
$this->assertSame($docComment, $node->getDocComment());
|
||||||
|
|
||||||
|
// Replace it
|
||||||
|
$docComment = new Comment\Doc('/** doc 2 */');
|
||||||
|
$node->setDocComment($docComment);
|
||||||
|
$this->assertSame($docComment, $node->getDocComment());
|
||||||
|
|
||||||
|
// Add docmment to node with other comments
|
||||||
|
$c1 = new Comment('/* foo */');
|
||||||
|
$c2 = new Comment('/* bar */');
|
||||||
|
$docComment = new Comment\Doc('/** baz */');
|
||||||
|
$node->setAttribute('comments', [$c1, $c2]);
|
||||||
|
$node->setDocComment($docComment);
|
||||||
|
$this->assertSame([$c1, $c2, $docComment], $node->getAttribute('comments'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider provideNodes
|
* @dataProvider provideNodes
|
||||||
*/
|
*/
|
||||||
|
@ -10,7 +10,6 @@ class NodeDumperTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider provideTestDump
|
* @dataProvider provideTestDump
|
||||||
* @covers PhpParser\NodeDumper::dump
|
|
||||||
*/
|
*/
|
||||||
public function testDump($node, $dump) {
|
public function testDump($node, $dump) {
|
||||||
$dumper = new NodeDumper;
|
$dumper = new NodeDumper;
|
||||||
@ -61,6 +60,40 @@ class NodeDumperTest extends \PHPUnit_Framework_TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testDumpWithPositions() {
|
||||||
|
$parser = (new ParserFactory)->create(
|
||||||
|
ParserFactory::ONLY_PHP7,
|
||||||
|
new Lexer(['usedAttributes' => ['startLine', 'endLine', 'startFilePos', 'endFilePos']])
|
||||||
|
);
|
||||||
|
$dumper = new NodeDumper(['dumpPositions' => true]);
|
||||||
|
|
||||||
|
$code = "<?php\n\$a = 1;\necho \$a;";
|
||||||
|
$expected = <<<'OUT'
|
||||||
|
array(
|
||||||
|
0: Expr_Assign[2:1 - 2:6](
|
||||||
|
var: Expr_Variable[2:1 - 2:2](
|
||||||
|
name: a
|
||||||
|
)
|
||||||
|
expr: Scalar_LNumber[2:6 - 2:6](
|
||||||
|
value: 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
1: Stmt_Echo[3:1 - 3:8](
|
||||||
|
exprs: array(
|
||||||
|
0: Expr_Variable[3:6 - 3:7](
|
||||||
|
name: a
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
OUT;
|
||||||
|
|
||||||
|
$stmts = $parser->parse($code);
|
||||||
|
$dump = $dumper->dump($stmts, $code);
|
||||||
|
|
||||||
|
$this->assertSame($this->canonicalize($expected), $this->canonicalize($dump));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException \InvalidArgumentException
|
* @expectedException \InvalidArgumentException
|
||||||
* @expectedExceptionMessage Can only dump nodes and arrays.
|
* @expectedExceptionMessage Can only dump nodes and arrays.
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace PhpParser;
|
namespace PhpParser;
|
||||||
|
|
||||||
use PhpParser\Node\Scalar\String_;
|
|
||||||
use PhpParser\Node\Expr;
|
use PhpParser\Node\Expr;
|
||||||
|
use PhpParser\Node\Scalar\String_;
|
||||||
|
|
||||||
class NodeTraverserTest extends \PHPUnit_Framework_TestCase
|
class NodeTraverserTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
@ -13,7 +13,7 @@ class NodeTraverserTest extends \PHPUnit_Framework_TestCase
|
|||||||
$echoNode = new Node\Stmt\Echo_(array($str1Node, $str2Node));
|
$echoNode = new Node\Stmt\Echo_(array($str1Node, $str2Node));
|
||||||
$stmts = array($echoNode);
|
$stmts = array($echoNode);
|
||||||
|
|
||||||
$visitor = $this->getMock('PhpParser\NodeVisitor');
|
$visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
|
||||||
|
|
||||||
$visitor->expects($this->at(0))->method('beforeTraverse')->with($stmts);
|
$visitor->expects($this->at(0))->method('beforeTraverse')->with($stmts);
|
||||||
$visitor->expects($this->at(1))->method('enterNode')->with($echoNode);
|
$visitor->expects($this->at(1))->method('enterNode')->with($echoNode);
|
||||||
@ -36,8 +36,8 @@ class NodeTraverserTest extends \PHPUnit_Framework_TestCase
|
|||||||
$printNode = new Expr\Print_($str1Node);
|
$printNode = new Expr\Print_($str1Node);
|
||||||
|
|
||||||
// first visitor changes the node, second verifies the change
|
// first visitor changes the node, second verifies the change
|
||||||
$visitor1 = $this->getMock('PhpParser\NodeVisitor');
|
$visitor1 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
|
||||||
$visitor2 = $this->getMock('PhpParser\NodeVisitor');
|
$visitor2 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
|
||||||
|
|
||||||
// replace empty statements with string1 node
|
// replace empty statements with string1 node
|
||||||
$visitor1->expects($this->at(0))->method('beforeTraverse')->with(array())
|
$visitor1->expects($this->at(0))->method('beforeTraverse')->with(array())
|
||||||
@ -81,7 +81,7 @@ class NodeTraverserTest extends \PHPUnit_Framework_TestCase
|
|||||||
$str1Node = new String_('Foo');
|
$str1Node = new String_('Foo');
|
||||||
$str2Node = new String_('Bar');
|
$str2Node = new String_('Bar');
|
||||||
|
|
||||||
$visitor = $this->getMock('PhpParser\NodeVisitor');
|
$visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
|
||||||
|
|
||||||
// remove the string1 node, leave the string2 node
|
// remove the string1 node, leave the string2 node
|
||||||
$visitor->expects($this->at(2))->method('leaveNode')->with($str1Node)
|
$visitor->expects($this->at(2))->method('leaveNode')->with($str1Node)
|
||||||
@ -100,7 +100,7 @@ class NodeTraverserTest extends \PHPUnit_Framework_TestCase
|
|||||||
$strR1 = new String_('Replacement 1');
|
$strR1 = new String_('Replacement 1');
|
||||||
$strR2 = new String_('Replacement 2');
|
$strR2 = new String_('Replacement 2');
|
||||||
|
|
||||||
$visitor = $this->getMock('PhpParser\NodeVisitor');
|
$visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
|
||||||
|
|
||||||
// replace strMiddle with strR1 and strR2 by merge
|
// replace strMiddle with strR1 and strR2 by merge
|
||||||
$visitor->expects($this->at(4))->method('leaveNode')->with($strMiddle)
|
$visitor->expects($this->at(4))->method('leaveNode')->with($strMiddle)
|
||||||
@ -119,7 +119,7 @@ class NodeTraverserTest extends \PHPUnit_Framework_TestCase
|
|||||||
$strNode = new String_('Foo');
|
$strNode = new String_('Foo');
|
||||||
$stmts = array(array(array($strNode)));
|
$stmts = array(array(array($strNode)));
|
||||||
|
|
||||||
$visitor = $this->getMock('PhpParser\NodeVisitor');
|
$visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
|
||||||
$visitor->expects($this->at(1))->method('enterNode')->with($strNode);
|
$visitor->expects($this->at(1))->method('enterNode')->with($strNode);
|
||||||
|
|
||||||
$traverser = new NodeTraverser;
|
$traverser = new NodeTraverser;
|
||||||
@ -136,8 +136,8 @@ class NodeTraverserTest extends \PHPUnit_Framework_TestCase
|
|||||||
$negNode = new Expr\UnaryMinus($mulNode);
|
$negNode = new Expr\UnaryMinus($mulNode);
|
||||||
$stmts = array($printNode, $negNode);
|
$stmts = array($printNode, $negNode);
|
||||||
|
|
||||||
$visitor1 = $this->getMock('PhpParser\NodeVisitor');
|
$visitor1 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
|
||||||
$visitor2 = $this->getMock('PhpParser\NodeVisitor');
|
$visitor2 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
|
||||||
|
|
||||||
$visitor1->expects($this->at(1))->method('enterNode')->with($printNode)
|
$visitor1->expects($this->at(1))->method('enterNode')->with($printNode)
|
||||||
->will($this->returnValue(NodeTraverser::DONT_TRAVERSE_CHILDREN));
|
->will($this->returnValue(NodeTraverser::DONT_TRAVERSE_CHILDREN));
|
||||||
@ -167,9 +167,9 @@ class NodeTraverserTest extends \PHPUnit_Framework_TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function testRemovingVisitor() {
|
public function testRemovingVisitor() {
|
||||||
$visitor1 = $this->getMock('PhpParser\NodeVisitor');
|
$visitor1 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
|
||||||
$visitor2 = $this->getMock('PhpParser\NodeVisitor');
|
$visitor2 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
|
||||||
$visitor3 = $this->getMock('PhpParser\NodeVisitor');
|
$visitor3 = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
|
||||||
|
|
||||||
$traverser = new NodeTraverser;
|
$traverser = new NodeTraverser;
|
||||||
$traverser->addVisitor($visitor1);
|
$traverser->addVisitor($visitor1);
|
||||||
@ -185,15 +185,7 @@ class NodeTraverserTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertAttributeSame($postExpected, 'visitors', $traverser, 'The appropriate visitors are not present after removal');
|
$this->assertAttributeSame($postExpected, 'visitors', $traverser, 'The appropriate visitors are not present after removal');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCloneNodes() {
|
public function testNoCloneNodes() {
|
||||||
$stmts = array(new Node\Stmt\Echo_(array(new String_('Foo'), new String_('Bar'))));
|
|
||||||
|
|
||||||
$traverser = new NodeTraverser(true);
|
|
||||||
|
|
||||||
$this->assertNotSame($stmts, $traverser->traverse($stmts));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testNoCloneNodesByDefault() {
|
|
||||||
$stmts = array(new Node\Stmt\Echo_(array(new String_('Foo'), new String_('Bar'))));
|
$stmts = array(new Node\Stmt\Echo_(array(new String_('Foo'), new String_('Bar'))));
|
||||||
|
|
||||||
$traverser = new NodeTraverser;
|
$traverser = new NodeTraverser;
|
||||||
@ -208,7 +200,7 @@ class NodeTraverserTest extends \PHPUnit_Framework_TestCase
|
|||||||
public function testReplaceByArrayOnlyAllowedIfParentIsArray() {
|
public function testReplaceByArrayOnlyAllowedIfParentIsArray() {
|
||||||
$stmts = array(new Node\Expr\UnaryMinus(new Node\Scalar\LNumber(42)));
|
$stmts = array(new Node\Expr\UnaryMinus(new Node\Scalar\LNumber(42)));
|
||||||
|
|
||||||
$visitor = $this->getMock('PhpParser\NodeVisitor');
|
$visitor = $this->getMockBuilder('PhpParser\NodeVisitor')->getMock();
|
||||||
$visitor->method('leaveNode')->willReturn(array(new Node\Scalar\DNumber(42.0)));
|
$visitor->method('leaveNode')->willReturn(array(new Node\Scalar\DNumber(42.0)));
|
||||||
|
|
||||||
$traverser = new NodeTraverser();
|
$traverser = new NodeTraverser();
|
||||||
|
@ -4,9 +4,9 @@ namespace PhpParser\NodeVisitor;
|
|||||||
|
|
||||||
use PhpParser;
|
use PhpParser;
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Expr;
|
||||||
use PhpParser\Node\Name;
|
use PhpParser\Node\Name;
|
||||||
use PhpParser\Node\Stmt;
|
use PhpParser\Node\Stmt;
|
||||||
use PhpParser\Node\Expr;
|
|
||||||
|
|
||||||
class NameResolverTest extends \PHPUnit_Framework_TestCase
|
class NameResolverTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
@ -118,8 +118,8 @@ namespace {
|
|||||||
new \Hallo\Bar();
|
new \Hallo\Bar();
|
||||||
new \Bar();
|
new \Bar();
|
||||||
new \Bar();
|
new \Bar();
|
||||||
bar();
|
\bar();
|
||||||
hi();
|
\hi();
|
||||||
\Hallo\bar();
|
\Hallo\bar();
|
||||||
\foo\bar();
|
\foo\bar();
|
||||||
\bar();
|
\bar();
|
||||||
@ -278,7 +278,7 @@ EOC;
|
|||||||
$this->assertEquals($stmts, $traverser->traverse($stmts));
|
$this->assertEquals($stmts, $traverser->traverse($stmts));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAddNamespacedName() {
|
public function testAddDeclarationNamespacedName() {
|
||||||
$nsStmts = array(
|
$nsStmts = array(
|
||||||
new Stmt\Class_('A'),
|
new Stmt\Class_('A'),
|
||||||
new Stmt\Interface_('B'),
|
new Stmt\Interface_('B'),
|
||||||
@ -310,6 +310,29 @@ EOC;
|
|||||||
$this->assertObjectNotHasAttribute('namespacedName', $stmts[0]->stmts[5]->class);
|
$this->assertObjectNotHasAttribute('namespacedName', $stmts[0]->stmts[5]->class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testAddRuntimeResolvedNamespacedName() {
|
||||||
|
$stmts = array(
|
||||||
|
new Stmt\Namespace_(new Name('NS'), array(
|
||||||
|
new Expr\FuncCall(new Name('foo')),
|
||||||
|
new Expr\ConstFetch(new Name('FOO')),
|
||||||
|
)),
|
||||||
|
new Stmt\Namespace_(null, array(
|
||||||
|
new Expr\FuncCall(new Name('foo')),
|
||||||
|
new Expr\ConstFetch(new Name('FOO')),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
$traverser = new PhpParser\NodeTraverser;
|
||||||
|
$traverser->addVisitor(new NameResolver);
|
||||||
|
$stmts = $traverser->traverse($stmts);
|
||||||
|
|
||||||
|
$this->assertSame('NS\\foo', (string) $stmts[0]->stmts[0]->name->getAttribute('namespacedName'));
|
||||||
|
$this->assertSame('NS\\FOO', (string) $stmts[0]->stmts[1]->name->getAttribute('namespacedName'));
|
||||||
|
|
||||||
|
$this->assertFalse($stmts[1]->stmts[0]->name->hasAttribute('namespacedName'));
|
||||||
|
$this->assertFalse($stmts[1]->stmts[1]->name->hasAttribute('namespacedName'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider provideTestError
|
* @dataProvider provideTestError
|
||||||
*/
|
*/
|
||||||
|
@ -4,10 +4,10 @@ namespace PhpParser\Parser;
|
|||||||
|
|
||||||
use PhpParser\Error;
|
use PhpParser\Error;
|
||||||
use PhpParser\Lexer;
|
use PhpParser\Lexer;
|
||||||
use PhpParser\Node\Scalar\LNumber;
|
|
||||||
use PhpParser\ParserTest;
|
|
||||||
use PhpParser\Node\Expr;
|
use PhpParser\Node\Expr;
|
||||||
|
use PhpParser\Node\Scalar\LNumber;
|
||||||
use PhpParser\Node\Stmt;
|
use PhpParser\Node\Stmt;
|
||||||
|
use PhpParser\ParserTest;
|
||||||
|
|
||||||
require_once __DIR__ . '/../ParserTest.php';
|
require_once __DIR__ . '/../ParserTest.php';
|
||||||
|
|
||||||
@ -30,7 +30,6 @@ class MultipleTest extends ParserTest {
|
|||||||
/** @dataProvider provideTestParse */
|
/** @dataProvider provideTestParse */
|
||||||
public function testParse($code, Multiple $parser, $expected) {
|
public function testParse($code, Multiple $parser, $expected) {
|
||||||
$this->assertEquals($expected, $parser->parse($code));
|
$this->assertEquals($expected, $parser->parse($code));
|
||||||
$this->assertSame([], $parser->getErrors());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function provideTestParse() {
|
public function provideTestParse() {
|
||||||
@ -92,22 +91,4 @@ class MultipleTest extends ParserTest {
|
|||||||
$parser = new Multiple([$parserA, $parserB]);
|
$parser = new Multiple([$parserA, $parserB]);
|
||||||
$parser->parse('dummy');
|
$parser->parse('dummy');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetErrors() {
|
|
||||||
$errorsA = [new Error('A1'), new Error('A2')];
|
|
||||||
$parserA = $this->getMockBuilder('PhpParser\Parser')->getMock();
|
|
||||||
$parserA->expects($this->at(0))->method('parse');
|
|
||||||
$parserA->expects($this->at(1))
|
|
||||||
->method('getErrors')->will($this->returnValue($errorsA));
|
|
||||||
|
|
||||||
$errorsB = [new Error('B1'), new Error('B2')];
|
|
||||||
$parserB = $this->getMockBuilder('PhpParser\Parser')->getMock();
|
|
||||||
$parserB->expects($this->at(0))->method('parse');
|
|
||||||
$parserB->expects($this->at(1))
|
|
||||||
->method('getErrors')->will($this->returnValue($errorsB));
|
|
||||||
|
|
||||||
$parser = new Multiple([$parserA, $parserB]);
|
|
||||||
$parser->parse('dummy');
|
|
||||||
$this->assertSame($errorsA, $parser->getErrors());
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -30,6 +30,15 @@ abstract class ParserTest extends \PHPUnit_Framework_TestCase
|
|||||||
$parser->parse('<?php use foo as self;');
|
$parser->parse('<?php use foo as self;');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \PhpParser\Error
|
||||||
|
* @expectedExceptionMessage Unterminated comment on line 1
|
||||||
|
*/
|
||||||
|
public function testParserThrowsLexerError() {
|
||||||
|
$parser = $this->getParser(new Lexer());
|
||||||
|
$parser->parse('<?php /*');
|
||||||
|
}
|
||||||
|
|
||||||
public function testAttributeAssignment() {
|
public function testAttributeAssignment() {
|
||||||
$lexer = new Lexer(array(
|
$lexer = new Lexer(array(
|
||||||
'usedAttributes' => array(
|
'usedAttributes' => array(
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace PhpParser\Unserializer;
|
namespace PhpParser\Unserializer;
|
||||||
|
|
||||||
use PhpParser\Node\Scalar;
|
|
||||||
use PhpParser\Comment;
|
use PhpParser\Comment;
|
||||||
|
use PhpParser\Node\Scalar;
|
||||||
|
|
||||||
class XMLTest extends \PHPUnit_Framework_TestCase
|
class XMLTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
|
124
test/code/parser/errorHandling/lexerErrors.test
Normal file
124
test/code/parser/errorHandling/lexerErrors.test
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
Lexer errors
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$a = 42;
|
||||||
|
/*
|
||||||
|
$b = 24;
|
||||||
|
-----
|
||||||
|
Unterminated comment from 4:1 to 5:9
|
||||||
|
array(
|
||||||
|
0: Expr_Assign(
|
||||||
|
var: Expr_Variable(
|
||||||
|
name: a
|
||||||
|
)
|
||||||
|
expr: Scalar_LNumber(
|
||||||
|
value: 42
|
||||||
|
)
|
||||||
|
)
|
||||||
|
1: Stmt_Nop(
|
||||||
|
comments: array(
|
||||||
|
0: /*
|
||||||
|
$b = 24;
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$a = 42;
|
||||||
|
@@{ "\1" }@@
|
||||||
|
$b = 24;
|
||||||
|
-----
|
||||||
|
Unexpected character "@@{ "\1" }@@" (ASCII 1) from 4:1 to 4:1
|
||||||
|
array(
|
||||||
|
0: Expr_Assign(
|
||||||
|
var: Expr_Variable(
|
||||||
|
name: a
|
||||||
|
)
|
||||||
|
expr: Scalar_LNumber(
|
||||||
|
value: 42
|
||||||
|
)
|
||||||
|
)
|
||||||
|
1: Expr_Assign(
|
||||||
|
var: Expr_Variable(
|
||||||
|
name: b
|
||||||
|
)
|
||||||
|
expr: Scalar_LNumber(
|
||||||
|
value: 24
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$a = 42;
|
||||||
|
@@{ "\0" }@@
|
||||||
|
$b = 24;
|
||||||
|
-----
|
||||||
|
Unexpected null byte from 4:1 to 4:1
|
||||||
|
array(
|
||||||
|
0: Expr_Assign(
|
||||||
|
var: Expr_Variable(
|
||||||
|
name: a
|
||||||
|
)
|
||||||
|
expr: Scalar_LNumber(
|
||||||
|
value: 42
|
||||||
|
)
|
||||||
|
)
|
||||||
|
1: Expr_Assign(
|
||||||
|
var: Expr_Variable(
|
||||||
|
name: b
|
||||||
|
)
|
||||||
|
expr: Scalar_LNumber(
|
||||||
|
value: 24
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$a = 1;
|
||||||
|
@@{ "\1" }@@
|
||||||
|
$b = 2;
|
||||||
|
@@{ "\2" }@@
|
||||||
|
$c = 3;
|
||||||
|
-----
|
||||||
|
Unexpected character "@@{ "\1" }@@" (ASCII 1) from 4:1 to 4:1
|
||||||
|
Unexpected character "@@{ "\2" }@@" (ASCII 2) from 6:1 to 6:1
|
||||||
|
array(
|
||||||
|
0: Expr_Assign(
|
||||||
|
var: Expr_Variable(
|
||||||
|
name: a
|
||||||
|
)
|
||||||
|
expr: Scalar_LNumber(
|
||||||
|
value: 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
1: Expr_Assign(
|
||||||
|
var: Expr_Variable(
|
||||||
|
name: b
|
||||||
|
)
|
||||||
|
expr: Scalar_LNumber(
|
||||||
|
value: 2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
2: Expr_Assign(
|
||||||
|
var: Expr_Variable(
|
||||||
|
name: c
|
||||||
|
)
|
||||||
|
expr: Scalar_LNumber(
|
||||||
|
value: 3
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
|
||||||
|
if ($b) {
|
||||||
|
$a = 1;
|
||||||
|
/* unterminated
|
||||||
|
}
|
||||||
|
-----
|
||||||
|
Unterminated comment from 5:5 to 6:2
|
||||||
|
Syntax error, unexpected EOF from 6:2 to 6:2
|
@ -245,13 +245,14 @@ Syntax error, unexpected EOF from 8:12 to 8:12
|
|||||||
$foo->
|
$foo->
|
||||||
;
|
;
|
||||||
-----
|
-----
|
||||||
Syntax error, unexpected ';' from 3:1 to 3:1
|
!!positions
|
||||||
|
Syntax error, unexpected ';', expecting T_STRING or T_VARIABLE or '{' or '$' from 3:1 to 3:1
|
||||||
array(
|
array(
|
||||||
0: Expr_PropertyFetch(
|
0: Expr_PropertyFetch[2:1 - 3:1](
|
||||||
var: Expr_Variable(
|
var: Expr_Variable[2:1 - 2:4](
|
||||||
name: foo
|
name: foo
|
||||||
)
|
)
|
||||||
name: Expr_Error(
|
name: Expr_Error[3:1 - 3:1](
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -261,22 +262,114 @@ function foo() {
|
|||||||
$bar->
|
$bar->
|
||||||
}
|
}
|
||||||
-----
|
-----
|
||||||
Syntax error, unexpected '}' from 4:1 to 4:1
|
!!positions
|
||||||
|
Syntax error, unexpected '}', expecting T_STRING or T_VARIABLE or '{' or '$' from 4:1 to 4:1
|
||||||
array(
|
array(
|
||||||
0: Stmt_Function(
|
0: Stmt_Function[2:1 - 4:1](
|
||||||
byRef: false
|
byRef: false
|
||||||
name: foo
|
name: foo
|
||||||
params: array(
|
params: array(
|
||||||
)
|
)
|
||||||
returnType: null
|
returnType: null
|
||||||
stmts: array(
|
stmts: array(
|
||||||
0: Expr_PropertyFetch(
|
0: Expr_PropertyFetch[3:5 - 4:1](
|
||||||
var: Expr_Variable(
|
var: Expr_Variable[3:5 - 3:8](
|
||||||
name: bar
|
name: bar
|
||||||
)
|
)
|
||||||
name: Expr_Error(
|
name: Expr_Error[4:1 - 4:1](
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
new T
|
||||||
|
-----
|
||||||
|
Syntax error, unexpected EOF from 2:6 to 2:6
|
||||||
|
array(
|
||||||
|
0: Expr_New(
|
||||||
|
class: Name(
|
||||||
|
parts: array(
|
||||||
|
0: T
|
||||||
|
)
|
||||||
|
)
|
||||||
|
args: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
new
|
||||||
|
-----
|
||||||
|
!!php7,positions
|
||||||
|
Syntax error, unexpected EOF from 2:4 to 2:4
|
||||||
|
array(
|
||||||
|
0: Expr_New[2:1 - 2:4](
|
||||||
|
class: Expr_Error[2:4 - 2:4](
|
||||||
|
)
|
||||||
|
args: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
$foo instanceof
|
||||||
|
-----
|
||||||
|
!!php7
|
||||||
|
Syntax error, unexpected EOF from 2:16 to 2:16
|
||||||
|
array(
|
||||||
|
0: Expr_Instanceof(
|
||||||
|
expr: Expr_Variable(
|
||||||
|
name: foo
|
||||||
|
)
|
||||||
|
class: Expr_Error(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
$
|
||||||
|
-----
|
||||||
|
!!php7
|
||||||
|
Syntax error, unexpected EOF, expecting T_VARIABLE or '{' or '$' from 2:2 to 2:2
|
||||||
|
array(
|
||||||
|
0: Expr_Variable(
|
||||||
|
name: Expr_Error(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
Foo::$
|
||||||
|
-----
|
||||||
|
!!php7
|
||||||
|
Syntax error, unexpected EOF, expecting T_VARIABLE or '{' or '$' from 2:7 to 2:7
|
||||||
|
array(
|
||||||
|
0: Expr_StaticPropertyFetch(
|
||||||
|
class: Name(
|
||||||
|
parts: array(
|
||||||
|
0: Foo
|
||||||
|
)
|
||||||
|
)
|
||||||
|
name: Expr_Error(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
Foo::
|
||||||
|
-----
|
||||||
|
!!php7
|
||||||
|
Syntax error, unexpected EOF from 2:6 to 2:6
|
||||||
|
array(
|
||||||
|
0: Expr_ClassConstFetch(
|
||||||
|
class: Name(
|
||||||
|
parts: array(
|
||||||
|
0: Foo
|
||||||
|
)
|
||||||
|
)
|
||||||
|
name: Expr_Error(
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
@ -3,6 +3,21 @@ New without a class
|
|||||||
<?php
|
<?php
|
||||||
new;
|
new;
|
||||||
-----
|
-----
|
||||||
|
!!php5
|
||||||
Syntax error, unexpected ';' from 2:4 to 2:4
|
Syntax error, unexpected ';' from 2:4 to 2:4
|
||||||
array(
|
array(
|
||||||
)
|
)
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
new;
|
||||||
|
-----
|
||||||
|
!!php7
|
||||||
|
Syntax error, unexpected ';' from 2:4 to 2:4
|
||||||
|
array(
|
||||||
|
0: Expr_New(
|
||||||
|
class: Expr_Error(
|
||||||
|
)
|
||||||
|
args: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
@ -5,6 +5,11 @@ Invalid octal literals
|
|||||||
-----
|
-----
|
||||||
!!php7
|
!!php7
|
||||||
Invalid numeric literal from 2:1 to 2:4
|
Invalid numeric literal from 2:1 to 2:4
|
||||||
|
array(
|
||||||
|
0: Scalar_LNumber(
|
||||||
|
value: 0
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php
|
<?php
|
||||||
0787;
|
0787;
|
||||||
|
@ -6,7 +6,29 @@ class A {
|
|||||||
}
|
}
|
||||||
-----
|
-----
|
||||||
!!php7
|
!!php7
|
||||||
Cannot use 'static' as constant modifier on line 3
|
Cannot use 'static' as constant modifier from 3:5 to 3:10
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_ClassConst(
|
||||||
|
flags: MODIFIER_STATIC (8)
|
||||||
|
consts: array(
|
||||||
|
0: Const(
|
||||||
|
name: X
|
||||||
|
value: Scalar_LNumber(
|
||||||
|
value: 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php
|
<?php
|
||||||
class A {
|
class A {
|
||||||
@ -14,7 +36,29 @@ class A {
|
|||||||
}
|
}
|
||||||
-----
|
-----
|
||||||
!!php7
|
!!php7
|
||||||
Cannot use 'abstract' as constant modifier on line 3
|
Cannot use 'abstract' as constant modifier from 3:5 to 3:12
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_ClassConst(
|
||||||
|
flags: MODIFIER_ABSTRACT (16)
|
||||||
|
consts: array(
|
||||||
|
0: Const(
|
||||||
|
name: X
|
||||||
|
value: Scalar_LNumber(
|
||||||
|
value: 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php
|
<?php
|
||||||
class A {
|
class A {
|
||||||
@ -22,11 +66,56 @@ class A {
|
|||||||
}
|
}
|
||||||
-----
|
-----
|
||||||
!!php7
|
!!php7
|
||||||
Cannot use 'final' as constant modifier on line 3
|
Cannot use 'final' as constant modifier from 3:5 to 3:9
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_ClassConst(
|
||||||
|
flags: MODIFIER_FINAL (32)
|
||||||
|
consts: array(
|
||||||
|
0: Const(
|
||||||
|
name: X
|
||||||
|
value: Scalar_LNumber(
|
||||||
|
value: 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php
|
<?php
|
||||||
class A {
|
class A {
|
||||||
public public const X = 1;
|
public public const X = 1;
|
||||||
}
|
}
|
||||||
-----
|
-----
|
||||||
Multiple access type modifiers are not allowed on line 3
|
!!php7
|
||||||
|
Multiple access type modifiers are not allowed from 3:12 to 3:17
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_ClassConst(
|
||||||
|
flags: MODIFIER_PUBLIC (1)
|
||||||
|
consts: array(
|
||||||
|
0: Const(
|
||||||
|
name: X
|
||||||
|
value: Scalar_LNumber(
|
||||||
|
value: 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
@ -2,27 +2,148 @@ Invalid modifier combination
|
|||||||
-----
|
-----
|
||||||
<?php class A { public public $a; }
|
<?php class A { public public $a; }
|
||||||
-----
|
-----
|
||||||
Multiple access type modifiers are not allowed on line 1
|
Multiple access type modifiers are not allowed from 1:24 to 1:29
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_Property(
|
||||||
|
flags: MODIFIER_PUBLIC (1)
|
||||||
|
props: array(
|
||||||
|
0: Stmt_PropertyProperty(
|
||||||
|
name: a
|
||||||
|
default: null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php class A { public protected $a; }
|
<?php class A { public protected $a; }
|
||||||
-----
|
-----
|
||||||
Multiple access type modifiers are not allowed on line 1
|
Multiple access type modifiers are not allowed from 1:24 to 1:32
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_Property(
|
||||||
|
flags: MODIFIER_PUBLIC | MODIFIER_PROTECTED (3)
|
||||||
|
props: array(
|
||||||
|
0: Stmt_PropertyProperty(
|
||||||
|
name: a
|
||||||
|
default: null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php class A { abstract abstract a(); }
|
<?php class A { abstract abstract function a(); }
|
||||||
-----
|
-----
|
||||||
Multiple abstract modifiers are not allowed on line 1
|
Multiple abstract modifiers are not allowed from 1:26 to 1:33
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_ClassMethod(
|
||||||
|
flags: MODIFIER_ABSTRACT (16)
|
||||||
|
byRef: false
|
||||||
|
name: a
|
||||||
|
params: array(
|
||||||
|
)
|
||||||
|
returnType: null
|
||||||
|
stmts: null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php class A { static static $a; }
|
<?php class A { static static $a; }
|
||||||
-----
|
-----
|
||||||
Multiple static modifiers are not allowed on line 1
|
Multiple static modifiers are not allowed from 1:24 to 1:29
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_Property(
|
||||||
|
flags: MODIFIER_STATIC (8)
|
||||||
|
props: array(
|
||||||
|
0: Stmt_PropertyProperty(
|
||||||
|
name: a
|
||||||
|
default: null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php class A { final final a() {} }
|
<?php class A { final final function a() {} }
|
||||||
-----
|
-----
|
||||||
Multiple final modifiers are not allowed on line 1
|
Multiple final modifiers are not allowed from 1:23 to 1:27
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_ClassMethod(
|
||||||
|
flags: MODIFIER_FINAL (32)
|
||||||
|
byRef: false
|
||||||
|
name: a
|
||||||
|
params: array(
|
||||||
|
)
|
||||||
|
returnType: null
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php class A { abstract final a(); }
|
<?php class A { abstract final function a(); }
|
||||||
-----
|
-----
|
||||||
Cannot use the final modifier on an abstract class member on line 1
|
Cannot use the final modifier on an abstract class member from 1:26 to 1:30
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_ClassMethod(
|
||||||
|
flags: MODIFIER_ABSTRACT | MODIFIER_FINAL (48)
|
||||||
|
byRef: false
|
||||||
|
name: a
|
||||||
|
params: array(
|
||||||
|
)
|
||||||
|
returnType: null
|
||||||
|
stmts: null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php abstract final class A { }
|
<?php abstract final class A { }
|
||||||
// Type in the partial parse could conceivably be any of 0, 16 or 32
|
// Type in the partial parse could conceivably be any of 0, 16 or 32
|
||||||
@ -47,8 +168,48 @@ array(
|
|||||||
-----
|
-----
|
||||||
<?php class A { abstract $a; }
|
<?php class A { abstract $a; }
|
||||||
-----
|
-----
|
||||||
Properties cannot be declared abstract on line 1
|
Properties cannot be declared abstract from 1:17 to 1:24
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_Property(
|
||||||
|
flags: MODIFIER_ABSTRACT (16)
|
||||||
|
props: array(
|
||||||
|
0: Stmt_PropertyProperty(
|
||||||
|
name: a
|
||||||
|
default: null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php class A { final $a; }
|
<?php class A { final $a; }
|
||||||
-----
|
-----
|
||||||
Properties cannot be declared final on line 1
|
Properties cannot be declared final from 1:17 to 1:21
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_Property(
|
||||||
|
flags: MODIFIER_FINAL (32)
|
||||||
|
props: array(
|
||||||
|
0: Stmt_PropertyProperty(
|
||||||
|
name: a
|
||||||
|
default: null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
@ -2,11 +2,33 @@ Invalid class name
|
|||||||
-----
|
-----
|
||||||
<?php class self {}
|
<?php class self {}
|
||||||
-----
|
-----
|
||||||
Cannot use 'self' as class name as it is reserved on line 1
|
Cannot use 'self' as class name as it is reserved from 1:13 to 1:16
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: self
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php class PARENT {}
|
<?php class PARENT {}
|
||||||
-----
|
-----
|
||||||
Cannot use 'PARENT' as class name as it is reserved on line 1
|
Cannot use 'PARENT' as class name as it is reserved from 1:13 to 1:18
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: PARENT
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php class static {}
|
<?php class static {}
|
||||||
-----
|
-----
|
||||||
@ -17,10 +39,40 @@ array(
|
|||||||
<?php class A extends self {}
|
<?php class A extends self {}
|
||||||
-----
|
-----
|
||||||
Cannot use 'self' as class name as it is reserved from 1:23 to 1:26
|
Cannot use 'self' as class name as it is reserved from 1:23 to 1:26
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: Name(
|
||||||
|
parts: array(
|
||||||
|
0: self
|
||||||
|
)
|
||||||
|
)
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php class A extends PARENT {}
|
<?php class A extends PARENT {}
|
||||||
-----
|
-----
|
||||||
Cannot use 'PARENT' as class name as it is reserved from 1:23 to 1:28
|
Cannot use 'PARENT' as class name as it is reserved from 1:23 to 1:28
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: Name(
|
||||||
|
parts: array(
|
||||||
|
0: PARENT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php class A extends static {}
|
<?php class A extends static {}
|
||||||
-----
|
-----
|
||||||
@ -31,10 +83,42 @@ array(
|
|||||||
<?php class A implements self {}
|
<?php class A implements self {}
|
||||||
-----
|
-----
|
||||||
Cannot use 'self' as interface name as it is reserved from 1:26 to 1:29
|
Cannot use 'self' as interface name as it is reserved from 1:26 to 1:29
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
0: Name(
|
||||||
|
parts: array(
|
||||||
|
0: self
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php class A implements PARENT {}
|
<?php class A implements PARENT {}
|
||||||
-----
|
-----
|
||||||
Cannot use 'PARENT' as interface name as it is reserved from 1:26 to 1:31
|
Cannot use 'PARENT' as interface name as it is reserved from 1:26 to 1:31
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
0: Name(
|
||||||
|
parts: array(
|
||||||
|
0: PARENT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php class A implements static {}
|
<?php class A implements static {}
|
||||||
-----
|
-----
|
||||||
@ -44,11 +128,29 @@ array(
|
|||||||
-----
|
-----
|
||||||
<?php interface self {}
|
<?php interface self {}
|
||||||
-----
|
-----
|
||||||
Cannot use 'self' as class name as it is reserved on line 1
|
Cannot use 'self' as class name as it is reserved from 1:17 to 1:20
|
||||||
|
array(
|
||||||
|
0: Stmt_Interface(
|
||||||
|
name: self
|
||||||
|
extends: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php interface PARENT {}
|
<?php interface PARENT {}
|
||||||
-----
|
-----
|
||||||
Cannot use 'PARENT' as class name as it is reserved on line 1
|
Cannot use 'PARENT' as class name as it is reserved from 1:17 to 1:22
|
||||||
|
array(
|
||||||
|
0: Stmt_Interface(
|
||||||
|
name: PARENT
|
||||||
|
extends: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php interface static {}
|
<?php interface static {}
|
||||||
-----
|
-----
|
||||||
@ -59,10 +161,38 @@ array(
|
|||||||
<?php interface A extends self {}
|
<?php interface A extends self {}
|
||||||
-----
|
-----
|
||||||
Cannot use 'self' as interface name as it is reserved from 1:27 to 1:30
|
Cannot use 'self' as interface name as it is reserved from 1:27 to 1:30
|
||||||
|
array(
|
||||||
|
0: Stmt_Interface(
|
||||||
|
name: A
|
||||||
|
extends: array(
|
||||||
|
0: Name(
|
||||||
|
parts: array(
|
||||||
|
0: self
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php interface A extends PARENT {}
|
<?php interface A extends PARENT {}
|
||||||
-----
|
-----
|
||||||
Cannot use 'PARENT' as interface name as it is reserved from 1:27 to 1:32
|
Cannot use 'PARENT' as interface name as it is reserved from 1:27 to 1:32
|
||||||
|
array(
|
||||||
|
0: Stmt_Interface(
|
||||||
|
name: A
|
||||||
|
extends: array(
|
||||||
|
0: Name(
|
||||||
|
parts: array(
|
||||||
|
0: PARENT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php interface A extends static {}
|
<?php interface A extends static {}
|
||||||
-----
|
-----
|
||||||
|
@ -2,24 +2,150 @@ Some special methods cannot be static
|
|||||||
-----
|
-----
|
||||||
<?php class A { static function __construct() {} }
|
<?php class A { static function __construct() {} }
|
||||||
-----
|
-----
|
||||||
Constructor __construct() cannot be static on line 1
|
Constructor __construct() cannot be static from 1:17 to 1:22
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_ClassMethod(
|
||||||
|
flags: MODIFIER_STATIC (8)
|
||||||
|
byRef: false
|
||||||
|
name: __construct
|
||||||
|
params: array(
|
||||||
|
)
|
||||||
|
returnType: null
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php class A { static function __destruct() {} }
|
<?php class A { static function __destruct() {} }
|
||||||
-----
|
-----
|
||||||
Destructor __destruct() cannot be static on line 1
|
Destructor __destruct() cannot be static from 1:17 to 1:22
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_ClassMethod(
|
||||||
|
flags: MODIFIER_STATIC (8)
|
||||||
|
byRef: false
|
||||||
|
name: __destruct
|
||||||
|
params: array(
|
||||||
|
)
|
||||||
|
returnType: null
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php class A { static function __clone() {} }
|
<?php class A { static function __clone() {} }
|
||||||
-----
|
-----
|
||||||
Clone method __clone() cannot be static on line 1
|
Clone method __clone() cannot be static from 1:17 to 1:22
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_ClassMethod(
|
||||||
|
flags: MODIFIER_STATIC (8)
|
||||||
|
byRef: false
|
||||||
|
name: __clone
|
||||||
|
params: array(
|
||||||
|
)
|
||||||
|
returnType: null
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php class A { static function __CONSTRUCT() {} }
|
<?php class A { static function __CONSTRUCT() {} }
|
||||||
-----
|
-----
|
||||||
Constructor __CONSTRUCT() cannot be static on line 1
|
Constructor __CONSTRUCT() cannot be static from 1:17 to 1:22
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_ClassMethod(
|
||||||
|
flags: MODIFIER_STATIC (8)
|
||||||
|
byRef: false
|
||||||
|
name: __CONSTRUCT
|
||||||
|
params: array(
|
||||||
|
)
|
||||||
|
returnType: null
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php class A { static function __Destruct() {} }
|
<?php class A { static function __Destruct() {} }
|
||||||
-----
|
-----
|
||||||
Destructor __Destruct() cannot be static on line 1
|
Destructor __Destruct() cannot be static from 1:17 to 1:22
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_ClassMethod(
|
||||||
|
flags: MODIFIER_STATIC (8)
|
||||||
|
byRef: false
|
||||||
|
name: __Destruct
|
||||||
|
params: array(
|
||||||
|
)
|
||||||
|
returnType: null
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php class A { static function __cLoNe() {} }
|
<?php class A { static function __cLoNe() {} }
|
||||||
-----
|
-----
|
||||||
Clone method __cLoNe() cannot be static on line 1
|
Clone method __cLoNe() cannot be static from 1:17 to 1:22
|
||||||
|
array(
|
||||||
|
0: Stmt_Class(
|
||||||
|
flags: 0
|
||||||
|
name: A
|
||||||
|
extends: null
|
||||||
|
implements: array(
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_ClassMethod(
|
||||||
|
flags: MODIFIER_STATIC (8)
|
||||||
|
byRef: false
|
||||||
|
name: __cLoNe
|
||||||
|
params: array(
|
||||||
|
)
|
||||||
|
returnType: null
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
@ -4,3 +4,24 @@ Invalid variadic function
|
|||||||
function foo(...$foo = []) {}
|
function foo(...$foo = []) {}
|
||||||
-----
|
-----
|
||||||
Variadic parameter cannot have a default value from 2:24 to 2:25
|
Variadic parameter cannot have a default value from 2:24 to 2:25
|
||||||
|
array(
|
||||||
|
0: Stmt_Function(
|
||||||
|
byRef: false
|
||||||
|
name: foo
|
||||||
|
params: array(
|
||||||
|
0: Param(
|
||||||
|
type: null
|
||||||
|
byRef: false
|
||||||
|
variadic: true
|
||||||
|
name: foo
|
||||||
|
default: Expr_Array(
|
||||||
|
items: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
returnType: null
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
28
test/code/parser/stmt/namespace/groupUsePositions.test
Normal file
28
test/code/parser/stmt/namespace/groupUsePositions.test
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
Ensure correct file position attributes for group use prefix
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
use Foo\Bar\{Baz};
|
||||||
|
-----
|
||||||
|
!!positions
|
||||||
|
array(
|
||||||
|
0: Stmt_GroupUse[2:1 - 2:17](
|
||||||
|
type: TYPE_UNKNOWN (0)
|
||||||
|
prefix: Name[2:5 - 2:11](
|
||||||
|
parts: array(
|
||||||
|
0: Foo
|
||||||
|
1: Bar
|
||||||
|
)
|
||||||
|
)
|
||||||
|
uses: array(
|
||||||
|
0: Stmt_UseUse[2:14 - 2:16](
|
||||||
|
type: TYPE_NORMAL (1)
|
||||||
|
name: Name[2:14 - 2:16](
|
||||||
|
parts: array(
|
||||||
|
0: Baz
|
||||||
|
)
|
||||||
|
)
|
||||||
|
alias: Baz
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
@ -3,10 +3,32 @@ Invalid namespace names
|
|||||||
<?php namespace self;
|
<?php namespace self;
|
||||||
-----
|
-----
|
||||||
Cannot use 'self' as namespace name from 1:17 to 1:20
|
Cannot use 'self' as namespace name from 1:17 to 1:20
|
||||||
|
array(
|
||||||
|
0: Stmt_Namespace(
|
||||||
|
name: Name(
|
||||||
|
parts: array(
|
||||||
|
0: self
|
||||||
|
)
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php namespace PARENT;
|
<?php namespace PARENT;
|
||||||
-----
|
-----
|
||||||
Cannot use 'PARENT' as namespace name from 1:17 to 1:22
|
Cannot use 'PARENT' as namespace name from 1:17 to 1:22
|
||||||
|
array(
|
||||||
|
0: Stmt_Namespace(
|
||||||
|
name: Name(
|
||||||
|
parts: array(
|
||||||
|
0: PARENT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php namespace static;
|
<?php namespace static;
|
||||||
-----
|
-----
|
||||||
@ -16,11 +38,43 @@ array(
|
|||||||
-----
|
-----
|
||||||
<?php use A as self;
|
<?php use A as self;
|
||||||
-----
|
-----
|
||||||
Cannot use A as self because 'self' is a special class name on line 1
|
Cannot use A as self because 'self' is a special class name from 1:16 to 1:19
|
||||||
|
array(
|
||||||
|
0: Stmt_Use(
|
||||||
|
type: TYPE_NORMAL (1)
|
||||||
|
uses: array(
|
||||||
|
0: Stmt_UseUse(
|
||||||
|
type: TYPE_UNKNOWN (0)
|
||||||
|
name: Name(
|
||||||
|
parts: array(
|
||||||
|
0: A
|
||||||
|
)
|
||||||
|
)
|
||||||
|
alias: self
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php use B as PARENT;
|
<?php use B as PARENT;
|
||||||
-----
|
-----
|
||||||
Cannot use B as PARENT because 'PARENT' is a special class name on line 1
|
Cannot use B as PARENT because 'PARENT' is a special class name from 1:16 to 1:21
|
||||||
|
array(
|
||||||
|
0: Stmt_Use(
|
||||||
|
type: TYPE_NORMAL (1)
|
||||||
|
uses: array(
|
||||||
|
0: Stmt_UseUse(
|
||||||
|
type: TYPE_UNKNOWN (0)
|
||||||
|
name: Name(
|
||||||
|
parts: array(
|
||||||
|
0: B
|
||||||
|
)
|
||||||
|
)
|
||||||
|
alias: PARENT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php use C as static;
|
<?php use C as static;
|
||||||
-----
|
-----
|
||||||
|
@ -2,12 +2,102 @@ Namespace types cannot be mixed
|
|||||||
-----
|
-----
|
||||||
<?php
|
<?php
|
||||||
namespace A;
|
namespace A;
|
||||||
namespace B {}
|
echo 1;
|
||||||
|
namespace B {
|
||||||
|
echo 2;
|
||||||
|
}
|
||||||
|
echo 3;
|
||||||
-----
|
-----
|
||||||
Cannot mix bracketed namespace declarations with unbracketed namespace declarations on line 3
|
Cannot mix bracketed namespace declarations with unbracketed namespace declarations on line 4
|
||||||
|
array(
|
||||||
|
0: Stmt_Namespace(
|
||||||
|
name: Name(
|
||||||
|
parts: array(
|
||||||
|
0: A
|
||||||
|
)
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_Echo(
|
||||||
|
exprs: array(
|
||||||
|
0: Scalar_LNumber(
|
||||||
|
value: 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
1: Stmt_Namespace(
|
||||||
|
name: Name(
|
||||||
|
parts: array(
|
||||||
|
0: B
|
||||||
|
)
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_Echo(
|
||||||
|
exprs: array(
|
||||||
|
0: Scalar_LNumber(
|
||||||
|
value: 2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
2: Stmt_Echo(
|
||||||
|
exprs: array(
|
||||||
|
0: Scalar_LNumber(
|
||||||
|
value: 3
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php
|
<?php
|
||||||
namespace A {}
|
namespace A {
|
||||||
|
echo 1;
|
||||||
|
}
|
||||||
|
echo 2;
|
||||||
namespace B;
|
namespace B;
|
||||||
|
echo 3;
|
||||||
-----
|
-----
|
||||||
Cannot mix bracketed namespace declarations with unbracketed namespace declarations on line 3
|
Cannot mix bracketed namespace declarations with unbracketed namespace declarations on line 6
|
||||||
|
array(
|
||||||
|
0: Stmt_Namespace(
|
||||||
|
name: Name(
|
||||||
|
parts: array(
|
||||||
|
0: A
|
||||||
|
)
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_Echo(
|
||||||
|
exprs: array(
|
||||||
|
0: Scalar_LNumber(
|
||||||
|
value: 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
1: Stmt_Echo(
|
||||||
|
exprs: array(
|
||||||
|
0: Scalar_LNumber(
|
||||||
|
value: 2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
2: Stmt_Namespace(
|
||||||
|
name: Name(
|
||||||
|
parts: array(
|
||||||
|
0: B
|
||||||
|
)
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_Echo(
|
||||||
|
exprs: array(
|
||||||
|
0: Scalar_LNumber(
|
||||||
|
value: 3
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
@ -8,3 +8,23 @@ namespace A {
|
|||||||
}
|
}
|
||||||
-----
|
-----
|
||||||
Namespace declarations cannot be nested from 3:5 to 5:5
|
Namespace declarations cannot be nested from 3:5 to 5:5
|
||||||
|
array(
|
||||||
|
0: Stmt_Namespace(
|
||||||
|
name: Name(
|
||||||
|
parts: array(
|
||||||
|
0: A
|
||||||
|
)
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_Namespace(
|
||||||
|
name: Name(
|
||||||
|
parts: array(
|
||||||
|
0: B
|
||||||
|
)
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
@ -2,19 +2,104 @@ There (mostly) can't be statements outside of namespaces
|
|||||||
-----
|
-----
|
||||||
<?php
|
<?php
|
||||||
echo 1;
|
echo 1;
|
||||||
|
echo 2;
|
||||||
namespace A;
|
namespace A;
|
||||||
-----
|
-----
|
||||||
Namespace declaration statement has to be the very first statement in the script on line 3
|
Namespace declaration statement has to be the very first statement in the script on line 4
|
||||||
|
array(
|
||||||
|
0: Stmt_Echo(
|
||||||
|
exprs: array(
|
||||||
|
0: Scalar_LNumber(
|
||||||
|
value: 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
1: Stmt_Echo(
|
||||||
|
exprs: array(
|
||||||
|
0: Scalar_LNumber(
|
||||||
|
value: 2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
2: Stmt_Namespace(
|
||||||
|
name: Name(
|
||||||
|
parts: array(
|
||||||
|
0: A
|
||||||
|
)
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php
|
<?php
|
||||||
namespace A {}
|
namespace A {}
|
||||||
echo 1;
|
echo 1;
|
||||||
-----
|
-----
|
||||||
No code may exist outside of namespace {} on line 3
|
No code may exist outside of namespace {} from 3:1 to 3:7
|
||||||
|
array(
|
||||||
|
0: Stmt_Namespace(
|
||||||
|
name: Name(
|
||||||
|
parts: array(
|
||||||
|
0: A
|
||||||
|
)
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
1: Stmt_Echo(
|
||||||
|
exprs: array(
|
||||||
|
0: Scalar_LNumber(
|
||||||
|
value: 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
-----
|
-----
|
||||||
<?php
|
<?php
|
||||||
namespace A {}
|
namespace A {}
|
||||||
declare(ticks=1);
|
declare(ticks=1);
|
||||||
|
foo();
|
||||||
namespace B {}
|
namespace B {}
|
||||||
-----
|
-----
|
||||||
No code may exist outside of namespace {} on line 3
|
No code may exist outside of namespace {} from 3:1 to 3:17
|
||||||
|
array(
|
||||||
|
0: Stmt_Namespace(
|
||||||
|
name: Name(
|
||||||
|
parts: array(
|
||||||
|
0: A
|
||||||
|
)
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
1: Stmt_Declare(
|
||||||
|
declares: array(
|
||||||
|
0: Stmt_DeclareDeclare(
|
||||||
|
key: ticks
|
||||||
|
value: Scalar_LNumber(
|
||||||
|
value: 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
stmts: null
|
||||||
|
)
|
||||||
|
2: Expr_FuncCall(
|
||||||
|
name: Name(
|
||||||
|
parts: array(
|
||||||
|
0: foo
|
||||||
|
)
|
||||||
|
)
|
||||||
|
args: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
3: Stmt_Namespace(
|
||||||
|
name: Name(
|
||||||
|
parts: array(
|
||||||
|
0: B
|
||||||
|
)
|
||||||
|
)
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
@ -2,6 +2,26 @@ Cannot use try without catch or finally
|
|||||||
-----
|
-----
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
try { }
|
try {
|
||||||
|
foo();
|
||||||
|
}
|
||||||
-----
|
-----
|
||||||
Cannot use try without catch or finally on line 3
|
Cannot use try without catch or finally from 3:1 to 5:1
|
||||||
|
array(
|
||||||
|
0: Stmt_TryCatch(
|
||||||
|
stmts: array(
|
||||||
|
0: Expr_FuncCall(
|
||||||
|
name: Name(
|
||||||
|
parts: array(
|
||||||
|
0: foo
|
||||||
|
)
|
||||||
|
)
|
||||||
|
args: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
catches: array(
|
||||||
|
)
|
||||||
|
finally: null
|
||||||
|
)
|
||||||
|
)
|
Reference in New Issue
Block a user