1 module dparse.formatter;
2 
3 import std.algorithm;
4 import std.range;
5 import std.stdio;
6 import std.typetuple:TypeTuple;
7 
8 import dparse.ast;
9 import dparse.lexer;
10 version (unittest)
11 {
12     import dparse.parser;
13     import dparse.rollback_allocator;
14     import std.array : Appender;
15     import std.algorithm : canFind;
16 }
17 
18 //debug = verbose;
19 
20 /**
21  * The only brace styles worth using.
22  */
23 enum IndentStyle
24 {
25     /**
26      * ---
27      * if (something)
28      * {
29      *     foo();
30      *     bar();
31      * }
32      * else
33      * {
34      *     bar();
35      *     baz();
36      * }
37      * ---
38      */
39     allman,
40     /**
41      * ---
42      * if (something) {
43      *     foo();
44      *     bar();
45      * } else {
46      *     bar();
47      *     baz();
48      * }
49      * ---
50      */
51     otbs,
52 }
53 
54 /**
55  *
56  */
57 void format(Sink, T)(Sink sink, T node, bool useTabs = false,
58     IndentStyle style = IndentStyle.allman, uint indentWith = 4)
59 {
60     Formatter!Sink formatter = new Formatter!(Sink)(sink, useTabs, style, indentWith);
61     formatter.format(node);
62 }
63 
64 ///
65 class Formatter(Sink)
66 {
67     /**
68      * Params:
69      *     sink = the output range that the formatted source code is placed in
70      *     useTabs = if true, tabs are used for indent levels instead of spaces
71      *     style = the brace style
72      *     indentWidth = the number of spaces used for indentation if useTabs is false
73      */
74     this(Sink sink, bool useTabs = false, IndentStyle style = IndentStyle.allman, uint indentWidth = 4)
75     {
76         this.sink = sink;
77         this.useTabs = useTabs;
78         this.style = style;
79         this.indentWidth = indentWidth;
80     }
81 
82     ///
83     void format(const AddExpression addExpression)
84     {
85         debug(verbose) writeln("AddExpression");
86         mixin(binary("addExpression"));
87     }
88 
89     ///
90     void format(const AliasDeclaration aliasDeclaration, const Attribute[] attrs = null)
91     {
92         debug(verbose) writeln("AliasDeclaration");
93 
94         /**
95         LinkageAttribute linkageAttribute;
96         Type type;
97         Token name;
98         AliasInitializer[] initializers;
99         string comment;
100         **/
101 
102         with(aliasDeclaration)
103         {
104             newThing(What.other);
105             putComment(comment);
106             putAttrs(attrs);
107             put("alias ");
108 
109             if (initializers.length) // alias ident = a, ident2 = b, etc
110             {
111                 foreach(count, init; initializers)
112                 {
113                     if (count)
114                         put(", ");
115                     format(init);
116                 }
117             }
118             else
119             {
120                 foreach (storageClass; storageClasses)
121                 {
122                     format(storageClass);
123                     space();
124                 }
125 
126                 if (type)
127                 {
128                     format(type);
129                     space();
130                 }
131                 if (declaratorIdentifierList)
132                 {
133                     format(declaratorIdentifierList);
134                 }
135             }
136             put(";");
137         }
138     }
139 
140     void format(const AliasInitializer aliasInitializer)
141     {
142         debug(verbose) writeln("AliasInitializer");
143 
144         /**
145         Token name;
146         Type type;
147         **/
148 
149         with(aliasInitializer)
150         {
151             format(name);
152             put(" = ");
153             format(type);
154         }
155     }
156 
157     void format(const AliasThisDeclaration decl, const Attribute[] attrs = null)
158     {
159         debug(verbose) writeln("AliasThisDeclaration");
160 
161         /**
162         Token identifier;
163         **/
164 
165         putAttrs(attrs);
166         put("alias ");
167         format(decl.identifier);
168         put(" this;");
169     }
170 
171     void format(const AlignAttribute alignAttribute)
172     {
173         debug(verbose) writeln("AlignAttribute");
174 
175         /**
176         Token intLiteral;
177         **/
178 
179         put("align");
180         if (alignAttribute.assignExpression !is null)
181         {
182             put("(");
183             format(alignAttribute.assignExpression);
184             put(")");
185         }
186     }
187 
188     void format(const AndAndExpression andAndExpression)
189     {
190         debug(verbose) writeln("AndAndExpression");
191 
192         with(andAndExpression)
193         {
194             format(left);
195             if (right)
196             {
197                 put(" && ");
198                 format(right);
199             }
200         }
201     }
202 
203     void format(const AndExpression andExpression)
204     {
205         debug(verbose) writeln("AndExpression");
206 
207         with(andExpression)
208         {
209             format(left);
210             if (right)
211             {
212                 put(" & ");
213                 format(right);
214             }
215         }
216     }
217 
218     void format(const ArgumentList argumentList)
219     {
220         debug(verbose) writeln("ArgumentList");
221 
222         foreach(count, arg; argumentList.items)
223         {
224             if (count) put(", ");
225             format(arg);
226         }
227     }
228 
229     void format(const Arguments arguments)
230     {
231         debug(verbose) writeln("Arguments");
232 
233         put("(");
234         if (arguments.argumentList) format(arguments.argumentList);
235         put(")");
236     }
237 
238     void format(const ArrayInitializer arrayInitializer)
239     {
240         debug(verbose) writeln("ArrayInitializer");
241 
242         /**
243         ArrayMemberInitialization[] arrayMemberInitializations;
244         **/
245 
246         put("[");
247         foreach(count, init; arrayInitializer.arrayMemberInitializations)
248         {
249             format(init);
250             if (count < arrayInitializer.arrayMemberInitializations.length - 1)
251                 put(", ");
252         }
253         put("]");
254     }
255 
256     void format(const ArrayLiteral arrayLiteral)
257     {
258         debug(verbose) writeln("ArrayLiteral");
259 
260         /**
261         ArgumentList argumentList;
262         **/
263         put("[");
264         if (arrayLiteral.argumentList)
265             format(arrayLiteral.argumentList);
266         put("]");
267     }
268 
269     void format(const ArrayMemberInitialization arrayMemberInitialization)
270     {
271         debug(verbose) writeln("ArrayMemberInitialization");
272 
273         /**
274         AssignExpression assignExpression;
275         NonVoidInitializer nonVoidInitializer;
276         **/
277 
278         with(arrayMemberInitialization)
279         {
280             if (assignExpression)
281             {
282                 format(assignExpression);
283                 put(":");
284             }
285             if (nonVoidInitializer)
286                 format(nonVoidInitializer);
287 
288         }
289     }
290 
291     void format(const AsmAddExp asmAddExp)
292     {
293         assert(false);
294     }
295 
296     void format(const AsmAndExp asmAndExp)
297     {
298         assert(false);
299     }
300 
301     void format(const AsmBrExp asmBrExp)
302     {
303         assert(false);
304     }
305 
306     void format(const AsmEqualExp asmEqualExp)
307     {
308         assert(false);
309     }
310 
311     void format(const AsmExp asmExp)
312     {
313         assert(false);
314     }
315 
316     void format(const AsmInstruction asmInstruction)
317     {
318         assert(false);
319     }
320 
321     void format(const AsmLogAndExp asmLogAndExp)
322     {
323         assert(false);
324     }
325 
326     void format(const AsmLogOrExp asmLogOrExp)
327     {
328         assert(false);
329     }
330 
331     void format(const AsmMulExp asmMulExp)
332     {
333         assert(false);
334     }
335 
336     void format(const AsmOrExp asmOrExp)
337     {
338         assert(false);
339     }
340 
341     void format(const AsmPrimaryExp asmPrimaryExp)
342     {
343         assert(false);
344     }
345 
346     void format(const AsmRelExp asmRelExp)
347     {
348         assert(false);
349     }
350 
351     void format(const AsmShiftExp asmShiftExp)
352     {
353         assert(false);
354     }
355 
356     void format(const AsmStatement asmStatement)
357     {
358         assert(false);
359     }
360 
361     void format(const AsmTypePrefix asmTypePrefix)
362     {
363         assert(false);
364     }
365 
366     void format(const AsmUnaExp asmUnaExp)
367     {
368         assert(false);
369     }
370 
371     void format(const AsmXorExp asmXorExp)
372     {
373         assert(false);
374     }
375 
376     void format(const AssertExpression assertExpression)
377     {
378         debug(verbose) writeln("AssertExpression");
379 
380         /**
381         AssignExpression assertion;
382         AssignExpression message;
383         **/
384 
385         with(assertExpression)
386         {
387             put("assert (");
388             format(assertion);
389             if (message)
390             {
391                 put(", ");
392                 format(message);
393             }
394             put(")");
395         }
396     }
397 
398     void format(const AssignExpression assignExpression)
399     {
400         debug(verbose) writeln("AssignExpression");
401 
402         /**
403         ExpressionNode ternaryExpression;
404         ExpressionNode assignExpression;
405         IdType operator;
406         **/
407 
408         if (assignExpression.ternaryExpression)
409             format(assignExpression.ternaryExpression);
410 
411         if(assignExpression.expression)
412         {
413             space();
414             put(tokenRep(assignExpression.operator));
415             space();
416             format(assignExpression.expression);
417         }
418     }
419 
420     void format(const AssocArrayLiteral assocArrayLiteral)
421     {
422         debug(verbose) writeln("AssocArrayLiteral");
423 
424         /**
425         KeyValuePairs keyValuePairs;
426         **/
427 
428         put("[");
429         format(assocArrayLiteral.keyValuePairs);
430         put("]");
431     }
432 
433     void format(const AtAttribute atAttribute)
434     {
435         debug(verbose) writeln("AtAttribute");
436 
437         /**
438         FunctionCallExpression functionCallExpression;
439         ArgumentList argumentList;
440         Token identifier;
441         **/
442 
443         with(atAttribute)
444         {
445             put("@");
446             format(identifier);
447             if(argumentList) format(argumentList);
448         }
449     }
450 
451     void format(const Attribute att)
452     {
453         debug(verbose) writeln("Attribute");
454 
455         /**
456         LinkageAttribute linkageAttribute;
457         AlignAttribute alignAttribute;
458         PragmaExpression pragmaExpression;
459         StorageClass storageClass;
460         IdType attribute;
461         **/
462 
463         with(att)
464         {
465             if (pragmaExpression) format(pragmaExpression);
466             if (attribute.type != tok!"") put(tokenRep(attribute.type));
467             if (identifierChain)
468             {
469                 put("(");
470                 format(identifierChain);
471                 put(")");
472             }
473             if (deprecated_) format(deprecated_);
474             if (atAttribute) format(atAttribute);
475             if (linkageAttribute) format(linkageAttribute);
476         }
477     }
478 
479     void format(const AttributeDeclaration decl, const Attribute[] attrs = null)
480     {
481         debug(verbose) writeln("AttributeDeclaration");
482 
483         auto cIndent = indentLevel;
484         outdent();
485         newThing(What.attributeDecl);
486         putAttrs(attrs);
487         format(decl.attribute);
488         put(":");
489         indentLevel = cIndent;
490     }
491 
492     void format(const AutoDeclaration decl)
493     {
494         debug(verbose) writeln("AutoDeclaration");
495 
496         /**
497         Token[] identifiers;
498         Initializer[] initializers;
499         **/
500 
501         // zip doesn't work here, dmd 2.064.2
502         foreach(i, part; decl.parts)
503         {
504             if (i > 0) put(", ");
505             format(part.identifier);
506             if (part.templateParameters)
507                 format(part.templateParameters);
508             put(" = ");
509             format(part.initializer);
510         }
511     }
512 
513     void format(const BlockStatement blockStatement)
514     {
515         debug(verbose) writeln("BlockStatement");
516 
517         if (blockStatement.declarationsAndStatements is null)
518         {
519             space();
520             put("{}");
521         }
522         else
523         {
524             startBlock();
525             format(blockStatement.declarationsAndStatements);
526             endBlock();
527         }
528     }
529 
530     void format(const BodyStatement bodyStatement)
531     {
532         debug(verbose) writeln("BodyStatement");
533 
534         newline();
535         put("do");
536         format(bodyStatement.blockStatement);
537     }
538 
539     void format(const BreakStatement breakStatement)
540     {
541         debug(verbose) writeln("BreakStatement");
542 
543         put("break");
544         if (breakStatement.label != tok!"")
545         {
546             space();
547             format(breakStatement.label);
548         }
549         put(";");
550     }
551 
552     void format(const BaseClass baseClass)
553     {
554         debug(verbose) writeln("BaseClass");
555         with(baseClass)
556         {
557             if (type2) format(type2);
558         }
559     }
560 
561     void format(const BaseClassList baseClassList)
562     {
563         debug(verbose) writeln("BaseClassList");
564         put(" : ");
565         foreach(count, item; baseClassList.items)
566         {
567             format(item);
568             if (count < baseClassList.items.length - 1)
569                 put(", ");
570         }
571     }
572 
573     void format(const CaseRangeStatement caseRangeStatement)
574     {
575         debug(verbose) writeln("CaseRangeStatement");
576 
577         /**
578         AssignExpression low;
579         AssignExpression high;
580         DeclarationsAndStatements declarationsAndStatements;
581         **/
582 
583         with(caseRangeStatement)
584         {
585             if (low)
586             {
587                 put("case ");
588                 format(low);
589                 put(": .. ");
590             }
591             put("case ");
592             format(high);
593             put(":");
594 
595             formatCaseDecls(declarationsAndStatements);
596         }
597     }
598 
599     void format(const CaseStatement caseStatement)
600     {
601         debug(verbose) writeln("CaseStatement");
602 
603         /**
604         ArgumentList argumentList;
605         DeclarationsAndStatements declarationsAndStatements;
606         **/
607 
608         with(caseStatement)
609         {
610             if (argumentList)
611             {
612                 put("case ");
613                 format(argumentList);
614                 put(":");
615             }
616 
617             formatCaseDecls(declarationsAndStatements);
618         }
619     }
620 
621     void format(const CastExpression castExpression)
622     {
623         debug(verbose) writeln("CastExpression");
624 
625         /**
626         Type type;
627         CastQualifier castQualifier;
628         UnaryExpression unaryExpression;
629         **/
630 
631         with(castExpression)
632         {
633             put("cast(");
634             if (castQualifier)
635             {
636                 format(castQualifier);
637                 space();
638             }
639             if (type) format(type);
640             put(")");
641             if (unaryExpression) format(unaryExpression);
642         }
643     }
644 
645     void format(const CastQualifier qual)
646     {
647         debug(verbose) writeln("CastQualifier");
648 
649         /**
650         Token first;
651         Token second;
652         **/
653 
654         format(qual.first);
655         if (qual.second != tok!"")
656         {
657             space();
658             format(qual.second);
659         }
660     }
661 
662     void format(const Catch catch_)
663     {
664         debug(verbose) writeln("Catch");
665 
666         /**
667         Type type;
668         Token identifier;
669         DeclarationOrStatement declarationOrStatement;
670         **/
671 
672         with(catch_)
673         {
674             newThing(What.catch_);
675             put("catch(");
676             format(type);
677             if (identifier != tok!"")
678             {
679                 space();
680                 format(identifier);
681             }
682             put(")");
683             if (declarationOrStatement) maybeIndent(declarationOrStatement);
684         }
685     }
686 
687     void format(const Catches catches)
688     {
689         debug(verbose) writeln("Catches");
690 
691         /**
692         Catch[] catches;
693         LastCatch lastCatch;
694         **/
695 
696         foreach(c; catches.catches)
697             format(c);
698         if (catches.lastCatch)
699             format(catches.lastCatch);
700     }
701 
702     void format(const ClassDeclaration decl, const Attribute[] attrs = null)
703     {
704         debug(verbose) writeln("ClassDeclaration");
705 
706         /**
707         Token name;
708         TemplateParameters templateParameters;
709         Constraint constraint;
710         BaseClassList baseClassList;
711         StructBody structBody;
712         string comment;
713         **/
714 
715         newThing(What.aggregateDecl);
716         putComment(decl.comment);
717         putAttrs(attrs);
718 
719         put("class ");
720         format(decl.name);
721 
722         if (decl.templateParameters)
723             format(decl.templateParameters);
724 
725         if (decl.constraint)
726         {
727             space();
728             format(decl.constraint);
729         }
730 
731         if (decl.baseClassList)
732         {
733             format(decl.baseClassList);
734         }
735 
736         format(decl.structBody);
737     }
738 
739     void format(const CmpExpression cmpExpression)
740     {
741         debug(verbose) writeln("CmpExpression");
742 
743         /**
744         ExpressionNode shiftExpression;
745         ExpressionNode equalExpression;
746         ExpressionNode identityExpression;
747         ExpressionNode relExpression;
748         ExpressionNode inExpression;
749         **/
750 
751         with(cmpExpression)
752         {
753             if (shiftExpression) format(shiftExpression);
754             else if (equalExpression) format(equalExpression);
755             else if (identityExpression) format(identityExpression);
756             else if (relExpression) format(relExpression);
757             else if (inExpression) format(inExpression);
758         }
759     }
760 
761     void format(const CompileCondition compileCondition)
762     {
763         debug(verbose) writeln("CompileCondition");
764 
765         /**
766         VersionCondition versionCondition;
767         DebugCondition debugCondition;
768         StaticIfCondition staticIfCondition;
769         **/
770 
771         with(compileCondition)
772         {
773             if (versionCondition) format(versionCondition);
774             else if (debugCondition) format(debugCondition);
775             else if (staticIfCondition) format(staticIfCondition);
776         }
777     }
778 
779     void format(const ConditionalDeclaration decl, const Attribute[] attrs = null)
780     {
781         debug(verbose) writeln("ConditionalDeclaration");
782 
783         /**
784         CompileCondition compileCondition;
785         Declaration[] trueDeclarations;
786         Declaration[] falseDeclaration;
787         **/
788 
789         newThing(What.conditionalDecl);
790         putAttrs(attrs);
791         format(decl.compileCondition);
792 
793         if (decl.trueDeclarations.length > 1)
794         {
795             startBlock();
796             foreach (d; decl.trueDeclarations)
797                 format(d);
798             endBlock();
799         }
800         else if (decl.trueDeclarations.length == 0)
801             maybeIndent(decl.trueDeclarations[0]);
802         else
803             put("{}");
804 
805         if (decl.falseDeclarations.length > 0)
806             put("else");
807 
808         if (decl.falseDeclarations.length > 1)
809         {
810             startBlock();
811             foreach (d; decl.falseDeclarations)
812                 format(d);
813             endBlock();
814         }
815         else if (decl.falseDeclarations.length == 1)
816             maybeIndent(decl.falseDeclarations[0]);
817         else
818             put("{}");
819     }
820 
821     void format(const ConditionalStatement stmnt)
822     {
823         debug(verbose) writeln("ConditionalStatement");
824 
825         /**
826         CompileCondition compileCondition;
827         DeclarationOrStatement trueStatement;
828         DeclarationOrStatement falseStatement;
829         **/
830 
831         newThing(What.other);
832         if (stmnt.compileCondition)
833             format(stmnt.compileCondition);
834 
835         if (stmnt.trueStatement)
836             maybeIndent(stmnt.trueStatement);
837 
838         if (stmnt.falseStatement)
839         {
840             newThing(What.else_);
841             put("else ");
842 
843             // else if...
844             if (stmnt.falseStatement.statement &&
845                 stmnt.falseStatement.statement.statementNoCaseNoDefault &&
846                 stmnt.falseStatement.statement.statementNoCaseNoDefault.conditionalStatement)
847             {
848                 format(stmnt.falseStatement.statement.statementNoCaseNoDefault.conditionalStatement);
849                 return;
850             }
851 
852             maybeIndent(stmnt.falseStatement);
853         }
854     }
855 
856     void format(const Constraint constraint)
857     {
858         debug(verbose) writeln("Constraint");
859 
860         if (constraint.expression)
861         {
862             indent();
863             newline();
864             put("if(");
865             format(constraint.expression);
866             put(")");
867             outdent();
868         }
869     }
870 
871     void format(const Constructor constructor, const Attribute[] attrs = null)
872     {
873         debug(verbose) writeln("Constructor");
874 
875         /**
876         Parameters parameters;
877         FunctionBody functionBody;
878         Constraint constraint;
879         MemberFunctionAttribute[] memberFunctionAttributes;
880         TemplateParameters templateParameters;
881         size_t location;
882         string comment;
883         **/
884 
885         newThing(What.functionDecl);
886         putComment(constructor.comment);
887         putAttrs(attrs);
888 
889         put("this");
890 
891         if (constructor.templateParameters)
892             format(constructor.templateParameters);
893 
894         if (constructor.parameters)
895             format(constructor.parameters);
896 
897         foreach(att; constructor.memberFunctionAttributes)
898         {
899             space();
900             format(att);
901         }
902 
903         if (constructor.constraint)
904         {
905             space();
906             format(constructor.constraint);
907         }
908 
909         if (constructor.functionBody)
910             format(constructor.functionBody);
911         else
912             put(";");
913     }
914 
915     void format(const ContinueStatement continueStatement)
916     {
917         debug(verbose) writeln("ContinueStatement");
918 
919         put("continue");
920         if (continueStatement.label != tok!"")
921         {
922             space();
923             format(continueStatement.label);
924         }
925         put(";");
926     }
927 
928     void format(const DebugCondition debugCondition)
929     {
930         debug(verbose) writeln("DebugCondition");
931 
932         put("debug");
933         if (debugCondition.identifierOrInteger != tok!"")
934         {
935             put("(");
936             format(debugCondition.identifierOrInteger);
937             put(")");
938         }
939     }
940 
941     void format(const DebugSpecification debugSpecification)
942     {
943         debug(verbose) writeln("DebugSpecification");
944 
945         newThing(What.other);
946         put("debug = ");
947         format(debugSpecification.identifierOrInteger);
948         put(";");
949     }
950 
951     void format(const Declaration declaration)
952     {
953         debug(verbose) writeln("Declaration");
954 
955         with(declaration)
956         {
957             string mix(string[] s) {
958                 string r;
959                 foreach(c, d; s)
960                     r ~= (c > 0 ? "else " : "") ~ "if (" ~ d ~ ") { format(" ~ d ~ ", attributes); }";
961                 return r;
962             }
963 
964             mixin(mix(possibleDeclarations));
965 
966             if (declarations.length)
967             {
968                 putAttrs(attributes);
969                 startBlock();
970                 foreach(d; declarations)
971                     format(d);
972                 endBlock();
973             }
974         }
975     }
976 
977     void format(const DeclarationOrStatement declarationsOrStatement)
978     {
979         debug(verbose) writeln("DeclarationOrStatement");
980 
981         with(declarationsOrStatement)
982             declaration !is null ? format(declaration) : format(statement);
983     }
984 
985     void format(const DeclarationsAndStatements declarationsAndStatements)
986     {
987         debug(verbose) writeln("DeclarationsAndStatements");
988 
989         foreach(ds; declarationsAndStatements.declarationsAndStatements)
990             format(ds);
991     }
992 
993     void format(const Declarator declarator)
994     {
995         debug(verbose) writeln("Declarator");
996 
997         /**
998         Token name;
999         Initializer initializer;
1000         **/
1001 
1002         format(declarator.name);
1003 
1004         foreach(suffix; declarator.cstyle)
1005             format(suffix);
1006 
1007         if (declarator.templateParameters)
1008             format(declarator.templateParameters);
1009 
1010         if (declarator.initializer)
1011         {
1012             put(" = ");
1013             format(declarator.initializer);
1014         }
1015     }
1016 
1017     void format(const DefaultStatement defaultStatement)
1018     {
1019         debug(verbose) writeln("DefaultStatement");
1020 
1021         /**
1022         DeclarationsAndStatements declarationsAndStatements;
1023         **/
1024 
1025         put("default:");
1026         formatCaseDecls(defaultStatement.declarationsAndStatements);
1027     }
1028 
1029     void format(const DeleteExpression deleteExpression)
1030     {
1031         debug(verbose) writeln("DeleteExpression");
1032 
1033         put("delete ");
1034         format(deleteExpression.unaryExpression);
1035     }
1036 
1037     void format(const DeleteStatement deleteStatement)
1038     {
1039         debug(verbose) writeln("DeleteStatement");
1040 
1041         format(deleteStatement.deleteExpression);
1042         put(";");
1043     }
1044 
1045     void format(const Deprecated deprecated_)
1046     {
1047         debug (verbose)
1048             writeln("Deprecated");
1049         put("deprecated");
1050         if (deprecated_.assignExpression !is null)
1051         {
1052             put("(");
1053             format(deprecated_.assignExpression);
1054             put(")");
1055         }
1056     }
1057 
1058     void format(const Destructor destructor, const Attribute[] attrs = null)
1059     {
1060         debug(verbose) writeln("Destructor");
1061 
1062         /**
1063         FunctionBody functionBody;
1064         **/
1065 
1066         newThing(What.functionDecl);
1067         putAttrs(attrs);
1068         put("~this()");
1069 
1070         if (destructor.functionBody)
1071             format(destructor.functionBody);
1072         else
1073             put(";");
1074     }
1075 
1076     void format(const DoStatement doStatement)
1077     {
1078         debug(verbose) writeln("DoStatement");
1079 
1080         /**
1081         StatementNoCaseNoDefault statementNoCaseNoDefault;
1082         Expression expression;
1083         **/
1084 
1085         with(doStatement)
1086         {
1087             newThing(What.other);
1088             put("do");
1089             if (statementNoCaseNoDefault) format(statementNoCaseNoDefault);
1090             space();
1091             put("while (");
1092             format(expression);
1093             put(");");
1094         }
1095     }
1096 
1097     void format(const EnumBody enumBody)
1098     {
1099         debug(verbose) writeln("EnumBody");
1100 
1101         newline();
1102         startBlock();
1103         foreach(count, member; enumBody.enumMembers)
1104         {
1105             format(member);
1106 
1107             if (count < enumBody.enumMembers.length - 1)
1108                 put(",");
1109 
1110             if (member.comment.length)
1111             {
1112                 space();
1113                 put(member.comment);
1114             }
1115         }
1116         endBlock();
1117     }
1118 
1119     void format(const EnumDeclaration enumDeclaration, const Attribute[] attrs = null)
1120     {
1121         debug(verbose) writeln("EnumDeclaration");
1122 
1123         /**
1124         Token name;
1125         Type type;
1126         EnumBody enumBody;
1127         string comment;
1128         **/
1129 
1130         with(enumDeclaration)
1131         {
1132             newThing(What.aggregateDecl);
1133             putComment(comment);
1134             putAttrs(attrs);
1135             put("enum ");
1136             if (name != tok!"")
1137             {
1138                 format(name);
1139                 space();
1140             }
1141             if (type)
1142             {
1143                 put(": ");
1144                 format(type);
1145                 space();
1146             }
1147             if (enumBody) format(enumBody);
1148         }
1149     }
1150 
1151     void format(const EnumMember enumMember)
1152     {
1153         debug(verbose) writeln("EnumMember");
1154 
1155         /**
1156         Token name;
1157         Type type;
1158         AssignExpression assignExpression;
1159         string comment;
1160         **/
1161 
1162         with(enumMember)
1163         {
1164             newline();
1165             if (type) format(type);
1166             format(name);
1167             if (assignExpression)
1168             {
1169                 put(" = ");
1170                 format(assignExpression);
1171             }
1172         }
1173     }
1174 
1175     void format(const EponymousTemplateDeclaration decl)
1176     {
1177         debug(verbose) writeln("EponymousTemplateDeclaration");
1178 
1179         /**
1180         Token name;
1181         TemplateParameters templateParameters;
1182         AssignExpression assignExpression;
1183         **/
1184 
1185         put("enum ");
1186         put(tokenRep(decl.name));
1187         if (decl.templateParameters)
1188             format(decl.templateParameters);
1189         if (decl.assignExpression)
1190         {
1191             put(" = ");
1192             format(decl.assignExpression);
1193         }
1194         put(";");
1195     }
1196 
1197     void format(const EqualExpression equalExpression)
1198     {
1199         debug(verbose) writeln("EqualExpression");
1200 
1201         mixin(binary("equalExpression"));
1202     }
1203 
1204     void format(const Expression expression)
1205     {
1206         debug(verbose) writeln("Expression");
1207 
1208         foreach(count, item; expression.items)
1209         {
1210             if (count)
1211                 put(", ");
1212             format(item);
1213         }
1214     }
1215 
1216     void format(const ExpressionNode n)
1217     {
1218         debug(verbose) writeln("ExpressionNode");
1219 
1220         if (cast(AddExpression) n) format(cast(AddExpression) n);
1221         else if (cast(AndAndExpression) n) format(cast(AndAndExpression) n);
1222         else if (cast(AndExpression) n) format(cast(AndExpression) n);
1223         else if (cast(AsmAddExp) n) format(cast(AsmAddExp) n);
1224         else if (cast(AsmAndExp) n) format(cast(AsmAndExp) n);
1225         else if (cast(AsmEqualExp) n) format(cast(AsmEqualExp) n);
1226         else if (cast(AsmLogAndExp) n) format(cast(AsmLogAndExp) n);
1227         else if (cast(AsmLogOrExp) n) format(cast(AsmLogOrExp) n);
1228         else if (cast(AsmMulExp) n) format(cast(AsmMulExp) n);
1229         else if (cast(AsmOrExp) n) format(cast(AsmOrExp) n);
1230         else if (cast(AsmRelExp) n) format(cast(AsmRelExp) n);
1231         else if (cast(AsmShiftExp) n) format(cast(AsmShiftExp) n);
1232         else if (cast(AssertExpression) n) format(cast(AssertExpression) n);
1233         else if (cast(AssignExpression) n) format(cast(AssignExpression) n);
1234         else if (cast(CmpExpression) n) format(cast(CmpExpression) n);
1235         else if (cast(DeleteExpression) n) format(cast(DeleteExpression) n);
1236         else if (cast(EqualExpression) n) format(cast(EqualExpression) n);
1237         else if (cast(Expression) n) format(cast(Expression) n);
1238         else if (cast(FunctionCallExpression) n) format(cast(FunctionCallExpression) n);
1239         else if (cast(FunctionLiteralExpression) n) format(cast(FunctionLiteralExpression) n);
1240         else if (cast(IdentityExpression) n) format(cast(IdentityExpression) n);
1241         else if (cast(ImportExpression) n) format(cast(ImportExpression) n);
1242         else if (cast(IndexExpression) n) format(cast(IndexExpression) n);
1243         else if (cast(InExpression) n) format(cast(InExpression) n);
1244         else if (cast(IsExpression) n) format(cast(IsExpression) n);
1245         else if (cast(MixinExpression) n) format(cast(MixinExpression) n);
1246         else if (cast(MulExpression) n) format(cast(MulExpression) n);
1247         else if (cast(NewAnonClassExpression) n) format(cast(NewAnonClassExpression) n);
1248         else if (cast(NewExpression) n) format(cast(NewExpression) n);
1249         else if (cast(OrExpression) n) format(cast(OrExpression) n);
1250         else if (cast(OrOrExpression) n) format(cast(OrOrExpression) n);
1251         else if (cast(PowExpression) n) format(cast(PowExpression) n);
1252         else if (cast(PragmaExpression) n) format(cast(PragmaExpression) n);
1253         else if (cast(PrimaryExpression) n) format(cast(PrimaryExpression) n);
1254         else if (cast(RelExpression) n) format(cast(RelExpression) n);
1255         else if (cast(ShiftExpression) n) format(cast(ShiftExpression) n);
1256         else if (cast(TemplateMixinExpression) n) format(cast(TemplateMixinExpression) n);
1257         else if (cast(TernaryExpression) n) format(cast(TernaryExpression) n);
1258         else if (cast(TraitsExpression) n) format(cast(TraitsExpression) n);
1259         else if (cast(TypeidExpression) n) format(cast(TypeidExpression) n);
1260         else if (cast(TypeofExpression) n) format(cast(TypeofExpression) n);
1261         else if (cast(UnaryExpression) n) format(cast(UnaryExpression) n);
1262         else if (cast(XorExpression) n) format(cast(XorExpression) n);
1263     }
1264 
1265     void format(const ExpressionStatement expressionStatement)
1266     {
1267         debug(verbose) writeln("ExpressionStatement");
1268 
1269         if (expressionStatement.expression)
1270             format(expressionStatement.expression);
1271         put(";");
1272     }
1273 
1274     void format(const FinalSwitchStatement finalSwitchStatement)
1275     {
1276         debug(verbose) writeln("FinalSwitchStatement");
1277 
1278         format(finalSwitchStatement.switchStatement, true);
1279     }
1280 
1281     void format(const Finally finally_)
1282     {
1283         debug(verbose) writeln("Finally");
1284 
1285         put("finally");
1286         format(finally_.declarationOrStatement);
1287     }
1288 
1289     void format(const ForStatement forStatement)
1290     {
1291         debug(verbose) writeln("ForStatement");
1292 
1293         /**
1294         DeclarationOrStatement initialization;
1295         ExpressionStatement test;
1296         Expression increment;
1297         DeclarationOrStatement declarationOrStatement;
1298         **/
1299 
1300         with(forStatement)
1301         {
1302             newThing(What.other);
1303             put("for (");
1304             if (initialization) format(initialization);
1305             else put(";");
1306             space();
1307             if (test) format(test);
1308             put(";");
1309             space();
1310             if (increment) format(increment);
1311             put(")");
1312 
1313             if (declarationOrStatement) maybeIndent(declarationOrStatement);
1314         }
1315     }
1316 
1317     void format(const ForeachStatement foreachStatement)
1318     {
1319         debug(verbose) writeln("ForeachStatement");
1320 
1321         /**
1322         IdType type;
1323         ForeachTypeList foreachTypeList;
1324         ForeachType foreachType;
1325         Expression low;
1326         Expression high;
1327         DeclarationOrStatement declarationOrStatement;
1328         size_t startIndex;
1329         **/
1330 
1331         with(foreachStatement)
1332         {
1333             newThing(What.loop);
1334             if (type) put(tokenRep(type));
1335             else assert(false);
1336 
1337             put(" (");
1338             if (foreachTypeList) format(foreachTypeList);
1339             else if (foreachType) format(foreachType);
1340 
1341             put("; ");
1342 
1343             if (low) format(low);
1344             if (high)
1345             {
1346                 put("..");
1347                 format(high);
1348             }
1349             put(")");
1350             format(declarationOrStatement);
1351         }
1352     }
1353 
1354     void format(const ForeachType foreachType)
1355     {
1356         debug(verbose) writeln("ForeachType");
1357 
1358         /**
1359         IdType[] typeConstructors;
1360         Type type;
1361         Token identifier;
1362         **/
1363 
1364         with(foreachType)
1365         {
1366             foreach(tp; typeConstructors)
1367             {
1368                 if (tp) put(tokenRep(tp));
1369                 space();
1370             }
1371             if (type)
1372             {
1373                 format(type);
1374                 space();
1375             }
1376             format(identifier);
1377         }
1378     }
1379 
1380     void format(const ForeachTypeList foreachTypeList)
1381     {
1382         debug(verbose) writeln("ForeachTypeList");
1383 
1384         /**
1385         ForeachType[] items;
1386         **/
1387 
1388         foreach(count, item; foreachTypeList.items)
1389         {
1390             format(item);
1391             if (count < foreachTypeList.items.length - 1)
1392                 put(", ");
1393         }
1394     }
1395 
1396     void format(const FunctionAttribute functionAttribute)
1397     {
1398         debug(verbose) writeln("FunctionAttribute");
1399 
1400         /**
1401         Token token;
1402         AtAttribute atAttribute;
1403         **/
1404 
1405         with(functionAttribute)
1406         {
1407             if (token != tok!"")
1408             {
1409                 format(token);
1410                 space();
1411             }
1412             if (atAttribute) format(atAttribute);
1413         }
1414     }
1415 
1416     void format(const FunctionBody functionBody)
1417     {
1418         debug(verbose) writeln("FunctionBody");
1419 
1420         with(functionBody)
1421         {
1422             if (blockStatement)
1423             {
1424                 format(blockStatement);
1425                 return;
1426             }
1427             if (inStatement)
1428                 format(inStatement);
1429             if (outStatement)
1430                 format(outStatement);
1431             if (bodyStatement)
1432                 format(bodyStatement);
1433         }
1434     }
1435 
1436     void format(const FunctionCallExpression functionCallExpression)
1437     {
1438         debug(verbose) writeln("FunctionCallExpression");
1439 
1440         /**
1441         Type type;
1442         UnaryExpression unaryExpression;
1443         TemplateArguments templateArguments;
1444         Arguments arguments;
1445         **/
1446 
1447         with(functionCallExpression)
1448         {
1449             if (type) format(type);
1450             if (unaryExpression) format(unaryExpression);
1451             if (templateArguments) format(templateArguments);
1452             if (arguments) format(arguments);
1453         }
1454     }
1455 
1456     void format(const FunctionDeclaration decl, const Attribute[] attrs = null)
1457     {
1458         debug(verbose) writeln("FunctionDeclaration");
1459 
1460         /**
1461         bool hasAuto;
1462         bool hasRef;
1463         **/
1464 
1465         newThing(What.functionDecl);
1466         putComment(decl.comment);
1467         putAttrs(attrs);
1468 
1469         foreach (sc; decl.storageClasses)
1470             format(sc);
1471 
1472         if (decl.returnType)
1473             format(decl.returnType);
1474 
1475         space();
1476         format(decl.name);
1477 
1478         if (decl.templateParameters)
1479             format(decl.templateParameters);
1480         if (decl.parameters)
1481             format(decl.parameters);
1482         foreach(attr; decl.memberFunctionAttributes)
1483         {
1484             space();
1485             format(attr);
1486         }
1487         if (decl.constraint)
1488         {
1489             space();
1490             format(decl.constraint);
1491         }
1492 
1493         if (decl.functionBody)
1494             format(decl.functionBody);
1495         else
1496             put(";");
1497     }
1498 
1499     void format(const FunctionLiteralExpression functionLiteralExpression)
1500     {
1501         debug(verbose) writeln("FunctionLiteralExpression");
1502         /**
1503         ExpressionNode assignExpression;
1504         FunctionAttribute[] functionAttributes;
1505         FunctionBody functionBody;
1506         IdType functionOrDelegate;
1507         MemberFunctionAttribute[] memberFunctionAttributes;
1508         Parameters parameters;
1509         Token identifier;
1510         Type returnType;
1511         **/
1512 
1513         with(functionLiteralExpression)
1514         {
1515             put(tokenRep(functionOrDelegate));
1516 
1517             if (returnType || parameters)
1518                 space();
1519 
1520             if (returnType) format(returnType);
1521             if (parameters) format(parameters);
1522 
1523             foreach(att; memberFunctionAttributes)
1524             {
1525                 space();
1526                 format(att);
1527             }
1528 
1529             ignoreNewlines = true;
1530             if (functionBody)
1531                 format(functionBody);
1532             else
1533             {
1534                 format(identifier);
1535                 put(" => ");
1536                 format(assignExpression);
1537             }
1538             ignoreNewlines = false;
1539         }
1540     }
1541 
1542     void format(const GotoStatement gotoStatement)
1543     {
1544         debug(verbose) writeln("GotoStatement");
1545 
1546         put("goto ");
1547         gotoStatement.label != tok!"" ?
1548             put(tokenRep(gotoStatement.label)) :
1549                 format(gotoStatement.expression);
1550         put(";");
1551     }
1552 
1553     void format(const IdentifierChain identifierChain)
1554     {
1555         debug(verbose) writeln("IdentifierChain");
1556 
1557         foreach(count, ident; identifierChain.identifiers)
1558         {
1559             if (count) put(".");
1560             put(ident.text);
1561         }
1562     }
1563 
1564     void format(const DeclaratorIdentifierList declaratorIdentifierList)
1565     {
1566         debug(verbose) writeln("DeclaratorIdentifierList");
1567 
1568         foreach(count, ident; declaratorIdentifierList.identifiers)
1569         {
1570             if (count)
1571                 put(", ");
1572             put(ident.text);
1573         }
1574     }
1575 
1576     void format(const TypeIdentifierPart typeIdentifierPart)
1577     {
1578         debug(verbose) writeln("TypeIdentifierPart");
1579 
1580         if (typeIdentifierPart.dot)
1581         {
1582             put(".");
1583         }
1584         if (typeIdentifierPart.identifierOrTemplateInstance)
1585         {
1586             format(typeIdentifierPart.identifierOrTemplateInstance);
1587         }
1588         if (typeIdentifierPart.indexer)
1589         {
1590             put("[");
1591             format(typeIdentifierPart.indexer);
1592             put("]");
1593         }
1594         if (typeIdentifierPart.typeIdentifierPart)
1595         {
1596             put(".");
1597             format(typeIdentifierPart.typeIdentifierPart);
1598         }
1599     }
1600 
1601     void format(const IdentifierOrTemplateChain identifierOrTemplateChain)
1602     {
1603         debug(verbose) writeln("IdentifierOrTemplateChain");
1604 
1605         with(identifierOrTemplateChain)
1606         {
1607             foreach(count, ident; identifiersOrTemplateInstances)
1608             {
1609                 if (count) put(".");
1610                 format(ident);
1611             }
1612         }
1613     }
1614 
1615     void format(const IdentifierOrTemplateInstance identifierOrTemplateInstance)
1616     {
1617         debug(verbose) writeln("IdentifierOrTemplateInstance");
1618 
1619         with(identifierOrTemplateInstance)
1620         {
1621             format(identifier);
1622             if (templateInstance)
1623                 format(templateInstance);
1624         }
1625     }
1626 
1627     void format(const IdentityExpression identityExpression)
1628     {
1629         debug(verbose) writeln("IdentityExpression");
1630 
1631         with(identityExpression)
1632         {
1633             if (left) format(left);
1634             put(negated ? " !is " : " is ");
1635             if (right) format(right);
1636         }
1637     }
1638 
1639     void format(const IfStatement ifStatement)
1640     {
1641         debug(verbose) writeln("IfStatement");
1642 
1643         /**
1644         Token identifier;
1645         Type type;
1646         Expression expression;
1647         DeclarationOrStatement thenStatement;
1648         DeclarationOrStatement elseStatement;
1649         **/
1650 
1651         with(ifStatement)
1652         {
1653             bool isAuto = identifier != tok!"" && !type;
1654             bool isAssign = isAuto || type;
1655 
1656             put("if (");
1657 
1658             if (isAuto) put("auto ");
1659             if (type)
1660             {
1661                 format(type);
1662                 space();
1663             }
1664             if (identifier != tok!"")
1665             {
1666                 format(identifier);
1667                 space();
1668             }
1669             if (isAssign) put("= ");
1670             if (expression) format(expression);
1671             put(")");
1672 
1673             if (thenStatement)
1674                 maybeIndent(thenStatement);
1675 
1676             if (elseStatement)
1677             {
1678                 newThing(What.else_);
1679                 put("else ");
1680 
1681                 if (elseStatement.statement &&
1682                     elseStatement.statement.statementNoCaseNoDefault &&
1683                     elseStatement.statement.statementNoCaseNoDefault.ifStatement)
1684                 {
1685                     // this is to stop automatic newlineIndent
1686                     format(elseStatement.statement.statementNoCaseNoDefault.ifStatement);
1687                 }
1688                 else
1689                     maybeIndent(elseStatement);
1690             }
1691 
1692         }
1693     }
1694 
1695     void format(const ImportBind importBind)
1696     {
1697         debug(verbose) writeln("ImportBind");
1698 
1699         format(importBind.left);
1700         if (importBind.right != tok!"")
1701         {
1702             put(" = ");
1703             format(importBind.right);
1704         }
1705     }
1706 
1707     void format(const ImportBindings importBindings)
1708     {
1709         debug(verbose) writeln("ImportBindings");
1710 
1711         /**
1712         SingleImport singleImport;
1713         ImportBind[] importBinds;
1714         **/
1715 
1716         with(importBindings)
1717         {
1718             format(singleImport);
1719             put(" : ");
1720             foreach(count, bind; importBinds)
1721             {
1722                 if (count) put(", ");
1723                 format(bind);
1724             }
1725         }
1726     }
1727 
1728     void format(const ImportDeclaration importDeclaration, const Attribute[] attrs = null)
1729     {
1730         debug(verbose) writeln("ImportDeclaration");
1731 
1732         /**
1733         SingleImport[] singleImports;
1734         ImportBindings importBindings;
1735         **/
1736 
1737         with(importDeclaration)
1738         {
1739             newThing(What.importDecl);
1740             putAttrs(attrs);
1741             put("import ");
1742 
1743             if (singleImports.length == 1)
1744             {
1745                 format(singleImports[0]);
1746             }
1747             else if (singleImports.length > 1)
1748             {
1749                 indent();
1750                 newlineIndent();
1751                 foreach(count, imp; singleImports)
1752                 {
1753                     format(imp);
1754                     if (count < singleImports.length - 1)
1755                     {
1756                         put(", ");
1757                         newlineIndent();
1758                     }
1759                 }
1760                 outdent();
1761             }
1762 
1763             if (importBindings)
1764             {
1765                 if (singleImports.length)
1766                     put(", ");
1767                 format(importBindings);
1768             }
1769             put(";");
1770         }
1771     }
1772 
1773     void format(const ImportExpression importExpression)
1774     {
1775         debug(verbose) writeln("ImportExpression");
1776 
1777         put("import (");
1778         format(importExpression.assignExpression);
1779         put(");");
1780     }
1781 
1782     void format(const Index index)
1783     {
1784         format(index.low);
1785         if (index.high !is null)
1786         {
1787             put(" .. ");
1788             format(index.high);
1789         }
1790     }
1791 
1792     void format(const IndexExpression indexExpression)
1793     {
1794         debug(verbose) writeln("IndexExpression");
1795 
1796         /**
1797         UnaryExpression unaryExpression;
1798         ArgumentList argumentList;
1799         **/
1800 
1801         with(indexExpression)
1802         {
1803             format(indexExpression.unaryExpression);
1804             put("[");
1805             foreach (i, index; indexes)
1806             {
1807                 if (i != 0)
1808                     put(", ");
1809                 format(index);
1810             }
1811             put("]");
1812         }
1813     }
1814 
1815     void format(const InExpression inExpression)
1816     {
1817         debug(verbose) writeln("InExpression");
1818 
1819         with(inExpression)
1820         {
1821             if (left) format(left);
1822             put(negated ? " !in " : " in ");
1823             if (right) format(right);
1824         }
1825     }
1826 
1827     void format(const InStatement inStatement)
1828     {
1829         debug(verbose) writeln("InStatement");
1830         put("in");
1831         format(inStatement.blockStatement);
1832     }
1833 
1834     void format(const Initialize initialize)
1835     {
1836         debug(verbose) writeln("Initialize");
1837         assert(false);
1838     }
1839 
1840     void format(const Initializer initializer)
1841     {
1842         debug(verbose) writeln("Initializer");
1843 
1844         initializer.nonVoidInitializer ? format(initializer.nonVoidInitializer) : put("void");
1845     }
1846 
1847     void format(const InterfaceDeclaration interfaceDeclaration, const Attribute[] attrs = null)
1848     {
1849         debug(verbose) writeln("InterfaceDeclaration");
1850 
1851         /**
1852         Token name;
1853         TemplateParameters templateParameters;
1854         Constraint constraint;
1855         BaseClassList baseClassList;
1856         StructBody structBody;
1857         string comment;
1858         **/
1859 
1860         with(interfaceDeclaration)
1861         {
1862             newThing(What.aggregateDecl);
1863             putComment(comment);
1864             putAttrs(attrs);
1865 
1866             put("interface ");
1867             format(name);
1868             if (templateParameters) format(templateParameters);
1869             if (constraint)
1870             {
1871                 space();
1872                 format(constraint);
1873             }
1874             if (baseClassList)
1875             {
1876                 format(baseClassList);
1877             }
1878 
1879             if (structBody)
1880                 format(structBody);
1881             else
1882                 put(";");
1883         }
1884     }
1885 
1886     void format(const Invariant invariant_, const Attribute[] attrs = null)
1887     {
1888         debug(verbose) writeln("Invariant");
1889 
1890         /**
1891         BlockStatement blockStatement;
1892         string comment;
1893         **/
1894 
1895         putComment(invariant_.comment);
1896         putAttrs(attrs);
1897         put("invariant()");
1898         format(invariant_.blockStatement);
1899     }
1900 
1901     void format(const IsExpression isExpression)
1902     {
1903         debug(verbose) writeln("IsExpression");
1904 
1905         /**
1906         Type type;
1907         Token identifier;
1908         TypeSpecialization typeSpecialization;
1909         TemplateParameterList templateParameterList;
1910         IdType equalsOrColon;
1911         **/
1912 
1913         with(isExpression)
1914         {
1915             put("is(");
1916             if (type) format(type);
1917             if (identifier != tok!"")
1918             {
1919                 space();
1920                 format(identifier);
1921             }
1922 
1923             if (equalsOrColon)
1924             {
1925                 space();
1926                 put(tokenRep(equalsOrColon));
1927                 space();
1928             }
1929 
1930             if (typeSpecialization) format(typeSpecialization);
1931             if (templateParameterList)
1932             {
1933                 put(", ");
1934                 format(templateParameterList);
1935             }
1936             put(")");
1937         }
1938     }
1939 
1940     void format(const KeyValuePair keyValuePair)
1941     {
1942         debug(verbose) writeln("KeyValuePair");
1943 
1944         /**
1945         AssignExpression key;
1946         AssignExpression value;
1947         **/
1948 
1949         format(keyValuePair.key);
1950         put(":");
1951         format(keyValuePair.value);
1952     }
1953 
1954     void format(const KeyValuePairs keyValuePairs)
1955     {
1956         debug(verbose) writeln("KeyValuePairs");
1957 
1958         /**
1959         KeyValuePair[] keyValuePairs;
1960         **/
1961 
1962         foreach(count, pair; keyValuePairs.keyValuePairs)
1963         {
1964             format(pair);
1965             if (count + 1 < keyValuePairs.keyValuePairs.length)
1966                 put(", ");
1967         }
1968     }
1969 
1970     void format(const LabeledStatement stmt)
1971     {
1972         debug(verbose) writeln("LabeledStatement");
1973 
1974         /**
1975         Token identifier;
1976         DeclarationOrStatement declarationOrStatement;
1977         **/
1978 
1979         format(stmt.identifier);
1980         put(":");
1981         if (stmt.declarationOrStatement)
1982             format(stmt.declarationOrStatement);
1983     }
1984 
1985     void format(const LastCatch lastCatch)
1986     {
1987         debug(verbose) writeln("LastCatch");
1988 
1989         put("catch");
1990         format(lastCatch.statementNoCaseNoDefault);
1991     }
1992 
1993     void format(const LinkageAttribute linkageAttribute)
1994     {
1995         debug(verbose) writeln("LinkageAttribute");
1996 
1997         /**
1998         Token identifier;
1999         bool hasPlusPlus;
2000         IdentifierChain identifierChain;
2001         **/
2002 
2003         put("extern (");
2004         format(linkageAttribute.identifier);
2005         if (linkageAttribute.identifier.text == "Objective")
2006             put("-C");
2007         if (linkageAttribute.hasPlusPlus)
2008         {
2009             put("++");
2010             if (linkageAttribute.typeIdentifierPart)
2011             {
2012                 put(", ");
2013                 format(linkageAttribute.typeIdentifierPart);
2014             }
2015             else if (linkageAttribute.classOrStruct == tok!"class")
2016                 put(", class");
2017             else if (linkageAttribute.classOrStruct == tok!"struct")
2018                 put(", struct");
2019         }
2020         put(")");
2021     }
2022 
2023     void format(const MemberFunctionAttribute memberFunctionAttribute)
2024     {
2025         debug(verbose) writeln("MemberFunctionAttribute");
2026 
2027         /**
2028         IdType tokenType;
2029         AtAttribute atAttribute;
2030         **/
2031 
2032         with(memberFunctionAttribute)
2033         {
2034             if (tokenType) put(tokenRep(tokenType));
2035             else format(atAttribute);
2036         }
2037     }
2038 
2039     void format(const MixinDeclaration mixinDeclaration, const Attribute[] attrs = null)
2040     {
2041         debug(verbose) writeln("MixinDeclaration");
2042 
2043         /**
2044         MixinExpression mixinExpression;
2045         TemplateMixinExpression templateMixinExpression;
2046         **/
2047 
2048         with(mixinDeclaration)
2049         {
2050             putAttrs(attrs);
2051             if (mixinExpression) format(mixinExpression);
2052             else format(templateMixinExpression);
2053             put(";");
2054         }
2055     }
2056 
2057     void format(const MixinExpression mixinExpression)
2058     {
2059         debug(verbose) writeln("MixinExpression");
2060 
2061         put("mixin (");
2062         format(mixinExpression.assignExpression);
2063         put(")");
2064     }
2065 
2066     void format(const MixinTemplateDeclaration mixinTemplateDeclaration, const Attribute[] attrs = null)
2067     {
2068         debug(verbose) writeln("MixinTemplateDeclaration");
2069 
2070         putAttrs(attrs);
2071         put("mixin ");
2072         format(mixinTemplateDeclaration.templateDeclaration);
2073     }
2074 
2075     void format(const MixinTemplateName mixinTemplateName)
2076     {
2077         debug(verbose) writeln("MixinTemplateName");
2078 
2079         /**
2080         Symbol symbol;
2081         IdentifierOrTemplateChain identifierOrTemplateChain;
2082         TypeofExpression typeofExpression;
2083         **/
2084 
2085         with(mixinTemplateName)
2086         {
2087             if (symbol) format(symbol);
2088             else
2089             {
2090                 format(typeofExpression);
2091                 put(".");
2092                 format(identifierOrTemplateChain);
2093             }
2094         }
2095     }
2096 
2097     void format(const Module module_)
2098     {
2099         debug(verbose) writeln("Module");
2100 
2101         /**
2102         ModuleDeclaration moduleDeclaration;
2103         Declaration[] declarations;
2104         **/
2105 
2106         format(module_.moduleDeclaration);
2107         foreach(decl; module_.declarations)
2108             format(decl);
2109     }
2110 
2111     void format(const ModuleDeclaration moduleDeclaration)
2112     {
2113         debug(verbose) writeln("ModuleDeclaration");
2114         if (moduleDeclaration is null) return;
2115 
2116         /**
2117         IdentifierChain moduleName;
2118         **/
2119 
2120         put("module ");
2121         format(moduleDeclaration.moduleName);
2122         put(";");
2123         newlineIndent();
2124         newlineIndent();
2125     }
2126 
2127     void format(const MulExpression mulExpression)
2128     {
2129         debug(verbose) writeln("MulExpression");
2130         mixin(binary("mulExpression"));
2131     }
2132 
2133     void format(const NewAnonClassExpression newAnonClassExpression)
2134     {
2135         debug(verbose) writeln("NewAnonClassExpression");
2136 
2137         /**
2138         Arguments allocatorArguments;
2139         Arguments constructorArguments;
2140         BaseClassList baseClassList;
2141         StructBody structBody;
2142         **/
2143 
2144         with(newAnonClassExpression)
2145         {
2146             if (allocatorArguments)
2147             {
2148                 format(allocatorArguments);
2149                 space();
2150             }
2151             put("class");
2152             if (constructorArguments)
2153                 format(constructorArguments);
2154 
2155             if (baseClassList)
2156             {
2157                 space();
2158                 format(baseClassList);
2159             }
2160 
2161             format(structBody);
2162         }
2163     }
2164 
2165     void format(const NewExpression newExpression)
2166     {
2167         debug(verbose) writeln("NewExpression");
2168 
2169         /**
2170         Type type;
2171         NewAnonClassExpression newAnonClassExpression;
2172         Arguments arguments;
2173         AssignExpression assignExpression;
2174         **/
2175 
2176         with(newExpression)
2177         {
2178             put("new ");
2179             if (newAnonClassExpression) format(newAnonClassExpression);
2180             else
2181             {
2182                 if (type) format(type);
2183                 if (arguments) format(arguments);
2184                 if (assignExpression)
2185                 {
2186                     put("[");
2187                     format(assignExpression);
2188                     put("]");
2189                 }
2190             }
2191         }
2192     }
2193 
2194     void format(const NonVoidInitializer nonVoidInitializer)
2195     {
2196         debug(verbose) writeln("NonVoidInitializer");
2197 
2198         /**
2199         AssignExpression assignExpression;
2200         ArrayInitializer arrayInitializer;
2201         StructInitializer structInitializer;
2202         **/
2203 
2204         with(nonVoidInitializer)
2205         {
2206             if (assignExpression) format(assignExpression);
2207             else if (arrayInitializer) format(arrayInitializer);
2208             else if (structInitializer) format(structInitializer);
2209         }
2210     }
2211 
2212     void format(const Operands operands)
2213     {
2214         debug(verbose) writeln("Operands");
2215         assert(false);
2216     }
2217 
2218     void format(const OrExpression orExpression)
2219     {
2220         debug(verbose) writeln("OrExpression");
2221         mixin(binary("orExpression", "|"));
2222     }
2223 
2224     void format(const OrOrExpression orOrExpression)
2225     {
2226         debug(verbose) writeln("OrOrExpression");
2227         mixin(binary("orOrExpression", "||"));
2228     }
2229 
2230     void format(const OutStatement stmnt)
2231     {
2232         debug(verbose) writeln("OutStatement");
2233 
2234         /**
2235         Token parameter;
2236         BlockStatement blockStatement;
2237         **/
2238 
2239         put("out");
2240         if (stmnt.parameter != tok!"")
2241         {
2242             put(" (");
2243             format(stmnt.parameter);
2244             put(")");
2245         }
2246         format(stmnt.blockStatement);
2247     }
2248 
2249     void format(const Parameter parameter)
2250     {
2251         debug(verbose) writeln("Parameter");
2252 
2253         /**
2254         IdType[] parameterAttributes;
2255         Type type;
2256         Token name;
2257         bool vararg;
2258         AssignExpression default_;
2259         TypeSuffix[] cstyle;
2260         **/
2261 
2262         foreach (count, attribute; parameter.parameterAttributes)
2263         {
2264             if (count) space();
2265             put(tokenRep(attribute));
2266         }
2267 
2268         if (parameter.parameterAttributes.length > 0)
2269             space();
2270 
2271         if (parameter.type !is null)
2272             format(parameter.type);
2273 
2274         if (parameter.name.type != tok!"")
2275         {
2276             space();
2277             put(parameter.name.text);
2278         }
2279 
2280         foreach(suffix; parameter.cstyle)
2281             format(suffix);
2282 
2283         if (parameter.default_)
2284         {
2285             put(" = ");
2286             format(parameter.default_);
2287         }
2288 
2289         if (parameter.vararg)
2290             put("...");
2291     }
2292 
2293     void format(const Parameters parameters)
2294     {
2295         debug(verbose) writeln("Parameters");
2296 
2297         /**
2298         Parameter[] parameters;
2299         bool hasVarargs;
2300         **/
2301 
2302         put("(");
2303         foreach (count, param; parameters.parameters)
2304         {
2305             if (count) put(", ");
2306             format(param);
2307         }
2308         if (parameters.hasVarargs)
2309         {
2310             if (parameters.parameters.length)
2311                 put(", ");
2312             put("...");
2313         }
2314         put(")");
2315     }
2316 
2317     void format(const Postblit postblit, const Attribute[] attrs = null)
2318     {
2319         debug(verbose) writeln("Postblit");
2320 
2321         /**
2322         FunctionBody functionBody;
2323         **/
2324 
2325         newThing(What.functionDecl);
2326         putAttrs(attrs);
2327         put("this(this)");
2328 
2329         foreach(attr; postblit.memberFunctionAttributes)
2330         {
2331             space();
2332             format(attr);
2333         }
2334 
2335         if (postblit.functionBody)
2336             format(postblit.functionBody);
2337         else
2338             put(";");
2339     }
2340 
2341     void format(const PowExpression powExpression)
2342     {
2343         debug(verbose) writeln("PowExpression");
2344         mixin(binary("powExpression", "^^", true));
2345     }
2346 
2347     void format(const PragmaDeclaration pragmaDeclaration, const Attribute[] attrs = null)
2348     {
2349         debug(verbose) writeln("PragmaDeclaration");
2350 
2351         /**
2352         PragmaExpression pragmaExpression;
2353         **/
2354 
2355         putAttrs(attrs);
2356         format(pragmaDeclaration.pragmaExpression);
2357         put(";");
2358     }
2359 
2360     void format(const PragmaExpression pragmaExpression)
2361     {
2362         debug(verbose) writeln("PragmaExpression");
2363 
2364         /**
2365         Token identifier;
2366         ArgumentList argumentList;
2367         **/
2368 
2369         put("pragma(");
2370         format(pragmaExpression.identifier);
2371         if (pragmaExpression.argumentList)
2372         {
2373             put(", ");
2374             format(pragmaExpression.argumentList);
2375         }
2376         put(")");
2377     }
2378 
2379     void format(const PrimaryExpression primaryExpression)
2380     {
2381         debug(verbose) writeln("PrimaryExpression");
2382 
2383         /**
2384         Token dot;
2385         Token primary;
2386         IdentifierOrTemplateInstance identifierOrTemplateInstance;
2387         Token basicType;
2388         TypeofExpression typeofExpression;
2389         TypeidExpression typeidExpression;
2390         ArrayLiteral arrayLiteral;
2391         AssocArrayLiteral assocArrayLiteral;
2392         Expression expression;
2393         IsExpression isExpression;
2394         FunctionLiteralExpression functionLiteralExpression;
2395         TraitsExpression traitsExpression;
2396         MixinExpression mixinExpression;
2397         ImportExpression importExpression;
2398         Vector vector;
2399         Type type;
2400         Token typeConstructor;
2401         Arguments arguments;
2402         **/
2403 
2404         with(primaryExpression)
2405         {
2406             if (dot != tok!"") put(".");
2407             if (basicType != tok!"") format(basicType);
2408             if (primary != tok!"")
2409             {
2410                 if (basicType != tok!"") put("."); // i.e. : uint.max
2411                 format(primary);
2412             }
2413 
2414             if (expression)
2415             {
2416                 put("(");
2417                 format(expression);
2418                 put(")");
2419             }
2420             else if (identifierOrTemplateInstance)
2421             {
2422                 format(identifierOrTemplateInstance);
2423             }
2424             else if (typeofExpression) format(typeofExpression);
2425             else if (typeidExpression) format(typeidExpression);
2426             else if (arrayLiteral) format(arrayLiteral);
2427             else if (assocArrayLiteral) format(assocArrayLiteral);
2428             else if (isExpression) format(isExpression);
2429             else if (functionLiteralExpression) format(functionLiteralExpression);
2430             else if (traitsExpression) format(traitsExpression);
2431             else if (mixinExpression) format(mixinExpression);
2432             else if (importExpression) format(importExpression);
2433             else if (vector) format(vector);
2434             else if (type) format(type);
2435             else if (arguments) format(arguments);
2436         }
2437     }
2438 
2439     void format(const Register register)
2440     {
2441         debug(verbose) writeln("Register");
2442         assert(false);
2443     }
2444 
2445     void format(const RelExpression relExpression)
2446     {
2447         debug(verbose) writeln("RelExpression");
2448         mixin(binary("relExpression"));
2449     }
2450 
2451     void format(const ReturnStatement returnStatement)
2452     {
2453         debug(verbose) writeln("ReturnStatement");
2454 
2455         put("return");
2456         if (returnStatement.expression)
2457         {
2458             space();
2459             format(returnStatement.expression);
2460         }
2461         put(";");
2462     }
2463 
2464     void format(const ScopeGuardStatement scopeGuardStatement)
2465     {
2466         debug(verbose) writeln("ScopeGuardStatement");
2467 
2468         /**
2469         Token identifier;
2470         StatementNoCaseNoDefault statementNoCaseNoDefault;
2471         **/
2472 
2473         with(scopeGuardStatement)
2474         {
2475             put("scope(");
2476             format(identifier);
2477             put(")");
2478             indent();
2479             format(statementNoCaseNoDefault);
2480             outdent();
2481         }
2482     }
2483 
2484     void format(const SharedStaticConstructor sharedStaticConstructor, const Attribute[] attrs = null)
2485     {
2486         debug(verbose) writeln("SharedStaticConstructor");
2487 
2488         with(sharedStaticConstructor)
2489         {
2490             newThing(What.functionDecl);
2491             putComment(comment);
2492             putAttrs(attrs);
2493             put("shared static this()");
2494             format(functionBody);
2495         }
2496     }
2497 
2498     void format(const SharedStaticDestructor sharedStaticDestructor, const Attribute[] attrs = null)
2499     {
2500         debug(verbose) writeln("SharedStaticDestructor");
2501 
2502         with(sharedStaticDestructor)
2503         {
2504             newThing(What.functionDecl);
2505             putComment(comment);
2506             putAttrs(attrs);
2507             put("shared static ~this()");
2508             format(functionBody);
2509         }
2510     }
2511 
2512     void format(const ShiftExpression shiftExpression)
2513     {
2514         debug(verbose) writeln("ShiftExpression");
2515         mixin(binary("shiftExpression"));
2516     }
2517 
2518     void format(const SingleImport singleImport)
2519     {
2520         debug(verbose) writeln("SingleImport");
2521 
2522         /**
2523         Token rename;
2524         IdentifierChain identifierChain;
2525         **/
2526 
2527         if (singleImport.rename != tok!"")
2528         {
2529             format(singleImport.rename);
2530             put(" = ");
2531         }
2532         format(singleImport.identifierChain);
2533     }
2534 
2535     void format(const Statement statement)
2536     {
2537         debug(verbose) writeln("Statement");
2538 
2539         /**
2540         StatementNoCaseNoDefault statementNoCaseNoDefault;
2541         CaseStatement caseStatement;
2542         CaseRangeStatement caseRangeStatement;
2543         DefaultStatement defaultStatement;
2544         **/
2545 
2546         with(statement)
2547         {
2548             if (statementNoCaseNoDefault)
2549             {
2550                 format(statementNoCaseNoDefault);
2551                 return;
2552             }
2553 
2554             newlineIndent();
2555             if (caseStatement) format(caseStatement);
2556             else if (caseRangeStatement) format(caseRangeStatement);
2557             else if (defaultStatement) format(defaultStatement);
2558         }
2559     }
2560 
2561     void format(const StatementNoCaseNoDefault statementNoCaseNoDefault)
2562     {
2563         debug(verbose) writeln("StatementNoCaseNoDefault");
2564 
2565         string mix(string s) { return "if (" ~ s ~ ") format(" ~ s ~ ");"; }
2566 
2567         with(statementNoCaseNoDefault)
2568         {
2569             if (!blockStatement) newlineIndent();
2570 
2571             enum stmnts = TypeTuple!(
2572                 "labeledStatement",
2573                 "blockStatement",
2574                 "ifStatement",
2575                 "whileStatement",
2576                 "doStatement",
2577                 "forStatement",
2578                 "foreachStatement",
2579                 "switchStatement",
2580                 "finalSwitchStatement",
2581                 "continueStatement",
2582                 "breakStatement",
2583                 "returnStatement",
2584                 "gotoStatement",
2585                 "withStatement",
2586                 "synchronizedStatement",
2587                 "tryStatement",
2588                 "throwStatement",
2589                 "scopeGuardStatement",
2590                 "asmStatement",
2591                 "conditionalStatement",
2592                 "staticAssertStatement",
2593                 "versionSpecification",
2594                 "debugSpecification",
2595                 "expressionStatement"
2596             );
2597 
2598             foreach(s; stmnts)
2599                 mixin(mix(s));
2600         }
2601     }
2602 
2603     void format(const StaticAssertDeclaration staticAssertDeclaration, const Attribute[] attrs = null)
2604     {
2605         debug(verbose) writeln("StaticAssertDeclaration");
2606 
2607         newThing(What.other);
2608         putAttrs(attrs);
2609         format(staticAssertDeclaration.staticAssertStatement);
2610         put(";");
2611     }
2612 
2613     void format(const StaticAssertStatement staticAssertStatement)
2614     {
2615         debug(verbose) writeln("StaticAssertStatement");
2616 
2617         put("static ");
2618         format(staticAssertStatement.assertExpression);
2619     }
2620 
2621     void format(const StaticConstructor staticConstructor, const Attribute[] attrs = null)
2622     {
2623         debug(verbose) writeln("StaticConstructor");
2624 
2625         putAttrs(attrs);
2626         put("static this()");
2627         format(staticConstructor.functionBody);
2628     }
2629 
2630     void format(const StaticDestructor staticDestructor, const Attribute[] attrs = null)
2631     {
2632         debug(verbose) writeln("StaticDestructor");
2633 
2634         putAttrs(attrs);
2635         put("static ~this()");
2636         format(staticDestructor.functionBody);
2637     }
2638 
2639     void format(const StaticIfCondition staticIfCondition)
2640     {
2641         debug(verbose) writeln("StaticIfCondition");
2642 
2643         put("static if (");
2644         format(staticIfCondition.assignExpression);
2645         put(")");
2646     }
2647 
2648     void format(const StorageClass storageClass)
2649     {
2650         debug(verbose) writeln("StorageClass");
2651 
2652         /**
2653         AtAttribute atAttribute;
2654         Deprecated deprecated_;
2655         LinkageAttribute linkageAttribute;
2656         Token token;
2657         **/
2658 
2659         with(storageClass)
2660         {
2661             if (atAttribute) format(atAttribute);
2662             else if (deprecated_) format(deprecated_);
2663             else if (linkageAttribute) format(linkageAttribute);
2664             else format(token);
2665         }
2666     }
2667 
2668     void format(const StructBody structBody)
2669     {
2670         debug(verbose) writeln("StructBody");
2671 
2672         if (structBody.declarations.length > 0)
2673         {
2674             startBlock();
2675             foreach(count, decl; structBody.declarations)
2676                 format(decl);
2677             endBlock();
2678         }
2679         else
2680         {
2681             space();
2682             put("{}");
2683         }
2684     }
2685 
2686     void format(const StructDeclaration decl, const Attribute[] attrs = null)
2687     {
2688         debug(verbose) writeln("StructDeclaration");
2689 
2690         /**
2691         Token name;
2692         TemplateParameters templateParameters;
2693         Constraint constraint;
2694         StructBody structBody;
2695         string comment;
2696         **/
2697 
2698         newThing(What.aggregateDecl);
2699         putComment(decl.comment);
2700         putAttrs(attrs);
2701         put("struct ");
2702         format(decl.name);
2703 
2704         if (decl.templateParameters)
2705             format(decl.templateParameters);
2706 
2707         if (decl.constraint)
2708         {
2709             space();
2710             format(decl.constraint);
2711         }
2712 
2713         if (decl.structBody)
2714             format(decl.structBody);
2715         else
2716             put(";");
2717     }
2718 
2719     void format(const StructInitializer structInitializer)
2720     {
2721         debug(verbose) writeln("StructInitializer");
2722 
2723         put("{");
2724         format(structInitializer.structMemberInitializers);
2725         put("}");
2726     }
2727 
2728     void format(const StructMemberInitializer structMemberInitializer)
2729     {
2730         debug(verbose) writeln("StructMemberInitializer");
2731 
2732         /**
2733         Token identifier;
2734         NonVoidInitializer nonVoidInitializer;
2735         **/
2736 
2737         with(structMemberInitializer)
2738         {
2739             if (identifier != tok!"")
2740             {
2741                 format(identifier);
2742                 put(":");
2743             }
2744             format(nonVoidInitializer);
2745         }
2746     }
2747 
2748     void format(const StructMemberInitializers structMemberInitializers)
2749     {
2750         debug(verbose) writeln("StructMemberInitializers");
2751 
2752         foreach(count, mem; structMemberInitializers.structMemberInitializers)
2753         {
2754             if (count) put(", ");
2755             format(mem);
2756         }
2757     }
2758 
2759     void format(const SwitchStatement switchStatement, bool isFinal = false)
2760     {
2761         debug(verbose) writeln("SwitchStatement");
2762 
2763         /**
2764         Expression expression;
2765         Statement statement;
2766         **/
2767 
2768         with(switchStatement)
2769         {
2770             newThing(What.other);
2771             isFinal ? put(" final switch(") : put("switch(");
2772             format(expression);
2773             put(")");
2774 
2775             bool needBlock = statement.statementNoCaseNoDefault &&
2776                              !(statement.statementNoCaseNoDefault.withStatement ||
2777                                statement.statementNoCaseNoDefault.blockStatement );
2778 
2779             if (needBlock)
2780                 startBlock();
2781             format(statement);
2782             if (needBlock)
2783                 endBlock();
2784         }
2785     }
2786 
2787     void format(const Symbol symbol)
2788     {
2789         debug(verbose) writeln("Symbol");
2790 
2791         if (symbol.dot)
2792             put(".");
2793         format(symbol.identifierOrTemplateChain);
2794     }
2795 
2796     void format(const SynchronizedStatement synchronizedStatement)
2797     {
2798         debug(verbose) writeln("SynchronizedStatement");
2799 
2800         /**
2801         Expression expression;
2802         StatementNoCaseNoDefault statementNoCaseNoDefault;
2803         **/
2804 
2805         with(synchronizedStatement)
2806         {
2807             put("synchronized");
2808             if (expression)
2809             {
2810                 put("(");
2811                 format(expression);
2812                 put(")");
2813             }
2814             format(statementNoCaseNoDefault);
2815         }
2816     }
2817 
2818     void format(const TemplateAliasParameter templateAliasParameter)
2819     {
2820         debug(verbose) writeln("TemplateAliasParameter");
2821 
2822         /**
2823         Type type;
2824         Token identifier;
2825         Type colonType;
2826         AssignExpression colonExpression;
2827         Type assignType;
2828         AssignExpression assignExpression;
2829         **/
2830 
2831         with(templateAliasParameter)
2832         {
2833             put("alias ");
2834             if (type)
2835             {
2836                 format(type);
2837                 space();
2838             }
2839             format(identifier);
2840             if (colonType)
2841             {
2842                 put(" : ");
2843                 format(colonType);
2844             }
2845             else if (colonExpression)
2846             {
2847                 put(" : ");
2848                 format(colonExpression);
2849             }
2850             if (assignType)
2851             {
2852                 put(" = ");
2853                 format(assignType);
2854             }
2855             else if (assignExpression)
2856             {
2857                 put(" = ");
2858                 format(assignExpression);
2859             }
2860         }
2861     }
2862 
2863     void format(const TemplateArgument templateArgument)
2864     {
2865         debug(verbose) writeln("TemplateArgument");
2866 
2867         /**
2868         Type type;
2869         AssignExpression assignExpression;
2870         **/
2871 
2872         with(templateArgument)
2873         {
2874             if (type) format(type);
2875             if (assignExpression) format(assignExpression);
2876         }
2877     }
2878 
2879     void format(const TemplateArgumentList templateArgumentList, bool parens = true)
2880     {
2881         debug(verbose) writeln("TemplateArgumentList");
2882 
2883         if (parens) put("!(");
2884         foreach(count, arg; templateArgumentList.items)
2885         {
2886             if (count) put(", ");
2887             format(arg);
2888         }
2889         if (parens) put(")");
2890     }
2891 
2892     void format(const TemplateArguments templateArguments)
2893     {
2894         debug(verbose) writeln("TemplateArguments");
2895 
2896         /**
2897         TemplateArgumentList templateArgumentList;
2898         TemplateSingleArgument templateSingleArgument;
2899         **/
2900 
2901         with(templateArguments)
2902         {
2903             if (templateArgumentList) format(templateArgumentList);
2904             else if (templateSingleArgument) format(templateSingleArgument);
2905             else put("!()");
2906         }
2907     }
2908 
2909     void format(const TemplateDeclaration templateDeclaration, const Attribute[] attrs = null)
2910     {
2911         debug(verbose) writeln("TemplateDeclaration");
2912 
2913         /**
2914         Token name;
2915         TemplateParameters templateParameters;
2916         Constraint constraint;
2917         Declaration[] declarations;
2918         EponymousTemplateDeclaration eponymousTemplateDeclaration;
2919         string comment;
2920         **/
2921 
2922         with(templateDeclaration)
2923         {
2924             newThing(What.other);
2925             putComment(comment);
2926             putAttrs(attrs);
2927 
2928             put("template ");
2929             format(name);
2930 
2931             if (templateParameters)
2932                 format(templateParameters);
2933 
2934             if (constraint)
2935             {
2936                 space();
2937                 format(constraint);
2938             }
2939 
2940             startBlock();
2941             foreach(d; declarations)
2942                 format(d);
2943             endBlock();
2944         }
2945     }
2946 
2947     void format(const TemplateInstance templateInstance)
2948     {
2949         debug(verbose) writeln("TemplateInstance");
2950 
2951         /**
2952         Token identifier;
2953         TemplateArguments templateArguments;
2954         **/
2955 
2956         with(templateInstance)
2957         {
2958             format(identifier);
2959             if (templateArguments) format(templateArguments);
2960         }
2961     }
2962 
2963     void format(const TemplateMixinExpression templateMixinExpression)
2964     {
2965         debug(verbose) writeln("TemplateMixinExpression");
2966 
2967         /**
2968         Token identifier;
2969         TemplateArguments templateArguments;
2970         MixinTemplateName mixinTemplateName;
2971         **/
2972 
2973         with(templateMixinExpression)
2974         {
2975             put("mixin ");
2976             format(mixinTemplateName);
2977             if (templateArguments) format(templateArguments);
2978             space();
2979             format(identifier);
2980         }
2981     }
2982 
2983     void format(const TemplateParameter templateParameter)
2984     {
2985         debug(verbose) writeln("TemplateParameter");
2986 
2987         with(templateParameter)
2988         {
2989             if (templateTypeParameter)
2990                 format(templateTypeParameter);
2991             else if (templateValueParameter)
2992                 format(templateValueParameter);
2993             else if (templateAliasParameter)
2994                 format(templateAliasParameter);
2995             else if (templateTupleParameter)
2996                 format(templateTupleParameter);
2997             else if (templateThisParameter)
2998                 format(templateThisParameter);
2999         }
3000     }
3001 
3002     void format(const TemplateParameterList templateParameterList)
3003     {
3004         debug(verbose) writeln("TemplateParameterList");
3005 
3006         foreach(i, param; templateParameterList.items)
3007         {
3008             if (i) put(", ");
3009             format(param);
3010         }
3011     }
3012 
3013     void format(const TemplateParameters templateParameters)
3014     {
3015         debug(verbose) writeln("TemplateParameters");
3016 
3017         with(templateParameters)
3018         {
3019             put("(");
3020             if (templateParameterList)
3021                 format(templateParameterList);
3022             put(")");
3023         }
3024     }
3025 
3026     void format(const TemplateSingleArgument templateSingleArgument)
3027     {
3028         debug(verbose) writeln("TemplateSingleArgument");
3029 
3030         /**
3031         Token token;
3032         **/
3033 
3034         put("!");
3035         format(templateSingleArgument.token);
3036     }
3037 
3038     void format(const TemplateThisParameter templateThisParameter)
3039     {
3040         debug(verbose) writeln("TemplateThisParameter");
3041 
3042         with(templateThisParameter)
3043         {
3044             put("this ");
3045             if (templateTypeParameter)
3046                 format(templateTypeParameter);
3047         }
3048     }
3049 
3050     void format(const TemplateTupleParameter templateTupleParameter)
3051     {
3052         debug(verbose) writeln("TemplateTupleParameter");
3053 
3054         format(templateTupleParameter.identifier);
3055         put("...");
3056     }
3057 
3058     void format(const TemplateTypeParameter templateTypeParameter)
3059     {
3060         debug(verbose) writeln("TemplateTypeParameter");
3061 
3062         /**
3063         Token identifier;
3064         Type colonType;
3065         Type assignType;
3066         **/
3067 
3068         with(templateTypeParameter)
3069         {
3070             format(identifier);
3071             if (colonType)
3072             {
3073                 put(" : ");
3074                 format(colonType);
3075             }
3076             if (assignType)
3077             {
3078                 put(" = ");
3079                 format(assignType);
3080             }
3081         }
3082     }
3083 
3084     void format(const TemplateValueParameter templateValueParameter)
3085     {
3086         debug(verbose) writeln("TemplateValueParameter");
3087 
3088         /**
3089         Type type;
3090         Token identifier;
3091         Expression expression;
3092         TemplateValueParameterDefault templateValueParameterDefault;
3093         **/
3094 
3095         with(templateValueParameter)
3096         {
3097             if (type) format(type);
3098             space();
3099             format(identifier);
3100 
3101             if (assignExpression)
3102             {
3103                 put(" : ");
3104                 format(assignExpression);
3105             }
3106 
3107             if (templateValueParameterDefault)
3108             {
3109                 put(" = ");
3110                 format(templateValueParameterDefault);
3111             }
3112         }
3113     }
3114 
3115     void format(const TemplateValueParameterDefault templateValueParameterDefault)
3116     {
3117         debug(verbose) writeln("TemplateValueParameterDefault");
3118 
3119         with(templateValueParameterDefault)
3120             assignExpression ? format(assignExpression) : format(token);
3121     }
3122 
3123     void format(const TernaryExpression expr)
3124     {
3125         debug(verbose) writeln("TernaryExpression");
3126 
3127         /**
3128         ExpressionNode orOrExpression;
3129         ExpressionNode expression;
3130         ExpressionNode ternaryExpression;
3131         **/
3132 
3133         format(expr.orOrExpression);
3134 
3135         if (expr.expression && expr.ternaryExpression)
3136         {
3137             put(" ? ");
3138             format(expr.expression);
3139             put(" : ");
3140             format(expr.ternaryExpression);
3141         }
3142     }
3143 
3144     void format(const ThrowStatement throwStatement)
3145     {
3146         debug(verbose) writeln("ThrowStatement");
3147 
3148         put("throw ");
3149         assert(throwStatement.expression);
3150         format(throwStatement.expression);
3151         put(";");
3152     }
3153 
3154     void format(const Token token)
3155     {
3156         debug(verbose) writeln("Token ", tokenRep(token));
3157         put(tokenRep(token));
3158     }
3159 
3160     void format(const TraitsExpression traitExpr)
3161     {
3162         debug(verbose) writeln("TraitsExpression");
3163 
3164         /**
3165         Token identifier;
3166         TemplateArgumentList templateArgumentList;
3167         **/
3168 
3169         put("__traits(");
3170         format(traitExpr.identifier);
3171         put(", ");
3172         format(traitExpr.templateArgumentList, false);
3173         put(")");
3174     }
3175 
3176     void format(const TryStatement tryStatement)
3177     {
3178         debug(verbose) writeln("TryStatement");
3179 
3180         /**
3181         DeclarationOrStatement declarationOrStatement;
3182         Catches catches;
3183         Finally finally_;
3184         **/
3185 
3186         with(tryStatement)
3187         {
3188             newThing(What.other);
3189             put("try");
3190             maybeIndent(declarationOrStatement);
3191             if (catches) format(catches);
3192             if (finally_) format(finally_);
3193         }
3194     }
3195 
3196     void format(const Type type)
3197     {
3198         debug(verbose) writeln("Type(");
3199 
3200         /**
3201         IdType[] typeConstructors;
3202         TypeSuffix[] typeSuffixes;
3203         Type2 type2;
3204         **/
3205 
3206         foreach (count, constructor; type.typeConstructors)
3207         {
3208             if (count) space();
3209             put(tokenRep(constructor));
3210         }
3211 
3212         if (type.typeConstructors.length) space();
3213         format(type.type2);
3214 
3215         foreach (suffix; type.typeSuffixes)
3216             format(suffix);
3217 
3218         debug(verbose) writeln(")");
3219     }
3220 
3221     void format(const Type2 type2)
3222     {
3223         debug(verbose) writeln("Type2");
3224 
3225         /**
3226         IdType builtinType;
3227         TypeofExpression typeofExpression;
3228         IdentifierList identifierList;
3229         IdType typeConstructor;
3230         Type type;
3231         **/
3232 
3233         if (type2.typeIdentifierPart !is null)
3234         {
3235             format(type2.typeIdentifierPart);
3236         }
3237         else if (type2.typeofExpression !is null)
3238         {
3239             format(type2.typeofExpression);
3240             if (type2.typeIdentifierPart)
3241             {
3242                 put(".");
3243                 format(type2.typeIdentifierPart);
3244             }
3245             return;
3246         }
3247         else if (type2.typeConstructor != tok!"")
3248         {
3249             put(tokenRep(type2.typeConstructor));
3250             put("(");
3251             format(type2.type);
3252             put(")");
3253         }
3254         else
3255         {
3256             put(tokenRep(type2.builtinType));
3257             if (type2.typeIdentifierPart)
3258             {
3259                 put(".");
3260                 format(type2.typeIdentifierPart);
3261             }
3262         }
3263     }
3264 
3265     void format(const TypeSpecialization typeSpecialization)
3266     {
3267         debug(verbose) writeln("TypeSpecialization");
3268 
3269         /**
3270         Token token;
3271         Type type;
3272         **/
3273 
3274         with(typeSpecialization)
3275         {
3276             format(token);
3277             if (type) format(type);
3278         }
3279     }
3280 
3281     void format(const TypeSuffix typeSuffix)
3282     {
3283         debug(verbose) writeln("TypeSuffix");
3284 
3285         /**
3286         Token delegateOrFunction;
3287         bool star;
3288         bool array;
3289         Type type;
3290         AssignExpression low;
3291         AssignExpression high;
3292         Parameters parameters;
3293         MemberFunctionAttribute[] memberFunctionAttributes;
3294         **/
3295 
3296         if (typeSuffix.star.type != tok!"")
3297         {
3298             put("*");
3299             return;
3300         }
3301         else if (typeSuffix.array)
3302         {
3303             if (typeSuffix.type is null)
3304             {
3305                 if (typeSuffix.low is null)
3306                 {
3307                     put("[]");
3308                     return;
3309                 }
3310                 else
3311                 {
3312                     if (typeSuffix.high is null)
3313                     {
3314                         put("[");
3315                         format(typeSuffix.low);
3316                         put("]");
3317                         return;
3318                     }
3319                     else
3320                     {
3321                         put("[");
3322                         format(typeSuffix.low);
3323                         put("..");
3324                         format(typeSuffix.high);
3325                         put("]");
3326                         return;
3327                     }
3328                 }
3329             }
3330             else
3331             {
3332                 put("[");
3333                 format(typeSuffix.type);
3334                 put("]");
3335                 return;
3336             }
3337         }
3338         else
3339         {
3340             space();
3341             format(typeSuffix.delegateOrFunction);
3342             if (typeSuffix.parameters) format(typeSuffix.parameters);
3343             foreach(attr; typeSuffix.memberFunctionAttributes)
3344             {
3345                 space();
3346                 format(attr);
3347             }
3348             return;
3349         }
3350     }
3351 
3352     void format(const TypeidExpression idExpr)
3353     {
3354         debug(verbose) writeln("TypeidExpression");
3355 
3356         /**
3357         Type type;
3358         Expression expression;
3359         **/
3360 
3361         put("typeid (");
3362         idExpr.type ? format(idExpr.type) : format(idExpr.expression);
3363         put(")");
3364     }
3365 
3366     void format(const TypeofExpression typeofExpr)
3367     {
3368         debug(verbose) writeln("TypeofExpression");
3369 
3370         /**
3371         Expression expression;
3372         Token return_;
3373         **/
3374 
3375         put("typeof(");
3376         typeofExpr.expression ? format(typeofExpr.expression) : format(typeofExpr.return_);
3377         put(")");
3378     }
3379 
3380     void format(const UnaryExpression unary)
3381     {
3382         debug(verbose) writeln("UnaryExpression(");
3383 
3384         /**
3385         Type type;
3386         PrimaryExpression primaryExpression;
3387         Token prefix;
3388         Token suffix;
3389         UnaryExpression unaryExpression;
3390         NewExpression newExpression;
3391         DeleteExpression deleteExpression;
3392         CastExpression castExpression;
3393         FunctionCallExpression functionCallExpression;
3394         ArgumentList argumentList;
3395         IdentifierOrTemplateInstance identifierOrTemplateInstance;
3396         AssertExpression assertExpression;
3397         SliceExpression sliceExpression;
3398         IndexExpression indexExpression;
3399         **/
3400 
3401         with(unary)
3402         {
3403             if (prefix != tok!"") format(prefix);
3404 
3405             if (type)
3406             {
3407                 // handle things like (void*).sizeof
3408                 if (identifierOrTemplateInstance)
3409                 {
3410                     put("(");
3411                     format(type);
3412                     put(")");
3413                 }
3414                 else
3415                 {
3416                     format(type);
3417                     put("(");
3418                     if (argumentList)
3419                         format(argumentList);
3420                     put(")");
3421                 }
3422             }
3423 
3424             if (primaryExpression) format(primaryExpression);
3425             if (newExpression) format(newExpression);
3426             if (deleteExpression) format(deleteExpression);
3427             if (castExpression) format(castExpression);
3428             if (functionCallExpression) format(functionCallExpression);
3429             if (assertExpression) format(assertExpression);
3430             if (indexExpression) format(indexExpression);
3431 
3432             if (unaryExpression) format(unaryExpression);
3433             if (suffix != tok!"") format(suffix);
3434 
3435             if (identifierOrTemplateInstance)
3436             {
3437                 put(".");
3438                 format(identifierOrTemplateInstance);
3439             }
3440         }
3441 
3442         debug(verbose) writeln(")");
3443     }
3444 
3445     void format(const UnionDeclaration decl, const Attribute[] attrs = null)
3446     {
3447         debug(verbose) writeln("UnionDeclaration");
3448 
3449         /**
3450         Token name;
3451         TemplateParameters templateParameters;
3452         Constraint constraint;
3453         StructBody structBody;
3454         string comment;
3455         **/
3456 
3457         newThing(What.aggregateDecl);
3458         putComment(decl.comment);
3459         putAttrs(attrs);
3460         put("union ");
3461         format(decl.name);
3462         if (decl.templateParameters)
3463             format(decl.templateParameters);
3464         if (decl.constraint)
3465         {
3466             space();
3467             format(decl.constraint);
3468         }
3469         format(decl.structBody);
3470     }
3471 
3472     void format(const Unittest unittest_, const Attribute[] attrs = null)
3473     {
3474         debug(verbose) writeln("Unittest");
3475 
3476         /**
3477         BlockStatement blockStatement;
3478         string comment;
3479         **/
3480 
3481         newThing(What.functionDecl);
3482         putComment(unittest_.comment);
3483         putAttrs(attrs);
3484         put("unittest");
3485         format(unittest_.blockStatement);
3486     }
3487 
3488     void format(const VariableDeclaration decl, const Attribute[] attrs = null)
3489     {
3490         debug(verbose) writeln("VariableDeclaration");
3491 
3492         /**
3493         Type type;
3494         Declarator[] declarators;
3495         StorageClass storageClass;
3496         AutoDeclaration autoDeclaration;
3497         string comment;
3498         **/
3499 
3500         newThing(What.variableDecl);
3501         putComment(decl.comment);
3502         putAttrs(attrs);
3503 
3504         if (decl.autoDeclaration)
3505             format(decl.autoDeclaration);
3506         else
3507         {
3508             foreach (c; decl.storageClasses)
3509             {
3510                 format(c);
3511                 space();
3512             }
3513             if (decl.type) format(decl.type);
3514             if (decl.declarators.length) space();
3515             foreach(count, d; decl.declarators)
3516             {
3517                 if (count) put(", ");
3518                 format(d);
3519             }
3520         }
3521         put(";");
3522     }
3523 
3524     void format(const Vector vector)
3525     {
3526         debug(verbose) writeln("Vector");
3527 
3528         put("__vector(");
3529         format(vector.type);
3530         put(")");
3531     }
3532 
3533     void format(const VersionCondition versionCondition)
3534     {
3535         debug(verbose) writeln("VersionCondition");
3536 
3537         put("version (");
3538         format(versionCondition.token);
3539         put(")");
3540     }
3541 
3542     void format(const VersionSpecification ver, const Attribute[] attrs = null)
3543     {
3544         debug(verbose) writeln("VersionSpecification");
3545 
3546         newThing(What.other);
3547         putAttrs(attrs);
3548         put("version = ");
3549         format(ver.token);
3550         put(";");
3551     }
3552 
3553     void format(const WhileStatement stmt)
3554     {
3555         debug(verbose) writeln("WhileStatement");
3556 
3557         /**
3558         Expression expression;
3559         DeclarationOrStatement declarationOrStatement;
3560         **/
3561 
3562         newThing(What.other);
3563         put("while (");
3564         format(stmt.expression);
3565         put(")");
3566         maybeIndent(stmt.declarationOrStatement);
3567     }
3568 
3569     void format(const WithStatement stmt)
3570     {
3571         debug(verbose) writeln("WithStatement");
3572 
3573         /**
3574         Expression expression;
3575         DeclarationsOrStatement declarationOrStatement;
3576         **/
3577 
3578         space();
3579         put("with (");
3580         format(stmt.expression);
3581         put(")");
3582         if (stmt.declarationOrStatement)
3583             format(stmt.declarationOrStatement);
3584     }
3585 
3586     void format(const XorExpression xorExpression)
3587     {
3588         debug(verbose) writeln("XorExpression");
3589         mixin(binary("xorExpression", "^"));
3590     }
3591 
3592     Sink sink;
3593 
3594 protected:
3595 
3596     import std.uni : isWhite;
3597 
3598     void indent()
3599     {
3600         indentLevel++;
3601     }
3602 
3603     void outdent()
3604     {
3605         if (indentLevel == 0)
3606             return;
3607         indentLevel--;
3608     }
3609 
3610     void putIndent()
3611     {
3612         if (!indentLevel) return;
3613         auto i = getIndent();
3614         put(i);
3615     }
3616 
3617     string getIndent()
3618     {
3619         if (useTabs)
3620         {
3621             char[] c = new char[indentLevel];
3622             c[] = '\t';
3623             return cast(string) c;
3624         }
3625         else
3626         {
3627             char[] c = new char[indentLevel * indentWidth];
3628             c[] = ' ';
3629             return cast(string) c;
3630         }
3631     }
3632 
3633     enum What
3634     {
3635         functionDecl,
3636         aggregateDecl,
3637         attributeDecl,
3638         conditionalDecl,
3639         variableDecl,
3640         importDecl,
3641         expr,
3642         loop,
3643         else_,
3644         catch_,
3645         other
3646     }
3647 
3648     void newThing(What thing)
3649     {
3650         lastThing = currentThing;
3651         currentThing = thing;
3652 
3653         with(What) {
3654 
3655             if (lastThing == importDecl && thing != importDecl)
3656             {
3657                 lineGap(1);
3658                 return;
3659             }
3660 
3661             if (lastThing == loop)
3662             {
3663                 lineGap(1);
3664                 return;
3665             }
3666 
3667             switch(thing)
3668             {
3669                 case other:
3670                     newline();
3671                     break;
3672                 case aggregateDecl:
3673                 case attributeDecl:
3674                 case functionDecl:
3675                     lineGap(1);
3676                     break;
3677                 case conditionalDecl:
3678                     lineGap(1);
3679                     break;
3680                 case variableDecl:
3681                     lineGap(1);
3682                     break;
3683                 case importDecl:
3684                     newlineIndent();
3685                     break;
3686                 case expr: break;
3687                 case catch_: goto case;
3688                 case else_:
3689                     final switch(style) with(IndentStyle)
3690                     {
3691                         case allman: newline(); break;
3692                         case otbs: space(); break;
3693                     }
3694                     break;
3695                 default: newlineIndent(); break;
3696             }
3697         }
3698     }
3699 
3700     void lineGap(int gap)
3701     {
3702         foreach (i; 0 .. gap + 1)
3703         {
3704             if (i == gap)
3705                 newlineIndent();
3706             else
3707                 newline();
3708         }
3709     }
3710 
3711     void newlineIndent()
3712     {
3713         if (ignoreNewlines)
3714         {
3715             space(); // don't do this when splitting lines
3716         }
3717         else
3718         {
3719             sink.put("\n");
3720             lineLength = 0;
3721             putIndent();
3722         }
3723     }
3724 
3725     void newline()
3726     {
3727         sink.put("\n");
3728         lineLength = 0;
3729     }
3730 
3731     void space()
3732     {
3733         put(" ");
3734     }
3735 
3736     static string binary(string symbol, string operator = null, bool nospace = false)
3737     {
3738         return "with(" ~ symbol ~ "){"
3739              ~ "format(left); if (right is null) return;"
3740              ~ (nospace ? "" : "put(` `);")
3741              ~ (operator ? "put(`" ~ operator ~ "`);" : "put(tokenRep(operator));")
3742              ~ (nospace ? "" : "put(` `);")
3743              ~ "format(right);}";
3744     }
3745 
3746     void startBlock()
3747     {
3748         final switch(style) with(IndentStyle)
3749         {
3750             case allman: newline(); break;
3751             case otbs: space(); break;
3752         }
3753         putIndent();
3754         put("{");
3755         indent();
3756     }
3757 
3758     void endBlock()
3759     {
3760         outdent();
3761         newline();
3762         putIndent();
3763         put("}");
3764     }
3765 
3766     string tokenRep(Token t)
3767     {
3768         return t.text.length ? t.text : tokenRep(t.type);
3769     }
3770 
3771     string tokenRep(IdType t)
3772     {
3773         return t ? str(t) : "";
3774     }
3775 
3776     void putComment(string c)
3777     {
3778         import std.string : splitLines;
3779         if (!c.length) return;
3780         put(c.splitLines().join("\n" ~ getIndent()));
3781         newlineIndent();
3782     }
3783 
3784     void putAttrs(const Attribute[] attrs)
3785     {
3786         if (attrs !is null)
3787         {
3788             foreach(count, attr; attrs)
3789             {
3790                 format(attr);
3791                 space();
3792             }
3793         }
3794     }
3795 
3796     void put(string s)
3797     {
3798         sink.put(s);
3799         lineLength += s.length; // TODO: tabs / spaces?
3800     }
3801 
3802     void formatCaseDecls(const DeclarationsAndStatements declsAndStmnts)
3803     {
3804         bool seenBlock = false;
3805         auto items = declsAndStmnts.declarationsAndStatements;
3806         foreach(item; items)
3807         {
3808             bool _indent = false;
3809             if (item.declaration) _indent = true;
3810             if (item.statement && item.statement.statementNoCaseNoDefault)
3811             {
3812                 if (item.statement.statementNoCaseNoDefault.blockStatement)
3813                     seenBlock = true;
3814                 else if (!item.statement.statementNoCaseNoDefault.labeledStatement)
3815                     _indent = true;
3816             }
3817             if (seenBlock) _indent = false;
3818             if (_indent) indent();
3819             format(item);
3820             if (_indent) outdent();
3821         }
3822     }
3823 
3824     bool needIndent(const Statement s)
3825     {
3826         return s.statementNoCaseNoDefault &&
3827                !s.statementNoCaseNoDefault.blockStatement;
3828     }
3829 
3830     bool needIndent(const Declaration d)
3831     {
3832         return !d.declarations.length;
3833     }
3834 
3835     bool needIndent(const DeclarationOrStatement dors)
3836     {
3837         return (dors.declaration && needIndent(dors.declaration)) ||
3838                (dors.statement && needIndent(dors.statement));
3839     }
3840 
3841     void maybeIndent(T)(const T t)
3842     {
3843         auto _indent = needIndent(t);
3844         if (_indent) indent();
3845         format(t);
3846         if (_indent) outdent();
3847     }
3848 
3849     bool isEmptyDeclaration(const Declaration decl)
3850     {
3851         with(decl)
3852         {
3853             string mix(string[] s) {
3854                 string r;
3855                 foreach(c, d; s)
3856                     r ~= (c > 0 ? "else " : "") ~ "if (" ~ d ~ ") return false;";
3857                 return r;
3858             }
3859             mixin(mix(possibleDeclarations));
3860             return attributes.length == 0 &&
3861                    declarations.length == 0;
3862         }
3863     }
3864 
3865     bool ignoreNewlines = false;
3866     bool useTabs;
3867     uint caseDepth;
3868     uint indentWidth;
3869     uint indentLevel;
3870     IndentStyle style;
3871 
3872 
3873     What lastThing, currentThing;
3874     uint lineLength;
3875     uint maxLineLength = 80;
3876 
3877     enum possibleDeclarations = [
3878         "attributeDeclaration",
3879         "importDeclaration",
3880         "functionDeclaration",
3881         "variableDeclaration",
3882         "aliasThisDeclaration",
3883         "structDeclaration",
3884         "classDeclaration",
3885         "interfaceDeclaration",
3886         "unionDeclaration",
3887         "enumDeclaration",
3888         "aliasDeclaration",
3889         "mixinDeclaration",
3890         "mixinTemplateDeclaration",
3891         "unittest_",
3892         "staticAssertDeclaration",
3893         "templateDeclaration",
3894         "constructor",
3895         "destructor",
3896         "staticConstructor",
3897         "staticDestructor",
3898         "sharedStaticDestructor",
3899         "sharedStaticConstructor",
3900         "conditionalDeclaration",
3901         "pragmaDeclaration",
3902         "versionSpecification",
3903         "invariant_",
3904         "postblit"
3905     ];
3906 }
3907 
3908 version (unittest)
3909 void testFormatNode(Node)(string sourceCode)
3910 {
3911     Appender!string fmt;
3912     ubyte[] code = cast(ubyte[]) sourceCode;
3913 
3914     class CatchInterestingStuff : ASTVisitor
3915     {
3916         alias visit = ASTVisitor.visit;
3917         override void visit(const(Node) stuff)
3918         {
3919             stuff.accept(this);
3920             format(&fmt, stuff);
3921             assert(fmt.data.canFind(code), fmt.data);
3922         }
3923     }
3924 
3925     LexerConfig config;
3926     StringCache cache = StringCache(32);
3927     RollbackAllocator rba;
3928     auto toks = getTokensForParser(code, config, &cache);
3929     Module mod = parseModule(toks, "stdin", &rba);
3930     (new CatchInterestingStuff).visit(mod);
3931 }
3932 
3933 unittest
3934 {
3935     testFormatNode!(VariableDeclaration)("T.T y;");
3936     testFormatNode!(VariableDeclaration)("T[] y;");
3937     testFormatNode!(VariableDeclaration)("T* y;");
3938     testFormatNode!(VariableDeclaration)("T[0].Y y;");
3939     testFormatNode!(VariableDeclaration)("T.T[] y;");
3940     testFormatNode!(VariableDeclaration)("T.T[8] y;");
3941     testFormatNode!(VariableDeclaration)("T.T[8].T y;");
3942     testFormatNode!(VariableDeclaration)(`.T!"af" taf;`);
3943     testFormatNode!(VariableDeclaration)(`.T!0[] t;`);
3944     testFormatNode!(VariableDeclaration)(`T!(0)[] t;`);
3945     testFormatNode!(VariableDeclaration)(`T!(0)[dim] t;`);
3946 }