diff --git a/doc/component/Pretty_printing.markdown b/doc/component/Pretty_printing.markdown index db6ea1dc83..1a09143836 100644 --- a/doc/component/Pretty_printing.markdown +++ b/doc/component/Pretty_printing.markdown @@ -36,6 +36,10 @@ The pretty printer respects a number of attributes used by some nodes: * `kind` on `Scalar\String_` to use single quotes (default), double quotes, heredoc or nowdoc. In the latter two cases, the heredoc/nowdoc label from the `docLabel` attribute is used. * `kind` on `Scalar\Int_` to use decimal (default), binary, octal or hexadecimal representation. + * `shouldPrintRawValue` and `rawValue` on `Scalar\Int_` to preserve the original formatting of + integer literals (e.g., numeric separators like `1_000`). When `shouldPrintRawValue` is set to + `true`, the value from `rawValue` is used instead of the computed representation. This works for + all integer formats (decimal, binary, octal, hexadecimal). * `kind` on `Cast\Double` to use `(double)` (default), `(float)` or `(real)`. * `kind` on `Expr\List_` to use `[]` or `list()` (default depends on `phpVersion` option). * `kind` on `Expr\Array_` to use `[]` or `array()` (default depends on `shortArraySyntax` option). diff --git a/lib/PhpParser/PrettyPrinter/Standard.php b/lib/PhpParser/PrettyPrinter/Standard.php index 4cf374f9e8..d70843776e 100644 --- a/lib/PhpParser/PrettyPrinter/Standard.php +++ b/lib/PhpParser/PrettyPrinter/Standard.php @@ -197,6 +197,10 @@ protected function pScalar_InterpolatedString(Scalar\InterpolatedString $node): } protected function pScalar_Int(Scalar\Int_ $node): string { + if ($node->getAttribute('shouldPrintRawValue') === true) { + return $node->getAttribute('rawValue'); + } + if ($node->value === -\PHP_INT_MAX - 1) { // PHP_INT_MIN cannot be represented as a literal, // because the sign is not part of the literal @@ -204,6 +208,7 @@ protected function pScalar_Int(Scalar\Int_ $node): string { } $kind = $node->getAttribute('kind', Scalar\Int_::KIND_DEC); + if (Scalar\Int_::KIND_DEC === $kind) { return (string) $node->value; } diff --git a/test/PhpParser/PrettyPrinterTest.php b/test/PhpParser/PrettyPrinterTest.php index 8e0e472179..aa956377ad 100644 --- a/test/PhpParser/PrettyPrinterTest.php +++ b/test/PhpParser/PrettyPrinterTest.php @@ -165,6 +165,28 @@ public static function provideTestUnnaturalLiterals() { ]; } + /** @dataProvider provideTestCustomRawValue */ + public function printCustomRawValue($node, $expected): void { + $prettyPrinter = new PrettyPrinter\Standard(); + $result = $prettyPrinter->prettyPrintExpr($node); + $this->assertSame($expected, $result); + } + + public static function provideTestCustomRawValue() { + return [ + // Decimal with separator + [new Int_(1000, ['rawValue' => '10_00', 'shouldPrintRawValue' => true]), '10_00'], + // Hexadecimal with separator + [new Int_(0xDEADBEEF, ['kind' => Int_::KIND_HEX, 'rawValue' => '0xDEAD_BEEF', 'shouldPrintRawValue' => true]), '0xDEAD_BEEF'], + // Binary with separator + [new Int_(0b11110000, ['kind' => Int_::KIND_BIN, 'rawValue' => '0b1111_0000', 'shouldPrintRawValue' => true]), '0b1111_0000'], + // Octal with separator + [new Int_(0755, ['kind' => Int_::KIND_OCT, 'rawValue' => '0755_000', 'shouldPrintRawValue' => true]), '0755_000'], + // Without flag set, should use default formatting + [new Int_(1000, ['rawValue' => '10_00', 'shouldPrintRawValue' => false]), '1000'], + ]; + } + public function testPrettyPrintWithError(): void { $this->expectException(\LogicException::class); $this->expectExceptionMessage('Cannot pretty-print AST with Error nodes');