From 18cd8ddd883b633074b067e751af813a97dcb901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dalibor=20Karlovi=C4=87?= Date: Fri, 28 Feb 2025 11:23:18 +0100 Subject: [PATCH 1/4] test: array tests --- lib/PhpParser/Node/Expr/Array_.php | 1 + lib/PhpParser/PrettyPrinter/Standard.php | 18 +++++++++++------- test/code/prettyPrinter/stmt/arrays.test | 22 ++++++++++++++++++++++ 3 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 test/code/prettyPrinter/stmt/arrays.test diff --git a/lib/PhpParser/Node/Expr/Array_.php b/lib/PhpParser/Node/Expr/Array_.php index 3c8c9c2fcf..11ca813509 100644 --- a/lib/PhpParser/Node/Expr/Array_.php +++ b/lib/PhpParser/Node/Expr/Array_.php @@ -9,6 +9,7 @@ class Array_ extends Expr { // For use in "kind" attribute public const KIND_LONG = 1; // array() syntax public const KIND_SHORT = 2; // [] syntax + public const KIND_MULTILINE = 4; // force multiline formatting /** @var ArrayItem[] Items */ public array $items; diff --git a/lib/PhpParser/PrettyPrinter/Standard.php b/lib/PhpParser/PrettyPrinter/Standard.php index 0a9dfd750c..130a2b0335 100644 --- a/lib/PhpParser/PrettyPrinter/Standard.php +++ b/lib/PhpParser/PrettyPrinter/Standard.php @@ -600,12 +600,16 @@ protected function pExpr_Variable(Expr\Variable $node): string { } protected function pExpr_Array(Expr\Array_ $node): string { - $syntax = $node->getAttribute('kind', + $kind = $node->getAttribute('kind', $this->shortArraySyntax ? Expr\Array_::KIND_SHORT : Expr\Array_::KIND_LONG); + + $forceMultiline = ($kind & Expr\Array_::KIND_MULTILINE) === Expr\Array_::KIND_MULTILINE; + $syntax = $kind & ~Expr\Array_::KIND_MULTILINE; + if ($syntax === Expr\Array_::KIND_SHORT) { - return '[' . $this->pMaybeMultiline($node->items, true) . ']'; + return '[' . $this->pMaybeMultiline($node->items, true, $forceMultiline) . ']'; } else { - return 'array(' . $this->pMaybeMultiline($node->items, true) . ')'; + return 'array(' . $this->pMaybeMultiline($node->items, true, $forceMultiline) . ')'; } } @@ -1181,12 +1185,12 @@ protected function hasNodeWithComments(array $nodes): bool { } /** @param Node[] $nodes */ - protected function pMaybeMultiline(array $nodes, bool $trailingComma = false): string { - if (!$this->hasNodeWithComments($nodes)) { - return $this->pCommaSeparated($nodes); - } else { + protected function pMaybeMultiline(array $nodes, bool $trailingComma = false, bool $forceMultiline = false): string { + if ($forceMultiline || $this->hasNodeWithComments($nodes)) { return $this->pCommaSeparatedMultiline($nodes, $trailingComma) . $this->nl; } + + return $this->pCommaSeparated($nodes); } /** @param Node\Param[] $params diff --git a/test/code/prettyPrinter/stmt/arrays.test b/test/code/prettyPrinter/stmt/arrays.test new file mode 100644 index 0000000000..9da895778a --- /dev/null +++ b/test/code/prettyPrinter/stmt/arrays.test @@ -0,0 +1,22 @@ +Arrays +----- + Date: Mon, 10 Mar 2025 13:07:15 +0100 Subject: [PATCH 2/4] fix: preserve multiline --- grammar/php.y | 10 ++++++++-- lib/PhpParser/ParserAbstract.php | 8 ++++++++ test/code/prettyPrinter/stmt/arrays.test | 12 ++++++++++-- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/grammar/php.y b/grammar/php.y index 44c76f8b0f..52ad413d53 100644 --- a/grammar/php.y +++ b/grammar/php.y @@ -1267,13 +1267,19 @@ class_constant: array_short_syntax: '[' array_pair_list ']' - { $attrs = attributes(); $attrs['kind'] = Expr\Array_::KIND_SHORT; + { $attrs = attributes(); + $attrs['kind'] = $this->isMultiline($attrs) + ? Expr\Array_::KIND_SHORT | Expr\Array_::KIND_MULTILINE + : Expr\Array_::KIND_SHORT; $$ = new Expr\Array_($2, $attrs); } ; dereferenceable_scalar: T_ARRAY '(' array_pair_list ')' - { $attrs = attributes(); $attrs['kind'] = Expr\Array_::KIND_LONG; + { $attrs = attributes(); + $attrs['kind'] = $this->isMultiline($attrs) + ? Expr\Array_::KIND_LONG | Expr\Array_::KIND_MULTILINE + : Expr\Array_::KIND_LONG; $$ = new Expr\Array_($3, $attrs); $this->createdArrays->offsetSet($$); } | array_short_syntax diff --git a/lib/PhpParser/ParserAbstract.php b/lib/PhpParser/ParserAbstract.php index c10a0c9757..39f75aa6d1 100644 --- a/lib/PhpParser/ParserAbstract.php +++ b/lib/PhpParser/ParserAbstract.php @@ -1264,6 +1264,14 @@ private function isSimpleExit(array $args): bool { return false; } + protected function isMultiline(array $attributes): bool { + if (!isset($attributes['startLine']) || !isset($attributes['endLine'])) { + return false; + } + + return $attributes['startLine'] !== $attributes['endLine']; + } + /** * @param array $args * @param array $attrs diff --git a/test/code/prettyPrinter/stmt/arrays.test b/test/code/prettyPrinter/stmt/arrays.test index 9da895778a..884ad902c8 100644 --- a/test/code/prettyPrinter/stmt/arrays.test +++ b/test/code/prettyPrinter/stmt/arrays.test @@ -17,6 +17,14 @@ $longMultiline = array( ); ----- $short = [1, 2, 3]; -$shortMultiline = [1, 2, 3]; +$shortMultiline = [ + 1, + 2, + 3, +]; $long = array(1, 2, 3); -$longMultiline = array(1, 2, 3); +$longMultiline = array( + 1, + 2, + 3, +); From 4b9866f194002a286e41064d5acb697312de2fd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dalibor=20Karlovi=C4=87?= Date: Mon, 10 Mar 2025 13:51:40 +0100 Subject: [PATCH 3/4] cs --- lib/PhpParser/PrettyPrinter/Standard.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/PhpParser/PrettyPrinter/Standard.php b/lib/PhpParser/PrettyPrinter/Standard.php index 130a2b0335..541dd45b93 100644 --- a/lib/PhpParser/PrettyPrinter/Standard.php +++ b/lib/PhpParser/PrettyPrinter/Standard.php @@ -605,7 +605,7 @@ protected function pExpr_Array(Expr\Array_ $node): string { $forceMultiline = ($kind & Expr\Array_::KIND_MULTILINE) === Expr\Array_::KIND_MULTILINE; $syntax = $kind & ~Expr\Array_::KIND_MULTILINE; - + if ($syntax === Expr\Array_::KIND_SHORT) { return '[' . $this->pMaybeMultiline($node->items, true, $forceMultiline) . ']'; } else { From 2b8c12dbc5ef06c38fb81c8ced1451f8cb2d6dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dalibor=20Karlovi=C4=87?= Date: Mon, 10 Mar 2025 13:54:04 +0100 Subject: [PATCH 4/4] Rebase + a few more test cases --- lib/PhpParser/Parser/Php7.php | 10 ++++- lib/PhpParser/Parser/Php8.php | 10 ++++- lib/PhpParser/ParserAbstract.php | 9 ++-- test/code/prettyPrinter/stmt/arrays.test | 53 ++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 7 deletions(-) diff --git a/lib/PhpParser/Parser/Php7.php b/lib/PhpParser/Parser/Php7.php index 7784e8806c..4b799e4f03 100644 --- a/lib/PhpParser/Parser/Php7.php +++ b/lib/PhpParser/Parser/Php7.php @@ -2686,11 +2686,17 @@ protected function initReduceCallbacks(): void { $self->semValue = new Expr\ClassConstFetch($self->semStack[$stackPos-(3-1)], new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos-(3-3)], $self->tokenEndStack[$stackPos-(3-3)])), $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos])); $self->errorState = 2; }, 560 => static function ($self, $stackPos) { - $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Expr\Array_::KIND_SHORT; + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = $self->isMultiline($attrs) + ? Expr\Array_::KIND_SHORT | Expr\Array_::KIND_MULTILINE + : Expr\Array_::KIND_SHORT; $self->semValue = new Expr\Array_($self->semStack[$stackPos-(3-2)], $attrs); }, 561 => static function ($self, $stackPos) { - $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Expr\Array_::KIND_LONG; + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = $self->isMultiline($attrs) + ? Expr\Array_::KIND_LONG | Expr\Array_::KIND_MULTILINE + : Expr\Array_::KIND_LONG; $self->semValue = new Expr\Array_($self->semStack[$stackPos-(4-3)], $attrs); $self->createdArrays->offsetSet($self->semValue); }, diff --git a/lib/PhpParser/Parser/Php8.php b/lib/PhpParser/Parser/Php8.php index 7a15cef564..e7090be411 100644 --- a/lib/PhpParser/Parser/Php8.php +++ b/lib/PhpParser/Parser/Php8.php @@ -2687,11 +2687,17 @@ protected function initReduceCallbacks(): void { $self->semValue = new Expr\ClassConstFetch($self->semStack[$stackPos-(3-1)], new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos-(3-3)], $self->tokenEndStack[$stackPos-(3-3)])), $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos])); $self->errorState = 2; }, 563 => static function ($self, $stackPos) { - $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Expr\Array_::KIND_SHORT; + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = $self->isMultiline($attrs) + ? Expr\Array_::KIND_SHORT | Expr\Array_::KIND_MULTILINE + : Expr\Array_::KIND_SHORT; $self->semValue = new Expr\Array_($self->semStack[$stackPos-(3-2)], $attrs); }, 564 => static function ($self, $stackPos) { - $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Expr\Array_::KIND_LONG; + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = $self->isMultiline($attrs) + ? Expr\Array_::KIND_LONG | Expr\Array_::KIND_MULTILINE + : Expr\Array_::KIND_LONG; $self->semValue = new Expr\Array_($self->semStack[$stackPos-(4-3)], $attrs); $self->createdArrays->offsetSet($self->semValue); }, diff --git a/lib/PhpParser/ParserAbstract.php b/lib/PhpParser/ParserAbstract.php index 39f75aa6d1..7890dfdd96 100644 --- a/lib/PhpParser/ParserAbstract.php +++ b/lib/PhpParser/ParserAbstract.php @@ -1264,12 +1264,15 @@ private function isSimpleExit(array $args): bool { return false; } - protected function isMultiline(array $attributes): bool { - if (!isset($attributes['startLine']) || !isset($attributes['endLine'])) { + /** + * @param array{startLine?:int, endLine?: int} $attrs + */ + protected function isMultiline(array $attrs): bool { + if (!isset($attrs['startLine']) || !isset($attrs['endLine'])) { return false; } - return $attributes['startLine'] !== $attributes['endLine']; + return $attrs['startLine'] !== $attrs['endLine']; } /** diff --git a/test/code/prettyPrinter/stmt/arrays.test b/test/code/prettyPrinter/stmt/arrays.test index 884ad902c8..38fccbdb85 100644 --- a/test/code/prettyPrinter/stmt/arrays.test +++ b/test/code/prettyPrinter/stmt/arrays.test @@ -15,6 +15,27 @@ $longMultiline = array( 2, 3 ); + +$mixedShort = array( + array(1, 2, 3), + array(1, + 2, 3), + [4, 5, 6], + [1, + 2, 3], + 2, + 3, +); +$mixedLong = [ + array(1, 2, 3), + array(1, + 2, 3), + [4, 5, 6], + [1, + 2, 3], + 2, + 3 +]; ----- $short = [1, 2, 3]; $shortMultiline = [ @@ -28,3 +49,35 @@ $longMultiline = array( 2, 3, ); +$mixedShort = array( + array(1, 2, 3), + array( + 1, + 2, + 3, + ), + [4, 5, 6], + [ + 1, + 2, + 3, + ], + 2, + 3, +); +$mixedLong = [ + array(1, 2, 3), + array( + 1, + 2, + 3, + ), + [4, 5, 6], + [ + 1, + 2, + 3, + ], + 2, + 3, +];