mirror of
https://github.com/nikic/PHP-Parser.git
synced 2025-06-25 17:43:47 +02:00
Compare commits
230 Commits
v1.0.0beta
...
v2.0.0alph
Author | SHA1 | Date | |
---|---|---|---|
e0a75ededa | |||
2496cd38ad | |||
965e53a164 | |||
dc85742034 | |||
196f177cfe | |||
b9afcdfd92 | |||
3bb874fcec | |||
feb82eed33 | |||
0ef15c111a | |||
d341d94976 | |||
0265c28e6e | |||
5bd8cb84de | |||
ebeeae19a6 | |||
5ede167835 | |||
49324ea412 | |||
21e51c8cf6 | |||
e7a2abb03b | |||
b862de1f5b | |||
8090531acd | |||
49253c5dbb | |||
c5ac17711d | |||
1d62e9d8cc | |||
e3195c246f | |||
2a3bc608dc | |||
90ab32f046 | |||
7434a682e5 | |||
0fbb5f90a1 | |||
5e6627c895 | |||
f872fa9b0b | |||
d5668f536d | |||
a5db176903 | |||
7fbbf83011 | |||
42e368e964 | |||
9c9a8cddce | |||
fd7ee2e083 | |||
179d32cfaf | |||
f2b7a31509 | |||
d8312a09a3 | |||
813c9f1545 | |||
ef9a154d09 | |||
0da72fad00 | |||
71fa7c6674 | |||
f3f24e03ae | |||
bc21514ecf | |||
04e05907c3 | |||
61e060694d | |||
602b9807eb | |||
f372a4c4ab | |||
d18dcc0c7f | |||
74c57eef0e | |||
fdbddc4b8c | |||
ca3b44bf60 | |||
dca46febc9 | |||
1a1bd1448d | |||
9620f79cdc | |||
583b560f71 | |||
db3dafd64d | |||
bb2c5303ae | |||
5038dcc251 | |||
69c00ebbe4 | |||
a0e7d5e0aa | |||
51ec2a25fe | |||
5d1e3be7d4 | |||
9d42e4a2e2 | |||
cc75dd3612 | |||
5f621c5adc | |||
29b9015f51 | |||
e6619f5514 | |||
6b4a17b3e0 | |||
30abe062f2 | |||
dff239267f | |||
8b64195cf2 | |||
9caa51b3a5 | |||
5513073a53 | |||
659d26c231 | |||
648800f07f | |||
23bf4f0c13 | |||
57ac7e39bf | |||
272ab6c8d8 | |||
0731b47655 | |||
3b7d8e8b5d | |||
a35c2a2067 | |||
55b2ead967 | |||
e1a0ec3724 | |||
66896dbde6 | |||
338bc1f8e7 | |||
ab80054e97 | |||
a6d2cd69f8 | |||
6996db1e3a | |||
e30c3ac01b | |||
a5477a4eaf | |||
7a40498cb4 | |||
65f1adbe65 | |||
c8454271e1 | |||
62f83a0dc2 | |||
611fa5c7f1 | |||
4defbc2174 | |||
33a39fae06 | |||
e4eab9ec0c | |||
6aaa87f143 | |||
08f97eb4ef | |||
8d18848fb0 | |||
805078e0a9 | |||
52dafafd10 | |||
dba7524b37 | |||
617bf0aa41 | |||
dce19b074b | |||
edbf162e4c | |||
b23c53df5f | |||
cea0c4a9d6 | |||
879e8dcd6d | |||
729c7bde0c | |||
8982315b4e | |||
0f556c16f5 | |||
7ec277e1e1 | |||
1a627872f0 | |||
592836c4dc | |||
68defc2c6a | |||
d225555830 | |||
251e689283 | |||
01f4be6b4d | |||
dc28449d81 | |||
3ad0d4b310 | |||
4dbf067b4b | |||
5567f0ab3b | |||
0c34706799 | |||
f9fc2fc9ee | |||
a2d7e8977a | |||
73cace360d | |||
c96636d192 | |||
d56ff5a351 | |||
3028bc8081 | |||
91295a0790 | |||
d600c60779 | |||
e3bc5b564d | |||
53eac36a3f | |||
ce5c76d79b | |||
b7ffdbbb92 | |||
8f1eacdab7 | |||
1366e833a1 | |||
6930feac43 | |||
54275ad181 | |||
21ca7eaf1b | |||
a86779198f | |||
ac05ef6f95 | |||
74251fca9f | |||
0a445c7656 | |||
a710f32a6a | |||
9689763e20 | |||
1a63a915f2 | |||
4071c4645d | |||
f56db26d8b | |||
0dd2b9a74c | |||
4cd2b95a23 | |||
7ab88416ac | |||
ba625063e7 | |||
b4b93ccb21 | |||
01643e06d3 | |||
4387454fe0 | |||
55fdbc6dbc | |||
e69c9ee38c | |||
894c3f787d | |||
a7797918b8 | |||
46975107a7 | |||
e0f3e8a492 | |||
158322e1e4 | |||
2438848487 | |||
f5432a76b6 | |||
800d278369 | |||
8507af6f4a | |||
7c98ad6f9b | |||
d774dbc1b7 | |||
1a93cc3b9d | |||
e26e63e9b0 | |||
0f69f12b94 | |||
a8ffc6fcfc | |||
7fbdb79a08 | |||
6fad8ff32a | |||
b9a60372f2 | |||
eb20e32914 | |||
f41a4c9acb | |||
767f23c3a9 | |||
f8678ad7e9 | |||
63c18b29e4 | |||
99df8b86ae | |||
66fd29cb58 | |||
3d40e2217d | |||
16dff7c2e6 | |||
88e2d42ba4 | |||
69701430c1 | |||
6dc24fa9f5 | |||
3e1665bbbd | |||
2b96ab8edc | |||
7503356e03 | |||
22ef0de7ef | |||
5d7fec2027 | |||
6423864160 | |||
fd064dac6c | |||
d9bd550414 | |||
94eca2ce44 | |||
e65fd664d1 | |||
7a3789f1a9 | |||
b31f36bf89 | |||
3d583ab19c | |||
616be1d0fc | |||
7c81229261 | |||
452e1c0180 | |||
31bc022d0d | |||
ce1078bc00 | |||
6d0589d14f | |||
ef121e690c | |||
c0340053d1 | |||
39f323b5ad | |||
22c76a3da4 | |||
a332352dbc | |||
ef70767475 | |||
1cecf9efc5 | |||
1f143393e5 | |||
6d1f77132c | |||
2e195d7cb2 | |||
947a897238 | |||
1edbc89749 | |||
0faa844a75 | |||
3db3ad7d1e | |||
4743e9b0b8 | |||
8499696021 | |||
e4e56511b9 | |||
5960ecfc10 | |||
c341ab2ecf | |||
c62ffedfca |
@ -1,12 +1,13 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
- hhvm
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- php: hhvm
|
||||
- php: 7.0
|
||||
fast_finish: true
|
||||
|
233
CHANGELOG.md
233
CHANGELOG.md
@ -1,9 +1,229 @@
|
||||
Version 1.0.0-dev
|
||||
-----------------
|
||||
Version 2.0.0-dev-dev
|
||||
---------------------
|
||||
|
||||
Nothing yet.
|
||||
|
||||
Version 1.0.0-beta1 (27.03.2014)
|
||||
Version 2.0.0-alpha1 (2015-07-14)
|
||||
---------------------------------
|
||||
|
||||
A more detailed description of backwards incompatible changes can be found in the
|
||||
[upgrading guide](UPGRADE-2.0.md).
|
||||
|
||||
### Removed
|
||||
|
||||
* Removed support for running on PHP 5.4. It is however still possible to parse PHP 5.2 and PHP 5.3
|
||||
code while running on a newer version.
|
||||
* Removed legacy class name aliases. This includes the old non-namespaced class names and the old
|
||||
names for classes that were renamed for PHP 7 compatibility.
|
||||
* Removed support for legacy node format. All nodes must have a `getSubNodeNames()` method now.
|
||||
|
||||
### Added
|
||||
|
||||
* Added support for remaining PHP 7 features that were not present in 1.x:
|
||||
* Group use declarations. These are represented using `Stmt\GroupUse` nodes. Furthermore a `type`
|
||||
attribute was added to `Stmt\UseUse` to handle mixed group use declarations.
|
||||
* Uniform variable syntax.
|
||||
* Generalized yield operator.
|
||||
* Scalar type declarations. These are presented using `'bool'`, `'int'`, `'float'` and `'string'`
|
||||
as the type. The PHP 5 parser also accepts these, however they'll be `Name` instances there.
|
||||
* Unicode escape sequences.
|
||||
* Added `PhpParser\ParserFactory` class, which should be used to create parser instances.
|
||||
* Added `Name::concat()` which concatenates two names.
|
||||
* Added `Name->slice()` which takes a subslice of a name.
|
||||
|
||||
### Changed
|
||||
|
||||
* `PhpParser\Parser` is now an interface, implemented by `Parser\Php5`, `Parser\Php7` and
|
||||
`Parser\Multiple`. The `Multiple` parser will try multiple parsers, until one succeeds.
|
||||
* Token constants are now defined on `PhpParser\Parser\Tokens` rather than `PhpParser\Parser`.
|
||||
* The `Name->set()`, `Name->append()`, `Name->prepend()` and `Name->setFirst()` methods are
|
||||
deprecated in favor of `Name::concat()` and `Name->slice()`.
|
||||
* The `NodeTraverser` no longer clones nodes by default. The old behavior can be restored by
|
||||
passing `true` to the constructor.
|
||||
* The constructor for `Scalar` nodes no longer has a default value. E.g. `new LNumber()` should now
|
||||
be written as `new LNumber(0)`.
|
||||
|
||||
Version 1.4.0 (2015-07-14)
|
||||
--------------------------
|
||||
|
||||
### Added
|
||||
|
||||
* Added interface `PhpParser\Node\FunctionLike`, which is implemented by `Stmt\ClassMethod`,
|
||||
`Stmt\Function_` and `Expr\Closure` nodes. This interface provides getters for their common
|
||||
subnodes.
|
||||
* Added `Node\Stmt\ClassLike::getMethod()` to look up a specific method on a class/interface/trait.
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed `isPublic()` return value for implicitly public properties and methods that define and
|
||||
additional modifier like `static` or `abstract`.
|
||||
* Properties are now accepted by the trait builder.
|
||||
* Fixed `__HALT_COMPILER_OFFSET__` support on HHVM.
|
||||
|
||||
Version 1.3.0 (2015-05-02)
|
||||
--------------------------
|
||||
|
||||
### Added
|
||||
|
||||
* Errors can now store the attributes of the node/token where the error occurred. Previously only the start line was
|
||||
stored.
|
||||
* If file positions are enabled in the lexer, errors can now provide column information if it is available. See
|
||||
[documentation](https://github.com/nikic/PHP-Parser/blob/master/doc/component/Error.markdown#column-information).
|
||||
* The parser now provides an experimental error recovery mode, which can be enabled by disabling the `throwOnError`
|
||||
parser option. In this mode the parser will try to construct a partial AST even if the code is not valid PHP. See
|
||||
[documentation](https://github.com/nikic/PHP-Parser/blob/master/doc/component/Error.markdown#error-recovery).
|
||||
* Added support for PHP 7 `yield from` expression. It is represented by `Expr\YieldFrom`.
|
||||
* Added support for PHP 7 anonymous classes. These are represented by ordinary `Stmt\Class_` nodes with the name set to
|
||||
`null`. Furthermore this implies that `Expr\New_` can now contain a `Stmt\Class_` in its `class` subnode.
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed registration of PHP 7 aliases, for the case where the old name was used before the new name.
|
||||
* Fixed handling of precedence when pretty-printing `print` expressions.
|
||||
* Floating point numbers are now pretty-printed with a higher precision.
|
||||
* Checks for special class names like `self` are now case-insensitive.
|
||||
|
||||
Version 1.2.2 (2015-04-03)
|
||||
--------------------------
|
||||
|
||||
* The `NameResolver` now resolves parameter type hints when entering the function/method/closure node. As such other
|
||||
visitors running after it will be able to make use of the resolved names at that point already.
|
||||
* The autoloader no longer sets the `unserialize_callback_func` ini option on registration - this is not necessary and
|
||||
may cause issues when running PhpUnit tests with process isolation.
|
||||
|
||||
Version 1.2.1 (2015-03-24)
|
||||
--------------------------
|
||||
|
||||
* Fixed registration of the aliases introduced in 1.2.0. Previously the old class names could not be used in
|
||||
`instanceof` checks under some circumstances.
|
||||
|
||||
Version 1.2.0 (2015-03-22)
|
||||
--------------------------
|
||||
|
||||
### Changed
|
||||
|
||||
* To ensure compatibility with PHP 7, the following node classes have been renamed:
|
||||
|
||||
OLD => NEW
|
||||
PhpParser\Node\Expr\Cast\Bool => PhpParser\Node\Expr\Cast\Bool_
|
||||
PhpParser\Node\Expr\Cast\Int => PhpParser\Node\Expr\Cast\Int_
|
||||
PhpParser\Node\Expr\Cast\Object => PhpParser\Node\Expr\Cast\Object_
|
||||
PhpParser\Node\Expr\Cast\String => PhpParser\Node\Expr\Cast\String_
|
||||
PhpParser\Node\Scalar\String => PhpParser\Node\Scalar\String_
|
||||
|
||||
**The previous class names are still supported as aliases.** However it is strongly encouraged to use the new names
|
||||
in order to make your code compatible with PHP 7.
|
||||
|
||||
* Subnodes are now stored using real properties instead of an array. This improves performance and memory usage of the
|
||||
initial parse and subsequent node tree operations. The `NodeAbstract` class still supports the old way of specifying
|
||||
subnodes, however this is *deprecated*. In any case properties that are assigned to a node after creation will no
|
||||
longer be considered as subnodes.
|
||||
|
||||
* Methods and property declarations will no longer set the `Stmt\Class_::MODIFIER_PUBLIC` flag if no visibility is
|
||||
explicitly given. However the `isPublic()` method will continue to return true. This allows you to distinguish whether
|
||||
a method/property is explicitly or implicitly public and control the pretty printer output more precisely.
|
||||
|
||||
* The `Stmt\Class_`, `Stmt\Interface_` and `Stmt\Trait_` nodes now inherit from `Stmt\ClassLike`, which provides a
|
||||
`getMethods()` method. Previously this method was only available on `Stmt\Class_`.
|
||||
|
||||
* Support including the `bootstrap.php` file multiple times.
|
||||
|
||||
* Make documentation and tests part of the release tarball again.
|
||||
|
||||
* Improve support for HHVM and PHP 7.
|
||||
|
||||
### Added
|
||||
|
||||
* Added support for PHP 7 return type declarations. This adds an additional `returnType` subnode to `Stmt\Function_`,
|
||||
`Stmt\ClassMethod` and `Expr\Closure`.
|
||||
|
||||
* Added support for the PHP 7 null coalesce operator `??`. The operator is represented by `Expr\BinaryOp\Coalesce`.
|
||||
|
||||
* Added support for the PHP 7 spaceship operator `<=>`. The operator is represented by `Expr\BinaryOp\Spaceship`.
|
||||
|
||||
* Added use builder.
|
||||
|
||||
* Added global namespace support to the namespace builder.
|
||||
|
||||
* Added a constructor flag to `NodeTraverser`, which disables cloning of nodes.
|
||||
|
||||
Version 1.1.0 (2015-01-18)
|
||||
--------------------------
|
||||
|
||||
* Methods that do not specify an explicit visibility (e.g. `function method()`) will now have the `MODIFIER_PUBLIC`
|
||||
flag set. This also means that their `isPublic()` method will return true.
|
||||
|
||||
* Declaring a property as abstract or final is now an error.
|
||||
|
||||
* The `Lexer` and `Lexer\Emulative` classes now accept an `$options` array in their constructors. Currently only the
|
||||
`usedAttributes` option is supported, which determines which attributes will be added to AST nodes. In particular
|
||||
it is now possible to add information on the token and file positions corresponding to a node. For more details see
|
||||
the [Lexer component](https://github.com/nikic/PHP-Parser/blob/master/doc/component/Lexer.markdown) documentation.
|
||||
|
||||
* Node visitors can now return `NodeTraverser::DONT_TRAVERSE_CHILDREN` from `enterNode()` in order to skip all children
|
||||
of the current node, for all visitors.
|
||||
|
||||
* Added builders for traits and namespaces.
|
||||
|
||||
* The class, interface, trait, function, method and property builders now support adding doc comments using the
|
||||
`setDocComment()` method.
|
||||
|
||||
* Added support for fully-qualified and namespace-relative names in builders. No longer allow use of name component
|
||||
arrays.
|
||||
|
||||
* Do not add documentation and tests to distribution archive files.
|
||||
|
||||
Version 1.0.2 (2014-11-04)
|
||||
--------------------------
|
||||
|
||||
* The `NameResolver` visitor now also resolves names in trait adaptations (aliases and precedence declarations).
|
||||
|
||||
* Remove stray whitespace when pretty-printing trait adaptations that only change visibility.
|
||||
|
||||
Version 1.0.1 (2014-10-14)
|
||||
--------------------------
|
||||
|
||||
* Disallow `new` expressions without a class name. Previously `new;` was accidentally considered to be valid code.
|
||||
|
||||
* Support T_ONUMBER token used by HHVM.
|
||||
|
||||
* Add ability to directly pass code to the `php-parse.php` script.
|
||||
|
||||
* Prevent truncation of `var_dump()` output in the `php-parse.php` script if XDebug is used.
|
||||
|
||||
Version 1.0.0 (2014-09-12)
|
||||
--------------------------
|
||||
|
||||
* [BC] Removed deprecated `Template` and `TemplateLoader` classes.
|
||||
|
||||
* Fixed XML unserializer to properly work with new namespaced node names.
|
||||
|
||||
Version 1.0.0-beta2 (2014-08-31)
|
||||
--------------------------------
|
||||
|
||||
* [PHP 5.6] Updated support for constant scalar expressions to comply with latest changes. This means that arrays
|
||||
and array dimension fetches are now supported as well.
|
||||
|
||||
* [PHP 5.6] Direct array dereferencing of constants is supported now, i.e. both `FOO[0]` and `Foo::BAR[0]` are valid
|
||||
now.
|
||||
|
||||
* Fixed handling of special class names (`self`, `parent` and `static`) in the name resolver to be case insensitive.
|
||||
Additionally the name resolver now enforces that special class names are only used as unqualified names, e.g. `\self`
|
||||
is considered invalid.
|
||||
|
||||
* The case of references to the `static` class name is now preserved. Previously `static` was always lowercased,
|
||||
regardless of the case used in the source code.
|
||||
|
||||
* The autoloader now only requires a file if it exists. This allows usages like
|
||||
`class_exists('PhpParser\NotExistingClass')`.
|
||||
|
||||
* Added experimental `bin/php-parse.php` script, which is intended to help exploring and debugging the node tree.
|
||||
|
||||
* Separated the parser implemention (in `lib/PhpParser/ParserAbstract.php`) and the generated data (in
|
||||
`lib/PhpParser/Parser.php`). Furthermore the parser now uses meaningful variable names and contains comments
|
||||
explaining their usage.
|
||||
|
||||
Version 1.0.0-beta1 (2014-03-27)
|
||||
--------------------------------
|
||||
|
||||
* [BC] PHP-Parser now requires PHP 5.3 or newer to run. It is however still possible to *parse* PHP 5.2 source code,
|
||||
@ -45,7 +265,7 @@ Version 1.0.0-beta1 (27.03.2014)
|
||||
|
||||
* Added `Scalar\MagicConstant->getName()`, which returns the name of the magic constant (e.g. `__CLASS__`).
|
||||
|
||||
**The following changes are also included in 0.9.5-dev**:
|
||||
**The following changes are also included in 0.9.5**:
|
||||
|
||||
* [BC] Deprecated `PHPParser_Template` and `PHPParser_TemplateLoader`. This functionality does not belong in the main project
|
||||
and - as far as I know - nobody is using it.
|
||||
@ -60,6 +280,5 @@ Version 1.0.0-beta1 (27.03.2014)
|
||||
|
||||
---
|
||||
|
||||
**This changelog only includes changes from the 1.0 series. For older changes see the [0.9 series changelog][1].**
|
||||
|
||||
[1]: https://github.com/nikic/PHP-Parser/blob/0.9/CHANGELOG.md
|
||||
**This changelog only includes changes from the 1.0 and 2.0 series. For older changes see the
|
||||
[0.9 series changelog][https://github.com/nikic/PHP-Parser/blob/0.9/CHANGELOG.md].**
|
34
README.md
34
README.md
@ -1,23 +1,18 @@
|
||||
PHP Parser
|
||||
==========
|
||||
|
||||
This is a PHP 5.6 (and older) parser written in PHP. It's purpose is to simplify static code analysis and
|
||||
This is a PHP 5.2 to PHP 5.6 parser written in PHP. Its purpose is to simplify static code analysis and
|
||||
manipulation.
|
||||
|
||||
[**Documentation for version 0.9.x**][doc_0_9] (stable; for running on PHP 5.2).
|
||||
[**Documentation for version 1.x**][doc_1_x] (stable; for running on PHP >= 5.3).
|
||||
|
||||
[**Documentation for version 1.0.x**][doc_master] (beta; for running on PHP >= 5.3).
|
||||
|
||||
***Note: This project is experimental, so the API is subject to change.***
|
||||
[Documentation for version 2.x-dev][doc_master] (dev; for running on PHP >= 5.4).
|
||||
|
||||
In a Nutshell
|
||||
-------------
|
||||
|
||||
Basically, the parser does nothing more than turn some PHP code into an abstract syntax tree. ("nothing
|
||||
more" is kind of sarcastic here as PHP has a ... uhm, let's just say "not nice" ... grammar, which makes
|
||||
parsing PHP very hard.)
|
||||
|
||||
For example, if you stick this code in the parser:
|
||||
The parser turns PHP source code into an abstract syntax tree. For example, if you pass the following code into the
|
||||
parser:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -27,7 +22,7 @@ hello\world('foo', 'bar' . 'baz');
|
||||
|
||||
You'll get a syntax tree looking roughly like this:
|
||||
|
||||
```
|
||||
```php
|
||||
array(
|
||||
0: Stmt_Echo(
|
||||
exprs: array(
|
||||
@ -75,7 +70,18 @@ programming errors or security issues).
|
||||
Additionally, you can convert a syntax tree back to PHP code. This allows you to do code preprocessing
|
||||
(like automatedly porting code to older PHP versions).
|
||||
|
||||
So, that's it, in a nutshell. You can find everything else in the [docs][doc_master].
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
[doc_0_9]: https://github.com/nikic/PHP-Parser/tree/0.9/doc
|
||||
[doc_master]: https://github.com/nikic/PHP-Parser/tree/master/doc
|
||||
1. [Introduction](doc/0_Introduction.markdown)
|
||||
2. [Installation](doc/1_Installation.markdown)
|
||||
3. [Usage of basic components](doc/2_Usage_of_basic_components.markdown)
|
||||
4. [Other node tree representations](doc/3_Other_node_tree_representations.markdown)
|
||||
5. [Code generation](doc/4_Code_generation.markdown)
|
||||
|
||||
Component documentation:
|
||||
|
||||
1. [Lexer](doc/component/Lexer.markdown)
|
||||
|
||||
[doc_1_x]: https://github.com/nikic/PHP-Parser/tree/1.x/doc
|
||||
[doc_master]: https://github.com/nikic/PHP-Parser/tree/master/doc
|
||||
|
121
UPGRADE-1.0.md
Normal file
121
UPGRADE-1.0.md
Normal file
@ -0,0 +1,121 @@
|
||||
Upgrading from PHP-Parser 0.9 to 1.0
|
||||
====================================
|
||||
|
||||
### PHP version requirements
|
||||
|
||||
PHP-Parser now requires PHP 5.3 or newer to run. It is however still possible to *parse* PHP 5.2 source code, while
|
||||
running on a newer version.
|
||||
|
||||
### Move to namespaced names
|
||||
|
||||
The library has been moved to use namespaces with the `PhpParser` vendor prefix. However, the old names using
|
||||
underscores are still available as aliases, as such most code should continue running on the new version without
|
||||
further changes.
|
||||
|
||||
Old (still works, but discouraged):
|
||||
|
||||
```php
|
||||
$parser = new \PHPParser_Parser(new \PHPParser_Lexer_Emulative);
|
||||
$prettyPrinter = new \PHPParser_PrettyPrinter_Default;
|
||||
```
|
||||
|
||||
New:
|
||||
|
||||
```php
|
||||
$parser = new \PhpParser\Parser(new PhpParser\Lexer\Emulative);
|
||||
$prettyPrinter = new \PhpParser\PrettyPrinter\Standard;
|
||||
```
|
||||
|
||||
Note that the `PHPParser` prefix was changed to `PhpParser`. While PHP class names are technically case-insensitive,
|
||||
the autoloader will not be able to load `PHPParser\Parser` or other case variants.
|
||||
|
||||
Due to conflicts with reserved keywords, some class names now end with an underscore, e.g. `PHPParser_Node_Stmt_Class`
|
||||
is now `PhpParser\Node\Stmt\Class_`. (But as usual, the old name is still available.)
|
||||
|
||||
### Changes to `Node::getType()`
|
||||
|
||||
The `Node::getType()` method continues to return names using underscores instead of namespace separators and also does
|
||||
not contain the trailing underscore that may be present in the class name. As such its output will not change in many
|
||||
cases.
|
||||
|
||||
However, some node classes have been moved to a different namespace or renamed, which will result in a different
|
||||
`Node::getType()` output:
|
||||
|
||||
```
|
||||
Expr_AssignBitwiseAnd => Expr_AssignOp_BitwiseAnd
|
||||
Expr_AssignBitwiseOr => Expr_AssignOp_BitwiseOr
|
||||
Expr_AssignBitwiseXor => Expr_AssignOp_BitwiseXor
|
||||
Expr_AssignConcat => Expr_AssignOp_Concat
|
||||
Expr_AssignDiv => Expr_AssignOp_Div
|
||||
Expr_AssignMinus => Expr_AssignOp_Minus
|
||||
Expr_AssignMod => Expr_AssignOp_Mod
|
||||
Expr_AssignMul => Expr_AssignOp_Mul
|
||||
Expr_AssignPlus => Expr_AssignOp_Plus
|
||||
Expr_AssignShiftLeft => Expr_AssignOp_ShiftLeft
|
||||
Expr_AssignShiftRight => Expr_AssignOp_ShiftRight
|
||||
|
||||
Expr_BitwiseAnd => Expr_BinaryOp_BitwiseAnd
|
||||
Expr_BitwiseOr => Expr_BinaryOp_BitwiseOr
|
||||
Expr_BitwiseXor => Expr_BinaryOp_BitwiseXor
|
||||
Expr_BooleanAnd => Expr_BinaryOp_BooleanAnd
|
||||
Expr_BooleanOr => Expr_BinaryOp_BooleanOr
|
||||
Expr_Concat => Expr_BinaryOp_Concat
|
||||
Expr_Div => Expr_BinaryOp_Div
|
||||
Expr_Equal => Expr_BinaryOp_Equal
|
||||
Expr_Greater => Expr_BinaryOp_Greater
|
||||
Expr_GreaterOrEqual => Expr_BinaryOp_GreaterOrEqual
|
||||
Expr_Identical => Expr_BinaryOp_Identical
|
||||
Expr_LogicalAnd => Expr_BinaryOp_LogicalAnd
|
||||
Expr_LogicalOr => Expr_BinaryOp_LogicalOr
|
||||
Expr_LogicalXor => Expr_BinaryOp_LogicalXor
|
||||
Expr_Minus => Expr_BinaryOp_Minus
|
||||
Expr_Mod => Expr_BinaryOp_Mod
|
||||
Expr_Mul => Expr_BinaryOp_Mul
|
||||
Expr_NotEqual => Expr_BinaryOp_NotEqual
|
||||
Expr_NotIdentical => Expr_BinaryOp_NotIdentical
|
||||
Expr_Plus => Expr_BinaryOp_Plus
|
||||
Expr_ShiftLeft => Expr_BinaryOp_ShiftLeft
|
||||
Expr_ShiftRight => Expr_BinaryOp_ShiftRight
|
||||
Expr_Smaller => Expr_BinaryOp_Smaller
|
||||
Expr_SmallerOrEqual => Expr_BinaryOp_SmallerOrEqual
|
||||
|
||||
Scalar_ClassConst => Scalar_MagicConst_Class
|
||||
Scalar_DirConst => Scalar_MagicConst_Dir
|
||||
Scalar_FileConst => Scalar_MagicConst_File
|
||||
Scalar_FuncConst => Scalar_MagicConst_Function
|
||||
Scalar_LineConst => Scalar_MagicConst_Line
|
||||
Scalar_MethodConst => Scalar_MagicConst_Method
|
||||
Scalar_NSConst => Scalar_MagicConst_Namespace
|
||||
Scalar_TraitConst => Scalar_MagicConst_Trait
|
||||
```
|
||||
|
||||
These changes may affect custom pretty printers and code comparing the return value of `Node::getType()` to specific
|
||||
strings.
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
* The classes `Template` and `TemplateLoader` have been removed. You should use some other [code generation][code_gen]
|
||||
project built on top of PHP-Parser instead.
|
||||
|
||||
* The `PrettyPrinterAbstract::pStmts()` method now emits a leading newline if the statement list is not empty.
|
||||
Custom pretty printers should remove the explicit newline before `pStmts()` calls.
|
||||
|
||||
Old:
|
||||
|
||||
```php
|
||||
public function pStmt_Trait(PHPParser_Node_Stmt_Trait $node) {
|
||||
return 'trait ' . $node->name
|
||||
. "\n" . '{' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
|
||||
}
|
||||
```
|
||||
|
||||
New:
|
||||
|
||||
```php
|
||||
public function pStmt_Trait(Stmt\Trait_ $node) {
|
||||
return 'trait ' . $node->name
|
||||
. "\n" . '{' . $this->pStmts($node->stmts) . "\n" . '}';
|
||||
}
|
||||
```
|
||||
|
||||
[code_gen]: https://github.com/nikic/PHP-Parser/wiki/Projects-using-the-PHP-Parser#code-generation
|
71
UPGRADE-2.0.md
Normal file
71
UPGRADE-2.0.md
Normal file
@ -0,0 +1,71 @@
|
||||
Upgrading from PHP-Parser 1.x to 2.0
|
||||
====================================
|
||||
|
||||
### PHP version requirements
|
||||
|
||||
PHP-Parser now requires PHP 5.4 or newer to run. It is however still possible to *parse* PHP 5.2 and
|
||||
PHP 5.3 source code, while running on a newer version.
|
||||
|
||||
### Creating a parser instance
|
||||
|
||||
Parser instances should now be created through the `ParserFactory`. Old direct instantiation code
|
||||
will not work, because the parser class was renamed.
|
||||
|
||||
Old:
|
||||
|
||||
```php
|
||||
use PhpParser\Parser, PhpParser\Lexer;
|
||||
$parser = new Parser(new Lexer\Emulative);
|
||||
```
|
||||
|
||||
New:
|
||||
|
||||
```php
|
||||
use PhpParser\ParserFactory;
|
||||
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
|
||||
```
|
||||
|
||||
The first argument to `ParserFactory` determines how different PHP versions are handled. The
|
||||
possible values are:
|
||||
|
||||
* `ParserFactory::PREFER_PHP7`: Try to parse code as PHP 7. If this fails, try to parse it as PHP 5.
|
||||
* `ParserFactory::PREFER_PHP5`: Try to parse code as PHP 5. If this fails, try to parse it as PHP 7.
|
||||
* `ParserFactory::ONLY_PHP7`: Parse code as PHP 7.
|
||||
* `ParserFactory::ONLY_PHP5`: Parse code as PHP 5.
|
||||
|
||||
For most practical purposes the difference between `PREFER_PHP7` and `PREFER_PHP5` is mainly whether
|
||||
a scalar type hint like `string` will be stored as `'string'` (PHP 7) or as `new Name('string')`
|
||||
(PHP 5).
|
||||
|
||||
To use a custom lexer, pass it as the second argument to the `create()` method:
|
||||
|
||||
```php
|
||||
use PhpParser\ParserFactory;
|
||||
$lexer = new MyLexer;
|
||||
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7, $lexer);
|
||||
```
|
||||
|
||||
### Rename of the `PhpParser\Parser` class
|
||||
|
||||
`PhpParser\Parser` is now an interface, which is implemented by `Parser\Php5`, `Parser\Php7` and
|
||||
`Parser\Multiple`. Parser tokens are now defined in `Parser\Tokens`. If you use the `ParserFactory`
|
||||
described above to create your parser instance, these changes should have no further impact on you.
|
||||
|
||||
### Removal of legacy aliases
|
||||
|
||||
All legacy aliases for classes have been removed. This includes the old non-namespaced `PHPParser_`
|
||||
classes, as well as the classes that had to be renamed for PHP 7 support.
|
||||
|
||||
### Deprecations
|
||||
|
||||
The `set()`, `setFirst()`, `append()` and `prepend()` methods of the `Node\Name` class have been
|
||||
deprecated. Instead `Name::concat()` and `Name->slice()` should be used.
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
* The `NodeTraverser` no longer clones nodes by default. If you want to restore the old behavior,
|
||||
pass `true` to the constructor.
|
||||
* The legacy node format has been removed. If you use custom nodes, they are now expected to
|
||||
implement a `getSubNodeNames()` method.
|
||||
* The default value for `Scalar` node constructors was removed. This means that something like
|
||||
`new LNumber()` should be replaced by `new LNumber(0)`.
|
161
bin/php-parse.php
Executable file
161
bin/php-parse.php
Executable file
@ -0,0 +1,161 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
require __DIR__ . '/../lib/bootstrap.php';
|
||||
|
||||
ini_set('xdebug.max_nesting_level', 3000);
|
||||
|
||||
// Disable XDebug var_dump() output truncation
|
||||
ini_set('xdebug.var_display_max_children', -1);
|
||||
ini_set('xdebug.var_display_max_data', -1);
|
||||
ini_set('xdebug.var_display_max_depth', -1);
|
||||
|
||||
list($operations, $files, $attributes) = parseArgs($argv);
|
||||
|
||||
/* Dump nodes by default */
|
||||
if (empty($operations)) {
|
||||
$operations[] = 'dump';
|
||||
}
|
||||
|
||||
if (empty($files)) {
|
||||
showHelp("Must specify at least one file.");
|
||||
}
|
||||
|
||||
$lexer = new PhpParser\Lexer\Emulative(array('usedAttributes' => array(
|
||||
'startLine', 'endLine', 'startFilePos', 'endFilePos'
|
||||
)));
|
||||
$parser = (new PhpParser\ParserFactory)->create(PhpParser\ParserFactory::PREFER_PHP7, $lexer);
|
||||
$dumper = new PhpParser\NodeDumper;
|
||||
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
|
||||
$serializer = new PhpParser\Serializer\XML;
|
||||
|
||||
$traverser = new PhpParser\NodeTraverser();
|
||||
$traverser->addVisitor(new PhpParser\NodeVisitor\NameResolver);
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (strpos($file, '<?php') === 0) {
|
||||
$code = $file;
|
||||
echo "====> Code $code\n";
|
||||
} else {
|
||||
if (!file_exists($file)) {
|
||||
die("File $file does not exist.\n");
|
||||
}
|
||||
|
||||
$code = file_get_contents($file);
|
||||
echo "====> File $file:\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$stmts = $parser->parse($code);
|
||||
} catch (PhpParser\Error $e) {
|
||||
if ($attributes['with-column-info'] && $e->hasColumnInfo()) {
|
||||
$startLine = $e->getStartLine();
|
||||
$endLine = $e->getEndLine();
|
||||
$startColumn = $e->getStartColumn($code);
|
||||
$endColumn = $e->getEndColumn($code);
|
||||
$message .= $e->getRawMessage() . " from $startLine:$startColumn to $endLine:$endColumn";
|
||||
} else {
|
||||
$message = $e->getMessage();
|
||||
}
|
||||
|
||||
die($message . "\n");
|
||||
}
|
||||
|
||||
foreach ($operations as $operation) {
|
||||
if ('dump' === $operation) {
|
||||
echo "==> Node dump:\n";
|
||||
echo $dumper->dump($stmts), "\n";
|
||||
} elseif ('pretty-print' === $operation) {
|
||||
echo "==> Pretty print:\n";
|
||||
echo $prettyPrinter->prettyPrintFile($stmts), "\n";
|
||||
} elseif ('serialize-xml' === $operation) {
|
||||
echo "==> Serialized XML:\n";
|
||||
echo $serializer->serialize($stmts), "\n";
|
||||
} elseif ('var-dump' === $operation) {
|
||||
echo "==> var_dump():\n";
|
||||
var_dump($stmts);
|
||||
} elseif ('resolve-names' === $operation) {
|
||||
echo "==> Resolved names.\n";
|
||||
$stmts = $traverser->traverse($stmts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showHelp($error) {
|
||||
die($error . "\n\n" .
|
||||
<<<OUTPUT
|
||||
Usage: php php-parse.php [operations] file1.php [file2.php ...]
|
||||
or: php php-parse.php [operations] "<?php code"
|
||||
Turn PHP source code into an abstract syntax tree.
|
||||
|
||||
Operations is a list of the following options (--dump by default):
|
||||
|
||||
-d, --dump Dump nodes using NodeDumper
|
||||
-p, --pretty-print Pretty print file using PrettyPrinter\Standard
|
||||
--serialize-xml Serialize nodes using Serializer\XML
|
||||
--var-dump var_dump() nodes (for exact structure)
|
||||
-N, --resolve-names Resolve names using NodeVisitor\NameResolver
|
||||
-c, --with-column-info Show column-numbers for errors (if available)
|
||||
|
||||
Example:
|
||||
php php-parse.php -d -p -N -d file.php
|
||||
|
||||
Dumps nodes, pretty prints them, then resolves names and dumps them again.
|
||||
|
||||
|
||||
OUTPUT
|
||||
);
|
||||
}
|
||||
|
||||
function parseArgs($args) {
|
||||
$operations = array();
|
||||
$files = array();
|
||||
$attributes = array(
|
||||
'with-column-info' => false,
|
||||
);
|
||||
|
||||
array_shift($args);
|
||||
$parseOptions = true;
|
||||
foreach ($args as $arg) {
|
||||
if (!$parseOptions) {
|
||||
$files[] = $arg;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch ($arg) {
|
||||
case '--dump':
|
||||
case '-d':
|
||||
$operations[] = 'dump';
|
||||
break;
|
||||
case '--pretty-print':
|
||||
case '-p':
|
||||
$operations[] = 'pretty-print';
|
||||
break;
|
||||
case '--serialize-xml':
|
||||
$operations[] = 'serialize-xml';
|
||||
break;
|
||||
case '--var-dump':
|
||||
$operations[] = 'var-dump';
|
||||
break;
|
||||
case '--resolve-names':
|
||||
case '-N';
|
||||
$operations[] = 'resolve-names';
|
||||
break;
|
||||
case '--with-column-info':
|
||||
case '-c';
|
||||
$attributes['with-column-info'] = true;
|
||||
break;
|
||||
case '--':
|
||||
$parseOptions = false;
|
||||
break;
|
||||
default:
|
||||
if ($arg[0] === '-') {
|
||||
showHelp("Invalid operation $arg.");
|
||||
} else {
|
||||
$files[] = $arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array($operations, $files, $attributes);
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3",
|
||||
"php": ">=5.4",
|
||||
"ext-tokenizer": "*"
|
||||
},
|
||||
"autoload": {
|
||||
@ -18,7 +18,7 @@
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
"dev-master": "2.0-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
Introduction
|
||||
============
|
||||
|
||||
This project is a PHP 5.5 (and older) parser **written in PHP itself**.
|
||||
This project is a PHP 5.2 to PHP 5.6 parser **written in PHP itself**.
|
||||
|
||||
What is this for?
|
||||
-----------------
|
||||
|
||||
A parser is useful for [static analysis][0] and manipulation of code and basically any other
|
||||
A parser is useful for [static analysis][0], manipulation of code and basically any other
|
||||
application dealing with code programmatically. A parser constructs an [Abstract Syntax Tree][1]
|
||||
(AST) of the code and thus allows dealing with it in an abstract and robust way.
|
||||
|
||||
There are other ways of dealing with source code. One that PHP supports natively is using the
|
||||
There are other ways of processing source code. One that PHP supports natively is using the
|
||||
token stream generated by [`token_get_all`][2]. The token stream is much more low level than
|
||||
the AST and thus has different applications: It allows to also analyze the exact formatting of
|
||||
a file. On the other hand the token stream is much harder to deal with for more complex analysis.
|
||||
@ -26,13 +26,12 @@ programmatic PHP code analysis are incidentally PHP developers, not C developers
|
||||
What can it parse?
|
||||
------------------
|
||||
|
||||
The parser uses a PHP 5.5 compliant grammar, which is backwards compatible with at least PHP 5.4, PHP 5.3
|
||||
and PHP 5.2 (and maybe older).
|
||||
The parser supports parsing PHP 5.2-5.6 and PHP 7.
|
||||
|
||||
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 new tokens from 5.3, 5.4 and 5.5 is provided. This
|
||||
allows to parse PHP 5.5 source code running on PHP 5.2, for example. This emulation is very hacky and not
|
||||
yet perfect, but it should work well on any sane code.
|
||||
version it runs on), additionally a wrapper for emulating new tokens from 5.5, 5.6 and 7.0 is
|
||||
provided. This allows to parse PHP 7.0 source code running on PHP 5.4, for example. This emulation
|
||||
is somewhat hacky and not perfect, but it should work well on any sane code.
|
||||
|
||||
What output does it produce?
|
||||
----------------------------
|
||||
@ -56,7 +55,7 @@ array(
|
||||
)
|
||||
```
|
||||
|
||||
This matches the semantics the program had: An echo statement, which takes two strings as expressions,
|
||||
This matches the structure of the code: An echo statement, which takes two strings as expressions,
|
||||
with the values `Hi` and `World!`.
|
||||
|
||||
You can also see that the AST does not contain any whitespace information (but most comments are saved).
|
||||
@ -78,4 +77,4 @@ Apart from the parser itself this package also bundles support for some other, r
|
||||
|
||||
[0]: http://en.wikipedia.org/wiki/Static_program_analysis
|
||||
[1]: http://en.wikipedia.org/wiki/Abstract_syntax_tree
|
||||
[2]: http://php.net/token_get_all
|
||||
[2]: http://php.net/token_get_all
|
||||
|
@ -3,30 +3,17 @@ Installation
|
||||
|
||||
There are multiple ways to include the PHP parser into your project:
|
||||
|
||||
Installing from the Zip- or Tarball
|
||||
-----------------------------------
|
||||
|
||||
Download the latest version from [the download page][2], unpack it and move the files somewhere into your project.
|
||||
|
||||
Installing via Composer
|
||||
-----------------------
|
||||
|
||||
Create a `composer.json` file in your project root and use it to define your dependencies:
|
||||
Run the following command inside your project:
|
||||
|
||||
{
|
||||
"require": {
|
||||
"nikic/php-parser": "1.0.0-beta1"
|
||||
}
|
||||
}
|
||||
php composer.phar require nikic/php-parser
|
||||
|
||||
Then install Composer in your project (or [download the composer.phar][1] directly):
|
||||
If you haven't installed [Composer][1] yet, you can do so using:
|
||||
|
||||
curl -s http://getcomposer.org/installer | php
|
||||
|
||||
And finally ask Composer to install the dependencies:
|
||||
|
||||
php composer.phar install
|
||||
|
||||
Installing as a Git Submodule
|
||||
-----------------------------
|
||||
|
||||
@ -34,7 +21,11 @@ Run the following command to install the parser into the `vendor/PHP-Parser` fol
|
||||
|
||||
git submodule add git://github.com/nikic/PHP-Parser.git vendor/PHP-Parser
|
||||
|
||||
Installing from the Zip- or Tarball
|
||||
-----------------------------------
|
||||
|
||||
Download the latest version from [the download page][2], unpack it and move the files somewhere into your project.
|
||||
|
||||
|
||||
[1]: http://getcomposer.org/composer.phar
|
||||
[2]: https://github.com/nikic/PHP-Parser/tags
|
||||
[1]: https://getcomposer.org/
|
||||
[2]: https://github.com/nikic/PHP-Parser/tags
|
||||
|
@ -6,19 +6,17 @@ This document explains how to use the parser, the pretty printer and the node tr
|
||||
Bootstrapping
|
||||
-------------
|
||||
|
||||
The library needs to register a class autoloader; this is done by including the
|
||||
`bootstrap.php` file:
|
||||
The library needs to register a class autoloader. When using composer, include the usual
|
||||
`vendor/autoload.php` file (alternatively you can use the bundled `lib/bootstrap.php` file):
|
||||
|
||||
```php
|
||||
<?php
|
||||
require 'path/to/PHP-Parser/lib/bootstrap.php';
|
||||
require 'path/to/vendor/autoload.php';
|
||||
```
|
||||
|
||||
Additionally you may want to set the `xdebug.max_nesting_level` ini option to a higher value:
|
||||
|
||||
```php
|
||||
<?php
|
||||
ini_set('xdebug.max_nesting_level', 2000);
|
||||
ini_set('xdebug.max_nesting_level', 3000);
|
||||
```
|
||||
|
||||
This ensures that there will be no errors when traversing highly nested node trees.
|
||||
@ -26,31 +24,46 @@ This ensures that there will be no errors when traversing highly nested node tre
|
||||
Parsing
|
||||
-------
|
||||
|
||||
In order to parse some source code you first have to create a `PhpParser\Parser` object (which
|
||||
needs to be passed a `PhpParser\Lexer` instance) and then pass the code (including `<?php` opening
|
||||
tags) to the `parse` method. If a syntax error is encountered `PhpParser\Error` is thrown, so this
|
||||
exception should be `catch`ed.
|
||||
In order to parse code, you first have to create a parser instance:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$code = '<?php // some code';
|
||||
use PhpParser\ParserFactory;
|
||||
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
|
||||
```
|
||||
|
||||
$parser = new PhpParser\Parser(new PhpParser\Lexer);
|
||||
The factory accepts a kind argument, that determines how different PHP versions are treated:
|
||||
|
||||
Kind | Behavior
|
||||
-----|---------
|
||||
`ParserFactory::PREFER_PHP7` | Try to parse code as PHP 7. If this fails, try to parse it as PHP 5.
|
||||
`ParserFactory::PREFER_PHP5` | Try to parse code as PHP 5. If this fails, try to parse it as PHP 7.
|
||||
`ParserFactory::ONLY_PHP7` | Parse code as PHP 7.
|
||||
`ParserFactory::ONLY_PHP5` | Parse code as PHP 5.
|
||||
|
||||
Unless you have strong reason to use something else, `PREFER_PHP7` is a reasonable default.
|
||||
|
||||
The `create()` method optionally accepts a `Lexer` instance as the second argument. Some use cases
|
||||
that require customized lexers are discussed in the [lexer documentation](component/Lexer.markdown).
|
||||
|
||||
Subsequently you can pass PHP code (including the opening `<?php` tag) to the `parse` method in order to
|
||||
create a syntax tree. If a syntax error is encountered, an `PhpParser\Error` exception will be thrown:
|
||||
|
||||
```php
|
||||
use PhpParser\Error;
|
||||
use PhpParser\ParserFactory;
|
||||
|
||||
$code = '<?php // some code';
|
||||
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
|
||||
|
||||
try {
|
||||
$stmts = $parser->parse($code);
|
||||
} catch (PhpParser\Error $e) {
|
||||
// $stmts is an array of statement nodes
|
||||
} catch (Error $e) {
|
||||
echo 'Parse Error: ', $e->getMessage();
|
||||
}
|
||||
```
|
||||
|
||||
The `parse` method will return an array of statement nodes (`$stmts`).
|
||||
|
||||
### Emulative lexer
|
||||
|
||||
Instead of `PhpParser\Lexer` one can also use `PhpParser\Lexer\Emulative`. This class will emulate tokens
|
||||
of newer PHP versions and as such allow parsing PHP 5.5 on PHP 5.2, for example. So if you want to parse
|
||||
PHP code of newer versions than the one you are running, you should use the emulative lexer.
|
||||
A parser instance can be reused to parse multiple files.
|
||||
|
||||
Node tree
|
||||
---------
|
||||
@ -93,7 +106,7 @@ with them easier they are grouped into three categories:
|
||||
and thus can occur in other expressions. Examples of expressions are `$var`
|
||||
(`PhpParser\Node\Expr\Variable`) and `func()` (`PhpParser\Node\Expr\FuncCall`).
|
||||
* `PhpParser\Node\Scalar`s are nodes representing scalar values, like `'string'`
|
||||
(`PhpParser\Node\Scalar\String`), `0` (`PhpParser\Node\Scalar\LNumber`) or magic constants
|
||||
(`PhpParser\Node\Scalar\String_`), `0` (`PhpParser\Node\Scalar\LNumber`) or magic constants
|
||||
like `__FILE__` (`PhpParser\Node\Scalar\MagicConst\File`). All `PhpParser\Node\Scalar`s extend
|
||||
`PhpParser\Node\Expr`, as scalars are expressions, too.
|
||||
* There are some nodes not in either of these groups, for example names (`PhpParser\Node\Name`)
|
||||
@ -104,7 +117,7 @@ with a PHP keyword.
|
||||
|
||||
Every node has a (possibly zero) number of subnodes. You can access subnodes by writing
|
||||
`$node->subNodeName`. The `Stmt\Echo_` node has only one subnode `exprs`. So in order to access it
|
||||
in the above example you would write `$stmts[0]->exprs`. If you wanted to access name of the function
|
||||
in the above example you would write `$stmts[0]->exprs`. If you wanted to access the name of the function
|
||||
call, you would write `$stmts[0]->exprs[1]->name`.
|
||||
|
||||
All nodes also define a `getType()` method that returns the node type. The type is the class name
|
||||
@ -128,11 +141,14 @@ information the formatting is done using a specified scheme. Currently there is
|
||||
namely `PhpParser\PrettyPrinter\Standard`.
|
||||
|
||||
```php
|
||||
<?php
|
||||
use PhpParser\Error;
|
||||
use PhpParser\ParserFactory;
|
||||
use PhpParser\PrettyPrinter;
|
||||
|
||||
$code = "<?php echo 'Hi ', hi\\getTarget();";
|
||||
|
||||
$parser = new PhpParser\Parser(new PhpParser\Lexer);
|
||||
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
|
||||
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
|
||||
$prettyPrinter = new PrettyPrinter\Standard;
|
||||
|
||||
try {
|
||||
// parse
|
||||
@ -143,20 +159,20 @@ try {
|
||||
->exprs // sub expressions
|
||||
[0] // the first of them (the string node)
|
||||
->value // it's value, i.e. 'Hi '
|
||||
= 'Hallo '; // change to 'Hallo '
|
||||
= 'Hello '; // change to 'Hello '
|
||||
|
||||
// pretty print
|
||||
$code = '<?php ' . $prettyPrinter->prettyPrint($stmts);
|
||||
$code = $prettyPrinter->prettyPrint($stmts);
|
||||
|
||||
echo $code;
|
||||
} catch (PhpParser\Error $e) {
|
||||
} catch (Error $e) {
|
||||
echo 'Parse Error: ', $e->getMessage();
|
||||
}
|
||||
```
|
||||
|
||||
The above code will output:
|
||||
|
||||
<?php echo 'Hallo ', hi\getTarget();
|
||||
<?php echo 'Hello ', hi\getTarget();
|
||||
|
||||
As you can see the source code was first parsed using `PhpParser\Parser->parse()`, then changed and then
|
||||
again converted to code using `PhpParser\PrettyPrinter\Standard->prettyPrint()`.
|
||||
@ -164,6 +180,9 @@ again converted to code using `PhpParser\PrettyPrinter\Standard->prettyPrint()`.
|
||||
The `prettyPrint()` method pretty prints a statements array. It is also possible to pretty print only a
|
||||
single expression using `prettyPrintExpr()`.
|
||||
|
||||
The `prettyPrintFile()` method can be used to print an entire file. This will include the opening `<?php` tag
|
||||
and handle inline HTML as the first/last statement more gracefully.
|
||||
|
||||
Node traversation
|
||||
-----------------
|
||||
|
||||
@ -176,17 +195,20 @@ For this purpose the parser provides a component for traversing and visiting the
|
||||
structure of a program using this `PhpParser\NodeTraverser` looks like this:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$code = "<?php // some code";
|
||||
use PhpParser\NodeTraverser;
|
||||
use PhpParser\ParserFactory;
|
||||
use PhpParser\PrettyPrinter;
|
||||
|
||||
$parser = new PhpParser\Parser(new PhpParser\Lexer);
|
||||
$traverser = new PhpParser\NodeTraverser;
|
||||
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
|
||||
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
|
||||
$traverser = new NodeTraverser;
|
||||
$prettyPrinter = new PrettyPrinter\Standard;
|
||||
|
||||
// add your visitor
|
||||
$traverser->addVisitor(new MyNodeVisitor);
|
||||
|
||||
try {
|
||||
$code = file_get_contents($fileName);
|
||||
|
||||
// parse
|
||||
$stmts = $parser->parse($code);
|
||||
|
||||
@ -194,7 +216,7 @@ try {
|
||||
$stmts = $traverser->traverse($stmts);
|
||||
|
||||
// pretty print
|
||||
$code = '<?php ' . $prettyPrinter->prettyPrint($stmts);
|
||||
$code = $prettyPrinter->prettyPrintFile($stmts);
|
||||
|
||||
echo $code;
|
||||
} catch (PhpParser\Error $e) {
|
||||
@ -202,14 +224,16 @@ try {
|
||||
}
|
||||
```
|
||||
|
||||
A same node visitor for this code might look like this:
|
||||
The corresponding node visitor might look like this:
|
||||
|
||||
```php
|
||||
<?php
|
||||
class MyNodeVisitor extends PhpParser\NodeVisitorAbstract
|
||||
use PhpParser\Node;
|
||||
use PhpParser\NodeVisitorAbstract;
|
||||
|
||||
class MyNodeVisitor extends NodeVisitorAbstract
|
||||
{
|
||||
public function leaveNode(PhpParser\Node $node) {
|
||||
if ($node instanceof PhpParser\Node\Scalar\String) {
|
||||
public function leaveNode(Node $node) {
|
||||
if ($node instanceof Node\Scalar\String_) {
|
||||
$node->value = 'foo';
|
||||
}
|
||||
}
|
||||
@ -218,30 +242,37 @@ class MyNodeVisitor extends PhpParser\NodeVisitorAbstract
|
||||
|
||||
The above node visitor would change all string literals in the program to `'foo'`.
|
||||
|
||||
All visitors must implement the `PhpParser\NodeVisitor` interface, which defined the following four
|
||||
All visitors must implement the `PhpParser\NodeVisitor` interface, which defines the following four
|
||||
methods:
|
||||
|
||||
public function beforeTraverse(array $nodes);
|
||||
public function enterNode(PhpParser\Node $node);
|
||||
public function leaveNode(PhpParser\Node $node);
|
||||
public function afterTraverse(array $nodes);
|
||||
```php
|
||||
public function beforeTraverse(array $nodes);
|
||||
public function enterNode(\PhpParser\Node $node);
|
||||
public function leaveNode(\PhpParser\Node $node);
|
||||
public function afterTraverse(array $nodes);
|
||||
```
|
||||
|
||||
The `beforeTraverse` method is called once before the traversal begins and is passed the nodes the
|
||||
The `beforeTraverse()` method is called once before the traversal begins and is passed the nodes the
|
||||
traverser was called with. This method can be used for resetting values before traversation or
|
||||
preparing the tree for traversal.
|
||||
|
||||
The `afterTraverse` method is similar to the `beforeTraverse` method, with the only difference that
|
||||
The `afterTraverse()` method is similar to the `beforeTraverse()` method, with the only difference that
|
||||
it is called once after the traversal.
|
||||
|
||||
The `enterNode` and `leaveNode` methods are called on every node, the former when it is entered,
|
||||
The `enterNode()` and `leaveNode()` methods are called on every node, the former when it is entered,
|
||||
i.e. before its subnodes are traversed, the latter when it is left.
|
||||
|
||||
All four methods can either return the changed node or not return at all (i.e. `null`) in which
|
||||
case the current node is not changed. The `leaveNode` method can furthermore return two special
|
||||
values: If `false` is returned the current node will be removed from the parent array. If an `array`
|
||||
is returned the current node will be merged into the parent array at the offset of the current node.
|
||||
I.e. if in `array(A, B, C)` the node `B` should be replaced with `array(X, Y, Z)` the result will be
|
||||
`array(A, X, Y, Z, C)`.
|
||||
case the current node is not changed.
|
||||
|
||||
The `enterNode()` method can additionally return the value `NodeTraverser::DONT_TRAVERSE_CHILDREN`,
|
||||
which instructs the traverser to skip all children of the current node.
|
||||
|
||||
The `leaveNode()` method can additionally return the value `NodeTraverser::REMOVE_NODE`, in which
|
||||
case the current node will be removed from the parent array. Furthermove it is possible to return
|
||||
an array of nodes, which will be merged into the parent array at the offset of the current node.
|
||||
I.e. if in `array(A, B, C)` the node `B` should be replaced with `array(X, Y, Z)` the result will
|
||||
be `array(A, X, Y, Z, C)`.
|
||||
|
||||
Instead of manually implementing the `NodeVisitor` interface you can also extend the `NodeVisitorAbstract`
|
||||
class, which will define empty default implementations for all the above methods.
|
||||
@ -279,21 +310,24 @@ assume that no dynamic features are used.
|
||||
We start off with the following base code:
|
||||
|
||||
```php
|
||||
<?php
|
||||
const IN_DIR = '/some/path';
|
||||
const OUT_DIR = '/some/other/path';
|
||||
use PhpParser\ParserFactory;
|
||||
use PhpParser\PrettyPrinter;
|
||||
use PhpParser\NodeTraverser;
|
||||
use PhpParser\NodeVisitor\NameResolver;
|
||||
|
||||
// use the emulative lexer here, as we are running PHP 5.2 but want to parse PHP 5.3
|
||||
$parser = new PhpParser\Parser(new PhpParser\Lexer\Emulative);
|
||||
$traverser = new PhpParser\NodeTraverser;
|
||||
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
|
||||
$inDir = '/some/path';
|
||||
$outDir = '/some/other/path';
|
||||
|
||||
$traverser->addVisitor(new PhpParser\NodeVisitor\NameResolver); // we will need resolved names
|
||||
$traverser->addVisitor(new NodeVisitor\NamespaceConverter); // our own node visitor
|
||||
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
|
||||
$traverser = new NodeTraverser;
|
||||
$prettyPrinter = new PrettyPrinter\Standard;
|
||||
|
||||
$traverser->addVisitor(new NameResolver); // we will need resolved names
|
||||
$traverser->addVisitor(new NamespaceConverter); // our own node visitor
|
||||
|
||||
// iterate over all .php files in the directory
|
||||
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(IN_DIR));
|
||||
$files = new RegexIterator($files, '/\.php$/');
|
||||
$files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($inDir));
|
||||
$files = new \RegexIterator($files, '/\.php$/');
|
||||
|
||||
foreach ($files as $file) {
|
||||
try {
|
||||
@ -307,11 +341,11 @@ foreach ($files as $file) {
|
||||
$stmts = $traverser->traverse($stmts);
|
||||
|
||||
// pretty print
|
||||
$code = '<?php ' . $prettyPrinter->prettyPrint($stmts);
|
||||
$code = $prettyPrinter->prettyPrintFile($stmts);
|
||||
|
||||
// write the converted file to the target directory
|
||||
file_put_contents(
|
||||
substr_replace($file->getPathname(), OUT_DIR, 0, strlen(IN_DIR)),
|
||||
substr_replace($file->getPathname(), $outDir, 0, strlen($inDir)),
|
||||
$code
|
||||
);
|
||||
} catch (PhpParser\Error $e) {
|
||||
@ -320,13 +354,13 @@ foreach ($files as $file) {
|
||||
}
|
||||
```
|
||||
|
||||
Now lets start with the main code, the `NodeVisitor_NamespaceConverter`. One thing it needs to do
|
||||
Now lets start with the main code, the `NodeVisitor\NamespaceConverter`. One thing it needs to do
|
||||
is convert `A\\B` style names to `A_B` style ones.
|
||||
|
||||
```php
|
||||
<?php
|
||||
use PhpParser\Node;
|
||||
class NodeVisitor_NamespaceConverter extends PhpParser\NodeVisitorAbstract
|
||||
|
||||
class NamespaceConverter extends \PhpParser\NodeVisitorAbstract
|
||||
{
|
||||
public function leaveNode(Node $node) {
|
||||
if ($node instanceof Node\Name) {
|
||||
@ -337,20 +371,20 @@ class NodeVisitor_NamespaceConverter extends PhpParser\NodeVisitorAbstract
|
||||
```
|
||||
|
||||
The above code profits from the fact that the `NameResolver` already resolved all names as far as
|
||||
possible, so we don't need to do that. All the need to create a string with the name parts separated
|
||||
possible, so we don't need to do that. We only need to create a string with the name parts separated
|
||||
by underscores instead of backslashes. This is what `$node->toString('_')` does. (If you want to
|
||||
create a name with backslashes either write `$node->toString()` or `(string) $node`.) Then we create
|
||||
a new name from the string and return it. Returning a new node replaces the old node.
|
||||
|
||||
Another thing we need to do is change the class/function/const declarations. Currently they contain
|
||||
only the shortname (i.e. the last part of the name), but they need to contain the complete class
|
||||
name:
|
||||
only the shortname (i.e. the last part of the name), but they need to contain the complete name inclduing
|
||||
the namespace prefix:
|
||||
|
||||
```php
|
||||
<?php
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt;
|
||||
class NodeVisitor_NamespaceConverter extends PhpParser\NodeVisitorAbstract
|
||||
|
||||
class NodeVisitor_NamespaceConverter extends \PhpParser\NodeVisitorAbstract
|
||||
{
|
||||
public function leaveNode(Node $node) {
|
||||
if ($node instanceof Node\Name) {
|
||||
@ -373,10 +407,10 @@ There is not much more to it than converting the namespaced name to string with
|
||||
The last thing we need to do is remove the `namespace` and `use` statements:
|
||||
|
||||
```php
|
||||
<?php
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt;
|
||||
class NodeVisitor_NamespaceConverter extends PhpParser\NodeVisitorAbstract
|
||||
|
||||
class NodeVisitor_NamespaceConverter extends \PhpParser\NodeVisitorAbstract
|
||||
{
|
||||
public function leaveNode(Node $node) {
|
||||
if ($node instanceof Node\Name) {
|
||||
@ -400,4 +434,4 @@ class NodeVisitor_NamespaceConverter extends PhpParser\NodeVisitorAbstract
|
||||
}
|
||||
```
|
||||
|
||||
That's all.
|
||||
That's all.
|
||||
|
@ -1,7 +1,7 @@
|
||||
Other node tree representations
|
||||
===============================
|
||||
|
||||
It is possible to convert the AST in several textual representations, which serve different uses.
|
||||
It is possible to convert the AST into several textual representations, which serve different uses.
|
||||
|
||||
Simple serialization
|
||||
--------------------
|
||||
@ -13,33 +13,33 @@ but PHP, but it is compact and generates fast. The main application thus is in c
|
||||
Human readable dumping
|
||||
----------------------
|
||||
|
||||
Furthermore it is possible to dump nodes into a human readable form using the `dump` method of
|
||||
Furthermore it is possible to dump nodes into a human readable format using the `dump` method of
|
||||
`PhpParser\NodeDumper`. This can be used for debugging.
|
||||
|
||||
```php
|
||||
<?php
|
||||
$code = <<<'CODE'
|
||||
<?php
|
||||
function printLine($msg) {
|
||||
echo $msg, "\n";
|
||||
}
|
||||
|
||||
printLine('Hallo World!!!');
|
||||
function printLine($msg) {
|
||||
echo $msg, "\n";
|
||||
}
|
||||
|
||||
printLine('Hello World!!!');
|
||||
CODE;
|
||||
|
||||
$parser = new PhpParser\Parser(new PhpParser\Lexer);
|
||||
$parser = (new PhpParser\ParserFactory)->create(PhpParser\ParserFactory::PREFER_PHP7);
|
||||
$nodeDumper = new PhpParser\NodeDumper;
|
||||
|
||||
try {
|
||||
$stmts = $parser->parse($code);
|
||||
|
||||
echo '<pre>' . htmlspecialchars($nodeDumper->dump($stmts)) . '</pre>';
|
||||
echo $nodeDumper->dump($stmts), "\n";
|
||||
} catch (PhpParser\Error $e) {
|
||||
echo 'Parse Error: ', $e->getMessage();
|
||||
}
|
||||
```
|
||||
|
||||
The above output will have an output looking roughly like this:
|
||||
The above script will have an output looking roughly like this:
|
||||
|
||||
```
|
||||
array(
|
||||
@ -77,7 +77,7 @@ array(
|
||||
args: array(
|
||||
0: Arg(
|
||||
value: Scalar_String(
|
||||
value: Hallo World!!!
|
||||
value: Hello World!!!
|
||||
)
|
||||
byRef: false
|
||||
)
|
||||
@ -97,20 +97,21 @@ interfacing with other languages and applications or for doing transformation us
|
||||
<?php
|
||||
$code = <<<'CODE'
|
||||
<?php
|
||||
function printLine($msg) {
|
||||
echo $msg, "\n";
|
||||
}
|
||||
|
||||
printLine('Hallo World!!!');
|
||||
function printLine($msg) {
|
||||
echo $msg, "\n";
|
||||
}
|
||||
|
||||
printLine('Hello World!!!');
|
||||
CODE;
|
||||
|
||||
$parser = new PhpParser\Parser(new PhpParser\Lexer);
|
||||
$parser = (new PhpParser\ParserFactory)->create(PhpParser\ParserFactory::PREFER_PHP7);
|
||||
$serializer = new PhpParser\Serializer\XML;
|
||||
|
||||
try {
|
||||
$stmts = $parser->parse($code);
|
||||
|
||||
echo '<pre>' . htmlspecialchars($serializer->serialize($stmts)) . '</pre>';
|
||||
echo $serializer->serialize($stmts);
|
||||
} catch (PhpParser\Error $e) {
|
||||
echo 'Parse Error: ', $e->getMessage();
|
||||
}
|
||||
@ -185,7 +186,7 @@ Produces:
|
||||
<subNode:value>
|
||||
<node:Scalar_String line="6">
|
||||
<subNode:value>
|
||||
<scalar:string>Hallo World!!!</scalar:string>
|
||||
<scalar:string>Hello World!!!</scalar:string>
|
||||
</subNode:value>
|
||||
</node:Scalar_String>
|
||||
</subNode:value>
|
||||
|
@ -2,266 +2,82 @@ Code generation
|
||||
===============
|
||||
|
||||
It is also possible to generate code using the parser, by first creating an Abstract Syntax Tree and then using the
|
||||
pretty printer to convert it to PHP code. To simplify code generation, the project comes with a set of builders for
|
||||
common structures as well as simple templating support. Both features are described in the following:
|
||||
pretty printer to convert it to PHP code. To simplify code generation, the project comes with builders which allow
|
||||
creating node trees using a fluid interface, instead of instantiating all nodes manually. Builders are available for
|
||||
the following syntactic elements:
|
||||
|
||||
Builders
|
||||
--------
|
||||
|
||||
The project provides builders for classes, interfaces, methods, functions, parameters and properties, which
|
||||
allow creating node trees with a fluid interface, instead of instantiating all nodes manually.
|
||||
* namespaces and use statements
|
||||
* classes, interfaces and traits
|
||||
* methods, functions and parameters
|
||||
* properties
|
||||
|
||||
Here is an example:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$factory = new PhpParser\BuilderFactory;
|
||||
$node = $factory->class('SomeClass')
|
||||
->extend('SomeOtherClass')
|
||||
->implement('A\Few', 'Interfaces')
|
||||
->makeAbstract() // ->makeFinal()
|
||||
use PhpParser\BuilderFactory;
|
||||
use PhpParser\PrettyPrinter;
|
||||
use PhpParser\Node;
|
||||
|
||||
->addStmt($factory->method('someMethod')
|
||||
$factory = new BuilderFactory;
|
||||
$node = $factory->namespace('Name\Space')
|
||||
->addStmt($factory->use('Some\Other\Thingy')->as('SomeOtherClass'))
|
||||
->addStmt($factory->class('SomeClass')
|
||||
->extend('SomeOtherClass')
|
||||
->implement('A\Few', '\Interfaces')
|
||||
->makeAbstract() // ->makeFinal()
|
||||
->addParam($factory->param('someParam')->setTypeHint('SomeClass'))
|
||||
)
|
||||
|
||||
->addStmt($factory->method('anotherMethod')
|
||||
->makeProtected() // ->makePublic() [default], ->makePrivate()
|
||||
->addParam($factory->param('someParam')->setDefault('test'))
|
||||
// it is possible to add manually created nodes
|
||||
->addStmt(new PhpParser\Node\Expr\Print_(new PhpParser\Node\Expr\Variable('someParam')))
|
||||
)
|
||||
->addStmt($factory->method('someMethod')
|
||||
->makePublic()
|
||||
->makeAbstract() // ->makeFinal()
|
||||
->addParam($factory->param('someParam')->setTypeHint('SomeClass'))
|
||||
->setDocComment('/**
|
||||
* This method does something.
|
||||
*
|
||||
* @param SomeClass And takes a parameter
|
||||
*/')
|
||||
)
|
||||
|
||||
// properties will be correctly reordered above the methods
|
||||
->addStmt($factory->property('someProperty')->makeProtected())
|
||||
->addStmt($factory->property('anotherProperty')->makePrivate()->setDefault(array(1, 2, 3)))
|
||||
->addStmt($factory->method('anotherMethod')
|
||||
->makeProtected() // ->makePublic() [default], ->makePrivate()
|
||||
->addParam($factory->param('someParam')->setDefault('test'))
|
||||
// it is possible to add manually created nodes
|
||||
->addStmt(new Node\Expr\Print_(new Node\Expr\Variable('someParam')))
|
||||
)
|
||||
|
||||
// properties will be correctly reordered above the methods
|
||||
->addStmt($factory->property('someProperty')->makeProtected())
|
||||
->addStmt($factory->property('anotherProperty')->makePrivate()->setDefault(array(1, 2, 3)))
|
||||
)
|
||||
|
||||
->getNode()
|
||||
;
|
||||
|
||||
$stmts = array($node);
|
||||
echo $prettyPrinter->prettyPrint($stmts);
|
||||
$prettyPrinter = new PrettyPrinter\Standard();
|
||||
echo $prettyPrinter->prettyPrintFile($stmts);
|
||||
```
|
||||
|
||||
This will produce the following output with the default pretty printer:
|
||||
This will produce the following output with the standard pretty printer:
|
||||
|
||||
```php
|
||||
<?php
|
||||
abstract class SomeClass extends SomeOtherClass implements A\Few, Interfaces
|
||||
|
||||
namespace Name\Space;
|
||||
|
||||
use Some\Other\Thingy as SomeClass;
|
||||
abstract class SomeClass extends SomeOtherClass implements A\Few, \Interfaces
|
||||
{
|
||||
protected $someProperty;
|
||||
private $anotherProperty = array(1, 2, 3);
|
||||
abstract function someMethod(SomeClass $someParam);
|
||||
/**
|
||||
* This method does something.
|
||||
*
|
||||
* @param SomeClass And takes a parameter
|
||||
*/
|
||||
public abstract function someMethod(SomeClass $someParam);
|
||||
protected function anotherMethod($someParam = 'test')
|
||||
{
|
||||
print $someParam;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Templates
|
||||
---------
|
||||
|
||||
> **DEPRECATED**: This feature is deprecated and will be removed in PHP-Parser 1.0.
|
||||
|
||||
Additionally it is possible to generate code from reusable templates.
|
||||
|
||||
As an example consider the following template, which defines a general getter/setter skeleton in terms of a property
|
||||
`__name__` and its `__type__`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
class GetterSetterTemplate
|
||||
{
|
||||
/**
|
||||
* @var __type__ The __name__
|
||||
*/
|
||||
protected $__name__;
|
||||
|
||||
/**
|
||||
* Gets the __name__.
|
||||
*
|
||||
* @return __type__ The __name__
|
||||
*/
|
||||
public function get__Name__() {
|
||||
return $this->__name__;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the __name__.
|
||||
*
|
||||
* @param __type__ $__name__ The new __name__
|
||||
*/
|
||||
public function set__Name__($__name__) {
|
||||
$this->__name__ = $__name__;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Using this template we can easily create a class with multiple properties and their respective getters and setters:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
// $templateString contains the above template
|
||||
$template = new PhpParser\Template($parser, $templateString);
|
||||
|
||||
// We only have to specify the __name__ placeholder, as the
|
||||
// capitalized __Name__ placeholder is automatically created
|
||||
$properties = [
|
||||
['name' => 'title', 'type' => 'string'],
|
||||
['name' => 'body', 'type' => 'string'],
|
||||
['name' => 'author', 'type' => 'User'],
|
||||
['name' => 'timestamp', 'type' => 'DateTime'],
|
||||
];
|
||||
|
||||
$class = $factory->class('BlogPost')->implement('Post');
|
||||
|
||||
foreach ($properties as $propertyPlaceholders) {
|
||||
$stmts = $template->getStmts($propertyPlaceholders);
|
||||
|
||||
$class->addStmts(
|
||||
// $stmts contains all statements from the template. So [0] fetches the class statement
|
||||
// and ->stmts retrieves the methods.
|
||||
$stmts[0]->stmts
|
||||
);
|
||||
}
|
||||
|
||||
echo $prettyPrinter->prettyPrint(array($class->getNode()));
|
||||
```
|
||||
|
||||
The result would look roughly like this:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
class BlogPost implements Post
|
||||
{
|
||||
/**
|
||||
* @var string The title
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
/**
|
||||
* @var string The body
|
||||
*/
|
||||
protected $body;
|
||||
|
||||
/**
|
||||
* @var User The author
|
||||
*/
|
||||
protected $author;
|
||||
|
||||
/**
|
||||
* @var DateTime The timestamp
|
||||
*/
|
||||
protected $timestamp;
|
||||
|
||||
/**
|
||||
* Gets the title.
|
||||
*
|
||||
* @return string The title
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the title.
|
||||
*
|
||||
* @param string $title The new title
|
||||
*/
|
||||
public function setTitle($title)
|
||||
{
|
||||
$this->title = $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the body.
|
||||
*
|
||||
* @return string The body
|
||||
*/
|
||||
public function getBody()
|
||||
{
|
||||
return $this->body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the body.
|
||||
*
|
||||
* @param string $body The new body
|
||||
*/
|
||||
public function setBody($body)
|
||||
{
|
||||
$this->body = $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the author.
|
||||
*
|
||||
* @return User The author
|
||||
*/
|
||||
public function getAuthor()
|
||||
{
|
||||
return $this->author;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the author.
|
||||
*
|
||||
* @param User $author The new author
|
||||
*/
|
||||
public function setAuthor($author)
|
||||
{
|
||||
$this->author = $author;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the timestamp.
|
||||
*
|
||||
* @return DateTime The timestamp
|
||||
*/
|
||||
public function getTimestamp()
|
||||
{
|
||||
return $this->timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the timestamp.
|
||||
*
|
||||
* @param DateTime $timestamp The new timestamp
|
||||
*/
|
||||
public function setTimestamp($timestamp)
|
||||
{
|
||||
$this->timestamp = $timestamp;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When using multiple templates it is easier to manage them on the filesystem. They can be loaded using the
|
||||
`TemplateLoader`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
// We'll store our templates in ./templates and give them a .php suffix
|
||||
$loader = new PhpParser\TemplateLoader($parser, './templates', '.php');
|
||||
|
||||
// loads ./templates/GetterSetter.php
|
||||
$getterSetterTemplate = $loader->load('GetterSetter');
|
||||
|
||||
// loads ./templates/Collection.php
|
||||
$collectionTemplate = $loader->load('Collection');
|
||||
|
||||
// The use of a suffix is optional. The following code for example is equivalent:
|
||||
$loader = new PhpParser\TemplateLoader($parser, './templates');
|
||||
|
||||
// loads ./templates/GetterSetter.php
|
||||
$getterSetterTemplate = $loader->load('GetterSetter.php');
|
||||
|
||||
// loads ./templates/Collection.php
|
||||
$collectionTemplate = $loader->load('Collection.php');
|
||||
```
|
77
doc/component/Error.markdown
Normal file
77
doc/component/Error.markdown
Normal file
@ -0,0 +1,77 @@
|
||||
Error handling
|
||||
==============
|
||||
|
||||
Errors during parsing or analysis are represented using the `PhpParser\Error` exception class. In addition to an error
|
||||
message, an error can also store additional information about the location the error occurred at.
|
||||
|
||||
How much location information is available depends on the origin of the error and how many lexer attributes have been
|
||||
enabled. At a minimum the start line of the error is usually available.
|
||||
|
||||
Column information
|
||||
------------------
|
||||
|
||||
In order to receive information about not only the line, but also the column span an error occurred at, the file
|
||||
position attributes in the lexer need to be enabled:
|
||||
|
||||
```php
|
||||
$lexer = new PhpParser\Lexer(array(
|
||||
'usedAttributes' => array('comments', 'startLine', 'endLine', 'startFilePos', 'endFilePos'),
|
||||
));
|
||||
$parser = (new PhpParser\ParserFactory)->create(PhpParser\ParserFactory::PREFER_PHP7, $lexer);
|
||||
|
||||
try {
|
||||
$stmts = $parser->parse($code);
|
||||
// ...
|
||||
} catch (PhpParser\Error $e) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Before using column information its availability needs to be checked with `$e->hasColumnInfo()`, as the precise
|
||||
location of an error cannot always be determined. The methods for retrieving column information also have to be passed
|
||||
the source code of the parsed file. An example for printing an error:
|
||||
|
||||
```php
|
||||
if ($e->hasColumnInfo()) {
|
||||
echo $e->getRawMessage() . ' from ' . $e->getStartLine() . ':' . $e->getStartColumn($code)
|
||||
. ' to ' . $e->getEndLine() . ':' . $e->getEndColumn($code);
|
||||
} else {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
```
|
||||
|
||||
Both line numbers and column numbers are 1-based. EOF errors will be located at the position one past the end of the
|
||||
file.
|
||||
|
||||
Error recovery
|
||||
--------------
|
||||
|
||||
> **EXPERIMENTAL**
|
||||
|
||||
By default the parser will throw an exception upon encountering the first error during parsing. An alternative mode is
|
||||
also supported, in which the parser will remember the error, but try to continue parsing the rest of the source code.
|
||||
|
||||
To enable this mode the `throwOnError` parser option needs to be disabled. Any errors that occurred during parsing can
|
||||
then be retrieved using `$parser->getErrors()`. The `$parser->parse()` method will either return a partial syntax tree
|
||||
or `null` if recovery fails.
|
||||
|
||||
A usage example:
|
||||
|
||||
```php
|
||||
$parser = (new PhpParser\ParserFactory)->create(PhpParser\ParserFactory::PREFER_PHP7, null, array(
|
||||
'throwOnError' => false,
|
||||
));
|
||||
|
||||
$stmts = $parser->parse($code);
|
||||
$errors = $parser->getErrors();
|
||||
|
||||
foreach ($errors as $error) {
|
||||
// $error is an ordinary PhpParser\Error
|
||||
}
|
||||
|
||||
if (null !== $stmts) {
|
||||
// $stmts is a best-effort partial AST
|
||||
}
|
||||
```
|
||||
|
||||
The error recovery implementation is experimental -- it currently won't be able to recover from many types of errors.
|
@ -5,47 +5,115 @@ The lexer is responsible for providing tokens to the parser. The project comes w
|
||||
`PhpParser\Lexer\Emulative`. The latter is an extension of the former, which adds the ability to emulate tokens of
|
||||
newer PHP versions and thus allows parsing of new code on older versions.
|
||||
|
||||
A lexer has to define the following public interface:
|
||||
This documentation discusses options available for the default lexers and explains how lexers can be extended.
|
||||
|
||||
startLexing($code);
|
||||
getNextToken(&$value = null, &$startAttributes = null, &$endAttributes = null);
|
||||
handleHaltCompiler();
|
||||
Lexer options
|
||||
-------------
|
||||
|
||||
startLexing
|
||||
-----------
|
||||
|
||||
The `startLexing` method is invoked when the `parse()` method of the parser is called. It's argument will be whatever
|
||||
was passed to the `parse()` method.
|
||||
|
||||
Even though `startLexing` is meant to accept a source code string, you could for example overwrite it to accept a file:
|
||||
The two default lexers accept an `$options` array in the constructor. Currently only the `'usedAttributes'` option is
|
||||
supported, which allows you to specify which attributes will be added to the AST nodes. The attributes can then be
|
||||
accessed using `$node->getAttribute()`, `$node->setAttribute()`, `$node->hasAttribute()` and `$node->getAttributes()`
|
||||
methods. A sample options array:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$lexer = new PhpParser\Lexer(array(
|
||||
'usedAttributes' => array(
|
||||
'comments', 'startLine', 'endLine'
|
||||
)
|
||||
));
|
||||
```
|
||||
|
||||
class FileLexer extends PhpParser\Lexer {
|
||||
public function startLexing($fileName) {
|
||||
if (!file_exists($fileName)) {
|
||||
throw new InvalidArgumentException(sprintf('File "%s" does not exist', $fileName));
|
||||
The attributes used in this example match the default behavior of the lexer. The following attributes are supported:
|
||||
|
||||
* `comments`: Array of `PhpParser\Comment` or `PhpParser\Comment\Doc` instances, representing all comments that occurred
|
||||
between the previous non-discarded token and the current one. Use of this attribute is required for the
|
||||
`$node->getDocComment()` method to work. The attribute is also needed if you wish the pretty printer to retain
|
||||
comments present in the original code.
|
||||
* `startLine`: Line in which the node starts. This attribute is required for the `$node->getLine()` to work. It is also
|
||||
required if syntax errors should contain line number information.
|
||||
* `endLine`: Line in which the node ends.
|
||||
* `startTokenPos`: Offset into the token array of the first token in the node.
|
||||
* `endTokenPos`: Offset into the token array of the last token in the node.
|
||||
* `startFilePos`: Offset into the code string of the first character that is part of the node.
|
||||
* `endFilePos`: Offset into the code string of the last character that is part of the node.
|
||||
|
||||
### Using token positions
|
||||
|
||||
The token offset information is useful if you wish to examine the exact formatting used for a node. For example the AST
|
||||
does not distinguish whether a property was declared using `public` or using `var`, but you can retrieve this
|
||||
information based on the token position:
|
||||
|
||||
```php
|
||||
function isDeclaredUsingVar(array $tokens, PhpParser\Node\Stmt\Property $prop) {
|
||||
$i = $prop->getAttribute('startTokenPos');
|
||||
return $tokens[$i][0] === T_VAR;
|
||||
}
|
||||
```
|
||||
|
||||
In order to make use of this function, you will have to provide the tokens from the lexer to your node visitor using
|
||||
code similar to the following:
|
||||
|
||||
```php
|
||||
class MyNodeVisitor extends PhpParser\NodeVisitorAbstract {
|
||||
private $tokens;
|
||||
public function setTokens(array $tokens) {
|
||||
$this->tokens = $tokens;
|
||||
}
|
||||
|
||||
public function leaveNode(PhpParser\Node $node) {
|
||||
if ($node instanceof PhpParser\Node\Stmt\Property) {
|
||||
var_dump(isDeclaredUsingVar($this->tokens, $node));
|
||||
}
|
||||
|
||||
parent::startLexing(file_get_contents($fileName));
|
||||
}
|
||||
}
|
||||
|
||||
$parser = new PhpParser\Parser(new FileLexer);
|
||||
$lexer = new PhpParser\Lexer(array(
|
||||
'usedAttributes' => array(
|
||||
'comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos'
|
||||
)
|
||||
));
|
||||
$parser = (new PhpParser\ParserFactory)->create(PhpParser\ParserFactory::PREFER_PHP7, $lexer);
|
||||
|
||||
var_dump($parser->parse('someFile.php'));
|
||||
var_dump($parser->parse('someOtherFile.php'));
|
||||
$visitor = new MyNodeVisitor();
|
||||
$traverser = new PhpParser\NodeTraverser();
|
||||
$traverser->addVisitor($visitor);
|
||||
|
||||
try {
|
||||
$stmts = $parser->parse($code);
|
||||
$visitor->setTokens($lexer->getTokens());
|
||||
$stmts = $traverser->traverse($stmts);
|
||||
} catch (PhpParser\Error $e) {
|
||||
echo 'Parse Error: ', $e->getMessage();
|
||||
}
|
||||
```
|
||||
|
||||
getNextToken
|
||||
------------
|
||||
The same approach can also be used to perform specific modifications in the code, without changing the formatting in
|
||||
other places (which is the case when using the pretty printer).
|
||||
|
||||
`getNextToken` returns the ID of the next token and sets some additional information in the three variables which it
|
||||
accepts by-ref. If no more tokens are available it has to return `0`, which is the ID of the `EOF` token.
|
||||
Lexer extension
|
||||
---------------
|
||||
|
||||
The first by-ref variable `$value` should contain the textual content of the token. It is what will be available as `$1`
|
||||
etc in the parser.
|
||||
A lexer has to define the following public interface:
|
||||
|
||||
void startLexing(string $code);
|
||||
array getTokens();
|
||||
string handleHaltCompiler();
|
||||
int getNextToken(string &$value = null, array &$startAttributes = null, array &$endAttributes = null);
|
||||
|
||||
The `startLexing()` method is invoked with the source code that is to be lexed (including the opening tag) whenever the
|
||||
`parse()` method of the parser is called. It can be used to reset state or preprocess the source code or tokens.
|
||||
|
||||
The `getTokens()` method returns the current token array, in the usual `token_get_all()` format. This method is not
|
||||
used by the parser (which uses `getNextToken()`), but is useful in combination with the token position attributes.
|
||||
|
||||
The `handleHaltCompiler()` method is called whenever a `T_HALT_COMPILER` token is encountered. It has to return the
|
||||
remaining string after the construct (not including `();`).
|
||||
|
||||
The `getNextToken()` method returns the ID of the next token (as defined by the `Parser::T_*` constants). If no more
|
||||
tokens are available it must return `0`, which is the ID of the `EOF` token. Furthermore the string content of the
|
||||
token should be written into the by-reference `$value` parameter (which will then be available as `$n` in the parser).
|
||||
|
||||
### Attribute handling
|
||||
|
||||
The other two by-ref variables `$startAttributes` and `$endAttributes` define which attributes will eventually be
|
||||
assigned to the generated nodes: The parser will take the `$startAttributes` from the first token which is part of the
|
||||
@ -54,61 +122,28 @@ node and the `$endAttributes` from the last token that is part of the node.
|
||||
E.g. if the tokens `T_FUNCTION T_STRING ... '{' ... '}'` constitute a node, then the `$startAttributes` from the
|
||||
`T_FUNCTION` token will be taken and the `$endAttributes` from the `'}'` token.
|
||||
|
||||
By default the lexer creates the attributes `startLine`, `comments` (both part of `$startAttributes`) and `endLine`
|
||||
(part of `$endAttributes`).
|
||||
|
||||
If you don't want all these attributes to be added (to reduce memory usage of the AST) you can simply remove them by
|
||||
overriding the method:
|
||||
An application of custom attributes is storing the original formatting of literals: The parser does not retain
|
||||
information about the formatting of integers (like decimal vs. hexadecimal) or strings (like used quote type or used
|
||||
escape sequences). This can be remedied by storing the original value in an attribute:
|
||||
|
||||
```php
|
||||
<?php
|
||||
use PhpParser\Lexer;
|
||||
use PhpParser\Parser\Tokens;
|
||||
|
||||
class LessAttributesLexer extends PhpParser\Lexer {
|
||||
class KeepOriginalValueLexer extends Lexer // or Lexer\Emulative
|
||||
{
|
||||
public function getNextToken(&$value = null, &$startAttributes = null, &$endAttributes = null) {
|
||||
$tokenId = parent::getNextToken($value, $startAttributes, $endAttributes);
|
||||
|
||||
// only keep startLine attribute
|
||||
unset($startAttributes['comments']);
|
||||
unset($endAttributes['endLine']);
|
||||
|
||||
return $tokenId;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can obviously also add additional attributes. E.g. in conjunction with the above `FileLexer` you might want to add
|
||||
a `fileName` attribute to all nodes:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
class FileLexer extends PhpParser\Lexer {
|
||||
protected $fileName;
|
||||
|
||||
public function startLexing($fileName) {
|
||||
if (!file_exists($fileName)) {
|
||||
throw new InvalidArgumentException(sprintf('File "%s" does not exist', $fileName));
|
||||
if ($tokenId == Tokens::T_CONSTANT_ENCAPSED_STRING // non-interpolated string
|
||||
|| $tokenId == Tokens::T_LNUMBER // integer
|
||||
|| $tokenId == Tokens::T_DNUMBER // floating point number
|
||||
) {
|
||||
// could also use $startAttributes, doesn't really matter here
|
||||
$endAttributes['originalValue'] = $value;
|
||||
}
|
||||
|
||||
$this->fileName = $fileName;
|
||||
parent::startLexing(file_get_contents($fileName));
|
||||
}
|
||||
|
||||
public function getNextToken(&$value = null, &$startAttributes = null, &$endAttributes = null) {
|
||||
$tokenId = parent::getNextToken($value, $startAttributes, $endAttributes);
|
||||
|
||||
// we could use either $startAttributes or $endAttributes here, because the fileName is always the same
|
||||
// (regardless of whether it is the start or end token). We choose $endAttributes, because it is slightly
|
||||
// more efficient (as the parser has to keep a stack for the $startAttributes).
|
||||
$endAttributes['fileName'] = $this->fileName;
|
||||
|
||||
return $tokenId;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
handleHaltCompiler
|
||||
------------------
|
||||
|
||||
The method is invoked whenever a `T_HALT_COMPILER` token is encountered. It has to return the remaining string after the
|
||||
construct (not including `();`).
|
||||
|
@ -1,23 +1,23 @@
|
||||
What do all those files mean?
|
||||
=============================
|
||||
|
||||
* `zend_language_parser.phpy`: PHP grammer written in a pseudo language
|
||||
* `analyze.php`: Analyzes the `.phpy`-grammer and outputs some info about it
|
||||
* `rebuildParser.php`: Preprocesses the `.phpy`-grammar and builds the parser using `kmyacc`
|
||||
* `kmyacc.php.parser`: A `kmyacc` parser prototype file for PHP
|
||||
* `php5.y`: PHP 5 grammar written in a pseudo language
|
||||
* `php7.y`: PHP 7 grammar written in a pseudo language
|
||||
* `tokens.y`: Tokens definition shared between PHP 5 and PHP 7 grammars
|
||||
* `parser.template`: A `kmyacc` parser prototype file for PHP
|
||||
* `tokens.template`: A `kmyacc` prototype file for the `Tokens` class
|
||||
* `analyze.php`: Analyzes the grammer and outputs some info about it
|
||||
* `rebuildParser.php`: Preprocesses the grammar and builds the parser using `kmyacc`
|
||||
|
||||
.phpy pseudo language
|
||||
=====================
|
||||
|
||||
The `.phpy` file is a normal grammer in `kmyacc` (`yacc`) style, with some transformations
|
||||
The `.y` file is a normal grammer in `kmyacc` (`yacc`) style, with some transformations
|
||||
applied to it:
|
||||
|
||||
* Nodes are created using the syntax `Name[..., ...]`. This is transformed into
|
||||
`new Node\Name(..., ..., $attributes)`
|
||||
* `Name::abc` is transformed to `Node\Name::abc`
|
||||
`new Name(..., ..., attributes())`
|
||||
* Some function-like constructs are resolved (see `rebuildParser.php` for a list)
|
||||
* Associative arrays are written as `[key: value, ...]`, which is transformed to
|
||||
`array('key' => value, ...)`
|
||||
|
||||
Building the parser
|
||||
===================
|
||||
@ -25,5 +25,5 @@ Building the parser
|
||||
In order to rebuild the parser, you need [moriyoshi's fork of kmyacc](https://github.com/moriyoshi/kmyacc-forked).
|
||||
After you compiled/installed it, run the `rebuildParser.php` script.
|
||||
|
||||
By default only the `Parser.php` is built. If you want to additionally build `Parser/Debug.php` and `y.output` run the
|
||||
script with `--debug`. If you want to retain the preprocessed grammar pass `--keep-tmp-grammar`.
|
||||
By default only the `Parser.php` is built. If you want to additionally emit debug symbols and create `y.output`, run the
|
||||
script with `--debug`. If you want to retain the preprocessed grammar pass `--keep-tmp-grammar`.
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
const GRAMMAR_FILE = './zend_language_parser.phpy';
|
||||
const GRAMMAR_FILE = './php5.y';
|
||||
|
||||
const LIB = '(?(DEFINE)
|
||||
(?<singleQuotedString>\'[^\\\\\']*+(?:\\\\.[^\\\\\']*+)*+\')
|
||||
@ -93,4 +93,4 @@ foreach ($ruleBlocksMatches as $match) {
|
||||
}
|
||||
|
||||
echo $ruleBlockName, ':', "\n", ' ', implode("\n" . ' | ', $rules), "\n", ';', "\n\n";
|
||||
}
|
||||
}
|
||||
|
@ -1,363 +0,0 @@
|
||||
<?php
|
||||
$meta #
|
||||
#semval($) $this->yyval
|
||||
#semval($,%t) $this->yyval
|
||||
#semval(%n) $this->yyastk[$this->stackPos-(%l-%n)]
|
||||
#semval(%n,%t) $this->yyastk[$this->stackPos-(%l-%n)]
|
||||
#include;
|
||||
|
||||
namespace PhpParser;
|
||||
|
||||
/* This is an automatically GENERATED file, which should not be manually edited.
|
||||
* Instead edit one of the following:
|
||||
* * the grammar file grammar/zend_language_parser.phpy
|
||||
* * the parser skeleton grammar/kymacc.php.parser
|
||||
* * the preprocessing script grammar/rebuildParser.php
|
||||
*
|
||||
* The skeleton for this parser was written by Moriyoshi Koizumi and is based on
|
||||
* the work by Masato Bito and is in the PUBLIC DOMAIN.
|
||||
*/
|
||||
#if -t
|
||||
class #(-p)_Debug extends #(-p)
|
||||
#endif
|
||||
#ifnot -t
|
||||
class #(-p)
|
||||
#endif
|
||||
{
|
||||
#ifnot -t
|
||||
const TOKEN_NONE = -1;
|
||||
const TOKEN_INVALID = #(YYBADCH);
|
||||
|
||||
const TOKEN_MAP_SIZE = #(YYMAXLEX);
|
||||
|
||||
const YYLAST = #(YYLAST);
|
||||
const YY2TBLSTATE = #(YY2TBLSTATE);
|
||||
const YYGLAST = #(YYGLAST);
|
||||
const YYNLSTATES = #(YYNLSTATES);
|
||||
const YYUNEXPECTED = #(YYUNEXPECTED);
|
||||
const YYDEFAULT = #(YYDEFAULT);
|
||||
|
||||
// {{{ Tokens
|
||||
#tokenval
|
||||
const %s = %n;
|
||||
#endtokenval
|
||||
// }}}
|
||||
|
||||
/* @var array Map of token ids to their respective names */
|
||||
protected static $terminals = array(
|
||||
#listvar terminals
|
||||
, "???"
|
||||
);
|
||||
|
||||
/* @var array Map which translates lexer tokens to internal tokens */
|
||||
protected static $translate = array(
|
||||
#listvar yytranslate
|
||||
);
|
||||
|
||||
protected static $yyaction = array(
|
||||
#listvar yyaction
|
||||
);
|
||||
|
||||
protected static $yycheck = array(
|
||||
#listvar yycheck
|
||||
);
|
||||
|
||||
protected static $yybase = array(
|
||||
#listvar yybase
|
||||
);
|
||||
|
||||
protected static $yydefault = array(
|
||||
#listvar yydefault
|
||||
);
|
||||
|
||||
protected static $yygoto = array(
|
||||
#listvar yygoto
|
||||
);
|
||||
|
||||
protected static $yygcheck = array(
|
||||
#listvar yygcheck
|
||||
);
|
||||
|
||||
protected static $yygbase = array(
|
||||
#listvar yygbase
|
||||
);
|
||||
|
||||
protected static $yygdefault = array(
|
||||
#listvar yygdefault
|
||||
);
|
||||
|
||||
protected static $yylhs = array(
|
||||
#listvar yylhs
|
||||
);
|
||||
|
||||
protected static $yylen = array(
|
||||
#listvar yylen
|
||||
);
|
||||
|
||||
protected $yyval;
|
||||
protected $yyastk;
|
||||
protected $stackPos;
|
||||
protected $lexer;
|
||||
|
||||
/**
|
||||
* Creates a parser instance.
|
||||
*
|
||||
* @param Lexer $lexer A lexer
|
||||
*/
|
||||
public function __construct(Lexer $lexer) {
|
||||
$this->lexer = $lexer;
|
||||
}
|
||||
#endif
|
||||
#if -t
|
||||
protected static $yyproduction = array(
|
||||
#production-strings;
|
||||
);
|
||||
|
||||
protected function yyprintln($msg) {
|
||||
echo $msg, "\n";
|
||||
}
|
||||
|
||||
protected function YYTRACE_NEWSTATE($state, $tokenId) {
|
||||
$this->yyprintln(
|
||||
'% State ' . $state
|
||||
. ', Lookahead ' . ($tokenId == self::TOKEN_NONE ? '--none--' : self::$terminals[$tokenId])
|
||||
);
|
||||
}
|
||||
|
||||
protected function YYTRACE_READ($tokenId) {
|
||||
$this->yyprintln('% Reading ' . self::$terminals[$tokenId]);
|
||||
}
|
||||
|
||||
protected function YYTRACE_SHIFT($tokenId) {
|
||||
$this->yyprintln('% Shift ' . self::$terminals[$tokenId]);
|
||||
}
|
||||
|
||||
protected function YYTRACE_ACCEPT() {
|
||||
$this->yyprintln('% Accepted.');
|
||||
}
|
||||
|
||||
protected function YYTRACE_REDUCE($n) {
|
||||
$this->yyprintln('% Reduce by (' . $n . ') ' . self::$yyproduction[$n]);
|
||||
}
|
||||
|
||||
protected function YYTRACE_POP($state) {
|
||||
$this->yyprintln('% Recovering, uncovers state ' . $state);
|
||||
}
|
||||
|
||||
protected function YYTRACE_DISCARD($tokenId) {
|
||||
$this->yyprintln('% Discard ' . self::$terminals[$tokenId]);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
#ifnot -t
|
||||
* Parses PHP code into a node tree.
|
||||
#endif
|
||||
#if -t
|
||||
* Parses PHP code into a node tree and prints out debugging information.
|
||||
#endif
|
||||
*
|
||||
* @param string $code The source code to parse
|
||||
*
|
||||
* @return Node[] Array of statements
|
||||
*/
|
||||
public function parse($code) {
|
||||
$this->lexer->startLexing($code);
|
||||
|
||||
// We start off with no lookahead-token
|
||||
$tokenId = self::TOKEN_NONE;
|
||||
|
||||
// The attributes for a node are taken from the first and last token of the node.
|
||||
// From the first token only the startAttributes are taken and from the last only
|
||||
// the endAttributes. Both are merged using the array union operator (+).
|
||||
$startAttributes = array('startLine' => 1);
|
||||
$endAttributes = array();
|
||||
|
||||
// In order to figure out the attributes for the starting token, we have to keep
|
||||
// them in a stack
|
||||
$attributeStack = array($startAttributes);
|
||||
|
||||
// Start off in the initial state and keep a stack of previous states
|
||||
$state = 0;
|
||||
$stateStack = array($state);
|
||||
|
||||
// AST stack (?)
|
||||
$this->yyastk = array();
|
||||
|
||||
// Current position in the stack(s)
|
||||
$this->stackPos = 0;
|
||||
|
||||
for (;;) {
|
||||
#if -t
|
||||
$this->YYTRACE_NEWSTATE($state, $tokenId);
|
||||
|
||||
#endif
|
||||
if (self::$yybase[$state] == 0) {
|
||||
$yyn = self::$yydefault[$state];
|
||||
} else {
|
||||
if ($tokenId === self::TOKEN_NONE) {
|
||||
// Fetch the next token id from the lexer and fetch additional info by-ref.
|
||||
// The end attributes are fetched into a temporary variable and only set once the token is really
|
||||
// shifted (not during read). Otherwise you would sometimes get off-by-one errors, when a rule is
|
||||
// reduced after a token was read but not yet shifted.
|
||||
$origTokenId = $this->lexer->getNextToken($tokenValue, $startAttributes, $nextEndAttributes);
|
||||
|
||||
// map the lexer token id to the internally used token id's
|
||||
$tokenId = $origTokenId >= 0 && $origTokenId < self::TOKEN_MAP_SIZE
|
||||
? self::$translate[$origTokenId]
|
||||
: self::TOKEN_INVALID;
|
||||
|
||||
if ($tokenId === self::TOKEN_INVALID) {
|
||||
throw new \RangeException(sprintf(
|
||||
'The lexer returned an invalid token (id=%d, value=%s)',
|
||||
$origTokenId, $tokenValue
|
||||
));
|
||||
}
|
||||
|
||||
$attributeStack[$this->stackPos] = $startAttributes;
|
||||
#if -t
|
||||
|
||||
$this->YYTRACE_READ($tokenId);
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((($yyn = self::$yybase[$state] + $tokenId) >= 0
|
||||
&& $yyn < self::YYLAST && self::$yycheck[$yyn] == $tokenId
|
||||
|| ($state < self::YY2TBLSTATE
|
||||
&& ($yyn = self::$yybase[$state + self::YYNLSTATES] + $tokenId) >= 0
|
||||
&& $yyn < self::YYLAST
|
||||
&& self::$yycheck[$yyn] == $tokenId))
|
||||
&& ($yyn = self::$yyaction[$yyn]) != self::YYDEFAULT) {
|
||||
/*
|
||||
* >= YYNLSTATE: shift and reduce
|
||||
* > 0: shift
|
||||
* = 0: accept
|
||||
* < 0: reduce
|
||||
* = -YYUNEXPECTED: error
|
||||
*/
|
||||
if ($yyn > 0) {
|
||||
/* shift */
|
||||
#if -t
|
||||
$this->YYTRACE_SHIFT($tokenId);
|
||||
|
||||
#endif
|
||||
++$this->stackPos;
|
||||
|
||||
$stateStack[$this->stackPos] = $state = $yyn;
|
||||
$this->yyastk[$this->stackPos] = $tokenValue;
|
||||
$attributeStack[$this->stackPos] = $startAttributes;
|
||||
$endAttributes = $nextEndAttributes;
|
||||
$tokenId = self::TOKEN_NONE;
|
||||
|
||||
if ($yyn < self::YYNLSTATES)
|
||||
continue;
|
||||
|
||||
/* $yyn >= YYNLSTATES means shift-and-reduce */
|
||||
$yyn -= self::YYNLSTATES;
|
||||
} else {
|
||||
$yyn = -$yyn;
|
||||
}
|
||||
} else {
|
||||
$yyn = self::$yydefault[$state];
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
/* reduce/error */
|
||||
if ($yyn == 0) {
|
||||
/* accept */
|
||||
#if -t
|
||||
$this->YYTRACE_ACCEPT();
|
||||
#endif
|
||||
return $this->yyval;
|
||||
} elseif ($yyn != self::YYUNEXPECTED) {
|
||||
/* reduce */
|
||||
#if -t
|
||||
$this->YYTRACE_REDUCE($yyn);
|
||||
#endif
|
||||
try {
|
||||
$this->{'yyn' . $yyn}(
|
||||
$attributeStack[$this->stackPos - self::$yylen[$yyn]]
|
||||
+ $endAttributes
|
||||
);
|
||||
} catch (Error $e) {
|
||||
if (-1 === $e->getRawLine()) {
|
||||
$e->setRawLine($startAttributes['startLine']);
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
/* Goto - shift nonterminal */
|
||||
$this->stackPos -= self::$yylen[$yyn];
|
||||
$yyn = self::$yylhs[$yyn];
|
||||
if (($yyp = self::$yygbase[$yyn] + $stateStack[$this->stackPos]) >= 0
|
||||
&& $yyp < self::YYGLAST
|
||||
&& self::$yygcheck[$yyp] == $yyn) {
|
||||
$state = self::$yygoto[$yyp];
|
||||
} else {
|
||||
$state = self::$yygdefault[$yyn];
|
||||
}
|
||||
|
||||
++$this->stackPos;
|
||||
|
||||
$stateStack[$this->stackPos] = $state;
|
||||
$this->yyastk[$this->stackPos] = $this->yyval;
|
||||
$attributeStack[$this->stackPos] = $startAttributes;
|
||||
} else {
|
||||
/* error */
|
||||
$expected = array();
|
||||
|
||||
$base = self::$yybase[$state];
|
||||
for ($i = 0; $i < self::TOKEN_MAP_SIZE; ++$i) {
|
||||
$n = $base + $i;
|
||||
if ($n >= 0 && $n < self::YYLAST && self::$yycheck[$n] == $i
|
||||
|| $state < self::YY2TBLSTATE
|
||||
&& ($n = self::$yybase[$state + self::YYNLSTATES] + $i) >= 0
|
||||
&& $n < self::YYLAST && self::$yycheck[$n] == $i
|
||||
) {
|
||||
if (self::$yyaction[$n] != self::YYUNEXPECTED) {
|
||||
if (count($expected) == 4) {
|
||||
/* Too many expected tokens */
|
||||
$expected = array();
|
||||
break;
|
||||
}
|
||||
|
||||
$expected[] = self::$terminals[$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$expectedString = '';
|
||||
if ($expected) {
|
||||
$expectedString = ', expecting ' . implode(' or ', $expected);
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
'Syntax error, unexpected ' . self::$terminals[$tokenId] . $expectedString,
|
||||
$startAttributes['startLine']
|
||||
);
|
||||
}
|
||||
|
||||
if ($state < self::YYNLSTATES)
|
||||
break;
|
||||
/* >= YYNLSTATES means shift-and-reduce */
|
||||
$yyn = $state - self::YYNLSTATES;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifnot -t
|
||||
#reduce
|
||||
|
||||
protected function yyn%n($attributes) {
|
||||
%b
|
||||
}
|
||||
#noact
|
||||
|
||||
protected function yyn%n() {
|
||||
$this->yyval = $this->yyastk[$this->stackPos];
|
||||
}
|
||||
#endreduce
|
||||
#endif
|
||||
}
|
||||
#tailcode;
|
103
grammar/parser.template
Normal file
103
grammar/parser.template
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
$meta #
|
||||
#semval($) $this->semValue
|
||||
#semval($,%t) $this->semValue
|
||||
#semval(%n) $this->stackPos-(%l-%n)
|
||||
#semval(%n,%t) $this->stackPos-(%l-%n)
|
||||
|
||||
namespace PhpParser\Parser;
|
||||
|
||||
use PhpParser\Error;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Scalar;
|
||||
use PhpParser\Node\Stmt;
|
||||
#include;
|
||||
|
||||
/* This is an automatically GENERATED file, which should not be manually edited.
|
||||
* Instead edit one of the following:
|
||||
* * the grammar files grammar/php5.y or grammar/php7.y
|
||||
* * the skeleton file grammar/parser.template
|
||||
* * the preprocessing script grammar/rebuildParsers.php
|
||||
*/
|
||||
class #(-p) extends \PhpParser\ParserAbstract
|
||||
{
|
||||
protected $tokenToSymbolMapSize = #(YYMAXLEX);
|
||||
protected $actionTableSize = #(YYLAST);
|
||||
protected $gotoTableSize = #(YYGLAST);
|
||||
|
||||
protected $invalidSymbol = #(YYBADCH);
|
||||
protected $errorSymbol = #(YYINTERRTOK);
|
||||
protected $defaultAction = #(YYDEFAULT);
|
||||
protected $unexpectedTokenRule = #(YYUNEXPECTED);
|
||||
|
||||
protected $YY2TBLSTATE = #(YY2TBLSTATE);
|
||||
protected $YYNLSTATES = #(YYNLSTATES);
|
||||
|
||||
protected $symbolToName = array(
|
||||
#listvar terminals
|
||||
);
|
||||
|
||||
protected $tokenToSymbol = array(
|
||||
#listvar yytranslate
|
||||
);
|
||||
|
||||
protected $action = array(
|
||||
#listvar yyaction
|
||||
);
|
||||
|
||||
protected $actionCheck = array(
|
||||
#listvar yycheck
|
||||
);
|
||||
|
||||
protected $actionBase = array(
|
||||
#listvar yybase
|
||||
);
|
||||
|
||||
protected $actionDefault = array(
|
||||
#listvar yydefault
|
||||
);
|
||||
|
||||
protected $goto = array(
|
||||
#listvar yygoto
|
||||
);
|
||||
|
||||
protected $gotoCheck = array(
|
||||
#listvar yygcheck
|
||||
);
|
||||
|
||||
protected $gotoBase = array(
|
||||
#listvar yygbase
|
||||
);
|
||||
|
||||
protected $gotoDefault = array(
|
||||
#listvar yygdefault
|
||||
);
|
||||
|
||||
protected $ruleToNonTerminal = array(
|
||||
#listvar yylhs
|
||||
);
|
||||
|
||||
protected $ruleToLength = array(
|
||||
#listvar yylen
|
||||
);
|
||||
#if -t
|
||||
|
||||
protected $productions = array(
|
||||
#production-strings;
|
||||
);
|
||||
#endif
|
||||
#reduce
|
||||
|
||||
protected function reduceRule%n() {
|
||||
%b
|
||||
}
|
||||
#noact
|
||||
|
||||
protected function reduceRule%n() {
|
||||
$this->semValue = $this->semStack[$this->stackPos];
|
||||
}
|
||||
#endreduce
|
||||
}
|
||||
#tailcode;
|
@ -1,118 +1,12 @@
|
||||
%pure_parser
|
||||
%expect 2
|
||||
%expect 6
|
||||
|
||||
%left T_INCLUDE T_INCLUDE_ONCE T_EVAL T_REQUIRE T_REQUIRE_ONCE
|
||||
%left ','
|
||||
%left T_LOGICAL_OR
|
||||
%left T_LOGICAL_XOR
|
||||
%left T_LOGICAL_AND
|
||||
%right T_PRINT
|
||||
%right T_YIELD
|
||||
%left '=' T_PLUS_EQUAL T_MINUS_EQUAL T_MUL_EQUAL T_DIV_EQUAL T_CONCAT_EQUAL T_MOD_EQUAL T_AND_EQUAL T_OR_EQUAL T_XOR_EQUAL T_SL_EQUAL T_SR_EQUAL T_POW_EQUAL
|
||||
%left '?' ':'
|
||||
%left T_BOOLEAN_OR
|
||||
%left T_BOOLEAN_AND
|
||||
%left '|'
|
||||
%left '^'
|
||||
%left '&'
|
||||
%nonassoc T_IS_EQUAL T_IS_NOT_EQUAL T_IS_IDENTICAL T_IS_NOT_IDENTICAL
|
||||
%nonassoc '<' T_IS_SMALLER_OR_EQUAL '>' T_IS_GREATER_OR_EQUAL
|
||||
%left T_SL T_SR
|
||||
%left '+' '-' '.'
|
||||
%left '*' '/' '%'
|
||||
%right '!'
|
||||
%nonassoc T_INSTANCEOF
|
||||
%right '~' T_INC T_DEC T_INT_CAST T_DOUBLE_CAST T_STRING_CAST T_ARRAY_CAST T_OBJECT_CAST T_BOOL_CAST T_UNSET_CAST '@'
|
||||
%right T_POW
|
||||
%right '['
|
||||
%nonassoc T_NEW T_CLONE
|
||||
%token T_EXIT
|
||||
%token T_IF
|
||||
%left T_ELSEIF
|
||||
%left T_ELSE
|
||||
%left T_ENDIF
|
||||
%token T_LNUMBER
|
||||
%token T_DNUMBER
|
||||
%token T_STRING
|
||||
%token T_STRING_VARNAME
|
||||
%token T_VARIABLE
|
||||
%token T_NUM_STRING
|
||||
%token T_INLINE_HTML
|
||||
%token T_CHARACTER
|
||||
%token T_BAD_CHARACTER
|
||||
%token T_ENCAPSED_AND_WHITESPACE
|
||||
%token T_CONSTANT_ENCAPSED_STRING
|
||||
%token T_ECHO
|
||||
%token T_DO
|
||||
%token T_WHILE
|
||||
%token T_ENDWHILE
|
||||
%token T_FOR
|
||||
%token T_ENDFOR
|
||||
%token T_FOREACH
|
||||
%token T_ENDFOREACH
|
||||
%token T_DECLARE
|
||||
%token T_ENDDECLARE
|
||||
%token T_AS
|
||||
%token T_SWITCH
|
||||
%token T_ENDSWITCH
|
||||
%token T_CASE
|
||||
%token T_DEFAULT
|
||||
%token T_BREAK
|
||||
%token T_CONTINUE
|
||||
%token T_GOTO
|
||||
%token T_FUNCTION
|
||||
%token T_CONST
|
||||
%token T_RETURN
|
||||
%token T_TRY
|
||||
%token T_CATCH
|
||||
%token T_FINALLY
|
||||
%token T_THROW
|
||||
%token T_USE
|
||||
%token T_INSTEADOF
|
||||
%token T_GLOBAL
|
||||
%right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC
|
||||
%token T_VAR
|
||||
%token T_UNSET
|
||||
%token T_ISSET
|
||||
%token T_EMPTY
|
||||
%token T_HALT_COMPILER
|
||||
%token T_CLASS
|
||||
%token T_TRAIT
|
||||
%token T_INTERFACE
|
||||
%token T_EXTENDS
|
||||
%token T_IMPLEMENTS
|
||||
%token T_OBJECT_OPERATOR
|
||||
%token T_DOUBLE_ARROW
|
||||
%token T_LIST
|
||||
%token T_ARRAY
|
||||
%token T_CALLABLE
|
||||
%token T_CLASS_C
|
||||
%token T_TRAIT_C
|
||||
%token T_METHOD_C
|
||||
%token T_FUNC_C
|
||||
%token T_LINE
|
||||
%token T_FILE
|
||||
%token T_COMMENT
|
||||
%token T_DOC_COMMENT
|
||||
%token T_OPEN_TAG
|
||||
%token T_OPEN_TAG_WITH_ECHO
|
||||
%token T_CLOSE_TAG
|
||||
%token T_WHITESPACE
|
||||
%token T_START_HEREDOC
|
||||
%token T_END_HEREDOC
|
||||
%token T_DOLLAR_OPEN_CURLY_BRACES
|
||||
%token T_CURLY_OPEN
|
||||
%token T_PAAMAYIM_NEKUDOTAYIM
|
||||
%token T_NAMESPACE
|
||||
%token T_NS_C
|
||||
%token T_DIR
|
||||
%token T_NS_SEPARATOR
|
||||
%token T_ELLIPSIS
|
||||
%tokens
|
||||
|
||||
%%
|
||||
|
||||
start:
|
||||
top_statement_list { $$ = Stmt\Namespace_::postprocess($1); }
|
||||
top_statement_list { $$ = $this->handleNamespaces($1); }
|
||||
;
|
||||
|
||||
top_statement_list:
|
||||
@ -120,6 +14,25 @@ top_statement_list:
|
||||
| /* empty */ { init(); }
|
||||
;
|
||||
|
||||
reserved_non_modifiers:
|
||||
T_INCLUDE | T_INCLUDE_ONCE | T_EVAL | T_REQUIRE | T_REQUIRE_ONCE | T_LOGICAL_OR | T_LOGICAL_XOR | T_LOGICAL_AND
|
||||
| T_INSTANCEOF | T_NEW | T_CLONE | T_EXIT | T_IF | T_ELSEIF | T_ELSE | T_ENDIF | T_ECHO | T_DO | T_WHILE
|
||||
| T_ENDWHILE | T_FOR | T_ENDFOR | T_FOREACH | T_ENDFOREACH | T_DECLARE | T_ENDDECLARE | T_AS | T_TRY | T_CATCH
|
||||
| T_FINALLY | T_THROW | T_USE | T_INSTEADOF | T_GLOBAL | T_VAR | T_UNSET | T_ISSET | T_EMPTY | T_CONTINUE | T_GOTO
|
||||
| T_FUNCTION | T_CONST | T_RETURN | T_PRINT | T_YIELD | T_LIST | T_SWITCH | T_ENDSWITCH | T_CASE | T_DEFAULT
|
||||
| T_BREAK | T_ARRAY | T_CALLABLE | T_EXTENDS | T_IMPLEMENTS | T_NAMESPACE | T_TRAIT | T_INTERFACE | T_CLASS
|
||||
;
|
||||
|
||||
semi_reserved:
|
||||
reserved_non_modifiers
|
||||
| T_STATIC | T_ABSTRACT | T_FINAL | T_PRIVATE | T_PROTECTED | T_PUBLIC
|
||||
;
|
||||
|
||||
identifier:
|
||||
T_STRING { $$ = $1; }
|
||||
| semi_reserved { $$ = $1; }
|
||||
;
|
||||
|
||||
namespace_name_parts:
|
||||
T_STRING { init($1); }
|
||||
| namespace_name_parts T_NS_SEPARATOR T_STRING { push($1, $3); }
|
||||
@ -139,21 +52,44 @@ top_statement:
|
||||
| T_NAMESPACE namespace_name '{' top_statement_list '}' { $$ = Stmt\Namespace_[$2, $4]; }
|
||||
| T_NAMESPACE '{' top_statement_list '}' { $$ = Stmt\Namespace_[null, $3]; }
|
||||
| T_USE use_declarations ';' { $$ = Stmt\Use_[$2, Stmt\Use_::TYPE_NORMAL]; }
|
||||
| T_USE T_FUNCTION use_declarations ';' { $$ = Stmt\Use_[$3, Stmt\Use_::TYPE_FUNCTION]; }
|
||||
| T_USE T_CONST use_declarations ';' { $$ = Stmt\Use_[$3, Stmt\Use_::TYPE_CONSTANT]; }
|
||||
| T_USE use_type use_declarations ';' { $$ = Stmt\Use_[$3, $2]; }
|
||||
| group_use_declaration { $$ = $1; }
|
||||
| T_CONST constant_declaration_list ';' { $$ = Stmt\Const_[$2]; }
|
||||
;
|
||||
|
||||
use_type:
|
||||
T_FUNCTION { $$ = Stmt\Use_::TYPE_FUNCTION; }
|
||||
| T_CONST { $$ = Stmt\Use_::TYPE_CONSTANT; }
|
||||
;
|
||||
|
||||
/* Using namespace_name_parts here to avoid s/r conflict on T_NS_SEPARATOR */
|
||||
group_use_declaration:
|
||||
T_USE use_type namespace_name_parts T_NS_SEPARATOR '{' use_declarations '}'
|
||||
{ $$ = Stmt\GroupUse[Name[$3], $6, $2]; }
|
||||
| T_USE namespace_name_parts T_NS_SEPARATOR '{' inline_use_declarations '}'
|
||||
{ $$ = Stmt\GroupUse[Name[$2], $5, Stmt\Use_::TYPE_UNKNOWN]; }
|
||||
;
|
||||
|
||||
use_declarations:
|
||||
use_declarations ',' use_declaration { push($1, $3); }
|
||||
| use_declaration { init($1); }
|
||||
;
|
||||
|
||||
use_declaration:
|
||||
namespace_name { $$ = Stmt\UseUse[$1, null]; }
|
||||
| namespace_name T_AS T_STRING { $$ = Stmt\UseUse[$1, $3]; }
|
||||
| T_NS_SEPARATOR namespace_name { $$ = Stmt\UseUse[$2, null]; }
|
||||
| T_NS_SEPARATOR namespace_name T_AS T_STRING { $$ = Stmt\UseUse[$2, $4]; }
|
||||
namespace_name { $$ = Stmt\UseUse[$1, null, Stmt\Use_::TYPE_UNKNOWN]; }
|
||||
| namespace_name T_AS T_STRING { $$ = Stmt\UseUse[$1, $3, Stmt\Use_::TYPE_UNKNOWN]; }
|
||||
| T_NS_SEPARATOR namespace_name { $$ = Stmt\UseUse[$2, null, Stmt\Use_::TYPE_UNKNOWN]; }
|
||||
| T_NS_SEPARATOR namespace_name T_AS T_STRING { $$ = Stmt\UseUse[$2, $4, Stmt\Use_::TYPE_UNKNOWN]; }
|
||||
;
|
||||
|
||||
inline_use_declarations:
|
||||
inline_use_declarations ',' inline_use_declaration { push($1, $3); }
|
||||
| inline_use_declaration { init($1); }
|
||||
;
|
||||
|
||||
inline_use_declaration:
|
||||
use_declaration { $$ = $1; $$->type = Stmt\Use_::TYPE_NORMAL; }
|
||||
| use_type use_declaration { $$ = $2; $$->type = $1; }
|
||||
;
|
||||
|
||||
constant_declaration_list:
|
||||
@ -162,7 +98,16 @@ constant_declaration_list:
|
||||
;
|
||||
|
||||
constant_declaration:
|
||||
T_STRING '=' static_scalar { $$ = Const_[$1, $3]; }
|
||||
T_STRING '=' static_scalar { $$ = Node\Const_[$1, $3]; }
|
||||
;
|
||||
|
||||
class_const_list:
|
||||
class_const_list ',' class_const { push($1, $3); }
|
||||
| class_const { init($1); }
|
||||
;
|
||||
|
||||
class_const:
|
||||
identifier '=' static_scalar { $$ = Node\Const_[$1, $3]; }
|
||||
;
|
||||
|
||||
inner_statement_list:
|
||||
@ -174,19 +119,20 @@ inner_statement:
|
||||
statement { $$ = $1; }
|
||||
| function_declaration_statement { $$ = $1; }
|
||||
| class_declaration_statement { $$ = $1; }
|
||||
| T_HALT_COMPILER { error('__HALT_COMPILER() can only be used from the outermost scope'); }
|
||||
| T_HALT_COMPILER
|
||||
{ throw new Error('__HALT_COMPILER() can only be used from the outermost scope', attributes()); }
|
||||
;
|
||||
|
||||
statement:
|
||||
'{' inner_statement_list '}' { $$ = $2; }
|
||||
| T_IF parentheses_expr statement elseif_list else_single
|
||||
{ $$ = Stmt\If_[$2, [stmts: toArray($3), elseifs: $4, else: $5]]; }
|
||||
{ $$ = Stmt\If_[$2, ['stmts' => toArray($3), 'elseifs' => $4, 'else' => $5]]; }
|
||||
| T_IF parentheses_expr ':' inner_statement_list new_elseif_list new_else_single T_ENDIF ';'
|
||||
{ $$ = Stmt\If_[$2, [stmts: $4, elseifs: $5, else: $6]]; }
|
||||
{ $$ = Stmt\If_[$2, ['stmts' => $4, 'elseifs' => $5, 'else' => $6]]; }
|
||||
| T_WHILE parentheses_expr while_statement { $$ = Stmt\While_[$2, $3]; }
|
||||
| T_DO statement T_WHILE parentheses_expr ';' { $$ = Stmt\Do_ [$4, toArray($2)]; }
|
||||
| T_FOR '(' for_expr ';' for_expr ';' for_expr ')' for_statement
|
||||
{ $$ = Stmt\For_[[init: $3, cond: $5, loop: $7, stmts: $9]]; }
|
||||
{ $$ = Stmt\For_[['init' => $3, 'cond' => $5, 'loop' => $7, 'stmts' => $9]]; }
|
||||
| T_SWITCH parentheses_expr switch_case_list { $$ = Stmt\Switch_[$2, $3]; }
|
||||
| T_BREAK ';' { $$ = Stmt\Break_[null]; }
|
||||
| T_BREAK expr ';' { $$ = Stmt\Break_[$2]; }
|
||||
@ -202,9 +148,9 @@ statement:
|
||||
| expr ';' { $$ = $1; }
|
||||
| T_UNSET '(' variables_list ')' ';' { $$ = Stmt\Unset_[$3]; }
|
||||
| T_FOREACH '(' expr T_AS foreach_variable ')' foreach_statement
|
||||
{ $$ = Stmt\Foreach_[$3, $5[0], [keyVar: null, byRef: $5[1], stmts: $7]]; }
|
||||
{ $$ = Stmt\Foreach_[$3, $5[0], ['keyVar' => null, 'byRef' => $5[1], 'stmts' => $7]]; }
|
||||
| T_FOREACH '(' expr T_AS variable T_DOUBLE_ARROW foreach_variable ')' foreach_statement
|
||||
{ $$ = Stmt\Foreach_[$3, $7[0], [keyVar: $5, byRef: $7[1], stmts: $9]]; }
|
||||
{ $$ = Stmt\Foreach_[$3, $7[0], ['keyVar' => $5, 'byRef' => $7[1], 'stmts' => $9]]; }
|
||||
| T_DECLARE '(' declare_list ')' declare_statement { $$ = Stmt\Declare_[$3, $5]; }
|
||||
| ';' { $$ = array(); /* means: no statement */ }
|
||||
| T_TRY '{' inner_statement_list '}' catches optional_finally
|
||||
@ -212,6 +158,7 @@ statement:
|
||||
| T_THROW expr ';' { $$ = Stmt\Throw_[$2]; }
|
||||
| T_GOTO T_STRING ';' { $$ = Stmt\Goto_[$2]; }
|
||||
| T_STRING ':' { $$ = Stmt\Label[$1]; }
|
||||
| error { $$ = array(); /* means: no statement */ }
|
||||
;
|
||||
|
||||
catches:
|
||||
@ -245,15 +192,15 @@ optional_ellipsis:
|
||||
;
|
||||
|
||||
function_declaration_statement:
|
||||
T_FUNCTION optional_ref T_STRING '(' parameter_list ')' '{' inner_statement_list '}'
|
||||
{ $$ = Stmt\Function_[$3, [byRef: $2, params: $5, stmts: $8]]; }
|
||||
T_FUNCTION optional_ref T_STRING '(' parameter_list ')' optional_return_type '{' inner_statement_list '}'
|
||||
{ $$ = Stmt\Function_[$3, ['byRef' => $2, 'params' => $5, 'returnType' => $7, 'stmts' => $9]]; }
|
||||
;
|
||||
|
||||
class_declaration_statement:
|
||||
class_entry_type T_STRING extends_from implements_list '{' class_statement_list '}'
|
||||
{ $$ = Stmt\Class_[$2, [type: $1, extends: $3, implements: $4, stmts: $6]]; }
|
||||
{ $$ = Stmt\Class_[$2, ['type' => $1, 'extends' => $3, 'implements' => $4, 'stmts' => $6]]; }
|
||||
| T_INTERFACE T_STRING interface_extends_list '{' class_statement_list '}'
|
||||
{ $$ = Stmt\Interface_[$2, [extends: $3, stmts: $5]]; }
|
||||
{ $$ = Stmt\Interface_[$2, ['extends' => $3, 'stmts' => $5]]; }
|
||||
| T_TRAIT T_STRING '{' class_statement_list '}'
|
||||
{ $$ = Stmt\Trait_[$2, $4]; }
|
||||
;
|
||||
@ -380,23 +327,32 @@ non_empty_parameter_list:
|
||||
;
|
||||
|
||||
parameter:
|
||||
optional_class_type optional_ref optional_ellipsis T_VARIABLE
|
||||
{ $$ = Param[parseVar($4), null, $1, $2, $3]; }
|
||||
| optional_class_type optional_ref optional_ellipsis T_VARIABLE '=' static_scalar
|
||||
{ $$ = Param[parseVar($4), $6, $1, $2, $3]; }
|
||||
optional_param_type optional_ref optional_ellipsis T_VARIABLE
|
||||
{ $$ = Node\Param[parseVar($4), null, $1, $2, $3]; }
|
||||
| optional_param_type optional_ref optional_ellipsis T_VARIABLE '=' static_scalar
|
||||
{ $$ = Node\Param[parseVar($4), $6, $1, $2, $3]; }
|
||||
;
|
||||
|
||||
optional_class_type:
|
||||
/* empty */ { $$ = null; }
|
||||
| name { $$ = $1; }
|
||||
type:
|
||||
name { $$ = $1; }
|
||||
| T_ARRAY { $$ = 'array'; }
|
||||
| T_CALLABLE { $$ = 'callable'; }
|
||||
;
|
||||
|
||||
optional_param_type:
|
||||
/* empty */ { $$ = null; }
|
||||
| type { $$ = $1; }
|
||||
;
|
||||
|
||||
optional_return_type:
|
||||
/* empty */ { $$ = null; }
|
||||
| ':' type { $$ = $2; }
|
||||
;
|
||||
|
||||
argument_list:
|
||||
'(' ')' { $$ = array(); }
|
||||
| '(' non_empty_argument_list ')' { $$ = $2; }
|
||||
| '(' yield_expr ')' { $$ = array(Arg[$2, false, false]); }
|
||||
| '(' yield_expr ')' { $$ = array(Node\Arg[$2, false, false]); }
|
||||
;
|
||||
|
||||
non_empty_argument_list:
|
||||
@ -405,9 +361,9 @@ non_empty_argument_list:
|
||||
;
|
||||
|
||||
argument:
|
||||
expr { $$ = Arg[$1, false, false]; }
|
||||
| '&' variable { $$ = Arg[$2, true, false]; }
|
||||
| T_ELLIPSIS expr { $$ = Arg[$2, false, true]; }
|
||||
expr { $$ = Node\Arg[$1, false, false]; }
|
||||
| '&' variable { $$ = Node\Arg[$2, true, false]; }
|
||||
| T_ELLIPSIS expr { $$ = Node\Arg[$2, false, true]; }
|
||||
;
|
||||
|
||||
global_var_list:
|
||||
@ -438,9 +394,9 @@ class_statement_list:
|
||||
|
||||
class_statement:
|
||||
variable_modifiers property_declaration_list ';' { $$ = Stmt\Property[$1, $2]; }
|
||||
| T_CONST constant_declaration_list ';' { $$ = Stmt\ClassConst[$2]; }
|
||||
| method_modifiers T_FUNCTION optional_ref T_STRING '(' parameter_list ')' method_body
|
||||
{ $$ = Stmt\ClassMethod[$4, [type: $1, byRef: $3, params: $6, stmts: $8]]; }
|
||||
| T_CONST class_const_list ';' { $$ = Stmt\ClassConst[$2]; }
|
||||
| method_modifiers T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type method_body
|
||||
{ $$ = Stmt\ClassMethod[$4, ['type' => $1, 'byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9]]; }
|
||||
| T_USE name_list trait_adaptations { $$ = Stmt\TraitUse[$2, $3]; }
|
||||
;
|
||||
|
||||
@ -457,20 +413,22 @@ trait_adaptation_list:
|
||||
trait_adaptation:
|
||||
trait_method_reference_fully_qualified T_INSTEADOF name_list ';'
|
||||
{ $$ = Stmt\TraitUseAdaptation\Precedence[$1[0], $1[1], $3]; }
|
||||
| trait_method_reference T_AS member_modifier T_STRING ';'
|
||||
| trait_method_reference T_AS member_modifier identifier ';'
|
||||
{ $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], $3, $4]; }
|
||||
| trait_method_reference T_AS member_modifier ';'
|
||||
{ $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], $3, null]; }
|
||||
| trait_method_reference T_AS T_STRING ';'
|
||||
{ $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], null, $3]; }
|
||||
| trait_method_reference T_AS reserved_non_modifiers ';'
|
||||
{ $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], null, $3]; }
|
||||
;
|
||||
|
||||
trait_method_reference_fully_qualified:
|
||||
name T_PAAMAYIM_NEKUDOTAYIM T_STRING { $$ = array($1, $3); }
|
||||
name T_PAAMAYIM_NEKUDOTAYIM identifier { $$ = array($1, $3); }
|
||||
;
|
||||
trait_method_reference:
|
||||
trait_method_reference_fully_qualified { $$ = $1; }
|
||||
| T_STRING { $$ = array(null, $1); }
|
||||
| identifier { $$ = array(null, $1); }
|
||||
;
|
||||
|
||||
method_body:
|
||||
@ -480,11 +438,11 @@ method_body:
|
||||
|
||||
variable_modifiers:
|
||||
non_empty_member_modifiers { $$ = $1; }
|
||||
| T_VAR { $$ = Stmt\Class_::MODIFIER_PUBLIC; }
|
||||
| T_VAR { $$ = 0; }
|
||||
;
|
||||
|
||||
method_modifiers:
|
||||
/* empty */ { $$ = Stmt\Class_::MODIFIER_PUBLIC; }
|
||||
/* empty */ { $$ = 0; }
|
||||
| non_empty_member_modifiers { $$ = $1; }
|
||||
;
|
||||
|
||||
@ -571,6 +529,7 @@ expr:
|
||||
| expr T_IS_NOT_IDENTICAL expr { $$ = Expr\BinaryOp\NotIdentical [$1, $3]; }
|
||||
| expr T_IS_EQUAL expr { $$ = Expr\BinaryOp\Equal [$1, $3]; }
|
||||
| expr T_IS_NOT_EQUAL expr { $$ = Expr\BinaryOp\NotEqual [$1, $3]; }
|
||||
| expr T_SPACESHIP expr { $$ = Expr\BinaryOp\Spaceship [$1, $3]; }
|
||||
| expr '<' expr { $$ = Expr\BinaryOp\Smaller [$1, $3]; }
|
||||
| expr T_IS_SMALLER_OR_EQUAL expr { $$ = Expr\BinaryOp\SmallerOrEqual[$1, $3]; }
|
||||
| expr '>' expr { $$ = Expr\BinaryOp\Greater [$1, $3]; }
|
||||
@ -581,6 +540,7 @@ expr:
|
||||
| '(' new_expr ')' { $$ = $2; }
|
||||
| expr '?' expr ':' expr { $$ = Expr\Ternary[$1, $3, $5]; }
|
||||
| expr '?' ':' expr { $$ = Expr\Ternary[$1, null, $4]; }
|
||||
| expr T_COALESCE expr { $$ = Expr\BinaryOp\Coalesce[$1, $3]; }
|
||||
| T_ISSET '(' variables_list ')' { $$ = Expr\Isset_[$3]; }
|
||||
| T_EMPTY '(' expr ')' { $$ = Expr\Empty_[$3]; }
|
||||
| T_INCLUDE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_INCLUDE]; }
|
||||
@ -588,12 +548,12 @@ expr:
|
||||
| T_EVAL parentheses_expr { $$ = Expr\Eval_[$2]; }
|
||||
| T_REQUIRE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_REQUIRE]; }
|
||||
| T_REQUIRE_ONCE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_REQUIRE_ONCE]; }
|
||||
| T_INT_CAST expr { $$ = Expr\Cast\Int [$2]; }
|
||||
| T_INT_CAST expr { $$ = Expr\Cast\Int_ [$2]; }
|
||||
| T_DOUBLE_CAST expr { $$ = Expr\Cast\Double [$2]; }
|
||||
| T_STRING_CAST expr { $$ = Expr\Cast\String [$2]; }
|
||||
| T_STRING_CAST expr { $$ = Expr\Cast\String_ [$2]; }
|
||||
| T_ARRAY_CAST expr { $$ = Expr\Cast\Array_ [$2]; }
|
||||
| T_OBJECT_CAST expr { $$ = Expr\Cast\Object [$2]; }
|
||||
| T_BOOL_CAST expr { $$ = Expr\Cast\Bool [$2]; }
|
||||
| T_OBJECT_CAST expr { $$ = Expr\Cast\Object_ [$2]; }
|
||||
| T_BOOL_CAST expr { $$ = Expr\Cast\Bool_ [$2]; }
|
||||
| T_UNSET_CAST expr { $$ = Expr\Cast\Unset_ [$2]; }
|
||||
| T_EXIT exit_expr { $$ = Expr\Exit_ [$2]; }
|
||||
| '@' expr { $$ = Expr\ErrorSuppress[$2]; }
|
||||
@ -603,10 +563,13 @@ expr:
|
||||
| '`' backticks_expr '`' { $$ = Expr\ShellExec[$2]; }
|
||||
| T_PRINT expr { $$ = Expr\Print_[$2]; }
|
||||
| T_YIELD { $$ = Expr\Yield_[null, null]; }
|
||||
| T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars '{' inner_statement_list '}'
|
||||
{ $$ = Expr\Closure[[static: false, byRef: $2, params: $4, uses: $6, stmts: $8]]; }
|
||||
| T_STATIC T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars '{' inner_statement_list '}'
|
||||
{ $$ = Expr\Closure[[static: true, byRef: $3, params: $5, uses: $7, stmts: $9]]; }
|
||||
| T_YIELD_FROM expr { $$ = Expr\YieldFrom[$2]; }
|
||||
| T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type
|
||||
'{' inner_statement_list '}'
|
||||
{ $$ = Expr\Closure[['static' => false, 'byRef' => $2, 'params' => $4, 'uses' => $6, 'returnType' => $7, 'stmts' => $9]]; }
|
||||
| T_STATIC T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type
|
||||
'{' inner_statement_list '}'
|
||||
{ $$ = Expr\Closure[['static' => true, 'byRef' => $3, 'params' => $5, 'uses' => $7, 'returnType' => $8, 'stmts' => $10]]; }
|
||||
;
|
||||
|
||||
parentheses_expr:
|
||||
@ -627,13 +590,20 @@ array_expr:
|
||||
scalar_dereference:
|
||||
array_expr '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
||||
| T_CONSTANT_ENCAPSED_STRING '[' dim_offset ']'
|
||||
{ $$ = Expr\ArrayDimFetch[Scalar\String[Scalar\String::parse($1)], $3]; }
|
||||
{ $$ = Expr\ArrayDimFetch[Scalar\String_[Scalar\String_::parse($1, false)], $3]; }
|
||||
| constant '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
||||
| scalar_dereference '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
||||
/* alternative array syntax missing intentionally */
|
||||
;
|
||||
|
||||
anonymous_class:
|
||||
T_CLASS ctor_arguments extends_from implements_list '{' class_statement_list '}'
|
||||
{ $$ = array(Stmt\Class_[null, ['type' => 0, 'extends' => $3, 'implements' => $4, 'stmts' => $6]], $2); }
|
||||
|
||||
new_expr:
|
||||
T_NEW class_name_reference ctor_arguments { $$ = Expr\New_[$2, $3]; }
|
||||
| T_NEW anonymous_class
|
||||
{ list($class, $ctorArgs) = $2; $$ = Expr\New_[$class, $ctorArgs]; }
|
||||
;
|
||||
|
||||
lexical_vars:
|
||||
@ -652,7 +622,7 @@ lexical_var:
|
||||
|
||||
function_call:
|
||||
name argument_list { $$ = Expr\FuncCall[$1, $2]; }
|
||||
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM T_STRING argument_list
|
||||
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier argument_list
|
||||
{ $$ = Expr\StaticCall[$1, $3, $4]; }
|
||||
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM '{' expr '}' argument_list
|
||||
{ $$ = Expr\StaticCall[$1, $4, $6]; }
|
||||
@ -678,7 +648,7 @@ function_call:
|
||||
;
|
||||
|
||||
class_name:
|
||||
T_STATIC { $$ = Name['static']; }
|
||||
T_STATIC { $$ = Name[$1]; }
|
||||
| name { $$ = $1; }
|
||||
;
|
||||
|
||||
@ -704,7 +674,7 @@ class_name_or_var:
|
||||
;
|
||||
|
||||
object_access_for_dcnr:
|
||||
| base_variable T_OBJECT_OPERATOR object_property
|
||||
base_variable T_OBJECT_OPERATOR object_property
|
||||
{ $$ = Expr\PropertyFetch[$1, $3]; }
|
||||
| object_access_for_dcnr T_OBJECT_OPERATOR object_property
|
||||
{ $$ = Expr\PropertyFetch[$1, $3]; }
|
||||
@ -720,8 +690,9 @@ exit_expr:
|
||||
|
||||
backticks_expr:
|
||||
/* empty */ { $$ = array(); }
|
||||
| T_ENCAPSED_AND_WHITESPACE { $$ = array(Scalar\String::parseEscapeSequences($1, '`')); }
|
||||
| encaps_list { parseEncapsed($1, '`'); $$ = $1; }
|
||||
| T_ENCAPSED_AND_WHITESPACE
|
||||
{ $$ = array(Scalar\String_::parseEscapeSequences($1, '`', false)); }
|
||||
| encaps_list { parseEncapsed($1, '`', false); $$ = $1; }
|
||||
;
|
||||
|
||||
ctor_arguments:
|
||||
@ -732,7 +703,7 @@ ctor_arguments:
|
||||
common_scalar:
|
||||
T_LNUMBER { $$ = Scalar\LNumber[Scalar\LNumber::parse($1)]; }
|
||||
| T_DNUMBER { $$ = Scalar\DNumber[Scalar\DNumber::parse($1)]; }
|
||||
| T_CONSTANT_ENCAPSED_STRING { $$ = Scalar\String[Scalar\String::parse($1)]; }
|
||||
| T_CONSTANT_ENCAPSED_STRING { $$ = Scalar\String_[Scalar\String_::parse($1, false)]; }
|
||||
| T_LINE { $$ = Scalar\MagicConst\Line[]; }
|
||||
| T_FILE { $$ = Scalar\MagicConst\File[]; }
|
||||
| T_DIR { $$ = Scalar\MagicConst\Dir[]; }
|
||||
@ -742,73 +713,69 @@ common_scalar:
|
||||
| T_FUNC_C { $$ = Scalar\MagicConst\Function_[]; }
|
||||
| T_NS_C { $$ = Scalar\MagicConst\Namespace_[]; }
|
||||
| T_START_HEREDOC T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC
|
||||
{ $$ = Scalar\String[Scalar\String::parseDocString($1, $2)]; }
|
||||
{ $$ = Scalar\String_[Scalar\String_::parseDocString($1, $2, false)]; }
|
||||
| T_START_HEREDOC T_END_HEREDOC
|
||||
{ $$ = Scalar\String['']; }
|
||||
| name { $$ = Expr\ConstFetch[$1]; }
|
||||
{ $$ = Scalar\String_['']; }
|
||||
;
|
||||
|
||||
/* Arrays are currently not allowed in static scalar operations */
|
||||
static_scalar:
|
||||
static_scalar_value { $$ = $1; }
|
||||
common_scalar { $$ = $1; }
|
||||
| class_name T_PAAMAYIM_NEKUDOTAYIM identifier { $$ = Expr\ClassConstFetch[$1, $3]; }
|
||||
| name { $$ = Expr\ConstFetch[$1]; }
|
||||
| T_ARRAY '(' static_array_pair_list ')' { $$ = Expr\Array_[$3]; }
|
||||
| '[' static_array_pair_list ']' { $$ = Expr\Array_[$2]; }
|
||||
;
|
||||
|
||||
static_scalar_value:
|
||||
common_scalar { $$ = $1; }
|
||||
| class_name T_PAAMAYIM_NEKUDOTAYIM class_const_name { $$ = Expr\ClassConstFetch[$1, $3]; }
|
||||
| static_operation { $$ = $1; }
|
||||
;
|
||||
|
||||
static_operation:
|
||||
static_scalar_value T_BOOLEAN_OR static_scalar_value { $$ = Expr\BinaryOp\BooleanOr [$1, $3]; }
|
||||
| static_scalar_value T_BOOLEAN_AND static_scalar_value { $$ = Expr\BinaryOp\BooleanAnd[$1, $3]; }
|
||||
| static_scalar_value T_LOGICAL_OR static_scalar_value { $$ = Expr\BinaryOp\LogicalOr [$1, $3]; }
|
||||
| static_scalar_value T_LOGICAL_AND static_scalar_value { $$ = Expr\BinaryOp\LogicalAnd[$1, $3]; }
|
||||
| static_scalar_value T_LOGICAL_XOR static_scalar_value { $$ = Expr\BinaryOp\LogicalXor[$1, $3]; }
|
||||
| static_scalar_value '|' static_scalar_value { $$ = Expr\BinaryOp\BitwiseOr [$1, $3]; }
|
||||
| static_scalar_value '&' static_scalar_value { $$ = Expr\BinaryOp\BitwiseAnd[$1, $3]; }
|
||||
| static_scalar_value '^' static_scalar_value { $$ = Expr\BinaryOp\BitwiseXor[$1, $3]; }
|
||||
| static_scalar_value '.' static_scalar_value { $$ = Expr\BinaryOp\Concat [$1, $3]; }
|
||||
| static_scalar_value '+' static_scalar_value { $$ = Expr\BinaryOp\Plus [$1, $3]; }
|
||||
| static_scalar_value '-' static_scalar_value { $$ = Expr\BinaryOp\Minus [$1, $3]; }
|
||||
| static_scalar_value '*' static_scalar_value { $$ = Expr\BinaryOp\Mul [$1, $3]; }
|
||||
| static_scalar_value '/' static_scalar_value { $$ = Expr\BinaryOp\Div [$1, $3]; }
|
||||
| static_scalar_value '%' static_scalar_value { $$ = Expr\BinaryOp\Mod [$1, $3]; }
|
||||
| static_scalar_value T_SL static_scalar_value { $$ = Expr\BinaryOp\ShiftLeft [$1, $3]; }
|
||||
| static_scalar_value T_SR static_scalar_value { $$ = Expr\BinaryOp\ShiftRight[$1, $3]; }
|
||||
| static_scalar_value T_POW static_scalar_value { $$ = Expr\BinaryOp\Pow [$1, $3]; }
|
||||
| '+' static_scalar_value %prec T_INC { $$ = Expr\UnaryPlus [$2]; }
|
||||
| '-' static_scalar_value %prec T_INC { $$ = Expr\UnaryMinus[$2]; }
|
||||
| '!' static_scalar_value { $$ = Expr\BooleanNot[$2]; }
|
||||
| '~' static_scalar_value { $$ = Expr\BitwiseNot[$2]; }
|
||||
| static_scalar_value T_IS_IDENTICAL static_scalar_value { $$ = Expr\BinaryOp\Identical [$1, $3]; }
|
||||
| static_scalar_value T_IS_NOT_IDENTICAL static_scalar_value { $$ = Expr\BinaryOp\NotIdentical [$1, $3]; }
|
||||
| static_scalar_value T_IS_EQUAL static_scalar_value { $$ = Expr\BinaryOp\Equal [$1, $3]; }
|
||||
| static_scalar_value T_IS_NOT_EQUAL static_scalar_value { $$ = Expr\BinaryOp\NotEqual [$1, $3]; }
|
||||
| static_scalar_value '<' static_scalar_value { $$ = Expr\BinaryOp\Smaller [$1, $3]; }
|
||||
| static_scalar_value T_IS_SMALLER_OR_EQUAL static_scalar_value { $$ = Expr\BinaryOp\SmallerOrEqual[$1, $3]; }
|
||||
| static_scalar_value '>' static_scalar_value { $$ = Expr\BinaryOp\Greater [$1, $3]; }
|
||||
| static_scalar_value T_IS_GREATER_OR_EQUAL static_scalar_value { $$ = Expr\BinaryOp\GreaterOrEqual[$1, $3]; }
|
||||
| static_scalar_value '?' static_scalar_value ':' static_scalar_value { $$ = Expr\Ternary[$1, $3, $5]; }
|
||||
| static_scalar_value '?' ':' static_scalar_value { $$ = Expr\Ternary[$1, null, $4]; }
|
||||
| '(' static_scalar_value ')' { $$ = $2; }
|
||||
static_scalar T_BOOLEAN_OR static_scalar { $$ = Expr\BinaryOp\BooleanOr [$1, $3]; }
|
||||
| static_scalar T_BOOLEAN_AND static_scalar { $$ = Expr\BinaryOp\BooleanAnd[$1, $3]; }
|
||||
| static_scalar T_LOGICAL_OR static_scalar { $$ = Expr\BinaryOp\LogicalOr [$1, $3]; }
|
||||
| static_scalar T_LOGICAL_AND static_scalar { $$ = Expr\BinaryOp\LogicalAnd[$1, $3]; }
|
||||
| static_scalar T_LOGICAL_XOR static_scalar { $$ = Expr\BinaryOp\LogicalXor[$1, $3]; }
|
||||
| static_scalar '|' static_scalar { $$ = Expr\BinaryOp\BitwiseOr [$1, $3]; }
|
||||
| static_scalar '&' static_scalar { $$ = Expr\BinaryOp\BitwiseAnd[$1, $3]; }
|
||||
| static_scalar '^' static_scalar { $$ = Expr\BinaryOp\BitwiseXor[$1, $3]; }
|
||||
| static_scalar '.' static_scalar { $$ = Expr\BinaryOp\Concat [$1, $3]; }
|
||||
| static_scalar '+' static_scalar { $$ = Expr\BinaryOp\Plus [$1, $3]; }
|
||||
| static_scalar '-' static_scalar { $$ = Expr\BinaryOp\Minus [$1, $3]; }
|
||||
| static_scalar '*' static_scalar { $$ = Expr\BinaryOp\Mul [$1, $3]; }
|
||||
| static_scalar '/' static_scalar { $$ = Expr\BinaryOp\Div [$1, $3]; }
|
||||
| static_scalar '%' static_scalar { $$ = Expr\BinaryOp\Mod [$1, $3]; }
|
||||
| static_scalar T_SL static_scalar { $$ = Expr\BinaryOp\ShiftLeft [$1, $3]; }
|
||||
| static_scalar T_SR static_scalar { $$ = Expr\BinaryOp\ShiftRight[$1, $3]; }
|
||||
| static_scalar T_POW static_scalar { $$ = Expr\BinaryOp\Pow [$1, $3]; }
|
||||
| '+' static_scalar %prec T_INC { $$ = Expr\UnaryPlus [$2]; }
|
||||
| '-' static_scalar %prec T_INC { $$ = Expr\UnaryMinus[$2]; }
|
||||
| '!' static_scalar { $$ = Expr\BooleanNot[$2]; }
|
||||
| '~' static_scalar { $$ = Expr\BitwiseNot[$2]; }
|
||||
| static_scalar T_IS_IDENTICAL static_scalar { $$ = Expr\BinaryOp\Identical [$1, $3]; }
|
||||
| static_scalar T_IS_NOT_IDENTICAL static_scalar { $$ = Expr\BinaryOp\NotIdentical [$1, $3]; }
|
||||
| static_scalar T_IS_EQUAL static_scalar { $$ = Expr\BinaryOp\Equal [$1, $3]; }
|
||||
| static_scalar T_IS_NOT_EQUAL static_scalar { $$ = Expr\BinaryOp\NotEqual [$1, $3]; }
|
||||
| static_scalar '<' static_scalar { $$ = Expr\BinaryOp\Smaller [$1, $3]; }
|
||||
| static_scalar T_IS_SMALLER_OR_EQUAL static_scalar { $$ = Expr\BinaryOp\SmallerOrEqual[$1, $3]; }
|
||||
| static_scalar '>' static_scalar { $$ = Expr\BinaryOp\Greater [$1, $3]; }
|
||||
| static_scalar T_IS_GREATER_OR_EQUAL static_scalar { $$ = Expr\BinaryOp\GreaterOrEqual[$1, $3]; }
|
||||
| static_scalar '?' static_scalar ':' static_scalar { $$ = Expr\Ternary[$1, $3, $5]; }
|
||||
| static_scalar '?' ':' static_scalar { $$ = Expr\Ternary[$1, null, $4]; }
|
||||
| static_scalar '[' static_scalar ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
||||
| '(' static_scalar ')' { $$ = $2; }
|
||||
;
|
||||
|
||||
constant:
|
||||
name { $$ = Expr\ConstFetch[$1]; }
|
||||
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier
|
||||
{ $$ = Expr\ClassConstFetch[$1, $3]; }
|
||||
;
|
||||
|
||||
scalar:
|
||||
common_scalar { $$ = $1; }
|
||||
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM class_const_name
|
||||
{ $$ = Expr\ClassConstFetch[$1, $3]; }
|
||||
| constant { $$ = $1; }
|
||||
| '"' encaps_list '"'
|
||||
{ parseEncapsed($2, '"'); $$ = Scalar\Encapsed[$2]; }
|
||||
{ parseEncapsed($2, '"', false); $$ = Scalar\Encapsed[$2]; }
|
||||
| T_START_HEREDOC encaps_list T_END_HEREDOC
|
||||
{ parseEncapsedDoc($2); $$ = Scalar\Encapsed[$2]; }
|
||||
;
|
||||
|
||||
class_const_name:
|
||||
T_STRING { $$ = $1; }
|
||||
| T_CLASS { $$ = 'class'; }
|
||||
{ parseEncapsedDoc($2, false); $$ = Scalar\Encapsed[$2]; }
|
||||
;
|
||||
|
||||
static_array_pair_list:
|
||||
@ -953,8 +920,8 @@ encaps_var:
|
||||
;
|
||||
|
||||
encaps_var_offset:
|
||||
T_STRING { $$ = Scalar\String[$1]; }
|
||||
| T_NUM_STRING { $$ = Scalar\String[$1]; }
|
||||
T_STRING { $$ = Scalar\String_[$1]; }
|
||||
| T_NUM_STRING { $$ = Scalar\String_[$1]; }
|
||||
| T_VARIABLE { $$ = Expr\Variable[parseVar($1)]; }
|
||||
;
|
||||
|
795
grammar/php7.y
Normal file
795
grammar/php7.y
Normal file
@ -0,0 +1,795 @@
|
||||
%pure_parser
|
||||
%expect 2
|
||||
|
||||
%tokens
|
||||
|
||||
%%
|
||||
|
||||
start:
|
||||
top_statement_list { $$ = $this->handleNamespaces($1); }
|
||||
;
|
||||
|
||||
top_statement_list:
|
||||
top_statement_list top_statement { pushNormalizing($1, $2); }
|
||||
| /* empty */ { init(); }
|
||||
;
|
||||
|
||||
reserved_non_modifiers:
|
||||
T_INCLUDE | T_INCLUDE_ONCE | T_EVAL | T_REQUIRE | T_REQUIRE_ONCE | T_LOGICAL_OR | T_LOGICAL_XOR | T_LOGICAL_AND
|
||||
| T_INSTANCEOF | T_NEW | T_CLONE | T_EXIT | T_IF | T_ELSEIF | T_ELSE | T_ENDIF | T_ECHO | T_DO | T_WHILE
|
||||
| T_ENDWHILE | T_FOR | T_ENDFOR | T_FOREACH | T_ENDFOREACH | T_DECLARE | T_ENDDECLARE | T_AS | T_TRY | T_CATCH
|
||||
| T_FINALLY | T_THROW | T_USE | T_INSTEADOF | T_GLOBAL | T_VAR | T_UNSET | T_ISSET | T_EMPTY | T_CONTINUE | T_GOTO
|
||||
| T_FUNCTION | T_CONST | T_RETURN | T_PRINT | T_YIELD | T_LIST | T_SWITCH | T_ENDSWITCH | T_CASE | T_DEFAULT
|
||||
| T_BREAK | T_ARRAY | T_CALLABLE | T_EXTENDS | T_IMPLEMENTS | T_NAMESPACE | T_TRAIT | T_INTERFACE | T_CLASS
|
||||
;
|
||||
|
||||
semi_reserved:
|
||||
reserved_non_modifiers
|
||||
| T_STATIC | T_ABSTRACT | T_FINAL | T_PRIVATE | T_PROTECTED | T_PUBLIC
|
||||
;
|
||||
|
||||
identifier:
|
||||
T_STRING { $$ = $1; }
|
||||
| semi_reserved { $$ = $1; }
|
||||
;
|
||||
|
||||
namespace_name_parts:
|
||||
T_STRING { init($1); }
|
||||
| namespace_name_parts T_NS_SEPARATOR T_STRING { push($1, $3); }
|
||||
;
|
||||
|
||||
namespace_name:
|
||||
namespace_name_parts { $$ = Name[$1]; }
|
||||
;
|
||||
|
||||
top_statement:
|
||||
statement { $$ = $1; }
|
||||
| function_declaration_statement { $$ = $1; }
|
||||
| class_declaration_statement { $$ = $1; }
|
||||
| T_HALT_COMPILER
|
||||
{ $$ = Stmt\HaltCompiler[$this->lexer->handleHaltCompiler()]; }
|
||||
| T_NAMESPACE namespace_name ';' { $$ = Stmt\Namespace_[$2, null]; }
|
||||
| T_NAMESPACE namespace_name '{' top_statement_list '}' { $$ = Stmt\Namespace_[$2, $4]; }
|
||||
| T_NAMESPACE '{' top_statement_list '}' { $$ = Stmt\Namespace_[null, $3]; }
|
||||
| T_USE use_declarations ';' { $$ = Stmt\Use_[$2, Stmt\Use_::TYPE_NORMAL]; }
|
||||
| T_USE use_type use_declarations ';' { $$ = Stmt\Use_[$3, $2]; }
|
||||
| group_use_declaration { $$ = $1; }
|
||||
| T_CONST constant_declaration_list ';' { $$ = Stmt\Const_[$2]; }
|
||||
;
|
||||
|
||||
use_type:
|
||||
T_FUNCTION { $$ = Stmt\Use_::TYPE_FUNCTION; }
|
||||
| T_CONST { $$ = Stmt\Use_::TYPE_CONSTANT; }
|
||||
;
|
||||
|
||||
/* Using namespace_name_parts here to avoid s/r conflict on T_NS_SEPARATOR */
|
||||
group_use_declaration:
|
||||
T_USE use_type namespace_name_parts T_NS_SEPARATOR '{' use_declarations '}'
|
||||
{ $$ = Stmt\GroupUse[Name[$3], $6, $2]; }
|
||||
| T_USE namespace_name_parts T_NS_SEPARATOR '{' inline_use_declarations '}'
|
||||
{ $$ = Stmt\GroupUse[Name[$2], $5, Stmt\Use_::TYPE_UNKNOWN]; }
|
||||
;
|
||||
|
||||
use_declarations:
|
||||
use_declarations ',' use_declaration { push($1, $3); }
|
||||
| use_declaration { init($1); }
|
||||
;
|
||||
|
||||
use_declaration:
|
||||
namespace_name { $$ = Stmt\UseUse[$1, null, Stmt\Use_::TYPE_UNKNOWN]; }
|
||||
| namespace_name T_AS T_STRING { $$ = Stmt\UseUse[$1, $3, Stmt\Use_::TYPE_UNKNOWN]; }
|
||||
| T_NS_SEPARATOR namespace_name { $$ = Stmt\UseUse[$2, null, Stmt\Use_::TYPE_UNKNOWN]; }
|
||||
| T_NS_SEPARATOR namespace_name T_AS T_STRING { $$ = Stmt\UseUse[$2, $4, Stmt\Use_::TYPE_UNKNOWN]; }
|
||||
;
|
||||
|
||||
inline_use_declarations:
|
||||
inline_use_declarations ',' inline_use_declaration { push($1, $3); }
|
||||
| inline_use_declaration { init($1); }
|
||||
;
|
||||
|
||||
inline_use_declaration:
|
||||
use_declaration { $$ = $1; $$->type = Stmt\Use_::TYPE_NORMAL; }
|
||||
| use_type use_declaration { $$ = $2; $$->type = $1; }
|
||||
;
|
||||
|
||||
constant_declaration_list:
|
||||
constant_declaration_list ',' constant_declaration { push($1, $3); }
|
||||
| constant_declaration { init($1); }
|
||||
;
|
||||
|
||||
constant_declaration:
|
||||
T_STRING '=' expr { $$ = Node\Const_[$1, $3]; }
|
||||
;
|
||||
|
||||
class_const_list:
|
||||
class_const_list ',' class_const { push($1, $3); }
|
||||
| class_const { init($1); }
|
||||
;
|
||||
|
||||
class_const:
|
||||
identifier '=' expr { $$ = Node\Const_[$1, $3]; }
|
||||
;
|
||||
|
||||
inner_statement_list:
|
||||
inner_statement_list inner_statement { pushNormalizing($1, $2); }
|
||||
| /* empty */ { init(); }
|
||||
;
|
||||
|
||||
inner_statement:
|
||||
statement { $$ = $1; }
|
||||
| function_declaration_statement { $$ = $1; }
|
||||
| class_declaration_statement { $$ = $1; }
|
||||
| T_HALT_COMPILER
|
||||
{ throw new Error('__HALT_COMPILER() can only be used from the outermost scope', attributes()); }
|
||||
;
|
||||
|
||||
statement:
|
||||
'{' inner_statement_list '}' { $$ = $2; }
|
||||
| T_IF '(' expr ')' statement elseif_list else_single
|
||||
{ $$ = Stmt\If_[$3, ['stmts' => toArray($5), 'elseifs' => $6, 'else' => $7]]; }
|
||||
| T_IF '(' expr ')' ':' inner_statement_list new_elseif_list new_else_single T_ENDIF ';'
|
||||
{ $$ = Stmt\If_[$3, ['stmts' => $6, 'elseifs' => $7, 'else' => $8]]; }
|
||||
| T_WHILE '(' expr ')' while_statement { $$ = Stmt\While_[$3, $5]; }
|
||||
| T_DO statement T_WHILE '(' expr ')' ';' { $$ = Stmt\Do_ [$5, toArray($2)]; }
|
||||
| T_FOR '(' for_expr ';' for_expr ';' for_expr ')' for_statement
|
||||
{ $$ = Stmt\For_[['init' => $3, 'cond' => $5, 'loop' => $7, 'stmts' => $9]]; }
|
||||
| T_SWITCH '(' expr ')' switch_case_list { $$ = Stmt\Switch_[$3, $5]; }
|
||||
| T_BREAK optional_expr ';' { $$ = Stmt\Break_[$2]; }
|
||||
| T_CONTINUE optional_expr ';' { $$ = Stmt\Continue_[$2]; }
|
||||
| T_RETURN optional_expr ';' { $$ = Stmt\Return_[$2]; }
|
||||
| T_GLOBAL global_var_list ';' { $$ = Stmt\Global_[$2]; }
|
||||
| T_STATIC static_var_list ';' { $$ = Stmt\Static_[$2]; }
|
||||
| T_ECHO expr_list ';' { $$ = Stmt\Echo_[$2]; }
|
||||
| T_INLINE_HTML { $$ = Stmt\InlineHTML[$1]; }
|
||||
| expr ';' { $$ = $1; }
|
||||
| T_UNSET '(' variables_list ')' ';' { $$ = Stmt\Unset_[$3]; }
|
||||
| T_FOREACH '(' expr T_AS foreach_variable ')' foreach_statement
|
||||
{ $$ = Stmt\Foreach_[$3, $5[0], ['keyVar' => null, 'byRef' => $5[1], 'stmts' => $7]]; }
|
||||
| T_FOREACH '(' expr T_AS variable T_DOUBLE_ARROW foreach_variable ')' foreach_statement
|
||||
{ $$ = Stmt\Foreach_[$3, $7[0], ['keyVar' => $5, 'byRef' => $7[1], 'stmts' => $9]]; }
|
||||
| T_DECLARE '(' declare_list ')' declare_statement { $$ = Stmt\Declare_[$3, $5]; }
|
||||
| ';' { $$ = array(); /* means: no statement */ }
|
||||
| T_TRY '{' inner_statement_list '}' catches optional_finally
|
||||
{ $$ = Stmt\TryCatch[$3, $5, $6]; }
|
||||
| T_THROW expr ';' { $$ = Stmt\Throw_[$2]; }
|
||||
| T_GOTO T_STRING ';' { $$ = Stmt\Goto_[$2]; }
|
||||
| T_STRING ':' { $$ = Stmt\Label[$1]; }
|
||||
| error { $$ = array(); /* means: no statement */ }
|
||||
;
|
||||
|
||||
catches:
|
||||
/* empty */ { init(); }
|
||||
| catches catch { push($1, $2); }
|
||||
;
|
||||
|
||||
catch:
|
||||
T_CATCH '(' name T_VARIABLE ')' '{' inner_statement_list '}'
|
||||
{ $$ = Stmt\Catch_[$3, parseVar($4), $7]; }
|
||||
;
|
||||
|
||||
optional_finally:
|
||||
/* empty */ { $$ = null; }
|
||||
| T_FINALLY '{' inner_statement_list '}' { $$ = $3; }
|
||||
;
|
||||
|
||||
variables_list:
|
||||
variable { init($1); }
|
||||
| variables_list ',' variable { push($1, $3); }
|
||||
;
|
||||
|
||||
optional_ref:
|
||||
/* empty */ { $$ = false; }
|
||||
| '&' { $$ = true; }
|
||||
;
|
||||
|
||||
optional_ellipsis:
|
||||
/* empty */ { $$ = false; }
|
||||
| T_ELLIPSIS { $$ = true; }
|
||||
;
|
||||
|
||||
function_declaration_statement:
|
||||
T_FUNCTION optional_ref T_STRING '(' parameter_list ')' optional_return_type '{' inner_statement_list '}'
|
||||
{ $$ = Stmt\Function_[$3, ['byRef' => $2, 'params' => $5, 'returnType' => $7, 'stmts' => $9]]; }
|
||||
;
|
||||
|
||||
class_declaration_statement:
|
||||
class_entry_type T_STRING extends_from implements_list '{' class_statement_list '}'
|
||||
{ $$ = Stmt\Class_[$2, ['type' => $1, 'extends' => $3, 'implements' => $4, 'stmts' => $6]]; }
|
||||
| T_INTERFACE T_STRING interface_extends_list '{' class_statement_list '}'
|
||||
{ $$ = Stmt\Interface_[$2, ['extends' => $3, 'stmts' => $5]]; }
|
||||
| T_TRAIT T_STRING '{' class_statement_list '}'
|
||||
{ $$ = Stmt\Trait_[$2, $4]; }
|
||||
;
|
||||
|
||||
class_entry_type:
|
||||
T_CLASS { $$ = 0; }
|
||||
| T_ABSTRACT T_CLASS { $$ = Stmt\Class_::MODIFIER_ABSTRACT; }
|
||||
| T_FINAL T_CLASS { $$ = Stmt\Class_::MODIFIER_FINAL; }
|
||||
;
|
||||
|
||||
extends_from:
|
||||
/* empty */ { $$ = null; }
|
||||
| T_EXTENDS name { $$ = $2; }
|
||||
;
|
||||
|
||||
interface_extends_list:
|
||||
/* empty */ { $$ = array(); }
|
||||
| T_EXTENDS name_list { $$ = $2; }
|
||||
;
|
||||
|
||||
implements_list:
|
||||
/* empty */ { $$ = array(); }
|
||||
| T_IMPLEMENTS name_list { $$ = $2; }
|
||||
;
|
||||
|
||||
name_list:
|
||||
name { init($1); }
|
||||
| name_list ',' name { push($1, $3); }
|
||||
;
|
||||
|
||||
for_statement:
|
||||
statement { $$ = toArray($1); }
|
||||
| ':' inner_statement_list T_ENDFOR ';' { $$ = $2; }
|
||||
;
|
||||
|
||||
foreach_statement:
|
||||
statement { $$ = toArray($1); }
|
||||
| ':' inner_statement_list T_ENDFOREACH ';' { $$ = $2; }
|
||||
;
|
||||
|
||||
declare_statement:
|
||||
statement { $$ = toArray($1); }
|
||||
| ':' inner_statement_list T_ENDDECLARE ';' { $$ = $2; }
|
||||
;
|
||||
|
||||
declare_list:
|
||||
declare_list_element { init($1); }
|
||||
| declare_list ',' declare_list_element { push($1, $3); }
|
||||
;
|
||||
|
||||
declare_list_element:
|
||||
T_STRING '=' expr { $$ = Stmt\DeclareDeclare[$1, $3]; }
|
||||
;
|
||||
|
||||
switch_case_list:
|
||||
'{' case_list '}' { $$ = $2; }
|
||||
| '{' ';' case_list '}' { $$ = $3; }
|
||||
| ':' case_list T_ENDSWITCH ';' { $$ = $2; }
|
||||
| ':' ';' case_list T_ENDSWITCH ';' { $$ = $3; }
|
||||
;
|
||||
|
||||
case_list:
|
||||
/* empty */ { init(); }
|
||||
| case_list case { push($1, $2); }
|
||||
;
|
||||
|
||||
case:
|
||||
T_CASE expr case_separator inner_statement_list { $$ = Stmt\Case_[$2, $4]; }
|
||||
| T_DEFAULT case_separator inner_statement_list { $$ = Stmt\Case_[null, $3]; }
|
||||
;
|
||||
|
||||
case_separator:
|
||||
':'
|
||||
| ';'
|
||||
;
|
||||
|
||||
while_statement:
|
||||
statement { $$ = toArray($1); }
|
||||
| ':' inner_statement_list T_ENDWHILE ';' { $$ = $2; }
|
||||
;
|
||||
|
||||
elseif_list:
|
||||
/* empty */ { init(); }
|
||||
| elseif_list elseif { push($1, $2); }
|
||||
;
|
||||
|
||||
elseif:
|
||||
T_ELSEIF '(' expr ')' statement { $$ = Stmt\ElseIf_[$3, toArray($5)]; }
|
||||
;
|
||||
|
||||
new_elseif_list:
|
||||
/* empty */ { init(); }
|
||||
| new_elseif_list new_elseif { push($1, $2); }
|
||||
;
|
||||
|
||||
new_elseif:
|
||||
T_ELSEIF '(' expr ')' ':' inner_statement_list { $$ = Stmt\ElseIf_[$3, $6]; }
|
||||
;
|
||||
|
||||
else_single:
|
||||
/* empty */ { $$ = null; }
|
||||
| T_ELSE statement { $$ = Stmt\Else_[toArray($2)]; }
|
||||
;
|
||||
|
||||
new_else_single:
|
||||
/* empty */ { $$ = null; }
|
||||
| T_ELSE ':' inner_statement_list { $$ = Stmt\Else_[$3]; }
|
||||
;
|
||||
|
||||
foreach_variable:
|
||||
variable { $$ = array($1, false); }
|
||||
| '&' variable { $$ = array($2, true); }
|
||||
| list_expr { $$ = array($1, false); }
|
||||
;
|
||||
|
||||
parameter_list:
|
||||
non_empty_parameter_list { $$ = $1; }
|
||||
| /* empty */ { $$ = array(); }
|
||||
;
|
||||
|
||||
non_empty_parameter_list:
|
||||
parameter { init($1); }
|
||||
| non_empty_parameter_list ',' parameter { push($1, $3); }
|
||||
;
|
||||
|
||||
parameter:
|
||||
optional_param_type optional_ref optional_ellipsis T_VARIABLE
|
||||
{ $$ = Node\Param[parseVar($4), null, $1, $2, $3]; }
|
||||
| optional_param_type optional_ref optional_ellipsis T_VARIABLE '=' expr
|
||||
{ $$ = Node\Param[parseVar($4), $6, $1, $2, $3]; }
|
||||
;
|
||||
|
||||
type:
|
||||
name { $$ = $this->handleScalarTypes($1); }
|
||||
| T_ARRAY { $$ = 'array'; }
|
||||
| T_CALLABLE { $$ = 'callable'; }
|
||||
;
|
||||
|
||||
optional_param_type:
|
||||
/* empty */ { $$ = null; }
|
||||
| type { $$ = $1; }
|
||||
;
|
||||
|
||||
optional_return_type:
|
||||
/* empty */ { $$ = null; }
|
||||
| ':' type { $$ = $2; }
|
||||
;
|
||||
|
||||
argument_list:
|
||||
'(' ')' { $$ = array(); }
|
||||
| '(' non_empty_argument_list ')' { $$ = $2; }
|
||||
;
|
||||
|
||||
non_empty_argument_list:
|
||||
argument { init($1); }
|
||||
| non_empty_argument_list ',' argument { push($1, $3); }
|
||||
;
|
||||
|
||||
argument:
|
||||
expr { $$ = Node\Arg[$1, false, false]; }
|
||||
| '&' variable { $$ = Node\Arg[$2, true, false]; }
|
||||
| T_ELLIPSIS expr { $$ = Node\Arg[$2, false, true]; }
|
||||
;
|
||||
|
||||
global_var_list:
|
||||
global_var_list ',' global_var { push($1, $3); }
|
||||
| global_var { init($1); }
|
||||
;
|
||||
|
||||
global_var:
|
||||
simple_variable { $$ = Expr\Variable[$1]; }
|
||||
;
|
||||
|
||||
static_var_list:
|
||||
static_var_list ',' static_var { push($1, $3); }
|
||||
| static_var { init($1); }
|
||||
;
|
||||
|
||||
static_var:
|
||||
T_VARIABLE { $$ = Stmt\StaticVar[parseVar($1), null]; }
|
||||
| T_VARIABLE '=' expr { $$ = Stmt\StaticVar[parseVar($1), $3]; }
|
||||
;
|
||||
|
||||
class_statement_list:
|
||||
class_statement_list class_statement { push($1, $2); }
|
||||
| /* empty */ { init(); }
|
||||
;
|
||||
|
||||
class_statement:
|
||||
variable_modifiers property_declaration_list ';' { $$ = Stmt\Property[$1, $2]; }
|
||||
| T_CONST class_const_list ';' { $$ = Stmt\ClassConst[$2]; }
|
||||
| method_modifiers T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type method_body
|
||||
{ $$ = Stmt\ClassMethod[$4, ['type' => $1, 'byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9]]; }
|
||||
| T_USE name_list trait_adaptations { $$ = Stmt\TraitUse[$2, $3]; }
|
||||
;
|
||||
|
||||
trait_adaptations:
|
||||
';' { $$ = array(); }
|
||||
| '{' trait_adaptation_list '}' { $$ = $2; }
|
||||
;
|
||||
|
||||
trait_adaptation_list:
|
||||
/* empty */ { init(); }
|
||||
| trait_adaptation_list trait_adaptation { push($1, $2); }
|
||||
;
|
||||
|
||||
trait_adaptation:
|
||||
trait_method_reference_fully_qualified T_INSTEADOF name_list ';'
|
||||
{ $$ = Stmt\TraitUseAdaptation\Precedence[$1[0], $1[1], $3]; }
|
||||
| trait_method_reference T_AS member_modifier identifier ';'
|
||||
{ $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], $3, $4]; }
|
||||
| trait_method_reference T_AS member_modifier ';'
|
||||
{ $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], $3, null]; }
|
||||
| trait_method_reference T_AS T_STRING ';'
|
||||
{ $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], null, $3]; }
|
||||
| trait_method_reference T_AS reserved_non_modifiers ';'
|
||||
{ $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], null, $3]; }
|
||||
;
|
||||
|
||||
trait_method_reference_fully_qualified:
|
||||
name T_PAAMAYIM_NEKUDOTAYIM identifier { $$ = array($1, $3); }
|
||||
;
|
||||
trait_method_reference:
|
||||
trait_method_reference_fully_qualified { $$ = $1; }
|
||||
| identifier { $$ = array(null, $1); }
|
||||
;
|
||||
|
||||
method_body:
|
||||
';' /* abstract method */ { $$ = null; }
|
||||
| '{' inner_statement_list '}' { $$ = $2; }
|
||||
;
|
||||
|
||||
variable_modifiers:
|
||||
non_empty_member_modifiers { $$ = $1; }
|
||||
| T_VAR { $$ = 0; }
|
||||
;
|
||||
|
||||
method_modifiers:
|
||||
/* empty */ { $$ = 0; }
|
||||
| non_empty_member_modifiers { $$ = $1; }
|
||||
;
|
||||
|
||||
non_empty_member_modifiers:
|
||||
member_modifier { $$ = $1; }
|
||||
| non_empty_member_modifiers member_modifier { Stmt\Class_::verifyModifier($1, $2); $$ = $1 | $2; }
|
||||
;
|
||||
|
||||
member_modifier:
|
||||
T_PUBLIC { $$ = Stmt\Class_::MODIFIER_PUBLIC; }
|
||||
| T_PROTECTED { $$ = Stmt\Class_::MODIFIER_PROTECTED; }
|
||||
| T_PRIVATE { $$ = Stmt\Class_::MODIFIER_PRIVATE; }
|
||||
| T_STATIC { $$ = Stmt\Class_::MODIFIER_STATIC; }
|
||||
| T_ABSTRACT { $$ = Stmt\Class_::MODIFIER_ABSTRACT; }
|
||||
| T_FINAL { $$ = Stmt\Class_::MODIFIER_FINAL; }
|
||||
;
|
||||
|
||||
property_declaration_list:
|
||||
property_declaration { init($1); }
|
||||
| property_declaration_list ',' property_declaration { push($1, $3); }
|
||||
;
|
||||
|
||||
property_declaration:
|
||||
T_VARIABLE { $$ = Stmt\PropertyProperty[parseVar($1), null]; }
|
||||
| T_VARIABLE '=' expr { $$ = Stmt\PropertyProperty[parseVar($1), $3]; }
|
||||
;
|
||||
|
||||
expr_list:
|
||||
expr_list ',' expr { push($1, $3); }
|
||||
| expr { init($1); }
|
||||
;
|
||||
|
||||
for_expr:
|
||||
/* empty */ { $$ = array(); }
|
||||
| expr_list { $$ = $1; }
|
||||
;
|
||||
|
||||
expr:
|
||||
variable { $$ = $1; }
|
||||
| list_expr '=' expr { $$ = Expr\Assign[$1, $3]; }
|
||||
| variable '=' expr { $$ = Expr\Assign[$1, $3]; }
|
||||
| variable '=' '&' variable { $$ = Expr\AssignRef[$1, $4]; }
|
||||
| variable '=' '&' new_expr { $$ = Expr\AssignRef[$1, $4]; }
|
||||
| new_expr { $$ = $1; }
|
||||
| T_CLONE expr { $$ = Expr\Clone_[$2]; }
|
||||
| variable T_PLUS_EQUAL expr { $$ = Expr\AssignOp\Plus [$1, $3]; }
|
||||
| variable T_MINUS_EQUAL expr { $$ = Expr\AssignOp\Minus [$1, $3]; }
|
||||
| variable T_MUL_EQUAL expr { $$ = Expr\AssignOp\Mul [$1, $3]; }
|
||||
| variable T_DIV_EQUAL expr { $$ = Expr\AssignOp\Div [$1, $3]; }
|
||||
| variable T_CONCAT_EQUAL expr { $$ = Expr\AssignOp\Concat [$1, $3]; }
|
||||
| variable T_MOD_EQUAL expr { $$ = Expr\AssignOp\Mod [$1, $3]; }
|
||||
| variable T_AND_EQUAL expr { $$ = Expr\AssignOp\BitwiseAnd[$1, $3]; }
|
||||
| variable T_OR_EQUAL expr { $$ = Expr\AssignOp\BitwiseOr [$1, $3]; }
|
||||
| variable T_XOR_EQUAL expr { $$ = Expr\AssignOp\BitwiseXor[$1, $3]; }
|
||||
| variable T_SL_EQUAL expr { $$ = Expr\AssignOp\ShiftLeft [$1, $3]; }
|
||||
| variable T_SR_EQUAL expr { $$ = Expr\AssignOp\ShiftRight[$1, $3]; }
|
||||
| variable T_POW_EQUAL expr { $$ = Expr\AssignOp\Pow [$1, $3]; }
|
||||
| variable T_INC { $$ = Expr\PostInc[$1]; }
|
||||
| T_INC variable { $$ = Expr\PreInc [$2]; }
|
||||
| variable T_DEC { $$ = Expr\PostDec[$1]; }
|
||||
| T_DEC variable { $$ = Expr\PreDec [$2]; }
|
||||
| expr T_BOOLEAN_OR expr { $$ = Expr\BinaryOp\BooleanOr [$1, $3]; }
|
||||
| expr T_BOOLEAN_AND expr { $$ = Expr\BinaryOp\BooleanAnd[$1, $3]; }
|
||||
| expr T_LOGICAL_OR expr { $$ = Expr\BinaryOp\LogicalOr [$1, $3]; }
|
||||
| expr T_LOGICAL_AND expr { $$ = Expr\BinaryOp\LogicalAnd[$1, $3]; }
|
||||
| expr T_LOGICAL_XOR expr { $$ = Expr\BinaryOp\LogicalXor[$1, $3]; }
|
||||
| expr '|' expr { $$ = Expr\BinaryOp\BitwiseOr [$1, $3]; }
|
||||
| expr '&' expr { $$ = Expr\BinaryOp\BitwiseAnd[$1, $3]; }
|
||||
| expr '^' expr { $$ = Expr\BinaryOp\BitwiseXor[$1, $3]; }
|
||||
| expr '.' expr { $$ = Expr\BinaryOp\Concat [$1, $3]; }
|
||||
| expr '+' expr { $$ = Expr\BinaryOp\Plus [$1, $3]; }
|
||||
| expr '-' expr { $$ = Expr\BinaryOp\Minus [$1, $3]; }
|
||||
| expr '*' expr { $$ = Expr\BinaryOp\Mul [$1, $3]; }
|
||||
| expr '/' expr { $$ = Expr\BinaryOp\Div [$1, $3]; }
|
||||
| expr '%' expr { $$ = Expr\BinaryOp\Mod [$1, $3]; }
|
||||
| expr T_SL expr { $$ = Expr\BinaryOp\ShiftLeft [$1, $3]; }
|
||||
| expr T_SR expr { $$ = Expr\BinaryOp\ShiftRight[$1, $3]; }
|
||||
| expr T_POW expr { $$ = Expr\BinaryOp\Pow [$1, $3]; }
|
||||
| '+' expr %prec T_INC { $$ = Expr\UnaryPlus [$2]; }
|
||||
| '-' expr %prec T_INC { $$ = Expr\UnaryMinus[$2]; }
|
||||
| '!' expr { $$ = Expr\BooleanNot[$2]; }
|
||||
| '~' expr { $$ = Expr\BitwiseNot[$2]; }
|
||||
| expr T_IS_IDENTICAL expr { $$ = Expr\BinaryOp\Identical [$1, $3]; }
|
||||
| expr T_IS_NOT_IDENTICAL expr { $$ = Expr\BinaryOp\NotIdentical [$1, $3]; }
|
||||
| expr T_IS_EQUAL expr { $$ = Expr\BinaryOp\Equal [$1, $3]; }
|
||||
| expr T_IS_NOT_EQUAL expr { $$ = Expr\BinaryOp\NotEqual [$1, $3]; }
|
||||
| expr T_SPACESHIP expr { $$ = Expr\BinaryOp\Spaceship [$1, $3]; }
|
||||
| expr '<' expr { $$ = Expr\BinaryOp\Smaller [$1, $3]; }
|
||||
| expr T_IS_SMALLER_OR_EQUAL expr { $$ = Expr\BinaryOp\SmallerOrEqual[$1, $3]; }
|
||||
| expr '>' expr { $$ = Expr\BinaryOp\Greater [$1, $3]; }
|
||||
| expr T_IS_GREATER_OR_EQUAL expr { $$ = Expr\BinaryOp\GreaterOrEqual[$1, $3]; }
|
||||
| expr T_INSTANCEOF class_name_reference { $$ = Expr\Instanceof_[$1, $3]; }
|
||||
| '(' expr ')' { $$ = $2; }
|
||||
| expr '?' expr ':' expr { $$ = Expr\Ternary[$1, $3, $5]; }
|
||||
| expr '?' ':' expr { $$ = Expr\Ternary[$1, null, $4]; }
|
||||
| expr T_COALESCE expr { $$ = Expr\BinaryOp\Coalesce[$1, $3]; }
|
||||
| T_ISSET '(' variables_list ')' { $$ = Expr\Isset_[$3]; }
|
||||
| T_EMPTY '(' expr ')' { $$ = Expr\Empty_[$3]; }
|
||||
| T_INCLUDE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_INCLUDE]; }
|
||||
| T_INCLUDE_ONCE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_INCLUDE_ONCE]; }
|
||||
| T_EVAL '(' expr ')' { $$ = Expr\Eval_[$3]; }
|
||||
| T_REQUIRE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_REQUIRE]; }
|
||||
| T_REQUIRE_ONCE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_REQUIRE_ONCE]; }
|
||||
| T_INT_CAST expr { $$ = Expr\Cast\Int_ [$2]; }
|
||||
| T_DOUBLE_CAST expr { $$ = Expr\Cast\Double [$2]; }
|
||||
| T_STRING_CAST expr { $$ = Expr\Cast\String_ [$2]; }
|
||||
| T_ARRAY_CAST expr { $$ = Expr\Cast\Array_ [$2]; }
|
||||
| T_OBJECT_CAST expr { $$ = Expr\Cast\Object_ [$2]; }
|
||||
| T_BOOL_CAST expr { $$ = Expr\Cast\Bool_ [$2]; }
|
||||
| T_UNSET_CAST expr { $$ = Expr\Cast\Unset_ [$2]; }
|
||||
| T_EXIT exit_expr { $$ = Expr\Exit_ [$2]; }
|
||||
| '@' expr { $$ = Expr\ErrorSuppress[$2]; }
|
||||
| scalar { $$ = $1; }
|
||||
| '`' backticks_expr '`' { $$ = Expr\ShellExec[$2]; }
|
||||
| T_PRINT expr { $$ = Expr\Print_[$2]; }
|
||||
| T_YIELD { $$ = Expr\Yield_[null, null]; }
|
||||
| T_YIELD expr { $$ = Expr\Yield_[$2, null]; }
|
||||
| T_YIELD expr T_DOUBLE_ARROW expr { $$ = Expr\Yield_[$4, $2]; }
|
||||
| T_YIELD_FROM expr { $$ = Expr\YieldFrom[$2]; }
|
||||
| T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type
|
||||
'{' inner_statement_list '}'
|
||||
{ $$ = Expr\Closure[['static' => false, 'byRef' => $2, 'params' => $4, 'uses' => $6, 'returnType' => $7, 'stmts' => $9]]; }
|
||||
| T_STATIC T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type
|
||||
'{' inner_statement_list '}'
|
||||
{ $$ = Expr\Closure[['static' => true, 'byRef' => $3, 'params' => $5, 'uses' => $7, 'returnType' => $8, 'stmts' => $10]]; }
|
||||
;
|
||||
|
||||
anonymous_class:
|
||||
T_CLASS ctor_arguments extends_from implements_list '{' class_statement_list '}'
|
||||
{ $$ = array(Stmt\Class_[null, ['type' => 0, 'extends' => $3, 'implements' => $4, 'stmts' => $6]], $2); }
|
||||
|
||||
new_expr:
|
||||
T_NEW class_name_reference ctor_arguments { $$ = Expr\New_[$2, $3]; }
|
||||
| T_NEW anonymous_class
|
||||
{ list($class, $ctorArgs) = $2; $$ = Expr\New_[$class, $ctorArgs]; }
|
||||
;
|
||||
|
||||
lexical_vars:
|
||||
/* empty */ { $$ = array(); }
|
||||
| T_USE '(' lexical_var_list ')' { $$ = $3; }
|
||||
;
|
||||
|
||||
lexical_var_list:
|
||||
lexical_var { init($1); }
|
||||
| lexical_var_list ',' lexical_var { push($1, $3); }
|
||||
;
|
||||
|
||||
lexical_var:
|
||||
optional_ref T_VARIABLE { $$ = Expr\ClosureUse[parseVar($2), $1]; }
|
||||
;
|
||||
|
||||
function_call:
|
||||
name 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
|
||||
{ $$ = Expr\StaticCall[$1, $3, $4]; }
|
||||
;
|
||||
|
||||
class_name:
|
||||
T_STATIC { $$ = Name[$1]; }
|
||||
| name { $$ = $1; }
|
||||
;
|
||||
|
||||
name:
|
||||
namespace_name_parts { $$ = Name[$1]; }
|
||||
| T_NS_SEPARATOR namespace_name_parts { $$ = Name\FullyQualified[$2]; }
|
||||
| T_NAMESPACE T_NS_SEPARATOR namespace_name_parts { $$ = Name\Relative[$3]; }
|
||||
;
|
||||
|
||||
class_name_reference:
|
||||
class_name { $$ = $1; }
|
||||
| new_variable { $$ = $1; }
|
||||
;
|
||||
|
||||
class_name_or_var:
|
||||
class_name { $$ = $1; }
|
||||
| dereferencable { $$ = $1; }
|
||||
;
|
||||
|
||||
exit_expr:
|
||||
/* empty */ { $$ = null; }
|
||||
| '(' optional_expr ')' { $$ = $2; }
|
||||
;
|
||||
|
||||
backticks_expr:
|
||||
/* empty */ { $$ = array(); }
|
||||
| T_ENCAPSED_AND_WHITESPACE { $$ = array(Scalar\String_::parseEscapeSequences($1, '`')); }
|
||||
| encaps_list { parseEncapsed($1, '`', true); $$ = $1; }
|
||||
;
|
||||
|
||||
ctor_arguments:
|
||||
/* empty */ { $$ = array(); }
|
||||
| argument_list { $$ = $1; }
|
||||
;
|
||||
|
||||
constant:
|
||||
name { $$ = Expr\ConstFetch[$1]; }
|
||||
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier
|
||||
{ $$ = Expr\ClassConstFetch[$1, $3]; }
|
||||
;
|
||||
|
||||
dereferencable_scalar:
|
||||
T_ARRAY '(' array_pair_list ')' { $$ = Expr\Array_[$3]; }
|
||||
| '[' array_pair_list ']' { $$ = Expr\Array_[$2]; }
|
||||
| T_CONSTANT_ENCAPSED_STRING { $$ = Scalar\String_[Scalar\String_::parse($1)]; }
|
||||
;
|
||||
|
||||
scalar:
|
||||
T_LNUMBER { $$ = Scalar\LNumber[Scalar\LNumber::parse($1)]; }
|
||||
| T_DNUMBER { $$ = Scalar\DNumber[Scalar\DNumber::parse($1)]; }
|
||||
| T_LINE { $$ = Scalar\MagicConst\Line[]; }
|
||||
| T_FILE { $$ = Scalar\MagicConst\File[]; }
|
||||
| T_DIR { $$ = Scalar\MagicConst\Dir[]; }
|
||||
| T_CLASS_C { $$ = Scalar\MagicConst\Class_[]; }
|
||||
| T_TRAIT_C { $$ = Scalar\MagicConst\Trait_[]; }
|
||||
| T_METHOD_C { $$ = Scalar\MagicConst\Method[]; }
|
||||
| T_FUNC_C { $$ = Scalar\MagicConst\Function_[]; }
|
||||
| T_NS_C { $$ = Scalar\MagicConst\Namespace_[]; }
|
||||
| dereferencable_scalar { $$ = $1; }
|
||||
| constant { $$ = $1; }
|
||||
| T_START_HEREDOC T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC
|
||||
{ $$ = Scalar\String_[Scalar\String_::parseDocString($1, $2)]; }
|
||||
| T_START_HEREDOC T_END_HEREDOC
|
||||
{ $$ = Scalar\String_['']; }
|
||||
| '"' encaps_list '"'
|
||||
{ parseEncapsed($2, '"', true); $$ = Scalar\Encapsed[$2]; }
|
||||
| T_START_HEREDOC encaps_list T_END_HEREDOC
|
||||
{ parseEncapsedDoc($2, true); $$ = Scalar\Encapsed[$2]; }
|
||||
;
|
||||
|
||||
optional_comma:
|
||||
/* empty */
|
||||
| ','
|
||||
;
|
||||
|
||||
optional_expr:
|
||||
/* empty */ { $$ = null; }
|
||||
| expr { $$ = $1; }
|
||||
;
|
||||
|
||||
dereferencable:
|
||||
variable { $$ = $1; }
|
||||
| '(' expr ')' { $$ = $2; }
|
||||
| dereferencable_scalar { $$ = $1; }
|
||||
;
|
||||
|
||||
callable_expr:
|
||||
callable_variable { $$ = $1; }
|
||||
| '(' expr ')' { $$ = $2; }
|
||||
| dereferencable_scalar { $$ = $1; }
|
||||
;
|
||||
|
||||
callable_variable:
|
||||
simple_variable { $$ = Expr\Variable[$1]; }
|
||||
| dereferencable '[' optional_expr ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
||||
| constant '[' optional_expr ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
||||
| dereferencable '{' expr '}' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
||||
| function_call { $$ = $1; }
|
||||
| dereferencable T_OBJECT_OPERATOR property_name argument_list
|
||||
{ $$ = Expr\MethodCall[$1, $3, $4]; }
|
||||
;
|
||||
|
||||
variable:
|
||||
callable_variable { $$ = $1; }
|
||||
| static_member { $$ = $1; }
|
||||
| dereferencable T_OBJECT_OPERATOR property_name { $$ = Expr\PropertyFetch[$1, $3]; }
|
||||
;
|
||||
|
||||
simple_variable:
|
||||
T_VARIABLE { $$ = parseVar($1); }
|
||||
| '$' '{' expr '}' { $$ = $3; }
|
||||
| '$' simple_variable { $$ = Expr\Variable[$2]; }
|
||||
;
|
||||
|
||||
static_member:
|
||||
class_name_or_var T_PAAMAYIM_NEKUDOTAYIM simple_variable
|
||||
{ $$ = Expr\StaticPropertyFetch[$1, $3]; }
|
||||
;
|
||||
|
||||
new_variable:
|
||||
simple_variable { $$ = Expr\Variable[$1]; }
|
||||
| new_variable '[' optional_expr ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
||||
| new_variable '{' expr '}' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
||||
| new_variable T_OBJECT_OPERATOR property_name { $$ = Expr\PropertyFetch[$1, $3]; }
|
||||
| class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable { $$ = Expr\StaticPropertyFetch[$1, $3]; }
|
||||
| new_variable T_PAAMAYIM_NEKUDOTAYIM simple_variable { $$ = Expr\StaticPropertyFetch[$1, $3]; }
|
||||
;
|
||||
|
||||
member_name:
|
||||
identifier { $$ = $1; }
|
||||
| '{' expr '}' { $$ = $2; }
|
||||
| simple_variable { $$ = Expr\Variable[$1]; }
|
||||
;
|
||||
|
||||
property_name:
|
||||
T_STRING { $$ = $1; }
|
||||
| '{' expr '}' { $$ = $2; }
|
||||
| simple_variable { $$ = Expr\Variable[$1]; }
|
||||
;
|
||||
|
||||
list_expr:
|
||||
T_LIST '(' list_expr_elements ')' { $$ = Expr\List_[$3]; }
|
||||
;
|
||||
|
||||
list_expr_elements:
|
||||
list_expr_elements ',' list_expr_element { push($1, $3); }
|
||||
| list_expr_element { init($1); }
|
||||
;
|
||||
|
||||
list_expr_element:
|
||||
variable { $$ = $1; }
|
||||
| list_expr { $$ = $1; }
|
||||
| /* empty */ { $$ = null; }
|
||||
;
|
||||
|
||||
array_pair_list:
|
||||
/* empty */ { $$ = array(); }
|
||||
| non_empty_array_pair_list optional_comma { $$ = $1; }
|
||||
;
|
||||
|
||||
non_empty_array_pair_list:
|
||||
non_empty_array_pair_list ',' array_pair { push($1, $3); }
|
||||
| array_pair { init($1); }
|
||||
;
|
||||
|
||||
array_pair:
|
||||
expr T_DOUBLE_ARROW expr { $$ = Expr\ArrayItem[$3, $1, false]; }
|
||||
| expr { $$ = Expr\ArrayItem[$1, null, false]; }
|
||||
| expr T_DOUBLE_ARROW '&' variable { $$ = Expr\ArrayItem[$4, $1, true]; }
|
||||
| '&' variable { $$ = Expr\ArrayItem[$2, null, true]; }
|
||||
;
|
||||
|
||||
encaps_list:
|
||||
encaps_list encaps_var { push($1, $2); }
|
||||
| encaps_list T_ENCAPSED_AND_WHITESPACE { push($1, $2); }
|
||||
| encaps_var { init($1); }
|
||||
| T_ENCAPSED_AND_WHITESPACE encaps_var { init($1, $2); }
|
||||
;
|
||||
|
||||
encaps_var:
|
||||
T_VARIABLE { $$ = Expr\Variable[parseVar($1)]; }
|
||||
| T_VARIABLE '[' encaps_var_offset ']' { $$ = Expr\ArrayDimFetch[Expr\Variable[parseVar($1)], $3]; }
|
||||
| T_VARIABLE T_OBJECT_OPERATOR T_STRING { $$ = Expr\PropertyFetch[Expr\Variable[parseVar($1)], $3]; }
|
||||
| T_DOLLAR_OPEN_CURLY_BRACES expr '}' { $$ = Expr\Variable[$2]; }
|
||||
| T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '}' { $$ = Expr\Variable[$2]; }
|
||||
| T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '[' expr ']' '}'
|
||||
{ $$ = Expr\ArrayDimFetch[Expr\Variable[$2], $4]; }
|
||||
| T_CURLY_OPEN variable '}' { $$ = $2; }
|
||||
;
|
||||
|
||||
encaps_var_offset:
|
||||
T_STRING { $$ = Scalar\String_[$1]; }
|
||||
| T_NUM_STRING { $$ = Scalar\String_[$1]; }
|
||||
| T_VARIABLE { $$ = Expr\Variable[parseVar($1)]; }
|
||||
;
|
||||
|
||||
%%
|
@ -1,11 +1,17 @@
|
||||
<?php
|
||||
|
||||
$grammarFile = __DIR__ . '/zend_language_parser.phpy';
|
||||
$skeletonFile = __DIR__ . '/kmyacc.php.parser';
|
||||
$tmpGrammarFile = __DIR__ . '/tmp_parser.phpy';
|
||||
$tmpResultFile = __DIR__ . '/tmp_parser.php';
|
||||
$parserResultFile = __DIR__ . '/../lib/PhpParser/Parser.php';
|
||||
$debugParserResultFile = __DIR__ . '/../lib/PhpParser/Parser/Debug.php';
|
||||
$grammarFileToName = [
|
||||
__DIR__ . '/php5.y' => 'Php5',
|
||||
__DIR__ . '/php7.y' => 'Php7',
|
||||
];
|
||||
|
||||
$tokensFile = __DIR__ . '/tokens.y';
|
||||
$tokensTemplate = __DIR__ . '/tokens.template';
|
||||
$skeletonFile = __DIR__ . '/parser.template';
|
||||
$tmpGrammarFile = __DIR__ . '/tmp_parser.phpy';
|
||||
$tmpResultFile = __DIR__ . '/tmp_parser.php';
|
||||
$resultDir = __DIR__ . '/../lib/PhpParser/Parser';
|
||||
$tokensResultsFile = $resultDir . '/Tokens.php';
|
||||
|
||||
// check for kmyacc.exe binary in this directory, otherwise fall back to global name
|
||||
$kmyacc = __DIR__ . '/kmyacc.exe';
|
||||
@ -36,43 +42,47 @@ const ARGS = '\((?<args>[^()]*+(?:\((?&args)\)[^()]*+)*+)\)';
|
||||
/// Main script ///
|
||||
///////////////////
|
||||
|
||||
echo 'Building temporary preproprocessed grammar file.', "\n";
|
||||
$tokens = file_get_contents($tokensFile);
|
||||
|
||||
$grammarCode = file_get_contents($grammarFile);
|
||||
foreach ($grammarFileToName as $grammarFile => $name) {
|
||||
echo "Building temporary $name grammar file.\n";
|
||||
|
||||
$grammarCode = resolveConstants($grammarCode);
|
||||
$grammarCode = resolveNodes($grammarCode);
|
||||
$grammarCode = resolveMacros($grammarCode);
|
||||
$grammarCode = resolveArrays($grammarCode);
|
||||
$grammarCode = file_get_contents($grammarFile);
|
||||
$grammarCode = str_replace('%tokens', $tokens, $grammarCode);
|
||||
|
||||
file_put_contents($tmpGrammarFile, $grammarCode);
|
||||
$grammarCode = resolveNodes($grammarCode);
|
||||
$grammarCode = resolveMacros($grammarCode);
|
||||
$grammarCode = resolveStackAccess($grammarCode);
|
||||
|
||||
echo "Building parser.\n";
|
||||
$output = trim(shell_exec("$kmyacc -l -m $skeletonFile -p Parser $tmpGrammarFile 2>&1"));
|
||||
echo "Output: \"$output\"\n";
|
||||
file_put_contents($tmpGrammarFile, $grammarCode);
|
||||
|
||||
moveFileWithDirCheck($tmpResultFile, $parserResultFile);
|
||||
$additionalArgs = $optionDebug ? '-t -v' : '';
|
||||
|
||||
if ($optionDebug) {
|
||||
echo "Building debug parser.\n";
|
||||
$output = trim(shell_exec("$kmyacc -t -v -l -m $skeletonFile -p Parser $tmpGrammarFile 2>&1"));
|
||||
echo "Building $name parser.\n";
|
||||
$output = trim(shell_exec("$kmyacc $additionalArgs -l -m $skeletonFile -p $name $tmpGrammarFile 2>&1"));
|
||||
echo "Output: \"$output\"\n";
|
||||
|
||||
moveFileWithDirCheck($tmpResultFile, $debugParserResultFile);
|
||||
}
|
||||
$resultCode = file_get_contents($tmpResultFile);
|
||||
$resultCode = removeTrailingWhitespace($resultCode);
|
||||
|
||||
if (!$optionKeepTmpGrammar) {
|
||||
unlink($tmpGrammarFile);
|
||||
ensureDirExists($resultDir);
|
||||
file_put_contents("$resultDir/$name.php", $resultCode);
|
||||
unlink($tmpResultFile);
|
||||
|
||||
echo "Building token definition.\n";
|
||||
$output = trim(shell_exec("$kmyacc -l -m $tokensTemplate $tmpGrammarFile 2>&1"));
|
||||
assert($output === '');
|
||||
rename($tmpResultFile, $tokensResultsFile);
|
||||
|
||||
if (!$optionKeepTmpGrammar) {
|
||||
unlink($tmpGrammarFile);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
/// Preprocessing functions ///
|
||||
///////////////////////////////
|
||||
|
||||
function resolveConstants($code) {
|
||||
return preg_replace('~[A-Z][a-zA-Z_\\\\]++::~', 'Node\\\\$0', $code);
|
||||
}
|
||||
|
||||
function resolveNodes($code) {
|
||||
return preg_replace_callback(
|
||||
'~(?<name>[A-Z][a-zA-Z_\\\\]++)\s*' . PARAMS . '~',
|
||||
@ -90,7 +100,7 @@ function resolveNodes($code) {
|
||||
$paramCode .= $param . ', ';
|
||||
}
|
||||
|
||||
return 'new Node\\' . $matches['name'] . '(' . $paramCode . '$attributes)';
|
||||
return 'new ' . $matches['name'] . '(' . $paramCode . 'attributes())';
|
||||
},
|
||||
$code
|
||||
);
|
||||
@ -109,10 +119,9 @@ function resolveMacros($code) {
|
||||
$matches['args']
|
||||
);
|
||||
|
||||
if ('error' == $name) {
|
||||
assertArgs(1, $args, $name);
|
||||
|
||||
return 'throw new Error(' . $args[0] . ')';
|
||||
if ('attributes' == $name) {
|
||||
assertArgs(0, $args, $name);
|
||||
return '$this->startAttributeStack[#1] + $this->endAttributes';
|
||||
}
|
||||
|
||||
if ('init' == $name) {
|
||||
@ -128,7 +137,8 @@ function resolveMacros($code) {
|
||||
if ('pushNormalizing' == $name) {
|
||||
assertArgs(2, $args, $name);
|
||||
|
||||
return 'if (is_array(' . $args[1] . ')) { $$ = array_merge(' . $args[0] . ', ' . $args[1] . '); } else { ' . $args[0] . '[] = ' . $args[1] . '; $$ = ' . $args[0] . '; }';
|
||||
return 'if (is_array(' . $args[1] . ')) { $$ = array_merge(' . $args[0] . ', ' . $args[1] . '); }'
|
||||
. ' else { ' . $args[0] . '[] = ' . $args[1] . '; $$ = ' . $args[0] . '; }';
|
||||
}
|
||||
|
||||
if ('toArray' == $name) {
|
||||
@ -144,18 +154,22 @@ function resolveMacros($code) {
|
||||
}
|
||||
|
||||
if ('parseEncapsed' == $name) {
|
||||
assertArgs(2, $args, $name);
|
||||
assertArgs(3, $args, $name);
|
||||
|
||||
return 'foreach (' . $args[0] . ' as &$s) { if (is_string($s)) { $s = Node\Scalar\String::parseEscapeSequences($s, ' . $args[1] . '); } }';
|
||||
return 'foreach (' . $args[0] . ' as &$s) { if (is_string($s)) {'
|
||||
. ' $s = Node\Scalar\String_::parseEscapeSequences($s, ' . $args[1] . ', ' . $args[2] . '); } }';
|
||||
}
|
||||
|
||||
if ('parseEncapsedDoc' == $name) {
|
||||
assertArgs(1, $args, $name);
|
||||
assertArgs(2, $args, $name);
|
||||
|
||||
return 'foreach (' . $args[0] . ' as &$s) { if (is_string($s)) { $s = Node\Scalar\String::parseEscapeSequences($s, null); } } $s = preg_replace(\'~(\r\n|\n|\r)$~\', \'\', $s); if (\'\' === $s) array_pop(' . $args[0] . ');';
|
||||
return 'foreach (' . $args[0] . ' as &$s) { if (is_string($s)) {'
|
||||
. ' $s = Node\Scalar\String_::parseEscapeSequences($s, null, ' . $args[1] . '); } }'
|
||||
. ' $s = preg_replace(\'~(\r\n|\n|\r)$~\', \'\', $s);'
|
||||
. ' if (\'\' === $s) array_pop(' . $args[0] . ');';
|
||||
}
|
||||
|
||||
throw new Exception(sprintf('Unknown macro "%s"', $name));
|
||||
return $matches[0];
|
||||
},
|
||||
$code
|
||||
);
|
||||
@ -167,43 +181,22 @@ function assertArgs($num, $args, $name) {
|
||||
}
|
||||
}
|
||||
|
||||
function resolveArrays($code) {
|
||||
return preg_replace_callback(
|
||||
'~' . PARAMS . '~',
|
||||
function ($matches) {
|
||||
$elements = magicSplit(
|
||||
'(?:' . PARAMS . '|' . ARGS . ')(*SKIP)(*FAIL)|,',
|
||||
$matches['params']
|
||||
);
|
||||
|
||||
// don't convert [] to array, it might have different meaning
|
||||
if (empty($elements)) {
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
$elementCodes = array();
|
||||
foreach ($elements as $element) {
|
||||
// convert only arrays where all elements have keys
|
||||
if (false === strpos($element, ':')) {
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
list($key, $value) = explode(':', $element, 2);
|
||||
$elementCodes[] = "'" . $key . "' =>" . $value;
|
||||
}
|
||||
|
||||
return 'array(' . implode(', ', $elementCodes) . ')';
|
||||
},
|
||||
$code
|
||||
);
|
||||
function resolveStackAccess($code) {
|
||||
$code = preg_replace('/\$\d+/', '$this->semStack[$0]', $code);
|
||||
$code = preg_replace('/#(\d+)/', '$$1', $code);
|
||||
return $code;
|
||||
}
|
||||
|
||||
function moveFileWithDirCheck($fromPath, $toPath) {
|
||||
$dir = dirname($toPath);
|
||||
function removeTrailingWhitespace($code) {
|
||||
$lines = explode("\n", $code);
|
||||
$lines = array_map('rtrim', $lines);
|
||||
return implode("\n", $lines);
|
||||
}
|
||||
|
||||
function ensureDirExists($dir) {
|
||||
if (!is_dir($dir)) {
|
||||
mkdir($dir, 0777, true);
|
||||
}
|
||||
rename($fromPath, $toPath);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
@ -221,5 +214,9 @@ function magicSplit($regex, $string) {
|
||||
$piece = trim($piece);
|
||||
}
|
||||
|
||||
return array_filter($pieces);
|
||||
if ($pieces === ['']) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $pieces;
|
||||
}
|
17
grammar/tokens.template
Normal file
17
grammar/tokens.template
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
$meta #
|
||||
#semval($) $this->semValue
|
||||
#semval($,%t) $this->semValue
|
||||
#semval(%n) $this->stackPos-(%l-%n)
|
||||
#semval(%n,%t) $this->stackPos-(%l-%n)
|
||||
|
||||
namespace PhpParser\Parser;
|
||||
#include;
|
||||
|
||||
/* GENERATED file based on grammar/tokens.y */
|
||||
final class Tokens
|
||||
{
|
||||
#tokenval
|
||||
const %s = %n;
|
||||
#endtokenval
|
||||
}
|
113
grammar/tokens.y
Normal file
113
grammar/tokens.y
Normal file
@ -0,0 +1,113 @@
|
||||
/* We currently rely on the token ID mapping to be the same between PHP 5 and PHP 7 - so the same lexer can be used for
|
||||
* both. This is enforced by sharing this token file. */
|
||||
|
||||
%left T_INCLUDE T_INCLUDE_ONCE T_EVAL T_REQUIRE T_REQUIRE_ONCE
|
||||
%left ','
|
||||
%left T_LOGICAL_OR
|
||||
%left T_LOGICAL_XOR
|
||||
%left T_LOGICAL_AND
|
||||
%right T_PRINT
|
||||
%right T_YIELD
|
||||
%right T_DOUBLE_ARROW
|
||||
%right T_YIELD_FROM
|
||||
%left '=' T_PLUS_EQUAL T_MINUS_EQUAL T_MUL_EQUAL T_DIV_EQUAL T_CONCAT_EQUAL T_MOD_EQUAL T_AND_EQUAL T_OR_EQUAL T_XOR_EQUAL T_SL_EQUAL T_SR_EQUAL T_POW_EQUAL
|
||||
%left '?' ':'
|
||||
%right T_COALESCE
|
||||
%left T_BOOLEAN_OR
|
||||
%left T_BOOLEAN_AND
|
||||
%left '|'
|
||||
%left '^'
|
||||
%left '&'
|
||||
%nonassoc T_IS_EQUAL T_IS_NOT_EQUAL T_IS_IDENTICAL T_IS_NOT_IDENTICAL T_SPACESHIP
|
||||
%nonassoc '<' T_IS_SMALLER_OR_EQUAL '>' T_IS_GREATER_OR_EQUAL
|
||||
%left T_SL T_SR
|
||||
%left '+' '-' '.'
|
||||
%left '*' '/' '%'
|
||||
%right '!'
|
||||
%nonassoc T_INSTANCEOF
|
||||
%right '~' T_INC T_DEC T_INT_CAST T_DOUBLE_CAST T_STRING_CAST T_ARRAY_CAST T_OBJECT_CAST T_BOOL_CAST T_UNSET_CAST '@'
|
||||
%right T_POW
|
||||
%right '['
|
||||
%nonassoc T_NEW T_CLONE
|
||||
%token T_EXIT
|
||||
%token T_IF
|
||||
%left T_ELSEIF
|
||||
%left T_ELSE
|
||||
%left T_ENDIF
|
||||
%token T_LNUMBER
|
||||
%token T_DNUMBER
|
||||
%token T_STRING
|
||||
%token T_STRING_VARNAME
|
||||
%token T_VARIABLE
|
||||
%token T_NUM_STRING
|
||||
%token T_INLINE_HTML
|
||||
%token T_CHARACTER
|
||||
%token T_BAD_CHARACTER
|
||||
%token T_ENCAPSED_AND_WHITESPACE
|
||||
%token T_CONSTANT_ENCAPSED_STRING
|
||||
%token T_ECHO
|
||||
%token T_DO
|
||||
%token T_WHILE
|
||||
%token T_ENDWHILE
|
||||
%token T_FOR
|
||||
%token T_ENDFOR
|
||||
%token T_FOREACH
|
||||
%token T_ENDFOREACH
|
||||
%token T_DECLARE
|
||||
%token T_ENDDECLARE
|
||||
%token T_AS
|
||||
%token T_SWITCH
|
||||
%token T_ENDSWITCH
|
||||
%token T_CASE
|
||||
%token T_DEFAULT
|
||||
%token T_BREAK
|
||||
%token T_CONTINUE
|
||||
%token T_GOTO
|
||||
%token T_FUNCTION
|
||||
%token T_CONST
|
||||
%token T_RETURN
|
||||
%token T_TRY
|
||||
%token T_CATCH
|
||||
%token T_FINALLY
|
||||
%token T_THROW
|
||||
%token T_USE
|
||||
%token T_INSTEADOF
|
||||
%token T_GLOBAL
|
||||
%right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC
|
||||
%token T_VAR
|
||||
%token T_UNSET
|
||||
%token T_ISSET
|
||||
%token T_EMPTY
|
||||
%token T_HALT_COMPILER
|
||||
%token T_CLASS
|
||||
%token T_TRAIT
|
||||
%token T_INTERFACE
|
||||
%token T_EXTENDS
|
||||
%token T_IMPLEMENTS
|
||||
%token T_OBJECT_OPERATOR
|
||||
%token T_DOUBLE_ARROW
|
||||
%token T_LIST
|
||||
%token T_ARRAY
|
||||
%token T_CALLABLE
|
||||
%token T_CLASS_C
|
||||
%token T_TRAIT_C
|
||||
%token T_METHOD_C
|
||||
%token T_FUNC_C
|
||||
%token T_LINE
|
||||
%token T_FILE
|
||||
%token T_COMMENT
|
||||
%token T_DOC_COMMENT
|
||||
%token T_OPEN_TAG
|
||||
%token T_OPEN_TAG_WITH_ECHO
|
||||
%token T_CLOSE_TAG
|
||||
%token T_WHITESPACE
|
||||
%token T_START_HEREDOC
|
||||
%token T_END_HEREDOC
|
||||
%token T_DOLLAR_OPEN_CURLY_BRACES
|
||||
%token T_CURLY_OPEN
|
||||
%token T_PAAMAYIM_NEKUDOTAYIM
|
||||
%token T_NAMESPACE
|
||||
%token T_NS_C
|
||||
%token T_DIR
|
||||
%token T_NS_SEPARATOR
|
||||
%token T_ELLIPSIS
|
@ -7,14 +7,21 @@ namespace PhpParser;
|
||||
*/
|
||||
class Autoloader
|
||||
{
|
||||
/** @var bool Whether the autoloader has been registered. */
|
||||
private static $registered = false;
|
||||
|
||||
/**
|
||||
* Registers PhpParser\Autoloader as an SPL autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader instead of appending
|
||||
*/
|
||||
static public function register($prepend = false) {
|
||||
ini_set('unserialize_callback_func', 'spl_autoload_call');
|
||||
if (self::$registered === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend);
|
||||
self::$registered = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -24,207 +31,10 @@ class Autoloader
|
||||
*/
|
||||
static public function autoload($class) {
|
||||
if (0 === strpos($class, 'PhpParser\\')) {
|
||||
$fileName = dirname(__DIR__) . '/' . rtrim(strtr($class, '\\', '/'), '_') . '.php';
|
||||
require $fileName;
|
||||
} else if (0 === strpos($class, 'PHPParser_')) {
|
||||
if (isset(self::$oldToNewMap[$class])) {
|
||||
self::registerLegacyAliases();
|
||||
$fileName = dirname(__DIR__) . '/' . strtr($class, '\\', '/') . '.php';
|
||||
if (file_exists($fileName)) {
|
||||
require $fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function registerLegacyAliases() {
|
||||
foreach (self::$oldToNewMap as $old => $new) {
|
||||
class_alias($new, $old);
|
||||
}
|
||||
}
|
||||
|
||||
private static $oldToNewMap = array(
|
||||
'PHPParser_Builder' => 'PhpParser\Builder',
|
||||
'PHPParser_BuilderAbstract' => 'PhpParser\BuilderAbstract',
|
||||
'PHPParser_BuilderFactory' => 'PhpParser\BuilderFactory',
|
||||
'PHPParser_Comment' => 'PhpParser\Comment',
|
||||
'PHPParser_Comment_Doc' => 'PhpParser\Comment\Doc',
|
||||
'PHPParser_Error' => 'PhpParser\Error',
|
||||
'PHPParser_Lexer' => 'PhpParser\Lexer',
|
||||
'PHPParser_Lexer_Emulative' => 'PhpParser\Lexer\Emulative',
|
||||
'PHPParser_Node' => 'PhpParser\Node',
|
||||
'PHPParser_NodeAbstract' => 'PhpParser\NodeAbstract',
|
||||
'PHPParser_NodeDumper' => 'PhpParser\NodeDumper',
|
||||
'PHPParser_NodeTraverser' => 'PhpParser\NodeTraverser',
|
||||
'PHPParser_NodeTraverserInterface' => 'PhpParser\NodeTraverserInterface',
|
||||
'PHPParser_NodeVisitor' => 'PhpParser\NodeVisitor',
|
||||
'PHPParser_NodeVisitor_NameResolver' => 'PhpParser\NodeVisitor\NameResolver',
|
||||
'PHPParser_NodeVisitorAbstract' => 'PhpParser\NodeVisitorAbstract',
|
||||
'PHPParser_Parser' => 'PhpParser\Parser',
|
||||
'PHPParser_PrettyPrinterAbstract' => 'PhpParser\PrettyPrinterAbstract',
|
||||
'PHPParser_PrettyPrinter_Default' => 'PhpParser\PrettyPrinter\Standard',
|
||||
'PHPParser_PrettyPrinter_Zend' => 'PhpParser\PrettyPrinter\Standard',
|
||||
'PHPParser_Serializer' => 'PhpParser\Serializer',
|
||||
'PHPParser_Serializer_XML' => 'PhpParser\Serializer\XML',
|
||||
'PHPParser_Template' => 'PhpParser\Template',
|
||||
'PHPParser_TemplateLoader' => 'PhpParser\TemplateLoader',
|
||||
'PHPParser_Unserializer' => 'PhpParser\Unserializer',
|
||||
'PHPParser_Unserializer_XML' => 'PhpParser\Unserializer\XML',
|
||||
|
||||
'PHPParser_Builder_Class' => 'PhpParser\Builder\Class_',
|
||||
'PHPParser_Builder_Function' => 'PhpParser\Builder\Function_',
|
||||
'PHPParser_Builder_Interface' => 'PhpParser\Builder\Interface_',
|
||||
'PHPParser_Builder_Method' => 'PhpParser\Builder\Method',
|
||||
'PHPParser_Builder_Param' => 'PhpParser\Builder\Param',
|
||||
'PHPParser_Builder_Property' => 'PhpParser\Builder\Property',
|
||||
|
||||
'PHPParser_Node_Arg' => 'PhpParser\Node\Arg',
|
||||
'PHPParser_Node_Const' => 'PhpParser\Node\Const_',
|
||||
'PHPParser_Node_Expr' => 'PhpParser\Node\Expr',
|
||||
'PHPParser_Node_Name' => 'PhpParser\Node\Name',
|
||||
'PHPParser_Node_Name_FullyQualified' => 'PhpParser\Node\Name\FullyQualified',
|
||||
'PHPParser_Node_Name_Relative' => 'PhpParser\Node\Name\Relative',
|
||||
'PHPParser_Node_Param' => 'PhpParser\Node\Param',
|
||||
'PHPParser_Node_Scalar' => 'PhpParser\Node\Scalar',
|
||||
'PHPParser_Node_Stmt' => 'PhpParser\Node\Stmt',
|
||||
|
||||
'PHPParser_Node_Stmt_Break' => 'PhpParser\Node\Stmt\Break_',
|
||||
'PHPParser_Node_Stmt_Case' => 'PhpParser\Node\Stmt\Case_',
|
||||
'PHPParser_Node_Stmt_Catch' => 'PhpParser\Node\Stmt\Catch_',
|
||||
'PHPParser_Node_Stmt_Class' => 'PhpParser\Node\Stmt\Class_',
|
||||
'PHPParser_Node_Stmt_ClassConst' => 'PhpParser\Node\Stmt\ClassConst',
|
||||
'PHPParser_Node_Stmt_ClassMethod' => 'PhpParser\Node\Stmt\ClassMethod',
|
||||
'PHPParser_Node_Stmt_Const' => 'PhpParser\Node\Stmt\Const_',
|
||||
'PHPParser_Node_Stmt_Continue' => 'PhpParser\Node\Stmt\Continue_',
|
||||
'PHPParser_Node_Stmt_Declare' => 'PhpParser\Node\Stmt\Declare_',
|
||||
'PHPParser_Node_Stmt_DeclareDeclare' => 'PhpParser\Node\Stmt\DeclareDeclare',
|
||||
'PHPParser_Node_Stmt_Do' => 'PhpParser\Node\Stmt\Do_',
|
||||
'PHPParser_Node_Stmt_Echo' => 'PhpParser\Node\Stmt\Echo_',
|
||||
'PHPParser_Node_Stmt_Else' => 'PhpParser\Node\Stmt\Else_',
|
||||
'PHPParser_Node_Stmt_ElseIf' => 'PhpParser\Node\Stmt\ElseIf_',
|
||||
'PHPParser_Node_Stmt_For' => 'PhpParser\Node\Stmt\For_',
|
||||
'PHPParser_Node_Stmt_Foreach' => 'PhpParser\Node\Stmt\Foreach_',
|
||||
'PHPParser_Node_Stmt_Function' => 'PhpParser\Node\Stmt\Function_',
|
||||
'PHPParser_Node_Stmt_Global' => 'PhpParser\Node\Stmt\Global_',
|
||||
'PHPParser_Node_Stmt_Goto' => 'PhpParser\Node\Stmt\Goto_',
|
||||
'PHPParser_Node_Stmt_HaltCompiler' => 'PhpParser\Node\Stmt\HaltCompiler',
|
||||
'PHPParser_Node_Stmt_If' => 'PhpParser\Node\Stmt\If_',
|
||||
'PHPParser_Node_Stmt_InlineHTML' => 'PhpParser\Node\Stmt\InlineHTML',
|
||||
'PHPParser_Node_Stmt_Interface' => 'PhpParser\Node\Stmt\Interface_',
|
||||
'PHPParser_Node_Stmt_Label' => 'PhpParser\Node\Stmt\Label',
|
||||
'PHPParser_Node_Stmt_Namespace' => 'PhpParser\Node\Stmt\Namespace_',
|
||||
'PHPParser_Node_Stmt_Property' => 'PhpParser\Node\Stmt\Property',
|
||||
'PHPParser_Node_Stmt_PropertyProperty' => 'PhpParser\Node\Stmt\PropertyProperty',
|
||||
'PHPParser_Node_Stmt_Return' => 'PhpParser\Node\Stmt\Return_',
|
||||
'PHPParser_Node_Stmt_Static' => 'PhpParser\Node\Stmt\Static_',
|
||||
'PHPParser_Node_Stmt_StaticVar' => 'PhpParser\Node\Stmt\StaticVar',
|
||||
'PHPParser_Node_Stmt_Switch' => 'PhpParser\Node\Stmt\Switch_',
|
||||
'PHPParser_Node_Stmt_Throw' => 'PhpParser\Node\Stmt\Throw_',
|
||||
'PHPParser_Node_Stmt_Trait' => 'PhpParser\Node\Stmt\Trait_',
|
||||
'PHPParser_Node_Stmt_TraitUse' => 'PhpParser\Node\Stmt\TraitUse',
|
||||
'PHPParser_Node_Stmt_TraitUseAdaptation' => 'PhpParser\Node\Stmt\TraitUseAdaptation',
|
||||
'PHPParser_Node_Stmt_TraitUseAdaptation_Alias' => 'PhpParser\Node\Stmt\TraitUseAdaptation\Alias',
|
||||
'PHPParser_Node_Stmt_TraitUseAdaptation_Precedence' => 'PhpParser\Node\Stmt\TraitUseAdaptation\Precedence',
|
||||
'PHPParser_Node_Stmt_TryCatch' => 'PhpParser\Node\Stmt\TryCatch',
|
||||
'PHPParser_Node_Stmt_Unset' => 'PhpParser\Node\Stmt\Unset_',
|
||||
'PHPParser_Node_Stmt_UseUse' => 'PhpParser\Node\Stmt\UseUse',
|
||||
'PHPParser_Node_Stmt_Use' => 'PhpParser\Node\Stmt\Use_',
|
||||
'PHPParser_Node_Stmt_While' => 'PhpParser\Node\Stmt\While_',
|
||||
|
||||
'PHPParser_Node_Expr_AssignBitwiseAnd' => 'PhpParser\Node\Expr\AssignOp\BitwiseAnd',
|
||||
'PHPParser_Node_Expr_AssignBitwiseOr' => 'PhpParser\Node\Expr\AssignOp\BitwiseOr',
|
||||
'PHPParser_Node_Expr_AssignBitwiseXor' => 'PhpParser\Node\Expr\AssignOp\BitwiseXor',
|
||||
'PHPParser_Node_Expr_AssignConcat' => 'PhpParser\Node\Expr\AssignOp\Concat',
|
||||
'PHPParser_Node_Expr_AssignDiv' => 'PhpParser\Node\Expr\AssignOp\Div',
|
||||
'PHPParser_Node_Expr_AssignMinus' => 'PhpParser\Node\Expr\AssignOp\Minus',
|
||||
'PHPParser_Node_Expr_AssignMod' => 'PhpParser\Node\Expr\AssignOp\Mod',
|
||||
'PHPParser_Node_Expr_AssignMul' => 'PhpParser\Node\Expr\AssignOp\Mul',
|
||||
'PHPParser_Node_Expr_AssignPlus' => 'PhpParser\Node\Expr\AssignOp\Plus',
|
||||
'PHPParser_Node_Expr_AssignShiftLeft' => 'PhpParser\Node\Expr\AssignOp\ShiftLeft',
|
||||
'PHPParser_Node_Expr_AssignShiftRight' => 'PhpParser\Node\Expr\AssignOp\ShiftRight',
|
||||
|
||||
'PHPParser_Node_Expr_Cast' => 'PhpParser\Node\Expr\Cast',
|
||||
'PHPParser_Node_Expr_Cast_Array' => 'PhpParser\Node\Expr\Cast\Array_',
|
||||
'PHPParser_Node_Expr_Cast_Bool' => 'PhpParser\Node\Expr\Cast\Bool',
|
||||
'PHPParser_Node_Expr_Cast_Double' => 'PhpParser\Node\Expr\Cast\Double',
|
||||
'PHPParser_Node_Expr_Cast_Int' => 'PhpParser\Node\Expr\Cast\Int',
|
||||
'PHPParser_Node_Expr_Cast_Object' => 'PhpParser\Node\Expr\Cast\Object',
|
||||
'PHPParser_Node_Expr_Cast_String' => 'PhpParser\Node\Expr\Cast\String',
|
||||
'PHPParser_Node_Expr_Cast_Unset' => 'PhpParser\Node\Expr\Cast\Unset_',
|
||||
|
||||
'PHPParser_Node_Expr_BitwiseAnd' => 'PhpParser\Node\Expr\BinaryOp\BitwiseAnd',
|
||||
'PHPParser_Node_Expr_BitwiseOr' => 'PhpParser\Node\Expr\BinaryOp\BitwiseOr',
|
||||
'PHPParser_Node_Expr_BitwiseXor' => 'PhpParser\Node\Expr\BinaryOp\BitwiseXor',
|
||||
'PHPParser_Node_Expr_BooleanAnd' => 'PhpParser\Node\Expr\BinaryOp\BooleanAnd',
|
||||
'PHPParser_Node_Expr_BooleanOr' => 'PhpParser\Node\Expr\BinaryOp\BooleanOr',
|
||||
'PHPParser_Node_Expr_Concat' => 'PhpParser\Node\Expr\BinaryOp\Concat',
|
||||
'PHPParser_Node_Expr_Div' => 'PhpParser\Node\Expr\BinaryOp\Div',
|
||||
'PHPParser_Node_Expr_Equal' => 'PhpParser\Node\Expr\BinaryOp\Equal',
|
||||
'PHPParser_Node_Expr_Greater' => 'PhpParser\Node\Expr\BinaryOp\Greater',
|
||||
'PHPParser_Node_Expr_GreaterOrEqual' => 'PhpParser\Node\Expr\BinaryOp\GreaterOrEqual',
|
||||
'PHPParser_Node_Expr_Identical' => 'PhpParser\Node\Expr\BinaryOp\Identical',
|
||||
'PHPParser_Node_Expr_LogicalAnd' => 'PhpParser\Node\Expr\BinaryOp\LogicalAnd',
|
||||
'PHPParser_Node_Expr_LogicalOr' => 'PhpParser\Node\Expr\BinaryOp\LogicalOr',
|
||||
'PHPParser_Node_Expr_LogicalXor' => 'PhpParser\Node\Expr\BinaryOp\LogicalXor',
|
||||
'PHPParser_Node_Expr_Minus' => 'PhpParser\Node\Expr\BinaryOp\Minus',
|
||||
'PHPParser_Node_Expr_Mod' => 'PhpParser\Node\Expr\BinaryOp\Mod',
|
||||
'PHPParser_Node_Expr_Mul' => 'PhpParser\Node\Expr\BinaryOp\Mul',
|
||||
'PHPParser_Node_Expr_NotEqual' => 'PhpParser\Node\Expr\BinaryOp\NotEqual',
|
||||
'PHPParser_Node_Expr_NotIdentical' => 'PhpParser\Node\Expr\BinaryOp\NotIdentical',
|
||||
'PHPParser_Node_Expr_Plus' => 'PhpParser\Node\Expr\BinaryOp\Plus',
|
||||
'PHPParser_Node_Expr_ShiftLeft' => 'PhpParser\Node\Expr\BinaryOp\ShiftLeft',
|
||||
'PHPParser_Node_Expr_ShiftRight' => 'PhpParser\Node\Expr\BinaryOp\ShiftRight',
|
||||
'PHPParser_Node_Expr_Smaller' => 'PhpParser\Node\Expr\BinaryOp\Smaller',
|
||||
'PHPParser_Node_Expr_SmallerOrEqual' => 'PhpParser\Node\Expr\BinaryOp\SmallerOrEqual',
|
||||
|
||||
'PHPParser_Node_Expr_Array' => 'PhpParser\Node\Expr\Array_',
|
||||
'PHPParser_Node_Expr_ArrayDimFetch' => 'PhpParser\Node\Expr\ArrayDimFetch',
|
||||
'PHPParser_Node_Expr_ArrayItem' => 'PhpParser\Node\Expr\ArrayItem',
|
||||
'PHPParser_Node_Expr_Assign' => 'PhpParser\Node\Expr\Assign',
|
||||
'PHPParser_Node_Expr_AssignRef' => 'PhpParser\Node\Expr\AssignRef',
|
||||
'PHPParser_Node_Expr_BitwiseNot' => 'PhpParser\Node\Expr\BitwiseNot',
|
||||
'PHPParser_Node_Expr_BooleanNot' => 'PhpParser\Node\Expr\BooleanNot',
|
||||
'PHPParser_Node_Expr_ClassConstFetch' => 'PhpParser\Node\Expr\ClassConstFetch',
|
||||
'PHPParser_Node_Expr_Clone' => 'PhpParser\Node\Expr\Clone_',
|
||||
'PHPParser_Node_Expr_Closure' => 'PhpParser\Node\Expr\Closure',
|
||||
'PHPParser_Node_Expr_ClosureUse' => 'PhpParser\Node\Expr\ClosureUse',
|
||||
'PHPParser_Node_Expr_ConstFetch' => 'PhpParser\Node\Expr\ConstFetch',
|
||||
'PHPParser_Node_Expr_Empty' => 'PhpParser\Node\Expr\Empty_',
|
||||
'PHPParser_Node_Expr_ErrorSuppress' => 'PhpParser\Node\Expr\ErrorSuppress',
|
||||
'PHPParser_Node_Expr_Eval' => 'PhpParser\Node\Expr\Eval_',
|
||||
'PHPParser_Node_Expr_Exit' => 'PhpParser\Node\Expr\Exit_',
|
||||
'PHPParser_Node_Expr_FuncCall' => 'PhpParser\Node\Expr\FuncCall',
|
||||
'PHPParser_Node_Expr_Include' => 'PhpParser\Node\Expr\Include_',
|
||||
'PHPParser_Node_Expr_Instanceof' => 'PhpParser\Node\Expr\Instanceof_',
|
||||
'PHPParser_Node_Expr_Isset' => 'PhpParser\Node\Expr\Isset_',
|
||||
'PHPParser_Node_Expr_List' => 'PhpParser\Node\Expr\List_',
|
||||
'PHPParser_Node_Expr_MethodCall' => 'PhpParser\Node\Expr\MethodCall',
|
||||
'PHPParser_Node_Expr_New' => 'PhpParser\Node\Expr\New_',
|
||||
'PHPParser_Node_Expr_PostDec' => 'PhpParser\Node\Expr\PostDec',
|
||||
'PHPParser_Node_Expr_PostInc' => 'PhpParser\Node\Expr\PostInc',
|
||||
'PHPParser_Node_Expr_PreDec' => 'PhpParser\Node\Expr\PreDec',
|
||||
'PHPParser_Node_Expr_PreInc' => 'PhpParser\Node\Expr\PreInc',
|
||||
'PHPParser_Node_Expr_Print' => 'PhpParser\Node\Expr\Print_',
|
||||
'PHPParser_Node_Expr_PropertyFetch' => 'PhpParser\Node\Expr\PropertyFetch',
|
||||
'PHPParser_Node_Expr_ShellExec' => 'PhpParser\Node\Expr\ShellExec',
|
||||
'PHPParser_Node_Expr_StaticCall' => 'PhpParser\Node\Expr\StaticCall',
|
||||
'PHPParser_Node_Expr_StaticPropertyFetch' => 'PhpParser\Node\Expr\StaticPropertyFetch',
|
||||
'PHPParser_Node_Expr_Ternary' => 'PhpParser\Node\Expr\Ternary',
|
||||
'PHPParser_Node_Expr_UnaryMinus' => 'PhpParser\Node\Expr\UnaryMinus',
|
||||
'PHPParser_Node_Expr_UnaryPlus' => 'PhpParser\Node\Expr\UnaryPlus',
|
||||
'PHPParser_Node_Expr_Variable' => 'PhpParser\Node\Expr\Variable',
|
||||
'PHPParser_Node_Expr_Yield' => 'PhpParser\Node\Expr\Yield_',
|
||||
|
||||
'PHPParser_Node_Scalar_ClassConst' => 'PhpParser\Node\Scalar\MagicConst\Class_',
|
||||
'PHPParser_Node_Scalar_DirConst' => 'PhpParser\Node\Scalar\MagicConst\Dir',
|
||||
'PHPParser_Node_Scalar_FileConst' => 'PhpParser\Node\Scalar\MagicConst\File',
|
||||
'PHPParser_Node_Scalar_FuncConst' => 'PhpParser\Node\Scalar\MagicConst\Function_',
|
||||
'PHPParser_Node_Scalar_LineConst' => 'PhpParser\Node\Scalar\MagicConst\Line',
|
||||
'PHPParser_Node_Scalar_MethodConst' => 'PhpParser\Node\Scalar\MagicConst\Method',
|
||||
'PHPParser_Node_Scalar_NSConst' => 'PhpParser\Node\Scalar\MagicConst\Namespace_',
|
||||
'PHPParser_Node_Scalar_TraitConst' => 'PhpParser\Node\Scalar\MagicConst\Trait_',
|
||||
|
||||
'PHPParser_Node_Scalar_DNumber' => 'PhpParser\Node\Scalar\DNumber',
|
||||
'PHPParser_Node_Scalar_Encapsed' => 'PhpParser\Node\Scalar\Encapsed',
|
||||
'PHPParser_Node_Scalar_LNumber' => 'PhpParser\Node\Scalar\LNumber',
|
||||
'PHPParser_Node_Scalar_String' => 'PhpParser\Node\Scalar\String',
|
||||
);
|
||||
}
|
||||
|
||||
class_alias('PhpParser\Autoloader', 'PHPParser_Autoloader');
|
@ -6,18 +6,18 @@ use PhpParser;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt;
|
||||
|
||||
class Class_ extends PhpParser\BuilderAbstract
|
||||
class Class_ extends Declaration
|
||||
{
|
||||
protected $name;
|
||||
|
||||
protected $extends;
|
||||
protected $implements;
|
||||
protected $type;
|
||||
protected $extends = null;
|
||||
protected $implements = array();
|
||||
protected $type = 0;
|
||||
|
||||
protected $uses;
|
||||
protected $constants;
|
||||
protected $properties;
|
||||
protected $methods;
|
||||
protected $uses = array();
|
||||
protected $constants = array();
|
||||
protected $properties = array();
|
||||
protected $methods = array();
|
||||
|
||||
/**
|
||||
* Creates a class builder.
|
||||
@ -26,12 +26,6 @@ class Class_ extends PhpParser\BuilderAbstract
|
||||
*/
|
||||
public function __construct($name) {
|
||||
$this->name = $name;
|
||||
|
||||
$this->type = 0;
|
||||
$this->extends = null;
|
||||
$this->implements = array();
|
||||
|
||||
$this->uses = $this->constants = $this->properties = $this->methods = array();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -39,7 +33,7 @@ class Class_ extends PhpParser\BuilderAbstract
|
||||
*
|
||||
* @param Name|string $class Name of class to extend
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function extend($class) {
|
||||
$this->extends = $this->normalizeName($class);
|
||||
@ -53,7 +47,7 @@ class Class_ extends PhpParser\BuilderAbstract
|
||||
* @param Name|string $interface Name of interface to implement
|
||||
* @param Name|string $... More interfaces to implement
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function implement() {
|
||||
foreach (func_get_args() as $interface) {
|
||||
@ -66,7 +60,7 @@ class Class_ extends PhpParser\BuilderAbstract
|
||||
/**
|
||||
* Makes the class abstract.
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makeAbstract() {
|
||||
$this->setModifier(Stmt\Class_::MODIFIER_ABSTRACT);
|
||||
@ -77,7 +71,7 @@ class Class_ extends PhpParser\BuilderAbstract
|
||||
/**
|
||||
* Makes the class final.
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makeFinal() {
|
||||
$this->setModifier(Stmt\Class_::MODIFIER_FINAL);
|
||||
@ -90,7 +84,7 @@ class Class_ extends PhpParser\BuilderAbstract
|
||||
*
|
||||
* @param Stmt|PhpParser\Builder $stmt The statement to add
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function addStmt($stmt) {
|
||||
$stmt = $this->normalizeNode($stmt);
|
||||
@ -112,21 +106,6 @@ class Class_ extends PhpParser\BuilderAbstract
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple statements.
|
||||
*
|
||||
* @param array $stmts The statements to add
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
*/
|
||||
public function addStmts(array $stmts) {
|
||||
foreach ($stmts as $stmt) {
|
||||
$this->addStmt($stmt);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the built class node.
|
||||
*
|
||||
@ -138,6 +117,6 @@ class Class_ extends PhpParser\BuilderAbstract
|
||||
'extends' => $this->extends,
|
||||
'implements' => $this->implements,
|
||||
'stmts' => array_merge($this->uses, $this->constants, $this->properties, $this->methods),
|
||||
));
|
||||
), $this->attributes);
|
||||
}
|
||||
}
|
44
lib/PhpParser/Builder/Declaration.php
Normal file
44
lib/PhpParser/Builder/Declaration.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace PhpParser\Builder;
|
||||
|
||||
use PhpParser;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt;
|
||||
|
||||
abstract class Declaration extends PhpParser\BuilderAbstract
|
||||
{
|
||||
protected $attributes = array();
|
||||
|
||||
abstract public function addStmt($stmt);
|
||||
|
||||
/**
|
||||
* Adds multiple statements.
|
||||
*
|
||||
* @param array $stmts The statements to add
|
||||
*
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function addStmts(array $stmts) {
|
||||
foreach ($stmts as $stmt) {
|
||||
$this->addStmt($stmt);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets doc comment for the declaration.
|
||||
*
|
||||
* @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'] = array(
|
||||
$this->normalizeDocComment($docComment)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace PhpParser\Builder;
|
||||
|
||||
use PhpParser;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt;
|
||||
|
||||
class Function_ extends PhpParser\BuilderAbstract
|
||||
{
|
||||
protected $name;
|
||||
|
||||
protected $returnByRef;
|
||||
protected $params;
|
||||
protected $stmts;
|
||||
|
||||
/**
|
||||
* Creates a function builder.
|
||||
*
|
||||
* @param string $name Name of the function
|
||||
*/
|
||||
public function __construct($name) {
|
||||
$this->name = $name;
|
||||
|
||||
$this->returnByRef = false;
|
||||
$this->params = array();
|
||||
$this->stmts = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the function return by reference.
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makeReturnByRef() {
|
||||
$this->returnByRef = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a parameter.
|
||||
*
|
||||
* @param Node\Param|Param $param The parameter to add
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
*/
|
||||
public function addParam($param) {
|
||||
$param = $this->normalizeNode($param);
|
||||
|
||||
if (!$param instanceof Node\Param) {
|
||||
throw new \LogicException(sprintf('Expected parameter node, got "%s"', $param->getType()));
|
||||
}
|
||||
|
||||
$this->params[] = $param;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple parameters.
|
||||
*
|
||||
* @param array $params The parameters to add
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
*/
|
||||
public function addParams(array $params) {
|
||||
foreach ($params as $param) {
|
||||
$this->addParam($param);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a statement.
|
||||
*
|
||||
* @param Node|PhpParser\Builder $stmt The statement to add
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
*/
|
||||
public function addStmt($stmt) {
|
||||
$this->stmts[] = $this->normalizeNode($stmt);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple statements.
|
||||
*
|
||||
* @param array $stmts The statements to add
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
*/
|
||||
public function addStmts(array $stmts) {
|
||||
foreach ($stmts as $stmt) {
|
||||
$this->addStmt($stmt);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the built function node.
|
||||
*
|
||||
* @return Stmt\Function_ The built function node
|
||||
*/
|
||||
public function getNode() {
|
||||
return new Stmt\Function_($this->name, array(
|
||||
'byRef' => $this->returnByRef,
|
||||
'params' => $this->params,
|
||||
'stmts' => $this->stmts,
|
||||
));
|
||||
}
|
||||
}
|
58
lib/PhpParser/Builder/FunctionLike.php
Normal file
58
lib/PhpParser/Builder/FunctionLike.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace PhpParser\Builder;
|
||||
|
||||
use PhpParser;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt;
|
||||
|
||||
abstract class FunctionLike extends Declaration
|
||||
{
|
||||
protected $returnByRef = false;
|
||||
protected $params = array();
|
||||
|
||||
/**
|
||||
* Make the function return by reference.
|
||||
*
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makeReturnByRef() {
|
||||
$this->returnByRef = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a parameter.
|
||||
*
|
||||
* @param Node\Param|Param $param The parameter to add
|
||||
*
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function addParam($param) {
|
||||
$param = $this->normalizeNode($param);
|
||||
|
||||
if (!$param instanceof Node\Param) {
|
||||
throw new \LogicException(sprintf('Expected parameter node, got "%s"', $param->getType()));
|
||||
}
|
||||
|
||||
$this->params[] = $param;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple parameters.
|
||||
*
|
||||
* @param array $params The parameters to add
|
||||
*
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function addParams(array $params) {
|
||||
foreach ($params as $param) {
|
||||
$this->addParam($param);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
48
lib/PhpParser/Builder/Function_.php
Normal file
48
lib/PhpParser/Builder/Function_.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace PhpParser\Builder;
|
||||
|
||||
use PhpParser;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt;
|
||||
|
||||
class Function_ extends FunctionLike
|
||||
{
|
||||
protected $name;
|
||||
protected $stmts = array();
|
||||
|
||||
/**
|
||||
* Creates a function builder.
|
||||
*
|
||||
* @param string $name Name of the function
|
||||
*/
|
||||
public function __construct($name) {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a statement.
|
||||
*
|
||||
* @param Node|PhpParser\Builder $stmt The statement to add
|
||||
*
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function addStmt($stmt) {
|
||||
$this->stmts[] = $this->normalizeNode($stmt);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the built function node.
|
||||
*
|
||||
* @return Stmt\Function_ The built function node
|
||||
*/
|
||||
public function getNode() {
|
||||
return new Stmt\Function_($this->name, array(
|
||||
'byRef' => $this->returnByRef,
|
||||
'params' => $this->params,
|
||||
'stmts' => $this->stmts,
|
||||
), $this->attributes);
|
||||
}
|
||||
}
|
@ -6,12 +6,12 @@ use PhpParser;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt;
|
||||
|
||||
class Interface_ extends PhpParser\BuilderAbstract
|
||||
class Interface_ extends Declaration
|
||||
{
|
||||
protected $name;
|
||||
protected $extends;
|
||||
protected $constants;
|
||||
protected $methods;
|
||||
protected $extends = array();
|
||||
protected $constants = array();
|
||||
protected $methods = array();
|
||||
|
||||
/**
|
||||
* Creates an interface builder.
|
||||
@ -20,8 +20,6 @@ class Interface_ extends PhpParser\BuilderAbstract
|
||||
*/
|
||||
public function __construct($name) {
|
||||
$this->name = $name;
|
||||
$this->extends = array();
|
||||
$this->constants = $this->methods = array();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -30,7 +28,7 @@ class Interface_ extends PhpParser\BuilderAbstract
|
||||
* @param Name|string $interface Name of interface to extend
|
||||
* @param Name|string $... More interfaces to extend
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function extend() {
|
||||
foreach (func_get_args() as $interface) {
|
||||
@ -45,7 +43,7 @@ class Interface_ extends PhpParser\BuilderAbstract
|
||||
*
|
||||
* @param Stmt|PhpParser\Builder $stmt The statement to add
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function addStmt($stmt) {
|
||||
$stmt = $this->normalizeNode($stmt);
|
||||
@ -70,22 +68,7 @@ class Interface_ extends PhpParser\BuilderAbstract
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple statements.
|
||||
*
|
||||
* @param array $stmts The statements to add
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
*/
|
||||
public function addStmts(array $stmts) {
|
||||
foreach ($stmts as $stmt) {
|
||||
$this->addStmt($stmt);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the built class node.
|
||||
* Returns the built interface node.
|
||||
*
|
||||
* @return Stmt\Interface_ The built interface node
|
||||
*/
|
||||
@ -93,6 +76,6 @@ class Interface_ extends PhpParser\BuilderAbstract
|
||||
return new Stmt\Interface_($this->name, array(
|
||||
'extends' => $this->extends,
|
||||
'stmts' => array_merge($this->constants, $this->methods),
|
||||
));
|
||||
), $this->attributes);
|
||||
}
|
||||
}
|
@ -6,14 +6,11 @@ use PhpParser;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt;
|
||||
|
||||
class Method extends PhpParser\BuilderAbstract
|
||||
class Method extends FunctionLike
|
||||
{
|
||||
protected $name;
|
||||
|
||||
protected $type;
|
||||
protected $returnByRef;
|
||||
protected $params;
|
||||
protected $stmts;
|
||||
protected $type = 0;
|
||||
protected $stmts = array();
|
||||
|
||||
/**
|
||||
* Creates a method builder.
|
||||
@ -22,17 +19,12 @@ class Method extends PhpParser\BuilderAbstract
|
||||
*/
|
||||
public function __construct($name) {
|
||||
$this->name = $name;
|
||||
|
||||
$this->type = 0;
|
||||
$this->returnByRef = false;
|
||||
$this->params = array();
|
||||
$this->stmts = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the method public.
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makePublic() {
|
||||
$this->setModifier(Stmt\Class_::MODIFIER_PUBLIC);
|
||||
@ -43,7 +35,7 @@ class Method extends PhpParser\BuilderAbstract
|
||||
/**
|
||||
* Makes the method protected.
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makeProtected() {
|
||||
$this->setModifier(Stmt\Class_::MODIFIER_PROTECTED);
|
||||
@ -54,7 +46,7 @@ class Method extends PhpParser\BuilderAbstract
|
||||
/**
|
||||
* Makes the method private.
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makePrivate() {
|
||||
$this->setModifier(Stmt\Class_::MODIFIER_PRIVATE);
|
||||
@ -65,7 +57,7 @@ class Method extends PhpParser\BuilderAbstract
|
||||
/**
|
||||
* Makes the method static.
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makeStatic() {
|
||||
$this->setModifier(Stmt\Class_::MODIFIER_STATIC);
|
||||
@ -76,7 +68,7 @@ class Method extends PhpParser\BuilderAbstract
|
||||
/**
|
||||
* Makes the method abstract.
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makeAbstract() {
|
||||
if (!empty($this->stmts)) {
|
||||
@ -92,7 +84,7 @@ class Method extends PhpParser\BuilderAbstract
|
||||
/**
|
||||
* Makes the method final.
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makeFinal() {
|
||||
$this->setModifier(Stmt\Class_::MODIFIER_FINAL);
|
||||
@ -100,57 +92,12 @@ class Method extends PhpParser\BuilderAbstract
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the method return by reference.
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makeReturnByRef() {
|
||||
$this->returnByRef = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a parameter.
|
||||
*
|
||||
* @param Node\Param|Param $param The parameter to add
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
*/
|
||||
public function addParam($param) {
|
||||
$param = $this->normalizeNode($param);
|
||||
|
||||
if (!$param instanceof Node\Param) {
|
||||
throw new \LogicException(sprintf('Expected parameter node, got "%s"', $param->getType()));
|
||||
}
|
||||
|
||||
$this->params[] = $param;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple parameters.
|
||||
*
|
||||
* @param array $params The parameters to add
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
*/
|
||||
public function addParams(array $params) {
|
||||
foreach ($params as $param) {
|
||||
$this->addParam($param);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a statement.
|
||||
*
|
||||
* @param Node|PhpParser\Builder $stmt The statement to add
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function addStmt($stmt) {
|
||||
if (null === $this->stmts) {
|
||||
@ -162,21 +109,6 @@ class Method extends PhpParser\BuilderAbstract
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple statements.
|
||||
*
|
||||
* @param array $stmts The statements to add
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
*/
|
||||
public function addStmts(array $stmts) {
|
||||
foreach ($stmts as $stmt) {
|
||||
$this->addStmt($stmt);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the built method node.
|
||||
*
|
||||
@ -184,10 +116,10 @@ class Method extends PhpParser\BuilderAbstract
|
||||
*/
|
||||
public function getNode() {
|
||||
return new Stmt\ClassMethod($this->name, array(
|
||||
'type' => $this->type !== 0 ? $this->type : Stmt\Class_::MODIFIER_PUBLIC,
|
||||
'type' => $this->type,
|
||||
'byRef' => $this->returnByRef,
|
||||
'params' => $this->params,
|
||||
'stmts' => $this->stmts,
|
||||
));
|
||||
), $this->attributes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
59
lib/PhpParser/Builder/Namespace_.php
Normal file
59
lib/PhpParser/Builder/Namespace_.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace PhpParser\Builder;
|
||||
|
||||
use PhpParser;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt;
|
||||
|
||||
class Namespace_ extends PhpParser\BuilderAbstract
|
||||
{
|
||||
private $name;
|
||||
private $stmts = array();
|
||||
|
||||
/**
|
||||
* Creates a namespace builder.
|
||||
*
|
||||
* @param Node\Name|string|null $name Name of the namespace
|
||||
*/
|
||||
public function __construct($name) {
|
||||
$this->name = null !== $name ? $this->normalizeName($name) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a statement.
|
||||
*
|
||||
* @param Node|PhpParser\Builder $stmt The statement to add
|
||||
*
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function addStmt($stmt) {
|
||||
$this->stmts[] = $this->normalizeNode($stmt);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple statements.
|
||||
*
|
||||
* @param array $stmts The statements to add
|
||||
*
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function addStmts(array $stmts) {
|
||||
foreach ($stmts as $stmt) {
|
||||
$this->addStmt($stmt);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the built node.
|
||||
*
|
||||
* @return Node The built node
|
||||
*/
|
||||
public function getNode() {
|
||||
return new Stmt\Namespace_($this->name, $this->stmts);
|
||||
}
|
||||
}
|
@ -9,9 +9,9 @@ class Param extends PhpParser\BuilderAbstract
|
||||
{
|
||||
protected $name;
|
||||
|
||||
protected $default;
|
||||
protected $type;
|
||||
protected $byRef;
|
||||
protected $default = null;
|
||||
protected $type = null;
|
||||
protected $byRef = false;
|
||||
|
||||
/**
|
||||
* Creates a parameter builder.
|
||||
@ -20,10 +20,6 @@ class Param extends PhpParser\BuilderAbstract
|
||||
*/
|
||||
public function __construct($name) {
|
||||
$this->name = $name;
|
||||
|
||||
$this->default = null;
|
||||
$this->type = null;
|
||||
$this->byRef = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -31,7 +27,7 @@ class Param extends PhpParser\BuilderAbstract
|
||||
*
|
||||
* @param mixed $value Default value to use
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function setDefault($value) {
|
||||
$this->default = $this->normalizeValue($value);
|
||||
@ -44,7 +40,7 @@ class Param extends PhpParser\BuilderAbstract
|
||||
*
|
||||
* @param string|Node\Name $type Type hint to use
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function setTypeHint($type) {
|
||||
if ($type === 'array' || $type === 'callable') {
|
||||
@ -59,7 +55,7 @@ class Param extends PhpParser\BuilderAbstract
|
||||
/**
|
||||
* Make the parameter accept the value by reference.
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makeByRef() {
|
||||
$this->byRef = true;
|
||||
|
@ -9,8 +9,9 @@ class Property extends PhpParser\BuilderAbstract
|
||||
{
|
||||
protected $name;
|
||||
|
||||
protected $type;
|
||||
protected $default;
|
||||
protected $type = 0;
|
||||
protected $default = null;
|
||||
protected $attributes = array();
|
||||
|
||||
/**
|
||||
* Creates a property builder.
|
||||
@ -19,15 +20,12 @@ class Property extends PhpParser\BuilderAbstract
|
||||
*/
|
||||
public function __construct($name) {
|
||||
$this->name = $name;
|
||||
|
||||
$this->type = 0;
|
||||
$this->default = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the property public.
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makePublic() {
|
||||
$this->setModifier(Stmt\Class_::MODIFIER_PUBLIC);
|
||||
@ -38,7 +36,7 @@ class Property extends PhpParser\BuilderAbstract
|
||||
/**
|
||||
* Makes the property protected.
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makeProtected() {
|
||||
$this->setModifier(Stmt\Class_::MODIFIER_PROTECTED);
|
||||
@ -49,7 +47,7 @@ class Property extends PhpParser\BuilderAbstract
|
||||
/**
|
||||
* Makes the property private.
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makePrivate() {
|
||||
$this->setModifier(Stmt\Class_::MODIFIER_PRIVATE);
|
||||
@ -60,7 +58,7 @@ class Property extends PhpParser\BuilderAbstract
|
||||
/**
|
||||
* Makes the property static.
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makeStatic() {
|
||||
$this->setModifier(Stmt\Class_::MODIFIER_STATIC);
|
||||
@ -73,7 +71,7 @@ class Property extends PhpParser\BuilderAbstract
|
||||
*
|
||||
* @param mixed $value Default value to use
|
||||
*
|
||||
* @return self The builder instance (for fluid interface)
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function setDefault($value) {
|
||||
$this->default = $this->normalizeValue($value);
|
||||
@ -81,6 +79,21 @@ class Property extends PhpParser\BuilderAbstract
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets doc comment for the property.
|
||||
*
|
||||
* @param PhpParser\Comment\Doc|string $docComment Doc comment to set
|
||||
*
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function setDocComment($docComment) {
|
||||
$this->attributes = array(
|
||||
'comments' => array($this->normalizeDocComment($docComment))
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the built class node.
|
||||
*
|
||||
@ -91,7 +104,8 @@ class Property extends PhpParser\BuilderAbstract
|
||||
$this->type !== 0 ? $this->type : Stmt\Class_::MODIFIER_PUBLIC,
|
||||
array(
|
||||
new Stmt\PropertyProperty($this->name, $this->default)
|
||||
)
|
||||
),
|
||||
$this->attributes
|
||||
);
|
||||
}
|
||||
}
|
55
lib/PhpParser/Builder/Trait_.php
Normal file
55
lib/PhpParser/Builder/Trait_.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace PhpParser\Builder;
|
||||
|
||||
use PhpParser;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt;
|
||||
|
||||
class Trait_ extends Declaration
|
||||
{
|
||||
protected $name;
|
||||
protected $properties = array();
|
||||
protected $methods = array();
|
||||
|
||||
/**
|
||||
* Creates an interface builder.
|
||||
*
|
||||
* @param string $name Name of the interface
|
||||
*/
|
||||
public function __construct($name) {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = $this->normalizeNode($stmt);
|
||||
|
||||
if ($stmt instanceof Stmt\Property) {
|
||||
$this->properties[] = $stmt;
|
||||
} else if ($stmt instanceof Stmt\ClassMethod) {
|
||||
$this->methods[] = $stmt;
|
||||
} else {
|
||||
throw new \LogicException(sprintf('Unexpected node of type "%s"', $stmt->getType()));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the built trait node.
|
||||
*
|
||||
* @return Stmt\Trait_ The built interface node
|
||||
*/
|
||||
public function getNode() {
|
||||
return new Stmt\Trait_(
|
||||
$this->name, array_merge($this->properties, $this->methods), $this->attributes
|
||||
);
|
||||
}
|
||||
}
|
58
lib/PhpParser/Builder/Use_.php
Normal file
58
lib/PhpParser/Builder/Use_.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace PhpParser\Builder;
|
||||
|
||||
use PhpParser\BuilderAbstract;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt;
|
||||
|
||||
/**
|
||||
* @method $this as(string $alias) Sets alias for used name.
|
||||
*/
|
||||
class Use_ extends BuilderAbstract {
|
||||
protected $name;
|
||||
protected $type;
|
||||
protected $alias = null;
|
||||
|
||||
/**
|
||||
* Creates a name use (alias) builder.
|
||||
*
|
||||
* @param Node\Name|string $name Name of the entity (namespace, class, function, constant) to alias
|
||||
* @param int $type One of the Stmt\Use_::TYPE_* constants
|
||||
*/
|
||||
public function __construct($name, $type) {
|
||||
$this->name = $this->normalizeName($name);
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets alias for used name.
|
||||
*
|
||||
* @param string $alias Alias to use (last component of full name by default)
|
||||
*
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
protected function as_($alias) {
|
||||
$this->alias = $alias;
|
||||
return $this;
|
||||
}
|
||||
public function __call($name, $args) {
|
||||
if (method_exists($this, $name . '_')) {
|
||||
return call_user_func_array(array($this, $name . '_'), $args);
|
||||
}
|
||||
|
||||
throw new \LogicException(sprintf('Method "%s" does not exist', $name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the built node.
|
||||
*
|
||||
* @return Node The built node
|
||||
*/
|
||||
public function getNode() {
|
||||
$alias = null !== $this->alias ? $this->alias : $this->name->getLast();
|
||||
return new Stmt\Use_(array(
|
||||
new Stmt\UseUse($this->name, $alias)
|
||||
), $this->type);
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Scalar;
|
||||
use PhpParser\Comment;
|
||||
|
||||
abstract class BuilderAbstract implements Builder {
|
||||
/**
|
||||
@ -35,9 +36,21 @@ abstract class BuilderAbstract implements Builder {
|
||||
protected function normalizeName($name) {
|
||||
if ($name instanceof Name) {
|
||||
return $name;
|
||||
} else {
|
||||
return new Name($name);
|
||||
} elseif (is_string($name)) {
|
||||
if (!$name) {
|
||||
throw new \LogicException('Name cannot be empty');
|
||||
}
|
||||
|
||||
if ($name[0] == '\\') {
|
||||
return new Name\FullyQualified(substr($name, 1));
|
||||
} elseif (0 === strpos($name, 'namespace\\')) {
|
||||
return new Name\Relative(substr($name, strlen('namespace\\')));
|
||||
} else {
|
||||
return new Name($name);
|
||||
}
|
||||
}
|
||||
|
||||
throw new \LogicException('Name must be a string or an instance of PhpParser\Node\Name');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -64,7 +77,7 @@ abstract class BuilderAbstract implements Builder {
|
||||
} elseif (is_float($value)) {
|
||||
return new Scalar\DNumber($value);
|
||||
} elseif (is_string($value)) {
|
||||
return new Scalar\String($value);
|
||||
return new Scalar\String_($value);
|
||||
} elseif (is_array($value)) {
|
||||
$items = array();
|
||||
$lastKey = -1;
|
||||
@ -89,6 +102,23 @@ abstract class BuilderAbstract implements Builder {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a doc comment: Converts plain strings to PhpParser\Comment\Doc.
|
||||
*
|
||||
* @param Comment\Doc|string $docComment The doc comment to normalize
|
||||
*
|
||||
* @return Comment\Doc The normalized doc comment
|
||||
*/
|
||||
protected function normalizeDocComment($docComment) {
|
||||
if ($docComment instanceof Comment\Doc) {
|
||||
return $docComment;
|
||||
} else if (is_string($docComment)) {
|
||||
return new Comment\Doc($docComment);
|
||||
} else {
|
||||
throw new \LogicException('Doc comment must be a string or an instance of PhpParser\Comment\Doc');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a modifier in the $this->type property.
|
||||
*
|
||||
@ -98,4 +128,4 @@ abstract class BuilderAbstract implements Builder {
|
||||
Stmt\Class_::verifyModifier($this->type, $modifier);
|
||||
$this->type |= $modifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,18 +3,32 @@
|
||||
namespace PhpParser;
|
||||
|
||||
use PhpParser\Builder;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
|
||||
/**
|
||||
* "class", "interface" and "function" are reserved keywords, so the methods are defined as _class(),
|
||||
* _interface() and _function() in the class and are made available as class(), interface() and function()
|
||||
* through __call() magic.
|
||||
* The following methods use reserved keywords, so their implementation is defined with an underscore and made available
|
||||
* with the reserved name through __call() magic.
|
||||
*
|
||||
* @method Builder\Class class(string $name) Creates a class builder.
|
||||
* @method Builder\Function_ function(string $name) Creates a function builder
|
||||
* @method Builder\Namespace_ namespace(string $name) Creates a namespace builder.
|
||||
* @method Builder\Class_ class(string $name) Creates a class builder.
|
||||
* @method Builder\Interface_ interface(string $name) Creates an interface builder.
|
||||
* @method Builder\Trait_ trait(string $name) Creates a trait builder.
|
||||
* @method Builder\Function_ function(string $name) Creates a function builder.
|
||||
* @method Builder\Use_ use(string $name) Creates a namespace/class use builder.
|
||||
*/
|
||||
class BuilderFactory
|
||||
{
|
||||
/**
|
||||
* Creates a namespace builder.
|
||||
*
|
||||
* @param null|string|Node\Name $name Name of the namespace
|
||||
*
|
||||
* @return Builder\Namespace_ The created namespace builder
|
||||
*/
|
||||
protected function _namespace($name) {
|
||||
return new Builder\Namespace_($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a class builder.
|
||||
*
|
||||
@ -27,7 +41,7 @@ class BuilderFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a interface builder.
|
||||
* Creates an interface builder.
|
||||
*
|
||||
* @param string $name Name of the interface
|
||||
*
|
||||
@ -37,6 +51,17 @@ class BuilderFactory
|
||||
return new Builder\Interface_($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a trait builder.
|
||||
*
|
||||
* @param string $name Name of the trait
|
||||
*
|
||||
* @return Builder\Trait_ The created trait builder
|
||||
*/
|
||||
protected function _trait($name) {
|
||||
return new Builder\Trait_($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a method builder.
|
||||
*
|
||||
@ -81,6 +106,17 @@ class BuilderFactory
|
||||
return new Builder\Function_($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a namespace/class use builder.
|
||||
*
|
||||
* @param string|Node\Name Name to alias
|
||||
*
|
||||
* @return Builder\Use_ The create use builder
|
||||
*/
|
||||
protected function _use($name) {
|
||||
return new Builder\Use_($name, Use_::TYPE_NORMAL);
|
||||
}
|
||||
|
||||
public function __call($name, array $args) {
|
||||
if (method_exists($this, '_' . $name)) {
|
||||
return call_user_func_array(array($this, '_' . $name), $args);
|
||||
@ -88,4 +124,4 @@ class BuilderFactory
|
||||
|
||||
throw new \LogicException(sprintf('Method "%s" does not exist', $name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,17 +5,22 @@ namespace PhpParser;
|
||||
class Error extends \RuntimeException
|
||||
{
|
||||
protected $rawMessage;
|
||||
protected $rawLine;
|
||||
protected $attributes;
|
||||
|
||||
/**
|
||||
* Creates an Exception signifying a parse error.
|
||||
*
|
||||
* @param string $message Error message
|
||||
* @param int $line Error line in PHP file
|
||||
* @param string $message Error message
|
||||
* @param array|int $attributes Attributes of node/token where error occurred
|
||||
* (or start line of error -- deprecated)
|
||||
*/
|
||||
public function __construct($message, $line = -1) {
|
||||
public function __construct($message, $attributes = array()) {
|
||||
$this->rawMessage = (string) $message;
|
||||
$this->rawLine = (int) $line;
|
||||
if (is_array($attributes)) {
|
||||
$this->attributes = $attributes;
|
||||
} else {
|
||||
$this->attributes = array('startLine' => $attributes);
|
||||
}
|
||||
$this->updateMessage();
|
||||
}
|
||||
|
||||
@ -28,6 +33,34 @@ class Error extends \RuntimeException
|
||||
return $this->rawMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the line the error starts in.
|
||||
*
|
||||
* @return int Error start line
|
||||
*/
|
||||
public function getStartLine() {
|
||||
return isset($this->attributes['startLine']) ? $this->attributes['startLine'] : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the line the error ends in.
|
||||
*
|
||||
* @return int Error end line
|
||||
*/
|
||||
public function getEndLine() {
|
||||
return isset($this->attributes['endLine']) ? $this->attributes['endLine'] : -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the attributes of the node/token the error occurred at.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAttributes() {
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the line of the PHP file the error occurred in.
|
||||
*
|
||||
@ -39,22 +72,65 @@ class Error extends \RuntimeException
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error line in the PHP file.
|
||||
* Sets the line the error starts in.
|
||||
*
|
||||
* @return int Error line in the PHP file
|
||||
* @param int $line Error start line
|
||||
*/
|
||||
public function getRawLine() {
|
||||
return $this->rawLine;
|
||||
public function setStartLine($line) {
|
||||
$this->attributes['startLine'] = (int) $line;
|
||||
$this->updateMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the line of the PHP file the error occurred in.
|
||||
* Returns whether the error has start and end column information.
|
||||
*
|
||||
* @param int $line Error line in the PHP file
|
||||
* For column information enable the startFilePos and endFilePos in the lexer options.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function setRawLine($line) {
|
||||
$this->rawLine = (int) $line;
|
||||
$this->updateMessage();
|
||||
public function hasColumnInfo() {
|
||||
return isset($this->attributes['startFilePos']) && isset($this->attributes['endFilePos']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the start column (1-based) into the line where the error started.
|
||||
*
|
||||
* @param string $code Source code of the file
|
||||
* @return int
|
||||
*/
|
||||
public function getStartColumn($code) {
|
||||
if (!$this->hasColumnInfo()) {
|
||||
throw new \RuntimeException('Error does not have column information');
|
||||
}
|
||||
|
||||
return $this->toColumn($code, $this->attributes['startFilePos']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the end column (1-based) into the line where the error ended.
|
||||
*
|
||||
* @param string $code Source code of the file
|
||||
* @return int
|
||||
*/
|
||||
public function getEndColumn($code) {
|
||||
if (!$this->hasColumnInfo()) {
|
||||
throw new \RuntimeException('Error does not have column information');
|
||||
}
|
||||
|
||||
return $this->toColumn($code, $this->attributes['endFilePos']);
|
||||
}
|
||||
|
||||
private function toColumn($code, $pos) {
|
||||
if ($pos > strlen($code)) {
|
||||
throw new \RuntimeException('Invalid position information');
|
||||
}
|
||||
|
||||
$lineStartPos = strrpos($code, "\n", $pos - strlen($code));
|
||||
if (false === $lineStartPos) {
|
||||
$lineStartPos = -1;
|
||||
}
|
||||
|
||||
return $pos - $lineStartPos;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -63,10 +139,20 @@ class Error extends \RuntimeException
|
||||
protected function updateMessage() {
|
||||
$this->message = $this->rawMessage;
|
||||
|
||||
if (-1 === $this->rawLine) {
|
||||
if (-1 === $this->getStartLine()) {
|
||||
$this->message .= ' on unknown line';
|
||||
} else {
|
||||
$this->message .= ' on line ' . $this->rawLine;
|
||||
$this->message .= ' on line ' . $this->getStartLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @deprecated Use getStartLine() instead */
|
||||
public function getRawLine() {
|
||||
return $this->getStartLine();
|
||||
}
|
||||
|
||||
/** @deprecated Use setStartLine() instead */
|
||||
public function setRawLine($line) {
|
||||
$this->setStartLine($line);
|
||||
}
|
||||
}
|
||||
|
@ -2,26 +2,44 @@
|
||||
|
||||
namespace PhpParser;
|
||||
|
||||
use PhpParser\Parser\Tokens;
|
||||
|
||||
class Lexer
|
||||
{
|
||||
protected $code;
|
||||
protected $tokens;
|
||||
protected $pos;
|
||||
protected $line;
|
||||
protected $filePos;
|
||||
|
||||
protected $tokenMap;
|
||||
protected $dropTokens;
|
||||
|
||||
protected $usedAttributes;
|
||||
|
||||
/**
|
||||
* Creates a Lexer.
|
||||
*
|
||||
* @param array $options Options array. Currently only the 'usedAttributes' option is supported,
|
||||
* which is an array of attributes to add to the AST nodes. Possible attributes
|
||||
* are: 'comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos',
|
||||
* 'startFilePos', 'endFilePos'. The option defaults to the first three.
|
||||
* For more info see getNextToken() docs.
|
||||
*/
|
||||
public function __construct() {
|
||||
public function __construct(array $options = array()) {
|
||||
// map from internal tokens to PhpParser tokens
|
||||
$this->tokenMap = $this->createTokenMap();
|
||||
|
||||
// map of tokens to drop while lexing (the map is only used for isset lookup,
|
||||
// that's why the value is simply set to 1; the value is never actually used.)
|
||||
$this->dropTokens = array_fill_keys(array(T_WHITESPACE, T_OPEN_TAG), 1);
|
||||
|
||||
// the usedAttributes member is a map of the used attribute names to a dummy
|
||||
// value (here "true")
|
||||
$options += array(
|
||||
'usedAttributes' => array('comments', 'startLine', 'endLine'),
|
||||
);
|
||||
$this->usedAttributes = array_fill_keys($options['usedAttributes'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -32,13 +50,20 @@ class Lexer
|
||||
* @throws Error on lexing errors (unterminated comment or unexpected character)
|
||||
*/
|
||||
public function startLexing($code) {
|
||||
$scream = ini_set('xdebug.scream', '0');
|
||||
|
||||
$this->resetErrors();
|
||||
$this->tokens = @token_get_all($code);
|
||||
$this->handleErrors();
|
||||
|
||||
if (false !== $scream) {
|
||||
ini_set('xdebug.scream', $scream);
|
||||
}
|
||||
|
||||
$this->code = $code; // keep the code around for __halt_compiler() handling
|
||||
$this->pos = -1;
|
||||
$this->line = 1;
|
||||
$this->filePos = 0;
|
||||
}
|
||||
|
||||
protected function resetErrors() {
|
||||
@ -55,7 +80,7 @@ class Lexer
|
||||
'~^Unterminated comment starting line ([0-9]+)$~',
|
||||
$error['message'], $matches
|
||||
)) {
|
||||
throw new Error('Unterminated comment', $matches[1]);
|
||||
throw new Error('Unterminated comment', (int) $matches[1]);
|
||||
}
|
||||
|
||||
if (preg_match(
|
||||
@ -77,6 +102,19 @@ class Lexer
|
||||
/**
|
||||
* Fetches the next token.
|
||||
*
|
||||
* The available attributes are determined by the 'usedAttributes' option, which can
|
||||
* be specified in the constructor. The following attributes are supported:
|
||||
*
|
||||
* * 'comments' => Array of PhpParser\Comment or PhpParser\Comment\Doc instances,
|
||||
* representing all comments that occurred between the previous
|
||||
* non-discarded token and the current one.
|
||||
* * 'startLine' => Line in which the node starts.
|
||||
* * 'endLine' => Line in which the node ends.
|
||||
* * 'startTokenPos' => Offset into the token array of the first token in the node.
|
||||
* * 'endTokenPos' => Offset into the token array of the last token in the node.
|
||||
* * 'startFilePos' => Offset into the code string of the first character that is part of the node.
|
||||
* * 'endFilePos' => Offset into the code string of the last character that is part of the node
|
||||
*
|
||||
* @param mixed $value Variable to store token content in
|
||||
* @param mixed $startAttributes Variable to store start attributes in
|
||||
* @param mixed $endAttributes Variable to store end attributes in
|
||||
@ -87,42 +125,95 @@ class Lexer
|
||||
$startAttributes = array();
|
||||
$endAttributes = array();
|
||||
|
||||
while (isset($this->tokens[++$this->pos])) {
|
||||
$token = $this->tokens[$this->pos];
|
||||
while (1) {
|
||||
if (isset($this->tokens[++$this->pos])) {
|
||||
$token = $this->tokens[$this->pos];
|
||||
} else {
|
||||
// EOF token with ID 0
|
||||
$token = "\0";
|
||||
}
|
||||
|
||||
if (isset($this->usedAttributes['startTokenPos'])) {
|
||||
$startAttributes['startTokenPos'] = $this->pos;
|
||||
}
|
||||
if (isset($this->usedAttributes['startFilePos'])) {
|
||||
$startAttributes['startFilePos'] = $this->filePos;
|
||||
}
|
||||
|
||||
if (is_string($token)) {
|
||||
$startAttributes['startLine'] = $this->line;
|
||||
$endAttributes['endLine'] = $this->line;
|
||||
|
||||
// bug in token_get_all
|
||||
if ('b"' === $token) {
|
||||
$value = 'b"';
|
||||
return ord('"');
|
||||
$this->filePos += 2;
|
||||
$id = ord('"');
|
||||
} else {
|
||||
$value = $token;
|
||||
return ord($token);
|
||||
$this->filePos += 1;
|
||||
$id = ord($token);
|
||||
}
|
||||
|
||||
if (isset($this->usedAttributes['startLine'])) {
|
||||
$startAttributes['startLine'] = $this->line;
|
||||
}
|
||||
if (isset($this->usedAttributes['endLine'])) {
|
||||
$endAttributes['endLine'] = $this->line;
|
||||
}
|
||||
if (isset($this->usedAttributes['endTokenPos'])) {
|
||||
$endAttributes['endTokenPos'] = $this->pos;
|
||||
}
|
||||
if (isset($this->usedAttributes['endFilePos'])) {
|
||||
$endAttributes['endFilePos'] = $this->filePos - 1;
|
||||
}
|
||||
|
||||
return $id;
|
||||
} else {
|
||||
$this->line += substr_count($token[1], "\n");
|
||||
$this->filePos += strlen($token[1]);
|
||||
|
||||
if (T_COMMENT === $token[0]) {
|
||||
$startAttributes['comments'][] = new Comment($token[1], $token[2]);
|
||||
if (isset($this->usedAttributes['comments'])) {
|
||||
$startAttributes['comments'][] = new Comment($token[1], $token[2]);
|
||||
}
|
||||
} elseif (T_DOC_COMMENT === $token[0]) {
|
||||
$startAttributes['comments'][] = new Comment\Doc($token[1], $token[2]);
|
||||
if (isset($this->usedAttributes['comments'])) {
|
||||
$startAttributes['comments'][] = new Comment\Doc($token[1], $token[2]);
|
||||
}
|
||||
} elseif (!isset($this->dropTokens[$token[0]])) {
|
||||
$value = $token[1];
|
||||
$startAttributes['startLine'] = $token[2];
|
||||
$endAttributes['endLine'] = $this->line;
|
||||
|
||||
if (isset($this->usedAttributes['startLine'])) {
|
||||
$startAttributes['startLine'] = $token[2];
|
||||
}
|
||||
if (isset($this->usedAttributes['endLine'])) {
|
||||
$endAttributes['endLine'] = $this->line;
|
||||
}
|
||||
if (isset($this->usedAttributes['endTokenPos'])) {
|
||||
$endAttributes['endTokenPos'] = $this->pos;
|
||||
}
|
||||
if (isset($this->usedAttributes['endFilePos'])) {
|
||||
$endAttributes['endFilePos'] = $this->filePos - 1;
|
||||
}
|
||||
|
||||
return $this->tokenMap[$token[0]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$startAttributes['startLine'] = $this->line;
|
||||
throw new \RuntimeException('Reached end of lexer loop');
|
||||
}
|
||||
|
||||
// 0 is the EOF token
|
||||
return 0;
|
||||
/**
|
||||
* Returns the token array for current code.
|
||||
*
|
||||
* The token array is in the same format as provided by the
|
||||
* token_get_all() function and does not discard tokens (i.e.
|
||||
* whitespace and comments are included). The token position
|
||||
* attributes are against this token array.
|
||||
*
|
||||
* @return array Array of tokens in token_get_all() format
|
||||
*/
|
||||
public function getTokens() {
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -131,23 +222,13 @@ class Lexer
|
||||
* @return string Remaining text
|
||||
*/
|
||||
public function handleHaltCompiler() {
|
||||
// get the length of the text before the T_HALT_COMPILER token
|
||||
$textBefore = '';
|
||||
for ($i = 0; $i <= $this->pos; ++$i) {
|
||||
if (is_string($this->tokens[$i])) {
|
||||
$textBefore .= $this->tokens[$i];
|
||||
} else {
|
||||
$textBefore .= $this->tokens[$i][1];
|
||||
}
|
||||
}
|
||||
|
||||
// text after T_HALT_COMPILER, still including ();
|
||||
$textAfter = substr($this->code, strlen($textBefore));
|
||||
$textAfter = substr($this->code, $this->filePos);
|
||||
|
||||
// ensure that it is followed by ();
|
||||
// this simplifies the situation, by not allowing any comments
|
||||
// in between of the tokens.
|
||||
if (!preg_match('~\s*\(\s*\)\s*(?:;|\?>\r?\n?)~', $textAfter, $matches)) {
|
||||
if (!preg_match('~^\s*\(\s*\)\s*(?:;|\?>\r?\n?)~', $textAfter, $matches)) {
|
||||
throw new Error('__HALT_COMPILER must be followed by "();"');
|
||||
}
|
||||
|
||||
@ -173,23 +254,35 @@ class Lexer
|
||||
// 256 is the minimum possible token number, as everything below
|
||||
// it is an ASCII value
|
||||
for ($i = 256; $i < 1000; ++$i) {
|
||||
// T_DOUBLE_COLON is equivalent to T_PAAMAYIM_NEKUDOTAYIM
|
||||
if (T_DOUBLE_COLON === $i) {
|
||||
$tokenMap[$i] = Parser::T_PAAMAYIM_NEKUDOTAYIM;
|
||||
// T_OPEN_TAG_WITH_ECHO with dropped T_OPEN_TAG results in T_ECHO
|
||||
// T_DOUBLE_COLON is equivalent to T_PAAMAYIM_NEKUDOTAYIM
|
||||
$tokenMap[$i] = Tokens::T_PAAMAYIM_NEKUDOTAYIM;
|
||||
} elseif(T_OPEN_TAG_WITH_ECHO === $i) {
|
||||
$tokenMap[$i] = Parser::T_ECHO;
|
||||
// T_CLOSE_TAG is equivalent to ';'
|
||||
// T_OPEN_TAG_WITH_ECHO with dropped T_OPEN_TAG results in T_ECHO
|
||||
$tokenMap[$i] = Tokens::T_ECHO;
|
||||
} elseif(T_CLOSE_TAG === $i) {
|
||||
// T_CLOSE_TAG is equivalent to ';'
|
||||
$tokenMap[$i] = ord(';');
|
||||
// and the others can be mapped directly
|
||||
} elseif ('UNKNOWN' !== ($name = token_name($i))
|
||||
&& defined($name = 'PhpParser\Parser::' . $name)
|
||||
) {
|
||||
$tokenMap[$i] = constant($name);
|
||||
} elseif ('UNKNOWN' !== $name = token_name($i)) {
|
||||
if ('T_HASHBANG' === $name) {
|
||||
// HHVM uses a special token for #! hashbang lines
|
||||
$tokenMap[$i] = Tokens::T_INLINE_HTML;
|
||||
} else if (defined($name = 'PhpParser\Parser\Tokens::' . $name)) {
|
||||
// Other tokens can be mapped directly
|
||||
$tokenMap[$i] = constant($name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HHVM uses a special token for numbers that overflow to double
|
||||
if (defined('T_ONUMBER')) {
|
||||
$tokenMap[T_ONUMBER] = Tokens::T_DNUMBER;
|
||||
}
|
||||
// HHVM also has a separate token for the __COMPILER_HALT_OFFSET__ constant
|
||||
if (defined('T_COMPILER_HALT_OFFSET')) {
|
||||
$tokenMap[T_COMPILER_HALT_OFFSET] = Tokens::T_STRING;
|
||||
}
|
||||
|
||||
return $tokenMap;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace PhpParser\Lexer;
|
||||
|
||||
use PhpParser\Parser;
|
||||
use PhpParser\Parser\Tokens;
|
||||
|
||||
/**
|
||||
* ATTENTION: This code is WRITE-ONLY. Do not try to read it.
|
||||
@ -12,27 +12,24 @@ class Emulative extends \PhpParser\Lexer
|
||||
protected $newKeywords;
|
||||
protected $inObjectAccess;
|
||||
|
||||
const T_ELLIPSIS = 1001;
|
||||
const T_POW = 1002;
|
||||
const T_POW_EQUAL = 1003;
|
||||
const T_ELLIPSIS = 1001;
|
||||
const T_POW = 1002;
|
||||
const T_POW_EQUAL = 1003;
|
||||
const T_COALESCE = 1004;
|
||||
const T_SPACESHIP = 1005;
|
||||
const T_YIELD_FROM = 1006;
|
||||
|
||||
const PHP_5_6 = '5.6.0beta1';
|
||||
const PHP_7_0 = '7.0.0dev';
|
||||
const PHP_5_6 = '5.6.0rc1';
|
||||
const PHP_5_5 = '5.5.0beta1';
|
||||
const PHP_5_4 = '5.4.0beta1';
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
public function __construct(array $options = array()) {
|
||||
parent::__construct($options);
|
||||
|
||||
$newKeywordsPerVersion = array(
|
||||
self::PHP_5_5 => array(
|
||||
'finally' => Parser::T_FINALLY,
|
||||
'yield' => Parser::T_YIELD,
|
||||
),
|
||||
self::PHP_5_4 => array(
|
||||
'callable' => Parser::T_CALLABLE,
|
||||
'insteadof' => Parser::T_INSTEADOF,
|
||||
'trait' => Parser::T_TRAIT,
|
||||
'__trait__' => Parser::T_TRAIT_C,
|
||||
'finally' => Tokens::T_FINALLY,
|
||||
'yield' => Tokens::T_YIELD,
|
||||
),
|
||||
);
|
||||
|
||||
@ -45,11 +42,19 @@ class Emulative extends \PhpParser\Lexer
|
||||
$this->newKeywords += $newKeywords;
|
||||
}
|
||||
|
||||
if (version_compare(PHP_VERSION, self::PHP_5_6, '<')) {
|
||||
$this->tokenMap[self::T_ELLIPSIS] = Parser::T_ELLIPSIS;
|
||||
$this->tokenMap[self::T_POW] = Parser::T_POW;
|
||||
$this->tokenMap[self::T_POW_EQUAL] = Parser::T_POW_EQUAL;
|
||||
if (version_compare(PHP_VERSION, self::PHP_7_0, '>=')) {
|
||||
return;
|
||||
}
|
||||
$this->tokenMap[self::T_COALESCE] = Tokens::T_COALESCE;
|
||||
$this->tokenMap[self::T_SPACESHIP] = Tokens::T_SPACESHIP;
|
||||
$this->tokenMap[self::T_YIELD_FROM] = Tokens::T_YIELD_FROM;
|
||||
|
||||
if (version_compare(PHP_VERSION, self::PHP_5_6, '>=')) {
|
||||
return;
|
||||
}
|
||||
$this->tokenMap[self::T_ELLIPSIS] = Tokens::T_ELLIPSIS;
|
||||
$this->tokenMap[self::T_POW] = Tokens::T_POW;
|
||||
$this->tokenMap[self::T_POW_EQUAL] = Tokens::T_POW_EQUAL;
|
||||
}
|
||||
|
||||
public function startLexing($code) {
|
||||
@ -60,6 +65,10 @@ class Emulative extends \PhpParser\Lexer
|
||||
if ($preprocessedCode !== $code) {
|
||||
$this->postprocessTokens();
|
||||
}
|
||||
|
||||
// Set code property back to the original code, so __halt_compiler()
|
||||
// handling and (start|end)FilePos attributes use the correct offsets
|
||||
$this->code = $code;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -71,6 +80,17 @@ class Emulative extends \PhpParser\Lexer
|
||||
* inside a string, i.e. a place where they don't have a special meaning).
|
||||
*/
|
||||
protected function preprocessCode($code) {
|
||||
if (version_compare(PHP_VERSION, self::PHP_7_0, '>=')) {
|
||||
return $code;
|
||||
}
|
||||
|
||||
$code = str_replace('??', '~__EMU__COALESCE__~', $code);
|
||||
$code = str_replace('<=>', '~__EMU__SPACESHIP__~', $code);
|
||||
$code = preg_replace_callback('(yield[ \n\r\t]+from)', function($matches) {
|
||||
// Encoding $0 in order to preserve exact whitespace
|
||||
return '~__EMU__YIELDFROM__' . bin2hex($matches[0]) . '__~';
|
||||
}, $code);
|
||||
|
||||
if (version_compare(PHP_VERSION, self::PHP_5_6, '>=')) {
|
||||
return $code;
|
||||
}
|
||||
@ -79,12 +99,7 @@ class Emulative extends \PhpParser\Lexer
|
||||
$code = preg_replace('((?<!/)\*\*=)', '~__EMU__POWEQUAL__~', $code);
|
||||
$code = preg_replace('((?<!/)\*\*(?!/))', '~__EMU__POW__~', $code);
|
||||
|
||||
if (version_compare(PHP_VERSION, self::PHP_5_4, '>=')) {
|
||||
return $code;
|
||||
}
|
||||
|
||||
// binary notation (0b010101101001...)
|
||||
return preg_replace('(\b0b[01]+\b)', '~__EMU__BINARY__$0__~', $code);
|
||||
return $code;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -103,13 +118,7 @@ class Emulative extends \PhpParser\Lexer
|
||||
&& T_STRING === $this->tokens[$i + 1][0]
|
||||
&& preg_match('(^__EMU__([A-Z]++)__(?:([A-Za-z0-9]++)__)?$)', $this->tokens[$i + 1][1], $matches)
|
||||
) {
|
||||
if ('BINARY' === $matches[1]) {
|
||||
// the binary number can either be an integer or a double, so return a LNUMBER
|
||||
// or DNUMBER respectively
|
||||
$replace = array(
|
||||
array(is_int(bindec($matches[2])) ? T_LNUMBER : T_DNUMBER, $matches[2], $this->tokens[$i + 1][2])
|
||||
);
|
||||
} else if ('ELLIPSIS' === $matches[1]) {
|
||||
if ('ELLIPSIS' === $matches[1]) {
|
||||
$replace = array(
|
||||
array(self::T_ELLIPSIS, '...', $this->tokens[$i + 1][2])
|
||||
);
|
||||
@ -121,9 +130,21 @@ class Emulative extends \PhpParser\Lexer
|
||||
$replace = array(
|
||||
array(self::T_POW_EQUAL, '**=', $this->tokens[$i + 1][2])
|
||||
);
|
||||
} else if ('COALESCE' === $matches[1]) {
|
||||
$replace = array(
|
||||
array(self::T_COALESCE, '??', $this->tokens[$i + 1][2])
|
||||
);
|
||||
} else if ('SPACESHIP' === $matches[1]) {
|
||||
$replace = array(
|
||||
array(self::T_SPACESHIP, '<=>', $this->tokens[$i + 1][2]),
|
||||
);
|
||||
} else if ('YIELDFROM' === $matches[1]) {
|
||||
$content = hex2bin($matches[2]);
|
||||
$replace = array(
|
||||
array(self::T_YIELD_FROM, $content, $this->tokens[$i + 1][2] - substr_count($content, "\n"))
|
||||
);
|
||||
} else {
|
||||
// just ignore all other __EMU__ sequences
|
||||
continue;
|
||||
throw new \RuntimeException('Invalid __EMU__ sequence');
|
||||
}
|
||||
|
||||
array_splice($this->tokens, $i, 3, $replace);
|
||||
@ -147,14 +168,18 @@ class Emulative extends \PhpParser\Lexer
|
||||
* multichar tokens (like strings) to their original value.
|
||||
*/
|
||||
public function restoreContentCallback(array $matches) {
|
||||
if ('BINARY' === $matches[1]) {
|
||||
return $matches[2];
|
||||
} else if ('ELLIPSIS' === $matches[1]) {
|
||||
if ('ELLIPSIS' === $matches[1]) {
|
||||
return '...';
|
||||
} else if ('POW' === $matches[1]) {
|
||||
return '**';
|
||||
} else if ('POWEQUAL' === $matches[1]) {
|
||||
return '**=';
|
||||
} else if ('COALESCE' === $matches[1]) {
|
||||
return '??';
|
||||
} else if ('SPACESHIP' === $matches[1]) {
|
||||
return '<=>';
|
||||
} else if ('YIELDFROM' === $matches[1]) {
|
||||
return hex2bin($matches[2]);
|
||||
} else {
|
||||
return $matches[0];
|
||||
}
|
||||
@ -166,17 +191,15 @@ class Emulative extends \PhpParser\Lexer
|
||||
// replace new keywords by their respective tokens. This is not done
|
||||
// if we currently are in an object access (e.g. in $obj->namespace
|
||||
// "namespace" stays a T_STRING tokens and isn't converted to T_NAMESPACE)
|
||||
if (Parser::T_STRING === $token && !$this->inObjectAccess) {
|
||||
if (Tokens::T_STRING === $token && !$this->inObjectAccess) {
|
||||
if (isset($this->newKeywords[strtolower($value)])) {
|
||||
return $this->newKeywords[strtolower($value)];
|
||||
}
|
||||
// keep track of whether we currently are in an object access (after ->)
|
||||
} elseif (Parser::T_OBJECT_OPERATOR === $token) {
|
||||
$this->inObjectAccess = true;
|
||||
} else {
|
||||
$this->inObjectAccess = false;
|
||||
// keep track of whether we currently are in an object access (after ->)
|
||||
$this->inObjectAccess = Tokens::T_OBJECT_OPERATOR === $token;
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,13 +4,15 @@ namespace PhpParser\Node;
|
||||
|
||||
use PhpParser\NodeAbstract;
|
||||
|
||||
/**
|
||||
* @property Expr $value Value to pass
|
||||
* @property bool $byRef Whether to pass by ref
|
||||
* @property bool $unpack Whether to unpack the argument
|
||||
*/
|
||||
class Arg extends NodeAbstract
|
||||
{
|
||||
/** @var Expr Value to pass */
|
||||
public $value;
|
||||
/** @var bool Whether to pass by ref */
|
||||
public $byRef;
|
||||
/** @var bool Whether to unpack the argument */
|
||||
public $unpack;
|
||||
|
||||
/**
|
||||
* Constructs a function call argument node.
|
||||
*
|
||||
@ -20,13 +22,13 @@ class Arg extends NodeAbstract
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $value, $byRef = false, $unpack = false, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'value' => $value,
|
||||
'byRef' => $byRef,
|
||||
'unpack' => $unpack,
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->value = $value;
|
||||
$this->byRef = $byRef;
|
||||
$this->unpack = $unpack;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('value', 'byRef', 'unpack');
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,13 @@ namespace PhpParser\Node;
|
||||
|
||||
use PhpParser\NodeAbstract;
|
||||
|
||||
/**
|
||||
* @property string $name Name
|
||||
* @property Expr $value Value
|
||||
*/
|
||||
class Const_ extends NodeAbstract
|
||||
{
|
||||
/** @var string Name */
|
||||
public $name;
|
||||
/** @var Expr Value */
|
||||
public $value;
|
||||
|
||||
/**
|
||||
* Constructs a const node for use in class const and const statements.
|
||||
*
|
||||
@ -18,12 +19,12 @@ class Const_ extends NodeAbstract
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($name, Expr $value, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'name' => $name,
|
||||
'value' => $value,
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->name = $name;
|
||||
$this->value = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('name', 'value');
|
||||
}
|
||||
}
|
@ -4,12 +4,13 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $var Variable
|
||||
* @property null|Expr $dim Array index / dim
|
||||
*/
|
||||
class ArrayDimFetch extends Expr
|
||||
{
|
||||
/** @var Expr Variable */
|
||||
public $var;
|
||||
/** @var null|Expr Array index / dim */
|
||||
public $dim;
|
||||
|
||||
/**
|
||||
* Constructs an array index fetch node.
|
||||
*
|
||||
@ -18,12 +19,12 @@ class ArrayDimFetch extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $var, Expr $dim = null, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'var' => $var,
|
||||
'dim' => $dim
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->var = $var;
|
||||
$this->dim = $dim;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubnodeNames() {
|
||||
return array('var', 'dim');
|
||||
}
|
||||
}
|
||||
|
@ -4,13 +4,15 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $value Value
|
||||
* @property null|Expr $key Key
|
||||
* @property bool $byRef Whether to assign by reference
|
||||
*/
|
||||
class ArrayItem extends Expr
|
||||
{
|
||||
/** @var null|Expr Key */
|
||||
public $key;
|
||||
/** @var Expr Value */
|
||||
public $value;
|
||||
/** @var bool Whether to assign by reference */
|
||||
public $byRef;
|
||||
|
||||
/**
|
||||
* Constructs an array item node.
|
||||
*
|
||||
@ -20,13 +22,13 @@ class ArrayItem extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $value, Expr $key = null, $byRef = false, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'key' => $key,
|
||||
'value' => $value,
|
||||
'byRef' => $byRef
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->key = $key;
|
||||
$this->value = $value;
|
||||
$this->byRef = $byRef;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('key', 'value', 'byRef');
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property ArrayItem[] $items Items
|
||||
*/
|
||||
class Array_ extends Expr
|
||||
{
|
||||
/** @var ArrayItem[] Items */
|
||||
public $items;
|
||||
|
||||
/**
|
||||
* Constructs an array node.
|
||||
*
|
||||
@ -16,11 +16,11 @@ class Array_ extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(array $items = array(), array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'items' => $items
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->items = $items;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('items');
|
||||
}
|
||||
}
|
@ -4,12 +4,13 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $var Variable
|
||||
* @property Expr $expr Expression
|
||||
*/
|
||||
class Assign extends Expr
|
||||
{
|
||||
/** @var Expr Variable */
|
||||
public $var;
|
||||
/** @var Expr Expression */
|
||||
public $expr;
|
||||
|
||||
/**
|
||||
* Constructs an assignment node.
|
||||
*
|
||||
@ -18,12 +19,12 @@ class Assign extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $var, Expr $expr, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'var' => $var,
|
||||
'expr' => $expr
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->var = $var;
|
||||
$this->expr = $expr;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('var', 'expr');
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,11 @@ use PhpParser\Node\Expr;
|
||||
*/
|
||||
abstract class AssignOp extends Expr
|
||||
{
|
||||
/** @var Expr Variable */
|
||||
public $var;
|
||||
/** @var Expr Expression */
|
||||
public $expr;
|
||||
|
||||
/**
|
||||
* Constructs a compound assignment operation node.
|
||||
*
|
||||
@ -18,12 +23,12 @@ abstract class AssignOp extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $var, Expr $expr, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'var' => $var,
|
||||
'expr' => $expr
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->var = $var;
|
||||
$this->expr = $expr;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('var', 'expr');
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,11 @@ use PhpParser\Node\Expr;
|
||||
*/
|
||||
class AssignRef extends Expr
|
||||
{
|
||||
/** @var Expr Variable reference is assigned to */
|
||||
public $var;
|
||||
/** @var Expr Variable which is referenced */
|
||||
public $expr;
|
||||
|
||||
/**
|
||||
* Constructs an assignment node.
|
||||
*
|
||||
@ -18,12 +23,12 @@ class AssignRef extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $var, Expr $expr, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'var' => $var,
|
||||
'expr' => $expr
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->var = $var;
|
||||
$this->expr = $expr;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('var', 'expr');
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,13 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $left The left hand side expression
|
||||
* @property Expr $right The right hand side expression
|
||||
*/
|
||||
class BinaryOp extends Expr
|
||||
abstract class BinaryOp extends Expr
|
||||
{
|
||||
/** @var Expr The left hand side expression */
|
||||
public $left;
|
||||
/** @var Expr The right hand side expression */
|
||||
public $right;
|
||||
|
||||
/**
|
||||
* Constructs a bitwise and node.
|
||||
*
|
||||
@ -18,12 +19,12 @@ class BinaryOp extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $left, Expr $right, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'left' => $left,
|
||||
'right' => $right
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->left = $left;
|
||||
$this->right = $right;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('left', 'right');
|
||||
}
|
||||
}
|
||||
|
9
lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php
Normal file
9
lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace PhpParser\Node\Expr\BinaryOp;
|
||||
|
||||
use PhpParser\Node\Expr\BinaryOp;
|
||||
|
||||
class Coalesce extends BinaryOp
|
||||
{
|
||||
}
|
9
lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php
Normal file
9
lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace PhpParser\Node\Expr\BinaryOp;
|
||||
|
||||
use PhpParser\Node\Expr\BinaryOp;
|
||||
|
||||
class Spaceship extends BinaryOp
|
||||
{
|
||||
}
|
@ -4,11 +4,11 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $expr Expression
|
||||
*/
|
||||
class BitwiseNot extends Expr
|
||||
{
|
||||
/** @var Expr Expression */
|
||||
public $expr;
|
||||
|
||||
/**
|
||||
* Constructs a bitwise not node.
|
||||
*
|
||||
@ -16,11 +16,11 @@ class BitwiseNot extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $expr, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'expr' => $expr
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->expr = $expr;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('expr');
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $expr Expression
|
||||
*/
|
||||
class BooleanNot extends Expr
|
||||
{
|
||||
/** @var Expr Expression */
|
||||
public $expr;
|
||||
|
||||
/**
|
||||
* Constructs a boolean not node.
|
||||
*
|
||||
@ -16,11 +16,11 @@ class BooleanNot extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $expr, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'expr' => $expr
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->expr = $expr;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('expr');
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $expr Expression
|
||||
*/
|
||||
abstract class Cast extends Expr
|
||||
{
|
||||
/** @var Expr Expression */
|
||||
public $expr;
|
||||
|
||||
/**
|
||||
* Constructs a cast node.
|
||||
*
|
||||
@ -16,11 +16,11 @@ abstract class Cast extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $expr, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'expr' => $expr
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->expr = $expr;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('expr');
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,6 @@ namespace PhpParser\Node\Expr\Cast;
|
||||
|
||||
use PhpParser\Node\Expr\Cast;
|
||||
|
||||
class Int extends Cast
|
||||
class Bool_ extends Cast
|
||||
{
|
||||
}
|
||||
}
|
@ -6,4 +6,4 @@ use PhpParser\Node\Expr\Cast;
|
||||
|
||||
class Double extends Cast
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,6 @@ namespace PhpParser\Node\Expr\Cast;
|
||||
|
||||
use PhpParser\Node\Expr\Cast;
|
||||
|
||||
class Bool extends Cast
|
||||
class Int_ extends Cast
|
||||
{
|
||||
}
|
||||
}
|
@ -4,6 +4,6 @@ namespace PhpParser\Node\Expr\Cast;
|
||||
|
||||
use PhpParser\Node\Expr\Cast;
|
||||
|
||||
class Object extends Cast
|
||||
class Object_ extends Cast
|
||||
{
|
||||
}
|
||||
}
|
@ -4,6 +4,6 @@ namespace PhpParser\Node\Expr\Cast;
|
||||
|
||||
use PhpParser\Node\Expr\Cast;
|
||||
|
||||
class String extends Cast
|
||||
class String_ extends Cast
|
||||
{
|
||||
}
|
||||
}
|
@ -5,12 +5,13 @@ namespace PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Name|Expr $class Class name
|
||||
* @property string $name Constant name
|
||||
*/
|
||||
class ClassConstFetch extends Expr
|
||||
{
|
||||
/** @var Name|Expr Class name */
|
||||
public $class;
|
||||
/** @var string Constant name */
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* Constructs a class const fetch node.
|
||||
*
|
||||
@ -19,12 +20,12 @@ class ClassConstFetch extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($class, $name, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'class' => $class,
|
||||
'name' => $name
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->class = $class;
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('class', 'name');
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $expr Expression
|
||||
*/
|
||||
class Clone_ extends Expr
|
||||
{
|
||||
/** @var Expr Expression */
|
||||
public $expr;
|
||||
|
||||
/**
|
||||
* Constructs a clone node.
|
||||
*
|
||||
@ -16,11 +16,11 @@ class Clone_ extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $expr, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'expr' => $expr
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->expr = $expr;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('expr');
|
||||
}
|
||||
}
|
@ -4,37 +4,62 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\FunctionLike;
|
||||
|
||||
/**
|
||||
* @property Node[] $stmts Statements
|
||||
* @property Node\Param[] $params Parameters
|
||||
* @property ClosureUse[] $uses use()s
|
||||
* @property bool $byRef Whether to return by reference
|
||||
* @property bool $static Whether the closure is static
|
||||
*/
|
||||
class Closure extends Expr
|
||||
class Closure extends Expr implements FunctionLike
|
||||
{
|
||||
/** @var bool Whether the closure is static */
|
||||
public $static;
|
||||
/** @var bool Whether to return by reference */
|
||||
public $byRef;
|
||||
/** @var Node\Param[] Parameters */
|
||||
public $params;
|
||||
/** @var ClosureUse[] use()s */
|
||||
public $uses;
|
||||
/** @var null|string|Node\Name Return type */
|
||||
public $returnType;
|
||||
/** @var Node[] Statements */
|
||||
public $stmts;
|
||||
|
||||
/**
|
||||
* Constructs a lambda function node.
|
||||
*
|
||||
* @param array $subNodes Array of the following optional subnodes:
|
||||
* 'static' => false : Whether the closure is static
|
||||
* 'byRef' => false : Whether to return by reference
|
||||
* 'params' => array(): Parameters
|
||||
* 'uses' => array(): use()s
|
||||
* 'stmts' => array(): Statements
|
||||
* 'static' => false : Whether the closure is static
|
||||
* 'byRef' => false : Whether to return by reference
|
||||
* 'params' => array(): Parameters
|
||||
* 'uses' => array(): use()s
|
||||
* 'returnType' => null : Return type
|
||||
* 'stmts' => array(): Statements
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(array $subNodes = array(), array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'static' => isset($subNodes['static']) ? $subNodes['static'] : false,
|
||||
'byRef' => isset($subNodes['byRef']) ? $subNodes['byRef'] : false,
|
||||
'params' => isset($subNodes['params']) ? $subNodes['params'] : array(),
|
||||
'uses' => isset($subNodes['uses']) ? $subNodes['uses'] : array(),
|
||||
'stmts' => isset($subNodes['stmts']) ? $subNodes['stmts'] : array(),
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->static = isset($subNodes['static']) ? $subNodes['static'] : false;
|
||||
$this->byRef = isset($subNodes['byRef']) ? $subNodes['byRef'] : false;
|
||||
$this->params = isset($subNodes['params']) ? $subNodes['params'] : array();
|
||||
$this->uses = isset($subNodes['uses']) ? $subNodes['uses'] : array();
|
||||
$this->returnType = isset($subNodes['returnType']) ? $subNodes['returnType'] : null;
|
||||
$this->stmts = isset($subNodes['stmts']) ? $subNodes['stmts'] : array();
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('static', 'byRef', 'params', 'uses', 'returnType', 'stmts');
|
||||
}
|
||||
|
||||
public function returnsByRef() {
|
||||
return $this->byRef;
|
||||
}
|
||||
|
||||
public function getParams() {
|
||||
return $this->params;
|
||||
}
|
||||
|
||||
public function getReturnType() {
|
||||
return $this->returnType;
|
||||
}
|
||||
|
||||
public function getStmts() {
|
||||
return $this->stmts;
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,13 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property string $var Name of variable
|
||||
* @property bool $byRef Whether to use by reference
|
||||
*/
|
||||
class ClosureUse extends Expr
|
||||
{
|
||||
/** @var string Name of variable */
|
||||
public $var;
|
||||
/** @var bool Whether to use by reference */
|
||||
public $byRef;
|
||||
|
||||
/**
|
||||
* Constructs a closure use node.
|
||||
*
|
||||
@ -18,12 +19,12 @@ class ClosureUse extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($var, $byRef = false, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'var' => $var,
|
||||
'byRef' => $byRef
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->var = $var;
|
||||
$this->byRef = $byRef;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('var', 'byRef');
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,11 @@ namespace PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Name $name Constant name
|
||||
*/
|
||||
class ConstFetch extends Expr
|
||||
{
|
||||
/** @var Name Constant name */
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* Constructs a const fetch node.
|
||||
*
|
||||
@ -17,11 +17,11 @@ class ConstFetch extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Name $name, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'name' => $name
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('name');
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $expr Expression
|
||||
*/
|
||||
class Empty_ extends Expr
|
||||
{
|
||||
/** @var Expr Expression */
|
||||
public $expr;
|
||||
|
||||
/**
|
||||
* Constructs an empty() node.
|
||||
*
|
||||
@ -16,11 +16,11 @@ class Empty_ extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $expr, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'expr' => $expr
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->expr = $expr;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('expr');
|
||||
}
|
||||
}
|
@ -4,11 +4,11 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $expr Expression
|
||||
*/
|
||||
class ErrorSuppress extends Expr
|
||||
{
|
||||
/** @var Expr Expression */
|
||||
public $expr;
|
||||
|
||||
/**
|
||||
* Constructs an error suppress node.
|
||||
*
|
||||
@ -16,11 +16,11 @@ class ErrorSuppress extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $expr, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'expr' => $expr
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->expr = $expr;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('expr');
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $expr Expression
|
||||
*/
|
||||
class Eval_ extends Expr
|
||||
{
|
||||
/** @var Expr Expression */
|
||||
public $expr;
|
||||
|
||||
/**
|
||||
* Constructs an eval() node.
|
||||
*
|
||||
@ -16,11 +16,11 @@ class Eval_ extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $expr, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'expr' => $expr
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->expr = $expr;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('expr');
|
||||
}
|
||||
}
|
@ -4,11 +4,11 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property null|Expr $expr Expression
|
||||
*/
|
||||
class Exit_ extends Expr
|
||||
{
|
||||
/** @var null|Expr Expression */
|
||||
public $expr;
|
||||
|
||||
/**
|
||||
* Constructs an exit() node.
|
||||
*
|
||||
@ -16,11 +16,11 @@ class Exit_ extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $expr = null, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'expr' => $expr
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->expr = $expr;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('expr');
|
||||
}
|
||||
}
|
@ -5,12 +5,13 @@ namespace PhpParser\Node\Expr;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Node\Name|Expr $name Function name
|
||||
* @property Node\Arg[] $args Arguments
|
||||
*/
|
||||
class FuncCall extends Expr
|
||||
{
|
||||
/** @var Node\Name|Expr Function name */
|
||||
public $name;
|
||||
/** @var Node\Arg[] Arguments */
|
||||
public $args;
|
||||
|
||||
/**
|
||||
* Constructs a function call node.
|
||||
*
|
||||
@ -19,12 +20,12 @@ class FuncCall extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($name, array $args = array(), array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'name' => $name,
|
||||
'args' => $args
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->name = $name;
|
||||
$this->args = $args;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('name', 'args');
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,6 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $expr Expression
|
||||
* @property int $type Type of include
|
||||
*/
|
||||
class Include_ extends Expr
|
||||
{
|
||||
const TYPE_INCLUDE = 1;
|
||||
@ -15,6 +11,11 @@ class Include_ extends Expr
|
||||
const TYPE_REQUIRE = 3;
|
||||
const TYPE_REQUIRE_ONCE = 4;
|
||||
|
||||
/** @var Expr Expression */
|
||||
public $expr;
|
||||
/** @var int Type of include */
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* Constructs an include node.
|
||||
*
|
||||
@ -23,12 +24,12 @@ class Include_ extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $expr, $type, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'expr' => $expr,
|
||||
'type' => $type
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->expr = $expr;
|
||||
$this->type = $type;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('expr', 'type');
|
||||
}
|
||||
}
|
@ -5,12 +5,13 @@ namespace PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $expr Expression
|
||||
* @property Name|Expr $class Class name
|
||||
*/
|
||||
class Instanceof_ extends Expr
|
||||
{
|
||||
/** @var Expr Expression */
|
||||
public $expr;
|
||||
/** @var Name|Expr Class name */
|
||||
public $class;
|
||||
|
||||
/**
|
||||
* Constructs an instanceof check node.
|
||||
*
|
||||
@ -19,12 +20,12 @@ class Instanceof_ extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $expr, $class, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'expr' => $expr,
|
||||
'class' => $class
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->expr = $expr;
|
||||
$this->class = $class;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('expr', 'class');
|
||||
}
|
||||
}
|
@ -4,11 +4,11 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr[] $vars Variables
|
||||
*/
|
||||
class Isset_ extends Expr
|
||||
{
|
||||
/** @var Expr[] Variables */
|
||||
public $vars;
|
||||
|
||||
/**
|
||||
* Constructs an array node.
|
||||
*
|
||||
@ -16,11 +16,11 @@ class Isset_ extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(array $vars, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'vars' => $vars
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->vars = $vars;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('vars');
|
||||
}
|
||||
}
|
@ -4,11 +4,11 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr[] $vars List of variables to assign to
|
||||
*/
|
||||
class List_ extends Expr
|
||||
{
|
||||
/** @var Expr[] List of variables to assign to */
|
||||
public $vars;
|
||||
|
||||
/**
|
||||
* Constructs a list() destructuring node.
|
||||
*
|
||||
@ -16,11 +16,11 @@ class List_ extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(array $vars, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'vars' => $vars,
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->vars = $vars;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('vars');
|
||||
}
|
||||
}
|
@ -5,13 +5,15 @@ namespace PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $var Variable holding object
|
||||
* @property string|Expr $name Method name
|
||||
* @property Arg[] $args Arguments
|
||||
*/
|
||||
class MethodCall extends Expr
|
||||
{
|
||||
/** @var Expr Variable holding object */
|
||||
public $var;
|
||||
/** @var string|Expr Method name */
|
||||
public $name;
|
||||
/** @var Arg[] Arguments */
|
||||
public $args;
|
||||
|
||||
/**
|
||||
* Constructs a function call node.
|
||||
*
|
||||
@ -21,13 +23,13 @@ class MethodCall extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $var, $name, array $args = array(), array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'var' => $var,
|
||||
'name' => $name,
|
||||
'args' => $args
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->var = $var;
|
||||
$this->name = $name;
|
||||
$this->args = $args;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('var', 'name', 'args');
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Node\Name|Expr $class Class name
|
||||
* @property Node\Arg[] $args Arguments
|
||||
*/
|
||||
class New_ extends Expr
|
||||
{
|
||||
/**
|
||||
* Constructs a function call node.
|
||||
*
|
||||
* @param Node\Name|Expr $class Class name
|
||||
* @param Node\Arg[] $args Arguments
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($class, array $args = array(), array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'class' => $class,
|
||||
'args' => $args
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
}
|
||||
}
|
31
lib/PhpParser/Node/Expr/New_.php
Normal file
31
lib/PhpParser/Node/Expr/New_.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
class New_ extends Expr
|
||||
{
|
||||
/** @var Node\Name|Expr|Node\Stmt\Class_ Class name */
|
||||
public $class;
|
||||
/** @var Node\Arg[] Arguments */
|
||||
public $args;
|
||||
|
||||
/**
|
||||
* Constructs a function call node.
|
||||
*
|
||||
* @param Node\Name|Expr|Node\Stmt\Class_ $class Class name (or class node for anonymous classes)
|
||||
* @param Node\Arg[] $args Arguments
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($class, array $args = array(), array $attributes = array()) {
|
||||
parent::__construct($attributes);
|
||||
$this->class = $class;
|
||||
$this->args = $args;
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('class', 'args');
|
||||
}
|
||||
}
|
@ -4,11 +4,11 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $var Variable
|
||||
*/
|
||||
class PostDec extends Expr
|
||||
{
|
||||
/** @var Expr Variable */
|
||||
public $var;
|
||||
|
||||
/**
|
||||
* Constructs a post decrement node.
|
||||
*
|
||||
@ -16,11 +16,11 @@ class PostDec extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $var, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'var' => $var
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->var = $var;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('var');
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $var Variable
|
||||
*/
|
||||
class PostInc extends Expr
|
||||
{
|
||||
/** @var Expr Variable */
|
||||
public $var;
|
||||
|
||||
/**
|
||||
* Constructs a post increment node.
|
||||
*
|
||||
@ -16,11 +16,11 @@ class PostInc extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $var, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'var' => $var
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->var = $var;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('var');
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $var Variable
|
||||
*/
|
||||
class PreDec extends Expr
|
||||
{
|
||||
/** @var Expr Variable */
|
||||
public $var;
|
||||
|
||||
/**
|
||||
* Constructs a pre decrement node.
|
||||
*
|
||||
@ -16,11 +16,11 @@ class PreDec extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $var, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'var' => $var
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->var = $var;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('var');
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $var Variable
|
||||
*/
|
||||
class PreInc extends Expr
|
||||
{
|
||||
/** @var Expr Variable */
|
||||
public $var;
|
||||
|
||||
/**
|
||||
* Constructs a pre increment node.
|
||||
*
|
||||
@ -16,11 +16,11 @@ class PreInc extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $var, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'var' => $var
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->var = $var;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('var');
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $expr Expression
|
||||
*/
|
||||
class Print_ extends Expr
|
||||
{
|
||||
/** @var Expr Expression */
|
||||
public $expr;
|
||||
|
||||
/**
|
||||
* Constructs an print() node.
|
||||
*
|
||||
@ -16,11 +16,11 @@ class Print_ extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $expr, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'expr' => $expr
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->expr = $expr;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('expr');
|
||||
}
|
||||
}
|
@ -4,12 +4,13 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $var Variable holding object
|
||||
* @property string|Expr $name Property Name
|
||||
*/
|
||||
class PropertyFetch extends Expr
|
||||
{
|
||||
/** @var Expr Variable holding object */
|
||||
public $var;
|
||||
/** @var string|Expr Property name */
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* Constructs a function call node.
|
||||
*
|
||||
@ -18,12 +19,12 @@ class PropertyFetch extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $var, $name, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'var' => $var,
|
||||
'name' => $name
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->var = $var;
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('var', 'name');
|
||||
}
|
||||
}
|
||||
|
@ -4,23 +4,23 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property array $parts Encapsed string array
|
||||
*/
|
||||
class ShellExec extends Expr
|
||||
{
|
||||
/** @var array Encapsed string array */
|
||||
public $parts;
|
||||
|
||||
/**
|
||||
* Constructs a shell exec (backtick) node.
|
||||
*
|
||||
* @param array $parts Encapsed string array
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($parts, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'parts' => $parts
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
public function __construct(array $parts, array $attributes = array()) {
|
||||
parent::__construct($attributes);
|
||||
$this->parts = $parts;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('parts');
|
||||
}
|
||||
}
|
||||
|
@ -5,13 +5,15 @@ namespace PhpParser\Node\Expr;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Node\Name|Expr $class Class name
|
||||
* @property string|Expr $name Method name
|
||||
* @property Node\Arg[] $args Arguments
|
||||
*/
|
||||
class StaticCall extends Expr
|
||||
{
|
||||
/** @var Node\Name|Expr Class name */
|
||||
public $class;
|
||||
/** @var string|Expr Method name */
|
||||
public $name;
|
||||
/** @var Node\Arg[] Arguments */
|
||||
public $args;
|
||||
|
||||
/**
|
||||
* Constructs a static method call node.
|
||||
*
|
||||
@ -21,13 +23,13 @@ class StaticCall extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($class, $name, array $args = array(), array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'class' => $class,
|
||||
'name' => $name,
|
||||
'args' => $args
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->class = $class;
|
||||
$this->name = $name;
|
||||
$this->args = $args;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('class', 'name', 'args');
|
||||
}
|
||||
}
|
||||
|
@ -5,12 +5,13 @@ namespace PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Name|Expr $class Class name
|
||||
* @property string|Expr $name Property name
|
||||
*/
|
||||
class StaticPropertyFetch extends Expr
|
||||
{
|
||||
/** @var Name|Expr Class name */
|
||||
public $class;
|
||||
/** @var string|Expr Property name */
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* Constructs a static property fetch node.
|
||||
*
|
||||
@ -19,12 +20,12 @@ class StaticPropertyFetch extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($class, $name, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'class' => $class,
|
||||
'name' => $name
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->class = $class;
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('class', 'name');
|
||||
}
|
||||
}
|
||||
|
@ -4,13 +4,15 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $cond Condition
|
||||
* @property null|Expr $if Expression for true
|
||||
* @property Expr $else Expression for false
|
||||
*/
|
||||
class Ternary extends Expr
|
||||
{
|
||||
/** @var Expr Condition */
|
||||
public $cond;
|
||||
/** @var null|Expr Expression for true */
|
||||
public $if;
|
||||
/** @var Expr Expression for false */
|
||||
public $else;
|
||||
|
||||
/**
|
||||
* Constructs a ternary operator node.
|
||||
*
|
||||
@ -20,13 +22,13 @@ class Ternary extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $cond, $if, Expr $else, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'cond' => $cond,
|
||||
'if' => $if,
|
||||
'else' => $else
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->cond = $cond;
|
||||
$this->if = $if;
|
||||
$this->else = $else;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('cond', 'if', 'else');
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $expr Expression
|
||||
*/
|
||||
class UnaryMinus extends Expr
|
||||
{
|
||||
/** @var Expr Expression */
|
||||
public $expr;
|
||||
|
||||
/**
|
||||
* Constructs a unary minus node.
|
||||
*
|
||||
@ -16,11 +16,11 @@ class UnaryMinus extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $expr, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'expr' => $expr
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->expr = $expr;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('expr');
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property Expr $expr Expression
|
||||
*/
|
||||
class UnaryPlus extends Expr
|
||||
{
|
||||
/** @var Expr Expression */
|
||||
public $expr;
|
||||
|
||||
/**
|
||||
* Constructs a unary plus node.
|
||||
*
|
||||
@ -16,11 +16,11 @@ class UnaryPlus extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $expr, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'expr' => $expr
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->expr = $expr;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('expr');
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property string|Expr $name Name
|
||||
*/
|
||||
class Variable extends Expr
|
||||
{
|
||||
/** @var string|Expr Name */
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* Constructs a variable node.
|
||||
*
|
||||
@ -16,11 +16,11 @@ class Variable extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($name, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'name' => $name
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('name');
|
||||
}
|
||||
}
|
||||
|
26
lib/PhpParser/Node/Expr/YieldFrom.php
Normal file
26
lib/PhpParser/Node/Expr/YieldFrom.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
class YieldFrom extends Expr
|
||||
{
|
||||
/** @var Expr Expression to yield from */
|
||||
public $expr;
|
||||
|
||||
/**
|
||||
* Constructs an "yield from" node.
|
||||
*
|
||||
* @param Expr $expr Expression
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $expr, array $attributes = array()) {
|
||||
parent::__construct($attributes);
|
||||
$this->expr = $expr;
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('expr');
|
||||
}
|
||||
}
|
@ -4,12 +4,13 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property null|Expr $value Value expression
|
||||
* @property null|Expr $key Key expression
|
||||
*/
|
||||
class Yield_ extends Expr
|
||||
{
|
||||
/** @var null|Expr Key expression */
|
||||
public $key;
|
||||
/** @var null|Expr Value expression */
|
||||
public $value;
|
||||
|
||||
/**
|
||||
* Constructs a yield expression node.
|
||||
*
|
||||
@ -18,12 +19,12 @@ class Yield_ extends Expr
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $value = null, Expr $key = null, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'key' => $key,
|
||||
'value' => $value,
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->key = $key;
|
||||
$this->value = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('key', 'value');
|
||||
}
|
||||
}
|
36
lib/PhpParser/Node/FunctionLike.php
Normal file
36
lib/PhpParser/Node/FunctionLike.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace PhpParser\Node;
|
||||
|
||||
use PhpParser\Node;
|
||||
|
||||
interface FunctionLike extends Node
|
||||
{
|
||||
/**
|
||||
* Whether to return by reference
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function returnsByRef();
|
||||
|
||||
/**
|
||||
* List of parameters
|
||||
*
|
||||
* @return Node\Param[]
|
||||
*/
|
||||
public function getParams();
|
||||
|
||||
/**
|
||||
* Get the declared return type or null
|
||||
*
|
||||
* @return null|string|Node\Name
|
||||
*/
|
||||
public function getReturnType();
|
||||
|
||||
/**
|
||||
* The function body
|
||||
*
|
||||
* @return Node\Stmt[]
|
||||
*/
|
||||
public function getStmts();
|
||||
}
|
@ -4,11 +4,11 @@ namespace PhpParser\Node;
|
||||
|
||||
use PhpParser\NodeAbstract;
|
||||
|
||||
/**
|
||||
* @property array $parts Parts of the name
|
||||
*/
|
||||
class Name extends NodeAbstract
|
||||
{
|
||||
/** @var string[] Parts of the name */
|
||||
public $parts;
|
||||
|
||||
/**
|
||||
* Constructs a name node.
|
||||
*
|
||||
@ -20,12 +20,12 @@ class Name extends NodeAbstract
|
||||
$parts = explode('\\', $parts);
|
||||
}
|
||||
|
||||
parent::__construct(
|
||||
array(
|
||||
'parts' => $parts,
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
parent::__construct($attributes);
|
||||
$this->parts = $parts;
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('parts');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,37 +106,45 @@ class Name extends NodeAbstract
|
||||
/**
|
||||
* Sets the whole name.
|
||||
*
|
||||
* @deprecated Create a new Name instead, or manually modify the $parts property
|
||||
*
|
||||
* @param string|array|self $name The name to set the whole name to
|
||||
*/
|
||||
public function set($name) {
|
||||
$this->parts = $this->prepareName($name);
|
||||
$this->parts = self::prepareName($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends a name to this name.
|
||||
*
|
||||
* @deprecated Use Name::concat($name1, $name2) instead
|
||||
*
|
||||
* @param string|array|self $name Name to prepend
|
||||
*/
|
||||
public function prepend($name) {
|
||||
$this->parts = array_merge($this->prepareName($name), $this->parts);
|
||||
$this->parts = array_merge(self::prepareName($name), $this->parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a name to this name.
|
||||
*
|
||||
* @deprecated Use Name::concat($name1, $name2) instead
|
||||
*
|
||||
* @param string|array|self $name Name to append
|
||||
*/
|
||||
public function append($name) {
|
||||
$this->parts = array_merge($this->parts, $this->prepareName($name));
|
||||
$this->parts = array_merge($this->parts, self::prepareName($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the first part of the name.
|
||||
*
|
||||
* @deprecated Use concat($first, $name->slice(1)) instead
|
||||
*
|
||||
* @param string|array|self $name The name to set the first part to
|
||||
*/
|
||||
public function setFirst($name) {
|
||||
array_splice($this->parts, 0, 1, $this->prepareName($name));
|
||||
array_splice($this->parts, 0, 1, self::prepareName($name));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -145,7 +153,47 @@ class Name extends NodeAbstract
|
||||
* @param string|array|self $name The name to set the last part to
|
||||
*/
|
||||
public function setLast($name) {
|
||||
array_splice($this->parts, -1, 1, $this->prepareName($name));
|
||||
array_splice($this->parts, -1, 1, self::prepareName($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a slice of a name (similar to array_slice).
|
||||
*
|
||||
* This method returns a new instance of the same type as the original and with the same
|
||||
* attributes.
|
||||
*
|
||||
* If the slice is empty, a Name with an empty parts array is returned. While this is
|
||||
* meaningless in itself, it works correctly in conjunction with concat().
|
||||
*
|
||||
* @param int $offset Offset to start the slice at
|
||||
*
|
||||
* @return static Sliced name
|
||||
*/
|
||||
public function slice($offset) {
|
||||
// TODO negative offset and length
|
||||
if ($offset < 0 || $offset > count($this->parts)) {
|
||||
throw new \OutOfBoundsException(sprintf('Offset %d is out of bounds', $offset));
|
||||
}
|
||||
|
||||
return new static(array_slice($this->parts, $offset), $this->attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate two names, yielding a new Name instance.
|
||||
*
|
||||
* The type of the generated instance depends on which class this method is called on, for
|
||||
* example Name\FullyQualified::concat() will yield a Name\FullyQualified instance.
|
||||
*
|
||||
* @param string|array|self $name1 The first name
|
||||
* @param string|array|self $name2 The second name
|
||||
* @param array $attributes Attributes to assign to concatenated name
|
||||
*
|
||||
* @return static Concatenated name
|
||||
*/
|
||||
public static function concat($name1, $name2, array $attributes = []) {
|
||||
return new static(
|
||||
array_merge(self::prepareName($name1), self::prepareName($name2)), $attributes
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -156,7 +204,7 @@ class Name extends NodeAbstract
|
||||
*
|
||||
* @return array Prepared name
|
||||
*/
|
||||
protected function prepareName($name) {
|
||||
private static function prepareName($name) {
|
||||
if (is_string($name)) {
|
||||
return explode('\\', $name);
|
||||
} elseif (is_array($name)) {
|
||||
@ -169,4 +217,4 @@ class Name extends NodeAbstract
|
||||
'When changing a name you need to pass either a string, an array or a Name node'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,15 +5,19 @@ namespace PhpParser\Node;
|
||||
use PhpParser\Error;
|
||||
use PhpParser\NodeAbstract;
|
||||
|
||||
/**
|
||||
* @property null|string|Name $type Typehint
|
||||
* @property bool $byRef Whether is passed by reference
|
||||
* @property bool $variadic Whether this is a variadic argument
|
||||
* @property string $name Name
|
||||
* @property null|Expr $default Default value
|
||||
*/
|
||||
class Param extends NodeAbstract
|
||||
{
|
||||
/** @var null|string|Name Typehint */
|
||||
public $type;
|
||||
/** @var bool Whether parameter is passed by reference */
|
||||
public $byRef;
|
||||
/** @var bool Whether this is a variadic argument */
|
||||
public $variadic;
|
||||
/** @var string Name */
|
||||
public $name;
|
||||
/** @var null|Expr Default value */
|
||||
public $default;
|
||||
|
||||
/**
|
||||
* Constructs a parameter node.
|
||||
*
|
||||
@ -24,20 +28,20 @@ class Param extends NodeAbstract
|
||||
* @param bool $variadic Whether this is a variadic argument
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($name, $default = null, $type = null, $byRef = false, $variadic = false, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'type' => $type,
|
||||
'byRef' => $byRef,
|
||||
'variadic' => $variadic,
|
||||
'name' => $name,
|
||||
'default' => $default,
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
public function __construct($name, Expr $default = null, $type = null, $byRef = false, $variadic = false, array $attributes = array()) {
|
||||
parent::__construct($attributes);
|
||||
$this->type = $type;
|
||||
$this->byRef = $byRef;
|
||||
$this->variadic = $variadic;
|
||||
$this->name = $name;
|
||||
$this->default = $default;
|
||||
|
||||
if ($variadic && null !== $default) {
|
||||
throw new Error('Variadic parameter cannot have a default value');
|
||||
throw new Error('Variadic parameter cannot have a default value', $default->getAttributes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('type', 'byRef', 'variadic', 'name', 'default');
|
||||
}
|
||||
}
|
||||
|
@ -4,27 +4,29 @@ namespace PhpParser\Node\Scalar;
|
||||
|
||||
use PhpParser\Node\Scalar;
|
||||
|
||||
/**
|
||||
* @property float $value Number value
|
||||
*/
|
||||
class DNumber extends Scalar
|
||||
{
|
||||
/** @var float Number value */
|
||||
public $value;
|
||||
|
||||
/**
|
||||
* Constructs a float number scalar node.
|
||||
*
|
||||
* @param float $value Value of the number
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($value = 0.0, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'value' => $value
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
public function __construct($value, array $attributes = array()) {
|
||||
parent::__construct($attributes);
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('value');
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* Parses a DNUMBER token like PHP would.
|
||||
*
|
||||
* @param string $str A string number
|
||||
@ -59,4 +61,4 @@ class DNumber extends Scalar
|
||||
// dec
|
||||
return (float) $str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,23 +4,23 @@ namespace PhpParser\Node\Scalar;
|
||||
|
||||
use PhpParser\Node\Scalar;
|
||||
|
||||
/**
|
||||
* @property array $parts Encaps list
|
||||
*/
|
||||
class Encapsed extends Scalar
|
||||
{
|
||||
/** @var array Encaps list */
|
||||
public $parts;
|
||||
|
||||
/**
|
||||
* Constructs an encapsed string node.
|
||||
*
|
||||
* @param array $parts Encaps list
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(array $parts = array(), array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'parts' => $parts
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
public function __construct(array $parts, array $attributes = array()) {
|
||||
parent::__construct($attributes);
|
||||
$this->parts = $parts;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('parts');
|
||||
}
|
||||
}
|
||||
|
@ -4,27 +4,29 @@ namespace PhpParser\Node\Scalar;
|
||||
|
||||
use PhpParser\Node\Scalar;
|
||||
|
||||
/**
|
||||
* @property int $value Number value
|
||||
*/
|
||||
class LNumber extends Scalar
|
||||
{
|
||||
/** @var int Number value */
|
||||
public $value;
|
||||
|
||||
/**
|
||||
* Constructs an integer number scalar node.
|
||||
*
|
||||
* @param int $value Value of the number
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($value = 0, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'value' => $value
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
public function __construct($value, array $attributes = array()) {
|
||||
parent::__construct($attributes);
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('value');
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* Parses an LNUMBER token (dec, hex, oct and bin notations) like PHP would.
|
||||
*
|
||||
* @param string $str A string number
|
||||
@ -56,4 +58,4 @@ class LNumber extends Scalar
|
||||
// dec
|
||||
return (int) $str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user