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