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