Assemble NodeDumper result in property

Append to a property instead of returning strings. This is
significantly faster when dumping large ASTs.

This also fixes an inconsistency where the indentation level for
strings and comments was off-by-one.
This commit is contained in:
Nikita Popov 2023-09-23 18:42:57 +02:00
parent 8f175fe7c8
commit 80851163a6
6 changed files with 73 additions and 72 deletions

View File

@ -11,6 +11,8 @@ class NodeDumper {
private bool $dumpComments; private bool $dumpComments;
private bool $dumpPositions; private bool $dumpPositions;
private ?string $code; private ?string $code;
private string $res;
private string $nl;
/** /**
* Constructs a NodeDumper. * Constructs a NodeDumper.
@ -39,72 +41,76 @@ class NodeDumper {
*/ */
public function dump($node, ?string $code = null): string { public function dump($node, ?string $code = null): string {
$this->code = $code; $this->code = $code;
return $this->dumpRecursive($node); $this->res = '';
$this->nl = "\n";
$this->dumpRecursive($node, false);
return $this->res;
} }
/** @param Node|Comment|array $node */ /** @param mixed $node */
protected function dumpRecursive($node): string { protected function dumpRecursive($node, bool $indent = true): void {
if ($indent) {
$this->nl .= " ";
}
if ($node instanceof Node) { if ($node instanceof Node) {
$r = $node->getType(); $this->res .= $node->getType();
if ($this->dumpPositions && null !== $p = $this->dumpPosition($node)) { if ($this->dumpPositions && null !== $p = $this->dumpPosition($node)) {
$r .= $p; $this->res .= $p;
} }
$r .= '('; $this->res .= '(';
foreach ($node->getSubNodeNames() as $key) { foreach ($node->getSubNodeNames() as $key) {
$r .= "\n " . $key . ': '; $this->res .= "$this->nl " . $key . ': ';
$value = $node->$key; $value = $node->$key;
if (null === $value) { if (\is_int($value)) {
$r .= 'null';
} elseif (false === $value) {
$r .= 'false';
} elseif (true === $value) {
$r .= 'true';
} elseif (is_scalar($value)) {
if ('flags' === $key || 'newModifier' === $key) { if ('flags' === $key || 'newModifier' === $key) {
$r .= $this->dumpFlags($value); $this->res .= $this->dumpFlags($value);
} elseif ('type' === $key && $node instanceof Include_) { continue;
$r .= $this->dumpIncludeType($value); }
} elseif ('type' === $key if ('type' === $key && $node instanceof Include_) {
&& ($node instanceof Use_ || $node instanceof UseItem || $node instanceof GroupUse)) { $this->res .= $this->dumpIncludeType($value);
$r .= $this->dumpUseType($value); continue;
} else { }
$r .= $value; if ('type' === $key
&& ($node instanceof Use_ || $node instanceof UseItem || $node instanceof GroupUse)) {
$this->res .= $this->dumpUseType($value);
continue;
} }
} else {
$r .= str_replace("\n", "\n ", $this->dumpRecursive($value));
} }
$this->dumpRecursive($value);
} }
if ($this->dumpComments && $comments = $node->getComments()) { if ($this->dumpComments && $comments = $node->getComments()) {
$r .= "\n comments: " . str_replace("\n", "\n ", $this->dumpRecursive($comments)); $this->res .= "$this->nl comments: ";
$this->dumpRecursive($comments);
} }
} elseif (is_array($node)) { $this->res .= "$this->nl)";
$r = 'array('; } elseif (\is_array($node)) {
$this->res .= 'array(';
foreach ($node as $key => $value) { foreach ($node as $key => $value) {
$r .= "\n " . $key . ': '; $this->res .= "$this->nl " . $key . ': ';
$this->dumpRecursive($value);
if (null === $value) {
$r .= 'null';
} elseif (false === $value) {
$r .= 'false';
} elseif (true === $value) {
$r .= 'true';
} elseif (is_scalar($value)) {
$r .= $value;
} else {
$r .= str_replace("\n", "\n ", $this->dumpRecursive($value));
}
} }
$this->res .= "$this->nl)";
} elseif ($node instanceof Comment) { } elseif ($node instanceof Comment) {
return $node->getReformattedText(); $this->res .= \str_replace("\n", $this->nl, $node->getReformattedText());
} elseif (\is_string($node)) {
$this->res .= \str_replace("\n", $this->nl, (string)$node);
} elseif (\is_int($node) || \is_float($node)) {
$this->res .= $node;
} elseif (null === $node) {
$this->res .= 'null';
} elseif (false === $node) {
$this->res .= 'false';
} elseif (true === $node) {
$this->res .= 'true';
} else { } else {
throw new \InvalidArgumentException('Can only dump nodes and arrays.'); throw new \InvalidArgumentException('Can only dump nodes and arrays.');
} }
if ($indent) {
return $r . "\n)"; $this->nl = \substr($this->nl, 0, -4);
}
} }
protected function dumpFlags(int $flags): string { protected function dumpFlags(int $flags): string {

View File

@ -100,11 +100,6 @@ parameters:
count: 1 count: 1
path: lib/PhpParser/NodeDumper.php path: lib/PhpParser/NodeDumper.php
-
message: "#^Method PhpParser\\\\NodeDumper\\:\\:dumpRecursive\\(\\) has parameter \\$node with no value type specified in iterable type array\\.$#"
count: 1
path: lib/PhpParser/NodeDumper.php
- -
message: "#^Method PhpParser\\\\NodeTraverser\\:\\:traverseArray\\(\\) has parameter \\$nodes with no value type specified in iterable type array\\.$#" message: "#^Method PhpParser\\\\NodeTraverser\\:\\:traverseArray\\(\\) has parameter \\$nodes with no value type specified in iterable type array\\.$#"
count: 1 count: 1

View File

@ -75,7 +75,7 @@ array(
11: Stmt_Expression( 11: Stmt_Expression(
expr: Scalar_String( expr: Scalar_String(
value: !"!\!$! value: !"!\!$!
!@@{ "\r" }@@!@@{ "\t" }@@!@@{ "\f" }@@!@@{ "\v" }@@!@@{ chr(27) /* "\e" */ }@@!\a !@@{ "\r" }@@!@@{ "\t" }@@!@@{ "\f" }@@!@@{ "\v" }@@!@@{ chr(27) /* "\e" */ }@@!\a
) )
) )
12: Stmt_Expression( 12: Stmt_Expression(

View File

@ -155,12 +155,12 @@ array(
4: Stmt_Expression( 4: Stmt_Expression(
expr: Scalar_String( expr: Scalar_String(
value: a value: a
b b
c c
d d
e e
) )
) )
5: Stmt_Expression( 5: Stmt_Expression(
@ -168,7 +168,7 @@ array(
parts: array( parts: array(
0: InterpolatedStringPart( 0: InterpolatedStringPart(
value: a value: a
b b
) )
1: Expr_Variable( 1: Expr_Variable(
@ -176,8 +176,8 @@ array(
) )
2: InterpolatedStringPart( 2: InterpolatedStringPart(
value: value:
d d
e e
) )
) )
) )
@ -185,15 +185,15 @@ array(
6: Stmt_Expression( 6: Stmt_Expression(
expr: Scalar_String( expr: Scalar_String(
value: value:
a a
b b
c c
d d
e e
) )
) )
@ -203,9 +203,9 @@ array(
0: InterpolatedStringPart( 0: InterpolatedStringPart(
value: a value: a
@@{ "\t" }@@a @@{ "\t" }@@a
b b
) )
@ -215,9 +215,9 @@ array(
2: InterpolatedStringPart( 2: InterpolatedStringPart(
value: value:
d d
e e
) )
) )
@ -321,7 +321,7 @@ array(
) )
1: InterpolatedStringPart( 1: InterpolatedStringPart(
value: value:
- -
) )
) )
) )
@ -334,7 +334,7 @@ array(
) )
1: InterpolatedStringPart( 1: InterpolatedStringPart(
value: value:
- -
) )
) )
) )

View File

@ -67,8 +67,8 @@ array(
exprs: array( exprs: array(
0: Scalar_String( 0: Scalar_String(
value: a value: a
b b
c c
) )
) )
) )

View File

@ -28,6 +28,6 @@ array(
) )
1: Stmt_HaltCompiler( 1: Stmt_HaltCompiler(
remaining: remaining:
Foo Foo
) )
) )