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