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-2024 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
;
39 import dmd
.identifier
;
45 import dmd
.root
.complex
;
46 import dmd
.root
.ctfloat
;
47 import dmd
.common
.outbuffer
;
48 import dmd
.rootobject
;
49 import dmd
.root
.string
;
51 import dmd
.staticassert
;
57 bool hdrgen
; /// true if generating header file
58 bool ddoc
; /// true if generating Ddoc file
59 bool fullDump
; /// true if generating a full AST dump file
60 bool importcHdr
; /// true if generating a .di file from an ImportC file
61 bool doFuncBodies
; /// include function bodies in output
62 bool vcg_ast
; /// write out codegen-ast
63 bool skipConstraints
; // skip constraints when doing templates
65 bool fullQual
; /// fully qualify types when printing
72 bool declstring
; // set while declaring alias for string,wstring or dstring
73 EnumDeclaration inEnumDecl
;
76 enum TEST_EMIT_ALL
= 0;
78 /****************************************
79 * Generate a header (.di) file for Module m.
81 * m = Module to generate header for
82 * doFuncBodies = generate function definitions rather than just declarations
83 * buf = buffer to write the data to
85 extern (C
++) void genhdrfile(Module m
, bool doFuncBodies
, ref OutBuffer buf
)
88 buf
.printf("// D import file generated from '%s'", m
.srcfile
.toChars());
92 hgs
.importcHdr
= (m
.filetype
== FileType
.c
);
93 hgs
.doFuncBodies
= doFuncBodies
;
94 toCBuffer(m
, buf
, hgs
);
97 /***************************************
98 * Turn a Statement into a string suitable for printf.
101 * s = Statement to convert
103 * 0-terminated string
105 public extern (C
++) const(char)* toChars(const Statement s
)
109 toCBuffer(s
, buf
, hgs
);
111 return buf
.extractSlice().ptr
;
114 public extern (C
++) const(char)* toChars(const Expression e
)
118 toCBuffer(e
, buf
, hgs
);
119 return buf
.extractChars();
122 public extern (C
++) const(char)* toChars(const Initializer i
)
126 toCBuffer(i
, buf
, hgs
);
127 return buf
.extractChars();
130 public extern (C
++) const(char)* toChars(const Type t
)
135 hgs
.fullQual
= (t
.ty
== Tclass
&& !t
.mod
);
137 toCBuffer(t
, buf
, null, hgs
);
138 return buf
.extractChars();
141 public const(char)[] toString(const Initializer i
)
145 toCBuffer(i
, buf
, hgs
);
146 return buf
.extractSlice();
150 * Dumps the full contents of module `m` to `buf`.
152 * buf = buffer to write to.
153 * vcg_ast = write out codegen ast
154 * m = module to visit all members of.
156 extern (C
++) void moduleToBuffer(ref OutBuffer buf
, bool vcg_ast
, Module m
)
160 hgs
.vcg_ast
= vcg_ast
;
161 toCBuffer(m
, buf
, hgs
);
164 void moduleToBuffer2(Module m
, ref OutBuffer buf
, ref HdrGenState hgs
)
168 if (m
.userAttribDecl
)
170 buf
.writestring("@(");
171 argsToBuffer(m
.userAttribDecl
.atts
, buf
, hgs
);
175 if (m
.md
.isdeprecated
)
179 buf
.writestring("deprecated(");
180 m
.md
.msg
.expressionToBuffer(buf
, hgs
);
181 buf
.writestring(") ");
184 buf
.writestring("deprecated ");
186 buf
.writestring("module ");
187 buf
.writestring(m
.md
.toChars());
192 foreach (s
; *m
.members
)
194 s
.dsymbolToBuffer(buf
, hgs
);
198 private void statementToBuffer(Statement s
, ref OutBuffer buf
, ref HdrGenState hgs
)
200 void visitDefaultCase(Statement s
)
202 printf("Statement::toCBuffer() %d\n", s
.stmt
);
203 assert(0, "unrecognized statement in statementToBuffer()");
206 void visitError(ErrorStatement s
)
208 buf
.writestring("__error__");
212 void visitExp(ExpStatement s
)
214 if (s
.exp
&& s
.exp
.op
== EXP
.declaration
&&
215 (cast(DeclarationExp
)s
.exp
).declaration
)
217 // bypass visit(DeclarationExp)
218 (cast(DeclarationExp
)s
.exp
).declaration
.dsymbolToBuffer(buf
, hgs
);
222 s
.exp
.expressionToBuffer(buf
, hgs
);
224 if (!hgs
.forStmtInit
)
228 void visitDtorExp(DtorExpStatement s
)
233 void visitMixin(MixinStatement s
)
235 buf
.writestring("mixin(");
236 argsToBuffer(s
.exps
, buf
, hgs
, null);
237 buf
.writestring(");");
238 if (!hgs
.forStmtInit
)
242 void visitCompound(CompoundStatement s
)
244 foreach (sx
; *s
.statements
)
247 sx
.statementToBuffer(buf
, hgs
);
251 void visitCompoundAsm(CompoundAsmStatement s
)
256 void visitCompoundDeclaration(CompoundDeclarationStatement s
)
258 bool anywritten
= false;
259 foreach (sx
; *s
.statements
)
261 auto ds = sx ? sx
.isExpStatement() : null;
262 if (ds && ds.exp
.isDeclarationExp())
264 auto d
= ds.exp
.isDeclarationExp().declaration
;
265 if (auto v
= d
.isVarDeclaration())
267 visitVarDecl(v
, anywritten
, buf
, hgs
);
270 d
.dsymbolToBuffer(buf
, hgs
);
275 if (!hgs
.forStmtInit
)
279 void visitUnrolledLoop(UnrolledLoopStatement s
)
281 buf
.writestring("/*unrolled*/ {");
284 foreach (sx
; *s
.statements
)
287 sx
.statementToBuffer(buf
, hgs
);
294 void visitScope(ScopeStatement s
)
300 s
.statement
.statementToBuffer(buf
, hgs
);
306 void visitWhile(WhileStatement s
)
308 buf
.writestring("while (");
309 if (auto p
= s
.param
)
311 // Print condition assignment
312 StorageClass
stc = p
.storageClass
;
315 if (stcToBuffer(buf
, stc))
318 typeToBuffer(p
.type
, p
.ident
, buf
, hgs
);
320 buf
.writestring(p
.ident
.toString());
321 buf
.writestring(" = ");
323 s
.condition
.expressionToBuffer(buf
, hgs
);
327 s
._body
.statementToBuffer(buf
, hgs
);
330 void visitDo(DoStatement s
)
332 buf
.writestring("do");
335 s
._body
.statementToBuffer(buf
, hgs
);
336 buf
.writestring("while (");
337 s
.condition
.expressionToBuffer(buf
, hgs
);
338 buf
.writestring(");");
342 void visitFor(ForStatement s
)
344 buf
.writestring("for (");
348 s
._init
.statementToBuffer(buf
, hgs
);
356 s
.condition
.expressionToBuffer(buf
, hgs
);
362 s
.increment
.expressionToBuffer(buf
, hgs
);
370 s
._body
.statementToBuffer(buf
, hgs
);
376 void foreachWithoutBody(ForeachStatement s
)
378 buf
.writestring(Token
.toString(s
.op
));
379 buf
.writestring(" (");
380 foreach (i
, p
; *s
.parameters
)
383 buf
.writestring(", ");
384 if (stcToBuffer(buf
, p
.storageClass
))
387 typeToBuffer(p
.type
, p
.ident
, buf
, hgs
);
389 buf
.writestring(p
.ident
.toString());
391 buf
.writestring("; ");
392 s
.aggr
.expressionToBuffer(buf
, hgs
);
397 void visitForeach(ForeachStatement s
)
399 foreachWithoutBody(s
);
404 s
._body
.statementToBuffer(buf
, hgs
);
410 void foreachRangeWithoutBody(ForeachRangeStatement s
)
412 buf
.writestring(Token
.toString(s
.op
));
413 buf
.writestring(" (");
415 typeToBuffer(s
.prm
.type
, s
.prm
.ident
, buf
, hgs
);
417 buf
.writestring(s
.prm
.ident
.toString());
418 buf
.writestring("; ");
419 s
.lwr
.expressionToBuffer(buf
, hgs
);
420 buf
.writestring(" .. ");
421 s
.upr
.expressionToBuffer(buf
, hgs
);
426 void visitForeachRange(ForeachRangeStatement s
)
428 foreachRangeWithoutBody(s
);
433 s
._body
.statementToBuffer(buf
, hgs
);
439 void visitStaticForeach(StaticForeachStatement s
)
441 buf
.writestring("static ");
444 visitForeach(s
.sfe
.aggrfe
);
448 assert(s
.sfe
.rangefe
);
449 visitForeachRange(s
.sfe
.rangefe
);
453 void visitForwarding(ForwardingStatement s
)
455 s
.statement
.statementToBuffer(buf
, hgs
);
458 void visitIf(IfStatement s
)
460 buf
.writestring("if (");
461 if (Parameter p
= s
.prm
)
463 StorageClass
stc = p
.storageClass
;
466 if (stcToBuffer(buf
, stc))
469 typeToBuffer(p
.type
, p
.ident
, buf
, hgs
);
471 buf
.writestring(p
.ident
.toString());
472 buf
.writestring(" = ");
474 s
.condition
.expressionToBuffer(buf
, hgs
);
477 if (s
.ifbody
.isScopeStatement())
479 s
.ifbody
.statementToBuffer(buf
, hgs
);
484 s
.ifbody
.statementToBuffer(buf
, hgs
);
489 buf
.writestring("else");
490 if (!s
.elsebody
.isIfStatement())
498 if (s
.elsebody
.isScopeStatement() || s
.elsebody
.isIfStatement())
500 s
.elsebody
.statementToBuffer(buf
, hgs
);
505 s
.elsebody
.statementToBuffer(buf
, hgs
);
511 void visitConditional(ConditionalStatement s
)
513 s
.condition
.conditionToBuffer(buf
, hgs
);
519 s
.ifbody
.statementToBuffer(buf
, hgs
);
525 buf
.writestring("else");
530 s
.elsebody
.statementToBuffer(buf
, hgs
);
537 void visitPragma(PragmaStatement s
)
539 buf
.writestring("pragma (");
540 buf
.writestring(s
.ident
.toString());
541 if (s
.args
&& s
.args
.length
)
543 buf
.writestring(", ");
544 argsToBuffer(s
.args
, buf
, hgs
);
553 s
._body
.statementToBuffer(buf
, hgs
);
565 void visitStaticAssert(StaticAssertStatement s
)
567 s
.sa
.dsymbolToBuffer(buf
, hgs
);
570 void visitSwitch(SwitchStatement s
)
572 buf
.writestring(s
.isFinal ?
"final switch (" : "switch (");
573 if (auto p
= s
.param
)
575 // Print condition assignment
576 StorageClass
stc = p
.storageClass
;
579 if (stcToBuffer(buf
, stc))
582 typeToBuffer(p
.type
, p
.ident
, buf
, hgs
);
584 buf
.writestring(p
.ident
.toString());
585 buf
.writestring(" = ");
587 s
.condition
.expressionToBuffer(buf
, hgs
);
592 if (!s
._body
.isScopeStatement())
597 s
._body
.statementToBuffer(buf
, hgs
);
604 s
._body
.statementToBuffer(buf
, hgs
);
609 void visitCase(CaseStatement s
)
611 buf
.writestring("case ");
612 s
.exp
.expressionToBuffer(buf
, hgs
);
615 s
.statement
.statementToBuffer(buf
, hgs
);
618 void visitCaseRange(CaseRangeStatement s
)
620 buf
.writestring("case ");
621 s
.first
.expressionToBuffer(buf
, hgs
);
622 buf
.writestring(": .. case ");
623 s
.last
.expressionToBuffer(buf
, hgs
);
626 s
.statement
.statementToBuffer(buf
, hgs
);
629 void visitDefault(DefaultStatement s
)
631 buf
.writestring("default:");
633 s
.statement
.statementToBuffer(buf
, hgs
);
636 void visitGotoDefault(GotoDefaultStatement s
)
638 buf
.writestring("goto default;");
642 void visitGotoCase(GotoCaseStatement s
)
644 buf
.writestring("goto case");
648 s
.exp
.expressionToBuffer(buf
, hgs
);
654 void visitSwitchError(SwitchErrorStatement s
)
656 buf
.writestring("SwitchErrorStatement::toCBuffer()");
660 void visitReturn(ReturnStatement s
)
662 buf
.writestring("return ");
664 s
.exp
.expressionToBuffer(buf
, hgs
);
669 void visitBreak(BreakStatement s
)
671 buf
.writestring("break");
675 buf
.writestring(s
.ident
.toString());
681 void visitContinue(ContinueStatement s
)
683 buf
.writestring("continue");
687 buf
.writestring(s
.ident
.toString());
693 void visitSynchronized(SynchronizedStatement s
)
695 buf
.writestring("synchronized");
699 s
.exp
.expressionToBuffer(buf
, hgs
);
705 s
._body
.statementToBuffer(buf
, hgs
);
709 void visitWith(WithStatement s
)
711 buf
.writestring("with (");
712 s
.exp
.expressionToBuffer(buf
, hgs
);
713 buf
.writestring(")");
716 s
._body
.statementToBuffer(buf
, hgs
);
719 void visitTryCatch(TryCatchStatement s
)
721 buf
.writestring("try");
725 if (s
._body
.isScopeStatement())
727 s
._body
.statementToBuffer(buf
, hgs
);
732 s
._body
.statementToBuffer(buf
, hgs
);
736 foreach (c
; *s
.catches
)
738 buf
.writestring("catch");
742 typeToBuffer(c
.type
, c
.ident
, buf
, hgs
);
750 c
.handler
.statementToBuffer(buf
, hgs
);
757 void visitTryFinally(TryFinallyStatement s
)
759 buf
.writestring("try");
764 s
._body
.statementToBuffer(buf
, hgs
);
768 buf
.writestring("finally");
770 if (s
.finalbody
.isScopeStatement())
772 s
.finalbody
.statementToBuffer(buf
, hgs
);
777 s
.finalbody
.statementToBuffer(buf
, hgs
);
782 void visitScopeGuard(ScopeGuardStatement s
)
784 buf
.writestring(Token
.toString(s
.tok
));
787 s
.statement
.statementToBuffer(buf
, hgs
);
790 void visitThrow(ThrowStatement s
)
792 buf
.writestring("throw ");
793 s
.exp
.expressionToBuffer(buf
, hgs
);
798 void visitDebug(DebugStatement s
)
802 s
.statement
.statementToBuffer(buf
, hgs
);
806 void visitGoto(GotoStatement s
)
808 buf
.writestring("goto ");
809 buf
.writestring(s
.ident
.toString());
814 void visitLabel(LabelStatement s
)
816 buf
.writestring(s
.ident
.toString());
820 s
.statement
.statementToBuffer(buf
, hgs
);
823 void visitAsm(AsmStatement s
)
825 buf
.writestring("asm { ");
830 buf
.writestring(t
.toString());
832 t
.value
!= TOK
.min
&&
833 t
.value
!= TOK
.comma
&& t
.next
.value
!= TOK
.comma
&&
834 t
.value
!= TOK
.leftBracket
&& t
.next
.value
!= TOK
.leftBracket
&&
835 t
.next
.value
!= TOK
.rightBracket
&&
836 t
.value
!= TOK
.leftParenthesis
&& t
.next
.value
!= TOK
.leftParenthesis
&&
837 t
.next
.value
!= TOK
.rightParenthesis
&&
838 t
.value
!= TOK
.dot
&& t
.next
.value
!= TOK
.dot
)
845 buf
.writestring("; }");
849 void visitInlineAsm(InlineAsmStatement s
)
854 void visitGccAsm(GccAsmStatement s
)
859 void visitImport(ImportStatement s
)
861 foreach (imp
; *s
.imports
)
863 imp
.dsymbolToBuffer(buf
, hgs
);
867 mixin VisitStatement
!void visit
;
868 visit
.VisitStatement(s
);
871 private void dsymbolToBuffer(Dsymbol s
, ref OutBuffer buf
, ref HdrGenState hgs
)
873 toCBuffer(s
, buf
, hgs
);
876 void toCBuffer(Dsymbol s
, ref OutBuffer buf
, ref HdrGenState hgs
)
878 void visitDsymbol(Dsymbol s
)
880 buf
.writestring(s
.toChars());
883 void visitStaticAssert(StaticAssert s
)
885 buf
.writestring(s
.kind());
887 s
.exp
.expressionToBuffer(buf
, hgs
);
890 foreach (m
; (*s
.msgs
)[])
892 buf
.writestring(", ");
893 m
.expressionToBuffer(buf
, hgs
);
896 buf
.writestring(");");
900 void visitDebugSymbol(DebugSymbol s
)
902 buf
.writestring("debug = ");
904 buf
.writestring(s
.ident
.toString());
911 void visitVersionSymbol(VersionSymbol s
)
913 buf
.writestring("version = ");
915 buf
.writestring(s
.ident
.toString());
922 void visitEnumMember(EnumMember em
)
925 typeToBuffer(em
.type
, em
.ident
, buf
, hgs
);
927 buf
.writestring(em
.ident
.toString());
930 buf
.writestring(" = ");
931 em
.value
.expressionToBuffer(buf
, hgs
);
935 void visitImport(Import imp
)
937 if (hgs
.hdrgen
&& imp
.id
== Id
.object
)
938 return; // object is imported by default
940 buf
.writestring("static ");
941 buf
.writestring("import ");
944 buf
.printf("%s = ", imp
.aliasId
.toChars());
946 foreach (const pid
; imp
.packages
)
948 buf
.write(pid
.toString());
951 buf
.writestring(imp
.id
.toString());
952 if (imp
.names
.length
)
954 buf
.writestring(" : ");
955 foreach (const i
, const name
; imp
.names
)
958 buf
.writestring(", ");
959 const _alias
= imp
.aliases
[i
];
961 buf
.printf("%s = %s", _alias
.toChars(), name
.toChars());
963 buf
.writestring(name
.toChars());
970 void visitAliasThis(AliasThis d
)
972 buf
.writestring("alias ");
973 buf
.writestring(d
.ident
.toString());
974 buf
.writestring(" this;\n");
977 void visitAttribDeclaration(AttribDeclaration d
)
980 if (auto stcd
= d
.isStorageClassDeclaration
)
982 hasSTC
= stcToBuffer(buf
, stcd
.stc);
991 if (d
.decl
.length
== 0 ||
(hgs
.hdrgen
&& d
.decl
.length
== 1 && (*d
.decl
)[0].isUnitTestDeclaration()))
993 // hack for https://issues.dlang.org/show_bug.cgi?id=8081
994 if (hasSTC
) buf
.writeByte(' ');
995 buf
.writestring("{}");
997 else if (d
.decl
.length
== 1)
999 if (hasSTC
) buf
.writeByte(' ');
1000 toCBuffer((*d
.decl
)[0], buf
, hgs
);
1009 foreach (de; *d
.decl
)
1010 toCBuffer(de, buf
, hgs
);
1017 void visitStorageClassDeclaration(StorageClassDeclaration d
)
1019 visitAttribDeclaration(d
);
1022 void visitDeprecatedDeclaration(DeprecatedDeclaration d
)
1024 buf
.writestring("deprecated(");
1025 d
.msg
.expressionToBuffer(buf
, hgs
);
1026 buf
.writestring(") ");
1027 visitAttribDeclaration(d
);
1030 void visitLinkDeclaration(LinkDeclaration d
)
1032 buf
.writestring("extern (");
1033 buf
.writestring(linkageToString(d
.linkage
));
1034 buf
.writestring(") ");
1035 visitAttribDeclaration(d
);
1038 void visitCPPMangleDeclaration(CPPMangleDeclaration d
)
1041 final switch (d
.cppmangle
)
1043 case CPPMANGLE
.asClass
:
1046 case CPPMANGLE
.asStruct
:
1052 buf
.writestring("extern (C++, ");
1054 buf
.writestring(") ");
1055 visitAttribDeclaration(d
);
1058 void visitVisibilityDeclaration(VisibilityDeclaration d
)
1060 visibilityToBuffer(buf
, d
.visibility
);
1061 AttribDeclaration ad
= cast(AttribDeclaration
)d
;
1062 if (ad
.decl
.length
<= 1)
1064 if (ad
.decl
.length
== 1 && (*ad
.decl
)[0].isVisibilityDeclaration
)
1065 visitAttribDeclaration((*ad
.decl
)[0].isVisibilityDeclaration
);
1067 visitAttribDeclaration(d
);
1070 void visitAlignDeclaration(AlignDeclaration d
)
1074 foreach (i
, exp
; (*d
.exps
)[])
1078 buf
.writestring("align (");
1079 toCBuffer(exp
, buf
, hgs
);
1082 if (d
.decl
&& d
.decl
.length
< 2)
1086 buf
.writestring("align ");
1088 visitAttribDeclaration(d
.isAttribDeclaration());
1091 void visitAnonDeclaration(AnonDeclaration d
)
1093 buf
.writestring(d
.isunion ?
"union" : "struct");
1095 buf
.writestring("{");
1100 foreach (de; *d
.decl
)
1101 toCBuffer(de, buf
, hgs
);
1104 buf
.writestring("}");
1108 void visitPragmaDeclaration(PragmaDeclaration d
)
1110 buf
.writestring("pragma (");
1111 buf
.writestring(d
.ident
.toString());
1112 if (d
.args
&& d
.args
.length
)
1114 buf
.writestring(", ");
1115 argsToBuffer(d
.args
, buf
, hgs
);
1120 // https://issues.dlang.org/show_bug.cgi?id=14690
1121 // Unconditionally perform a full output dump
1122 // for `pragma(inline)` declarations.
1123 const saved
= hgs
.doFuncBodies
;
1124 if (d
.ident
== Id
.Pinline
)
1125 hgs
.doFuncBodies
= true;
1127 visitAttribDeclaration(d
);
1128 hgs
.doFuncBodies
= saved
;
1131 void visitConditionalDeclaration(ConditionalDeclaration d
)
1133 d
.condition
.conditionToBuffer(buf
, hgs
);
1134 if (d
.decl || d
.elsedecl
)
1142 foreach (de; *d
.decl
)
1143 toCBuffer(de, buf
, hgs
);
1150 buf
.writestring("else");
1155 foreach (de; *d
.elsedecl
)
1156 toCBuffer(de, buf
, hgs
);
1166 void visitStaticForeachDeclaration(StaticForeachDeclaration s
)
1168 void foreachWithoutBody(ForeachStatement s
)
1170 buf
.writestring(Token
.toString(s
.op
));
1171 buf
.writestring(" (");
1172 foreach (i
, p
; *s
.parameters
)
1175 buf
.writestring(", ");
1176 if (stcToBuffer(buf
, p
.storageClass
))
1179 typeToBuffer(p
.type
, p
.ident
, buf
, hgs
);
1181 buf
.writestring(p
.ident
.toString());
1183 buf
.writestring("; ");
1184 s
.aggr
.expressionToBuffer(buf
, hgs
);
1189 void foreachRangeWithoutBody(ForeachRangeStatement s
)
1191 /* s.op ( prm ; lwr .. upr )
1193 buf
.writestring(Token
.toString(s
.op
));
1194 buf
.writestring(" (");
1196 typeToBuffer(s
.prm
.type
, s
.prm
.ident
, buf
, hgs
);
1198 buf
.writestring(s
.prm
.ident
.toString());
1199 buf
.writestring("; ");
1200 s
.lwr
.expressionToBuffer(buf
, hgs
);
1201 buf
.writestring(" .. ");
1202 s
.upr
.expressionToBuffer(buf
, hgs
);
1207 buf
.writestring("static ");
1210 foreachWithoutBody(s
.sfe
.aggrfe
);
1214 assert(s
.sfe
.rangefe
);
1215 foreachRangeWithoutBody(s
.sfe
.rangefe
);
1220 visitAttribDeclaration(s
);
1227 void visitMixinDeclaration(MixinDeclaration d
)
1229 buf
.writestring("mixin(");
1230 argsToBuffer(d
.exps
, buf
, hgs
, null);
1231 buf
.writestring(");");
1235 void visitUserAttributeDeclaration(UserAttributeDeclaration d
)
1237 buf
.writestring("@(");
1238 argsToBuffer(d
.atts
, buf
, hgs
);
1240 visitAttribDeclaration(d
);
1243 void visitTemplateConstraint(Expression constraint
)
1247 buf
.writestring(" if (");
1248 constraint
.expressionToBuffer(buf
, hgs
);
1252 /// Returns: whether `do` is needed to write the function body
1253 bool contractsToBuffer(FuncDeclaration f
)
1255 bool requireDo
= false;
1259 foreach (frequire
; *f
.frequires
)
1261 buf
.writestring("in");
1262 if (auto es
= frequire
.isExpStatement())
1264 assert(es
.exp
&& es
.exp
.op
== EXP
.assert_
);
1265 buf
.writestring(" (");
1266 (cast(AssertExp
)es
.exp
).e1
.expressionToBuffer(buf
, hgs
);
1274 frequire
.statementToBuffer(buf
, hgs
);
1282 foreach (fensure
; *f
.fensures
)
1284 buf
.writestring("out");
1285 if (auto es
= fensure
.ensure
.isExpStatement())
1287 assert(es
.exp
&& es
.exp
.op
== EXP
.assert_
);
1288 buf
.writestring(" (");
1291 buf
.writestring(fensure
.id
.toString());
1293 buf
.writestring("; ");
1294 (cast(AssertExp
)es
.exp
).e1
.expressionToBuffer(buf
, hgs
);
1304 buf
.writestring(fensure
.id
.toString());
1308 fensure
.ensure
.statementToBuffer(buf
, hgs
);
1316 void bodyToBuffer(FuncDeclaration f
)
1318 if (!f
.fbody ||
(hgs
.hdrgen
&& hgs
.doFuncBodies
== false && !hgs
.autoMember
&& !hgs
.tpltMember
&& !hgs
.insideFuncBody
))
1320 if (!f
.fbody
&& (f
.fensures || f
.frequires
))
1323 contractsToBuffer(f
);
1330 // there is no way to know if a function is nested
1331 // or not after parsing. We need scope information
1332 // for that, which is avaible during semantic
1333 // analysis. To overcome that, a simple mechanism
1334 // is implemented: everytime we print a function
1335 // body (templated or not) we increment a counter.
1336 // We decredement the counter when we stop
1337 // printing the function body.
1338 ++hgs
.insideFuncBody
;
1339 scope(exit
) { --hgs
.insideFuncBody
; }
1341 const savetlpt
= hgs
.tpltMember
;
1342 const saveauto
= hgs
.autoMember
;
1346 bool requireDo
= contractsToBuffer(f
);
1350 buf
.writestring("do");
1356 f
.fbody
.statementToBuffer(buf
, hgs
);
1360 hgs
.tpltMember
= savetlpt
;
1361 hgs
.autoMember
= saveauto
;
1364 void visitBaseClasses(ClassDeclaration d
)
1366 if (!d ||
!d
.baseclasses
.length
)
1368 if (!d
.isAnonymous())
1369 buf
.writestring(" : ");
1370 foreach (i
, b
; *d
.baseclasses
)
1373 buf
.writestring(", ");
1374 typeToBuffer(b
.type
, null, buf
, hgs
);
1378 bool visitEponymousMember(TemplateDeclaration d
)
1380 if (!d
.members || d
.members
.length
!= 1)
1382 Dsymbol onemember
= (*d
.members
)[0];
1383 if (onemember
.ident
!= d
.ident
)
1385 if (FuncDeclaration fd
= onemember
.isFuncDeclaration())
1388 if (stcToBuffer(buf
, fd
.storage_class
))
1390 functionToBufferFull(cast(TypeFunction
)fd
.type
, buf
, d
.ident
, hgs
, d
);
1391 visitTemplateConstraint(d
.constraint
);
1397 if (AggregateDeclaration ad
= onemember
.isAggregateDeclaration())
1399 buf
.writestring(ad
.kind());
1401 buf
.writestring(ad
.ident
.toString());
1403 visitTemplateParameters(hgs
.ddoc ? d
.origParameters
: d
.parameters
, buf
, hgs
);
1405 visitTemplateConstraint(d
.constraint
);
1406 visitBaseClasses(ad
.isClassDeclaration());
1414 foreach (s
; *ad
.members
)
1415 toCBuffer(s
, buf
, hgs
);
1425 if (VarDeclaration vd
= onemember
.isVarDeclaration())
1429 if (stcToBuffer(buf
, vd
.storage_class
))
1432 typeToBuffer(vd
.type
, vd
.ident
, buf
, hgs
);
1434 buf
.writestring(vd
.ident
.toString());
1436 visitTemplateParameters(hgs
.ddoc ? d
.origParameters
: d
.parameters
, buf
, hgs
);
1440 buf
.writestring(" = ");
1441 ExpInitializer ie
= vd
._init
.isExpInitializer();
1442 if (ie
&& (ie
.exp
.op
== EXP
.construct || ie
.exp
.op
== EXP
.blit
))
1443 (cast(AssignExp
)ie
.exp
).e2
.expressionToBuffer(buf
, hgs
);
1445 vd
._init
.initializerToBuffer(buf
, hgs
);
1454 void visitTemplateDeclaration(TemplateDeclaration d
)
1458 // Should handle template functions for doc generation
1459 if (onemember
&& onemember
.isFuncDeclaration())
1460 buf
.writestring("foo ");
1462 if ((hgs
.hdrgen || hgs
.fullDump
) && visitEponymousMember(d
))
1465 buf
.writestring(d
.kind());
1467 buf
.writestring("template");
1469 buf
.writestring(d
.ident
.toString());
1471 visitTemplateParameters(hgs
.ddoc ? d
.origParameters
: d
.parameters
, buf
, hgs
);
1473 visitTemplateConstraint(d
.constraint
);
1474 if (hgs
.hdrgen || hgs
.fullDump
)
1481 foreach (s
; *d
.members
)
1482 toCBuffer(s
, buf
, hgs
);
1490 void visitTemplateInstance(TemplateInstance ti
)
1492 buf
.writestring(ti
.name
.toChars());
1493 tiargsToBuffer(ti
, buf
, hgs
);
1498 dumpTemplateInstance(ti
, buf
, hgs
);
1502 void visitTemplateMixin(TemplateMixin tm
)
1504 buf
.writestring("mixin ");
1505 typeToBuffer(tm
.tqual
, null, buf
, hgs
);
1506 tiargsToBuffer(tm
, buf
, hgs
);
1507 if (tm
.ident
&& memcmp(tm
.ident
.toString().ptr
, cast(const(char)*) "__mixin", 7) != 0)
1510 buf
.writestring(tm
.ident
.toString());
1515 dumpTemplateInstance(tm
, buf
, hgs
);
1518 void visitEnumDeclaration(EnumDeclaration d
)
1520 auto oldInEnumDecl
= hgs
.inEnumDecl
;
1521 scope(exit
) hgs
.inEnumDecl
= oldInEnumDecl
;
1523 buf
.writestring("enum ");
1526 buf
.writestring(d
.ident
.toString());
1530 buf
.writestring(" : ");
1531 typeToBuffer(d
.memtype
, null, buf
, hgs
);
1543 foreach (em
; *d
.members
)
1547 toCBuffer(em
, buf
, hgs
);
1555 if (!hgs
.importcHdr
)
1558 /* C enums get their members inserted into the symbol table of the enum declaration.
1559 * This is accomplished in addEnumMembersToSymtab().
1560 * But when generating D code from ImportC code, D rulez are followed.
1561 * Accomplish this by generating an alias declaration for each member
1563 foreach (em
; *d
.members
)
1567 buf
.writestring("alias ");
1568 buf
.writestring(em
.ident
.toString
);
1569 buf
.writestring(" = ");
1570 buf
.writestring(d
.ident
.toString
);
1572 buf
.writestring(em
.ident
.toString
);
1578 void visitNspace(Nspace d
)
1580 buf
.writestring("extern (C++, ");
1581 buf
.writestring(d
.ident
.toString());
1587 foreach (s
; *d
.members
)
1588 toCBuffer(s
, buf
, hgs
);
1594 void visitStructDeclaration(StructDeclaration d
)
1596 //printf("visitStructDeclaration() %s\n", d.ident.toChars());
1597 buf
.writestring(d
.kind());
1599 if (!d
.isAnonymous())
1600 buf
.writestring(d
.toChars());
1611 hgs
.insideAggregate
++;
1612 foreach (s
; *d
.members
)
1613 toCBuffer(s
, buf
, hgs
);
1614 hgs
.insideAggregate
--;
1620 void visitClassDeclaration(ClassDeclaration d
)
1622 if (!d
.isAnonymous())
1624 buf
.writestring(d
.kind());
1626 buf
.writestring(d
.ident
.toString());
1628 visitBaseClasses(d
);
1635 hgs
.insideAggregate
++;
1636 foreach (s
; *d
.members
)
1637 toCBuffer(s
, buf
, hgs
);
1638 hgs
.insideAggregate
--;
1647 void visitAliasDeclaration(AliasDeclaration d
)
1649 if (d
.storage_class
& STC
.local
)
1651 if (d
.adFlags
& d
.hidden
)
1653 buf
.writestring("alias ");
1656 buf
.writestring(d
.ident
.toString());
1657 buf
.writestring(" = ");
1658 if (stcToBuffer(buf
, d
.storage_class
))
1661 https://issues.dlang.org/show_bug.cgi?id=23223
1662 https://issues.dlang.org/show_bug.cgi?id=23222
1663 This special case (initially just for modules) avoids some segfaults
1664 and nicer -vcg-ast output.
1666 if (d
.aliassym
.isModule())
1668 buf
.writestring(d
.aliassym
.ident
.toString());
1672 toCBuffer(d
.aliassym
, buf
, hgs
);
1675 else if (d
.type
.ty
== Tfunction
)
1677 if (stcToBuffer(buf
, d
.storage_class
))
1679 typeToBuffer(d
.type
, d
.ident
, buf
, hgs
);
1683 hgs
.declstring
= (d
.ident
== Id
.string || d
.ident
== Id
.wstring || d
.ident
== Id
.dstring
);
1684 buf
.writestring(d
.ident
.toString());
1685 buf
.writestring(" = ");
1686 if (stcToBuffer(buf
, d
.storage_class
))
1688 typeToBuffer(d
.type
, null, buf
, hgs
);
1689 hgs
.declstring
= false;
1695 void visitAliasAssign(AliasAssign d
)
1697 buf
.writestring(d
.ident
.toString());
1698 buf
.writestring(" = ");
1700 toCBuffer(d
.aliassym
, buf
, hgs
);
1702 typeToBuffer(d
.type
, null, buf
, hgs
);
1707 void visitVarDeclaration(VarDeclaration d
)
1709 if (d
.storage_class
& STC
.local
)
1711 visitVarDecl(d
, false, buf
, hgs
);
1716 void visitFuncDeclaration(FuncDeclaration f
)
1718 //printf("FuncDeclaration::toCBuffer() '%s'\n", f.toChars());
1719 if (stcToBuffer(buf
, f
.storage_class
))
1721 auto tf
= f
.type
.isTypeFunction();
1722 typeToBuffer(tf
, f
.ident
, buf
, hgs
);
1726 // if the return type is missing (e.g. ref functions or auto)
1727 // https://issues.dlang.org/show_bug.cgi?id=20090
1728 // constructors are an exception: they don't have an explicit return
1729 // type but we still don't output the body.
1730 if ((!f
.isCtorDeclaration() && !tf
.next
) || f
.storage_class
& STC
.auto_
)
1736 else if (hgs
.tpltMember
== 0 && hgs
.doFuncBodies
== false && !hgs
.insideFuncBody
)
1740 // this can happen on interfaces / abstract functions, see `allowsContractWithoutBody`
1741 if (f
.fensures || f
.frequires
)
1743 contractsToBuffer(f
);
1755 void visitFuncLiteralDeclaration(FuncLiteralDeclaration f
)
1757 if (f
.type
.ty
== Terror
)
1759 buf
.writestring("__error");
1762 if (f
.tok
!= TOK
.reserved
)
1764 buf
.writestring(f
.kind());
1767 TypeFunction tf
= cast(TypeFunction
)f
.type
;
1769 if (!f
.inferRetType
&& tf
.next
)
1770 typeToBuffer(tf
.next
, null, buf
, hgs
);
1771 parametersToBuffer(tf
.parameterList
, buf
, hgs
);
1773 // https://issues.dlang.org/show_bug.cgi?id=20074
1774 void printAttribute(string
str)
1777 buf
.writestring(str);
1779 tf
.attributesApply(&printAttribute
);
1782 CompoundStatement cs
= f
.fbody
.isCompoundStatement();
1784 if (f
.semanticRun
>= PASS
.semantic3done
&& cs
)
1786 s1
= (*cs
.statements
)[cs
.statements
.length
- 1];
1789 s1
= !cs ? f
.fbody
: null;
1790 ReturnStatement rs
= s1 ? s1
.endsWithReturnStatement() : null;
1793 buf
.writestring(" => ");
1794 rs
.exp
.expressionToBuffer(buf
, hgs
);
1804 void visitPostBlitDeclaration(PostBlitDeclaration d
)
1806 if (stcToBuffer(buf
, d
.storage_class
))
1808 buf
.writestring("this(this)");
1812 void visitDtorDeclaration(DtorDeclaration d
)
1814 if (stcToBuffer(buf
, d
.storage_class
))
1816 buf
.writestring("~this()");
1820 void visitStaticCtorDeclaration(StaticCtorDeclaration d
)
1822 if (stcToBuffer(buf
, d
.storage_class
& ~STC
.static_
))
1824 if (d
.isSharedStaticCtorDeclaration())
1825 buf
.writestring("shared ");
1826 buf
.writestring("static this()");
1827 if (hgs
.hdrgen
&& !hgs
.tpltMember
)
1836 void visitStaticDtorDeclaration(StaticDtorDeclaration d
)
1838 if (stcToBuffer(buf
, d
.storage_class
& ~STC
.static_
))
1840 if (d
.isSharedStaticDtorDeclaration())
1841 buf
.writestring("shared ");
1842 buf
.writestring("static ~this()");
1843 if (hgs
.hdrgen
&& !hgs
.tpltMember
)
1852 void visitInvariantDeclaration(InvariantDeclaration d
)
1856 if (stcToBuffer(buf
, d
.storage_class
))
1858 buf
.writestring("invariant");
1859 if(auto es
= d
.fbody
.isExpStatement())
1861 assert(es
.exp
&& es
.exp
.op
== EXP
.assert_
);
1862 buf
.writestring(" (");
1863 (cast(AssertExp
)es
.exp
).e1
.expressionToBuffer(buf
, hgs
);
1864 buf
.writestring(");");
1873 void visitUnitTestDeclaration(UnitTestDeclaration d
)
1877 if (stcToBuffer(buf
, d
.storage_class
))
1879 buf
.writestring("unittest");
1883 void visitBitFieldDeclaration(BitFieldDeclaration d
)
1885 if (stcToBuffer(buf
, d
.storage_class
))
1887 Identifier id
= d
.isAnonymous() ?
null : d
.ident
;
1888 typeToBuffer(d
.type
, id
, buf
, hgs
);
1889 buf
.writestring(" : ");
1890 d
.width
.expressionToBuffer(buf
, hgs
);
1895 void visitNewDeclaration(NewDeclaration d
)
1897 if (stcToBuffer(buf
, d
.storage_class
& ~STC
.static_
))
1899 buf
.writestring("new();");
1902 void visitModule(Module m
)
1904 moduleToBuffer2(m
, buf
, hgs
);
1908 final class DsymbolPrettyPrintVisitor
: Visitor
1910 alias visit
= Visitor
.visit
;
1914 void visit(Dsymbol s
) { visitDsymbol(s
); }
1915 void visit(StaticAssert s
) { visitStaticAssert(s
); }
1916 void visit(DebugSymbol s
) { visitDebugSymbol(s
); }
1917 void visit(VersionSymbol s
) { visitVersionSymbol(s
); }
1918 void visit(EnumMember em
) { visitEnumMember(em
); }
1919 void visit(Import imp
) { visitImport(imp
); }
1920 void visit(AliasThis d
) { visitAliasThis(d
); }
1921 void visit(AttribDeclaration d
) { visitAttribDeclaration(d
); }
1922 void visit(StorageClassDeclaration d
) { visitStorageClassDeclaration(d
); }
1923 void visit(DeprecatedDeclaration d
) { visitDeprecatedDeclaration(d
); }
1924 void visit(LinkDeclaration d
) { visitLinkDeclaration(d
); }
1925 void visit(CPPMangleDeclaration d
) { visitCPPMangleDeclaration(d
); }
1926 void visit(VisibilityDeclaration d
) { visitVisibilityDeclaration(d
); }
1927 void visit(AlignDeclaration d
) { visitAlignDeclaration(d
); }
1928 void visit(AnonDeclaration d
) { visitAnonDeclaration(d
); }
1929 void visit(PragmaDeclaration d
) { visitPragmaDeclaration(d
); }
1930 void visit(ConditionalDeclaration d
) { visitConditionalDeclaration(d
); }
1931 void visit(StaticForeachDeclaration s
) { visitStaticForeachDeclaration(s
); }
1932 void visit(MixinDeclaration d
) { visitMixinDeclaration(d
); }
1933 void visit(UserAttributeDeclaration d
) { visitUserAttributeDeclaration(d
); }
1934 void visit(TemplateDeclaration d
) { visitTemplateDeclaration(d
); }
1935 void visit(TemplateInstance ti
) { visitTemplateInstance(ti
); }
1936 void visit(TemplateMixin tm
) { visitTemplateMixin(tm
); }
1937 void visit(EnumDeclaration d
) { visitEnumDeclaration(d
); }
1938 void visit(Nspace d
) { visitNspace(d
); }
1939 void visit(StructDeclaration d
) { visitStructDeclaration(d
); }
1940 void visit(ClassDeclaration d
) { visitClassDeclaration(d
); }
1941 void visit(AliasDeclaration d
) { visitAliasDeclaration(d
); }
1942 void visit(AliasAssign d
) { visitAliasAssign(d
); }
1943 void visit(VarDeclaration d
) { visitVarDeclaration(d
); }
1944 void visit(FuncDeclaration f
) { visitFuncDeclaration(f
); }
1945 void visit(FuncLiteralDeclaration f
) { visitFuncLiteralDeclaration(f
); }
1946 void visit(PostBlitDeclaration d
) { visitPostBlitDeclaration(d
); }
1947 void visit(DtorDeclaration d
) { visitDtorDeclaration(d
); }
1948 void visit(StaticCtorDeclaration d
) { visitStaticCtorDeclaration(d
); }
1949 void visit(StaticDtorDeclaration d
) { visitStaticDtorDeclaration(d
); }
1950 void visit(InvariantDeclaration d
) { visitInvariantDeclaration(d
); }
1951 void visit(UnitTestDeclaration d
) { visitUnitTestDeclaration(d
); }
1952 void visit(BitFieldDeclaration d
) { visitBitFieldDeclaration(d
); }
1953 void visit(NewDeclaration d
) { visitNewDeclaration(d
); }
1954 void visit(Module m
) { visitModule(m
); }
1957 scope v
= new DsymbolPrettyPrintVisitor();
1961 // Note: this function is not actually `const`, because iterating the
1962 // function parameter list may run dsymbolsemantic on enum types
1964 void toCharsMaybeConstraints(const TemplateDeclaration td
, ref OutBuffer buf
, ref HdrGenState hgs
)
1966 buf
.writestring(td
.ident
== Id
.ctor ?
"this" : td
.ident
.toString());
1968 foreach (i
, const tp
; *td
.parameters
)
1971 buf
.writestring(", ");
1972 toCBuffer(tp
, buf
, hgs
);
1978 if (const fd
= td
.onemember
.isFuncDeclaration())
1980 if (TypeFunction tf
= cast(TypeFunction
)fd
.type
.isTypeFunction())
1982 // !! Casted away const
1983 buf
.writestring(parametersTypeToChars(tf
.parameterList
));
1987 buf
.MODtoBuffer(tf
.mod
);
1993 if (!hgs
.skipConstraints
&&
1996 buf
.writestring(" if (");
1997 toCBuffer(td
.constraint
, buf
, hgs
);
2003 /*****************************************
2004 * Pretty-print a template parameter list to a buffer.
2006 private void visitTemplateParameters(TemplateParameters
* parameters
, ref OutBuffer buf
, ref HdrGenState hgs
)
2010 foreach (i
, p
; *parameters
)
2013 buf
.writestring(", ");
2014 toCBuffer(p
, buf
, hgs
);
2019 /*******************************************
2020 * Pretty-print a VarDeclaration to buf.
2022 private void visitVarDecl(VarDeclaration v
, bool anywritten
, ref OutBuffer buf
, ref HdrGenState hgs
)
2024 const bool isextern
= hgs
.hdrgen
&&
2025 !hgs
.insideFuncBody
&&
2027 !hgs
.insideAggregate
&&
2028 !(v
.storage_class
& STC
.manifest
);
2030 void vinit(VarDeclaration v
)
2032 auto ie
= v
._init
.isExpInitializer();
2033 if (ie
&& (ie
.exp
.op
== EXP
.construct || ie
.exp
.op
== EXP
.blit
))
2034 (cast(AssignExp
)ie
.exp
).e2
.expressionToBuffer(buf
, hgs
);
2036 v
._init
.initializerToBuffer(buf
, hgs
);
2039 const commentIt
= hgs
.importcHdr
&& isSpecialCName(v
.ident
);
2041 buf
.writestring("/+");
2045 buf
.writestring(", ");
2046 buf
.writestring(v
.ident
.toString());
2050 const bool useTypeof
= isextern
&& v
._init
&& !v
.type
;
2051 auto stc = v
.storage_class
;
2056 if (stcToBuffer(buf
, stc))
2059 typeToBuffer(v
.type
, v
.ident
, buf
, hgs
);
2062 buf
.writestring("typeof(");
2064 buf
.writestring(") ");
2065 buf
.writestring(v
.ident
.toString());
2068 buf
.writestring(v
.ident
.toString());
2070 if (v
._init
&& !isextern
)
2072 buf
.writestring(" = ");
2076 buf
.writestring("+/");
2079 /*************************************
2080 * The names __DATE__, __TIME__,__EOF__, __VENDOR__, __TIMESTAMP__, __VERSION__
2081 * are special to the D lexer and cannot be used as D source variable names.
2083 * id = name to check
2085 * true if special C name
2087 private bool isSpecialCName(Identifier id
)
2089 auto s
= id
.toString();
2090 if (s
.length
>= 7 && s
[0] == '_' && s
[1] == '_' &&
2095 id
== Id
.TIMESTAMP ||
2101 /*********************************************
2102 * Print expression to buffer.
2104 private void expressionPrettyPrint(Expression e
, ref OutBuffer buf
, ref HdrGenState hgs
)
2106 void visit(Expression e
)
2108 buf
.writestring(EXPtoString(e
.op
));
2111 void visitInteger(IntegerExp e
)
2113 const ulong v
= e
.toInteger();
2122 TypeEnum te
= cast(TypeEnum
)t
;
2124 if (sym
&& sym
.members
&& (!hgs
.inEnumDecl || hgs
.inEnumDecl
!= sym
))
2126 foreach (em
; *sym
.members
)
2128 if ((cast(EnumMember
)em
).value
.toInteger
== v
)
2130 const id
= em
.ident
.toString();
2131 buf
.printf("%s.%.*s", sym
.toChars(), cast(int)id
.length
, id
.ptr
);
2137 buf
.printf("cast(%s)", te
.sym
.toChars());
2145 const o
= buf
.length
;
2146 writeSingleCharLiteral(buf
, cast(dchar) v
);
2148 escapeDdocString(buf
, o
);
2152 buf
.writestring("cast(byte)");
2155 buf
.writestring("cast(short)");
2159 buf
.printf("%d", cast(int)v
);
2162 buf
.writestring("cast(ubyte)");
2165 buf
.writestring("cast(ushort)");
2168 buf
.printf("%uu", cast(uint)v
);
2173 // https://issues.dlang.org/show_bug.cgi?id=23173
2174 // This is a special case because - is not part of the
2175 // integer literal and 9223372036854775808L overflows a long
2176 buf
.writestring("cast(long)-9223372036854775808");
2180 buf
.printf("%lldL", v
);
2184 buf
.printf("%lluLU", v
);
2187 buf
.writestring(v ?
"true" : "false");
2190 buf
.writestring("cast(");
2192 HdrGenState hgs2
; // should re-examine need for new hgs
2193 hgs2
.fullQual
= (t
.ty
== Tclass
&& !t
.mod
);
2194 toCBuffer(t
, buf
, null, hgs2
);
2196 buf
.writestring(")cast(size_t)");
2200 buf
.writestring("cast(void)0");
2204 /* This can happen if errors, such as
2205 * the type is painted on like in fromConstInitializer().
2211 else if (v
& 0x8000000000000000L
)
2212 buf
.printf("0x%llx", v
);
2217 void visitError(ErrorExp e
)
2219 buf
.writestring("__error");
2222 void visitVoidInit(VoidInitExp e
)
2224 buf
.writestring("void");
2227 void floatToBuffer(Type type
, real_t value
)
2229 .floatToBuffer(type
, value
, buf
, hgs
.hdrgen
);
2232 void visitReal(RealExp e
)
2234 floatToBuffer(e
.type
, e
.value
);
2237 void visitComplex(ComplexExp e
)
2243 floatToBuffer(e
.type
, creall(e
.value
));
2245 floatToBuffer(e
.type
, cimagl(e
.value
));
2246 buf
.writestring("i)");
2249 void visitIdentifier(IdentifierExp e
)
2251 if (hgs
.hdrgen || hgs
.ddoc
)
2252 buf
.writestring(e
.ident
.toHChars2());
2254 buf
.writestring(e
.ident
.toString());
2257 void visitDsymbol(DsymbolExp e
)
2259 buf
.writestring(e
.s
.toChars());
2262 void visitThis(ThisExp e
)
2264 buf
.writestring("this");
2267 void visitSuper(SuperExp e
)
2269 buf
.writestring("super");
2272 void visitNull(NullExp e
)
2274 buf
.writestring("null");
2277 void visitString(StringExp e
)
2279 if (e
.hexString || e
.sz
== 8)
2283 buf
.writeHexString(e
.peekData
, true);
2286 buf
.writeByte(e
.postfix
);
2290 const o
= buf
.length
;
2291 foreach (i
; 0 .. e
.len
)
2293 writeCharLiteral(buf
, e
.getCodeUnit(i
));
2296 escapeDdocString(buf
, o
);
2299 buf
.writeByte(e
.postfix
);
2302 void visitInterpolation(InterpExp e
)
2306 const o
= buf
.length
;
2308 foreach (idx
, str; e
.interpolatedSet
.parts
)
2313 writeCharLiteral(buf
, ch
);
2326 escapeDdocString(buf
, o
);
2329 buf
.writeByte(e
.postfix
);
2333 void visitArrayLiteral(ArrayLiteralExp e
)
2336 argsToBuffer(e
.elements
, buf
, hgs
, e
.basis
);
2340 void visitAssocArrayLiteral(AssocArrayLiteralExp e
)
2343 foreach (i
, key
; *e
.keys
)
2346 buf
.writestring(", ");
2347 expToBuffer(key
, PREC
.assign
, buf
, hgs
);
2349 auto value
= (*e
.values
)[i
];
2350 expToBuffer(value
, PREC
.assign
, buf
, hgs
);
2355 void visitStructLiteral(StructLiteralExp e
)
2357 buf
.writestring(e
.sd
.toChars());
2359 // CTFE can generate struct literals that contain an AddrExp pointing
2360 // to themselves, need to avoid infinite recursion:
2361 // struct S { this(int){ this.s = &this; } S* s; }
2362 // const foo = new S(0);
2363 if (e
.stageflags
& stageToCBuffer
)
2364 buf
.writestring("<recursion>");
2367 const old
= e
.stageflags
;
2368 e
.stageflags |
= stageToCBuffer
;
2369 argsToBuffer(e
.elements
, buf
, hgs
);
2375 void visitCompoundLiteral(CompoundLiteralExp e
)
2378 typeToBuffer(e
.type
, null, buf
, hgs
);
2380 e
.initializer
.initializerToBuffer(buf
, hgs
);
2383 void visitType(TypeExp e
)
2385 typeToBuffer(e
.type
, null, buf
, hgs
);
2388 void visitScope(ScopeExp e
)
2390 if (e
.sds
.isTemplateInstance())
2392 e
.sds
.dsymbolToBuffer(buf
, hgs
);
2397 if (auto m
= e
.sds
.isModule())
2398 buf
.writestring(m
.md
.toChars());
2400 buf
.writestring(e
.sds
.toChars());
2404 buf
.writestring(e
.sds
.kind());
2406 buf
.writestring(e
.sds
.toChars());
2410 void visitTemplate(TemplateExp e
)
2412 buf
.writestring(e
.td
.toChars());
2415 void visitNew(NewExp e
)
2419 expToBuffer(e
.thisexp
, PREC
.primary
, buf
, hgs
);
2422 buf
.writestring("new ");
2423 typeToBuffer(e
.newtype
, null, buf
, hgs
);
2424 if (e
.arguments
&& e
.arguments
.length
)
2427 argsToBuffer(e
.arguments
, buf
, hgs
, null, e
.names
);
2432 void visitNewAnonClass(NewAnonClassExp e
)
2436 expToBuffer(e
.thisexp
, PREC
.primary
, buf
, hgs
);
2439 buf
.writestring("new");
2440 buf
.writestring(" class ");
2441 if (e
.arguments
&& e
.arguments
.length
)
2444 argsToBuffer(e
.arguments
, buf
, hgs
);
2448 e
.cd
.dsymbolToBuffer(buf
, hgs
);
2451 void visitSymOff(SymOffExp e
)
2454 buf
.printf("(& %s%+lld)", e
.var
.toChars(), e
.offset
);
2455 else if (e
.var
.isTypeInfoDeclaration())
2456 buf
.writestring(e
.var
.toChars());
2458 buf
.printf("& %s", e
.var
.toChars());
2461 void visitVar(VarExp e
)
2463 buf
.writestring(e
.var
.toChars());
2466 void visitOver(OverExp e
)
2468 buf
.writestring(e
.vars
.ident
.toString());
2471 void visitTuple(TupleExp e
)
2476 e
.e0
.expressionPrettyPrint(buf
, hgs
);
2477 buf
.writestring(", AliasSeq!(");
2478 argsToBuffer(e
.exps
, buf
, hgs
);
2479 buf
.writestring("))");
2483 buf
.writestring("AliasSeq!(");
2484 argsToBuffer(e
.exps
, buf
, hgs
);
2489 void visitFunc(FuncExp e
)
2491 e
.fd
.dsymbolToBuffer(buf
, hgs
);
2492 //buf.writestring(e.fd.toChars());
2495 void visitDeclaration(DeclarationExp e
)
2497 /* Normal dmd execution won't reach here - regular variable declarations
2498 * are handled in visit(ExpStatement), so here would be used only when
2499 * we'll directly call Expression.toChars() for debugging.
2503 if (auto var
= e
.declaration
.isVarDeclaration())
2505 // For debugging use:
2506 // - Avoid printing newline.
2507 // - Intentionally use the format (Type var;)
2508 // which isn't correct as regular D code.
2511 visitVarDecl(var
, false, buf
, hgs
);
2516 else e
.declaration
.dsymbolToBuffer(buf
, hgs
);
2520 void visitTypeid(TypeidExp e
)
2522 buf
.writestring("typeid(");
2523 objectToBuffer(e
.obj
, buf
, hgs
);
2527 void visitTraits(TraitsExp e
)
2529 buf
.writestring("__traits(");
2531 buf
.writestring(e
.ident
.toString());
2534 foreach (arg
; *e
.args
)
2536 buf
.writestring(", ");
2537 objectToBuffer(arg
, buf
, hgs
);
2543 void visitHalt(HaltExp e
)
2545 buf
.writestring("halt");
2548 void visitIs(IsExp e
)
2550 buf
.writestring("is(");
2551 typeToBuffer(e
.targ
, e
.id
, buf
, hgs
);
2552 if (e
.tok2
!= TOK
.reserved
)
2555 buf
.writestring(Token
.toString(e
.tok
));
2557 buf
.writestring(Token
.toString(e
.tok2
));
2561 if (e
.tok
== TOK
.colon
)
2562 buf
.writestring(" : ");
2564 buf
.writestring(" == ");
2565 typeToBuffer(e
.tspec
, null, buf
, hgs
);
2567 if (e
.parameters
&& e
.parameters
.length
)
2569 buf
.writestring(", ");
2570 visitTemplateParameters(e
.parameters
, buf
, hgs
);
2575 void visitUna(UnaExp e
)
2577 buf
.writestring(EXPtoString(e
.op
));
2578 expToBuffer(e
.e1
, precedence
[e
.op
], buf
, hgs
);
2581 void visitLoweredAssignExp(LoweredAssignExp e
)
2585 expressionToBuffer(e
.lowering
, buf
, hgs
);
2589 visit(cast(BinExp
)e
);
2591 void visitBin(BinExp e
)
2593 expToBuffer(e
.e1
, precedence
[e
.op
], buf
, hgs
);
2595 buf
.writestring(EXPtoString(e
.op
));
2597 expToBuffer(e
.e2
, cast(PREC
)(precedence
[e
.op
] + 1), buf
, hgs
);
2600 void visitComma(CommaExp e
)
2602 // CommaExp is generated by the compiler so it shouldn't
2603 // appear in error messages or header files.
2604 // For now, this treats the case where the compiler
2605 // generates CommaExp for temporaries by calling
2606 // the `sideeffect.copyToTemp` function.
2607 auto ve
= e
.e2
.isVarExp();
2609 // not a CommaExp introduced for temporaries, go on
2611 if (!ve ||
!(ve
.var
.storage_class
& STC
.temp
))
2613 visitBin(cast(BinExp
)e
);
2617 // CommaExp that contain temporaries inserted via
2618 // `copyToTemp` are usually of the form
2619 // ((T __temp = exp), __tmp).
2620 // Asserts are here to easily spot
2621 // missing cases where CommaExp
2622 // are used for other constructs
2623 auto vd
= ve
.var
.isVarDeclaration();
2624 assert(vd
&& vd
._init
);
2626 if (auto ei
= vd
._init
.isExpInitializer())
2628 Expression commaExtract
;
2630 if (auto ce
= exp
.isConstructExp())
2631 commaExtract
= ce
.e2
;
2632 else if (auto se
= exp
.isStructLiteralExp())
2637 expToBuffer(commaExtract
, precedence
[exp
.op
], buf
, hgs
);
2642 // not one of the known cases, go on the old path
2643 visitBin(cast(BinExp
)e
);
2647 void visitMixin(MixinExp e
)
2649 buf
.writestring("mixin(");
2650 argsToBuffer(e
.exps
, buf
, hgs
, null);
2654 void visitImport(ImportExp e
)
2656 buf
.writestring("import(");
2657 expToBuffer(e
.e1
, PREC
.assign
, buf
, hgs
);
2661 void visitAssert(AssertExp e
)
2663 buf
.writestring("assert(");
2664 expToBuffer(e
.e1
, PREC
.assign
, buf
, hgs
);
2667 buf
.writestring(", ");
2668 expToBuffer(e
.msg
, PREC
.assign
, buf
, hgs
);
2673 void visitThrow(ThrowExp e
)
2675 buf
.writestring("throw ");
2676 expToBuffer(e
.e1
, PREC
.unary
, buf
, hgs
);
2679 void visitDotId(DotIdExp e
)
2681 expToBuffer(e
.e1
, PREC
.primary
, buf
, hgs
);
2683 buf
.writestring("->");
2686 buf
.writestring(e
.ident
.toString());
2689 void visitDotTemplate(DotTemplateExp e
)
2691 expToBuffer(e
.e1
, PREC
.primary
, buf
, hgs
);
2693 buf
.writestring(e
.td
.toChars());
2696 void visitDotVar(DotVarExp e
)
2698 expToBuffer(e
.e1
, PREC
.primary
, buf
, hgs
);
2700 buf
.writestring(e
.var
.toChars());
2703 void visitDotTemplateInstance(DotTemplateInstanceExp e
)
2705 expToBuffer(e
.e1
, PREC
.primary
, buf
, hgs
);
2707 e
.ti
.dsymbolToBuffer(buf
, hgs
);
2710 void visitDelegate(DelegateExp e
)
2713 if (!e
.func
.isNested() || e
.func
.needThis())
2715 expToBuffer(e
.e1
, PREC
.primary
, buf
, hgs
);
2718 buf
.writestring(e
.func
.toChars());
2721 void visitDotType(DotTypeExp e
)
2723 expToBuffer(e
.e1
, PREC
.primary
, buf
, hgs
);
2725 buf
.writestring(e
.sym
.toChars());
2728 void visitCall(CallExp e
)
2730 if (e
.e1
.op
== EXP
.type
)
2732 /* Avoid parens around type to prevent forbidden cast syntax:
2734 * This is ok since types in constructor calls
2735 * can never depend on parens anyway
2737 e
.e1
.expressionPrettyPrint(buf
, hgs
);
2740 expToBuffer(e
.e1
, precedence
[e
.op
], buf
, hgs
);
2742 argsToBuffer(e
.arguments
, buf
, hgs
, null, e
.names
);
2746 void visitPtr(PtrExp e
)
2749 expToBuffer(e
.e1
, precedence
[e
.op
], buf
, hgs
);
2752 void visitDelete(DeleteExp e
)
2754 buf
.writestring("delete ");
2755 expToBuffer(e
.e1
, precedence
[e
.op
], buf
, hgs
);
2758 void visitCast(CastExp e
)
2760 buf
.writestring("cast(");
2762 typeToBuffer(e
.to
, null, buf
, hgs
);
2765 MODtoBuffer(buf
, e
.mod
);
2768 expToBuffer(e
.e1
, precedence
[e
.op
], buf
, hgs
);
2771 void visitVector(VectorExp e
)
2773 buf
.writestring("cast(");
2774 typeToBuffer(e
.to
, null, buf
, hgs
);
2776 expToBuffer(e
.e1
, precedence
[e
.op
], buf
, hgs
);
2779 void visitVectorArray(VectorArrayExp e
)
2781 expToBuffer(e
.e1
, PREC
.primary
, buf
, hgs
);
2782 buf
.writestring(".array");
2785 void visitSlice(SliceExp e
)
2787 expToBuffer(e
.e1
, precedence
[e
.op
], buf
, hgs
);
2792 sizeToBuffer(e
.lwr
, buf
, hgs
);
2795 buf
.writestring("..");
2797 sizeToBuffer(e
.upr
, buf
, hgs
);
2804 void visitArrayLength(ArrayLengthExp e
)
2806 expToBuffer(e
.e1
, PREC
.primary
, buf
, hgs
);
2807 buf
.writestring(".length");
2810 void visitInterval(IntervalExp e
)
2812 expToBuffer(e
.lwr
, PREC
.assign
, buf
, hgs
);
2813 buf
.writestring("..");
2814 expToBuffer(e
.upr
, PREC
.assign
, buf
, hgs
);
2817 void visitDelegatePtr(DelegatePtrExp e
)
2819 expToBuffer(e
.e1
, PREC
.primary
, buf
, hgs
);
2820 buf
.writestring(".ptr");
2823 void visitDelegateFuncptr(DelegateFuncptrExp e
)
2825 expToBuffer(e
.e1
, PREC
.primary
, buf
, hgs
);
2826 buf
.writestring(".funcptr");
2829 void visitArray(ArrayExp e
)
2831 expToBuffer(e
.e1
, PREC
.primary
, buf
, hgs
);
2833 argsToBuffer(e
.arguments
, buf
, hgs
);
2837 void visitDot(DotExp e
)
2839 expToBuffer(e
.e1
, PREC
.primary
, buf
, hgs
);
2841 expToBuffer(e
.e2
, PREC
.primary
, buf
, hgs
);
2844 void visitIndex(IndexExp e
)
2846 expToBuffer(e
.e1
, PREC
.primary
, buf
, hgs
);
2848 sizeToBuffer(e
.e2
, buf
, hgs
);
2852 void visitPost(PostExp e
)
2854 expToBuffer(e
.e1
, precedence
[e
.op
], buf
, hgs
);
2855 buf
.writestring(EXPtoString(e
.op
));
2858 void visitPre(PreExp e
)
2860 buf
.writestring(EXPtoString(e
.op
));
2861 expToBuffer(e
.e1
, precedence
[e
.op
], buf
, hgs
);
2864 void visitRemove(RemoveExp e
)
2866 expToBuffer(e
.e1
, PREC
.primary
, buf
, hgs
);
2867 buf
.writestring(".remove(");
2868 expToBuffer(e
.e2
, PREC
.assign
, buf
, hgs
);
2872 void visitCond(CondExp e
)
2874 expToBuffer(e
.econd
, PREC
.oror
, buf
, hgs
);
2875 buf
.writestring(" ? ");
2876 expToBuffer(e
.e1
, PREC
.expr
, buf
, hgs
);
2877 buf
.writestring(" : ");
2878 expToBuffer(e
.e2
, PREC
.cond
, buf
, hgs
);
2881 void visitDefaultInit(DefaultInitExp e
)
2883 buf
.writestring(EXPtoString(e
.op
));
2886 void visitClassReference(ClassReferenceExp e
)
2888 buf
.writestring(e
.value
.toChars());
2894 if (auto be
= e
.isBinExp())
2895 return visitBin(be
);
2896 else if (auto ue
= e
.isUnaExp())
2897 return visitUna(ue
);
2898 else if (auto de = e
.isDefaultInitExp())
2899 return visitDefaultInit(e
.isDefaultInitExp());
2902 case EXP
.int64
: return visitInteger(e
.isIntegerExp());
2903 case EXP
.error
: return visitError(e
.isErrorExp());
2904 case EXP
.void_
: return visitVoidInit(e
.isVoidInitExp());
2905 case EXP
.float64
: return visitReal(e
.isRealExp());
2906 case EXP
.complex80
: return visitComplex(e
.isComplexExp());
2907 case EXP
.identifier
: return visitIdentifier(e
.isIdentifierExp());
2908 case EXP
.dSymbol
: return visitDsymbol(e
.isDsymbolExp());
2909 case EXP
.this_
: return visitThis(e
.isThisExp());
2910 case EXP
.super_
: return visitSuper(e
.isSuperExp());
2911 case EXP
.null_
: return visitNull(e
.isNullExp());
2912 case EXP
.string_
: return visitString(e
.isStringExp());
2913 case EXP
.interpolated
: return visitInterpolation(e
.isInterpExp());
2914 case EXP
.arrayLiteral
: return visitArrayLiteral(e
.isArrayLiteralExp());
2915 case EXP
.assocArrayLiteral
: return visitAssocArrayLiteral(e
.isAssocArrayLiteralExp());
2916 case EXP
.structLiteral
: return visitStructLiteral(e
.isStructLiteralExp());
2917 case EXP
.compoundLiteral
: return visitCompoundLiteral(e
.isCompoundLiteralExp());
2918 case EXP
.type
: return visitType(e
.isTypeExp());
2919 case EXP
.scope_
: return visitScope(e
.isScopeExp());
2920 case EXP
.template_
: return visitTemplate(e
.isTemplateExp());
2921 case EXP
.new_
: return visitNew(e
.isNewExp());
2922 case EXP
.newAnonymousClass
: return visitNewAnonClass(e
.isNewAnonClassExp());
2923 case EXP
.symbolOffset
: return visitSymOff(e
.isSymOffExp());
2924 case EXP
.variable
: return visitVar(e
.isVarExp());
2925 case EXP
.overloadSet
: return visitOver(e
.isOverExp());
2926 case EXP
.tuple
: return visitTuple(e
.isTupleExp());
2927 case EXP
.function_
: return visitFunc(e
.isFuncExp());
2928 case EXP
.declaration
: return visitDeclaration(e
.isDeclarationExp());
2929 case EXP
.typeid_
: return visitTypeid(e
.isTypeidExp());
2930 case EXP
.traits
: return visitTraits(e
.isTraitsExp());
2931 case EXP
.halt
: return visitHalt(e
.isHaltExp());
2932 case EXP
.is_
: return visitIs(e
.isExp());
2933 case EXP
.comma
: return visitComma(e
.isCommaExp());
2934 case EXP
.mixin_
: return visitMixin(e
.isMixinExp());
2935 case EXP
.import_
: return visitImport(e
.isImportExp());
2936 case EXP
.assert_
: return visitAssert(e
.isAssertExp());
2937 case EXP
.throw_
: return visitThrow(e
.isThrowExp());
2938 case EXP
.dotIdentifier
: return visitDotId(e
.isDotIdExp());
2939 case EXP
.dotTemplateDeclaration
: return visitDotTemplate(e
.isDotTemplateExp());
2940 case EXP
.dotVariable
: return visitDotVar(e
.isDotVarExp());
2941 case EXP
.dotTemplateInstance
: return visitDotTemplateInstance(e
.isDotTemplateInstanceExp());
2942 case EXP
.delegate_
: return visitDelegate(e
.isDelegateExp());
2943 case EXP
.dotType
: return visitDotType(e
.isDotTypeExp());
2944 case EXP
.call: return visitCall(e
.isCallExp());
2945 case EXP
.star
: return visitPtr(e
.isPtrExp());
2946 case EXP
.delete_
: return visitDelete(e
.isDeleteExp());
2947 case EXP
.cast_
: return visitCast(e
.isCastExp());
2948 case EXP
.vector
: return visitVector(e
.isVectorExp());
2949 case EXP
.vectorArray
: return visitVectorArray(e
.isVectorArrayExp());
2950 case EXP
.slice
: return visitSlice(e
.isSliceExp());
2951 case EXP
.arrayLength
: return visitArrayLength(e
.isArrayLengthExp());
2952 case EXP
.interval
: return visitInterval(e
.isIntervalExp());
2953 case EXP
.delegatePointer
: return visitDelegatePtr(e
.isDelegatePtrExp());
2954 case EXP
.delegateFunctionPointer
: return visitDelegateFuncptr(e
.isDelegateFuncptrExp());
2955 case EXP
.array
: return visitArray(e
.isArrayExp());
2956 case EXP
.dot
: return visitDot(e
.isDotExp());
2957 case EXP
.index
: return visitIndex(e
.isIndexExp());
2958 case EXP
.minusMinus
:
2959 case EXP
.plusPlus
: return visitPost(e
.isPostExp());
2960 case EXP
.preMinusMinus
:
2961 case EXP
.prePlusPlus
: return visitPre(e
.isPreExp());
2962 case EXP
.remove
: return visitRemove(e
.isRemoveExp());
2963 case EXP
.question
: return visitCond(e
.isCondExp());
2964 case EXP
.classReference
: return visitClassReference(e
.isClassReferenceExp());
2965 case EXP
.loweredAssignExp
: return visitLoweredAssignExp(e
.isLoweredAssignExp());
2970 * Formats `value` as a literal of type `type` into `buf`.
2973 * type = literal type (e.g. Tfloat)
2974 * value = value to print
2975 * buf = target buffer
2976 * allowHex = whether hex floating point literals may be used
2977 * for greater accuracy
2979 void floatToBuffer(Type type
, const real_t value
, ref OutBuffer buf
, const bool allowHex
)
2981 /** sizeof(value)*3 is because each byte of mantissa is max
2982 of 256 (3 characters). The string will be "-M.MMMMe-4932".
2983 (ie, 8 chars more than mantissa). Plus one for trailing \0.
2984 Plus one for rounding. */
2985 const(size_t
) BUFFER_LEN
= value
.sizeof
* 3 + 8 + 1 + 1;
2986 char[BUFFER_LEN
] buffer
= void;
2987 CTFloat
.sprint(buffer
.ptr
, BUFFER_LEN
, 'g', value
);
2988 assert(strlen(buffer
.ptr
) < BUFFER_LEN
);
2992 real_t r
= CTFloat
.parse(buffer
.ptr
, isOutOfRange
);
2993 //assert(!isOutOfRange); // test/compilable/test22725.c asserts here
2994 if (r
!= value
) // if exact duplication
2995 CTFloat
.sprint(buffer
.ptr
, BUFFER_LEN
, 'a', value
);
2997 buf
.writestring(buffer
.ptr
);
2998 if (buffer
.ptr
[strlen(buffer
.ptr
) - 1] == '.')
2999 buf
.remove(buf
.length() - 1, 1);
3003 Type t
= type
.toBasetype();
3019 if (t
.isimaginary())
3024 void toCBuffer(const TemplateParameter tp
, ref OutBuffer buf
, ref HdrGenState hgs
)
3026 scope v
= new TemplateParameterPrettyPrintVisitor(&buf
, &hgs
);
3027 (cast() tp
).accept(v
);
3030 private extern (C
++) final class TemplateParameterPrettyPrintVisitor
: Visitor
3032 alias visit
= Visitor
.visit
;
3037 extern (D
) this(OutBuffer
* buf
, HdrGenState
* hgs
) scope @safe
3043 override void visit(TemplateTypeParameter tp
)
3045 buf
.writestring(tp
.ident
.toString());
3048 buf
.writestring(" : ");
3049 typeToBuffer(tp
.specType
, null, *buf
, *hgs
);
3053 buf
.writestring(" = ");
3054 typeToBuffer(tp
.defaultType
, null, *buf
, *hgs
);
3058 override void visit(TemplateThisParameter tp
)
3060 buf
.writestring("this ");
3061 visit(cast(TemplateTypeParameter
)tp
);
3064 override void visit(TemplateAliasParameter tp
)
3066 buf
.writestring("alias ");
3068 typeToBuffer(tp
.specType
, tp
.ident
, *buf
, *hgs
);
3070 buf
.writestring(tp
.ident
.toString());
3073 buf
.writestring(" : ");
3074 objectToBuffer(tp
.specAlias
, *buf
, *hgs
);
3076 if (tp
.defaultAlias
)
3078 buf
.writestring(" = ");
3079 objectToBuffer(tp
.defaultAlias
, *buf
, *hgs
);
3083 override void visit(TemplateValueParameter tp
)
3085 typeToBuffer(tp
.valType
, tp
.ident
, *buf
, *hgs
);
3088 buf
.writestring(" : ");
3089 tp
.specValue
.expressionToBuffer(*buf
, *hgs
);
3091 if (tp
.defaultValue
)
3093 buf
.writestring(" = ");
3094 tp
.defaultValue
.expressionToBuffer(*buf
, *hgs
);
3098 override void visit(TemplateTupleParameter tp
)
3100 buf
.writestring(tp
.ident
.toString());
3101 buf
.writestring("...");
3105 private void conditionToBuffer(Condition c
, ref OutBuffer buf
, ref HdrGenState hgs
)
3107 scope v
= new ConditionPrettyPrintVisitor(&buf
, &hgs
);
3111 private extern (C
++) final class ConditionPrettyPrintVisitor
: Visitor
3113 alias visit
= Visitor
.visit
;
3118 extern (D
) this(OutBuffer
* buf
, HdrGenState
* hgs
) scope @safe
3124 override void visit(DebugCondition c
)
3126 buf
.writestring("debug (");
3128 buf
.writestring(c
.ident
.toString());
3134 override void visit(VersionCondition c
)
3136 buf
.writestring("version (");
3138 buf
.writestring(c
.ident
.toString());
3144 override void visit(StaticIfCondition c
)
3146 buf
.writestring("static if (");
3147 c
.exp
.expressionToBuffer(*buf
, *hgs
);
3152 void toCBuffer(const Statement s
, ref OutBuffer buf
, ref HdrGenState hgs
)
3154 (cast()s
).statementToBuffer(buf
, hgs
);
3157 void toCBuffer(const Type t
, ref OutBuffer buf
, const Identifier ident
, ref HdrGenState hgs
)
3159 typeToBuffer(cast() t
, ident
, buf
, hgs
);
3162 // used from TemplateInstance::toChars() and TemplateMixin::toChars()
3163 void toCBufferInstance(const TemplateInstance ti
, ref OutBuffer buf
, bool qualifyTypes
= false)
3166 hgs
.fullQual
= qualifyTypes
;
3168 buf
.writestring(ti
.name
.toChars());
3169 tiargsToBuffer(cast() ti
, buf
, hgs
);
3172 void toCBuffer(const Initializer iz
, ref OutBuffer buf
, ref HdrGenState hgs
)
3174 initializerToBuffer(cast() iz
, buf
, hgs
);
3177 bool stcToBuffer(ref OutBuffer buf
, StorageClass
stc) @safe
3179 //printf("stc: %llx\n", stc);
3180 bool result
= false;
3182 if (stc & STC
.scopeinferred
)
3184 //buf.writestring("scope-inferred ");
3185 stc &= ~(STC
.scope_ | STC
.scopeinferred
);
3187 if (stc & STC
.returninferred
)
3189 //buf.writestring((stc & STC.returnScope) ? "return-scope-inferred " : "return-ref-inferred ");
3190 stc &= ~(STC
.return_ | STC
.returninferred
);
3193 /* Put scope ref return into a standard order
3196 const isout
= (stc & STC
.out_
) != 0;
3197 //printf("bsr = %d %llx\n", buildScopeRef(stc), stc);
3198 final switch (buildScopeRef(stc))
3201 case ScopeRef
.Scope
:
3203 case ScopeRef
.Return
:
3206 case ScopeRef
.ReturnScope
: rrs
= "return scope"; goto L1
;
3207 case ScopeRef
.ReturnRef
: rrs
= isout ?
"return out" : "return ref"; goto L1
;
3208 case ScopeRef
.RefScope
: rrs
= isout ?
"out scope" : "ref scope"; goto L1
;
3209 case ScopeRef
.ReturnRef_Scope
: rrs
= isout ?
"return out scope" : "return ref scope"; goto L1
;
3210 case ScopeRef
.Ref_ReturnScope
: rrs
= isout ?
"out return scope" : "ref return scope"; goto L1
;
3212 buf
.writestring(rrs
);
3214 stc &= ~(STC
.out_ | STC
.scope_ | STC
.ref_ | STC
.return_
);
3220 const s
= stcToString(stc);
3232 /*************************************************
3233 * Pick off one of the storage classes from stc,
3234 * and return a string representation of it.
3235 * stc is reduced by the one picked.
3237 string
stcToString(ref StorageClass
stc) @safe
3239 static struct SCstring
3245 // Note: The identifier needs to be `\0` terminated
3246 // as some code assumes it (e.g. when printing error messages)
3247 static immutable SCstring
[] table
=
3249 SCstring(STC
.auto_
, Token
.toString(TOK
.auto_
)),
3250 SCstring(STC
.scope_
, Token
.toString(TOK
.scope_
)),
3251 SCstring(STC
.static_
, Token
.toString(TOK
.static_
)),
3252 SCstring(STC
.extern_
, Token
.toString(TOK
.extern_
)),
3253 SCstring(STC
.const_
, Token
.toString(TOK
.const_
)),
3254 SCstring(STC
.final_
, Token
.toString(TOK
.final_
)),
3255 SCstring(STC
.abstract_
, Token
.toString(TOK
.abstract_
)),
3256 SCstring(STC
.synchronized_
, Token
.toString(TOK
.synchronized_
)),
3257 SCstring(STC
.deprecated_
, Token
.toString(TOK
.deprecated_
)),
3258 SCstring(STC
.override_
, Token
.toString(TOK
.override_
)),
3259 SCstring(STC
.lazy_
, Token
.toString(TOK
.lazy_
)),
3260 SCstring(STC
.alias_
, Token
.toString(TOK
.alias_
)),
3261 SCstring(STC
.out_
, Token
.toString(TOK
.out_
)),
3262 SCstring(STC
.in_
, Token
.toString(TOK
.in_
)),
3263 SCstring(STC
.manifest
, Token
.toString(TOK
.enum_
)),
3264 SCstring(STC
.immutable_
, Token
.toString(TOK
.immutable_
)),
3265 SCstring(STC
.shared_
, Token
.toString(TOK
.shared_
)),
3266 SCstring(STC
.nothrow_
, Token
.toString(TOK
.nothrow_
)),
3267 SCstring(STC
.wild
, Token
.toString(TOK
.inout_
)),
3268 SCstring(STC
.pure_
, Token
.toString(TOK
.pure_
)),
3269 SCstring(STC
.ref_
, Token
.toString(TOK
.ref_
)),
3270 SCstring(STC
.return_
, Token
.toString(TOK
.return_
)),
3271 SCstring(STC
.gshared
, Token
.toString(TOK
.gshared
)),
3272 SCstring(STC
.nogc
, "@nogc"),
3273 SCstring(STC
.live
, "@live"),
3274 SCstring(STC
.property
, "@property"),
3275 SCstring(STC
.safe
, "@safe"),
3276 SCstring(STC
.trusted
, "@trusted"),
3277 SCstring(STC
.system
, "@system"),
3278 SCstring(STC
.disable
, "@disable"),
3279 SCstring(STC
.future
, "@__future"),
3280 SCstring(STC
.local
, "__local"),
3282 foreach (ref entry
; table
)
3284 const StorageClass tbl
= entry
.stc;
3285 assert(tbl
& STC
.visibleStorageClasses
);
3292 //printf("stc = %llx\n", stc);
3296 private void linkageToBuffer(ref OutBuffer buf
, LINK linkage
) @safe
3298 const s
= linkageToString(linkage
);
3301 buf
.writestring("extern (");
3307 const(char)* linkageToChars(LINK linkage
)
3309 /// Works because we return a literal
3310 return linkageToString(linkage
).ptr
;
3313 string
linkageToString(LINK linkage
) pure nothrow @safe
3317 immutable string
[7] a
= [
3322 windows
: "Windows",
3323 objc
: "Objective-C",
3324 system
: "System" ];
3329 void visibilityToBuffer(ref OutBuffer buf
, Visibility vis
)
3331 buf
.writestring(visibilityToString(vis
.kind
));
3332 if (vis
.kind
== Visibility
.Kind
.package_
&& vis
.pkg
)
3335 buf
.writestring(vis
.pkg
.toPrettyChars(true));
3342 * a human readable representation of `kind`
3344 const(char)* visibilityToChars(Visibility
.Kind kind
)
3346 // Null terminated because we return a literal
3347 return visibilityToString(kind
).ptr
;
3351 extern (D
) string
visibilityToString(Visibility
.Kind kind
) nothrow pure @safe
3353 with (Visibility
.Kind
)
3355 immutable string
[7] a
= [
3357 private_
: "private",
3358 package_
: "package",
3359 protected_
: "protected",
3361 export_
: "export" ];
3366 // Print the full function signature with correct ident, attributes and template args
3367 void functionToBufferFull(TypeFunction tf
, ref OutBuffer buf
, const Identifier ident
, ref HdrGenState hgs
, TemplateDeclaration td
)
3369 //printf("TypeFunction::toCBuffer() this = %p\n", this);
3370 visitFuncIdentWithPrefix(tf
, ident
, td
, buf
, hgs
);
3373 // ident is inserted before the argument list and will be "function" or "delegate" for a type
3374 void functionToBufferWithIdent(TypeFunction tf
, ref OutBuffer buf
, const(char)* ident
, bool isStatic
)
3377 visitFuncIdentWithPostfix(tf
, ident
.toDString(), buf
, hgs
, isStatic
);
3380 void toCBuffer(const Expression e
, ref OutBuffer buf
, ref HdrGenState hgs
)
3382 expressionPrettyPrint(cast()e
, buf
, hgs
);
3385 /**************************************************
3386 * Write out argument types to buf.
3388 void argExpTypesToCBuffer(ref OutBuffer buf
, Expressions
* arguments
)
3390 if (!arguments ||
!arguments
.length
)
3393 foreach (i
, arg
; *arguments
)
3396 buf
.writestring(", ");
3397 typeToBuffer(arg
.type
, null, buf
, hgs
);
3401 void arrayObjectsToBuffer(ref OutBuffer buf
, Objects
* objects
)
3403 if (!objects ||
!objects
.length
)
3406 foreach (i
, o
; *objects
)
3409 buf
.writestring(", ");
3410 objectToBuffer(o
, buf
, hgs
);
3414 /*************************************************************
3415 * Pretty print function parameters.
3417 * pl = parameter list to print
3418 * Returns: Null-terminated string representing parameters.
3420 extern (C
++) const(char)* parametersTypeToChars(ParameterList pl
)
3424 parametersToBuffer(pl
, buf
, hgs
);
3425 return buf
.extractChars();
3428 /*************************************************************
3429 * Pretty print function parameter.
3431 * parameter = parameter to print.
3432 * tf = TypeFunction which holds parameter.
3433 * fullQual = whether to fully qualify types.
3434 * Returns: Null-terminated string representing parameters.
3436 const(char)* parameterToChars(Parameter parameter
, TypeFunction tf
, bool fullQual
)
3440 hgs
.fullQual
= fullQual
;
3442 parameterToBuffer(parameter
, buf
, hgs
);
3444 if (tf
.parameterList
.varargs
== VarArg
.typesafe
&& parameter
== tf
.parameterList
[tf
.parameterList
.parameters
.length
- 1])
3446 buf
.writestring("...");
3448 return buf
.extractChars();
3452 /*************************************************
3453 * Write ParameterList to buffer.
3455 * pl = parameter list to serialize
3456 * buf = buffer to write it to
3460 private void parametersToBuffer(ParameterList pl
, ref OutBuffer buf
, ref HdrGenState hgs
)
3463 foreach (i
; 0 .. pl
.length
)
3466 buf
.writestring(", ");
3467 pl
[i
].parameterToBuffer(buf
, hgs
);
3469 final switch (pl
.varargs
)
3472 case VarArg
.KRvariadic
:
3475 case VarArg
.variadic
:
3477 buf
.writestring(", ");
3479 if (stcToBuffer(buf
, pl
.stc))
3481 goto case VarArg
.typesafe
;
3483 case VarArg
.typesafe
:
3484 buf
.writestring("...");
3491 /***********************************************************
3492 * Write parameter `p` to buffer `buf`.
3494 * p = parameter to serialize
3495 * buf = buffer to write it to
3498 private void parameterToBuffer(Parameter p
, ref OutBuffer buf
, ref HdrGenState hgs
)
3500 if (p
.userAttribDecl
)
3504 bool isAnonymous
= p
.userAttribDecl
.atts
.length
> 0 && !(*p
.userAttribDecl
.atts
)[0].isCallExp();
3508 argsToBuffer(p
.userAttribDecl
.atts
, buf
, hgs
);
3514 if (p
.storageClass
& STC
.auto_
)
3515 buf
.writestring("auto ");
3517 StorageClass
stc = p
.storageClass
;
3518 if (p
.storageClass
& STC
.in_
)
3520 buf
.writestring("in ");
3521 if ((p
.storageClass
& (STC
.constscoperef | STC
.ref_
)) == (STC
.constscoperef | STC
.ref_
))
3524 else if (p
.storageClass
& STC
.lazy_
)
3525 buf
.writestring("lazy ");
3526 else if (p
.storageClass
& STC
.alias_
)
3527 buf
.writestring("alias ");
3529 if (p
.type
&& p
.type
.mod
& MODFlags
.shared_
)
3530 stc &= ~STC
.shared_
;
3532 if (stcToBuffer(buf
, stc & (STC
.const_ | STC
.immutable_ | STC
.wild | STC
.shared_ |
3533 STC
.return_ | STC
.returninferred | STC
.scope_ | STC
.scopeinferred | STC
.out_ | STC
.ref_ | STC
.returnScope
)))
3537 if (p
.storageClass
& STC
.alias_
)
3540 buf
.writestring(p
.ident
.toString());
3542 else if (p
.type
.isTypeIdentifier() &&
3543 (s
= p
.type
.isTypeIdentifier().ident
.toString()).length
> 3 &&
3546 // print parameter name, instead of undetermined type parameter
3547 buf
.writestring(p
.ident
.toString());
3551 typeToBuffer(p
.type
, p
.ident
, buf
, hgs
, (stc & STC
.in_
) ? MODFlags
.const_
: 0);
3556 buf
.writestring(" = ");
3557 p
.defaultArg
.expToBuffer(PREC
.assign
, buf
, hgs
);
3562 /**************************************************
3563 * Write out argument list to buf.
3565 * expressions = argument list
3566 * buf = buffer to write to
3568 * basis = replace `null`s in argument list with this expression (for sparse array literals)
3569 * names = if non-null, use these as the names for the arguments
3571 private void argsToBuffer(Expressions
* expressions
, ref OutBuffer buf
, ref HdrGenState hgs
, Expression basis
= null, Identifiers
* names
= null)
3573 if (!expressions ||
!expressions
.length
)
3577 foreach (i
, el
; *expressions
)
3580 buf
.writestring(", ");
3582 if (names
&& i
< names
.length
&& (*names
)[i
])
3584 buf
.writestring((*names
)[i
].toString());
3585 buf
.writestring(": ");
3590 expToBuffer(el
, PREC
.assign
, buf
, hgs
);
3595 // Sparse style formatting, for debug use only
3596 // [0..length: basis, 1: e1, 5: e5]
3599 buf
.writestring("0..");
3600 buf
.print(expressions
.length
);
3601 buf
.writestring(": ");
3602 expToBuffer(basis
, PREC
.assign
, buf
, hgs
);
3604 foreach (i
, el
; *expressions
)
3610 buf
.writestring(", ");
3612 buf
.writestring(": ");
3615 buf
.writestring(", ");
3616 expToBuffer(el
, PREC
.assign
, buf
, hgs
);
3622 private void sizeToBuffer(Expression e
, ref OutBuffer buf
, ref HdrGenState hgs
)
3624 if (e
.type
== Type
.tsize_t
)
3626 Expression ex
= (e
.op
== EXP
.cast_ ?
(cast(CastExp
)e
).e1
: e
);
3627 ex
= ex
.optimize(WANTvalue
);
3628 const ulong uval
= ex
.op
== EXP
.int64 ? ex
.toInteger() : cast(ulong)-1;
3629 if (cast(long)uval
>= 0)
3631 if (uval
<= 0xFFFFU
)
3636 if (uval
<= 0x7FFF_FFFF_FFFF_FFFFUL
)
3638 buf
.writestring("cast(size_t)");
3644 expToBuffer(e
, PREC
.assign
, buf
, hgs
);
3647 private void expressionToBuffer(Expression e
, ref OutBuffer buf
, ref HdrGenState hgs
)
3649 expressionPrettyPrint(e
, buf
, hgs
);
3652 /**************************************************
3653 * Write expression out to buf, but wrap it
3654 * in ( ) if its precedence is less than pr.
3656 private void expToBuffer(Expression e
, PREC pr
, ref OutBuffer buf
, ref HdrGenState hgs
)
3660 if (precedence
[e
.op
] == PREC
.zero
)
3661 printf("precedence not defined for token '%s'\n", EXPtoString(e
.op
).ptr
);
3665 buf
.writestring("<FF>");
3668 assert(precedence
[e
.op
] != PREC
.zero
);
3669 assert(pr
!= PREC
.zero
);
3670 /* Despite precedence, we don't allow a<b<c expressions.
3671 * They must be parenthesized.
3673 if (precedence
[e
.op
] < pr ||
(pr
== PREC
.rel
&& precedence
[e
.op
] == pr
)
3674 ||
(pr
>= PREC
.or && pr
<= PREC
.and && precedence
[e
.op
] == PREC
.rel
))
3677 e
.expressionToBuffer(buf
, hgs
);
3682 e
.expressionToBuffer(buf
, hgs
);
3687 /**************************************************
3688 * An entry point to pretty-print type.
3690 private void typeToBuffer(Type t
, const Identifier ident
, ref OutBuffer buf
, ref HdrGenState hgs
,
3693 if (auto tf
= t
.isTypeFunction())
3695 visitFuncIdentWithPrefix(tf
, ident
, null, buf
, hgs
);
3698 visitWithMask(t
, modMask
, buf
, hgs
);
3702 buf
.writestring(ident
.toString());
3706 private void visitWithMask(Type t
, ubyte modMask
, ref OutBuffer buf
, ref HdrGenState hgs
)
3708 // Tuples and functions don't use the type constructor syntax
3709 if (modMask
== t
.mod || t
.ty
== Tfunction || t
.ty
== Ttuple
)
3711 typeToBufferx(t
, buf
, hgs
);
3715 ubyte m
= t
.mod
& ~(t
.mod
& modMask
);
3716 if (m
& MODFlags
.shared_
)
3718 MODtoBuffer(buf
, MODFlags
.shared_
);
3721 if (m
& MODFlags
.wild
)
3723 MODtoBuffer(buf
, MODFlags
.wild
);
3726 if (m
& (MODFlags
.const_ | MODFlags
.immutable_
))
3728 MODtoBuffer(buf
, m
& (MODFlags
.const_ | MODFlags
.immutable_
));
3731 typeToBufferx(t
, buf
, hgs
);
3732 if (m
& (MODFlags
.const_ | MODFlags
.immutable_
))
3734 if (m
& MODFlags
.wild
)
3736 if (m
& MODFlags
.shared_
)
3742 private void dumpTemplateInstance(TemplateInstance ti
, ref OutBuffer buf
, ref HdrGenState hgs
)
3750 ti
.aliasdecl
.dsymbolToBuffer(buf
, hgs
);
3753 else if (ti
.members
)
3755 foreach(m
;*ti
.members
)
3756 m
.dsymbolToBuffer(buf
, hgs
);
3765 private void tiargsToBuffer(TemplateInstance ti
, ref OutBuffer buf
, ref HdrGenState hgs
)
3770 buf
.writestring("(...)");
3775 buf
.writestring("()");
3778 if (ti
.tiargs
.length
== 1)
3780 RootObject oarg
= (*ti
.tiargs
)[0];
3781 if (Type t
= isType(oarg
))
3783 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))
3785 HdrGenState hgs2
; // re-examine need for new hgs
3786 hgs2
.fullQual
= (t
.ty
== Tclass
&& !t
.mod
);
3787 toCBuffer(t
, buf
, null, hgs2
);
3791 else if (Expression e
= isExpression(oarg
))
3793 if (e
.op
== EXP
.int64 || e
.op
== EXP
.float64 || e
.op
== EXP
.null_ || e
.op
== EXP
.string_ || e
.op
== EXP
.this_
)
3795 toCBuffer(e
, buf
, hgs
);
3802 foreach (i
, arg
; *ti
.tiargs
)
3805 buf
.writestring(", ");
3806 objectToBuffer(arg
, buf
, hgs
);
3812 /****************************************
3813 * This makes a 'pretty' version of the template arguments.
3814 * It's analogous to genIdent() which makes a mangled version.
3816 private void objectToBuffer(RootObject oarg
, ref OutBuffer buf
, ref HdrGenState hgs
)
3818 //printf("objectToBuffer()\n");
3819 /* The logic of this should match what genIdent() does. The _dynamic_cast()
3820 * function relies on all the pretty strings to be unique for different classes
3821 * See https://issues.dlang.org/show_bug.cgi?id=7375
3822 * Perhaps it would be better to demangle what genIdent() does.
3824 if (auto t
= isType(oarg
))
3826 //printf("\tt: %s ty = %d\n", t.toChars(), t.ty);
3827 typeToBuffer(t
, null, buf
, hgs
);
3829 else if (auto e
= isExpression(oarg
))
3831 if (e
.op
== EXP
.variable
)
3832 e
= e
.optimize(WANTvalue
); // added to fix https://issues.dlang.org/show_bug.cgi?id=7375
3833 expToBuffer(e
, PREC
.assign
, buf
, hgs
);
3835 else if (Dsymbol s
= isDsymbol(oarg
))
3838 buf
.writestring(s
.ident
.toString());
3840 buf
.writestring(s
.toChars());
3842 else if (auto v
= isTuple(oarg
))
3844 auto args
= &v
.objects
;
3845 foreach (i
, arg
; *args
)
3848 buf
.writestring(", ");
3849 objectToBuffer(arg
, buf
, hgs
);
3852 else if (auto p
= isParameter(oarg
))
3854 parameterToBuffer(p
, buf
, hgs
);
3858 buf
.writestring("NULL");
3864 printf("bad Object = %p\n", oarg
);
3871 private void visitFuncIdentWithPostfix(TypeFunction t
, const char[] ident
, ref OutBuffer buf
, ref HdrGenState hgs
, bool isStatic
)
3875 t
.inuse
= 2; // flag error to caller
3879 if (t
.linkage
> LINK
.d
&& hgs
.ddoc
!= 1 && !hgs
.hdrgen
)
3881 linkageToBuffer(buf
, t
.linkage
);
3884 if (t
.linkage
== LINK
.objc
&& isStatic
)
3885 buf
.write("static ");
3888 typeToBuffer(t
.next
, null, buf
, hgs
);
3893 buf
.writestring("auto ");
3895 buf
.writestring(ident
);
3896 parametersToBuffer(t
.parameterList
, buf
, hgs
);
3897 /* Use postfix style for attributes
3902 MODtoBuffer(buf
, t
.mod
);
3908 buf
.writestring(str);
3910 t
.attributesApply(&dg
);
3915 private void visitFuncIdentWithPrefix(TypeFunction t
, const Identifier ident
, TemplateDeclaration td
,
3916 ref OutBuffer buf
, ref HdrGenState hgs
)
3920 t
.inuse
= 2; // flag error to caller
3925 /* Use 'storage class' (prefix) style for attributes
3929 MODtoBuffer(buf
, t
.mod
);
3933 void ignoreReturn(string
str)
3935 if (str != "return")
3937 // don't write 'ref' for ctors
3938 if ((ident
== Id
.ctor
) && str == "ref")
3940 buf
.writestring(str);
3944 t
.attributesApply(&ignoreReturn
);
3946 if (t
.linkage
> LINK
.d
&& hgs
.ddoc
!= 1 && !hgs
.hdrgen
)
3948 linkageToBuffer(buf
, t
.linkage
);
3951 if (ident
&& ident
.toHChars2() != ident
.toChars())
3953 // Don't print return type for ctor, dtor, unittest, etc
3957 typeToBuffer(t
.next
, null, buf
, hgs
);
3962 buf
.writestring("auto ");
3964 buf
.writestring(ident
.toHChars2());
3968 foreach (i
, p
; *td
.origParameters
)
3971 buf
.writestring(", ");
3972 toCBuffer(p
, buf
, hgs
);
3976 parametersToBuffer(t
.parameterList
, buf
, hgs
);
3979 buf
.writestring(" return");
3985 private void initializerToBuffer(Initializer inx
, ref OutBuffer buf
, ref HdrGenState hgs
)
3987 void visitError(ErrorInitializer iz
)
3989 buf
.writestring("__error__");
3992 void visitVoid(VoidInitializer iz
)
3994 buf
.writestring("void");
3997 void visitDefault(DefaultInitializer iz
)
3999 buf
.writestring("{ }");
4002 void visitStruct(StructInitializer si
)
4004 //printf("StructInitializer::toCBuffer()\n");
4006 foreach (i
, const id
; si
.field
)
4009 buf
.writestring(", ");
4012 buf
.writestring(id
.toString());
4015 if (auto iz
= si
.value
[i
])
4016 initializerToBuffer(iz
, buf
, hgs
);
4021 void visitArray(ArrayInitializer ai
)
4024 foreach (i
, ex
; ai
.index
)
4027 buf
.writestring(", ");
4030 ex
.expressionToBuffer(buf
, hgs
);
4033 if (auto iz
= ai
.value
[i
])
4034 initializerToBuffer(iz
, buf
, hgs
);
4039 void visitExp(ExpInitializer ei
)
4041 ei
.exp
.expressionToBuffer(buf
, hgs
);
4044 void visitC(CInitializer ci
)
4047 foreach (i
, ref DesigInit
di; ci
.initializerList
)
4050 buf
.writestring(", ");
4051 if (di.designatorList
)
4053 foreach (ref Designator d
; (*di.designatorList
)[])
4058 toCBuffer(d
.exp
, buf
, hgs
);
4064 buf
.writestring(d
.ident
.toString());
4069 initializerToBuffer(di.initializer
, buf
, hgs
);
4074 mixin VisitInitializer
!void visit
;
4075 visit
.VisitInitializer(inx
);
4079 private void typeToBufferx(Type t
, ref OutBuffer buf
, ref HdrGenState hgs
)
4081 void visitType(Type t
)
4083 printf("t = %p, ty = %d\n", t
, t
.ty
);
4087 void visitError(TypeError t
)
4089 buf
.writestring("_error_");
4092 void visitBasic(TypeBasic t
)
4094 //printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod);
4095 buf
.writestring(t
.dstring
);
4098 void visitTraits(TypeTraits t
)
4100 //printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod);
4101 t
.exp
.expressionToBuffer(buf
, hgs
);
4104 void visitVector(TypeVector t
)
4106 //printf("TypeVector::toCBuffer2(t.mod = %d)\n", t.mod);
4107 buf
.writestring("__vector(");
4108 visitWithMask(t
.basetype
, t
.mod
, buf
, hgs
);
4109 buf
.writestring(")");
4112 void visitSArray(TypeSArray t
)
4114 visitWithMask(t
.next
, t
.mod
, buf
, hgs
);
4116 sizeToBuffer(t
.dim
, buf
, hgs
);
4120 void visitDArray(TypeDArray t
)
4122 Type ut
= t
.castMod(0);
4125 if (ut
.equals(Type
.tstring
))
4126 buf
.writestring("string");
4127 else if (ut
.equals(Type
.twstring
))
4128 buf
.writestring("wstring");
4129 else if (ut
.equals(Type
.tdstring
))
4130 buf
.writestring("dstring");
4134 visitWithMask(t
.next
, t
.mod
, buf
, hgs
);
4135 buf
.writestring("[]");
4139 void visitAArray(TypeAArray t
)
4141 visitWithMask(t
.next
, t
.mod
, buf
, hgs
);
4143 visitWithMask(t
.index
, 0, buf
, hgs
);
4147 void visitPointer(TypePointer t
)
4149 //printf("TypePointer::toCBuffer2() next = %d\n", t.next.ty);
4150 if (t
.next
.ty
== Tfunction
)
4151 visitFuncIdentWithPostfix(cast(TypeFunction
)t
.next
, "function", buf
, hgs
, false);
4154 visitWithMask(t
.next
, t
.mod
, buf
, hgs
);
4159 void visitReference(TypeReference t
)
4161 visitWithMask(t
.next
, t
.mod
, buf
, hgs
);
4165 void visitFunction(TypeFunction t
)
4167 //printf("TypeFunction::toCBuffer2() t = %p, ref = %d\n", t, t.isref);
4168 visitFuncIdentWithPostfix(t
, null, buf
, hgs
, false);
4171 void visitDelegate(TypeDelegate t
)
4173 visitFuncIdentWithPostfix(cast(TypeFunction
)t
.next
, "delegate", buf
, hgs
, false);
4176 void visitTypeQualifiedHelper(TypeQualified t
)
4178 foreach (id
; t
.idents
)
4180 switch (id
.dyncast()) with (DYNCAST
)
4184 TemplateInstance ti
= cast(TemplateInstance
)id
;
4185 ti
.dsymbolToBuffer(buf
, hgs
);
4189 (cast(Expression
)id
).expressionToBuffer(buf
, hgs
);
4194 typeToBufferx(cast(Type
)id
, buf
, hgs
);
4199 buf
.writestring(id
.toString());
4204 void visitIdentifier(TypeIdentifier t
)
4206 //printf("visitTypeIdentifier() %s\n", t.ident.toChars());
4207 buf
.writestring(t
.ident
.toString());
4208 visitTypeQualifiedHelper(t
);
4211 void visitInstance(TypeInstance t
)
4213 t
.tempinst
.dsymbolToBuffer(buf
, hgs
);
4214 visitTypeQualifiedHelper(t
);
4217 void visitTypeof(TypeTypeof t
)
4219 buf
.writestring("typeof(");
4220 t
.exp
.expressionToBuffer(buf
, hgs
);
4222 visitTypeQualifiedHelper(t
);
4225 void visitReturn(TypeReturn t
)
4227 buf
.writestring("typeof(return)");
4228 visitTypeQualifiedHelper(t
);
4231 void visitEnum(TypeEnum t
)
4233 //printf("visitEnum: %s\n", t.sym.toChars());
4234 buf
.writestring(hgs
.fullQual ? t
.sym
.toPrettyChars() : t
.sym
.toChars());
4237 void visitStruct(TypeStruct t
)
4239 //printf("visitTypeStruct() %s\n", t.sym.toChars());
4241 // https://issues.dlang.org/show_bug.cgi?id=13776
4242 // Don't use ti.toAlias() to avoid forward reference error
4243 // while printing messages.
4244 TemplateInstance ti
= t
.sym
.parent ? t
.sym
.parent
.isTemplateInstance() : null;
4245 if (ti
&& ti
.aliasdecl
== t
.sym
)
4246 buf
.writestring(hgs
.fullQual ? ti
.toPrettyChars() : ti
.toChars());
4248 buf
.writestring(hgs
.fullQual ? t
.sym
.toPrettyChars() : t
.sym
.toChars());
4251 void visitClass(TypeClass t
)
4253 // https://issues.dlang.org/show_bug.cgi?id=13776
4254 // Don't use ti.toAlias() to avoid forward reference error
4255 // while printing messages.
4256 TemplateInstance ti
= t
.sym
.parent ? t
.sym
.parent
.isTemplateInstance() : null;
4257 if (ti
&& ti
.aliasdecl
== t
.sym
)
4258 buf
.writestring(hgs
.fullQual ? ti
.toPrettyChars() : ti
.toChars());
4260 buf
.writestring(hgs
.fullQual ? t
.sym
.toPrettyChars() : t
.sym
.toChars());
4263 void visitTag(TypeTag t
)
4265 if (t
.mod
& MODFlags
.const_
)
4266 buf
.writestring("const ");
4267 if (hgs
.importcHdr
&& t
.id
)
4269 buf
.writestring(t
.id
.toString());
4272 buf
.writestring(Token
.toString(t
.tok
));
4275 buf
.writestring(t
.id
.toString());
4276 if (t
.tok
== TOK
.enum_
&& t
.base
&& t
.base
.ty
!= TY
.Tint32
)
4278 buf
.writestring(" : ");
4279 visitWithMask(t
.base
, t
.mod
, buf
, hgs
);
4283 void visitTuple(TypeTuple t
)
4285 parametersToBuffer(ParameterList(t
.arguments
, VarArg
.none
), buf
, hgs
);
4288 void visitSlice(TypeSlice t
)
4290 visitWithMask(t
.next
, t
.mod
, buf
, hgs
);
4292 sizeToBuffer(t
.lwr
, buf
, hgs
);
4293 buf
.writestring(" .. ");
4294 sizeToBuffer(t
.upr
, buf
, hgs
);
4298 void visitNull(TypeNull t
)
4300 buf
.writestring("typeof(null)");
4303 void visitMixin(TypeMixin t
)
4305 buf
.writestring("mixin(");
4306 argsToBuffer(t
.exps
, buf
, hgs
, null);
4310 void visitNoreturn(TypeNoreturn t
)
4312 buf
.writestring("noreturn");
4318 default: return t
.isTypeBasic() ?
4319 visitBasic(cast(TypeBasic
)t
) :
4322 case Terror
: return visitError(cast(TypeError
)t
);
4323 case Ttraits
: return visitTraits(cast(TypeTraits
)t
);
4324 case Tvector
: return visitVector(cast(TypeVector
)t
);
4325 case Tsarray
: return visitSArray(cast(TypeSArray
)t
);
4326 case Tarray
: return visitDArray(cast(TypeDArray
)t
);
4327 case Taarray
: return visitAArray(cast(TypeAArray
)t
);
4328 case Tpointer
: return visitPointer(cast(TypePointer
)t
);
4329 case Treference
: return visitReference(cast(TypeReference
)t
);
4330 case Tfunction
: return visitFunction(cast(TypeFunction
)t
);
4331 case Tdelegate
: return visitDelegate(cast(TypeDelegate
)t
);
4332 case Tident
: return visitIdentifier(cast(TypeIdentifier
)t
);
4333 case Tinstance
: return visitInstance(cast(TypeInstance
)t
);
4334 case Ttypeof
: return visitTypeof(cast(TypeTypeof
)t
);
4335 case Treturn
: return visitReturn(cast(TypeReturn
)t
);
4336 case Tenum
: return visitEnum(cast(TypeEnum
)t
);
4337 case Tstruct
: return visitStruct(cast(TypeStruct
)t
);
4338 case Tclass
: return visitClass(cast(TypeClass
)t
);
4339 case Ttuple
: return visitTuple (cast(TypeTuple
)t
);
4340 case Tslice
: return visitSlice(cast(TypeSlice
)t
);
4341 case Tnull
: return visitNull(cast(TypeNull
)t
);
4342 case Tmixin
: return visitMixin(cast(TypeMixin
)t
);
4343 case Tnoreturn
: return visitNoreturn(cast(TypeNoreturn
)t
);
4344 case Ttag
: return visitTag(cast(TypeTag
)t
);
4348 /****************************************
4349 * Convert EXP to char*.
4352 string
EXPtoString(EXP op
)
4354 static immutable char*[EXP
.max
+ 1] strings
=
4357 EXP
.error
: "error",
4358 EXP
.objcClassReference
: "class",
4360 EXP
.mixin_
: "mixin",
4362 EXP
.import_
: "import",
4363 EXP
.dotVariable
: "dotvar",
4364 EXP
.scope_
: "scope",
4365 EXP
.identifier
: "identifier",
4367 EXP
.super_
: "super",
4369 EXP
.float64
: "double",
4370 EXP
.complex80
: "creal",
4372 EXP
.string_
: "string",
4373 EXP
.arrayLiteral
: "arrayliteral",
4374 EXP
.assocArrayLiteral
: "assocarrayliteral",
4375 EXP
.classReference
: "classreference",
4376 EXP
.file
: "__FILE__",
4377 EXP
.fileFullPath
: "__FILE_FULL_PATH__",
4378 EXP
.line
: "__LINE__",
4379 EXP
.moduleString
: "__MODULE__",
4380 EXP
.functionString
: "__FUNCTION__",
4381 EXP
.prettyFunction
: "__PRETTY_FUNCTION__",
4382 EXP
.typeid_
: "typeid",
4384 EXP
.assert_
: "assert",
4386 EXP
.template_
: "template",
4387 EXP
.dSymbol
: "symbol",
4388 EXP
.function_
: "function",
4389 EXP
.variable
: "var",
4390 EXP
.symbolOffset
: "symoff",
4391 EXP
.structLiteral
: "structLiteral",
4392 EXP
.compoundLiteral
: "compoundliteral",
4393 EXP
.arrayLength
: "arraylength",
4394 EXP
.delegatePointer
: "delegateptr",
4395 EXP
.delegateFunctionPointer
: "delegatefuncptr",
4396 EXP
.remove
: "remove",
4397 EXP
.tuple
: "sequence",
4398 EXP
.traits
: "__traits",
4399 EXP
.overloadSet
: "__overloadset",
4401 EXP
.vectorArray
: "vectorarray",
4402 EXP
._Generic
: "_Generic",
4405 EXP
.dotTemplateInstance
: "dotti",
4406 EXP
.dotIdentifier
: "dotid",
4407 EXP
.dotTemplateDeclaration
: "dottd",
4409 EXP
.dotType
: "dottype",
4410 EXP
.plusPlus
: "++",
4411 EXP
.minusMinus
: "--",
4412 EXP
.prePlusPlus
: "++",
4413 EXP
.preMinusMinus
: "--",
4419 EXP
.delegate_
: "delegate",
4426 EXP
.delete_
: "delete",
4428 EXP
.newAnonymousClass
: "newanonclass",
4431 EXP
.vector
: "__vector",
4440 EXP
.concatenate
: "~",
4442 EXP
.leftShift
: "<<",
4443 EXP
.rightShift
: ">>",
4444 EXP
.unsignedRightShift
: ">>>",
4447 EXP
.lessOrEqual
: "<=",
4448 EXP
.greaterThan
: ">",
4449 EXP
.greaterOrEqual
: ">=",
4453 EXP
.notEqual
: "!=",
4454 EXP
.identity
: "is",
4455 EXP
.notIdentity
: "!is",
4467 EXP
.construct
: "=",
4469 EXP
.addAssign
: "+=",
4470 EXP
.minAssign
: "-=",
4471 EXP
.concatenateAssign
: "~=",
4472 EXP
.concatenateElemAssign
: "~=",
4473 EXP
.concatenateDcharAssign
: "~=",
4474 EXP
.mulAssign
: "*=",
4475 EXP
.divAssign
: "/=",
4476 EXP
.modAssign
: "%=",
4477 EXP
.powAssign
: "^^=",
4478 EXP
.leftShiftAssign
: "<<=",
4479 EXP
.rightShiftAssign
: ">>=",
4480 EXP
.unsignedRightShiftAssign
: ">>>=",
4481 EXP
.andAssign
: "&=",
4482 EXP
.orAssign
: "|=",
4483 EXP
.xorAssign
: "^=",
4486 EXP
.declaration
: "declaration",
4488 EXP
.interval
: "interval",
4489 EXP
.loweredAssignExp
: "="
4491 const p
= strings
[op
];
4494 printf("error: EXP %d has no string\n", op
);
4499 return p
[0 .. strlen(p
)];