PluginProbe
Code Engine – PHP Snippets, AI Functions & Automation for WordPress / 0.3.0
Code Engine – PHP Snippets, AI Functions & Automation for WordPress v0.3.0
0.5.7 0.5.6 0.5.5 0.5.4 0.5.3 0.5.2 0.5.1 0.5.0 0.4.9 0.4.8 0.4.7 0.4.6 trunk 0.0.1 0.0.2 0.2.8 0.2.9 0.3.0 0.3.1 0.3.2 0.3.3 0.3.4 0.3.5 0.3.6 0.3.7 All 33 releases
code-engine / vendor / nikic / php-parser / lib / PhpParser / NodeDumper.php

NodeDumper.php in Code Engine – PHP Snippets, AI Functions & Automation for WordPress 0.3.0, at vendor/nikic/php-parser/lib/PhpParser/NodeDumper.php

291 lines 10.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php declare(strict_types=1);
2
3 namespace PhpParser;
4
5 use PhpParser\Node\Expr\Array_;
6 use PhpParser\Node\Expr\Include_;
7 use PhpParser\Node\Expr\List_;
8 use PhpParser\Node\Scalar\Int_;
9 use PhpParser\Node\Scalar\InterpolatedString;
10 use PhpParser\Node\Scalar\String_;
11 use PhpParser\Node\Stmt\GroupUse;
12 use PhpParser\Node\Stmt\Use_;
13 use PhpParser\Node\UseItem;
14
15 class NodeDumper {
16 private bool $dumpComments;
17 private bool $dumpPositions;
18 private bool $dumpOtherAttributes;
19 private ?string $code;
20 private string $res;
21 private string $nl;
22
23 private const IGNORE_ATTRIBUTES = [
24 'comments' => true,
25 'startLine' => true,
26 'endLine' => true,
27 'startFilePos' => true,
28 'endFilePos' => true,
29 'startTokenPos' => true,
30 'endTokenPos' => true,
31 ];
32
33 /**
34 * Constructs a NodeDumper.
35 *
36 * Supported options:
37 * * bool dumpComments: Whether comments should be dumped.
38 * * bool dumpPositions: Whether line/offset information should be dumped. To dump offset
39 * information, the code needs to be passed to dump().
40 * * bool dumpOtherAttributes: Whether non-comment, non-position attributes should be dumped.
41 *
42 * @param array $options Options (see description)
43 */
44 public function __construct(array $options = []) {
45 $this->dumpComments = !empty($options['dumpComments']);
46 $this->dumpPositions = !empty($options['dumpPositions']);
47 $this->dumpOtherAttributes = !empty($options['dumpOtherAttributes']);
48 }
49
50 /**
51 * Dumps a node or array.
52 *
53 * @param array|Node $node Node or array to dump
54 * @param string|null $code Code corresponding to dumped AST. This only needs to be passed if
55 * the dumpPositions option is enabled and the dumping of node offsets
56 * is desired.
57 *
58 * @return string Dumped value
59 */
60 public function dump($node, ?string $code = null): string {
61 $this->code = $code;
62 $this->res = '';
63 $this->nl = "\n";
64 $this->dumpRecursive($node, false);
65 return $this->res;
66 }
67
68 /** @param mixed $node */
69 protected function dumpRecursive($node, bool $indent = true): void {
70 if ($indent) {
71 $this->nl .= " ";
72 }
73 if ($node instanceof Node) {
74 $this->res .= $node->getType();
75 if ($this->dumpPositions && null !== $p = $this->dumpPosition($node)) {
76 $this->res .= $p;
77 }
78 $this->res .= '(';
79
80 foreach ($node->getSubNodeNames() as $key) {
81 $this->res .= "$this->nl " . $key . ': ';
82
83 $value = $node->$key;
84 if (\is_int($value)) {
85 if ('flags' === $key || 'newModifier' === $key) {
86 $this->res .= $this->dumpFlags($value);
87 continue;
88 }
89 if ('type' === $key && $node instanceof Include_) {
90 $this->res .= $this->dumpIncludeType($value);
91 continue;
92 }
93 if ('type' === $key
94 && ($node instanceof Use_ || $node instanceof UseItem || $node instanceof GroupUse)) {
95 $this->res .= $this->dumpUseType($value);
96 continue;
97 }
98 }
99 $this->dumpRecursive($value);
100 }
101
102 if ($this->dumpComments && $comments = $node->getComments()) {
103 $this->res .= "$this->nl comments: ";
104 $this->dumpRecursive($comments);
105 }
106
107 if ($this->dumpOtherAttributes) {
108 foreach ($node->getAttributes() as $key => $value) {
109 if (isset(self::IGNORE_ATTRIBUTES[$key])) {
110 continue;
111 }
112
113 $this->res .= "$this->nl $key: ";
114 if (\is_int($value)) {
115 if ('kind' === $key) {
116 if ($node instanceof Int_) {
117 $this->res .= $this->dumpIntKind($value);
118 continue;
119 }
120 if ($node instanceof String_ || $node instanceof InterpolatedString) {
121 $this->res .= $this->dumpStringKind($value);
122 continue;
123 }
124 if ($node instanceof Array_) {
125 $this->res .= $this->dumpArrayKind($value);
126 continue;
127 }
128 if ($node instanceof List_) {
129 $this->res .= $this->dumpListKind($value);
130 continue;
131 }
132 }
133 }
134 $this->dumpRecursive($value);
135 }
136 }
137 $this->res .= "$this->nl)";
138 } elseif (\is_array($node)) {
139 $this->res .= 'array(';
140 foreach ($node as $key => $value) {
141 $this->res .= "$this->nl " . $key . ': ';
142 $this->dumpRecursive($value);
143 }
144 $this->res .= "$this->nl)";
145 } elseif ($node instanceof Comment) {
146 $this->res .= \str_replace("\n", $this->nl, $node->getReformattedText());
147 } elseif (\is_string($node)) {
148 $this->res .= \str_replace("\n", $this->nl, (string)$node);
149 } elseif (\is_int($node) || \is_float($node)) {
150 $this->res .= $node;
151 } elseif (null === $node) {
152 $this->res .= 'null';
153 } elseif (false === $node) {
154 $this->res .= 'false';
155 } elseif (true === $node) {
156 $this->res .= 'true';
157 } else {
158 throw new \InvalidArgumentException('Can only dump nodes and arrays.');
159 }
160 if ($indent) {
161 $this->nl = \substr($this->nl, 0, -4);
162 }
163 }
164
165 protected function dumpFlags(int $flags): string {
166 $strs = [];
167 if ($flags & Modifiers::PUBLIC) {
168 $strs[] = 'PUBLIC';
169 }
170 if ($flags & Modifiers::PROTECTED) {
171 $strs[] = 'PROTECTED';
172 }
173 if ($flags & Modifiers::PRIVATE) {
174 $strs[] = 'PRIVATE';
175 }
176 if ($flags & Modifiers::ABSTRACT) {
177 $strs[] = 'ABSTRACT';
178 }
179 if ($flags & Modifiers::STATIC) {
180 $strs[] = 'STATIC';
181 }
182 if ($flags & Modifiers::FINAL) {
183 $strs[] = 'FINAL';
184 }
185 if ($flags & Modifiers::READONLY) {
186 $strs[] = 'READONLY';
187 }
188
189 if ($strs) {
190 return implode(' | ', $strs) . ' (' . $flags . ')';
191 } else {
192 return (string) $flags;
193 }
194 }
195
196 /** @param array<int, string> $map */
197 private function dumpEnum(int $value, array $map): string {
198 if (!isset($map[$value])) {
199 return (string) $value;
200 }
201 return $map[$value] . ' (' . $value . ')';
202 }
203
204 private function dumpIncludeType(int $type): string {
205 return $this->dumpEnum($type, [
206 Include_::TYPE_INCLUDE => 'TYPE_INCLUDE',
207 Include_::TYPE_INCLUDE_ONCE => 'TYPE_INCLUDE_ONCE',
208 Include_::TYPE_REQUIRE => 'TYPE_REQUIRE',
209 Include_::TYPE_REQUIRE_ONCE => 'TYPE_REQUIRE_ONCE',
210 ]);
211 }
212
213 private function dumpUseType(int $type): string {
214 return $this->dumpEnum($type, [
215 Use_::TYPE_UNKNOWN => 'TYPE_UNKNOWN',
216 Use_::TYPE_NORMAL => 'TYPE_NORMAL',
217 Use_::TYPE_FUNCTION => 'TYPE_FUNCTION',
218 Use_::TYPE_CONSTANT => 'TYPE_CONSTANT',
219 ]);
220 }
221
222 private function dumpIntKind(int $kind): string {
223 return $this->dumpEnum($kind, [
224 Int_::KIND_BIN => 'KIND_BIN',
225 Int_::KIND_OCT => 'KIND_OCT',
226 Int_::KIND_DEC => 'KIND_DEC',
227 Int_::KIND_HEX => 'KIND_HEX',
228 ]);
229 }
230
231 private function dumpStringKind(int $kind): string {
232 return $this->dumpEnum($kind, [
233 String_::KIND_SINGLE_QUOTED => 'KIND_SINGLE_QUOTED',
234 String_::KIND_DOUBLE_QUOTED => 'KIND_DOUBLE_QUOTED',
235 String_::KIND_HEREDOC => 'KIND_HEREDOC',
236 String_::KIND_NOWDOC => 'KIND_NOWDOC',
237 ]);
238 }
239
240 private function dumpArrayKind(int $kind): string {
241 return $this->dumpEnum($kind, [
242 Array_::KIND_LONG => 'KIND_LONG',
243 Array_::KIND_SHORT => 'KIND_SHORT',
244 ]);
245 }
246
247 private function dumpListKind(int $kind): string {
248 return $this->dumpEnum($kind, [
249 List_::KIND_LIST => 'KIND_LIST',
250 List_::KIND_ARRAY => 'KIND_ARRAY',
251 ]);
252 }
253
254 /**
255 * Dump node position, if possible.
256 *
257 * @param Node $node Node for which to dump position
258 *
259 * @return string|null Dump of position, or null if position information not available
260 */
261 protected function dumpPosition(Node $node): ?string {
262 if (!$node->hasAttribute('startLine') || !$node->hasAttribute('endLine')) {
263 return null;
264 }
265
266 $start = $node->getStartLine();
267 $end = $node->getEndLine();
268 if ($node->hasAttribute('startFilePos') && $node->hasAttribute('endFilePos')
269 && null !== $this->code
270 ) {
271 $start .= ':' . $this->toColumn($this->code, $node->getStartFilePos());
272 $end .= ':' . $this->toColumn($this->code, $node->getEndFilePos());
273 }
274 return "[$start - $end]";
275 }
276
277 // Copied from Error class
278 private function toColumn(string $code, int $pos): int {
279 if ($pos > strlen($code)) {
280 throw new \RuntimeException('Invalid position information');
281 }
282
283 $lineStartPos = strrpos($code, "\n", $pos - strlen($code));
284 if (false === $lineStartPos) {
285 $lineStartPos = -1;
286 }
287
288 return $pos - $lineStartPos;
289 }
290 }
291