Compare commits

...

49 Commits

Author SHA1 Message Date
1e5e280ae8 Release PHP-Parser 0.9.4 2013-08-25 19:11:40 +02:00
3d467ca18e Add PHP 5.5 to .travis.yml 2013-08-04 16:15:12 +02:00
c8695a8f56 Remove obsolete item from grammar/README.md 2013-08-04 16:14:44 +02:00
01123ae6af Fix notices when generating expected tokens list (continued)
Forgot to add regenerated parser
2013-07-27 18:50:08 +02:00
09c106d11f Fix notices when generating expected tokens list 2013-07-27 18:48:49 +02:00
77c08a75c9 Fix pretty printing of include expressions 2013-07-27 16:23:27 +02:00
f9c3aa2a22 Improve PrettyPrinter construction perf by not using uniqid
The uniqid function is *very* slow on unix systems. The code has no
particular unique-ness requirements, so the much faster mt_rand()
function is used instead.

Closes PR #65.
2013-07-13 01:03:57 +02:00
5ccf6196d6 Update changelog 2013-05-23 15:17:59 +02:00
12faad529e Add interface builder 2013-05-23 15:14:58 +02:00
c0da1b88b2 Merge pull request #59 from Trismegiste/refactor-adding-an-interface-for-LSP
Adding an interface to the Node Traverser for LSP concern
2013-05-22 14:45:21 -07:00
bc9ab604f6 Merge pull request #58 from fantasticjamieburns/master
Fix typo in doccomment for lcfirst replacement
2013-05-17 08:14:14 -07:00
900a3f3b7c Implementing the interface for PHPParser_NodeTraverser 2013-05-16 15:44:12 +02:00
92df3e5add Adding the interface 2013-05-16 15:43:24 +02:00
ba91348142 Typo fix 2013-05-15 16:48:42 +02:00
8e686ce7a7 PHP-Parser supports PHP 5.5 2013-04-15 20:56:45 +02:00
08f0cde6f9 Add prettyPrintFile() method 2013-04-15 20:53:23 +02:00
5fca55702b Merge pull request #52 from igorw/patch-1
Add branch-alias
2013-03-05 06:42:24 -08:00
dc95f3b425 Add branch-alias
This allows "0.9.*" or "~0.9" to install the dev version, if the
consumer allows for dev versions to be installed.
2013-03-05 12:50:52 +01:00
75ec7a3e78 Looks like I forgot to git add some files... 2013-02-14 21:49:08 +01:00
a249c002dd Add support for ClassName::class (PHP 5.5) 2013-02-14 21:46:58 +01:00
81d20bf10e Pretty print namespaces in semicolon-style if possible 2013-01-15 18:21:42 +01:00
db18906dfc Rename PrettyPrinter_Zend to PrettyPrinter_Default 2013-01-15 17:43:36 +01:00
fbaa1e5fc3 Add information on expected tokens to syntax errors
This now mimics the error messages provided by PHP itself (pre 5.4).
2013-01-15 17:30:14 +01:00
222c9612ab Use RegexIterator in docs (by @lstrojny)
Also fix formatting in changelog and be more specific in a doc comment.
2012-12-21 13:28:35 +01:00
eeb5e899a5 Merge pull request #46 from siwinski/pr-composer-x-bit
Remove composer.json execute bit
2012-12-21 04:20:39 -08:00
01c5b84db5 Removed composer.json execute bit 2012-12-20 22:18:59 -05:00
98ebfc8d54 Release PHP-Parser 0.9.3 2012-11-22 19:54:05 +01:00
9f0e12bfca Update changelog 2012-11-22 19:51:21 +01:00
cdbad02fb2 Fix endAttributes assignment
The end attributes previously were always assigned from the last read token,
which does not necessarily correspond to the last token in the reduced rule.
In particular this occurs if the parser read a new token and based on that
lookahead decided to reduce a rule. The behavior was only correct if the
newly read token was first shifted and then the rule was reduced.

This is fixed by buffering the endAttributes of the new token in a temporary
variable and only assigning them once the token is shifted.
2012-11-20 16:12:19 +01:00
b0c8787406 Merge pull request #43 from nicmart/patch-1
Update BuilderAbstract::normalizeValue() doc comment
2012-11-06 11:12:30 -08:00
2ae2410dbd Merge pull request #40 from fabpot/patch-2
Fixed some typos in the doc
2012-11-06 11:10:08 -08:00
bdb58ada7c Update lib/PHPParser/BuilderAbstract.php
Updated BuilderAbstract::normalizeValue phpdoc description.
2012-11-06 18:28:15 +01:00
efa872692e Fixed some typos in the doc 2012-11-05 17:44:56 +01:00
fc56da59ce Rename pSafe to pNoIndent
Matches the function more closely
2012-10-31 17:50:54 +01:00
df17d62b40 Fix switch formatting
The switch cases were not indented and fall-through cases had an
unnecessary additional newline.

Patch by @pscheit (PR #39).
2012-10-31 17:46:48 +01:00
ac6f221c50 Better prededence and associativity handling in pretty printer
Previously the pretty printer added unnecessary and odd-looking parentheses
when several operators with the same precedence were chained:

    'a' . 'b' . 'c' . 'd' . 'e'
    // was printed as
    'a' . ('b' . ('c' . ('d' . 'e')))

Another issue reported as part of #39 was that assignments inside closures
were wrapped in parentheses:

    function() {
        $a = $b;
    }
    // was printed as
    function() {
        ($a = $b);
    }

This was caused by the automatic precedence handling, which just regarded
the closure as an ordinal nested expression.

With the new system the $predenceMap of PrettyPrinterAbstract contains both
precedence and associativity and there is a new method pPrec() which prints
a node taking precedence and associativity into account.

For simpler usage there are additional function pInfixOp(), pPrefixOp() and
pPostfixOp().

Prints not going through pPrec() do not have any precedence handling (fixing
the closure issue).
2012-10-31 17:34:06 +01:00
759c04db9b Turn rebuildParser.php into a CLI script
The paths are now more generic so it can be run from any directory, not
just grammar/.
2012-10-19 19:11:47 +02:00
9e43acee2c Scalar_String::create() -> Scalar_String::parse()
Directly creating the node isn't necessary anymore, the token only needs
to be parsed. This makes it consistent with the other scalar parsing
methods and removes the need to pass $arguments around.
2012-10-19 15:17:08 +02:00
9d8e13b4a9 Fix Switch subnode order
Not that it makes much of a difference, but could have caused issues with
"out of order" visiting of nodes.
2012-10-19 14:54:56 +02:00
af5d288fb3 Add support for expressions in empty (PHP 5.5)
Apart from the grammar modifications this also renames the Empty subnode
from var to expr. This breaks BC.
2012-09-07 23:42:01 +02:00
f6c1ab6657 Adjust list and yield parsing, update prettyprinter
* nested list()s will now create nested List nodes (instead of just
   nested arrays)
 * yield $k => $v was parsed with key and value swapped. This is now fixed
 * the pretty printer now works with the newly added language constructs
2012-09-07 23:41:59 +02:00
4259b44a84 Add support for constant dereferencing (PHP 5.5)
Examples: "foo"[2], [1, 2, 3][2]
2012-09-07 23:41:58 +02:00
417a8bb07e Add support for yield expressions (PHP 5.5)
This adds a new Yield expression type, with subnodes key and value.
2012-09-07 23:41:57 +02:00
ae3774f0f2 Add support for finally clauses (PHP 5.5)
This adds a new finallyStmts subnode to the TryCatch node. If there is
no finally clause it will be null.
2012-09-07 23:41:56 +02:00
f8f1e17e41 Add support for list() in foreach (PHP 5.5)
Example: foreach ($coords as list($x, $y)) { ... }

This change slightly breaks backwards compatability, as it changes the
node structure for the previously existing `list(...) = $foo` assignments.
Those no longer have a dedicated `AssignList` node; instead they are
parsed as a normal `Assign` node with a `List` as `var`. Similarly the
use in `foreach` will generate a `List` for `valueVar`.
2012-09-07 23:41:55 +02:00
8d218110db Fix some doc comments 2012-09-07 23:41:54 +02:00
a590937fdf Merge pull request #33 from hakre/patch-1
Change to SPDX License Identifier (BSD-3-Clause) for composer
2012-08-07 09:40:19 -07:00
84b23a3eb5 Change to SPDX License Identifier (BSD-3-Clause) for composer
The composer validate command is now supporting SPDX license identifers.
2012-08-07 18:51:11 +03:00
5a947e9843 Fix parsing of $foo =& new Bar;
By-reference assignments of new expressions are now parsed as AssignRef
(instead of just Assign).

Closes issue #31.
2012-07-23 11:36:47 +02:00
66 changed files with 4150 additions and 2674 deletions

View File

@ -4,3 +4,4 @@ php:
- 5.2
- 5.3
- 5.4
- 5.5

View File

@ -1,10 +1,83 @@
Version 0.9.3-dev
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.

View File

@ -1,7 +1,7 @@
PHP Parser
==========
This is a PHP 5.4 (and older) parser written in PHP. It's purpose is to simplify static code analysis and
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.

7
composer.json Executable file → Normal file
View File

@ -3,7 +3,7 @@
"description": "A PHP parser written in PHP",
"keywords": ["php", "parser"],
"type": "library",
"license": "BSD",
"license": "BSD-3-Clause",
"authors": [
{
"name": "Nikita Popov"
@ -14,5 +14,10 @@
},
"autoload": {
"psr-0": { "PHPParser": "lib/" }
},
"extra": {
"branch-alias": {
"dev-master": "0.9-dev"
}
}
}

View File

@ -1,7 +1,7 @@
Introduction
============
This project is a PHP 5.4 (and older) parser **written in PHP itself**.
This project is a PHP 5.5 (and older) parser **written in PHP itself**.
What is this for?
-----------------
@ -12,7 +12,7 @@ application dealing with code programmatically. A parser constructs an [Abstract
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 analyize the exact formating of
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
@ -21,17 +21,17 @@ 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 incidentially PHP developers, not C developers.
programmatic PHP code analysis are incidentally PHP developers, not C developers.
What can it parse?
------------------
The parser uses a PHP 5.4 compliant grammar, which is backwards compatible with at least PHP 5.3 and PHP
5.2 (and maybe older).
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 and 5.4 is provided. This
allows to parse PHP 5.4 source code running on PHP 5.2, for example. This emulation is very hacky and not
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?

View File

@ -15,7 +15,7 @@ Create a `composer.json` file in your project root and use it to define your dep
{
"require": {
"nikic/php-parser": "0.9.2"
"nikic/php-parser": "0.9.4"
}
}
@ -33,7 +33,7 @@ Installing as a PEAR package
Run the following two commands:
pear channel-discover nikic.github.com/pear
pear install channel://nikic.github.com/pear/PHPParser-0.9.2
pear install nikic/PHPParser-0.9.4
Installing as a Git Submodule
-----------------------------

View File

@ -49,7 +49,7 @@ 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.4 on PHP 5.2, for example. So if you want to parse
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
@ -121,15 +121,14 @@ 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_Zend` (the name "Zend" might be misleading. It does not strictly adhere
to the Zend Coding Standard.)
namely `PHPParser_PrettyPrinter_Default`.
```php
<?php
$code = "<?php echo 'Hi ', hi\\getTarget();";
$parser = new PHPParser_Parser(new PHPParser_Lexer);
$prettyPrinter = new PHPParser_PrettyPrinter_Zend;
$prettyPrinter = new PHPParser_PrettyPrinter_Default;
try {
// parse
@ -156,7 +155,7 @@ 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_Zend->prettyPrint`.
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`.
@ -178,7 +177,7 @@ $code = "<?php // some code";
$parser = new PHPParser_Parser(new PHPParser_Lexer);
$traverser = new PHPParser_NodeTraverser;
$prettyPrinter = new PHPParser_PrettyPrinter_Zend;
$prettyPrinter = new PHPParser_PrettyPrinter_Default;
// add your visitor
$traverser->addVisitor(new MyNodeVisitor);
@ -283,21 +282,16 @@ 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_Zend;
$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 files in the directory
foreach (new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(IN_DIR),
RecursiveIteratorIterator::LEAVES_ONLY)
as $file) {
// only convert .php files
if (!preg_match('~\.php$~', $file)) {
continue;
}
// 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);

View File

@ -8,7 +8,7 @@ common structures as well as simple templating support. Both features are descri
Builders
--------
The project provides builders for classes, methods, functions, parameters and properties, which
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:

View File

@ -1,7 +1,6 @@
What do all those files mean?
=============================
* `zend_language_parser.y`: Original PHP grammer this parser is based on
* `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`
@ -24,7 +23,7 @@ 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` file.
After you compiled/installed it, run the `rebuildParser.php` script.
By default only the Parser.php is built. If you want to build the Parser/Debug.php and the y.output
file you need to call the file with the debug option: `rebuildParser.php?debug`.
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

@ -47,7 +47,7 @@ class #(-p)
, "???"
);
/* @var Map which translates lexer tokens to internal tokens */
/* @var array Map which translates lexer tokens to internal tokens */
protected static $translate = array(
#listvar yytranslate
);
@ -157,7 +157,7 @@ class #(-p)
*
* @param string $code The source code to parse
*
* @return array Array of statements
* @return PHPParser_Node[] Array of statements
*/
public function parse($code) {
$this->lexer->startLexing($code);
@ -194,8 +194,11 @@ class #(-p)
$yyn = self::$yydefault[$state];
} else {
if ($tokenId === self::TOKEN_NONE) {
// fetch the next token id from the lexer and fetch additional info by-ref
$origTokenId = $this->lexer->getNextToken($tokenValue, $startAttributes, $endAttributes);
// 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
@ -241,6 +244,7 @@ class #(-p)
$stateStack[$this->stackPos] = $state = $yyn;
$this->yyastk[$this->stackPos] = $tokenValue;
$attributeStack[$this->stackPos] = $startAttributes;
$endAttributes = $nextEndAttributes;
$tokenId = self::TOKEN_NONE;
if ($yyn < self::YYNLSTATES)
@ -300,8 +304,35 @@ class #(-p)
$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(
'Unexpected token ' . self::$terminals[$tokenId],
'Syntax error, unexpected ' . self::$terminals[$tokenId] . $expectedString,
$startAttributes['startLine']
);
}

View File

@ -1,8 +1,21 @@
<?php
const GRAMMAR_FILE = './zend_language_parser.phpy';
const TMP_FILE = './tmp_parser.phpy';
const RESULT_FILE = './tmp_parser.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 ///
@ -23,42 +36,34 @@ const ARGS = '\((?<args>[^()]*+(?:\((?&args)\)[^()]*+)*+)\)';
/// Main script ///
///////////////////
echo '<pre>';
echo 'Building temporary preproprocessed grammar file.', "\n";
$grammarCode = file_get_contents(GRAMMAR_FILE);
$grammarCode = file_get_contents($grammarFile);
$grammarCode = resolveConstants($grammarCode);
$grammarCode = resolveNodes($grammarCode);
$grammarCode = resolveMacros($grammarCode);
$grammarCode = resolveArrays($grammarCode);
file_put_contents(TMP_FILE, $grammarCode);
file_put_contents($tmpGrammarFile, $grammarCode);
echo 'Building parser. Output: "',
trim(shell_exec('kmyacc -l -m kmyacc.php.parser -p PHPParser_Parser ' . TMP_FILE . ' 2>&1')),
'"', "\n";
echo "Building parser.\n";
$output = trim(shell_exec("$kmyacc -l -m $skeletonFile -p PHPParser_Parser $tmpGrammarFile 2>&1"));
echo "Output: \"$output\"\n";
rename(RESULT_FILE, '../lib/PHPParser/Parser.php');
moveFileWithDirCheck($tmpResultFile, $parserResultFile);
if (isset($_GET['debug'])) {
echo 'Building debug parser. Output: "',
trim(shell_exec('kmyacc -t -v -l -m kmyacc.php.parser -p PHPParser_Parser ' . TMP_FILE . ' 2>&1')),
'"', "\n";
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";
if (!is_dir('../lib/PHPParser/Parser')) {
mkdir('../lib/PHPParser/Parser');
}
rename(RESULT_FILE, '../lib/PHPParser/Parser/Debug.php');
moveFileWithDirCheck($tmpResultFile, $debugParserResultFile);
}
unlink(TMP_FILE);
echo 'The following temporary preproprocessed grammar file was used:', "\n", $grammarCode;
echo '</pre>';
if (!$optionKeepTmpGrammar) {
unlink($tmpGrammarFile);
}
///////////////////////////////
/// Preprocessing functions ///
@ -193,6 +198,14 @@ function resolveArrays($code) {
);
}
function moveFileWithDirCheck($fromPath, $toPath) {
$dir = dirname($toPath);
if (!is_dir($dir)) {
mkdir($dir, 0777, true);
}
rename($fromPath, $toPath);
}
//////////////////////////////
/// Regex helper functions ///
//////////////////////////////

View File

@ -7,6 +7,7 @@
%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
@ -63,6 +64,7 @@
%token T_RETURN
%token T_TRY
%token T_CATCH
%token T_FINALLY
%token T_THROW
%token T_USE
%token T_INSTEADOF
@ -169,42 +171,43 @@ inner_statement:
statement:
'{' inner_statement_list '}' { $$ = $2; }
| T_IF '(' expr ')' statement elseif_list else_single { $$ = Stmt_If[$3, [stmts: toArray($5), elseifs: $6, else: $7]]; }
| T_IF '(' expr ')' ':' inner_statement_list new_elseif_list new_else_single T_ENDIF ';'
{ $$ = Stmt_If[$3, [stmts: $6, elseifs: $7, else: $8]]; }
| T_WHILE '(' expr ')' while_statement { $$ = Stmt_While[$3, $5]; }
| T_DO statement T_WHILE '(' expr ')' ';' { $$ = Stmt_Do [$5, toArray($2)]; }
| T_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 '(' expr ')' switch_case_list { $$ = Stmt_Switch[$3, $5]; }
| 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 variable ')' foreach_statement
{ $$ = Stmt_Foreach[$3, $5, [keyVar: null, byRef: false, stmts: $7]]; }
| T_FOREACH '(' expr T_AS '&' variable ')' foreach_statement
{ $$ = Stmt_Foreach[$3, $6, [keyVar: null, byRef: true, stmts: $8]]; }
| T_FOREACH '(' expr T_AS variable T_DOUBLE_ARROW optional_ref variable ')' foreach_statement
{ $$ = Stmt_Foreach[$3, $8, [keyVar: $5, byRef: $7, stmts: $10]]; }
| 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 { $$ = Stmt_TryCatch[$3, $5]; }
| 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:
catch { init($1); }
/* empty */ { init(); }
| catches catch { push($1, $2); }
;
@ -213,6 +216,11 @@ catch:
{ $$ = 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); }
@ -320,7 +328,7 @@ elseif_list:
;
elseif:
T_ELSEIF '(' expr ')' statement { $$ = Stmt_ElseIf[$3, toArray($5)]; }
T_ELSEIF parentheses_expr statement { $$ = Stmt_ElseIf[$2, toArray($3)]; }
;
new_elseif_list:
@ -329,7 +337,7 @@ new_elseif_list:
;
new_elseif:
T_ELSEIF '(' expr ')' ':' inner_statement_list { $$ = Stmt_ElseIf[$3, $6]; }
T_ELSEIF parentheses_expr ':' inner_statement_list { $$ = Stmt_ElseIf[$2, $4]; }
;
else_single:
@ -342,6 +350,12 @@ new_else_single:
| 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(); }
@ -367,8 +381,9 @@ optional_class_type:
;
argument_list:
non_empty_argument_list { $$ = $1; }
| /* empty */ { $$ = array(); }
'(' ')' { $$ = array(); }
| '(' non_empty_argument_list ')' { $$ = $2; }
| '(' yield_expr ')' { $$ = array(Arg[$2, false]); }
;
non_empty_argument_list:
@ -495,10 +510,10 @@ for_expr:
expr:
variable { $$ = $1; }
| T_LIST '(' assignment_list ')' '=' expr { $$ = Expr_AssignList[$3, $6]; }
| list_expr '=' expr { $$ = Expr_Assign[$1, $3]; }
| variable '=' expr { $$ = Expr_Assign[$1, $3]; }
| variable '=' '&' variable { $$ = Expr_AssignRef[$1, $4]; }
| variable '=' '&' new_expr { $$ = Expr_Assign[$1, $4]; } /* reference dropped intentially */
| 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]; }
@ -545,16 +560,16 @@ expr:
| 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]; }
| '(' expr ')' { $$ = $2; }
| 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 '(' variable ')' { $$ = Expr_Empty[$3]; }
| T_EMPTY '(' expr ')' { $$ = Expr_Empty[$3]; }
| T_INCLUDE expr { $$ = Expr_Include[$2, Expr_Include::TYPE_INCLUDE]; }
| T_INCLUDE_ONCE expr { $$ = Expr_Include[$2, Expr_Include::TYPE_INCLUDE_ONCE]; }
| T_EVAL '(' expr ')' { $$ = Expr_Eval[$3]; }
| T_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]; }
@ -567,16 +582,40 @@ expr:
| T_EXIT exit_expr { $$ = Expr_Exit [$2]; }
| '@' expr { $$ = Expr_ErrorSuppress[$2]; }
| scalar { $$ = $1; }
| T_ARRAY '(' array_pair_list ')' { $$ = Expr_Array[$3]; }
| '[' array_pair_list ']' { $$ = Expr_Array[$2]; }
| 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]; }
;
@ -596,28 +635,28 @@ lexical_var:
;
function_call:
name '(' argument_list ')' { $$ = Expr_FuncCall[$1, $3]; }
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM T_STRING '(' argument_list ')'
{ $$ = Expr_StaticCall[$1, $3, $5]; }
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM '{' expr '}' '(' argument_list ')'
{ $$ = Expr_StaticCall[$1, $4, $7]; }
| static_property '(' argument_list ')' {
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], $3];
$$ = 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, $3];
$$ = 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, $3]; }
| variable_without_objects argument_list
{ $$ = Expr_FuncCall[$1, $2]; }
| function_call '[' dim_offset ']' { $$ = Expr_ArrayDimFetch[$1, $3]; }
/* alternative array syntax missing intentionally */
;
@ -660,7 +699,7 @@ object_access_for_dcnr:
exit_expr:
/* empty */ { $$ = null; }
| '(' ')' { $$ = null; }
| '(' expr ')' { $$ = $2; }
| parentheses_expr { $$ = $1; }
;
backticks_expr:
@ -671,13 +710,13 @@ backticks_expr:
ctor_arguments:
/* empty */ { $$ = array(); }
| '(' argument_list ')' { $$ = $2; }
| 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::create($1, $attributes); }
| T_CONSTANT_ENCAPSED_STRING { $$ = Scalar_String[Scalar_String::parse($1)]; }
| T_LINE { $$ = Scalar_LineConst[]; }
| T_FILE { $$ = Scalar_FileConst[]; }
| T_DIR { $$ = Scalar_DirConst[]; }
@ -695,7 +734,7 @@ common_scalar:
static_scalar: /* compile-time evaluated scalars */
common_scalar { $$ = $1; }
| class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { $$ = Expr_ClassConstFetch[$1, $3]; }
| 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]; }
@ -704,13 +743,19 @@ static_scalar: /* compile-time evaluated scalars */
scalar:
common_scalar { $$ = $1; }
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM T_STRING { $$ = Expr_ClassConstFetch[$1, $3]; }
| 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; }
@ -747,9 +792,9 @@ new_expr_array_deref:
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, $5]; }
| object_access '(' argument_list ')' { $$ = Expr_FuncCall[$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]; }
;
@ -802,14 +847,18 @@ object_property:
| variable_without_objects { $$ = $1; }
;
assignment_list:
assignment_list ',' assignment_list_element { push($1, $3); }
| assignment_list_element { init($1); }
list_expr:
T_LIST '(' list_expr_elements ')' { $$ = Expr_List[$3]; }
;
assignment_list_element:
list_expr_elements:
list_expr_elements ',' list_expr_element { push($1, $3); }
| list_expr_element { init($1); }
;
list_expr_element:
variable { $$ = $1; }
| T_LIST '(' assignment_list ')' { $$ = $3; }
| list_expr { $$ = $1; }
| /* empty */ { $$ = null; }
;

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

@ -35,7 +35,7 @@ abstract class PHPParser_BuilderAbstract implements PHPParser_Builder {
/**
* Normalizes a value: Converts nulls, booleans, integers,
* floats and strings into their respective nodes
* floats, strings and arrays into their respective nodes
*
* @param mixed $value The value to normalize
*

View File

@ -1,12 +1,13 @@
<?php
/**
* "class" and "function" are reserved keywords, so the methods are defined as _class()
* and _function() in the class and are made available as class() and function() through
* __call() magic.
* "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
{
@ -21,6 +22,17 @@ class PHPParser_BuilderFactory
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.
*
@ -66,10 +78,8 @@ class PHPParser_BuilderFactory
}
public function __call($name, array $args) {
if ('class' === $name) {
return call_user_func_array(array($this, '_class'), $args);
} elseif ('function' === $name) {
return call_user_func_array(array($this, '_function'), $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

@ -46,7 +46,7 @@ class PHPParser_Comment
/**
* Sets the line number the comment started on.
*
* @param int Line number
* @param int $line Line number
*/
public function setLine($line) {
$this->line = $line;

View File

@ -11,31 +11,33 @@ class PHPParser_Lexer_Emulative extends PHPParser_Lexer
public function __construct() {
parent::__construct();
$this->newKeywords = array();
if (version_compare(PHP_VERSION, '5.4.0RC1', '>=')) {
return;
}
// new PHP 5.4 keywords
$this->newKeywords += array(
$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,
);
if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
return;
}
// new PHP 5.3 keywords
$this->newKeywords += array(
),
'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) {

View File

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

View File

@ -2,7 +2,7 @@
/**
* @property PHPParser_Node[] $stmts Statements
* @property PHPParser_Node_Stmt_FuncParam[] $params Parameters
* @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

View File

@ -1,20 +1,20 @@
<?php
/**
* @property PHPParser_Node_Expr $var Variable
* @property PHPParser_Node_Expr $expr Expression
*/
class PHPParser_Node_Expr_Empty extends PHPParser_Node_Expr
{
/**
* Constructs an empty() 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, array $attributes = array()) {
public function __construct(PHPParser_Node_Expr $expr, array $attributes = array()) {
parent::__construct(
array(
'var' => $var
'expr' => $expr
),
$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 null|PHPParser_Node_Expr $value Value expression
* @property null|PHPParser_Node_Expr $key Key expression
*/
class PHPParser_Node_Expr_Yield extends PHPParser_Node_Expr
{
/**
* Constructs a yield expression node.
*
* @param null|PHPParser_Node_Expr $value ´ Value expression
* @param null|PHPParser_Node_Expr $key Key expression
* @param array $attributes Additional attributes
*/
public function __construct(PHPParser_Node_Expr $value = null, PHPParser_Node_Expr $key = null, array $attributes = array()) {
parent::__construct(
array(
'key' => $key,
'value' => $value,
),
$attributes
);
}
}

View File

@ -1,7 +1,7 @@
<?php
/**
* @property double $value Number value
* @property float $value Number value
*/
class PHPParser_Node_Scalar_DNumber extends PHPParser_Node_Scalar
{

View File

@ -32,30 +32,27 @@ class PHPParser_Node_Scalar_String extends PHPParser_Node_Scalar
}
/**
* Creates a String node from a string token (parses escape sequences).
* Parses a string token.
*
* @param string $str String
* @param array $attributes Additional attributes
* @param string $str String token content
*
* @return PHPParser_Node_Scalar_String String Node
* @return string The parsed string
*/
public static function create($str, array $attributes = array()) {
public static function parse($str) {
$bLength = 0;
if ('b' === $str[0]) {
$bLength = 1;
}
if ('\'' === $str[$bLength]) {
$str = str_replace(
return str_replace(
array('\\\\', '\\\''),
array( '\\', '\''),
substr($str, $bLength + 1, -1)
);
} else {
$str = self::parseEscapeSequences(substr($str, $bLength + 1, -1), '"');
return self::parseEscapeSequences(substr($str, $bLength + 1, -1), '"');
}
return new self($str, $attributes);
}
/**

View File

@ -16,8 +16,8 @@ class PHPParser_Node_Stmt_Case extends PHPParser_Node_Stmt
public function __construct($cond, array $stmts = array(), array $attributes = array()) {
parent::__construct(
array(
'stmts' => $stmts,
'cond' => $cond,
'stmts' => $stmts,
),
$attributes
);

View File

@ -1,14 +1,14 @@
<?php
/**
* @property PHPParser_Node_Stmts_StaticVar[] $vars Variable definitions
* @property PHPParser_Node_Stmt_StaticVar[] $vars Variable definitions
*/
class PHPParser_Node_Stmt_Static extends PHPParser_Node_Stmt
{
/**
* Constructs a static variables list node.
*
* @param PHPParser_Node_Stmts_StaticVar[] $vars Variable definitions
* @param PHPParser_Node_Stmt_StaticVar[] $vars Variable definitions
* @param array $attributes Additional attributes
*/
public function __construct(array $vars, array $attributes = array()) {

View File

@ -2,7 +2,7 @@
/**
* @property PHPParser_Node_Name[] $traits Traits
* @property PHPParser_Node_TraitUseAdaptation[] $adaptations Adaptations
* @property PHPParser_Node_Stmt_TraitUseAdaptation[] $adaptations Adaptations
*/
class PHPParser_Node_Stmt_TraitUse extends PHPParser_Node_Stmt
{
@ -10,7 +10,7 @@ class PHPParser_Node_Stmt_TraitUse extends PHPParser_Node_Stmt
* Constructs a trait use node.
*
* @param PHPParser_Node_Name[] $traits Traits
* @param PHPParser_Node_TraitUseAdaptation[] $adaptations Adaptations
* @param PHPParser_Node_Stmt_TraitUseAdaptation[] $adaptations Adaptations
* @param array $attributes Additional attributes
*/
public function __construct(array $traits, array $adaptations = array(), array $attributes = array()) {

View File

@ -3,6 +3,7 @@
/**
* @property PHPParser_Node[] $stmts Statements
* @property PHPParser_Node_Stmt_Catch[] $catches Catches
* @property PHPParser_Node[] $finallyStmts Finally statements
*/
class PHPParser_Node_Stmt_TryCatch extends PHPParser_Node_Stmt
{
@ -11,13 +12,19 @@ class PHPParser_Node_Stmt_TryCatch extends PHPParser_Node_Stmt
*
* @param PHPParser_Node[] $stmts Statements
* @param PHPParser_Node_Stmt_Catch[] $catches Catches
* @param array $attributes Additional attributes
* @param PHPParser_Node[] $finallyStmts Finally statements (null means no finally clause)
* @param array|null $attributes Additional attributes
*/
public function __construct(array $stmts, array $catches, array $attributes = array()) {
public function __construct(array $stmts, array $catches, array $finallyStmts = null, array $attributes = array()) {
if (empty($catches) && null === $finallyStmts) {
throw new PHPParser_Error('Cannot use try without catch or finally');
}
parent::__construct(
array(
'stmts' => $stmts,
'catches' => $catches,
'finallyStmts' => $finallyStmts,
),
$attributes
);

View File

@ -2,7 +2,7 @@
/**
* @property PHPParser_Node_Expr $cond Condition
* @property PHPParsre_Node[] $stmts Statements
* @property PHPParser_Node[] $stmts Statements
*/
class PHPParser_Node_Stmt_While extends PHPParser_Node_Stmt
{

View File

@ -1,6 +1,6 @@
<?php
class PHPParser_NodeTraverser
class PHPParser_NodeTraverser implements PHPParser_NodeTraverserInterface
{
/**
* @var PHPParser_NodeVisitor[] Visitors

View File

@ -0,0 +1,21 @@
<?php
interface PHPParser_NodeTraverserInterface
{
/**
* Adds a visitor.
*
* @param PHPParser_NodeVisitor $visitor Visitor to add
*/
function addVisitor(PHPParser_NodeVisitor $visitor);
/**
* Traverses an array of nodes using the registered visitors.
*
* @param PHPParser_Node[] $nodes Array of nodes
*
* @return PHPParser_Node[] Traversed array of nodes
*/
function traverse(array $nodes);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,725 @@
<?php
class PHPParser_PrettyPrinter_Default extends PHPParser_PrettyPrinterAbstract
{
// Special nodes
public function pParam(PHPParser_Node_Param $node) {
return ($node->type ? (is_string($node->type) ? $node->type : $this->p($node->type)) . ' ' : '')
. ($node->byRef ? '&' : '')
. '$' . $node->name
. ($node->default ? ' = ' . $this->p($node->default) : '');
}
public function pArg(PHPParser_Node_Arg $node) {
return ($node->byRef ? '&' : '') . $this->p($node->value);
}
public function pConst(PHPParser_Node_Const $node) {
return $node->name . ' = ' . $this->p($node->value);
}
// Names
public function pName(PHPParser_Node_Name $node) {
return implode('\\', $node->parts);
}
public function pName_FullyQualified(PHPParser_Node_Name_FullyQualified $node) {
return '\\' . implode('\\', $node->parts);
}
public function pName_Relative(PHPParser_Node_Name_Relative $node) {
return 'namespace\\' . implode('\\', $node->parts);
}
// Magic Constants
public function pScalar_ClassConst(PHPParser_Node_Scalar_ClassConst $node) {
return '__CLASS__';
}
public function pScalar_TraitConst(PHPParser_Node_Scalar_TraitConst $node) {
return '__TRAIT__';
}
public function pScalar_DirConst(PHPParser_Node_Scalar_DirConst $node) {
return '__DIR__';
}
public function pScalar_FileConst(PHPParser_Node_Scalar_FileConst $node) {
return '__FILE__';
}
public function pScalar_FuncConst(PHPParser_Node_Scalar_FuncConst $node) {
return '__FUNCTION__';
}
public function pScalar_LineConst(PHPParser_Node_Scalar_LineConst $node) {
return '__LINE__';
}
public function pScalar_MethodConst(PHPParser_Node_Scalar_MethodConst $node) {
return '__METHOD__';
}
public function pScalar_NSConst(PHPParser_Node_Scalar_NSConst $node) {
return '__NAMESPACE__';
}
// Scalars
public function pScalar_String(PHPParser_Node_Scalar_String $node) {
return '\'' . $this->pNoIndent(addcslashes($node->value, '\'\\')) . '\'';
}
public function pScalar_Encapsed(PHPParser_Node_Scalar_Encapsed $node) {
return '"' . $this->pEncapsList($node->parts, '"') . '"';
}
public function pScalar_LNumber(PHPParser_Node_Scalar_LNumber $node) {
return (string) $node->value;
}
public function pScalar_DNumber(PHPParser_Node_Scalar_DNumber $node) {
$stringValue = (string) $node->value;
// ensure that number is really printed as float
return ctype_digit($stringValue) ? $stringValue . '.0' : $stringValue;
}
// Assignments
public function pExpr_Assign(PHPParser_Node_Expr_Assign $node) {
return $this->pInfixOp('Expr_Assign', $node->var, ' = ', $node->expr);
}
public function pExpr_AssignRef(PHPParser_Node_Expr_AssignRef $node) {
return $this->pInfixOp('Expr_AssignRef', $node->var, ' =& ', $node->expr);
}
public function pExpr_AssignPlus(PHPParser_Node_Expr_AssignPlus $node) {
return $this->pInfixOp('Expr_AssignPlus', $node->var, ' += ', $node->expr);
}
public function pExpr_AssignMinus(PHPParser_Node_Expr_AssignMinus $node) {
return $this->pInfixOp('Expr_AssignMinus', $node->var, ' -= ', $node->expr);
}
public function pExpr_AssignMul(PHPParser_Node_Expr_AssignMul $node) {
return $this->pInfixOp('Expr_AssignMul', $node->var, ' *= ', $node->expr);
}
public function pExpr_AssignDiv(PHPParser_Node_Expr_AssignDiv $node) {
return $this->pInfixOp('Expr_AssignDiv', $node->var, ' /= ', $node->expr);
}
public function pExpr_AssignConcat(PHPParser_Node_Expr_AssignConcat $node) {
return $this->pInfixOp('Expr_AssignConcat', $node->var, ' .= ', $node->expr);
}
public function pExpr_AssignMod(PHPParser_Node_Expr_AssignMod $node) {
return $this->pInfixOp('Expr_AssignMod', $node->var, ' %= ', $node->expr);
}
public function pExpr_AssignBitwiseAnd(PHPParser_Node_Expr_AssignBitwiseAnd $node) {
return $this->pInfixOp('Expr_AssignBitwiseAnd', $node->var, ' &= ', $node->expr);
}
public function pExpr_AssignBitwiseOr(PHPParser_Node_Expr_AssignBitwiseOr $node) {
return $this->pInfixOp('Expr_AssignBitwiseOr', $node->var, ' |= ', $node->expr);
}
public function pExpr_AssignBitwiseXor(PHPParser_Node_Expr_AssignBitwiseXor $node) {
return $this->pInfixOp('Expr_AssignBitwiseXor', $node->var, ' ^= ', $node->expr);
}
public function pExpr_AssignShiftLeft(PHPParser_Node_Expr_AssignShiftLeft $node) {
return $this->pInfixOp('Expr_AssignShiftLeft', $node->var, ' <<= ', $node->expr);
}
public function pExpr_AssignShiftRight(PHPParser_Node_Expr_AssignShiftRight $node) {
return $this->pInfixOp('Expr_AssignShiftRight', $node->var, ' >>= ', $node->expr);
}
// Binary expressions
public function pExpr_Plus(PHPParser_Node_Expr_Plus $node) {
return $this->pInfixOp('Expr_Plus', $node->left, ' + ', $node->right);
}
public function pExpr_Minus(PHPParser_Node_Expr_Minus $node) {
return $this->pInfixOp('Expr_Minus', $node->left, ' - ', $node->right);
}
public function pExpr_Mul(PHPParser_Node_Expr_Mul $node) {
return $this->pInfixOp('Expr_Mul', $node->left, ' * ', $node->right);
}
public function pExpr_Div(PHPParser_Node_Expr_Div $node) {
return $this->pInfixOp('Expr_Div', $node->left, ' / ', $node->right);
}
public function pExpr_Concat(PHPParser_Node_Expr_Concat $node) {
return $this->pInfixOp('Expr_Concat', $node->left, ' . ', $node->right);
}
public function pExpr_Mod(PHPParser_Node_Expr_Mod $node) {
return $this->pInfixOp('Expr_Mod', $node->left, ' % ', $node->right);
}
public function pExpr_BooleanAnd(PHPParser_Node_Expr_BooleanAnd $node) {
return $this->pInfixOp('Expr_BooleanAnd', $node->left, ' && ', $node->right);
}
public function pExpr_BooleanOr(PHPParser_Node_Expr_BooleanOr $node) {
return $this->pInfixOp('Expr_BooleanOr', $node->left, ' || ', $node->right);
}
public function pExpr_BitwiseAnd(PHPParser_Node_Expr_BitwiseAnd $node) {
return $this->pInfixOp('Expr_BitwiseAnd', $node->left, ' & ', $node->right);
}
public function pExpr_BitwiseOr(PHPParser_Node_Expr_BitwiseOr $node) {
return $this->pInfixOp('Expr_BitwiseOr', $node->left, ' | ', $node->right);
}
public function pExpr_BitwiseXor(PHPParser_Node_Expr_BitwiseXor $node) {
return $this->pInfixOp('Expr_BitwiseXor', $node->left, ' ^ ', $node->right);
}
public function pExpr_ShiftLeft(PHPParser_Node_Expr_ShiftLeft $node) {
return $this->pInfixOp('Expr_ShiftLeft', $node->left, ' << ', $node->right);
}
public function pExpr_ShiftRight(PHPParser_Node_Expr_ShiftRight $node) {
return $this->pInfixOp('Expr_ShiftRight', $node->left, ' >> ', $node->right);
}
public function pExpr_LogicalAnd(PHPParser_Node_Expr_LogicalAnd $node) {
return $this->pInfixOp('Expr_LogicalAnd', $node->left, ' and ', $node->right);
}
public function pExpr_LogicalOr(PHPParser_Node_Expr_LogicalOr $node) {
return $this->pInfixOp('Expr_LogicalOr', $node->left, ' or ', $node->right);
}
public function pExpr_LogicalXor(PHPParser_Node_Expr_LogicalXor $node) {
return $this->pInfixOp('Expr_LogicalXor', $node->left, ' xor ', $node->right);
}
public function pExpr_Equal(PHPParser_Node_Expr_Equal $node) {
return $this->pInfixOp('Expr_Equal', $node->left, ' == ', $node->right);
}
public function pExpr_NotEqual(PHPParser_Node_Expr_NotEqual $node) {
return $this->pInfixOp('Expr_NotEqual', $node->left, ' != ', $node->right);
}
public function pExpr_Identical(PHPParser_Node_Expr_Identical $node) {
return $this->pInfixOp('Expr_Identical', $node->left, ' === ', $node->right);
}
public function pExpr_NotIdentical(PHPParser_Node_Expr_NotIdentical $node) {
return $this->pInfixOp('Expr_NotIdentical', $node->left, ' !== ', $node->right);
}
public function pExpr_Greater(PHPParser_Node_Expr_Greater $node) {
return $this->pInfixOp('Expr_Greater', $node->left, ' > ', $node->right);
}
public function pExpr_GreaterOrEqual(PHPParser_Node_Expr_GreaterOrEqual $node) {
return $this->pInfixOp('Expr_GreaterOrEqual', $node->left, ' >= ', $node->right);
}
public function pExpr_Smaller(PHPParser_Node_Expr_Smaller $node) {
return $this->pInfixOp('Expr_Smaller', $node->left, ' < ', $node->right);
}
public function pExpr_SmallerOrEqual(PHPParser_Node_Expr_SmallerOrEqual $node) {
return $this->pInfixOp('Expr_SmallerOrEqual', $node->left, ' <= ', $node->right);
}
public function pExpr_Instanceof(PHPParser_Node_Expr_Instanceof $node) {
return $this->pInfixOp('Expr_Instanceof', $node->expr, ' instanceof ', $node->class);
}
// Unary expressions
public function pExpr_BooleanNot(PHPParser_Node_Expr_BooleanNot $node) {
return $this->pPrefixOp('Expr_BooleanNot', '!', $node->expr);
}
public function pExpr_BitwiseNot(PHPParser_Node_Expr_BitwiseNot $node) {
return $this->pPrefixOp('Expr_BitwiseNot', '~', $node->expr);
}
public function pExpr_UnaryMinus(PHPParser_Node_Expr_UnaryMinus $node) {
return $this->pPrefixOp('Expr_UnaryMinus', '-', $node->expr);
}
public function pExpr_UnaryPlus(PHPParser_Node_Expr_UnaryPlus $node) {
return $this->pPrefixOp('Expr_UnaryPlus', '+', $node->expr);
}
public function pExpr_PreInc(PHPParser_Node_Expr_PreInc $node) {
return $this->pPrefixOp('Expr_PreInc', '++', $node->var);
}
public function pExpr_PreDec(PHPParser_Node_Expr_PreDec $node) {
return $this->pPrefixOp('Expr_PreDec', '--', $node->var);
}
public function pExpr_PostInc(PHPParser_Node_Expr_PostInc $node) {
return $this->pPostfixOp('Expr_PostInc', $node->var, '++');
}
public function pExpr_PostDec(PHPParser_Node_Expr_PostDec $node) {
return $this->pPostfixOp('Expr_PostDec', $node->var, '--');
}
public function pExpr_ErrorSuppress(PHPParser_Node_Expr_ErrorSuppress $node) {
return $this->pPrefixOp('Expr_ErrorSuppress', '@', $node->expr);
}
// Casts
public function pExpr_Cast_Int(PHPParser_Node_Expr_Cast_Int $node) {
return $this->pPrefixOp('Expr_Cast_Int', '(int) ', $node->expr);
}
public function pExpr_Cast_Double(PHPParser_Node_Expr_Cast_Double $node) {
return $this->pPrefixOp('Expr_Cast_Double', '(double) ', $node->expr);
}
public function pExpr_Cast_String(PHPParser_Node_Expr_Cast_String $node) {
return $this->pPrefixOp('Expr_Cast_String', '(string) ', $node->expr);
}
public function pExpr_Cast_Array(PHPParser_Node_Expr_Cast_Array $node) {
return $this->pPrefixOp('Expr_Cast_Array', '(array) ', $node->expr);
}
public function pExpr_Cast_Object(PHPParser_Node_Expr_Cast_Object $node) {
return $this->pPrefixOp('Expr_Cast_Object', '(object) ', $node->expr);
}
public function pExpr_Cast_Bool(PHPParser_Node_Expr_Cast_Bool $node) {
return $this->pPrefixOp('Expr_Cast_Bool', '(bool) ', $node->expr);
}
public function pExpr_Cast_Unset(PHPParser_Node_Expr_Cast_Unset $node) {
return $this->pPrefixOp('Expr_Cast_Unset', '(unset) ', $node->expr);
}
// Function calls and similar constructs
public function pExpr_FuncCall(PHPParser_Node_Expr_FuncCall $node) {
return $this->p($node->name) . '(' . $this->pCommaSeparated($node->args) . ')';
}
public function pExpr_MethodCall(PHPParser_Node_Expr_MethodCall $node) {
return $this->pVarOrNewExpr($node->var) . '->' . $this->pObjectProperty($node->name)
. '(' . $this->pCommaSeparated($node->args) . ')';
}
public function pExpr_StaticCall(PHPParser_Node_Expr_StaticCall $node) {
return $this->p($node->class) . '::'
. ($node->name instanceof PHPParser_Node_Expr
? ($node->name instanceof PHPParser_Node_Expr_Variable
|| $node->name instanceof PHPParser_Node_Expr_ArrayDimFetch
? $this->p($node->name)
: '{' . $this->p($node->name) . '}')
: $node->name)
. '(' . $this->pCommaSeparated($node->args) . ')';
}
public function pExpr_Empty(PHPParser_Node_Expr_Empty $node) {
return 'empty(' . $this->p($node->expr) . ')';
}
public function pExpr_Isset(PHPParser_Node_Expr_Isset $node) {
return 'isset(' . $this->pCommaSeparated($node->vars) . ')';
}
public function pExpr_Print(PHPParser_Node_Expr_Print $node) {
return 'print ' . $this->p($node->expr);
}
public function pExpr_Eval(PHPParser_Node_Expr_Eval $node) {
return 'eval(' . $this->p($node->expr) . ')';
}
public function pExpr_Include(PHPParser_Node_Expr_Include $node) {
static $map = array(
PHPParser_Node_Expr_Include::TYPE_INCLUDE => 'include',
PHPParser_Node_Expr_Include::TYPE_INCLUDE_ONCE => 'include_once',
PHPParser_Node_Expr_Include::TYPE_REQUIRE => 'require',
PHPParser_Node_Expr_Include::TYPE_REQUIRE_ONCE => 'require_once',
);
return $map[$node->type] . ' ' . $this->p($node->expr);
}
public function pExpr_List(PHPParser_Node_Expr_List $node) {
$pList = array();
foreach ($node->vars as $var) {
if (null === $var) {
$pList[] = '';
} else {
$pList[] = $this->p($var);
}
}
return 'list(' . implode(', ', $pList) . ')';
}
// Other
public function pExpr_Variable(PHPParser_Node_Expr_Variable $node) {
if ($node->name instanceof PHPParser_Node_Expr) {
return '${' . $this->p($node->name) . '}';
} else {
return '$' . $node->name;
}
}
public function pExpr_Array(PHPParser_Node_Expr_Array $node) {
return 'array(' . $this->pCommaSeparated($node->items) . ')';
}
public function pExpr_ArrayItem(PHPParser_Node_Expr_ArrayItem $node) {
return (null !== $node->key ? $this->p($node->key) . ' => ' : '')
. ($node->byRef ? '&' : '') . $this->p($node->value);
}
public function pExpr_ArrayDimFetch(PHPParser_Node_Expr_ArrayDimFetch $node) {
return $this->pVarOrNewExpr($node->var)
. '[' . (null !== $node->dim ? $this->p($node->dim) : '') . ']';
}
public function pExpr_ConstFetch(PHPParser_Node_Expr_ConstFetch $node) {
return $this->p($node->name);
}
public function pExpr_ClassConstFetch(PHPParser_Node_Expr_ClassConstFetch $node) {
return $this->p($node->class) . '::' . $node->name;
}
public function pExpr_PropertyFetch(PHPParser_Node_Expr_PropertyFetch $node) {
return $this->pVarOrNewExpr($node->var) . '->' . $this->pObjectProperty($node->name);
}
public function pExpr_StaticPropertyFetch(PHPParser_Node_Expr_StaticPropertyFetch $node) {
return $this->p($node->class) . '::$' . $this->pObjectProperty($node->name);
}
public function pExpr_ShellExec(PHPParser_Node_Expr_ShellExec $node) {
return '`' . $this->pEncapsList($node->parts, '`') . '`';
}
public function pExpr_Closure(PHPParser_Node_Expr_Closure $node) {
return ($node->static ? 'static ' : '')
. 'function ' . ($node->byRef ? '&' : '')
. '(' . $this->pCommaSeparated($node->params) . ')'
. (!empty($node->uses) ? ' use(' . $this->pCommaSeparated($node->uses) . ')': '')
. ' {' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pExpr_ClosureUse(PHPParser_Node_Expr_ClosureUse $node) {
return ($node->byRef ? '&' : '') . '$' . $node->var;
}
public function pExpr_New(PHPParser_Node_Expr_New $node) {
return 'new ' . $this->p($node->class) . '(' . $this->pCommaSeparated($node->args) . ')';
}
public function pExpr_Clone(PHPParser_Node_Expr_Clone $node) {
return 'clone ' . $this->p($node->expr);
}
public function pExpr_Ternary(PHPParser_Node_Expr_Ternary $node) {
// a bit of cheating: we treat the ternary as a binary op where the ?...: part is the operator.
// this is okay because the part between ? and : never needs parentheses.
return $this->pInfixOp('Expr_Ternary',
$node->cond, ' ?' . (null !== $node->if ? ' ' . $this->p($node->if) . ' ' : '') . ': ', $node->else
);
}
public function pExpr_Exit(PHPParser_Node_Expr_Exit $node) {
return 'die' . (null !== $node->expr ? '(' . $this->p($node->expr) . ')' : '');
}
public function pExpr_Yield(PHPParser_Node_Expr_Yield $node) {
if ($node->value === null) {
return 'yield';
} else {
// this is a bit ugly, but currently there is no way to detect whether the parentheses are necessary
return '(yield '
. ($node->key !== null ? $this->p($node->key) . ' => ' : '')
. $this->p($node->value)
. ')';
}
}
// Declarations
public function pStmt_Namespace(PHPParser_Node_Stmt_Namespace $node) {
if ($this->canUseSemicolonNamespaces) {
return 'namespace ' . $this->p($node->name) . ';' . "\n\n" . $this->pStmts($node->stmts, false);
} else {
return 'namespace' . (null !== $node->name ? ' ' . $this->p($node->name) : '')
. ' {' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
}
public function pStmt_Use(PHPParser_Node_Stmt_Use $node) {
return 'use ' . $this->pCommaSeparated($node->uses) . ';';
}
public function pStmt_UseUse(PHPParser_Node_Stmt_UseUse $node) {
return $this->p($node->name)
. ($node->name->getLast() !== $node->alias ? ' as ' . $node->alias : '');
}
public function pStmt_Interface(PHPParser_Node_Stmt_Interface $node) {
return 'interface ' . $node->name
. (!empty($node->extends) ? ' extends ' . $this->pCommaSeparated($node->extends) : '')
. "\n" . '{' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Class(PHPParser_Node_Stmt_Class $node) {
return $this->pModifiers($node->type)
. 'class ' . $node->name
. (null !== $node->extends ? ' extends ' . $this->p($node->extends) : '')
. (!empty($node->implements) ? ' implements ' . $this->pCommaSeparated($node->implements) : '')
. "\n" . '{' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Trait(PHPParser_Node_Stmt_Trait $node) {
return 'trait ' . $node->name
. "\n" . '{' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_TraitUse(PHPParser_Node_Stmt_TraitUse $node) {
return 'use ' . $this->pCommaSeparated($node->traits)
. (empty($node->adaptations)
? ';'
: ' {' . "\n" . $this->pStmts($node->adaptations) . "\n" . '}');
}
public function pStmt_TraitUseAdaptation_Precedence(PHPParser_Node_Stmt_TraitUseAdaptation_Precedence $node) {
return $this->p($node->trait) . '::' . $node->method
. ' insteadof ' . $this->pCommaSeparated($node->insteadof) . ';';
}
public function pStmt_TraitUseAdaptation_Alias(PHPParser_Node_Stmt_TraitUseAdaptation_Alias $node) {
return (null !== $node->trait ? $this->p($node->trait) . '::' : '')
. $node->method . ' as'
. (null !== $node->newModifier ? ' ' . $this->pModifiers($node->newModifier) : '')
. (null !== $node->newName ? ' ' . $node->newName : '')
. ';';
}
public function pStmt_Property(PHPParser_Node_Stmt_Property $node) {
return $this->pModifiers($node->type) . $this->pCommaSeparated($node->props) . ';';
}
public function pStmt_PropertyProperty(PHPParser_Node_Stmt_PropertyProperty $node) {
return '$' . $node->name
. (null !== $node->default ? ' = ' . $this->p($node->default) : '');
}
public function pStmt_ClassMethod(PHPParser_Node_Stmt_ClassMethod $node) {
return $this->pModifiers($node->type)
. 'function ' . ($node->byRef ? '&' : '') . $node->name
. '(' . $this->pCommaSeparated($node->params) . ')'
. (null !== $node->stmts
? "\n" . '{' . "\n" . $this->pStmts($node->stmts) . "\n" . '}'
: ';');
}
public function pStmt_ClassConst(PHPParser_Node_Stmt_ClassConst $node) {
return 'const ' . $this->pCommaSeparated($node->consts) . ';';
}
public function pStmt_Function(PHPParser_Node_Stmt_Function $node) {
return 'function ' . ($node->byRef ? '&' : '') . $node->name
. '(' . $this->pCommaSeparated($node->params) . ')'
. "\n" . '{' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Const(PHPParser_Node_Stmt_Const $node) {
return 'const ' . $this->pCommaSeparated($node->consts) . ';';
}
public function pStmt_Declare(PHPParser_Node_Stmt_Declare $node) {
return 'declare (' . $this->pCommaSeparated($node->declares) . ') {'
. "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_DeclareDeclare(PHPParser_Node_Stmt_DeclareDeclare $node) {
return $node->key . ' = ' . $this->p($node->value);
}
// Control flow
public function pStmt_If(PHPParser_Node_Stmt_If $node) {
return 'if (' . $this->p($node->cond) . ') {'
. "\n" . $this->pStmts($node->stmts) . "\n" . '}'
. $this->pImplode($node->elseifs)
. (null !== $node->else ? $this->p($node->else) : '');
}
public function pStmt_Elseif(PHPParser_Node_Stmt_Elseif $node) {
return ' elseif (' . $this->p($node->cond) . ') {'
. "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Else(PHPParser_Node_Stmt_Else $node) {
return ' else {' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_For(PHPParser_Node_Stmt_For $node) {
return 'for ('
. $this->pCommaSeparated($node->init) . ';' . (!empty($node->cond) ? ' ' : '')
. $this->pCommaSeparated($node->cond) . ';' . (!empty($node->loop) ? ' ' : '')
. $this->pCommaSeparated($node->loop)
. ') {' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Foreach(PHPParser_Node_Stmt_Foreach $node) {
return 'foreach (' . $this->p($node->expr) . ' as '
. (null !== $node->keyVar ? $this->p($node->keyVar) . ' => ' : '')
. ($node->byRef ? '&' : '') . $this->p($node->valueVar) . ') {'
. "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_While(PHPParser_Node_Stmt_While $node) {
return 'while (' . $this->p($node->cond) . ') {'
. "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Do(PHPParser_Node_Stmt_Do $node) {
return 'do {' . "\n" . $this->pStmts($node->stmts) . "\n"
. '} while (' . $this->p($node->cond) . ');';
}
public function pStmt_Switch(PHPParser_Node_Stmt_Switch $node) {
return 'switch (' . $this->p($node->cond) . ') {'
. "\n" . $this->pStmts($node->cases) . "\n" . '}';
}
public function pStmt_Case(PHPParser_Node_Stmt_Case $node) {
return (null !== $node->cond ? 'case ' . $this->p($node->cond) : 'default') . ':'
. ($node->stmts ? "\n" . $this->pStmts($node->stmts) : '');
}
public function pStmt_TryCatch(PHPParser_Node_Stmt_TryCatch $node) {
return 'try {' . "\n" . $this->pStmts($node->stmts) . "\n" . '}'
. $this->pImplode($node->catches)
. ($node->finallyStmts !== null
? ' finally {' . "\n" . $this->pStmts($node->finallyStmts) . "\n" . '}'
: '');
}
public function pStmt_Catch(PHPParser_Node_Stmt_Catch $node) {
return ' catch (' . $this->p($node->type) . ' $' . $node->var . ') {'
. "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Break(PHPParser_Node_Stmt_Break $node) {
return 'break' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';';
}
public function pStmt_Continue(PHPParser_Node_Stmt_Continue $node) {
return 'continue' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';';
}
public function pStmt_Return(PHPParser_Node_Stmt_Return $node) {
return 'return' . (null !== $node->expr ? ' ' . $this->p($node->expr) : '') . ';';
}
public function pStmt_Throw(PHPParser_Node_Stmt_Throw $node) {
return 'throw ' . $this->p($node->expr) . ';';
}
public function pStmt_Label(PHPParser_Node_Stmt_Label $node) {
return $node->name . ':';
}
public function pStmt_Goto(PHPParser_Node_Stmt_Goto $node) {
return 'goto ' . $node->name . ';';
}
// Other
public function pStmt_Echo(PHPParser_Node_Stmt_Echo $node) {
return 'echo ' . $this->pCommaSeparated($node->exprs) . ';';
}
public function pStmt_Static(PHPParser_Node_Stmt_Static $node) {
return 'static ' . $this->pCommaSeparated($node->vars) . ';';
}
public function pStmt_Global(PHPParser_Node_Stmt_Global $node) {
return 'global ' . $this->pCommaSeparated($node->vars) . ';';
}
public function pStmt_StaticVar(PHPParser_Node_Stmt_StaticVar $node) {
return '$' . $node->name
. (null !== $node->default ? ' = ' . $this->p($node->default) : '');
}
public function pStmt_Unset(PHPParser_Node_Stmt_Unset $node) {
return 'unset(' . $this->pCommaSeparated($node->vars) . ');';
}
public function pStmt_InlineHTML(PHPParser_Node_Stmt_InlineHTML $node) {
return '?>' . $this->pNoIndent("\n" . $node->value) . '<?php ';
}
public function pStmt_HaltCompiler(PHPParser_Node_Stmt_HaltCompiler $node) {
return '__halt_compiler();' . $node->remaining;
}
// Helpers
public function pObjectProperty($node) {
if ($node instanceof PHPParser_Node_Expr) {
return '{' . $this->p($node) . '}';
} else {
return $node;
}
}
public function pModifiers($modifiers) {
return ($modifiers & PHPParser_Node_Stmt_Class::MODIFIER_PUBLIC ? 'public ' : '')
. ($modifiers & PHPParser_Node_Stmt_Class::MODIFIER_PROTECTED ? 'protected ' : '')
. ($modifiers & PHPParser_Node_Stmt_Class::MODIFIER_PRIVATE ? 'private ' : '')
. ($modifiers & PHPParser_Node_Stmt_Class::MODIFIER_STATIC ? 'static ' : '')
. ($modifiers & PHPParser_Node_Stmt_Class::MODIFIER_ABSTRACT ? 'abstract ' : '')
. ($modifiers & PHPParser_Node_Stmt_Class::MODIFIER_FINAL ? 'final ' : '');
}
public function pEncapsList(array $encapsList, $quote) {
$return = '';
foreach ($encapsList as $element) {
if (is_string($element)) {
$return .= addcslashes($element, "\n\r\t\f\v$" . $quote . "\\");
} else {
$return .= '{' . $this->p($element) . '}';
}
}
return $return;
}
public function pVarOrNewExpr(PHPParser_Node $node) {
if ($node instanceof PHPParser_Node_Expr_New) {
return '(' . $this->p($node) . ')';
} else {
return $this->p($node);
}
}
}

View File

@ -1,713 +1,10 @@
<?php
class PHPParser_PrettyPrinter_Zend extends PHPParser_PrettyPrinterAbstract
/**
* This class is only retained for backwards compatibility. Use PHPParser_PrettyPrinter_Default instead.
*
* @deprecated
*/
class PHPParser_PrettyPrinter_Zend extends PHPParser_PrettyPrinter_Default
{
// Special nodes
public function pParam(PHPParser_Node_Param $node) {
return ($node->type ? (is_string($node->type) ? $node->type : $this->p($node->type)) . ' ' : '')
. ($node->byRef ? '&' : '')
. '$' . $node->name
. ($node->default ? ' = ' . $this->p($node->default) : '');
}
public function pArg(PHPParser_Node_Arg $node) {
return ($node->byRef ? '&' : '') . $this->p($node->value);
}
public function pConst(PHPParser_Node_Const $node) {
return $node->name . ' = ' . $this->p($node->value);
}
// Names
public function pName(PHPParser_Node_Name $node) {
return implode('\\', $node->parts);
}
public function pName_FullyQualified(PHPParser_Node_Name_FullyQualified $node) {
return '\\' . implode('\\', $node->parts);
}
public function pName_Relative(PHPParser_Node_Name_Relative $node) {
return 'namespace\\' . implode('\\', $node->parts);
}
// Magic Constants
public function pScalar_ClassConst(PHPParser_Node_Scalar_ClassConst $node) {
return '__CLASS__';
}
public function pScalar_TraitConst(PHPParser_Node_Scalar_TraitConst $node) {
return '__TRAIT__';
}
public function pScalar_DirConst(PHPParser_Node_Scalar_DirConst $node) {
return '__DIR__';
}
public function pScalar_FileConst(PHPParser_Node_Scalar_FileConst $node) {
return '__FILE__';
}
public function pScalar_FuncConst(PHPParser_Node_Scalar_FuncConst $node) {
return '__FUNCTION__';
}
public function pScalar_LineConst(PHPParser_Node_Scalar_LineConst $node) {
return '__LINE__';
}
public function pScalar_MethodConst(PHPParser_Node_Scalar_MethodConst $node) {
return '__METHOD__';
}
public function pScalar_NSConst(PHPParser_Node_Scalar_NSConst $node) {
return '__NAMESPACE__';
}
// Scalars
public function pScalar_String(PHPParser_Node_Scalar_String $node) {
return '\'' . $this->pSafe(addcslashes($node->value, '\'\\')) . '\'';
}
public function pScalar_Encapsed(PHPParser_Node_Scalar_Encapsed $node) {
return '"' . $this->pEncapsList($node->parts, '"') . '"';
}
public function pScalar_LNumber(PHPParser_Node_Scalar_LNumber $node) {
return (string) $node->value;
}
public function pScalar_DNumber(PHPParser_Node_Scalar_DNumber $node) {
$stringValue = (string) $node->value;
// ensure that number is really printed as float
return ctype_digit($stringValue) ? $stringValue . '.0' : $stringValue;
}
// Assignments
public function pExpr_Assign(PHPParser_Node_Expr_Assign $node) {
return $this->p($node->var) . ' = ' . $this->p($node->expr);
}
public function pExpr_AssignRef(PHPParser_Node_Expr_AssignRef $node) {
return $this->p($node->var) . ' =& ' . $this->p($node->expr);
}
public function pExpr_AssignPlus(PHPParser_Node_Expr_AssignPlus $node) {
return $this->p($node->var) . ' += ' . $this->p($node->expr);
}
public function pExpr_AssignMinus(PHPParser_Node_Expr_AssignMinus $node) {
return $this->p($node->var) . ' -= ' . $this->p($node->expr);
}
public function pExpr_AssignMul(PHPParser_Node_Expr_AssignMul $node) {
return $this->p($node->var) . ' *= ' . $this->p($node->expr);
}
public function pExpr_AssignDiv(PHPParser_Node_Expr_AssignDiv $node) {
return $this->p($node->var) . ' /= ' . $this->p($node->expr);
}
public function pExpr_AssignConcat(PHPParser_Node_Expr_AssignConcat $node) {
return $this->p($node->var) . ' .= ' . $this->p($node->expr);
}
public function pExpr_AssignMod(PHPParser_Node_Expr_AssignMod $node) {
return $this->p($node->var) . ' %= ' . $this->p($node->expr);
}
public function pExpr_AssignBitwiseAnd(PHPParser_Node_Expr_AssignBitwiseAnd $node) {
return $this->p($node->var) . ' &= ' . $this->p($node->expr);
}
public function pExpr_AssignBitwiseOr(PHPParser_Node_Expr_AssignBitwiseOr $node) {
return $this->p($node->var) . ' |= ' . $this->p($node->expr);
}
public function pExpr_AssignBitwiseXor(PHPParser_Node_Expr_AssignBitwiseXor $node) {
return $this->p($node->var) . ' ^= ' . $this->p($node->expr);
}
public function pExpr_AssignShiftLeft(PHPParser_Node_Expr_AssignShiftLeft $node) {
return $this->p($node->var) . ' <<= ' . $this->p($node->expr);
}
public function pExpr_AssignShiftRight(PHPParser_Node_Expr_AssignShiftRight $node) {
return $this->p($node->var) . ' >>= ' . $this->p($node->expr);
}
public function pExpr_AssignList(PHPParser_Node_Expr_AssignList $node) {
return $this->pAssignList($node->vars) . ' = ' . $this->p($node->expr);
}
// Binary expressions
public function pExpr_Plus(PHPParser_Node_Expr_Plus $node) {
return $this->p($node->left) . ' + ' . $this->p($node->right);
}
public function pExpr_Minus(PHPParser_Node_Expr_Minus $node) {
return $this->p($node->left) . ' - ' . $this->p($node->right);
}
public function pExpr_Mul(PHPParser_Node_Expr_Mul $node) {
return $this->p($node->left) . ' * ' . $this->p($node->right);
}
public function pExpr_Div(PHPParser_Node_Expr_Div $node) {
return $this->p($node->left) . ' / ' . $this->p($node->right);
}
public function pExpr_Concat(PHPParser_Node_Expr_Concat $node) {
return $this->p($node->left) . ' . ' . $this->p($node->right);
}
public function pExpr_Mod(PHPParser_Node_Expr_Mod $node) {
return $this->p($node->left) . ' % ' . $this->p($node->right);
}
public function pExpr_BooleanAnd(PHPParser_Node_Expr_BooleanAnd $node) {
return $this->p($node->left) . ' && ' . $this->p($node->right);
}
public function pExpr_BooleanOr(PHPParser_Node_Expr_BooleanOr $node) {
return $this->p($node->left) . ' || ' . $this->p($node->right);
}
public function pExpr_BitwiseAnd(PHPParser_Node_Expr_BitwiseAnd $node) {
return $this->p($node->left) . ' & ' . $this->p($node->right);
}
public function pExpr_BitwiseOr(PHPParser_Node_Expr_BitwiseOr $node) {
return $this->p($node->left) . ' | ' . $this->p($node->right);
}
public function pExpr_BitwiseXor(PHPParser_Node_Expr_BitwiseXor $node) {
return $this->p($node->left) . ' ^ ' . $this->p($node->right);
}
public function pExpr_ShiftLeft(PHPParser_Node_Expr_ShiftLeft $node) {
return $this->p($node->left) . ' << ' . $this->p($node->right);
}
public function pExpr_ShiftRight(PHPParser_Node_Expr_ShiftRight $node) {
return $this->p($node->left) . ' >> ' . $this->p($node->right);
}
public function pExpr_LogicalAnd(PHPParser_Node_Expr_LogicalAnd $node) {
return $this->p($node->left) . ' and ' . $this->p($node->right);
}
public function pExpr_LogicalOr(PHPParser_Node_Expr_LogicalOr $node) {
return $this->p($node->left) . ' or ' . $this->p($node->right);
}
public function pExpr_LogicalXor(PHPParser_Node_Expr_LogicalXor $node) {
return $this->p($node->left) . ' xor ' . $this->p($node->right);
}
public function pExpr_Equal(PHPParser_Node_Expr_Equal $node) {
return $this->p($node->left) . ' == ' . $this->p($node->right);
}
public function pExpr_NotEqual(PHPParser_Node_Expr_NotEqual $node) {
return $this->p($node->left) . ' != ' . $this->p($node->right);
}
public function pExpr_Identical(PHPParser_Node_Expr_Identical $node) {
return $this->p($node->left) . ' === ' . $this->p($node->right);
}
public function pExpr_NotIdentical(PHPParser_Node_Expr_NotIdentical $node) {
return $this->p($node->left) . ' !== ' . $this->p($node->right);
}
public function pExpr_Greater(PHPParser_Node_Expr_Greater $node) {
return $this->p($node->left) . ' > ' . $this->p($node->right);
}
public function pExpr_GreaterOrEqual(PHPParser_Node_Expr_GreaterOrEqual $node) {
return $this->p($node->left) . ' >= ' . $this->p($node->right);
}
public function pExpr_Smaller(PHPParser_Node_Expr_Smaller $node) {
return $this->p($node->left) . ' < ' . $this->p($node->right);
}
public function pExpr_SmallerOrEqual(PHPParser_Node_Expr_SmallerOrEqual $node) {
return $this->p($node->left) . ' <= ' . $this->p($node->right);
}
public function pExpr_Instanceof(PHPParser_Node_Expr_Instanceof $node) {
return $this->p($node->expr) . ' instanceof ' . $this->p($node->class);
}
// Unary expressions
public function pExpr_BooleanNot(PHPParser_Node_Expr_BooleanNot $node) {
return '!' . $this->p($node->expr);
}
public function pExpr_BitwiseNot(PHPParser_Node_Expr_BitwiseNot $node) {
return '~' . $this->p($node->expr);
}
public function pExpr_UnaryMinus(PHPParser_Node_Expr_UnaryMinus $node) {
return '-' . $this->p($node->expr);
}
public function pExpr_UnaryPlus(PHPParser_Node_Expr_UnaryPlus $node) {
return '+' . $this->p($node->expr);
}
public function pExpr_PreInc(PHPParser_Node_Expr_PreInc $node) {
return '++' . $this->p($node->var);
}
public function pExpr_PreDec(PHPParser_Node_Expr_PreDec $node) {
return '--' . $this->p($node->var);
}
public function pExpr_PostInc(PHPParser_Node_Expr_PostInc $node) {
return $this->p($node->var) . '++';
}
public function pExpr_PostDec(PHPParser_Node_Expr_PostDec $node) {
return $this->p($node->var) . '--';
}
public function pExpr_ErrorSuppress(PHPParser_Node_Expr_ErrorSuppress $node) {
return '@' . $this->p($node->expr);
}
// Casts
public function pExpr_Cast_Int(PHPParser_Node_Expr_Cast_Int $node) {
return '(int) ' . $this->p($node->expr);
}
public function pExpr_Cast_Double(PHPParser_Node_Expr_Cast_Double $node) {
return '(double) ' . $this->p($node->expr);
}
public function pExpr_Cast_String(PHPParser_Node_Expr_Cast_String $node) {
return '(string) ' . $this->p($node->expr);
}
public function pExpr_Cast_Array(PHPParser_Node_Expr_Cast_Array $node) {
return '(array) ' . $this->p($node->expr);
}
public function pExpr_Cast_Object(PHPParser_Node_Expr_Cast_Object $node) {
return '(object) ' . $this->p($node->expr);
}
public function pExpr_Cast_Bool(PHPParser_Node_Expr_Cast_Bool $node) {
return '(bool) ' . $this->p($node->expr);
}
public function pExpr_Cast_Unset(PHPParser_Node_Expr_Cast_Unset $node) {
return '(unset) ' . $this->p($node->expr);
}
// Function calls and similar constructs
public function pExpr_FuncCall(PHPParser_Node_Expr_FuncCall $node) {
return $this->p($node->name) . '(' . $this->pCommaSeparated($node->args) . ')';
}
public function pExpr_MethodCall(PHPParser_Node_Expr_MethodCall $node) {
return $this->pVarOrNewExpr($node->var) . '->' . $this->pObjectProperty($node->name)
. '(' . $this->pCommaSeparated($node->args) . ')';
}
public function pExpr_StaticCall(PHPParser_Node_Expr_StaticCall $node) {
return $this->p($node->class) . '::'
. ($node->name instanceof PHPParser_Node_Expr
? ($node->name instanceof PHPParser_Node_Expr_Variable
|| $node->name instanceof PHPParser_Node_Expr_ArrayDimFetch
? $this->p($node->name)
: '{' . $this->p($node->name) . '}')
: $node->name)
. '(' . $this->pCommaSeparated($node->args) . ')';
}
public function pExpr_Empty(PHPParser_Node_Expr_Empty $node) {
return 'empty(' . $this->p($node->var) . ')';
}
public function pExpr_Isset(PHPParser_Node_Expr_Isset $node) {
return 'isset(' . $this->pCommaSeparated($node->vars) . ')';
}
public function pExpr_Print(PHPParser_Node_Expr_Print $node) {
return 'print ' . $this->p($node->expr);
}
public function pExpr_Eval(PHPParser_Node_Expr_Eval $node) {
return 'eval(' . $this->p($node->expr) . ')';
}
public function pExpr_Include(PHPParser_Node_Expr_Include $node) {
static $map = array(
PHPParser_Node_Expr_Include::TYPE_INCLUDE => 'include',
PHPParser_Node_Expr_Include::TYPE_INCLUDE_ONCE => 'include_once',
PHPParser_Node_Expr_Include::TYPE_REQUIRE => 'require',
PHPParser_Node_Expr_Include::TYPE_REQUIRE_ONCE => 'require_once',
);
return $map[$node->type] . ' ' . $this->p($node->expr);
}
// Other
public function pExpr_Variable(PHPParser_Node_Expr_Variable $node) {
if ($node->name instanceof PHPParser_Node_Expr) {
return '${' . $this->p($node->name) . '}';
} else {
return '$' . $node->name;
}
}
public function pExpr_Array(PHPParser_Node_Expr_Array $node) {
return 'array(' . $this->pCommaSeparated($node->items) . ')';
}
public function pExpr_ArrayItem(PHPParser_Node_Expr_ArrayItem $node) {
return (null !== $node->key ? $this->p($node->key) . ' => ' : '')
. ($node->byRef ? '&' : '') . $this->p($node->value);
}
public function pExpr_ArrayDimFetch(PHPParser_Node_Expr_ArrayDimFetch $node) {
return $this->pVarOrNewExpr($node->var)
. '[' . (null !== $node->dim ? $this->p($node->dim) : '') . ']';
}
public function pExpr_ConstFetch(PHPParser_Node_Expr_ConstFetch $node) {
return $this->p($node->name);
}
public function pExpr_ClassConstFetch(PHPParser_Node_Expr_ClassConstFetch $node) {
return $this->p($node->class) . '::' . $node->name;
}
public function pExpr_PropertyFetch(PHPParser_Node_Expr_PropertyFetch $node) {
return $this->pVarOrNewExpr($node->var) . '->' . $this->pObjectProperty($node->name);
}
public function pExpr_StaticPropertyFetch(PHPParser_Node_Expr_StaticPropertyFetch $node) {
return $this->p($node->class) . '::$' . $this->pObjectProperty($node->name);
}
public function pExpr_ShellExec(PHPParser_Node_Expr_ShellExec $node) {
return '`' . $this->pEncapsList($node->parts, '`') . '`';
}
public function pExpr_Closure(PHPParser_Node_Expr_Closure $node) {
return ($node->static ? 'static ' : '')
. 'function ' . ($node->byRef ? '&' : '')
. '(' . $this->pCommaSeparated($node->params) . ')'
. (!empty($node->uses) ? ' use(' . $this->pCommaSeparated($node->uses) . ')': '')
. ' {' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pExpr_ClosureUse(PHPParser_Node_Expr_ClosureUse $node) {
return ($node->byRef ? '&' : '') . '$' . $node->var;
}
public function pExpr_New(PHPParser_Node_Expr_New $node) {
return 'new ' . $this->p($node->class) . '(' . $this->pCommaSeparated($node->args) . ')';
}
public function pExpr_Clone(PHPParser_Node_Expr_Clone $node) {
return 'clone ' . $this->p($node->expr);
}
public function pExpr_Ternary(PHPParser_Node_Expr_Ternary $node) {
return $this->p($node->cond) . ' ?'
. (null !== $node->if ? ' ' . $this->p($node->if) . ' ' : '')
. ': ' . $this->p($node->else);
}
public function pExpr_Exit(PHPParser_Node_Expr_Exit $node) {
return 'die' . (null !== $node->expr ? '(' . $this->p($node->expr) . ')' : '');
}
// Declarations
public function pStmt_Namespace(PHPParser_Node_Stmt_Namespace $node) {
return 'namespace' . (null !== $node->name ? ' ' . $this->p($node->name) : '')
. ' {' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Use(PHPParser_Node_Stmt_Use $node) {
return 'use ' . $this->pCommaSeparated($node->uses) . ';';
}
public function pStmt_UseUse(PHPParser_Node_Stmt_UseUse $node) {
return $this->p($node->name)
. ($node->name->getLast() !== $node->alias ? ' as ' . $node->alias : '');
}
public function pStmt_Interface(PHPParser_Node_Stmt_Interface $node) {
return 'interface ' . $node->name
. (!empty($node->extends) ? ' extends ' . $this->pCommaSeparated($node->extends) : '')
. "\n" . '{' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Class(PHPParser_Node_Stmt_Class $node) {
return $this->pModifiers($node->type)
. 'class ' . $node->name
. (null !== $node->extends ? ' extends ' . $this->p($node->extends) : '')
. (!empty($node->implements) ? ' implements ' . $this->pCommaSeparated($node->implements) : '')
. "\n" . '{' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Trait(PHPParser_Node_Stmt_Trait $node) {
return 'trait ' . $node->name
. "\n" . '{' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_TraitUse(PHPParser_Node_Stmt_TraitUse $node) {
return 'use ' . $this->pCommaSeparated($node->traits)
. (empty($node->adaptations)
? ';'
: ' {' . "\n" . $this->pStmts($node->adaptations) . "\n" . '}');
}
public function pStmt_TraitUseAdaptation_Precedence(PHPParser_Node_Stmt_TraitUseAdaptation_Precedence $node) {
return $this->p($node->trait) . '::' . $node->method
. ' insteadof ' . $this->pCommaSeparated($node->insteadof) . ';';
}
public function pStmt_TraitUseAdaptation_Alias(PHPParser_Node_Stmt_TraitUseAdaptation_Alias $node) {
return (null !== $node->trait ? $this->p($node->trait) . '::' : '')
. $node->method . ' as'
. (null !== $node->newModifier ? ' ' . $this->pModifiers($node->newModifier) : '')
. (null !== $node->newName ? ' ' . $node->newName : '')
. ';';
}
public function pStmt_Property(PHPParser_Node_Stmt_Property $node) {
return $this->pModifiers($node->type) . $this->pCommaSeparated($node->props) . ';';
}
public function pStmt_PropertyProperty(PHPParser_Node_Stmt_PropertyProperty $node) {
return '$' . $node->name
. (null !== $node->default ? ' = ' . $this->p($node->default) : '');
}
public function pStmt_ClassMethod(PHPParser_Node_Stmt_ClassMethod $node) {
return $this->pModifiers($node->type)
. 'function ' . ($node->byRef ? '&' : '') . $node->name
. '(' . $this->pCommaSeparated($node->params) . ')'
. (null !== $node->stmts
? "\n" . '{' . "\n" . $this->pStmts($node->stmts) . "\n" . '}'
: ';');
}
public function pStmt_ClassConst(PHPParser_Node_Stmt_ClassConst $node) {
return 'const ' . $this->pCommaSeparated($node->consts) . ';';
}
public function pStmt_Function(PHPParser_Node_Stmt_Function $node) {
return 'function ' . ($node->byRef ? '&' : '') . $node->name
. '(' . $this->pCommaSeparated($node->params) . ')'
. "\n" . '{' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Const(PHPParser_Node_Stmt_Const $node) {
return 'const ' . $this->pCommaSeparated($node->consts) . ';';
}
public function pStmt_Declare(PHPParser_Node_Stmt_Declare $node) {
return 'declare (' . $this->pCommaSeparated($node->declares) . ') {'
. "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_DeclareDeclare(PHPParser_Node_Stmt_DeclareDeclare $node) {
return $node->key . ' = ' . $this->p($node->value);
}
// Control flow
public function pStmt_If(PHPParser_Node_Stmt_If $node) {
return 'if (' . $this->p($node->cond) . ') {'
. "\n" . $this->pStmts($node->stmts) . "\n" . '}'
. $this->pImplode($node->elseifs)
. (null !== $node->else ? $this->p($node->else) : '');
}
public function pStmt_Elseif(PHPParser_Node_Stmt_Elseif $node) {
return ' elseif (' . $this->p($node->cond) . ') {'
. "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Else(PHPParser_Node_Stmt_Else $node) {
return ' else {' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_For(PHPParser_Node_Stmt_For $node) {
return 'for ('
. $this->pCommaSeparated($node->init) . ';' . (!empty($node->cond) ? ' ' : '')
. $this->pCommaSeparated($node->cond) . ';' . (!empty($node->loop) ? ' ' : '')
. $this->pCommaSeparated($node->loop)
. ') {' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Foreach(PHPParser_Node_Stmt_Foreach $node) {
return 'foreach (' . $this->p($node->expr) . ' as '
. (null !== $node->keyVar ? $this->p($node->keyVar) . ' => ' : '')
. ($node->byRef ? '&' : '') . $this->p($node->valueVar) . ') {'
. "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_While(PHPParser_Node_Stmt_While $node) {
return 'while (' . $this->p($node->cond) . ') {'
. "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Do(PHPParser_Node_Stmt_Do $node) {
return 'do {' . "\n" . $this->pStmts($node->stmts) . "\n"
. '} while (' . $this->p($node->cond) . ');';
}
public function pStmt_Switch(PHPParser_Node_Stmt_Switch $node) {
return 'switch (' . $this->p($node->cond) . ') {'
. "\n" . $this->pImplode($node->cases) . '}';
}
public function pStmt_TryCatch(PHPParser_Node_Stmt_TryCatch $node) {
return 'try {' . "\n" . $this->pStmts($node->stmts) . "\n" . '}'
. $this->pImplode($node->catches);
}
public function pStmt_Catch(PHPParser_Node_Stmt_Catch $node) {
return ' catch (' . $this->p($node->type) . ' $' . $node->var . ') {'
. "\n" . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Case(PHPParser_Node_Stmt_Case $node) {
return (null !== $node->cond ? 'case ' . $this->p($node->cond) : 'default') . ':'
. "\n" . $this->pStmts($node->stmts) . "\n";
}
public function pStmt_Break(PHPParser_Node_Stmt_Break $node) {
return 'break' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';';
}
public function pStmt_Continue(PHPParser_Node_Stmt_Continue $node) {
return 'continue' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';';
}
public function pStmt_Return(PHPParser_Node_Stmt_Return $node) {
return 'return' . (null !== $node->expr ? ' ' . $this->p($node->expr) : '') . ';';
}
public function pStmt_Throw(PHPParser_Node_Stmt_Throw $node) {
return 'throw ' . $this->p($node->expr) . ';';
}
public function pStmt_Label(PHPParser_Node_Stmt_Label $node) {
return $node->name . ':';
}
public function pStmt_Goto(PHPParser_Node_Stmt_Goto $node) {
return 'goto ' . $node->name . ';';
}
// Other
public function pStmt_Echo(PHPParser_Node_Stmt_Echo $node) {
return 'echo ' . $this->pCommaSeparated($node->exprs) . ';';
}
public function pStmt_Static(PHPParser_Node_Stmt_Static $node) {
return 'static ' . $this->pCommaSeparated($node->vars) . ';';
}
public function pStmt_Global(PHPParser_Node_Stmt_Global $node) {
return 'global ' . $this->pCommaSeparated($node->vars) . ';';
}
public function pStmt_StaticVar(PHPParser_Node_Stmt_StaticVar $node) {
return '$' . $node->name
. (null !== $node->default ? ' = ' . $this->p($node->default) : '');
}
public function pStmt_Unset(PHPParser_Node_Stmt_Unset $node) {
return 'unset(' . $this->pCommaSeparated($node->vars) . ');';
}
public function pStmt_InlineHTML(PHPParser_Node_Stmt_InlineHTML $node) {
return '?>' . $this->pSafe(
("\n" === $node->value[0] || "\r" === $node->value[0] ? "\n" : '')
. $node->value
) . '<?php ';
}
public function pStmt_HaltCompiler(PHPParser_Node_Stmt_HaltCompiler $node) {
return '__halt_compiler();' . $node->remaining;
}
// Helpers
public function pObjectProperty($node) {
if ($node instanceof PHPParser_Node_Expr) {
return '{' . $this->p($node) . '}';
} else {
return $node;
}
}
public function pModifiers($modifiers) {
return ($modifiers & PHPParser_Node_Stmt_Class::MODIFIER_PUBLIC ? 'public ' : '')
. ($modifiers & PHPParser_Node_Stmt_Class::MODIFIER_PROTECTED ? 'protected ' : '')
. ($modifiers & PHPParser_Node_Stmt_Class::MODIFIER_PRIVATE ? 'private ' : '')
. ($modifiers & PHPParser_Node_Stmt_Class::MODIFIER_STATIC ? 'static ' : '')
. ($modifiers & PHPParser_Node_Stmt_Class::MODIFIER_ABSTRACT ? 'abstract ' : '')
. ($modifiers & PHPParser_Node_Stmt_Class::MODIFIER_FINAL ? 'final ' : '');
}
public function pEncapsList(array $encapsList, $quote) {
$return = '';
foreach ($encapsList as $element) {
if (is_string($element)) {
$return .= addcslashes($element, "\n\r\t\f\v$" . $quote . "\\");
} else {
$return .= '{' . $this->p($element) . '}';
}
}
return $return;
}
public function pAssignList(array $elements) {
$pAssignList = array();
foreach ($elements as $element) {
if (null === $element) {
$pAssignList[] = '';
} elseif (is_array($element)) {
$pAssignList[] = $this->pAssignList($element);
} else {
$pAssignList[] = $this->p($element);
}
}
return 'list(' . implode(', ', $pAssignList) . ')';
}
public function pVarOrNewExpr(PHPParser_Node $node) {
if ($node instanceof PHPParser_Node_Expr_New) {
return '(' . $this->p($node) . ')';
} else {
return $this->p($node);
}
}
}

View File

@ -3,81 +3,84 @@
abstract class PHPParser_PrettyPrinterAbstract
{
protected $precedenceMap = array(
'Expr_BitwiseNot' => 1,
'Expr_PreInc' => 1,
'Expr_PreDec' => 1,
'Expr_PostInc' => 1,
'Expr_PostDec' => 1,
'Expr_UnaryPlus' => 1,
'Expr_UnaryMinus' => 1,
'Expr_Cast_Int' => 1,
'Expr_Cast_Double' => 1,
'Expr_Cast_String' => 1,
'Expr_Cast_Array' => 1,
'Expr_Cast_Object' => 1,
'Expr_Cast_Bool' => 1,
'Expr_Cast_Unset' => 1,
'Expr_ErrorSuppress' => 1,
'Expr_Instanceof' => 2,
'Expr_BooleanNot' => 3,
'Expr_Mul' => 4,
'Expr_Div' => 4,
'Expr_Mod' => 4,
'Expr_Plus' => 5,
'Expr_Minus' => 5,
'Expr_Concat' => 5,
'Expr_ShiftLeft' => 6,
'Expr_ShiftRight' => 6,
'Expr_Smaller' => 7,
'Expr_SmallerOrEqual' => 7,
'Expr_Greater' => 7,
'Expr_GreaterOrEqual' => 7,
'Expr_Equal' => 8,
'Expr_NotEqual' => 8,
'Expr_Identical' => 8,
'Expr_NotIdentical' => 8,
'Expr_BitwiseAnd' => 9,
'Expr_BitwiseXor' => 10,
'Expr_BitwiseOr' => 11,
'Expr_BooleanAnd' => 12,
'Expr_BooleanOr' => 13,
'Expr_Ternary' => 14,
'Expr_Assign' => 15,
'Expr_AssignPlus' => 15,
'Expr_AssignMinus' => 15,
'Expr_AssignMul' => 15,
'Expr_AssignDiv' => 15,
'Expr_AssignConcat' => 15,
'Expr_AssignMod' => 15,
'Expr_AssignBitwiseAnd' => 15,
'Expr_AssignBitwiseOr' => 15,
'Expr_AssignBitwiseXor' => 15,
'Expr_AssignShiftLeft' => 15,
'Expr_AssignShiftRight' => 15,
'Expr_AssignList' => 15,
'Expr_LogicalAnd' => 16,
'Expr_LogicalXor' => 17,
'Expr_LogicalOr' => 18,
// [precedence, associativity] where for the latter -1 is %left, 0 is %nonassoc and 1 is %right
'Expr_BitwiseNot' => array( 1, 1),
'Expr_PreInc' => array( 1, 1),
'Expr_PreDec' => array( 1, 1),
'Expr_PostInc' => array( 1, -1),
'Expr_PostDec' => array( 1, -1),
'Expr_UnaryPlus' => array( 1, 1),
'Expr_UnaryMinus' => array( 1, 1),
'Expr_Cast_Int' => array( 1, 1),
'Expr_Cast_Double' => array( 1, 1),
'Expr_Cast_String' => array( 1, 1),
'Expr_Cast_Array' => array( 1, 1),
'Expr_Cast_Object' => array( 1, 1),
'Expr_Cast_Bool' => array( 1, 1),
'Expr_Cast_Unset' => array( 1, 1),
'Expr_ErrorSuppress' => array( 1, 1),
'Expr_Instanceof' => array( 2, 0),
'Expr_BooleanNot' => array( 3, 1),
'Expr_Mul' => array( 4, -1),
'Expr_Div' => array( 4, -1),
'Expr_Mod' => array( 4, -1),
'Expr_Plus' => array( 5, -1),
'Expr_Minus' => array( 5, -1),
'Expr_Concat' => array( 5, -1),
'Expr_ShiftLeft' => array( 6, -1),
'Expr_ShiftRight' => array( 6, -1),
'Expr_Smaller' => array( 7, 0),
'Expr_SmallerOrEqual' => array( 7, 0),
'Expr_Greater' => array( 7, 0),
'Expr_GreaterOrEqual' => array( 7, 0),
'Expr_Equal' => array( 8, 0),
'Expr_NotEqual' => array( 8, 0),
'Expr_Identical' => array( 8, 0),
'Expr_NotIdentical' => array( 8, 0),
'Expr_BitwiseAnd' => array( 9, -1),
'Expr_BitwiseXor' => array(10, -1),
'Expr_BitwiseOr' => array(11, -1),
'Expr_BooleanAnd' => array(12, -1),
'Expr_BooleanOr' => array(13, -1),
'Expr_Ternary' => array(14, -1),
// parser uses %left for assignments, but they really behave as %right
'Expr_Assign' => array(15, 1),
'Expr_AssignRef' => array(15, 1),
'Expr_AssignPlus' => array(15, 1),
'Expr_AssignMinus' => array(15, 1),
'Expr_AssignMul' => array(15, 1),
'Expr_AssignDiv' => array(15, 1),
'Expr_AssignConcat' => array(15, 1),
'Expr_AssignMod' => array(15, 1),
'Expr_AssignBitwiseAnd' => array(15, 1),
'Expr_AssignBitwiseOr' => array(15, 1),
'Expr_AssignBitwiseXor' => array(15, 1),
'Expr_AssignShiftLeft' => array(15, 1),
'Expr_AssignShiftRight' => array(15, 1),
'Expr_LogicalAnd' => array(16, -1),
'Expr_LogicalXor' => array(17, -1),
'Expr_LogicalOr' => array(18, -1),
'Expr_Include' => array(19, -1),
);
protected $precedenceStack;
protected $precedenceStackPos;
protected $noIndentToken;
protected $canUseSemicolonNamespaces;
public function __construct() {
$this->precedenceStack = array($this->precedenceStackPos = 0 => 19);
$this->noIndentToken = uniqid('_NO_INDENT_');
$this->noIndentToken = '_NO_INDENT_' . mt_rand();
}
/**
* Pretty prints an array of nodes (statements).
* Pretty prints an array of statements.
*
* @param PHPParser_Node[] $nodes Array of nodes
* @param PHPParser_Node[] $stmts Array of statements
*
* @return string Pretty printed nodes
* @return string Pretty printed statements
*/
public function prettyPrint(array $nodes) {
return str_replace("\n" . $this->noIndentToken, "\n", $this->pStmts($nodes, false));
public function prettyPrint(array $stmts) {
$this->preprocessNodes($stmts);
return str_replace("\n" . $this->noIndentToken, "\n", $this->pStmts($stmts, false));
}
/**
@ -91,6 +94,41 @@ abstract class PHPParser_PrettyPrinterAbstract
return str_replace("\n" . $this->noIndentToken, "\n", $this->p($node));
}
/**
* Pretty prints a file of statements (includes the opening <?php tag if it is required).
*
* @param PHPParser_Node[] $stmts Array of statements
*
* @return string Pretty printed statements
*/
public function prettyPrintFile(array $stmts) {
$p = trim($this->prettyPrint($stmts));
$p = preg_replace('/^\?>\n?/', '', $p, -1, $count);
$p = preg_replace('/<\?php$/', '', $p);
if (!$count) {
$p = "<?php\n\n" . $p;
}
return $p;
}
/**
* Preprocesses the top-level nodes to initialize pretty printer state.
*
* @param PHPParser_Node[] $nodes Array of nodes
*/
protected function preprocessNodes(array $nodes) {
/* We can use semicolon-namespaces unless there is a global namespace declaration */
$this->canUseSemicolonNamespaces = true;
foreach ($nodes as $node) {
if ($node instanceof PHPParser_Node_Stmt_Namespace && null === $node->name) {
$this->canUseSemicolonNamespaces = false;
}
}
}
/**
* Pretty prints an array of nodes (statements) and indents them optionally.
*
@ -126,26 +164,52 @@ abstract class PHPParser_PrettyPrinterAbstract
* @return string Pretty printed node
*/
protected function p(PHPParser_Node $node) {
return $this->{'p' . $node->getType()}($node);
}
protected function pInfixOp($type, PHPParser_Node $leftNode, $operatorString, PHPParser_Node $rightNode) {
list($precedence, $associativity) = $this->precedenceMap[$type];
return $this->pPrec($leftNode, $precedence, $associativity, -1)
. $operatorString
. $this->pPrec($rightNode, $precedence, $associativity, 1);
}
protected function pPrefixOp($type, $operatorString, PHPParser_Node $node) {
list($precedence, $associativity) = $this->precedenceMap[$type];
return $operatorString . $this->pPrec($node, $precedence, $associativity, 1);
}
protected function pPostfixOp($type, PHPParser_Node $node, $operatorString) {
list($precedence, $associativity) = $this->precedenceMap[$type];
return $this->pPrec($node, $precedence, $associativity, -1) . $operatorString;
}
/**
* Prints an expression node with the least amount of parentheses necessary to preserve the meaning.
*
* @param PHPParser_Node $node Node to pretty print
* @param int $parentPrecedence Precedence of the parent operator
* @param int $parentAssociativity Associativity of parent operator
* (-1 is left, 0 is nonassoc, 1 is right)
* @param int $childPosition Position of the node relative to the operator
* (-1 is left, 1 is right)
*
* @return string The pretty printed node
*/
protected function pPrec(PHPParser_Node $node, $parentPrecedence, $parentAssociativity, $childPosition) {
$type = $node->getType();
if (isset($this->precedenceMap[$type])) {
$precedence = $this->precedenceMap[$type];
if ($precedence >= $this->precedenceStack[$this->precedenceStackPos]) {
$this->precedenceStack[++$this->precedenceStackPos] = $precedence;
$return = '(' . $this->{'p' . $type}($node) . ')';
--$this->precedenceStackPos;
} else {
$this->precedenceStack[++$this->precedenceStackPos] = $precedence;
$return = $this->{'p' . $type}($node);
--$this->precedenceStackPos;
$childPrecedence = $this->precedenceMap[$type][0];
if ($childPrecedence > $parentPrecedence
|| ($parentPrecedence == $childPrecedence && $parentAssociativity != $childPosition)
) {
return '(' . $this->{'p' . $type}($node) . ')';
}
}
return $return;
} else {
return $this->{'p' . $type}($node);
}
}
/**
* Pretty prints an array of nodes and implodes the printed values.
@ -176,13 +240,13 @@ abstract class PHPParser_PrettyPrinterAbstract
}
/**
* Signifies the pretty printer that a string shall not be indented.
* Signals the pretty printer that a string shall not be indented.
*
* @param string $string Not to be indented string
*
* @return mixed String marked with $this->noIndentToken's.
*/
protected function pSafe($string) {
protected function pNoIndent($string) {
return str_replace("\n", "\n" . $this->noIndentToken, $string);
}

View File

@ -4,7 +4,7 @@ require dirname(__FILE__) . '/PHPParser/Autoloader.php';
PHPParser_Autoloader::register();
/*
* lcfirst() was added in PHP 5.3, so we have to emulate it for PHP 5.3.
* lcfirst() was added in PHP 5.3, so we have to emulate it for PHP 5.2.
*/
if (!function_exists('lcfirst')) {
function lcfirst($string) {

View File

@ -0,0 +1,91 @@
<?php
/**
* This class unit-tests the interface builder
*/
class PHPParser_Tests_Builder_InterfaceTest extends PHPUnit_Framework_TestCase
{
/** @var PHPParser_Builder_Interface */
protected $builder;
protected function setUp() {
$this->builder = new PHPParser_Builder_Interface('Contract');
}
private function dump($node) {
$pp = new PHPParser_PrettyPrinter_Default();
return $pp->prettyPrint(array($node));
}
public function testEmpty() {
$contract = $this->builder->getNode();
$this->assertInstanceOf('PHPParser_Node_Stmt_Interface', $contract);
$this->assertEquals('Contract', $contract->name);
}
public function testExtending() {
$contract = $this->builder->extend('Space\Root1', 'Root2')->getNode();
$this->assertEquals(
new PHPParser_Node_Stmt_Interface('Contract', array(
'extends' => array(
new PHPParser_Node_Name('Space\Root1'),
new PHPParser_Node_Name('Root2')
),
)), $contract
);
}
public function testAddMethod() {
$method = new PHPParser_Node_Stmt_ClassMethod('doSomething');
$contract = $this->builder->addStmt($method)->getNode();
$this->assertEquals(array($method), $contract->stmts);
}
public function testAddConst() {
$const = new PHPParser_Node_Stmt_ClassConst(array(
new PHPParser_Node_Const('SPEED_OF_LIGHT', new PHPParser_Node_Scalar_DNumber(299792458))
));
$contract = $this->builder->addStmt($const)->getNode();
$this->assertEquals(299792458, $contract->stmts[0]->consts[0]->value->value);
}
public function testOrder() {
$const = new PHPParser_Node_Stmt_ClassConst(array(
new PHPParser_Node_Const('SPEED_OF_LIGHT', new PHPParser_Node_Scalar_DNumber(299792458))
));
$method = new PHPParser_Node_Stmt_ClassMethod('doSomething');
$contract = $this->builder
->addStmt($method)
->addStmt($const)
->getNode()
;
$this->assertInstanceOf('PHPParser_Node_Stmt_ClassConst', $contract->stmts[0]);
$this->assertInstanceOf('PHPParser_Node_Stmt_ClassMethod', $contract->stmts[1]);
}
/**
* @expectedException LogicException
* @expectedExceptionMessage Unexpected node of type "Stmt_PropertyProperty"
*/
public function testInvalidStmtError() {
$this->builder->addStmt(new PHPParser_Node_Stmt_PropertyProperty('invalid'));
}
public function testFullFunctional() {
$const = new PHPParser_Node_Stmt_ClassConst(array(
new PHPParser_Node_Const('SPEED_OF_LIGHT', new PHPParser_Node_Scalar_DNumber(299792458))
));
$method = new PHPParser_Node_Stmt_ClassMethod('doSomething');
$contract = $this->builder
->addStmt($method)
->addStmt($const)
->getNode()
;
eval($this->dump($contract));
$this->assertTrue(interface_exists('Contract', false));
}
}

View File

@ -2,28 +2,22 @@
class PHPParser_Tests_BuilderFactoryTest extends PHPUnit_Framework_TestCase
{
public function testCreateClassBuilder() {
/**
* @dataProvider provideTestFactory
*/
public function testFactory($methodName, $className) {
$factory = new PHPParser_BuilderFactory;
$this->assertInstanceOf('PHPParser_Builder_Class', $factory->class('Test'));
$this->assertInstanceOf($className, $factory->$methodName('test'));
}
public function testCreateMethodBuilder() {
$factory = new PHPParser_BuilderFactory;
$this->assertInstanceOf('PHPParser_Builder_Method', $factory->method('test'));
}
public function testCreateParamBuilder() {
$factory = new PHPParser_BuilderFactory;
$this->assertInstanceOf('PHPParser_Builder_Param', $factory->param('test'));
}
public function testCreatePropertyBuilder() {
$factory = new PHPParser_BuilderFactory;
$this->assertInstanceOf('PHPParser_Builder_Property', $factory->property('test'));
}
public function testCreateFunctionBuilder() {
$factory = new PHPParser_BuilderFactory;
$this->assertInstanceOf('PHPParser_Builder_Function', $factory->function('test'));
public function provideTestFactory() {
return array(
array('class', 'PHPParser_Builder_Class'),
array('interface', 'PHPParser_Builder_Interface'),
array('method', 'PHPParser_Builder_Method'),
array('function', 'PHPParser_Builder_Function'),
array('property', 'PHPParser_Builder_Property'),
array('param', 'PHPParser_Builder_Param'),
);
}
}

View File

@ -32,10 +32,17 @@ class PHPParser_Tests_Lexer_EmulativeTest extends PHPUnit_Framework_TestCase
public function provideTestReplaceKeywords() {
return array(
// PHP 5.5
array('finally', PHPParser_Parser::T_FINALLY),
array('yield', PHPParser_Parser::T_YIELD),
// PHP 5.4
array('callable', PHPParser_Parser::T_CALLABLE),
array('insteadof', PHPParser_Parser::T_INSTEADOF),
array('trait', PHPParser_Parser::T_TRAIT),
array('__TRAIT__', PHPParser_Parser::T_TRAIT_C),
// PHP 5.3
array('__DIR__', PHPParser_Parser::T_DIR),
array('goto', PHPParser_Parser::T_GOTO),
array('namespace', PHPParser_Parser::T_NAMESPACE),

View File

@ -13,12 +13,12 @@ class PHPParser_Tests_Node_Scalar_StringTest extends PHPUnit_Framework_TestCase
}
/**
* @dataProvider provideTestCreate
* @dataProvider provideTestParse
*/
public function testCreate($expected, $string) {
$this->assertEquals(
$expected,
PHPParser_Node_Scalar_String::create($string)->value
PHPParser_Node_Scalar_String::parse($string)
);
}
@ -37,7 +37,7 @@ class PHPParser_Tests_Node_Scalar_StringTest extends PHPUnit_Framework_TestCase
);
}
public function provideTestCreate() {
public function provideTestParse() {
$tests = array(
array('A', '\'A\''),
array('A', 'b\'A\''),

View File

@ -74,7 +74,7 @@ namespace {
EOC;
$parser = new PHPParser_Parser(new PHPParser_Lexer_Emulative);
$prettyPrinter = new PHPParser_PrettyPrinter_Zend;
$prettyPrinter = new PHPParser_PrettyPrinter_Default;
$traverser = new PHPParser_NodeTraverser;
$traverser->addVisitor(new PHPParser_NodeVisitor_NameResolver);
@ -90,58 +90,58 @@ EOC;
public function testResolveLocations() {
$code = <<<EOC
<?php
namespace NS {
class A extends B implements C {
namespace NS;
class A extends B implements C {
use A;
}
}
interface A extends C {
interface A extends C {
public function a(A \$a);
}
}
A::b();
A::\$b;
A::B;
new A;
\$a instanceof A;
A::b();
A::\$b;
A::B;
new A;
\$a instanceof A;
namespace\a();
namespace\A;
namespace\a();
namespace\A;
try {
try {
\$someThing;
} catch (A \$a) {
} catch (A \$a) {
\$someThingElse;
}
}
EOC;
$expectedCode = <<<EOC
namespace NS {
class A extends \\NS\\B implements \\NS\\C
{
namespace NS;
class A extends \\NS\\B implements \\NS\\C
{
use \\NS\\A;
}
interface A extends \\NS\\C
{
}
interface A extends \\NS\\C
{
public function a(\\NS\\A \$a);
}
\\NS\\A::b();
\\NS\\A::\$b;
\\NS\\A::B;
new \\NS\\A();
\$a instanceof \\NS\\A;
\\NS\\a();
\\NS\\A;
try {
}
\\NS\\A::b();
\\NS\\A::\$b;
\\NS\\A::B;
new \\NS\\A();
\$a instanceof \\NS\\A;
\\NS\\a();
\\NS\\A;
try {
\$someThing;
} catch (\\NS\\A \$a) {
} catch (\\NS\\A \$a) {
\$someThingElse;
}
}
EOC;
$parser = new PHPParser_Parser(new PHPParser_Lexer_Emulative);
$prettyPrinter = new PHPParser_PrettyPrinter_Zend;
$prettyPrinter = new PHPParser_PrettyPrinter_Default;
$traverser = new PHPParser_NodeTraverser;
$traverser->addVisitor(new PHPParser_NodeVisitor_NameResolver);

View File

@ -4,23 +4,39 @@ require_once dirname(__FILE__) . '/CodeTestAbstract.php';
class PHPParser_Tests_PrettyPrinterTest extends PHPParser_Tests_CodeTestAbstract
{
/**
* @dataProvider provideTestPrettyPrint
* @covers PHPParser_PrettyPrinter_Zend<extended>
*/
public function testPrettyPrint($name, $code, $dump) {
protected function doTestPrettyPrintMethod($method, $name, $code, $dump) {
$parser = new PHPParser_Parser(new PHPParser_Lexer_Emulative);
$prettyPrinter = new PHPParser_PrettyPrinter_Zend;
$prettyPrinter = new PHPParser_PrettyPrinter_Default;
$stmts = $parser->parse($code);
$this->assertEquals(
$this->canonicalize($dump),
$this->canonicalize($prettyPrinter->prettyPrint($stmts)),
$this->canonicalize($prettyPrinter->$method($stmts)),
$name
);
}
/**
* @dataProvider provideTestPrettyPrint
* @covers PHPParser_PrettyPrinter_Default<extended>
*/
public function testPrettyPrint($name, $code, $dump) {
$this->doTestPrettyPrintMethod('prettyPrint', $name, $code, $dump);
}
/**
* @dataProvider provideTestPrettyPrintFile
* @covers PHPParser_PrettyPrinter_Default<extended>
*/
public function testPrettyPrintFile($name, $code, $dump) {
$this->doTestPrettyPrintMethod('prettyPrintFile', $name, $code, $dump);
}
public function provideTestPrettyPrint() {
return $this->getTests(dirname(__FILE__) . '/../../code/prettyPrinter', 'test');
}
public function provideTestPrettyPrintFile() {
return $this->getTests(dirname(__FILE__) . '/../../code/prettyPrinter', 'file-test');
}
}

View File

@ -8,7 +8,7 @@ class PHPParser_Tests_TemplateTest extends PHPUnit_Framework_TestCase
*/
public function testPlaceholderReplacement($templateCode, $placeholders, $expectedPrettyPrint) {
$parser = new PHPParser_Parser(new PHPParser_Lexer);
$prettyPrinter = new PHPParser_PrettyPrinter_Zend;
$prettyPrinter = new PHPParser_PrettyPrinter_Default;
$template = new PHPParser_Template($parser, $templateCode);
$this->assertEquals(

View File

@ -137,7 +137,7 @@ array(
name: b
)
)
13: Expr_Assign(
13: Expr_AssignRef(
var: Expr_Variable(
name: a
)
@ -151,17 +151,20 @@ array(
)
)
)
14: Expr_AssignList(
14: Expr_Assign(
var: Expr_List(
vars: array(
0: Expr_Variable(
name: a
)
)
)
expr: Expr_Variable(
name: b
)
)
15: Expr_AssignList(
15: Expr_Assign(
var: Expr_List(
vars: array(
0: Expr_Variable(
name: a
@ -171,25 +174,30 @@ array(
name: b
)
)
)
expr: Expr_Variable(
name: c
)
)
16: Expr_AssignList(
16: Expr_Assign(
var: Expr_List(
vars: array(
0: Expr_Variable(
name: a
)
1: array(
1: Expr_List(
vars: array(
0: null
1: Expr_Variable(
name: c
)
)
)
2: Expr_Variable(
name: d
)
)
)
expr: Expr_Variable(
name: e
)

View File

@ -4,6 +4,7 @@ Constant fetches
A;
A::B;
A::class;
-----
array(
0: Expr_ConstFetch(
@ -21,4 +22,12 @@ array(
)
name: B
)
2: Expr_ClassConstFetch(
class: Name(
parts: array(
0: A
)
)
name: class
)
)

View File

@ -0,0 +1,181 @@
Array/string dereferencing
-----
<?php
"abc"[2];
"abc"[2][0][0];
[1, 2, 3][2];
[1, 2, 3][2][0][0];
array(1, 2, 3)[2];
array(1, 2, 3)[2][0][0];
-----
array(
0: Expr_ArrayDimFetch(
var: Scalar_String(
value: abc
)
dim: Scalar_LNumber(
value: 2
)
)
1: Expr_ArrayDimFetch(
var: Expr_ArrayDimFetch(
var: Expr_ArrayDimFetch(
var: Scalar_String(
value: abc
)
dim: Scalar_LNumber(
value: 2
)
)
dim: Scalar_LNumber(
value: 0
)
)
dim: Scalar_LNumber(
value: 0
)
)
2: Expr_ArrayDimFetch(
var: Expr_Array(
items: array(
0: Expr_ArrayItem(
key: null
value: Scalar_LNumber(
value: 1
)
byRef: false
)
1: Expr_ArrayItem(
key: null
value: Scalar_LNumber(
value: 2
)
byRef: false
)
2: Expr_ArrayItem(
key: null
value: Scalar_LNumber(
value: 3
)
byRef: false
)
)
)
dim: Scalar_LNumber(
value: 2
)
)
3: Expr_ArrayDimFetch(
var: Expr_ArrayDimFetch(
var: Expr_ArrayDimFetch(
var: Expr_Array(
items: array(
0: Expr_ArrayItem(
key: null
value: Scalar_LNumber(
value: 1
)
byRef: false
)
1: Expr_ArrayItem(
key: null
value: Scalar_LNumber(
value: 2
)
byRef: false
)
2: Expr_ArrayItem(
key: null
value: Scalar_LNumber(
value: 3
)
byRef: false
)
)
)
dim: Scalar_LNumber(
value: 2
)
)
dim: Scalar_LNumber(
value: 0
)
)
dim: Scalar_LNumber(
value: 0
)
)
4: Expr_ArrayDimFetch(
var: Expr_Array(
items: array(
0: Expr_ArrayItem(
key: null
value: Scalar_LNumber(
value: 1
)
byRef: false
)
1: Expr_ArrayItem(
key: null
value: Scalar_LNumber(
value: 2
)
byRef: false
)
2: Expr_ArrayItem(
key: null
value: Scalar_LNumber(
value: 3
)
byRef: false
)
)
)
dim: Scalar_LNumber(
value: 2
)
)
5: Expr_ArrayDimFetch(
var: Expr_ArrayDimFetch(
var: Expr_ArrayDimFetch(
var: Expr_Array(
items: array(
0: Expr_ArrayItem(
key: null
value: Scalar_LNumber(
value: 1
)
byRef: false
)
1: Expr_ArrayItem(
key: null
value: Scalar_LNumber(
value: 2
)
byRef: false
)
2: Expr_ArrayItem(
key: null
value: Scalar_LNumber(
value: 3
)
byRef: false
)
)
)
dim: Scalar_LNumber(
value: 2
)
)
dim: Scalar_LNumber(
value: 0
)
)
dim: Scalar_LNumber(
value: 0
)
)
)

View File

@ -5,6 +5,8 @@ isset($a);
isset($a, $b, $c);
empty($a);
empty(foo());
empty(array(1, 2, 3));
-----
array(
0: Expr_Isset(
@ -28,8 +30,46 @@ array(
)
)
2: Expr_Empty(
var: Expr_Variable(
expr: Expr_Variable(
name: a
)
)
3: Expr_Empty(
expr: Expr_FuncCall(
name: Name(
parts: array(
0: foo
)
)
args: array(
)
)
)
4: Expr_Empty(
expr: Expr_Array(
items: array(
0: Expr_ArrayItem(
key: null
value: Scalar_LNumber(
value: 1
)
byRef: false
)
1: Expr_ArrayItem(
key: null
value: Scalar_LNumber(
value: 2
)
byRef: false
)
2: Expr_ArrayItem(
key: null
value: Scalar_LNumber(
value: 3
)
byRef: false
)
)
)
)
)

View File

@ -15,7 +15,7 @@ new $a->b->c();
new $a->b['c']();
new $a->b{'c'}();
// test regression introduces by new dereferencing syntext
// test regression introduces by new dereferencing syntax
(new A);
-----
array(

View File

@ -26,4 +26,4 @@ Cannot use the final and abstract modifier at the same time on line 1
-----
<?php abstract final class A { }
-----
Unexpected token T_FINAL on line 1
Syntax error, unexpected T_FINAL, expecting T_CLASS on line 1

View File

@ -10,7 +10,7 @@ Cannot use "parent" as class name as it is reserved on line 1
-----
<?php class static {}
-----
Unexpected token T_STATIC on line 1
Syntax error, unexpected T_STATIC, expecting T_STRING on line 1
-----
<?php class A extends self {}
-----
@ -22,7 +22,7 @@ Cannot use "parent" as class name as it is reserved on line 1
-----
<?php class A extends static {}
-----
Unexpected token T_STATIC on line 1
Syntax error, unexpected T_STATIC, expecting T_STRING or T_NAMESPACE or T_NS_SEPARATOR on line 1
-----
<?php class A implements self {}
-----
@ -34,7 +34,7 @@ Cannot use "parent" as interface name as it is reserved on line 1
-----
<?php class A implements static {}
-----
Unexpected token T_STATIC on line 1
Syntax error, unexpected T_STATIC, expecting T_STRING or T_NAMESPACE or T_NS_SEPARATOR on line 1
-----
<?php interface self {}
-----
@ -46,7 +46,7 @@ Cannot use "parent" as interface name as it is reserved on line 1
-----
<?php interface static {}
-----
Unexpected token T_STATIC on line 1
Syntax error, unexpected T_STATIC, expecting T_STRING on line 1
-----
<?php interface A extends self {}
-----
@ -58,4 +58,4 @@ Cannot use "parent" as interface name as it is reserved on line 1
-----
<?php interface A extends static {}
-----
Unexpected token T_STATIC on line 1
Syntax error, unexpected T_STATIC, expecting T_STRING or T_NAMESPACE or T_NS_SEPARATOR on line 1

View File

@ -0,0 +1,227 @@
Generators (yield expression
-----
<?php
function gen() {
// statements
yield;
yield $value;
yield $key => $value;
// expressions
$data = yield;
$data = (yield $value);
$data = (yield $key => $value);
// yield in language constructs with their own parentheses
if (yield $foo); elseif (yield $foo);
if (yield $foo): elseif (yield $foo): endif;
while (yield $foo);
do {} while (yield $foo);
switch (yield $foo) {}
die(yield $foo);
// yield in function calls
func(yield $foo);
$foo->func(yield $foo);
new Foo(yield $foo);
}
-----
array(
0: Stmt_Function(
byRef: false
params: array(
)
stmts: array(
0: Expr_Yield(
key: null
value: null
)
1: Expr_Yield(
key: null
value: Expr_Variable(
name: value
)
)
2: Expr_Yield(
key: Expr_Variable(
name: key
)
value: Expr_Variable(
name: value
)
)
3: Expr_Assign(
var: Expr_Variable(
name: data
)
expr: Expr_Yield(
key: null
value: null
)
)
4: Expr_Assign(
var: Expr_Variable(
name: data
)
expr: Expr_Yield(
key: null
value: Expr_Variable(
name: value
)
)
)
5: Expr_Assign(
var: Expr_Variable(
name: data
)
expr: Expr_Yield(
key: Expr_Variable(
name: key
)
value: Expr_Variable(
name: value
)
)
)
6: Stmt_If(
stmts: array(
)
elseifs: array(
0: Stmt_ElseIf(
cond: Expr_Yield(
key: null
value: Expr_Variable(
name: foo
)
)
stmts: array(
)
)
)
else: null
cond: Expr_Yield(
key: null
value: Expr_Variable(
name: foo
)
)
)
7: Stmt_If(
stmts: array(
)
elseifs: array(
0: Stmt_ElseIf(
cond: Expr_Yield(
key: null
value: Expr_Variable(
name: foo
)
)
stmts: array(
)
)
)
else: null
cond: Expr_Yield(
key: null
value: Expr_Variable(
name: foo
)
)
)
8: Stmt_While(
cond: Expr_Yield(
key: null
value: Expr_Variable(
name: foo
)
)
stmts: array(
)
)
9: Stmt_Do(
cond: Expr_Yield(
key: null
value: Expr_Variable(
name: foo
)
)
stmts: array(
)
)
10: Stmt_Switch(
cond: Expr_Yield(
key: null
value: Expr_Variable(
name: foo
)
)
cases: array(
)
)
11: Expr_Exit(
expr: Expr_Yield(
key: null
value: Expr_Variable(
name: foo
)
)
)
12: Expr_FuncCall(
name: Name(
parts: array(
0: func
)
)
args: array(
0: Arg(
value: Expr_Yield(
key: null
value: Expr_Variable(
name: foo
)
)
byRef: false
)
)
)
13: Expr_MethodCall(
var: Expr_Variable(
name: foo
)
name: func
args: array(
0: Arg(
value: Expr_Yield(
key: null
value: Expr_Variable(
name: foo
)
)
byRef: false
)
)
)
14: Expr_New(
class: Name(
parts: array(
0: Foo
)
)
args: array(
0: Arg(
value: Expr_Yield(
key: null
value: Expr_Variable(
name: foo
)
)
byRef: false
)
)
)
)
name: gen
)
)

View File

@ -7,6 +7,8 @@ foreach ($a as $b) {}
foreach ($a as &$b) {}
foreach ($a as $b => $c) {}
foreach ($a as $b => &$c) {}
foreach ($a as list($a, $b)) {}
foreach ($a as $a => list($b, , $c)) {}
// foreach on expression
foreach (array() as $b) {}
@ -69,6 +71,47 @@ array(
)
)
4: Stmt_Foreach(
keyVar: null
byRef: false
stmts: array(
)
expr: Expr_Variable(
name: a
)
valueVar: Expr_List(
vars: array(
0: Expr_Variable(
name: a
)
1: Expr_Variable(
name: b
)
)
)
)
5: Stmt_Foreach(
keyVar: Expr_Variable(
name: a
)
byRef: false
stmts: array(
)
expr: Expr_Variable(
name: a
)
valueVar: Expr_List(
vars: array(
0: Expr_Variable(
name: b
)
1: null
2: Expr_Variable(
name: c
)
)
)
)
6: Stmt_Foreach(
keyVar: null
byRef: false
stmts: array(
@ -81,7 +124,7 @@ array(
name: b
)
)
5: Stmt_Foreach(
7: Stmt_Foreach(
keyVar: null
byRef: false
stmts: array(

View File

@ -10,7 +10,7 @@ Cannot use "parent" as namespace name as it is reserved on line 1
-----
<?php namespace static;
-----
Unexpected token T_STATIC on line 1
Syntax error, unexpected T_STATIC, expecting T_STRING or T_NS_SEPARATOR or '{' on line 1
-----
<?php use A as self;
-----
@ -22,4 +22,4 @@ Cannot use "B" as "parent" because "parent" is a special class name on line 1
-----
<?php use C as static;
-----
Unexpected token T_STATIC on line 1
Syntax error, unexpected T_STATIC, expecting T_STRING on line 1

View File

@ -23,23 +23,23 @@ array(
)
cases: array(
0: Stmt_Case(
stmts: array(
)
cond: Scalar_LNumber(
value: 0
)
)
1: Stmt_Case(
stmts: array(
)
)
1: Stmt_Case(
cond: Scalar_LNumber(
value: 1
)
)
2: Stmt_Case(
stmts: array(
)
)
2: Stmt_Case(
cond: null
stmts: array(
)
)
)
)

View File

@ -1,16 +1,92 @@
Try/catch
-----
<?php
try {
doTry();
} catch (A $b) {
doCatchA();
} catch (B $c) {
doCatchB();
} finally {
doFinally();
}
// no finally
try { }
catch (A $b) { }
// no catch
try { }
finally { }
-----
array(
0: Stmt_TryCatch(
stmts: array(
0: Expr_FuncCall(
name: Name(
parts: array(
0: doTry
)
)
args: array(
)
)
)
catches: array(
0: Stmt_Catch(
type: Name(
parts: array(
0: A
)
)
var: b
stmts: array(
0: Expr_FuncCall(
name: Name(
parts: array(
0: doCatchA
)
)
args: array(
)
)
)
)
1: Stmt_Catch(
type: Name(
parts: array(
0: B
)
)
var: c
stmts: array(
0: Expr_FuncCall(
name: Name(
parts: array(
0: doCatchB
)
)
args: array(
)
)
)
)
)
finallyStmts: array(
0: Expr_FuncCall(
name: Name(
parts: array(
0: doFinally
)
)
args: array(
)
)
)
)
1: Stmt_TryCatch(
stmts: array(
)
catches: array(
@ -24,16 +100,15 @@ array(
stmts: array(
)
)
1: Stmt_Catch(
type: Name(
parts: array(
0: B
)
finallyStmts: null
)
var: c
2: Stmt_TryCatch(
stmts: array(
)
catches: array(
)
finallyStmts: array(
)
)
)

View File

@ -0,0 +1,7 @@
Cannot use try without catch or finally
-----
<?php
try { }
-----
Cannot use try without catch or finally on line 3

View File

@ -0,0 +1,18 @@
Closures
-----
<?php
$closureWithArgs = function ($arg1, $arg2) {
$comment = 'closure body';
};
$closureWithArgsAndVars = function ($arg1, $arg2) use($var1, $var2) {
$comment = 'closure body';
};
-----
$closureWithArgs = function ($arg1, $arg2) {
$comment = 'closure body';
};
$closureWithArgsAndVars = function ($arg1, $arg2) use($var1, $var2) {
$comment = 'closure body';
};

View File

@ -2,7 +2,8 @@ Comments
-----
<?php
namespace JustForIndentation {
function justForIndentation()
{
// Some text
# Some text
/* Some text */
@ -28,7 +29,8 @@ namespace JustForIndentation {
}
-----
namespace JustForIndentation {
function justForIndentation()
{
// Some text
# Some text
/* Some text */

View File

@ -0,0 +1,7 @@
Include
-----
<?php
(include $foo) && (include $bar);
-----
(include $foo) && (include $bar);

View File

@ -0,0 +1,52 @@
File containing both inline HTML and PHP
-----
HTML
<?php
echo 'PHP';
-----
HTML
<?php
echo 'PHP';
-----
<?php
echo 'PHP';
?>
HTML
-----
<?php
echo 'PHP';
?>
HTML
-----
HTML
<?php
echo 'PHP';
?>
HTML
-----
HTML
<?php
echo 'PHP';
?>
HTML
-----
HTML
<?php
echo 'PHP';
?>
HTML
<?php
echo 'PHP';
?>
HTML
-----
HTML
<?php
echo 'PHP';
?>
HTML
<?php
echo 'PHP';
?>
HTML

View File

@ -0,0 +1,58 @@
Namespaces
-----
<?php
namespace Foo;
function foo()
{
}
namespace Bar;
function bar()
{
}
-----
namespace Foo;
function foo()
{
}
namespace Bar;
function bar()
{
}
-----
<?php
namespace Foo {
function foo()
{
}
}
namespace {
function glob() {
}
}
-----
namespace Foo {
function foo()
{
}
}
namespace {
function glob()
{
}
}

View File

@ -0,0 +1,11 @@
File containing only inline HTML
-----
Hallo World
Foo Bar
Bar Foo
World Hallo
-----
Hallo World
Foo Bar
Bar Foo
World Hallo

View File

@ -0,0 +1,11 @@
File containing only PHP
-----
<?php
echo 'Foo Bar';
echo 'Bar Foo';
-----
<?php
echo 'Foo Bar';
echo 'Bar Foo';

View File

@ -0,0 +1,45 @@
Pretty printer generates least-parentheses output
-----
<?php
echo 'abc' . 'cde' . 'fgh';
echo 'abc' . ('cde' . 'fgh');
echo 'abc' . 1 + 2 . 'fgh';
echo 'abc' . (1 + 2) . 'fgh';
echo 1 * 2 + 3 / 4 % 5 . 6;
echo 1 * (2 + 3) / (4 % (5 . 6));
$a = $b = $c = $d = $f && true;
($a = $b = $c = $d = $f) && true;
$a = $b = $c = $d = $f and true;
$a = $b = $c = $d = ($f and true);
$a ? $b : $c ? $d : $e ? $f : $g;
$a ? $b : ($c ? $d : ($e ? $f : $g));
$a ? $b ? $c : $d : $f;
(1 > 0) > (1 < 0);
// this will currently unnecessarily print !($a = $b). This is correct as far as operator precedence is concerned, but
// the parentheses are not really necessary, because = takes only variables as the left hand side operator.
!$a = $b;
-----
echo 'abc' . 'cde' . 'fgh';
echo 'abc' . ('cde' . 'fgh');
echo 'abc' . 1 + 2 . 'fgh';
echo 'abc' . (1 + 2) . 'fgh';
echo 1 * 2 + 3 / 4 % 5 . 6;
echo 1 * (2 + 3) / (4 % (5 . 6));
$a = $b = $c = $d = $f && true;
($a = $b = $c = $d = $f) && true;
$a = $b = $c = $d = $f and true;
$a = $b = $c = $d = ($f and true);
$a ? $b : $c ? $d : $e ? $f : $g;
$a ? $b : ($c ? $d : ($e ? $f : $g));
$a ? $b ? $c : $d : $f;
(1 > 0) > (1 < 0);
// this will currently unnecessarily print !($a = $b). This is correct as far as operator precedence is concerned, but
// the parentheses are not really necessary, because = takes only variables as the left hand side operator.
!($a = $b);

View File

@ -0,0 +1,35 @@
switch/case/default
-----
<?php
switch ($expr) {
case 0:
echo 'First case, with a break';
break;
case 1:
echo 'Second case, which falls through';
case 2:
case 3:
case 4:
echo 'Third case, return instead of break';
return;
default:
echo 'Default case';
break;
}
-----
switch ($expr) {
case 0:
echo 'First case, with a break';
break;
case 1:
echo 'Second case, which falls through';
case 2:
case 3:
case 4:
echo 'Third case, return instead of break';
return;
default:
echo 'Default case';
break;
}

View File

@ -69,7 +69,7 @@ require_once dirname(__FILE__) . '/../lib/PHPParser/Autoloader.php';
PHPParser_Autoloader::register();
$parser = new PHPParser_Parser(new PHPParser_Lexer_Emulative);
$prettyPrinter = new PHPParser_PrettyPrinter_Zend;
$prettyPrinter = new PHPParser_PrettyPrinter_Default;
$nodeDumper = new PHPParser_NodeDumper;
$parseFail = $ppFail = $compareFail = $count = 0;