1
0
mirror of https://github.com/danog/PHP-Parser.git synced 2024-11-27 04:14:44 +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; namespace PhpParser;
use PhpParser\Internal\DiffElem;
use PhpParser\Node\Expr; use PhpParser\Node\Expr;
use PhpParser\Node\Scalar; use PhpParser\Node\Scalar;
use PhpParser\Node\Stmt; use PhpParser\Node\Stmt;
@ -99,6 +100,8 @@ abstract class PrettyPrinterAbstract
protected $origTokens; protected $origTokens;
/** @var int Current indentation level during format-preserving pretty printing */ /** @var int Current indentation level during format-preserving pretty printing */
protected $fpIndentLevel; protected $fpIndentLevel;
/** @var Internal\Differ Differ for node lists */
protected $nodeListDiffer;
/** @var bool[] Map determining whether a certain character is a label character */ /** @var bool[] Map determining whether a certain character is a label character */
protected $labelCharMap; protected $labelCharMap;
/** /**
@ -441,6 +444,7 @@ abstract class PrettyPrinterAbstract
* @return string * @return string
*/ */
public function printFormatPreserving(array $stmts, array $origStmts, array $origTokens) : string { public function printFormatPreserving(array $stmts, array $origStmts, array $origTokens) : string {
$this->initializeNodeListDiffer();
$this->initializeLabelCharMap(); $this->initializeLabelCharMap();
$this->initializeFixupMap(); $this->initializeFixupMap();
$this->initializeRemovalMap(); $this->initializeRemovalMap();
@ -643,22 +647,24 @@ abstract class PrettyPrinterAbstract
* @return null|string Result of pretty print or null if cannot preserve formatting * @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) { protected function pArray(array $nodes, array $origNodes, int &$pos, int $indentAdjustment, $fixup) {
$len = count($nodes); $diff = $this->nodeListDiffer->diffWithReplacements($origNodes, $nodes);
$origLen = count($origNodes);
if ($len !== $origLen) { $result = '';
foreach ($diff as $diffElem) {
$diffType = $diffElem->type;
if ($diffType !== DiffElem::TYPE_KEEP && $diffType !== DiffElem::TYPE_REPLACE) {
// Only replace supported right now
return null; return null;
} }
$result = ''; /** @var Node|null $arrItem */
for ($i = 0; $i < $len; $i++) { $arrItem = $diffElem->new;
$arrItem = $nodes[$i]; /** @var Node|null $origArrItem */
$origArrItem = $origNodes[$i]; $origArrItem = $diffElem->old;
// We can only handle arrays of nodes meaningfully if ($origArrItem === null || $arrItem === null) {
if (!$arrItem instanceof Node || !$origArrItem instanceof Node) { // We can only handle the case where both are null
// Destructing can also contain null elements. If they occur symmetrically, this is if ($origArrItem === $arrItem) {
// fine as well
if ($arrItem === null && $origArrItem === null) {
continue; continue;
} }
return null; 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. * Lazily initializes fixup map.
* *

View File

@ -227,18 +227,19 @@ function foo() {
$tmp = $stmts[0]; $tmp = $stmts[0];
$stmts[0] = $stmts[1]; $stmts[0] = $stmts[1];
$stmts[1] = $tmp; $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 <?php
$x;
{ $x;
function foo() { function foo() {
foo(); foo();
/* /*
* bar * bar
*/ */
baz(); baz();
}
} }
----- -----
<?php <?php