PluginProbe
WPIDE – File Manager & Code Editor / 3.5.9
WPIDE – File Manager & Code Editor v3.5.9
3.5.9 3.5.8 3.5.7 2.0.14 2.0.15 2.0.16 2.0.2 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1 2.2 2.3 2.3.1 2.3.2 2.4.0 2.5 2.6 3.0 3.1 3.2 3.3 All 55 releases
wpide / vendor / nikic / php-parser / lib / PhpParser / NodeTraverser.php

NodeTraverser.php in WPIDE – File Manager & Code Editor 3.5.9, at vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php

292 lines 10.3 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 class NodeTraverser implements NodeTraverserInterface
6 {
7 /**
8 * If NodeVisitor::enterNode() returns DONT_TRAVERSE_CHILDREN, child nodes
9 * of the current node will not be traversed for any visitors.
10 *
11 * For subsequent visitors enterNode() will still be called on the current
12 * node and leaveNode() will also be invoked for the current node.
13 */
14 const DONT_TRAVERSE_CHILDREN = 1;
15
16 /**
17 * If NodeVisitor::enterNode() or NodeVisitor::leaveNode() returns
18 * STOP_TRAVERSAL, traversal is aborted.
19 *
20 * The afterTraverse() method will still be invoked.
21 */
22 const STOP_TRAVERSAL = 2;
23
24 /**
25 * If NodeVisitor::leaveNode() returns REMOVE_NODE for a node that occurs
26 * in an array, it will be removed from the array.
27 *
28 * For subsequent visitors leaveNode() will still be invoked for the
29 * removed node.
30 */
31 const REMOVE_NODE = 3;
32
33 /**
34 * If NodeVisitor::enterNode() returns DONT_TRAVERSE_CURRENT_AND_CHILDREN, child nodes
35 * of the current node will not be traversed for any visitors.
36 *
37 * For subsequent visitors enterNode() will not be called as well.
38 * leaveNode() will be invoked for visitors that has enterNode() method invoked.
39 */
40 const DONT_TRAVERSE_CURRENT_AND_CHILDREN = 4;
41
42 /** @var NodeVisitor[] Visitors */
43 protected $visitors = [];
44
45 /** @var bool Whether traversal should be stopped */
46 protected $stopTraversal;
47
48 public function __construct() {
49 // for BC
50 }
51
52 /**
53 * Adds a visitor.
54 *
55 * @param NodeVisitor $visitor Visitor to add
56 */
57 public function addVisitor(NodeVisitor $visitor) {
58 $this->visitors[] = $visitor;
59 }
60
61 /**
62 * Removes an added visitor.
63 *
64 * @param NodeVisitor $visitor
65 */
66 public function removeVisitor(NodeVisitor $visitor) {
67 foreach ($this->visitors as $index => $storedVisitor) {
68 if ($storedVisitor === $visitor) {
69 unset($this->visitors[$index]);
70 break;
71 }
72 }
73 }
74
75 /**
76 * Traverses an array of nodes using the registered visitors.
77 *
78 * @param Node[] $nodes Array of nodes
79 *
80 * @return Node[] Traversed array of nodes
81 */
82 public function traverse(array $nodes) : array {
83 $this->stopTraversal = false;
84
85 foreach ($this->visitors as $visitor) {
86 if (null !== $return = $visitor->beforeTraverse($nodes)) {
87 $nodes = $return;
88 }
89 }
90
91 $nodes = $this->traverseArray($nodes);
92
93 foreach ($this->visitors as $visitor) {
94 if (null !== $return = $visitor->afterTraverse($nodes)) {
95 $nodes = $return;
96 }
97 }
98
99 return $nodes;
100 }
101
102 /**
103 * Recursively traverse a node.
104 *
105 * @param Node $node Node to traverse.
106 *
107 * @return Node Result of traversal (may be original node or new one)
108 */
109 protected function traverseNode(Node $node) : Node {
110 foreach ($node->getSubNodeNames() as $name) {
111 $subNode =& $node->$name;
112
113 if (\is_array($subNode)) {
114 $subNode = $this->traverseArray($subNode);
115 if ($this->stopTraversal) {
116 break;
117 }
118 } elseif ($subNode instanceof Node) {
119 $traverseChildren = true;
120 $breakVisitorIndex = null;
121
122 foreach ($this->visitors as $visitorIndex => $visitor) {
123 $return = $visitor->enterNode($subNode);
124 if (null !== $return) {
125 if ($return instanceof Node) {
126 $this->ensureReplacementReasonable($subNode, $return);
127 $subNode = $return;
128 } elseif (self::DONT_TRAVERSE_CHILDREN === $return) {
129 $traverseChildren = false;
130 } elseif (self::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) {
131 $traverseChildren = false;
132 $breakVisitorIndex = $visitorIndex;
133 break;
134 } elseif (self::STOP_TRAVERSAL === $return) {
135 $this->stopTraversal = true;
136 break 2;
137 } else {
138 throw new \LogicException(
139 'enterNode() returned invalid value of type ' . gettype($return)
140 );
141 }
142 }
143 }
144
145 if ($traverseChildren) {
146 $subNode = $this->traverseNode($subNode);
147 if ($this->stopTraversal) {
148 break;
149 }
150 }
151
152 foreach ($this->visitors as $visitorIndex => $visitor) {
153 $return = $visitor->leaveNode($subNode);
154
155 if (null !== $return) {
156 if ($return instanceof Node) {
157 $this->ensureReplacementReasonable($subNode, $return);
158 $subNode = $return;
159 } elseif (self::STOP_TRAVERSAL === $return) {
160 $this->stopTraversal = true;
161 break 2;
162 } elseif (\is_array($return)) {
163 throw new \LogicException(
164 'leaveNode() may only return an array ' .
165 'if the parent structure is an array'
166 );
167 } else {
168 throw new \LogicException(
169 'leaveNode() returned invalid value of type ' . gettype($return)
170 );
171 }
172 }
173
174 if ($breakVisitorIndex === $visitorIndex) {
175 break;
176 }
177 }
178 }
179 }
180
181 return $node;
182 }
183
184 /**
185 * Recursively traverse array (usually of nodes).
186 *
187 * @param array $nodes Array to traverse
188 *
189 * @return array Result of traversal (may be original array or changed one)
190 */
191 protected function traverseArray(array $nodes) : array {
192 $doNodes = [];
193
194 foreach ($nodes as $i => &$node) {
195 if ($node instanceof Node) {
196 $traverseChildren = true;
197 $breakVisitorIndex = null;
198
199 foreach ($this->visitors as $visitorIndex => $visitor) {
200 $return = $visitor->enterNode($node);
201 if (null !== $return) {
202 if ($return instanceof Node) {
203 $this->ensureReplacementReasonable($node, $return);
204 $node = $return;
205 } elseif (self::DONT_TRAVERSE_CHILDREN === $return) {
206 $traverseChildren = false;
207 } elseif (self::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) {
208 $traverseChildren = false;
209 $breakVisitorIndex = $visitorIndex;
210 break;
211 } elseif (self::STOP_TRAVERSAL === $return) {
212 $this->stopTraversal = true;
213 break 2;
214 } else {
215 throw new \LogicException(
216 'enterNode() returned invalid value of type ' . gettype($return)
217 );
218 }
219 }
220 }
221
222 if ($traverseChildren) {
223 $node = $this->traverseNode($node);
224 if ($this->stopTraversal) {
225 break;
226 }
227 }
228
229 foreach ($this->visitors as $visitorIndex => $visitor) {
230 $return = $visitor->leaveNode($node);
231
232 if (null !== $return) {
233 if ($return instanceof Node) {
234 $this->ensureReplacementReasonable($node, $return);
235 $node = $return;
236 } elseif (\is_array($return)) {
237 $doNodes[] = [$i, $return];
238 break;
239 } elseif (self::REMOVE_NODE === $return) {
240 $doNodes[] = [$i, []];
241 break;
242 } elseif (self::STOP_TRAVERSAL === $return) {
243 $this->stopTraversal = true;
244 break 2;
245 } elseif (false === $return) {
246 throw new \LogicException(
247 'bool(false) return from leaveNode() no longer supported. ' .
248 'Return NodeTraverser::REMOVE_NODE instead'
249 );
250 } else {
251 throw new \LogicException(
252 'leaveNode() returned invalid value of type ' . gettype($return)
253 );
254 }
255 }
256
257 if ($breakVisitorIndex === $visitorIndex) {
258 break;
259 }
260 }
261 } elseif (\is_array($node)) {
262 throw new \LogicException('Invalid node structure: Contains nested arrays');
263 }
264 }
265
266 if (!empty($doNodes)) {
267 while (list($i, $replace) = array_pop($doNodes)) {
268 array_splice($nodes, $i, 1, $replace);
269 }
270 }
271
272 return $nodes;
273 }
274
275 private function ensureReplacementReasonable($old, $new) {
276 if ($old instanceof Node\Stmt && $new instanceof Node\Expr) {
277 throw new \LogicException(
278 "Trying to replace statement ({$old->getType()}) " .
279 "with expression ({$new->getType()}). Are you missing a " .
280 "Stmt_Expression wrapper?"
281 );
282 }
283
284 if ($old instanceof Node\Expr && $new instanceof Node\Stmt) {
285 throw new \LogicException(
286 "Trying to replace expression ({$old->getType()}) " .
287 "with statement ({$new->getType()})"
288 );
289 }
290 }
291 }
292