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