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