1 //          Copyright Brian Schott (Hackerpilot) 2012.
2 // Distributed under the Boost Software License, Version 1.0.
3 //    (See accompanying file LICENSE_1_0.txt or copy at
4 //          http://www.boost.org/LICENSE_1_0.txt)
5 
6 module dparse.astprinter;
7 
8 import std.array;
9 import std.stdio;
10 import std..string;
11 
12 import dparse.ast;
13 import dparse.formatter;
14 import dparse.lexer;
15 
16 
17 /**
18 * AST visitor that outputs an XML representation of the AST to its file.
19 */
20 class XMLPrinter : ASTVisitor
21 {
22 	override void visit(const AddExpression addExpression)
23 	{
24 		output.writeln("<addExpression operator=\"", str(addExpression.operator), "\">");
25 		output.writeln("<left>");
26 		visit(addExpression.left);
27 		output.writeln("</left>");
28 		if (addExpression.right !is null)
29 		{
30 			output.writeln("<right>");
31 			visit(addExpression.right);
32 			output.writeln("</right>");
33 		}
34 		output.writeln("</addExpression>");
35 	}
36 
37 	override void visit(const AliasDeclaration aliasDeclaration)
38 	{
39 		output.writeln("<aliasDeclaration>");
40 		writeDdoc(aliasDeclaration.comment);
41 		aliasDeclaration.accept(this);
42 		output.writeln("</aliasDeclaration>");
43 	}
44 
45 	override void visit(const AlignAttribute alignAttribute)
46 	{
47 		if (alignAttribute.assignExpression is null)
48 			output.writeln("<alignAttribute/>");
49 		else
50 		{
51 			output.write("<alignAttribute align=\"");
52 			format(output.lockingTextWriter, alignAttribute.assignExpression);
53 			output.writeln("\"/>");
54 		}
55 	}
56 
57 	override void visit(const AndAndExpression andAndExpression)
58 	{
59 		output.writeln("<andAndExpression>");
60 		output.writeln("<left>");
61 		visit(andAndExpression.left);
62 		output.writeln("</left>");
63 		if (andAndExpression.right !is null)
64 		{
65 			output.writeln("<right>");
66 			visit(andAndExpression.right);
67 			output.writeln("</right>");
68 		}
69 		output.writeln("</andAndExpression>");
70 	}
71 
72 	override void visit(const AndExpression andExpression)
73 	{
74 		output.writeln("<andExpression>");
75 		output.writeln("<left>");
76 		visit(andExpression.left);
77 		output.writeln("</left>");
78 		if (andExpression.right !is null)
79 		{
80 			output.writeln("<right>");
81 			visit(andExpression.right);
82 			output.writeln("</right>");
83 		}
84 		output.writeln("</andExpression>");
85 	}
86 
87 	override void visit(const AsmInstruction asmInstruction)
88 	{
89 		output.writeln("<asmInstruction>");
90 		if (asmInstruction.hasAlign)
91 		{
92 			output.writeln("<align>");
93 			visit(asmInstruction.identifierOrIntegerOrOpcode);
94 			output.writeln("</align>");
95 		}
96 		if (asmInstruction.asmInstruction !is null)
97 		{
98 			output.writeln("<label label=\"",
99 					asmInstruction.identifierOrIntegerOrOpcode.text, "\"/>");
100 			asmInstruction.asmInstruction.accept(this);
101 		}
102 		else if (asmInstruction.identifierOrIntegerOrOpcode != tok!"")
103 			visit(asmInstruction.identifierOrIntegerOrOpcode);
104 		if (asmInstruction.operands !is null)
105 		{
106 			visit(asmInstruction.operands);
107 		}
108 		output.writeln("</asmInstruction>");
109 	}
110 
111 	override void visit(const AssignExpression assignExpression)
112 	{
113 		if (assignExpression.expression is null)
114 			output.writeln("<expression>");
115 		else
116 			output.writeln("<expression operator=\"",
117 					xmlAttributeEscape(str(assignExpression.operator)), "\">");
118 		assignExpression.accept(this);
119 		output.writeln("</expression>");
120 	}
121 
122 	override void visit(const AtAttribute atAttribute)
123 	{
124 		output.writeln("<atAttribute>");
125 		if (atAttribute.identifier.type != tok!"")
126 			output.writeln("<identifier>", atAttribute.identifier.text, "</identifier>");
127 		atAttribute.accept(this);
128 		output.writeln("</atAttribute>");
129 	}
130 
131 	override void visit(const Attribute attribute)
132 	{
133 		if (attribute.attribute == tok!"")
134 		{
135 			output.writeln("<attribute>");
136 			attribute.accept(this);
137 			output.writeln("</attribute>");
138 		}
139 		else if (attribute.identifierChain is null)
140 			output.writeln("<attribute attribute=\"", str(attribute.attribute.type), "\"/>");
141 		else
142 		{
143 			output.writeln("<attribute attribute=\"", str(attribute.attribute.type), "\">");
144 			visit(attribute.identifierChain);
145 			output.writeln("</attribute>");
146 		}
147 	}
148 
149 	override void visit(const AutoDeclaration autoDec)
150 	{
151 		output.writeln("<autoDeclaration>");
152 		output.writeln("<storageClasses>");
153 		foreach (sc; autoDec.storageClasses)
154 			visit(sc);
155 		output.writeln("</storageClasses>");
156 
157 		foreach (part; autoDec.parts)
158 			visit(part);
159 		output.writeln("</autoDeclaration>");
160 	}
161 
162 	override void visit(const AutoDeclarationPart part)
163 	{
164 		output.writeln("<autoDeclarationPart>");
165 
166 		output.writeln("<item>");
167 		output.writeln("<name line=\"", part.identifier.line, "\">", part.identifier.text, "</name>");
168 		visit(part.initializer);
169 		output.writeln("</item>");
170 		output.writeln("</autoDeclarationPart>");
171 	}
172 
173 	override void visit(const BreakStatement breakStatement)
174 	{
175 		if (breakStatement.label.type == tok!"")
176 			output.writeln("<breakStatement/>");
177 		else
178 			output.writeln("<breakStatement label=\"", breakStatement.label.text, "\"/>");
179 	}
180 
181 	override void visit(const CaseRangeStatement caseRangeStatement)
182 	{
183 		output.writeln("<caseRangeStatement>");
184 		if (caseRangeStatement.low !is null)
185 		{
186 			output.writeln("<low>");
187 			visit(caseRangeStatement.low);
188 			output.writeln("</low>");
189 		}
190 		if (caseRangeStatement.high !is null)
191 		{
192 			output.writeln("<high>");
193 			visit(caseRangeStatement.high);
194 			output.writeln("</high>");
195 		}
196 		if (caseRangeStatement.declarationsAndStatements !is null)
197 			visit(caseRangeStatement.declarationsAndStatements);
198 		output.writeln("</caseRangeStatement>");
199 	}
200 
201 	override void visit(const Catch catch_)
202 	{
203 		output.writeln("<catch>");
204 		catch_.accept(this);
205 		output.writeln("</catch>");
206 	}
207 
208 	override void visit(const ClassDeclaration classDec)
209 	{
210 		output.writeln("<classDeclaration line=\"", classDec.name.line, "\">");
211 		writeName(classDec.name.text);
212 		writeDdoc(classDec.comment);
213 		classDec.accept(this);
214 		output.writeln("</classDeclaration>");
215 	}
216 
217 	override void visit(const ConditionalDeclaration conditionalDeclaration)
218 	{
219 		output.writeln("<conditionalDeclaration>");
220 		visit(conditionalDeclaration.compileCondition);
221 		output.writeln("<trueDeclarations style=\"", conditionalDeclaration.trueStyle, "\">");
222 		foreach (dec; conditionalDeclaration.trueDeclarations)
223 			visit(dec);
224 		output.writeln("</trueDeclarations>");
225 		if (conditionalDeclaration.falseDeclarations.length > 0)
226 		{
227 			output.writeln("<falseDeclarations style=\"", conditionalDeclaration.trueStyle, "\">");
228 			foreach (dec; conditionalDeclaration.falseDeclarations)
229 				visit(dec);
230 			output.writeln("</falseDeclarations>");
231 		}
232 		output.writeln("</conditionalDeclaration>");
233 	}
234 
235 	override void visit(const ConditionalStatement conditionalStatement)
236 	{
237 		output.writeln("<conditionalStatement>");
238 		visit(conditionalStatement.compileCondition);
239 		output.writeln("<trueStatement>");
240 		visit(conditionalStatement.trueStatement);
241 		output.writeln("</trueStatement>");
242 		if (conditionalStatement.falseStatement !is null)
243 		{
244 			output.writeln("<falseStatement>");
245 			visit(conditionalStatement.falseStatement);
246 			output.writeln("</falseStatement>");
247 		}
248 		output.writeln("</conditionalStatement>");
249 	}
250 
251 	override void visit(const ContinueStatement continueStatement)
252 	{
253 		if (continueStatement.label.type == tok!"")
254 			output.writeln("<continueStatement/>");
255 		else
256 			output.writeln("<continueStatement label=\"", continueStatement.label.text, "\"/>");
257 	}
258 
259 	override void visit(const DebugCondition debugCondition)
260 	{
261 		if (debugCondition.identifierOrInteger.type == tok!"")
262 			output.writeln("<debugCondition/>");
263 		else
264 			output.writeln("<debugCondition condition=\"",
265 					debugCondition.identifierOrInteger.text, "\"/>");
266 	}
267 
268 	override void visit(const DebugSpecification debugSpecification)
269 	{
270 		if (debugSpecification.identifierOrInteger.type == tok!"")
271 			output.writeln("<debugSpecification/>");
272 		else
273 			output.writeln("<debugSpecification condition=\"",
274 					debugSpecification.identifierOrInteger.text, "\"/>");
275 	}
276 
277 	override void visit(const Declarator declarator)
278 	{
279 		output.writeln("<declarator line=\"", declarator.name.line, "\">");
280 		writeName(declarator.name.text);
281 		writeDdoc(declarator.comment);
282 		declarator.accept(this);
283 		output.writeln("</declarator>");
284 	}
285 
286 	override void visit(const Deprecated deprecated_)
287 	{
288 		if (deprecated_.assignExpression !is null)
289 		{
290 			output.writeln("<deprecated>");
291 			visit(deprecated_.assignExpression);
292 			output.writeln("</deprecated>");
293 		}
294 		else
295 			output.writeln("<deprecated/>");
296 	}
297 
298 	override void visit(const EnumDeclaration enumDec)
299 	{
300 		output.writeln("<enumDeclaration line=\"", enumDec.name.line, "\">");
301 		writeDdoc(enumDec.comment);
302 		if (enumDec.name.type == tok!"identifier")
303 			writeName(enumDec.name.text);
304 		enumDec.accept(this);
305 		output.writeln("</enumDeclaration>");
306 	}
307 
308 	override void visit(const AnonymousEnumMember enumMember)
309 	{
310 		output.writeln("<anonymousEnumMember line=\"", enumMember.name.line, "\">");
311 		writeDdoc(enumMember.comment);
312 		if (enumMember.type !is null)
313 			visit(enumMember.type);
314 		output.write("<name>", enumMember.name.text, "</name>");
315 		if (enumMember.assignExpression !is null)
316 			visit(enumMember.assignExpression);
317 		output.writeln("</anonymousEnumMember>");
318 	}
319 
320 	override void visit(const EnumMember enumMem)
321 	{
322 		output.writeln("<enumMember line=\"", enumMem.name.line, "\">");
323 		writeDdoc(enumMem.comment);
324 		enumMem.accept(this);
325 		output.writeln("</enumMember>");
326 	}
327 
328 	override void visit(const EqualExpression equalExpression)
329 	{
330 		output.writeln("<equalExpression operator=\"", str(equalExpression.operator), "\">");
331 		output.writeln("<left>");
332 		visit(equalExpression.left);
333 		output.writeln("</left>");
334 		output.writeln("<right>");
335 		visit(equalExpression.right);
336 		output.writeln("</right>");
337 		output.writeln("</equalExpression>");
338 	}
339 
340 	override void visit(const Finally finally_)
341 	{
342 		output.writeln("<finally>");
343 		finally_.accept(this);
344 		output.writeln("</finally>");
345 	}
346 
347 	override void visit(const ForStatement forStatement)
348 	{
349 		output.writeln("<forStatement>");
350 		if (forStatement.initialization !is null)
351 		{
352 			output.writeln("<initialization>");
353 			visit(forStatement.initialization);
354 			output.writeln("</initialization>");
355 		}
356 		if (forStatement.test !is null)
357 		{
358 			output.writeln("<test>");
359 			visit(forStatement.test);
360 			output.writeln("</test>");
361 		}
362 		if (forStatement.increment !is null)
363 		{
364 			output.writeln("<increment>");
365 			visit(forStatement.increment);
366 			output.writeln("</increment>");
367 		}
368 		if (forStatement.declarationOrStatement !is null)
369 			visit(forStatement.declarationOrStatement);
370 		output.writeln("</forStatement>");
371 	}
372 
373 	override void visit(const ForeachStatement foreachStatement)
374 	{
375 		output.writeln("<foreachStatement type=\"", str(foreachStatement.type), "\">");
376 		if (foreachStatement.foreachType !is null)
377 			visit(foreachStatement.foreachType);
378 		if (foreachStatement.foreachTypeList !is null)
379 			visit(foreachStatement.foreachTypeList);
380 		output.writeln("<low>");
381 		visit(foreachStatement.low);
382 		output.writeln("</low>");
383 		if (foreachStatement.high !is null)
384 		{
385 			output.writeln("<high>");
386 			visit(foreachStatement.high);
387 			output.writeln("</high>");
388 		}
389 		visit(foreachStatement.declarationOrStatement);
390 		output.writeln("</foreachStatement>");
391 	}
392 
393 	override void visit(const ForeachType foreachType)
394 	{
395 		output.writeln("<foreachType>");
396 		foreach (constructor; foreachType.typeConstructors)
397 		{
398 			output.writeln("<typeConstructor>", str(constructor), "</typeConstructor>");
399 		}
400 		if (foreachType.type !is null)
401 			visit(foreachType.type);
402 		visit(foreachType.identifier);
403 		output.writeln("</foreachType>");
404 
405 	}
406 
407 	override void visit(const FunctionDeclaration functionDec)
408 	{
409 		output.writeln("<functionDeclaration line=\"", functionDec.name.line, "\">");
410 		writeName(functionDec.name.text);
411 		writeDdoc(functionDec.comment);
412 		if (functionDec.hasAuto)
413 			output.writeln("<auto/>");
414 		if (functionDec.hasRef)
415 			output.writeln("<ref/>");
416 		functionDec.accept(this);
417 		output.writeln("</functionDeclaration>");
418 	}
419 
420 	override void visit(const FunctionLiteralExpression functionLiteralExpression)
421 	{
422 		output.writeln("<functionLiteralExpression type=\"", functionLiteralExpression.functionOrDelegate != tok!""
423 				? str(functionLiteralExpression.functionOrDelegate) : "auto", "\">");
424 		functionLiteralExpression.accept(this);
425 		output.writeln("</functionLiteralExpression>");
426 	}
427 
428 	override void visit(const GotoStatement gotoStatement)
429 	{
430 		if (gotoStatement.label.type == tok!"default")
431 			output.writeln("<gotoStatement default=\"true\"/>");
432 		else if (gotoStatement.label.type == tok!"identifier")
433 			output.writeln("<gotoStatement label=\"", gotoStatement.label.text, "\"/>");
434 		else
435 		{
436 			output.writeln("<gotoStatement>");
437 			output.writeln("<case>");
438 			if (gotoStatement.expression)
439 				visit(gotoStatement.expression);
440 			output.writeln("</case>");
441 			output.writeln("</gotoStatement>");
442 		}
443 	}
444 
445 	override void visit(const IdentityExpression identityExpression)
446 	{
447 		if (identityExpression.negated)
448 			output.writeln("<identityExpression operator=\"!is\">");
449 		else
450 			output.writeln("<identityExpression operator=\"is\">");
451 		output.writeln("<left>");
452 		visit(identityExpression.left);
453 		output.writeln("</left>");
454 		output.writeln("<right>");
455 		visit(identityExpression.right);
456 		output.writeln("</right>");
457 		output.writeln("</identityExpression>");
458 	}
459 
460 	override void visit(const IfStatement ifStatement)
461 	{
462 		output.writeln("<ifStatement>");
463 
464 		output.writeln("<condition>");
465 		if (ifStatement.identifier.type != tok!"")
466 		{
467 			if (ifStatement.type is null)
468 				output.writeln("<auto/>");
469 			else
470 				visit(ifStatement.type);
471 			visit(ifStatement.identifier);
472 		}
473 		ifStatement.expression.accept(this);
474 		output.writeln("</condition>");
475 
476 		output.writeln("<then>");
477 		ifStatement.thenStatement.accept(this);
478 		output.writeln("</then>");
479 
480 		if (ifStatement.elseStatement !is null)
481 		{
482 			output.writeln("<else>");
483 			ifStatement.elseStatement.accept(this);
484 			output.writeln("</else>");
485 		}
486 		output.writeln("</ifStatement>");
487 	}
488 
489 	override void visit(const ImportBind importBind)
490 	{
491 		if (importBind.right.type == tok!"")
492 			output.writeln("<importBind symbol=\"", importBind.left.text, "\"/>");
493 		else
494 			output.writeln("<importBind symbol=\"", importBind.right.text,
495 					"\" rename=\"", importBind.left.text, "\"/>");
496 	}
497 
498 	override void visit(const InExpression inExpression)
499 	{
500 		if (inExpression.negated)
501 			output.writeln("<inExpression operator=\"!in\">");
502 		else
503 			output.writeln("<inExpression operator=\"in\">");
504 		output.writeln("<left>");
505 		visit(inExpression.left);
506 		output.writeln("</left>");
507 		output.writeln("<right>");
508 		visit(inExpression.right);
509 		output.writeln("</right>");
510 		output.writeln("</inExpression>");
511 	}
512 
513 	override void visit(const Initialize initialize)
514 	{
515 		if (initialize.statementNoCaseNoDefault is null)
516 			output.writeln("<initialize/>");
517 		else
518 		{
519 			output.writeln("<initialize>");
520 			visit(initialize.statementNoCaseNoDefault);
521 			output.writeln("</initialize>");
522 		}
523 	}
524 
525 	override void visit(const Initializer initializer)
526 	{
527 		if (initializer.nonVoidInitializer is null)
528 			output.writeln("<initializer void=\"true\"/>");
529 		else
530 		{
531 			output.writeln("<initializer>");
532 			visit(initializer.nonVoidInitializer);
533 			output.writeln("</initializer>");
534 		}
535 	}
536 
537 	override void visit(const InterfaceDeclaration interfaceDec)
538 	{
539 		output.writeln("<interfaceDeclaration line=\"", interfaceDec.name.line, "\">");
540 		writeName(interfaceDec.name.text);
541 		writeDdoc(interfaceDec.comment);
542 		interfaceDec.accept(this);
543 		output.writeln("</interfaceDeclaration>");
544 	}
545 
546 	override void visit(const Invariant invariant_)
547 	{
548 		output.writeln("<invariant>");
549 		writeDdoc(invariant_.comment);
550 		invariant_.accept(this);
551 		output.writeln("</invariant>");
552 	}
553 
554 	override void visit(const IsExpression isExpression)
555 	{
556 		output.writeln("<isExpression>");
557 		visit(isExpression.type);
558 		if (isExpression.identifier.type != tok!"")
559 			visit(isExpression.identifier);
560 		if (isExpression.typeSpecialization !is null)
561 		{
562 			if (isExpression.equalsOrColon == tok!":")
563 				output.writeln("<colon/>");
564 			else
565 				output.writeln("<equals/>");
566 			visit(isExpression.typeSpecialization);
567 			if (isExpression.templateParameterList !is null)
568 				visit(isExpression.templateParameterList);
569 		}
570 		output.writeln("</isExpression>");
571 	}
572 
573 	override void visit(const KeyValuePair keyValuePair)
574 	{
575 		output.writeln("<keyValuePair>");
576 		output.writeln("<key>");
577 		visit(keyValuePair.key);
578 		output.writeln("</key>");
579 		output.writeln("<value>");
580 		visit(keyValuePair.value);
581 		output.writeln("</value>");
582 		output.writeln("</keyValuePair>");
583 	}
584 
585 	override void visit(const LabeledStatement labeledStatement)
586 	{
587 		output.writeln("<labeledStatement label=\"", labeledStatement.identifier.text, "\">");
588 		if (labeledStatement.declarationOrStatement !is null)
589 			visit(labeledStatement.declarationOrStatement);
590 		output.writeln("</labeledStatement>");
591 	}
592 
593 	override void visit(const LinkageAttribute linkageAttribute)
594 	{
595 		if (linkageAttribute.hasPlusPlus)
596 		{
597 			output.write("<linkageAttribute linkage=\"C++\"");
598 			if (linkageAttribute.typeIdentifierPart !is null && linkageAttribute.typeIdentifierPart.typeIdentifierPart !is null)
599 			{
600 				output.write(" namespace=\"");
601 				format(output.lockingTextWriter, linkageAttribute.typeIdentifierPart);
602 				output.writeln("\"/>");
603 			}
604 			else if (linkageAttribute.classOrStruct == tok!"class")
605 				output.writeln(" mangleAs=\"class\"/>");
606 			else if (linkageAttribute.classOrStruct == tok!"struct")
607 				output.writeln(" mangleAs=\"struct\"/>");
608 			else
609 				output.writeln("/>");
610 		}
611 		else if (linkageAttribute.identifier.text == "Objective")
612 			output.writeln("<linkageAttribute linkage=\"Objective-C\"/>");
613 		else
614 			output.writeln("<linkageAttribute linkage=\"",
615 					linkageAttribute.identifier.text, "\"/>");
616 	}
617 
618 	override void visit(const MemberFunctionAttribute memberFunctionAttribute)
619 	{
620 		output.writeln("<memberFunctionAttribute>");
621 		if (memberFunctionAttribute.atAttribute is null)
622 			output.writeln(str(memberFunctionAttribute.tokenType));
623 		else
624 			memberFunctionAttribute.accept(this);
625 		output.writeln("</memberFunctionAttribute>");
626 	}
627 
628 	override void visit(const Module module_)
629 	{
630 		output.writeln("<?xml version=\"1.0\"?>");
631 		output.writeln("<module>");
632 		module_.accept(this);
633 		output.writeln("</module>");
634 	}
635 
636 	override void visit(const MulExpression mulExpression)
637 	{
638 		output.writeln("<mulExpression operator=\"", str(mulExpression.operator), "\">");
639 		output.writeln("<left>");
640 		visit(mulExpression.left);
641 		output.writeln("</left>");
642 		if (mulExpression.right !is null)
643 		{
644 			output.writeln("<right>");
645 			visit(mulExpression.right);
646 			output.writeln("</right>");
647 		}
648 		output.writeln("</mulExpression>");
649 	}
650 
651 	override void visit(const OrOrExpression orOrExpression)
652 	{
653 		output.writeln("<orOrExpression>");
654 		output.writeln("<left>");
655 		visit(orOrExpression.left);
656 		output.writeln("</left>");
657 		if (orOrExpression.right !is null)
658 		{
659 			output.writeln("<right>");
660 			visit(orOrExpression.right);
661 			output.writeln("</right>");
662 		}
663 		output.writeln("</orOrExpression>");
664 	}
665 
666 	override void visit(const ParameterAttribute pa)
667 	{
668 		output.writeln("<parameterAttribute>");
669 		if (pa.atAttribute)
670 			visit(pa.atAttribute);
671 		else
672 			writeln(str(pa.idType));
673 		output.writeln("</parameterAttribute>");
674 	}
675 
676 	override void visit(const Parameter param)
677 	{
678 		output.writeln("<parameter>");
679 		if (param.name.type == tok!"identifier")
680 			writeName(param.name.text);
681 		param.accept(this);
682 		if (param.vararg)
683 			output.writeln("<vararg/>");
684 		output.writeln("</parameter>");
685 	}
686 
687 	override void visit(const PowExpression powExpression)
688 	{
689 		output.writeln("<powExpression>");
690 		output.writeln("<left>");
691 		visit(powExpression.left);
692 		output.writeln("</left>");
693 		if (powExpression.right !is null)
694 		{
695 			output.writeln("<right>");
696 			visit(powExpression.right);
697 			output.writeln("</right>");
698 		}
699 		output.writeln("</powExpression>");
700 	}
701 
702 	override void visit(const RelExpression relExpression)
703 	{
704 		output.writeln("<relExpression operator=\"",
705 				xmlAttributeEscape(str(relExpression.operator)), "\">");
706 		output.writeln("<left>");
707 		visit(relExpression.left);
708 		output.writeln("</left>");
709 		output.writeln("<right>");
710 		visit(relExpression.right);
711 		output.writeln("</right>");
712 		output.writeln("</relExpression>");
713 	}
714 
715 	override void visit(const ReturnStatement returnStatement)
716 	{
717 		if (returnStatement.expression is null)
718 			output.writeln("<returnStatement/>");
719 		else
720 		{
721 			output.writeln("<returnStatement>");
722 			returnStatement.accept(this);
723 			output.writeln("</returnStatement>");
724 		}
725 	}
726 
727 	override void visit(const ShiftExpression shiftExpression)
728 	{
729 		output.writeln("<shiftExpression operator=\"",
730 				xmlAttributeEscape(str(shiftExpression.operator)), "\">");
731 		output.writeln("<left>");
732 		visit(shiftExpression.left);
733 		output.writeln("</left>");
734 		output.writeln("<right>");
735 		visit(shiftExpression.right);
736 		output.writeln("</right>");
737 		output.writeln("</shiftExpression>");
738 	}
739 
740 	override void visit(const SingleImport singleImport)
741 	{
742 		if (singleImport.rename.type == tok!"")
743 			output.writeln("<singleImport>");
744 		else
745 			output.writeln("<singleImport rename=\"", singleImport.rename.text, "\">");
746 		visit(singleImport.identifierChain);
747 		output.writeln("</singleImport>");
748 	}
749 
750 	override void visit(const StructDeclaration structDec)
751 	{
752 		output.writeln("<structDeclaration line=\"", structDec.name.line, "\">");
753 		writeName(structDec.name.text);
754 		writeDdoc(structDec.comment);
755 		structDec.accept(this);
756 		output.writeln("</structDeclaration>");
757 	}
758 
759 	override void visit(const TemplateAliasParameter templateAliasParameter)
760 	{
761 		output.writeln("<templateAliasParameter>");
762 		if (templateAliasParameter.type !is null)
763 			visit(templateAliasParameter.type);
764 		visit(templateAliasParameter.identifier);
765 		if (templateAliasParameter.colonExpression !is null)
766 		{
767 			output.writeln("<specialization>");
768 			visit(templateAliasParameter.colonExpression);
769 			output.writeln("</specialization>");
770 		}
771 		else if (templateAliasParameter.colonType !is null)
772 		{
773 			output.writeln("<specialization>");
774 			visit(templateAliasParameter.colonType);
775 			output.writeln("</specialization>");
776 		}
777 
778 		if (templateAliasParameter.assignExpression !is null)
779 		{
780 			output.writeln("<default>");
781 			visit(templateAliasParameter.assignExpression);
782 			output.writeln("</default>");
783 		}
784 		else if (templateAliasParameter.assignType !is null)
785 		{
786 			output.writeln("<default>");
787 			visit(templateAliasParameter.assignType);
788 			output.writeln("</default>");
789 		}
790 
791 		output.writeln("</templateAliasParameter>");
792 	}
793 
794 	override void visit(const TemplateDeclaration templateDeclaration)
795 	{
796 		writeDdoc(templateDeclaration.comment);
797 		output.writeln("<templateDeclaration line=\"", templateDeclaration.name.line, "\">");
798 		writeName(templateDeclaration.name.text);
799 		visit(templateDeclaration.templateParameters);
800 		if (templateDeclaration.constraint !is null)
801 			visit(templateDeclaration.constraint);
802 		foreach (dec; templateDeclaration.declarations)
803 		{
804 			if (dec !is null)
805 				visit(dec);
806 		}
807 		output.writeln("</templateDeclaration>");
808 	}
809 
810 	override void visit(const Token token)
811 	{
812 		string tagName;
813 		switch (token.type)
814 		{
815 		case tok!"":
816 			return;
817 		case tok!"identifier":
818 			tagName = "identifier";
819 			break;
820 		case tok!"doubleLiteral":
821 			tagName = "doubleLiteral";
822 			break;
823 		case tok!"idoubleLiteral":
824 			tagName = "idoubleLiteral";
825 			break;
826 		case tok!"floatLiteral":
827 			tagName = "floatLiteral";
828 			break;
829 		case tok!"ifloatLiteral":
830 			tagName = "ifloatLiteral";
831 			break;
832 		case tok!"intLiteral":
833 			tagName = "intLiteral";
834 			break;
835 		case tok!"uintLiteral":
836 			tagName = "uintLiteral";
837 			break;
838 		case tok!"longLiteral":
839 			tagName = "longLiteral";
840 			break;
841 		case tok!"ulongLiteral":
842 			tagName = "ulongLiteral";
843 			break;
844 		case tok!"realLiteral":
845 			tagName = "realLiteral";
846 			break;
847 		case tok!"irealLiteral":
848 			tagName = "irealLiteral";
849 			break;
850 		case tok!"characterLiteral":
851 			tagName = "characterLiteral";
852 			break;
853 		case tok!"stringLiteral":
854 			tagName = "stringLiteral";
855 			break;
856 		case tok!"dstringLiteral":
857 			tagName = "dstringLiteral";
858 			break;
859 		case tok!"wstringLiteral":
860 			tagName = "wstringLiteral";
861 			break;
862 		case tok!"scriptLine":
863 			tagName = "scriptLine";
864 			break;
865 		case tok!"$":
866 			output.writeln("<dollar/>");
867 			return;
868 		case tok!".":
869 			output.writeln("<dot/>");
870 			return;
871 		default:
872 			output.writeln("<", str(token.type), "/>");
873 			return;
874 		}
875 		output.writeln("<", tagName, ">", xmlEscape(token.text), "</", tagName, ">");
876 	}
877 
878 	override void visit(const Type type)
879 	{
880 		auto app = appender!string();
881 		auto formatter = new Formatter!(typeof(app))(app);
882 		formatter.format(type);
883 		output.writeln("<type pretty=\"", xmlAttributeEscape(app.data), "\">");
884 		type.accept(this);
885 		output.writeln("</type>");
886 	}
887 
888 	override void visit(const Type2 type2)
889 	{
890 		if (type2.builtinType != tok!"")
891 		{
892 			output.writeln("<type2>", str(type2.builtinType), "</type2>");
893 			if (type2.typeIdentifierPart !is null)
894 				visit(type2.typeIdentifierPart);
895 		}
896 		else
897 		{
898 			output.writeln("<type2>");
899 			type2.accept(this);
900 			output.writeln("</type2>");
901 		}
902 	}
903 
904 	override void visit(const TypeSuffix typeSuffix)
905 	{
906 		if (typeSuffix.star != tok!"")
907 			output.writeln("<typeSuffix type=\"*\"/>");
908 		else if (typeSuffix.array)
909 		{
910 			if (typeSuffix.low is null && typeSuffix.type is null)
911 				output.writeln("<typeSuffix type=\"[]\"/>");
912 			else
913 			{
914 				if (typeSuffix.low is null)
915 				{
916 					output.writeln("<typeSuffix type=\"[]\">");
917 					visit(typeSuffix.type);
918 					output.writeln("</typeSuffix>");
919 				}
920 				else
921 				{
922 					output.writeln("<typeSuffix type=\"[]\">");
923 					if (typeSuffix.high !is null)
924 					{
925 						output.writeln("<low>");
926 						visit(typeSuffix.low);
927 						output.writeln("</low>");
928 						output.writeln("<high>");
929 						visit(typeSuffix.high);
930 						output.writeln("</high>");
931 					}
932 					else
933 						visit(typeSuffix.low);
934 					output.writeln("</typeSuffix>");
935 				}
936 			}
937 		}
938 		else
939 		{
940 			visit(typeSuffix.delegateOrFunction);
941 			visit(typeSuffix.parameters);
942 			foreach (attr; typeSuffix.memberFunctionAttributes)
943 			{
944 				if (attr !is null)
945 					visit(attr);
946 			}
947 		}
948 	}
949 
950 	override void visit(const UnaryExpression unaryExpression)
951 	{
952 		output.writeln("<unaryExpression>");
953 		if (unaryExpression.prefix != tok!"")
954 		{
955 			output.writeln("<prefix>", xmlEscape(str(unaryExpression.prefix.type)), "</prefix>");
956 			unaryExpression.unaryExpression.accept(this);
957 		}
958 		else
959 		{
960 			if (unaryExpression.suffix != tok!"")
961 			{
962 				assert(unaryExpression.suffix.text == "");
963 				unaryExpression.unaryExpression.accept(this);
964 				output.writeln("<suffix>", str(unaryExpression.suffix.type), "</suffix>");
965 			}
966 			else
967 				unaryExpression.accept(this);
968 		}
969 		output.writeln("</unaryExpression>");
970 	}
971 
972 	override void visit(const UnionDeclaration unionDeclaration)
973 	{
974 		output.writeln("<unionDeclaration line=\"", unionDeclaration.name.line, "\">");
975 		if (unionDeclaration.name != tok!"")
976 			writeName(unionDeclaration.name.text);
977 		if (unionDeclaration.templateParameters !is null)
978 			visit(unionDeclaration.templateParameters);
979 		if (unionDeclaration.constraint !is null)
980 			visit(unionDeclaration.constraint);
981 		if (unionDeclaration.structBody !is null)
982 			visit(unionDeclaration.structBody);
983 		output.writeln("</unionDeclaration>");
984 	}
985 
986 	override void visit(const Unittest unittest_)
987 	{
988 		output.writeln("<unittest>");
989 		unittest_.accept(this);
990 		output.writeln("</unittest>");
991 	}
992 
993 	override void visit(const VariableDeclaration variableDeclaration)
994 	{
995 		output.writeln("<variableDeclaration>");
996 		writeDdoc(variableDeclaration.comment);
997 		variableDeclaration.accept(this);
998 		output.writeln("</variableDeclaration>");
999 	}
1000 
1001 	override void visit(const XorExpression xorExpression)
1002 	{
1003 		output.writeln("<xorExpression>");
1004 		output.writeln("<left>");
1005 		visit(xorExpression.left);
1006 		output.writeln("</left>");
1007 		if (xorExpression.right !is null)
1008 		{
1009 			output.writeln("<right>");
1010 			visit(xorExpression.right);
1011 			output.writeln("</right>");
1012 		}
1013 		output.writeln("</xorExpression>");
1014 	}
1015 
1016 	override void visit(const Index index)
1017 	{
1018 		output.writeln("<index>");
1019 		if (index.high)
1020 		{
1021 			output.writeln("<low>");
1022 			visit(index.low);
1023 			output.writeln("</low>");
1024 
1025 			output.writeln("<high>");
1026 			visit(index.high);
1027 			output.writeln("</high>");
1028 		}
1029 		else
1030 			visit(index.low);
1031 		output.writeln("</index>");
1032 	}
1033 
1034 	// dfmt off
1035 	override void visit(const AliasInitializer aliasInitializer) { mixin (tagAndAccept!"aliasInitializer"); }
1036 	override void visit(const AliasThisDeclaration aliasThisDeclaration) { mixin (tagAndAccept!"aliasThisDeclaration"); }
1037 	override void visit(const AnonymousEnumDeclaration anonymousEnumDeclaration) { mixin (tagAndAccept!"anonymousEnumDeclaration"); }
1038 	override void visit(const ArgumentList argumentList) { mixin (tagAndAccept!"argumentList"); }
1039 	override void visit(const Arguments arguments) { mixin (tagAndAccept!"arguments"); }
1040 	override void visit(const ArrayInitializer arrayInitializer) { mixin (tagAndAccept!"arrayInitializer"); }
1041 	override void visit(const ArrayLiteral arrayLiteral) { mixin (tagAndAccept!"arrayLiteral"); }
1042 	override void visit(const ArrayMemberInitialization arrayMemberInitialization) { mixin (tagAndAccept!"arrayMemberInitialization"); }
1043 	override void visit(const AsmAddExp asmAddExp) { mixin (tagAndAccept!"asmAddExp"); }
1044 	override void visit(const AsmAndExp asmAndExp) { mixin (tagAndAccept!"asmAndExp"); }
1045 	override void visit(const AsmBrExp asmBrExp) { mixin (tagAndAccept!"asmBrExp"); }
1046 	override void visit(const AsmEqualExp asmEqualExp) { mixin (tagAndAccept!"asmEqualExp"); }
1047 	override void visit(const AsmExp asmExp) { mixin (tagAndAccept!"asmExp"); }
1048 	override void visit(const AsmLogAndExp asmLogAndExp) { mixin (tagAndAccept!"asmLogAndExp"); }
1049 	override void visit(const AsmLogOrExp asmLogOrExp) { mixin (tagAndAccept!"asmLogOrExp"); }
1050 	override void visit(const AsmMulExp asmMulExp) { mixin (tagAndAccept!"asmMulExp"); }
1051 	override void visit(const AsmOrExp asmOrExp) { mixin (tagAndAccept!"asmOrExp"); }
1052 	override void visit(const AsmPrimaryExp asmPrimaryExp) { mixin (tagAndAccept!"asmPrimaryExp"); }
1053 	override void visit(const AsmRelExp asmRelExp) { mixin (tagAndAccept!"asmRelExp"); }
1054 	override void visit(const AsmShiftExp asmShiftExp) { mixin (tagAndAccept!"asmShiftExp"); }
1055 	override void visit(const AsmStatement asmStatement) { mixin (tagAndAccept!"asmStatement"); }
1056 	override void visit(const AsmTypePrefix asmTypePrefix) { mixin (tagAndAccept!"asmTypePrefix"); }
1057 	override void visit(const AsmUnaExp asmUnaExp) { mixin (tagAndAccept!"asmUnaExp"); }
1058 	override void visit(const AsmXorExp asmXorExp) { mixin (tagAndAccept!"asmXorExp"); }
1059 	override void visit(const AssocArrayLiteral assocArrayLiteral) { mixin (tagAndAccept!"assocArrayLiteral"); }
1060 	override void visit(const AssertExpression assertExpression) { mixin (tagAndAccept!"assertExpression"); }
1061 	override void visit(const AssertArguments assertArguments) { mixin (tagAndAccept!"assertArguments"); }
1062 	override void visit(const AttributeDeclaration attributeDeclaration) { mixin (tagAndAccept!"attributeDeclaration"); }
1063 	override void visit(const BaseClass baseClass) { mixin (tagAndAccept!"baseClass"); }
1064 	override void visit(const BaseClassList baseClassList) { mixin (tagAndAccept!"baseClassList"); }
1065 	override void visit(const BlockStatement blockStatement) { mixin (tagAndAccept!"blockStatement"); }
1066 	override void visit(const CaseStatement caseStatement) { mixin (tagAndAccept!"caseStatement"); }
1067 	override void visit(const CastExpression castExpression) { mixin (tagAndAccept!"castExpression"); }
1068 	override void visit(const CastQualifier castQualifier) { mixin (tagAndAccept!"castQualifier"); }
1069 	override void visit(const Catches catches) { mixin (tagAndAccept!"catches"); }
1070 	override void visit(const CmpExpression cmpExpression) { mixin (tagAndAccept!"cmpExpression"); }
1071 	override void visit(const CompileCondition compileCondition) { mixin (tagAndAccept!"compileCondition"); }
1072 	override void visit(const Constraint constraint) { mixin (tagAndAccept!"constraint"); }
1073 	override void visit(const Constructor constructor) { mixin (tagAndAccept!"constructor"); }
1074 	override void visit(const Declaration declaration) { mixin (tagAndAccept!"declaration"); }
1075 	override void visit(const DeclarationOrStatement declarationOrStatement) { mixin (tagAndAccept!"declarationOrStatement"); }
1076 	override void visit(const DeclarationsAndStatements declarationsAndStatements) { mixin (tagAndAccept!"declarationsAndStatements"); }
1077 	override void visit(const DeclaratorIdentifierList declaratorIdentifierList) { mixin (tagAndAccept!"declaratorIdentifierList"); }
1078 	override void visit(const DefaultStatement defaultStatement) { mixin (tagAndAccept!"defaultStatement"); }
1079 	override void visit(const DeleteExpression deleteExpression) { mixin (tagAndAccept!"deleteExpression"); }
1080 	override void visit(const DeleteStatement deleteStatement) { mixin (tagAndAccept!"deleteStatement"); }
1081 	override void visit(const Destructor destructor) { mixin (tagAndAccept!"destructor"); }
1082 	override void visit(const DoStatement doStatement) { mixin (tagAndAccept!"doStatement"); }
1083 	override void visit(const EnumBody enumBody) { mixin (tagAndAccept!"enumBody"); }
1084 	override void visit(const EponymousTemplateDeclaration eponymousTemplateDeclaration) { mixin (tagAndAccept!"eponymousTemplateDeclaration"); }
1085 	override void visit(const Expression expression) { mixin (tagAndAccept!"expression"); }
1086 	override void visit(const ExpressionStatement expressionStatement) { mixin (tagAndAccept!"expressionStatement"); }
1087 	override void visit(const FinalSwitchStatement finalSwitchStatement) { mixin (tagAndAccept!"finalSwitchStatement"); }
1088 	override void visit(const ForeachTypeList foreachTypeList) { mixin (tagAndAccept!"foreachTypeList"); }
1089 	override void visit(const FunctionAttribute functionAttribute) { mixin (tagAndAccept!"functionAttribute"); }
1090 	override void visit(const FunctionBody functionBody) { mixin (tagAndAccept!"functionBody"); }
1091 	override void visit(const FunctionCallExpression functionCallExpression) { mixin (tagAndAccept!"functionCallExpression"); }
1092 	override void visit(const IdentifierChain identifierChain) { mixin (tagAndAccept!"identifierChain"); }
1093 	override void visit(const IdentifierOrTemplateChain identifierOrTemplateChain) { mixin (tagAndAccept!"identifierOrTemplateChain"); }
1094 	override void visit(const IdentifierOrTemplateInstance identifierOrTemplateInstance) { mixin (tagAndAccept!"identifierOrTemplateInstance"); }
1095 	override void visit(const ImportBindings importBindings) { mixin (tagAndAccept!"importBindings"); }
1096 	override void visit(const ImportDeclaration importDeclaration) { mixin (tagAndAccept!"importDeclaration"); }
1097 	override void visit(const ImportExpression importExpression) { mixin (tagAndAccept!"importExpression"); }
1098 	override void visit(const IndexExpression indexExpression) { mixin (tagAndAccept!"indexExpression"); }
1099 	override void visit(const InStatement inStatement) { mixin (tagAndAccept!"inStatement"); }
1100 	override void visit(const InContractExpression inContractExpression) { mixin (tagAndAccept!"inContractExpression"); }
1101 	override void visit(const InOutContractExpression inOutContractExpression) { mixin (tagAndAccept!"inOutContractExpression"); }
1102 	override void visit(const KeyValuePairs keyValuePairs) { mixin (tagAndAccept!"keyValuePairs"); }
1103 	override void visit(const MixinExpression mixinExpression) { mixin (tagAndAccept!"mixinExpression"); }
1104 	override void visit(const MixinTemplateDeclaration mixinTemplateDeclaration) { mixin (tagAndAccept!"mixinTemplateDeclaration"); }
1105 	override void visit(const MixinTemplateName mixinTemplateName) { mixin (tagAndAccept!"mixinTemplateName"); }
1106 	override void visit(const ModuleDeclaration moduleDeclaration) { mixin (tagAndAccept!"moduleDeclaration"); }
1107 	override void visit(const LastCatch lastCatch) { mixin (tagAndAccept!"lastCatch"); }
1108 	override void visit(const NewExpression newExpression) { mixin (tagAndAccept!"newExpression"); }
1109 	override void visit(const NonVoidInitializer nonVoidInitializer) { mixin (tagAndAccept!"nonVoidInitializer"); }
1110 	override void visit(const Operands operands) { mixin (tagAndAccept!"operands"); }
1111 	override void visit(const OrExpression orExpression) { mixin (tagAndAccept!"orExpression"); }
1112 	override void visit(const OutStatement outStatement) { mixin (tagAndAccept!"outStatement"); } override void visit(const MixinDeclaration mixinDeclaration) { mixin (tagAndAccept!"mixinDeclaration"); }
1113 	override void visit(const Parameters parameters) { mixin (tagAndAccept!"parameters"); }
1114 	override void visit(const Postblit postblit) { mixin (tagAndAccept!"postblit"); } override void visit(const NewAnonClassExpression newAnonClassExpression) { mixin (tagAndAccept!"newAnonClassExpression"); }
1115 	override void visit(const PragmaDeclaration pragmaDeclaration) { mixin (tagAndAccept!"pragmaDeclaration"); }
1116 	override void visit(const PragmaExpression pragmaExpression) { mixin (tagAndAccept!"pragmaExpression"); }
1117 	override void visit(const PrimaryExpression primaryExpression) { mixin (tagAndAccept!"primaryExpression"); }
1118 	override void visit(const Register register) { mixin (tagAndAccept!"register"); }
1119 	override void visit(const ScopeGuardStatement scopeGuardStatement) { mixin (tagAndAccept!"scopeGuardStatement"); }
1120 	override void visit(const SharedStaticConstructor sharedStaticConstructor) { mixin (tagAndAccept!"sharedStaticConstructor"); }
1121 	override void visit(const SharedStaticDestructor sharedStaticDestructor) { mixin (tagAndAccept!"sharedStaticDestructor"); }
1122 	override void visit(const StatementNoCaseNoDefault statementNoCaseNoDefault) { mixin (tagAndAccept!"statementNoCaseNoDefault"); }
1123 	override void visit(const StaticAssertDeclaration staticAssertDeclaration) { mixin (tagAndAccept!"staticAssertDeclaration"); }
1124 	override void visit(const StaticAssertStatement staticAssertStatement) { mixin (tagAndAccept!"staticAssertStatement"); }
1125 	override void visit(const StaticConstructor staticConstructor) { mixin (tagAndAccept!"staticConstructor"); }
1126 	override void visit(const StaticDestructor staticDestructor) { mixin (tagAndAccept!"staticDestructor"); }
1127 	override void visit(const StaticIfCondition staticIfCondition) { mixin (tagAndAccept!"staticIfCondition"); }
1128 	override void visit(const StorageClass storageClass) { mixin (tagAndAccept!"storageClass"); }
1129 	override void visit(const StructBody structBody) { mixin (tagAndAccept!"structBody"); }
1130 	override void visit(const StructInitializer structInitializer) { mixin (tagAndAccept!"structInitializer"); }
1131 	override void visit(const StructMemberInitializers structMemberInitializers) { mixin (tagAndAccept!"structMemberInitializers"); }
1132 	override void visit(const StructMemberInitializer structMemberInitializer) { mixin (tagAndAccept!"structMemberInitializer"); }
1133 	override void visit(const SwitchStatement switchStatement) { mixin (tagAndAccept!"switchStatement"); }
1134 	override void visit(const Symbol symbol) { mixin (tagAndAccept!"symbol"); }
1135 	override void visit(const SynchronizedStatement synchronizedStatement) { mixin (tagAndAccept!"synchronizedStatement"); } override void visit(const Statement statement) { mixin (tagAndAccept!"statement"); }
1136 	override void visit(const TemplateArgumentList templateArgumentList) { mixin (tagAndAccept!"templateArgumentList"); }
1137 	override void visit(const TemplateArguments templateArguments) { mixin (tagAndAccept!"templateArguments"); }
1138 	override void visit(const TemplateArgument templateArgument) { mixin (tagAndAccept!"templateArgument"); }
1139 	override void visit(const TemplateMixinExpression templateMixinExpression) { mixin (tagAndAccept!"templateMixinExpression"); }
1140 	override void visit(const TemplateParameterList templateParameterList) { mixin (tagAndAccept!"templateParameterList"); }
1141 	override void visit(const TemplateParameters templateParameters) { mixin (tagAndAccept!"templateParameters"); }
1142 	override void visit(const TemplateParameter templateParameter) { mixin (tagAndAccept!"templateParameter"); }
1143 	override void visit(const TemplateSingleArgument templateSingleArgument) { mixin (tagAndAccept!"templateSingleArgument"); }
1144 	override void visit(const TemplateThisParameter templateThisParameter) { mixin (tagAndAccept!"templateThisParameter"); }
1145 	override void visit(const TemplateTupleParameter templateTupleParameter) { mixin (tagAndAccept!"templateTupleParameter"); }
1146 	override void visit(const TemplateTypeParameter templateTypeParameter) { mixin (tagAndAccept!"templateTypeParameter"); }
1147 	override void visit(const TemplateValueParameterDefault templateValueParameterDefault) { mixin (tagAndAccept!"templateValueParameterDefault"); }
1148 	override void visit(const TemplateValueParameter templateValueParameter) { mixin (tagAndAccept!"templateValueParameter"); }
1149 	override void visit(const TernaryExpression ternaryExpression) { mixin (tagAndAccept!"ternaryExpression"); }
1150 	override void visit(const TypeIdentifierPart typeIdentifierPart) { mixin (tagAndAccept!"typeIdentifierPart"); }
1151 	override void visit(const ThrowStatement throwStatement) { mixin (tagAndAccept!"throwStatement"); }
1152 	override void visit(const TryStatement tryStatement) { mixin (tagAndAccept!"tryStatement"); } override void visit(const TemplateInstance templateInstance) { mixin (tagAndAccept!"templateInstance"); }
1153 	override void visit(const TypeofExpression typeofExpression) { mixin (tagAndAccept!"typeofExpression"); } override void visit(const TypeSpecialization typeSpecialization) { mixin (tagAndAccept!"typeSpecialization"); } override void visit(const TraitsExpression traitsExpression) { mixin (tagAndAccept!"traitsExpression"); }
1154 	override void visit(const Vector vector) { mixin (tagAndAccept!"vector"); }
1155 	override void visit(const VersionCondition versionCondition) { mixin (tagAndAccept!"versionCondition"); }
1156 	override void visit(const VersionSpecification versionSpecification) { mixin (tagAndAccept!"versionSpecification"); }
1157 	override void visit(const WhileStatement whileStatement) { mixin (tagAndAccept!"whileStatement"); }
1158 	override void visit(const WithStatement withStatement) { mixin (tagAndAccept!"withStatement"); } override void visit(const TypeidExpression typeidExpression) { mixin (tagAndAccept!"typeidExpression"); }
1159 	// dfmt on
1160 
1161 	alias visit = ASTVisitor.visit;
1162 
1163 	private static string xmlEscape(string s)
1164 	{
1165 		return s.translate(['<' : "&lt;", '>' : "&gt;", '&' : "&amp;"]);
1166 	}
1167 
1168 	private static string xmlAttributeEscape(string s)
1169 	{
1170 		return s.translate(['<' : "&lt;", '>' : "&gt;", '&' : "&amp;", '\"'
1171 				: "&quot;", '\'' : "&apos;"]);
1172 	}
1173 
1174 	private void writeName(string name)
1175 	{
1176 		output.writeln("<name>", name, "</name>");
1177 	}
1178 
1179 	private void writeDdoc(string comment)
1180 	{
1181 		if (comment.ptr is null)
1182 			return;
1183 		output.writeln("<ddoc>", xmlEscape(comment), "</ddoc>");
1184 	}
1185 
1186 	/**
1187 	* File that output  is written to.
1188 	*/
1189 	File output;
1190 }
1191 
1192 private:
1193 
1194 template tagAndAccept(string tagName)
1195 {
1196 	immutable tagAndAccept = `output.writeln("<` ~ tagName ~ `>");` ~ tagName
1197 		~ `.accept(this);` ~ `output.writeln("</` ~ tagName ~ `>");`;
1198 }