Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. PrettyPrinterAbstract.php

function PrettyPrinterAbstract::pArray

Perform a format-preserving pretty print of an array.

Parameters

Node[] $nodes New nodes:

Node[] $origNodes Original nodes:

int $pos Current token position (updated by reference):

int $indentAdjustment Adjustment for indentation:

string $parentNodeClass Class of the containing node.:

string $subNodeName Name of array subnode.:

null|int $fixup Fixup information for array item nodes:

Return value

null|string Result of pretty print or null if cannot preserve formatting

2 calls to PrettyPrinterAbstract::pArray()
PrettyPrinterAbstract::p in vendor/nikic/php-parser/lib/PhpParser/PrettyPrinterAbstract.php
Pretty prints a node.
PrettyPrinterAbstract::printFormatPreserving in vendor/nikic/php-parser/lib/PhpParser/PrettyPrinterAbstract.php
Perform a format-preserving pretty print of an AST.

File

vendor/nikic/php-parser/lib/PhpParser/PrettyPrinterAbstract.php, line 779

Class

PrettyPrinterAbstract

Namespace

PhpParser

Code

protected function pArray(array $nodes, array $origNodes, int &$pos, int $indentAdjustment, string $parentNodeClass, string $subNodeName, ?int $fixup) : ?string {
    $diff = $this->nodeListDiffer
        ->diffWithReplacements($origNodes, $nodes);
    $mapKey = $parentNodeClass . '->' . $subNodeName;
    $insertStr = $this->listInsertionMap[$mapKey] ?? null;
    $isStmtList = $subNodeName === 'stmts';
    $beforeFirstKeepOrReplace = true;
    $skipRemovedNode = false;
    $delayedAdd = [];
    $lastElemIndentLevel = $this->indentLevel;
    $insertNewline = false;
    if ($insertStr === "\n") {
        $insertStr = '';
        $insertNewline = true;
    }
    if ($isStmtList && \count($origNodes) === 1 && \count($nodes) !== 1) {
        $startPos = $origNodes[0]->getStartTokenPos();
        $endPos = $origNodes[0]->getEndTokenPos();
        \assert($startPos >= 0 && $endPos >= 0);
        if (!$this->origTokens
            ->haveBraces($startPos, $endPos)) {
            // This was a single statement without braces, but either additional statements
            // have been added, or the single statement has been removed. This requires the
            // addition of braces. For now fall back.
            // TODO: Try to preserve formatting
            return null;
        }
    }
    $result = '';
    foreach ($diff as $i => $diffElem) {
        $diffType = $diffElem->type;
        
        /** @var Node|string|null $arrItem */
        $arrItem = $diffElem->new;
        
        /** @var Node|string|null $origArrItem */
        $origArrItem = $diffElem->old;
        if ($diffType === DiffElem::TYPE_KEEP || $diffType === DiffElem::TYPE_REPLACE) {
            $beforeFirstKeepOrReplace = false;
            if ($origArrItem === null || $arrItem === null) {
                // We can only handle the case where both are null
                if ($origArrItem === $arrItem) {
                    continue;
                }
                return null;
            }
            if (!$arrItem instanceof Node || !$origArrItem instanceof Node) {
                // We can only deal with nodes. This can occur for Names, which use string arrays.
                return null;
            }
            $itemStartPos = $origArrItem->getStartTokenPos();
            $itemEndPos = $origArrItem->getEndTokenPos();
            \assert($itemStartPos >= 0 && $itemEndPos >= 0 && $itemStartPos >= $pos);
            $origIndentLevel = $this->indentLevel;
            $lastElemIndentLevel = max($this->origTokens
                ->getIndentationBefore($itemStartPos) + $indentAdjustment, 0);
            $this->setIndentLevel($lastElemIndentLevel);
            $comments = $arrItem->getComments();
            $origComments = $origArrItem->getComments();
            $commentStartPos = $origComments ? $origComments[0]->getStartTokenPos() : $itemStartPos;
            \assert($commentStartPos >= 0);
            if ($commentStartPos < $pos) {
                // Comments may be assigned to multiple nodes if they start at the same position.
                // Make sure we don't try to print them multiple times.
                $commentStartPos = $itemStartPos;
            }
            if ($skipRemovedNode) {
                if ($isStmtList && $this->origTokens
                    ->haveTagInRange($pos, $itemStartPos)) {
                    // We'd remove an opening/closing PHP tag.
                    // TODO: Preserve formatting.
                    $this->setIndentLevel($origIndentLevel);
                    return null;
                }
            }
            else {
                $result .= $this->origTokens
                    ->getTokenCode($pos, $commentStartPos, $indentAdjustment);
            }
            if (!empty($delayedAdd)) {
                
                /** @var Node $delayedAddNode */
                foreach ($delayedAdd as $delayedAddNode) {
                    if ($insertNewline) {
                        $delayedAddComments = $delayedAddNode->getComments();
                        if ($delayedAddComments) {
                            $result .= $this->pComments($delayedAddComments) . $this->nl;
                        }
                    }
                    $this->safeAppend($result, $this->p($delayedAddNode, self::MAX_PRECEDENCE, self::MAX_PRECEDENCE, true));
                    if ($insertNewline) {
                        $result .= $insertStr . $this->nl;
                    }
                    else {
                        $result .= $insertStr;
                    }
                }
                $delayedAdd = [];
            }
            if ($comments !== $origComments) {
                if ($comments) {
                    $result .= $this->pComments($comments) . $this->nl;
                }
            }
            else {
                $result .= $this->origTokens
                    ->getTokenCode($commentStartPos, $itemStartPos, $indentAdjustment);
            }
            // If we had to remove anything, we have done so now.
            $skipRemovedNode = false;
        }
        elseif ($diffType === DiffElem::TYPE_ADD) {
            if (null === $insertStr) {
                // We don't have insertion information for this list type
                return null;
            }
            if (!$arrItem instanceof Node) {
                // We only support list insertion of nodes.
                return null;
            }
            // We go multiline if the original code was multiline,
            // or if it's an array item with a comment above it.
            // Match always uses multiline formatting.
            if ($insertStr === ', ' && ($this->isMultiline($origNodes) || $arrItem->getComments() || $parentNodeClass === Expr\Match_::class)) {
                $insertStr = ',';
                $insertNewline = true;
            }
            if ($beforeFirstKeepOrReplace) {
                // Will be inserted at the next "replace" or "keep" element
                $delayedAdd[] = $arrItem;
                continue;
            }
            $itemStartPos = $pos;
            $itemEndPos = $pos - 1;
            $origIndentLevel = $this->indentLevel;
            $this->setIndentLevel($lastElemIndentLevel);
            if ($insertNewline) {
                $result .= $insertStr . $this->nl;
                $comments = $arrItem->getComments();
                if ($comments) {
                    $result .= $this->pComments($comments) . $this->nl;
                }
            }
            else {
                $result .= $insertStr;
            }
        }
        elseif ($diffType === DiffElem::TYPE_REMOVE) {
            if (!$origArrItem instanceof Node) {
                // We only support removal for nodes
                return null;
            }
            $itemStartPos = $origArrItem->getStartTokenPos();
            $itemEndPos = $origArrItem->getEndTokenPos();
            \assert($itemStartPos >= 0 && $itemEndPos >= 0);
            // Consider comments part of the node.
            $origComments = $origArrItem->getComments();
            if ($origComments) {
                $itemStartPos = $origComments[0]->getStartTokenPos();
            }
            if ($i === 0) {
                // If we're removing from the start, keep the tokens before the node and drop those after it,
                // instead of the other way around.
                $result .= $this->origTokens
                    ->getTokenCode($pos, $itemStartPos, $indentAdjustment);
                $skipRemovedNode = true;
            }
            else {
                if ($isStmtList && $this->origTokens
                    ->haveTagInRange($pos, $itemStartPos)) {
                    // We'd remove an opening/closing PHP tag.
                    // TODO: Preserve formatting.
                    return null;
                }
            }
            $pos = $itemEndPos + 1;
            continue;
        }
        else {
            throw new \Exception("Shouldn't happen");
        }
        if (null !== $fixup && $arrItem->getAttribute('origNode') !== $origArrItem) {
            $res = $this->pFixup($fixup, $arrItem, null, $itemStartPos, $itemEndPos);
        }
        else {
            $res = $this->p($arrItem, self::MAX_PRECEDENCE, self::MAX_PRECEDENCE, true);
        }
        $this->safeAppend($result, $res);
        $this->setIndentLevel($origIndentLevel);
        $pos = $itemEndPos + 1;
    }
    if ($skipRemovedNode) {
        // TODO: Support removing single node.
        return null;
    }
    if (!empty($delayedAdd)) {
        if (!isset($this->emptyListInsertionMap[$mapKey])) {
            return null;
        }
        list($findToken, $extraLeft, $extraRight) = $this->emptyListInsertionMap[$mapKey];
        if (null !== $findToken) {
            $insertPos = $this->origTokens
                ->findRight($pos, $findToken) + 1;
            $result .= $this->origTokens
                ->getTokenCode($pos, $insertPos, $indentAdjustment);
            $pos = $insertPos;
        }
        $first = true;
        $result .= $extraLeft;
        foreach ($delayedAdd as $delayedAddNode) {
            if (!$first) {
                $result .= $insertStr;
                if ($insertNewline) {
                    $result .= $this->nl;
                }
            }
            $result .= $this->p($delayedAddNode, self::MAX_PRECEDENCE, self::MAX_PRECEDENCE, true);
            $first = false;
        }
        $result .= $extraRight === "\n" ? $this->nl : $extraRight;
    }
    return $result;
}

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal