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