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

View File

@ -100,11 +100,6 @@ parameters:
count: 1
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\\.$#"
count: 1

View File

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

View File

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

View File

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

View File

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