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