mirror of
https://github.com/nikic/PHP-Parser.git
synced 2025-07-14 10:56:55 +02:00
Compare commits
79 Commits
Author | SHA1 | Date | |
---|---|---|---|
220f5b3661 | |||
ad38d47247 | |||
6de6ede1cb | |||
20412455fc | |||
103f95d560 | |||
78f289c51f | |||
0f585f0e95 | |||
0ed4c8949a | |||
8a21ec3182 | |||
4d36e9c16f | |||
4e1b88d21c | |||
d4d4e3e155 | |||
32cdab9a03 | |||
c2403aa729 | |||
051ad218f8 | |||
1bcbb2179f | |||
05c01865ea | |||
2a5e81f7ca | |||
e453389866 | |||
402b6cf345 | |||
54103d8387 | |||
a6303e50c9 | |||
44fc92194b | |||
844c228bf2 | |||
6d2584bdf1 | |||
21a61ece15 | |||
8f8e47b6c1 | |||
0aad06bce3 | |||
80a680bf59 | |||
cfc54e30a4 | |||
05e84f7201 | |||
73ccbabbe7 | |||
19526a33fb | |||
1d0748ad35 | |||
c9e5a13d68 | |||
ba788aa98b | |||
11e2663a5b | |||
11e2dcd96c | |||
0ffddce52d | |||
6bb5176bc4 | |||
cad49f8ed3 | |||
570e980a20 | |||
a50b4310f7 | |||
8863f92b58 | |||
3182d12b55 | |||
1df465cd90 | |||
f59bbe44bf | |||
2e11deec46 | |||
a4fe65bf60 | |||
e072fd2c30 | |||
7027899d7f | |||
2f1fd784fe | |||
0ef6c55a3f | |||
8216e878be | |||
617d0220b9 | |||
a951e9e24d | |||
b30e7e73d5 | |||
ff24d1d61a | |||
e55f8c6b30 | |||
3ee592b6aa | |||
3fe2422e34 | |||
2d589921f2 | |||
cdb731fa8b | |||
e727475d08 | |||
34bea19b6e | |||
678ccbe072 | |||
5d83adcc0e | |||
3bf0082455 | |||
d3eb10aca1 | |||
a6e34665fd | |||
f4b835f7d8 | |||
210577fe3c | |||
f09f22760e | |||
d4cb98ae38 | |||
68d2a52b42 | |||
63f8699143 | |||
4122ff3a91 | |||
6f1f206862 | |||
99a24b6a55 |
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -1,5 +1,6 @@
|
|||||||
/.github export-ignore
|
/.github export-ignore
|
||||||
/doc export-ignore
|
/doc export-ignore
|
||||||
|
/grammar export-ignore
|
||||||
/test export-ignore
|
/test export-ignore
|
||||||
/test_old export-ignore
|
/test_old export-ignore
|
||||||
.editorconfig export-ignore
|
.editorconfig export-ignore
|
||||||
|
31
.github/workflows/main.yml
vendored
31
.github/workflows/main.yml
vendored
@ -5,17 +5,17 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
tests_70:
|
tests_71:
|
||||||
runs-on: "ubuntu-latest"
|
runs-on: "ubuntu-latest"
|
||||||
name: "PHP 7.0 Unit Tests"
|
name: "PHP 7.1 Unit Tests"
|
||||||
steps:
|
steps:
|
||||||
- name: "Checkout"
|
- name: "Checkout"
|
||||||
uses: "actions/checkout@v2"
|
uses: "actions/checkout@v3"
|
||||||
- name: "Install PHP"
|
- name: "Install PHP"
|
||||||
uses: "shivammathur/setup-php@v2"
|
uses: "shivammathur/setup-php@v2"
|
||||||
with:
|
with:
|
||||||
coverage: "xdebug"
|
coverage: "xdebug"
|
||||||
php-version: "7.0"
|
php-version: "7.1"
|
||||||
tools: composer:v2
|
tools: composer:v2
|
||||||
- name: "Install dependencies"
|
- name: "Install dependencies"
|
||||||
run: |
|
run: |
|
||||||
@ -34,23 +34,23 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
php-version:
|
php-version:
|
||||||
- "7.1"
|
|
||||||
- "7.2"
|
- "7.2"
|
||||||
- "7.3"
|
- "7.3"
|
||||||
- "7.4"
|
- "7.4"
|
||||||
- "8.0"
|
- "8.0"
|
||||||
- "8.1"
|
- "8.1"
|
||||||
include:
|
- "8.2"
|
||||||
- php-version: "8.1"
|
- "8.3"
|
||||||
flags: "--ignore-platform-req=php"
|
- "8.4"
|
||||||
steps:
|
steps:
|
||||||
- name: "Checkout"
|
- name: "Checkout"
|
||||||
uses: "actions/checkout@v2"
|
uses: "actions/checkout@v3"
|
||||||
- name: "Install PHP"
|
- name: "Install PHP"
|
||||||
uses: "shivammathur/setup-php@v2"
|
uses: "shivammathur/setup-php@v2"
|
||||||
with:
|
with:
|
||||||
coverage: "none"
|
coverage: "none"
|
||||||
php-version: "${{ matrix.php-version }}"
|
php-version: "${{ matrix.php-version }}"
|
||||||
|
ini-file: "development"
|
||||||
tools: composer:v2
|
tools: composer:v2
|
||||||
- name: "Install dependencies"
|
- name: "Install dependencies"
|
||||||
run: "composer update --no-progress --prefer-dist ${{ matrix.flags }}"
|
run: "composer update --no-progress --prefer-dist ${{ matrix.flags }}"
|
||||||
@ -61,30 +61,31 @@ jobs:
|
|||||||
name: "PHP 7.3 Code on PHP 8.0 Integration Tests"
|
name: "PHP 7.3 Code on PHP 8.0 Integration Tests"
|
||||||
steps:
|
steps:
|
||||||
- name: "Checkout"
|
- name: "Checkout"
|
||||||
uses: "actions/checkout@v2"
|
uses: "actions/checkout@v3"
|
||||||
- name: "Install PHP"
|
- name: "Install PHP"
|
||||||
uses: "shivammathur/setup-php@v2"
|
uses: "shivammathur/setup-php@v2"
|
||||||
with:
|
with:
|
||||||
coverage: "none"
|
coverage: "none"
|
||||||
php-version: "8.0"
|
php-version: "8.0"
|
||||||
|
ini-file: "development"
|
||||||
tools: composer:v2
|
tools: composer:v2
|
||||||
- name: "Install PHP 8 dependencies"
|
- name: "Install PHP 8 dependencies"
|
||||||
run: "composer update --no-progress --prefer-dist"
|
run: "composer update --no-progress --prefer-dist"
|
||||||
- name: "Tests"
|
- name: "Tests"
|
||||||
run: "test_old/run-php-src.sh 7.3.21"
|
run: "test_old/run-php-src.sh 7.3.21"
|
||||||
test_old_80_70:
|
test_old_80_71:
|
||||||
runs-on: "ubuntu-latest"
|
runs-on: "ubuntu-latest"
|
||||||
name: "PHP 8.0 Code on PHP 7.0 Integration Tests"
|
name: "PHP 8.1 Code on PHP 7.1 Integration Tests"
|
||||||
steps:
|
steps:
|
||||||
- name: "Checkout"
|
- name: "Checkout"
|
||||||
uses: "actions/checkout@v2"
|
uses: "actions/checkout@v3"
|
||||||
- name: "Install PHP"
|
- name: "Install PHP"
|
||||||
uses: "shivammathur/setup-php@v2"
|
uses: "shivammathur/setup-php@v2"
|
||||||
with:
|
with:
|
||||||
coverage: "none"
|
coverage: "none"
|
||||||
php-version: "7.0"
|
php-version: "7.1"
|
||||||
tools: composer:v2
|
tools: composer:v2
|
||||||
- name: "Install PHP 8 dependencies"
|
- name: "Install PHP 8 dependencies"
|
||||||
run: "composer update --no-progress --prefer-dist"
|
run: "composer update --no-progress --prefer-dist"
|
||||||
- name: "Tests"
|
- name: "Tests"
|
||||||
run: "test_old/run-php-src.sh 8.0.0"
|
run: "test_old/run-php-src.sh 8.1.6"
|
||||||
|
162
CHANGELOG.md
162
CHANGELOG.md
@ -1,7 +1,163 @@
|
|||||||
Version 4.13.2-dev
|
Version 4.19.3 (2024-09-29)
|
||||||
------------------
|
---------------------------
|
||||||
|
|
||||||
Nothing yet.
|
### Fixed
|
||||||
|
|
||||||
|
* Include the trailing semicolon inside `Stmt\GroupUse` nodes, making them consistent with
|
||||||
|
`Stmt\Use_` nodes.
|
||||||
|
* Fixed indentation sometimes becoming negative in formatting-preserving pretty printer, resulting
|
||||||
|
in `ValueError`s.
|
||||||
|
|
||||||
|
Version 4.19.2 (2024-09-17)
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Added support for passing enum values to various builder methods, like `BuilderFactory::val()`.
|
||||||
|
|
||||||
|
Version 4.19.1 (2024-03-17)
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Fixed "Optional parameter before required parameter" deprecation warning introduced in
|
||||||
|
previous version.
|
||||||
|
|
||||||
|
Version 4.19.0 (2024-03-16)
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
* Do not use implicitly nullable parameters, which are deprecated in PHP 8.4.
|
||||||
|
* Remove support for running on PHP 7.0, which does not support explicitly nullable parameters.
|
||||||
|
|
||||||
|
Version 4.18.0 (2023-12-10)
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Added methods `ParserFactory::createForNewestSupportedVersion()` and
|
||||||
|
`ParserFactory::createForHostVersion()` for forward-compatibility with PHP-Parser 5.0.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Fixed missing name resolution of class constant types.
|
||||||
|
* Fixed class members being dropped if an error is encountered while parsing a later class member
|
||||||
|
(when error recovery is enabeld).
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
* The `grammar/` directory has been excluded from exported git archives.
|
||||||
|
|
||||||
|
Version 4.17.1 (2023-08-13)
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Fixed phpdoc mismatches for `ClassConst::$type` introduced in previous release.
|
||||||
|
|
||||||
|
Version 4.17.0 (2023-08-13)
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* [PHP 8.3] Added support for typed class constants.
|
||||||
|
* [PHP 8.3] Added supprot for dynamic class constant fetch.
|
||||||
|
* [PHP 8.3] Added support for readonly anonymous classes.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Fixed missing required parentheses when pretty printing new with an expression class name.
|
||||||
|
* Fixed missing required parentheses when pretty printing `(CONST)::$x` and similar.
|
||||||
|
|
||||||
|
Version 4.16.0 (2023-06-25)
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Added `Name::getParts()` method for forward-compatibility with PHP-Parser 5.
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
* Deprecated direct access to `Name::$parts`, which will be removed in PHP-Parser 5.
|
||||||
|
|
||||||
|
Version 4.15.5 (2023-05-19)
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Added `makePrivate()`, `makeProtected()`, `makePublic()` and `makeReadonly()` methods to
|
||||||
|
`Builder\Param` to allow the creation of promoted parameters.
|
||||||
|
|
||||||
|
Version 4.15.4 (2023-03-05)
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Fixed formatting-preservation for alternative if syntax with trailing comments.
|
||||||
|
|
||||||
|
Version 4.15.3 (2023-01-16)
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Support readonly property with PHP 8.2 DNF type.
|
||||||
|
* Fixed PHP attribute group and PHP-Parser attribute mixup in EnumCase builder.
|
||||||
|
|
||||||
|
Version 4.15.2 (2022-11-12)
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Fixed parsing of large hex float literals that contain an "e" character.
|
||||||
|
* Fixed tests to pass on 32-bit.
|
||||||
|
* Fixed generation of invalid code when using formatting-preserving pretty printer with code that
|
||||||
|
uses inline HTML.
|
||||||
|
|
||||||
|
Version 4.15.1 (2022-09-04)
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Fixed formatting preservation when adding *multiple* attributes to a class/method/etc that
|
||||||
|
previously had none. This fixes a regression in the 4.15.0 release.
|
||||||
|
|
||||||
|
Version 4.15.0 (2022-09-03)
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* PHP 8.2: Added support for `true` type.
|
||||||
|
* PHP 8.2: Added support for DNF types.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Support `readonly` as a function name.
|
||||||
|
* Added `__serialize` and `__unserialize` to magic method list.
|
||||||
|
* Fixed bounds check in `Name::slice()`.
|
||||||
|
* Fixed formatting preservation when adding attributes to a class/method/etc that previously had none.
|
||||||
|
|
||||||
|
Version 4.14.0 (2022-05-31)
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Added support for readonly classes.
|
||||||
|
* Added `rawValue` attribute to `LNumber`, `DNumber` and `String_` nodes, which stores the unparsed
|
||||||
|
value of the literal (e.g. `"1_000"` rather than `1000`).
|
||||||
|
|
||||||
|
Version 4.13.2 (2021-11-30)
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Added builders for enums and enum cases.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* NullsafeMethodCall now extends from CallLike.
|
||||||
|
* The `namespacedName` property populated by the `NameResolver` is now declared on relevant nodes,
|
||||||
|
to avoid a dynamic property deprecation warning with PHP 8.2.
|
||||||
|
|
||||||
Version 4.13.1 (2021-11-03)
|
Version 4.13.1 (2021-11-03)
|
||||||
---------------------------
|
---------------------------
|
||||||
|
@ -3,10 +3,10 @@ PHP Parser
|
|||||||
|
|
||||||
[](https://coveralls.io/github/nikic/PHP-Parser?branch=master)
|
[](https://coveralls.io/github/nikic/PHP-Parser?branch=master)
|
||||||
|
|
||||||
This is a PHP 5.2 to PHP 8.0 parser written in PHP. Its purpose is to simplify static code analysis and
|
This is a PHP 5.2 to PHP 8.2 parser written in PHP. Its purpose is to simplify static code analysis and
|
||||||
manipulation.
|
manipulation.
|
||||||
|
|
||||||
[**Documentation for version 4.x**][doc_master] (stable; for running on PHP >= 7.0; for parsing PHP 5.2 to PHP 8.0).
|
[**Documentation for version 4.x**][doc_4_x] (stable; for running on PHP >= 7.1; for parsing PHP 5.2 to PHP 8.2).
|
||||||
|
|
||||||
[Documentation for version 3.x][doc_3_x] (unsupported; for running on PHP >= 5.5; for parsing PHP 5.2 to PHP 7.2).
|
[Documentation for version 3.x][doc_3_x] (unsupported; for running on PHP >= 5.5; for parsing PHP 5.2 to PHP 7.2).
|
||||||
|
|
||||||
@ -222,4 +222,4 @@ Component documentation:
|
|||||||
* Parent and sibling references
|
* Parent and sibling references
|
||||||
|
|
||||||
[doc_3_x]: https://github.com/nikic/PHP-Parser/tree/3.x/doc
|
[doc_3_x]: https://github.com/nikic/PHP-Parser/tree/3.x/doc
|
||||||
[doc_master]: https://github.com/nikic/PHP-Parser/tree/master/doc
|
[doc_4_x]: https://github.com/nikic/PHP-Parser/tree/4.x/doc
|
||||||
|
@ -13,11 +13,11 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.0",
|
"php": ">=7.1",
|
||||||
"ext-tokenizer": "*"
|
"ext-tokenizer": "*"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0",
|
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
|
||||||
"ircmaxell/php-yacc": "^0.0.7"
|
"ircmaxell/php-yacc": "^0.0.7"
|
||||||
},
|
},
|
||||||
"extra": {
|
"extra": {
|
||||||
|
@ -34,7 +34,7 @@ The parser supports parsing PHP 5.2-8.0, with the following exceptions:
|
|||||||
|
|
||||||
As the parser is based on the tokens returned by `token_get_all` (which is only able to lex the PHP
|
As the parser is based on the tokens returned by `token_get_all` (which is only able to lex the PHP
|
||||||
version it runs on), additionally a wrapper for emulating tokens from newer versions is provided.
|
version it runs on), additionally a wrapper for emulating tokens from newer versions is provided.
|
||||||
This allows to parse PHP 7.4 source code running on PHP 7.0, for example. This emulation is somewhat
|
This allows to parse PHP 7.4 source code running on PHP 7.1, for example. This emulation is somewhat
|
||||||
hacky and not perfect, but it should work well on any sane code.
|
hacky and not perfect, but it should work well on any sane code.
|
||||||
|
|
||||||
What output does it produce?
|
What output does it produce?
|
||||||
|
@ -88,7 +88,7 @@ top_statement:
|
|||||||
$this->checkNamespace($$); }
|
$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; }
|
||||||
| T_CONST constant_declaration_list ';' { $$ = Stmt\Const_[$2]; }
|
| T_CONST constant_declaration_list ';' { $$ = Stmt\Const_[$2]; }
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -98,9 +98,9 @@ use_type:
|
|||||||
;
|
;
|
||||||
|
|
||||||
group_use_declaration:
|
group_use_declaration:
|
||||||
T_USE use_type legacy_namespace_name T_NS_SEPARATOR '{' unprefixed_use_declarations '}'
|
T_USE use_type legacy_namespace_name T_NS_SEPARATOR '{' unprefixed_use_declarations '}' ';'
|
||||||
{ $$ = Stmt\GroupUse[$3, $6, $2]; }
|
{ $$ = Stmt\GroupUse[$3, $6, $2]; }
|
||||||
| T_USE legacy_namespace_name T_NS_SEPARATOR '{' inline_use_declarations '}'
|
| T_USE legacy_namespace_name T_NS_SEPARATOR '{' inline_use_declarations '}' ';'
|
||||||
{ $$ = Stmt\GroupUse[$2, $5, Stmt\Use_::TYPE_UNKNOWN]; }
|
{ $$ = Stmt\GroupUse[$2, $5, Stmt\Use_::TYPE_UNKNOWN]; }
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -264,8 +264,13 @@ optional_ellipsis:
|
|||||||
| T_ELLIPSIS { $$ = true; }
|
| T_ELLIPSIS { $$ = true; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
identifier_maybe_readonly:
|
||||||
|
identifier { $$ = $1; }
|
||||||
|
| T_READONLY { $$ = Node\Identifier[$1]; }
|
||||||
|
;
|
||||||
|
|
||||||
function_declaration_statement:
|
function_declaration_statement:
|
||||||
T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type '{' inner_statement_list '}'
|
T_FUNCTION optional_ref identifier_maybe_readonly '(' parameter_list ')' optional_return_type '{' inner_statement_list '}'
|
||||||
{ $$ = Stmt\Function_[$3, ['byRef' => $2, 'params' => $5, 'returnType' => $7, 'stmts' => $9]]; }
|
{ $$ = Stmt\Function_[$3, ['byRef' => $2, 'params' => $5, 'returnType' => $7, 'stmts' => $9]]; }
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -464,7 +469,7 @@ static_var:
|
|||||||
;
|
;
|
||||||
|
|
||||||
class_statement_list_ex:
|
class_statement_list_ex:
|
||||||
class_statement_list_ex class_statement { if ($2 !== null) { push($1, $2); } }
|
class_statement_list_ex class_statement { if ($2 !== null) { push($1, $2); } else { $$ = $1; } }
|
||||||
| /* empty */ { init(); }
|
| /* empty */ { init(); }
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -689,9 +694,7 @@ array_expr:
|
|||||||
|
|
||||||
scalar_dereference:
|
scalar_dereference:
|
||||||
array_expr '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
array_expr '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
||||||
| T_CONSTANT_ENCAPSED_STRING '[' dim_offset ']'
|
| T_CONSTANT_ENCAPSED_STRING '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[Scalar\String_::fromString($1, attributes()), $3]; }
|
||||||
{ $attrs = attributes(); $attrs['kind'] = strKind($1);
|
|
||||||
$$ = Expr\ArrayDimFetch[new Scalar\String_(Scalar\String_::parse($1), $attrs), $3]; }
|
|
||||||
| constant '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
| constant '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
||||||
| scalar_dereference '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
| scalar_dereference '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
||||||
/* alternative array syntax missing intentionally */
|
/* alternative array syntax missing intentionally */
|
||||||
@ -723,8 +726,13 @@ lexical_var:
|
|||||||
optional_ref plain_variable { $$ = Expr\ClosureUse[$2, $1]; }
|
optional_ref plain_variable { $$ = Expr\ClosureUse[$2, $1]; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
name_readonly:
|
||||||
|
T_READONLY { $$ = Name[$1]; }
|
||||||
|
;
|
||||||
|
|
||||||
function_call:
|
function_call:
|
||||||
name argument_list { $$ = Expr\FuncCall[$1, $2]; }
|
name argument_list { $$ = Expr\FuncCall[$1, $2]; }
|
||||||
|
| name_readonly argument_list { $$ = Expr\FuncCall[$1, $2]; }
|
||||||
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier_ex argument_list
|
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier_ex argument_list
|
||||||
{ $$ = Expr\StaticCall[$1, $3, $4]; }
|
{ $$ = Expr\StaticCall[$1, $3, $4]; }
|
||||||
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM '{' expr '}' argument_list
|
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM '{' expr '}' argument_list
|
||||||
@ -793,10 +801,8 @@ ctor_arguments:
|
|||||||
|
|
||||||
common_scalar:
|
common_scalar:
|
||||||
T_LNUMBER { $$ = $this->parseLNumber($1, attributes(), true); }
|
T_LNUMBER { $$ = $this->parseLNumber($1, attributes(), true); }
|
||||||
| T_DNUMBER { $$ = Scalar\DNumber[Scalar\DNumber::parse($1)]; }
|
| T_DNUMBER { $$ = Scalar\DNumber::fromString($1, attributes()); }
|
||||||
| T_CONSTANT_ENCAPSED_STRING
|
| T_CONSTANT_ENCAPSED_STRING { $$ = Scalar\String_::fromString($1, attributes(), false); }
|
||||||
{ $attrs = attributes(); $attrs['kind'] = strKind($1);
|
|
||||||
$$ = new Scalar\String_(Scalar\String_::parse($1, false), $attrs); }
|
|
||||||
| T_LINE { $$ = Scalar\MagicConst\Line[]; }
|
| T_LINE { $$ = Scalar\MagicConst\Line[]; }
|
||||||
| T_FILE { $$ = Scalar\MagicConst\File[]; }
|
| T_FILE { $$ = Scalar\MagicConst\File[]; }
|
||||||
| T_DIR { $$ = Scalar\MagicConst\Dir[]; }
|
| T_DIR { $$ = Scalar\MagicConst\Dir[]; }
|
||||||
@ -1002,7 +1008,7 @@ array_pair:
|
|||||||
| expr { $$ = Expr\ArrayItem[$1, null, false]; }
|
| expr { $$ = Expr\ArrayItem[$1, null, false]; }
|
||||||
| expr T_DOUBLE_ARROW ampersand variable { $$ = Expr\ArrayItem[$4, $1, true]; }
|
| expr T_DOUBLE_ARROW ampersand variable { $$ = Expr\ArrayItem[$4, $1, true]; }
|
||||||
| ampersand variable { $$ = Expr\ArrayItem[$2, null, true]; }
|
| ampersand variable { $$ = Expr\ArrayItem[$2, null, true]; }
|
||||||
| T_ELLIPSIS expr { $$ = Expr\ArrayItem[$2, null, false, attributes(), true]; }
|
| T_ELLIPSIS expr { $$ = new Expr\ArrayItem($2, null, false, attributes(), true); }
|
||||||
;
|
;
|
||||||
|
|
||||||
encaps_list:
|
encaps_list:
|
||||||
|
111
grammar/php7.y
111
grammar/php7.y
@ -133,7 +133,7 @@ top_statement:
|
|||||||
$this->checkNamespace($$); }
|
$this->checkNamespace($$); }
|
||||||
| T_USE use_declarations semi { $$ = Stmt\Use_[$2, Stmt\Use_::TYPE_NORMAL]; }
|
| T_USE use_declarations semi { $$ = Stmt\Use_[$2, Stmt\Use_::TYPE_NORMAL]; }
|
||||||
| T_USE use_type use_declarations semi { $$ = Stmt\Use_[$3, $2]; }
|
| T_USE use_type use_declarations semi { $$ = Stmt\Use_[$3, $2]; }
|
||||||
| group_use_declaration semi { $$ = $1; }
|
| group_use_declaration { $$ = $1; }
|
||||||
| T_CONST constant_declaration_list semi { $$ = Stmt\Const_[$2]; }
|
| T_CONST constant_declaration_list semi { $$ = Stmt\Const_[$2]; }
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -143,9 +143,9 @@ use_type:
|
|||||||
;
|
;
|
||||||
|
|
||||||
group_use_declaration:
|
group_use_declaration:
|
||||||
T_USE use_type legacy_namespace_name T_NS_SEPARATOR '{' unprefixed_use_declarations '}'
|
T_USE use_type legacy_namespace_name T_NS_SEPARATOR '{' unprefixed_use_declarations '}' semi
|
||||||
{ $$ = Stmt\GroupUse[$3, $6, $2]; }
|
{ $$ = Stmt\GroupUse[$3, $6, $2]; }
|
||||||
| T_USE legacy_namespace_name T_NS_SEPARATOR '{' inline_use_declarations '}'
|
| T_USE legacy_namespace_name T_NS_SEPARATOR '{' inline_use_declarations '}' semi
|
||||||
{ $$ = Stmt\GroupUse[$2, $5, Stmt\Use_::TYPE_UNKNOWN]; }
|
{ $$ = Stmt\GroupUse[$2, $5, Stmt\Use_::TYPE_UNKNOWN]; }
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -221,7 +221,10 @@ non_empty_class_const_list:
|
|||||||
;
|
;
|
||||||
|
|
||||||
class_const:
|
class_const:
|
||||||
identifier_maybe_reserved '=' expr { $$ = Node\Const_[$1, $3]; }
|
T_STRING '=' expr
|
||||||
|
{ $$ = Node\Const_[new Node\Identifier($1, stackAttributes(#1)), $3]; }
|
||||||
|
| semi_reserved '=' expr
|
||||||
|
{ $$ = Node\Const_[new Node\Identifier($1, stackAttributes(#1)), $3]; }
|
||||||
;
|
;
|
||||||
|
|
||||||
inner_statement_list_ex:
|
inner_statement_list_ex:
|
||||||
@ -350,15 +353,23 @@ block_or_error:
|
|||||||
| error { $$ = []; }
|
| error { $$ = []; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
identifier_maybe_readonly:
|
||||||
|
identifier_not_reserved { $$ = $1; }
|
||||||
|
| T_READONLY { $$ = Node\Identifier[$1]; }
|
||||||
|
;
|
||||||
|
|
||||||
function_declaration_statement:
|
function_declaration_statement:
|
||||||
T_FUNCTION optional_ref identifier_not_reserved '(' parameter_list ')' optional_return_type block_or_error
|
T_FUNCTION optional_ref identifier_maybe_readonly '(' parameter_list ')' optional_return_type block_or_error
|
||||||
{ $$ = Stmt\Function_[$3, ['byRef' => $2, 'params' => $5, 'returnType' => $7, 'stmts' => $8, 'attrGroups' => []]]; }
|
{ $$ = Stmt\Function_[$3, ['byRef' => $2, 'params' => $5, 'returnType' => $7, 'stmts' => $8, 'attrGroups' => []]]; }
|
||||||
| attributes T_FUNCTION optional_ref identifier_not_reserved '(' parameter_list ')' optional_return_type block_or_error
|
| attributes T_FUNCTION optional_ref identifier_maybe_readonly '(' parameter_list ')' optional_return_type block_or_error
|
||||||
{ $$ = Stmt\Function_[$4, ['byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9, 'attrGroups' => $1]]; }
|
{ $$ = Stmt\Function_[$4, ['byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9, 'attrGroups' => $1]]; }
|
||||||
;
|
;
|
||||||
|
|
||||||
class_declaration_statement:
|
class_declaration_statement:
|
||||||
optional_attributes class_entry_type identifier_not_reserved extends_from implements_list '{' class_statement_list '}'
|
class_entry_type identifier_not_reserved extends_from implements_list '{' class_statement_list '}'
|
||||||
|
{ $$ = Stmt\Class_[$2, ['type' => $1, 'extends' => $3, 'implements' => $4, 'stmts' => $6, 'attrGroups' => []]];
|
||||||
|
$this->checkClass($$, #2); }
|
||||||
|
| attributes class_entry_type identifier_not_reserved extends_from implements_list '{' class_statement_list '}'
|
||||||
{ $$ = Stmt\Class_[$3, ['type' => $2, 'extends' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]];
|
{ $$ = Stmt\Class_[$3, ['type' => $2, 'extends' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]];
|
||||||
$this->checkClass($$, #3); }
|
$this->checkClass($$, #3); }
|
||||||
| optional_attributes T_INTERFACE identifier_not_reserved interface_extends_list '{' class_statement_list '}'
|
| optional_attributes T_INTERFACE identifier_not_reserved interface_extends_list '{' class_statement_list '}'
|
||||||
@ -382,8 +393,18 @@ enum_case_expr:
|
|||||||
|
|
||||||
class_entry_type:
|
class_entry_type:
|
||||||
T_CLASS { $$ = 0; }
|
T_CLASS { $$ = 0; }
|
||||||
| T_ABSTRACT T_CLASS { $$ = Stmt\Class_::MODIFIER_ABSTRACT; }
|
| class_modifiers T_CLASS { $$ = $1; }
|
||||||
| T_FINAL T_CLASS { $$ = Stmt\Class_::MODIFIER_FINAL; }
|
;
|
||||||
|
|
||||||
|
class_modifiers:
|
||||||
|
class_modifier { $$ = $1; }
|
||||||
|
| class_modifiers class_modifier { $this->checkClassModifier($1, $2, #2); $$ = $1 | $2; }
|
||||||
|
;
|
||||||
|
|
||||||
|
class_modifier:
|
||||||
|
T_ABSTRACT { $$ = Stmt\Class_::MODIFIER_ABSTRACT; }
|
||||||
|
| T_FINAL { $$ = Stmt\Class_::MODIFIER_FINAL; }
|
||||||
|
| T_READONLY { $$ = Stmt\Class_::MODIFIER_READONLY; }
|
||||||
;
|
;
|
||||||
|
|
||||||
extends_from:
|
extends_from:
|
||||||
@ -500,7 +521,8 @@ new_elseif_list:
|
|||||||
;
|
;
|
||||||
|
|
||||||
new_elseif:
|
new_elseif:
|
||||||
T_ELSEIF '(' expr ')' ':' inner_statement_list { $$ = Stmt\ElseIf_[$3, $6]; }
|
T_ELSEIF '(' expr ')' ':' inner_statement_list
|
||||||
|
{ $$ = Stmt\ElseIf_[$3, $6]; $this->fixupAlternativeElse($$); }
|
||||||
;
|
;
|
||||||
|
|
||||||
else_single:
|
else_single:
|
||||||
@ -510,7 +532,8 @@ else_single:
|
|||||||
|
|
||||||
new_else_single:
|
new_else_single:
|
||||||
/* empty */ { $$ = null; }
|
/* empty */ { $$ = null; }
|
||||||
| T_ELSE ':' inner_statement_list { $$ = Stmt\Else_[$3]; }
|
| T_ELSE ':' inner_statement_list
|
||||||
|
{ $$ = Stmt\Else_[$3]; $this->fixupAlternativeElse($$); }
|
||||||
;
|
;
|
||||||
|
|
||||||
foreach_variable:
|
foreach_variable:
|
||||||
@ -561,7 +584,7 @@ type_expr:
|
|||||||
type { $$ = $1; }
|
type { $$ = $1; }
|
||||||
| '?' type { $$ = Node\NullableType[$2]; }
|
| '?' type { $$ = Node\NullableType[$2]; }
|
||||||
| union_type { $$ = Node\UnionType[$1]; }
|
| union_type { $$ = Node\UnionType[$1]; }
|
||||||
| intersection_type { $$ = Node\IntersectionType[$1]; }
|
| intersection_type { $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
type:
|
type:
|
||||||
@ -575,34 +598,52 @@ type_without_static:
|
|||||||
| T_CALLABLE { $$ = Node\Identifier['callable']; }
|
| T_CALLABLE { $$ = Node\Identifier['callable']; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
union_type_element:
|
||||||
|
type { $$ = $1; }
|
||||||
|
| '(' intersection_type ')' { $$ = $2; }
|
||||||
|
;
|
||||||
|
|
||||||
union_type:
|
union_type:
|
||||||
type '|' type { init($1, $3); }
|
union_type_element '|' union_type_element { init($1, $3); }
|
||||||
| union_type '|' type { push($1, $3); }
|
| union_type '|' union_type_element { push($1, $3); }
|
||||||
|
;
|
||||||
|
|
||||||
|
union_type_without_static_element:
|
||||||
|
type_without_static { $$ = $1; }
|
||||||
|
| '(' intersection_type_without_static ')' { $$ = $2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
union_type_without_static:
|
union_type_without_static:
|
||||||
type_without_static '|' type_without_static { init($1, $3); }
|
union_type_without_static_element '|' union_type_without_static_element { init($1, $3); }
|
||||||
| union_type_without_static '|' type_without_static { push($1, $3); }
|
| union_type_without_static '|' union_type_without_static_element { push($1, $3); }
|
||||||
|
;
|
||||||
|
|
||||||
|
intersection_type_list:
|
||||||
|
type T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type { init($1, $3); }
|
||||||
|
| intersection_type_list T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type
|
||||||
|
{ push($1, $3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
intersection_type:
|
intersection_type:
|
||||||
type T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type { init($1, $3); }
|
intersection_type_list { $$ = Node\IntersectionType[$1]; }
|
||||||
| intersection_type T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type
|
;
|
||||||
|
|
||||||
|
intersection_type_without_static_list:
|
||||||
|
type_without_static T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type_without_static
|
||||||
|
{ init($1, $3); }
|
||||||
|
| intersection_type_without_static_list T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type_without_static
|
||||||
{ push($1, $3); }
|
{ push($1, $3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
intersection_type_without_static:
|
intersection_type_without_static:
|
||||||
type_without_static T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type_without_static
|
intersection_type_without_static_list { $$ = Node\IntersectionType[$1]; }
|
||||||
{ init($1, $3); }
|
|
||||||
| intersection_type_without_static T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type_without_static
|
|
||||||
{ push($1, $3); }
|
|
||||||
;
|
;
|
||||||
|
|
||||||
type_expr_without_static:
|
type_expr_without_static:
|
||||||
type_without_static { $$ = $1; }
|
type_without_static { $$ = $1; }
|
||||||
| '?' type_without_static { $$ = Node\NullableType[$2]; }
|
| '?' type_without_static { $$ = Node\NullableType[$2]; }
|
||||||
| union_type_without_static { $$ = Node\UnionType[$1]; }
|
| union_type_without_static { $$ = Node\UnionType[$1]; }
|
||||||
| intersection_type_without_static { $$ = Node\IntersectionType[$1]; }
|
| intersection_type_without_static { $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
optional_type_without_static:
|
optional_type_without_static:
|
||||||
@ -667,7 +708,7 @@ static_var:
|
|||||||
;
|
;
|
||||||
|
|
||||||
class_statement_list_ex:
|
class_statement_list_ex:
|
||||||
class_statement_list_ex class_statement { if ($2 !== null) { push($1, $2); } }
|
class_statement_list_ex class_statement { if ($2 !== null) { push($1, $2); } else { $$ = $1; } }
|
||||||
| /* empty */ { init(); }
|
| /* empty */ { init(); }
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -684,6 +725,9 @@ class_statement:
|
|||||||
| optional_attributes method_modifiers T_CONST class_const_list semi
|
| optional_attributes method_modifiers T_CONST class_const_list semi
|
||||||
{ $$ = new Stmt\ClassConst($4, $2, attributes(), $1);
|
{ $$ = new Stmt\ClassConst($4, $2, attributes(), $1);
|
||||||
$this->checkClassConst($$, #2); }
|
$this->checkClassConst($$, #2); }
|
||||||
|
| optional_attributes method_modifiers T_CONST type_expr class_const_list semi
|
||||||
|
{ $$ = new Stmt\ClassConst($5, $2, attributes(), $1, $4);
|
||||||
|
$this->checkClassConst($$, #2); }
|
||||||
| optional_attributes method_modifiers T_FUNCTION optional_ref identifier_maybe_reserved '(' parameter_list ')'
|
| optional_attributes method_modifiers T_FUNCTION optional_ref identifier_maybe_reserved '(' parameter_list ')'
|
||||||
optional_return_type method_body
|
optional_return_type method_body
|
||||||
{ $$ = Stmt\ClassMethod[$5, ['type' => $2, 'byRef' => $4, 'params' => $7, 'returnType' => $9, 'stmts' => $10, 'attrGroups' => $1]];
|
{ $$ = Stmt\ClassMethod[$5, ['type' => $2, 'byRef' => $4, 'params' => $7, 'returnType' => $9, 'stmts' => $10, 'attrGroups' => $1]];
|
||||||
@ -905,8 +949,8 @@ expr:
|
|||||||
;
|
;
|
||||||
|
|
||||||
anonymous_class:
|
anonymous_class:
|
||||||
optional_attributes T_CLASS ctor_arguments extends_from implements_list '{' class_statement_list '}'
|
optional_attributes class_entry_type ctor_arguments extends_from implements_list '{' class_statement_list '}'
|
||||||
{ $$ = array(Stmt\Class_[null, ['type' => 0, 'extends' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]], $3);
|
{ $$ = array(Stmt\Class_[null, ['type' => $2, 'extends' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]], $3);
|
||||||
$this->checkClass($$[0], -1); }
|
$this->checkClass($$[0], -1); }
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -934,8 +978,13 @@ lexical_var:
|
|||||||
optional_ref plain_variable { $$ = Expr\ClosureUse[$2, $1]; }
|
optional_ref plain_variable { $$ = Expr\ClosureUse[$2, $1]; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
name_readonly:
|
||||||
|
T_READONLY { $$ = Name[$1]; }
|
||||||
|
;
|
||||||
|
|
||||||
function_call:
|
function_call:
|
||||||
name argument_list { $$ = Expr\FuncCall[$1, $2]; }
|
name argument_list { $$ = Expr\FuncCall[$1, $2]; }
|
||||||
|
| name_readonly argument_list { $$ = Expr\FuncCall[$1, $2]; }
|
||||||
| callable_expr argument_list { $$ = Expr\FuncCall[$1, $2]; }
|
| callable_expr argument_list { $$ = Expr\FuncCall[$1, $2]; }
|
||||||
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM member_name argument_list
|
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM member_name argument_list
|
||||||
{ $$ = Expr\StaticCall[$1, $3, $4]; }
|
{ $$ = Expr\StaticCall[$1, $3, $4]; }
|
||||||
@ -997,6 +1046,8 @@ constant:
|
|||||||
class_constant:
|
class_constant:
|
||||||
class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier_maybe_reserved
|
class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier_maybe_reserved
|
||||||
{ $$ = Expr\ClassConstFetch[$1, $3]; }
|
{ $$ = Expr\ClassConstFetch[$1, $3]; }
|
||||||
|
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM '{' expr '}'
|
||||||
|
{ $$ = Expr\ClassConstFetch[$1, $4]; }
|
||||||
/* We interpret an isolated FOO:: as an unfinished class constant fetch. It could also be
|
/* We interpret an isolated FOO:: as an unfinished class constant fetch. It could also be
|
||||||
an unfinished static property fetch or unfinished scoped call. */
|
an unfinished static property fetch or unfinished scoped call. */
|
||||||
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM error
|
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM error
|
||||||
@ -1014,9 +1065,7 @@ dereferencable_scalar:
|
|||||||
{ $attrs = attributes(); $attrs['kind'] = Expr\Array_::KIND_LONG;
|
{ $attrs = attributes(); $attrs['kind'] = Expr\Array_::KIND_LONG;
|
||||||
$$ = new Expr\Array_($3, $attrs); }
|
$$ = new Expr\Array_($3, $attrs); }
|
||||||
| array_short_syntax { $$ = $1; }
|
| array_short_syntax { $$ = $1; }
|
||||||
| T_CONSTANT_ENCAPSED_STRING
|
| T_CONSTANT_ENCAPSED_STRING { $$ = Scalar\String_::fromString($1, attributes()); }
|
||||||
{ $attrs = attributes(); $attrs['kind'] = strKind($1);
|
|
||||||
$$ = new Scalar\String_(Scalar\String_::parse($1), $attrs); }
|
|
||||||
| '"' encaps_list '"'
|
| '"' encaps_list '"'
|
||||||
{ $attrs = attributes(); $attrs['kind'] = Scalar\String_::KIND_DOUBLE_QUOTED;
|
{ $attrs = attributes(); $attrs['kind'] = Scalar\String_::KIND_DOUBLE_QUOTED;
|
||||||
parseEncapsed($2, '"', true); $$ = new Scalar\Encapsed($2, $attrs); }
|
parseEncapsed($2, '"', true); $$ = new Scalar\Encapsed($2, $attrs); }
|
||||||
@ -1024,7 +1073,7 @@ dereferencable_scalar:
|
|||||||
|
|
||||||
scalar:
|
scalar:
|
||||||
T_LNUMBER { $$ = $this->parseLNumber($1, attributes()); }
|
T_LNUMBER { $$ = $this->parseLNumber($1, attributes()); }
|
||||||
| T_DNUMBER { $$ = Scalar\DNumber[Scalar\DNumber::parse($1)]; }
|
| T_DNUMBER { $$ = Scalar\DNumber::fromString($1, attributes()); }
|
||||||
| dereferencable_scalar { $$ = $1; }
|
| dereferencable_scalar { $$ = $1; }
|
||||||
| constant { $$ = $1; }
|
| constant { $$ = $1; }
|
||||||
| class_constant { $$ = $1; }
|
| class_constant { $$ = $1; }
|
||||||
@ -1153,7 +1202,7 @@ array_pair:
|
|||||||
| expr T_DOUBLE_ARROW expr { $$ = Expr\ArrayItem[$3, $1, false]; }
|
| expr T_DOUBLE_ARROW expr { $$ = Expr\ArrayItem[$3, $1, false]; }
|
||||||
| expr T_DOUBLE_ARROW ampersand variable { $$ = Expr\ArrayItem[$4, $1, true]; }
|
| expr T_DOUBLE_ARROW ampersand variable { $$ = Expr\ArrayItem[$4, $1, true]; }
|
||||||
| expr T_DOUBLE_ARROW list_expr { $$ = Expr\ArrayItem[$3, $1, false]; }
|
| expr T_DOUBLE_ARROW list_expr { $$ = Expr\ArrayItem[$3, $1, false]; }
|
||||||
| T_ELLIPSIS expr { $$ = Expr\ArrayItem[$2, null, false, attributes(), true]; }
|
| T_ELLIPSIS expr { $$ = new Expr\ArrayItem($2, null, false, attributes(), true); }
|
||||||
| /* empty */ { $$ = null; }
|
| /* empty */ { $$ = null; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -128,14 +128,6 @@ function resolveMacros($code) {
|
|||||||
. ' else { ' . $args[0] . ' = null; }';
|
. ' else { ' . $args[0] . ' = null; }';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('strKind' === $name) {
|
|
||||||
assertArgs(1, $args, $name);
|
|
||||||
|
|
||||||
return '(' . $args[0] . '[0] === "\'" || (' . $args[0] . '[1] === "\'" && '
|
|
||||||
. '(' . $args[0] . '[0] === \'b\' || ' . $args[0] . '[0] === \'B\')) '
|
|
||||||
. '? Scalar\String_::KIND_SINGLE_QUOTED : Scalar\String_::KIND_DOUBLE_QUOTED)';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('prependLeadingComments' === $name) {
|
if ('prependLeadingComments' === $name) {
|
||||||
assertArgs(1, $args, $name);
|
assertArgs(1, $args, $name);
|
||||||
|
|
||||||
|
@ -19,12 +19,14 @@ class ClassConst implements PhpParser\Builder
|
|||||||
|
|
||||||
/** @var Node\AttributeGroup[] */
|
/** @var Node\AttributeGroup[] */
|
||||||
protected $attributeGroups = [];
|
protected $attributeGroups = [];
|
||||||
|
/** @var Identifier|Node\Name|Node\ComplexType */
|
||||||
|
protected $type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a class constant builder
|
* Creates a class constant builder
|
||||||
*
|
*
|
||||||
* @param string|Identifier $name Name
|
* @param string|Identifier $name Name
|
||||||
* @param Node\Expr|bool|null|int|float|string|array $value Value
|
* @param Node\Expr|bool|null|int|float|string|array|\UnitEnum $value Value
|
||||||
*/
|
*/
|
||||||
public function __construct($name, $value) {
|
public function __construct($name, $value) {
|
||||||
$this->constants = [new Const_($name, BuilderHelpers::normalizeValue($value))];
|
$this->constants = [new Const_($name, BuilderHelpers::normalizeValue($value))];
|
||||||
@ -34,7 +36,7 @@ class ClassConst implements PhpParser\Builder
|
|||||||
* Add another constant to const group
|
* Add another constant to const group
|
||||||
*
|
*
|
||||||
* @param string|Identifier $name Name
|
* @param string|Identifier $name Name
|
||||||
* @param Node\Expr|bool|null|int|float|string|array $value Value
|
* @param Node\Expr|bool|null|int|float|string|array|\UnitEnum $value Value
|
||||||
*
|
*
|
||||||
* @return $this The builder instance (for fluid interface)
|
* @return $this The builder instance (for fluid interface)
|
||||||
*/
|
*/
|
||||||
@ -116,6 +118,19 @@ class ClassConst implements PhpParser\Builder
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the constant type.
|
||||||
|
*
|
||||||
|
* @param string|Node\Name|Identifier|Node\ComplexType $type
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setType($type) {
|
||||||
|
$this->type = BuilderHelpers::normalizeType($type);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the built class node.
|
* Returns the built class node.
|
||||||
*
|
*
|
||||||
@ -126,7 +141,8 @@ class ClassConst implements PhpParser\Builder
|
|||||||
$this->constants,
|
$this->constants,
|
||||||
$this->flags,
|
$this->flags,
|
||||||
$this->attributes,
|
$this->attributes,
|
||||||
$this->attributeGroups
|
$this->attributeGroups,
|
||||||
|
$this->type
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ class Class_ extends Declaration
|
|||||||
* @return $this The builder instance (for fluid interface)
|
* @return $this The builder instance (for fluid interface)
|
||||||
*/
|
*/
|
||||||
public function makeAbstract() {
|
public function makeAbstract() {
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_ABSTRACT);
|
$this->flags = BuilderHelpers::addClassModifier($this->flags, Stmt\Class_::MODIFIER_ABSTRACT);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -78,7 +78,13 @@ class Class_ extends Declaration
|
|||||||
* @return $this The builder instance (for fluid interface)
|
* @return $this The builder instance (for fluid interface)
|
||||||
*/
|
*/
|
||||||
public function makeFinal() {
|
public function makeFinal() {
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_FINAL);
|
$this->flags = BuilderHelpers::addClassModifier($this->flags, Stmt\Class_::MODIFIER_FINAL);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function makeReadonly() {
|
||||||
|
$this->flags = BuilderHelpers::addClassModifier($this->flags, Stmt\Class_::MODIFIER_READONLY);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
85
lib/PhpParser/Builder/EnumCase.php
Normal file
85
lib/PhpParser/Builder/EnumCase.php
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser;
|
||||||
|
use PhpParser\BuilderHelpers;
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Identifier;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
|
class EnumCase implements PhpParser\Builder
|
||||||
|
{
|
||||||
|
protected $name;
|
||||||
|
protected $value = null;
|
||||||
|
protected $attributes = [];
|
||||||
|
|
||||||
|
/** @var Node\AttributeGroup[] */
|
||||||
|
protected $attributeGroups = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an enum case builder.
|
||||||
|
*
|
||||||
|
* @param string|Identifier $name Name
|
||||||
|
*/
|
||||||
|
public function __construct($name) {
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value.
|
||||||
|
*
|
||||||
|
* @param Node\Expr|string|int $value
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setValue($value) {
|
||||||
|
$this->value = BuilderHelpers::normalizeValue($value);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets doc comment for the constant.
|
||||||
|
*
|
||||||
|
* @param PhpParser\Comment\Doc|string $docComment Doc comment to set
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function setDocComment($docComment) {
|
||||||
|
$this->attributes = [
|
||||||
|
'comments' => [BuilderHelpers::normalizeDocComment($docComment)]
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an attribute group.
|
||||||
|
*
|
||||||
|
* @param Node\Attribute|Node\AttributeGroup $attribute
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addAttribute($attribute) {
|
||||||
|
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the built enum case node.
|
||||||
|
*
|
||||||
|
* @return Stmt\EnumCase The built constant node
|
||||||
|
*/
|
||||||
|
public function getNode(): PhpParser\Node {
|
||||||
|
return new Stmt\EnumCase(
|
||||||
|
$this->name,
|
||||||
|
$this->value,
|
||||||
|
$this->attributeGroups,
|
||||||
|
$this->attributes
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
117
lib/PhpParser/Builder/Enum_.php
Normal file
117
lib/PhpParser/Builder/Enum_.php
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser;
|
||||||
|
use PhpParser\BuilderHelpers;
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Identifier;
|
||||||
|
use PhpParser\Node\Name;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
|
class Enum_ extends Declaration
|
||||||
|
{
|
||||||
|
protected $name;
|
||||||
|
protected $scalarType = null;
|
||||||
|
|
||||||
|
protected $implements = [];
|
||||||
|
|
||||||
|
protected $uses = [];
|
||||||
|
protected $enumCases = [];
|
||||||
|
protected $constants = [];
|
||||||
|
protected $methods = [];
|
||||||
|
|
||||||
|
/** @var Node\AttributeGroup[] */
|
||||||
|
protected $attributeGroups = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an enum builder.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the enum
|
||||||
|
*/
|
||||||
|
public function __construct(string $name) {
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the scalar type.
|
||||||
|
*
|
||||||
|
* @param string|Identifier $type
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setScalarType($scalarType) {
|
||||||
|
$this->scalarType = BuilderHelpers::normalizeType($scalarType);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements one or more interfaces.
|
||||||
|
*
|
||||||
|
* @param Name|string ...$interfaces Names of interfaces to implement
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function implement(...$interfaces) {
|
||||||
|
foreach ($interfaces as $interface) {
|
||||||
|
$this->implements[] = BuilderHelpers::normalizeName($interface);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a statement.
|
||||||
|
*
|
||||||
|
* @param Stmt|PhpParser\Builder $stmt The statement to add
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addStmt($stmt) {
|
||||||
|
$stmt = BuilderHelpers::normalizeNode($stmt);
|
||||||
|
|
||||||
|
$targets = [
|
||||||
|
Stmt\TraitUse::class => &$this->uses,
|
||||||
|
Stmt\EnumCase::class => &$this->enumCases,
|
||||||
|
Stmt\ClassConst::class => &$this->constants,
|
||||||
|
Stmt\ClassMethod::class => &$this->methods,
|
||||||
|
];
|
||||||
|
|
||||||
|
$class = \get_class($stmt);
|
||||||
|
if (!isset($targets[$class])) {
|
||||||
|
throw new \LogicException(sprintf('Unexpected node of type "%s"', $stmt->getType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
$targets[$class][] = $stmt;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an attribute group.
|
||||||
|
*
|
||||||
|
* @param Node\Attribute|Node\AttributeGroup $attribute
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addAttribute($attribute) {
|
||||||
|
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the built class node.
|
||||||
|
*
|
||||||
|
* @return Stmt\Enum_ The built enum node
|
||||||
|
*/
|
||||||
|
public function getNode() : PhpParser\Node {
|
||||||
|
return new Stmt\Enum_($this->name, [
|
||||||
|
'scalarType' => $this->scalarType,
|
||||||
|
'implements' => $this->implements,
|
||||||
|
'stmts' => array_merge($this->uses, $this->enumCases, $this->constants, $this->methods),
|
||||||
|
'attrGroups' => $this->attributeGroups,
|
||||||
|
], $this->attributes);
|
||||||
|
}
|
||||||
|
}
|
@ -19,6 +19,8 @@ class Param implements PhpParser\Builder
|
|||||||
|
|
||||||
protected $variadic = false;
|
protected $variadic = false;
|
||||||
|
|
||||||
|
protected $flags = 0;
|
||||||
|
|
||||||
/** @var Node\AttributeGroup[] */
|
/** @var Node\AttributeGroup[] */
|
||||||
protected $attributeGroups = [];
|
protected $attributeGroups = [];
|
||||||
|
|
||||||
@ -95,6 +97,50 @@ class Param implements PhpParser\Builder
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the (promoted) parameter public.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makePublic() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_PUBLIC);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the (promoted) parameter protected.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeProtected() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_PROTECTED);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the (promoted) parameter private.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makePrivate() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_PRIVATE);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the (promoted) parameter readonly.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeReadonly() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_READONLY);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an attribute group.
|
* Adds an attribute group.
|
||||||
*
|
*
|
||||||
@ -116,7 +162,7 @@ class Param implements PhpParser\Builder
|
|||||||
public function getNode() : Node {
|
public function getNode() : Node {
|
||||||
return new Node\Param(
|
return new Node\Param(
|
||||||
new Node\Expr\Variable($this->name),
|
new Node\Expr\Variable($this->name),
|
||||||
$this->default, $this->type, $this->byRef, $this->variadic, [], 0, $this->attributeGroups
|
$this->default, $this->type, $this->byRef, $this->variadic, [], $this->flags, $this->attributeGroups
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,6 +71,17 @@ class BuilderFactory
|
|||||||
return new Builder\Trait_($name);
|
return new Builder\Trait_($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an enum builder.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the enum
|
||||||
|
*
|
||||||
|
* @return Builder\Enum_ The created enum builder
|
||||||
|
*/
|
||||||
|
public function enum(string $name) : Builder\Enum_ {
|
||||||
|
return new Builder\Enum_($name);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a trait use builder.
|
* Creates a trait use builder.
|
||||||
*
|
*
|
||||||
@ -188,10 +199,21 @@ class BuilderFactory
|
|||||||
return new Builder\ClassConst($name, $value);
|
return new Builder\ClassConst($name, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an enum case builder.
|
||||||
|
*
|
||||||
|
* @param string|Identifier $name Name
|
||||||
|
*
|
||||||
|
* @return Builder\EnumCase The created use const builder
|
||||||
|
*/
|
||||||
|
public function enumCase($name) : Builder\EnumCase {
|
||||||
|
return new Builder\EnumCase($name);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates node a for a literal value.
|
* Creates node a for a literal value.
|
||||||
*
|
*
|
||||||
* @param Expr|bool|null|int|float|string|array $value $value
|
* @param Expr|bool|null|int|float|string|array|\UnitEnum $value $value
|
||||||
*
|
*
|
||||||
* @return Expr
|
* @return Expr
|
||||||
*/
|
*/
|
||||||
@ -328,14 +350,14 @@ class BuilderFactory
|
|||||||
* Creates a class constant fetch node.
|
* Creates a class constant fetch node.
|
||||||
*
|
*
|
||||||
* @param string|Name|Expr $class Class name
|
* @param string|Name|Expr $class Class name
|
||||||
* @param string|Identifier $name Constant name
|
* @param string|Identifier|Expr $name Constant name
|
||||||
*
|
*
|
||||||
* @return Expr\ClassConstFetch
|
* @return Expr\ClassConstFetch
|
||||||
*/
|
*/
|
||||||
public function classConstFetch($class, $name): Expr\ClassConstFetch {
|
public function classConstFetch($class, $name): Expr\ClassConstFetch {
|
||||||
return new Expr\ClassConstFetch(
|
return new Expr\ClassConstFetch(
|
||||||
BuilderHelpers::normalizeNameOrExpr($class),
|
BuilderHelpers::normalizeNameOrExpr($class),
|
||||||
BuilderHelpers::normalizeIdentifier($name)
|
BuilderHelpers::normalizeIdentifierOrExpr($name)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ use PhpParser\Node\ComplexType;
|
|||||||
use PhpParser\Node\Expr;
|
use PhpParser\Node\Expr;
|
||||||
use PhpParser\Node\Identifier;
|
use PhpParser\Node\Identifier;
|
||||||
use PhpParser\Node\Name;
|
use PhpParser\Node\Name;
|
||||||
|
use PhpParser\Node\Name\FullyQualified;
|
||||||
use PhpParser\Node\NullableType;
|
use PhpParser\Node\NullableType;
|
||||||
use PhpParser\Node\Scalar;
|
use PhpParser\Node\Scalar;
|
||||||
use PhpParser\Node\Stmt;
|
use PhpParser\Node\Stmt;
|
||||||
@ -178,7 +179,20 @@ final class BuilderHelpers
|
|||||||
}
|
}
|
||||||
|
|
||||||
$builtinTypes = [
|
$builtinTypes = [
|
||||||
'array', 'callable', 'string', 'int', 'float', 'bool', 'iterable', 'void', 'object', 'mixed', 'never',
|
'array',
|
||||||
|
'callable',
|
||||||
|
'bool',
|
||||||
|
'int',
|
||||||
|
'float',
|
||||||
|
'string',
|
||||||
|
'iterable',
|
||||||
|
'void',
|
||||||
|
'object',
|
||||||
|
'null',
|
||||||
|
'false',
|
||||||
|
'mixed',
|
||||||
|
'never',
|
||||||
|
'true',
|
||||||
];
|
];
|
||||||
|
|
||||||
$lowerType = strtolower($type);
|
$lowerType = strtolower($type);
|
||||||
@ -202,7 +216,7 @@ final class BuilderHelpers
|
|||||||
* Normalizes a value: Converts nulls, booleans, integers,
|
* Normalizes a value: Converts nulls, booleans, integers,
|
||||||
* floats, strings and arrays into their respective nodes
|
* floats, strings and arrays into their respective nodes
|
||||||
*
|
*
|
||||||
* @param Node\Expr|bool|null|int|float|string|array $value The value to normalize
|
* @param Node\Expr|bool|null|int|float|string|array|\UnitEnum $value The value to normalize
|
||||||
*
|
*
|
||||||
* @return Expr The normalized value
|
* @return Expr The normalized value
|
||||||
*/
|
*/
|
||||||
@ -256,6 +270,10 @@ final class BuilderHelpers
|
|||||||
return new Expr\Array_($items);
|
return new Expr\Array_($items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($value instanceof \UnitEnum) {
|
||||||
|
return new Expr\ClassConstFetch(new FullyQualified(\get_class($value)), new Identifier($value->name));
|
||||||
|
}
|
||||||
|
|
||||||
throw new \LogicException('Invalid value');
|
throw new \LogicException('Invalid value');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,4 +328,13 @@ final class BuilderHelpers
|
|||||||
Stmt\Class_::verifyModifier($modifiers, $modifier);
|
Stmt\Class_::verifyModifier($modifiers, $modifier);
|
||||||
return $modifiers | $modifier;
|
return $modifiers | $modifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a modifier and returns new modifier bitmask.
|
||||||
|
* @return int New modifiers
|
||||||
|
*/
|
||||||
|
public static function addClassModifier(int $existingModifiers, int $modifierToSet) : int {
|
||||||
|
Stmt\Class_::verifyClassModifier($existingModifiers, $modifierToSet);
|
||||||
|
return $existingModifiers | $modifierToSet;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ class ConstExprEvaluator
|
|||||||
*
|
*
|
||||||
* @param callable|null $fallbackEvaluator To call if subexpression cannot be evaluated
|
* @param callable|null $fallbackEvaluator To call if subexpression cannot be evaluated
|
||||||
*/
|
*/
|
||||||
public function __construct(callable $fallbackEvaluator = null) {
|
public function __construct(?callable $fallbackEvaluator = null) {
|
||||||
$this->fallbackEvaluator = $fallbackEvaluator ?? function(Expr $expr) {
|
$this->fallbackEvaluator = $fallbackEvaluator ?? function(Expr $expr) {
|
||||||
throw new ConstExprEvaluationException(
|
throw new ConstExprEvaluationException(
|
||||||
"Expression of type {$expr->getType()} cannot be evaluated"
|
"Expression of type {$expr->getType()} cannot be evaluated"
|
||||||
|
@ -19,6 +19,8 @@ class PrintableNewAnonClassNode extends Expr
|
|||||||
{
|
{
|
||||||
/** @var Node\AttributeGroup[] PHP attribute groups */
|
/** @var Node\AttributeGroup[] PHP attribute groups */
|
||||||
public $attrGroups;
|
public $attrGroups;
|
||||||
|
/** @var int Modifiers */
|
||||||
|
public $flags;
|
||||||
/** @var Node\Arg[] Arguments */
|
/** @var Node\Arg[] Arguments */
|
||||||
public $args;
|
public $args;
|
||||||
/** @var null|Node\Name Name of extended class */
|
/** @var null|Node\Name Name of extended class */
|
||||||
@ -29,11 +31,12 @@ class PrintableNewAnonClassNode extends Expr
|
|||||||
public $stmts;
|
public $stmts;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
array $attrGroups, array $args, Node\Name $extends = null, array $implements,
|
array $attrGroups, int $flags, array $args, ?Node\Name $extends, array $implements,
|
||||||
array $stmts, array $attributes
|
array $stmts, array $attributes
|
||||||
) {
|
) {
|
||||||
parent::__construct($attributes);
|
parent::__construct($attributes);
|
||||||
$this->attrGroups = $attrGroups;
|
$this->attrGroups = $attrGroups;
|
||||||
|
$this->flags = $flags;
|
||||||
$this->args = $args;
|
$this->args = $args;
|
||||||
$this->extends = $extends;
|
$this->extends = $extends;
|
||||||
$this->implements = $implements;
|
$this->implements = $implements;
|
||||||
@ -46,7 +49,7 @@ class PrintableNewAnonClassNode extends Expr
|
|||||||
// We don't assert that $class->name is null here, to allow consumers to assign unique names
|
// We don't assert that $class->name is null here, to allow consumers to assign unique names
|
||||||
// to anonymous classes for their own purposes. We simplify ignore the name here.
|
// to anonymous classes for their own purposes. We simplify ignore the name here.
|
||||||
return new self(
|
return new self(
|
||||||
$class->attrGroups, $newNode->args, $class->extends, $class->implements,
|
$class->attrGroups, $class->flags, $newNode->args, $class->extends, $class->implements,
|
||||||
$class->stmts, $newNode->getAttributes()
|
$class->stmts, $newNode->getAttributes()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -56,6 +59,6 @@ class PrintableNewAnonClassNode extends Expr
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getSubNodeNames() : array {
|
public function getSubNodeNames() : array {
|
||||||
return ['attrGroups', 'args', 'extends', 'implements', 'stmts'];
|
return ['attrGroups', 'flags', 'args', 'extends', 'implements', 'stmts'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,6 +206,11 @@ class TokenStream
|
|||||||
|| $this->haveTokenInRange($startPos, $endPos, '}');
|
|| $this->haveTokenInRange($startPos, $endPos, '}');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function haveTagInRange(int $startPos, int $endPos): bool {
|
||||||
|
return $this->haveTokenInRange($startPos, $endPos, \T_OPEN_TAG)
|
||||||
|
|| $this->haveTokenInRange($startPos, $endPos, \T_CLOSE_TAG);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get indentation before token position.
|
* Get indentation before token position.
|
||||||
*
|
*
|
||||||
|
@ -69,7 +69,7 @@ class Lexer
|
|||||||
* @param ErrorHandler|null $errorHandler Error handler to use for lexing errors. Defaults to
|
* @param ErrorHandler|null $errorHandler Error handler to use for lexing errors. Defaults to
|
||||||
* ErrorHandler\Throwing
|
* ErrorHandler\Throwing
|
||||||
*/
|
*/
|
||||||
public function startLexing(string $code, ErrorHandler $errorHandler = null) {
|
public function startLexing(string $code, ?ErrorHandler $errorHandler = null) {
|
||||||
if (null === $errorHandler) {
|
if (null === $errorHandler) {
|
||||||
$errorHandler = new ErrorHandler\Throwing();
|
$errorHandler = new ErrorHandler\Throwing();
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ use PhpParser\Lexer\TokenEmulator\FnTokenEmulator;
|
|||||||
use PhpParser\Lexer\TokenEmulator\MatchTokenEmulator;
|
use PhpParser\Lexer\TokenEmulator\MatchTokenEmulator;
|
||||||
use PhpParser\Lexer\TokenEmulator\NullsafeTokenEmulator;
|
use PhpParser\Lexer\TokenEmulator\NullsafeTokenEmulator;
|
||||||
use PhpParser\Lexer\TokenEmulator\NumericLiteralSeparatorEmulator;
|
use PhpParser\Lexer\TokenEmulator\NumericLiteralSeparatorEmulator;
|
||||||
|
use PhpParser\Lexer\TokenEmulator\ReadonlyFunctionTokenEmulator;
|
||||||
use PhpParser\Lexer\TokenEmulator\ReadonlyTokenEmulator;
|
use PhpParser\Lexer\TokenEmulator\ReadonlyTokenEmulator;
|
||||||
use PhpParser\Lexer\TokenEmulator\ReverseEmulator;
|
use PhpParser\Lexer\TokenEmulator\ReverseEmulator;
|
||||||
use PhpParser\Lexer\TokenEmulator\TokenEmulator;
|
use PhpParser\Lexer\TokenEmulator\TokenEmulator;
|
||||||
@ -24,6 +25,7 @@ class Emulative extends Lexer
|
|||||||
const PHP_7_4 = '7.4dev';
|
const PHP_7_4 = '7.4dev';
|
||||||
const PHP_8_0 = '8.0dev';
|
const PHP_8_0 = '8.0dev';
|
||||||
const PHP_8_1 = '8.1dev';
|
const PHP_8_1 = '8.1dev';
|
||||||
|
const PHP_8_2 = '8.2dev';
|
||||||
|
|
||||||
/** @var mixed[] Patches used to reverse changes introduced in the code */
|
/** @var mixed[] Patches used to reverse changes introduced in the code */
|
||||||
private $patches = [];
|
private $patches = [];
|
||||||
@ -37,11 +39,11 @@ class Emulative extends Lexer
|
|||||||
/**
|
/**
|
||||||
* @param mixed[] $options Lexer options. In addition to the usual options,
|
* @param mixed[] $options Lexer options. In addition to the usual options,
|
||||||
* accepts a 'phpVersion' string that specifies the
|
* accepts a 'phpVersion' string that specifies the
|
||||||
* version to emulated. Defaults to newest supported.
|
* version to emulate. Defaults to newest supported.
|
||||||
*/
|
*/
|
||||||
public function __construct(array $options = [])
|
public function __construct(array $options = [])
|
||||||
{
|
{
|
||||||
$this->targetPhpVersion = $options['phpVersion'] ?? Emulative::PHP_8_1;
|
$this->targetPhpVersion = $options['phpVersion'] ?? Emulative::PHP_8_2;
|
||||||
unset($options['phpVersion']);
|
unset($options['phpVersion']);
|
||||||
|
|
||||||
parent::__construct($options);
|
parent::__construct($options);
|
||||||
@ -57,6 +59,7 @@ class Emulative extends Lexer
|
|||||||
new EnumTokenEmulator(),
|
new EnumTokenEmulator(),
|
||||||
new ReadonlyTokenEmulator(),
|
new ReadonlyTokenEmulator(),
|
||||||
new ExplicitOctalEmulator(),
|
new ExplicitOctalEmulator(),
|
||||||
|
new ReadonlyFunctionTokenEmulator(),
|
||||||
];
|
];
|
||||||
|
|
||||||
// Collect emulators that are relevant for the PHP version we're running
|
// Collect emulators that are relevant for the PHP version we're running
|
||||||
@ -71,7 +74,7 @@ class Emulative extends Lexer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function startLexing(string $code, ErrorHandler $errorHandler = null) {
|
public function startLexing(string $code, ?ErrorHandler $errorHandler = null) {
|
||||||
$emulators = array_filter($this->emulators, function($emulator) use($code) {
|
$emulators = array_filter($this->emulators, function($emulator) use($code) {
|
||||||
return $emulator->isEmulationNeeded($code);
|
return $emulator->isEmulationNeeded($code);
|
||||||
});
|
});
|
||||||
|
@ -33,7 +33,7 @@ abstract class KeywordEmulator extends TokenEmulator
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mixed[] $tokens
|
* @param mixed[] $tokens
|
||||||
* @return mixed[]|null
|
* @return array|string|null
|
||||||
*/
|
*/
|
||||||
private function getPreviousNonSpaceToken(array $tokens, int $start)
|
private function getPreviousNonSpaceToken(array $tokens, int $start)
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Lexer\TokenEmulator;
|
||||||
|
|
||||||
|
use PhpParser\Lexer\Emulative;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In PHP 8.1, "readonly(" was special cased in the lexer in order to support functions with
|
||||||
|
* name readonly. In PHP 8.2, this may conflict with readonly properties having a DNF type. For
|
||||||
|
* this reason, PHP 8.2 instead treats this as T_READONLY and then handles it specially in the
|
||||||
|
* parser. This emulator only exists to handle this special case, which is skipped by the
|
||||||
|
* PHP 8.1 ReadonlyTokenEmulator.
|
||||||
|
*/
|
||||||
|
class ReadonlyFunctionTokenEmulator extends KeywordEmulator {
|
||||||
|
public function getKeywordString(): string {
|
||||||
|
return 'readonly';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getKeywordToken(): int {
|
||||||
|
return \T_READONLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPhpVersion(): string {
|
||||||
|
return Emulative::PHP_8_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reverseEmulate(string $code, array $tokens): array {
|
||||||
|
// Don't bother
|
||||||
|
return $tokens;
|
||||||
|
}
|
||||||
|
}
|
@ -20,4 +20,17 @@ final class ReadonlyTokenEmulator extends KeywordEmulator
|
|||||||
{
|
{
|
||||||
return \T_READONLY;
|
return \T_READONLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function isKeywordContext(array $tokens, int $pos): bool
|
||||||
|
{
|
||||||
|
if (!parent::isKeywordContext($tokens, $pos)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Support "function readonly("
|
||||||
|
return !(isset($tokens[$pos + 1]) &&
|
||||||
|
($tokens[$pos + 1][0] === '(' ||
|
||||||
|
($tokens[$pos + 1][0] === \T_WHITESPACE &&
|
||||||
|
isset($tokens[$pos + 2]) &&
|
||||||
|
$tokens[$pos + 2][0] === '(')));
|
||||||
|
}
|
||||||
}
|
}
|
@ -36,7 +36,7 @@ class NameContext
|
|||||||
*
|
*
|
||||||
* @param Name|null $namespace Null is the global namespace
|
* @param Name|null $namespace Null is the global namespace
|
||||||
*/
|
*/
|
||||||
public function startNamespace(Name $namespace = null) {
|
public function startNamespace(?Name $namespace = null) {
|
||||||
$this->namespace = $namespace;
|
$this->namespace = $namespace;
|
||||||
$this->origAliases = $this->aliases = [
|
$this->origAliases = $this->aliases = [
|
||||||
Stmt\Use_::TYPE_NORMAL => [],
|
Stmt\Use_::TYPE_NORMAL => [],
|
||||||
|
@ -27,7 +27,7 @@ class Arg extends NodeAbstract
|
|||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
Expr $value, bool $byRef = false, bool $unpack = false, array $attributes = [],
|
Expr $value, bool $byRef = false, bool $unpack = false, array $attributes = [],
|
||||||
Identifier $name = null
|
?Identifier $name = null
|
||||||
) {
|
) {
|
||||||
$this->attributes = $attributes;
|
$this->attributes = $attributes;
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
|
@ -4,9 +4,6 @@ namespace PhpParser\Node;
|
|||||||
|
|
||||||
use PhpParser\NodeAbstract;
|
use PhpParser\NodeAbstract;
|
||||||
|
|
||||||
/**
|
|
||||||
* @property Name $namespacedName Namespaced name (for global constants, if using NameResolver)
|
|
||||||
*/
|
|
||||||
class Const_ extends NodeAbstract
|
class Const_ extends NodeAbstract
|
||||||
{
|
{
|
||||||
/** @var Identifier Name */
|
/** @var Identifier Name */
|
||||||
@ -14,6 +11,9 @@ class Const_ extends NodeAbstract
|
|||||||
/** @var Expr Value */
|
/** @var Expr Value */
|
||||||
public $value;
|
public $value;
|
||||||
|
|
||||||
|
/** @var Name|null Namespaced name (if using NameResolver) */
|
||||||
|
public $namespacedName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a const node for use in class const and const statements.
|
* Constructs a const node for use in class const and const statements.
|
||||||
*
|
*
|
||||||
|
@ -18,7 +18,7 @@ class ArrayDimFetch extends Expr
|
|||||||
* @param null|Expr $dim Array index / dim
|
* @param null|Expr $dim Array index / dim
|
||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct(Expr $var, Expr $dim = null, array $attributes = []) {
|
public function __construct(Expr $var, ?Expr $dim = null, array $attributes = []) {
|
||||||
$this->attributes = $attributes;
|
$this->attributes = $attributes;
|
||||||
$this->var = $var;
|
$this->var = $var;
|
||||||
$this->dim = $dim;
|
$this->dim = $dim;
|
||||||
|
@ -23,7 +23,7 @@ class ArrayItem extends Expr
|
|||||||
* @param bool $byRef Whether to assign by reference
|
* @param bool $byRef Whether to assign by reference
|
||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct(Expr $value, Expr $key = null, bool $byRef = false, array $attributes = [], bool $unpack = false) {
|
public function __construct(Expr $value, ?Expr $key = null, bool $byRef = false, array $attributes = [], bool $unpack = false) {
|
||||||
$this->attributes = $attributes;
|
$this->attributes = $attributes;
|
||||||
$this->key = $key;
|
$this->key = $key;
|
||||||
$this->value = $value;
|
$this->value = $value;
|
||||||
|
@ -10,14 +10,14 @@ class ClassConstFetch extends Expr
|
|||||||
{
|
{
|
||||||
/** @var Name|Expr Class name */
|
/** @var Name|Expr Class name */
|
||||||
public $class;
|
public $class;
|
||||||
/** @var Identifier|Error Constant name */
|
/** @var Identifier|Expr|Error Constant name */
|
||||||
public $name;
|
public $name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a class const fetch node.
|
* Constructs a class const fetch node.
|
||||||
*
|
*
|
||||||
* @param Name|Expr $class Class name
|
* @param Name|Expr $class Class name
|
||||||
* @param string|Identifier|Error $name Constant name
|
* @param string|Identifier|Expr|Error $name Constant name
|
||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct($class, $name, array $attributes = []) {
|
public function __construct($class, $name, array $attributes = []) {
|
||||||
|
@ -19,7 +19,7 @@ class Exit_ extends Expr
|
|||||||
* @param null|Expr $expr Expression
|
* @param null|Expr $expr Expression
|
||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct(Expr $expr = null, array $attributes = []) {
|
public function __construct(?Expr $expr = null, array $attributes = []) {
|
||||||
$this->attributes = $attributes;
|
$this->attributes = $attributes;
|
||||||
$this->expr = $expr;
|
$this->expr = $expr;
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,15 @@ namespace PhpParser\Node\Expr;
|
|||||||
use PhpParser\Node\Arg;
|
use PhpParser\Node\Arg;
|
||||||
use PhpParser\Node\Expr;
|
use PhpParser\Node\Expr;
|
||||||
use PhpParser\Node\Identifier;
|
use PhpParser\Node\Identifier;
|
||||||
|
use PhpParser\Node\VariadicPlaceholder;
|
||||||
|
|
||||||
class NullsafeMethodCall extends Expr
|
class NullsafeMethodCall extends CallLike
|
||||||
{
|
{
|
||||||
/** @var Expr Variable holding object */
|
/** @var Expr Variable holding object */
|
||||||
public $var;
|
public $var;
|
||||||
/** @var Identifier|Expr Method name */
|
/** @var Identifier|Expr Method name */
|
||||||
public $name;
|
public $name;
|
||||||
/** @var Arg[] Arguments */
|
/** @var array<Arg|VariadicPlaceholder> Arguments */
|
||||||
public $args;
|
public $args;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -20,7 +21,7 @@ class NullsafeMethodCall extends Expr
|
|||||||
*
|
*
|
||||||
* @param Expr $var Variable holding object
|
* @param Expr $var Variable holding object
|
||||||
* @param string|Identifier|Expr $name Method name
|
* @param string|Identifier|Expr $name Method name
|
||||||
* @param Arg[] $args Arguments
|
* @param array<Arg|VariadicPlaceholder> $args Arguments
|
||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct(Expr $var, $name, array $args = [], array $attributes = []) {
|
public function __construct(Expr $var, $name, array $args = [], array $attributes = []) {
|
||||||
@ -37,4 +38,8 @@ class NullsafeMethodCall extends Expr
|
|||||||
public function getType() : string {
|
public function getType() : string {
|
||||||
return 'Expr_NullsafeMethodCall';
|
return 'Expr_NullsafeMethodCall';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getRawArgs(): array {
|
||||||
|
return $this->args;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ class Yield_ extends Expr
|
|||||||
* @param null|Expr $key Key expression
|
* @param null|Expr $key Key expression
|
||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct(Expr $value = null, Expr $key = null, array $attributes = []) {
|
public function __construct(?Expr $value = null, ?Expr $key = null, array $attributes = []) {
|
||||||
$this->attributes = $attributes;
|
$this->attributes = $attributes;
|
||||||
$this->key = $key;
|
$this->key = $key;
|
||||||
$this->value = $value;
|
$this->value = $value;
|
||||||
|
@ -6,7 +6,10 @@ use PhpParser\NodeAbstract;
|
|||||||
|
|
||||||
class Name extends NodeAbstract
|
class Name extends NodeAbstract
|
||||||
{
|
{
|
||||||
/** @var string[] Parts of the name */
|
/**
|
||||||
|
* @var string[] Parts of the name
|
||||||
|
* @deprecated Use getParts() instead
|
||||||
|
*/
|
||||||
public $parts;
|
public $parts;
|
||||||
|
|
||||||
private static $specialClassNames = [
|
private static $specialClassNames = [
|
||||||
@ -30,6 +33,15 @@ class Name extends NodeAbstract
|
|||||||
return ['parts'];
|
return ['parts'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get parts of name (split by the namespace separator).
|
||||||
|
*
|
||||||
|
* @return string[] Parts of name
|
||||||
|
*/
|
||||||
|
public function getParts(): array {
|
||||||
|
return $this->parts;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the first part of the name, i.e. everything before the first namespace separator.
|
* Gets the first part of the name, i.e. everything before the first namespace separator.
|
||||||
*
|
*
|
||||||
@ -150,7 +162,7 @@ class Name extends NodeAbstract
|
|||||||
*
|
*
|
||||||
* @return static|null Sliced name
|
* @return static|null Sliced name
|
||||||
*/
|
*/
|
||||||
public function slice(int $offset, int $length = null) {
|
public function slice(int $offset, ?int $length = null) {
|
||||||
$numParts = count($this->parts);
|
$numParts = count($this->parts);
|
||||||
|
|
||||||
$realOffset = $offset < 0 ? $offset + $numParts : $offset;
|
$realOffset = $offset < 0 ? $offset + $numParts : $offset;
|
||||||
@ -162,7 +174,7 @@ class Name extends NodeAbstract
|
|||||||
$realLength = $numParts - $realOffset;
|
$realLength = $numParts - $realOffset;
|
||||||
} else {
|
} else {
|
||||||
$realLength = $length < 0 ? $length + $numParts - $realOffset : $length;
|
$realLength = $length < 0 ? $length + $numParts - $realOffset : $length;
|
||||||
if ($realLength < 0 || $realLength > $numParts) {
|
if ($realLength < 0 || $realLength > $numParts - $realOffset) {
|
||||||
throw new \OutOfBoundsException(sprintf('Length %d is out of bounds', $length));
|
throw new \OutOfBoundsException(sprintf('Length %d is out of bounds', $length));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ class Param extends NodeAbstract
|
|||||||
* @param AttributeGroup[] $attrGroups PHP attribute groups
|
* @param AttributeGroup[] $attrGroups PHP attribute groups
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
$var, Expr $default = null, $type = null,
|
$var, ?Expr $default = null, $type = null,
|
||||||
bool $byRef = false, bool $variadic = false,
|
bool $byRef = false, bool $variadic = false,
|
||||||
array $attributes = [],
|
array $attributes = [],
|
||||||
int $flags = 0,
|
int $flags = 0,
|
||||||
|
@ -24,6 +24,17 @@ class DNumber extends Scalar
|
|||||||
return ['value'];
|
return ['value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed[] $attributes
|
||||||
|
*/
|
||||||
|
public static function fromString(string $str, array $attributes = []): DNumber
|
||||||
|
{
|
||||||
|
$attributes['rawValue'] = $str;
|
||||||
|
$float = self::parse($str);
|
||||||
|
|
||||||
|
return new DNumber($float, $attributes);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*
|
*
|
||||||
@ -36,13 +47,7 @@ class DNumber extends Scalar
|
|||||||
public static function parse(string $str) : float {
|
public static function parse(string $str) : float {
|
||||||
$str = str_replace('_', '', $str);
|
$str = str_replace('_', '', $str);
|
||||||
|
|
||||||
// if string contains any of .eE just cast it to float
|
// Check whether this is one of the special integer notations.
|
||||||
if (false !== strpbrk($str, '.eE')) {
|
|
||||||
return (float) $str;
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise it's an integer notation that overflowed into a float
|
|
||||||
// if it starts with 0 it's one of the special integer notations
|
|
||||||
if ('0' === $str[0]) {
|
if ('0' === $str[0]) {
|
||||||
// hex
|
// hex
|
||||||
if ('x' === $str[1] || 'X' === $str[1]) {
|
if ('x' === $str[1] || 'X' === $str[1]) {
|
||||||
@ -54,11 +59,13 @@ class DNumber extends Scalar
|
|||||||
return bindec($str);
|
return bindec($str);
|
||||||
}
|
}
|
||||||
|
|
||||||
// oct
|
// oct, but only if the string does not contain any of '.eE'.
|
||||||
// substr($str, 0, strcspn($str, '89')) cuts the string at the first invalid digit (8 or 9)
|
if (false === strpbrk($str, '.eE')) {
|
||||||
// so that only the digits before that are used
|
// substr($str, 0, strcspn($str, '89')) cuts the string at the first invalid digit
|
||||||
|
// (8 or 9) so that only the digits before that are used.
|
||||||
return octdec(substr($str, 0, strcspn($str, '89')));
|
return octdec(substr($str, 0, strcspn($str, '89')));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// dec
|
// dec
|
||||||
return (float) $str;
|
return (float) $str;
|
||||||
|
@ -41,6 +41,8 @@ class LNumber extends Scalar
|
|||||||
* @return LNumber The constructed LNumber, including kind attribute
|
* @return LNumber The constructed LNumber, including kind attribute
|
||||||
*/
|
*/
|
||||||
public static function fromString(string $str, array $attributes = [], bool $allowInvalidOctal = false) : LNumber {
|
public static function fromString(string $str, array $attributes = [], bool $allowInvalidOctal = false) : LNumber {
|
||||||
|
$attributes['rawValue'] = $str;
|
||||||
|
|
||||||
$str = str_replace('_', '', $str);
|
$str = str_replace('_', '', $str);
|
||||||
|
|
||||||
if ('0' !== $str[0] || '0' === $str) {
|
if ('0' !== $str[0] || '0' === $str) {
|
||||||
|
@ -42,6 +42,22 @@ class String_ extends Scalar
|
|||||||
return ['value'];
|
return ['value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $parseUnicodeEscape Whether to parse PHP 7 \u escapes
|
||||||
|
*/
|
||||||
|
public static function fromString(string $str, array $attributes = [], bool $parseUnicodeEscape = true): self
|
||||||
|
{
|
||||||
|
$attributes['kind'] = ($str[0] === "'" || ($str[1] === "'" && ($str[0] === 'b' || $str[0] === 'B')))
|
||||||
|
? Scalar\String_::KIND_SINGLE_QUOTED
|
||||||
|
: Scalar\String_::KIND_DOUBLE_QUOTED;
|
||||||
|
|
||||||
|
$attributes['rawValue'] = $str;
|
||||||
|
|
||||||
|
$string = self::parse($str, $parseUnicodeEscape);
|
||||||
|
|
||||||
|
return new self($string, $attributes);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*
|
*
|
||||||
|
@ -15,7 +15,7 @@ class Break_ extends Node\Stmt
|
|||||||
* @param null|Node\Expr $num Number of loops to break
|
* @param null|Node\Expr $num Number of loops to break
|
||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct(Node\Expr $num = null, array $attributes = []) {
|
public function __construct(?Node\Expr $num = null, array $attributes = []) {
|
||||||
$this->attributes = $attributes;
|
$this->attributes = $attributes;
|
||||||
$this->num = $num;
|
$this->num = $num;
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ class Catch_ extends Node\Stmt
|
|||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
array $types, Expr\Variable $var = null, array $stmts = [], array $attributes = []
|
array $types, ?Expr\Variable $var = null, array $stmts = [], array $attributes = []
|
||||||
) {
|
) {
|
||||||
$this->attributes = $attributes;
|
$this->attributes = $attributes;
|
||||||
$this->types = $types;
|
$this->types = $types;
|
||||||
|
@ -10,8 +10,10 @@ class ClassConst extends Node\Stmt
|
|||||||
public $flags;
|
public $flags;
|
||||||
/** @var Node\Const_[] Constant declarations */
|
/** @var Node\Const_[] Constant declarations */
|
||||||
public $consts;
|
public $consts;
|
||||||
/** @var Node\AttributeGroup[] */
|
/** @var Node\AttributeGroup[] PHP attribute groups */
|
||||||
public $attrGroups;
|
public $attrGroups;
|
||||||
|
/** @var Node\Identifier|Node\Name|Node\ComplexType|null Type declaration */
|
||||||
|
public $type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a class const list node.
|
* Constructs a class const list node.
|
||||||
@ -20,21 +22,24 @@ class ClassConst extends Node\Stmt
|
|||||||
* @param int $flags Modifiers
|
* @param int $flags Modifiers
|
||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
* @param Node\AttributeGroup[] $attrGroups PHP attribute groups
|
* @param Node\AttributeGroup[] $attrGroups PHP attribute groups
|
||||||
|
* @param null|string|Node\Identifier|Node\Name|Node\ComplexType $type Type declaration
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
array $consts,
|
array $consts,
|
||||||
int $flags = 0,
|
int $flags = 0,
|
||||||
array $attributes = [],
|
array $attributes = [],
|
||||||
array $attrGroups = []
|
array $attrGroups = [],
|
||||||
|
$type = null
|
||||||
) {
|
) {
|
||||||
$this->attributes = $attributes;
|
$this->attributes = $attributes;
|
||||||
$this->flags = $flags;
|
$this->flags = $flags;
|
||||||
$this->consts = $consts;
|
$this->consts = $consts;
|
||||||
$this->attrGroups = $attrGroups;
|
$this->attrGroups = $attrGroups;
|
||||||
|
$this->type = \is_string($type) ? new Node\Identifier($type) : $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSubNodeNames() : array {
|
public function getSubNodeNames() : array {
|
||||||
return ['attrGroups', 'flags', 'consts'];
|
return ['attrGroups', 'flags', 'type', 'consts'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,9 +4,6 @@ namespace PhpParser\Node\Stmt;
|
|||||||
|
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
|
|
||||||
/**
|
|
||||||
* @property Node\Name $namespacedName Namespaced name (if using NameResolver)
|
|
||||||
*/
|
|
||||||
abstract class ClassLike extends Node\Stmt
|
abstract class ClassLike extends Node\Stmt
|
||||||
{
|
{
|
||||||
/** @var Node\Identifier|null Name */
|
/** @var Node\Identifier|null Name */
|
||||||
@ -16,6 +13,9 @@ abstract class ClassLike extends Node\Stmt
|
|||||||
/** @var Node\AttributeGroup[] PHP attribute groups */
|
/** @var Node\AttributeGroup[] PHP attribute groups */
|
||||||
public $attrGroups;
|
public $attrGroups;
|
||||||
|
|
||||||
|
/** @var Node\Name|null Namespaced name (if using NameResolver) */
|
||||||
|
public $namespacedName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return TraitUse[]
|
* @return TraitUse[]
|
||||||
*/
|
*/
|
||||||
|
@ -38,6 +38,8 @@ class ClassMethod extends Node\Stmt implements FunctionLike
|
|||||||
'__clone' => true,
|
'__clone' => true,
|
||||||
'__invoke' => true,
|
'__invoke' => true,
|
||||||
'__debuginfo' => true,
|
'__debuginfo' => true,
|
||||||
|
'__serialize' => true,
|
||||||
|
'__unserialize' => true,
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,6 +68,10 @@ class Class_ extends ClassLike
|
|||||||
return (bool) ($this->flags & self::MODIFIER_FINAL);
|
return (bool) ($this->flags & self::MODIFIER_FINAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isReadonly() : bool {
|
||||||
|
return (bool) ($this->flags & self::MODIFIER_READONLY);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the class is anonymous.
|
* Whether the class is anonymous.
|
||||||
*
|
*
|
||||||
@ -77,6 +81,27 @@ class Class_ extends ClassLike
|
|||||||
return null === $this->name;
|
return null === $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
public static function verifyClassModifier($a, $b) {
|
||||||
|
if ($a & self::MODIFIER_ABSTRACT && $b & self::MODIFIER_ABSTRACT) {
|
||||||
|
throw new Error('Multiple abstract modifiers are not allowed');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($a & self::MODIFIER_FINAL && $b & self::MODIFIER_FINAL) {
|
||||||
|
throw new Error('Multiple final modifiers are not allowed');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($a & self::MODIFIER_READONLY && $b & self::MODIFIER_READONLY) {
|
||||||
|
throw new Error('Multiple readonly modifiers are not allowed');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($a & 48 && $b & 48) {
|
||||||
|
throw new Error('Cannot use the final modifier on an abstract class');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
|
@ -15,7 +15,7 @@ class Continue_ extends Node\Stmt
|
|||||||
* @param null|Node\Expr $num Number of loops to continue
|
* @param null|Node\Expr $num Number of loops to continue
|
||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct(Node\Expr $num = null, array $attributes = []) {
|
public function __construct(?Node\Expr $num = null, array $attributes = []) {
|
||||||
$this->attributes = $attributes;
|
$this->attributes = $attributes;
|
||||||
$this->num = $num;
|
$this->num = $num;
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ class Declare_ extends Node\Stmt
|
|||||||
* @param Node\Stmt[]|null $stmts Statements
|
* @param Node\Stmt[]|null $stmts Statements
|
||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct(array $declares, array $stmts = null, array $attributes = []) {
|
public function __construct(array $declares, ?array $stmts = null, array $attributes = []) {
|
||||||
$this->attributes = $attributes;
|
$this->attributes = $attributes;
|
||||||
$this->declares = $declares;
|
$this->declares = $declares;
|
||||||
$this->stmts = $stmts;
|
$this->stmts = $stmts;
|
||||||
|
@ -20,7 +20,7 @@ class EnumCase extends Node\Stmt
|
|||||||
* @param AttributeGroup[] $attrGroups PHP attribute groups
|
* @param AttributeGroup[] $attrGroups PHP attribute groups
|
||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct($name, Node\Expr $expr = null, array $attrGroups = [], array $attributes = []) {
|
public function __construct($name, ?Node\Expr $expr = null, array $attrGroups = [], array $attributes = []) {
|
||||||
parent::__construct($attributes);
|
parent::__construct($attributes);
|
||||||
$this->name = \is_string($name) ? new Node\Identifier($name) : $name;
|
$this->name = \is_string($name) ? new Node\Identifier($name) : $name;
|
||||||
$this->expr = $expr;
|
$this->expr = $expr;
|
||||||
|
@ -5,9 +5,6 @@ namespace PhpParser\Node\Stmt;
|
|||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
use PhpParser\Node\FunctionLike;
|
use PhpParser\Node\FunctionLike;
|
||||||
|
|
||||||
/**
|
|
||||||
* @property Node\Name $namespacedName Namespaced name (if using NameResolver)
|
|
||||||
*/
|
|
||||||
class Function_ extends Node\Stmt implements FunctionLike
|
class Function_ extends Node\Stmt implements FunctionLike
|
||||||
{
|
{
|
||||||
/** @var bool Whether function returns by reference */
|
/** @var bool Whether function returns by reference */
|
||||||
@ -23,6 +20,9 @@ class Function_ extends Node\Stmt implements FunctionLike
|
|||||||
/** @var Node\AttributeGroup[] PHP attribute groups */
|
/** @var Node\AttributeGroup[] PHP attribute groups */
|
||||||
public $attrGroups;
|
public $attrGroups;
|
||||||
|
|
||||||
|
/** @var Node\Name|null Namespaced name (if using NameResolver) */
|
||||||
|
public $namespacedName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a function node.
|
* Constructs a function node.
|
||||||
*
|
*
|
||||||
|
@ -22,7 +22,7 @@ class Namespace_ extends Node\Stmt
|
|||||||
* @param null|Node\Stmt[] $stmts Statements
|
* @param null|Node\Stmt[] $stmts Statements
|
||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct(Node\Name $name = null, $stmts = [], array $attributes = []) {
|
public function __construct(?Node\Name $name = null, $stmts = [], array $attributes = []) {
|
||||||
$this->attributes = $attributes;
|
$this->attributes = $attributes;
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
$this->stmts = $stmts;
|
$this->stmts = $stmts;
|
||||||
|
@ -18,7 +18,7 @@ class PropertyProperty extends Node\Stmt
|
|||||||
* @param null|Node\Expr $default Default value
|
* @param null|Node\Expr $default Default value
|
||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct($name, Node\Expr $default = null, array $attributes = []) {
|
public function __construct($name, ?Node\Expr $default = null, array $attributes = []) {
|
||||||
$this->attributes = $attributes;
|
$this->attributes = $attributes;
|
||||||
$this->name = \is_string($name) ? new Node\VarLikeIdentifier($name) : $name;
|
$this->name = \is_string($name) ? new Node\VarLikeIdentifier($name) : $name;
|
||||||
$this->default = $default;
|
$this->default = $default;
|
||||||
|
@ -15,7 +15,7 @@ class Return_ extends Node\Stmt
|
|||||||
* @param null|Node\Expr $expr Expression
|
* @param null|Node\Expr $expr Expression
|
||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct(Node\Expr $expr = null, array $attributes = []) {
|
public function __construct(?Node\Expr $expr = null, array $attributes = []) {
|
||||||
$this->attributes = $attributes;
|
$this->attributes = $attributes;
|
||||||
$this->expr = $expr;
|
$this->expr = $expr;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ class StaticVar extends Node\Stmt
|
|||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
Expr\Variable $var, Node\Expr $default = null, array $attributes = []
|
Expr\Variable $var, ?Node\Expr $default = null, array $attributes = []
|
||||||
) {
|
) {
|
||||||
$this->attributes = $attributes;
|
$this->attributes = $attributes;
|
||||||
$this->var = $var;
|
$this->var = $var;
|
||||||
|
@ -21,7 +21,7 @@ class TryCatch extends Node\Stmt
|
|||||||
* @param null|Finally_ $finally Optional finally node
|
* @param null|Finally_ $finally Optional finally node
|
||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct(array $stmts, array $catches, Finally_ $finally = null, array $attributes = []) {
|
public function __construct(array $stmts, array $catches, ?Finally_ $finally = null, array $attributes = []) {
|
||||||
$this->attributes = $attributes;
|
$this->attributes = $attributes;
|
||||||
$this->stmts = $stmts;
|
$this->stmts = $stmts;
|
||||||
$this->catches = $catches;
|
$this->catches = $catches;
|
||||||
|
@ -4,13 +4,13 @@ namespace PhpParser\Node;
|
|||||||
|
|
||||||
class UnionType extends ComplexType
|
class UnionType extends ComplexType
|
||||||
{
|
{
|
||||||
/** @var (Identifier|Name)[] Types */
|
/** @var (Identifier|Name|IntersectionType)[] Types */
|
||||||
public $types;
|
public $types;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a union type.
|
* Constructs a union type.
|
||||||
*
|
*
|
||||||
* @param (Identifier|Name)[] $types Types
|
* @param (Identifier|Name|IntersectionType)[] $types Types
|
||||||
* @param array $attributes Additional attributes
|
* @param array $attributes Additional attributes
|
||||||
*/
|
*/
|
||||||
public function __construct(array $types, array $attributes = []) {
|
public function __construct(array $types, array $attributes = []) {
|
||||||
|
@ -39,7 +39,7 @@ class NodeDumper
|
|||||||
*
|
*
|
||||||
* @return string Dumped value
|
* @return string Dumped value
|
||||||
*/
|
*/
|
||||||
public function dump($node, string $code = null) : string {
|
public function dump($node, ?string $code = null) : string {
|
||||||
$this->code = $code;
|
$this->code = $code;
|
||||||
return $this->dumpRecursive($node);
|
return $this->dumpRecursive($node);
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ class NameResolver extends NodeVisitorAbstract
|
|||||||
* @param ErrorHandler|null $errorHandler Error handler
|
* @param ErrorHandler|null $errorHandler Error handler
|
||||||
* @param array $options Options
|
* @param array $options Options
|
||||||
*/
|
*/
|
||||||
public function __construct(ErrorHandler $errorHandler = null, array $options = []) {
|
public function __construct(?ErrorHandler $errorHandler = null, array $options = []) {
|
||||||
$this->nameContext = new NameContext($errorHandler ?? new ErrorHandler\Throwing);
|
$this->nameContext = new NameContext($errorHandler ?? new ErrorHandler\Throwing);
|
||||||
$this->preserveOriginalNames = $options['preserveOriginalNames'] ?? false;
|
$this->preserveOriginalNames = $options['preserveOriginalNames'] ?? false;
|
||||||
$this->replaceNodes = $options['replaceNodes'] ?? true;
|
$this->replaceNodes = $options['replaceNodes'] ?? true;
|
||||||
@ -118,6 +118,9 @@ class NameResolver extends NodeVisitorAbstract
|
|||||||
$this->addNamespacedName($const);
|
$this->addNamespacedName($const);
|
||||||
}
|
}
|
||||||
} else if ($node instanceof Stmt\ClassConst) {
|
} else if ($node instanceof Stmt\ClassConst) {
|
||||||
|
if (null !== $node->type) {
|
||||||
|
$node->type = $this->resolveType($node->type);
|
||||||
|
}
|
||||||
$this->resolveAttrGroups($node);
|
$this->resolveAttrGroups($node);
|
||||||
} else if ($node instanceof Stmt\EnumCase) {
|
} else if ($node instanceof Stmt\EnumCase) {
|
||||||
$this->resolveAttrGroups($node);
|
$this->resolveAttrGroups($node);
|
||||||
@ -161,7 +164,7 @@ class NameResolver extends NodeVisitorAbstract
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function addAlias(Stmt\UseUse $use, $type, Name $prefix = null) {
|
private function addAlias(Stmt\UseUse $use, int $type, ?Name $prefix = null) {
|
||||||
// Add prefix for group uses
|
// Add prefix for group uses
|
||||||
$name = $prefix ? Name::concat($prefix, $use->name) : $use->name;
|
$name = $prefix ? Name::concat($prefix, $use->name) : $use->name;
|
||||||
// Type is determined either by individual element or whole use declaration
|
// Type is determined either by individual element or whole use declaration
|
||||||
|
@ -14,5 +14,5 @@ interface Parser
|
|||||||
* @return Node\Stmt[]|null Array of statements (or null non-throwing error handler is used and
|
* @return Node\Stmt[]|null Array of statements (or null non-throwing error handler is used and
|
||||||
* the parser was unable to recover from an error).
|
* the parser was unable to recover from an error).
|
||||||
*/
|
*/
|
||||||
public function parse(string $code, ErrorHandler $errorHandler = null);
|
public function parse(string $code, ?ErrorHandler $errorHandler = null);
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ class Multiple implements Parser
|
|||||||
$this->parsers = $parsers;
|
$this->parsers = $parsers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function parse(string $code, ErrorHandler $errorHandler = null) {
|
public function parse(string $code, ?ErrorHandler $errorHandler = null) {
|
||||||
if (null === $errorHandler) {
|
if (null === $errorHandler) {
|
||||||
$errorHandler = new ErrorHandler\Throwing;
|
$errorHandler = new ErrorHandler\Throwing;
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2791
lib/PhpParser/Parser/Php8.php
Normal file
2791
lib/PhpParser/Parser/Php8.php
Normal file
File diff suppressed because it is too large
Load Diff
@ -16,9 +16,12 @@ use PhpParser\Node\Scalar\String_;
|
|||||||
use PhpParser\Node\Stmt\Class_;
|
use PhpParser\Node\Stmt\Class_;
|
||||||
use PhpParser\Node\Stmt\ClassConst;
|
use PhpParser\Node\Stmt\ClassConst;
|
||||||
use PhpParser\Node\Stmt\ClassMethod;
|
use PhpParser\Node\Stmt\ClassMethod;
|
||||||
|
use PhpParser\Node\Stmt\Else_;
|
||||||
|
use PhpParser\Node\Stmt\ElseIf_;
|
||||||
use PhpParser\Node\Stmt\Enum_;
|
use PhpParser\Node\Stmt\Enum_;
|
||||||
use PhpParser\Node\Stmt\Interface_;
|
use PhpParser\Node\Stmt\Interface_;
|
||||||
use PhpParser\Node\Stmt\Namespace_;
|
use PhpParser\Node\Stmt\Namespace_;
|
||||||
|
use PhpParser\Node\Stmt\Nop;
|
||||||
use PhpParser\Node\Stmt\Property;
|
use PhpParser\Node\Stmt\Property;
|
||||||
use PhpParser\Node\Stmt\TryCatch;
|
use PhpParser\Node\Stmt\TryCatch;
|
||||||
use PhpParser\Node\Stmt\UseUse;
|
use PhpParser\Node\Stmt\UseUse;
|
||||||
@ -152,7 +155,7 @@ abstract class ParserAbstract implements Parser
|
|||||||
* @return Node\Stmt[]|null Array of statements (or null non-throwing error handler is used and
|
* @return Node\Stmt[]|null Array of statements (or null non-throwing error handler is used and
|
||||||
* the parser was unable to recover from an error).
|
* the parser was unable to recover from an error).
|
||||||
*/
|
*/
|
||||||
public function parse(string $code, ErrorHandler $errorHandler = null) {
|
public function parse(string $code, ?ErrorHandler $errorHandler = null) {
|
||||||
$this->errorHandler = $errorHandler ?: new ErrorHandler\Throwing;
|
$this->errorHandler = $errorHandler ?: new ErrorHandler\Throwing;
|
||||||
|
|
||||||
$this->lexer->startLexing($code, $this->errorHandler);
|
$this->lexer->startLexing($code, $this->errorHandler);
|
||||||
@ -664,6 +667,7 @@ abstract class ParserAbstract implements Parser
|
|||||||
'false' => true,
|
'false' => true,
|
||||||
'mixed' => true,
|
'mixed' => true,
|
||||||
'never' => true,
|
'never' => true,
|
||||||
|
'true' => true,
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!$name->isUnqualified()) {
|
if (!$name->isUnqualified()) {
|
||||||
@ -875,6 +879,33 @@ abstract class ParserAbstract implements Parser
|
|||||||
return $attributes;
|
return $attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param ElseIf_|Else_ $node */
|
||||||
|
protected function fixupAlternativeElse($node) {
|
||||||
|
// Make sure a trailing nop statement carrying comments is part of the node.
|
||||||
|
$numStmts = \count($node->stmts);
|
||||||
|
if ($numStmts !== 0 && $node->stmts[$numStmts - 1] instanceof Nop) {
|
||||||
|
$nopAttrs = $node->stmts[$numStmts - 1]->getAttributes();
|
||||||
|
if (isset($nopAttrs['endLine'])) {
|
||||||
|
$node->setAttribute('endLine', $nopAttrs['endLine']);
|
||||||
|
}
|
||||||
|
if (isset($nopAttrs['endFilePos'])) {
|
||||||
|
$node->setAttribute('endFilePos', $nopAttrs['endFilePos']);
|
||||||
|
}
|
||||||
|
if (isset($nopAttrs['endTokenPos'])) {
|
||||||
|
$node->setAttribute('endTokenPos', $nopAttrs['endTokenPos']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function checkClassModifier($a, $b, $modifierPos) {
|
||||||
|
try {
|
||||||
|
Class_::verifyClassModifier($a, $b);
|
||||||
|
} catch (Error $error) {
|
||||||
|
$error->setAttributes($this->getAttributesAt($modifierPos));
|
||||||
|
$this->emitError($error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected function checkModifier($a, $b, $modifierPos) {
|
protected function checkModifier($a, $b, $modifierPos) {
|
||||||
// Jumping through some hoops here because verifyModifier() is also used elsewhere
|
// Jumping through some hoops here because verifyModifier() is also used elsewhere
|
||||||
try {
|
try {
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
namespace PhpParser;
|
namespace PhpParser;
|
||||||
|
|
||||||
|
use PhpParser\Lexer\Emulative;
|
||||||
|
use PhpParser\Parser\Php7;
|
||||||
|
|
||||||
class ParserFactory
|
class ParserFactory
|
||||||
{
|
{
|
||||||
const PREFER_PHP7 = 1;
|
const PREFER_PHP7 = 1;
|
||||||
@ -18,7 +21,7 @@ class ParserFactory
|
|||||||
*
|
*
|
||||||
* @return Parser The parser instance
|
* @return Parser The parser instance
|
||||||
*/
|
*/
|
||||||
public function create(int $kind, Lexer $lexer = null, array $parserOptions = []) : Parser {
|
public function create(int $kind, ?Lexer $lexer = null, array $parserOptions = []) : Parser {
|
||||||
if (null === $lexer) {
|
if (null === $lexer) {
|
||||||
$lexer = new Lexer\Emulative();
|
$lexer = new Lexer\Emulative();
|
||||||
}
|
}
|
||||||
@ -41,4 +44,33 @@ class ParserFactory
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a parser targeting the newest version supported by this library. Code for older
|
||||||
|
* versions will be accepted if there have been no relevant backwards-compatibility breaks in
|
||||||
|
* PHP.
|
||||||
|
*
|
||||||
|
* All supported lexer attributes (comments, startLine, endLine, startTokenPos, endTokenPos,
|
||||||
|
* startFilePos, endFilePos) will be enabled.
|
||||||
|
*/
|
||||||
|
public function createForNewestSupportedVersion(): Parser {
|
||||||
|
return new Php7(new Emulative($this->getLexerOptions()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a parser targeting the host PHP version, that is the PHP version we're currently
|
||||||
|
* running on. This parser will not use any token emulation.
|
||||||
|
*
|
||||||
|
* All supported lexer attributes (comments, startLine, endLine, startTokenPos, endTokenPos,
|
||||||
|
* startFilePos, endFilePos) will be enabled.
|
||||||
|
*/
|
||||||
|
public function createForHostVersion(): Parser {
|
||||||
|
return new Php7(new Lexer($this->getLexerOptions()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getLexerOptions(): array {
|
||||||
|
return ['usedAttributes' => [
|
||||||
|
'comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos', 'startFilePos', 'endFilePos',
|
||||||
|
]];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,15 @@ class Standard extends PrettyPrinterAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function pUnionType(Node\UnionType $node) {
|
protected function pUnionType(Node\UnionType $node) {
|
||||||
return $this->pImplode($node->types, '|');
|
$types = [];
|
||||||
|
foreach ($node->types as $typeNode) {
|
||||||
|
if ($typeNode instanceof Node\IntersectionType) {
|
||||||
|
$types[] = '('. $this->p($typeNode) . ')';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$types[] = $this->p($typeNode);
|
||||||
|
}
|
||||||
|
return implode('|', $types);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function pIntersectionType(Node\IntersectionType $node) {
|
protected function pIntersectionType(Node\IntersectionType $node) {
|
||||||
@ -521,7 +529,7 @@ class Standard extends PrettyPrinterAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function pExpr_StaticCall(Expr\StaticCall $node) {
|
protected function pExpr_StaticCall(Expr\StaticCall $node) {
|
||||||
return $this->pDereferenceLhs($node->class) . '::'
|
return $this->pStaticDereferenceLhs($node->class) . '::'
|
||||||
. ($node->name instanceof Expr
|
. ($node->name instanceof Expr
|
||||||
? ($node->name instanceof Expr\Variable
|
? ($node->name instanceof Expr\Variable
|
||||||
? $this->p($node->name)
|
? $this->p($node->name)
|
||||||
@ -598,7 +606,7 @@ class Standard extends PrettyPrinterAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function pExpr_ClassConstFetch(Expr\ClassConstFetch $node) {
|
protected function pExpr_ClassConstFetch(Expr\ClassConstFetch $node) {
|
||||||
return $this->pDereferenceLhs($node->class) . '::' . $this->p($node->name);
|
return $this->pStaticDereferenceLhs($node->class) . '::' . $this->pObjectProperty($node->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function pExpr_PropertyFetch(Expr\PropertyFetch $node) {
|
protected function pExpr_PropertyFetch(Expr\PropertyFetch $node) {
|
||||||
@ -610,7 +618,7 @@ class Standard extends PrettyPrinterAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function pExpr_StaticPropertyFetch(Expr\StaticPropertyFetch $node) {
|
protected function pExpr_StaticPropertyFetch(Expr\StaticPropertyFetch $node) {
|
||||||
return $this->pDereferenceLhs($node->class) . '::$' . $this->pObjectProperty($node->name);
|
return $this->pStaticDereferenceLhs($node->class) . '::$' . $this->pObjectProperty($node->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function pExpr_ShellExec(Expr\ShellExec $node) {
|
protected function pExpr_ShellExec(Expr\ShellExec $node) {
|
||||||
@ -806,7 +814,9 @@ class Standard extends PrettyPrinterAbstract
|
|||||||
protected function pStmt_ClassConst(Stmt\ClassConst $node) {
|
protected function pStmt_ClassConst(Stmt\ClassConst $node) {
|
||||||
return $this->pAttrGroups($node->attrGroups)
|
return $this->pAttrGroups($node->attrGroups)
|
||||||
. $this->pModifiers($node->flags)
|
. $this->pModifiers($node->flags)
|
||||||
. 'const ' . $this->pCommaSeparated($node->consts) . ';';
|
. 'const '
|
||||||
|
. (null !== $node->type ? $this->p($node->type) . ' ' : '')
|
||||||
|
. $this->pCommaSeparated($node->consts) . ';';
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function pStmt_Function(Stmt\Function_ $node) {
|
protected function pStmt_Function(Stmt\Function_ $node) {
|
||||||
@ -1059,6 +1069,14 @@ class Standard extends PrettyPrinterAbstract
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function pStaticDereferenceLhs(Node $node) {
|
||||||
|
if (!$this->staticDereferenceLhsRequiresParens($node)) {
|
||||||
|
return $this->p($node);
|
||||||
|
} else {
|
||||||
|
return '(' . $this->p($node) . ')';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected function pCallLhs(Node $node) {
|
protected function pCallLhs(Node $node) {
|
||||||
if (!$this->callLhsRequiresParens($node)) {
|
if (!$this->callLhsRequiresParens($node)) {
|
||||||
return $this->p($node);
|
return $this->p($node);
|
||||||
@ -1067,9 +1085,12 @@ class Standard extends PrettyPrinterAbstract
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function pNewVariable(Node $node) {
|
protected function pNewVariable(Node $node): string {
|
||||||
// TODO: This is not fully accurate.
|
if (!$this->newOperandRequiresParens($node)) {
|
||||||
return $this->pDereferenceLhs($node);
|
return $this->p($node);
|
||||||
|
} else {
|
||||||
|
return '(' . $this->p($node) . ')';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,6 +21,8 @@ abstract class PrettyPrinterAbstract
|
|||||||
const FIXUP_BRACED_NAME = 4; // Name operand that may require bracing
|
const FIXUP_BRACED_NAME = 4; // Name operand that may require bracing
|
||||||
const FIXUP_VAR_BRACED_NAME = 5; // Name operand that may require ${} bracing
|
const FIXUP_VAR_BRACED_NAME = 5; // Name operand that may require ${} bracing
|
||||||
const FIXUP_ENCAPSED = 6; // Encapsed string part
|
const FIXUP_ENCAPSED = 6; // Encapsed string part
|
||||||
|
const FIXUP_NEW = 7; // New/instanceof operand
|
||||||
|
const FIXUP_STATIC_DEREF_LHS = 8; // LHS of static dereferencing operation
|
||||||
|
|
||||||
protected $precedenceMap = [
|
protected $precedenceMap = [
|
||||||
// [precedence, associativity]
|
// [precedence, associativity]
|
||||||
@ -656,7 +658,7 @@ abstract class PrettyPrinterAbstract
|
|||||||
$result .= $extraLeft;
|
$result .= $extraLeft;
|
||||||
|
|
||||||
$origIndentLevel = $this->indentLevel;
|
$origIndentLevel = $this->indentLevel;
|
||||||
$this->setIndentLevel($this->origTokens->getIndentationBefore($subStartPos) + $indentAdjustment);
|
$this->setIndentLevel(max($this->origTokens->getIndentationBefore($subStartPos) + $indentAdjustment, 0));
|
||||||
|
|
||||||
// If it's the same node that was previously in this position, it certainly doesn't
|
// If it's the same node that was previously in this position, it certainly doesn't
|
||||||
// need fixup. It's important to check this here, because our fixup checks are more
|
// need fixup. It's important to check this here, because our fixup checks are more
|
||||||
@ -759,7 +761,7 @@ abstract class PrettyPrinterAbstract
|
|||||||
\assert($itemStartPos >= 0 && $itemEndPos >= 0 && $itemStartPos >= $pos);
|
\assert($itemStartPos >= 0 && $itemEndPos >= 0 && $itemStartPos >= $pos);
|
||||||
|
|
||||||
$origIndentLevel = $this->indentLevel;
|
$origIndentLevel = $this->indentLevel;
|
||||||
$lastElemIndentLevel = $this->origTokens->getIndentationBefore($itemStartPos) + $indentAdjustment;
|
$lastElemIndentLevel = max($this->origTokens->getIndentationBefore($itemStartPos) + $indentAdjustment, 0);
|
||||||
$this->setIndentLevel($lastElemIndentLevel);
|
$this->setIndentLevel($lastElemIndentLevel);
|
||||||
|
|
||||||
$comments = $arrItem->getComments();
|
$comments = $arrItem->getComments();
|
||||||
@ -774,7 +776,8 @@ abstract class PrettyPrinterAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($skipRemovedNode) {
|
if ($skipRemovedNode) {
|
||||||
if ($isStmtList && $this->origTokens->haveBracesInRange($pos, $itemStartPos)) {
|
if ($isStmtList && ($this->origTokens->haveBracesInRange($pos, $itemStartPos) ||
|
||||||
|
$this->origTokens->haveTagInRange($pos, $itemStartPos))) {
|
||||||
// We'd remove the brace of a code block.
|
// We'd remove the brace of a code block.
|
||||||
// TODO: Preserve formatting.
|
// TODO: Preserve formatting.
|
||||||
$this->setIndentLevel($origIndentLevel);
|
$this->setIndentLevel($origIndentLevel);
|
||||||
@ -877,7 +880,8 @@ abstract class PrettyPrinterAbstract
|
|||||||
$pos, $itemStartPos, $indentAdjustment);
|
$pos, $itemStartPos, $indentAdjustment);
|
||||||
$skipRemovedNode = true;
|
$skipRemovedNode = true;
|
||||||
} else {
|
} else {
|
||||||
if ($isStmtList && $this->origTokens->haveBracesInRange($pos, $itemStartPos)) {
|
if ($isStmtList && ($this->origTokens->haveBracesInRange($pos, $itemStartPos) ||
|
||||||
|
$this->origTokens->haveTagInRange($pos, $itemStartPos))) {
|
||||||
// We'd remove the brace of a code block.
|
// We'd remove the brace of a code block.
|
||||||
// TODO: Preserve formatting.
|
// TODO: Preserve formatting.
|
||||||
return null;
|
return null;
|
||||||
@ -923,11 +927,14 @@ abstract class PrettyPrinterAbstract
|
|||||||
foreach ($delayedAdd as $delayedAddNode) {
|
foreach ($delayedAdd as $delayedAddNode) {
|
||||||
if (!$first) {
|
if (!$first) {
|
||||||
$result .= $insertStr;
|
$result .= $insertStr;
|
||||||
|
if ($insertNewline) {
|
||||||
|
$result .= $this->nl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$result .= $this->p($delayedAddNode, true);
|
$result .= $this->p($delayedAddNode, true);
|
||||||
$first = false;
|
$first = false;
|
||||||
}
|
}
|
||||||
$result .= $extraRight;
|
$result .= $extraRight === "\n" ? $this->nl : $extraRight;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
@ -972,6 +979,19 @@ abstract class PrettyPrinterAbstract
|
|||||||
return '(' . $this->p($subNode) . ')';
|
return '(' . $this->p($subNode) . ')';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case self::FIXUP_STATIC_DEREF_LHS:
|
||||||
|
if ($this->staticDereferenceLhsRequiresParens($subNode)
|
||||||
|
&& !$this->origTokens->haveParens($subStartPos, $subEndPos)
|
||||||
|
) {
|
||||||
|
return '(' . $this->p($subNode) . ')';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case self::FIXUP_NEW:
|
||||||
|
if ($this->newOperandRequiresParens($subNode)
|
||||||
|
&& !$this->origTokens->haveParens($subStartPos, $subEndPos)) {
|
||||||
|
return '(' . $this->p($subNode) . ')';
|
||||||
|
}
|
||||||
|
break;
|
||||||
case self::FIXUP_BRACED_NAME:
|
case self::FIXUP_BRACED_NAME:
|
||||||
case self::FIXUP_VAR_BRACED_NAME:
|
case self::FIXUP_VAR_BRACED_NAME:
|
||||||
if ($subNode instanceof Expr
|
if ($subNode instanceof Expr
|
||||||
@ -1042,13 +1062,26 @@ abstract class PrettyPrinterAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether the LHS of a dereferencing operation must be wrapped in parenthesis.
|
* Determines whether the LHS of an array/object operation must be wrapped in parentheses.
|
||||||
*
|
*
|
||||||
* @param Node $node LHS of dereferencing operation
|
* @param Node $node LHS of dereferencing operation
|
||||||
*
|
*
|
||||||
* @return bool Whether parentheses are required
|
* @return bool Whether parentheses are required
|
||||||
*/
|
*/
|
||||||
protected function dereferenceLhsRequiresParens(Node $node) : bool {
|
protected function dereferenceLhsRequiresParens(Node $node) : bool {
|
||||||
|
// A constant can occur on the LHS of an array/object deref, but not a static deref.
|
||||||
|
return $this->staticDereferenceLhsRequiresParens($node)
|
||||||
|
&& !$node instanceof Expr\ConstFetch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the LHS of a static operation must be wrapped in parentheses.
|
||||||
|
*
|
||||||
|
* @param Node $node LHS of dereferencing operation
|
||||||
|
*
|
||||||
|
* @return bool Whether parentheses are required
|
||||||
|
*/
|
||||||
|
protected function staticDereferenceLhsRequiresParens(Node $node): bool {
|
||||||
return !($node instanceof Expr\Variable
|
return !($node instanceof Expr\Variable
|
||||||
|| $node instanceof Node\Name
|
|| $node instanceof Node\Name
|
||||||
|| $node instanceof Expr\ArrayDimFetch
|
|| $node instanceof Expr\ArrayDimFetch
|
||||||
@ -1061,10 +1094,31 @@ abstract class PrettyPrinterAbstract
|
|||||||
|| $node instanceof Expr\StaticCall
|
|| $node instanceof Expr\StaticCall
|
||||||
|| $node instanceof Expr\Array_
|
|| $node instanceof Expr\Array_
|
||||||
|| $node instanceof Scalar\String_
|
|| $node instanceof Scalar\String_
|
||||||
|| $node instanceof Expr\ConstFetch
|
|
||||||
|| $node instanceof Expr\ClassConstFetch);
|
|| $node instanceof Expr\ClassConstFetch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether an expression used in "new" or "instanceof" requires parentheses.
|
||||||
|
*
|
||||||
|
* @param Node $node New or instanceof operand
|
||||||
|
*
|
||||||
|
* @return bool Whether parentheses are required
|
||||||
|
*/
|
||||||
|
protected function newOperandRequiresParens(Node $node): bool {
|
||||||
|
if ($node instanceof Node\Name || $node instanceof Expr\Variable) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($node instanceof Expr\ArrayDimFetch || $node instanceof Expr\PropertyFetch ||
|
||||||
|
$node instanceof Expr\NullsafePropertyFetch
|
||||||
|
) {
|
||||||
|
return $this->newOperandRequiresParens($node->var);
|
||||||
|
}
|
||||||
|
if ($node instanceof Expr\StaticPropertyFetch) {
|
||||||
|
return $this->newOperandRequiresParens($node->class);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print modifiers, including trailing whitespace.
|
* Print modifiers, including trailing whitespace.
|
||||||
*
|
*
|
||||||
@ -1166,7 +1220,7 @@ abstract class PrettyPrinterAbstract
|
|||||||
Expr\PostDec::class => ['var' => self::FIXUP_PREC_LEFT],
|
Expr\PostDec::class => ['var' => self::FIXUP_PREC_LEFT],
|
||||||
Expr\Instanceof_::class => [
|
Expr\Instanceof_::class => [
|
||||||
'expr' => self::FIXUP_PREC_LEFT,
|
'expr' => self::FIXUP_PREC_LEFT,
|
||||||
'class' => self::FIXUP_PREC_RIGHT, // TODO: FIXUP_NEW_VARIABLE
|
'class' => self::FIXUP_NEW,
|
||||||
],
|
],
|
||||||
Expr\Ternary::class => [
|
Expr\Ternary::class => [
|
||||||
'cond' => self::FIXUP_PREC_LEFT,
|
'cond' => self::FIXUP_PREC_LEFT,
|
||||||
@ -1174,10 +1228,13 @@ abstract class PrettyPrinterAbstract
|
|||||||
],
|
],
|
||||||
|
|
||||||
Expr\FuncCall::class => ['name' => self::FIXUP_CALL_LHS],
|
Expr\FuncCall::class => ['name' => self::FIXUP_CALL_LHS],
|
||||||
Expr\StaticCall::class => ['class' => self::FIXUP_DEREF_LHS],
|
Expr\StaticCall::class => ['class' => self::FIXUP_STATIC_DEREF_LHS],
|
||||||
Expr\ArrayDimFetch::class => ['var' => self::FIXUP_DEREF_LHS],
|
Expr\ArrayDimFetch::class => ['var' => self::FIXUP_DEREF_LHS],
|
||||||
Expr\ClassConstFetch::class => ['var' => self::FIXUP_DEREF_LHS],
|
Expr\ClassConstFetch::class => [
|
||||||
Expr\New_::class => ['class' => self::FIXUP_DEREF_LHS], // TODO: FIXUP_NEW_VARIABLE
|
'class' => self::FIXUP_STATIC_DEREF_LHS,
|
||||||
|
'name' => self::FIXUP_BRACED_NAME,
|
||||||
|
],
|
||||||
|
Expr\New_::class => ['class' => self::FIXUP_NEW],
|
||||||
Expr\MethodCall::class => [
|
Expr\MethodCall::class => [
|
||||||
'var' => self::FIXUP_DEREF_LHS,
|
'var' => self::FIXUP_DEREF_LHS,
|
||||||
'name' => self::FIXUP_BRACED_NAME,
|
'name' => self::FIXUP_BRACED_NAME,
|
||||||
@ -1187,7 +1244,7 @@ abstract class PrettyPrinterAbstract
|
|||||||
'name' => self::FIXUP_BRACED_NAME,
|
'name' => self::FIXUP_BRACED_NAME,
|
||||||
],
|
],
|
||||||
Expr\StaticPropertyFetch::class => [
|
Expr\StaticPropertyFetch::class => [
|
||||||
'class' => self::FIXUP_DEREF_LHS,
|
'class' => self::FIXUP_STATIC_DEREF_LHS,
|
||||||
'name' => self::FIXUP_VAR_BRACED_NAME,
|
'name' => self::FIXUP_VAR_BRACED_NAME,
|
||||||
],
|
],
|
||||||
Expr\PropertyFetch::class => [
|
Expr\PropertyFetch::class => [
|
||||||
@ -1273,6 +1330,7 @@ abstract class PrettyPrinterAbstract
|
|||||||
'Param->default' => $stripEquals,
|
'Param->default' => $stripEquals,
|
||||||
'Stmt_Break->num' => $stripBoth,
|
'Stmt_Break->num' => $stripBoth,
|
||||||
'Stmt_Catch->var' => $stripLeft,
|
'Stmt_Catch->var' => $stripLeft,
|
||||||
|
'Stmt_ClassConst->type' => $stripRight,
|
||||||
'Stmt_ClassMethod->returnType' => $stripColon,
|
'Stmt_ClassMethod->returnType' => $stripColon,
|
||||||
'Stmt_Class->extends' => ['left' => \T_EXTENDS],
|
'Stmt_Class->extends' => ['left' => \T_EXTENDS],
|
||||||
'Stmt_Enum->scalarType' => $stripColon,
|
'Stmt_Enum->scalarType' => $stripColon,
|
||||||
@ -1314,6 +1372,7 @@ abstract class PrettyPrinterAbstract
|
|||||||
'Stmt_Break->num' => [\T_BREAK, false, ' ', null],
|
'Stmt_Break->num' => [\T_BREAK, false, ' ', null],
|
||||||
'Stmt_Catch->var' => [null, false, ' ', null],
|
'Stmt_Catch->var' => [null, false, ' ', null],
|
||||||
'Stmt_ClassMethod->returnType' => [')', false, ' : ', null],
|
'Stmt_ClassMethod->returnType' => [')', false, ' : ', null],
|
||||||
|
'Stmt_ClassConst->type' => [\T_CONST, false, ' ', null],
|
||||||
'Stmt_Class->extends' => [null, false, ' extends ', null],
|
'Stmt_Class->extends' => [null, false, ' extends ', null],
|
||||||
'Stmt_Enum->scalarType' => [null, false, ' : ', null],
|
'Stmt_Enum->scalarType' => [null, false, ' : ', null],
|
||||||
'Stmt_EnumCase->expr' => [null, false, ' = ', null],
|
'Stmt_EnumCase->expr' => [null, false, ' = ', null],
|
||||||
@ -1454,6 +1513,16 @@ abstract class PrettyPrinterAbstract
|
|||||||
'Stmt_ClassMethod->params' => ['(', '', ''],
|
'Stmt_ClassMethod->params' => ['(', '', ''],
|
||||||
'Stmt_Interface->extends' => [null, ' extends ', ''],
|
'Stmt_Interface->extends' => [null, ' extends ', ''],
|
||||||
'Stmt_Function->params' => ['(', '', ''],
|
'Stmt_Function->params' => ['(', '', ''],
|
||||||
|
'Stmt_Interface->attrGroups' => [null, '', "\n"],
|
||||||
|
'Stmt_Class->attrGroups' => [null, '', "\n"],
|
||||||
|
'Stmt_ClassConst->attrGroups' => [null, '', "\n"],
|
||||||
|
'Stmt_ClassMethod->attrGroups' => [null, '', "\n"],
|
||||||
|
'Stmt_Function->attrGroups' => [null, '', "\n"],
|
||||||
|
'Stmt_Property->attrGroups' => [null, '', "\n"],
|
||||||
|
'Stmt_Trait->attrGroups' => [null, '', "\n"],
|
||||||
|
'Expr_ArrowFunction->attrGroups' => [null, '', ' '],
|
||||||
|
'Expr_Closure->attrGroups' => [null, '', ' '],
|
||||||
|
'Expr_PrintableNewAnonClass->attrGroups' => [\T_NEW, ' ', ''],
|
||||||
|
|
||||||
/* These cannot be empty to start with:
|
/* These cannot be empty to start with:
|
||||||
* Expr_Isset->vars
|
* Expr_Isset->vars
|
||||||
@ -1493,6 +1562,7 @@ abstract class PrettyPrinterAbstract
|
|||||||
'Stmt_ClassMethod->flags' => \T_FUNCTION,
|
'Stmt_ClassMethod->flags' => \T_FUNCTION,
|
||||||
'Stmt_Class->flags' => \T_CLASS,
|
'Stmt_Class->flags' => \T_CLASS,
|
||||||
'Stmt_Property->flags' => \T_VARIABLE,
|
'Stmt_Property->flags' => \T_VARIABLE,
|
||||||
|
'Expr_PrintableNewAnonClass->flags' => \T_CLASS,
|
||||||
'Param->flags' => \T_VARIABLE,
|
'Param->flags' => \T_VARIABLE,
|
||||||
//'Stmt_TraitUseAdaptation_Alias->newModifier' => 0, // TODO
|
//'Stmt_TraitUseAdaptation_Alias->newModifier' => 0, // TODO
|
||||||
];
|
];
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
||||||
backupGlobals="false"
|
backupGlobals="false"
|
||||||
colors="true"
|
colors="true"
|
||||||
|
convertDeprecationsToExceptions="true"
|
||||||
beStrictAboutTestsThatDoNotTestAnything="false"
|
beStrictAboutTestsThatDoNotTestAnything="false"
|
||||||
bootstrap="./test/bootstrap.php">
|
bootstrap="./test/bootstrap.php">
|
||||||
<testsuites>
|
<testsuites>
|
||||||
|
@ -142,6 +142,18 @@ class ClassConstTest extends \PHPUnit\Framework\TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testType() {
|
||||||
|
$node = $this->createClassConstBuilder('TYPE', 1)
|
||||||
|
->setType('int')
|
||||||
|
->getNode();
|
||||||
|
$this->assertEquals(
|
||||||
|
new Stmt\ClassConst(
|
||||||
|
[new Const_('TYPE', new LNumber(1))],
|
||||||
|
0, [], [], new Identifier('int')),
|
||||||
|
$node
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider provideTestDefaultValues
|
* @dataProvider provideTestDefaultValues
|
||||||
*/
|
*/
|
||||||
|
@ -68,6 +68,20 @@ class ClassTest extends \PHPUnit\Framework\TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testReadonly() {
|
||||||
|
$node = $this->createClassBuilder('Test')
|
||||||
|
->makeReadonly()
|
||||||
|
->getNode()
|
||||||
|
;
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
new Stmt\Class_('Test', [
|
||||||
|
'flags' => Stmt\Class_::MODIFIER_READONLY
|
||||||
|
]),
|
||||||
|
$node
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function testStatementOrder() {
|
public function testStatementOrder() {
|
||||||
$method = new Stmt\ClassMethod('testMethod');
|
$method = new Stmt\ClassMethod('testMethod');
|
||||||
$property = new Stmt\Property(
|
$property = new Stmt\Property(
|
||||||
|
84
test/PhpParser/Builder/EnumCaseTest.php
Normal file
84
test/PhpParser/Builder/EnumCaseTest.php
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser\Comment;
|
||||||
|
use PhpParser\Node\Arg;
|
||||||
|
use PhpParser\Node\Attribute;
|
||||||
|
use PhpParser\Node\AttributeGroup;
|
||||||
|
use PhpParser\Node\Identifier;
|
||||||
|
use PhpParser\Node\Name;
|
||||||
|
use PhpParser\Node\Scalar;
|
||||||
|
use PhpParser\Node\Scalar\LNumber;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
|
class EnumCaseTest extends \PHPUnit\Framework\TestCase
|
||||||
|
{
|
||||||
|
public function createEnumCaseBuilder($name) {
|
||||||
|
return new EnumCase($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDocComment() {
|
||||||
|
$node = $this->createEnumCaseBuilder('TEST')
|
||||||
|
->setDocComment('/** Test */')
|
||||||
|
->getNode();
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
new Stmt\EnumCase(
|
||||||
|
"TEST",
|
||||||
|
null,
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
'comments' => [new Comment\Doc('/** Test */')]
|
||||||
|
]
|
||||||
|
),
|
||||||
|
$node
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAddAttribute() {
|
||||||
|
$attribute = new Attribute(
|
||||||
|
new Name('Attr'),
|
||||||
|
[new Arg(new LNumber(1), false, false, [], new Identifier('name'))]
|
||||||
|
);
|
||||||
|
$attributeGroup = new AttributeGroup([$attribute]);
|
||||||
|
|
||||||
|
$node = $this->createEnumCaseBuilder('ATTR_GROUP')
|
||||||
|
->addAttribute($attributeGroup)
|
||||||
|
->getNode();
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
new Stmt\EnumCase(
|
||||||
|
"ATTR_GROUP",
|
||||||
|
null,
|
||||||
|
[$attributeGroup]
|
||||||
|
),
|
||||||
|
$node
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideTestDefaultValues
|
||||||
|
*/
|
||||||
|
public function testValues($value, $expectedValueNode) {
|
||||||
|
$node = $this->createEnumCaseBuilder('TEST')
|
||||||
|
->setValue($value)
|
||||||
|
->getNode()
|
||||||
|
;
|
||||||
|
|
||||||
|
$this->assertEquals($expectedValueNode, $node->expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideTestDefaultValues() {
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
31415,
|
||||||
|
new Scalar\LNumber(31415)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'Hallo World',
|
||||||
|
new Scalar\String_('Hallo World')
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
159
test/PhpParser/Builder/EnumTest.php
Normal file
159
test/PhpParser/Builder/EnumTest.php
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser\Comment;
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Arg;
|
||||||
|
use PhpParser\Node\Attribute;
|
||||||
|
use PhpParser\Node\AttributeGroup;
|
||||||
|
use PhpParser\Node\Identifier;
|
||||||
|
use PhpParser\Node\Name;
|
||||||
|
use PhpParser\Node\Scalar\LNumber;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
|
class EnumTest extends \PHPUnit\Framework\TestCase
|
||||||
|
{
|
||||||
|
protected function createEnumBuilder($class) {
|
||||||
|
return new Enum_($class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testImplements() {
|
||||||
|
$node = $this->createEnumBuilder('SomeEnum')
|
||||||
|
->implement('Namespaced\SomeInterface', new Name('OtherInterface'))
|
||||||
|
->getNode()
|
||||||
|
;
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
new Stmt\Enum_('SomeEnum', [
|
||||||
|
'implements' => [
|
||||||
|
new Name('Namespaced\SomeInterface'),
|
||||||
|
new Name('OtherInterface'),
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
$node
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetScalarType() {
|
||||||
|
$node = $this->createEnumBuilder('Test')
|
||||||
|
->setScalarType('int')
|
||||||
|
->getNode()
|
||||||
|
;
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
new Stmt\Enum_('Test', [
|
||||||
|
'scalarType' => new Identifier('int'),
|
||||||
|
]),
|
||||||
|
$node
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testStatementOrder() {
|
||||||
|
$method = new Stmt\ClassMethod('testMethod');
|
||||||
|
$enumCase = new Stmt\EnumCase(
|
||||||
|
'TEST_ENUM_CASE'
|
||||||
|
);
|
||||||
|
$const = new Stmt\ClassConst([
|
||||||
|
new Node\Const_('TEST_CONST', new Node\Scalar\String_('ABC'))
|
||||||
|
]);
|
||||||
|
$use = new Stmt\TraitUse([new Name('SomeTrait')]);
|
||||||
|
|
||||||
|
$node = $this->createEnumBuilder('Test')
|
||||||
|
->addStmt($method)
|
||||||
|
->addStmt($enumCase)
|
||||||
|
->addStmts([$const, $use])
|
||||||
|
->getNode()
|
||||||
|
;
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
new Stmt\Enum_('Test', [
|
||||||
|
'stmts' => [$use, $enumCase, $const, $method]
|
||||||
|
]),
|
||||||
|
$node
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDocComment() {
|
||||||
|
$docComment = <<<'DOC'
|
||||||
|
/**
|
||||||
|
* Test
|
||||||
|
*/
|
||||||
|
DOC;
|
||||||
|
$enum = $this->createEnumBuilder('Test')
|
||||||
|
->setDocComment($docComment)
|
||||||
|
->getNode();
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
new Stmt\Enum_('Test', [], [
|
||||||
|
'comments' => [
|
||||||
|
new Comment\Doc($docComment)
|
||||||
|
]
|
||||||
|
]),
|
||||||
|
$enum
|
||||||
|
);
|
||||||
|
|
||||||
|
$enum = $this->createEnumBuilder('Test')
|
||||||
|
->setDocComment(new Comment\Doc($docComment))
|
||||||
|
->getNode();
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
new Stmt\Enum_('Test', [], [
|
||||||
|
'comments' => [
|
||||||
|
new Comment\Doc($docComment)
|
||||||
|
]
|
||||||
|
]),
|
||||||
|
$enum
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAddAttribute() {
|
||||||
|
$attribute = new Attribute(
|
||||||
|
new Name('Attr'),
|
||||||
|
[new Arg(new LNumber(1), false, false, [], new Identifier('name'))]
|
||||||
|
);
|
||||||
|
$attributeGroup = new AttributeGroup([$attribute]);
|
||||||
|
|
||||||
|
$enum = $this->createEnumBuilder('ATTR_GROUP')
|
||||||
|
->addAttribute($attributeGroup)
|
||||||
|
->getNode();
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
new Stmt\Enum_('ATTR_GROUP', [
|
||||||
|
'attrGroups' => [
|
||||||
|
$attributeGroup,
|
||||||
|
]
|
||||||
|
], []),
|
||||||
|
$enum
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInvalidStmtError() {
|
||||||
|
$this->expectException(\LogicException::class);
|
||||||
|
$this->expectExceptionMessage('Unexpected node of type "Stmt_PropertyProperty"');
|
||||||
|
$this->createEnumBuilder('Test')
|
||||||
|
->addStmt(new Stmt\PropertyProperty('property'))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInvalidDocComment() {
|
||||||
|
$this->expectException(\LogicException::class);
|
||||||
|
$this->expectExceptionMessage('Doc comment must be a string or an instance of PhpParser\Comment\Doc');
|
||||||
|
$this->createEnumBuilder('Test')
|
||||||
|
->setDocComment(new Comment('Test'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEmptyName() {
|
||||||
|
$this->expectException(\LogicException::class);
|
||||||
|
$this->expectExceptionMessage('Name cannot be empty');
|
||||||
|
$this->createEnumBuilder('Test')
|
||||||
|
->implement('');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInvalidName() {
|
||||||
|
$this->expectException(\LogicException::class);
|
||||||
|
$this->expectExceptionMessage('Name must be a string or an instance of Node\Name');
|
||||||
|
$this->createEnumBuilder('Test')
|
||||||
|
->implement(['Foo']);
|
||||||
|
}
|
||||||
|
}
|
@ -205,6 +205,54 @@ class ParamTest extends \PHPUnit\Framework\TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testMakePublic() {
|
||||||
|
$node = $this->createParamBuilder('test')
|
||||||
|
->makePublic()
|
||||||
|
->getNode()
|
||||||
|
;
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
new Node\Param(new Expr\Variable('test'), null, null, false, false, [], Node\Stmt\Class_::MODIFIER_PUBLIC),
|
||||||
|
$node
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMakeProtected() {
|
||||||
|
$node = $this->createParamBuilder('test')
|
||||||
|
->makeProtected()
|
||||||
|
->getNode()
|
||||||
|
;
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
new Node\Param(new Expr\Variable('test'), null, null, false, false, [], Node\Stmt\Class_::MODIFIER_PROTECTED),
|
||||||
|
$node
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMakePrivate() {
|
||||||
|
$node = $this->createParamBuilder('test')
|
||||||
|
->makePrivate()
|
||||||
|
->getNode()
|
||||||
|
;
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
new Node\Param(new Expr\Variable('test'), null, null, false, false, [], Node\Stmt\Class_::MODIFIER_PRIVATE),
|
||||||
|
$node
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMakeReadonly() {
|
||||||
|
$node = $this->createParamBuilder('test')
|
||||||
|
->makeReadonly()
|
||||||
|
->getNode()
|
||||||
|
;
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
new Node\Param(new Expr\Variable('test'), null, null, false, false, [], Node\Stmt\Class_::MODIFIER_READONLY),
|
||||||
|
$node
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function testAddAttribute() {
|
public function testAddAttribute() {
|
||||||
$attribute = new Attribute(
|
$attribute = new Attribute(
|
||||||
new Name('Attr'),
|
new Name('Attr'),
|
||||||
|
@ -27,6 +27,7 @@ class BuilderFactoryTest extends \PHPUnit\Framework\TestCase
|
|||||||
['class', Builder\Class_::class],
|
['class', Builder\Class_::class],
|
||||||
['interface', Builder\Interface_::class],
|
['interface', Builder\Interface_::class],
|
||||||
['trait', Builder\Trait_::class],
|
['trait', Builder\Trait_::class],
|
||||||
|
['enum', Builder\Enum_::class],
|
||||||
['method', Builder\Method::class],
|
['method', Builder\Method::class],
|
||||||
['function', Builder\Function_::class],
|
['function', Builder\Function_::class],
|
||||||
['property', Builder\Property::class],
|
['property', Builder\Property::class],
|
||||||
@ -34,6 +35,7 @@ class BuilderFactoryTest extends \PHPUnit\Framework\TestCase
|
|||||||
['use', Builder\Use_::class],
|
['use', Builder\Use_::class],
|
||||||
['useFunction', Builder\Use_::class],
|
['useFunction', Builder\Use_::class],
|
||||||
['useConst', Builder\Use_::class],
|
['useConst', Builder\Use_::class],
|
||||||
|
['enumCase', Builder\EnumCase::class],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,6 +210,10 @@ class BuilderFactoryTest extends \PHPUnit\Framework\TestCase
|
|||||||
new Expr\ClassConstFetch(new Expr\Variable('foo'), new Identifier('BAR')),
|
new Expr\ClassConstFetch(new Expr\Variable('foo'), new Identifier('BAR')),
|
||||||
$factory->classConstFetch(new Expr\Variable('foo'), 'BAR')
|
$factory->classConstFetch(new Expr\Variable('foo'), 'BAR')
|
||||||
);
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
new Expr\ClassConstFetch(new Name('Foo'), new Expr\Variable('foo')),
|
||||||
|
$factory->classConstFetch('Foo', $factory->var('foo'))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testVar() {
|
public function testVar() {
|
||||||
@ -241,7 +247,7 @@ class BuilderFactoryTest extends \PHPUnit\Framework\TestCase
|
|||||||
public function testInvalidIdentifier() {
|
public function testInvalidIdentifier() {
|
||||||
$this->expectException(\LogicException::class);
|
$this->expectException(\LogicException::class);
|
||||||
$this->expectExceptionMessage('Expected string or instance of Node\Identifier');
|
$this->expectExceptionMessage('Expected string or instance of Node\Identifier');
|
||||||
(new BuilderFactory())->classConstFetch('Foo', new Expr\Variable('foo'));
|
(new BuilderFactory())->classConstFetch('Foo', new Name('foo'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testInvalidIdentifierOrExpr() {
|
public function testInvalidIdentifierOrExpr() {
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
namespace PhpParser;
|
namespace PhpParser;
|
||||||
|
|
||||||
use PhpParser\Builder\Class_;
|
use PhpParser\Builder\Class_;
|
||||||
|
use PhpParser\Node\Identifier;
|
||||||
|
use PhpParser\Node\Name\FullyQualified;
|
||||||
use PhpParser\Node\Scalar;
|
use PhpParser\Node\Scalar;
|
||||||
use PhpParser\Node\Stmt;
|
use PhpParser\Node\Stmt;
|
||||||
use PhpParser\Node\Expr;
|
use PhpParser\Node\Expr;
|
||||||
@ -125,8 +127,11 @@ class BuilderHelpersTest extends \PHPUnit\Framework\TestCase
|
|||||||
$this->assertEquals(new Node\Identifier('iterable'), BuilderHelpers::normalizeType('iterable'));
|
$this->assertEquals(new Node\Identifier('iterable'), BuilderHelpers::normalizeType('iterable'));
|
||||||
$this->assertEquals(new Node\Identifier('void'), BuilderHelpers::normalizeType('void'));
|
$this->assertEquals(new Node\Identifier('void'), BuilderHelpers::normalizeType('void'));
|
||||||
$this->assertEquals(new Node\Identifier('object'), BuilderHelpers::normalizeType('object'));
|
$this->assertEquals(new Node\Identifier('object'), BuilderHelpers::normalizeType('object'));
|
||||||
|
$this->assertEquals(new Node\Identifier('null'), BuilderHelpers::normalizeType('null'));
|
||||||
|
$this->assertEquals(new Node\Identifier('false'), BuilderHelpers::normalizeType('false'));
|
||||||
$this->assertEquals(new Node\Identifier('mixed'), BuilderHelpers::normalizeType('mixed'));
|
$this->assertEquals(new Node\Identifier('mixed'), BuilderHelpers::normalizeType('mixed'));
|
||||||
$this->assertEquals(new Node\Identifier('never'), BuilderHelpers::normalizeType('never'));
|
$this->assertEquals(new Node\Identifier('never'), BuilderHelpers::normalizeType('never'));
|
||||||
|
$this->assertEquals(new Node\Identifier('true'), BuilderHelpers::normalizeType('true'));
|
||||||
|
|
||||||
$intIdentifier = new Node\Identifier('int');
|
$intIdentifier = new Node\Identifier('int');
|
||||||
$this->assertSame($intIdentifier, BuilderHelpers::normalizeType($intIdentifier));
|
$this->assertSame($intIdentifier, BuilderHelpers::normalizeType($intIdentifier));
|
||||||
@ -219,4 +224,14 @@ class BuilderHelpersTest extends \PHPUnit\Framework\TestCase
|
|||||||
$this->expectExceptionMessage('Attribute must be an instance of PhpParser\Node\Attribute or PhpParser\Node\AttributeGroup');
|
$this->expectExceptionMessage('Attribute must be an instance of PhpParser\Node\Attribute or PhpParser\Node\AttributeGroup');
|
||||||
BuilderHelpers::normalizeAttribute('test');
|
BuilderHelpers::normalizeAttribute('test');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testNormalizeValueEnum() {
|
||||||
|
if (\PHP_VERSION_ID <= 80100) {
|
||||||
|
$this->markTestSkipped('Enums are supported since PHP 8.1');
|
||||||
|
}
|
||||||
|
|
||||||
|
include __DIR__ . '/../fixtures/Suit.php';
|
||||||
|
|
||||||
|
$this->assertEquals(new Expr\ClassConstFetch(new FullyQualified(\Suit::class), new Identifier('Hearts')), BuilderHelpers::normalizeValue(\Suit::Hearts));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -241,8 +241,8 @@ class EmulativeTest extends LexerTest
|
|||||||
['1_000', [
|
['1_000', [
|
||||||
[Tokens::T_LNUMBER, '1_000'],
|
[Tokens::T_LNUMBER, '1_000'],
|
||||||
]],
|
]],
|
||||||
['0xCAFE_F00D', [
|
['0x7AFE_F00D', [
|
||||||
[Tokens::T_LNUMBER, '0xCAFE_F00D'],
|
[Tokens::T_LNUMBER, '0x7AFE_F00D'],
|
||||||
]],
|
]],
|
||||||
['0b0101_1111', [
|
['0b0101_1111', [
|
||||||
[Tokens::T_LNUMBER, '0b0101_1111'],
|
[Tokens::T_LNUMBER, '0b0101_1111'],
|
||||||
@ -354,6 +354,20 @@ class EmulativeTest extends LexerTest
|
|||||||
['0o1000000000000000000000', [
|
['0o1000000000000000000000', [
|
||||||
[Tokens::T_DNUMBER, '0o1000000000000000000000'],
|
[Tokens::T_DNUMBER, '0o1000000000000000000000'],
|
||||||
]],
|
]],
|
||||||
|
['readonly class', [
|
||||||
|
[Tokens::T_READONLY, 'readonly'],
|
||||||
|
[Tokens::T_CLASS, 'class'],
|
||||||
|
]],
|
||||||
|
['function readonly(', [
|
||||||
|
[Tokens::T_FUNCTION, 'function'],
|
||||||
|
[Tokens::T_READONLY, 'readonly'],
|
||||||
|
[ord('('), '('],
|
||||||
|
]],
|
||||||
|
['function readonly (', [
|
||||||
|
[Tokens::T_FUNCTION, 'function'],
|
||||||
|
[Tokens::T_READONLY, 'readonly'],
|
||||||
|
[ord('('), '('],
|
||||||
|
]],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,8 +29,10 @@ class CallableLikeTest extends \PHPUnit\Framework\TestCase {
|
|||||||
[new StaticCall(new Name('Test'), 'test', $normalArgs), false],
|
[new StaticCall(new Name('Test'), 'test', $normalArgs), false],
|
||||||
[new StaticCall(new Name('Test'), 'test', $callableArgs), true],
|
[new StaticCall(new Name('Test'), 'test', $callableArgs), true],
|
||||||
[new New_(new Name('Test'), $normalArgs), false],
|
[new New_(new Name('Test'), $normalArgs), false],
|
||||||
|
[new NullsafeMethodCall(new Variable('this'), 'test', $normalArgs), false],
|
||||||
// This is not legal code, but accepted by the parser.
|
// This is not legal code, but accepted by the parser.
|
||||||
[new New_(new Name('Test'), $callableArgs), true],
|
[new New_(new Name('Test'), $callableArgs), true],
|
||||||
|
[new NullsafeMethodCall(new Variable('this'), 'test', $callableArgs), true],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,10 +19,12 @@ class NameTest extends \PHPUnit\Framework\TestCase
|
|||||||
$name = new Name('foo');
|
$name = new Name('foo');
|
||||||
$this->assertSame('foo', $name->getFirst());
|
$this->assertSame('foo', $name->getFirst());
|
||||||
$this->assertSame('foo', $name->getLast());
|
$this->assertSame('foo', $name->getLast());
|
||||||
|
$this->assertSame(['foo'], $name->getParts());
|
||||||
|
|
||||||
$name = new Name('foo\bar');
|
$name = new Name('foo\bar');
|
||||||
$this->assertSame('foo', $name->getFirst());
|
$this->assertSame('foo', $name->getFirst());
|
||||||
$this->assertSame('bar', $name->getLast());
|
$this->assertSame('bar', $name->getLast());
|
||||||
|
$this->assertSame(['foo', 'bar'], $name->getParts());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testToString() {
|
public function testToString() {
|
||||||
@ -73,6 +75,12 @@ class NameTest extends \PHPUnit\Framework\TestCase
|
|||||||
(new Name('foo\bar\baz'))->slice(0, -4);
|
(new Name('foo\bar\baz'))->slice(0, -4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSliceLengthTooLargeWithOffset() {
|
||||||
|
$this->expectException(\OutOfBoundsException::class);
|
||||||
|
$this->expectExceptionMessage('Length 3 is out of bounds');
|
||||||
|
(new Name('foo\bar\baz'))->slice(1, 3);
|
||||||
|
}
|
||||||
|
|
||||||
public function testConcat() {
|
public function testConcat() {
|
||||||
$this->assertEquals(new Name('foo\bar\baz'), Name::concat('foo', 'bar\baz'));
|
$this->assertEquals(new Name('foo\bar\baz'), Name::concat('foo', 'bar\baz'));
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
|
27
test/PhpParser/Node/Scalar/DNumberTest.php
Normal file
27
test/PhpParser/Node/Scalar/DNumberTest.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Node\Scalar;
|
||||||
|
|
||||||
|
use PhpParser\Node\Stmt\Echo_;
|
||||||
|
use PhpParser\ParserFactory;
|
||||||
|
|
||||||
|
class DNumberTest extends \PHPUnit\Framework\TestCase
|
||||||
|
{
|
||||||
|
public function testRawValue()
|
||||||
|
{
|
||||||
|
$parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
|
||||||
|
$nodes = $parser->parse('<?php echo 1_234.56;');
|
||||||
|
|
||||||
|
$echo = $nodes[0];
|
||||||
|
$this->assertInstanceOf(Echo_::class, $echo);
|
||||||
|
|
||||||
|
/** @var Echo_ $echo */
|
||||||
|
$lLumber = $echo->exprs[0];
|
||||||
|
$this->assertInstanceOf(DNumber::class, $lLumber);
|
||||||
|
|
||||||
|
/** @var DNumber $dnumber */
|
||||||
|
$this->assertSame(1234.56, $lLumber->value);
|
||||||
|
$this->assertSame('1_234.56', $lLumber->getAttribute('rawValue'));
|
||||||
|
}
|
||||||
|
}
|
26
test/PhpParser/Node/Scalar/NumberTest.php
Normal file
26
test/PhpParser/Node/Scalar/NumberTest.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Node\Scalar;
|
||||||
|
|
||||||
|
use PhpParser\Node\Stmt\Echo_;
|
||||||
|
use PhpParser\ParserFactory;
|
||||||
|
|
||||||
|
class NumberTest extends \PHPUnit\Framework\TestCase
|
||||||
|
{
|
||||||
|
public function testRawValue()
|
||||||
|
{
|
||||||
|
$parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
|
||||||
|
$nodes = $parser->parse('<?php echo 1_234;');
|
||||||
|
|
||||||
|
$echo = $nodes[0];
|
||||||
|
$this->assertInstanceOf(Echo_::class, $echo);
|
||||||
|
|
||||||
|
/** @var Echo_ $echo */
|
||||||
|
$lLumber = $echo->exprs[0];
|
||||||
|
$this->assertInstanceOf(LNumber::class, $lLumber);
|
||||||
|
|
||||||
|
/** @var LNumber $lnumber */
|
||||||
|
$this->assertSame(1234, $lLumber->value);
|
||||||
|
$this->assertSame('1_234', $lLumber->getAttribute('rawValue'));
|
||||||
|
}
|
||||||
|
}
|
@ -2,8 +2,28 @@
|
|||||||
|
|
||||||
namespace PhpParser\Node\Scalar;
|
namespace PhpParser\Node\Scalar;
|
||||||
|
|
||||||
|
use PhpParser\Node\Stmt\Echo_;
|
||||||
|
use PhpParser\ParserFactory;
|
||||||
|
|
||||||
class StringTest extends \PHPUnit\Framework\TestCase
|
class StringTest extends \PHPUnit\Framework\TestCase
|
||||||
{
|
{
|
||||||
|
public function testRawValue()
|
||||||
|
{
|
||||||
|
$parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
|
||||||
|
$nodes = $parser->parse('<?php echo "sequence \x41";');
|
||||||
|
|
||||||
|
$echo = $nodes[0];
|
||||||
|
$this->assertInstanceOf(Echo_::class, $echo);
|
||||||
|
|
||||||
|
/** @var Echo_ $echo */
|
||||||
|
$string = $echo->exprs[0];
|
||||||
|
$this->assertInstanceOf(String_::class, $string);
|
||||||
|
|
||||||
|
/** @var String_ $string */
|
||||||
|
$this->assertSame('sequence A', $string->value);
|
||||||
|
$this->assertSame('"sequence \\x41"', $string->getAttribute('rawValue'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider provideTestParseEscapeSequences
|
* @dataProvider provideTestParseEscapeSequences
|
||||||
*/
|
*/
|
||||||
|
@ -6,11 +6,13 @@ class DummyNode extends NodeAbstract
|
|||||||
{
|
{
|
||||||
public $subNode1;
|
public $subNode1;
|
||||||
public $subNode2;
|
public $subNode2;
|
||||||
|
public $notSubNode;
|
||||||
|
|
||||||
public function __construct($subNode1, $subNode2, $attributes) {
|
public function __construct($subNode1, $subNode2, $notSubNode, $attributes) {
|
||||||
parent::__construct($attributes);
|
parent::__construct($attributes);
|
||||||
$this->subNode1 = $subNode1;
|
$this->subNode1 = $subNode1;
|
||||||
$this->subNode2 = $subNode2;
|
$this->subNode2 = $subNode2;
|
||||||
|
$this->notSubNode = $notSubNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSubNodeNames() : array {
|
public function getSubNodeNames() : array {
|
||||||
@ -40,8 +42,7 @@ class NodeAbstractTest extends \PHPUnit\Framework\TestCase
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$node = new DummyNode('value1', 'value2', $attributes);
|
$node = new DummyNode('value1', 'value2', 'value3', $attributes);
|
||||||
$node->notSubNode = 'value3';
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
[$attributes, $node],
|
[$attributes, $node],
|
||||||
@ -64,9 +65,9 @@ class NodeAbstractTest extends \PHPUnit\Framework\TestCase
|
|||||||
$this->assertSame('/** doc comment */', $node->getDocComment()->getText());
|
$this->assertSame('/** doc comment */', $node->getDocComment()->getText());
|
||||||
$this->assertSame('value1', $node->subNode1);
|
$this->assertSame('value1', $node->subNode1);
|
||||||
$this->assertSame('value2', $node->subNode2);
|
$this->assertSame('value2', $node->subNode2);
|
||||||
$this->assertObjectHasAttribute('subNode1', $node);
|
$this->assertTrue(isset($node->subNode1));
|
||||||
$this->assertObjectHasAttribute('subNode2', $node);
|
$this->assertTrue(isset($node->subNode2));
|
||||||
$this->assertObjectNotHasAttribute('subNode3', $node);
|
$this->assertTrue(!isset($node->subNode3));
|
||||||
$this->assertSame($attributes, $node->getAttributes());
|
$this->assertSame($attributes, $node->getAttributes());
|
||||||
$this->assertSame($attributes['comments'], $node->getComments());
|
$this->assertSame($attributes['comments'], $node->getComments());
|
||||||
|
|
||||||
@ -90,7 +91,7 @@ class NodeAbstractTest extends \PHPUnit\Framework\TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function testSetDocComment() {
|
public function testSetDocComment() {
|
||||||
$node = new DummyNode(null, null, []);
|
$node = new DummyNode(null, null, null, []);
|
||||||
|
|
||||||
// Add doc comment to node without comments
|
// Add doc comment to node without comments
|
||||||
$docComment = new Comment\Doc('/** doc */');
|
$docComment = new Comment\Doc('/** doc */');
|
||||||
@ -120,19 +121,19 @@ class NodeAbstractTest extends \PHPUnit\Framework\TestCase
|
|||||||
/**
|
/**
|
||||||
* @dataProvider provideNodes
|
* @dataProvider provideNodes
|
||||||
*/
|
*/
|
||||||
public function testChange(array $attributes, Node $node) {
|
public function testChange(array $attributes, DummyNode $node) {
|
||||||
// direct modification
|
// direct modification
|
||||||
$node->subNode = 'newValue';
|
$node->subNode1 = 'newValue';
|
||||||
$this->assertSame('newValue', $node->subNode);
|
$this->assertSame('newValue', $node->subNode1);
|
||||||
|
|
||||||
// indirect modification
|
// indirect modification
|
||||||
$subNode =& $node->subNode;
|
$subNode =& $node->subNode1;
|
||||||
$subNode = 'newNewValue';
|
$subNode = 'newNewValue';
|
||||||
$this->assertSame('newNewValue', $node->subNode);
|
$this->assertSame('newNewValue', $node->subNode1);
|
||||||
|
|
||||||
// removal
|
// removal
|
||||||
unset($node->subNode);
|
unset($node->subNode1);
|
||||||
$this->assertObjectNotHasAttribute('subNode', $node);
|
$this->assertFalse(isset($node->subNode1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -244,6 +245,7 @@ PHP;
|
|||||||
"attributes": {
|
"attributes": {
|
||||||
"startLine": 4,
|
"startLine": 4,
|
||||||
"endLine": 4,
|
"endLine": 4,
|
||||||
|
"rawValue": "0",
|
||||||
"kind": 10
|
"kind": 10
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -272,7 +274,8 @@ PHP;
|
|||||||
"value": 1,
|
"value": 1,
|
||||||
"attributes": {
|
"attributes": {
|
||||||
"startLine": 4,
|
"startLine": 4,
|
||||||
"endLine": 4
|
"endLine": 4,
|
||||||
|
"rawValue": "1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flags": 0,
|
"flags": 0,
|
||||||
@ -294,7 +297,8 @@ PHP;
|
|||||||
"attributes": {
|
"attributes": {
|
||||||
"startLine": 5,
|
"startLine": 5,
|
||||||
"endLine": 5,
|
"endLine": 5,
|
||||||
"kind": 1
|
"kind": 1,
|
||||||
|
"rawValue": "'Foo'"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -305,6 +309,7 @@ PHP;
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"attrGroups": [],
|
"attrGroups": [],
|
||||||
|
"namespacedName": null,
|
||||||
"attributes": {
|
"attributes": {
|
||||||
"startLine": 4,
|
"startLine": 4,
|
||||||
"comments": [
|
"comments": [
|
||||||
@ -396,6 +401,7 @@ JSON;
|
|||||||
"attributes": {
|
"attributes": {
|
||||||
"startLine": 4,
|
"startLine": 4,
|
||||||
"endLine": 4,
|
"endLine": 4,
|
||||||
|
"rawValue": "0",
|
||||||
"kind": 10
|
"kind": 10
|
||||||
},
|
},
|
||||||
"value": 0
|
"value": 0
|
||||||
@ -424,7 +430,8 @@ JSON;
|
|||||||
"nodeType": "Scalar_DNumber",
|
"nodeType": "Scalar_DNumber",
|
||||||
"attributes": {
|
"attributes": {
|
||||||
"startLine": 4,
|
"startLine": 4,
|
||||||
"endLine": 4
|
"endLine": 4,
|
||||||
|
"rawValue": "1.0"
|
||||||
},
|
},
|
||||||
"value": 1
|
"value": 1
|
||||||
},
|
},
|
||||||
@ -446,14 +453,16 @@ JSON;
|
|||||||
"attributes": {
|
"attributes": {
|
||||||
"startLine": 5,
|
"startLine": 5,
|
||||||
"endLine": 5,
|
"endLine": 5,
|
||||||
"kind": 1
|
"kind": 1,
|
||||||
|
"rawValue": "'Foo'"
|
||||||
},
|
},
|
||||||
"value": "Foo"
|
"value": "Foo"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"attrGroups": []
|
"attrGroups": [],
|
||||||
|
"namespacedName": null
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
JSON;
|
JSON;
|
||||||
|
@ -198,6 +198,10 @@ class A extends B implements C, D {
|
|||||||
|
|
||||||
#[X]
|
#[X]
|
||||||
const C = 1;
|
const C = 1;
|
||||||
|
|
||||||
|
public const X A = X::Bar;
|
||||||
|
public const X\Foo B = X\Foo::Bar;
|
||||||
|
public const \X\Foo C = \X\Foo::Bar;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[X]
|
#[X]
|
||||||
@ -263,6 +267,9 @@ class A extends \NS\B implements \NS\C, \NS\D
|
|||||||
public \NS\A|\NS\B|int $prop;
|
public \NS\A|\NS\B|int $prop;
|
||||||
#[\NS\X]
|
#[\NS\X]
|
||||||
const C = 1;
|
const C = 1;
|
||||||
|
public const \NS\X A = \NS\X::Bar;
|
||||||
|
public const \NS\X\Foo B = \NS\X\Foo::Bar;
|
||||||
|
public const \X\Foo C = \X\Foo::Bar;
|
||||||
}
|
}
|
||||||
#[\NS\X]
|
#[\NS\X]
|
||||||
interface A extends \NS\C, \NS\D
|
interface A extends \NS\C, \NS\D
|
||||||
@ -353,7 +360,7 @@ EOC;
|
|||||||
$this->assertSame('NS\\C', (string) $stmts[0]->stmts[2]->namespacedName);
|
$this->assertSame('NS\\C', (string) $stmts[0]->stmts[2]->namespacedName);
|
||||||
$this->assertSame('NS\\D', (string) $stmts[0]->stmts[3]->consts[0]->namespacedName);
|
$this->assertSame('NS\\D', (string) $stmts[0]->stmts[3]->consts[0]->namespacedName);
|
||||||
$this->assertSame('NS\\E', (string) $stmts[0]->stmts[4]->namespacedName);
|
$this->assertSame('NS\\E', (string) $stmts[0]->stmts[4]->namespacedName);
|
||||||
$this->assertObjectNotHasAttribute('namespacedName', $stmts[0]->stmts[5]->class);
|
$this->assertNull($stmts[0]->stmts[5]->class->namespacedName);
|
||||||
$this->assertSame('NS\\F', (string) $stmts[0]->stmts[6]->namespacedName);
|
$this->assertSame('NS\\F', (string) $stmts[0]->stmts[6]->namespacedName);
|
||||||
|
|
||||||
$stmts = $traverser->traverse([new Stmt\Namespace_(null, $nsStmts)]);
|
$stmts = $traverser->traverse([new Stmt\Namespace_(null, $nsStmts)]);
|
||||||
@ -362,7 +369,7 @@ EOC;
|
|||||||
$this->assertSame('C', (string) $stmts[0]->stmts[2]->namespacedName);
|
$this->assertSame('C', (string) $stmts[0]->stmts[2]->namespacedName);
|
||||||
$this->assertSame('D', (string) $stmts[0]->stmts[3]->consts[0]->namespacedName);
|
$this->assertSame('D', (string) $stmts[0]->stmts[3]->consts[0]->namespacedName);
|
||||||
$this->assertSame('E', (string) $stmts[0]->stmts[4]->namespacedName);
|
$this->assertSame('E', (string) $stmts[0]->stmts[4]->namespacedName);
|
||||||
$this->assertObjectNotHasAttribute('namespacedName', $stmts[0]->stmts[5]->class);
|
$this->assertNull($stmts[0]->stmts[5]->class->namespacedName);
|
||||||
$this->assertSame('F', (string) $stmts[0]->stmts[6]->namespacedName);
|
$this->assertSame('F', (string) $stmts[0]->stmts[6]->namespacedName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,12 +83,12 @@ class MultipleTest extends ParserTest
|
|||||||
$this->expectExceptionMessage('FAIL A');
|
$this->expectExceptionMessage('FAIL A');
|
||||||
|
|
||||||
$parserA = new class implements \PhpParser\Parser {
|
$parserA = new class implements \PhpParser\Parser {
|
||||||
public function parse(string $code, ErrorHandler $errorHandler = null) {
|
public function parse(string $code, ?ErrorHandler $errorHandler = null) {
|
||||||
throw new Error('FAIL A');
|
throw new Error('FAIL A');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
$parserB = new class implements \PhpParser\Parser {
|
$parserB = new class implements \PhpParser\Parser {
|
||||||
public function parse(string $code, ErrorHandler $errorHandler = null) {
|
public function parse(string $code, ?ErrorHandler $errorHandler = null) {
|
||||||
throw new Error('FAIL B');
|
throw new Error('FAIL B');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -5,6 +5,8 @@ namespace PhpParser;
|
|||||||
/* This test is very weak, because PHPUnit's assertEquals assertion is way too slow dealing with the
|
/* This test is very weak, because PHPUnit's assertEquals assertion is way too slow dealing with the
|
||||||
* large objects involved here. So we just do some basic instanceof tests instead. */
|
* large objects involved here. So we just do some basic instanceof tests instead. */
|
||||||
|
|
||||||
|
use PhpParser\Node\Stmt\Echo_;
|
||||||
|
|
||||||
class ParserFactoryTest extends \PHPUnit\Framework\TestCase
|
class ParserFactoryTest extends \PHPUnit\Framework\TestCase
|
||||||
{
|
{
|
||||||
/** @dataProvider provideTestCreate */
|
/** @dataProvider provideTestCreate */
|
||||||
@ -33,4 +35,26 @@ class ParserFactoryTest extends \PHPUnit\Framework\TestCase
|
|||||||
]
|
]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @dataProvider provideTestLexerAttributes */
|
||||||
|
public function testLexerAttributes(Parser $parser) {
|
||||||
|
$stmts = $parser->parse("<?php /* Bar */ echo 'Foo';");
|
||||||
|
$stmt = $stmts[0];
|
||||||
|
$this->assertInstanceOf(Echo_::class, $stmt);
|
||||||
|
$this->assertCount(1, $stmt->getComments());
|
||||||
|
$this->assertSame(1, $stmt->getStartLine());
|
||||||
|
$this->assertSame(1, $stmt->getEndLine());
|
||||||
|
$this->assertSame(3, $stmt->getStartTokenPos());
|
||||||
|
$this->assertSame(6, $stmt->getEndTokenPos());
|
||||||
|
$this->assertSame(16, $stmt->getStartFilePos());
|
||||||
|
$this->assertSame(26, $stmt->getEndFilePos());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideTestLexerAttributes() {
|
||||||
|
$factory = new ParserFactory();
|
||||||
|
return [
|
||||||
|
[$factory->createForHostVersion()],
|
||||||
|
[$factory->createForNewestSupportedVersion()],
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,12 +102,16 @@ function() {};
|
|||||||
fn()
|
fn()
|
||||||
=> 42;
|
=> 42;
|
||||||
-----
|
-----
|
||||||
// TODO: Currently we lose formatting for this case.
|
|
||||||
$attrGroup = new Node\AttributeGroup([
|
$attrGroup = new Node\AttributeGroup([
|
||||||
new Node\Attribute(new Node\Name('A'), []),
|
new Node\Attribute(new Node\Name('A'), []),
|
||||||
]);
|
]);
|
||||||
|
$attrGroup2 = new Node\AttributeGroup([
|
||||||
|
new Node\Attribute(new Node\Name('B'), []),
|
||||||
|
]);
|
||||||
$stmts[0]->attrGroups[] = $attrGroup;
|
$stmts[0]->attrGroups[] = $attrGroup;
|
||||||
|
$stmts[0]->attrGroups[] = $attrGroup2;
|
||||||
$stmts[0]->stmts[0]->attrGroups[] = $attrGroup;
|
$stmts[0]->stmts[0]->attrGroups[] = $attrGroup;
|
||||||
|
$stmts[0]->stmts[0]->attrGroups[] = $attrGroup2;
|
||||||
$stmts[0]->stmts[1]->attrGroups[] = $attrGroup;
|
$stmts[0]->stmts[1]->attrGroups[] = $attrGroup;
|
||||||
$stmts[0]->stmts[2]->attrGroups[] = $attrGroup;
|
$stmts[0]->stmts[2]->attrGroups[] = $attrGroup;
|
||||||
$stmts[1]->attrGroups[] = $attrGroup;
|
$stmts[1]->attrGroups[] = $attrGroup;
|
||||||
@ -119,39 +123,34 @@ $stmts[6]->expr->attrGroups[] = $attrGroup;
|
|||||||
-----
|
-----
|
||||||
<?php
|
<?php
|
||||||
#[A]
|
#[A]
|
||||||
class X
|
#[B]
|
||||||
{
|
class X {
|
||||||
#[A]
|
#[A]
|
||||||
public function m()
|
#[B]
|
||||||
{
|
public function m() {}
|
||||||
}
|
|
||||||
#[A]
|
#[A]
|
||||||
public $prop;
|
public
|
||||||
|
$prop;
|
||||||
|
|
||||||
#[A]
|
#[A]
|
||||||
const X = 42;
|
const
|
||||||
|
X = 42;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[A]
|
#[A]
|
||||||
trait X
|
trait X {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#[A]
|
#[A]
|
||||||
interface X
|
interface X {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#[A]
|
#[A]
|
||||||
function f()
|
function f() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
new #[A] class
|
new #[A] class {};
|
||||||
{
|
#[A] function() {};
|
||||||
};
|
#[A] fn()
|
||||||
#[A] function () {
|
=> 42;
|
||||||
};
|
|
||||||
#[A] fn() => 42;
|
|
||||||
-----
|
-----
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
@ -42,6 +42,12 @@ $foo -> bar;
|
|||||||
$foo -> bar;
|
$foo -> bar;
|
||||||
self :: $foo;
|
self :: $foo;
|
||||||
self :: $foo;
|
self :: $foo;
|
||||||
|
new Foo();
|
||||||
|
$x instanceof Foo;
|
||||||
|
Foo :: bar;
|
||||||
|
Foo :: $bar;
|
||||||
|
Foo :: bar();
|
||||||
|
Foo :: bar;
|
||||||
-----
|
-----
|
||||||
$stmts[0]->expr->name = new Expr\Variable('a');
|
$stmts[0]->expr->name = new Expr\Variable('a');
|
||||||
$stmts[1]->expr->name = new Expr\BinaryOp\Concat(new Expr\Variable('a'), new Expr\Variable('b'));
|
$stmts[1]->expr->name = new Expr\BinaryOp\Concat(new Expr\Variable('a'), new Expr\Variable('b'));
|
||||||
@ -54,6 +60,12 @@ $stmts[5]->expr->name = new Expr\Variable('bar');
|
|||||||
$stmts[6]->expr->name = new Expr\BinaryOp\Concat(new Expr\Variable('a'), new Expr\Variable('b'));
|
$stmts[6]->expr->name = new Expr\BinaryOp\Concat(new Expr\Variable('a'), new Expr\Variable('b'));
|
||||||
$stmts[7]->expr->name = new Node\VarLikeIdentifier('bar');
|
$stmts[7]->expr->name = new Node\VarLikeIdentifier('bar');
|
||||||
$stmts[8]->expr->name = new Expr\BinaryOp\Concat(new Expr\Variable('a'), new Expr\Variable('b'));
|
$stmts[8]->expr->name = new Expr\BinaryOp\Concat(new Expr\Variable('a'), new Expr\Variable('b'));
|
||||||
|
$stmts[9]->expr->class = new Scalar\String_('Foo');
|
||||||
|
$stmts[10]->expr->class = new Scalar\String_('Foo');
|
||||||
|
$stmts[11]->expr->class = new Expr\ConstFetch(new Node\Name('FOO'));
|
||||||
|
$stmts[12]->expr->class = new Expr\ConstFetch(new Node\Name('FOO'));
|
||||||
|
$stmts[13]->expr->class = new Expr\ConstFetch(new Node\Name('FOO'));
|
||||||
|
$stmts[14]->expr->name = new Expr\Variable('bar');
|
||||||
-----
|
-----
|
||||||
<?php
|
<?php
|
||||||
$a ();
|
$a ();
|
||||||
@ -65,3 +77,9 @@ $foo -> {$bar};
|
|||||||
$foo -> {$a . $b};
|
$foo -> {$a . $b};
|
||||||
self :: $bar;
|
self :: $bar;
|
||||||
self :: ${$a . $b};
|
self :: ${$a . $b};
|
||||||
|
new ('Foo')();
|
||||||
|
$x instanceof ('Foo');
|
||||||
|
(FOO) :: bar;
|
||||||
|
(FOO) :: $bar;
|
||||||
|
(FOO) :: bar();
|
||||||
|
Foo :: {$bar};
|
||||||
|
9
test/code/formatPreservation/group_use.test
Normal file
9
test/code/formatPreservation/group_use.test
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
Group use should include trailing semicolon
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
use A\{B, C};
|
||||||
|
-----
|
||||||
|
$stmts[0] = new Stmt\Use_([new Stmt\UseUse(new Node\Name('A\B'))]);
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
use A\B;
|
34
test/code/formatPreservation/indent.test
Normal file
34
test/code/formatPreservation/indent.test
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
Indentation
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
array_merge(
|
||||||
|
[
|
||||||
|
$x,
|
||||||
|
$y,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
-----
|
||||||
|
$call = $stmts[0]->expr;
|
||||||
|
$stmts[0]->expr = new Expr\StaticCall(new Node\Name\FullyQualified('Compat'), $call->name, $call->args);
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
\Compat::array_merge([
|
||||||
|
$x,
|
||||||
|
$y,
|
||||||
|
]);
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
if ($a) {
|
||||||
|
if (
|
||||||
|
$b
|
||||||
|
) {}
|
||||||
|
}
|
||||||
|
-----
|
||||||
|
$stmts[0] = new Stmt\While_($stmts[0]->cond, $stmts[0]->stmts);
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
while ($a) {
|
||||||
|
if (
|
||||||
|
$b
|
||||||
|
) {}
|
||||||
|
}
|
@ -42,13 +42,71 @@ function test() {
|
|||||||
baz();
|
baz();
|
||||||
}
|
}
|
||||||
-----
|
-----
|
||||||
// TODO Fix broken result
|
// TODO Preserve formatting
|
||||||
$stmts[0]->stmts[1] = $stmts[0]->stmts[2];
|
$stmts[0]->stmts[1] = $stmts[0]->stmts[2];
|
||||||
-----
|
-----
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
function test() {
|
function test()
|
||||||
foo();<?php
|
{
|
||||||
|
foo();
|
||||||
baz();
|
baz();
|
||||||
baz();
|
baz();
|
||||||
}
|
}
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
foo();
|
||||||
|
?>Bar<?php
|
||||||
|
baz();
|
||||||
|
}
|
||||||
|
-----
|
||||||
|
// TODO Preserve formatting
|
||||||
|
unset($stmts[0]->stmts[2]);
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function test()
|
||||||
|
{
|
||||||
|
foo();
|
||||||
|
?>Bar<?php
|
||||||
|
}
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
foo();
|
||||||
|
?>Bar<?php
|
||||||
|
baz();
|
||||||
|
}
|
||||||
|
-----
|
||||||
|
// TODO Preserve formatting
|
||||||
|
array_splice($stmts[0]->stmts, 0, 1, []);
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function test()
|
||||||
|
{
|
||||||
|
?>Bar<?php
|
||||||
|
baz();
|
||||||
|
}
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
foo();
|
||||||
|
?>Bar<?php
|
||||||
|
baz();
|
||||||
|
}
|
||||||
|
-----
|
||||||
|
// TODO Preserve formatting
|
||||||
|
array_splice($stmts[0]->stmts, 1, 1, []);
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function test()
|
||||||
|
{
|
||||||
|
foo();
|
||||||
|
baz();
|
||||||
|
}
|
||||||
|
@ -49,6 +49,10 @@ X
|
|||||||
private
|
private
|
||||||
$x
|
$x
|
||||||
;
|
;
|
||||||
|
|
||||||
|
const
|
||||||
|
X
|
||||||
|
= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (
|
foreach (
|
||||||
@ -86,6 +90,7 @@ $stmts[9]->expr = new Expr\Variable('x');
|
|||||||
$stmts[10]->extends = new Node\Name\FullyQualified('Bar');
|
$stmts[10]->extends = new Node\Name\FullyQualified('Bar');
|
||||||
$stmts[10]->stmts[0]->returnType = new Node\Name('Y');
|
$stmts[10]->stmts[0]->returnType = new Node\Name('Y');
|
||||||
$stmts[10]->stmts[1]->props[0]->default = new Scalar\DNumber(42.0);
|
$stmts[10]->stmts[1]->props[0]->default = new Scalar\DNumber(42.0);
|
||||||
|
$stmts[10]->stmts[2]->type = new Node\Identifier('int');
|
||||||
$stmts[11]->keyVar = new Expr\Variable('z');
|
$stmts[11]->keyVar = new Expr\Variable('z');
|
||||||
$stmts[12]->vars[0]->default = new Scalar\String_('abc');
|
$stmts[12]->vars[0]->default = new Scalar\String_('abc');
|
||||||
$stmts[13]->finally = new Stmt\Finally_([]);
|
$stmts[13]->finally = new Stmt\Finally_([]);
|
||||||
@ -140,6 +145,10 @@ X extends \Bar
|
|||||||
private
|
private
|
||||||
$x = 42.0
|
$x = 42.0
|
||||||
;
|
;
|
||||||
|
|
||||||
|
const int
|
||||||
|
X
|
||||||
|
= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (
|
foreach (
|
||||||
|
@ -55,3 +55,14 @@ function test(
|
|||||||
public T3 $z
|
public T3 $z
|
||||||
= 'x',
|
= 'x',
|
||||||
) {}
|
) {}
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
new class {};
|
||||||
|
new readonly class {};
|
||||||
|
-----
|
||||||
|
$stmts[0]->expr->class->flags = Stmt\Class_::MODIFIER_READONLY;
|
||||||
|
$stmts[1]->expr->class->flags = 0;
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
readonly class {};
|
||||||
|
class {};
|
||||||
|
@ -35,6 +35,11 @@ Bar
|
|||||||
y
|
y
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const
|
||||||
|
int
|
||||||
|
X
|
||||||
|
= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$foo [ $bar ];
|
$foo [ $bar ];
|
||||||
@ -97,6 +102,7 @@ $stmts[2]->extends = null;
|
|||||||
$stmts[2]->stmts[0]->returnType = null;
|
$stmts[2]->stmts[0]->returnType = null;
|
||||||
$stmts[2]->stmts[1]->props[0]->default = null;
|
$stmts[2]->stmts[1]->props[0]->default = null;
|
||||||
$stmts[2]->stmts[2]->adaptations[0]->newName = null;
|
$stmts[2]->stmts[2]->adaptations[0]->newName = null;
|
||||||
|
$stmts[2]->stmts[3]->type = null;
|
||||||
$stmts[3]->expr->dim = null;
|
$stmts[3]->expr->dim = null;
|
||||||
$stmts[4]->expr->expr = null;
|
$stmts[4]->expr->expr = null;
|
||||||
$stmts[5]->expr->if = null;
|
$stmts[5]->expr->if = null;
|
||||||
@ -141,6 +147,10 @@ Foo
|
|||||||
public
|
public
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const
|
||||||
|
X
|
||||||
|
= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$foo [];
|
$foo [];
|
||||||
|
@ -745,6 +745,7 @@ array(
|
|||||||
attrGroups: array(
|
attrGroups: array(
|
||||||
)
|
)
|
||||||
flags: 0
|
flags: 0
|
||||||
|
type: null
|
||||||
consts: array(
|
consts: array(
|
||||||
0: Const(
|
0: Const(
|
||||||
name: Identifier(
|
name: Identifier(
|
||||||
@ -899,12 +900,13 @@ array(
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
class Foo {
|
class Foo {
|
||||||
|
public $bar1;
|
||||||
publi $foo;
|
publi $foo;
|
||||||
public $bar;
|
public $bar;
|
||||||
}
|
}
|
||||||
-----
|
-----
|
||||||
!!php7
|
!!php7
|
||||||
Syntax error, unexpected T_STRING from 4:5 to 4:9
|
Syntax error, unexpected T_STRING from 5:5 to 5:9
|
||||||
array(
|
array(
|
||||||
0: Stmt_Class(
|
0: Stmt_Class(
|
||||||
attrGroups: array(
|
attrGroups: array(
|
||||||
@ -918,6 +920,20 @@ array(
|
|||||||
)
|
)
|
||||||
stmts: array(
|
stmts: array(
|
||||||
0: Stmt_Property(
|
0: Stmt_Property(
|
||||||
|
attrGroups: array(
|
||||||
|
)
|
||||||
|
flags: MODIFIER_PUBLIC (1)
|
||||||
|
type: null
|
||||||
|
props: array(
|
||||||
|
0: Stmt_PropertyProperty(
|
||||||
|
name: VarLikeIdentifier(
|
||||||
|
name: bar1
|
||||||
|
)
|
||||||
|
default: null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
1: Stmt_Property(
|
||||||
attrGroups: array(
|
attrGroups: array(
|
||||||
)
|
)
|
||||||
flags: MODIFIER_PUBLIC (1)
|
flags: MODIFIER_PUBLIC (1)
|
||||||
@ -1508,6 +1524,7 @@ array(
|
|||||||
attrGroups: array(
|
attrGroups: array(
|
||||||
)
|
)
|
||||||
flags: 0
|
flags: 0
|
||||||
|
type: null
|
||||||
consts: array(
|
consts: array(
|
||||||
0: Const(
|
0: Const(
|
||||||
name: Identifier(
|
name: Identifier(
|
||||||
|
43
test/code/parser/expr/dynamicClassConst.test
Normal file
43
test/code/parser/expr/dynamicClassConst.test
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
Dynamic class constant fetch
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
Foo::{bar()};
|
||||||
|
$foo::{bar()};
|
||||||
|
-----
|
||||||
|
!!php7
|
||||||
|
array(
|
||||||
|
0: Stmt_Expression(
|
||||||
|
expr: Expr_ClassConstFetch(
|
||||||
|
class: Name(
|
||||||
|
parts: array(
|
||||||
|
0: Foo
|
||||||
|
)
|
||||||
|
)
|
||||||
|
name: Expr_FuncCall(
|
||||||
|
name: Name(
|
||||||
|
parts: array(
|
||||||
|
0: bar
|
||||||
|
)
|
||||||
|
)
|
||||||
|
args: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
1: Stmt_Expression(
|
||||||
|
expr: Expr_ClassConstFetch(
|
||||||
|
class: Expr_Variable(
|
||||||
|
name: foo
|
||||||
|
)
|
||||||
|
name: Expr_FuncCall(
|
||||||
|
name: Name(
|
||||||
|
parts: array(
|
||||||
|
0: bar
|
||||||
|
)
|
||||||
|
)
|
||||||
|
args: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
@ -7,6 +7,7 @@ A::foo(...);
|
|||||||
|
|
||||||
// These are invalid, but accepted on the parser level.
|
// These are invalid, but accepted on the parser level.
|
||||||
new Foo(...);
|
new Foo(...);
|
||||||
|
$this?->foo(...);
|
||||||
|
|
||||||
#[Foo(...)]
|
#[Foo(...)]
|
||||||
function foo() {}
|
function foo() {}
|
||||||
@ -75,7 +76,21 @@ array(
|
|||||||
0: // These are invalid, but accepted on the parser level.
|
0: // These are invalid, but accepted on the parser level.
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
4: Stmt_Function(
|
4: Stmt_Expression(
|
||||||
|
expr: Expr_NullsafeMethodCall(
|
||||||
|
var: Expr_Variable(
|
||||||
|
name: this
|
||||||
|
)
|
||||||
|
name: Identifier(
|
||||||
|
name: foo
|
||||||
|
)
|
||||||
|
args: array(
|
||||||
|
0: VariadicPlaceholder(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
5: Stmt_Function(
|
||||||
attrGroups: array(
|
attrGroups: array(
|
||||||
0: AttributeGroup(
|
0: AttributeGroup(
|
||||||
attrs: array(
|
attrs: array(
|
||||||
|
@ -17,6 +17,7 @@ Different float syntaxes
|
|||||||
// (all are actually the same number, just in different representations)
|
// (all are actually the same number, just in different representations)
|
||||||
18446744073709551615;
|
18446744073709551615;
|
||||||
0xFFFFFFFFFFFFFFFF;
|
0xFFFFFFFFFFFFFFFF;
|
||||||
|
0xEEEEEEEEEEEEEEEE;
|
||||||
01777777777777777777777;
|
01777777777777777777777;
|
||||||
0177777777777777777777787;
|
0177777777777777777777787;
|
||||||
0b1111111111111111111111111111111111111111111111111111111111111111;
|
0b1111111111111111111111111111111111111111111111111111111111111111;
|
||||||
@ -92,7 +93,7 @@ array(
|
|||||||
)
|
)
|
||||||
12: Stmt_Expression(
|
12: Stmt_Expression(
|
||||||
expr: Scalar_DNumber(
|
expr: Scalar_DNumber(
|
||||||
value: 1.844674407371E+19
|
value: 1.7216961135462E+19
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
13: Stmt_Expression(
|
13: Stmt_Expression(
|
||||||
@ -105,4 +106,9 @@ array(
|
|||||||
value: 1.844674407371E+19
|
value: 1.844674407371E+19
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
15: Stmt_Expression(
|
||||||
|
expr: Scalar_DNumber(
|
||||||
|
value: 1.844674407371E+19
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
@ -4,7 +4,7 @@ Different integer syntaxes
|
|||||||
|
|
||||||
6.674_083e-11;
|
6.674_083e-11;
|
||||||
299_792_458;
|
299_792_458;
|
||||||
0xCAFE_F00D;
|
0x7AFE_F00D;
|
||||||
0b0101_1111;
|
0b0101_1111;
|
||||||
0137_041;
|
0137_041;
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ array(
|
|||||||
)
|
)
|
||||||
2: Stmt_Expression(
|
2: Stmt_Expression(
|
||||||
expr: Scalar_LNumber(
|
expr: Scalar_LNumber(
|
||||||
value: 3405705229
|
value: 2063527949
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
3: Stmt_Expression(
|
3: Stmt_Expression(
|
||||||
|
@ -152,6 +152,7 @@ array(
|
|||||||
attrGroups: array(
|
attrGroups: array(
|
||||||
)
|
)
|
||||||
flags: 0
|
flags: 0
|
||||||
|
type: null
|
||||||
consts: array(
|
consts: array(
|
||||||
0: Const(
|
0: Const(
|
||||||
name: Identifier(
|
name: Identifier(
|
||||||
@ -175,6 +176,7 @@ array(
|
|||||||
attrGroups: array(
|
attrGroups: array(
|
||||||
)
|
)
|
||||||
flags: 0
|
flags: 0
|
||||||
|
type: null
|
||||||
consts: array(
|
consts: array(
|
||||||
0: Const(
|
0: Const(
|
||||||
name: Identifier(
|
name: Identifier(
|
||||||
|
@ -205,6 +205,7 @@ array(
|
|||||||
attrGroups: array(
|
attrGroups: array(
|
||||||
)
|
)
|
||||||
flags: 0
|
flags: 0
|
||||||
|
type: null
|
||||||
consts: array(
|
consts: array(
|
||||||
0: Const(
|
0: Const(
|
||||||
name: Identifier(
|
name: Identifier(
|
||||||
|
@ -23,6 +23,7 @@ array(
|
|||||||
attrGroups: array(
|
attrGroups: array(
|
||||||
)
|
)
|
||||||
flags: MODIFIER_STATIC (8)
|
flags: MODIFIER_STATIC (8)
|
||||||
|
type: null
|
||||||
consts: array(
|
consts: array(
|
||||||
0: Const(
|
0: Const(
|
||||||
name: Identifier(
|
name: Identifier(
|
||||||
@ -61,6 +62,7 @@ array(
|
|||||||
attrGroups: array(
|
attrGroups: array(
|
||||||
)
|
)
|
||||||
flags: MODIFIER_ABSTRACT (16)
|
flags: MODIFIER_ABSTRACT (16)
|
||||||
|
type: null
|
||||||
consts: array(
|
consts: array(
|
||||||
0: Const(
|
0: Const(
|
||||||
name: Identifier(
|
name: Identifier(
|
||||||
@ -99,6 +101,7 @@ array(
|
|||||||
attrGroups: array(
|
attrGroups: array(
|
||||||
)
|
)
|
||||||
flags: MODIFIER_READONLY (64)
|
flags: MODIFIER_READONLY (64)
|
||||||
|
type: null
|
||||||
consts: array(
|
consts: array(
|
||||||
0: Const(
|
0: Const(
|
||||||
name: Identifier(
|
name: Identifier(
|
||||||
@ -137,6 +140,7 @@ array(
|
|||||||
attrGroups: array(
|
attrGroups: array(
|
||||||
)
|
)
|
||||||
flags: MODIFIER_PUBLIC (1)
|
flags: MODIFIER_PUBLIC (1)
|
||||||
|
type: null
|
||||||
consts: array(
|
consts: array(
|
||||||
0: Const(
|
0: Const(
|
||||||
name: Identifier(
|
name: Identifier(
|
||||||
|
@ -27,6 +27,7 @@ array(
|
|||||||
attrGroups: array(
|
attrGroups: array(
|
||||||
)
|
)
|
||||||
flags: 0
|
flags: 0
|
||||||
|
type: null
|
||||||
consts: array(
|
consts: array(
|
||||||
0: Const(
|
0: Const(
|
||||||
name: Identifier(
|
name: Identifier(
|
||||||
@ -42,6 +43,7 @@ array(
|
|||||||
attrGroups: array(
|
attrGroups: array(
|
||||||
)
|
)
|
||||||
flags: MODIFIER_PUBLIC (1)
|
flags: MODIFIER_PUBLIC (1)
|
||||||
|
type: null
|
||||||
consts: array(
|
consts: array(
|
||||||
0: Const(
|
0: Const(
|
||||||
name: Identifier(
|
name: Identifier(
|
||||||
@ -57,6 +59,7 @@ array(
|
|||||||
attrGroups: array(
|
attrGroups: array(
|
||||||
)
|
)
|
||||||
flags: MODIFIER_PROTECTED (2)
|
flags: MODIFIER_PROTECTED (2)
|
||||||
|
type: null
|
||||||
consts: array(
|
consts: array(
|
||||||
0: Const(
|
0: Const(
|
||||||
name: Identifier(
|
name: Identifier(
|
||||||
@ -72,6 +75,7 @@ array(
|
|||||||
attrGroups: array(
|
attrGroups: array(
|
||||||
)
|
)
|
||||||
flags: MODIFIER_PRIVATE (4)
|
flags: MODIFIER_PRIVATE (4)
|
||||||
|
type: null
|
||||||
consts: array(
|
consts: array(
|
||||||
0: Const(
|
0: Const(
|
||||||
name: Identifier(
|
name: Identifier(
|
||||||
@ -87,6 +91,7 @@ array(
|
|||||||
attrGroups: array(
|
attrGroups: array(
|
||||||
)
|
)
|
||||||
flags: MODIFIER_FINAL (32)
|
flags: MODIFIER_FINAL (32)
|
||||||
|
type: null
|
||||||
consts: array(
|
consts: array(
|
||||||
0: Const(
|
0: Const(
|
||||||
name: Identifier(
|
name: Identifier(
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user