the whole shebang

This commit is contained in:
2014-11-25 16:42:40 +01:00
parent 7f74c0613e
commit ab1334c0cf
3686 changed files with 496409 additions and 1 deletions

7
vendor/nikic/php-parser/.travis.yml vendored Normal file
View File

@@ -0,0 +1,7 @@
language: php
php:
- 5.2
- 5.3
- 5.4
- 5.5

155
vendor/nikic/php-parser/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,155 @@
Version 0.9.5-dev
-----------------
Nothing yet.
Version 0.9.4 (25.08.2013)
--------------------------
* [PHP 5.5] Add support for `ClassName::class`. This is parsed as an `Expr_ClassConstFetch` with `'class'` being the
constant name.
* Syntax errors now include information on expected tokens and mimic the format of PHP's own (pre 5.4) error messages.
Example:
Old: Unexpected token T_STATIC on line 1
New: Syntax error, unexpected T_STATIC, expecting T_STRING or T_NS_SEPARATOR or '{'
* `PHPParser_PrettyPrinter_Zend` was renamed to `PHPParser_PrettyPrinter_Default` as the default pretty printer only
very loosely applies the Zend Coding Standard. The class `PHPParser_PrettyPrinter_Zend` extends
`PHPParser_PrettyPrinter_Default` to maintain backwards compatibility.
* The pretty printer now prints namespaces in semicolon-style if possible (i.e. if the file does not contain a global
namespace declaration).
* Added `prettyPrintFile(array $stmts)` method which will pretty print a file of statements including the opening
`<?php` tag if it is required. Use of this method will also eliminate the unnecessary `<?php ?>` at the start and end
of files using inline HTML.
* There now is a builder for interfaces (`PHPParser_Builder_Interface`).
* An interface for the node traversation has been added: `PHPParser_NodeTraverserInterface`
* Fix pretty printing of `include` expressions (precedence information was missing).
* Fix "undefined index" notices when generating the expected tokens for a syntax error.
* Improve performance of `PrettyPrinter` construction by no longer using the `uniqid()` function.
Version 0.9.3 (22.11.2012)
--------------------------
* [BC] As `list()` in `foreach` is now supported the structure of list assignments changed:
1. There is no longer a dedicated `AssignList` node; instead a normal `Assign` node is used with a `List` as `var`.
2. Nested lists are now `List` nodes too, instead of just arrays.
* [BC] As arbitrary expressions are allowed in `empty()` now its subnode was renamed from `var` to `expr`.
* [BC] The protected `pSafe()` method in `PrettyPrinterAbstract` was renamed to `pNoIndent()`.
* [PHP 5.5] Add support for arbitrary expressions in `empty()`.
* [PHP 5.5] Add support for constant array / string dereferencing.
Examples: `"foo"[2]`, `[1, 2, 3][2]`
* [PHP 5.5] Add support for `yield` expressions. This adds a new `Yield` expression type, with subnodes `key` and
`value`.
* [PHP 5.5] Add support for `finally`. This adds a new `finallyStmts` subnode to the `TryCatch` node. If there is no
finally clause it will be `null`.
* [PHP 5.5] Add support for `list()` destructuring of `foreach` values.
Example: `foreach ($coords as list($x, $y)) { ... }`
* Improve pretty printing of expressions by printing less unnecessary parentheses. In particular concatenations are now
printed as `$a . $b . $c . $d . $e` rather than `$a . ($b . ($c . ($d . $e)))`. This is implemented by taking operator
associativity into account. New protected methods added to the pretty printer are `pPrec()`, `pInfixOp()`,
`pPrefixOp()` and `pPostfixOp()`. This also fixes an issue with extraneous parentheses in closure bodies.
* Fix formatting of fall-through `case` statements in the Zend pretty printer.
* Fix parsing of `$foo =& new Bar`. It is now properly parsed as `AssignRef` (instead of `Assign`).
* Fix assignment of `$endAttributes`. Sometimes the attributes of the token right after the node were assigned, rather
than the attributes of the last token in the node.
* `rebuildParser.php` is now designed to be run from the command line rather than from the browser.
Version 0.9.2 (07.07.2012)
--------------------------
* Add `Class->getMethods()` function, which returns all methods contained in the `stmts` array of the class node. This
does not take inherited methods into account.
* Add `isPublic()`, `isProtected()`, `isPrivate()`. `isAbstract()`, `isFinal()` and `isStatic()` accessors to the
`ClassMethod`, `Property` and `Class` nodes. (`Property` and `Class` obviously only have the accessors relevant to
them.)
* Fix parsing of new expressions in parentheses, e.g. `return(new Foo);`.
* [BC] Due to the below changes nodes now optionally accept an `$attributes` array as the
last parameter, instead of the previously used `$line` and `$docComment` parameters.
* Add mechanism for adding attributes to nodes in the lexer.
The following attributes are now added by default:
* `startLine`: The line the node started in.
* `endLine`: The line the node ended in.
* `comments`: An array of comments. The comments are instances of `PHPParser_Comment`
(or `PHPParser_Comment_Doc` for doc comments).
The methods `getLine()` and `setLine()` still exist and function as before, but internally
operator on the `startLine` attribute.
`getDocComment()` also continues to exist. It returns the last comment in the `comments`
attribute if it is a doc comment, otherwise `null`. As `getDocComment()` now returns a
comment object (which can be modified using `->setText()`) the `setDocComment()` method was
removed. Comment objects implement a `__toString()` method, so `getDocComment()` should
continue to work properly with old code.
* [BC] Use inject-once approach for lexer:
Now the lexer is injected only once when creating the parser. Instead of
$parser = new PHPParser_Parser;
$parser->parse(new PHPParser_Lexer($code));
$parser->parse(new PHPParser_Lexer($code2));
you write:
$parser = new PHPParser_Parser(new PHPParser_Lexer);
$parser->parse($code);
$parser->parse($code2);
* Fix `NameResolver` visitor to also resolve class names in `catch` blocks.
Version 0.9.1 (24.04.2012)
--------------------------
* Add ability to add attributes to nodes:
It is now possible to add attributes to a node using `$node->setAttribute('name', 'value')` and to retrieve them using
`$node->getAttribute('name' [, 'default'])`. Additionally the existance of an attribute can be checked with
`$node->hasAttribute('name')` and all attributes can be returned using `$node->getAttributes()`.
* Add code generation features: Builders and templates.
For more infos, see the [code generation documentation][1].
* [BC] Don't traverse nodes merged by another visitor:
If a NodeVisitor returns an array of nodes to merge, these will no longer be traversed by all other visitors. This
behavior only caused problems.
* Fix line numbers for some list structures.
* Fix XML unserialization of empty nodes.
* Fix parsing of integers that overflow into floats.
* Fix emulation of NOWDOC and binary floats.
Version 0.9.0 (05.01.2012)
--------------------------
First version.
[1]: https://github.com/nikic/PHP-Parser/blob/master/doc/3_Code_generation.markdown

31
vendor/nikic/php-parser/LICENSE vendored Normal file
View File

@@ -0,0 +1,31 @@
Copyright (c) 2011 by Nikita Popov.
Some rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* The names of the contributors may not be used to endorse or
promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

78
vendor/nikic/php-parser/README.md vendored Normal file
View File

@@ -0,0 +1,78 @@
PHP Parser
==========
This is a PHP 5.5 (and older) parser written in PHP. It's purpose is to simplify static code analysis and
manipulation.
Documentation can be found in the [`doc/`][1] directory.
***Note: This project is experimental, so the API is subject to change.***
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:
```php
<?php
echo 'Hi', 'World';
hello\world('foo', 'bar' . 'baz');
```
You'll get a syntax tree looking roughly like this:
```
array(
0: Stmt_Echo(
exprs: array(
0: Scalar_String(
value: Hi
)
1: Scalar_String(
value: World
)
)
)
1: Expr_FuncCall(
name: Name(
parts: array(
0: hello
1: world
)
)
args: array(
0: Arg(
value: Scalar_String(
value: foo
)
byRef: false
)
1: Arg(
value: Expr_Concat(
left: Scalar_String(
value: bar
)
right: Scalar_String(
value: baz
)
)
byRef: false
)
)
)
)
```
You can then work with this syntax tree, for example to statically analyze the code (e.g. to find
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][1].
[1]: https://github.com/nikic/PHP-Parser/tree/master/doc

23
vendor/nikic/php-parser/composer.json vendored Normal file
View File

@@ -0,0 +1,23 @@
{
"name": "nikic/php-parser",
"description": "A PHP parser written in PHP",
"keywords": ["php", "parser"],
"type": "library",
"license": "BSD-3-Clause",
"authors": [
{
"name": "Nikita Popov"
}
],
"require": {
"php": ">=5.2"
},
"autoload": {
"psr-0": { "PHPParser": "lib/" }
},
"extra": {
"branch-alias": {
"dev-master": "0.9-dev"
}
}
}

View File

@@ -0,0 +1,81 @@
Introduction
============
This project is a PHP 5.5 (and older) 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
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
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.
For example an AST abstracts away the fact that in PHP variables can be written as `$foo`, but also
as `$$bar`, `${'foobar'}` or even `${!${''}=barfoo()}`. You don't have to worry about recognizing
all the different syntaxes from a stream of tokens.
Another questions is: Why would I want to have a PHP parser *written in PHP*? Well, PHP might not be
a language especially suited for fast parsing, but processing the AST is much easier in PHP than it
would be in other, faster languages like C. Furthermore the people most probably wanting to do
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).
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.
What output does it produce?
----------------------------
The parser produces an [Abstract Syntax Tree][1] (AST) also known as a node tree. How this looks like
can best be seen in an example. The program `<?php echo 'Hi', 'World';` will give you a node tree
roughly looking like this:
```
array(
0: Stmt_Echo(
exprs: array(
0: Scalar_String(
value: Hi
)
1: Scalar_String(
value: World
)
)
)
)
```
This matches the semantics the program had: 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).
So using it for formatting analysis is not possible.
What else can it do?
--------------------
Apart from the parser itself this package also bundles support for some other, related features:
* Support for pretty printing, which is the act of converting an AST into PHP code. Please note
that "pretty printing" does not imply that the output is especially pretty. It's just how it's
called ;)
* Support for serializing and unserializing the node tree to XML
* Support for dumping the node tree in a human readable form (see the section above for an
example of how the output looks like)
* Infrastructure for traversing and changing the AST (node traverser and node visitors)
* A node visitor for resolving namespaced names
[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

View File

@@ -0,0 +1,48 @@
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:
{
"require": {
"nikic/php-parser": "0.9.4"
}
}
Then install Composer in your project (or [download the composer.phar][1] directly):
curl -s http://getcomposer.org/installer | php
And finally ask Composer to install the dependencies:
php composer.phar install
Installing as a PEAR package
----------------------------
Run the following two commands:
pear channel-discover nikic.github.com/pear
pear install nikic/PHPParser-0.9.4
Installing as a Git Submodule
-----------------------------
Run the following command to install the parser into the `vendor/PHP-Parser` folder:
git submodule add git://github.com/nikic/PHP-Parser.git vendor/PHP-Parser
[1]: http://getcomposer.org/composer.phar
[2]: https://github.com/nikic/PHP-Parser/tags

View File

@@ -0,0 +1,394 @@
Usage of basic components
=========================
This document explains how to use the parser, the pretty printer and the node traverser.
Bootstrapping
-------------
The library needs to register a class autoloader; this is done by including the
`bootstrap.php` file:
```php
<?php
require 'path/to/PHP-Parser/lib/bootstrap.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);
```
This ensures that there will be no errors when traversing highly nested node trees.
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.
```php
<?php
$code = '<?php // some code';
$parser = new PHPParser_Parser(new PHPParser_Lexer);
try {
$stmts = $parser->parse($code);
} catch (PHPParser_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.
Node tree
---------
If you use the above code with `$code = "<?php echo 'Hi ', hi\\getTarget();"` the parser will
generate a node tree looking like this:
```
array(
0: Stmt_Echo(
exprs: array(
0: Scalar_String(
value: Hi
)
1: Expr_FuncCall(
name: Name(
parts: array(
0: hi
1: getTarget
)
)
args: array(
)
)
)
)
)
```
Thus `$stmts` will contain an array with only one node, with this node being an instance of
`PHPParser_Node_Stmt_Echo`.
As PHP is a large language there are approximately 140 different nodes. In order to make work
with them easier they are grouped into three categories:
* `PHPParser_Node_Stmt`s are statement nodes, i.e. language constructs that do not return
a value and can not occur in an expression. For example a class definition is a statement.
It doesn't return a value and you can't write something like `func(class A {});`.
* `PHPParser_Node_Expr`s are expression nodes, i.e. language constructs that return a value
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
like `__FILE__` (`PHPParser_Node_Scalar_FileConst`). 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`)
and call arguments (`PHPParser_Node_Arg`).
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
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
without the `PHPParser_Node_` prefix).
It is possible to associate custom metadata with a node using the `setAttribute()` method. This data
can then be retrieved using `hasAttribute()`, `getAttribute()` and `getAttributes()`.
By default the lexer adds the `startLine`, `endLine` and `comments` attributes. `comments` is an array
of `PHPParser_Comment[_Doc]` instances.
The start line can also be accessed using `getLine()`/`setLine()` (instead of `getAttribute('startLine')`).
The last doc comment from the `comments` attribute can be obtained using `getDocComment()`.
Pretty printer
--------------
The pretty printer component compiles the AST back to PHP code. As the parser does not retain formatting
information the formatting is done using a specified scheme. Currently there is only one scheme available,
namely `PHPParser_PrettyPrinter_Default`.
```php
<?php
$code = "<?php echo 'Hi ', hi\\getTarget();";
$parser = new PHPParser_Parser(new PHPParser_Lexer);
$prettyPrinter = new PHPParser_PrettyPrinter_Default;
try {
// parse
$stmts = $parser->parse($code);
// change
$stmts[0] // the echo statement
->exprs // sub expressions
[0] // the first of them (the string node)
->value // it's value, i.e. 'Hi '
= 'Hallo '; // change to 'Hallo '
// pretty print
$code = '<?php ' . $prettyPrinter->prettyPrint($stmts);
echo $code;
} catch (PHPParser_Error $e) {
echo 'Parse Error: ', $e->getMessage();
}
```
The above code will output:
<?php echo 'Hallo ', 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_Default->prettyPrint`.
The `prettyPrint` method pretty prints a statements array. It is also possible to pretty print only a
single expression using `prettyPrintExpr`.
Node traversation
-----------------
The above pretty printing example used the fact that the source code was known and thus it was easy to
write code that accesses a certain part of a node tree and changes it. Normally this is not the case.
Usually you want to change / analyze code in a generic way, where you don't know how the node tree is
going to look like.
For this purpose the parser provides a component for traversing and visiting the node tree. The basic
structure of a program using this `PHPParser_NodeTraverser` looks like this:
```php
<?php
$code = "<?php // some code";
$parser = new PHPParser_Parser(new PHPParser_Lexer);
$traverser = new PHPParser_NodeTraverser;
$prettyPrinter = new PHPParser_PrettyPrinter_Default;
// add your visitor
$traverser->addVisitor(new MyNodeVisitor);
try {
// parse
$stmts = $parser->parse($code);
// traverse
$stmts = $traverser->traverse($stmts);
// pretty print
$code = '<?php ' . $prettyPrinter->prettyPrint($stmts);
echo $code;
} catch (PHPParser_Error $e) {
echo 'Parse Error: ', $e->getMessage();
}
```
A same node visitor for this code might look like this:
```php
<?php
class MyNodeVisitor extends PHPParser_NodeVisitorAbstract
{
public function leaveNode(PHPParser_Node $node) {
if ($node instanceof PHPParser_Node_Scalar_String) {
$node->value = 'foo';
}
}
}
```
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
methods:
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
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
it is called once after the traversal.
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)`.
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.
The NameResolver node visitor
-----------------------------
One visitor is already bundled with the package: `PHPParser_NodeVisitor_NameResolver`. This visitor
helps you work with namespaced code by trying to resolve most names to fully qualified ones.
For example, consider the following code:
use A as B;
new B\C();
In order to know that `B\C` really is `A\C` you would need to track aliases and namespaces yourself.
The `NameResolver` takes care of that and resolves names as far as possible.
After running it most names will be fully qualified. The only names that will stay unqualified are
unqualified function and constant names. These are resolved at runtime and thus the visitor can't
know which function they are referring to. In most cases this is a non-issue as the global functions
are meant.
Also the `NameResolver` adds a `namespacedName` subnode to class, function and constant declarations
that contains the namespaced name instead of only the shortname that is available via `name`.
Example: Converting namespaced code to pseudo namespaces
--------------------------------------------------------
A small example to understand the concept: We want to convert namespaced code to pseudo namespaces
so it works on 5.2, i.e. names like `A\\B` should be converted to `A_B`. Note that such conversions
are fairly complicated if you take PHP's dynamic features into account, so our conversion will
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 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_Default;
$traverser->addVisitor(new PHPParser_NodeVisitor_NameResolver); // we will need resolved names
$traverser->addVisitor(new NodeVisitor_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$/');
foreach ($files as $file) {
try {
// read the file that should be converted
$code = file_get_contents($file);
// parse
$stmts = $parser->parse($code);
// traverse
$stmts = $traverser->traverse($stmts);
// pretty print
$code = '<?php ' . $prettyPrinter->prettyPrint($stmts);
// write the converted file to the target directory
file_put_contents(
substr_replace($file->getPathname(), OUT_DIR, 0, strlen(IN_DIR)),
$code
);
} catch (PHPParser_Error $e) {
echo 'Parse Error: ', $e->getMessage();
}
}
```
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
class NodeVisitor_NamespaceConverter extends PHPParser_NodeVisitorAbstract
{
public function leaveNode(PHPParser_Node $node) {
if ($node instanceof PHPParser_Node_Name) {
return new PHPParser_Node_Name($node->toString('_'));
}
}
}
```
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
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:
```php
<?php
class NodeVisitor_NamespaceConverter extends PHPParser_NodeVisitorAbstract
{
public function leaveNode(PHPParser_Node $node) {
if ($node instanceof PHPParser_Node_Name) {
return new PHPParser_Node_Name($node->toString('_'));
} elseif ($node instanceof PHPParser_Node_Stmt_Class
|| $node instanceof PHPParser_Node_Stmt_Interface
|| $node instanceof PHPParser_Node_Stmt_Function) {
$node->name = $node->namespacedName->toString('_');
} elseif ($node instanceof PHPParser_Node_Stmt_Const) {
foreach ($node->consts as $const) {
$const->name = $const->namespacedName->toString('_');
}
}
}
}
```
There is not much more to it than converting the namespaced name to string with `_` as separator.
The last thing we need to do is remove the `namespace` and `use` statements:
```php
<?php
class NodeVisitor_NamespaceConverter extends PHPParser_NodeVisitorAbstract
{
public function leaveNode(PHPParser_Node $node) {
if ($node instanceof PHPParser_Node_Name) {
return new PHPParser_Node_Name($node->toString('_'));
} elseif ($node instanceof PHPParser_Node_Stmt_Class
|| $node instanceof PHPParser_Node_Stmt_Interface
|| $node instanceof PHPParser_Node_Stmt_Function) {
$node->name = $node->namespacedName->toString('_');
} elseif ($node instanceof PHPParser_Node_Stmt_Const) {
foreach ($node->consts as $const) {
$const->name = $const->namespacedName->toString('_');
}
} elseif ($node instanceof PHPParser_Node_Stmt_Namespace) {
// returning an array merges is into the parent array
return $node->stmts;
} elseif ($node instanceof PHPParser_Node_Stmt_Use) {
// returning false removed the node altogether
return false;
}
}
}
```
That's all.

View File

@@ -0,0 +1,201 @@
Other node tree representations
===============================
It is possible to convert the AST in several textual representations, which serve different uses.
Simple serialization
--------------------
It is possible to serialize the node tree using `serialize()` and also unserialize it using
`unserialize()`. The output is not human readable and not easily processable from anything
but PHP, but it is compact and generates fast. The main application thus is in caching.
Human readable dumping
----------------------
Furthermore it is possible to dump nodes into a human readable form 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!!!');
CODE;
$parser = new PHPParser_Parser(new PHPParser_Lexer);
$nodeDumper = new PHPParser_NodeDumper;
try {
$stmts = $parser->parse($code);
echo '<pre>' . htmlspecialchars($nodeDumper->dump($stmts)) . '</pre>';
} catch (PHPParser_Error $e) {
echo 'Parse Error: ', $e->getMessage();
}
```
The above output will have an output looking roughly like this:
```
array(
0: Stmt_Function(
byRef: false
params: array(
0: Param(
name: msg
default: null
type: null
byRef: false
)
)
stmts: array(
0: Stmt_Echo(
exprs: array(
0: Expr_Variable(
name: msg
)
1: Scalar_String(
value:
)
)
)
)
name: printLine
)
1: Expr_FuncCall(
name: Name(
parts: array(
0: printLine
)
)
args: array(
0: Arg(
value: Scalar_String(
value: Hallo World!!!
)
byRef: false
)
)
)
)
```
Serialization to XML
--------------------
It is also possible to serialize the node tree to XML using `PHPParser_Serializer_XML->serialize()`
and to unserialize it using `PHPParser_Unserializer_XML->unserialize()`. This is useful for
interfacing with other languages and applications or for doing transformation using XSLT.
```php
<?php
$code = <<<'CODE'
<?php
function printLine($msg) {
echo $msg, "\n";
}
printLine('Hallo World!!!');
CODE;
$parser = new PHPParser_Parser(new PHPParser_Lexer);
$serializer = new PHPParser_Serializer_XML;
try {
$stmts = $parser->parse($code);
echo '<pre>' . htmlspecialchars($serializer->serialize($stmts)) . '</pre>';
} catch (PHPParser_Error $e) {
echo 'Parse Error: ', $e->getMessage();
}
```
Produces:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<AST xmlns:node="http://nikic.github.com/PHPParser/XML/node" xmlns:subNode="http://nikic.github.com/PHPParser/XML/subNode" xmlns:scalar="http://nikic.github.com/PHPParser/XML/scalar">
<scalar:array>
<node:Stmt_Function line="2">
<subNode:byRef>
<scalar:false/>
</subNode:byRef>
<subNode:params>
<scalar:array>
<node:Param line="2">
<subNode:name>
<scalar:string>msg</scalar:string>
</subNode:name>
<subNode:default>
<scalar:null/>
</subNode:default>
<subNode:type>
<scalar:null/>
</subNode:type>
<subNode:byRef>
<scalar:false/>
</subNode:byRef>
</node:Param>
</scalar:array>
</subNode:params>
<subNode:stmts>
<scalar:array>
<node:Stmt_Echo line="3">
<subNode:exprs>
<scalar:array>
<node:Expr_Variable line="3">
<subNode:name>
<scalar:string>msg</scalar:string>
</subNode:name>
</node:Expr_Variable>
<node:Scalar_String line="3">
<subNode:value>
<scalar:string>
</scalar:string>
</subNode:value>
</node:Scalar_String>
</scalar:array>
</subNode:exprs>
</node:Stmt_Echo>
</scalar:array>
</subNode:stmts>
<subNode:name>
<scalar:string>printLine</scalar:string>
</subNode:name>
</node:Stmt_Function>
<node:Expr_FuncCall line="6">
<subNode:name>
<node:Name line="6">
<subNode:parts>
<scalar:array>
<scalar:string>printLine</scalar:string>
</scalar:array>
</subNode:parts>
</node:Name>
</subNode:name>
<subNode:args>
<scalar:array>
<node:Arg line="6">
<subNode:value>
<node:Scalar_String line="6">
<subNode:value>
<scalar:string>Hallo World!!!</scalar:string>
</subNode:value>
</node:Scalar_String>
</subNode:value>
<subNode:byRef>
<scalar:false/>
</subNode:byRef>
</node:Arg>
</scalar:array>
</subNode:args>
</node:Expr_FuncCall>
</scalar:array>
</AST>
```

View File

@@ -0,0 +1,265 @@
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:
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.
Here is an example:
```php
<?php
$factory = new PHPParser_BuilderFactory;
$node = $factory->class('SomeClass')
->extend('SomeOtherClass')
->implement('A\Few', 'Interfaces')
->makeAbstract() // ->makeFinal()
->addStmt($factory->method('someMethod')
->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')))
)
// 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);
```
This will produce the following output with the default pretty printer:
```php
<?php
abstract class SomeClass extends SomeOtherClass implements A\Few, Interfaces
{
protected $someProperty;
private $anotherProperty = array(1, 2, 3);
abstract function someMethod(SomeClass $someParam);
protected function anotherMethod($someParam = 'test')
{
print $someParam;
}
}
```
Templates
---------
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');
```

View File

@@ -0,0 +1,114 @@
Lexer component documentation
=============================
The lexer is responsible for providing tokens to the parser. The project comes with two lexers: `PHPParser_Lexer` and
`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:
startLexing($code);
getNextToken(&$value = null, &$startAttributes = null, &$endAttributes = null);
handleHaltCompiler();
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:
```php
<?php
class FileLexer extends PHPParser_Lexer {
public function startLexing($fileName) {
if (!file_exists($fileName)) {
throw new InvalidArgumentException(sprintf('File "%s" does not exist', $fileName));
}
parent::startLexing(file_get_contents($fileName));
}
}
$parser = new PHPParser_Parser(new FileLexer);
var_dump($parser->parse('someFile.php'));
var_dump($parser->parse('someOtherFile.php'));
```
getNextToken
------------
`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.
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.
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
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:
```php
<?php
class LessAttributesLexer extends PHPParser_Lexer {
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));
}
$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'] = $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 `();`).

View File

@@ -0,0 +1,29 @@
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
.phpy pseudo language
=====================
The `.phpy` 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 PHPParser_Node_Name(..., ..., $attributes)`
* `Name::abc` is transformed to `PHPParser_Node_Name::abc`
* 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
===================
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`.

View File

@@ -0,0 +1,96 @@
<?php
const GRAMMAR_FILE = './zend_language_parser.phpy';
const LIB = '(?(DEFINE)
(?<singleQuotedString>\'[^\\\\\']*+(?:\\\\.[^\\\\\']*+)*+\')
(?<doubleQuotedString>"[^\\\\"]*+(?:\\\\.[^\\\\"]*+)*+")
(?<string>(?&singleQuotedString)|(?&doubleQuotedString))
(?<comment>/\*[^*]*+(?:\*(?!/)[^*]*+)*+\*/)
(?<code>\{[^\'"/{}]*+(?:(?:(?&string)|(?&comment)|(?&code)|/)[^\'"/{}]*+)*+})
)';
const RULE_BLOCK = '(?<name>[a-z_]++):(?<rules>[^\'"/{};]*+(?:(?:(?&string)|(?&comment)|(?&code)|/|})[^\'"/{};]*+)*+);';
$usedTerminals = array_flip(array(
'T_VARIABLE', 'T_STRING', 'T_INLINE_HTML', 'T_ENCAPSED_AND_WHITESPACE',
'T_LNUMBER', 'T_DNUMBER', 'T_CONSTANT_ENCAPSED_STRING', 'T_STRING_VARNAME', 'T_NUM_STRING'
));
$unusedNonterminals = array_flip(array(
'case_separator', 'optional_comma'
));
function regex($regex) {
return '~' . LIB . '(?:' . str_replace('~', '\~', $regex) . ')~';
}
function magicSplit($regex, $string) {
$pieces = preg_split(regex('(?:(?&string)|(?&comment)|(?&code))(*SKIP)(*FAIL)|' . $regex), $string);
foreach ($pieces as &$piece) {
$piece = trim($piece);
}
return array_filter($pieces);
}
echo '<pre>';
////////////////////
////////////////////
////////////////////
list($defs, $ruleBlocks) = magicSplit('%%', file_get_contents(GRAMMAR_FILE));
if ('' !== trim(preg_replace(regex(RULE_BLOCK), '', $ruleBlocks))) {
die('Not all rule blocks were properly recognized!');
}
preg_match_all(regex(RULE_BLOCK), $ruleBlocks, $ruleBlocksMatches, PREG_SET_ORDER);
foreach ($ruleBlocksMatches as $match) {
$ruleBlockName = $match['name'];
$rules = magicSplit('\|', $match['rules']);
foreach ($rules as &$rule) {
$parts = magicSplit('\s+', $rule);
$usedParts = array();
foreach ($parts as $part) {
if ('{' === $part[0]) {
preg_match_all('~\$([0-9]+)~', $part, $backReferencesMatches, PREG_SET_ORDER);
foreach ($backReferencesMatches as $match) {
$usedParts[$match[1]] = true;
}
}
}
$i = 1;
foreach ($parts as &$part) {
if ('/' === $part[0]) {
continue;
}
if (isset($usedParts[$i])) {
if ('\'' === $part[0] || '{' === $part[0]
|| (ctype_upper($part[0]) && !isset($usedTerminals[$part]))
|| (ctype_lower($part[0]) && isset($unusedNonterminals[$part]))
) {
$part = '<span style="background-color: red; color: white;">' . $part . '</span>';
} else {
$part = '<strong><em>' . $part . '</em></strong>';
}
} elseif ((ctype_upper($part[0]) && isset($usedTerminals[$part]))
|| (ctype_lower($part[0]) && !isset($unusedNonterminals[$part]))
) {
$part = '<span style="background-color: blue; color: white;">' . $part . '</span>';
}
++$i;
}
$rule = implode(' ', $parts);
}
echo $ruleBlockName, ':', "\n", ' ', implode("\n" . ' | ', $rules), "\n", ';', "\n\n";
}

View File

@@ -0,0 +1,361 @@
<?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;
/* 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 PHPParser_Lexer $lexer A lexer
*/
public function __construct(PHPParser_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 PHPParser_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 (PHPParser_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 PHPParser_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;

View File

@@ -0,0 +1,225 @@
<?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';
// check for kmyacc.exe binary in this directory, otherwise fall back to global name
$kmyacc = __DIR__ . '/kmyacc.exe';
if (!file_exists($kmyacc)) {
$kmyacc = 'kmyacc';
}
$options = array_flip($argv);
$optionDebug = isset($options['--debug']);
$optionKeepTmpGrammar = isset($options['--keep-tmp-grammar']);
///////////////////////////////
/// Utility regex constants ///
///////////////////////////////
const LIB = '(?(DEFINE)
(?<singleQuotedString>\'[^\\\\\']*+(?:\\\\.[^\\\\\']*+)*+\')
(?<doubleQuotedString>"[^\\\\"]*+(?:\\\\.[^\\\\"]*+)*+")
(?<string>(?&singleQuotedString)|(?&doubleQuotedString))
(?<comment>/\*[^*]*+(?:\*(?!/)[^*]*+)*+\*/)
(?<code>\{[^\'"/{}]*+(?:(?:(?&string)|(?&comment)|(?&code)|/)[^\'"/{}]*+)*+})
)';
const PARAMS = '\[(?<params>[^[\]]*+(?:\[(?&params)\][^[\]]*+)*+)\]';
const ARGS = '\((?<args>[^()]*+(?:\((?&args)\)[^()]*+)*+)\)';
///////////////////
/// Main script ///
///////////////////
echo 'Building temporary preproprocessed grammar file.', "\n";
$grammarCode = file_get_contents($grammarFile);
$grammarCode = resolveConstants($grammarCode);
$grammarCode = resolveNodes($grammarCode);
$grammarCode = resolveMacros($grammarCode);
$grammarCode = resolveArrays($grammarCode);
file_put_contents($tmpGrammarFile, $grammarCode);
echo "Building parser.\n";
$output = trim(shell_exec("$kmyacc -l -m $skeletonFile -p PHPParser_Parser $tmpGrammarFile 2>&1"));
echo "Output: \"$output\"\n";
moveFileWithDirCheck($tmpResultFile, $parserResultFile);
if ($optionDebug) {
echo "Building debug parser.\n";
$output = trim(shell_exec("$kmyacc -t -v -l -m $skeletonFile -p PHPParser_Parser $tmpGrammarFile 2>&1"));
echo "Output: \"$output\"\n";
moveFileWithDirCheck($tmpResultFile, $debugParserResultFile);
}
if (!$optionKeepTmpGrammar) {
unlink($tmpGrammarFile);
}
///////////////////////////////
/// Preprocessing functions ///
///////////////////////////////
function resolveConstants($code) {
return preg_replace('~[A-Z][a-zA-Z_]++::~', 'PHPParser_Node_$0', $code);
}
function resolveNodes($code) {
return preg_replace_callback(
'~(?<name>[A-Z][a-zA-Z_]++)\s*' . PARAMS . '~',
function($matches) {
// recurse
$matches['params'] = resolveNodes($matches['params']);
$params = magicSplit(
'(?:' . PARAMS . '|' . ARGS . ')(*SKIP)(*FAIL)|,',
$matches['params']
);
$paramCode = '';
foreach ($params as $param) {
$paramCode .= $param . ', ';
}
return 'new PHPParser_Node_' . $matches['name'] . '(' . $paramCode . '$attributes)';
},
$code
);
}
function resolveMacros($code) {
return preg_replace_callback(
'~\b(?<!::|->)(?!array\()(?<name>[a-z][A-Za-z]++)' . ARGS . '~',
function($matches) {
// recurse
$matches['args'] = resolveMacros($matches['args']);
$name = $matches['name'];
$args = magicSplit(
'(?:' . PARAMS . '|' . ARGS . ')(*SKIP)(*FAIL)|,',
$matches['args']
);
if ('error' == $name) {
assertArgs(1, $args, $name);
return 'throw new PHPParser_Error(' . $args[0] . ')';
}
if ('init' == $name) {
return '$$ = array(' . implode(', ', $args) . ')';
}
if ('push' == $name) {
assertArgs(2, $args, $name);
return $args[0] . '[] = ' . $args[1] . '; $$ = ' . $args[0];
}
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] . '; }';
}
if ('toArray' == $name) {
assertArgs(1, $args, $name);
return 'is_array(' . $args[0] . ') ? ' . $args[0] . ' : array(' . $args[0] . ')';
}
if ('parseVar' == $name) {
assertArgs(1, $args, $name);
return 'substr(' . $args[0] . ', 1)';
}
if ('parseEncapsed' == $name) {
assertArgs(2, $args, $name);
return 'foreach (' . $args[0] . ' as &$s) { if (is_string($s)) { $s = PHPParser_Node_Scalar_String::parseEscapeSequences($s, ' . $args[1] . '); } }';
}
if ('parseEncapsedDoc' == $name) {
assertArgs(1, $args, $name);
return 'foreach (' . $args[0] . ' as &$s) { if (is_string($s)) { $s = PHPParser_Node_Scalar_String::parseEscapeSequences($s, null); } } $s = preg_replace(\'~(\r\n|\n|\r)$~\', \'\', $s); if (\'\' === $s) array_pop(' . $args[0] . ');';
}
throw new Exception(sprintf('Unknown macro "%s"', $name));
},
$code
);
}
function assertArgs($num, $args, $name) {
if ($num != count($args)) {
die('Wrong argument count for ' . $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 moveFileWithDirCheck($fromPath, $toPath) {
$dir = dirname($toPath);
if (!is_dir($dir)) {
mkdir($dir, 0777, true);
}
rename($fromPath, $toPath);
}
//////////////////////////////
/// Regex helper functions ///
//////////////////////////////
function regex($regex) {
return '~' . LIB . '(?:' . str_replace('~', '\~', $regex) . ')~';
}
function magicSplit($regex, $string) {
$pieces = preg_split(regex('(?:(?&string)|(?&comment)|(?&code))(*SKIP)(*FAIL)|' . $regex), $string);
foreach ($pieces as &$piece) {
$piece = trim($piece);
}
return array_filter($pieces);
}

View File

@@ -0,0 +1,906 @@
%pure_parser
%expect 2
%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
%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 '['
%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
%%
start:
top_statement_list { $$ = Stmt_Namespace::postprocess($1); }
;
top_statement_list:
top_statement_list top_statement { pushNormalizing($1, $2); }
| /* empty */ { init(); }
;
namespace_name:
T_STRING { init($1); }
| namespace_name T_NS_SEPARATOR T_STRING { push($1, $3); }
;
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[Name[$2], null]; }
| T_NAMESPACE namespace_name '{' top_statement_list '}' { $$ = Stmt_Namespace[Name[$2], $4]; }
| T_NAMESPACE '{' top_statement_list '}' { $$ = Stmt_Namespace[null, $3]; }
| T_USE use_declarations ';' { $$ = Stmt_Use[$2]; }
| T_CONST constant_declaration_list ';' { $$ = Stmt_Const[$2]; }
;
use_declarations:
use_declarations ',' use_declaration { push($1, $3); }
| use_declaration { init($1); }
;
use_declaration:
namespace_name { $$ = Stmt_UseUse[Name[$1], null]; }
| namespace_name T_AS T_STRING { $$ = Stmt_UseUse[Name[$1], $3]; }
| T_NS_SEPARATOR namespace_name { $$ = Stmt_UseUse[Name[$2], null]; }
| T_NS_SEPARATOR namespace_name T_AS T_STRING { $$ = Stmt_UseUse[Name[$2], $4]; }
;
constant_declaration_list:
constant_declaration_list ',' constant_declaration { push($1, $3); }
| constant_declaration { init($1); }
;
constant_declaration:
T_STRING '=' static_scalar { $$ = 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 { error('__halt_compiler() can only be used from the outermost scope'); }
;
statement:
'{' inner_statement_list '}' { $$ = $2; }
| T_IF parentheses_expr statement elseif_list else_single
{ $$ = 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]]; }
| 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]]; }
| T_SWITCH parentheses_expr switch_case_list { $$ = Stmt_Switch[$2, $3]; }
| T_BREAK ';' { $$ = Stmt_Break[null]; }
| T_BREAK expr ';' { $$ = Stmt_Break[$2]; }
| T_CONTINUE ';' { $$ = Stmt_Continue[null]; }
| T_CONTINUE expr ';' { $$ = Stmt_Continue[$2]; }
| T_RETURN ';' { $$ = Stmt_Return[null]; }
| T_RETURN expr ';' { $$ = Stmt_Return[$2]; }
| yield_expr ';' { $$ = $1; }
| 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]; }
;
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; }
;
function_declaration_statement:
T_FUNCTION optional_ref T_STRING '(' parameter_list ')' '{' inner_statement_list '}'
{ $$ = Stmt_Function[$3, [byRef: $2, params: $5, stmts: $8]]; }
;
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 '=' static_scalar { $$ = 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 parentheses_expr statement { $$ = Stmt_ElseIf[$2, toArray($3)]; }
;
new_elseif_list:
/* empty */ { init(); }
| new_elseif_list new_elseif { push($1, $2); }
;
new_elseif:
T_ELSEIF parentheses_expr ':' inner_statement_list { $$ = Stmt_ElseIf[$2, $4]; }
;
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_class_type optional_ref T_VARIABLE
{ $$ = Param[parseVar($3), null, $1, $2]; }
| optional_class_type optional_ref T_VARIABLE '=' static_scalar
{ $$ = Param[parseVar($3), $5, $1, $2]; }
;
optional_class_type:
/* empty */ { $$ = null; }
| name { $$ = $1; }
| T_ARRAY { $$ = 'array'; }
| T_CALLABLE { $$ = 'callable'; }
;
argument_list:
'(' ')' { $$ = array(); }
| '(' non_empty_argument_list ')' { $$ = $2; }
| '(' yield_expr ')' { $$ = array(Arg[$2, false]); }
;
non_empty_argument_list:
argument { init($1); }
| non_empty_argument_list ',' argument { push($1, $3); }
;
argument:
expr { $$ = Arg[$1, false]; }
| '&' variable { $$ = Arg[$2, true]; }
;
global_var_list:
global_var_list ',' global_var { push($1, $3); }
| global_var { init($1); }
;
global_var:
T_VARIABLE { $$ = Expr_Variable[parseVar($1)]; }
| '$' variable { $$ = Expr_Variable[$2]; }
| '$' '{' expr '}' { $$ = Expr_Variable[$3]; }
;
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 '=' static_scalar { $$ = 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 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_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 T_STRING ';'
{ $$ = 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_fully_qualified:
name T_PAAMAYIM_NEKUDOTAYIM T_STRING { $$ = array($1, $3); }
;
trait_method_reference:
trait_method_reference_fully_qualified { $$ = $1; }
| T_STRING { $$ = array(null, $1); }
;
method_body:
';' /* abstract method */ { $$ = null; }
| '{' inner_statement_list '}' { $$ = $2; }
;
variable_modifiers:
non_empty_member_modifiers { $$ = $1; }
| T_VAR { $$ = Stmt_Class::MODIFIER_PUBLIC; }
;
method_modifiers:
/* empty */ { $$ = Stmt_Class::MODIFIER_PUBLIC; }
| 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 '=' static_scalar { $$ = 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_AssignPlus [$1, $3]; }
| variable T_MINUS_EQUAL expr { $$ = Expr_AssignMinus [$1, $3]; }
| variable T_MUL_EQUAL expr { $$ = Expr_AssignMul [$1, $3]; }
| variable T_DIV_EQUAL expr { $$ = Expr_AssignDiv [$1, $3]; }
| variable T_CONCAT_EQUAL expr { $$ = Expr_AssignConcat [$1, $3]; }
| variable T_MOD_EQUAL expr { $$ = Expr_AssignMod [$1, $3]; }
| variable T_AND_EQUAL expr { $$ = Expr_AssignBitwiseAnd[$1, $3]; }
| variable T_OR_EQUAL expr { $$ = Expr_AssignBitwiseOr [$1, $3]; }
| variable T_XOR_EQUAL expr { $$ = Expr_AssignBitwiseXor[$1, $3]; }
| variable T_SL_EQUAL expr { $$ = Expr_AssignShiftLeft [$1, $3]; }
| variable T_SR_EQUAL expr { $$ = Expr_AssignShiftRight[$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_BooleanOr [$1, $3]; }
| expr T_BOOLEAN_AND expr { $$ = Expr_BooleanAnd[$1, $3]; }
| expr T_LOGICAL_OR expr { $$ = Expr_LogicalOr [$1, $3]; }
| expr T_LOGICAL_AND expr { $$ = Expr_LogicalAnd[$1, $3]; }
| expr T_LOGICAL_XOR expr { $$ = Expr_LogicalXor[$1, $3]; }
| expr '|' expr { $$ = Expr_BitwiseOr [$1, $3]; }
| expr '&' expr { $$ = Expr_BitwiseAnd[$1, $3]; }
| expr '^' expr { $$ = Expr_BitwiseXor[$1, $3]; }
| expr '.' expr { $$ = Expr_Concat [$1, $3]; }
| expr '+' expr { $$ = Expr_Plus [$1, $3]; }
| expr '-' expr { $$ = Expr_Minus [$1, $3]; }
| expr '*' expr { $$ = Expr_Mul [$1, $3]; }
| expr '/' expr { $$ = Expr_Div [$1, $3]; }
| expr '%' expr { $$ = Expr_Mod [$1, $3]; }
| expr T_SL expr { $$ = Expr_ShiftLeft [$1, $3]; }
| expr T_SR expr { $$ = Expr_ShiftRight[$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_Identical [$1, $3]; }
| expr T_IS_NOT_IDENTICAL expr { $$ = Expr_NotIdentical [$1, $3]; }
| expr T_IS_EQUAL expr { $$ = Expr_Equal [$1, $3]; }
| expr T_IS_NOT_EQUAL expr { $$ = Expr_NotEqual [$1, $3]; }
| expr '<' expr { $$ = Expr_Smaller [$1, $3]; }
| expr T_IS_SMALLER_OR_EQUAL expr { $$ = Expr_SmallerOrEqual[$1, $3]; }
| expr '>' expr { $$ = Expr_Greater [$1, $3]; }
| expr T_IS_GREATER_OR_EQUAL expr { $$ = Expr_GreaterOrEqual[$1, $3]; }
| expr T_INSTANCEOF class_name_reference { $$ = Expr_Instanceof [$1, $3]; }
| parentheses_expr { $$ = $1; }
/* we need a separate '(' new_expr ')' rule to avoid problems caused by a s/r conflict */
| '(' new_expr ')' { $$ = $2; }
| expr '?' expr ':' expr { $$ = Expr_Ternary[$1, $3, $5]; }
| expr '?' ':' expr { $$ = Expr_Ternary[$1, null, $4]; }
| 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 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_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; }
| array_expr { $$ = $1; }
| scalar_dereference { $$ = $1; }
| '`' 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]]; }
;
parentheses_expr:
'(' expr ')' { $$ = $2; }
| '(' yield_expr ')' { $$ = $2; }
;
yield_expr:
T_YIELD expr { $$ = Expr_Yield[$2, null]; }
| T_YIELD expr T_DOUBLE_ARROW expr { $$ = Expr_Yield[$4, $2]; }
;
array_expr:
T_ARRAY '(' array_pair_list ')' { $$ = Expr_Array[$3]; }
| '[' array_pair_list ']' { $$ = Expr_Array[$2]; }
;
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]; }
| scalar_dereference '[' dim_offset ']' { $$ = Expr_ArrayDimFetch[$1, $3]; }
/* alternative array syntax missing intentionally */
;
new_expr:
T_NEW class_name_reference ctor_arguments { $$ = Expr_New[$2, $3]; }
;
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]; }
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM T_STRING argument_list
{ $$ = Expr_StaticCall[$1, $3, $4]; }
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM '{' expr '}' argument_list
{ $$ = Expr_StaticCall[$1, $4, $6]; }
| static_property argument_list {
if ($1 instanceof PHPParser_Node_Expr_StaticPropertyFetch) {
$$ = Expr_StaticCall[$1->class, Expr_Variable[$1->name], $2];
} elseif ($1 instanceof PHPParser_Node_Expr_ArrayDimFetch) {
$tmp = $1;
while ($tmp->var instanceof PHPParser_Node_Expr_ArrayDimFetch) {
$tmp = $tmp->var;
}
$$ = Expr_StaticCall[$tmp->var->class, $1, $2];
$tmp->var = Expr_Variable[$tmp->var->name];
} else {
throw new Exception;
}
}
| variable_without_objects argument_list
{ $$ = Expr_FuncCall[$1, $2]; }
| function_call '[' dim_offset ']' { $$ = Expr_ArrayDimFetch[$1, $3]; }
/* alternative array syntax missing intentionally */
;
class_name:
T_STATIC { $$ = Name['static']; }
| name { $$ = $1; }
;
name:
namespace_name { $$ = Name[$1]; }
| T_NS_SEPARATOR namespace_name { $$ = Name_FullyQualified[$2]; }
| T_NAMESPACE T_NS_SEPARATOR namespace_name { $$ = Name_Relative[$3]; }
;
class_name_reference:
class_name { $$ = $1; }
| dynamic_class_name_reference { $$ = $1; }
;
dynamic_class_name_reference:
object_access_for_dcnr { $$ = $1; }
| base_variable { $$ = $1; }
;
class_name_or_var:
class_name { $$ = $1; }
| reference_variable { $$ = $1; }
;
object_access_for_dcnr:
| base_variable T_OBJECT_OPERATOR object_property
{ $$ = Expr_PropertyFetch[$1, $3]; }
| object_access_for_dcnr T_OBJECT_OPERATOR object_property
{ $$ = Expr_PropertyFetch[$1, $3]; }
| object_access_for_dcnr '[' dim_offset ']' { $$ = Expr_ArrayDimFetch[$1, $3]; }
| object_access_for_dcnr '{' expr '}' { $$ = Expr_ArrayDimFetch[$1, $3]; }
;
exit_expr:
/* empty */ { $$ = null; }
| '(' ')' { $$ = null; }
| parentheses_expr { $$ = $1; }
;
backticks_expr:
/* empty */ { $$ = array(); }
| T_ENCAPSED_AND_WHITESPACE { $$ = array(Scalar_String::parseEscapeSequences($1, '`')); }
| encaps_list { parseEncapsed($1, '`'); $$ = $1; }
;
ctor_arguments:
/* empty */ { $$ = array(); }
| argument_list { $$ = $1; }
;
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_LINE { $$ = Scalar_LineConst[]; }
| T_FILE { $$ = Scalar_FileConst[]; }
| T_DIR { $$ = Scalar_DirConst[]; }
| T_CLASS_C { $$ = Scalar_ClassConst[]; }
| T_TRAIT_C { $$ = Scalar_TraitConst[]; }
| T_METHOD_C { $$ = Scalar_MethodConst[]; }
| T_FUNC_C { $$ = Scalar_FuncConst[]; }
| T_NS_C { $$ = Scalar_NSConst[]; }
| 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['']; }
| name { $$ = Expr_ConstFetch[$1]; }
;
static_scalar: /* compile-time evaluated scalars */
common_scalar { $$ = $1; }
| class_name T_PAAMAYIM_NEKUDOTAYIM class_const_name { $$ = Expr_ClassConstFetch[$1, $3]; }
| '+' static_scalar { $$ = Expr_UnaryPlus[$2]; }
| '-' static_scalar { $$ = Expr_UnaryMinus[$2]; }
| T_ARRAY '(' static_array_pair_list ')' { $$ = Expr_Array[$3]; }
| '[' static_array_pair_list ']' { $$ = Expr_Array[$2]; }
;
scalar:
common_scalar { $$ = $1; }
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM class_const_name
{ $$ = Expr_ClassConstFetch[$1, $3]; }
| '"' encaps_list '"'
{ parseEncapsed($2, '"'); $$ = 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'; }
;
static_array_pair_list:
/* empty */ { $$ = array(); }
| non_empty_static_array_pair_list optional_comma { $$ = $1; }
;
optional_comma:
/* empty */
| ','
;
non_empty_static_array_pair_list:
non_empty_static_array_pair_list ',' static_array_pair { push($1, $3); }
| static_array_pair { init($1); }
;
static_array_pair:
static_scalar T_DOUBLE_ARROW static_scalar { $$ = Expr_ArrayItem[$3, $1, false]; }
| static_scalar { $$ = Expr_ArrayItem[$1, null, false]; }
;
variable:
object_access { $$ = $1; }
| base_variable { $$ = $1; }
| function_call { $$ = $1; }
| new_expr_array_deref { $$ = $1; }
;
new_expr_array_deref:
'(' new_expr ')' '[' dim_offset ']' { $$ = Expr_ArrayDimFetch[$2, $5]; }
| new_expr_array_deref '[' dim_offset ']' { $$ = Expr_ArrayDimFetch[$1, $3]; }
/* alternative array syntax missing intentionally */
;
object_access:
variable_or_new_expr T_OBJECT_OPERATOR object_property
{ $$ = Expr_PropertyFetch[$1, $3]; }
| variable_or_new_expr T_OBJECT_OPERATOR object_property argument_list
{ $$ = Expr_MethodCall[$1, $3, $4]; }
| object_access argument_list { $$ = Expr_FuncCall[$1, $2]; }
| object_access '[' dim_offset ']' { $$ = Expr_ArrayDimFetch[$1, $3]; }
| object_access '{' expr '}' { $$ = Expr_ArrayDimFetch[$1, $3]; }
;
variable_or_new_expr:
variable { $$ = $1; }
| '(' new_expr ')' { $$ = $2; }
;
variable_without_objects:
reference_variable { $$ = $1; }
| '$' variable_without_objects { $$ = Expr_Variable[$2]; }
;
base_variable:
variable_without_objects { $$ = $1; }
| static_property { $$ = $1; }
;
static_property:
class_name_or_var T_PAAMAYIM_NEKUDOTAYIM '$' reference_variable
{ $$ = Expr_StaticPropertyFetch[$1, $4]; }
| static_property_with_arrays { $$ = $1; }
;
static_property_with_arrays:
class_name_or_var T_PAAMAYIM_NEKUDOTAYIM T_VARIABLE
{ $$ = Expr_StaticPropertyFetch[$1, parseVar($3)]; }
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM '$' '{' expr '}'
{ $$ = Expr_StaticPropertyFetch[$1, $5]; }
| static_property_with_arrays '[' dim_offset ']' { $$ = Expr_ArrayDimFetch[$1, $3]; }
| static_property_with_arrays '{' expr '}' { $$ = Expr_ArrayDimFetch[$1, $3]; }
;
reference_variable:
reference_variable '[' dim_offset ']' { $$ = Expr_ArrayDimFetch[$1, $3]; }
| reference_variable '{' expr '}' { $$ = Expr_ArrayDimFetch[$1, $3]; }
| T_VARIABLE { $$ = Expr_Variable[parseVar($1)]; }
| '$' '{' expr '}' { $$ = Expr_Variable[$3]; }
;
dim_offset:
/* empty */ { $$ = null; }
| expr { $$ = $1; }
;
object_property:
T_STRING { $$ = $1; }
| '{' expr '}' { $$ = $2; }
| variable_without_objects { $$ = $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)]; }
;
%%

View File

@@ -0,0 +1,33 @@
<?php
/**
* @codeCoverageIgnore
*/
class PHPParser_Autoloader
{
/**
* Registers PHPParser_Autoloader as an SPL autoloader.
*/
static public function register()
{
ini_set('unserialize_callback_func', 'spl_autoload_call');
spl_autoload_register(array(__CLASS__, 'autoload'));
}
/**
* Handles autoloading of classes.
*
* @param string $class A class name.
*/
static public function autoload($class)
{
if (0 !== strpos($class, 'PHPParser')) {
return;
}
$file = dirname(dirname(__FILE__)) . '/' . strtr($class, '_', '/') . '.php';
if (is_file($file)) {
require $file;
}
}
}

View File

@@ -0,0 +1,11 @@
<?php
interface PHPParser_Builder
{
/**
* Returns the built node.
*
* @return PHPParser_Node The built node
*/
public function getNode();
}

View File

@@ -0,0 +1,137 @@
<?php
class PHPParser_Builder_Class extends PHPParser_BuilderAbstract
{
protected $name;
protected $extends;
protected $implements;
protected $type;
protected $uses;
protected $constants;
protected $properties;
protected $methods;
/**
* Creates a class builder.
*
* @param string $name Name of the class
*/
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();
}
/**
* Extends a class.
*
* @param PHPParser_Node_Name|string $class Name of class to extend
*
* @return PHPParser_Builder_Class The builder instance (for fluid interface)
*/
public function extend($class) {
$this->extends = $this->normalizeName($class);
return $this;
}
/**
* Implements one or more interfaces.
*
* @param PHPParser_Node_Name|string $interface Name of interface to implement
* @param PHPParser_Node_Name|string $... More interfaces to implement
*
* @return PHPParser_Builder_Class The builder instance (for fluid interface)
*/
public function implement() {
foreach (func_get_args() as $interface) {
$this->implements[] = $this->normalizeName($interface);
}
return $this;
}
/**
* Makes the class abstract.
*
* @return PHPParser_Builder_Class The builder instance (for fluid interface)
*/
public function makeAbstract() {
$this->setModifier(PHPParser_Node_Stmt_Class::MODIFIER_ABSTRACT);
return $this;
}
/**
* Makes the class final.
*
* @return PHPParser_Builder_Class The builder instance (for fluid interface)
*/
public function makeFinal() {
$this->setModifier(PHPParser_Node_Stmt_Class::MODIFIER_FINAL);
return $this;
}
/**
* Adds a statement.
*
* @param PHPParser_Node_Stmt|PHPParser_Builder $stmt The statement to add
*
* @return PHPParser_Builder_Class The builder instance (for fluid interface)
*/
public function addStmt($stmt) {
$stmt = $this->normalizeNode($stmt);
$targets = array(
'Stmt_TraitUse' => &$this->uses,
'Stmt_ClassConst' => &$this->constants,
'Stmt_Property' => &$this->properties,
'Stmt_ClassMethod' => &$this->methods,
);
$type = $stmt->getType();
if (!isset($targets[$type])) {
throw new LogicException(sprintf('Unexpected node of type "%s"', $type));
}
$targets[$type][] = $stmt;
return $this;
}
/**
* Adds multiple statements.
*
* @param array $stmts The statements to add
*
* @return PHPParser_Builder_Class 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.
*
* @return PHPParser_Node_Stmt_Class The built class node
*/
public function getNode() {
return new PHPParser_Node_Stmt_Class($this->name, array(
'type' => $this->type,
'extends' => $this->extends,
'implements' => $this->implements,
'stmts' => array_merge($this->uses, $this->constants, $this->properties, $this->methods),
));
}
}

View File

@@ -0,0 +1,109 @@
<?php
class PHPParser_Builder_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 PHPParser_Builder_Function The builder instance (for fluid interface)
*/
public function makeReturnByRef() {
$this->returnByRef = true;
return $this;
}
/**
* Adds a parameter.
*
* @param PHPParser_Node_Param|PHPParser_Builder_Param $param The parameter to add
*
* @return PHPParser_Builder_Function The builder instance (for fluid interface)
*/
public function addParam($param) {
$param = $this->normalizeNode($param);
if (!$param instanceof PHPParser_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 PHPParser_Builder_Function The builder instance (for fluid interface)
*/
public function addParams(array $params) {
foreach ($params as $param) {
$this->addParam($param);
}
return $this;
}
/**
* Adds a statement.
*
* @param PHPParser_Node|PHPParser_Builder $stmt The statement to add
*
* @return PHPParser_Builder_Function 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 PHPParser_Builder_Function 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 PHPParser_Node_Stmt_Function The built function node
*/
public function getNode() {
return new PHPParser_Node_Stmt_Function($this->name, array(
'byRef' => $this->returnByRef,
'params' => $this->params,
'stmts' => $this->stmts,
));
}
}

View File

@@ -0,0 +1,92 @@
<?php
class PHPParser_Builder_Interface extends PHPParser_BuilderAbstract
{
protected $name;
protected $extends;
protected $constants;
protected $methods;
/**
* Creates an interface builder.
*
* @param string $name Name of the interface
*/
public function __construct($name) {
$this->name = $name;
$this->extends = array();
$this->constants = $this->methods = array();
}
/**
* Extends one or more interfaces.
*
* @param PHPParser_Node_Name|string $interface Name of interface to extend
* @param PHPParser_Node_Name|string $... More interfaces to extend
*
* @return PHPParser_Builder_Interface The builder instance (for fluid interface)
*/
public function extend() {
foreach (func_get_args() as $interface) {
$this->extends[] = $this->normalizeName($interface);
}
return $this;
}
/**
* Adds a statement.
*
* @param PHPParser_Node_Stmt|PHPParser_Builder $stmt The statement to add
*
* @return PHPParser_Builder_Interface The builder instance (for fluid interface)
*/
public function addStmt($stmt) {
$stmt = $this->normalizeNode($stmt);
$type = $stmt->getType();
switch ($type) {
case 'Stmt_ClassConst':
$this->constants[] = $stmt;
break;
case 'Stmt_ClassMethod':
// we erase all statements in the body of an interface method
$stmt->stmts = null;
$this->methods[] = $stmt;
break;
default:
throw new LogicException(sprintf('Unexpected node of type "%s"', $type));
}
return $this;
}
/**
* Adds multiple statements.
*
* @param array $stmts The statements to add
*
* @return PHPParser_Builder_Class 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.
*
* @return PHPParser_Node_Stmt_Interface The built interface node
*/
public function getNode() {
return new PHPParser_Node_Stmt_Interface($this->name, array(
'extends' => $this->extends,
'stmts' => array_merge($this->constants, $this->methods),
));
}
}

View File

@@ -0,0 +1,187 @@
<?php
class PHPParser_Builder_Method extends PHPParser_BuilderAbstract
{
protected $name;
protected $type;
protected $returnByRef;
protected $params;
protected $stmts;
/**
* Creates a method builder.
*
* @param string $name Name of the method
*/
public function __construct($name) {
$this->name = $name;
$this->type = 0;
$this->returnByRef = false;
$this->params = array();
$this->stmts = array();
}
/**
* Makes the method public.
*
* @return PHPParser_Builder_Method The builder instance (for fluid interface)
*/
public function makePublic() {
$this->setModifier(PHPParser_Node_Stmt_Class::MODIFIER_PUBLIC);
return $this;
}
/**
* Makes the method protected.
*
* @return PHPParser_Builder_Method The builder instance (for fluid interface)
*/
public function makeProtected() {
$this->setModifier(PHPParser_Node_Stmt_Class::MODIFIER_PROTECTED);
return $this;
}
/**
* Makes the method private.
*
* @return PHPParser_Builder_Method The builder instance (for fluid interface)
*/
public function makePrivate() {
$this->setModifier(PHPParser_Node_Stmt_Class::MODIFIER_PRIVATE);
return $this;
}
/**
* Makes the method static.
*
* @return PHPParser_Builder_Method The builder instance (for fluid interface)
*/
public function makeStatic() {
$this->setModifier(PHPParser_Node_Stmt_Class::MODIFIER_STATIC);
return $this;
}
/**
* Makes the method abstract.
*
* @return PHPParser_Builder_Method The builder instance (for fluid interface)
*/
public function makeAbstract() {
if (!empty($this->stmts)) {
throw new LogicException('Cannot make method with statements abstract');
}
$this->setModifier(PHPParser_Node_Stmt_Class::MODIFIER_ABSTRACT);
$this->stmts = null; // abstract methods don't have statements
return $this;
}
/**
* Makes the method final.
*
* @return PHPParser_Builder_Method The builder instance (for fluid interface)
*/
public function makeFinal() {
$this->setModifier(PHPParser_Node_Stmt_Class::MODIFIER_FINAL);
return $this;
}
/**
* Make the method return by reference.
*
* @return PHPParser_Builder_Method The builder instance (for fluid interface)
*/
public function makeReturnByRef() {
$this->returnByRef = true;
return $this;
}
/**
* Adds a parameter.
*
* @param PHPParser_Node_Param|PHPParser_Builder_Param $param The parameter to add
*
* @return PHPParser_Builder_Method The builder instance (for fluid interface)
*/
public function addParam($param) {
$param = $this->normalizeNode($param);
if (!$param instanceof PHPParser_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 PHPParser_Builder_Method The builder instance (for fluid interface)
*/
public function addParams(array $params) {
foreach ($params as $param) {
$this->addParam($param);
}
return $this;
}
/**
* Adds a statement.
*
* @param PHPParser_Node|PHPParser_Builder $stmt The statement to add
*
* @return PHPParser_Builder_Method The builder instance (for fluid interface)
*/
public function addStmt($stmt) {
if (null === $this->stmts) {
throw new LogicException('Cannot add statements to an abstract method');
}
$this->stmts[] = $this->normalizeNode($stmt);
return $this;
}
/**
* Adds multiple statements.
*
* @param array $stmts The statements to add
*
* @return PHPParser_Builder_Method 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.
*
* @return PHPParser_Node_Stmt_ClassMethod The built method node
*/
public function getNode() {
return new PHPParser_Node_Stmt_ClassMethod($this->name, array(
'type' => $this->type !== 0 ? $this->type : PHPParser_Node_Stmt_Class::MODIFIER_PUBLIC,
'byRef' => $this->returnByRef,
'params' => $this->params,
'stmts' => $this->stmts,
));
}
}

View File

@@ -0,0 +1,75 @@
<?php
class PHPParser_Builder_Param extends PHPParser_BuilderAbstract
{
protected $name;
protected $default;
protected $type;
protected $byRef;
/**
* Creates a parameter builder.
*
* @param string $name Name of the parameter
*/
public function __construct($name) {
$this->name = $name;
$this->default = null;
$this->type = null;
$this->byRef = false;
}
/**
* Sets default value for the parameter.
*
* @param mixed $value Default value to use
*
* @return PHPParser_Builder_Param The builder instance (for fluid interface)
*/
public function setDefault($value) {
$this->default = $this->normalizeValue($value);
return $this;
}
/**
* Sets type hint for the parameter.
*
* @param string|PHPParser_Node_Name $type Type hint to use
*
* @return PHPParser_Builder_Param The builder instance (for fluid interface)
*/
public function setTypeHint($type) {
if ($type === 'array' || $type === 'callable') {
$this->type = $type;
} else {
$this->type = $this->normalizeName($type);
}
return $this;
}
/**
* Make the parameter accept the value by reference.
*
* @return PHPParser_Builder_Param The builder instance (for fluid interface)
*/
public function makeByRef() {
$this->byRef = true;
return $this;
}
/**
* Returns the built parameter node.
*
* @return PHPParser_Node_Param The built parameter node
*/
public function getNode() {
return new PHPParser_Node_Param(
$this->name, $this->default, $this->type, $this->byRef
);
}
}

View File

@@ -0,0 +1,92 @@
<?php
class PHPParser_Builder_Property extends PHPParser_BuilderAbstract
{
protected $name;
protected $type;
protected $default;
/**
* Creates a property builder.
*
* @param string $name Name of the property
*/
public function __construct($name) {
$this->name = $name;
$this->type = 0;
$this->default = null;
}
/**
* Makes the property public.
*
* @return PHPParser_Builder_Property The builder instance (for fluid interface)
*/
public function makePublic() {
$this->setModifier(PHPParser_Node_Stmt_Class::MODIFIER_PUBLIC);
return $this;
}
/**
* Makes the property protected.
*
* @return PHPParser_Builder_Property The builder instance (for fluid interface)
*/
public function makeProtected() {
$this->setModifier(PHPParser_Node_Stmt_Class::MODIFIER_PROTECTED);
return $this;
}
/**
* Makes the property private.
*
* @return PHPParser_Builder_Property The builder instance (for fluid interface)
*/
public function makePrivate() {
$this->setModifier(PHPParser_Node_Stmt_Class::MODIFIER_PRIVATE);
return $this;
}
/**
* Makes the property static.
*
* @return PHPParser_Builder_Property The builder instance (for fluid interface)
*/
public function makeStatic() {
$this->setModifier(PHPParser_Node_Stmt_Class::MODIFIER_STATIC);
return $this;
}
/**
* Sets default value for the property.
*
* @param mixed $value Default value to use
*
* @return PHPParser_Builder_Property The builder instance (for fluid interface)
*/
public function setDefault($value) {
$this->default = $this->normalizeValue($value);
return $this;
}
/**
* Returns the built class node.
*
* @return PHPParser_Node_Stmt_Property The built property node
*/
public function getNode() {
return new PHPParser_Node_Stmt_Property(
$this->type !== 0 ? $this->type : PHPParser_Node_Stmt_Class::MODIFIER_PUBLIC,
array(
new PHPParser_Node_Stmt_PropertyProperty($this->name, $this->default)
)
);
}
}

View File

@@ -0,0 +1,94 @@
<?php
abstract class PHPParser_BuilderAbstract implements PHPParser_Builder {
/**
* Normalizes a node: Converts builder objects to nodes.
*
* @param PHPParser_Node|PHPParser_Builder $node The node to normalize
*
* @return PHPParser_Node The normalized node
*/
protected function normalizeNode($node) {
if ($node instanceof PHPParser_Builder) {
return $node->getNode();
} elseif ($node instanceof PHPParser_Node) {
return $node;
}
throw new LogicException('Expected node or builder object');
}
/**
* Normalizes a name: Converts plain string names to PHPParser_Node_Name.
*
* @param PHPParser_Node_Name|string $name The name to normalize
*
* @return PHPParser_Node_Name The normalized name
*/
protected function normalizeName($name) {
if ($name instanceof PHPParser_Node_Name) {
return $name;
} else {
return new PHPParser_Node_Name($name);
}
}
/**
* Normalizes a value: Converts nulls, booleans, integers,
* floats, strings and arrays into their respective nodes
*
* @param mixed $value The value to normalize
*
* @return PHPParser_Node_Expr The normalized value
*/
protected function normalizeValue($value) {
if ($value instanceof PHPParser_Node) {
return $value;
} elseif (is_null($value)) {
return new PHPParser_Node_Expr_ConstFetch(
new PHPParser_Node_Name('null')
);
} elseif (is_bool($value)) {
return new PHPParser_Node_Expr_ConstFetch(
new PHPParser_Node_Name($value ? 'true' : 'false')
);
} elseif (is_int($value)) {
return new PHPParser_Node_Scalar_LNumber($value);
} elseif (is_float($value)) {
return new PHPParser_Node_Scalar_DNumber($value);
} elseif (is_string($value)) {
return new PHPParser_Node_Scalar_String($value);
} elseif (is_array($value)) {
$items = array();
$lastKey = -1;
foreach ($value as $itemKey => $itemValue) {
// for consecutive, numeric keys don't generate keys
if (null !== $lastKey && ++$lastKey === $itemKey) {
$items[] = new PHPParser_Node_Expr_ArrayItem(
$this->normalizeValue($itemValue)
);
} else {
$lastKey = null;
$items[] = new PHPParser_Node_Expr_ArrayItem(
$this->normalizeValue($itemValue),
$this->normalizeValue($itemKey)
);
}
}
return new PHPParser_Node_Expr_Array($items);
} else {
throw new LogicException('Invalid value');
}
}
/**
* Sets a modifier in the $this->type property.
*
* @param int $modifier Modifier to set
*/
protected function setModifier($modifier) {
PHPParser_Node_Stmt_Class::verifyModifier($this->type, $modifier);
$this->type |= $modifier;
}
}

View File

@@ -0,0 +1,87 @@
<?php
/**
* "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.
*
* @method PHPParser_Builder_Class class(string $name) Creates a class builder.
* @method PHPParser_Builder_Function function(string $name) Creates a function builder
* @method PHPParser_Builder_Interface interface(string $name) Creates an interface builder.
*/
class PHPParser_BuilderFactory
{
/**
* Creates a class builder.
*
* @param string $name Name of the class
*
* @return PHPParser_Builder_Class The created class builder
*/
protected function _class($name) {
return new PHPParser_Builder_Class($name);
}
/**
* Creates a interface builder.
*
* @param string $name Name of the interface
*
* @return PHPParser_Builder_Class The created interface builder
*/
protected function _interface($name) {
return new PHPParser_Builder_Interface($name);
}
/**
* Creates a method builder.
*
* @param string $name Name of the method
*
* @return PHPParser_Builder_Method The created method builder
*/
public function method($name) {
return new PHPParser_Builder_Method($name);
}
/**
* Creates a parameter builder.
*
* @param string $name Name of the parameter
*
* @return PHPParser_Builder_Param The created parameter builder
*/
public function param($name) {
return new PHPParser_Builder_Param($name);
}
/**
* Creates a property builder.
*
* @param string $name Name of the property
*
* @return PHPParser_Builder_Property The created property builder
*/
public function property($name) {
return new PHPParser_Builder_Property($name);
}
/**
* Creates a function builder.
*
* @param string $name Name of the function
*
* @return PHPParser_Builder_Property The created function builder
*/
protected function _function($name) {
return new PHPParser_Builder_Function($name);
}
public function __call($name, array $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));
}
}

View File

@@ -0,0 +1,117 @@
<?php
class PHPParser_Comment
{
protected $text;
protected $line;
/**
* Constructs a comment node.
*
* @param string $text Comment text (including comment delimiters like /*)
* @param int $line Line number the comment started on
*/
public function __construct($text, $line = -1) {
$this->text = $text;
$this->line = $line;
}
/**
* Gets the comment text.
*
* @return string The comment text (including comment delimiters like /*)
*/
public function getText() {
return $this->text;
}
/**
* Sets the comment text.
*
* @param string $text The comment text (including comment delimiters like /*)
*/
public function setText($text) {
$this->text = $text;
}
/**
* Gets the line number the comment started on.
*
* @return int Line number
*/
public function getLine() {
return $this->line;
}
/**
* Sets the line number the comment started on.
*
* @param int $line Line number
*/
public function setLine($line) {
$this->line = $line;
}
/**
* Gets the comment text.
*
* @return string The comment text (including comment delimiters like /*)
*/
public function __toString() {
return $this->text;
}
/**
* Gets the reformatted comment text.
*
* "Reformatted" here means that we try to clean up the whitespace at the
* starts of the lines. This is necessary because we receive the comments
* without trailing whitespace on the first line, but with trailing whitespace
* on all subsequent lines.
*
* @return mixed|string
*/
public function getReformattedText() {
$text = trim($this->text);
if (false === strpos($text, "\n")) {
// Single line comments don't need further processing
return $text;
} elseif (preg_match('((*BSR_ANYCRLF)(*ANYCRLF)^.*(?:\R\s+\*.*)+$)', $text)) {
// Multi line comment of the type
//
// /*
// * Some text.
// * Some more text.
// */
//
// is handled by replacing the whitespace sequences before the * by a single space
return preg_replace('(^\s+\*)m', ' *', $this->text);
} elseif (preg_match('(^/\*\*?\s*[\r\n])', $text) && preg_match('(\n(\s*)\*/$)', $text, $matches)) {
// Multi line comment of the type
//
// /*
// Some text.
// Some more text.
// */
//
// is handled by removing the whitespace sequence on the line before the closing
// */ on all lines. So if the last line is " */", then " " is removed at the
// start of all lines.
return preg_replace('(^' . preg_quote($matches[1]) . ')m', '', $text);
} elseif (preg_match('(^/\*\*?\s*(?!\s))', $text, $matches)) {
// Multi line comment of the type
//
// /* Some text.
// Some more text.
// Even more text. */
//
// is handled by taking the length of the "/* " segment and leaving only that
// many space characters before the lines. Thus in the above example only three
// space characters are left at the start of every line.
return preg_replace('(^\s*(?= {' . strlen($matches[0]) . '}(?!\s)))m', '', $text);
}
// No idea how to format this comment, so simply return as is
return $text;
}
}

View File

@@ -0,0 +1,5 @@
<?php
class PHPParser_Comment_Doc extends PHPParser_Comment
{
}

View File

@@ -0,0 +1,70 @@
<?php
class PHPParser_Error extends RuntimeException
{
protected $rawMessage;
protected $rawLine;
/**
* Creates an Exception signifying a parse error.
*
* @param string $message Error message
* @param int $line Error line in PHP file
*/
public function __construct($message, $line = -1) {
$this->rawMessage = (string) $message;
$this->rawLine = (int) $line;
$this->updateMessage();
}
/**
* Gets the error message
*
* @return string Error message
*/
public function getRawMessage() {
return $this->rawMessage;
}
/**
* Sets the line of the PHP file the error occurred in.
*
* @param string $message Error message
*/
public function setRawMessage($message) {
$this->rawMessage = (string) $message;
$this->updateMessage();
}
/**
* Gets the error line in the PHP file.
*
* @return int Error line in the PHP file
*/
public function getRawLine() {
return $this->rawLine;
}
/**
* Sets the line of the PHP file the error occurred in.
*
* @param int $line Error line in the PHP file
*/
public function setRawLine($line) {
$this->rawLine = (int) $line;
$this->updateMessage();
}
/**
* Updates the exception message after a change to rawMessage or rawLine.
*/
protected function updateMessage() {
$this->message = $this->rawMessage;
if (-1 === $this->rawLine) {
$this->message .= ' on unknown line';
} else {
$this->message .= ' on line ' . $this->rawLine;
}
}
}

View File

@@ -0,0 +1,191 @@
<?php
class PHPParser_Lexer
{
protected $code;
protected $tokens;
protected $pos;
protected $line;
protected $tokenMap;
protected $dropTokens;
/**
* Creates a Lexer.
*/
public function __construct() {
// 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);
}
/**
* Initializes the lexer for lexing the provided source code.
*
* @param string $code The source code to lex
*
* @throws PHPParser_Error on lexing errors (unterminated comment or unexpected character)
*/
public function startLexing($code) {
$this->resetErrors();
$this->tokens = @token_get_all($code);
$this->handleErrors();
$this->code = $code; // keep the code around for __halt_compiler() handling
$this->pos = -1;
$this->line = 1;
}
protected function resetErrors() {
// clear error_get_last() by forcing an undefined variable error
@$undefinedVariable;
}
protected function handleErrors() {
$error = error_get_last();
if (preg_match(
'~^Unterminated comment starting line ([0-9]+)$~',
$error['message'], $matches
)) {
throw new PHPParser_Error('Unterminated comment', $matches[1]);
}
if (preg_match(
'~^Unexpected character in input: \'(.)\' \(ASCII=([0-9]+)\)~s',
$error['message'], $matches
)) {
throw new PHPParser_Error(sprintf(
'Unexpected character "%s" (ASCII %d)',
$matches[1], $matches[2]
));
}
// PHP cuts error message after null byte, so need special case
if (preg_match('~^Unexpected character in input: \'$~', $error['message'])) {
throw new PHPParser_Error('Unexpected null byte');
}
}
/**
* Fetches the next token.
*
* @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
*
* @return int Token id
*/
public function getNextToken(&$value = null, &$startAttributes = null, &$endAttributes = null) {
$startAttributes = array();
$endAttributes = array();
while (isset($this->tokens[++$this->pos])) {
$token = $this->tokens[$this->pos];
if (is_string($token)) {
$startAttributes['startLine'] = $this->line;
$endAttributes['endLine'] = $this->line;
// bug in token_get_all
if ('b"' === $token) {
$value = 'b"';
return ord('"');
} else {
$value = $token;
return ord($token);
}
} else {
$this->line += substr_count($token[1], "\n");
if (T_COMMENT === $token[0]) {
$startAttributes['comments'][] = new PHPParser_Comment($token[1], $token[2]);
} elseif (T_DOC_COMMENT === $token[0]) {
$startAttributes['comments'][] = new PHPParser_Comment_Doc($token[1], $token[2]);
} elseif (!isset($this->dropTokens[$token[0]])) {
$value = $token[1];
$startAttributes['startLine'] = $token[2];
$endAttributes['endLine'] = $this->line;
return $this->tokenMap[$token[0]];
}
}
}
$startAttributes['startLine'] = $this->line;
// 0 is the EOF token
return 0;
}
/**
* Handles __halt_compiler() by returning the text after it.
*
* @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));
// 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)) {
throw new PHPParser_Error('__halt_compiler must be followed by "();"');
}
// prevent the lexer from returning any further tokens
$this->pos = count($this->tokens);
// return with (); removed
return (string) substr($textAfter, strlen($matches[0])); // (string) converts false to ''
}
/**
* Creates the token map.
*
* The token map maps the PHP internal token identifiers
* to the identifiers used by the Parser. Additionally it
* maps T_OPEN_TAG_WITH_ECHO to T_ECHO and T_CLOSE_TAG to ';'.
*
* @return array The token map
*/
protected function createTokenMap() {
$tokenMap = array();
// 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] = PHPParser_Parser::T_PAAMAYIM_NEKUDOTAYIM;
// T_OPEN_TAG_WITH_ECHO with dropped T_OPEN_TAG results in T_ECHO
} elseif(T_OPEN_TAG_WITH_ECHO === $i) {
$tokenMap[$i] = PHPParser_Parser::T_ECHO;
// T_CLOSE_TAG is equivalent to ';'
} elseif(T_CLOSE_TAG === $i) {
$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);
}
}
return $tokenMap;
}
}

View File

@@ -0,0 +1,200 @@
<?php
/**
* ATTENTION: This code is WRITE-ONLY. Do not try to read it.
*/
class PHPParser_Lexer_Emulative extends PHPParser_Lexer
{
protected $newKeywords;
protected $inObjectAccess;
public function __construct() {
parent::__construct();
$newKeywordsPerVersion = array(
'5.5.0-dev' => array(
'finally' => PHPParser_Parser::T_FINALLY,
'yield' => PHPParser_Parser::T_YIELD,
),
'5.4.0-dev' => array(
'callable' => PHPParser_Parser::T_CALLABLE,
'insteadof' => PHPParser_Parser::T_INSTEADOF,
'trait' => PHPParser_Parser::T_TRAIT,
'__trait__' => PHPParser_Parser::T_TRAIT_C,
),
'5.3.0-dev' => array(
'__dir__' => PHPParser_Parser::T_DIR,
'goto' => PHPParser_Parser::T_GOTO,
'namespace' => PHPParser_Parser::T_NAMESPACE,
'__namespace__' => PHPParser_Parser::T_NS_C,
),
);
$this->newKeywords = array();
foreach ($newKeywordsPerVersion as $version => $newKeywords) {
if (version_compare(PHP_VERSION, $version, '>=')) {
break;
}
$this->newKeywords += $newKeywords;
}
}
public function startLexing($code) {
$this->inObjectAccess = false;
// on PHP 5.4 don't do anything
if (version_compare(PHP_VERSION, '5.4.0RC1', '>=')) {
parent::startLexing($code);
} else {
$code = $this->preprocessCode($code);
parent::startLexing($code);
$this->postprocessTokens();
}
}
/*
* Replaces new features in the code by ~__EMU__{NAME}__{DATA}__~ sequences.
* ~LABEL~ is never valid PHP code, that's why we can (to some degree) safely
* use it here.
* Later when preprocessing the tokens these sequences will either be replaced
* by real tokens or replaced with their original content (e.g. if they occured
* inside a string, i.e. a place where they don't have a special meaning).
*/
protected function preprocessCode($code) {
// binary notation (0b010101101001...)
$code = preg_replace('(\b0b[01]+\b)', '~__EMU__BINARY__$0__~', $code);
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
// namespace separator (backslash not followed by some special characters,
// which are not valid after a NS separator, but would cause problems with
// escape sequence parsing if one would replace the backslash there)
$code = preg_replace('(\\\\(?!["\'`${\\\\]))', '~__EMU__NS__~', $code);
// nowdoc (<<<'ABC'\ncontent\nABC;)
$code = preg_replace_callback(
'((*BSR_ANYCRLF) # set \R to (?>\r\n|\r|\n)
(b?<<<[\t ]*\'([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\'\R) # opening token
((?:(?!\2;?\R).*\R)*) # content
(\2) # closing token
(?=;?\R) # must be followed by newline (with optional semicolon)
)x',
array($this, 'encodeNowdocCallback'),
$code
);
}
return $code;
}
/*
* As nowdocs can have arbitrary content but LABELs can only contain a certain
* range of characters, the nowdoc content is encoded as hex and separated by
* 'x' tokens. So the result of the encoding will look like this:
* ~__EMU__NOWDOC__{HEX(START_TOKEN)}x{HEX(CONTENT)}x{HEX(END_TOKEN)}~
*/
public function encodeNowdocCallback(array $matches) {
return '~__EMU__NOWDOC__'
. bin2hex($matches[1]) . 'x' . bin2hex($matches[3]) . 'x' . bin2hex($matches[4])
. '__~';
}
/*
* Replaces the ~__EMU__...~ sequences with real tokens or their original
* value.
*/
protected function postprocessTokens() {
// we need to manually iterate and manage a count because we'll change
// the tokens array on the way
for ($i = 0, $c = count($this->tokens); $i < $c; ++$i) {
// first check that the following tokens are form ~LABEL~,
// then match the __EMU__... sequence.
if ('~' === $this->tokens[$i]
&& isset($this->tokens[$i + 2])
&& '~' === $this->tokens[$i + 2]
&& 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])
);
} elseif ('NS' === $matches[1]) {
// a \ single char token is returned here and replaced by a
// PHPParser_Parser::T_NS_SEPARATOR token in ->getNextToken(). This hacks around
// the limitations arising from T_NS_SEPARATOR not being defined on 5.3
$replace = array('\\');
} elseif ('NOWDOC' === $matches[1]) {
// decode the encoded nowdoc payload; pack('H*' is bin2hex( for 5.3
list($start, $content, $end) = explode('x', $matches[2]);
list($start, $content, $end) = array(pack('H*', $start), pack('H*', $content), pack('H*', $end));
$replace = array();
$replace[] = array(T_START_HEREDOC, $start, $this->tokens[$i + 1][2]);
if ('' !== $content) {
$replace[] = array(T_ENCAPSED_AND_WHITESPACE, $content, -1);
}
$replace[] = array(T_END_HEREDOC, $end, -1);
} else {
// just ignore all other __EMU__ sequences
continue;
}
array_splice($this->tokens, $i, 3, $replace);
$c -= 3 - count($replace);
// for multichar tokens (e.g. strings) replace any ~__EMU__...~ sequences
// in their content with the original character sequence
} elseif (is_array($this->tokens[$i])
&& 0 !== strpos($this->tokens[$i][1], '__EMU__')
) {
$this->tokens[$i][1] = preg_replace_callback(
'(~__EMU__([A-Z]++)__(?:([A-Za-z0-9]++)__)?~)',
array($this, 'restoreContentCallback'),
$this->tokens[$i][1]
);
}
}
}
/*
* This method is a callback for restoring EMU sequences in
* multichar tokens (like strings) to their original value.
*/
public function restoreContentCallback(array $matches) {
if ('BINARY' === $matches[1]) {
return $matches[2];
} elseif ('NS' === $matches[1]) {
return '\\';
} elseif ('NOWDOC' === $matches[1]) {
list($start, $content, $end) = explode('x', $matches[2]);
return pack('H*', $start) . pack('H*', $content) . pack('H*', $end);
} else {
return $matches[0];
}
}
public function getNextToken(&$value = null, &$startAttributes = null, &$endAttributes = null) {
$token = parent::getNextToken($value, $startAttributes, $endAttributes);
// 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 (PHPParser_Parser::T_STRING === $token && !$this->inObjectAccess) {
if (isset($this->newKeywords[strtolower($value)])) {
return $this->newKeywords[strtolower($value)];
}
// backslashes are replaced by T_NS_SEPARATOR tokens
} elseif (92 === $token) { // ord('\\')
return PHPParser_Parser::T_NS_SEPARATOR;
// keep track of whether we currently are in an object access (after ->)
} elseif (PHPParser_Parser::T_OBJECT_OPERATOR === $token) {
$this->inObjectAccess = true;
} else {
$this->inObjectAccess = false;
}
return $token;
}
}

View File

@@ -0,0 +1,75 @@
<?php
interface PHPParser_Node
{
/**
* Gets the type of the node.
*
* @return string Type of the node
*/
public function getType();
/**
* Gets the names of the sub nodes.
*
* @return array Names of sub nodes
*/
public function getSubNodeNames();
/**
* Gets line the node started in.
*
* @return int Line
*/
public function getLine();
/**
* Sets line the node started in.
*
* @param int $line Line
*/
public function setLine($line);
/**
* Gets the doc comment of the node.
*
* The doc comment has to be the last comment associated with the node.
*
* @return null|PHPParser_Comment_Doc Doc comment object or null
*/
public function getDocComment();
/**
* Sets an attribute on a node.
*
* @param string $key
* @param mixed $value
*/
public function setAttribute($key, $value);
/**
* Returns whether an attribute exists.
*
* @param string $key
*
* @return bool
*/
public function hasAttribute($key);
/**
* Returns the value of an attribute.
*
* @param string $key
* @param mixed $default
*
* @return mixed
*/
public function &getAttribute($key, $default = null);
/**
* Returns all attributes for the given node.
*
* @return array
*/
public function getAttributes();
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $value Value to pass
* @property bool $byRef Whether to pass by ref
*/
class PHPParser_Node_Arg extends PHPParser_NodeAbstract
{
/**
* Constructs a function call argument node.
*
* @param PHPParser_Node_Expr $value Value to pass
* @param bool $byRef Whether to pass by ref
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $value, $byRef = false, array $attributes = array()) {
parent::__construct(
array(
'value' => $value,
'byRef' => $byRef
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property string $name Name
* @property PHPParser_Node_Expr $value Value
*/
class PHPParser_Node_Const extends PHPParser_NodeAbstract
{
/**
* Constructs a const node for use in class const and const statements.
*
* @param string $name Name
* @param PHPParser_Node_Expr $value Value
* @param array $attributes Additional attributes
*/
public function __construct($name, PHPParser_Node_Expr $value, array $attributes = array()) {
parent::__construct(
array(
'name' => $name,
'value' => $value,
),
$attributes
);
}
}

View File

@@ -0,0 +1,5 @@
<?php
abstract class PHPParser_Node_Expr extends PHPParser_NodeAbstract
{
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @property PHPParser_Node_Expr_ArrayItem[] $items Items
*/
class PHPParser_Node_Expr_Array extends PHPParser_Node_Expr
{
/**
* Constructs an array node.
*
* @param PHPParser_Node_Expr_ArrayItem[] $items Items of the array
* @param array $attributes Additional attributes
*/
public function __construct(array $items = array(), array $attributes = array()) {
parent::__construct(
array(
'items' => $items
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $var Variable
* @property null|PHPParser_Node_Expr $dim Array index / dim
*/
class PHPParser_Node_Expr_ArrayDimFetch extends PHPParser_Node_Expr
{
/**
* Constructs an array index fetch node.
*
* @param PHPParser_Node_Expr $var Variable
* @param null|PHPParser_Node_Expr $dim Array index / dim
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $var, PHPParser_Node_Expr $dim = null, array $attributes = array()) {
parent::__construct(
array(
'var' => $var,
'dim' => $dim
),
$attributes
);
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* @property PHPParser_Node_Expr $value Value
* @property null|PHPParser_Node_Expr $key Key
* @property bool $byRef Whether to assign by reference
*/
class PHPParser_Node_Expr_ArrayItem extends PHPParser_Node_Expr
{
/**
* Constructs an array item node.
*
* @param PHPParser_Node_Expr $value Value
* @param null|PHPParser_Node_Expr $key Key
* @param bool $byRef Whether to assign by reference
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $value, PHPParser_Node_Expr $key = null, $byRef = false, array $attributes = array()) {
parent::__construct(
array(
'key' => $key,
'value' => $value,
'byRef' => $byRef
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $var Variable
* @property PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_Assign extends PHPParser_Node_Expr
{
/**
* Constructs an assignment node.
*
* @param PHPParser_Node_Expr $var Variable
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $var, PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'var' => $var,
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $var Variable
* @property PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_AssignBitwiseAnd extends PHPParser_Node_Expr
{
/**
* Constructs an assignment with bitwise and node.
*
* @param PHPParser_Node_Expr $var Variable
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $var, PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'var' => $var,
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $var Variable
* @property PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_AssignBitwiseOr extends PHPParser_Node_Expr
{
/**
* Constructs an assignment with bitwise or node.
*
* @param PHPParser_Node_Expr $var Variable
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $var, PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'var' => $var,
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $var Variable
* @property PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_AssignBitwiseXor extends PHPParser_Node_Expr
{
/**
* Constructs an assignment with bitwise xor node.
*
* @param PHPParser_Node_Expr $var Variable
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $var, PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'var' => $var,
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $var Variable
* @property PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_AssignConcat extends PHPParser_Node_Expr
{
/**
* Constructs an assignment with concat node.
*
* @param PHPParser_Node_Expr $var Variable
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $var, PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'var' => $var,
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $var Variable
* @property PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_AssignDiv extends PHPParser_Node_Expr
{
/**
* Constructs an assignment with division node.
*
* @param PHPParser_Node_Expr $var Variable
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $var, PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'var' => $var,
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $var Variable
* @property PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_AssignMinus extends PHPParser_Node_Expr
{
/**
* Constructs an assignment with minus node.
*
* @param PHPParser_Node_Expr $var Variable
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $var, PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'var' => $var,
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $var Variable
* @property PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_AssignMod extends PHPParser_Node_Expr
{
/**
* Constructs an assignment with modulo node.
*
* @param PHPParser_Node_Expr $var Variable
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $var, PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'var' => $var,
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $var Variable
* @property PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_AssignMul extends PHPParser_Node_Expr
{
/**
* Constructs an assignment with multiplication node.
*
* @param PHPParser_Node_Expr $var Variable
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $var, PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'var' => $var,
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $var Variable
* @property PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_AssignPlus extends PHPParser_Node_Expr
{
/**
* Constructs an assignment with addition node.
*
* @param PHPParser_Node_Expr $var Variable
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $var, PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'var' => $var,
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $var Variable reference is assigned to
* @property PHPParser_Node_Expr $expr Variable which is referenced
*/
class PHPParser_Node_Expr_AssignRef extends PHPParser_Node_Expr
{
/**
* Constructs an assignment node.
*
* @param PHPParser_Node_Expr $var Variable
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $var, PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'var' => $var,
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $var Variable
* @property PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_AssignShiftLeft extends PHPParser_Node_Expr
{
/**
* Constructs an assignment with left shift node.
*
* @param PHPParser_Node_Expr $var Variable
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $var, PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'var' => $var,
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $var Variable
* @property PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_AssignShiftRight extends PHPParser_Node_Expr
{
/**
* Constructs an assignment with right shift node.
*
* @param PHPParser_Node_Expr $var Variable
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $var, PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'var' => $var,
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_BitwiseAnd extends PHPParser_Node_Expr
{
/**
* Constructs a bitwise and node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @property PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_BitwiseNot extends PHPParser_Node_Expr
{
/**
* Constructs a bitwise not node.
*
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_BitwiseOr extends PHPParser_Node_Expr
{
/**
* Constructs a bitwise or node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_BitwiseXor extends PHPParser_Node_Expr
{
/**
* Constructs a bitwise xor node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_BooleanAnd extends PHPParser_Node_Expr
{
/**
* Constructs a boolean and node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @property PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_BooleanNot extends PHPParser_Node_Expr
{
/**
* Constructs a boolean not node.
*
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_BooleanOr extends PHPParser_Node_Expr
{
/**
* Constructs a boolean or node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @property PHPParser_Node_Expr $expr Expression
*/
abstract class PHPParser_Node_Expr_Cast extends PHPParser_Node_Expr
{
/**
* Constructs a cast node.
*
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,5 @@
<?php
class PHPParser_Node_Expr_Cast_Array extends PHPParser_Node_Expr_Cast
{
}

View File

@@ -0,0 +1,5 @@
<?php
class PHPParser_Node_Expr_Cast_Bool extends PHPParser_Node_Expr_Cast
{
}

View File

@@ -0,0 +1,5 @@
<?php
class PHPParser_Node_Expr_Cast_Double extends PHPParser_Node_Expr_Cast
{
}

View File

@@ -0,0 +1,5 @@
<?php
class PHPParser_Node_Expr_Cast_Int extends PHPParser_Node_Expr_Cast
{
}

View File

@@ -0,0 +1,5 @@
<?php
class PHPParser_Node_Expr_Cast_Object extends PHPParser_Node_Expr_Cast
{
}

View File

@@ -0,0 +1,5 @@
<?php
class PHPParser_Node_Expr_Cast_String extends PHPParser_Node_Expr_Cast
{
}

View File

@@ -0,0 +1,5 @@
<?php
class PHPParser_Node_Expr_Cast_Unset extends PHPParser_Node_Expr_Cast
{
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Name|PHPParser_Node_Expr $class Class name
* @property string $name Constant name
*/
class PHPParser_Node_Expr_ClassConstFetch extends PHPParser_Node_Expr
{
/**
* Constructs a class const fetch node.
*
* @param PHPParser_Node_Name|PHPParser_Node_Expr $class Class name
* @param string $name Constant name
* @param array $attributes Additional attributes
*/
public function __construct($class, $name, array $attributes = array()) {
parent::__construct(
array(
'class' => $class,
'name' => $name
),
$attributes
);
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @property PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_Clone extends PHPParser_Node_Expr
{
/**
* Constructs a clone node.
*
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* @property PHPParser_Node[] $stmts Statements
* @property PHPParser_Node_Param[] $params Parameters
* @property PHPParser_Node_Expr_ClosureUse[] $uses use()s
* @property bool $byRef Whether to return by reference
* @property bool $static Whether the closure is static
*/
class PHPParser_Node_Expr_Closure extends PHPParser_Node_Expr
{
/**
* Constructs a lambda function node.
*
* @param array $subNodes Array of the following optional subnodes:
* 'stmts' => array(): Statements
* 'params' => array(): Parameters
* 'uses' => array(): use()s
* 'byRef' => false : Whether to return by reference
* 'static' => false : Whether the closure is static
* @param array $attributes Additional attributes
*/
public function __construct(array $subNodes = array(), array $attributes = array()) {
parent::__construct(
$subNodes + array(
'stmts' => array(),
'params' => array(),
'uses' => array(),
'byRef' => false,
'static' => false,
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property string $var Name of variable
* @property bool $byRef Whether to use by reference
*/
class PHPParser_Node_Expr_ClosureUse extends PHPParser_Node_Expr
{
/**
* Constructs a closure use node.
*
* @param string $var Name of variable
* @param bool $byRef Whether to use by reference
* @param array $attributes Additional attributes
*/
public function __construct($var, $byRef = false, array $attributes = array()) {
parent::__construct(
array(
'var' => $var,
'byRef' => $byRef
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_Concat extends PHPParser_Node_Expr
{
/**
* Constructs a concat node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @property PHPParser_Node_Name $name Constant name
*/
class PHPParser_Node_Expr_ConstFetch extends PHPParser_Node_Expr
{
/**
* Constructs a const fetch node.
*
* @param PHPParser_Node_Name $name Constant name
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Name $name, array $attributes = array()) {
parent::__construct(
array(
'name' => $name
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_Div extends PHPParser_Node_Expr
{
/**
* Constructs a division node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @property PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_Empty extends PHPParser_Node_Expr
{
/**
* Constructs an empty() node.
*
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_Equal extends PHPParser_Node_Expr
{
/**
* Constructs a equality comparison node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @property PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_ErrorSuppress extends PHPParser_Node_Expr
{
/**
* Constructs an error suppress node.
*
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @property PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_Eval extends PHPParser_Node_Expr
{
/**
* Constructs an eval() node.
*
* @param PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @property null|PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_Exit extends PHPParser_Node_Expr
{
/**
* Constructs an exit() node.
*
* @param null|PHPParser_Node_Expr $expr Expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $expr = null, array $attributes = array()) {
parent::__construct(
array(
'expr' => $expr
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Name|PHPParser_Node_Expr $name Function name
* @property PHPParser_Node_Arg[] $args Arguments
*/
class PHPParser_Node_Expr_FuncCall extends PHPParser_Node_Expr
{
/**
* Constructs a function call node.
*
* @param PHPParser_Node_Name|PHPParser_Node_Expr $name Function name
* @param PHPParser_Node_Arg[] $args Arguments
* @param array $attributes Additional attributes
*/
public function __construct($name, array $args = array(), array $attributes = array()) {
parent::__construct(
array(
'name' => $name,
'args' => $args
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_Greater extends PHPParser_Node_Expr
{
/**
* Constructs a greater than comparison node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_GreaterOrEqual extends PHPParser_Node_Expr
{
/**
* Constructs a greater than or equal node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_Identical extends PHPParser_Node_Expr
{
/**
* Constructs an identicality comparison node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,30 @@
<?php
/**
* @property PHPParser_Node_Expr $expr Expression
* @property int $type Type of include
*/
class PHPParser_Node_Expr_Include extends PHPParser_Node_Expr
{
const TYPE_INCLUDE = 1;
const TYPE_INCLUDE_ONCE = 2;
const TYPE_REQUIRE = 3;
const TYPE_REQUIRE_ONCE = 4;
/**
* Constructs an include node.
*
* @param PHPParser_Node_Expr $expr Expression
* @param int $type Type of include
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $expr, $type, array $attributes = array()) {
parent::__construct(
array(
'expr' => $expr,
'type' => $type
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $expr Expression
* @property PHPParser_Node_Name|PHPParser_Node_Expr $class Class name
*/
class PHPParser_Node_Expr_Instanceof extends PHPParser_Node_Expr
{
/**
* Constructs an instanceof check node.
*
* @param PHPParser_Node_Expr $expr Expression
* @param PHPParser_Node_Name|PHPParser_Node_Expr $class Class name
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $expr, $class, array $attributes = array()) {
parent::__construct(
array(
'expr' => $expr,
'class' => $class
),
$attributes
);
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @property PHPParser_Node_Expr[] $vars Variables
*/
class PHPParser_Node_Expr_Isset extends PHPParser_Node_Expr
{
/**
* Constructs an array node.
*
* @param PHPParser_Node_Expr[] $vars Variables
* @param array $attributes Additional attributes
*/
public function __construct(array $vars, array $attributes = array()) {
parent::__construct(
array(
'vars' => $vars
),
$attributes
);
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @property array $vars List of variables to assign to
*/
class PHPParser_Node_Expr_List extends PHPParser_Node_Expr
{
/**
* Constructs a list() destructuring node.
*
* @param array $vars List of variables to assign to
* @param array $attributes Additional attributes
*/
public function __construct(array $vars, array $attributes = array()) {
parent::__construct(
array(
'vars' => $vars,
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_LogicalAnd extends PHPParser_Node_Expr
{
/**
* Constructs a logical and node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_LogicalOr extends PHPParser_Node_Expr
{
/**
* Constructs a logical or node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_LogicalXor extends PHPParser_Node_Expr
{
/**
* Constructs a logical xor node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* @property PHPParser_Node_Expr $var Variable holding object
* @property string|PHPParser_Node_Expr $name Method name
* @property PHPParser_Node_Arg[] $args Arguments
*/
class PHPParser_Node_Expr_MethodCall extends PHPParser_Node_Expr
{
/**
* Constructs a function call node.
*
* @param PHPParser_Node_Expr $var Variable holding object
* @param string|PHPParser_Node_Expr $name Method name
* @param PHPParser_Node_Arg[] $args Arguments
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $var, $name, array $args = array(), array $attributes = array()) {
parent::__construct(
array(
'var' => $var,
'name' => $name,
'args' => $args
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_Minus extends PHPParser_Node_Expr
{
/**
* Constructs a substraction node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_Mod extends PHPParser_Node_Expr
{
/**
* Constructs a modulo node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_Mul extends PHPParser_Node_Expr
{
/**
* Constructs a multiplication node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Name|PHPParser_Node_Expr $class Class name
* @property PHPParser_Node_Arg[] $args Arguments
*/
class PHPParser_Node_Expr_New extends PHPParser_Node_Expr
{
/**
* Constructs a function call node.
*
* @param PHPParser_Node_Name|PHPParser_Node_Expr $class Class name
* @param PHPParser_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
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_NotEqual extends PHPParser_Node_Expr
{
/**
* Constructs a not equal comparison node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_NotIdentical extends PHPParser_Node_Expr
{
/**
* Constructs a not identical comparison node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @property PHPParser_Node_Expr $left The left hand side expression
* @property PHPParser_Node_Expr $right The right hand side expression
*/
class PHPParser_Node_Expr_Plus extends PHPParser_Node_Expr
{
/**
* Constructs an addition node.
*
* @param PHPParser_Node_Expr $left The left hand side expression
* @param PHPParser_Node_Expr $right The right hand side expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $left, PHPParser_Node_Expr $right, array $attributes = array()) {
parent::__construct(
array(
'left' => $left,
'right' => $right
),
$attributes
);
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @property PHPParser_Node_Expr $var Variable
*/
class PHPParser_Node_Expr_PostDec extends PHPParser_Node_Expr
{
/**
* Constructs a post decrement node.
*
* @param PHPParser_Node_Expr $var Variable
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $var, array $attributes = array()) {
parent::__construct(
array(
'var' => $var
),
$attributes
);
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @property PHPParser_Node_Expr $var Variable
*/
class PHPParser_Node_Expr_PostInc extends PHPParser_Node_Expr
{
/**
* Constructs a post increment node.
*
* @param PHPParser_Node_Expr $var Variable
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $var, array $attributes = array()) {
parent::__construct(
array(
'var' => $var
),
$attributes
);
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @property PHPParser_Node_Expr $var Variable
*/
class PHPParser_Node_Expr_PreDec extends PHPParser_Node_Expr
{
/**
* Constructs a pre decrement node.
*
* @param PHPParser_Node_Expr $var Variable
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $var, array $attributes = array()) {
parent::__construct(
array(
'var' => $var
),
$attributes
);
}
}

Some files were not shown because too many files have changed in this diff Show More