2 * Generate $(LINK2 https://dlang.org/dmd-windows.html#interface-files, D interface files).
4 * Also used to convert AST nodes to D code in general, e.g. for error messages or `printf` debugging.
6 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/hdrgen.d, _hdrgen.d)
10 * Documentation: https://dlang.org/phobos/dmd_hdrgen.html
11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/hdrgen.d
16 import core.stdc.ctype;
17 import core.stdc.stdio;
18 import core.stdc.string;
21 import dmd.arraytypes;
27 import dmd.declaration;
36 import dmd.expression;
40 import dmd.identifier;
45 import dmd.root.complex;
46 import dmd.root.ctfloat;
47 import dmd.common.outbuffer;
48 import dmd.root.rootobject;
49 import dmd.root.string;
51 import dmd.staticassert;
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
63 bool fullQual; /// fully qualify types when printing
69 bool declstring; // set while declaring alias for string,wstring or dstring
70 EnumDeclaration inEnumDecl;
73 enum TEST_EMIT_ALL = 0;
75 extern (C++) void genhdrfile(Module m)
79 buf.printf("// D import file generated from '%s'", m.srcfile.toChars());
83 toCBuffer(m, &buf, &hgs);
84 writeFile(m.loc, m.hdrfile.toString(), buf[]);
88 * Dumps the full contents of module `m` to `buf`.
90 * buf = buffer to write to.
91 * m = module to visit all members of.
93 extern (C++) void moduleToBuffer(OutBuffer* buf, Module m)
97 toCBuffer(m, buf, &hgs);
100 void moduleToBuffer2(Module m, OutBuffer* buf, HdrGenState* hgs)
104 if (m.userAttribDecl)
106 buf.writestring("@(");
107 argsToBuffer(m.userAttribDecl.atts, buf, hgs);
111 if (m.md.isdeprecated)
115 buf.writestring("deprecated(");
116 m.md.msg.expressionToBuffer(buf, hgs);
117 buf.writestring(") ");
120 buf.writestring("deprecated ");
122 buf.writestring("module ");
123 buf.writestring(m.md.toChars());
128 foreach (s; *m.members)
130 s.dsymbolToBuffer(buf, hgs);
134 private void statementToBuffer(Statement s, OutBuffer* buf, HdrGenState* hgs)
136 scope v = new StatementPrettyPrintVisitor(buf, hgs);
140 private extern (C++) final class StatementPrettyPrintVisitor : Visitor
142 alias visit = Visitor.visit;
147 extern (D) this(OutBuffer* buf, HdrGenState* hgs)
153 override void visit(Statement s)
155 buf.writestring("Statement::toCBuffer()");
160 override void visit(ErrorStatement s)
162 buf.writestring("__error__");
166 override void visit(ExpStatement s)
168 if (s.exp && s.exp.op == EXP.declaration &&
169 (cast(DeclarationExp)s.exp).declaration)
171 // bypass visit(DeclarationExp)
172 (cast(DeclarationExp)s.exp).declaration.dsymbolToBuffer(buf, hgs);
176 s.exp.expressionToBuffer(buf, hgs);
178 if (!hgs.forStmtInit)
182 override void visit(CompileStatement s)
184 buf.writestring("mixin(");
185 argsToBuffer(s.exps, buf, hgs, null);
186 buf.writestring(");");
187 if (!hgs.forStmtInit)
191 override void visit(CompoundStatement s)
193 foreach (sx; *s.statements)
200 override void visit(CompoundDeclarationStatement s)
202 bool anywritten = false;
203 foreach (sx; *s.statements)
205 auto ds = sx ? sx.isExpStatement() : null;
206 if (ds && ds.exp.op == EXP.declaration)
208 auto d = (cast(DeclarationExp)ds.exp).declaration;
209 assert(d.isDeclaration());
210 if (auto v = d.isVarDeclaration())
212 scope ppv = new DsymbolPrettyPrintVisitor(buf, hgs);
213 ppv.visitVarDecl(v, anywritten);
216 d.dsymbolToBuffer(buf, hgs);
221 if (!hgs.forStmtInit)
225 override void visit(UnrolledLoopStatement s)
227 buf.writestring("/*unrolled*/ {");
230 foreach (sx; *s.statements)
240 override void visit(ScopeStatement s)
246 s.statement.accept(this);
252 override void visit(WhileStatement s)
254 buf.writestring("while (");
255 if (auto p = s.param)
257 // Print condition assignment
258 StorageClass stc = p.storageClass;
261 if (stcToBuffer(buf, stc))
264 typeToBuffer(p.type, p.ident, buf, hgs);
266 buf.writestring(p.ident.toString());
267 buf.writestring(" = ");
269 s.condition.expressionToBuffer(buf, hgs);
273 s._body.accept(this);
276 override void visit(DoStatement s)
278 buf.writestring("do");
281 s._body.accept(this);
282 buf.writestring("while (");
283 s.condition.expressionToBuffer(buf, hgs);
284 buf.writestring(");");
288 override void visit(ForStatement s)
290 buf.writestring("for (");
294 s._init.accept(this);
302 s.condition.expressionToBuffer(buf, hgs);
308 s.increment.expressionToBuffer(buf, hgs);
316 s._body.accept(this);
322 private void foreachWithoutBody(ForeachStatement s)
324 buf.writestring(Token.toString(s.op));
325 buf.writestring(" (");
326 foreach (i, p; *s.parameters)
329 buf.writestring(", ");
330 if (stcToBuffer(buf, p.storageClass))
333 typeToBuffer(p.type, p.ident, buf, hgs);
335 buf.writestring(p.ident.toString());
337 buf.writestring("; ");
338 s.aggr.expressionToBuffer(buf, hgs);
343 override void visit(ForeachStatement s)
345 foreachWithoutBody(s);
350 s._body.accept(this);
356 private void foreachRangeWithoutBody(ForeachRangeStatement s)
358 buf.writestring(Token.toString(s.op));
359 buf.writestring(" (");
361 typeToBuffer(s.prm.type, s.prm.ident, buf, hgs);
363 buf.writestring(s.prm.ident.toString());
364 buf.writestring("; ");
365 s.lwr.expressionToBuffer(buf, hgs);
366 buf.writestring(" .. ");
367 s.upr.expressionToBuffer(buf, hgs);
372 override void visit(ForeachRangeStatement s)
374 foreachRangeWithoutBody(s);
379 s._body.accept(this);
385 override void visit(StaticForeachStatement s)
387 buf.writestring("static ");
394 assert(s.sfe.rangefe);
395 visit(s.sfe.rangefe);
399 override void visit(ForwardingStatement s)
401 s.statement.accept(this);
404 override void visit(IfStatement s)
406 buf.writestring("if (");
407 if (Parameter p = s.prm)
409 StorageClass stc = p.storageClass;
412 if (stcToBuffer(buf, stc))
415 typeToBuffer(p.type, p.ident, buf, hgs);
417 buf.writestring(p.ident.toString());
418 buf.writestring(" = ");
420 s.condition.expressionToBuffer(buf, hgs);
423 if (s.ifbody.isScopeStatement())
425 s.ifbody.accept(this);
430 s.ifbody.accept(this);
435 buf.writestring("else");
436 if (!s.elsebody.isIfStatement())
444 if (s.elsebody.isScopeStatement() || s.elsebody.isIfStatement())
446 s.elsebody.accept(this);
451 s.elsebody.accept(this);
457 override void visit(ConditionalStatement s)
459 s.condition.conditionToBuffer(buf, hgs);
465 s.ifbody.accept(this);
471 buf.writestring("else");
476 s.elsebody.accept(this);
483 override void visit(PragmaStatement s)
485 buf.writestring("pragma (");
486 buf.writestring(s.ident.toString());
487 if (s.args && s.args.length)
489 buf.writestring(", ");
490 argsToBuffer(s.args, buf, hgs);
499 s._body.accept(this);
511 override void visit(StaticAssertStatement s)
513 s.sa.dsymbolToBuffer(buf, hgs);
516 override void visit(SwitchStatement s)
518 buf.writestring(s.isFinal ? "final switch (" : "switch (");
519 s.condition.expressionToBuffer(buf, hgs);
524 if (!s._body.isScopeStatement())
529 s._body.accept(this);
536 s._body.accept(this);
541 override void visit(CaseStatement s)
543 buf.writestring("case ");
544 s.exp.expressionToBuffer(buf, hgs);
547 s.statement.accept(this);
550 override void visit(CaseRangeStatement s)
552 buf.writestring("case ");
553 s.first.expressionToBuffer(buf, hgs);
554 buf.writestring(": .. case ");
555 s.last.expressionToBuffer(buf, hgs);
558 s.statement.accept(this);
561 override void visit(DefaultStatement s)
563 buf.writestring("default:");
565 s.statement.accept(this);
568 override void visit(GotoDefaultStatement s)
570 buf.writestring("goto default;");
574 override void visit(GotoCaseStatement s)
576 buf.writestring("goto case");
580 s.exp.expressionToBuffer(buf, hgs);
586 override void visit(SwitchErrorStatement s)
588 buf.writestring("SwitchErrorStatement::toCBuffer()");
592 override void visit(ReturnStatement s)
594 buf.writestring("return ");
596 s.exp.expressionToBuffer(buf, hgs);
601 override void visit(BreakStatement s)
603 buf.writestring("break");
607 buf.writestring(s.ident.toString());
613 override void visit(ContinueStatement s)
615 buf.writestring("continue");
619 buf.writestring(s.ident.toString());
625 override void visit(SynchronizedStatement s)
627 buf.writestring("synchronized");
631 s.exp.expressionToBuffer(buf, hgs);
637 s._body.accept(this);
641 override void visit(WithStatement s)
643 buf.writestring("with (");
644 s.exp.expressionToBuffer(buf, hgs);
645 buf.writestring(")");
648 s._body.accept(this);
651 override void visit(TryCatchStatement s)
653 buf.writestring("try");
657 if (s._body.isScopeStatement())
659 s._body.accept(this);
664 s._body.accept(this);
668 foreach (c; *s.catches)
674 override void visit(TryFinallyStatement s)
676 buf.writestring("try");
681 s._body.accept(this);
685 buf.writestring("finally");
687 if (s.finalbody.isScopeStatement())
689 s.finalbody.accept(this);
694 s.finalbody.accept(this);
699 override void visit(ScopeGuardStatement s)
701 buf.writestring(Token.toString(s.tok));
704 s.statement.accept(this);
707 override void visit(ThrowStatement s)
709 buf.writestring("throw ");
710 s.exp.expressionToBuffer(buf, hgs);
715 override void visit(DebugStatement s)
719 s.statement.accept(this);
723 override void visit(GotoStatement s)
725 buf.writestring("goto ");
726 buf.writestring(s.ident.toString());
731 override void visit(LabelStatement s)
733 buf.writestring(s.ident.toString());
737 s.statement.accept(this);
740 override void visit(AsmStatement s)
742 buf.writestring("asm { ");
747 buf.writestring(t.toChars());
749 t.value != TOK.min &&
750 t.value != TOK.comma && t.next.value != TOK.comma &&
751 t.value != TOK.leftBracket && t.next.value != TOK.leftBracket &&
752 t.next.value != TOK.rightBracket &&
753 t.value != TOK.leftParenthesis && t.next.value != TOK.leftParenthesis &&
754 t.next.value != TOK.rightParenthesis &&
755 t.value != TOK.dot && t.next.value != TOK.dot)
762 buf.writestring("; }");
766 override void visit(ImportStatement s)
768 foreach (imp; *s.imports)
770 imp.dsymbolToBuffer(buf, hgs);
776 buf.writestring("catch");
780 typeToBuffer(c.type, c.ident, buf, hgs);
788 c.handler.accept(this);
795 private void dsymbolToBuffer(Dsymbol s, OutBuffer* buf, HdrGenState* hgs)
797 scope v = new DsymbolPrettyPrintVisitor(buf, hgs);
801 private extern (C++) final class DsymbolPrettyPrintVisitor : Visitor
803 alias visit = Visitor.visit;
808 extern (D) this(OutBuffer* buf, HdrGenState* hgs)
814 ////////////////////////////////////////////////////////////////////////////
816 override void visit(Dsymbol s)
818 buf.writestring(s.toChars());
821 override void visit(StaticAssert s)
823 buf.writestring(s.kind());
825 s.exp.expressionToBuffer(buf, hgs);
828 foreach (m; (*s.msgs)[])
830 buf.writestring(", ");
831 m.expressionToBuffer(buf, hgs);
834 buf.writestring(");");
838 override void visit(DebugSymbol s)
840 buf.writestring("debug = ");
842 buf.writestring(s.ident.toString());
849 override void visit(VersionSymbol s)
851 buf.writestring("version = ");
853 buf.writestring(s.ident.toString());
860 override void visit(EnumMember em)
863 typeToBuffer(em.type, em.ident, buf, hgs);
865 buf.writestring(em.ident.toString());
868 buf.writestring(" = ");
869 em.value.expressionToBuffer(buf, hgs);
873 override void visit(Import imp)
875 if (hgs.hdrgen && imp.id == Id.object)
876 return; // object is imported by default
878 buf.writestring("static ");
879 buf.writestring("import ");
882 buf.printf("%s = ", imp.aliasId.toChars());
884 foreach (const pid; imp.packages)
886 buf.printf("%s.", pid.toChars());
888 buf.writestring(imp.id.toString());
889 if (imp.names.length)
891 buf.writestring(" : ");
892 foreach (const i, const name; imp.names)
895 buf.writestring(", ");
896 const _alias = imp.aliases[i];
898 buf.printf("%s = %s", _alias.toChars(), name.toChars());
900 buf.writestring(name.toChars());
907 override void visit(AliasThis d)
909 buf.writestring("alias ");
910 buf.writestring(d.ident.toString());
911 buf.writestring(" this;\n");
914 override void visit(AttribDeclaration d)
917 if (auto stcd = d.isStorageClassDeclaration)
919 hasSTC = stcToBuffer(buf, stcd.stc);
928 if (d.decl.length == 0 || (hgs.hdrgen && d.decl.length == 1 && (*d.decl)[0].isUnitTestDeclaration()))
930 // hack for bugzilla 8081
931 if (hasSTC) buf.writeByte(' ');
932 buf.writestring("{}");
934 else if (d.decl.length == 1)
936 if (hasSTC) buf.writeByte(' ');
937 (*d.decl)[0].accept(this);
946 foreach (de; *d.decl)
954 override void visit(StorageClassDeclaration d)
956 visit(cast(AttribDeclaration)d);
959 override void visit(DeprecatedDeclaration d)
961 buf.writestring("deprecated(");
962 d.msg.expressionToBuffer(buf, hgs);
963 buf.writestring(") ");
964 visit(cast(AttribDeclaration)d);
967 override void visit(LinkDeclaration d)
969 buf.writestring("extern (");
970 buf.writestring(linkageToString(d.linkage));
971 buf.writestring(") ");
972 visit(cast(AttribDeclaration)d);
975 override void visit(CPPMangleDeclaration d)
978 final switch (d.cppmangle)
980 case CPPMANGLE.asClass:
983 case CPPMANGLE.asStruct:
989 buf.writestring("extern (C++, ");
991 buf.writestring(") ");
992 visit(cast(AttribDeclaration)d);
995 override void visit(VisibilityDeclaration d)
997 visibilityToBuffer(buf, d.visibility);
998 AttribDeclaration ad = cast(AttribDeclaration)d;
999 if (ad.decl.length <= 1)
1001 if (ad.decl.length == 1 && (*ad.decl)[0].isVisibilityDeclaration)
1002 visit(cast(AttribDeclaration)(*ad.decl)[0]);
1004 visit(cast(AttribDeclaration)d);
1007 override void visit(AlignDeclaration d)
1011 foreach (i, exp; (*d.exps)[])
1015 buf.printf("align (%s)", exp.toChars());
1017 if (d.decl && d.decl.length < 2)
1021 buf.writestring("align ");
1023 visit(d.isAttribDeclaration());
1026 override void visit(AnonDeclaration d)
1028 buf.writestring(d.isunion ? "union" : "struct");
1030 buf.writestring("{");
1035 foreach (de; *d.decl)
1039 buf.writestring("}");
1043 override void visit(PragmaDeclaration d)
1045 buf.writestring("pragma (");
1046 buf.writestring(d.ident.toString());
1047 if (d.args && d.args.length)
1049 buf.writestring(", ");
1050 argsToBuffer(d.args, buf, hgs);
1055 // https://issues.dlang.org/show_bug.cgi?id=14690
1056 // Unconditionally perform a full output dump
1057 // for `pragma(inline)` declarations.
1058 bool savedFullDump = global.params.dihdr.fullOutput;
1059 if (d.ident == Id.Pinline)
1060 global.params.dihdr.fullOutput = true;
1062 visit(cast(AttribDeclaration)d);
1063 global.params.dihdr.fullOutput = savedFullDump;
1066 override void visit(ConditionalDeclaration d)
1068 d.condition.conditionToBuffer(buf, hgs);
1069 if (d.decl || d.elsedecl)
1077 foreach (de; *d.decl)
1085 buf.writestring("else");
1090 foreach (de; *d.elsedecl)
1101 override void visit(StaticForeachDeclaration s)
1103 void foreachWithoutBody(ForeachStatement s)
1105 buf.writestring(Token.toString(s.op));
1106 buf.writestring(" (");
1107 foreach (i, p; *s.parameters)
1110 buf.writestring(", ");
1111 if (stcToBuffer(buf, p.storageClass))
1114 typeToBuffer(p.type, p.ident, buf, hgs);
1116 buf.writestring(p.ident.toString());
1118 buf.writestring("; ");
1119 s.aggr.expressionToBuffer(buf, hgs);
1124 void foreachRangeWithoutBody(ForeachRangeStatement s)
1126 /* s.op ( prm ; lwr .. upr )
1128 buf.writestring(Token.toString(s.op));
1129 buf.writestring(" (");
1131 typeToBuffer(s.prm.type, s.prm.ident, buf, hgs);
1133 buf.writestring(s.prm.ident.toString());
1134 buf.writestring("; ");
1135 s.lwr.expressionToBuffer(buf, hgs);
1136 buf.writestring(" .. ");
1137 s.upr.expressionToBuffer(buf, hgs);
1142 buf.writestring("static ");
1145 foreachWithoutBody(s.sfe.aggrfe);
1149 assert(s.sfe.rangefe);
1150 foreachRangeWithoutBody(s.sfe.rangefe);
1155 visit(cast(AttribDeclaration)s);
1162 override void visit(CompileDeclaration d)
1164 buf.writestring("mixin(");
1165 argsToBuffer(d.exps, buf, hgs, null);
1166 buf.writestring(");");
1170 override void visit(UserAttributeDeclaration d)
1172 buf.writestring("@(");
1173 argsToBuffer(d.atts, buf, hgs);
1175 visit(cast(AttribDeclaration)d);
1178 override void visit(TemplateDeclaration d)
1182 // Should handle template functions for doc generation
1183 if (onemember && onemember.isFuncDeclaration())
1184 buf.writestring("foo ");
1186 if ((hgs.hdrgen || hgs.fullDump) && visitEponymousMember(d))
1189 buf.writestring(d.kind());
1191 buf.writestring("template");
1193 buf.writestring(d.ident.toString());
1195 visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters);
1197 visitTemplateConstraint(d.constraint);
1198 if (hgs.hdrgen || hgs.fullDump)
1205 foreach (s; *d.members)
1214 bool visitEponymousMember(TemplateDeclaration d)
1216 if (!d.members || d.members.length != 1)
1218 Dsymbol onemember = (*d.members)[0];
1219 if (onemember.ident != d.ident)
1221 if (FuncDeclaration fd = onemember.isFuncDeclaration())
1224 if (stcToBuffer(buf, fd.storage_class))
1226 functionToBufferFull(cast(TypeFunction)fd.type, buf, d.ident, hgs, d);
1227 visitTemplateConstraint(d.constraint);
1233 if (AggregateDeclaration ad = onemember.isAggregateDeclaration())
1235 buf.writestring(ad.kind());
1237 buf.writestring(ad.ident.toString());
1239 visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters);
1241 visitTemplateConstraint(d.constraint);
1242 visitBaseClasses(ad.isClassDeclaration());
1250 foreach (s; *ad.members)
1261 if (VarDeclaration vd = onemember.isVarDeclaration())
1265 if (stcToBuffer(buf, vd.storage_class))
1268 typeToBuffer(vd.type, vd.ident, buf, hgs);
1270 buf.writestring(vd.ident.toString());
1272 visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters);
1276 buf.writestring(" = ");
1277 ExpInitializer ie = vd._init.isExpInitializer();
1278 if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit))
1279 (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs);
1281 vd._init.initializerToBuffer(buf, hgs);
1290 void visitTemplateParameters(TemplateParameters* parameters)
1292 if (!parameters || !parameters.length)
1294 foreach (i, p; *parameters)
1297 buf.writestring(", ");
1298 p.templateParameterToBuffer(buf, hgs);
1302 void visitTemplateConstraint(Expression constraint)
1306 buf.writestring(" if (");
1307 constraint.expressionToBuffer(buf, hgs);
1311 override void visit(TemplateInstance ti)
1313 buf.writestring(ti.name.toChars());
1314 tiargsToBuffer(ti, buf, hgs);
1319 dumpTemplateInstance(ti, buf, hgs);
1323 override void visit(TemplateMixin tm)
1325 buf.writestring("mixin ");
1326 typeToBuffer(tm.tqual, null, buf, hgs);
1327 tiargsToBuffer(tm, buf, hgs);
1328 if (tm.ident && memcmp(tm.ident.toChars(), cast(const(char)*)"__mixin", 7) != 0)
1331 buf.writestring(tm.ident.toString());
1336 dumpTemplateInstance(tm, buf, hgs);
1339 override void visit(EnumDeclaration d)
1341 auto oldInEnumDecl = hgs.inEnumDecl;
1342 scope(exit) hgs.inEnumDecl = oldInEnumDecl;
1344 buf.writestring("enum ");
1347 buf.writestring(d.ident.toString());
1351 buf.writestring(" : ");
1352 typeToBuffer(d.memtype, null, buf, hgs);
1364 foreach (em; *d.members)
1377 override void visit(Nspace d)
1379 buf.writestring("extern (C++, ");
1380 buf.writestring(d.ident.toString());
1386 foreach (s; *d.members)
1393 override void visit(StructDeclaration d)
1395 buf.writestring(d.kind());
1397 if (!d.isAnonymous())
1398 buf.writestring(d.toChars());
1409 foreach (s; *d.members)
1416 override void visit(ClassDeclaration d)
1418 if (!d.isAnonymous())
1420 buf.writestring(d.kind());
1422 buf.writestring(d.ident.toString());
1424 visitBaseClasses(d);
1431 foreach (s; *d.members)
1441 void visitBaseClasses(ClassDeclaration d)
1443 if (!d || !d.baseclasses.length)
1445 if (!d.isAnonymous())
1446 buf.writestring(" : ");
1447 foreach (i, b; *d.baseclasses)
1450 buf.writestring(", ");
1451 typeToBuffer(b.type, null, buf, hgs);
1455 override void visit(AliasDeclaration d)
1457 if (d.storage_class & STC.local)
1459 buf.writestring("alias ");
1462 buf.writestring(d.ident.toString());
1463 buf.writestring(" = ");
1464 if (stcToBuffer(buf, d.storage_class))
1467 https://issues.dlang.org/show_bug.cgi?id=23223
1468 https://issues.dlang.org/show_bug.cgi?id=23222
1469 This special case (initially just for modules) avoids some segfaults
1470 and nicer -vcg-ast output.
1472 if (d.aliassym.isModule())
1474 buf.writestring(d.aliassym.ident.toString());
1478 d.aliassym.accept(this);
1481 else if (d.type.ty == Tfunction)
1483 if (stcToBuffer(buf, d.storage_class))
1485 typeToBuffer(d.type, d.ident, buf, hgs);
1489 hgs.declstring = (d.ident == Id.string || d.ident == Id.wstring || d.ident == Id.dstring);
1490 buf.writestring(d.ident.toString());
1491 buf.writestring(" = ");
1492 if (stcToBuffer(buf, d.storage_class))
1494 typeToBuffer(d.type, null, buf, hgs);
1495 hgs.declstring = false;
1501 override void visit(AliasAssign d)
1503 buf.writestring(d.ident.toString());
1504 buf.writestring(" = ");
1506 d.aliassym.accept(this);
1508 typeToBuffer(d.type, null, buf, hgs);
1513 override void visit(VarDeclaration d)
1515 if (d.storage_class & STC.local)
1517 visitVarDecl(d, false);
1522 void visitVarDecl(VarDeclaration v, bool anywritten)
1526 buf.writestring(", ");
1527 buf.writestring(v.ident.toString());
1531 if (stcToBuffer(buf, v.storage_class))
1534 typeToBuffer(v.type, v.ident, buf, hgs);
1536 buf.writestring(v.ident.toString());
1540 buf.writestring(" = ");
1541 auto ie = v._init.isExpInitializer();
1542 if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit))
1543 (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs);
1545 v._init.initializerToBuffer(buf, hgs);
1549 override void visit(FuncDeclaration f)
1551 //printf("FuncDeclaration::toCBuffer() '%s'\n", f.toChars());
1552 if (stcToBuffer(buf, f.storage_class))
1554 auto tf = cast(TypeFunction)f.type;
1555 typeToBuffer(tf, f.ident, buf, hgs);
1559 // if the return type is missing (e.g. ref functions or auto)
1560 if (!tf.next || f.storage_class & STC.auto_)
1566 else if (hgs.tpltMember == 0 && global.params.dihdr.fullOutput == false && !hgs.insideFuncBody)
1570 // this can happen on interfaces / abstract functions, see `allowsContractWithoutBody`
1571 if (f.fensures || f.frequires)
1573 contractsToBuffer(f);
1585 /// Returns: whether `do` is needed to write the function body
1586 bool contractsToBuffer(FuncDeclaration f)
1588 bool requireDo = false;
1592 foreach (frequire; *f.frequires)
1594 buf.writestring("in");
1595 if (auto es = frequire.isExpStatement())
1597 assert(es.exp && es.exp.op == EXP.assert_);
1598 buf.writestring(" (");
1599 (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs);
1607 frequire.statementToBuffer(buf, hgs);
1615 foreach (fensure; *f.fensures)
1617 buf.writestring("out");
1618 if (auto es = fensure.ensure.isExpStatement())
1620 assert(es.exp && es.exp.op == EXP.assert_);
1621 buf.writestring(" (");
1624 buf.writestring(fensure.id.toString());
1626 buf.writestring("; ");
1627 (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs);
1637 buf.writestring(fensure.id.toString());
1641 fensure.ensure.statementToBuffer(buf, hgs);
1649 void bodyToBuffer(FuncDeclaration f)
1651 if (!f.fbody || (hgs.hdrgen && global.params.dihdr.fullOutput == false && !hgs.autoMember && !hgs.tpltMember && !hgs.insideFuncBody))
1653 if (!f.fbody && (f.fensures || f.frequires))
1656 contractsToBuffer(f);
1663 // there is no way to know if a function is nested
1664 // or not after parsing. We need scope information
1665 // for that, which is avaible during semantic
1666 // analysis. To overcome that, a simple mechanism
1667 // is implemented: everytime we print a function
1668 // body (templated or not) we increment a counter.
1669 // We decredement the counter when we stop
1670 // printing the function body.
1671 ++hgs.insideFuncBody;
1672 scope(exit) { --hgs.insideFuncBody; }
1674 const savetlpt = hgs.tpltMember;
1675 const saveauto = hgs.autoMember;
1679 bool requireDo = contractsToBuffer(f);
1683 buf.writestring("do");
1689 f.fbody.statementToBuffer(buf, hgs);
1693 hgs.tpltMember = savetlpt;
1694 hgs.autoMember = saveauto;
1697 override void visit(FuncLiteralDeclaration f)
1699 if (f.type.ty == Terror)
1701 buf.writestring("__error");
1704 if (f.tok != TOK.reserved)
1706 buf.writestring(f.kind());
1709 TypeFunction tf = cast(TypeFunction)f.type;
1711 if (!f.inferRetType && tf.next)
1712 typeToBuffer(tf.next, null, buf, hgs);
1713 parametersToBuffer(tf.parameterList, buf, hgs);
1715 // https://issues.dlang.org/show_bug.cgi?id=20074
1716 void printAttribute(string str)
1719 buf.writestring(str);
1721 tf.attributesApply(&printAttribute);
1724 CompoundStatement cs = f.fbody.isCompoundStatement();
1726 if (f.semanticRun >= PASS.semantic3done && cs)
1728 s1 = (*cs.statements)[cs.statements.length - 1];
1731 s1 = !cs ? f.fbody : null;
1732 ReturnStatement rs = s1 ? s1.endsWithReturnStatement() : null;
1735 buf.writestring(" => ");
1736 rs.exp.expressionToBuffer(buf, hgs);
1746 override void visit(PostBlitDeclaration d)
1748 if (stcToBuffer(buf, d.storage_class))
1750 buf.writestring("this(this)");
1754 override void visit(DtorDeclaration d)
1756 if (stcToBuffer(buf, d.storage_class))
1758 buf.writestring("~this()");
1762 override void visit(StaticCtorDeclaration d)
1764 if (stcToBuffer(buf, d.storage_class & ~STC.static_))
1766 if (d.isSharedStaticCtorDeclaration())
1767 buf.writestring("shared ");
1768 buf.writestring("static this()");
1769 if (hgs.hdrgen && !hgs.tpltMember)
1778 override void visit(StaticDtorDeclaration d)
1780 if (stcToBuffer(buf, d.storage_class & ~STC.static_))
1782 if (d.isSharedStaticDtorDeclaration())
1783 buf.writestring("shared ");
1784 buf.writestring("static ~this()");
1785 if (hgs.hdrgen && !hgs.tpltMember)
1794 override void visit(InvariantDeclaration d)
1798 if (stcToBuffer(buf, d.storage_class))
1800 buf.writestring("invariant");
1801 if(auto es = d.fbody.isExpStatement())
1803 assert(es.exp && es.exp.op == EXP.assert_);
1804 buf.writestring(" (");
1805 (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs);
1806 buf.writestring(");");
1815 override void visit(UnitTestDeclaration d)
1819 if (stcToBuffer(buf, d.storage_class))
1821 buf.writestring("unittest");
1825 override void visit(BitFieldDeclaration d)
1827 if (stcToBuffer(buf, d.storage_class))
1829 Identifier id = d.isAnonymous() ? null : d.ident;
1830 typeToBuffer(d.type, id, buf, hgs);
1831 buf.writestring(" : ");
1832 d.width.expressionToBuffer(buf, hgs);
1837 override void visit(NewDeclaration d)
1839 if (stcToBuffer(buf, d.storage_class & ~STC.static_))
1841 buf.writestring("new();");
1844 override void visit(Module m)
1846 moduleToBuffer2(m, buf, hgs);
1850 /*********************************************
1851 * Print expression to buffer.
1853 private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hgs)
1855 void visit(Expression e)
1857 buf.writestring(EXPtoString(e.op));
1860 void visitInteger(IntegerExp e)
1862 const dinteger_t v = e.toInteger();
1871 TypeEnum te = cast(TypeEnum)t;
1873 if (sym && sym.members && (!hgs.inEnumDecl || hgs.inEnumDecl != sym))
1875 foreach (em; *sym.members)
1877 if ((cast(EnumMember)em).value.toInteger == v)
1879 buf.printf("%s.%s", sym.toChars(), em.ident.toChars());
1885 buf.printf("cast(%s)", te.sym.toChars());
1893 const o = buf.length;
1894 writeSingleCharLiteral(*buf, cast(dchar) v);
1896 escapeDdocString(buf, o);
1900 buf.writestring("cast(byte)");
1903 buf.writestring("cast(short)");
1907 buf.printf("%d", cast(int)v);
1910 buf.writestring("cast(ubyte)");
1913 buf.writestring("cast(ushort)");
1916 buf.printf("%uu", cast(uint)v);
1921 // https://issues.dlang.org/show_bug.cgi?id=23173
1922 // This is a special case because - is not part of the
1923 // integer literal and 9223372036854775808L overflows a long
1924 buf.writestring("cast(long)-9223372036854775808");
1928 buf.printf("%lldL", v);
1932 buf.printf("%lluLU", v);
1935 buf.writestring(v ? "true" : "false");
1938 buf.writestring("cast(");
1939 buf.writestring(t.toChars());
1941 if (target.ptrsize == 8)
1943 else if (target.ptrsize == 4 ||
1944 target.ptrsize == 2)
1950 buf.writestring("cast(void)0");
1954 /* This can happen if errors, such as
1955 * the type is painted on like in fromConstInitializer().
1964 else if (v & 0x8000000000000000L)
1965 buf.printf("0x%llx", v);
1970 void visitError(ErrorExp e)
1972 buf.writestring("__error");
1975 void visitVoidInit(VoidInitExp e)
1977 buf.writestring("__void");
1980 void floatToBuffer(Type type, real_t value)
1982 .floatToBuffer(type, value, buf, hgs.hdrgen);
1985 void visitReal(RealExp e)
1987 floatToBuffer(e.type, e.value);
1990 void visitComplex(ComplexExp e)
1996 floatToBuffer(e.type, creall(e.value));
1998 floatToBuffer(e.type, cimagl(e.value));
1999 buf.writestring("i)");
2002 void visitIdentifier(IdentifierExp e)
2004 if (hgs.hdrgen || hgs.ddoc)
2005 buf.writestring(e.ident.toHChars2());
2007 buf.writestring(e.ident.toString());
2010 void visitDsymbol(DsymbolExp e)
2012 buf.writestring(e.s.toChars());
2015 void visitThis(ThisExp e)
2017 buf.writestring("this");
2020 void visitSuper(SuperExp e)
2022 buf.writestring("super");
2025 void visitNull(NullExp e)
2027 buf.writestring("null");
2030 void visitString(StringExp e)
2033 const o = buf.length;
2034 foreach (i; 0 .. e.len)
2036 writeCharLiteral(*buf, e.getCodeUnit(i));
2039 escapeDdocString(buf, o);
2042 buf.writeByte(e.postfix);
2045 void visitArrayLiteral(ArrayLiteralExp e)
2048 argsToBuffer(e.elements, buf, hgs, e.basis);
2052 void visitAssocArrayLiteral(AssocArrayLiteralExp e)
2055 foreach (i, key; *e.keys)
2058 buf.writestring(", ");
2059 expToBuffer(key, PREC.assign, buf, hgs);
2061 auto value = (*e.values)[i];
2062 expToBuffer(value, PREC.assign, buf, hgs);
2067 void visitStructLiteral(StructLiteralExp e)
2069 buf.writestring(e.sd.toChars());
2071 // CTFE can generate struct literals that contain an AddrExp pointing
2072 // to themselves, need to avoid infinite recursion:
2073 // struct S { this(int){ this.s = &this; } S* s; }
2074 // const foo = new S(0);
2075 if (e.stageflags & stageToCBuffer)
2076 buf.writestring("<recursion>");
2079 const old = e.stageflags;
2080 e.stageflags |= stageToCBuffer;
2081 argsToBuffer(e.elements, buf, hgs);
2087 void visitCompoundLiteral(CompoundLiteralExp e)
2090 typeToBuffer(e.type, null, buf, hgs);
2092 e.initializer.initializerToBuffer(buf, hgs);
2095 void visitType(TypeExp e)
2097 typeToBuffer(e.type, null, buf, hgs);
2100 void visitScope(ScopeExp e)
2102 if (e.sds.isTemplateInstance())
2104 e.sds.dsymbolToBuffer(buf, hgs);
2106 else if (hgs !is null && hgs.ddoc)
2109 if (auto m = e.sds.isModule())
2110 buf.writestring(m.md.toChars());
2112 buf.writestring(e.sds.toChars());
2116 buf.writestring(e.sds.kind());
2118 buf.writestring(e.sds.toChars());
2122 void visitTemplate(TemplateExp e)
2124 buf.writestring(e.td.toChars());
2127 void visitNew(NewExp e)
2131 expToBuffer(e.thisexp, PREC.primary, buf, hgs);
2134 buf.writestring("new ");
2135 typeToBuffer(e.newtype, null, buf, hgs);
2136 if (e.arguments && e.arguments.length)
2139 argsToBuffer(e.arguments, buf, hgs);
2144 void visitNewAnonClass(NewAnonClassExp e)
2148 expToBuffer(e.thisexp, PREC.primary, buf, hgs);
2151 buf.writestring("new");
2152 buf.writestring(" class ");
2153 if (e.arguments && e.arguments.length)
2156 argsToBuffer(e.arguments, buf, hgs);
2160 e.cd.dsymbolToBuffer(buf, hgs);
2163 void visitSymOff(SymOffExp e)
2166 buf.printf("(& %s%+lld)", e.var.toChars(), e.offset);
2167 else if (e.var.isTypeInfoDeclaration())
2168 buf.writestring(e.var.toChars());
2170 buf.printf("& %s", e.var.toChars());
2173 void visitVar(VarExp e)
2175 buf.writestring(e.var.toChars());
2178 void visitOver(OverExp e)
2180 buf.writestring(e.vars.ident.toString());
2183 void visitTuple(TupleExp e)
2188 e.e0.expressionPrettyPrint(buf, hgs);
2189 buf.writestring(", tuple(");
2190 argsToBuffer(e.exps, buf, hgs);
2191 buf.writestring("))");
2195 buf.writestring("tuple(");
2196 argsToBuffer(e.exps, buf, hgs);
2201 void visitFunc(FuncExp e)
2203 e.fd.dsymbolToBuffer(buf, hgs);
2204 //buf.writestring(e.fd.toChars());
2207 void visitDeclaration(DeclarationExp e)
2209 /* Normal dmd execution won't reach here - regular variable declarations
2210 * are handled in visit(ExpStatement), so here would be used only when
2211 * we'll directly call Expression.toChars() for debugging.
2215 if (auto var = e.declaration.isVarDeclaration())
2217 // For debugging use:
2218 // - Avoid printing newline.
2219 // - Intentionally use the format (Type var;)
2220 // which isn't correct as regular D code.
2223 scope v = new DsymbolPrettyPrintVisitor(buf, hgs);
2224 v.visitVarDecl(var, false);
2229 else e.declaration.dsymbolToBuffer(buf, hgs);
2233 void visitTypeid(TypeidExp e)
2235 buf.writestring("typeid(");
2236 objectToBuffer(e.obj, buf, hgs);
2240 void visitTraits(TraitsExp e)
2242 buf.writestring("__traits(");
2244 buf.writestring(e.ident.toString());
2247 foreach (arg; *e.args)
2249 buf.writestring(", ");
2250 objectToBuffer(arg, buf, hgs);
2256 void visitHalt(HaltExp e)
2258 buf.writestring("halt");
2261 void visitIs(IsExp e)
2263 buf.writestring("is(");
2264 typeToBuffer(e.targ, e.id, buf, hgs);
2265 if (e.tok2 != TOK.reserved)
2267 buf.printf(" %s %s", Token.toChars(e.tok), Token.toChars(e.tok2));
2271 if (e.tok == TOK.colon)
2272 buf.writestring(" : ");
2274 buf.writestring(" == ");
2275 typeToBuffer(e.tspec, null, buf, hgs);
2277 if (e.parameters && e.parameters.length)
2279 buf.writestring(", ");
2280 scope v = new DsymbolPrettyPrintVisitor(buf, hgs);
2281 v.visitTemplateParameters(e.parameters);
2286 void visitUna(UnaExp e)
2288 buf.writestring(EXPtoString(e.op));
2289 expToBuffer(e.e1, precedence[e.op], buf, hgs);
2292 void visitBin(BinExp e)
2294 expToBuffer(e.e1, precedence[e.op], buf, hgs);
2296 buf.writestring(EXPtoString(e.op));
2298 expToBuffer(e.e2, cast(PREC)(precedence[e.op] + 1), buf, hgs);
2301 void visitComma(CommaExp e)
2303 // CommaExp is generated by the compiler so it shouldn't
2304 // appear in error messages or header files.
2305 // For now, this treats the case where the compiler
2306 // generates CommaExp for temporaries by calling
2307 // the `sideeffect.copyToTemp` function.
2308 auto ve = e.e2.isVarExp();
2310 // not a CommaExp introduced for temporaries, go on
2312 if (!ve || !(ve.var.storage_class & STC.temp))
2314 visitBin(cast(BinExp)e);
2318 // CommaExp that contain temporaries inserted via
2319 // `copyToTemp` are usually of the form
2320 // ((T __temp = exp), __tmp).
2321 // Asserts are here to easily spot
2322 // missing cases where CommaExp
2323 // are used for other constructs
2324 auto vd = ve.var.isVarDeclaration();
2325 assert(vd && vd._init);
2327 if (auto ei = vd._init.isExpInitializer())
2329 Expression commaExtract;
2331 if (auto ce = exp.isConstructExp())
2332 commaExtract = ce.e2;
2333 else if (auto se = exp.isStructLiteralExp())
2338 expToBuffer(commaExtract, precedence[exp.op], buf, hgs);
2343 // not one of the known cases, go on the old path
2344 visitBin(cast(BinExp)e);
2348 void visitMixin(MixinExp e)
2350 buf.writestring("mixin(");
2351 argsToBuffer(e.exps, buf, hgs, null);
2355 void visitImport(ImportExp e)
2357 buf.writestring("import(");
2358 expToBuffer(e.e1, PREC.assign, buf, hgs);
2362 void visitAssert(AssertExp e)
2364 buf.writestring("assert(");
2365 expToBuffer(e.e1, PREC.assign, buf, hgs);
2368 buf.writestring(", ");
2369 expToBuffer(e.msg, PREC.assign, buf, hgs);
2374 void visitThrow(ThrowExp e)
2376 buf.writestring("throw ");
2377 expToBuffer(e.e1, PREC.unary, buf, hgs);
2380 void visitDotId(DotIdExp e)
2382 expToBuffer(e.e1, PREC.primary, buf, hgs);
2384 buf.writestring("->");
2387 buf.writestring(e.ident.toString());
2390 void visitDotTemplate(DotTemplateExp e)
2392 expToBuffer(e.e1, PREC.primary, buf, hgs);
2394 buf.writestring(e.td.toChars());
2397 void visitDotVar(DotVarExp e)
2399 expToBuffer(e.e1, PREC.primary, buf, hgs);
2401 buf.writestring(e.var.toChars());
2404 void visitDotTemplateInstance(DotTemplateInstanceExp e)
2406 expToBuffer(e.e1, PREC.primary, buf, hgs);
2408 e.ti.dsymbolToBuffer(buf, hgs);
2411 void visitDelegate(DelegateExp e)
2414 if (!e.func.isNested() || e.func.needThis())
2416 expToBuffer(e.e1, PREC.primary, buf, hgs);
2419 buf.writestring(e.func.toChars());
2422 void visitDotType(DotTypeExp e)
2424 expToBuffer(e.e1, PREC.primary, buf, hgs);
2426 buf.writestring(e.sym.toChars());
2429 void visitCall(CallExp e)
2431 if (e.e1.op == EXP.type)
2433 /* Avoid parens around type to prevent forbidden cast syntax:
2435 * This is ok since types in constructor calls
2436 * can never depend on parens anyway
2438 e.e1.expressionPrettyPrint(buf, hgs);
2441 expToBuffer(e.e1, precedence[e.op], buf, hgs);
2443 argsToBuffer(e.arguments, buf, hgs);
2447 void visitPtr(PtrExp e)
2450 expToBuffer(e.e1, precedence[e.op], buf, hgs);
2453 void visitDelete(DeleteExp e)
2455 buf.writestring("delete ");
2456 expToBuffer(e.e1, precedence[e.op], buf, hgs);
2459 void visitCast(CastExp e)
2461 buf.writestring("cast(");
2463 typeToBuffer(e.to, null, buf, hgs);
2466 MODtoBuffer(buf, e.mod);
2469 expToBuffer(e.e1, precedence[e.op], buf, hgs);
2472 void visitVector(VectorExp e)
2474 buf.writestring("cast(");
2475 typeToBuffer(e.to, null, buf, hgs);
2477 expToBuffer(e.e1, precedence[e.op], buf, hgs);
2480 void visitVectorArray(VectorArrayExp e)
2482 expToBuffer(e.e1, PREC.primary, buf, hgs);
2483 buf.writestring(".array");
2486 void visitSlice(SliceExp e)
2488 expToBuffer(e.e1, precedence[e.op], buf, hgs);
2493 sizeToBuffer(e.lwr, buf, hgs);
2496 buf.writestring("..");
2498 sizeToBuffer(e.upr, buf, hgs);
2505 void visitArrayLength(ArrayLengthExp e)
2507 expToBuffer(e.e1, PREC.primary, buf, hgs);
2508 buf.writestring(".length");
2511 void visitInterval(IntervalExp e)
2513 expToBuffer(e.lwr, PREC.assign, buf, hgs);
2514 buf.writestring("..");
2515 expToBuffer(e.upr, PREC.assign, buf, hgs);
2518 void visitDelegatePtr(DelegatePtrExp e)
2520 expToBuffer(e.e1, PREC.primary, buf, hgs);
2521 buf.writestring(".ptr");
2524 void visitDelegateFuncptr(DelegateFuncptrExp e)
2526 expToBuffer(e.e1, PREC.primary, buf, hgs);
2527 buf.writestring(".funcptr");
2530 void visitArray(ArrayExp e)
2532 expToBuffer(e.e1, PREC.primary, buf, hgs);
2534 argsToBuffer(e.arguments, buf, hgs);
2538 void visitDot(DotExp e)
2540 expToBuffer(e.e1, PREC.primary, buf, hgs);
2542 expToBuffer(e.e2, PREC.primary, buf, hgs);
2545 void visitIndex(IndexExp e)
2547 expToBuffer(e.e1, PREC.primary, buf, hgs);
2549 sizeToBuffer(e.e2, buf, hgs);
2553 void visitPost(PostExp e)
2555 expToBuffer(e.e1, precedence[e.op], buf, hgs);
2556 buf.writestring(EXPtoString(e.op));
2559 void visitPre(PreExp e)
2561 buf.writestring(EXPtoString(e.op));
2562 expToBuffer(e.e1, precedence[e.op], buf, hgs);
2565 void visitRemove(RemoveExp e)
2567 expToBuffer(e.e1, PREC.primary, buf, hgs);
2568 buf.writestring(".remove(");
2569 expToBuffer(e.e2, PREC.assign, buf, hgs);
2573 void visitCond(CondExp e)
2575 expToBuffer(e.econd, PREC.oror, buf, hgs);
2576 buf.writestring(" ? ");
2577 expToBuffer(e.e1, PREC.expr, buf, hgs);
2578 buf.writestring(" : ");
2579 expToBuffer(e.e2, PREC.cond, buf, hgs);
2582 void visitDefaultInit(DefaultInitExp e)
2584 buf.writestring(EXPtoString(e.op));
2587 void visitClassReference(ClassReferenceExp e)
2589 buf.writestring(e.value.toChars());
2595 if (auto be = e.isBinExp())
2596 return visitBin(be);
2597 else if (auto ue = e.isUnaExp())
2598 return visitUna(ue);
2599 else if (auto de = e.isDefaultInitExp())
2600 return visitDefaultInit(e.isDefaultInitExp());
2603 case EXP.int64: return visitInteger(e.isIntegerExp());
2604 case EXP.error: return visitError(e.isErrorExp());
2605 case EXP.void_: return visitVoidInit(e.isVoidInitExp());
2606 case EXP.float64: return visitReal(e.isRealExp());
2607 case EXP.complex80: return visitComplex(e.isComplexExp());
2608 case EXP.identifier: return visitIdentifier(e.isIdentifierExp());
2609 case EXP.dSymbol: return visitDsymbol(e.isDsymbolExp());
2610 case EXP.this_: return visitThis(e.isThisExp());
2611 case EXP.super_: return visitSuper(e.isSuperExp());
2612 case EXP.null_: return visitNull(e.isNullExp());
2613 case EXP.string_: return visitString(e.isStringExp());
2614 case EXP.arrayLiteral: return visitArrayLiteral(e.isArrayLiteralExp());
2615 case EXP.assocArrayLiteral: return visitAssocArrayLiteral(e.isAssocArrayLiteralExp());
2616 case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp());
2617 case EXP.compoundLiteral: return visitCompoundLiteral(e.isCompoundLiteralExp());
2618 case EXP.type: return visitType(e.isTypeExp());
2619 case EXP.scope_: return visitScope(e.isScopeExp());
2620 case EXP.template_: return visitTemplate(e.isTemplateExp());
2621 case EXP.new_: return visitNew(e.isNewExp());
2622 case EXP.newAnonymousClass: return visitNewAnonClass(e.isNewAnonClassExp());
2623 case EXP.symbolOffset: return visitSymOff(e.isSymOffExp());
2624 case EXP.variable: return visitVar(e.isVarExp());
2625 case EXP.overloadSet: return visitOver(e.isOverExp());
2626 case EXP.tuple: return visitTuple(e.isTupleExp());
2627 case EXP.function_: return visitFunc(e.isFuncExp());
2628 case EXP.declaration: return visitDeclaration(e.isDeclarationExp());
2629 case EXP.typeid_: return visitTypeid(e.isTypeidExp());
2630 case EXP.traits: return visitTraits(e.isTraitsExp());
2631 case EXP.halt: return visitHalt(e.isHaltExp());
2632 case EXP.is_: return visitIs(e.isExp());
2633 case EXP.comma: return visitComma(e.isCommaExp());
2634 case EXP.mixin_: return visitMixin(e.isMixinExp());
2635 case EXP.import_: return visitImport(e.isImportExp());
2636 case EXP.assert_: return visitAssert(e.isAssertExp());
2637 case EXP.throw_: return visitThrow(e.isThrowExp());
2638 case EXP.dotIdentifier: return visitDotId(e.isDotIdExp());
2639 case EXP.dotTemplateDeclaration: return visitDotTemplate(e.isDotTemplateExp());
2640 case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
2641 case EXP.dotTemplateInstance: return visitDotTemplateInstance(e.isDotTemplateInstanceExp());
2642 case EXP.delegate_: return visitDelegate(e.isDelegateExp());
2643 case EXP.dotType: return visitDotType(e.isDotTypeExp());
2644 case EXP.call: return visitCall(e.isCallExp());
2645 case EXP.star: return visitPtr(e.isPtrExp());
2646 case EXP.delete_: return visitDelete(e.isDeleteExp());
2647 case EXP.cast_: return visitCast(e.isCastExp());
2648 case EXP.vector: return visitVector(e.isVectorExp());
2649 case EXP.vectorArray: return visitVectorArray(e.isVectorArrayExp());
2650 case EXP.slice: return visitSlice(e.isSliceExp());
2651 case EXP.arrayLength: return visitArrayLength(e.isArrayLengthExp());
2652 case EXP.interval: return visitInterval(e.isIntervalExp());
2653 case EXP.delegatePointer: return visitDelegatePtr(e.isDelegatePtrExp());
2654 case EXP.delegateFunctionPointer: return visitDelegateFuncptr(e.isDelegateFuncptrExp());
2655 case EXP.array: return visitArray(e.isArrayExp());
2656 case EXP.dot: return visitDot(e.isDotExp());
2657 case EXP.index: return visitIndex(e.isIndexExp());
2658 case EXP.minusMinus:
2659 case EXP.plusPlus: return visitPost(e.isPostExp());
2660 case EXP.preMinusMinus:
2661 case EXP.prePlusPlus: return visitPre(e.isPreExp());
2662 case EXP.remove: return visitRemove(e.isRemoveExp());
2663 case EXP.question: return visitCond(e.isCondExp());
2664 case EXP.classReference: return visitClassReference(e.isClassReferenceExp());
2669 * Formats `value` as a literal of type `type` into `buf`.
2672 * type = literal type (e.g. Tfloat)
2673 * value = value to print
2674 * buf = target buffer
2675 * allowHex = whether hex floating point literals may be used
2676 * for greater accuracy
2678 void floatToBuffer(Type type, const real_t value, OutBuffer* buf, const bool allowHex)
2680 /** sizeof(value)*3 is because each byte of mantissa is max
2681 of 256 (3 characters). The string will be "-M.MMMMe-4932".
2682 (ie, 8 chars more than mantissa). Plus one for trailing \0.
2683 Plus one for rounding. */
2684 const(size_t) BUFFER_LEN = value.sizeof * 3 + 8 + 1 + 1;
2685 char[BUFFER_LEN] buffer = void;
2686 CTFloat.sprint(buffer.ptr, 'g', value);
2687 assert(strlen(buffer.ptr) < BUFFER_LEN);
2691 real_t r = CTFloat.parse(buffer.ptr, isOutOfRange);
2692 //assert(!isOutOfRange); // test/compilable/test22725.c asserts here
2693 if (r != value) // if exact duplication
2694 CTFloat.sprint(buffer.ptr, 'a', value);
2696 buf.writestring(buffer.ptr);
2697 if (buffer.ptr[strlen(buffer.ptr) - 1] == '.')
2698 buf.remove(buf.length() - 1, 1);
2702 Type t = type.toBasetype();
2718 if (t.isimaginary())
2723 private void templateParameterToBuffer(TemplateParameter tp, OutBuffer* buf, HdrGenState* hgs)
2725 scope v = new TemplateParameterPrettyPrintVisitor(buf, hgs);
2729 private extern (C++) final class TemplateParameterPrettyPrintVisitor : Visitor
2731 alias visit = Visitor.visit;
2736 extern (D) this(OutBuffer* buf, HdrGenState* hgs)
2742 override void visit(TemplateTypeParameter tp)
2744 buf.writestring(tp.ident.toString());
2747 buf.writestring(" : ");
2748 typeToBuffer(tp.specType, null, buf, hgs);
2752 buf.writestring(" = ");
2753 typeToBuffer(tp.defaultType, null, buf, hgs);
2757 override void visit(TemplateThisParameter tp)
2759 buf.writestring("this ");
2760 visit(cast(TemplateTypeParameter)tp);
2763 override void visit(TemplateAliasParameter tp)
2765 buf.writestring("alias ");
2767 typeToBuffer(tp.specType, tp.ident, buf, hgs);
2769 buf.writestring(tp.ident.toString());
2772 buf.writestring(" : ");
2773 objectToBuffer(tp.specAlias, buf, hgs);
2775 if (tp.defaultAlias)
2777 buf.writestring(" = ");
2778 objectToBuffer(tp.defaultAlias, buf, hgs);
2782 override void visit(TemplateValueParameter tp)
2784 typeToBuffer(tp.valType, tp.ident, buf, hgs);
2787 buf.writestring(" : ");
2788 tp.specValue.expressionToBuffer(buf, hgs);
2790 if (tp.defaultValue)
2792 buf.writestring(" = ");
2793 tp.defaultValue.expressionToBuffer(buf, hgs);
2797 override void visit(TemplateTupleParameter tp)
2799 buf.writestring(tp.ident.toString());
2800 buf.writestring("...");
2804 private void conditionToBuffer(Condition c, OutBuffer* buf, HdrGenState* hgs)
2806 scope v = new ConditionPrettyPrintVisitor(buf, hgs);
2810 private extern (C++) final class ConditionPrettyPrintVisitor : Visitor
2812 alias visit = Visitor.visit;
2817 extern (D) this(OutBuffer* buf, HdrGenState* hgs)
2823 override void visit(DebugCondition c)
2825 buf.writestring("debug (");
2827 buf.writestring(c.ident.toString());
2833 override void visit(VersionCondition c)
2835 buf.writestring("version (");
2837 buf.writestring(c.ident.toString());
2843 override void visit(StaticIfCondition c)
2845 buf.writestring("static if (");
2846 c.exp.expressionToBuffer(buf, hgs);
2851 void toCBuffer(const Statement s, OutBuffer* buf, HdrGenState* hgs)
2853 scope v = new StatementPrettyPrintVisitor(buf, hgs);
2854 (cast() s).accept(v);
2857 void toCBuffer(const Type t, OutBuffer* buf, const Identifier ident, HdrGenState* hgs)
2859 typeToBuffer(cast() t, ident, buf, hgs);
2862 void toCBuffer(Dsymbol s, OutBuffer* buf, HdrGenState* hgs)
2864 scope v = new DsymbolPrettyPrintVisitor(buf, hgs);
2868 // used from TemplateInstance::toChars() and TemplateMixin::toChars()
2869 void toCBufferInstance(const TemplateInstance ti, OutBuffer* buf, bool qualifyTypes = false)
2872 hgs.fullQual = qualifyTypes;
2873 scope v = new DsymbolPrettyPrintVisitor(buf, &hgs);
2877 void toCBuffer(const Initializer iz, OutBuffer* buf, HdrGenState* hgs)
2879 initializerToBuffer(cast() iz, buf, hgs);
2882 bool stcToBuffer(OutBuffer* buf, StorageClass stc)
2884 //printf("stc: %llx\n", stc);
2885 bool result = false;
2887 if (stc & STC.scopeinferred)
2889 //buf.writestring("scope-inferred ");
2890 stc &= ~(STC.scope_ | STC.scopeinferred);
2892 if (stc & STC.returninferred)
2894 //buf.writestring((stc & STC.returnScope) ? "return-scope-inferred " : "return-ref-inferred ");
2895 stc &= ~(STC.return_ | STC.returninferred);
2898 /* Put scope ref return into a standard order
2901 const isout = (stc & STC.out_) != 0;
2902 //printf("bsr = %d %llx\n", buildScopeRef(stc), stc);
2903 final switch (buildScopeRef(stc))
2906 case ScopeRef.Scope:
2908 case ScopeRef.Return:
2911 case ScopeRef.ReturnScope: rrs = "return scope"; goto L1;
2912 case ScopeRef.ReturnRef: rrs = isout ? "return out" : "return ref"; goto L1;
2913 case ScopeRef.RefScope: rrs = isout ? "out scope" : "ref scope"; goto L1;
2914 case ScopeRef.ReturnRef_Scope: rrs = isout ? "return out scope" : "return ref scope"; goto L1;
2915 case ScopeRef.Ref_ReturnScope: rrs = isout ? "out return scope" : "ref return scope"; goto L1;
2917 buf.writestring(rrs);
2919 stc &= ~(STC.out_ | STC.scope_ | STC.ref_ | STC.return_);
2925 const s = stcToString(stc);
2937 /*************************************************
2938 * Pick off one of the storage classes from stc,
2939 * and return a string representation of it.
2940 * stc is reduced by the one picked.
2942 string stcToString(ref StorageClass stc)
2944 static struct SCstring
2950 // Note: The identifier needs to be `\0` terminated
2951 // as some code assumes it (e.g. when printing error messages)
2952 static immutable SCstring[] table =
2954 SCstring(STC.auto_, Token.toString(TOK.auto_)),
2955 SCstring(STC.scope_, Token.toString(TOK.scope_)),
2956 SCstring(STC.static_, Token.toString(TOK.static_)),
2957 SCstring(STC.extern_, Token.toString(TOK.extern_)),
2958 SCstring(STC.const_, Token.toString(TOK.const_)),
2959 SCstring(STC.final_, Token.toString(TOK.final_)),
2960 SCstring(STC.abstract_, Token.toString(TOK.abstract_)),
2961 SCstring(STC.synchronized_, Token.toString(TOK.synchronized_)),
2962 SCstring(STC.deprecated_, Token.toString(TOK.deprecated_)),
2963 SCstring(STC.override_, Token.toString(TOK.override_)),
2964 SCstring(STC.lazy_, Token.toString(TOK.lazy_)),
2965 SCstring(STC.alias_, Token.toString(TOK.alias_)),
2966 SCstring(STC.out_, Token.toString(TOK.out_)),
2967 SCstring(STC.in_, Token.toString(TOK.in_)),
2968 SCstring(STC.manifest, Token.toString(TOK.enum_)),
2969 SCstring(STC.immutable_, Token.toString(TOK.immutable_)),
2970 SCstring(STC.shared_, Token.toString(TOK.shared_)),
2971 SCstring(STC.nothrow_, Token.toString(TOK.nothrow_)),
2972 SCstring(STC.wild, Token.toString(TOK.inout_)),
2973 SCstring(STC.pure_, Token.toString(TOK.pure_)),
2974 SCstring(STC.ref_, Token.toString(TOK.ref_)),
2975 SCstring(STC.return_, Token.toString(TOK.return_)),
2976 SCstring(STC.gshared, Token.toString(TOK.gshared)),
2977 SCstring(STC.nogc, "@nogc"),
2978 SCstring(STC.live, "@live"),
2979 SCstring(STC.property, "@property"),
2980 SCstring(STC.safe, "@safe"),
2981 SCstring(STC.trusted, "@trusted"),
2982 SCstring(STC.system, "@system"),
2983 SCstring(STC.disable, "@disable"),
2984 SCstring(STC.future, "@__future"),
2985 SCstring(STC.local, "__local"),
2987 foreach (ref entry; table)
2989 const StorageClass tbl = entry.stc;
2990 assert(tbl & STC.visibleStorageClasses);
2997 //printf("stc = %llx\n", stc);
3001 private void linkageToBuffer(OutBuffer* buf, LINK linkage)
3003 const s = linkageToString(linkage);
3006 buf.writestring("extern (");
3012 const(char)* linkageToChars(LINK linkage)
3014 /// Works because we return a literal
3015 return linkageToString(linkage).ptr;
3018 string linkageToString(LINK linkage) pure nothrow
3020 final switch (linkage)
3033 return "Objective-C";
3039 void visibilityToBuffer(OutBuffer* buf, Visibility vis)
3041 buf.writestring(visibilityToString(vis.kind));
3042 if (vis.kind == Visibility.Kind.package_ && vis.pkg)
3045 buf.writestring(vis.pkg.toPrettyChars(true));
3052 * a human readable representation of `kind`
3054 const(char)* visibilityToChars(Visibility.Kind kind)
3056 // Null terminated because we return a literal
3057 return visibilityToString(kind).ptr;
3061 extern (D) string visibilityToString(Visibility.Kind kind) nothrow pure
3065 case Visibility.Kind.undefined:
3067 case Visibility.Kind.none:
3069 case Visibility.Kind.private_:
3071 case Visibility.Kind.package_:
3073 case Visibility.Kind.protected_:
3075 case Visibility.Kind.public_:
3077 case Visibility.Kind.export_:
3082 // Print the full function signature with correct ident, attributes and template args
3083 void functionToBufferFull(TypeFunction tf, OutBuffer* buf, const Identifier ident, HdrGenState* hgs, TemplateDeclaration td)
3085 //printf("TypeFunction::toCBuffer() this = %p\n", this);
3086 visitFuncIdentWithPrefix(tf, ident, td, buf, hgs);
3089 // ident is inserted before the argument list and will be "function" or "delegate" for a type
3090 void functionToBufferWithIdent(TypeFunction tf, OutBuffer* buf, const(char)* ident, bool isStatic)
3093 visitFuncIdentWithPostfix(tf, ident.toDString(), buf, &hgs, isStatic);
3096 void toCBuffer(const Expression e, OutBuffer* buf, HdrGenState* hgs)
3098 expressionPrettyPrint(cast()e, buf, hgs);
3101 /**************************************************
3102 * Write out argument types to buf.
3104 void argExpTypesToCBuffer(OutBuffer* buf, Expressions* arguments)
3106 if (!arguments || !arguments.length)
3109 foreach (i, arg; *arguments)
3112 buf.writestring(", ");
3113 typeToBuffer(arg.type, null, buf, &hgs);
3117 void toCBuffer(const TemplateParameter tp, OutBuffer* buf, HdrGenState* hgs)
3119 scope v = new TemplateParameterPrettyPrintVisitor(buf, hgs);
3120 (cast() tp).accept(v);
3123 void arrayObjectsToBuffer(OutBuffer* buf, Objects* objects)
3125 if (!objects || !objects.length)
3128 foreach (i, o; *objects)
3131 buf.writestring(", ");
3132 objectToBuffer(o, buf, &hgs);
3136 /*************************************************************
3137 * Pretty print function parameters.
3139 * pl = parameter list to print
3140 * Returns: Null-terminated string representing parameters.
3142 extern (C++) const(char)* parametersTypeToChars(ParameterList pl)
3146 parametersToBuffer(pl, &buf, &hgs);
3147 return buf.extractChars();
3150 /*************************************************************
3151 * Pretty print function parameter.
3153 * parameter = parameter to print.
3154 * tf = TypeFunction which holds parameter.
3155 * fullQual = whether to fully qualify types.
3156 * Returns: Null-terminated string representing parameters.
3158 const(char)* parameterToChars(Parameter parameter, TypeFunction tf, bool fullQual)
3162 hgs.fullQual = fullQual;
3164 parameterToBuffer(parameter, &buf, &hgs);
3166 if (tf.parameterList.varargs == VarArg.typesafe && parameter == tf.parameterList[tf.parameterList.parameters.length - 1])
3168 buf.writestring("...");
3170 return buf.extractChars();
3174 /*************************************************
3175 * Write ParameterList to buffer.
3177 * pl = parameter list to serialize
3178 * buf = buffer to write it to
3182 private void parametersToBuffer(ParameterList pl, OutBuffer* buf, HdrGenState* hgs)
3185 foreach (i; 0 .. pl.length)
3188 buf.writestring(", ");
3189 pl[i].parameterToBuffer(buf, hgs);
3191 final switch (pl.varargs)
3196 case VarArg.variadic:
3198 buf.writestring(", ");
3200 if (stcToBuffer(buf, pl.stc))
3202 goto case VarArg.typesafe;
3204 case VarArg.typesafe:
3205 buf.writestring("...");
3212 /***********************************************************
3213 * Write parameter `p` to buffer `buf`.
3215 * p = parameter to serialize
3216 * buf = buffer to write it to
3219 private void parameterToBuffer(Parameter p, OutBuffer* buf, HdrGenState* hgs)
3221 if (p.userAttribDecl)
3225 bool isAnonymous = p.userAttribDecl.atts.length > 0 && !(*p.userAttribDecl.atts)[0].isCallExp();
3229 argsToBuffer(p.userAttribDecl.atts, buf, hgs);
3235 if (p.storageClass & STC.auto_)
3236 buf.writestring("auto ");
3238 StorageClass stc = p.storageClass;
3239 if (p.storageClass & STC.in_)
3241 buf.writestring("in ");
3242 if (global.params.previewIn && p.storageClass & STC.ref_)
3245 else if (p.storageClass & STC.lazy_)
3246 buf.writestring("lazy ");
3247 else if (p.storageClass & STC.alias_)
3248 buf.writestring("alias ");
3250 if (p.type && p.type.mod & MODFlags.shared_)
3251 stc &= ~STC.shared_;
3253 if (stcToBuffer(buf, stc & (STC.const_ | STC.immutable_ | STC.wild | STC.shared_ |
3254 STC.return_ | STC.returninferred | STC.scope_ | STC.scopeinferred | STC.out_ | STC.ref_ | STC.returnScope)))
3257 if (p.storageClass & STC.alias_)
3260 buf.writestring(p.ident.toString());
3262 else if (p.type.ty == Tident &&
3263 (cast(TypeIdentifier)p.type).ident.toString().length > 3 &&
3264 strncmp((cast(TypeIdentifier)p.type).ident.toChars(), "__T", 3) == 0)
3266 // print parameter name, instead of undetermined type parameter
3267 buf.writestring(p.ident.toString());
3271 typeToBuffer(p.type, p.ident, buf, hgs, (stc & STC.in_) ? MODFlags.const_ : 0);
3276 buf.writestring(" = ");
3277 p.defaultArg.expToBuffer(PREC.assign, buf, hgs);
3282 /**************************************************
3283 * Write out argument list to buf.
3285 private void argsToBuffer(Expressions* expressions, OutBuffer* buf, HdrGenState* hgs, Expression basis = null)
3287 if (!expressions || !expressions.length)
3291 foreach (i, el; *expressions)
3294 buf.writestring(", ");
3298 expToBuffer(el, PREC.assign, buf, hgs);
3303 // Sparse style formatting, for debug use only
3304 // [0..length: basis, 1: e1, 5: e5]
3307 buf.writestring("0..");
3308 buf.print(expressions.length);
3309 buf.writestring(": ");
3310 expToBuffer(basis, PREC.assign, buf, hgs);
3312 foreach (i, el; *expressions)
3318 buf.writestring(", ");
3320 buf.writestring(": ");
3323 buf.writestring(", ");
3324 expToBuffer(el, PREC.assign, buf, hgs);
3330 private void sizeToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs)
3332 if (e.type == Type.tsize_t)
3334 Expression ex = (e.op == EXP.cast_ ? (cast(CastExp)e).e1 : e);
3335 ex = ex.optimize(WANTvalue);
3336 const dinteger_t uval = ex.op == EXP.int64 ? ex.toInteger() : cast(dinteger_t)-1;
3337 if (cast(sinteger_t)uval >= 0)
3339 dinteger_t sizemax = void;
3340 if (target.ptrsize == 8)
3341 sizemax = 0xFFFFFFFFFFFFFFFFUL;
3342 else if (target.ptrsize == 4)
3343 sizemax = 0xFFFFFFFFU;
3344 else if (target.ptrsize == 2)
3348 if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFUL)
3355 expToBuffer(e, PREC.assign, buf, hgs);
3358 private void expressionToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs)
3360 expressionPrettyPrint(e, buf, hgs);
3363 /**************************************************
3364 * Write expression out to buf, but wrap it
3365 * in ( ) if its precedence is less than pr.
3367 private void expToBuffer(Expression e, PREC pr, OutBuffer* buf, HdrGenState* hgs)
3371 if (precedence[e.op] == PREC.zero)
3372 printf("precedence not defined for token '%s'\n", EXPtoString(e.op).ptr);
3376 buf.writestring("<FF>");
3379 assert(precedence[e.op] != PREC.zero);
3380 assert(pr != PREC.zero);
3381 /* Despite precedence, we don't allow a<b<c expressions.
3382 * They must be parenthesized.
3384 if (precedence[e.op] < pr || (pr == PREC.rel && precedence[e.op] == pr)
3385 || (pr >= PREC.or && pr <= PREC.and && precedence[e.op] == PREC.rel))
3388 e.expressionToBuffer(buf, hgs);
3393 e.expressionToBuffer(buf, hgs);
3398 /**************************************************
3399 * An entry point to pretty-print type.
3401 private void typeToBuffer(Type t, const Identifier ident, OutBuffer* buf, HdrGenState* hgs,
3404 if (auto tf = t.isTypeFunction())
3406 visitFuncIdentWithPrefix(tf, ident, null, buf, hgs);
3409 visitWithMask(t, modMask, buf, hgs);
3413 buf.writestring(ident.toString());
3417 private void visitWithMask(Type t, ubyte modMask, OutBuffer* buf, HdrGenState* hgs)
3419 // Tuples and functions don't use the type constructor syntax
3420 if (modMask == t.mod || t.ty == Tfunction || t.ty == Ttuple)
3422 typeToBufferx(t, buf, hgs);
3426 ubyte m = t.mod & ~(t.mod & modMask);
3427 if (m & MODFlags.shared_)
3429 MODtoBuffer(buf, MODFlags.shared_);
3432 if (m & MODFlags.wild)
3434 MODtoBuffer(buf, MODFlags.wild);
3437 if (m & (MODFlags.const_ | MODFlags.immutable_))
3439 MODtoBuffer(buf, m & (MODFlags.const_ | MODFlags.immutable_));
3442 typeToBufferx(t, buf, hgs);
3443 if (m & (MODFlags.const_ | MODFlags.immutable_))
3445 if (m & MODFlags.wild)
3447 if (m & MODFlags.shared_)
3453 private void dumpTemplateInstance(TemplateInstance ti, OutBuffer* buf, HdrGenState* hgs)
3461 ti.aliasdecl.dsymbolToBuffer(buf, hgs);
3464 else if (ti.members)
3466 foreach(m;*ti.members)
3467 m.dsymbolToBuffer(buf, hgs);
3476 private void tiargsToBuffer(TemplateInstance ti, OutBuffer* buf, HdrGenState* hgs)
3481 buf.writestring("(...)");
3486 buf.writestring("()");
3489 if (ti.tiargs.length == 1)
3491 RootObject oarg = (*ti.tiargs)[0];
3492 if (Type t = isType(oarg))
3494 if (t.equals(Type.tstring) || t.equals(Type.twstring) || t.equals(Type.tdstring) || t.mod == 0 && (t.isTypeBasic() || t.ty == Tident && (cast(TypeIdentifier)t).idents.length == 0))
3496 buf.writestring(t.toChars());
3500 else if (Expression e = isExpression(oarg))
3502 if (e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.this_)
3504 buf.writestring(e.toChars());
3511 foreach (i, arg; *ti.tiargs)
3514 buf.writestring(", ");
3515 objectToBuffer(arg, buf, hgs);
3521 /****************************************
3522 * This makes a 'pretty' version of the template arguments.
3523 * It's analogous to genIdent() which makes a mangled version.
3525 private void objectToBuffer(RootObject oarg, OutBuffer* buf, HdrGenState* hgs)
3527 //printf("objectToBuffer()\n");
3528 /* The logic of this should match what genIdent() does. The _dynamic_cast()
3529 * function relies on all the pretty strings to be unique for different classes
3530 * See https://issues.dlang.org/show_bug.cgi?id=7375
3531 * Perhaps it would be better to demangle what genIdent() does.
3533 if (auto t = isType(oarg))
3535 //printf("\tt: %s ty = %d\n", t.toChars(), t.ty);
3536 typeToBuffer(t, null, buf, hgs);
3538 else if (auto e = isExpression(oarg))
3540 if (e.op == EXP.variable)
3541 e = e.optimize(WANTvalue); // added to fix https://issues.dlang.org/show_bug.cgi?id=7375
3542 expToBuffer(e, PREC.assign, buf, hgs);
3544 else if (Dsymbol s = isDsymbol(oarg))
3546 const p = s.ident ? s.ident.toChars() : s.toChars();
3549 else if (auto v = isTuple(oarg))
3551 auto args = &v.objects;
3552 foreach (i, arg; *args)
3555 buf.writestring(", ");
3556 objectToBuffer(arg, buf, hgs);
3559 else if (auto p = isParameter(oarg))
3561 parameterToBuffer(p, buf, hgs);
3565 buf.writestring("NULL");
3571 printf("bad Object = %p\n", oarg);
3578 private void visitFuncIdentWithPostfix(TypeFunction t, const char[] ident, OutBuffer* buf, HdrGenState* hgs, bool isStatic)
3582 t.inuse = 2; // flag error to caller
3586 if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen)
3588 linkageToBuffer(buf, t.linkage);
3591 if (t.linkage == LINK.objc && isStatic)
3592 buf.write("static ");
3595 typeToBuffer(t.next, null, buf, hgs);
3600 buf.writestring("auto ");
3602 buf.writestring(ident);
3603 parametersToBuffer(t.parameterList, buf, hgs);
3604 /* Use postfix style for attributes
3609 MODtoBuffer(buf, t.mod);
3615 buf.writestring(str);
3617 t.attributesApply(&dg);
3622 private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, TemplateDeclaration td,
3623 OutBuffer* buf, HdrGenState* hgs)
3627 t.inuse = 2; // flag error to caller
3632 /* Use 'storage class' (prefix) style for attributes
3636 MODtoBuffer(buf, t.mod);
3640 void ignoreReturn(string str)
3642 if (str != "return")
3644 // don't write 'ref' for ctors
3645 if ((ident == Id.ctor) && str == "ref")
3647 buf.writestring(str);
3651 t.attributesApply(&ignoreReturn);
3653 if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen)
3655 linkageToBuffer(buf, t.linkage);
3658 if (ident && ident.toHChars2() != ident.toChars())
3660 // Don't print return type for ctor, dtor, unittest, etc
3664 typeToBuffer(t.next, null, buf, hgs);
3669 buf.writestring("auto ");
3671 buf.writestring(ident.toHChars2());
3675 foreach (i, p; *td.origParameters)
3678 buf.writestring(", ");
3679 p.templateParameterToBuffer(buf, hgs);
3683 parametersToBuffer(t.parameterList, buf, hgs);
3686 buf.writestring(" return");
3692 private void initializerToBuffer(Initializer inx, OutBuffer* buf, HdrGenState* hgs)
3694 void visitError(ErrorInitializer iz)
3696 buf.writestring("__error__");
3699 void visitVoid(VoidInitializer iz)
3701 buf.writestring("void");
3704 void visitStruct(StructInitializer si)
3706 //printf("StructInitializer::toCBuffer()\n");
3708 foreach (i, const id; si.field)
3711 buf.writestring(", ");
3714 buf.writestring(id.toString());
3717 if (auto iz = si.value[i])
3718 initializerToBuffer(iz, buf, hgs);
3723 void visitArray(ArrayInitializer ai)
3726 foreach (i, ex; ai.index)
3729 buf.writestring(", ");
3732 ex.expressionToBuffer(buf, hgs);
3735 if (auto iz = ai.value[i])
3736 initializerToBuffer(iz, buf, hgs);
3741 void visitExp(ExpInitializer ei)
3743 ei.exp.expressionToBuffer(buf, hgs);
3746 void visitC(CInitializer ci)
3749 foreach (i, ref DesigInit di; ci.initializerList)
3752 buf.writestring(", ");
3753 if (di.designatorList)
3755 foreach (ref Designator d; (*di.designatorList)[])
3760 toCBuffer(d.exp, buf, hgs);
3766 buf.writestring(d.ident.toString());
3771 initializerToBuffer(di.initializer, buf, hgs);
3776 final switch (inx.kind)
3778 case InitKind.error: return visitError (inx.isErrorInitializer ());
3779 case InitKind.void_: return visitVoid (inx.isVoidInitializer ());
3780 case InitKind.struct_: return visitStruct(inx.isStructInitializer());
3781 case InitKind.array: return visitArray (inx.isArrayInitializer ());
3782 case InitKind.exp: return visitExp (inx.isExpInitializer ());
3783 case InitKind.C_: return visitC (inx.isCInitializer ());
3788 private void typeToBufferx(Type t, OutBuffer* buf, HdrGenState* hgs)
3790 void visitType(Type t)
3792 printf("t = %p, ty = %d\n", t, t.ty);
3796 void visitError(TypeError t)
3798 buf.writestring("_error_");
3801 void visitBasic(TypeBasic t)
3803 //printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod);
3804 buf.writestring(t.dstring);
3807 void visitTraits(TypeTraits t)
3809 //printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod);
3810 t.exp.expressionToBuffer(buf, hgs);
3813 void visitVector(TypeVector t)
3815 //printf("TypeVector::toCBuffer2(t.mod = %d)\n", t.mod);
3816 buf.writestring("__vector(");
3817 visitWithMask(t.basetype, t.mod, buf, hgs);
3818 buf.writestring(")");
3821 void visitSArray(TypeSArray t)
3823 visitWithMask(t.next, t.mod, buf, hgs);
3825 sizeToBuffer(t.dim, buf, hgs);
3829 void visitDArray(TypeDArray t)
3831 Type ut = t.castMod(0);
3834 if (ut.equals(Type.tstring))
3835 buf.writestring("string");
3836 else if (ut.equals(Type.twstring))
3837 buf.writestring("wstring");
3838 else if (ut.equals(Type.tdstring))
3839 buf.writestring("dstring");
3843 visitWithMask(t.next, t.mod, buf, hgs);
3844 buf.writestring("[]");
3848 void visitAArray(TypeAArray t)
3850 visitWithMask(t.next, t.mod, buf, hgs);
3852 visitWithMask(t.index, 0, buf, hgs);
3856 void visitPointer(TypePointer t)
3858 //printf("TypePointer::toCBuffer2() next = %d\n", t.next.ty);
3859 if (t.next.ty == Tfunction)
3860 visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "function", buf, hgs, false);
3863 visitWithMask(t.next, t.mod, buf, hgs);
3868 void visitReference(TypeReference t)
3870 visitWithMask(t.next, t.mod, buf, hgs);
3874 void visitFunction(TypeFunction t)
3876 //printf("TypeFunction::toCBuffer2() t = %p, ref = %d\n", t, t.isref);
3877 visitFuncIdentWithPostfix(t, null, buf, hgs, false);
3880 void visitDelegate(TypeDelegate t)
3882 visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "delegate", buf, hgs, false);
3885 void visitTypeQualifiedHelper(TypeQualified t)
3887 foreach (id; t.idents)
3889 switch (id.dyncast()) with (DYNCAST)
3893 TemplateInstance ti = cast(TemplateInstance)id;
3894 ti.dsymbolToBuffer(buf, hgs);
3898 (cast(Expression)id).expressionToBuffer(buf, hgs);
3903 typeToBufferx(cast(Type)id, buf, hgs);
3908 buf.writestring(id.toString());
3913 void visitIdentifier(TypeIdentifier t)
3915 buf.writestring(t.ident.toString());
3916 visitTypeQualifiedHelper(t);
3919 void visitInstance(TypeInstance t)
3921 t.tempinst.dsymbolToBuffer(buf, hgs);
3922 visitTypeQualifiedHelper(t);
3925 void visitTypeof(TypeTypeof t)
3927 buf.writestring("typeof(");
3928 t.exp.expressionToBuffer(buf, hgs);
3930 visitTypeQualifiedHelper(t);
3933 void visitReturn(TypeReturn t)
3935 buf.writestring("typeof(return)");
3936 visitTypeQualifiedHelper(t);
3939 void visitEnum(TypeEnum t)
3941 buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars());
3944 void visitStruct(TypeStruct t)
3946 // https://issues.dlang.org/show_bug.cgi?id=13776
3947 // Don't use ti.toAlias() to avoid forward reference error
3948 // while printing messages.
3949 TemplateInstance ti = t.sym.parent ? t.sym.parent.isTemplateInstance() : null;
3950 if (ti && ti.aliasdecl == t.sym)
3951 buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars());
3953 buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars());
3956 void visitClass(TypeClass t)
3958 // https://issues.dlang.org/show_bug.cgi?id=13776
3959 // Don't use ti.toAlias() to avoid forward reference error
3960 // while printing messages.
3961 TemplateInstance ti = t.sym.parent ? t.sym.parent.isTemplateInstance() : null;
3962 if (ti && ti.aliasdecl == t.sym)
3963 buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars());
3965 buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars());
3968 void visitTag(TypeTag t)
3970 if (t.mod & MODFlags.const_)
3971 buf.writestring("const ");
3972 buf.writestring(Token.toChars(t.tok));
3975 buf.writestring(t.id.toChars());
3976 if (t.tok == TOK.enum_ && t.base.ty != TY.Tint32)
3978 buf.writestring(" : ");
3979 visitWithMask(t.base, t.mod, buf, hgs);
3983 void visitTuple(TypeTuple t)
3985 parametersToBuffer(ParameterList(t.arguments, VarArg.none), buf, hgs);
3988 void visitSlice(TypeSlice t)
3990 visitWithMask(t.next, t.mod, buf, hgs);
3992 sizeToBuffer(t.lwr, buf, hgs);
3993 buf.writestring(" .. ");
3994 sizeToBuffer(t.upr, buf, hgs);
3998 void visitNull(TypeNull t)
4000 buf.writestring("typeof(null)");
4003 void visitMixin(TypeMixin t)
4005 buf.writestring("mixin(");
4006 argsToBuffer(t.exps, buf, hgs, null);
4010 void visitNoreturn(TypeNoreturn t)
4012 buf.writestring("noreturn");
4018 default: return t.isTypeBasic() ?
4019 visitBasic(cast(TypeBasic)t) :
4022 case Terror: return visitError(cast(TypeError)t);
4023 case Ttraits: return visitTraits(cast(TypeTraits)t);
4024 case Tvector: return visitVector(cast(TypeVector)t);
4025 case Tsarray: return visitSArray(cast(TypeSArray)t);
4026 case Tarray: return visitDArray(cast(TypeDArray)t);
4027 case Taarray: return visitAArray(cast(TypeAArray)t);
4028 case Tpointer: return visitPointer(cast(TypePointer)t);
4029 case Treference: return visitReference(cast(TypeReference)t);
4030 case Tfunction: return visitFunction(cast(TypeFunction)t);
4031 case Tdelegate: return visitDelegate(cast(TypeDelegate)t);
4032 case Tident: return visitIdentifier(cast(TypeIdentifier)t);
4033 case Tinstance: return visitInstance(cast(TypeInstance)t);
4034 case Ttypeof: return visitTypeof(cast(TypeTypeof)t);
4035 case Treturn: return visitReturn(cast(TypeReturn)t);
4036 case Tenum: return visitEnum(cast(TypeEnum)t);
4037 case Tstruct: return visitStruct(cast(TypeStruct)t);
4038 case Tclass: return visitClass(cast(TypeClass)t);
4039 case Ttuple: return visitTuple (cast(TypeTuple)t);
4040 case Tslice: return visitSlice(cast(TypeSlice)t);
4041 case Tnull: return visitNull(cast(TypeNull)t);
4042 case Tmixin: return visitMixin(cast(TypeMixin)t);
4043 case Tnoreturn: return visitNoreturn(cast(TypeNoreturn)t);
4044 case Ttag: return visitTag(cast(TypeTag)t);
4048 /****************************************
4049 * Convert EXP to char*.
4052 string EXPtoString(EXP op)
4054 static immutable char*[EXP.max + 1] strings =
4057 EXP.error : "error",
4058 EXP.objcClassReference : "class",
4060 EXP.typeof_ : "typeof",
4061 EXP.mixin_ : "mixin",
4063 EXP.import_ : "import",
4064 EXP.dotVariable : "dotvar",
4065 EXP.scope_ : "scope",
4066 EXP.identifier : "identifier",
4068 EXP.super_ : "super",
4070 EXP.float64 : "double",
4071 EXP.complex80 : "creal",
4073 EXP.string_ : "string",
4074 EXP.arrayLiteral : "arrayliteral",
4075 EXP.assocArrayLiteral : "assocarrayliteral",
4076 EXP.classReference : "classreference",
4077 EXP.file : "__FILE__",
4078 EXP.fileFullPath : "__FILE_FULL_PATH__",
4079 EXP.line : "__LINE__",
4080 EXP.moduleString : "__MODULE__",
4081 EXP.functionString : "__FUNCTION__",
4082 EXP.prettyFunction : "__PRETTY_FUNCTION__",
4083 EXP.typeid_ : "typeid",
4085 EXP.assert_ : "assert",
4087 EXP.template_ : "template",
4088 EXP.dSymbol : "symbol",
4089 EXP.function_ : "function",
4090 EXP.variable : "var",
4091 EXP.symbolOffset : "symoff",
4092 EXP.structLiteral : "structLiteral",
4093 EXP.compoundLiteral : "compoundliteral",
4094 EXP.arrayLength : "arraylength",
4095 EXP.delegatePointer : "delegateptr",
4096 EXP.delegateFunctionPointer : "delegatefuncptr",
4097 EXP.remove : "remove",
4098 EXP.tuple : "tuple",
4099 EXP.traits : "__traits",
4100 EXP.default_ : "default",
4101 EXP.overloadSet : "__overloadset",
4103 EXP.vectorArray : "vectorarray",
4104 EXP._Generic : "_Generic",
4107 EXP.dotTemplateInstance : "dotti",
4108 EXP.dotIdentifier : "dotid",
4109 EXP.dotTemplateDeclaration : "dottd",
4111 EXP.dotType : "dottype",
4112 EXP.plusPlus : "++",
4113 EXP.minusMinus : "--",
4114 EXP.prePlusPlus : "++",
4115 EXP.preMinusMinus : "--",
4121 EXP.delegate_ : "delegate",
4128 EXP.delete_ : "delete",
4130 EXP.newAnonymousClass : "newanonclass",
4133 EXP.vector : "__vector",
4142 EXP.concatenate : "~",
4144 EXP.leftShift : "<<",
4145 EXP.rightShift : ">>",
4146 EXP.unsignedRightShift : ">>>",
4149 EXP.lessOrEqual : "<=",
4150 EXP.greaterThan : ">",
4151 EXP.greaterOrEqual : ">=",
4155 EXP.notEqual : "!=",
4156 EXP.identity : "is",
4157 EXP.notIdentity : "!is",
4169 EXP.construct : "=",
4171 EXP.addAssign : "+=",
4172 EXP.minAssign : "-=",
4173 EXP.concatenateAssign : "~=",
4174 EXP.concatenateElemAssign : "~=",
4175 EXP.concatenateDcharAssign : "~=",
4176 EXP.mulAssign : "*=",
4177 EXP.divAssign : "/=",
4178 EXP.modAssign : "%=",
4179 EXP.powAssign : "^^=",
4180 EXP.leftShiftAssign : "<<=",
4181 EXP.rightShiftAssign : ">>=",
4182 EXP.unsignedRightShiftAssign : ">>>=",
4183 EXP.andAssign : "&=",
4184 EXP.orAssign : "|=",
4185 EXP.xorAssign : "^=",
4188 EXP.declaration : "declaration",
4190 EXP.interval : "interval",
4192 const p = strings[op];
4195 printf("error: EXP %d has no string\n", op);
4200 return p[0 .. strlen(p)];