comparison vendor/nikic/php-parser/lib/PhpParser/NodeDumper.php @ 0:4c8ae668cc8c

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