Mercurial > hg > isophonics-drupal-site
comparison vendor/nikic/php-parser/lib/PhpParser/PrettyPrinterAbstract.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; | |
6 use PhpParser\Node\Stmt; | |
7 | |
8 abstract class PrettyPrinterAbstract | |
9 { | |
10 protected $precedenceMap = array( | |
11 // [precedence, associativity] where for the latter -1 is %left, 0 is %nonassoc and 1 is %right | |
12 'Expr_BinaryOp_Pow' => array( 0, 1), | |
13 'Expr_BitwiseNot' => array( 10, 1), | |
14 'Expr_PreInc' => array( 10, 1), | |
15 'Expr_PreDec' => array( 10, 1), | |
16 'Expr_PostInc' => array( 10, -1), | |
17 'Expr_PostDec' => array( 10, -1), | |
18 'Expr_UnaryPlus' => array( 10, 1), | |
19 'Expr_UnaryMinus' => array( 10, 1), | |
20 'Expr_Cast_Int' => array( 10, 1), | |
21 'Expr_Cast_Double' => array( 10, 1), | |
22 'Expr_Cast_String' => array( 10, 1), | |
23 'Expr_Cast_Array' => array( 10, 1), | |
24 'Expr_Cast_Object' => array( 10, 1), | |
25 'Expr_Cast_Bool' => array( 10, 1), | |
26 'Expr_Cast_Unset' => array( 10, 1), | |
27 'Expr_ErrorSuppress' => array( 10, 1), | |
28 'Expr_Instanceof' => array( 20, 0), | |
29 'Expr_BooleanNot' => array( 30, 1), | |
30 'Expr_BinaryOp_Mul' => array( 40, -1), | |
31 'Expr_BinaryOp_Div' => array( 40, -1), | |
32 'Expr_BinaryOp_Mod' => array( 40, -1), | |
33 'Expr_BinaryOp_Plus' => array( 50, -1), | |
34 'Expr_BinaryOp_Minus' => array( 50, -1), | |
35 'Expr_BinaryOp_Concat' => array( 50, -1), | |
36 'Expr_BinaryOp_ShiftLeft' => array( 60, -1), | |
37 'Expr_BinaryOp_ShiftRight' => array( 60, -1), | |
38 'Expr_BinaryOp_Smaller' => array( 70, 0), | |
39 'Expr_BinaryOp_SmallerOrEqual' => array( 70, 0), | |
40 'Expr_BinaryOp_Greater' => array( 70, 0), | |
41 'Expr_BinaryOp_GreaterOrEqual' => array( 70, 0), | |
42 'Expr_BinaryOp_Equal' => array( 80, 0), | |
43 'Expr_BinaryOp_NotEqual' => array( 80, 0), | |
44 'Expr_BinaryOp_Identical' => array( 80, 0), | |
45 'Expr_BinaryOp_NotIdentical' => array( 80, 0), | |
46 'Expr_BinaryOp_Spaceship' => array( 80, 0), | |
47 'Expr_BinaryOp_BitwiseAnd' => array( 90, -1), | |
48 'Expr_BinaryOp_BitwiseXor' => array(100, -1), | |
49 'Expr_BinaryOp_BitwiseOr' => array(110, -1), | |
50 'Expr_BinaryOp_BooleanAnd' => array(120, -1), | |
51 'Expr_BinaryOp_BooleanOr' => array(130, -1), | |
52 'Expr_BinaryOp_Coalesce' => array(140, 1), | |
53 'Expr_Ternary' => array(150, -1), | |
54 // parser uses %left for assignments, but they really behave as %right | |
55 'Expr_Assign' => array(160, 1), | |
56 'Expr_AssignRef' => array(160, 1), | |
57 'Expr_AssignOp_Plus' => array(160, 1), | |
58 'Expr_AssignOp_Minus' => array(160, 1), | |
59 'Expr_AssignOp_Mul' => array(160, 1), | |
60 'Expr_AssignOp_Div' => array(160, 1), | |
61 'Expr_AssignOp_Concat' => array(160, 1), | |
62 'Expr_AssignOp_Mod' => array(160, 1), | |
63 'Expr_AssignOp_BitwiseAnd' => array(160, 1), | |
64 'Expr_AssignOp_BitwiseOr' => array(160, 1), | |
65 'Expr_AssignOp_BitwiseXor' => array(160, 1), | |
66 'Expr_AssignOp_ShiftLeft' => array(160, 1), | |
67 'Expr_AssignOp_ShiftRight' => array(160, 1), | |
68 'Expr_AssignOp_Pow' => array(160, 1), | |
69 'Expr_YieldFrom' => array(165, 1), | |
70 'Expr_Print' => array(168, 1), | |
71 'Expr_BinaryOp_LogicalAnd' => array(170, -1), | |
72 'Expr_BinaryOp_LogicalXor' => array(180, -1), | |
73 'Expr_BinaryOp_LogicalOr' => array(190, -1), | |
74 'Expr_Include' => array(200, -1), | |
75 ); | |
76 | |
77 protected $noIndentToken; | |
78 protected $docStringEndToken; | |
79 protected $canUseSemicolonNamespaces; | |
80 protected $options; | |
81 | |
82 /** | |
83 * Creates a pretty printer instance using the given options. | |
84 * | |
85 * Supported options: | |
86 * * bool $shortArraySyntax = false: Whether to use [] instead of array() as the default array | |
87 * syntax, if the node does not specify a format. | |
88 * | |
89 * @param array $options Dictionary of formatting options | |
90 */ | |
91 public function __construct(array $options = []) { | |
92 $this->noIndentToken = '_NO_INDENT_' . mt_rand(); | |
93 $this->docStringEndToken = '_DOC_STRING_END_' . mt_rand(); | |
94 | |
95 $defaultOptions = ['shortArraySyntax' => false]; | |
96 $this->options = $options + $defaultOptions; | |
97 } | |
98 | |
99 /** | |
100 * Pretty prints an array of statements. | |
101 * | |
102 * @param Node[] $stmts Array of statements | |
103 * | |
104 * @return string Pretty printed statements | |
105 */ | |
106 public function prettyPrint(array $stmts) { | |
107 $this->preprocessNodes($stmts); | |
108 | |
109 return ltrim($this->handleMagicTokens($this->pStmts($stmts, false))); | |
110 } | |
111 | |
112 /** | |
113 * Pretty prints an expression. | |
114 * | |
115 * @param Expr $node Expression node | |
116 * | |
117 * @return string Pretty printed node | |
118 */ | |
119 public function prettyPrintExpr(Expr $node) { | |
120 return $this->handleMagicTokens($this->p($node)); | |
121 } | |
122 | |
123 /** | |
124 * Pretty prints a file of statements (includes the opening <?php tag if it is required). | |
125 * | |
126 * @param Node[] $stmts Array of statements | |
127 * | |
128 * @return string Pretty printed statements | |
129 */ | |
130 public function prettyPrintFile(array $stmts) { | |
131 if (!$stmts) { | |
132 return "<?php\n\n"; | |
133 } | |
134 | |
135 $p = "<?php\n\n" . $this->prettyPrint($stmts); | |
136 | |
137 if ($stmts[0] instanceof Stmt\InlineHTML) { | |
138 $p = preg_replace('/^<\?php\s+\?>\n?/', '', $p); | |
139 } | |
140 if ($stmts[count($stmts) - 1] instanceof Stmt\InlineHTML) { | |
141 $p = preg_replace('/<\?php$/', '', rtrim($p)); | |
142 } | |
143 | |
144 return $p; | |
145 } | |
146 | |
147 /** | |
148 * Preprocesses the top-level nodes to initialize pretty printer state. | |
149 * | |
150 * @param Node[] $nodes Array of nodes | |
151 */ | |
152 protected function preprocessNodes(array $nodes) { | |
153 /* We can use semicolon-namespaces unless there is a global namespace declaration */ | |
154 $this->canUseSemicolonNamespaces = true; | |
155 foreach ($nodes as $node) { | |
156 if ($node instanceof Stmt\Namespace_ && null === $node->name) { | |
157 $this->canUseSemicolonNamespaces = false; | |
158 } | |
159 } | |
160 } | |
161 | |
162 protected function handleMagicTokens($str) { | |
163 // Drop no-indent tokens | |
164 $str = str_replace($this->noIndentToken, '', $str); | |
165 | |
166 // Replace doc-string-end tokens with nothing or a newline | |
167 $str = str_replace($this->docStringEndToken . ";\n", ";\n", $str); | |
168 $str = str_replace($this->docStringEndToken, "\n", $str); | |
169 | |
170 return $str; | |
171 } | |
172 | |
173 /** | |
174 * Pretty prints an array of nodes (statements) and indents them optionally. | |
175 * | |
176 * @param Node[] $nodes Array of nodes | |
177 * @param bool $indent Whether to indent the printed nodes | |
178 * | |
179 * @return string Pretty printed statements | |
180 */ | |
181 protected function pStmts(array $nodes, $indent = true) { | |
182 $result = ''; | |
183 foreach ($nodes as $node) { | |
184 $comments = $node->getAttribute('comments', array()); | |
185 if ($comments) { | |
186 $result .= "\n" . $this->pComments($comments); | |
187 if ($node instanceof Stmt\Nop) { | |
188 continue; | |
189 } | |
190 } | |
191 | |
192 $result .= "\n" . $this->p($node) . ($node instanceof Expr ? ';' : ''); | |
193 } | |
194 | |
195 if ($indent) { | |
196 return preg_replace('~\n(?!$|' . $this->noIndentToken . ')~', "\n ", $result); | |
197 } else { | |
198 return $result; | |
199 } | |
200 } | |
201 | |
202 /** | |
203 * Pretty prints a node. | |
204 * | |
205 * @param Node $node Node to be pretty printed | |
206 * | |
207 * @return string Pretty printed node | |
208 */ | |
209 protected function p(Node $node) { | |
210 return $this->{'p' . $node->getType()}($node); | |
211 } | |
212 | |
213 protected function pInfixOp($type, Node $leftNode, $operatorString, Node $rightNode) { | |
214 list($precedence, $associativity) = $this->precedenceMap[$type]; | |
215 | |
216 return $this->pPrec($leftNode, $precedence, $associativity, -1) | |
217 . $operatorString | |
218 . $this->pPrec($rightNode, $precedence, $associativity, 1); | |
219 } | |
220 | |
221 protected function pPrefixOp($type, $operatorString, Node $node) { | |
222 list($precedence, $associativity) = $this->precedenceMap[$type]; | |
223 return $operatorString . $this->pPrec($node, $precedence, $associativity, 1); | |
224 } | |
225 | |
226 protected function pPostfixOp($type, Node $node, $operatorString) { | |
227 list($precedence, $associativity) = $this->precedenceMap[$type]; | |
228 return $this->pPrec($node, $precedence, $associativity, -1) . $operatorString; | |
229 } | |
230 | |
231 /** | |
232 * Prints an expression node with the least amount of parentheses necessary to preserve the meaning. | |
233 * | |
234 * @param Node $node Node to pretty print | |
235 * @param int $parentPrecedence Precedence of the parent operator | |
236 * @param int $parentAssociativity Associativity of parent operator | |
237 * (-1 is left, 0 is nonassoc, 1 is right) | |
238 * @param int $childPosition Position of the node relative to the operator | |
239 * (-1 is left, 1 is right) | |
240 * | |
241 * @return string The pretty printed node | |
242 */ | |
243 protected function pPrec(Node $node, $parentPrecedence, $parentAssociativity, $childPosition) { | |
244 $type = $node->getType(); | |
245 if (isset($this->precedenceMap[$type])) { | |
246 $childPrecedence = $this->precedenceMap[$type][0]; | |
247 if ($childPrecedence > $parentPrecedence | |
248 || ($parentPrecedence == $childPrecedence && $parentAssociativity != $childPosition) | |
249 ) { | |
250 return '(' . $this->p($node) . ')'; | |
251 } | |
252 } | |
253 | |
254 return $this->p($node); | |
255 } | |
256 | |
257 /** | |
258 * Pretty prints an array of nodes and implodes the printed values. | |
259 * | |
260 * @param Node[] $nodes Array of Nodes to be printed | |
261 * @param string $glue Character to implode with | |
262 * | |
263 * @return string Imploded pretty printed nodes | |
264 */ | |
265 protected function pImplode(array $nodes, $glue = '') { | |
266 $pNodes = array(); | |
267 foreach ($nodes as $node) { | |
268 if (null === $node) { | |
269 $pNodes[] = ''; | |
270 } else { | |
271 $pNodes[] = $this->p($node); | |
272 } | |
273 } | |
274 | |
275 return implode($glue, $pNodes); | |
276 } | |
277 | |
278 /** | |
279 * Pretty prints an array of nodes and implodes the printed values with commas. | |
280 * | |
281 * @param Node[] $nodes Array of Nodes to be printed | |
282 * | |
283 * @return string Comma separated pretty printed nodes | |
284 */ | |
285 protected function pCommaSeparated(array $nodes) { | |
286 return $this->pImplode($nodes, ', '); | |
287 } | |
288 | |
289 /** | |
290 * Pretty prints a comma-separated list of nodes in multiline style, including comments. | |
291 * | |
292 * The result includes a leading newline and one level of indentation (same as pStmts). | |
293 * | |
294 * @param Node[] $nodes Array of Nodes to be printed | |
295 * @param bool $trailingComma Whether to use a trailing comma | |
296 * | |
297 * @return string Comma separated pretty printed nodes in multiline style | |
298 */ | |
299 protected function pCommaSeparatedMultiline(array $nodes, $trailingComma) { | |
300 $result = ''; | |
301 $lastIdx = count($nodes) - 1; | |
302 foreach ($nodes as $idx => $node) { | |
303 if ($node !== null) { | |
304 $comments = $node->getAttribute('comments', array()); | |
305 if ($comments) { | |
306 $result .= "\n" . $this->pComments($comments); | |
307 } | |
308 | |
309 $result .= "\n" . $this->p($node); | |
310 } else { | |
311 $result .= "\n"; | |
312 } | |
313 if ($trailingComma || $idx !== $lastIdx) { | |
314 $result .= ','; | |
315 } | |
316 } | |
317 | |
318 return preg_replace('~\n(?!$|' . $this->noIndentToken . ')~', "\n ", $result); | |
319 } | |
320 | |
321 /** | |
322 * Signals the pretty printer that a string shall not be indented. | |
323 * | |
324 * @param string $string Not to be indented string | |
325 * | |
326 * @return string String marked with $this->noIndentToken's. | |
327 */ | |
328 protected function pNoIndent($string) { | |
329 return str_replace("\n", "\n" . $this->noIndentToken, $string); | |
330 } | |
331 | |
332 /** | |
333 * Prints reformatted text of the passed comments. | |
334 * | |
335 * @param Comment[] $comments List of comments | |
336 * | |
337 * @return string Reformatted text of comments | |
338 */ | |
339 protected function pComments(array $comments) { | |
340 $formattedComments = []; | |
341 | |
342 foreach ($comments as $comment) { | |
343 $formattedComments[] = $comment->getReformattedText(); | |
344 } | |
345 | |
346 return implode("\n", $formattedComments); | |
347 } | |
348 } |