1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved
6  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
7  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8  * Source:      $(DMDSRC _hdrgen.d)
9  */
10 
11 module ddmd.hdrgen;
12 
13 import core.stdc.ctype;
14 import core.stdc.stdio;
15 import core.stdc..string;
16 import ddmd.aggregate;
17 import ddmd.aliasthis;
18 import ddmd.arraytypes;
19 import ddmd.attrib;
20 import ddmd.complex;
21 import ddmd.cond;
22 import ddmd.ctfeexpr;
23 import ddmd.dclass;
24 import ddmd.declaration;
25 import ddmd.denum;
26 import ddmd.dimport;
27 import ddmd.dmodule;
28 import ddmd.doc;
29 import ddmd.dstruct;
30 import ddmd.dsymbol;
31 import ddmd.dtemplate;
32 import ddmd.dversion;
33 import ddmd.expression;
34 import ddmd.func;
35 import ddmd.globals;
36 import ddmd.id;
37 import ddmd.identifier;
38 import ddmd.init;
39 import ddmd.mtype;
40 import ddmd.nspace;
41 import ddmd.parse;
42 import ddmd.root.ctfloat;
43 import ddmd.root.outbuffer;
44 import ddmd.root.rootobject;
45 import ddmd.statement;
46 import ddmd.staticassert;
47 import ddmd.target;
48 import ddmd.tokens;
49 import ddmd.utils;
50 import ddmd.visitor;
51 
52 struct HdrGenState
53 {
54     bool hdrgen;        // true if generating header file
55     bool ddoc;          // true if generating Ddoc file
56     bool fullQual;      // fully qualify types when printing
57     int tpltMember;
58     int autoMember;
59     int forStmtInit;
60 }
61 
62 enum TEST_EMIT_ALL = 0;
63 
64 extern (C++) void genhdrfile(Module m)
65 {
66     OutBuffer buf;
67     buf.doindent = 1;
68     buf.printf("// D import file generated from '%s'", m.srcfile.toChars());
69     buf.writenl();
70     HdrGenState hgs;
71     hgs.hdrgen = true;
72     toCBuffer(m, &buf, &hgs);
73     // Transfer image to file
74     m.hdrfile.setbuffer(buf.data, buf.offset);
75     buf.extractData();
76     ensurePathToNameExists(Loc(), m.hdrfile.toChars());
77     writeFile(m.loc, m.hdrfile);
78 }
79 
80 extern (C++) final class PrettyPrintVisitor : Visitor
81 {
82     alias visit = super.visit;
83 public:
84     OutBuffer* buf;
85     HdrGenState* hgs;
86     bool declstring; // set while declaring alias for string,wstring or dstring
87 
88     extern (D) this(OutBuffer* buf, HdrGenState* hgs)
89     {
90         this.buf = buf;
91         this.hgs = hgs;
92     }
93 
94     override void visit(Statement s)
95     {
96         buf.printf("Statement::toCBuffer()");
97         buf.writenl();
98         assert(0);
99     }
100 
101     override void visit(ErrorStatement s)
102     {
103         buf.printf("__error__");
104         buf.writenl();
105     }
106 
107     override void visit(ExpStatement s)
108     {
109         if (s.exp && s.exp.op == TOKdeclaration)
110         {
111             // bypass visit(DeclarationExp)
112             (cast(DeclarationExp)s.exp).declaration.accept(this);
113             return;
114         }
115         if (s.exp)
116             s.exp.accept(this);
117         buf.writeByte(';');
118         if (!hgs.forStmtInit)
119             buf.writenl();
120     }
121 
122     override void visit(CompileStatement s)
123     {
124         buf.writestring("mixin(");
125         s.exp.accept(this);
126         buf.writestring(");");
127         if (!hgs.forStmtInit)
128             buf.writenl();
129     }
130 
131     override void visit(CompoundStatement s)
132     {
133         foreach (sx; *s.statements)
134         {
135             if (sx)
136                 sx.accept(this);
137         }
138     }
139 
140     override void visit(CompoundDeclarationStatement s)
141     {
142         bool anywritten = false;
143         foreach (sx; *s.statements)
144         {
145             auto ds = sx ? sx.isExpStatement() : null;
146             if (ds && ds.exp.op == TOKdeclaration)
147             {
148                 auto d = (cast(DeclarationExp)ds.exp).declaration;
149                 assert(d.isDeclaration());
150                 if (auto v = d.isVarDeclaration())
151                     visitVarDecl(v, anywritten);
152                 else
153                     d.accept(this);
154                 anywritten = true;
155             }
156         }
157         buf.writeByte(';');
158         if (!hgs.forStmtInit)
159             buf.writenl();
160     }
161 
162     override void visit(UnrolledLoopStatement s)
163     {
164         buf.writestring("unrolled {");
165         buf.writenl();
166         buf.level++;
167         foreach (sx; *s.statements)
168         {
169             if (sx)
170                 sx.accept(this);
171         }
172         buf.level--;
173         buf.writeByte('}');
174         buf.writenl();
175     }
176 
177     override void visit(ScopeStatement s)
178     {
179         buf.writeByte('{');
180         buf.writenl();
181         buf.level++;
182         if (s.statement)
183             s.statement.accept(this);
184         buf.level--;
185         buf.writeByte('}');
186         buf.writenl();
187     }
188 
189     override void visit(WhileStatement s)
190     {
191         buf.writestring("while (");
192         s.condition.accept(this);
193         buf.writeByte(')');
194         buf.writenl();
195         if (s._body)
196             s._body.accept(this);
197     }
198 
199     override void visit(DoStatement s)
200     {
201         buf.writestring("do");
202         buf.writenl();
203         if (s._body)
204             s._body.accept(this);
205         buf.writestring("while (");
206         s.condition.accept(this);
207         buf.writestring(");");
208         buf.writenl();
209     }
210 
211     override void visit(ForStatement s)
212     {
213         buf.writestring("for (");
214         if (s._init)
215         {
216             hgs.forStmtInit++;
217             s._init.accept(this);
218             hgs.forStmtInit--;
219         }
220         else
221             buf.writeByte(';');
222         if (s.condition)
223         {
224             buf.writeByte(' ');
225             s.condition.accept(this);
226         }
227         buf.writeByte(';');
228         if (s.increment)
229         {
230             buf.writeByte(' ');
231             s.increment.accept(this);
232         }
233         buf.writeByte(')');
234         buf.writenl();
235         buf.writeByte('{');
236         buf.writenl();
237         buf.level++;
238         if (s._body)
239             s._body.accept(this);
240         buf.level--;
241         buf.writeByte('}');
242         buf.writenl();
243     }
244 
245     override void visit(ForeachStatement s)
246     {
247         buf.writestring(Token.toString(s.op));
248         buf.writestring(" (");
249         foreach (i, p; *s.parameters)
250         {
251             if (i)
252                 buf.writestring(", ");
253             if (stcToBuffer(buf, p.storageClass))
254                 buf.writeByte(' ');
255             if (p.type)
256                 typeToBuffer(p.type, p.ident);
257             else
258                 buf.writestring(p.ident.toChars());
259         }
260         buf.writestring("; ");
261         s.aggr.accept(this);
262         buf.writeByte(')');
263         buf.writenl();
264         buf.writeByte('{');
265         buf.writenl();
266         buf.level++;
267         if (s._body)
268             s._body.accept(this);
269         buf.level--;
270         buf.writeByte('}');
271         buf.writenl();
272     }
273 
274     override void visit(ForeachRangeStatement s)
275     {
276         buf.writestring(Token.toString(s.op));
277         buf.writestring(" (");
278         if (s.prm.type)
279             typeToBuffer(s.prm.type, s.prm.ident);
280         else
281             buf.writestring(s.prm.ident.toChars());
282         buf.writestring("; ");
283         s.lwr.accept(this);
284         buf.writestring(" .. ");
285         s.upr.accept(this);
286         buf.writeByte(')');
287         buf.writenl();
288         buf.writeByte('{');
289         buf.writenl();
290         buf.level++;
291         if (s._body)
292             s._body.accept(this);
293         buf.level--;
294         buf.writeByte('}');
295         buf.writenl();
296     }
297 
298     override void visit(IfStatement s)
299     {
300         buf.writestring("if (");
301         if (Parameter p = s.prm)
302         {
303             StorageClass stc = p.storageClass;
304             if (!p.type && !stc)
305                 stc = STCauto;
306             if (stcToBuffer(buf, stc))
307                 buf.writeByte(' ');
308             if (p.type)
309                 typeToBuffer(p.type, p.ident);
310             else
311                 buf.writestring(p.ident.toChars());
312             buf.writestring(" = ");
313         }
314         s.condition.accept(this);
315         buf.writeByte(')');
316         buf.writenl();
317         if (!s.ifbody.isScopeStatement())
318             buf.level++;
319         s.ifbody.accept(this);
320         if (!s.ifbody.isScopeStatement())
321             buf.level--;
322         if (s.elsebody)
323         {
324             buf.writestring("else");
325             buf.writenl();
326             if (!s.elsebody.isScopeStatement())
327                 buf.level++;
328             s.elsebody.accept(this);
329             if (!s.elsebody.isScopeStatement())
330                 buf.level--;
331         }
332     }
333 
334     override void visit(ConditionalStatement s)
335     {
336         s.condition.accept(this);
337         buf.writenl();
338         buf.writeByte('{');
339         buf.writenl();
340         buf.level++;
341         if (s.ifbody)
342             s.ifbody.accept(this);
343         buf.level--;
344         buf.writeByte('}');
345         buf.writenl();
346         if (s.elsebody)
347         {
348             buf.writestring("else");
349             buf.writenl();
350             buf.writeByte('{');
351             buf.level++;
352             buf.writenl();
353             s.elsebody.accept(this);
354             buf.level--;
355             buf.writeByte('}');
356         }
357         buf.writenl();
358     }
359 
360     override void visit(PragmaStatement s)
361     {
362         buf.writestring("pragma (");
363         buf.writestring(s.ident.toChars());
364         if (s.args && s.args.dim)
365         {
366             buf.writestring(", ");
367             argsToBuffer(s.args);
368         }
369         buf.writeByte(')');
370         if (s._body)
371         {
372             buf.writenl();
373             buf.writeByte('{');
374             buf.writenl();
375             buf.level++;
376             s._body.accept(this);
377             buf.level--;
378             buf.writeByte('}');
379             buf.writenl();
380         }
381         else
382         {
383             buf.writeByte(';');
384             buf.writenl();
385         }
386     }
387 
388     override void visit(StaticAssertStatement s)
389     {
390         s.sa.accept(this);
391     }
392 
393     override void visit(SwitchStatement s)
394     {
395         buf.writestring(s.isFinal ? "final switch (" : "switch (");
396         s.condition.accept(this);
397         buf.writeByte(')');
398         buf.writenl();
399         if (s._body)
400         {
401             if (!s._body.isScopeStatement())
402             {
403                 buf.writeByte('{');
404                 buf.writenl();
405                 buf.level++;
406                 s._body.accept(this);
407                 buf.level--;
408                 buf.writeByte('}');
409                 buf.writenl();
410             }
411             else
412             {
413                 s._body.accept(this);
414             }
415         }
416     }
417 
418     override void visit(CaseStatement s)
419     {
420         buf.writestring("case ");
421         s.exp.accept(this);
422         buf.writeByte(':');
423         buf.writenl();
424         s.statement.accept(this);
425     }
426 
427     override void visit(CaseRangeStatement s)
428     {
429         buf.writestring("case ");
430         s.first.accept(this);
431         buf.writestring(": .. case ");
432         s.last.accept(this);
433         buf.writeByte(':');
434         buf.writenl();
435         s.statement.accept(this);
436     }
437 
438     override void visit(DefaultStatement s)
439     {
440         buf.writestring("default:");
441         buf.writenl();
442         s.statement.accept(this);
443     }
444 
445     override void visit(GotoDefaultStatement s)
446     {
447         buf.writestring("goto default;");
448         buf.writenl();
449     }
450 
451     override void visit(GotoCaseStatement s)
452     {
453         buf.writestring("goto case");
454         if (s.exp)
455         {
456             buf.writeByte(' ');
457             s.exp.accept(this);
458         }
459         buf.writeByte(';');
460         buf.writenl();
461     }
462 
463     override void visit(SwitchErrorStatement s)
464     {
465         buf.writestring("SwitchErrorStatement::toCBuffer()");
466         buf.writenl();
467     }
468 
469     override void visit(ReturnStatement s)
470     {
471         buf.printf("return ");
472         if (s.exp)
473             s.exp.accept(this);
474         buf.writeByte(';');
475         buf.writenl();
476     }
477 
478     override void visit(BreakStatement s)
479     {
480         buf.writestring("break");
481         if (s.ident)
482         {
483             buf.writeByte(' ');
484             buf.writestring(s.ident.toChars());
485         }
486         buf.writeByte(';');
487         buf.writenl();
488     }
489 
490     override void visit(ContinueStatement s)
491     {
492         buf.writestring("continue");
493         if (s.ident)
494         {
495             buf.writeByte(' ');
496             buf.writestring(s.ident.toChars());
497         }
498         buf.writeByte(';');
499         buf.writenl();
500     }
501 
502     override void visit(SynchronizedStatement s)
503     {
504         buf.writestring("synchronized");
505         if (s.exp)
506         {
507             buf.writeByte('(');
508             s.exp.accept(this);
509             buf.writeByte(')');
510         }
511         if (s._body)
512         {
513             buf.writeByte(' ');
514             s._body.accept(this);
515         }
516     }
517 
518     override void visit(WithStatement s)
519     {
520         buf.writestring("with (");
521         s.exp.accept(this);
522         buf.writestring(")");
523         buf.writenl();
524         if (s._body)
525             s._body.accept(this);
526     }
527 
528     override void visit(TryCatchStatement s)
529     {
530         buf.writestring("try");
531         buf.writenl();
532         if (s._body)
533             s._body.accept(this);
534         foreach (c; *s.catches)
535         {
536             visit(c);
537         }
538     }
539 
540     override void visit(TryFinallyStatement s)
541     {
542         buf.writestring("try");
543         buf.writenl();
544         buf.writeByte('{');
545         buf.writenl();
546         buf.level++;
547         s._body.accept(this);
548         buf.level--;
549         buf.writeByte('}');
550         buf.writenl();
551         buf.writestring("finally");
552         buf.writenl();
553         buf.writeByte('{');
554         buf.writenl();
555         buf.level++;
556         s.finalbody.accept(this);
557         buf.level--;
558         buf.writeByte('}');
559         buf.writenl();
560     }
561 
562     override void visit(OnScopeStatement s)
563     {
564         buf.writestring(Token.toString(s.tok));
565         buf.writeByte(' ');
566         s.statement.accept(this);
567     }
568 
569     override void visit(ThrowStatement s)
570     {
571         buf.printf("throw ");
572         s.exp.accept(this);
573         buf.writeByte(';');
574         buf.writenl();
575     }
576 
577     override void visit(DebugStatement s)
578     {
579         if (s.statement)
580         {
581             s.statement.accept(this);
582         }
583     }
584 
585     override void visit(GotoStatement s)
586     {
587         buf.writestring("goto ");
588         buf.writestring(s.ident.toChars());
589         buf.writeByte(';');
590         buf.writenl();
591     }
592 
593     override void visit(LabelStatement s)
594     {
595         buf.writestring(s.ident.toChars());
596         buf.writeByte(':');
597         buf.writenl();
598         if (s.statement)
599             s.statement.accept(this);
600     }
601 
602     override void visit(AsmStatement s)
603     {
604         buf.writestring("asm { ");
605         Token* t = s.tokens;
606         buf.level++;
607         while (t)
608         {
609             buf.writestring(t.toChars());
610             if (t.next &&
611                 t.value != TOKmin      &&
612                 t.value != TOKcomma    && t.next.value != TOKcomma    &&
613                 t.value != TOKlbracket && t.next.value != TOKlbracket &&
614                                           t.next.value != TOKrbracket &&
615                 t.value != TOKlparen   && t.next.value != TOKlparen   &&
616                                           t.next.value != TOKrparen   &&
617                 t.value != TOKdot      && t.next.value != TOKdot)
618             {
619                 buf.writeByte(' ');
620             }
621             t = t.next;
622         }
623         buf.level--;
624         buf.writestring("; }");
625         buf.writenl();
626     }
627 
628     override void visit(ImportStatement s)
629     {
630         foreach (imp; *s.imports)
631         {
632             imp.accept(this);
633         }
634     }
635 
636     void visit(Catch c)
637     {
638         buf.writestring("catch");
639         if (c.type)
640         {
641             buf.writeByte('(');
642             typeToBuffer(c.type, c.ident);
643             buf.writeByte(')');
644         }
645         buf.writenl();
646         buf.writeByte('{');
647         buf.writenl();
648         buf.level++;
649         if (c.handler)
650             c.handler.accept(this);
651         buf.level--;
652         buf.writeByte('}');
653         buf.writenl();
654     }
655 
656     ////////////////////////////////////////////////////////////////////////////
657     /**************************************************
658      * An entry point to pretty-print type.
659      */
660     void typeToBuffer(Type t, Identifier ident)
661     {
662         if (t.ty == Tfunction)
663         {
664             visitFuncIdentWithPrefix(cast(TypeFunction)t, ident, null, true);
665             return;
666         }
667         visitWithMask(t, 0);
668         if (ident)
669         {
670             buf.writeByte(' ');
671             buf.writestring(ident.toChars());
672         }
673     }
674 
675     void visitWithMask(Type t, ubyte modMask)
676     {
677         // Tuples and functions don't use the type constructor syntax
678         if (modMask == t.mod || t.ty == Tfunction || t.ty == Ttuple)
679         {
680             t.accept(this);
681         }
682         else
683         {
684             ubyte m = t.mod & ~(t.mod & modMask);
685             if (m & MODshared)
686             {
687                 MODtoBuffer(buf, MODshared);
688                 buf.writeByte('(');
689             }
690             if (m & MODwild)
691             {
692                 MODtoBuffer(buf, MODwild);
693                 buf.writeByte('(');
694             }
695             if (m & (MODconst | MODimmutable))
696             {
697                 MODtoBuffer(buf, m & (MODconst | MODimmutable));
698                 buf.writeByte('(');
699             }
700             t.accept(this);
701             if (m & (MODconst | MODimmutable))
702                 buf.writeByte(')');
703             if (m & MODwild)
704                 buf.writeByte(')');
705             if (m & MODshared)
706                 buf.writeByte(')');
707         }
708     }
709 
710     override void visit(Type t)
711     {
712         printf("t = %p, ty = %d\n", t, t.ty);
713         assert(0);
714     }
715 
716     override void visit(TypeError t)
717     {
718         buf.writestring("_error_");
719     }
720 
721     override void visit(TypeBasic t)
722     {
723         //printf("TypeBasic::toCBuffer2(t->mod = %d)\n", t->mod);
724         buf.writestring(t.dstring);
725     }
726 
727     override void visit(TypeVector t)
728     {
729         //printf("TypeVector::toCBuffer2(t->mod = %d)\n", t->mod);
730         buf.writestring("__vector(");
731         visitWithMask(t.basetype, t.mod);
732         buf.writestring(")");
733     }
734 
735     override void visit(TypeSArray t)
736     {
737         visitWithMask(t.next, t.mod);
738         buf.writeByte('[');
739         sizeToBuffer(t.dim);
740         buf.writeByte(']');
741     }
742 
743     override void visit(TypeDArray t)
744     {
745         Type ut = t.castMod(0);
746         if (declstring)
747             goto L1;
748         if (ut.equals(Type.tstring))
749             buf.writestring("string");
750         else if (ut.equals(Type.twstring))
751             buf.writestring("wstring");
752         else if (ut.equals(Type.tdstring))
753             buf.writestring("dstring");
754         else
755         {
756         L1:
757             visitWithMask(t.next, t.mod);
758             buf.writestring("[]");
759         }
760     }
761 
762     override void visit(TypeAArray t)
763     {
764         visitWithMask(t.next, t.mod);
765         buf.writeByte('[');
766         visitWithMask(t.index, 0);
767         buf.writeByte(']');
768     }
769 
770     override void visit(TypePointer t)
771     {
772         //printf("TypePointer::toCBuffer2() next = %d\n", t->next->ty);
773         if (t.next.ty == Tfunction)
774             visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "function");
775         else
776         {
777             visitWithMask(t.next, t.mod);
778             buf.writeByte('*');
779         }
780     }
781 
782     override void visit(TypeReference t)
783     {
784         visitWithMask(t.next, t.mod);
785         buf.writeByte('&');
786     }
787 
788     override void visit(TypeFunction t)
789     {
790         //printf("TypeFunction::toCBuffer2() t = %p, ref = %d\n", t, t->isref);
791         visitFuncIdentWithPostfix(t, null);
792     }
793 
794     // callback for TypeFunction::attributesApply
795     struct PrePostAppendStrings
796     {
797         OutBuffer* buf;
798         bool isPostfixStyle;
799         bool isCtor;
800 
801         extern (C++) static int fp(void* param, const(char)* str)
802         {
803             PrePostAppendStrings* p = cast(PrePostAppendStrings*)param;
804             // don't write 'ref' for ctors
805             if (p.isCtor && strcmp(str, "ref") == 0)
806                 return 0;
807             if (p.isPostfixStyle)
808                 p.buf.writeByte(' ');
809             p.buf.writestring(str);
810             if (!p.isPostfixStyle)
811                 p.buf.writeByte(' ');
812             return 0;
813         }
814     }
815 
816     void visitFuncIdentWithPostfix(TypeFunction t, const(char)* ident)
817     {
818         if (t.inuse)
819         {
820             t.inuse = 2; // flag error to caller
821             return;
822         }
823         t.inuse++;
824         PrePostAppendStrings pas;
825         pas.buf = buf;
826         pas.isCtor = false;
827         pas.isPostfixStyle = true;
828         if (t.linkage > LINKd && hgs.ddoc != 1 && !hgs.hdrgen)
829         {
830             linkageToBuffer(buf, t.linkage);
831             buf.writeByte(' ');
832         }
833         if (t.next)
834         {
835             typeToBuffer(t.next, null);
836             if (ident)
837                 buf.writeByte(' ');
838         }
839         else if (hgs.ddoc)
840             buf.writestring("auto ");
841         if (ident)
842             buf.writestring(ident);
843         parametersToBuffer(t.parameters, t.varargs);
844         /* Use postfix style for attributes
845          */
846         if (t.mod)
847         {
848             buf.writeByte(' ');
849             MODtoBuffer(buf, t.mod);
850         }
851         t.attributesApply(&pas, &PrePostAppendStrings.fp);
852         t.inuse--;
853     }
854 
855     void visitFuncIdentWithPrefix(TypeFunction t, Identifier ident, TemplateDeclaration td, bool isPostfixStyle)
856     {
857         if (t.inuse)
858         {
859             t.inuse = 2; // flag error to caller
860             return;
861         }
862         t.inuse++;
863         PrePostAppendStrings pas;
864         pas.buf = buf;
865         pas.isCtor = (ident == Id.ctor);
866         pas.isPostfixStyle = false;
867         /* Use 'storage class' (prefix) style for attributes
868          */
869         if (t.mod)
870         {
871             MODtoBuffer(buf, t.mod);
872             buf.writeByte(' ');
873         }
874         t.attributesApply(&pas, &PrePostAppendStrings.fp);
875         if (t.linkage > LINKd && hgs.ddoc != 1 && !hgs.hdrgen)
876         {
877             linkageToBuffer(buf, t.linkage);
878             buf.writeByte(' ');
879         }
880         if (ident && ident.toHChars2() != ident.toChars())
881         {
882             // Don't print return type for ctor, dtor, unittest, etc
883         }
884         else if (t.next)
885         {
886             typeToBuffer(t.next, null);
887             if (ident)
888                 buf.writeByte(' ');
889         }
890         else if (hgs.ddoc)
891             buf.writestring("auto ");
892         if (ident)
893             buf.writestring(ident.toHChars2());
894         if (td)
895         {
896             buf.writeByte('(');
897             foreach (i, p; *td.origParameters)
898             {
899                 if (i)
900                     buf.writestring(", ");
901                 p.accept(this);
902             }
903             buf.writeByte(')');
904         }
905         parametersToBuffer(t.parameters, t.varargs);
906         t.inuse--;
907     }
908 
909     override void visit(TypeDelegate t)
910     {
911         visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "delegate");
912     }
913 
914     void visitTypeQualifiedHelper(TypeQualified t)
915     {
916         foreach (id; t.idents)
917         {
918             if (id.dyncast() == DYNCAST_DSYMBOL)
919             {
920                 buf.writeByte('.');
921                 TemplateInstance ti = cast(TemplateInstance)id;
922                 ti.accept(this);
923             }
924             else if (id.dyncast() == DYNCAST_EXPRESSION)
925             {
926                 buf.writeByte('[');
927                 (cast(Expression)id).accept(this);
928                 buf.writeByte(']');
929             }
930             else if (id.dyncast() == DYNCAST_TYPE)
931             {
932                 buf.writeByte('[');
933                 (cast(Type)id).accept(this);
934                 buf.writeByte(']');
935             }
936             else
937             {
938                 buf.writeByte('.');
939                 buf.writestring(id.toChars());
940             }
941         }
942     }
943 
944     override void visit(TypeIdentifier t)
945     {
946         buf.writestring(t.ident.toChars());
947         visitTypeQualifiedHelper(t);
948     }
949 
950     override void visit(TypeInstance t)
951     {
952         t.tempinst.accept(this);
953         visitTypeQualifiedHelper(t);
954     }
955 
956     override void visit(TypeTypeof t)
957     {
958         buf.writestring("typeof(");
959         t.exp.accept(this);
960         buf.writeByte(')');
961         visitTypeQualifiedHelper(t);
962     }
963 
964     override void visit(TypeReturn t)
965     {
966         buf.writestring("typeof(return)");
967         visitTypeQualifiedHelper(t);
968     }
969 
970     override void visit(TypeEnum t)
971     {
972         buf.writestring(t.sym.toChars());
973     }
974 
975     override void visit(TypeStruct t)
976     {
977         // Bugzilla 13776: Don't use ti->toAlias() to avoid forward reference error
978         // while printing messages.
979         TemplateInstance ti = t.sym.parent ? t.sym.parent.isTemplateInstance() : null;
980         if (ti && ti.aliasdecl == t.sym)
981             buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars());
982         else
983             buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars());
984     }
985 
986     override void visit(TypeClass t)
987     {
988         // Bugzilla 13776: Don't use ti->toAlias() to avoid forward reference error
989         // while printing messages.
990         TemplateInstance ti = t.sym.parent.isTemplateInstance();
991         if (ti && ti.aliasdecl == t.sym)
992             buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars());
993         else
994             buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars());
995     }
996 
997     override void visit(TypeTuple t)
998     {
999         parametersToBuffer(t.arguments, 0);
1000     }
1001 
1002     override void visit(TypeSlice t)
1003     {
1004         visitWithMask(t.next, t.mod);
1005         buf.writeByte('[');
1006         sizeToBuffer(t.lwr);
1007         buf.writestring(" .. ");
1008         sizeToBuffer(t.upr);
1009         buf.writeByte(']');
1010     }
1011 
1012     override void visit(TypeNull t)
1013     {
1014         buf.writestring("typeof(null)");
1015     }
1016 
1017     ////////////////////////////////////////////////////////////////////////////
1018     override void visit(Dsymbol s)
1019     {
1020         buf.writestring(s.toChars());
1021     }
1022 
1023     override void visit(StaticAssert s)
1024     {
1025         buf.writestring(s.kind());
1026         buf.writeByte('(');
1027         s.exp.accept(this);
1028         if (s.msg)
1029         {
1030             buf.writestring(", ");
1031             s.msg.accept(this);
1032         }
1033         buf.writestring(");");
1034         buf.writenl();
1035     }
1036 
1037     override void visit(DebugSymbol s)
1038     {
1039         buf.writestring("debug = ");
1040         if (s.ident)
1041             buf.writestring(s.ident.toChars());
1042         else
1043             buf.printf("%u", s.level);
1044         buf.writestring(";");
1045         buf.writenl();
1046     }
1047 
1048     override void visit(VersionSymbol s)
1049     {
1050         buf.writestring("version = ");
1051         if (s.ident)
1052             buf.writestring(s.ident.toChars());
1053         else
1054             buf.printf("%u", s.level);
1055         buf.writestring(";");
1056         buf.writenl();
1057     }
1058 
1059     override void visit(EnumMember em)
1060     {
1061         if (em.type)
1062             typeToBuffer(em.type, em.ident);
1063         else
1064             buf.writestring(em.ident.toChars());
1065         if (em.value)
1066         {
1067             buf.writestring(" = ");
1068             em.value.accept(this);
1069         }
1070     }
1071 
1072     override void visit(Import imp)
1073     {
1074         if (hgs.hdrgen && imp.id == Id.object)
1075             return; // object is imported by default
1076         if (imp.isstatic)
1077             buf.writestring("static ");
1078         buf.writestring("import ");
1079         if (imp.aliasId)
1080         {
1081             buf.printf("%s = ", imp.aliasId.toChars());
1082         }
1083         if (imp.packages && imp.packages.dim)
1084         {
1085             foreach (const pid; *imp.packages)
1086             {
1087                 buf.printf("%s.", pid.toChars());
1088             }
1089         }
1090         buf.printf("%s", imp.id.toChars());
1091         if (imp.names.dim)
1092         {
1093             buf.writestring(" : ");
1094             foreach (const i, const name; imp.names)
1095             {
1096                 if (i)
1097                     buf.writestring(", ");
1098                 const _alias = imp.aliases[i];
1099                 if (_alias)
1100                     buf.printf("%s = %s", _alias.toChars(), name.toChars());
1101                 else
1102                     buf.printf("%s", name.toChars());
1103             }
1104         }
1105         buf.printf(";");
1106         buf.writenl();
1107     }
1108 
1109     override void visit(AliasThis d)
1110     {
1111         buf.writestring("alias ");
1112         buf.writestring(d.ident.toChars());
1113         buf.writestring(" this;\n");
1114     }
1115 
1116     override void visit(AttribDeclaration d)
1117     {
1118         if (!d.decl)
1119         {
1120             buf.writeByte(';');
1121             buf.writenl();
1122             return;
1123         }
1124         if (d.decl.dim == 0)
1125             buf.writestring("{}");
1126         else if (hgs.hdrgen && d.decl.dim == 1 && (*d.decl)[0].isUnitTestDeclaration())
1127         {
1128             // hack for bugzilla 8081
1129             buf.writestring("{}");
1130         }
1131         else if (d.decl.dim == 1)
1132         {
1133             (*d.decl)[0].accept(this);
1134             return;
1135         }
1136         else
1137         {
1138             buf.writenl();
1139             buf.writeByte('{');
1140             buf.writenl();
1141             buf.level++;
1142             foreach (de; *d.decl)
1143                 de.accept(this);
1144             buf.level--;
1145             buf.writeByte('}');
1146         }
1147         buf.writenl();
1148     }
1149 
1150     override void visit(StorageClassDeclaration d)
1151     {
1152         if (stcToBuffer(buf, d.stc))
1153             buf.writeByte(' ');
1154         visit(cast(AttribDeclaration)d);
1155     }
1156 
1157     override void visit(DeprecatedDeclaration d)
1158     {
1159         buf.writestring("deprecated(");
1160         d.msg.accept(this);
1161         buf.writestring(") ");
1162         visit(cast(AttribDeclaration)d);
1163     }
1164 
1165     override void visit(LinkDeclaration d)
1166     {
1167         const(char)* p;
1168         switch (d.linkage)
1169         {
1170         case LINKd:
1171             p = "D";
1172             break;
1173         case LINKc:
1174             p = "C";
1175             break;
1176         case LINKcpp:
1177             p = "C++";
1178             break;
1179         case LINKwindows:
1180             p = "Windows";
1181             break;
1182         case LINKpascal:
1183             p = "Pascal";
1184             break;
1185         case LINKobjc:
1186             p = "Objective-C";
1187             break;
1188         default:
1189             assert(0);
1190         }
1191         buf.writestring("extern (");
1192         buf.writestring(p);
1193         buf.writestring(") ");
1194         visit(cast(AttribDeclaration)d);
1195     }
1196 
1197     override void visit(CPPMangleDeclaration d)
1198     {
1199         const(char)* p;
1200         switch (d.cppmangle)
1201         {
1202         case CPPMANGLE.asClass:
1203             p = "class";
1204             break;
1205         case CPPMANGLE.asStruct:
1206             p = "struct";
1207             break;
1208         default:
1209             assert(0);
1210         }
1211         buf.writestring("extern (C++, ");
1212         buf.writestring(p);
1213         buf.writestring(") ");
1214         visit(cast(AttribDeclaration)d);
1215     }
1216 
1217     override void visit(ProtDeclaration d)
1218     {
1219         protectionToBuffer(buf, d.protection);
1220         buf.writeByte(' ');
1221         visit(cast(AttribDeclaration)d);
1222     }
1223 
1224     override void visit(AlignDeclaration d)
1225     {
1226         if (!d.ealign)
1227             buf.printf("align ");
1228         else
1229             buf.printf("align (%s) ", d.ealign.toChars());
1230         visit(cast(AttribDeclaration)d);
1231     }
1232 
1233     override void visit(AnonDeclaration d)
1234     {
1235         buf.printf(d.isunion ? "union" : "struct");
1236         buf.writenl();
1237         buf.writestring("{");
1238         buf.writenl();
1239         buf.level++;
1240         if (d.decl)
1241         {
1242             foreach (de; *d.decl)
1243                 de.accept(this);
1244         }
1245         buf.level--;
1246         buf.writestring("}");
1247         buf.writenl();
1248     }
1249 
1250     override void visit(PragmaDeclaration d)
1251     {
1252         buf.printf("pragma (%s", d.ident.toChars());
1253         if (d.args && d.args.dim)
1254         {
1255             buf.writestring(", ");
1256             argsToBuffer(d.args);
1257         }
1258         buf.writeByte(')');
1259         visit(cast(AttribDeclaration)d);
1260     }
1261 
1262     override void visit(ConditionalDeclaration d)
1263     {
1264         d.condition.accept(this);
1265         if (d.decl || d.elsedecl)
1266         {
1267             buf.writenl();
1268             buf.writeByte('{');
1269             buf.writenl();
1270             buf.level++;
1271             if (d.decl)
1272             {
1273                 foreach (de; *d.decl)
1274                     de.accept(this);
1275             }
1276             buf.level--;
1277             buf.writeByte('}');
1278             if (d.elsedecl)
1279             {
1280                 buf.writenl();
1281                 buf.writestring("else");
1282                 buf.writenl();
1283                 buf.writeByte('{');
1284                 buf.writenl();
1285                 buf.level++;
1286                 foreach (de; *d.elsedecl)
1287                     de.accept(this);
1288                 buf.level--;
1289                 buf.writeByte('}');
1290             }
1291         }
1292         else
1293             buf.writeByte(':');
1294         buf.writenl();
1295     }
1296 
1297     override void visit(CompileDeclaration d)
1298     {
1299         buf.writestring("mixin(");
1300         d.exp.accept(this);
1301         buf.writestring(");");
1302         buf.writenl();
1303     }
1304 
1305     override void visit(UserAttributeDeclaration d)
1306     {
1307         buf.writestring("@(");
1308         argsToBuffer(d.atts);
1309         buf.writeByte(')');
1310         visit(cast(AttribDeclaration)d);
1311     }
1312 
1313     override void visit(TemplateDeclaration d)
1314     {
1315         version (none)
1316         {
1317             // Should handle template functions for doc generation
1318             if (onemember && onemember.isFuncDeclaration())
1319                 buf.writestring("foo ");
1320         }
1321         if (hgs.hdrgen && visitEponymousMember(d))
1322             return;
1323         if (hgs.ddoc)
1324             buf.writestring(d.kind());
1325         else
1326             buf.writestring("template");
1327         buf.writeByte(' ');
1328         buf.writestring(d.ident.toChars());
1329         buf.writeByte('(');
1330         visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters);
1331         buf.writeByte(')');
1332         visitTemplateConstraint(d.constraint);
1333         if (hgs.hdrgen)
1334         {
1335             hgs.tpltMember++;
1336             buf.writenl();
1337             buf.writeByte('{');
1338             buf.writenl();
1339             buf.level++;
1340             foreach (s; *d.members)
1341                 s.accept(this);
1342             buf.level--;
1343             buf.writeByte('}');
1344             buf.writenl();
1345             hgs.tpltMember--;
1346         }
1347     }
1348 
1349     bool visitEponymousMember(TemplateDeclaration d)
1350     {
1351         if (!d.members || d.members.dim != 1)
1352             return false;
1353         Dsymbol onemember = (*d.members)[0];
1354         if (onemember.ident != d.ident)
1355             return false;
1356         if (FuncDeclaration fd = onemember.isFuncDeclaration())
1357         {
1358             assert(fd.type);
1359             if (stcToBuffer(buf, fd.storage_class))
1360                 buf.writeByte(' ');
1361             functionToBufferFull(cast(TypeFunction)fd.type, buf, d.ident, hgs, d);
1362             visitTemplateConstraint(d.constraint);
1363             hgs.tpltMember++;
1364             bodyToBuffer(fd);
1365             hgs.tpltMember--;
1366             return true;
1367         }
1368         if (AggregateDeclaration ad = onemember.isAggregateDeclaration())
1369         {
1370             buf.writestring(ad.kind());
1371             buf.writeByte(' ');
1372             buf.writestring(ad.ident.toChars());
1373             buf.writeByte('(');
1374             visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters);
1375             buf.writeByte(')');
1376             visitTemplateConstraint(d.constraint);
1377             visitBaseClasses(ad.isClassDeclaration());
1378             hgs.tpltMember++;
1379             if (ad.members)
1380             {
1381                 buf.writenl();
1382                 buf.writeByte('{');
1383                 buf.writenl();
1384                 buf.level++;
1385                 foreach (s; *ad.members)
1386                     s.accept(this);
1387                 buf.level--;
1388                 buf.writeByte('}');
1389             }
1390             else
1391                 buf.writeByte(';');
1392             buf.writenl();
1393             hgs.tpltMember--;
1394             return true;
1395         }
1396         if (VarDeclaration vd = onemember.isVarDeclaration())
1397         {
1398             if (d.constraint)
1399                 return false;
1400             if (stcToBuffer(buf, vd.storage_class))
1401                 buf.writeByte(' ');
1402             if (vd.type)
1403                 typeToBuffer(vd.type, vd.ident);
1404             else
1405                 buf.writestring(vd.ident.toChars());
1406             buf.writeByte('(');
1407             visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters);
1408             buf.writeByte(')');
1409             if (vd._init)
1410             {
1411                 buf.writestring(" = ");
1412                 ExpInitializer ie = vd._init.isExpInitializer();
1413                 if (ie && (ie.exp.op == TOKconstruct || ie.exp.op == TOKblit))
1414                     (cast(AssignExp)ie.exp).e2.accept(this);
1415                 else
1416                     vd._init.accept(this);
1417             }
1418             buf.writeByte(';');
1419             buf.writenl();
1420             return true;
1421         }
1422         return false;
1423     }
1424 
1425     void visitTemplateParameters(TemplateParameters* parameters)
1426     {
1427         if (!parameters || !parameters.dim)
1428             return;
1429         foreach (i, p; *parameters)
1430         {
1431             if (i)
1432                 buf.writestring(", ");
1433             p.accept(this);
1434         }
1435     }
1436 
1437     void visitTemplateConstraint(Expression constraint)
1438     {
1439         if (!constraint)
1440             return;
1441         buf.writestring(" if (");
1442         constraint.accept(this);
1443         buf.writeByte(')');
1444     }
1445 
1446     override void visit(TemplateInstance ti)
1447     {
1448         buf.writestring(ti.name.toChars());
1449         tiargsToBuffer(ti);
1450     }
1451 
1452     override void visit(TemplateMixin tm)
1453     {
1454         buf.writestring("mixin ");
1455         typeToBuffer(tm.tqual, null);
1456         tiargsToBuffer(tm);
1457         if (tm.ident && memcmp(tm.ident.toChars(), cast(const(char)*)"__mixin", 7) != 0)
1458         {
1459             buf.writeByte(' ');
1460             buf.writestring(tm.ident.toChars());
1461         }
1462         buf.writeByte(';');
1463         buf.writenl();
1464     }
1465 
1466     void tiargsToBuffer(TemplateInstance ti)
1467     {
1468         buf.writeByte('!');
1469         if (ti.nest)
1470         {
1471             buf.writestring("(...)");
1472             return;
1473         }
1474         if (!ti.tiargs)
1475         {
1476             buf.writestring("()");
1477             return;
1478         }
1479         if (ti.tiargs.dim == 1)
1480         {
1481             RootObject oarg = (*ti.tiargs)[0];
1482             if (Type t = isType(oarg))
1483             {
1484                 if (t.equals(Type.tstring) || t.equals(Type.twstring) || t.equals(Type.tdstring) || t.mod == 0 && (t.isTypeBasic() || t.ty == Tident && (cast(TypeIdentifier)t).idents.dim == 0))
1485                 {
1486                     buf.writestring(t.toChars());
1487                     return;
1488                 }
1489             }
1490             else if (Expression e = isExpression(oarg))
1491             {
1492                 if (e.op == TOKint64 || e.op == TOKfloat64 || e.op == TOKnull || e.op == TOKstring || e.op == TOKthis)
1493                 {
1494                     buf.writestring(e.toChars());
1495                     return;
1496                 }
1497             }
1498         }
1499         buf.writeByte('(');
1500         ti.nest++;
1501         foreach (i, arg; *ti.tiargs)
1502         {
1503             if (i)
1504                 buf.writestring(", ");
1505             objectToBuffer(arg);
1506         }
1507         ti.nest--;
1508         buf.writeByte(')');
1509     }
1510 
1511     /****************************************
1512      * This makes a 'pretty' version of the template arguments.
1513      * It's analogous to genIdent() which makes a mangled version.
1514      */
1515     void objectToBuffer(RootObject oarg)
1516     {
1517         //printf("objectToBuffer()\n");
1518         /* The logic of this should match what genIdent() does. The _dynamic_cast()
1519          * function relies on all the pretty strings to be unique for different classes
1520          * (see Bugzilla 7375).
1521          * Perhaps it would be better to demangle what genIdent() does.
1522          */
1523         if (auto t = isType(oarg))
1524         {
1525             //printf("\tt: %s ty = %d\n", t->toChars(), t->ty);
1526             typeToBuffer(t, null);
1527         }
1528         else if (auto e = isExpression(oarg))
1529         {
1530             if (e.op == TOKvar)
1531                 e = e.optimize(WANTvalue); // added to fix Bugzilla 7375
1532             e.accept(this);
1533         }
1534         else if (Dsymbol s = isDsymbol(oarg))
1535         {
1536             const p = s.ident ? s.ident.toChars() : s.toChars();
1537             buf.writestring(p);
1538         }
1539         else if (auto v = isTuple(oarg))
1540         {
1541             auto args = &v.objects;
1542             foreach (i, arg; *args)
1543             {
1544                 if (i)
1545                     buf.writestring(", ");
1546                 objectToBuffer(arg);
1547             }
1548         }
1549         else if (!oarg)
1550         {
1551             buf.writestring("NULL");
1552         }
1553         else
1554         {
1555             debug
1556             {
1557                 printf("bad Object = %p\n", oarg);
1558             }
1559             assert(0);
1560         }
1561     }
1562 
1563     override void visit(EnumDeclaration d)
1564     {
1565         buf.writestring("enum ");
1566         if (d.ident)
1567         {
1568             buf.writestring(d.ident.toChars());
1569             buf.writeByte(' ');
1570         }
1571         if (d.memtype)
1572         {
1573             buf.writestring(": ");
1574             typeToBuffer(d.memtype, null);
1575         }
1576         if (!d.members)
1577         {
1578             buf.writeByte(';');
1579             buf.writenl();
1580             return;
1581         }
1582         buf.writenl();
1583         buf.writeByte('{');
1584         buf.writenl();
1585         buf.level++;
1586         foreach (em; *d.members)
1587         {
1588             if (!em)
1589                 continue;
1590             em.accept(this);
1591             buf.writeByte(',');
1592             buf.writenl();
1593         }
1594         buf.level--;
1595         buf.writeByte('}');
1596         buf.writenl();
1597     }
1598 
1599     override void visit(Nspace d)
1600     {
1601         buf.writestring("extern (C++, ");
1602         buf.writestring(d.ident.toChars());
1603         buf.writeByte(')');
1604         buf.writenl();
1605         buf.writeByte('{');
1606         buf.writenl();
1607         buf.level++;
1608         foreach (s; *d.members)
1609             s.accept(this);
1610         buf.level--;
1611         buf.writeByte('}');
1612         buf.writenl();
1613     }
1614 
1615     override void visit(StructDeclaration d)
1616     {
1617         buf.printf("%s ", d.kind());
1618         if (!d.isAnonymous())
1619             buf.writestring(d.toChars());
1620         if (!d.members)
1621         {
1622             buf.writeByte(';');
1623             buf.writenl();
1624             return;
1625         }
1626         buf.writenl();
1627         buf.writeByte('{');
1628         buf.writenl();
1629         buf.level++;
1630         foreach (s; *d.members)
1631             s.accept(this);
1632         buf.level--;
1633         buf.writeByte('}');
1634         buf.writenl();
1635     }
1636 
1637     override void visit(ClassDeclaration d)
1638     {
1639         if (!d.isAnonymous())
1640         {
1641             buf.writestring(d.kind());
1642             buf.writeByte(' ');
1643             buf.writestring(d.ident.toChars());
1644         }
1645         visitBaseClasses(d);
1646         if (d.members)
1647         {
1648             buf.writenl();
1649             buf.writeByte('{');
1650             buf.writenl();
1651             buf.level++;
1652             foreach (s; *d.members)
1653                 s.accept(this);
1654             buf.level--;
1655             buf.writeByte('}');
1656         }
1657         else
1658             buf.writeByte(';');
1659         buf.writenl();
1660     }
1661 
1662     void visitBaseClasses(ClassDeclaration d)
1663     {
1664         if (!d || !d.baseclasses.dim)
1665             return;
1666         buf.writestring(" : ");
1667         foreach (i, b; *d.baseclasses)
1668         {
1669             if (i)
1670                 buf.writestring(", ");
1671             typeToBuffer(b.type, null);
1672         }
1673     }
1674 
1675     override void visit(AliasDeclaration d)
1676     {
1677         buf.writestring("alias ");
1678         if (d.aliassym)
1679         {
1680             buf.writestring(d.ident.toChars());
1681             buf.writestring(" = ");
1682             if (stcToBuffer(buf, d.storage_class))
1683                 buf.writeByte(' ');
1684             d.aliassym.accept(this);
1685         }
1686         else if (d.type.ty == Tfunction)
1687         {
1688             if (stcToBuffer(buf, d.storage_class))
1689                 buf.writeByte(' ');
1690             typeToBuffer(d.type, d.ident);
1691         }
1692         else
1693         {
1694             declstring = (d.ident == Id..string || d.ident == Id.wstring || d.ident == Id.dstring);
1695             buf.writestring(d.ident.toChars());
1696             buf.writestring(" = ");
1697             if (stcToBuffer(buf, d.storage_class))
1698                 buf.writeByte(' ');
1699             typeToBuffer(d.type, null);
1700             declstring = false;
1701         }
1702         buf.writeByte(';');
1703         buf.writenl();
1704     }
1705 
1706     override void visit(VarDeclaration d)
1707     {
1708         visitVarDecl(d, false);
1709         buf.writeByte(';');
1710         buf.writenl();
1711     }
1712 
1713     void visitVarDecl(VarDeclaration v, bool anywritten)
1714     {
1715         if (anywritten)
1716         {
1717             buf.writestring(", ");
1718             buf.writestring(v.ident.toChars());
1719         }
1720         else
1721         {
1722             if (stcToBuffer(buf, v.storage_class))
1723                 buf.writeByte(' ');
1724             if (v.type)
1725                 typeToBuffer(v.type, v.ident);
1726             else
1727                 buf.writestring(v.ident.toChars());
1728         }
1729         if (v._init)
1730         {
1731             buf.writestring(" = ");
1732             auto ie = v._init.isExpInitializer();
1733             if (ie && (ie.exp.op == TOKconstruct || ie.exp.op == TOKblit))
1734                 (cast(AssignExp)ie.exp).e2.accept(this);
1735             else
1736                 v._init.accept(this);
1737         }
1738     }
1739 
1740     override void visit(FuncDeclaration f)
1741     {
1742         //printf("FuncDeclaration::toCBuffer() '%s'\n", f->toChars());
1743         if (stcToBuffer(buf, f.storage_class))
1744             buf.writeByte(' ');
1745         typeToBuffer(f.type, f.ident);
1746         if (hgs.hdrgen == 1)
1747         {
1748             if (f.storage_class & STCauto)
1749             {
1750                 hgs.autoMember++;
1751                 bodyToBuffer(f);
1752                 hgs.autoMember--;
1753             }
1754             else if (hgs.tpltMember == 0 && global.params.hdrStripPlainFunctions)
1755             {
1756                 buf.writeByte(';');
1757                 buf.writenl();
1758             }
1759             else
1760                 bodyToBuffer(f);
1761         }
1762         else
1763             bodyToBuffer(f);
1764     }
1765 
1766     void bodyToBuffer(FuncDeclaration f)
1767     {
1768         if (!f.fbody || (hgs.hdrgen && global.params.hdrStripPlainFunctions && !hgs.autoMember && !hgs.tpltMember))
1769         {
1770             buf.writeByte(';');
1771             buf.writenl();
1772             return;
1773         }
1774         int savetlpt = hgs.tpltMember;
1775         int saveauto = hgs.autoMember;
1776         hgs.tpltMember = 0;
1777         hgs.autoMember = 0;
1778         buf.writenl();
1779         // in{}
1780         if (f.frequire)
1781         {
1782             buf.writestring("in");
1783             buf.writenl();
1784             f.frequire.accept(this);
1785         }
1786         // out{}
1787         if (f.fensure)
1788         {
1789             buf.writestring("out");
1790             if (f.outId)
1791             {
1792                 buf.writeByte('(');
1793                 buf.writestring(f.outId.toChars());
1794                 buf.writeByte(')');
1795             }
1796             buf.writenl();
1797             f.fensure.accept(this);
1798         }
1799         if (f.frequire || f.fensure)
1800         {
1801             buf.writestring("body");
1802             buf.writenl();
1803         }
1804         buf.writeByte('{');
1805         buf.writenl();
1806         buf.level++;
1807         f.fbody.accept(this);
1808         buf.level--;
1809         buf.writeByte('}');
1810         buf.writenl();
1811         hgs.tpltMember = savetlpt;
1812         hgs.autoMember = saveauto;
1813     }
1814 
1815     override void visit(FuncLiteralDeclaration f)
1816     {
1817         if (f.type.ty == Terror)
1818         {
1819             buf.writestring("__error");
1820             return;
1821         }
1822         if (f.tok != TOKreserved)
1823         {
1824             buf.writestring(f.kind());
1825             buf.writeByte(' ');
1826         }
1827         TypeFunction tf = cast(TypeFunction)f.type;
1828         // Don't print tf->mod, tf->trust, and tf->linkage
1829         if (!f.inferRetType && tf.next)
1830             typeToBuffer(tf.next, null);
1831         parametersToBuffer(tf.parameters, tf.varargs);
1832         CompoundStatement cs = f.fbody.isCompoundStatement();
1833         Statement s1;
1834         if (f.semanticRun >= PASSsemantic3done && cs)
1835         {
1836             s1 = (*cs.statements)[cs.statements.dim - 1];
1837         }
1838         else
1839             s1 = !cs ? f.fbody : null;
1840         ReturnStatement rs = s1 ? s1.isReturnStatement() : null;
1841         if (rs && rs.exp)
1842         {
1843             buf.writestring(" => ");
1844             rs.exp.accept(this);
1845         }
1846         else
1847         {
1848             hgs.tpltMember++;
1849             bodyToBuffer(f);
1850             hgs.tpltMember--;
1851         }
1852     }
1853 
1854     override void visit(PostBlitDeclaration d)
1855     {
1856         buf.writestring("this(this)");
1857         bodyToBuffer(d);
1858     }
1859 
1860     override void visit(DtorDeclaration d)
1861     {
1862         buf.writestring("~this()");
1863         bodyToBuffer(d);
1864     }
1865 
1866     override void visit(StaticCtorDeclaration d)
1867     {
1868         if (stcToBuffer(buf, d.storage_class & ~STCstatic))
1869             buf.writeByte(' ');
1870         if (d.isSharedStaticCtorDeclaration())
1871             buf.writestring("shared ");
1872         buf.writestring("static this()");
1873         if (hgs.hdrgen && !hgs.tpltMember)
1874         {
1875             buf.writeByte(';');
1876             buf.writenl();
1877         }
1878         else
1879             bodyToBuffer(d);
1880     }
1881 
1882     override void visit(StaticDtorDeclaration d)
1883     {
1884         if (hgs.hdrgen)
1885             return;
1886         if (stcToBuffer(buf, d.storage_class & ~STCstatic))
1887             buf.writeByte(' ');
1888         if (d.isSharedStaticDtorDeclaration())
1889             buf.writestring("shared ");
1890         buf.writestring("static ~this()");
1891         bodyToBuffer(d);
1892     }
1893 
1894     override void visit(InvariantDeclaration d)
1895     {
1896         if (hgs.hdrgen)
1897             return;
1898         if (stcToBuffer(buf, d.storage_class))
1899             buf.writeByte(' ');
1900         buf.writestring("invariant");
1901         bodyToBuffer(d);
1902     }
1903 
1904     override void visit(UnitTestDeclaration d)
1905     {
1906         if (hgs.hdrgen)
1907             return;
1908         if (stcToBuffer(buf, d.storage_class))
1909             buf.writeByte(' ');
1910         buf.writestring("unittest");
1911         bodyToBuffer(d);
1912     }
1913 
1914     override void visit(NewDeclaration d)
1915     {
1916         if (stcToBuffer(buf, d.storage_class & ~STCstatic))
1917             buf.writeByte(' ');
1918         buf.writestring("new");
1919         parametersToBuffer(d.parameters, d.varargs);
1920         bodyToBuffer(d);
1921     }
1922 
1923     override void visit(DeleteDeclaration d)
1924     {
1925         if (stcToBuffer(buf, d.storage_class & ~STCstatic))
1926             buf.writeByte(' ');
1927         buf.writestring("delete");
1928         parametersToBuffer(d.parameters, 0);
1929         bodyToBuffer(d);
1930     }
1931 
1932     ////////////////////////////////////////////////////////////////////////////
1933     override void visit(ErrorInitializer iz)
1934     {
1935         buf.writestring("__error__");
1936     }
1937 
1938     override void visit(VoidInitializer iz)
1939     {
1940         buf.writestring("void");
1941     }
1942 
1943     override void visit(StructInitializer si)
1944     {
1945         //printf("StructInitializer::toCBuffer()\n");
1946         buf.writeByte('{');
1947         foreach (i, const id; si.field)
1948         {
1949             if (i)
1950                 buf.writestring(", ");
1951             if (id)
1952             {
1953                 buf.writestring(id.toChars());
1954                 buf.writeByte(':');
1955             }
1956             if (auto iz = si.value[i])
1957                 iz.accept(this);
1958         }
1959         buf.writeByte('}');
1960     }
1961 
1962     override void visit(ArrayInitializer ai)
1963     {
1964         buf.writeByte('[');
1965         foreach (i, ex; ai.index)
1966         {
1967             if (i)
1968                 buf.writestring(", ");
1969             if (ex)
1970             {
1971                 ex.accept(this);
1972                 buf.writeByte(':');
1973             }
1974             if (auto iz = ai.value[i])
1975                 iz.accept(this);
1976         }
1977         buf.writeByte(']');
1978     }
1979 
1980     override void visit(ExpInitializer ei)
1981     {
1982         ei.exp.accept(this);
1983     }
1984 
1985     ////////////////////////////////////////////////////////////////////////////
1986     /**************************************************
1987      * Write out argument list to buf.
1988      */
1989     void argsToBuffer(Expressions* expressions, Expression basis = null)
1990     {
1991         if (!expressions || !expressions.dim)
1992             return;
1993         version (all)
1994         {
1995             foreach (i, el; *expressions)
1996             {
1997                 if (i)
1998                     buf.writestring(", ");
1999                 if (!el)
2000                     el = basis;
2001                 if (el)
2002                     expToBuffer(el, PREC.assign);
2003             }
2004         }
2005         else
2006         {
2007             // Sparse style formatting, for debug use only
2008             //      [0..dim: basis, 1: e1, 5: e5]
2009             if (basis)
2010             {
2011                 buf.printf("0..%llu: ", cast(ulong)expressions.dim);
2012                 expToBuffer(basis, PREC.assign);
2013             }
2014             foreach (i, el; *expressions)
2015             {
2016                 if (el)
2017                 {
2018                     if (basis)
2019                         buf.printf(", %llu: ", cast(ulong)i);
2020                     else if (i)
2021                         buf.writestring(", ");
2022                     expToBuffer(el, PREC.assign);
2023                 }
2024             }
2025         }
2026     }
2027 
2028     void sizeToBuffer(Expression e)
2029     {
2030         if (e.type == Type.tsize_t)
2031         {
2032             Expression ex = (e.op == TOKcast ? (cast(CastExp)e).e1 : e);
2033             ex = ex.optimize(WANTvalue);
2034             dinteger_t uval = ex.op == TOKint64 ? ex.toInteger() : cast(dinteger_t)-1;
2035             if (cast(sinteger_t)uval >= 0)
2036             {
2037                 dinteger_t sizemax;
2038                 if (Target.ptrsize == 4)
2039                     sizemax = 0xFFFFFFFFU;
2040                 else if (Target.ptrsize == 8)
2041                     sizemax = 0xFFFFFFFFFFFFFFFFUL;
2042                 else
2043                     assert(0);
2044                 if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFUL)
2045                 {
2046                     buf.printf("%llu", uval);
2047                     return;
2048                 }
2049             }
2050         }
2051         expToBuffer(e, PREC.assign);
2052     }
2053 
2054     /**************************************************
2055      * Write expression out to buf, but wrap it
2056      * in ( ) if its precedence is less than pr.
2057      */
2058     void expToBuffer(Expression e, PREC pr)
2059     {
2060         debug
2061         {
2062             if (precedence[e.op] == PREC.zero)
2063                 printf("precedence not defined for token '%s'\n", Token.toChars(e.op));
2064         }
2065         assert(precedence[e.op] != PREC.zero);
2066         assert(pr != PREC.zero);
2067         //if (precedence[e->op] == 0) e->print();
2068         /* Despite precedence, we don't allow a<b<c expressions.
2069          * They must be parenthesized.
2070          */
2071         if (precedence[e.op] < pr || (pr == PREC.rel && precedence[e.op] == pr))
2072         {
2073             buf.writeByte('(');
2074             e.accept(this);
2075             buf.writeByte(')');
2076         }
2077         else
2078             e.accept(this);
2079     }
2080 
2081     override void visit(Expression e)
2082     {
2083         buf.writestring(Token.toString(e.op));
2084     }
2085 
2086     override void visit(IntegerExp e)
2087     {
2088         dinteger_t v = e.toInteger();
2089         if (e.type)
2090         {
2091             Type t = e.type;
2092         L1:
2093             switch (t.ty)
2094             {
2095             case Tenum:
2096                 {
2097                     TypeEnum te = cast(TypeEnum)t;
2098                     buf.printf("cast(%s)", te.sym.toChars());
2099                     t = te.sym.memtype;
2100                     goto L1;
2101                 }
2102             case Twchar:
2103                 // BUG: need to cast(wchar)
2104             case Tdchar:
2105                 // BUG: need to cast(dchar)
2106                 if (cast(uinteger_t)v > 0xFF)
2107                 {
2108                     buf.printf("'\\U%08x'", v);
2109                     break;
2110                 }
2111                 goto case;
2112             case Tchar:
2113                 {
2114                     size_t o = buf.offset;
2115                     if (v == '\'')
2116                         buf.writestring("'\\''");
2117                     else if (isprint(cast(int)v) && v != '\\')
2118                         buf.printf("'%c'", cast(int)v);
2119                     else
2120                         buf.printf("'\\x%02x'", cast(int)v);
2121                     if (hgs.ddoc)
2122                         escapeDdocString(buf, o);
2123                     break;
2124                 }
2125             case Tint8:
2126                 buf.writestring("cast(byte)");
2127                 goto L2;
2128             case Tint16:
2129                 buf.writestring("cast(short)");
2130                 goto L2;
2131             case Tint32:
2132             L2:
2133                 buf.printf("%d", cast(int)v);
2134                 break;
2135             case Tuns8:
2136                 buf.writestring("cast(ubyte)");
2137                 goto L3;
2138             case Tuns16:
2139                 buf.writestring("cast(ushort)");
2140                 goto L3;
2141             case Tuns32:
2142             L3:
2143                 buf.printf("%uu", cast(uint)v);
2144                 break;
2145             case Tint64:
2146                 buf.printf("%lldL", v);
2147                 break;
2148             case Tuns64:
2149             L4:
2150                 buf.printf("%lluLU", v);
2151                 break;
2152             case Tbool:
2153                 buf.writestring(v ? "true" : "false");
2154                 break;
2155             case Tpointer:
2156                 buf.writestring("cast(");
2157                 buf.writestring(t.toChars());
2158                 buf.writeByte(')');
2159                 if (Target.ptrsize == 4)
2160                     goto L3;
2161                 else if (Target.ptrsize == 8)
2162                     goto L4;
2163                 else
2164                     assert(0);
2165             default:
2166                 /* This can happen if errors, such as
2167                  * the type is painted on like in fromConstInitializer().
2168                  */
2169                 if (!global.errors)
2170                 {
2171                     debug
2172                     {
2173                         t.print();
2174                     }
2175                     assert(0);
2176                 }
2177                 break;
2178             }
2179         }
2180         else if (v & 0x8000000000000000L)
2181             buf.printf("0x%llx", v);
2182         else
2183             buf.printf("%lld", v);
2184     }
2185 
2186     override void visit(ErrorExp e)
2187     {
2188         buf.writestring("__error");
2189     }
2190 
2191     void floatToBuffer(Type type, real_t value)
2192     {
2193         /** sizeof(value)*3 is because each byte of mantissa is max
2194          of 256 (3 characters). The string will be "-M.MMMMe-4932".
2195          (ie, 8 chars more than mantissa). Plus one for trailing \0.
2196          Plus one for rounding. */
2197         const(size_t) BUFFER_LEN = value.sizeof * 3 + 8 + 1 + 1;
2198         char[BUFFER_LEN] buffer;
2199         CTFloat.sprint(buffer.ptr, 'g', value);
2200         assert(strlen(buffer.ptr) < BUFFER_LEN);
2201         if (hgs.hdrgen)
2202         {
2203             real_t r = CTFloat.parse(buffer.ptr);
2204             if (r != value) // if exact duplication
2205                 CTFloat.sprint(buffer.ptr, 'a', value);
2206         }
2207         buf.writestring(buffer.ptr);
2208         if (type)
2209         {
2210             Type t = type.toBasetype();
2211             switch (t.ty)
2212             {
2213             case Tfloat32:
2214             case Timaginary32:
2215             case Tcomplex32:
2216                 buf.writeByte('F');
2217                 break;
2218             case Tfloat80:
2219             case Timaginary80:
2220             case Tcomplex80:
2221                 buf.writeByte('L');
2222                 break;
2223             default:
2224                 break;
2225             }
2226             if (t.isimaginary())
2227                 buf.writeByte('i');
2228         }
2229     }
2230 
2231     override void visit(RealExp e)
2232     {
2233         floatToBuffer(e.type, e.value);
2234     }
2235 
2236     override void visit(ComplexExp e)
2237     {
2238         /* Print as:
2239          *  (re+imi)
2240          */
2241         buf.writeByte('(');
2242         floatToBuffer(e.type, creall(e.value));
2243         buf.writeByte('+');
2244         floatToBuffer(e.type, cimagl(e.value));
2245         buf.writestring("i)");
2246     }
2247 
2248     override void visit(IdentifierExp e)
2249     {
2250         if (hgs.hdrgen || hgs.ddoc)
2251             buf.writestring(e.ident.toHChars2());
2252         else
2253             buf.writestring(e.ident.toChars());
2254     }
2255 
2256     override void visit(DsymbolExp e)
2257     {
2258         buf.writestring(e.s.toChars());
2259     }
2260 
2261     override void visit(ThisExp e)
2262     {
2263         buf.writestring("this");
2264     }
2265 
2266     override void visit(SuperExp e)
2267     {
2268         buf.writestring("super");
2269     }
2270 
2271     override void visit(NullExp e)
2272     {
2273         buf.writestring("null");
2274     }
2275 
2276     override void visit(StringExp e)
2277     {
2278         buf.writeByte('"');
2279         size_t o = buf.offset;
2280         for (size_t i = 0; i < e.len; i++)
2281         {
2282             uint c = e.charAt(i);
2283             switch (c)
2284             {
2285             case '"':
2286             case '\\':
2287                 buf.writeByte('\\');
2288                 goto default;
2289             default:
2290                 if (c <= 0xFF)
2291                 {
2292                     if (c <= 0x7F && isprint(c))
2293                         buf.writeByte(c);
2294                     else
2295                         buf.printf("\\x%02x", c);
2296                 }
2297                 else if (c <= 0xFFFF)
2298                     buf.printf("\\x%02x\\x%02x", c & 0xFF, c >> 8);
2299                 else
2300                     buf.printf("\\x%02x\\x%02x\\x%02x\\x%02x", c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24);
2301                 break;
2302             }
2303         }
2304         if (hgs.ddoc)
2305             escapeDdocString(buf, o);
2306         buf.writeByte('"');
2307         if (e.postfix)
2308             buf.writeByte(e.postfix);
2309     }
2310 
2311     override void visit(ArrayLiteralExp e)
2312     {
2313         buf.writeByte('[');
2314         argsToBuffer(e.elements, e.basis);
2315         buf.writeByte(']');
2316     }
2317 
2318     override void visit(AssocArrayLiteralExp e)
2319     {
2320         buf.writeByte('[');
2321         foreach (i, key; *e.keys)
2322         {
2323             if (i)
2324                 buf.writestring(", ");
2325             expToBuffer(key, PREC.assign);
2326             buf.writeByte(':');
2327             auto value = (*e.values)[i];
2328             expToBuffer(value, PREC.assign);
2329         }
2330         buf.writeByte(']');
2331     }
2332 
2333     override void visit(StructLiteralExp e)
2334     {
2335         buf.writestring(e.sd.toChars());
2336         buf.writeByte('(');
2337         // CTFE can generate struct literals that contain an AddrExp pointing
2338         // to themselves, need to avoid infinite recursion:
2339         // struct S { this(int){ this.s = &this; } S* s; }
2340         // const foo = new S(0);
2341         if (e.stageflags & stageToCBuffer)
2342             buf.writestring("<recursion>");
2343         else
2344         {
2345             int old = e.stageflags;
2346             e.stageflags |= stageToCBuffer;
2347             argsToBuffer(e.elements);
2348             e.stageflags = old;
2349         }
2350         buf.writeByte(')');
2351     }
2352 
2353     override void visit(TypeExp e)
2354     {
2355         typeToBuffer(e.type, null);
2356     }
2357 
2358     override void visit(ScopeExp e)
2359     {
2360         if (e.sds.isTemplateInstance())
2361         {
2362             e.sds.accept(this);
2363         }
2364         else if (hgs !is null && hgs.ddoc)
2365         {
2366             // fixes bug 6491
2367             Module m = e.sds.isModule();
2368             if (m)
2369                 buf.writestring(m.md.toChars());
2370             else
2371                 buf.writestring(e.sds.toChars());
2372         }
2373         else
2374         {
2375             buf.writestring(e.sds.kind());
2376             buf.writeByte(' ');
2377             buf.writestring(e.sds.toChars());
2378         }
2379     }
2380 
2381     override void visit(TemplateExp e)
2382     {
2383         buf.writestring(e.td.toChars());
2384     }
2385 
2386     override void visit(NewExp e)
2387     {
2388         if (e.thisexp)
2389         {
2390             expToBuffer(e.thisexp, PREC.primary);
2391             buf.writeByte('.');
2392         }
2393         buf.writestring("new ");
2394         if (e.newargs && e.newargs.dim)
2395         {
2396             buf.writeByte('(');
2397             argsToBuffer(e.newargs);
2398             buf.writeByte(')');
2399         }
2400         typeToBuffer(e.newtype, null);
2401         if (e.arguments && e.arguments.dim)
2402         {
2403             buf.writeByte('(');
2404             argsToBuffer(e.arguments);
2405             buf.writeByte(')');
2406         }
2407     }
2408 
2409     override void visit(NewAnonClassExp e)
2410     {
2411         if (e.thisexp)
2412         {
2413             expToBuffer(e.thisexp, PREC.primary);
2414             buf.writeByte('.');
2415         }
2416         buf.writestring("new");
2417         if (e.newargs && e.newargs.dim)
2418         {
2419             buf.writeByte('(');
2420             argsToBuffer(e.newargs);
2421             buf.writeByte(')');
2422         }
2423         buf.writestring(" class ");
2424         if (e.arguments && e.arguments.dim)
2425         {
2426             buf.writeByte('(');
2427             argsToBuffer(e.arguments);
2428             buf.writeByte(')');
2429         }
2430         if (e.cd)
2431             e.cd.accept(this);
2432     }
2433 
2434     override void visit(SymOffExp e)
2435     {
2436         if (e.offset)
2437             buf.printf("(& %s+%u)", e.var.toChars(), e.offset);
2438         else if (e.var.isTypeInfoDeclaration())
2439             buf.printf("%s", e.var.toChars());
2440         else
2441             buf.printf("& %s", e.var.toChars());
2442     }
2443 
2444     override void visit(VarExp e)
2445     {
2446         buf.writestring(e.var.toChars());
2447     }
2448 
2449     override void visit(OverExp e)
2450     {
2451         buf.writestring(e.vars.ident.toChars());
2452     }
2453 
2454     override void visit(TupleExp e)
2455     {
2456         if (e.e0)
2457         {
2458             buf.writeByte('(');
2459             e.e0.accept(this);
2460             buf.writestring(", tuple(");
2461             argsToBuffer(e.exps);
2462             buf.writestring("))");
2463         }
2464         else
2465         {
2466             buf.writestring("tuple(");
2467             argsToBuffer(e.exps);
2468             buf.writeByte(')');
2469         }
2470     }
2471 
2472     override void visit(FuncExp e)
2473     {
2474         e.fd.accept(this);
2475         //buf->writestring(e->fd->toChars());
2476     }
2477 
2478     override void visit(DeclarationExp e)
2479     {
2480         /* Normal dmd execution won't reach here - regular variable declarations
2481          * are handled in visit(ExpStatement), so here would be used only when
2482          * we'll directly call Expression.toChars() for debugging.
2483          */
2484         if (auto v = e.declaration.isVarDeclaration())
2485         {
2486             // For debugging use:
2487             // - Avoid printing newline.
2488             // - Intentionally use the format (Type var;)
2489             //   which isn't correct as regular D code.
2490             buf.writeByte('(');
2491             visitVarDecl(v, false);
2492             buf.writeByte(';');
2493             buf.writeByte(')');
2494         }
2495         else
2496             e.declaration.accept(this);
2497     }
2498 
2499     override void visit(TypeidExp e)
2500     {
2501         buf.writestring("typeid(");
2502         objectToBuffer(e.obj);
2503         buf.writeByte(')');
2504     }
2505 
2506     override void visit(TraitsExp e)
2507     {
2508         buf.writestring("__traits(");
2509         buf.writestring(e.ident.toChars());
2510         if (e.args)
2511         {
2512             foreach (arg; *e.args)
2513             {
2514                 buf.writestring(", ");
2515                 objectToBuffer(arg);
2516             }
2517         }
2518         buf.writeByte(')');
2519     }
2520 
2521     override void visit(HaltExp e)
2522     {
2523         buf.writestring("halt");
2524     }
2525 
2526     override void visit(IsExp e)
2527     {
2528         buf.writestring("is(");
2529         typeToBuffer(e.targ, e.id);
2530         if (e.tok2 != TOKreserved)
2531         {
2532             buf.printf(" %s %s", Token.toChars(e.tok), Token.toChars(e.tok2));
2533         }
2534         else if (e.tspec)
2535         {
2536             if (e.tok == TOKcolon)
2537                 buf.writestring(" : ");
2538             else
2539                 buf.writestring(" == ");
2540             typeToBuffer(e.tspec, null);
2541         }
2542         if (e.parameters && e.parameters.dim)
2543         {
2544             buf.writestring(", ");
2545             visitTemplateParameters(e.parameters);
2546         }
2547         buf.writeByte(')');
2548     }
2549 
2550     override void visit(UnaExp e)
2551     {
2552         buf.writestring(Token.toString(e.op));
2553         expToBuffer(e.e1, precedence[e.op]);
2554     }
2555 
2556     override void visit(BinExp e)
2557     {
2558         expToBuffer(e.e1, precedence[e.op]);
2559         buf.writeByte(' ');
2560         buf.writestring(Token.toString(e.op));
2561         buf.writeByte(' ');
2562         expToBuffer(e.e2, cast(PREC)(precedence[e.op] + 1));
2563     }
2564 
2565     override void visit(CompileExp e)
2566     {
2567         buf.writestring("mixin(");
2568         expToBuffer(e.e1, PREC.assign);
2569         buf.writeByte(')');
2570     }
2571 
2572     override void visit(ImportExp e)
2573     {
2574         buf.writestring("import(");
2575         expToBuffer(e.e1, PREC.assign);
2576         buf.writeByte(')');
2577     }
2578 
2579     override void visit(AssertExp e)
2580     {
2581         buf.writestring("assert(");
2582         expToBuffer(e.e1, PREC.assign);
2583         if (e.msg)
2584         {
2585             buf.writestring(", ");
2586             expToBuffer(e.msg, PREC.assign);
2587         }
2588         buf.writeByte(')');
2589     }
2590 
2591     override void visit(DotIdExp e)
2592     {
2593         expToBuffer(e.e1, PREC.primary);
2594         buf.writeByte('.');
2595         buf.writestring(e.ident.toChars());
2596     }
2597 
2598     override void visit(DotTemplateExp e)
2599     {
2600         expToBuffer(e.e1, PREC.primary);
2601         buf.writeByte('.');
2602         buf.writestring(e.td.toChars());
2603     }
2604 
2605     override void visit(DotVarExp e)
2606     {
2607         expToBuffer(e.e1, PREC.primary);
2608         buf.writeByte('.');
2609         buf.writestring(e.var.toChars());
2610     }
2611 
2612     override void visit(DotTemplateInstanceExp e)
2613     {
2614         expToBuffer(e.e1, PREC.primary);
2615         buf.writeByte('.');
2616         e.ti.accept(this);
2617     }
2618 
2619     override void visit(DelegateExp e)
2620     {
2621         buf.writeByte('&');
2622         if (!e.func.isNested())
2623         {
2624             expToBuffer(e.e1, PREC.primary);
2625             buf.writeByte('.');
2626         }
2627         buf.writestring(e.func.toChars());
2628     }
2629 
2630     override void visit(DotTypeExp e)
2631     {
2632         expToBuffer(e.e1, PREC.primary);
2633         buf.writeByte('.');
2634         buf.writestring(e.sym.toChars());
2635     }
2636 
2637     override void visit(CallExp e)
2638     {
2639         if (e.e1.op == TOKtype)
2640         {
2641             /* Avoid parens around type to prevent forbidden cast syntax:
2642              *   (sometype)(arg1)
2643              * This is ok since types in constructor calls
2644              * can never depend on parens anyway
2645              */
2646             e.e1.accept(this);
2647         }
2648         else
2649             expToBuffer(e.e1, precedence[e.op]);
2650         buf.writeByte('(');
2651         argsToBuffer(e.arguments);
2652         buf.writeByte(')');
2653     }
2654 
2655     override void visit(PtrExp e)
2656     {
2657         buf.writeByte('*');
2658         expToBuffer(e.e1, precedence[e.op]);
2659     }
2660 
2661     override void visit(DeleteExp e)
2662     {
2663         buf.writestring("delete ");
2664         expToBuffer(e.e1, precedence[e.op]);
2665     }
2666 
2667     override void visit(CastExp e)
2668     {
2669         buf.writestring("cast(");
2670         if (e.to)
2671             typeToBuffer(e.to, null);
2672         else
2673         {
2674             MODtoBuffer(buf, e.mod);
2675         }
2676         buf.writeByte(')');
2677         expToBuffer(e.e1, precedence[e.op]);
2678     }
2679 
2680     override void visit(VectorExp e)
2681     {
2682         buf.writestring("cast(");
2683         typeToBuffer(e.to, null);
2684         buf.writeByte(')');
2685         expToBuffer(e.e1, precedence[e.op]);
2686     }
2687 
2688     override void visit(SliceExp e)
2689     {
2690         expToBuffer(e.e1, precedence[e.op]);
2691         buf.writeByte('[');
2692         if (e.upr || e.lwr)
2693         {
2694             if (e.lwr)
2695                 sizeToBuffer(e.lwr);
2696             else
2697                 buf.writeByte('0');
2698             buf.writestring("..");
2699             if (e.upr)
2700                 sizeToBuffer(e.upr);
2701             else
2702                 buf.writeByte('$');
2703         }
2704         buf.writeByte(']');
2705     }
2706 
2707     override void visit(ArrayLengthExp e)
2708     {
2709         expToBuffer(e.e1, PREC.primary);
2710         buf.writestring(".length");
2711     }
2712 
2713     override void visit(IntervalExp e)
2714     {
2715         expToBuffer(e.lwr, PREC.assign);
2716         buf.writestring("..");
2717         expToBuffer(e.upr, PREC.assign);
2718     }
2719 
2720     override void visit(DelegatePtrExp e)
2721     {
2722         expToBuffer(e.e1, PREC.primary);
2723         buf.writestring(".ptr");
2724     }
2725 
2726     override void visit(DelegateFuncptrExp e)
2727     {
2728         expToBuffer(e.e1, PREC.primary);
2729         buf.writestring(".funcptr");
2730     }
2731 
2732     override void visit(ArrayExp e)
2733     {
2734         expToBuffer(e.e1, PREC.primary);
2735         buf.writeByte('[');
2736         argsToBuffer(e.arguments);
2737         buf.writeByte(']');
2738     }
2739 
2740     override void visit(DotExp e)
2741     {
2742         expToBuffer(e.e1, PREC.primary);
2743         buf.writeByte('.');
2744         expToBuffer(e.e2, PREC.primary);
2745     }
2746 
2747     override void visit(IndexExp e)
2748     {
2749         expToBuffer(e.e1, PREC.primary);
2750         buf.writeByte('[');
2751         sizeToBuffer(e.e2);
2752         buf.writeByte(']');
2753     }
2754 
2755     override void visit(PostExp e)
2756     {
2757         expToBuffer(e.e1, precedence[e.op]);
2758         buf.writestring(Token.toString(e.op));
2759     }
2760 
2761     override void visit(PreExp e)
2762     {
2763         buf.writestring(Token.toString(e.op));
2764         expToBuffer(e.e1, precedence[e.op]);
2765     }
2766 
2767     override void visit(RemoveExp e)
2768     {
2769         expToBuffer(e.e1, PREC.primary);
2770         buf.writestring(".remove(");
2771         expToBuffer(e.e2, PREC.assign);
2772         buf.writeByte(')');
2773     }
2774 
2775     override void visit(CondExp e)
2776     {
2777         expToBuffer(e.econd, PREC.oror);
2778         buf.writestring(" ? ");
2779         expToBuffer(e.e1, PREC.expr);
2780         buf.writestring(" : ");
2781         expToBuffer(e.e2, PREC.cond);
2782     }
2783 
2784     override void visit(DefaultInitExp e)
2785     {
2786         buf.writestring(Token.toString(e.subop));
2787     }
2788 
2789     override void visit(ClassReferenceExp e)
2790     {
2791         buf.writestring(e.value.toChars());
2792     }
2793 
2794     ////////////////////////////////////////////////////////////////////////////
2795     override void visit(TemplateTypeParameter tp)
2796     {
2797         buf.writestring(tp.ident.toChars());
2798         if (tp.specType)
2799         {
2800             buf.writestring(" : ");
2801             typeToBuffer(tp.specType, null);
2802         }
2803         if (tp.defaultType)
2804         {
2805             buf.writestring(" = ");
2806             typeToBuffer(tp.defaultType, null);
2807         }
2808     }
2809 
2810     override void visit(TemplateThisParameter tp)
2811     {
2812         buf.writestring("this ");
2813         visit(cast(TemplateTypeParameter)tp);
2814     }
2815 
2816     override void visit(TemplateAliasParameter tp)
2817     {
2818         buf.writestring("alias ");
2819         if (tp.specType)
2820             typeToBuffer(tp.specType, tp.ident);
2821         else
2822             buf.writestring(tp.ident.toChars());
2823         if (tp.specAlias)
2824         {
2825             buf.writestring(" : ");
2826             objectToBuffer(tp.specAlias);
2827         }
2828         if (tp.defaultAlias)
2829         {
2830             buf.writestring(" = ");
2831             objectToBuffer(tp.defaultAlias);
2832         }
2833     }
2834 
2835     override void visit(TemplateValueParameter tp)
2836     {
2837         typeToBuffer(tp.valType, tp.ident);
2838         if (tp.specValue)
2839         {
2840             buf.writestring(" : ");
2841             tp.specValue.accept(this);
2842         }
2843         if (tp.defaultValue)
2844         {
2845             buf.writestring(" = ");
2846             tp.defaultValue.accept(this);
2847         }
2848     }
2849 
2850     override void visit(TemplateTupleParameter tp)
2851     {
2852         buf.writestring(tp.ident.toChars());
2853         buf.writestring("...");
2854     }
2855 
2856     ////////////////////////////////////////////////////////////////////////////
2857     override void visit(DebugCondition c)
2858     {
2859         if (c.ident)
2860             buf.printf("debug (%s)", c.ident.toChars());
2861         else
2862             buf.printf("debug (%u)", c.level);
2863     }
2864 
2865     override void visit(VersionCondition c)
2866     {
2867         if (c.ident)
2868             buf.printf("version (%s)", c.ident.toChars());
2869         else
2870             buf.printf("version (%u)", c.level);
2871     }
2872 
2873     override void visit(StaticIfCondition c)
2874     {
2875         buf.writestring("static if (");
2876         c.exp.accept(this);
2877         buf.writeByte(')');
2878     }
2879 
2880     ////////////////////////////////////////////////////////////////////////////
2881     override void visit(Parameter p)
2882     {
2883         if (p.storageClass & STCauto)
2884             buf.writestring("auto ");
2885         if (p.storageClass & STCreturn)
2886             buf.writestring("return ");
2887         if (p.storageClass & STCout)
2888             buf.writestring("out ");
2889         else if (p.storageClass & STCref)
2890             buf.writestring("ref ");
2891         else if (p.storageClass & STCin)
2892             buf.writestring("in ");
2893         else if (p.storageClass & STClazy)
2894             buf.writestring("lazy ");
2895         else if (p.storageClass & STCalias)
2896             buf.writestring("alias ");
2897         StorageClass stc = p.storageClass;
2898         if (p.type && p.type.mod & MODshared)
2899             stc &= ~STCshared;
2900         if (stcToBuffer(buf, stc & (STCconst | STCimmutable | STCwild | STCshared | STCscope)))
2901             buf.writeByte(' ');
2902         if (p.storageClass & STCalias)
2903         {
2904             if (p.ident)
2905                 buf.writestring(p.ident.toChars());
2906         }
2907         else if (p.type.ty == Tident &&
2908                  (cast(TypeIdentifier)p.type).ident.toString().length > 3 &&
2909                  strncmp((cast(TypeIdentifier)p.type).ident.toChars(), "__T", 3) == 0)
2910         {
2911             // print parameter name, instead of undetermined type parameter
2912             buf.writestring(p.ident.toChars());
2913         }
2914         else
2915             typeToBuffer(p.type, p.ident);
2916         if (p.defaultArg)
2917         {
2918             buf.writestring(" = ");
2919             p.defaultArg.accept(this);
2920         }
2921     }
2922 
2923     void parametersToBuffer(Parameters* parameters, int varargs)
2924     {
2925         buf.writeByte('(');
2926         if (parameters)
2927         {
2928             size_t dim = Parameter.dim(parameters);
2929             foreach (i; 0 .. dim)
2930             {
2931                 if (i)
2932                     buf.writestring(", ");
2933                 Parameter fparam = Parameter.getNth(parameters, i);
2934                 fparam.accept(this);
2935             }
2936             if (varargs)
2937             {
2938                 if (parameters.dim && varargs == 1)
2939                     buf.writestring(", ");
2940                 buf.writestring("...");
2941             }
2942         }
2943         buf.writeByte(')');
2944     }
2945 
2946     override void visit(Module m)
2947     {
2948         if (m.md)
2949         {
2950             if (m.userAttribDecl)
2951             {
2952                 buf.writestring("@(");
2953                 argsToBuffer(m.userAttribDecl.atts);
2954                 buf.writeByte(')');
2955                 buf.writenl();
2956             }
2957             if (m.md.isdeprecated)
2958             {
2959                 if (m.md.msg)
2960                 {
2961                     buf.writestring("deprecated(");
2962                     m.md.msg.accept(this);
2963                     buf.writestring(") ");
2964                 }
2965                 else
2966                     buf.writestring("deprecated ");
2967             }
2968             buf.writestring("module ");
2969             buf.writestring(m.md.toChars());
2970             buf.writeByte(';');
2971             buf.writenl();
2972         }
2973         foreach (s; *m.members)
2974         {
2975             s.accept(this);
2976         }
2977     }
2978 }
2979 
2980 extern (C++) void toCBuffer(Statement s, OutBuffer* buf, HdrGenState* hgs)
2981 {
2982     scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs);
2983     s.accept(v);
2984 }
2985 
2986 extern (C++) void toCBuffer(Type t, OutBuffer* buf, Identifier ident, HdrGenState* hgs)
2987 {
2988     scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs);
2989     v.typeToBuffer(t, ident);
2990 }
2991 
2992 extern (C++) void toCBuffer(Dsymbol s, OutBuffer* buf, HdrGenState* hgs)
2993 {
2994     scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs);
2995     s.accept(v);
2996 }
2997 
2998 // used from TemplateInstance::toChars() and TemplateMixin::toChars()
2999 extern (C++) void toCBufferInstance(TemplateInstance ti, OutBuffer* buf, bool qualifyTypes = false)
3000 {
3001     HdrGenState hgs;
3002     hgs.fullQual = qualifyTypes;
3003     scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, &hgs);
3004     v.visit(ti);
3005 }
3006 
3007 extern (C++) void toCBuffer(Initializer iz, OutBuffer* buf, HdrGenState* hgs)
3008 {
3009     scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs);
3010     iz.accept(v);
3011 }
3012 
3013 extern (C++) bool stcToBuffer(OutBuffer* buf, StorageClass stc)
3014 {
3015     bool result = false;
3016     if ((stc & (STCreturn | STCscope)) == (STCreturn | STCscope))
3017         stc &= ~STCscope;
3018     while (stc)
3019     {
3020         const(char)* p = stcToChars(stc);
3021         if (!p) // there's no visible storage classes
3022             break;
3023         if (!result)
3024             result = true;
3025         else
3026             buf.writeByte(' ');
3027         buf.writestring(p);
3028     }
3029     return result;
3030 }
3031 
3032 /*************************************************
3033  * Pick off one of the storage classes from stc,
3034  * and return a pointer to a string representation of it.
3035  * stc is reduced by the one picked.
3036  */
3037 extern (C++) const(char)* stcToChars(ref StorageClass stc)
3038 {
3039     struct SCstring
3040     {
3041         StorageClass stc;
3042         TOK tok;
3043         const(char)* id;
3044     }
3045 
3046     static __gshared SCstring* table =
3047     [
3048         SCstring(STCauto, TOKauto),
3049         SCstring(STCscope, TOKscope),
3050         SCstring(STCstatic, TOKstatic),
3051         SCstring(STCextern, TOKextern),
3052         SCstring(STCconst, TOKconst),
3053         SCstring(STCfinal, TOKfinal),
3054         SCstring(STCabstract, TOKabstract),
3055         SCstring(STCsynchronized, TOKsynchronized),
3056         SCstring(STCdeprecated, TOKdeprecated),
3057         SCstring(STCoverride, TOKoverride),
3058         SCstring(STClazy, TOKlazy),
3059         SCstring(STCalias, TOKalias),
3060         SCstring(STCout, TOKout),
3061         SCstring(STCin, TOKin),
3062         SCstring(STCmanifest, TOKenum),
3063         SCstring(STCimmutable, TOKimmutable),
3064         SCstring(STCshared, TOKshared),
3065         SCstring(STCnothrow, TOKnothrow),
3066         SCstring(STCwild, TOKwild),
3067         SCstring(STCpure, TOKpure),
3068         SCstring(STCref, TOKref),
3069         SCstring(STCtls),
3070         SCstring(STCgshared, TOKgshared),
3071         SCstring(STCnogc, TOKat, "@nogc"),
3072         SCstring(STCproperty, TOKat, "@property"),
3073         SCstring(STCsafe, TOKat, "@safe"),
3074         SCstring(STCtrusted, TOKat, "@trusted"),
3075         SCstring(STCsystem, TOKat, "@system"),
3076         SCstring(STCdisable, TOKat, "@disable"),
3077         SCstring(0, TOKreserved)
3078     ];
3079     for (int i = 0; table[i].stc; i++)
3080     {
3081         StorageClass tbl = table[i].stc;
3082         assert(tbl & STCStorageClass);
3083         if (stc & tbl)
3084         {
3085             stc &= ~tbl;
3086             if (tbl == STCtls) // TOKtls was removed
3087                 return "__thread";
3088             TOK tok = table[i].tok;
3089             if (tok == TOKat)
3090                 return table[i].id;
3091             else
3092                 return Token.toChars(tok);
3093         }
3094     }
3095     //printf("stc = %llx\n", stc);
3096     return null;
3097 }
3098 
3099 extern (C++) void trustToBuffer(OutBuffer* buf, TRUST trust)
3100 {
3101     const(char)* p = trustToChars(trust);
3102     if (p)
3103         buf.writestring(p);
3104 }
3105 
3106 extern (C++) const(char)* trustToChars(TRUST trust)
3107 {
3108     switch (trust)
3109     {
3110     case TRUSTdefault:
3111         return null;
3112     case TRUSTsystem:
3113         return "@system";
3114     case TRUSTtrusted:
3115         return "@trusted";
3116     case TRUSTsafe:
3117         return "@safe";
3118     default:
3119         assert(0);
3120     }
3121 }
3122 
3123 extern (C++) void linkageToBuffer(OutBuffer* buf, LINK linkage)
3124 {
3125     const(char)* p = linkageToChars(linkage);
3126     if (p)
3127     {
3128         buf.writestring("extern (");
3129         buf.writestring(p);
3130         buf.writeByte(')');
3131     }
3132 }
3133 
3134 extern (C++) const(char)* linkageToChars(LINK linkage)
3135 {
3136     switch (linkage)
3137     {
3138     case LINKdefault:
3139         return null;
3140     case LINKd:
3141         return "D";
3142     case LINKc:
3143         return "C";
3144     case LINKcpp:
3145         return "C++";
3146     case LINKwindows:
3147         return "Windows";
3148     case LINKpascal:
3149         return "Pascal";
3150     case LINKobjc:
3151         return "Objective-C";
3152     default:
3153         assert(0);
3154     }
3155 }
3156 
3157 extern (C++) void protectionToBuffer(OutBuffer* buf, Prot prot)
3158 {
3159     const(char)* p = protectionToChars(prot.kind);
3160     if (p)
3161         buf.writestring(p);
3162     if (prot.kind == PROTpackage && prot.pkg)
3163     {
3164         buf.writeByte('(');
3165         buf.writestring(prot.pkg.toPrettyChars(true));
3166         buf.writeByte(')');
3167     }
3168 }
3169 
3170 extern (C++) const(char)* protectionToChars(PROTKIND kind)
3171 {
3172     switch (kind)
3173     {
3174     case PROTundefined:
3175         return null;
3176     case PROTnone:
3177         return "none";
3178     case PROTprivate:
3179         return "private";
3180     case PROTpackage:
3181         return "package";
3182     case PROTprotected:
3183         return "protected";
3184     case PROTpublic:
3185         return "public";
3186     case PROTexport:
3187         return "export";
3188     default:
3189         assert(0);
3190     }
3191 }
3192 
3193 // Print the full function signature with correct ident, attributes and template args
3194 extern (C++) void functionToBufferFull(TypeFunction tf, OutBuffer* buf, Identifier ident, HdrGenState* hgs, TemplateDeclaration td)
3195 {
3196     //printf("TypeFunction::toCBuffer() this = %p\n", this);
3197     scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs);
3198     v.visitFuncIdentWithPrefix(tf, ident, td, true);
3199 }
3200 
3201 // ident is inserted before the argument list and will be "function" or "delegate" for a type
3202 extern (C++) void functionToBufferWithIdent(TypeFunction tf, OutBuffer* buf, const(char)* ident)
3203 {
3204     HdrGenState hgs;
3205     scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, &hgs);
3206     v.visitFuncIdentWithPostfix(tf, ident);
3207 }
3208 
3209 extern (C++) void toCBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs)
3210 {
3211     scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs);
3212     e.accept(v);
3213 }
3214 
3215 /**************************************************
3216  * Write out argument types to buf.
3217  */
3218 extern (C++) void argExpTypesToCBuffer(OutBuffer* buf, Expressions* arguments)
3219 {
3220     if (!arguments || !arguments.dim)
3221         return;
3222     HdrGenState hgs;
3223     scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, &hgs);
3224     foreach (i, arg; *arguments)
3225     {
3226         if (i)
3227             buf.writestring(", ");
3228         v.typeToBuffer(arg.type, null);
3229     }
3230 }
3231 
3232 extern (C++) void toCBuffer(TemplateParameter tp, OutBuffer* buf, HdrGenState* hgs)
3233 {
3234     scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs);
3235     tp.accept(v);
3236 }
3237 
3238 extern (C++) void arrayObjectsToBuffer(OutBuffer* buf, Objects* objects)
3239 {
3240     if (!objects || !objects.dim)
3241         return;
3242     HdrGenState hgs;
3243     scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, &hgs);
3244     foreach (i, o; *objects)
3245     {
3246         if (i)
3247             buf.writestring(", ");
3248         v.objectToBuffer(o);
3249     }
3250 }
3251 
3252 extern (C++) const(char)* parametersTypeToChars(Parameters* parameters, int varargs)
3253 {
3254     OutBuffer buf;
3255     HdrGenState hgs;
3256     scope PrettyPrintVisitor v = new PrettyPrintVisitor(&buf, &hgs);
3257     v.parametersToBuffer(parameters, varargs);
3258     return buf.extractString();
3259 }