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