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 visitAsyncModifier(AsyncModifier node) { | |
125 openAndCloseNode(node, "AsyncModifier", | |
126 {'asyncToken': node.asyncToken, | |
127 'starToken': node.starToken}); | |
128 } | |
129 | |
130 visitBlock(Block node) { | |
131 visitNodeWithChildren(node, "Block"); | |
132 } | |
133 | |
134 visitBreakStatement(BreakStatement node) { | |
135 visitNodeWithChildren(node, "BreakStatement"); | |
136 } | |
137 | |
138 visitCascade(Cascade node) { | |
139 visitNodeWithChildren(node, "Cascade"); | |
140 } | |
141 | |
142 visitCascadeReceiver(CascadeReceiver node) { | |
143 visitNodeWithChildren(node, "CascadeReceiver"); | |
144 } | |
145 | |
146 visitCaseMatch(CaseMatch node) { | |
147 visitNodeWithChildren(node, "CaseMatch"); | |
148 } | |
149 | |
150 visitCatchBlock(CatchBlock node) { | |
151 visitNodeWithChildren(node, "CatchBlock"); | |
152 } | |
153 | |
154 visitClassNode(ClassNode node) { | |
155 openNode(node, "ClassNode", { | |
156 "extendsKeyword" : tokenToStringOrNull(node.extendsKeyword) | |
157 }); | |
158 visitChildNode(node.name, "name"); | |
159 visitChildNode(node.superclass, "superclass"); | |
160 visitChildNode(node.interfaces, "interfaces"); | |
161 visitChildNode(node.typeParameters, "typeParameters"); | |
162 closeNode(); | |
163 } | |
164 | |
165 visitConditional(Conditional node) { | |
166 visitNodeWithChildren(node, "Conditional"); | |
167 } | |
168 | |
169 visitContinueStatement(ContinueStatement node) { | |
170 visitNodeWithChildren(node, "ContinueStatement"); | |
171 } | |
172 | |
173 visitDoWhile(DoWhile node) { | |
174 visitNodeWithChildren(node, "DoWhile"); | |
175 } | |
176 | |
177 visitEmptyStatement(EmptyStatement node) { | |
178 visitNodeWithChildren(node, "EmptyStatement"); | |
179 } | |
180 | |
181 visitExpressionStatement(ExpressionStatement node) { | |
182 visitNodeWithChildren(node, "ExpressionStatement"); | |
183 } | |
184 | |
185 visitFor(For node) { | |
186 visitNodeWithChildren(node, "For"); | |
187 } | |
188 | |
189 visitForIn(ForIn node) { | |
190 openNode(node, "ForIn", {'await': node.awaitToken}); | |
191 node.visitChildren(this); | |
192 closeNode(); | |
193 } | |
194 | |
195 visitFunctionDeclaration(FunctionDeclaration node) { | |
196 visitNodeWithChildren(node, "FunctionDeclaration"); | |
197 } | |
198 | |
199 visitFunctionExpression(FunctionExpression node) { | |
200 openNode(node, "FunctionExpression", { | |
201 "getOrSet" : tokenToStringOrNull(node.getOrSet) | |
202 }); | |
203 visitChildNode(node.modifiers, "modifiers"); | |
204 visitChildNode(node.returnType, "returnType"); | |
205 visitChildNode(node.name, "name"); | |
206 visitChildNode(node.parameters, "parameters"); | |
207 visitChildNode(node.initializers, "initializers"); | |
208 visitChildNode(node.body, "body"); | |
209 closeNode(); | |
210 } | |
211 | |
212 visitIdentifier(Identifier node) { | |
213 openAndCloseNode(node, "Identifier", {"token" : node.token}); | |
214 } | |
215 | |
216 visitIf(If node) { | |
217 visitNodeWithChildren(node, "If"); | |
218 } | |
219 | |
220 visitLabel(Label node) { | |
221 visitNodeWithChildren(node, "Label"); | |
222 } | |
223 | |
224 visitLabeledStatement(LabeledStatement node) { | |
225 visitNodeWithChildren(node, "LabeledStatement"); | |
226 } | |
227 | |
228 // Custom. | |
229 printLiteral(Literal node, String type) { | |
230 openAndCloseNode(node, type, {"value" : node.value.toString()}); | |
231 } | |
232 | |
233 visitLiteralBool(LiteralBool node) { | |
234 printLiteral(node, "LiteralBool"); | |
235 } | |
236 | |
237 visitLiteralDouble(LiteralDouble node) { | |
238 printLiteral(node, "LiteralDouble"); | |
239 } | |
240 | |
241 visitLiteralInt(LiteralInt node) { | |
242 printLiteral(node, "LiteralInt"); | |
243 } | |
244 | |
245 /** Returns token string value or [:null:] if token is [:null:]. */ | |
246 tokenToStringOrNull(Token token) => token == null ? null : token.stringValue; | |
247 | |
248 visitLiteralList(LiteralList node) { | |
249 openNode(node, "LiteralList", { | |
250 "constKeyword" : tokenToStringOrNull(node.constKeyword) | |
251 }); | |
252 visitChildNode(node.typeArguments, "typeArguments"); | |
253 visitChildNode(node.elements, "elements"); | |
254 closeNode(); | |
255 } | |
256 | |
257 visitLiteralMap(LiteralMap node) { | |
258 visitNodeWithChildren(node, "LiteralMap"); | |
259 } | |
260 | |
261 visitLiteralMapEntry(LiteralMapEntry node) { | |
262 visitNodeWithChildren(node, "LiteralMapEntry"); | |
263 } | |
264 | |
265 visitLiteralNull(LiteralNull node) { | |
266 printLiteral(node, "LiteralNull"); | |
267 } | |
268 | |
269 visitLiteralString(LiteralString node) { | |
270 openAndCloseNode(node, "LiteralString", | |
271 {"value" : node.token}); | |
272 } | |
273 | |
274 visitMixinApplication(MixinApplication node) { | |
275 visitNodeWithChildren(node, "MixinApplication"); | |
276 } | |
277 | |
278 visitModifiers(Modifiers node) { | |
279 visitNodeWithChildren(node, "Modifiers"); | |
280 } | |
281 | |
282 visitNamedArgument(NamedArgument node) { | |
283 visitNodeWithChildren(node, "NamedArgument"); | |
284 } | |
285 | |
286 visitNamedMixinApplication(NamedMixinApplication node) { | |
287 visitNodeWithChildren(node, "NamedMixinApplication"); | |
288 } | |
289 | |
290 visitNewExpression(NewExpression node) { | |
291 visitNodeWithChildren(node, "NewExpression"); | |
292 } | |
293 | |
294 visitNodeList(NodeList node) { | |
295 var params = { "delimiter" : node.delimiter }; | |
296 if (node.isEmpty) { | |
297 openAndCloseNode(node, "NodeList", params); | |
298 } else { | |
299 openNode(node, "NodeList", params); | |
300 node.visitChildren(this); | |
301 closeNode(); | |
302 } | |
303 } | |
304 | |
305 visitOperator(Operator node) { | |
306 openAndCloseNode(node, "Operator", {"value" : node.token}); | |
307 } | |
308 | |
309 visitParenthesizedExpression(ParenthesizedExpression node) { | |
310 visitNodeWithChildren(node, "ParenthesizedExpression"); | |
311 } | |
312 | |
313 visitRedirectingFactoryBody(RedirectingFactoryBody node) { | |
314 openNode(node, "RedirectingFactoryBody"); | |
315 visitChildNode(node.constructorReference, "constructorReference"); | |
316 closeNode(); | |
317 } | |
318 | |
319 visitRethrow(Rethrow node) { | |
320 visitNodeWithChildren(node, "Rethrow"); | |
321 } | |
322 | |
323 visitReturn(Return node) { | |
324 openNode(node, "Return"); | |
325 visitChildNode(node.expression, "expression"); | |
326 closeNode(); | |
327 } | |
328 | |
329 visitYield(Yield node) { | |
330 openNode(node, "Yield", {'star': node.starToken}); | |
331 visitChildNode(node.expression, "expression"); | |
332 closeNode(); | |
333 } | |
334 | |
335 visitChildNode(Node node, String fieldName) { | |
336 if (node == null) return; | |
337 addCurrentIndent(); | |
338 sb.write("<$fieldName>\n"); | |
339 pushTag(fieldName); | |
340 node.accept(this); | |
341 popTag(); | |
342 addCurrentIndent(); | |
343 sb.write("</$fieldName>\n"); | |
344 } | |
345 | |
346 openSendNodeWithFields(Send node, String type) { | |
347 openNode(node, type, { | |
348 "isPrefix" : "${node.isPrefix}", | |
349 "isPostfix" : "${node.isPostfix}", | |
350 "isIndex" : "${node.isIndex}" | |
351 }); | |
352 visitChildNode(node.receiver, "receiver"); | |
353 visitChildNode(node.selector, "selector"); | |
354 visitChildNode(node.argumentsNode, "argumentsNode"); | |
355 } | |
356 | |
357 visitSend(Send node) { | |
358 openSendNodeWithFields(node, "Send"); | |
359 closeNode(); | |
360 } | |
361 | |
362 visitSendSet(SendSet node) { | |
363 openSendNodeWithFields(node, "SendSet"); | |
364 visitChildNode(node.assignmentOperator, "assignmentOperator"); | |
365 closeNode(); | |
366 } | |
367 | |
368 visitStringInterpolation(StringInterpolation node) { | |
369 visitNodeWithChildren(node, "StringInterpolation"); | |
370 } | |
371 | |
372 visitStringInterpolationPart(StringInterpolationPart node) { | |
373 visitNodeWithChildren(node, "StringInterpolationPart"); | |
374 } | |
375 | |
376 visitStringJuxtaposition(StringJuxtaposition node) { | |
377 visitNodeWithChildren(node, "StringJuxtaposition"); | |
378 } | |
379 | |
380 visitSwitchCase(SwitchCase node) { | |
381 visitNodeWithChildren(node, "SwitchCase"); | |
382 } | |
383 | |
384 visitSwitchStatement(SwitchStatement node) { | |
385 visitNodeWithChildren(node, "SwitchStatement"); | |
386 } | |
387 | |
388 visitLiteralSymbol(LiteralSymbol node) { | |
389 openNode(node, "LiteralSymbol"); | |
390 visitChildNode(node.identifiers, "identifiers"); | |
391 closeNode(); | |
392 } | |
393 | |
394 visitThrow(Throw node) { | |
395 visitNodeWithChildren(node, "Throw"); | |
396 } | |
397 | |
398 visitAwait(Await node) { | |
399 visitNodeWithChildren(node, "Await"); | |
400 } | |
401 | |
402 visitTryStatement(TryStatement node) { | |
403 visitNodeWithChildren(node, "TryStatement"); | |
404 } | |
405 | |
406 visitTypeAnnotation(TypeAnnotation node) { | |
407 openNode(node, "TypeAnnotation"); | |
408 visitChildNode(node.typeName, "typeName"); | |
409 visitChildNode(node.typeArguments, "typeArguments"); | |
410 closeNode(); | |
411 } | |
412 | |
413 visitTypedef(Typedef node) { | |
414 visitNodeWithChildren(node, "Typedef"); | |
415 } | |
416 | |
417 visitTypeVariable(TypeVariable node) { | |
418 openNode(node, "TypeVariable"); | |
419 visitChildNode(node.name, "name"); | |
420 visitChildNode(node.bound, "bound"); | |
421 closeNode(); | |
422 } | |
423 | |
424 visitVariableDefinitions(VariableDefinitions node) { | |
425 openNode(node, "VariableDefinitions"); | |
426 visitChildNode(node.type, "type"); | |
427 visitChildNode(node.modifiers, "modifiers"); | |
428 visitChildNode(node.definitions, "definitions"); | |
429 closeNode(); | |
430 } | |
431 | |
432 visitWhile(While node) { | |
433 visitNodeWithChildren(node, "While"); | |
434 } | |
435 | |
436 visitMetadata(Metadata node) { | |
437 openNode(node, "Metadata", { | |
438 "token": node.token | |
439 }); | |
440 visitChildNode(node.expression, "expression"); | |
441 closeNode(); | |
442 } | |
443 | |
444 visitCombinator(Combinator node) { | |
445 openNode(node, "Combinator", {"isShow" : "${node.isShow}", | |
446 "isHide" : "${node.isHide}"}); | |
447 closeNode(); | |
448 } | |
449 | |
450 visitExport(Export node) { | |
451 openNode(node, "Export"); | |
452 visitChildNode(node.uri, "uri"); | |
453 visitChildNode(node.combinators, "combinators"); | |
454 closeNode(); | |
455 } | |
456 | |
457 visitImport(Import node) { | |
458 openNode(node, "Import", { | |
459 "isDeferred" : "${node.isDeferred}"}); | |
460 visitChildNode(node.uri, "uri"); | |
461 visitChildNode(node.combinators, "combinators"); | |
462 if (node.prefix != null) { | |
463 visitChildNode(node.prefix, "prefix"); | |
464 } | |
465 closeNode(); | |
466 } | |
467 | |
468 visitPart(Part node) { | |
469 openNode(node, "Part"); | |
470 visitChildNode(node.uri, "uri"); | |
471 closeNode(); | |
472 } | |
473 | |
474 visitPartOf(PartOf node) { | |
475 openNode(node, "PartOf"); | |
476 visitChildNode(node.name, "name"); | |
477 closeNode(); | |
478 } | |
479 | |
480 visitLibraryName(LibraryName node) { | |
481 openNode(node, "LibraryName"); | |
482 visitChildNode(node.name, "name"); | |
483 closeNode(); | |
484 } | |
485 | |
486 visitNode(Node node) { | |
487 unimplemented('visitNode', node: node); | |
488 } | |
489 | |
490 visitLibraryDependency(Node node) { | |
491 unimplemented('visitNode', node: node); | |
492 } | |
493 | |
494 visitLibraryTag(LibraryTag node) { | |
495 unimplemented('visitNode', node: node); | |
496 } | |
497 | |
498 visitLiteral(Literal node) { | |
499 unimplemented('visitNode', node: node); | |
500 } | |
501 | |
502 visitLoop(Loop node) { | |
503 unimplemented('visitNode', node: node); | |
504 } | |
505 | |
506 visitPostfix(Postfix node) { | |
507 unimplemented('visitNode', node: node); | |
508 } | |
509 | |
510 visitPrefix(Prefix node) { | |
511 unimplemented('visitNode', node: node); | |
512 } | |
513 | |
514 visitStringNode(StringNode node) { | |
515 unimplemented('visitNode', node: node); | |
516 } | |
517 | |
518 visitStatement(Statement node) { | |
519 unimplemented('visitNode', node: node); | |
520 } | |
521 | |
522 visitExpression(Expression node) { | |
523 unimplemented('visitNode', node: node); | |
524 } | |
525 | |
526 visitGotoStatement(GotoStatement node) { | |
527 unimplemented('visitNode', node: node); | |
528 } | |
529 | |
530 unimplemented(String message, {Node node}) { | |
531 throw message; | |
532 } | |
533 } | |
OLD | NEW |