xref: /netbsd-src/external/gpl3/gcc/dist/gcc/d/dmd/hdrgen.d (revision b1e838363e3c6fc78a55519254d99869742dd33c)
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-2022 by The D Language Foundation, All Rights Reserved
7  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
8  * License:     $(LINK2 https://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.cond;
25 import dmd.ctfeexpr;
26 import dmd.dclass;
27 import dmd.declaration;
28 import dmd.denum;
29 import dmd.dimport;
30 import dmd.dmodule;
31 import dmd.doc;
32 import dmd.dstruct;
33 import dmd.dsymbol;
34 import dmd.dtemplate;
35 import dmd.dversion;
36 import dmd.expression;
37 import dmd.func;
38 import dmd.globals;
39 import dmd.id;
40 import dmd.identifier;
41 import dmd.init;
42 import dmd.mtype;
43 import dmd.nspace;
44 import dmd.parse;
45 import dmd.root.complex;
46 import dmd.root.ctfloat;
47 import dmd.common.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 == EXP.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 == EXP.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         bool hasSTC;
913         if (auto stcd = d.isStorageClassDeclaration)
914         {
915             hasSTC = stcToBuffer(buf, stcd.stc);
916         }
917 
918         if (!d.decl)
919         {
920             buf.writeByte(';');
921             buf.writenl();
922             return;
923         }
924         if (d.decl.dim == 0 || (hgs.hdrgen && d.decl.dim == 1 && (*d.decl)[0].isUnitTestDeclaration()))
925         {
926             // hack for bugzilla 8081
927             if (hasSTC) buf.writeByte(' ');
928             buf.writestring("{}");
929         }
930         else if (d.decl.dim == 1)
931         {
932             if (hasSTC) buf.writeByte(' ');
933             (*d.decl)[0].accept(this);
934             return;
935         }
936         else
937         {
938             buf.writenl();
939             buf.writeByte('{');
940             buf.writenl();
941             buf.level++;
942             foreach (de; *d.decl)
943                 de.accept(this);
944             buf.level--;
945             buf.writeByte('}');
946         }
947         buf.writenl();
948     }
949 
visit(StorageClassDeclaration d)950     override void visit(StorageClassDeclaration d)
951     {
952         visit(cast(AttribDeclaration)d);
953     }
954 
visit(DeprecatedDeclaration d)955     override void visit(DeprecatedDeclaration d)
956     {
957         buf.writestring("deprecated(");
958         d.msg.expressionToBuffer(buf, hgs);
959         buf.writestring(") ");
960         visit(cast(AttribDeclaration)d);
961     }
962 
visit(LinkDeclaration d)963     override void visit(LinkDeclaration d)
964     {
965         buf.writestring("extern (");
966         buf.writestring(linkageToString(d.linkage));
967         buf.writestring(") ");
968         visit(cast(AttribDeclaration)d);
969     }
970 
visit(CPPMangleDeclaration d)971     override void visit(CPPMangleDeclaration d)
972     {
973         string s;
974         final switch (d.cppmangle)
975         {
976         case CPPMANGLE.asClass:
977             s = "class";
978             break;
979         case CPPMANGLE.asStruct:
980             s = "struct";
981             break;
982         case CPPMANGLE.def:
983             break;
984         }
985         buf.writestring("extern (C++, ");
986         buf.writestring(s);
987         buf.writestring(") ");
988         visit(cast(AttribDeclaration)d);
989     }
990 
visit(VisibilityDeclaration d)991     override void visit(VisibilityDeclaration d)
992     {
993         visibilityToBuffer(buf, d.visibility);
994         AttribDeclaration ad = cast(AttribDeclaration)d;
995         if (ad.decl.dim <= 1)
996             buf.writeByte(' ');
997         if (ad.decl.dim == 1 && (*ad.decl)[0].isVisibilityDeclaration)
998             visit(cast(AttribDeclaration)(*ad.decl)[0]);
999         else
1000             visit(cast(AttribDeclaration)d);
1001     }
1002 
visit(AlignDeclaration d)1003     override void visit(AlignDeclaration d)
1004     {
1005         if (d.exps)
1006         {
1007             foreach (i, exp; (*d.exps)[])
1008             {
1009                 if (i)
1010                     buf.writeByte(' ');
1011                 buf.printf("align (%s)", exp.toChars());
1012             }
1013             if (d.decl && d.decl.dim < 2)
1014                 buf.writeByte(' ');
1015         }
1016         else
1017             buf.writestring("align ");
1018 
1019         visit(d.isAttribDeclaration());
1020     }
1021 
visit(AnonDeclaration d)1022     override void visit(AnonDeclaration d)
1023     {
1024         buf.writestring(d.isunion ? "union" : "struct");
1025         buf.writenl();
1026         buf.writestring("{");
1027         buf.writenl();
1028         buf.level++;
1029         if (d.decl)
1030         {
1031             foreach (de; *d.decl)
1032                 de.accept(this);
1033         }
1034         buf.level--;
1035         buf.writestring("}");
1036         buf.writenl();
1037     }
1038 
visit(PragmaDeclaration d)1039     override void visit(PragmaDeclaration d)
1040     {
1041         buf.writestring("pragma (");
1042         buf.writestring(d.ident.toString());
1043         if (d.args && d.args.dim)
1044         {
1045             buf.writestring(", ");
1046             argsToBuffer(d.args, buf, hgs);
1047         }
1048         buf.writeByte(')');
1049         visit(cast(AttribDeclaration)d);
1050     }
1051 
visit(ConditionalDeclaration d)1052     override void visit(ConditionalDeclaration d)
1053     {
1054         d.condition.conditionToBuffer(buf, hgs);
1055         if (d.decl || d.elsedecl)
1056         {
1057             buf.writenl();
1058             buf.writeByte('{');
1059             buf.writenl();
1060             buf.level++;
1061             if (d.decl)
1062             {
1063                 foreach (de; *d.decl)
1064                     de.accept(this);
1065             }
1066             buf.level--;
1067             buf.writeByte('}');
1068             if (d.elsedecl)
1069             {
1070                 buf.writenl();
1071                 buf.writestring("else");
1072                 buf.writenl();
1073                 buf.writeByte('{');
1074                 buf.writenl();
1075                 buf.level++;
1076                 foreach (de; *d.elsedecl)
1077                     de.accept(this);
1078                 buf.level--;
1079                 buf.writeByte('}');
1080             }
1081         }
1082         else
1083             buf.writeByte(':');
1084         buf.writenl();
1085     }
1086 
visit(StaticForeachDeclaration s)1087     override void visit(StaticForeachDeclaration s)
1088     {
1089         void foreachWithoutBody(ForeachStatement s)
1090         {
1091             buf.writestring(Token.toString(s.op));
1092             buf.writestring(" (");
1093             foreach (i, p; *s.parameters)
1094             {
1095                 if (i)
1096                     buf.writestring(", ");
1097                 if (stcToBuffer(buf, p.storageClass))
1098                     buf.writeByte(' ');
1099                 if (p.type)
1100                     typeToBuffer(p.type, p.ident, buf, hgs);
1101                 else
1102                     buf.writestring(p.ident.toString());
1103             }
1104             buf.writestring("; ");
1105             s.aggr.expressionToBuffer(buf, hgs);
1106             buf.writeByte(')');
1107             buf.writenl();
1108         }
1109 
1110         void foreachRangeWithoutBody(ForeachRangeStatement s)
1111         {
1112             /* s.op ( prm ; lwr .. upr )
1113              */
1114             buf.writestring(Token.toString(s.op));
1115             buf.writestring(" (");
1116             if (s.prm.type)
1117                 typeToBuffer(s.prm.type, s.prm.ident, buf, hgs);
1118             else
1119                 buf.writestring(s.prm.ident.toString());
1120             buf.writestring("; ");
1121             s.lwr.expressionToBuffer(buf, hgs);
1122             buf.writestring(" .. ");
1123             s.upr.expressionToBuffer(buf, hgs);
1124             buf.writeByte(')');
1125             buf.writenl();
1126         }
1127 
1128         buf.writestring("static ");
1129         if (s.sfe.aggrfe)
1130         {
1131             foreachWithoutBody(s.sfe.aggrfe);
1132         }
1133         else
1134         {
1135             assert(s.sfe.rangefe);
1136             foreachRangeWithoutBody(s.sfe.rangefe);
1137         }
1138         buf.writeByte('{');
1139         buf.writenl();
1140         buf.level++;
1141         visit(cast(AttribDeclaration)s);
1142         buf.level--;
1143         buf.writeByte('}');
1144         buf.writenl();
1145 
1146     }
1147 
visit(CompileDeclaration d)1148     override void visit(CompileDeclaration d)
1149     {
1150         buf.writestring("mixin(");
1151         argsToBuffer(d.exps, buf, hgs, null);
1152         buf.writestring(");");
1153         buf.writenl();
1154     }
1155 
visit(UserAttributeDeclaration d)1156     override void visit(UserAttributeDeclaration d)
1157     {
1158         buf.writestring("@(");
1159         argsToBuffer(d.atts, buf, hgs);
1160         buf.writeByte(')');
1161         visit(cast(AttribDeclaration)d);
1162     }
1163 
visit(TemplateDeclaration d)1164     override void visit(TemplateDeclaration d)
1165     {
1166         version (none)
1167         {
1168             // Should handle template functions for doc generation
1169             if (onemember && onemember.isFuncDeclaration())
1170                 buf.writestring("foo ");
1171         }
1172         if ((hgs.hdrgen || hgs.fullDump) && visitEponymousMember(d))
1173             return;
1174         if (hgs.ddoc)
1175             buf.writestring(d.kind());
1176         else
1177             buf.writestring("template");
1178         buf.writeByte(' ');
1179         buf.writestring(d.ident.toString());
1180         buf.writeByte('(');
1181         visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters);
1182         buf.writeByte(')');
1183         visitTemplateConstraint(d.constraint);
1184         if (hgs.hdrgen || hgs.fullDump)
1185         {
1186             hgs.tpltMember++;
1187             buf.writenl();
1188             buf.writeByte('{');
1189             buf.writenl();
1190             buf.level++;
1191             foreach (s; *d.members)
1192                 s.accept(this);
1193             buf.level--;
1194             buf.writeByte('}');
1195             buf.writenl();
1196             hgs.tpltMember--;
1197         }
1198     }
1199 
visitEponymousMember(TemplateDeclaration d)1200     bool visitEponymousMember(TemplateDeclaration d)
1201     {
1202         if (!d.members || d.members.dim != 1)
1203             return false;
1204         Dsymbol onemember = (*d.members)[0];
1205         if (onemember.ident != d.ident)
1206             return false;
1207         if (FuncDeclaration fd = onemember.isFuncDeclaration())
1208         {
1209             assert(fd.type);
1210             if (stcToBuffer(buf, fd.storage_class))
1211                 buf.writeByte(' ');
1212             functionToBufferFull(cast(TypeFunction)fd.type, buf, d.ident, hgs, d);
1213             visitTemplateConstraint(d.constraint);
1214             hgs.tpltMember++;
1215             bodyToBuffer(fd);
1216             hgs.tpltMember--;
1217             return true;
1218         }
1219         if (AggregateDeclaration ad = onemember.isAggregateDeclaration())
1220         {
1221             buf.writestring(ad.kind());
1222             buf.writeByte(' ');
1223             buf.writestring(ad.ident.toString());
1224             buf.writeByte('(');
1225             visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters);
1226             buf.writeByte(')');
1227             visitTemplateConstraint(d.constraint);
1228             visitBaseClasses(ad.isClassDeclaration());
1229             hgs.tpltMember++;
1230             if (ad.members)
1231             {
1232                 buf.writenl();
1233                 buf.writeByte('{');
1234                 buf.writenl();
1235                 buf.level++;
1236                 foreach (s; *ad.members)
1237                     s.accept(this);
1238                 buf.level--;
1239                 buf.writeByte('}');
1240             }
1241             else
1242                 buf.writeByte(';');
1243             buf.writenl();
1244             hgs.tpltMember--;
1245             return true;
1246         }
1247         if (VarDeclaration vd = onemember.isVarDeclaration())
1248         {
1249             if (d.constraint)
1250                 return false;
1251             if (stcToBuffer(buf, vd.storage_class))
1252                 buf.writeByte(' ');
1253             if (vd.type)
1254                 typeToBuffer(vd.type, vd.ident, buf, hgs);
1255             else
1256                 buf.writestring(vd.ident.toString());
1257             buf.writeByte('(');
1258             visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters);
1259             buf.writeByte(')');
1260             if (vd._init)
1261             {
1262                 buf.writestring(" = ");
1263                 ExpInitializer ie = vd._init.isExpInitializer();
1264                 if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit))
1265                     (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs);
1266                 else
1267                     vd._init.initializerToBuffer(buf, hgs);
1268             }
1269             buf.writeByte(';');
1270             buf.writenl();
1271             return true;
1272         }
1273         return false;
1274     }
1275 
visitTemplateParameters(TemplateParameters * parameters)1276     void visitTemplateParameters(TemplateParameters* parameters)
1277     {
1278         if (!parameters || !parameters.dim)
1279             return;
1280         foreach (i, p; *parameters)
1281         {
1282             if (i)
1283                 buf.writestring(", ");
1284             p.templateParameterToBuffer(buf, hgs);
1285         }
1286     }
1287 
visitTemplateConstraint(Expression constraint)1288     void visitTemplateConstraint(Expression constraint)
1289     {
1290         if (!constraint)
1291             return;
1292         buf.writestring(" if (");
1293         constraint.expressionToBuffer(buf, hgs);
1294         buf.writeByte(')');
1295     }
1296 
visit(TemplateInstance ti)1297     override void visit(TemplateInstance ti)
1298     {
1299         buf.writestring(ti.name.toChars());
1300         tiargsToBuffer(ti, buf, hgs);
1301 
1302         if (hgs.fullDump)
1303         {
1304             buf.writenl();
1305             dumpTemplateInstance(ti, buf, hgs);
1306         }
1307     }
1308 
visit(TemplateMixin tm)1309     override void visit(TemplateMixin tm)
1310     {
1311         buf.writestring("mixin ");
1312         typeToBuffer(tm.tqual, null, buf, hgs);
1313         tiargsToBuffer(tm, buf, hgs);
1314         if (tm.ident && memcmp(tm.ident.toChars(), cast(const(char)*)"__mixin", 7) != 0)
1315         {
1316             buf.writeByte(' ');
1317             buf.writestring(tm.ident.toString());
1318         }
1319         buf.writeByte(';');
1320         buf.writenl();
1321         if (hgs.fullDump)
1322             dumpTemplateInstance(tm, buf, hgs);
1323     }
1324 
visit(EnumDeclaration d)1325     override void visit(EnumDeclaration d)
1326     {
1327         auto oldInEnumDecl = hgs.inEnumDecl;
1328         scope(exit) hgs.inEnumDecl = oldInEnumDecl;
1329         hgs.inEnumDecl = d;
1330         buf.writestring("enum ");
1331         if (d.ident)
1332         {
1333             buf.writestring(d.ident.toString());
1334         }
1335         if (d.memtype)
1336         {
1337             buf.writestring(" : ");
1338             typeToBuffer(d.memtype, null, buf, hgs);
1339         }
1340         if (!d.members)
1341         {
1342             buf.writeByte(';');
1343             buf.writenl();
1344             return;
1345         }
1346         buf.writenl();
1347         buf.writeByte('{');
1348         buf.writenl();
1349         buf.level++;
1350         foreach (em; *d.members)
1351         {
1352             if (!em)
1353                 continue;
1354             em.accept(this);
1355             buf.writeByte(',');
1356             buf.writenl();
1357         }
1358         buf.level--;
1359         buf.writeByte('}');
1360         buf.writenl();
1361     }
1362 
visit(Nspace d)1363     override void visit(Nspace d)
1364     {
1365         buf.writestring("extern (C++, ");
1366         buf.writestring(d.ident.toString());
1367         buf.writeByte(')');
1368         buf.writenl();
1369         buf.writeByte('{');
1370         buf.writenl();
1371         buf.level++;
1372         foreach (s; *d.members)
1373             s.accept(this);
1374         buf.level--;
1375         buf.writeByte('}');
1376         buf.writenl();
1377     }
1378 
visit(StructDeclaration d)1379     override void visit(StructDeclaration d)
1380     {
1381         buf.writestring(d.kind());
1382         buf.writeByte(' ');
1383         if (!d.isAnonymous())
1384             buf.writestring(d.toChars());
1385         if (!d.members)
1386         {
1387             buf.writeByte(';');
1388             buf.writenl();
1389             return;
1390         }
1391         buf.writenl();
1392         buf.writeByte('{');
1393         buf.writenl();
1394         buf.level++;
1395         foreach (s; *d.members)
1396             s.accept(this);
1397         buf.level--;
1398         buf.writeByte('}');
1399         buf.writenl();
1400     }
1401 
visit(ClassDeclaration d)1402     override void visit(ClassDeclaration d)
1403     {
1404         if (!d.isAnonymous())
1405         {
1406             buf.writestring(d.kind());
1407             buf.writeByte(' ');
1408             buf.writestring(d.ident.toString());
1409         }
1410         visitBaseClasses(d);
1411         if (d.members)
1412         {
1413             buf.writenl();
1414             buf.writeByte('{');
1415             buf.writenl();
1416             buf.level++;
1417             foreach (s; *d.members)
1418                 s.accept(this);
1419             buf.level--;
1420             buf.writeByte('}');
1421         }
1422         else
1423             buf.writeByte(';');
1424         buf.writenl();
1425     }
1426 
visitBaseClasses(ClassDeclaration d)1427     void visitBaseClasses(ClassDeclaration d)
1428     {
1429         if (!d || !d.baseclasses.dim)
1430             return;
1431         if (!d.isAnonymous())
1432             buf.writestring(" : ");
1433         foreach (i, b; *d.baseclasses)
1434         {
1435             if (i)
1436                 buf.writestring(", ");
1437             typeToBuffer(b.type, null, buf, hgs);
1438         }
1439     }
1440 
visit(AliasDeclaration d)1441     override void visit(AliasDeclaration d)
1442     {
1443         if (d.storage_class & STC.local)
1444             return;
1445         buf.writestring("alias ");
1446         if (d.aliassym)
1447         {
1448             buf.writestring(d.ident.toString());
1449             buf.writestring(" = ");
1450             if (stcToBuffer(buf, d.storage_class))
1451                 buf.writeByte(' ');
1452             d.aliassym.accept(this);
1453         }
1454         else if (d.type.ty == Tfunction)
1455         {
1456             if (stcToBuffer(buf, d.storage_class))
1457                 buf.writeByte(' ');
1458             typeToBuffer(d.type, d.ident, buf, hgs);
1459         }
1460         else if (d.ident)
1461         {
1462             hgs.declstring = (d.ident == Id.string || d.ident == Id.wstring || d.ident == Id.dstring);
1463             buf.writestring(d.ident.toString());
1464             buf.writestring(" = ");
1465             if (stcToBuffer(buf, d.storage_class))
1466                 buf.writeByte(' ');
1467             typeToBuffer(d.type, null, buf, hgs);
1468             hgs.declstring = false;
1469         }
1470         buf.writeByte(';');
1471         buf.writenl();
1472     }
1473 
visit(AliasAssign d)1474     override void visit(AliasAssign d)
1475     {
1476         buf.writestring(d.ident.toString());
1477         buf.writestring(" = ");
1478         if (d.aliassym)
1479             d.aliassym.accept(this);
1480         else // d.type
1481             typeToBuffer(d.type, null, buf, hgs);
1482         buf.writeByte(';');
1483         buf.writenl();
1484     }
1485 
visit(VarDeclaration d)1486     override void visit(VarDeclaration d)
1487     {
1488         if (d.storage_class & STC.local)
1489             return;
1490         visitVarDecl(d, false);
1491         buf.writeByte(';');
1492         buf.writenl();
1493     }
1494 
visitVarDecl(VarDeclaration v,bool anywritten)1495     void visitVarDecl(VarDeclaration v, bool anywritten)
1496     {
1497         if (anywritten)
1498         {
1499             buf.writestring(", ");
1500             buf.writestring(v.ident.toString());
1501         }
1502         else
1503         {
1504             if (stcToBuffer(buf, v.storage_class))
1505                 buf.writeByte(' ');
1506             if (v.type)
1507                 typeToBuffer(v.type, v.ident, buf, hgs);
1508             else
1509                 buf.writestring(v.ident.toString());
1510         }
1511         if (v._init)
1512         {
1513             buf.writestring(" = ");
1514             auto ie = v._init.isExpInitializer();
1515             if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit))
1516                 (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs);
1517             else
1518                 v._init.initializerToBuffer(buf, hgs);
1519         }
1520     }
1521 
visit(FuncDeclaration f)1522     override void visit(FuncDeclaration f)
1523     {
1524         //printf("FuncDeclaration::toCBuffer() '%s'\n", f.toChars());
1525         if (stcToBuffer(buf, f.storage_class))
1526             buf.writeByte(' ');
1527         auto tf = cast(TypeFunction)f.type;
1528         typeToBuffer(tf, f.ident, buf, hgs);
1529 
1530         if (hgs.hdrgen)
1531         {
1532             // if the return type is missing (e.g. ref functions or auto)
1533             if (!tf.next || f.storage_class & STC.auto_)
1534             {
1535                 hgs.autoMember++;
1536                 bodyToBuffer(f);
1537                 hgs.autoMember--;
1538             }
1539             else if (hgs.tpltMember == 0 && global.params.hdrStripPlainFunctions)
1540             {
1541                 if (!f.fbody)
1542                 {
1543                     // this can happen on interfaces / abstract functions, see `allowsContractWithoutBody`
1544                     if (f.fensures || f.frequires)
1545                         buf.writenl();
1546                     contractsToBuffer(f);
1547                 }
1548                 buf.writeByte(';');
1549                 buf.writenl();
1550             }
1551             else
1552                 bodyToBuffer(f);
1553         }
1554         else
1555             bodyToBuffer(f);
1556     }
1557 
1558     /// Returns: whether `do` is needed to write the function body
contractsToBuffer(FuncDeclaration f)1559     bool contractsToBuffer(FuncDeclaration f)
1560     {
1561         bool requireDo = false;
1562         // in{}
1563         if (f.frequires)
1564         {
1565             foreach (frequire; *f.frequires)
1566             {
1567                 buf.writestring("in");
1568                 if (auto es = frequire.isExpStatement())
1569                 {
1570                     assert(es.exp && es.exp.op == EXP.assert_);
1571                     buf.writestring(" (");
1572                     (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs);
1573                     buf.writeByte(')');
1574                     buf.writenl();
1575                     requireDo = false;
1576                 }
1577                 else
1578                 {
1579                     buf.writenl();
1580                     frequire.statementToBuffer(buf, hgs);
1581                     requireDo = true;
1582                 }
1583             }
1584         }
1585         // out{}
1586         if (f.fensures)
1587         {
1588             foreach (fensure; *f.fensures)
1589             {
1590                 buf.writestring("out");
1591                 if (auto es = fensure.ensure.isExpStatement())
1592                 {
1593                     assert(es.exp && es.exp.op == EXP.assert_);
1594                     buf.writestring(" (");
1595                     if (fensure.id)
1596                     {
1597                         buf.writestring(fensure.id.toString());
1598                     }
1599                     buf.writestring("; ");
1600                     (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs);
1601                     buf.writeByte(')');
1602                     buf.writenl();
1603                     requireDo = false;
1604                 }
1605                 else
1606                 {
1607                     if (fensure.id)
1608                     {
1609                         buf.writeByte('(');
1610                         buf.writestring(fensure.id.toString());
1611                         buf.writeByte(')');
1612                     }
1613                     buf.writenl();
1614                     fensure.ensure.statementToBuffer(buf, hgs);
1615                     requireDo = true;
1616                 }
1617             }
1618         }
1619         return requireDo;
1620     }
1621 
bodyToBuffer(FuncDeclaration f)1622     void bodyToBuffer(FuncDeclaration f)
1623     {
1624         if (!f.fbody || (hgs.hdrgen && global.params.hdrStripPlainFunctions && !hgs.autoMember && !hgs.tpltMember))
1625         {
1626             if (!f.fbody && (f.fensures || f.frequires))
1627             {
1628                 buf.writenl();
1629                 contractsToBuffer(f);
1630             }
1631             buf.writeByte(';');
1632             buf.writenl();
1633             return;
1634         }
1635         const savetlpt = hgs.tpltMember;
1636         const saveauto = hgs.autoMember;
1637         hgs.tpltMember = 0;
1638         hgs.autoMember = 0;
1639         buf.writenl();
1640         bool requireDo = contractsToBuffer(f);
1641 
1642         if (requireDo)
1643         {
1644             buf.writestring("do");
1645             buf.writenl();
1646         }
1647         buf.writeByte('{');
1648         buf.writenl();
1649         buf.level++;
1650         f.fbody.statementToBuffer(buf, hgs);
1651         buf.level--;
1652         buf.writeByte('}');
1653         buf.writenl();
1654         hgs.tpltMember = savetlpt;
1655         hgs.autoMember = saveauto;
1656     }
1657 
visit(FuncLiteralDeclaration f)1658     override void visit(FuncLiteralDeclaration f)
1659     {
1660         if (f.type.ty == Terror)
1661         {
1662             buf.writestring("__error");
1663             return;
1664         }
1665         if (f.tok != TOK.reserved)
1666         {
1667             buf.writestring(f.kind());
1668             buf.writeByte(' ');
1669         }
1670         TypeFunction tf = cast(TypeFunction)f.type;
1671 
1672         if (!f.inferRetType && tf.next)
1673             typeToBuffer(tf.next, null, buf, hgs);
1674         parametersToBuffer(tf.parameterList, buf, hgs);
1675 
1676         // https://issues.dlang.org/show_bug.cgi?id=20074
1677         void printAttribute(string str)
1678         {
1679             buf.writeByte(' ');
1680             buf.writestring(str);
1681         }
1682         tf.attributesApply(&printAttribute);
1683 
1684 
1685         CompoundStatement cs = f.fbody.isCompoundStatement();
1686         Statement s1;
1687         if (f.semanticRun >= PASS.semantic3done && cs)
1688         {
1689             s1 = (*cs.statements)[cs.statements.dim - 1];
1690         }
1691         else
1692             s1 = !cs ? f.fbody : null;
1693         ReturnStatement rs = s1 ? s1.endsWithReturnStatement() : null;
1694         if (rs && rs.exp)
1695         {
1696             buf.writestring(" => ");
1697             rs.exp.expressionToBuffer(buf, hgs);
1698         }
1699         else
1700         {
1701             hgs.tpltMember++;
1702             bodyToBuffer(f);
1703             hgs.tpltMember--;
1704         }
1705     }
1706 
visit(PostBlitDeclaration d)1707     override void visit(PostBlitDeclaration d)
1708     {
1709         if (stcToBuffer(buf, d.storage_class))
1710             buf.writeByte(' ');
1711         buf.writestring("this(this)");
1712         bodyToBuffer(d);
1713     }
1714 
visit(DtorDeclaration d)1715     override void visit(DtorDeclaration d)
1716     {
1717         if (stcToBuffer(buf, d.storage_class))
1718             buf.writeByte(' ');
1719         buf.writestring("~this()");
1720         bodyToBuffer(d);
1721     }
1722 
visit(StaticCtorDeclaration d)1723     override void visit(StaticCtorDeclaration d)
1724     {
1725         if (stcToBuffer(buf, d.storage_class & ~STC.static_))
1726             buf.writeByte(' ');
1727         if (d.isSharedStaticCtorDeclaration())
1728             buf.writestring("shared ");
1729         buf.writestring("static this()");
1730         if (hgs.hdrgen && !hgs.tpltMember)
1731         {
1732             buf.writeByte(';');
1733             buf.writenl();
1734         }
1735         else
1736             bodyToBuffer(d);
1737     }
1738 
visit(StaticDtorDeclaration d)1739     override void visit(StaticDtorDeclaration d)
1740     {
1741         if (stcToBuffer(buf, d.storage_class & ~STC.static_))
1742             buf.writeByte(' ');
1743         if (d.isSharedStaticDtorDeclaration())
1744             buf.writestring("shared ");
1745         buf.writestring("static ~this()");
1746         if (hgs.hdrgen && !hgs.tpltMember)
1747         {
1748             buf.writeByte(';');
1749             buf.writenl();
1750         }
1751         else
1752             bodyToBuffer(d);
1753     }
1754 
visit(InvariantDeclaration d)1755     override void visit(InvariantDeclaration d)
1756     {
1757         if (hgs.hdrgen)
1758             return;
1759         if (stcToBuffer(buf, d.storage_class))
1760             buf.writeByte(' ');
1761         buf.writestring("invariant");
1762         if(auto es = d.fbody.isExpStatement())
1763         {
1764             assert(es.exp && es.exp.op == EXP.assert_);
1765             buf.writestring(" (");
1766             (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs);
1767             buf.writestring(");");
1768             buf.writenl();
1769         }
1770         else
1771         {
1772             bodyToBuffer(d);
1773         }
1774     }
1775 
visit(UnitTestDeclaration d)1776     override void visit(UnitTestDeclaration d)
1777     {
1778         if (hgs.hdrgen)
1779             return;
1780         if (stcToBuffer(buf, d.storage_class))
1781             buf.writeByte(' ');
1782         buf.writestring("unittest");
1783         bodyToBuffer(d);
1784     }
1785 
visit(BitFieldDeclaration d)1786     override void visit(BitFieldDeclaration d)
1787     {
1788         if (stcToBuffer(buf, d.storage_class))
1789             buf.writeByte(' ');
1790         Identifier id = d.isAnonymous() ? null : d.ident;
1791         typeToBuffer(d.type, id, buf, hgs);
1792         buf.writestring(" : ");
1793         d.width.expressionToBuffer(buf, hgs);
1794         buf.writeByte(';');
1795         buf.writenl();
1796     }
1797 
visit(NewDeclaration d)1798     override void visit(NewDeclaration d)
1799     {
1800         if (stcToBuffer(buf, d.storage_class & ~STC.static_))
1801             buf.writeByte(' ');
1802         buf.writestring("new();");
1803     }
1804 
visit(Module m)1805     override void visit(Module m)
1806     {
1807         moduleToBuffer2(m, buf, hgs);
1808     }
1809 }
1810 
1811 /*********************************************
1812  * Print expression to buffer.
1813  */
expressionPrettyPrint(Expression e,OutBuffer * buf,HdrGenState * hgs)1814 private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hgs)
1815 {
1816     void visit(Expression e)
1817     {
1818         buf.writestring(EXPtoString(e.op));
1819     }
1820 
1821     void visitInteger(IntegerExp e)
1822     {
1823         const dinteger_t v = e.toInteger();
1824         if (e.type)
1825         {
1826             Type t = e.type;
1827         L1:
1828             switch (t.ty)
1829             {
1830             case Tenum:
1831                 {
1832                     TypeEnum te = cast(TypeEnum)t;
1833                     auto sym = te.sym;
1834                     if (sym && sym.members && (!hgs.inEnumDecl || hgs.inEnumDecl != sym))
1835                     {
1836                         foreach (em; *sym.members)
1837                         {
1838                             if ((cast(EnumMember)em).value.toInteger == v)
1839                             {
1840                                 buf.printf("%s.%s", sym.toChars(), em.ident.toChars());
1841                                 return ;
1842                             }
1843                         }
1844                     }
1845 
1846                     buf.printf("cast(%s)", te.sym.toChars());
1847                     t = te.sym.memtype;
1848                     goto L1;
1849                 }
1850             case Tchar:
1851             case Twchar:
1852             case Tdchar:
1853                 {
1854                     const o = buf.length;
1855                     writeSingleCharLiteral(*buf, cast(dchar) v);
1856                     if (hgs.ddoc)
1857                         escapeDdocString(buf, o);
1858                     break;
1859                 }
1860             case Tint8:
1861                 buf.writestring("cast(byte)");
1862                 goto L2;
1863             case Tint16:
1864                 buf.writestring("cast(short)");
1865                 goto L2;
1866             case Tint32:
1867             L2:
1868                 buf.printf("%d", cast(int)v);
1869                 break;
1870             case Tuns8:
1871                 buf.writestring("cast(ubyte)");
1872                 goto case Tuns32;
1873             case Tuns16:
1874                 buf.writestring("cast(ushort)");
1875                 goto case Tuns32;
1876             case Tuns32:
1877                 buf.printf("%uu", cast(uint)v);
1878                 break;
1879             case Tint64:
1880                 buf.printf("%lldL", v);
1881                 break;
1882             case Tuns64:
1883                 buf.printf("%lluLU", v);
1884                 break;
1885             case Tbool:
1886                 buf.writestring(v ? "true" : "false");
1887                 break;
1888             case Tpointer:
1889                 buf.writestring("cast(");
1890                 buf.writestring(t.toChars());
1891                 buf.writeByte(')');
1892                 if (target.ptrsize == 8)
1893                     goto case Tuns64;
1894                 else if (target.ptrsize == 4 ||
1895                          target.ptrsize == 2)
1896                     goto case Tuns32;
1897                 else
1898                     assert(0);
1899 
1900             case Tvoid:
1901                 buf.writestring("cast(void)0");
1902                 break;
1903 
1904             default:
1905                 /* This can happen if errors, such as
1906                  * the type is painted on like in fromConstInitializer().
1907                  */
1908                 if (!global.errors)
1909                 {
1910                     assert(0);
1911                 }
1912                 break;
1913             }
1914         }
1915         else if (v & 0x8000000000000000L)
1916             buf.printf("0x%llx", v);
1917         else
1918             buf.print(v);
1919     }
1920 
1921     void visitError(ErrorExp e)
1922     {
1923         buf.writestring("__error");
1924     }
1925 
1926     void visitVoidInit(VoidInitExp e)
1927     {
1928         buf.writestring("__void");
1929     }
1930 
1931     void floatToBuffer(Type type, real_t value)
1932     {
1933         .floatToBuffer(type, value, buf, hgs.hdrgen);
1934     }
1935 
1936     void visitReal(RealExp e)
1937     {
1938         floatToBuffer(e.type, e.value);
1939     }
1940 
1941     void visitComplex(ComplexExp e)
1942     {
1943         /* Print as:
1944          *  (re+imi)
1945          */
1946         buf.writeByte('(');
1947         floatToBuffer(e.type, creall(e.value));
1948         buf.writeByte('+');
1949         floatToBuffer(e.type, cimagl(e.value));
1950         buf.writestring("i)");
1951     }
1952 
1953     void visitIdentifier(IdentifierExp e)
1954     {
1955         if (hgs.hdrgen || hgs.ddoc)
1956             buf.writestring(e.ident.toHChars2());
1957         else
1958             buf.writestring(e.ident.toString());
1959     }
1960 
1961     void visitDsymbol(DsymbolExp e)
1962     {
1963         buf.writestring(e.s.toChars());
1964     }
1965 
1966     void visitThis(ThisExp e)
1967     {
1968         buf.writestring("this");
1969     }
1970 
1971     void visitSuper(SuperExp e)
1972     {
1973         buf.writestring("super");
1974     }
1975 
1976     void visitNull(NullExp e)
1977     {
1978         buf.writestring("null");
1979     }
1980 
1981     void visitString(StringExp e)
1982     {
1983         buf.writeByte('"');
1984         const o = buf.length;
1985         foreach (i; 0 .. e.len)
1986         {
1987             writeCharLiteral(*buf, e.getCodeUnit(i));
1988         }
1989         if (hgs.ddoc)
1990             escapeDdocString(buf, o);
1991         buf.writeByte('"');
1992         if (e.postfix)
1993             buf.writeByte(e.postfix);
1994     }
1995 
1996     void visitArrayLiteral(ArrayLiteralExp e)
1997     {
1998         buf.writeByte('[');
1999         argsToBuffer(e.elements, buf, hgs, e.basis);
2000         buf.writeByte(']');
2001     }
2002 
2003     void visitAssocArrayLiteral(AssocArrayLiteralExp e)
2004     {
2005         buf.writeByte('[');
2006         foreach (i, key; *e.keys)
2007         {
2008             if (i)
2009                 buf.writestring(", ");
2010             expToBuffer(key, PREC.assign, buf, hgs);
2011             buf.writeByte(':');
2012             auto value = (*e.values)[i];
2013             expToBuffer(value, PREC.assign, buf, hgs);
2014         }
2015         buf.writeByte(']');
2016     }
2017 
2018     void visitStructLiteral(StructLiteralExp e)
2019     {
2020         buf.writestring(e.sd.toChars());
2021         buf.writeByte('(');
2022         // CTFE can generate struct literals that contain an AddrExp pointing
2023         // to themselves, need to avoid infinite recursion:
2024         // struct S { this(int){ this.s = &this; } S* s; }
2025         // const foo = new S(0);
2026         if (e.stageflags & stageToCBuffer)
2027             buf.writestring("<recursion>");
2028         else
2029         {
2030             const old = e.stageflags;
2031             e.stageflags |= stageToCBuffer;
2032             argsToBuffer(e.elements, buf, hgs);
2033             e.stageflags = old;
2034         }
2035         buf.writeByte(')');
2036     }
2037 
2038     void visitCompoundLiteral(CompoundLiteralExp e)
2039     {
2040         buf.writeByte('(');
2041         typeToBuffer(e.type, null, buf, hgs);
2042         buf.writeByte(')');
2043         e.initializer.initializerToBuffer(buf, hgs);
2044     }
2045 
2046     void visitType(TypeExp e)
2047     {
2048         typeToBuffer(e.type, null, buf, hgs);
2049     }
2050 
2051     void visitScope(ScopeExp e)
2052     {
2053         if (e.sds.isTemplateInstance())
2054         {
2055             e.sds.dsymbolToBuffer(buf, hgs);
2056         }
2057         else if (hgs !is null && hgs.ddoc)
2058         {
2059             // fixes bug 6491
2060             if (auto m = e.sds.isModule())
2061                 buf.writestring(m.md.toChars());
2062             else
2063                 buf.writestring(e.sds.toChars());
2064         }
2065         else
2066         {
2067             buf.writestring(e.sds.kind());
2068             buf.writeByte(' ');
2069             buf.writestring(e.sds.toChars());
2070         }
2071     }
2072 
2073     void visitTemplate(TemplateExp e)
2074     {
2075         buf.writestring(e.td.toChars());
2076     }
2077 
2078     void visitNew(NewExp e)
2079     {
2080         if (e.thisexp)
2081         {
2082             expToBuffer(e.thisexp, PREC.primary, buf, hgs);
2083             buf.writeByte('.');
2084         }
2085         buf.writestring("new ");
2086         typeToBuffer(e.newtype, null, buf, hgs);
2087         if (e.arguments && e.arguments.dim)
2088         {
2089             buf.writeByte('(');
2090             argsToBuffer(e.arguments, buf, hgs);
2091             buf.writeByte(')');
2092         }
2093     }
2094 
2095     void visitNewAnonClass(NewAnonClassExp e)
2096     {
2097         if (e.thisexp)
2098         {
2099             expToBuffer(e.thisexp, PREC.primary, buf, hgs);
2100             buf.writeByte('.');
2101         }
2102         buf.writestring("new");
2103         buf.writestring(" class ");
2104         if (e.arguments && e.arguments.dim)
2105         {
2106             buf.writeByte('(');
2107             argsToBuffer(e.arguments, buf, hgs);
2108             buf.writeByte(')');
2109         }
2110         if (e.cd)
2111             e.cd.dsymbolToBuffer(buf, hgs);
2112     }
2113 
2114     void visitSymOff(SymOffExp e)
2115     {
2116         if (e.offset)
2117             buf.printf("(& %s%+lld)", e.var.toChars(), e.offset);
2118         else if (e.var.isTypeInfoDeclaration())
2119             buf.writestring(e.var.toChars());
2120         else
2121             buf.printf("& %s", e.var.toChars());
2122     }
2123 
2124     void visitVar(VarExp e)
2125     {
2126         buf.writestring(e.var.toChars());
2127     }
2128 
2129     void visitOver(OverExp e)
2130     {
2131         buf.writestring(e.vars.ident.toString());
2132     }
2133 
2134     void visitTuple(TupleExp e)
2135     {
2136         if (e.e0)
2137         {
2138             buf.writeByte('(');
2139             e.e0.expressionPrettyPrint(buf, hgs);
2140             buf.writestring(", tuple(");
2141             argsToBuffer(e.exps, buf, hgs);
2142             buf.writestring("))");
2143         }
2144         else
2145         {
2146             buf.writestring("tuple(");
2147             argsToBuffer(e.exps, buf, hgs);
2148             buf.writeByte(')');
2149         }
2150     }
2151 
2152     void visitFunc(FuncExp e)
2153     {
2154         e.fd.dsymbolToBuffer(buf, hgs);
2155         //buf.writestring(e.fd.toChars());
2156     }
2157 
2158     void visitDeclaration(DeclarationExp e)
2159     {
2160         /* Normal dmd execution won't reach here - regular variable declarations
2161          * are handled in visit(ExpStatement), so here would be used only when
2162          * we'll directly call Expression.toChars() for debugging.
2163          */
2164         if (e.declaration)
2165         {
2166             if (auto var = e.declaration.isVarDeclaration())
2167             {
2168             // For debugging use:
2169             // - Avoid printing newline.
2170             // - Intentionally use the format (Type var;)
2171             //   which isn't correct as regular D code.
2172                 buf.writeByte('(');
2173 
2174                 scope v = new DsymbolPrettyPrintVisitor(buf, hgs);
2175                 v.visitVarDecl(var, false);
2176 
2177                 buf.writeByte(';');
2178                 buf.writeByte(')');
2179             }
2180             else e.declaration.dsymbolToBuffer(buf, hgs);
2181         }
2182     }
2183 
2184     void visitTypeid(TypeidExp e)
2185     {
2186         buf.writestring("typeid(");
2187         objectToBuffer(e.obj, buf, hgs);
2188         buf.writeByte(')');
2189     }
2190 
2191     void visitTraits(TraitsExp e)
2192     {
2193         buf.writestring("__traits(");
2194         if (e.ident)
2195             buf.writestring(e.ident.toString());
2196         if (e.args)
2197         {
2198             foreach (arg; *e.args)
2199             {
2200                 buf.writestring(", ");
2201                 objectToBuffer(arg, buf, hgs);
2202             }
2203         }
2204         buf.writeByte(')');
2205     }
2206 
2207     void visitHalt(HaltExp e)
2208     {
2209         buf.writestring("halt");
2210     }
2211 
2212     void visitIs(IsExp e)
2213     {
2214         buf.writestring("is(");
2215         typeToBuffer(e.targ, e.id, buf, hgs);
2216         if (e.tok2 != TOK.reserved)
2217         {
2218             buf.printf(" %s %s", Token.toChars(e.tok), Token.toChars(e.tok2));
2219         }
2220         else if (e.tspec)
2221         {
2222             if (e.tok == TOK.colon)
2223                 buf.writestring(" : ");
2224             else
2225                 buf.writestring(" == ");
2226             typeToBuffer(e.tspec, null, buf, hgs);
2227         }
2228         if (e.parameters && e.parameters.dim)
2229         {
2230             buf.writestring(", ");
2231             scope v = new DsymbolPrettyPrintVisitor(buf, hgs);
2232             v.visitTemplateParameters(e.parameters);
2233         }
2234         buf.writeByte(')');
2235     }
2236 
2237     void visitUna(UnaExp e)
2238     {
2239         buf.writestring(EXPtoString(e.op));
2240         expToBuffer(e.e1, precedence[e.op], buf, hgs);
2241     }
2242 
2243     void visitBin(BinExp e)
2244     {
2245         expToBuffer(e.e1, precedence[e.op], buf, hgs);
2246         buf.writeByte(' ');
2247         buf.writestring(EXPtoString(e.op));
2248         buf.writeByte(' ');
2249         expToBuffer(e.e2, cast(PREC)(precedence[e.op] + 1), buf, hgs);
2250     }
2251 
2252     void visitComma(CommaExp e)
2253     {
2254         // CommaExp is generated by the compiler so it shouldn't
2255         // appear in error messages or header files.
2256         // For now, this treats the case where the compiler
2257         // generates CommaExp for temporaries by calling
2258         // the `sideeffect.copyToTemp` function.
2259         auto ve = e.e2.isVarExp();
2260 
2261         // not a CommaExp introduced for temporaries, go on
2262         // the old path
2263         if (!ve || !(ve.var.storage_class & STC.temp))
2264         {
2265             visitBin(cast(BinExp)e);
2266             return;
2267         }
2268 
2269         // CommaExp that contain temporaries inserted via
2270         // `copyToTemp` are usually of the form
2271         // ((T __temp = exp), __tmp).
2272         // Asserts are here to easily spot
2273         // missing cases where CommaExp
2274         // are used for other constructs
2275         auto vd = ve.var.isVarDeclaration();
2276         assert(vd && vd._init);
2277 
2278         if (auto ei = vd._init.isExpInitializer())
2279         {
2280             Expression commaExtract;
2281             auto exp = ei.exp;
2282             if (auto ce = exp.isConstructExp())
2283                 commaExtract = ce.e2;
2284             else if (auto se = exp.isStructLiteralExp())
2285                 commaExtract = se;
2286 
2287             if (commaExtract)
2288             {
2289                 expToBuffer(commaExtract, precedence[exp.op], buf, hgs);
2290                 return;
2291             }
2292         }
2293 
2294         // not one of the known cases, go on the old path
2295         visitBin(cast(BinExp)e);
2296         return;
2297     }
2298 
2299     void visitMixin(MixinExp e)
2300     {
2301         buf.writestring("mixin(");
2302         argsToBuffer(e.exps, buf, hgs, null);
2303         buf.writeByte(')');
2304     }
2305 
2306     void visitImport(ImportExp e)
2307     {
2308         buf.writestring("import(");
2309         expToBuffer(e.e1, PREC.assign, buf, hgs);
2310         buf.writeByte(')');
2311     }
2312 
2313     void visitAssert(AssertExp e)
2314     {
2315         buf.writestring("assert(");
2316         expToBuffer(e.e1, PREC.assign, buf, hgs);
2317         if (e.msg)
2318         {
2319             buf.writestring(", ");
2320             expToBuffer(e.msg, PREC.assign, buf, hgs);
2321         }
2322         buf.writeByte(')');
2323     }
2324 
2325     void visitThrow(ThrowExp e)
2326     {
2327         buf.writestring("throw ");
2328         expToBuffer(e.e1, PREC.unary, buf, hgs);
2329     }
2330 
2331     void visitDotId(DotIdExp e)
2332     {
2333         expToBuffer(e.e1, PREC.primary, buf, hgs);
2334         if (e.arrow)
2335             buf.writestring("->");
2336         else
2337             buf.writeByte('.');
2338         buf.writestring(e.ident.toString());
2339     }
2340 
2341     void visitDotTemplate(DotTemplateExp e)
2342     {
2343         expToBuffer(e.e1, PREC.primary, buf, hgs);
2344         buf.writeByte('.');
2345         buf.writestring(e.td.toChars());
2346     }
2347 
2348     void visitDotVar(DotVarExp e)
2349     {
2350         expToBuffer(e.e1, PREC.primary, buf, hgs);
2351         buf.writeByte('.');
2352         buf.writestring(e.var.toChars());
2353     }
2354 
2355     void visitDotTemplateInstance(DotTemplateInstanceExp e)
2356     {
2357         expToBuffer(e.e1, PREC.primary, buf, hgs);
2358         buf.writeByte('.');
2359         e.ti.dsymbolToBuffer(buf, hgs);
2360     }
2361 
2362     void visitDelegate(DelegateExp e)
2363     {
2364         buf.writeByte('&');
2365         if (!e.func.isNested() || e.func.needThis())
2366         {
2367             expToBuffer(e.e1, PREC.primary, buf, hgs);
2368             buf.writeByte('.');
2369         }
2370         buf.writestring(e.func.toChars());
2371     }
2372 
2373     void visitDotType(DotTypeExp e)
2374     {
2375         expToBuffer(e.e1, PREC.primary, buf, hgs);
2376         buf.writeByte('.');
2377         buf.writestring(e.sym.toChars());
2378     }
2379 
2380     void visitCall(CallExp e)
2381     {
2382         if (e.e1.op == EXP.type)
2383         {
2384             /* Avoid parens around type to prevent forbidden cast syntax:
2385              *   (sometype)(arg1)
2386              * This is ok since types in constructor calls
2387              * can never depend on parens anyway
2388              */
2389             e.e1.expressionPrettyPrint(buf, hgs);
2390         }
2391         else
2392             expToBuffer(e.e1, precedence[e.op], buf, hgs);
2393         buf.writeByte('(');
2394         argsToBuffer(e.arguments, buf, hgs);
2395         buf.writeByte(')');
2396     }
2397 
2398     void visitPtr(PtrExp e)
2399     {
2400         buf.writeByte('*');
2401         expToBuffer(e.e1, precedence[e.op], buf, hgs);
2402     }
2403 
2404     void visitDelete(DeleteExp e)
2405     {
2406         buf.writestring("delete ");
2407         expToBuffer(e.e1, precedence[e.op], buf, hgs);
2408     }
2409 
2410     void visitCast(CastExp e)
2411     {
2412         buf.writestring("cast(");
2413         if (e.to)
2414             typeToBuffer(e.to, null, buf, hgs);
2415         else
2416         {
2417             MODtoBuffer(buf, e.mod);
2418         }
2419         buf.writeByte(')');
2420         expToBuffer(e.e1, precedence[e.op], buf, hgs);
2421     }
2422 
2423     void visitVector(VectorExp e)
2424     {
2425         buf.writestring("cast(");
2426         typeToBuffer(e.to, null, buf, hgs);
2427         buf.writeByte(')');
2428         expToBuffer(e.e1, precedence[e.op], buf, hgs);
2429     }
2430 
2431     void visitVectorArray(VectorArrayExp e)
2432     {
2433         expToBuffer(e.e1, PREC.primary, buf, hgs);
2434         buf.writestring(".array");
2435     }
2436 
2437     void visitSlice(SliceExp e)
2438     {
2439         expToBuffer(e.e1, precedence[e.op], buf, hgs);
2440         buf.writeByte('[');
2441         if (e.upr || e.lwr)
2442         {
2443             if (e.lwr)
2444                 sizeToBuffer(e.lwr, buf, hgs);
2445             else
2446                 buf.writeByte('0');
2447             buf.writestring("..");
2448             if (e.upr)
2449                 sizeToBuffer(e.upr, buf, hgs);
2450             else
2451                 buf.writeByte('$');
2452         }
2453         buf.writeByte(']');
2454     }
2455 
2456     void visitArrayLength(ArrayLengthExp e)
2457     {
2458         expToBuffer(e.e1, PREC.primary, buf, hgs);
2459         buf.writestring(".length");
2460     }
2461 
2462     void visitInterval(IntervalExp e)
2463     {
2464         expToBuffer(e.lwr, PREC.assign, buf, hgs);
2465         buf.writestring("..");
2466         expToBuffer(e.upr, PREC.assign, buf, hgs);
2467     }
2468 
2469     void visitDelegatePtr(DelegatePtrExp e)
2470     {
2471         expToBuffer(e.e1, PREC.primary, buf, hgs);
2472         buf.writestring(".ptr");
2473     }
2474 
2475     void visitDelegateFuncptr(DelegateFuncptrExp e)
2476     {
2477         expToBuffer(e.e1, PREC.primary, buf, hgs);
2478         buf.writestring(".funcptr");
2479     }
2480 
2481     void visitArray(ArrayExp e)
2482     {
2483         expToBuffer(e.e1, PREC.primary, buf, hgs);
2484         buf.writeByte('[');
2485         argsToBuffer(e.arguments, buf, hgs);
2486         buf.writeByte(']');
2487     }
2488 
2489     void visitDot(DotExp e)
2490     {
2491         expToBuffer(e.e1, PREC.primary, buf, hgs);
2492         buf.writeByte('.');
2493         expToBuffer(e.e2, PREC.primary, buf, hgs);
2494     }
2495 
2496     void visitIndex(IndexExp e)
2497     {
2498         expToBuffer(e.e1, PREC.primary, buf, hgs);
2499         buf.writeByte('[');
2500         sizeToBuffer(e.e2, buf, hgs);
2501         buf.writeByte(']');
2502     }
2503 
2504     void visitPost(PostExp e)
2505     {
2506         expToBuffer(e.e1, precedence[e.op], buf, hgs);
2507         buf.writestring(EXPtoString(e.op));
2508     }
2509 
2510     void visitPre(PreExp e)
2511     {
2512         buf.writestring(EXPtoString(e.op));
2513         expToBuffer(e.e1, precedence[e.op], buf, hgs);
2514     }
2515 
2516     void visitRemove(RemoveExp e)
2517     {
2518         expToBuffer(e.e1, PREC.primary, buf, hgs);
2519         buf.writestring(".remove(");
2520         expToBuffer(e.e2, PREC.assign, buf, hgs);
2521         buf.writeByte(')');
2522     }
2523 
2524     void visitCond(CondExp e)
2525     {
2526         expToBuffer(e.econd, PREC.oror, buf, hgs);
2527         buf.writestring(" ? ");
2528         expToBuffer(e.e1, PREC.expr, buf, hgs);
2529         buf.writestring(" : ");
2530         expToBuffer(e.e2, PREC.cond, buf, hgs);
2531     }
2532 
2533     void visitDefaultInit(DefaultInitExp e)
2534     {
2535         buf.writestring(EXPtoString(e.op));
2536     }
2537 
2538     void visitClassReference(ClassReferenceExp e)
2539     {
2540         buf.writestring(e.value.toChars());
2541     }
2542 
2543     switch (e.op)
2544     {
2545         default:
2546             if (auto be = e.isBinExp())
2547                 return visitBin(be);
2548             else if (auto ue = e.isUnaExp())
2549                 return visitUna(ue);
2550             else if (auto de = e.isDefaultInitExp())
2551                 return visitDefaultInit(e.isDefaultInitExp());
2552             return visit(e);
2553 
2554         case EXP.int64:         return visitInteger(e.isIntegerExp());
2555         case EXP.error:         return visitError(e.isErrorExp());
2556         case EXP.void_:         return visitVoidInit(e.isVoidInitExp());
2557         case EXP.float64:       return visitReal(e.isRealExp());
2558         case EXP.complex80:     return visitComplex(e.isComplexExp());
2559         case EXP.identifier:    return visitIdentifier(e.isIdentifierExp());
2560         case EXP.dSymbol:       return visitDsymbol(e.isDsymbolExp());
2561         case EXP.this_:         return visitThis(e.isThisExp());
2562         case EXP.super_:        return visitSuper(e.isSuperExp());
2563         case EXP.null_:         return visitNull(e.isNullExp());
2564         case EXP.string_:       return visitString(e.isStringExp());
2565         case EXP.arrayLiteral:  return visitArrayLiteral(e.isArrayLiteralExp());
2566         case EXP.assocArrayLiteral:     return visitAssocArrayLiteral(e.isAssocArrayLiteralExp());
2567         case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp());
2568         case EXP.compoundLiteral:       return visitCompoundLiteral(e.isCompoundLiteralExp());
2569         case EXP.type:          return visitType(e.isTypeExp());
2570         case EXP.scope_:        return visitScope(e.isScopeExp());
2571         case EXP.template_:     return visitTemplate(e.isTemplateExp());
2572         case EXP.new_:          return visitNew(e.isNewExp());
2573         case EXP.newAnonymousClass:     return visitNewAnonClass(e.isNewAnonClassExp());
2574         case EXP.symbolOffset:  return visitSymOff(e.isSymOffExp());
2575         case EXP.variable:      return visitVar(e.isVarExp());
2576         case EXP.overloadSet:   return visitOver(e.isOverExp());
2577         case EXP.tuple:         return visitTuple(e.isTupleExp());
2578         case EXP.function_:     return visitFunc(e.isFuncExp());
2579         case EXP.declaration:   return visitDeclaration(e.isDeclarationExp());
2580         case EXP.typeid_:       return visitTypeid(e.isTypeidExp());
2581         case EXP.traits:        return visitTraits(e.isTraitsExp());
2582         case EXP.halt:          return visitHalt(e.isHaltExp());
2583         case EXP.is_:           return visitIs(e.isExp());
2584         case EXP.comma:         return visitComma(e.isCommaExp());
2585         case EXP.mixin_:        return visitMixin(e.isMixinExp());
2586         case EXP.import_:       return visitImport(e.isImportExp());
2587         case EXP.assert_:       return visitAssert(e.isAssertExp());
2588         case EXP.throw_:        return visitThrow(e.isThrowExp());
2589         case EXP.dotIdentifier: return visitDotId(e.isDotIdExp());
2590         case EXP.dotTemplateDeclaration:        return visitDotTemplate(e.isDotTemplateExp());
2591         case EXP.dotVariable:   return visitDotVar(e.isDotVarExp());
2592         case EXP.dotTemplateInstance:   return visitDotTemplateInstance(e.isDotTemplateInstanceExp());
2593         case EXP.delegate_:     return visitDelegate(e.isDelegateExp());
2594         case EXP.dotType:       return visitDotType(e.isDotTypeExp());
2595         case EXP.call:          return visitCall(e.isCallExp());
2596         case EXP.star:          return visitPtr(e.isPtrExp());
2597         case EXP.delete_:       return visitDelete(e.isDeleteExp());
2598         case EXP.cast_:         return visitCast(e.isCastExp());
2599         case EXP.vector:        return visitVector(e.isVectorExp());
2600         case EXP.vectorArray:   return visitVectorArray(e.isVectorArrayExp());
2601         case EXP.slice:         return visitSlice(e.isSliceExp());
2602         case EXP.arrayLength:   return visitArrayLength(e.isArrayLengthExp());
2603         case EXP.interval:      return visitInterval(e.isIntervalExp());
2604         case EXP.delegatePointer:       return visitDelegatePtr(e.isDelegatePtrExp());
2605         case EXP.delegateFunctionPointer:       return visitDelegateFuncptr(e.isDelegateFuncptrExp());
2606         case EXP.array:         return visitArray(e.isArrayExp());
2607         case EXP.dot:           return visitDot(e.isDotExp());
2608         case EXP.index:         return visitIndex(e.isIndexExp());
2609         case EXP.minusMinus:
2610         case EXP.plusPlus:      return visitPost(e.isPostExp());
2611         case EXP.preMinusMinus:
2612         case EXP.prePlusPlus:   return visitPre(e.isPreExp());
2613         case EXP.remove:        return visitRemove(e.isRemoveExp());
2614         case EXP.question:      return visitCond(e.isCondExp());
2615         case EXP.classReference:        return visitClassReference(e.isClassReferenceExp());
2616     }
2617 }
2618 
2619 /**
2620  * Formats `value` as a literal of type `type` into `buf`.
2621  *
2622  * Params:
2623  *   type     = literal type (e.g. Tfloat)
2624  *   value    = value to print
2625  *   buf      = target buffer
2626  *   allowHex = whether hex floating point literals may be used
2627  *              for greater accuracy
2628  */
floatToBuffer(Type type,const real_t value,OutBuffer * buf,const bool allowHex)2629 void floatToBuffer(Type type, const real_t value, OutBuffer* buf, const bool allowHex)
2630 {
2631     /** sizeof(value)*3 is because each byte of mantissa is max
2632         of 256 (3 characters). The string will be "-M.MMMMe-4932".
2633         (ie, 8 chars more than mantissa). Plus one for trailing \0.
2634         Plus one for rounding. */
2635     const(size_t) BUFFER_LEN = value.sizeof * 3 + 8 + 1 + 1;
2636     char[BUFFER_LEN] buffer = void;
2637     CTFloat.sprint(buffer.ptr, 'g', value);
2638     assert(strlen(buffer.ptr) < BUFFER_LEN);
2639     if (allowHex)
2640     {
2641         real_t r = CTFloat.parse(buffer.ptr);
2642         if (r != value) // if exact duplication
2643             CTFloat.sprint(buffer.ptr, 'a', value);
2644     }
2645     buf.writestring(buffer.ptr);
2646     if (buffer.ptr[strlen(buffer.ptr) - 1] == '.')
2647         buf.remove(buf.length() - 1, 1);
2648 
2649     if (type)
2650     {
2651         Type t = type.toBasetype();
2652         switch (t.ty)
2653         {
2654         case Tfloat32:
2655         case Timaginary32:
2656         case Tcomplex32:
2657             buf.writeByte('F');
2658             break;
2659         case Tfloat80:
2660         case Timaginary80:
2661         case Tcomplex80:
2662             buf.writeByte('L');
2663             break;
2664         default:
2665             break;
2666         }
2667         if (t.isimaginary())
2668             buf.writeByte('i');
2669     }
2670 }
2671 
templateParameterToBuffer(TemplateParameter tp,OutBuffer * buf,HdrGenState * hgs)2672 private void templateParameterToBuffer(TemplateParameter tp, OutBuffer* buf, HdrGenState* hgs)
2673 {
2674     scope v = new TemplateParameterPrettyPrintVisitor(buf, hgs);
2675     tp.accept(v);
2676 }
2677 
2678 private extern (C++) final class TemplateParameterPrettyPrintVisitor : Visitor
2679 {
2680     alias visit = Visitor.visit;
2681 public:
2682     OutBuffer* buf;
2683     HdrGenState* hgs;
2684 
this(OutBuffer * buf,HdrGenState * hgs)2685     extern (D) this(OutBuffer* buf, HdrGenState* hgs)
2686     {
2687         this.buf = buf;
2688         this.hgs = hgs;
2689     }
2690 
visit(TemplateTypeParameter tp)2691     override void visit(TemplateTypeParameter tp)
2692     {
2693         buf.writestring(tp.ident.toString());
2694         if (tp.specType)
2695         {
2696             buf.writestring(" : ");
2697             typeToBuffer(tp.specType, null, buf, hgs);
2698         }
2699         if (tp.defaultType)
2700         {
2701             buf.writestring(" = ");
2702             typeToBuffer(tp.defaultType, null, buf, hgs);
2703         }
2704     }
2705 
visit(TemplateThisParameter tp)2706     override void visit(TemplateThisParameter tp)
2707     {
2708         buf.writestring("this ");
2709         visit(cast(TemplateTypeParameter)tp);
2710     }
2711 
visit(TemplateAliasParameter tp)2712     override void visit(TemplateAliasParameter tp)
2713     {
2714         buf.writestring("alias ");
2715         if (tp.specType)
2716             typeToBuffer(tp.specType, tp.ident, buf, hgs);
2717         else
2718             buf.writestring(tp.ident.toString());
2719         if (tp.specAlias)
2720         {
2721             buf.writestring(" : ");
2722             objectToBuffer(tp.specAlias, buf, hgs);
2723         }
2724         if (tp.defaultAlias)
2725         {
2726             buf.writestring(" = ");
2727             objectToBuffer(tp.defaultAlias, buf, hgs);
2728         }
2729     }
2730 
visit(TemplateValueParameter tp)2731     override void visit(TemplateValueParameter tp)
2732     {
2733         typeToBuffer(tp.valType, tp.ident, buf, hgs);
2734         if (tp.specValue)
2735         {
2736             buf.writestring(" : ");
2737             tp.specValue.expressionToBuffer(buf, hgs);
2738         }
2739         if (tp.defaultValue)
2740         {
2741             buf.writestring(" = ");
2742             tp.defaultValue.expressionToBuffer(buf, hgs);
2743         }
2744     }
2745 
visit(TemplateTupleParameter tp)2746     override void visit(TemplateTupleParameter tp)
2747     {
2748         buf.writestring(tp.ident.toString());
2749         buf.writestring("...");
2750     }
2751 }
2752 
conditionToBuffer(Condition c,OutBuffer * buf,HdrGenState * hgs)2753 private void conditionToBuffer(Condition c, OutBuffer* buf, HdrGenState* hgs)
2754 {
2755     scope v = new ConditionPrettyPrintVisitor(buf, hgs);
2756     c.accept(v);
2757 }
2758 
2759 private extern (C++) final class ConditionPrettyPrintVisitor : Visitor
2760 {
2761     alias visit = Visitor.visit;
2762 public:
2763     OutBuffer* buf;
2764     HdrGenState* hgs;
2765 
this(OutBuffer * buf,HdrGenState * hgs)2766     extern (D) this(OutBuffer* buf, HdrGenState* hgs)
2767     {
2768         this.buf = buf;
2769         this.hgs = hgs;
2770     }
2771 
visit(DebugCondition c)2772     override void visit(DebugCondition c)
2773     {
2774         buf.writestring("debug (");
2775         if (c.ident)
2776             buf.writestring(c.ident.toString());
2777         else
2778             buf.print(c.level);
2779         buf.writeByte(')');
2780     }
2781 
visit(VersionCondition c)2782     override void visit(VersionCondition c)
2783     {
2784         buf.writestring("version (");
2785         if (c.ident)
2786             buf.writestring(c.ident.toString());
2787         else
2788             buf.print(c.level);
2789         buf.writeByte(')');
2790     }
2791 
visit(StaticIfCondition c)2792     override void visit(StaticIfCondition c)
2793     {
2794         buf.writestring("static if (");
2795         c.exp.expressionToBuffer(buf, hgs);
2796         buf.writeByte(')');
2797     }
2798 }
2799 
toCBuffer(const Statement s,OutBuffer * buf,HdrGenState * hgs)2800 void toCBuffer(const Statement s, OutBuffer* buf, HdrGenState* hgs)
2801 {
2802     scope v = new StatementPrettyPrintVisitor(buf, hgs);
2803     (cast() s).accept(v);
2804 }
2805 
toCBuffer(const Type t,OutBuffer * buf,const Identifier ident,HdrGenState * hgs)2806 void toCBuffer(const Type t, OutBuffer* buf, const Identifier ident, HdrGenState* hgs)
2807 {
2808     typeToBuffer(cast() t, ident, buf, hgs);
2809 }
2810 
toCBuffer(Dsymbol s,OutBuffer * buf,HdrGenState * hgs)2811 void toCBuffer(Dsymbol s, OutBuffer* buf, HdrGenState* hgs)
2812 {
2813     scope v = new DsymbolPrettyPrintVisitor(buf, hgs);
2814     s.accept(v);
2815 }
2816 
2817 // used from TemplateInstance::toChars() and TemplateMixin::toChars()
2818 void toCBufferInstance(const TemplateInstance ti, OutBuffer* buf, bool qualifyTypes = false)
2819 {
2820     HdrGenState hgs;
2821     hgs.fullQual = qualifyTypes;
2822     scope v = new DsymbolPrettyPrintVisitor(buf, &hgs);
2823     v.visit(cast() ti);
2824 }
2825 
toCBuffer(const Initializer iz,OutBuffer * buf,HdrGenState * hgs)2826 void toCBuffer(const Initializer iz, OutBuffer* buf, HdrGenState* hgs)
2827 {
2828     initializerToBuffer(cast() iz, buf, hgs);
2829 }
2830 
stcToBuffer(OutBuffer * buf,StorageClass stc)2831 bool stcToBuffer(OutBuffer* buf, StorageClass stc)
2832 {
2833     //printf("stc: %llx\n", stc);
2834     bool result = false;
2835 
2836     if (stc & STC.scopeinferred)
2837     {
2838         //buf.writestring("scope-inferred ");
2839         stc &= ~(STC.scope_ | STC.scopeinferred);
2840     }
2841     if (stc & STC.returninferred)
2842     {
2843         //buf.writestring((stc & STC.returnScope) ? "return-scope-inferred " : "return-ref-inferred ");
2844         stc &= ~(STC.return_ | STC.returninferred);
2845     }
2846 
2847     /* Put scope ref return into a standard order
2848      */
2849     string rrs;
2850     const isout = (stc & STC.out_) != 0;
2851     //printf("bsr = %d %llx\n", buildScopeRef(stc), stc);
2852     final switch (buildScopeRef(stc))
2853     {
2854         case ScopeRef.None:
2855         case ScopeRef.Scope:
2856         case ScopeRef.Ref:
2857         case ScopeRef.Return:
2858             break;
2859 
2860         case ScopeRef.ReturnScope:      rrs = "return scope"; goto L1;
2861         case ScopeRef.ReturnRef:        rrs = isout ? "return out"       : "return ref";       goto L1;
2862         case ScopeRef.RefScope:         rrs = isout ? "out scope"        : "ref scope";        goto L1;
2863         case ScopeRef.ReturnRef_Scope:  rrs = isout ? "return out scope" : "return ref scope"; goto L1;
2864         case ScopeRef.Ref_ReturnScope:  rrs = isout ? "out return scope" : "ref return scope"; goto L1;
2865         L1:
2866             buf.writestring(rrs);
2867             result = true;
2868             stc &= ~(STC.out_ | STC.scope_ | STC.ref_ | STC.return_);
2869             break;
2870     }
2871 
2872     while (stc)
2873     {
2874         const s = stcToString(stc);
2875         if (!s.length)
2876             break;
2877         if (result)
2878             buf.writeByte(' ');
2879         result = true;
2880         buf.writestring(s);
2881     }
2882 
2883     return result;
2884 }
2885 
2886 /*************************************************
2887  * Pick off one of the storage classes from stc,
2888  * and return a string representation of it.
2889  * stc is reduced by the one picked.
2890  */
stcToString(ref StorageClass stc)2891 string stcToString(ref StorageClass stc)
2892 {
2893     static struct SCstring
2894     {
2895         StorageClass stc;
2896         string id;
2897     }
2898 
2899     // Note: The identifier needs to be `\0` terminated
2900     // as some code assumes it (e.g. when printing error messages)
2901     static immutable SCstring[] table =
2902     [
2903         SCstring(STC.auto_, Token.toString(TOK.auto_)),
2904         SCstring(STC.scope_, Token.toString(TOK.scope_)),
2905         SCstring(STC.static_, Token.toString(TOK.static_)),
2906         SCstring(STC.extern_, Token.toString(TOK.extern_)),
2907         SCstring(STC.const_, Token.toString(TOK.const_)),
2908         SCstring(STC.final_, Token.toString(TOK.final_)),
2909         SCstring(STC.abstract_, Token.toString(TOK.abstract_)),
2910         SCstring(STC.synchronized_, Token.toString(TOK.synchronized_)),
2911         SCstring(STC.deprecated_, Token.toString(TOK.deprecated_)),
2912         SCstring(STC.override_, Token.toString(TOK.override_)),
2913         SCstring(STC.lazy_, Token.toString(TOK.lazy_)),
2914         SCstring(STC.alias_, Token.toString(TOK.alias_)),
2915         SCstring(STC.out_, Token.toString(TOK.out_)),
2916         SCstring(STC.in_, Token.toString(TOK.in_)),
2917         SCstring(STC.manifest, Token.toString(TOK.enum_)),
2918         SCstring(STC.immutable_, Token.toString(TOK.immutable_)),
2919         SCstring(STC.shared_, Token.toString(TOK.shared_)),
2920         SCstring(STC.nothrow_, Token.toString(TOK.nothrow_)),
2921         SCstring(STC.wild, Token.toString(TOK.inout_)),
2922         SCstring(STC.pure_, Token.toString(TOK.pure_)),
2923         SCstring(STC.ref_, Token.toString(TOK.ref_)),
2924         SCstring(STC.return_, Token.toString(TOK.return_)),
2925         SCstring(STC.gshared, Token.toString(TOK.gshared)),
2926         SCstring(STC.nogc, "@nogc"),
2927         SCstring(STC.live, "@live"),
2928         SCstring(STC.property, "@property"),
2929         SCstring(STC.safe, "@safe"),
2930         SCstring(STC.trusted, "@trusted"),
2931         SCstring(STC.system, "@system"),
2932         SCstring(STC.disable, "@disable"),
2933         SCstring(STC.future, "@__future"),
2934         SCstring(STC.local, "__local"),
2935     ];
2936     foreach (ref entry; table)
2937     {
2938         const StorageClass tbl = entry.stc;
2939         assert(tbl & STC.visibleStorageClasses);
2940         if (stc & tbl)
2941         {
2942             stc &= ~tbl;
2943             return entry.id;
2944         }
2945     }
2946     //printf("stc = %llx\n", stc);
2947     return null;
2948 }
2949 
linkageToBuffer(OutBuffer * buf,LINK linkage)2950 private void linkageToBuffer(OutBuffer* buf, LINK linkage)
2951 {
2952     const s = linkageToString(linkage);
2953     if (s.length)
2954     {
2955         buf.writestring("extern (");
2956         buf.writestring(s);
2957         buf.writeByte(')');
2958     }
2959 }
2960 
linkageToChars(LINK linkage)2961 const(char)* linkageToChars(LINK linkage)
2962 {
2963     /// Works because we return a literal
2964     return linkageToString(linkage).ptr;
2965 }
2966 
linkageToString(LINK linkage)2967 string linkageToString(LINK linkage) pure nothrow
2968 {
2969     final switch (linkage)
2970     {
2971     case LINK.default_:
2972         return null;
2973     case LINK.d:
2974         return "D";
2975     case LINK.c:
2976         return "C";
2977     case LINK.cpp:
2978         return "C++";
2979     case LINK.windows:
2980         return "Windows";
2981     case LINK.objc:
2982         return "Objective-C";
2983     case LINK.system:
2984         return "System";
2985     }
2986 }
2987 
visibilityToBuffer(OutBuffer * buf,Visibility vis)2988 void visibilityToBuffer(OutBuffer* buf, Visibility vis)
2989 {
2990     buf.writestring(visibilityToString(vis.kind));
2991     if (vis.kind == Visibility.Kind.package_ && vis.pkg)
2992     {
2993         buf.writeByte('(');
2994         buf.writestring(vis.pkg.toPrettyChars(true));
2995         buf.writeByte(')');
2996     }
2997 }
2998 
2999 /**
3000  * Returns:
3001  *   a human readable representation of `kind`
3002  */
3003 const(char)* visibilityToChars(Visibility.Kind kind)
3004 {
3005     // Null terminated because we return a literal
3006     return visibilityToString(kind).ptr;
3007 }
3008 
3009 /// Ditto
3010 extern (D) string visibilityToString(Visibility.Kind kind) nothrow pure
3011 {
3012     final switch (kind)
3013     {
3014     case Visibility.Kind.undefined:
3015         return null;
3016     case Visibility.Kind.none:
3017         return "none";
3018     case Visibility.Kind.private_:
3019         return "private";
3020     case Visibility.Kind.package_:
3021         return "package";
3022     case Visibility.Kind.protected_:
3023         return "protected";
3024     case Visibility.Kind.public_:
3025         return "public";
3026     case Visibility.Kind.export_:
3027         return "export";
3028     }
3029 }
3030 
3031 // Print the full function signature with correct ident, attributes and template args
functionToBufferFull(TypeFunction tf,OutBuffer * buf,const Identifier ident,HdrGenState * hgs,TemplateDeclaration td)3032 void functionToBufferFull(TypeFunction tf, OutBuffer* buf, const Identifier ident, HdrGenState* hgs, TemplateDeclaration td)
3033 {
3034     //printf("TypeFunction::toCBuffer() this = %p\n", this);
3035     visitFuncIdentWithPrefix(tf, ident, td, buf, hgs);
3036 }
3037 
3038 // 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)3039 void functionToBufferWithIdent(TypeFunction tf, OutBuffer* buf, const(char)* ident, bool isStatic)
3040 {
3041     HdrGenState hgs;
3042     visitFuncIdentWithPostfix(tf, ident.toDString(), buf, &hgs, isStatic);
3043 }
3044 
toCBuffer(const Expression e,OutBuffer * buf,HdrGenState * hgs)3045 void toCBuffer(const Expression e, OutBuffer* buf, HdrGenState* hgs)
3046 {
3047     expressionPrettyPrint(cast()e, buf, hgs);
3048 }
3049 
3050 /**************************************************
3051  * Write out argument types to buf.
3052  */
argExpTypesToCBuffer(OutBuffer * buf,Expressions * arguments)3053 void argExpTypesToCBuffer(OutBuffer* buf, Expressions* arguments)
3054 {
3055     if (!arguments || !arguments.dim)
3056         return;
3057     HdrGenState hgs;
3058     foreach (i, arg; *arguments)
3059     {
3060         if (i)
3061             buf.writestring(", ");
3062         typeToBuffer(arg.type, null, buf, &hgs);
3063     }
3064 }
3065 
toCBuffer(const TemplateParameter tp,OutBuffer * buf,HdrGenState * hgs)3066 void toCBuffer(const TemplateParameter tp, OutBuffer* buf, HdrGenState* hgs)
3067 {
3068     scope v = new TemplateParameterPrettyPrintVisitor(buf, hgs);
3069     (cast() tp).accept(v);
3070 }
3071 
arrayObjectsToBuffer(OutBuffer * buf,Objects * objects)3072 void arrayObjectsToBuffer(OutBuffer* buf, Objects* objects)
3073 {
3074     if (!objects || !objects.dim)
3075         return;
3076     HdrGenState hgs;
3077     foreach (i, o; *objects)
3078     {
3079         if (i)
3080             buf.writestring(", ");
3081         objectToBuffer(o, buf, &hgs);
3082     }
3083 }
3084 
3085 /*************************************************************
3086  * Pretty print function parameters.
3087  * Params:
3088  *  pl = parameter list to print
3089  * Returns: Null-terminated string representing parameters.
3090  */
parametersTypeToChars(ParameterList pl)3091 extern (C++) const(char)* parametersTypeToChars(ParameterList pl)
3092 {
3093     OutBuffer buf;
3094     HdrGenState hgs;
3095     parametersToBuffer(pl, &buf, &hgs);
3096     return buf.extractChars();
3097 }
3098 
3099 /*************************************************************
3100  * Pretty print function parameter.
3101  * Params:
3102  *  parameter = parameter to print.
3103  *  tf = TypeFunction which holds parameter.
3104  *  fullQual = whether to fully qualify types.
3105  * Returns: Null-terminated string representing parameters.
3106  */
parameterToChars(Parameter parameter,TypeFunction tf,bool fullQual)3107 const(char)* parameterToChars(Parameter parameter, TypeFunction tf, bool fullQual)
3108 {
3109     OutBuffer buf;
3110     HdrGenState hgs;
3111     hgs.fullQual = fullQual;
3112 
3113     parameterToBuffer(parameter, &buf, &hgs);
3114 
3115     if (tf.parameterList.varargs == VarArg.typesafe && parameter == tf.parameterList[tf.parameterList.parameters.dim - 1])
3116     {
3117         buf.writestring("...");
3118     }
3119     return buf.extractChars();
3120 }
3121 
3122 
3123 /*************************************************
3124  * Write ParameterList to buffer.
3125  * Params:
3126  *      pl = parameter list to serialize
3127  *      buf = buffer to write it to
3128  *      hgs = context
3129  */
3130 
parametersToBuffer(ParameterList pl,OutBuffer * buf,HdrGenState * hgs)3131 private void parametersToBuffer(ParameterList pl, OutBuffer* buf, HdrGenState* hgs)
3132 {
3133     buf.writeByte('(');
3134     foreach (i; 0 .. pl.length)
3135     {
3136         if (i)
3137             buf.writestring(", ");
3138         pl[i].parameterToBuffer(buf, hgs);
3139     }
3140     final switch (pl.varargs)
3141     {
3142         case VarArg.none:
3143             break;
3144 
3145         case VarArg.variadic:
3146             if (pl.length)
3147                 buf.writestring(", ");
3148 
3149             if (stcToBuffer(buf, pl.stc))
3150                 buf.writeByte(' ');
3151             goto case VarArg.typesafe;
3152 
3153         case VarArg.typesafe:
3154             buf.writestring("...");
3155             break;
3156     }
3157     buf.writeByte(')');
3158 }
3159 
3160 
3161 /***********************************************************
3162  * Write parameter `p` to buffer `buf`.
3163  * Params:
3164  *      p = parameter to serialize
3165  *      buf = buffer to write it to
3166  *      hgs = context
3167  */
parameterToBuffer(Parameter p,OutBuffer * buf,HdrGenState * hgs)3168 private void parameterToBuffer(Parameter p, OutBuffer* buf, HdrGenState* hgs)
3169 {
3170     if (p.userAttribDecl)
3171     {
3172         buf.writeByte('@');
3173 
3174         bool isAnonymous = p.userAttribDecl.atts.dim > 0 && !(*p.userAttribDecl.atts)[0].isCallExp();
3175         if (isAnonymous)
3176             buf.writeByte('(');
3177 
3178         argsToBuffer(p.userAttribDecl.atts, buf, hgs);
3179 
3180         if (isAnonymous)
3181             buf.writeByte(')');
3182         buf.writeByte(' ');
3183     }
3184     if (p.storageClass & STC.auto_)
3185         buf.writestring("auto ");
3186 
3187     StorageClass stc = p.storageClass;
3188     if (p.storageClass & STC.in_)
3189     {
3190         buf.writestring("in ");
3191         if (global.params.previewIn && p.storageClass & STC.ref_)
3192             stc &= ~STC.ref_;
3193     }
3194     else if (p.storageClass & STC.lazy_)
3195         buf.writestring("lazy ");
3196     else if (p.storageClass & STC.alias_)
3197         buf.writestring("alias ");
3198 
3199     if (p.type && p.type.mod & MODFlags.shared_)
3200         stc &= ~STC.shared_;
3201 
3202     if (stcToBuffer(buf, stc & (STC.const_ | STC.immutable_ | STC.wild | STC.shared_ |
3203         STC.return_ | STC.returninferred | STC.scope_ | STC.scopeinferred | STC.out_ | STC.ref_ | STC.returnScope)))
3204         buf.writeByte(' ');
3205 
3206     if (p.storageClass & STC.alias_)
3207     {
3208         if (p.ident)
3209             buf.writestring(p.ident.toString());
3210     }
3211     else if (p.type.ty == Tident &&
3212              (cast(TypeIdentifier)p.type).ident.toString().length > 3 &&
3213              strncmp((cast(TypeIdentifier)p.type).ident.toChars(), "__T", 3) == 0)
3214     {
3215         // print parameter name, instead of undetermined type parameter
3216         buf.writestring(p.ident.toString());
3217     }
3218     else
3219     {
3220         typeToBuffer(p.type, p.ident, buf, hgs, (stc & STC.in_) ? MODFlags.const_ : 0);
3221     }
3222 
3223     if (p.defaultArg)
3224     {
3225         buf.writestring(" = ");
3226         p.defaultArg.expToBuffer(PREC.assign, buf, hgs);
3227     }
3228 }
3229 
3230 
3231 /**************************************************
3232  * Write out argument list to buf.
3233  */
3234 private void argsToBuffer(Expressions* expressions, OutBuffer* buf, HdrGenState* hgs, Expression basis = null)
3235 {
3236     if (!expressions || !expressions.dim)
3237         return;
version(all)3238     version (all)
3239     {
3240         foreach (i, el; *expressions)
3241         {
3242             if (i)
3243                 buf.writestring(", ");
3244             if (!el)
3245                 el = basis;
3246             if (el)
3247                 expToBuffer(el, PREC.assign, buf, hgs);
3248         }
3249     }
3250     else
3251     {
3252         // Sparse style formatting, for debug use only
3253         //      [0..dim: basis, 1: e1, 5: e5]
3254         if (basis)
3255         {
3256             buf.writestring("0..");
3257             buf.print(expressions.dim);
3258             buf.writestring(": ");
3259             expToBuffer(basis, PREC.assign, buf, hgs);
3260         }
foreach(i,el;* expressions)3261         foreach (i, el; *expressions)
3262         {
3263             if (el)
3264             {
3265                 if (basis)
3266                 {
3267                     buf.writestring(", ");
3268                     buf.print(i);
3269                     buf.writestring(": ");
3270                 }
3271                 else if (i)
3272                     buf.writestring(", ");
3273                 expToBuffer(el, PREC.assign, buf, hgs);
3274             }
3275         }
3276     }
3277 }
3278 
sizeToBuffer(Expression e,OutBuffer * buf,HdrGenState * hgs)3279 private void sizeToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs)
3280 {
3281     if (e.type == Type.tsize_t)
3282     {
3283         Expression ex = (e.op == EXP.cast_ ? (cast(CastExp)e).e1 : e);
3284         ex = ex.optimize(WANTvalue);
3285         const dinteger_t uval = ex.op == EXP.int64 ? ex.toInteger() : cast(dinteger_t)-1;
3286         if (cast(sinteger_t)uval >= 0)
3287         {
3288             dinteger_t sizemax = void;
3289             if (target.ptrsize == 8)
3290                 sizemax = 0xFFFFFFFFFFFFFFFFUL;
3291             else if (target.ptrsize == 4)
3292                 sizemax = 0xFFFFFFFFU;
3293             else if (target.ptrsize == 2)
3294                 sizemax = 0xFFFFU;
3295             else
3296                 assert(0);
3297             if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFUL)
3298             {
3299                 buf.print(uval);
3300                 return;
3301             }
3302         }
3303     }
3304     expToBuffer(e, PREC.assign, buf, hgs);
3305 }
3306 
expressionToBuffer(Expression e,OutBuffer * buf,HdrGenState * hgs)3307 private void expressionToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs)
3308 {
3309     expressionPrettyPrint(e, buf, hgs);
3310 }
3311 
3312 /**************************************************
3313  * Write expression out to buf, but wrap it
3314  * in ( ) if its precedence is less than pr.
3315  */
expToBuffer(Expression e,PREC pr,OutBuffer * buf,HdrGenState * hgs)3316 private void expToBuffer(Expression e, PREC pr, OutBuffer* buf, HdrGenState* hgs)
3317 {
3318     debug
3319     {
3320         if (precedence[e.op] == PREC.zero)
3321             printf("precedence not defined for token '%s'\n", EXPtoString(e.op).ptr);
3322     }
3323     if (e.op == 0xFF)
3324     {
3325         buf.writestring("<FF>");
3326         return;
3327     }
3328     assert(precedence[e.op] != PREC.zero);
3329     assert(pr != PREC.zero);
3330     /* Despite precedence, we don't allow a<b<c expressions.
3331      * They must be parenthesized.
3332      */
3333     if (precedence[e.op] < pr || (pr == PREC.rel && precedence[e.op] == pr)
3334         || (pr >= PREC.or && pr <= PREC.and && precedence[e.op] == PREC.rel))
3335     {
3336         buf.writeByte('(');
3337         e.expressionToBuffer(buf, hgs);
3338         buf.writeByte(')');
3339     }
3340     else
3341     {
3342         e.expressionToBuffer(buf, hgs);
3343     }
3344 }
3345 
3346 
3347 /**************************************************
3348  * An entry point to pretty-print type.
3349  */
3350 private void typeToBuffer(Type t, const Identifier ident, OutBuffer* buf, HdrGenState* hgs,
3351                           ubyte modMask = 0)
3352 {
3353     if (auto tf = t.isTypeFunction())
3354     {
3355         visitFuncIdentWithPrefix(tf, ident, null, buf, hgs);
3356         return;
3357     }
3358     visitWithMask(t, modMask, buf, hgs);
3359     if (ident)
3360     {
3361         buf.writeByte(' ');
3362         buf.writestring(ident.toString());
3363     }
3364 }
3365 
visitWithMask(Type t,ubyte modMask,OutBuffer * buf,HdrGenState * hgs)3366 private void visitWithMask(Type t, ubyte modMask, OutBuffer* buf, HdrGenState* hgs)
3367 {
3368     // Tuples and functions don't use the type constructor syntax
3369     if (modMask == t.mod || t.ty == Tfunction || t.ty == Ttuple)
3370     {
3371         typeToBufferx(t, buf, hgs);
3372     }
3373     else
3374     {
3375         ubyte m = t.mod & ~(t.mod & modMask);
3376         if (m & MODFlags.shared_)
3377         {
3378             MODtoBuffer(buf, MODFlags.shared_);
3379             buf.writeByte('(');
3380         }
3381         if (m & MODFlags.wild)
3382         {
3383             MODtoBuffer(buf, MODFlags.wild);
3384             buf.writeByte('(');
3385         }
3386         if (m & (MODFlags.const_ | MODFlags.immutable_))
3387         {
3388             MODtoBuffer(buf, m & (MODFlags.const_ | MODFlags.immutable_));
3389             buf.writeByte('(');
3390         }
3391         typeToBufferx(t, buf, hgs);
3392         if (m & (MODFlags.const_ | MODFlags.immutable_))
3393             buf.writeByte(')');
3394         if (m & MODFlags.wild)
3395             buf.writeByte(')');
3396         if (m & MODFlags.shared_)
3397             buf.writeByte(')');
3398     }
3399 }
3400 
3401 
dumpTemplateInstance(TemplateInstance ti,OutBuffer * buf,HdrGenState * hgs)3402 private void dumpTemplateInstance(TemplateInstance ti, OutBuffer* buf, HdrGenState* hgs)
3403 {
3404     buf.writeByte('{');
3405     buf.writenl();
3406     buf.level++;
3407 
3408     if (ti.aliasdecl)
3409     {
3410         ti.aliasdecl.dsymbolToBuffer(buf, hgs);
3411         buf.writenl();
3412     }
3413     else if (ti.members)
3414     {
3415         foreach(m;*ti.members)
3416             m.dsymbolToBuffer(buf, hgs);
3417     }
3418 
3419     buf.level--;
3420     buf.writeByte('}');
3421     buf.writenl();
3422 
3423 }
3424 
tiargsToBuffer(TemplateInstance ti,OutBuffer * buf,HdrGenState * hgs)3425 private void tiargsToBuffer(TemplateInstance ti, OutBuffer* buf, HdrGenState* hgs)
3426 {
3427     buf.writeByte('!');
3428     if (ti.nest)
3429     {
3430         buf.writestring("(...)");
3431         return;
3432     }
3433     if (!ti.tiargs)
3434     {
3435         buf.writestring("()");
3436         return;
3437     }
3438     if (ti.tiargs.dim == 1)
3439     {
3440         RootObject oarg = (*ti.tiargs)[0];
3441         if (Type t = isType(oarg))
3442         {
3443             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))
3444             {
3445                 buf.writestring(t.toChars());
3446                 return;
3447             }
3448         }
3449         else if (Expression e = isExpression(oarg))
3450         {
3451             if (e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.this_)
3452             {
3453                 buf.writestring(e.toChars());
3454                 return;
3455             }
3456         }
3457     }
3458     buf.writeByte('(');
3459     ti.nestUp();
3460     foreach (i, arg; *ti.tiargs)
3461     {
3462         if (i)
3463             buf.writestring(", ");
3464         objectToBuffer(arg, buf, hgs);
3465     }
3466     ti.nestDown();
3467     buf.writeByte(')');
3468 }
3469 
3470 /****************************************
3471  * This makes a 'pretty' version of the template arguments.
3472  * It's analogous to genIdent() which makes a mangled version.
3473  */
objectToBuffer(RootObject oarg,OutBuffer * buf,HdrGenState * hgs)3474 private void objectToBuffer(RootObject oarg, OutBuffer* buf, HdrGenState* hgs)
3475 {
3476     //printf("objectToBuffer()\n");
3477     /* The logic of this should match what genIdent() does. The _dynamic_cast()
3478      * function relies on all the pretty strings to be unique for different classes
3479      * See https://issues.dlang.org/show_bug.cgi?id=7375
3480      * Perhaps it would be better to demangle what genIdent() does.
3481      */
3482     if (auto t = isType(oarg))
3483     {
3484         //printf("\tt: %s ty = %d\n", t.toChars(), t.ty);
3485         typeToBuffer(t, null, buf, hgs);
3486     }
3487     else if (auto e = isExpression(oarg))
3488     {
3489         if (e.op == EXP.variable)
3490             e = e.optimize(WANTvalue); // added to fix https://issues.dlang.org/show_bug.cgi?id=7375
3491         expToBuffer(e, PREC.assign, buf, hgs);
3492     }
3493     else if (Dsymbol s = isDsymbol(oarg))
3494     {
3495         const p = s.ident ? s.ident.toChars() : s.toChars();
3496         buf.writestring(p);
3497     }
3498     else if (auto v = isTuple(oarg))
3499     {
3500         auto args = &v.objects;
3501         foreach (i, arg; *args)
3502         {
3503             if (i)
3504                 buf.writestring(", ");
3505             objectToBuffer(arg, buf, hgs);
3506         }
3507     }
3508     else if (auto p = isParameter(oarg))
3509     {
3510         parameterToBuffer(p, buf, hgs);
3511     }
3512     else if (!oarg)
3513     {
3514         buf.writestring("NULL");
3515     }
3516     else
3517     {
3518         debug
3519         {
3520             printf("bad Object = %p\n", oarg);
3521         }
3522         assert(0);
3523     }
3524 }
3525 
3526 
visitFuncIdentWithPostfix(TypeFunction t,const char[]ident,OutBuffer * buf,HdrGenState * hgs,bool isStatic)3527 private void visitFuncIdentWithPostfix(TypeFunction t, const char[] ident, OutBuffer* buf, HdrGenState* hgs, bool isStatic)
3528 {
3529     if (t.inuse)
3530     {
3531         t.inuse = 2; // flag error to caller
3532         return;
3533     }
3534     t.inuse++;
3535     if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen)
3536     {
3537         linkageToBuffer(buf, t.linkage);
3538         buf.writeByte(' ');
3539     }
3540     if (t.linkage == LINK.objc && isStatic)
3541         buf.write("static ");
3542     if (t.next)
3543     {
3544         typeToBuffer(t.next, null, buf, hgs);
3545         if (ident)
3546             buf.writeByte(' ');
3547     }
3548     else if (hgs.ddoc)
3549         buf.writestring("auto ");
3550     if (ident)
3551         buf.writestring(ident);
3552     parametersToBuffer(t.parameterList, buf, hgs);
3553     /* Use postfix style for attributes
3554      */
3555     if (t.mod)
3556     {
3557         buf.writeByte(' ');
3558         MODtoBuffer(buf, t.mod);
3559     }
3560 
3561     void dg(string str)
3562     {
3563         buf.writeByte(' ');
3564         buf.writestring(str);
3565     }
3566     t.attributesApply(&dg);
3567 
3568     t.inuse--;
3569 }
3570 
visitFuncIdentWithPrefix(TypeFunction t,const Identifier ident,TemplateDeclaration td,OutBuffer * buf,HdrGenState * hgs)3571 private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, TemplateDeclaration td,
3572     OutBuffer* buf, HdrGenState* hgs)
3573 {
3574     if (t.inuse)
3575     {
3576         t.inuse = 2; // flag error to caller
3577         return;
3578     }
3579     t.inuse++;
3580 
3581     /* Use 'storage class' (prefix) style for attributes
3582      */
3583     if (t.mod)
3584     {
3585         MODtoBuffer(buf, t.mod);
3586         buf.writeByte(' ');
3587     }
3588 
3589     void ignoreReturn(string str)
3590     {
3591         if (str != "return")
3592         {
3593             // don't write 'ref' for ctors
3594             if ((ident == Id.ctor) && str == "ref")
3595                 return;
3596             buf.writestring(str);
3597             buf.writeByte(' ');
3598         }
3599     }
3600     t.attributesApply(&ignoreReturn);
3601 
3602     if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen)
3603     {
3604         linkageToBuffer(buf, t.linkage);
3605         buf.writeByte(' ');
3606     }
3607     if (ident && ident.toHChars2() != ident.toChars())
3608     {
3609         // Don't print return type for ctor, dtor, unittest, etc
3610     }
3611     else if (t.next)
3612     {
3613         typeToBuffer(t.next, null, buf, hgs);
3614         if (ident)
3615             buf.writeByte(' ');
3616     }
3617     else if (hgs.ddoc)
3618         buf.writestring("auto ");
3619     if (ident)
3620         buf.writestring(ident.toHChars2());
3621     if (td)
3622     {
3623         buf.writeByte('(');
3624         foreach (i, p; *td.origParameters)
3625         {
3626             if (i)
3627                 buf.writestring(", ");
3628             p.templateParameterToBuffer(buf, hgs);
3629         }
3630         buf.writeByte(')');
3631     }
3632     parametersToBuffer(t.parameterList, buf, hgs);
3633     if (t.isreturn)
3634     {
3635         buf.writestring(" return");
3636     }
3637     t.inuse--;
3638 }
3639 
3640 
initializerToBuffer(Initializer inx,OutBuffer * buf,HdrGenState * hgs)3641 private void initializerToBuffer(Initializer inx, OutBuffer* buf, HdrGenState* hgs)
3642 {
3643     void visitError(ErrorInitializer iz)
3644     {
3645         buf.writestring("__error__");
3646     }
3647 
3648     void visitVoid(VoidInitializer iz)
3649     {
3650         buf.writestring("void");
3651     }
3652 
3653     void visitStruct(StructInitializer si)
3654     {
3655         //printf("StructInitializer::toCBuffer()\n");
3656         buf.writeByte('{');
3657         foreach (i, const id; si.field)
3658         {
3659             if (i)
3660                 buf.writestring(", ");
3661             if (id)
3662             {
3663                 buf.writestring(id.toString());
3664                 buf.writeByte(':');
3665             }
3666             if (auto iz = si.value[i])
3667                 initializerToBuffer(iz, buf, hgs);
3668         }
3669         buf.writeByte('}');
3670     }
3671 
3672     void visitArray(ArrayInitializer ai)
3673     {
3674         buf.writeByte('[');
3675         foreach (i, ex; ai.index)
3676         {
3677             if (i)
3678                 buf.writestring(", ");
3679             if (ex)
3680             {
3681                 ex.expressionToBuffer(buf, hgs);
3682                 buf.writeByte(':');
3683             }
3684             if (auto iz = ai.value[i])
3685                 initializerToBuffer(iz, buf, hgs);
3686         }
3687         buf.writeByte(']');
3688     }
3689 
3690     void visitExp(ExpInitializer ei)
3691     {
3692         ei.exp.expressionToBuffer(buf, hgs);
3693     }
3694 
3695     void visitC(CInitializer ci)
3696     {
3697         buf.writeByte('{');
3698         foreach (i, ref DesigInit di; ci.initializerList)
3699         {
3700             if (i)
3701                 buf.writestring(", ");
3702             if (di.designatorList)
3703             {
3704                 foreach (ref Designator d; (*di.designatorList)[])
3705                 {
3706                     if (d.exp)
3707                     {
3708                         buf.writeByte('[');
3709                         toCBuffer(d.exp, buf, hgs);
3710                         buf.writeByte(']');
3711                     }
3712                     else
3713                     {
3714                         buf.writeByte('.');
3715                         buf.writestring(d.ident.toString());
3716                     }
3717                 }
3718                 buf.writeByte('=');
3719             }
3720             initializerToBuffer(di.initializer, buf, hgs);
3721         }
3722         buf.writeByte('}');
3723     }
3724 
3725     final switch (inx.kind)
3726     {
3727         case InitKind.error:   return visitError (inx.isErrorInitializer ());
3728         case InitKind.void_:   return visitVoid  (inx.isVoidInitializer  ());
3729         case InitKind.struct_: return visitStruct(inx.isStructInitializer());
3730         case InitKind.array:   return visitArray (inx.isArrayInitializer ());
3731         case InitKind.exp:     return visitExp   (inx.isExpInitializer   ());
3732         case InitKind.C_:      return visitC     (inx.isCInitializer     ());
3733     }
3734 }
3735 
3736 
typeToBufferx(Type t,OutBuffer * buf,HdrGenState * hgs)3737 private void typeToBufferx(Type t, OutBuffer* buf, HdrGenState* hgs)
3738 {
3739     void visitType(Type t)
3740     {
3741         printf("t = %p, ty = %d\n", t, t.ty);
3742         assert(0);
3743     }
3744 
3745     void visitError(TypeError t)
3746     {
3747         buf.writestring("_error_");
3748     }
3749 
3750     void visitBasic(TypeBasic t)
3751     {
3752         //printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod);
3753         buf.writestring(t.dstring);
3754     }
3755 
3756     void visitTraits(TypeTraits t)
3757     {
3758         //printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod);
3759         t.exp.expressionToBuffer(buf, hgs);
3760     }
3761 
3762     void visitVector(TypeVector t)
3763     {
3764         //printf("TypeVector::toCBuffer2(t.mod = %d)\n", t.mod);
3765         buf.writestring("__vector(");
3766         visitWithMask(t.basetype, t.mod, buf, hgs);
3767         buf.writestring(")");
3768     }
3769 
3770     void visitSArray(TypeSArray t)
3771     {
3772         visitWithMask(t.next, t.mod, buf, hgs);
3773         buf.writeByte('[');
3774         sizeToBuffer(t.dim, buf, hgs);
3775         buf.writeByte(']');
3776     }
3777 
3778     void visitDArray(TypeDArray t)
3779     {
3780         Type ut = t.castMod(0);
3781         if (hgs.declstring)
3782             goto L1;
3783         if (ut.equals(Type.tstring))
3784             buf.writestring("string");
3785         else if (ut.equals(Type.twstring))
3786             buf.writestring("wstring");
3787         else if (ut.equals(Type.tdstring))
3788             buf.writestring("dstring");
3789         else
3790         {
3791         L1:
3792             visitWithMask(t.next, t.mod, buf, hgs);
3793             buf.writestring("[]");
3794         }
3795     }
3796 
3797     void visitAArray(TypeAArray t)
3798     {
3799         visitWithMask(t.next, t.mod, buf, hgs);
3800         buf.writeByte('[');
3801         visitWithMask(t.index, 0, buf, hgs);
3802         buf.writeByte(']');
3803     }
3804 
3805     void visitPointer(TypePointer t)
3806     {
3807         //printf("TypePointer::toCBuffer2() next = %d\n", t.next.ty);
3808         if (t.next.ty == Tfunction)
3809             visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "function", buf, hgs, false);
3810         else
3811         {
3812             visitWithMask(t.next, t.mod, buf, hgs);
3813             buf.writeByte('*');
3814         }
3815     }
3816 
3817     void visitReference(TypeReference t)
3818     {
3819         visitWithMask(t.next, t.mod, buf, hgs);
3820         buf.writeByte('&');
3821     }
3822 
3823     void visitFunction(TypeFunction t)
3824     {
3825         //printf("TypeFunction::toCBuffer2() t = %p, ref = %d\n", t, t.isref);
3826         visitFuncIdentWithPostfix(t, null, buf, hgs, false);
3827     }
3828 
3829     void visitDelegate(TypeDelegate t)
3830     {
3831         visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "delegate", buf, hgs, false);
3832     }
3833 
3834     void visitTypeQualifiedHelper(TypeQualified t)
3835     {
3836         foreach (id; t.idents)
3837         {
3838             if (id.dyncast() == DYNCAST.dsymbol)
3839             {
3840                 buf.writeByte('.');
3841                 TemplateInstance ti = cast(TemplateInstance)id;
3842                 ti.dsymbolToBuffer(buf, hgs);
3843             }
3844             else if (id.dyncast() == DYNCAST.expression)
3845             {
3846                 buf.writeByte('[');
3847                 (cast(Expression)id).expressionToBuffer(buf, hgs);
3848                 buf.writeByte(']');
3849             }
3850             else if (id.dyncast() == DYNCAST.type)
3851             {
3852                 buf.writeByte('[');
3853                 typeToBufferx(cast(Type)id, buf, hgs);
3854                 buf.writeByte(']');
3855             }
3856             else
3857             {
3858                 buf.writeByte('.');
3859                 buf.writestring(id.toString());
3860             }
3861         }
3862     }
3863 
3864     void visitIdentifier(TypeIdentifier t)
3865     {
3866         buf.writestring(t.ident.toString());
3867         visitTypeQualifiedHelper(t);
3868     }
3869 
3870     void visitInstance(TypeInstance t)
3871     {
3872         t.tempinst.dsymbolToBuffer(buf, hgs);
3873         visitTypeQualifiedHelper(t);
3874     }
3875 
3876     void visitTypeof(TypeTypeof t)
3877     {
3878         buf.writestring("typeof(");
3879         t.exp.expressionToBuffer(buf, hgs);
3880         buf.writeByte(')');
3881         visitTypeQualifiedHelper(t);
3882     }
3883 
3884     void visitReturn(TypeReturn t)
3885     {
3886         buf.writestring("typeof(return)");
3887         visitTypeQualifiedHelper(t);
3888     }
3889 
3890     void visitEnum(TypeEnum t)
3891     {
3892         buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars());
3893     }
3894 
3895     void visitStruct(TypeStruct t)
3896     {
3897         // https://issues.dlang.org/show_bug.cgi?id=13776
3898         // Don't use ti.toAlias() to avoid forward reference error
3899         // while printing messages.
3900         TemplateInstance ti = t.sym.parent ? t.sym.parent.isTemplateInstance() : null;
3901         if (ti && ti.aliasdecl == t.sym)
3902             buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars());
3903         else
3904             buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars());
3905     }
3906 
3907     void visitClass(TypeClass t)
3908     {
3909         // https://issues.dlang.org/show_bug.cgi?id=13776
3910         // Don't use ti.toAlias() to avoid forward reference error
3911         // while printing messages.
3912         TemplateInstance ti = t.sym.parent ? t.sym.parent.isTemplateInstance() : null;
3913         if (ti && ti.aliasdecl == t.sym)
3914             buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars());
3915         else
3916             buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars());
3917     }
3918 
3919     void visitTag(TypeTag t)
3920     {
3921         buf.writestring(Token.toChars(t.tok));
3922         buf.writeByte(' ');
3923         if (t.id)
3924             buf.writestring(t.id.toChars());
3925         if (t.tok == TOK.enum_ && t.base.ty != TY.Tint32)
3926         {
3927             buf.writestring(" : ");
3928             visitWithMask(t.base, t.mod, buf, hgs);
3929         }
3930     }
3931 
3932     void visitTuple(TypeTuple t)
3933     {
3934         parametersToBuffer(ParameterList(t.arguments, VarArg.none), buf, hgs);
3935     }
3936 
3937     void visitSlice(TypeSlice t)
3938     {
3939         visitWithMask(t.next, t.mod, buf, hgs);
3940         buf.writeByte('[');
3941         sizeToBuffer(t.lwr, buf, hgs);
3942         buf.writestring(" .. ");
3943         sizeToBuffer(t.upr, buf, hgs);
3944         buf.writeByte(']');
3945     }
3946 
3947     void visitNull(TypeNull t)
3948     {
3949         buf.writestring("typeof(null)");
3950     }
3951 
3952     void visitMixin(TypeMixin t)
3953     {
3954         buf.writestring("mixin(");
3955         argsToBuffer(t.exps, buf, hgs, null);
3956         buf.writeByte(')');
3957     }
3958 
3959     void visitNoreturn(TypeNoreturn t)
3960     {
3961         buf.writestring("noreturn");
3962     }
3963 
3964 
3965     switch (t.ty)
3966     {
3967         default:        return t.isTypeBasic() ?
3968                                 visitBasic(cast(TypeBasic)t) :
3969                                 visitType(t);
3970 
3971         case Terror:     return visitError(cast(TypeError)t);
3972         case Ttraits:    return visitTraits(cast(TypeTraits)t);
3973         case Tvector:    return visitVector(cast(TypeVector)t);
3974         case Tsarray:    return visitSArray(cast(TypeSArray)t);
3975         case Tarray:     return visitDArray(cast(TypeDArray)t);
3976         case Taarray:    return visitAArray(cast(TypeAArray)t);
3977         case Tpointer:   return visitPointer(cast(TypePointer)t);
3978         case Treference: return visitReference(cast(TypeReference)t);
3979         case Tfunction:  return visitFunction(cast(TypeFunction)t);
3980         case Tdelegate:  return visitDelegate(cast(TypeDelegate)t);
3981         case Tident:     return visitIdentifier(cast(TypeIdentifier)t);
3982         case Tinstance:  return visitInstance(cast(TypeInstance)t);
3983         case Ttypeof:    return visitTypeof(cast(TypeTypeof)t);
3984         case Treturn:    return visitReturn(cast(TypeReturn)t);
3985         case Tenum:      return visitEnum(cast(TypeEnum)t);
3986         case Tstruct:    return visitStruct(cast(TypeStruct)t);
3987         case Tclass:     return visitClass(cast(TypeClass)t);
3988         case Ttuple:     return visitTuple (cast(TypeTuple)t);
3989         case Tslice:     return visitSlice(cast(TypeSlice)t);
3990         case Tnull:      return visitNull(cast(TypeNull)t);
3991         case Tmixin:     return visitMixin(cast(TypeMixin)t);
3992         case Tnoreturn:  return visitNoreturn(cast(TypeNoreturn)t);
3993         case Ttag:       return visitTag(cast(TypeTag)t);
3994     }
3995 }
3996 
3997 /****************************************
3998  * Convert EXP to char*.
3999  */
4000 
EXPtoString(EXP op)4001 string EXPtoString(EXP op)
4002 {
4003     static immutable char*[EXP.max + 1] strings =
4004     [
4005         EXP.type : "type",
4006         EXP.error : "error",
4007         EXP.objcClassReference : "class",
4008 
4009         EXP.typeof_ : "typeof",
4010         EXP.mixin_ : "mixin",
4011 
4012         EXP.import_ : "import",
4013         EXP.dotVariable : "dotvar",
4014         EXP.scope_ : "scope",
4015         EXP.identifier : "identifier",
4016         EXP.this_ : "this",
4017         EXP.super_ : "super",
4018         EXP.int64 : "long",
4019         EXP.float64 : "double",
4020         EXP.complex80 : "creal",
4021         EXP.null_ : "null",
4022         EXP.string_ : "string",
4023         EXP.arrayLiteral : "arrayliteral",
4024         EXP.assocArrayLiteral : "assocarrayliteral",
4025         EXP.classReference : "classreference",
4026         EXP.file : "__FILE__",
4027         EXP.fileFullPath : "__FILE_FULL_PATH__",
4028         EXP.line : "__LINE__",
4029         EXP.moduleString : "__MODULE__",
4030         EXP.functionString : "__FUNCTION__",
4031         EXP.prettyFunction : "__PRETTY_FUNCTION__",
4032         EXP.typeid_ : "typeid",
4033         EXP.is_ : "is",
4034         EXP.assert_ : "assert",
4035         EXP.halt : "halt",
4036         EXP.template_ : "template",
4037         EXP.dSymbol : "symbol",
4038         EXP.function_ : "function",
4039         EXP.variable : "var",
4040         EXP.symbolOffset : "symoff",
4041         EXP.structLiteral : "structLiteral",
4042         EXP.compoundLiteral : "compoundliteral",
4043         EXP.arrayLength : "arraylength",
4044         EXP.delegatePointer : "delegateptr",
4045         EXP.delegateFunctionPointer : "delegatefuncptr",
4046         EXP.remove : "remove",
4047         EXP.tuple : "tuple",
4048         EXP.traits : "__traits",
4049         EXP.default_ : "default",
4050         EXP.overloadSet : "__overloadset",
4051         EXP.void_ : "void",
4052         EXP.vectorArray : "vectorarray",
4053         EXP._Generic : "_Generic",
4054 
4055         // post
4056         EXP.dotTemplateInstance : "dotti",
4057         EXP.dotIdentifier : "dotid",
4058         EXP.dotTemplateDeclaration : "dottd",
4059         EXP.dot : ".",
4060         EXP.dotType : "dottype",
4061         EXP.plusPlus : "++",
4062         EXP.minusMinus : "--",
4063         EXP.prePlusPlus : "++",
4064         EXP.preMinusMinus : "--",
4065         EXP.call : "call",
4066         EXP.slice : "..",
4067         EXP.array : "[]",
4068         EXP.index : "[i]",
4069 
4070         EXP.delegate_ : "delegate",
4071         EXP.address : "&",
4072         EXP.star : "*",
4073         EXP.negate : "-",
4074         EXP.uadd : "+",
4075         EXP.not : "!",
4076         EXP.tilde : "~",
4077         EXP.delete_ : "delete",
4078         EXP.new_ : "new",
4079         EXP.newAnonymousClass : "newanonclass",
4080         EXP.cast_ : "cast",
4081 
4082         EXP.vector : "__vector",
4083         EXP.pow : "^^",
4084 
4085         EXP.mul : "*",
4086         EXP.div : "/",
4087         EXP.mod : "%",
4088 
4089         EXP.add : "+",
4090         EXP.min : "-",
4091         EXP.concatenate : "~",
4092 
4093         EXP.leftShift : "<<",
4094         EXP.rightShift : ">>",
4095         EXP.unsignedRightShift : ">>>",
4096 
4097         EXP.lessThan : "<",
4098         EXP.lessOrEqual : "<=",
4099         EXP.greaterThan : ">",
4100         EXP.greaterOrEqual : ">=",
4101         EXP.in_ : "in",
4102 
4103         EXP.equal : "==",
4104         EXP.notEqual : "!=",
4105         EXP.identity : "is",
4106         EXP.notIdentity : "!is",
4107 
4108         EXP.and : "&",
4109         EXP.xor : "^",
4110         EXP.or : "|",
4111 
4112         EXP.andAnd : "&&",
4113         EXP.orOr : "||",
4114 
4115         EXP.question : "?",
4116 
4117         EXP.assign : "=",
4118         EXP.construct : "=",
4119         EXP.blit : "=",
4120         EXP.addAssign : "+=",
4121         EXP.minAssign : "-=",
4122         EXP.concatenateAssign : "~=",
4123         EXP.concatenateElemAssign : "~=",
4124         EXP.concatenateDcharAssign : "~=",
4125         EXP.mulAssign : "*=",
4126         EXP.divAssign : "/=",
4127         EXP.modAssign : "%=",
4128         EXP.powAssign : "^^=",
4129         EXP.leftShiftAssign : "<<=",
4130         EXP.rightShiftAssign : ">>=",
4131         EXP.unsignedRightShiftAssign : ">>>=",
4132         EXP.andAssign : "&=",
4133         EXP.orAssign : "|=",
4134         EXP.xorAssign : "^=",
4135 
4136         EXP.comma : ",",
4137         EXP.declaration : "declaration",
4138 
4139         EXP.interval : "interval",
4140     ];
4141     const p = strings[op];
4142     if (!p)
4143     {
4144         printf("error: EXP %d has no string\n", op);
4145         return "XXXXX";
4146         //assert(0);
4147     }
4148     assert(p);
4149     return p[0 .. strlen(p)];
4150 }
4151