OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 part of tree; | |
6 | |
7 /** | |
8 * Pretty-prints Node tree in XML-like format. | |
9 * | |
10 * TODO(smok): Add main() to run from command-line to print out tree for given | |
11 * .dart file. | |
12 */ | |
13 class PrettyPrinter extends Indentation implements Visitor { | |
14 | |
15 StringBuffer sb; | |
16 Link<String> tagStack; | |
17 | |
18 PrettyPrinter() : | |
19 sb = new StringBuffer(), | |
20 tagStack = const Link<String>(); | |
21 | |
22 void pushTag(String tag) { | |
23 tagStack = tagStack.prepend(tag); | |
24 indentMore(); | |
25 } | |
26 | |
27 String popTag() { | |
28 assert(!tagStack.isEmpty); | |
29 String tag = tagStack.head; | |
30 tagStack = tagStack.tail; | |
31 indentLess(); | |
32 return tag; | |
33 } | |
34 | |
35 /** | |
36 * Adds given string to result string. | |
37 */ | |
38 void add(String string) { | |
39 sb.write(string); | |
40 } | |
41 | |
42 void addBeginAndEndTokensToParams(Node node, Map params) { | |
43 params['getBeginToken'] = tokenToStringOrNull(node.getBeginToken()); | |
44 params['getEndToken'] = tokenToStringOrNull(node.getEndToken()); | |
45 } | |
46 | |
47 /** | |
48 * Adds given node type to result string. | |
49 * The method "opens" the node, meaning that all output after calling | |
50 * this method and before calling closeNode() will represent contents | |
51 * of given node. | |
52 */ | |
53 void openNode(Node node, String type, [Map params]) { | |
54 if (params == null) params = new Map(); | |
55 addCurrentIndent(); | |
56 sb.write("<"); | |
57 addBeginAndEndTokensToParams(node, params); | |
58 addTypeWithParams(type, params); | |
59 sb.write(">\n"); | |
60 pushTag(type); | |
61 } | |
62 | |
63 /** | |
64 * Adds given node to result string. | |
65 */ | |
66 void openAndCloseNode(Node node, String type, [Map params]) { | |
67 if (params == null) params = new Map(); | |
68 addCurrentIndent(); | |
69 sb.write("<"); | |
70 addBeginAndEndTokensToParams(node, params); | |
71 addTypeWithParams(type, params); | |
72 sb.write("/>\n"); | |
73 } | |
74 | |
75 /** | |
76 * Closes current node type. | |
77 */ | |
78 void closeNode() { | |
79 String tag = popTag(); | |
80 addCurrentIndent(); | |
81 sb.write("</"); | |
82 addTypeWithParams(tag); | |
83 sb.write(">\n"); | |
84 } | |
85 | |
86 void addTypeWithParams(String type, [Map params]) { | |
87 if (params == null) params = new Map(); | |
88 sb.write("${type}"); | |
89 params.forEach((k, v) { | |
90 String value; | |
91 if (v != null) { | |
92 var str = v; | |
93 if (v is Token) str = v.value; | |
94 value = str | |
95 .replaceAll("<", "<") | |
96 .replaceAll(">", ">") | |
97 .replaceAll('"', "'"); | |
98 } else { | |
99 value = "[null]"; | |
100 } | |
101 sb.write(' $k="$value"'); | |
102 }); | |
103 } | |
104 | |
105 void addCurrentIndent() { | |
106 sb.write(indentation); | |
107 } | |
108 | |
109 /** | |
110 * Pretty-prints given node tree into string. | |
111 */ | |
112 static String prettyPrint(Node node) { | |
113 var p = new PrettyPrinter(); | |
114 node.accept(p); | |
115 return p.sb.toString(); | |
116 } | |
117 | |
118 visitNodeWithChildren(Node node, String type) { | |
119 openNode(node, type); | |
120 node.visitChildren(this); | |
121 closeNode(); | |
122 } | |
123 | |
124 visitBlock(Block node) { | |
125 visitNodeWithChildren(node, "Block"); | |
126 } | |
127 | |
128 visitBreakStatement(BreakStatement node) { | |
129 visitNodeWithChildren(node, "BreakStatement"); | |
130 } | |
131 | |
132 visitCascade(Cascade node) { | |
133 visitNodeWithChildren(node, "Cascade"); | |
134 } | |
135 | |
136 visitCascadeReceiver(CascadeReceiver node) { | |
137 visitNodeWithChildren(node, "CascadeReceiver"); | |
138 } | |
139 | |
140 visitCaseMatch(CaseMatch node) { | |
141 visitNodeWithChildren(node, "CaseMatch"); | |
142 } | |
143 | |
144 visitCatchBlock(CatchBlock node) { | |
145 visitNodeWithChildren(node, "CatchBlock"); | |
146 } | |
147 | |
148 visitClassNode(ClassNode node) { | |
149 openNode(node, "ClassNode", { | |
150 "extendsKeyword" : tokenToStringOrNull(node.extendsKeyword) | |
151 }); | |
152 visitChildNode(node.name, "name"); | |
153 visitChildNode(node.superclass, "superclass"); | |
154 visitChildNode(node.interfaces, "interfaces"); | |
155 visitChildNode(node.typeParameters, "typeParameters"); | |
156 closeNode(); | |
157 } | |
158 | |
159 visitConditional(Conditional node) { | |
160 visitNodeWithChildren(node, "Conditional"); | |
161 } | |
162 | |
163 visitContinueStatement(ContinueStatement node) { | |
164 visitNodeWithChildren(node, "ContinueStatement"); | |
165 } | |
166 | |
167 visitDoWhile(DoWhile node) { | |
168 visitNodeWithChildren(node, "DoWhile"); | |
169 } | |
170 | |
171 visitEmptyStatement(EmptyStatement node) { | |
172 visitNodeWithChildren(node, "EmptyStatement"); | |
173 } | |
174 | |
175 visitExpressionStatement(ExpressionStatement node) { | |
176 visitNodeWithChildren(node, "ExpressionStatement"); | |
177 } | |
178 | |
179 visitFor(For node) { | |
180 visitNodeWithChildren(node, "For"); | |
181 } | |
182 | |
183 visitForIn(ForIn node) { | |
184 visitNodeWithChildren(node, "ForIn"); | |
185 } | |
186 | |
187 visitFunctionDeclaration(FunctionDeclaration node) { | |
188 visitNodeWithChildren(node, "FunctionDeclaration"); | |
189 } | |
190 | |
191 visitFunctionExpression(FunctionExpression node) { | |
192 openNode(node, "FunctionExpression", { | |
193 "getOrSet" : tokenToStringOrNull(node.getOrSet) | |
194 }); | |
195 visitChildNode(node.modifiers, "modifiers"); | |
196 visitChildNode(node.returnType, "returnType"); | |
197 visitChildNode(node.name, "name"); | |
198 visitChildNode(node.parameters, "parameters"); | |
199 visitChildNode(node.initializers, "initializers"); | |
200 visitChildNode(node.body, "body"); | |
201 closeNode(); | |
202 } | |
203 | |
204 visitIdentifier(Identifier node) { | |
205 openAndCloseNode(node, "Identifier", {"token" : node.token}); | |
206 } | |
207 | |
208 visitIf(If node) { | |
209 visitNodeWithChildren(node, "If"); | |
210 } | |
211 | |
212 visitLabel(Label node) { | |
213 visitNodeWithChildren(node, "Label"); | |
214 } | |
215 | |
216 visitLabeledStatement(LabeledStatement node) { | |
217 visitNodeWithChildren(node, "LabeledStatement"); | |
218 } | |
219 | |
220 // Custom. | |
221 printLiteral(Literal node, String type) { | |
222 openAndCloseNode(node, type, {"value" : node.value.toString()}); | |
223 } | |
224 | |
225 visitLiteralBool(LiteralBool node) { | |
226 printLiteral(node, "LiteralBool"); | |
227 } | |
228 | |
229 visitLiteralDouble(LiteralDouble node) { | |
230 printLiteral(node, "LiteralDouble"); | |
231 } | |
232 | |
233 visitLiteralInt(LiteralInt node) { | |
234 printLiteral(node, "LiteralInt"); | |
235 } | |
236 | |
237 /** Returns token string value or [:null:] if token is [:null:]. */ | |
238 tokenToStringOrNull(Token token) => token == null ? null : token.stringValue; | |
239 | |
240 visitLiteralList(LiteralList node) { | |
241 openNode(node, "LiteralList", { | |
242 "constKeyword" : tokenToStringOrNull(node.constKeyword) | |
243 }); | |
244 visitChildNode(node.typeArguments, "typeArguments"); | |
245 visitChildNode(node.elements, "elements"); | |
246 closeNode(); | |
247 } | |
248 | |
249 visitLiteralMap(LiteralMap node) { | |
250 visitNodeWithChildren(node, "LiteralMap"); | |
251 } | |
252 | |
253 visitLiteralMapEntry(LiteralMapEntry node) { | |
254 visitNodeWithChildren(node, "LiteralMapEntry"); | |
255 } | |
256 | |
257 visitLiteralNull(LiteralNull node) { | |
258 printLiteral(node, "LiteralNull"); | |
259 } | |
260 | |
261 visitLiteralString(LiteralString node) { | |
262 openAndCloseNode(node, "LiteralString", | |
263 {"value" : node.token}); | |
264 } | |
265 | |
266 visitMixinApplication(MixinApplication node) { | |
267 visitNodeWithChildren(node, "MixinApplication"); | |
268 } | |
269 | |
270 visitModifiers(Modifiers node) { | |
271 visitNodeWithChildren(node, "Modifiers"); | |
272 } | |
273 | |
274 visitNamedArgument(NamedArgument node) { | |
275 visitNodeWithChildren(node, "NamedArgument"); | |
276 } | |
277 | |
278 visitNamedMixinApplication(NamedMixinApplication node) { | |
279 visitNodeWithChildren(node, "NamedMixinApplication"); | |
280 } | |
281 | |
282 visitNewExpression(NewExpression node) { | |
283 visitNodeWithChildren(node, "NewExpression"); | |
284 } | |
285 | |
286 visitNodeList(NodeList node) { | |
287 var params = { "delimiter" : node.delimiter }; | |
288 if (node.isEmpty) { | |
289 openAndCloseNode(node, "NodeList", params); | |
290 } else { | |
291 openNode(node, "NodeList", params); | |
292 node.visitChildren(this); | |
293 closeNode(); | |
294 } | |
295 } | |
296 | |
297 visitOperator(Operator node) { | |
298 openAndCloseNode(node, "Operator", {"value" : node.token}); | |
299 } | |
300 | |
301 visitParenthesizedExpression(ParenthesizedExpression node) { | |
302 visitNodeWithChildren(node, "ParenthesizedExpression"); | |
303 } | |
304 | |
305 visitRedirectingFactoryBody(RedirectingFactoryBody node) { | |
306 openNode(node, "RedirectingFactoryBody"); | |
307 visitChildNode(node.constructorReference, "constructorReference"); | |
308 closeNode(); | |
309 } | |
310 | |
311 visitRethrow(Rethrow node) { | |
312 visitNodeWithChildren(node, "Rethrow"); | |
313 } | |
314 | |
315 visitReturn(Return node) { | |
316 openNode(node, "Return"); | |
317 visitChildNode(node.expression, "expression"); | |
318 closeNode(); | |
319 } | |
320 | |
321 visitChildNode(Node node, String fieldName) { | |
322 if (node == null) return; | |
323 addCurrentIndent(); | |
324 sb.write("<$fieldName>\n"); | |
325 pushTag(fieldName); | |
326 node.accept(this); | |
327 popTag(); | |
328 addCurrentIndent(); | |
329 sb.write("</$fieldName>\n"); | |
330 } | |
331 | |
332 openSendNodeWithFields(Send node, String type) { | |
333 openNode(node, type, { | |
334 "isPrefix" : "${node.isPrefix}", | |
335 "isPostfix" : "${node.isPostfix}", | |
336 "isIndex" : "${node.isIndex}" | |
337 }); | |
338 visitChildNode(node.receiver, "receiver"); | |
339 visitChildNode(node.selector, "selector"); | |
340 visitChildNode(node.argumentsNode, "argumentsNode"); | |
341 } | |
342 | |
343 visitSend(Send node) { | |
344 openSendNodeWithFields(node, "Send"); | |
345 closeNode(); | |
346 } | |
347 | |
348 visitSendSet(SendSet node) { | |
349 openSendNodeWithFields(node, "SendSet"); | |
350 visitChildNode(node.assignmentOperator, "assignmentOperator"); | |
351 closeNode(); | |
352 } | |
353 | |
354 visitStringInterpolation(StringInterpolation node) { | |
355 visitNodeWithChildren(node, "StringInterpolation"); | |
356 } | |
357 | |
358 visitStringInterpolationPart(StringInterpolationPart node) { | |
359 visitNodeWithChildren(node, "StringInterpolationPart"); | |
360 } | |
361 | |
362 visitStringJuxtaposition(StringJuxtaposition node) { | |
363 visitNodeWithChildren(node, "StringJuxtaposition"); | |
364 } | |
365 | |
366 visitSwitchCase(SwitchCase node) { | |
367 visitNodeWithChildren(node, "SwitchCase"); | |
368 } | |
369 | |
370 visitSwitchStatement(SwitchStatement node) { | |
371 visitNodeWithChildren(node, "SwitchStatement"); | |
372 } | |
373 | |
374 visitLiteralSymbol(LiteralSymbol node) { | |
375 openNode(node, "LiteralSymbol"); | |
376 visitChildNode(node.identifiers, "identifiers"); | |
377 closeNode(); | |
378 } | |
379 | |
380 visitThrow(Throw node) { | |
381 visitNodeWithChildren(node, "Throw"); | |
382 } | |
383 | |
384 visitTryStatement(TryStatement node) { | |
385 visitNodeWithChildren(node, "TryStatement"); | |
386 } | |
387 | |
388 visitTypeAnnotation(TypeAnnotation node) { | |
389 openNode(node, "TypeAnnotation"); | |
390 visitChildNode(node.typeName, "typeName"); | |
391 visitChildNode(node.typeArguments, "typeArguments"); | |
392 closeNode(); | |
393 } | |
394 | |
395 visitTypedef(Typedef node) { | |
396 visitNodeWithChildren(node, "Typedef"); | |
397 } | |
398 | |
399 visitTypeVariable(TypeVariable node) { | |
400 openNode(node, "TypeVariable"); | |
401 visitChildNode(node.name, "name"); | |
402 visitChildNode(node.bound, "bound"); | |
403 closeNode(); | |
404 } | |
405 | |
406 visitVariableDefinitions(VariableDefinitions node) { | |
407 openNode(node, "VariableDefinitions"); | |
408 visitChildNode(node.type, "type"); | |
409 visitChildNode(node.modifiers, "modifiers"); | |
410 visitChildNode(node.definitions, "definitions"); | |
411 closeNode(); | |
412 } | |
413 | |
414 visitWhile(While node) { | |
415 visitNodeWithChildren(node, "While"); | |
416 } | |
417 | |
418 visitMetadata(Metadata node) { | |
419 openNode(node, "Metadata", { | |
420 "token": node.token | |
421 }); | |
422 visitChildNode(node.expression, "expression"); | |
423 closeNode(); | |
424 } | |
425 | |
426 visitCombinator(Combinator node) { | |
427 openNode(node, "Combinator", {"isShow" : "${node.isShow}", | |
428 "isHide" : "${node.isHide}"}); | |
429 closeNode(); | |
430 } | |
431 | |
432 visitExport(Export node) { | |
433 openNode(node, "Export"); | |
434 visitChildNode(node.uri, "uri"); | |
435 visitChildNode(node.combinators, "combinators"); | |
436 closeNode(); | |
437 } | |
438 | |
439 visitImport(Import node) { | |
440 openNode(node, "Import", { | |
441 "isDeferred" : "${node.isDeferred}"}); | |
442 visitChildNode(node.uri, "uri"); | |
443 visitChildNode(node.combinators, "combinators"); | |
444 if (node.prefix != null) { | |
445 visitChildNode(node.prefix, "prefix"); | |
446 } | |
447 closeNode(); | |
448 } | |
449 | |
450 visitPart(Part node) { | |
451 openNode(node, "Part"); | |
452 visitChildNode(node.uri, "uri"); | |
453 closeNode(); | |
454 } | |
455 | |
456 visitPartOf(PartOf node) { | |
457 openNode(node, "PartOf"); | |
458 visitChildNode(node.name, "name"); | |
459 closeNode(); | |
460 } | |
461 | |
462 visitLibraryName(LibraryName node) { | |
463 openNode(node, "LibraryName"); | |
464 visitChildNode(node.name, "name"); | |
465 closeNode(); | |
466 } | |
467 | |
468 visitNode(Node node) { | |
469 unimplemented('visitNode', node: node); | |
470 } | |
471 | |
472 visitLibraryDependency(Node node) { | |
473 unimplemented('visitNode', node: node); | |
474 } | |
475 | |
476 visitLibraryTag(LibraryTag node) { | |
477 unimplemented('visitNode', node: node); | |
478 } | |
479 | |
480 visitLiteral(Literal node) { | |
481 unimplemented('visitNode', node: node); | |
482 } | |
483 | |
484 visitLoop(Loop node) { | |
485 unimplemented('visitNode', node: node); | |
486 } | |
487 | |
488 visitPostfix(Postfix node) { | |
489 unimplemented('visitNode', node: node); | |
490 } | |
491 | |
492 visitPrefix(Prefix node) { | |
493 unimplemented('visitNode', node: node); | |
494 } | |
495 | |
496 visitStringNode(StringNode node) { | |
497 unimplemented('visitNode', node: node); | |
498 } | |
499 | |
500 visitStatement(Statement node) { | |
501 unimplemented('visitNode', node: node); | |
502 } | |
503 | |
504 visitExpression(Expression node) { | |
505 unimplemented('visitNode', node: node); | |
506 } | |
507 | |
508 visitGotoStatement(GotoStatement node) { | |
509 unimplemented('visitNode', node: node); | |
510 } | |
511 | |
512 unimplemented(String message, {Node node}) { | |
513 throw message; | |
514 } | |
515 } | |
OLD | NEW |