annotate vendor/nikic/php-parser/lib/PhpParser/NodeDumper.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 5fb285c0d0e3
children
rev   line source
Chris@13 1 <?php declare(strict_types=1);
Chris@0 2
Chris@0 3 namespace PhpParser;
Chris@0 4
Chris@0 5 use PhpParser\Node\Expr\Include_;
Chris@0 6 use PhpParser\Node\Stmt\Class_;
Chris@0 7 use PhpParser\Node\Stmt\GroupUse;
Chris@0 8 use PhpParser\Node\Stmt\Use_;
Chris@0 9 use PhpParser\Node\Stmt\UseUse;
Chris@0 10
Chris@0 11 class NodeDumper
Chris@0 12 {
Chris@0 13 private $dumpComments;
Chris@0 14 private $dumpPositions;
Chris@0 15 private $code;
Chris@0 16
Chris@0 17 /**
Chris@0 18 * Constructs a NodeDumper.
Chris@0 19 *
Chris@0 20 * Supported options:
Chris@0 21 * * bool dumpComments: Whether comments should be dumped.
Chris@0 22 * * bool dumpPositions: Whether line/offset information should be dumped. To dump offset
Chris@0 23 * information, the code needs to be passed to dump().
Chris@0 24 *
Chris@0 25 * @param array $options Options (see description)
Chris@0 26 */
Chris@0 27 public function __construct(array $options = []) {
Chris@0 28 $this->dumpComments = !empty($options['dumpComments']);
Chris@0 29 $this->dumpPositions = !empty($options['dumpPositions']);
Chris@0 30 }
Chris@0 31
Chris@0 32 /**
Chris@0 33 * Dumps a node or array.
Chris@0 34 *
Chris@0 35 * @param array|Node $node Node or array to dump
Chris@0 36 * @param string|null $code Code corresponding to dumped AST. This only needs to be passed if
Chris@0 37 * the dumpPositions option is enabled and the dumping of node offsets
Chris@0 38 * is desired.
Chris@0 39 *
Chris@0 40 * @return string Dumped value
Chris@0 41 */
Chris@13 42 public function dump($node, string $code = null) : string {
Chris@0 43 $this->code = $code;
Chris@0 44 return $this->dumpRecursive($node);
Chris@0 45 }
Chris@0 46
Chris@0 47 protected function dumpRecursive($node) {
Chris@0 48 if ($node instanceof Node) {
Chris@0 49 $r = $node->getType();
Chris@0 50 if ($this->dumpPositions && null !== $p = $this->dumpPosition($node)) {
Chris@0 51 $r .= $p;
Chris@0 52 }
Chris@0 53 $r .= '(';
Chris@0 54
Chris@0 55 foreach ($node->getSubNodeNames() as $key) {
Chris@0 56 $r .= "\n " . $key . ': ';
Chris@0 57
Chris@0 58 $value = $node->$key;
Chris@0 59 if (null === $value) {
Chris@0 60 $r .= 'null';
Chris@0 61 } elseif (false === $value) {
Chris@0 62 $r .= 'false';
Chris@0 63 } elseif (true === $value) {
Chris@0 64 $r .= 'true';
Chris@0 65 } elseif (is_scalar($value)) {
Chris@0 66 if ('flags' === $key || 'newModifier' === $key) {
Chris@0 67 $r .= $this->dumpFlags($value);
Chris@13 68 } elseif ('type' === $key && $node instanceof Include_) {
Chris@0 69 $r .= $this->dumpIncludeType($value);
Chris@13 70 } elseif ('type' === $key
Chris@0 71 && ($node instanceof Use_ || $node instanceof UseUse || $node instanceof GroupUse)) {
Chris@0 72 $r .= $this->dumpUseType($value);
Chris@0 73 } else {
Chris@0 74 $r .= $value;
Chris@0 75 }
Chris@0 76 } else {
Chris@0 77 $r .= str_replace("\n", "\n ", $this->dumpRecursive($value));
Chris@0 78 }
Chris@0 79 }
Chris@0 80
Chris@13 81 if ($this->dumpComments && $comments = $node->getComments()) {
Chris@0 82 $r .= "\n comments: " . str_replace("\n", "\n ", $this->dumpRecursive($comments));
Chris@0 83 }
Chris@0 84 } elseif (is_array($node)) {
Chris@0 85 $r = 'array(';
Chris@0 86
Chris@0 87 foreach ($node as $key => $value) {
Chris@0 88 $r .= "\n " . $key . ': ';
Chris@0 89
Chris@0 90 if (null === $value) {
Chris@0 91 $r .= 'null';
Chris@0 92 } elseif (false === $value) {
Chris@0 93 $r .= 'false';
Chris@0 94 } elseif (true === $value) {
Chris@0 95 $r .= 'true';
Chris@0 96 } elseif (is_scalar($value)) {
Chris@0 97 $r .= $value;
Chris@0 98 } else {
Chris@0 99 $r .= str_replace("\n", "\n ", $this->dumpRecursive($value));
Chris@0 100 }
Chris@0 101 }
Chris@0 102 } elseif ($node instanceof Comment) {
Chris@0 103 return $node->getReformattedText();
Chris@0 104 } else {
Chris@0 105 throw new \InvalidArgumentException('Can only dump nodes and arrays.');
Chris@0 106 }
Chris@0 107
Chris@0 108 return $r . "\n)";
Chris@0 109 }
Chris@0 110
Chris@0 111 protected function dumpFlags($flags) {
Chris@0 112 $strs = [];
Chris@0 113 if ($flags & Class_::MODIFIER_PUBLIC) {
Chris@0 114 $strs[] = 'MODIFIER_PUBLIC';
Chris@0 115 }
Chris@0 116 if ($flags & Class_::MODIFIER_PROTECTED) {
Chris@0 117 $strs[] = 'MODIFIER_PROTECTED';
Chris@0 118 }
Chris@0 119 if ($flags & Class_::MODIFIER_PRIVATE) {
Chris@0 120 $strs[] = 'MODIFIER_PRIVATE';
Chris@0 121 }
Chris@0 122 if ($flags & Class_::MODIFIER_ABSTRACT) {
Chris@0 123 $strs[] = 'MODIFIER_ABSTRACT';
Chris@0 124 }
Chris@0 125 if ($flags & Class_::MODIFIER_STATIC) {
Chris@0 126 $strs[] = 'MODIFIER_STATIC';
Chris@0 127 }
Chris@0 128 if ($flags & Class_::MODIFIER_FINAL) {
Chris@0 129 $strs[] = 'MODIFIER_FINAL';
Chris@0 130 }
Chris@0 131
Chris@0 132 if ($strs) {
Chris@0 133 return implode(' | ', $strs) . ' (' . $flags . ')';
Chris@0 134 } else {
Chris@0 135 return $flags;
Chris@0 136 }
Chris@0 137 }
Chris@0 138
Chris@0 139 protected function dumpIncludeType($type) {
Chris@0 140 $map = [
Chris@0 141 Include_::TYPE_INCLUDE => 'TYPE_INCLUDE',
Chris@0 142 Include_::TYPE_INCLUDE_ONCE => 'TYPE_INCLUDE_ONCE',
Chris@0 143 Include_::TYPE_REQUIRE => 'TYPE_REQUIRE',
Chris@13 144 Include_::TYPE_REQUIRE_ONCE => 'TYPE_REQUIRE_ONCE',
Chris@0 145 ];
Chris@0 146
Chris@0 147 if (!isset($map[$type])) {
Chris@0 148 return $type;
Chris@0 149 }
Chris@0 150 return $map[$type] . ' (' . $type . ')';
Chris@0 151 }
Chris@0 152
Chris@0 153 protected function dumpUseType($type) {
Chris@0 154 $map = [
Chris@0 155 Use_::TYPE_UNKNOWN => 'TYPE_UNKNOWN',
Chris@0 156 Use_::TYPE_NORMAL => 'TYPE_NORMAL',
Chris@0 157 Use_::TYPE_FUNCTION => 'TYPE_FUNCTION',
Chris@0 158 Use_::TYPE_CONSTANT => 'TYPE_CONSTANT',
Chris@0 159 ];
Chris@0 160
Chris@0 161 if (!isset($map[$type])) {
Chris@0 162 return $type;
Chris@0 163 }
Chris@0 164 return $map[$type] . ' (' . $type . ')';
Chris@0 165 }
Chris@0 166
Chris@13 167 /**
Chris@13 168 * Dump node position, if possible.
Chris@13 169 *
Chris@13 170 * @param Node $node Node for which to dump position
Chris@13 171 *
Chris@13 172 * @return string|null Dump of position, or null if position information not available
Chris@13 173 */
Chris@0 174 protected function dumpPosition(Node $node) {
Chris@0 175 if (!$node->hasAttribute('startLine') || !$node->hasAttribute('endLine')) {
Chris@0 176 return null;
Chris@0 177 }
Chris@0 178
Chris@13 179 $start = $node->getStartLine();
Chris@13 180 $end = $node->getEndLine();
Chris@0 181 if ($node->hasAttribute('startFilePos') && $node->hasAttribute('endFilePos')
Chris@0 182 && null !== $this->code
Chris@0 183 ) {
Chris@13 184 $start .= ':' . $this->toColumn($this->code, $node->getStartFilePos());
Chris@13 185 $end .= ':' . $this->toColumn($this->code, $node->getEndFilePos());
Chris@0 186 }
Chris@0 187 return "[$start - $end]";
Chris@0 188 }
Chris@0 189
Chris@0 190 // Copied from Error class
Chris@0 191 private function toColumn($code, $pos) {
Chris@0 192 if ($pos > strlen($code)) {
Chris@0 193 throw new \RuntimeException('Invalid position information');
Chris@0 194 }
Chris@0 195
Chris@0 196 $lineStartPos = strrpos($code, "\n", $pos - strlen($code));
Chris@0 197 if (false === $lineStartPos) {
Chris@0 198 $lineStartPos = -1;
Chris@0 199 }
Chris@0 200
Chris@0 201 return $pos - $lineStartPos;
Chris@0 202 }
Chris@0 203 }