1
0
mirror of https://github.com/danog/PHP-Parser.git synced 2024-11-26 20:04:48 +01:00

FPPP: Switch pArray() to use node list diffing

This commit is contained in:
Nikita Popov 2017-10-05 18:44:45 +02:00
parent 69aec6fb5b
commit ed8a744cd5
2 changed files with 46 additions and 22 deletions

View File

@ -2,6 +2,7 @@
namespace PhpParser;
use PhpParser\Internal\DiffElem;
use PhpParser\Node\Expr;
use PhpParser\Node\Scalar;
use PhpParser\Node\Stmt;
@ -99,6 +100,8 @@ abstract class PrettyPrinterAbstract
protected $origTokens;
/** @var int Current indentation level during format-preserving pretty printing */
protected $fpIndentLevel;
/** @var Internal\Differ Differ for node lists */
protected $nodeListDiffer;
/** @var bool[] Map determining whether a certain character is a label character */
protected $labelCharMap;
/**
@ -441,6 +444,7 @@ abstract class PrettyPrinterAbstract
* @return string
*/
public function printFormatPreserving(array $stmts, array $origStmts, array $origTokens) : string {
$this->initializeNodeListDiffer();
$this->initializeLabelCharMap();
$this->initializeFixupMap();
$this->initializeRemovalMap();
@ -643,22 +647,24 @@ abstract class PrettyPrinterAbstract
* @return null|string Result of pretty print or null if cannot preserve formatting
*/
protected function pArray(array $nodes, array $origNodes, int &$pos, int $indentAdjustment, $fixup) {
$len = count($nodes);
$origLen = count($origNodes);
if ($len !== $origLen) {
return null;
}
$diff = $this->nodeListDiffer->diffWithReplacements($origNodes, $nodes);
$result = '';
for ($i = 0; $i < $len; $i++) {
$arrItem = $nodes[$i];
$origArrItem = $origNodes[$i];
foreach ($diff as $diffElem) {
$diffType = $diffElem->type;
if ($diffType !== DiffElem::TYPE_KEEP && $diffType !== DiffElem::TYPE_REPLACE) {
// Only replace supported right now
return null;
}
// We can only handle arrays of nodes meaningfully
if (!$arrItem instanceof Node || !$origArrItem instanceof Node) {
// Destructing can also contain null elements. If they occur symmetrically, this is
// fine as well
if ($arrItem === null && $origArrItem === null) {
/** @var Node|null $arrItem */
$arrItem = $diffElem->new;
/** @var Node|null $origArrItem */
$origArrItem = $diffElem->old;
if ($origArrItem === null || $arrItem === null) {
// We can only handle the case where both are null
if ($origArrItem === $arrItem) {
continue;
}
return null;
@ -844,6 +850,23 @@ abstract class PrettyPrinterAbstract
}
}
/**
* Lazily initializes node list differ.
*
* The node list differ is used to determine differences between two array subnodes.
*/
protected function initializeNodeListDiffer() {
if ($this->nodeListDiffer) return;
$this->nodeListDiffer = new Internal\Differ(function ($a, $b) {
if ($a instanceof Node && $b instanceof Node) {
return $a === $b->getAttribute('origNode');
}
// Can happen for array destructuring
return $a === null && $b === null;
});
}
/**
* Lazily initializes fixup map.
*

View File

@ -227,18 +227,19 @@ function foo() {
$tmp = $stmts[0];
$stmts[0] = $stmts[1];
$stmts[1] = $tmp;
/* TODO This used to do two replacement operations, but with the node list diffing this is a
* remove, keep, add (which probably makes more sense). As such, this currently triggers a
* fallback. */
-----
<?php
$x;
{
function foo() {
foo();
/*
* bar
*/
baz();
}
$x;
function foo() {
foo();
/*
* bar
*/
baz();
}
-----
<?php