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(d.parameterList, 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(CommaExp e) 2269 { 2270 // CommaExp is generated by the compiler so it shouldn't 2271 // appear in error messages or header files. 2272 // For now, this treats the case where the compiler 2273 // generates CommaExp for temporaries by calling 2274 // the `sideeffect.copyToTemp` function. 2275 auto ve = e.e2.isVarExp(); 2276 2277 // not a CommaExp introduced for temporaries, go on 2278 // the old path 2279 if (!ve || !(ve.var.storage_class & STC.temp)) 2280 { 2281 visit(cast(BinExp)e); 2282 return; 2283 } 2284 2285 // CommaExp that contain temporaries inserted via 2286 // `copyToTemp` are usually of the form 2287 // ((T __temp = exp), __tmp). 2288 // Asserts are here to easily spot 2289 // missing cases where CommaExp 2290 // are used for other constructs 2291 auto vd = ve.var.isVarDeclaration(); 2292 assert(vd && vd._init); 2293 auto exp = vd._init.isExpInitializer.exp; 2294 assert(exp); 2295 Expression commaExtract; 2296 if (auto ce = exp.isConstructExp()) 2297 commaExtract = ce.e2; 2298 else if (auto se = exp.isStructLiteralExp) 2299 commaExtract = se; 2300 2301 // not one of the known cases, go on the old path 2302 if (!commaExtract) 2303 { 2304 visit(cast(BinExp)e); 2305 return; 2306 } 2307 expToBuffer(commaExtract, precedence[exp.op], buf, hgs); 2308 } 2309 2310 override void visit(CompileExp e) 2311 { 2312 buf.writestring("mixin("); 2313 argsToBuffer(e.exps, buf, hgs, null); 2314 buf.writeByte(')'); 2315 } 2316 2317 override void visit(ImportExp e) 2318 { 2319 buf.writestring("import("); 2320 expToBuffer(e.e1, PREC.assign, buf, hgs); 2321 buf.writeByte(')'); 2322 } 2323 2324 override void visit(AssertExp e) 2325 { 2326 buf.writestring("assert("); 2327 expToBuffer(e.e1, PREC.assign, buf, hgs); 2328 if (e.msg) 2329 { 2330 buf.writestring(", "); 2331 expToBuffer(e.msg, PREC.assign, buf, hgs); 2332 } 2333 buf.writeByte(')'); 2334 } 2335 2336 override void visit(DotIdExp e) 2337 { 2338 expToBuffer(e.e1, PREC.primary, buf, hgs); 2339 buf.writeByte('.'); 2340 buf.writestring(e.ident.toString()); 2341 } 2342 2343 override void visit(DotTemplateExp e) 2344 { 2345 expToBuffer(e.e1, PREC.primary, buf, hgs); 2346 buf.writeByte('.'); 2347 buf.writestring(e.td.toChars()); 2348 } 2349 2350 override void visit(DotVarExp e) 2351 { 2352 expToBuffer(e.e1, PREC.primary, buf, hgs); 2353 buf.writeByte('.'); 2354 buf.writestring(e.var.toChars()); 2355 } 2356 2357 override void visit(DotTemplateInstanceExp e) 2358 { 2359 expToBuffer(e.e1, PREC.primary, buf, hgs); 2360 buf.writeByte('.'); 2361 e.ti.dsymbolToBuffer(buf, hgs); 2362 } 2363 2364 override void visit(DelegateExp e) 2365 { 2366 buf.writeByte('&'); 2367 if (!e.func.isNested() || e.func.needThis()) 2368 { 2369 expToBuffer(e.e1, PREC.primary, buf, hgs); 2370 buf.writeByte('.'); 2371 } 2372 buf.writestring(e.func.toChars()); 2373 } 2374 2375 override void visit(DotTypeExp e) 2376 { 2377 expToBuffer(e.e1, PREC.primary, buf, hgs); 2378 buf.writeByte('.'); 2379 buf.writestring(e.sym.toChars()); 2380 } 2381 2382 override void visit(CallExp e) 2383 { 2384 if (e.e1.op == TOK.type) 2385 { 2386 /* Avoid parens around type to prevent forbidden cast syntax: 2387 * (sometype)(arg1) 2388 * This is ok since types in constructor calls 2389 * can never depend on parens anyway 2390 */ 2391 e.e1.accept(this); 2392 } 2393 else 2394 expToBuffer(e.e1, precedence[e.op], buf, hgs); 2395 buf.writeByte('('); 2396 argsToBuffer(e.arguments, buf, hgs); 2397 buf.writeByte(')'); 2398 } 2399 2400 override void visit(PtrExp e) 2401 { 2402 buf.writeByte('*'); 2403 expToBuffer(e.e1, precedence[e.op], buf, hgs); 2404 } 2405 2406 override void visit(DeleteExp e) 2407 { 2408 buf.writestring("delete "); 2409 expToBuffer(e.e1, precedence[e.op], buf, hgs); 2410 } 2411 2412 override void visit(CastExp e) 2413 { 2414 buf.writestring("cast("); 2415 if (e.to) 2416 typeToBuffer(e.to, null, buf, hgs); 2417 else 2418 { 2419 MODtoBuffer(buf, e.mod); 2420 } 2421 buf.writeByte(')'); 2422 expToBuffer(e.e1, precedence[e.op], buf, hgs); 2423 } 2424 2425 override void visit(VectorExp e) 2426 { 2427 buf.writestring("cast("); 2428 typeToBuffer(e.to, null, buf, hgs); 2429 buf.writeByte(')'); 2430 expToBuffer(e.e1, precedence[e.op], buf, hgs); 2431 } 2432 2433 override void visit(VectorArrayExp e) 2434 { 2435 expToBuffer(e.e1, PREC.primary, buf, hgs); 2436 buf.writestring(".array"); 2437 } 2438 2439 override void visit(SliceExp e) 2440 { 2441 expToBuffer(e.e1, precedence[e.op], buf, hgs); 2442 buf.writeByte('['); 2443 if (e.upr || e.lwr) 2444 { 2445 if (e.lwr) 2446 sizeToBuffer(e.lwr, buf, hgs); 2447 else 2448 buf.writeByte('0'); 2449 buf.writestring(".."); 2450 if (e.upr) 2451 sizeToBuffer(e.upr, buf, hgs); 2452 else 2453 buf.writeByte('$'); 2454 } 2455 buf.writeByte(']'); 2456 } 2457 2458 override void visit(ArrayLengthExp e) 2459 { 2460 expToBuffer(e.e1, PREC.primary, buf, hgs); 2461 buf.writestring(".length"); 2462 } 2463 2464 override void visit(IntervalExp e) 2465 { 2466 expToBuffer(e.lwr, PREC.assign, buf, hgs); 2467 buf.writestring(".."); 2468 expToBuffer(e.upr, PREC.assign, buf, hgs); 2469 } 2470 2471 override void visit(DelegatePtrExp e) 2472 { 2473 expToBuffer(e.e1, PREC.primary, buf, hgs); 2474 buf.writestring(".ptr"); 2475 } 2476 2477 override void visit(DelegateFuncptrExp e) 2478 { 2479 expToBuffer(e.e1, PREC.primary, buf, hgs); 2480 buf.writestring(".funcptr"); 2481 } 2482 2483 override void visit(ArrayExp e) 2484 { 2485 expToBuffer(e.e1, PREC.primary, buf, hgs); 2486 buf.writeByte('['); 2487 argsToBuffer(e.arguments, buf, hgs); 2488 buf.writeByte(']'); 2489 } 2490 2491 override void visit(DotExp e) 2492 { 2493 expToBuffer(e.e1, PREC.primary, buf, hgs); 2494 buf.writeByte('.'); 2495 expToBuffer(e.e2, PREC.primary, buf, hgs); 2496 } 2497 2498 override void visit(IndexExp e) 2499 { 2500 expToBuffer(e.e1, PREC.primary, buf, hgs); 2501 buf.writeByte('['); 2502 sizeToBuffer(e.e2, buf, hgs); 2503 buf.writeByte(']'); 2504 } 2505 2506 override void visit(PostExp e) 2507 { 2508 expToBuffer(e.e1, precedence[e.op], buf, hgs); 2509 buf.writestring(Token.toString(e.op)); 2510 } 2511 2512 override void visit(PreExp e) 2513 { 2514 buf.writestring(Token.toString(e.op)); 2515 expToBuffer(e.e1, precedence[e.op], buf, hgs); 2516 } 2517 2518 override void visit(RemoveExp e) 2519 { 2520 expToBuffer(e.e1, PREC.primary, buf, hgs); 2521 buf.writestring(".remove("); 2522 expToBuffer(e.e2, PREC.assign, buf, hgs); 2523 buf.writeByte(')'); 2524 } 2525 2526 override void visit(CondExp e) 2527 { 2528 expToBuffer(e.econd, PREC.oror, buf, hgs); 2529 buf.writestring(" ? "); 2530 expToBuffer(e.e1, PREC.expr, buf, hgs); 2531 buf.writestring(" : "); 2532 expToBuffer(e.e2, PREC.cond, buf, hgs); 2533 } 2534 2535 override void visit(DefaultInitExp e) 2536 { 2537 buf.writestring(Token.toString(e.op)); 2538 } 2539 2540 override void visit(ClassReferenceExp e) 2541 { 2542 buf.writestring(e.value.toChars()); 2543 } 2544 } 2545 2546 2547 private void templateParameterToBuffer(TemplateParameter tp, OutBuffer* buf, HdrGenState* hgs) 2548 { 2549 scope v = new TemplateParameterPrettyPrintVisitor(buf, hgs); 2550 tp.accept(v); 2551 } 2552 2553 private extern (C++) final class TemplateParameterPrettyPrintVisitor : Visitor 2554 { 2555 alias visit = Visitor.visit; 2556 public: 2557 OutBuffer* buf; 2558 HdrGenState* hgs; 2559 2560 extern (D) this(OutBuffer* buf, HdrGenState* hgs) 2561 { 2562 this.buf = buf; 2563 this.hgs = hgs; 2564 } 2565 2566 override void visit(TemplateTypeParameter tp) 2567 { 2568 buf.writestring(tp.ident.toString()); 2569 if (tp.specType) 2570 { 2571 buf.writestring(" : "); 2572 typeToBuffer(tp.specType, null, buf, hgs); 2573 } 2574 if (tp.defaultType) 2575 { 2576 buf.writestring(" = "); 2577 typeToBuffer(tp.defaultType, null, buf, hgs); 2578 } 2579 } 2580 2581 override void visit(TemplateThisParameter tp) 2582 { 2583 buf.writestring("this "); 2584 visit(cast(TemplateTypeParameter)tp); 2585 } 2586 2587 override void visit(TemplateAliasParameter tp) 2588 { 2589 buf.writestring("alias "); 2590 if (tp.specType) 2591 typeToBuffer(tp.specType, tp.ident, buf, hgs); 2592 else 2593 buf.writestring(tp.ident.toString()); 2594 if (tp.specAlias) 2595 { 2596 buf.writestring(" : "); 2597 objectToBuffer(tp.specAlias, buf, hgs); 2598 } 2599 if (tp.defaultAlias) 2600 { 2601 buf.writestring(" = "); 2602 objectToBuffer(tp.defaultAlias, buf, hgs); 2603 } 2604 } 2605 2606 override void visit(TemplateValueParameter tp) 2607 { 2608 typeToBuffer(tp.valType, tp.ident, buf, hgs); 2609 if (tp.specValue) 2610 { 2611 buf.writestring(" : "); 2612 tp.specValue.expressionToBuffer(buf, hgs); 2613 } 2614 if (tp.defaultValue) 2615 { 2616 buf.writestring(" = "); 2617 tp.defaultValue.expressionToBuffer(buf, hgs); 2618 } 2619 } 2620 2621 override void visit(TemplateTupleParameter tp) 2622 { 2623 buf.writestring(tp.ident.toString()); 2624 buf.writestring("..."); 2625 } 2626 } 2627 2628 private void conditionToBuffer(Condition c, OutBuffer* buf, HdrGenState* hgs) 2629 { 2630 scope v = new ConditionPrettyPrintVisitor(buf, hgs); 2631 c.accept(v); 2632 } 2633 2634 private extern (C++) final class ConditionPrettyPrintVisitor : Visitor 2635 { 2636 alias visit = Visitor.visit; 2637 public: 2638 OutBuffer* buf; 2639 HdrGenState* hgs; 2640 2641 extern (D) this(OutBuffer* buf, HdrGenState* hgs) 2642 { 2643 this.buf = buf; 2644 this.hgs = hgs; 2645 } 2646 2647 override void visit(DebugCondition c) 2648 { 2649 buf.writestring("debug ("); 2650 if (c.ident) 2651 buf.writestring(c.ident.toString()); 2652 else 2653 buf.print(c.level); 2654 buf.writeByte(')'); 2655 } 2656 2657 override void visit(VersionCondition c) 2658 { 2659 buf.writestring("version ("); 2660 if (c.ident) 2661 buf.writestring(c.ident.toString()); 2662 else 2663 buf.print(c.level); 2664 buf.writeByte(')'); 2665 } 2666 2667 override void visit(StaticIfCondition c) 2668 { 2669 buf.writestring("static if ("); 2670 c.exp.expressionToBuffer(buf, hgs); 2671 buf.writeByte(')'); 2672 } 2673 } 2674 2675 void toCBuffer(const Statement s, OutBuffer* buf, HdrGenState* hgs) 2676 { 2677 scope v = new StatementPrettyPrintVisitor(buf, hgs); 2678 (cast() s).accept(v); 2679 } 2680 2681 void toCBuffer(const Type t, OutBuffer* buf, const Identifier ident, HdrGenState* hgs) 2682 { 2683 typeToBuffer(cast() t, ident, buf, hgs); 2684 } 2685 2686 void toCBuffer(Dsymbol s, OutBuffer* buf, HdrGenState* hgs) 2687 { 2688 scope v = new DsymbolPrettyPrintVisitor(buf, hgs); 2689 s.accept(v); 2690 } 2691 2692 // used from TemplateInstance::toChars() and TemplateMixin::toChars() 2693 void toCBufferInstance(const TemplateInstance ti, OutBuffer* buf, bool qualifyTypes = false) 2694 { 2695 HdrGenState hgs; 2696 hgs.fullQual = qualifyTypes; 2697 scope v = new DsymbolPrettyPrintVisitor(buf, &hgs); 2698 v.visit(cast() ti); 2699 } 2700 2701 void toCBuffer(const Initializer iz, OutBuffer* buf, HdrGenState* hgs) 2702 { 2703 initializerToBuffer(cast() iz, buf, hgs); 2704 } 2705 2706 bool stcToBuffer(OutBuffer* buf, StorageClass stc) 2707 { 2708 bool result = false; 2709 if ((stc & (STC.return_ | STC.scope_)) == (STC.return_ | STC.scope_)) 2710 stc &= ~STC.scope_; 2711 if (stc & STC.scopeinferred) 2712 stc &= ~(STC.scope_ | STC.scopeinferred); 2713 while (stc) 2714 { 2715 const s = stcToString(stc); 2716 if (!s.length) 2717 break; 2718 if (result) 2719 buf.writeByte(' '); 2720 result = true; 2721 buf.writestring(s); 2722 } 2723 return result; 2724 } 2725 2726 /************************************************* 2727 * Pick off one of the storage classes from stc, 2728 * and return a string representation of it. 2729 * stc is reduced by the one picked. 2730 */ 2731 string stcToString(ref StorageClass stc) 2732 { 2733 struct SCstring 2734 { 2735 StorageClass stc; 2736 TOK tok; 2737 string id; 2738 } 2739 2740 __gshared SCstring* table = 2741 [ 2742 SCstring(STC.auto_, TOK.auto_), 2743 SCstring(STC.scope_, TOK.scope_), 2744 SCstring(STC.static_, TOK.static_), 2745 SCstring(STC.extern_, TOK.extern_), 2746 SCstring(STC.const_, TOK.const_), 2747 SCstring(STC.final_, TOK.final_), 2748 SCstring(STC.abstract_, TOK.abstract_), 2749 SCstring(STC.synchronized_, TOK.synchronized_), 2750 SCstring(STC.deprecated_, TOK.deprecated_), 2751 SCstring(STC.override_, TOK.override_), 2752 SCstring(STC.lazy_, TOK.lazy_), 2753 SCstring(STC.alias_, TOK.alias_), 2754 SCstring(STC.out_, TOK.out_), 2755 SCstring(STC.in_, TOK.in_), 2756 SCstring(STC.manifest, TOK.enum_), 2757 SCstring(STC.immutable_, TOK.immutable_), 2758 SCstring(STC.shared_, TOK.shared_), 2759 SCstring(STC.nothrow_, TOK.nothrow_), 2760 SCstring(STC.wild, TOK.inout_), 2761 SCstring(STC.pure_, TOK.pure_), 2762 SCstring(STC.ref_, TOK.ref_), 2763 SCstring(STC.return_, TOK.return_), 2764 SCstring(STC.tls), 2765 SCstring(STC.gshared, TOK.gshared), 2766 SCstring(STC.nogc, TOK.at, "@nogc"), 2767 SCstring(STC.property, TOK.at, "@property"), 2768 SCstring(STC.safe, TOK.at, "@safe"), 2769 SCstring(STC.trusted, TOK.at, "@trusted"), 2770 SCstring(STC.system, TOK.at, "@system"), 2771 SCstring(STC.disable, TOK.at, "@disable"), 2772 SCstring(STC.future, TOK.at, "@__future"), 2773 SCstring(STC.local, TOK.at, "__local"), 2774 SCstring(0, TOK.reserved) 2775 ]; 2776 for (int i = 0; table[i].stc; i++) 2777 { 2778 StorageClass tbl = table[i].stc; 2779 assert(tbl & STCStorageClass); 2780 if (stc & tbl) 2781 { 2782 stc &= ~tbl; 2783 if (tbl == STC.tls) // TOKtls was removed 2784 return "__thread"; 2785 TOK tok = table[i].tok; 2786 if (tok != TOK.at && !table[i].id.length) 2787 table[i].id = Token.toString(tok); // lazilly initialize table 2788 return table[i].id; 2789 } 2790 } 2791 //printf("stc = %llx\n", stc); 2792 return null; 2793 } 2794 2795 const(char)* stcToChars(ref StorageClass stc) 2796 { 2797 const s = stcToString(stc); 2798 return &s[0]; // assume 0 terminated 2799 } 2800 2801 2802 /// Ditto 2803 extern (D) string trustToString(TRUST trust) pure nothrow 2804 { 2805 final switch (trust) 2806 { 2807 case TRUST.default_: 2808 return null; 2809 case TRUST.system: 2810 return "@system"; 2811 case TRUST.trusted: 2812 return "@trusted"; 2813 case TRUST.safe: 2814 return "@safe"; 2815 } 2816 } 2817 2818 private void linkageToBuffer(OutBuffer* buf, LINK linkage) 2819 { 2820 const s = linkageToString(linkage); 2821 if (s.length) 2822 { 2823 buf.writestring("extern ("); 2824 buf.writestring(s); 2825 buf.writeByte(')'); 2826 } 2827 } 2828 2829 const(char)* linkageToChars(LINK linkage) 2830 { 2831 /// Works because we return a literal 2832 return linkageToString(linkage).ptr; 2833 } 2834 2835 string linkageToString(LINK linkage) pure nothrow 2836 { 2837 final switch (linkage) 2838 { 2839 case LINK.default_: 2840 return null; 2841 case LINK.d: 2842 return "D"; 2843 case LINK.c: 2844 return "C"; 2845 case LINK.cpp: 2846 return "C++"; 2847 case LINK.windows: 2848 return "Windows"; 2849 case LINK.pascal: 2850 return "Pascal"; 2851 case LINK.objc: 2852 return "Objective-C"; 2853 case LINK.system: 2854 return "System"; 2855 } 2856 } 2857 2858 void protectionToBuffer(OutBuffer* buf, Prot prot) 2859 { 2860 buf.writestring(protectionToString(prot.kind)); 2861 if (prot.kind == Prot.Kind.package_ && prot.pkg) 2862 { 2863 buf.writeByte('('); 2864 buf.writestring(prot.pkg.toPrettyChars(true)); 2865 buf.writeByte(')'); 2866 } 2867 } 2868 2869 /** 2870 * Returns: 2871 * a human readable representation of `kind` 2872 */ 2873 const(char)* protectionToChars(Prot.Kind kind) 2874 { 2875 // Null terminated because we return a literal 2876 return protectionToString(kind).ptr; 2877 } 2878 2879 /// Ditto 2880 extern (D) string protectionToString(Prot.Kind kind) nothrow pure 2881 { 2882 final switch (kind) 2883 { 2884 case Prot.Kind.undefined: 2885 return null; 2886 case Prot.Kind.none: 2887 return "none"; 2888 case Prot.Kind.private_: 2889 return "private"; 2890 case Prot.Kind.package_: 2891 return "package"; 2892 case Prot.Kind.protected_: 2893 return "protected"; 2894 case Prot.Kind.public_: 2895 return "public"; 2896 case Prot.Kind.export_: 2897 return "export"; 2898 } 2899 } 2900 2901 // Print the full function signature with correct ident, attributes and template args 2902 void functionToBufferFull(TypeFunction tf, OutBuffer* buf, const Identifier ident, HdrGenState* hgs, TemplateDeclaration td) 2903 { 2904 //printf("TypeFunction::toCBuffer() this = %p\n", this); 2905 visitFuncIdentWithPrefix(tf, ident, td, buf, hgs); 2906 } 2907 2908 // ident is inserted before the argument list and will be "function" or "delegate" for a type 2909 void functionToBufferWithIdent(TypeFunction tf, OutBuffer* buf, const(char)* ident) 2910 { 2911 HdrGenState hgs; 2912 visitFuncIdentWithPostfix(tf, ident.toDString(), buf, &hgs); 2913 } 2914 2915 void toCBuffer(const Expression e, OutBuffer* buf, HdrGenState* hgs) 2916 { 2917 scope v = new ExpressionPrettyPrintVisitor(buf, hgs); 2918 (cast() e).accept(v); 2919 } 2920 2921 /************************************************** 2922 * Write out argument types to buf. 2923 */ 2924 void argExpTypesToCBuffer(OutBuffer* buf, Expressions* arguments) 2925 { 2926 if (!arguments || !arguments.dim) 2927 return; 2928 HdrGenState hgs; 2929 foreach (i, arg; *arguments) 2930 { 2931 if (i) 2932 buf.writestring(", "); 2933 typeToBuffer(arg.type, null, buf, &hgs); 2934 } 2935 } 2936 2937 void toCBuffer(const TemplateParameter tp, OutBuffer* buf, HdrGenState* hgs) 2938 { 2939 scope v = new TemplateParameterPrettyPrintVisitor(buf, hgs); 2940 (cast() tp).accept(v); 2941 } 2942 2943 void arrayObjectsToBuffer(OutBuffer* buf, Objects* objects) 2944 { 2945 if (!objects || !objects.dim) 2946 return; 2947 HdrGenState hgs; 2948 foreach (i, o; *objects) 2949 { 2950 if (i) 2951 buf.writestring(", "); 2952 objectToBuffer(o, buf, &hgs); 2953 } 2954 } 2955 2956 /************************************************************* 2957 * Pretty print function parameters. 2958 * Params: 2959 * pl = parameter list to print 2960 * Returns: Null-terminated string representing parameters. 2961 */ 2962 extern (C++) const(char)* parametersTypeToChars(ParameterList pl) 2963 { 2964 OutBuffer buf; 2965 HdrGenState hgs; 2966 parametersToBuffer(pl, &buf, &hgs); 2967 return buf.extractChars(); 2968 } 2969 2970 /************************************************************* 2971 * Pretty print function parameter. 2972 * Params: 2973 * parameter = parameter to print. 2974 * tf = TypeFunction which holds parameter. 2975 * fullQual = whether to fully qualify types. 2976 * Returns: Null-terminated string representing parameters. 2977 */ 2978 const(char)* parameterToChars(Parameter parameter, TypeFunction tf, bool fullQual) 2979 { 2980 OutBuffer buf; 2981 HdrGenState hgs; 2982 hgs.fullQual = fullQual; 2983 2984 parameterToBuffer(parameter, &buf, &hgs); 2985 2986 if (tf.parameterList.varargs == VarArg.typesafe && parameter == tf.parameterList[tf.parameterList.parameters.dim - 1]) 2987 { 2988 buf.writestring("..."); 2989 } 2990 return buf.extractChars(); 2991 } 2992 2993 2994 /************************************************* 2995 * Write ParameterList to buffer. 2996 * Params: 2997 * pl = parameter list to serialize 2998 * buf = buffer to write it to 2999 * hgs = context 3000 */ 3001 3002 private void parametersToBuffer(ParameterList pl, OutBuffer* buf, HdrGenState* hgs) 3003 { 3004 buf.writeByte('('); 3005 foreach (i; 0 .. pl.length) 3006 { 3007 if (i) 3008 buf.writestring(", "); 3009 pl[i].parameterToBuffer(buf, hgs); 3010 } 3011 final switch (pl.varargs) 3012 { 3013 case VarArg.none: 3014 break; 3015 3016 case VarArg.variadic: 3017 if (pl.length) 3018 buf.writestring(", "); 3019 3020 if (stcToBuffer(buf, pl.stc)) 3021 buf.writeByte(' '); 3022 goto case VarArg.typesafe; 3023 3024 case VarArg.typesafe: 3025 buf.writestring("..."); 3026 break; 3027 } 3028 buf.writeByte(')'); 3029 } 3030 3031 3032 /*********************************************************** 3033 * Write parameter `p` to buffer `buf`. 3034 * Params: 3035 * p = parameter to serialize 3036 * buf = buffer to write it to 3037 * hgs = context 3038 */ 3039 private void parameterToBuffer(Parameter p, OutBuffer* buf, HdrGenState* hgs) 3040 { 3041 if (p.userAttribDecl) 3042 { 3043 buf.writeByte('@'); 3044 3045 bool isAnonymous = p.userAttribDecl.atts.dim > 0 && (*p.userAttribDecl.atts)[0].op != TOK.call; 3046 if (isAnonymous) 3047 buf.writeByte('('); 3048 3049 argsToBuffer(p.userAttribDecl.atts, buf, hgs); 3050 3051 if (isAnonymous) 3052 buf.writeByte(')'); 3053 buf.writeByte(' '); 3054 } 3055 if (p.storageClass & STC.auto_) 3056 buf.writestring("auto "); 3057 if (p.storageClass & STC.return_) 3058 buf.writestring("return "); 3059 3060 if (p.storageClass & STC.in_) 3061 buf.writestring("in "); 3062 else if (global.params.previewIn && p.storageClass & STC.ref_) 3063 buf.writestring("ref "); 3064 else if (p.storageClass & STC.out_) 3065 buf.writestring("out "); 3066 else if (p.storageClass & STC.lazy_) 3067 buf.writestring("lazy "); 3068 else if (p.storageClass & STC.alias_) 3069 buf.writestring("alias "); 3070 3071 if (!global.params.previewIn && p.storageClass & STC.ref_) 3072 buf.writestring("ref "); 3073 3074 StorageClass stc = p.storageClass; 3075 if (p.type && p.type.mod & MODFlags.shared_) 3076 stc &= ~STC.shared_; 3077 3078 if (stcToBuffer(buf, stc & (STC.const_ | STC.immutable_ | STC.wild | STC.shared_ | STC.scope_ | STC.scopeinferred))) 3079 buf.writeByte(' '); 3080 3081 if (p.storageClass & STC.alias_) 3082 { 3083 if (p.ident) 3084 buf.writestring(p.ident.toString()); 3085 } 3086 else if (p.type.ty == Tident && 3087 (cast(TypeIdentifier)p.type).ident.toString().length > 3 && 3088 strncmp((cast(TypeIdentifier)p.type).ident.toChars(), "__T", 3) == 0) 3089 { 3090 // print parameter name, instead of undetermined type parameter 3091 buf.writestring(p.ident.toString()); 3092 } 3093 else 3094 { 3095 typeToBuffer(p.type, p.ident, buf, hgs, (stc & STC.in_) ? MODFlags.const_ : 0); 3096 } 3097 3098 if (p.defaultArg) 3099 { 3100 buf.writestring(" = "); 3101 p.defaultArg.expToBuffer(PREC.assign, buf, hgs); 3102 } 3103 } 3104 3105 3106 /************************************************** 3107 * Write out argument list to buf. 3108 */ 3109 private void argsToBuffer(Expressions* expressions, OutBuffer* buf, HdrGenState* hgs, Expression basis = null) 3110 { 3111 if (!expressions || !expressions.dim) 3112 return; 3113 version (all) 3114 { 3115 foreach (i, el; *expressions) 3116 { 3117 if (i) 3118 buf.writestring(", "); 3119 if (!el) 3120 el = basis; 3121 if (el) 3122 expToBuffer(el, PREC.assign, buf, hgs); 3123 } 3124 } 3125 else 3126 { 3127 // Sparse style formatting, for debug use only 3128 // [0..dim: basis, 1: e1, 5: e5] 3129 if (basis) 3130 { 3131 buf.writestring("0.."); 3132 buf.print(expressions.dim); 3133 buf.writestring(": "); 3134 expToBuffer(basis, PREC.assign, buf, hgs); 3135 } 3136 foreach (i, el; *expressions) 3137 { 3138 if (el) 3139 { 3140 if (basis) 3141 { 3142 buf.writestring(", "); 3143 buf.print(i); 3144 buf.writestring(": "); 3145 } 3146 else if (i) 3147 buf.writestring(", "); 3148 expToBuffer(el, PREC.assign, buf, hgs); 3149 } 3150 } 3151 } 3152 } 3153 3154 private void sizeToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs) 3155 { 3156 if (e.type == Type.tsize_t) 3157 { 3158 Expression ex = (e.op == TOK.cast_ ? (cast(CastExp)e).e1 : e); 3159 ex = ex.optimize(WANTvalue); 3160 const dinteger_t uval = ex.op == TOK.int64 ? ex.toInteger() : cast(dinteger_t)-1; 3161 if (cast(sinteger_t)uval >= 0) 3162 { 3163 dinteger_t sizemax = void; 3164 if (target.ptrsize == 8) 3165 sizemax = 0xFFFFFFFFFFFFFFFFUL; 3166 else if (target.ptrsize == 4) 3167 sizemax = 0xFFFFFFFFU; 3168 else if (target.ptrsize == 2) 3169 sizemax = 0xFFFFU; 3170 else 3171 assert(0); 3172 if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFUL) 3173 { 3174 buf.print(uval); 3175 return; 3176 } 3177 } 3178 } 3179 expToBuffer(e, PREC.assign, buf, hgs); 3180 } 3181 3182 private void expressionToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs) 3183 { 3184 scope v = new ExpressionPrettyPrintVisitor(buf, hgs); 3185 e.accept(v); 3186 } 3187 3188 /************************************************** 3189 * Write expression out to buf, but wrap it 3190 * in ( ) if its precedence is less than pr. 3191 */ 3192 private void expToBuffer(Expression e, PREC pr, OutBuffer* buf, HdrGenState* hgs) 3193 { 3194 debug 3195 { 3196 if (precedence[e.op] == PREC.zero) 3197 printf("precedence not defined for token '%s'\n", Token.toChars(e.op)); 3198 } 3199 if (e.op == 0xFF) 3200 { 3201 buf.writestring("<FF>"); 3202 return; 3203 } 3204 assert(precedence[e.op] != PREC.zero); 3205 assert(pr != PREC.zero); 3206 /* Despite precedence, we don't allow a<b<c expressions. 3207 * They must be parenthesized. 3208 */ 3209 if (precedence[e.op] < pr || (pr == PREC.rel && precedence[e.op] == pr) 3210 || (pr >= PREC.or && pr <= PREC.and && precedence[e.op] == PREC.rel)) 3211 { 3212 buf.writeByte('('); 3213 e.expressionToBuffer(buf, hgs); 3214 buf.writeByte(')'); 3215 } 3216 else 3217 { 3218 e.expressionToBuffer(buf, hgs); 3219 } 3220 } 3221 3222 3223 /************************************************** 3224 * An entry point to pretty-print type. 3225 */ 3226 private void typeToBuffer(Type t, const Identifier ident, OutBuffer* buf, HdrGenState* hgs, 3227 ubyte modMask = 0) 3228 { 3229 if (auto tf = t.isTypeFunction()) 3230 { 3231 visitFuncIdentWithPrefix(tf, ident, null, buf, hgs); 3232 return; 3233 } 3234 visitWithMask(t, modMask, buf, hgs); 3235 if (ident) 3236 { 3237 buf.writeByte(' '); 3238 buf.writestring(ident.toString()); 3239 } 3240 } 3241 3242 private void visitWithMask(Type t, ubyte modMask, OutBuffer* buf, HdrGenState* hgs) 3243 { 3244 // Tuples and functions don't use the type constructor syntax 3245 if (modMask == t.mod || t.ty == Tfunction || t.ty == Ttuple) 3246 { 3247 typeToBufferx(t, buf, hgs); 3248 } 3249 else 3250 { 3251 ubyte m = t.mod & ~(t.mod & modMask); 3252 if (m & MODFlags.shared_) 3253 { 3254 MODtoBuffer(buf, MODFlags.shared_); 3255 buf.writeByte('('); 3256 } 3257 if (m & MODFlags.wild) 3258 { 3259 MODtoBuffer(buf, MODFlags.wild); 3260 buf.writeByte('('); 3261 } 3262 if (m & (MODFlags.const_ | MODFlags.immutable_)) 3263 { 3264 MODtoBuffer(buf, m & (MODFlags.const_ | MODFlags.immutable_)); 3265 buf.writeByte('('); 3266 } 3267 typeToBufferx(t, buf, hgs); 3268 if (m & (MODFlags.const_ | MODFlags.immutable_)) 3269 buf.writeByte(')'); 3270 if (m & MODFlags.wild) 3271 buf.writeByte(')'); 3272 if (m & MODFlags.shared_) 3273 buf.writeByte(')'); 3274 } 3275 } 3276 3277 3278 private void dumpTemplateInstance(TemplateInstance ti, OutBuffer* buf, HdrGenState* hgs) 3279 { 3280 buf.writeByte('{'); 3281 buf.writenl(); 3282 buf.level++; 3283 3284 if (ti.aliasdecl) 3285 { 3286 ti.aliasdecl.dsymbolToBuffer(buf, hgs); 3287 buf.writenl(); 3288 } 3289 else if (ti.members) 3290 { 3291 foreach(m;*ti.members) 3292 m.dsymbolToBuffer(buf, hgs); 3293 } 3294 3295 buf.level--; 3296 buf.writeByte('}'); 3297 buf.writenl(); 3298 3299 } 3300 3301 private void tiargsToBuffer(TemplateInstance ti, OutBuffer* buf, HdrGenState* hgs) 3302 { 3303 buf.writeByte('!'); 3304 if (ti.nest) 3305 { 3306 buf.writestring("(...)"); 3307 return; 3308 } 3309 if (!ti.tiargs) 3310 { 3311 buf.writestring("()"); 3312 return; 3313 } 3314 if (ti.tiargs.dim == 1) 3315 { 3316 RootObject oarg = (*ti.tiargs)[0]; 3317 if (Type t = isType(oarg)) 3318 { 3319 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)) 3320 { 3321 buf.writestring(t.toChars()); 3322 return; 3323 } 3324 } 3325 else if (Expression e = isExpression(oarg)) 3326 { 3327 if (e.op == TOK.int64 || e.op == TOK.float64 || e.op == TOK.null_ || e.op == TOK.string_ || e.op == TOK.this_) 3328 { 3329 buf.writestring(e.toChars()); 3330 return; 3331 } 3332 } 3333 } 3334 buf.writeByte('('); 3335 ti.nestUp(); 3336 foreach (i, arg; *ti.tiargs) 3337 { 3338 if (i) 3339 buf.writestring(", "); 3340 objectToBuffer(arg, buf, hgs); 3341 } 3342 ti.nestDown(); 3343 buf.writeByte(')'); 3344 } 3345 3346 /**************************************** 3347 * This makes a 'pretty' version of the template arguments. 3348 * It's analogous to genIdent() which makes a mangled version. 3349 */ 3350 private void objectToBuffer(RootObject oarg, OutBuffer* buf, HdrGenState* hgs) 3351 { 3352 //printf("objectToBuffer()\n"); 3353 /* The logic of this should match what genIdent() does. The _dynamic_cast() 3354 * function relies on all the pretty strings to be unique for different classes 3355 * See https://issues.dlang.org/show_bug.cgi?id=7375 3356 * Perhaps it would be better to demangle what genIdent() does. 3357 */ 3358 if (auto t = isType(oarg)) 3359 { 3360 //printf("\tt: %s ty = %d\n", t.toChars(), t.ty); 3361 typeToBuffer(t, null, buf, hgs); 3362 } 3363 else if (auto e = isExpression(oarg)) 3364 { 3365 if (e.op == TOK.variable) 3366 e = e.optimize(WANTvalue); // added to fix https://issues.dlang.org/show_bug.cgi?id=7375 3367 expToBuffer(e, PREC.assign, buf, hgs); 3368 } 3369 else if (Dsymbol s = isDsymbol(oarg)) 3370 { 3371 const p = s.ident ? s.ident.toChars() : s.toChars(); 3372 buf.writestring(p); 3373 } 3374 else if (auto v = isTuple(oarg)) 3375 { 3376 auto args = &v.objects; 3377 foreach (i, arg; *args) 3378 { 3379 if (i) 3380 buf.writestring(", "); 3381 objectToBuffer(arg, buf, hgs); 3382 } 3383 } 3384 else if (auto p = isParameter(oarg)) 3385 { 3386 parameterToBuffer(p, buf, hgs); 3387 } 3388 else if (!oarg) 3389 { 3390 buf.writestring("NULL"); 3391 } 3392 else 3393 { 3394 debug 3395 { 3396 printf("bad Object = %p\n", oarg); 3397 } 3398 assert(0); 3399 } 3400 } 3401 3402 3403 private void visitFuncIdentWithPostfix(TypeFunction t, const char[] ident, OutBuffer* buf, HdrGenState* hgs) 3404 { 3405 if (t.inuse) 3406 { 3407 t.inuse = 2; // flag error to caller 3408 return; 3409 } 3410 t.inuse++; 3411 if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen) 3412 { 3413 linkageToBuffer(buf, t.linkage); 3414 buf.writeByte(' '); 3415 } 3416 if (t.next) 3417 { 3418 typeToBuffer(t.next, null, buf, hgs); 3419 if (ident) 3420 buf.writeByte(' '); 3421 } 3422 else if (hgs.ddoc) 3423 buf.writestring("auto "); 3424 if (ident) 3425 buf.writestring(ident); 3426 parametersToBuffer(t.parameterList, buf, hgs); 3427 /* Use postfix style for attributes 3428 */ 3429 if (t.mod) 3430 { 3431 buf.writeByte(' '); 3432 MODtoBuffer(buf, t.mod); 3433 } 3434 3435 void dg(string str) 3436 { 3437 buf.writeByte(' '); 3438 buf.writestring(str); 3439 } 3440 t.attributesApply(&dg); 3441 3442 t.inuse--; 3443 } 3444 3445 private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, TemplateDeclaration td, 3446 OutBuffer* buf, HdrGenState* hgs) 3447 { 3448 if (t.inuse) 3449 { 3450 t.inuse = 2; // flag error to caller 3451 return; 3452 } 3453 t.inuse++; 3454 3455 /* Use 'storage class' (prefix) style for attributes 3456 */ 3457 if (t.mod) 3458 { 3459 MODtoBuffer(buf, t.mod); 3460 buf.writeByte(' '); 3461 } 3462 3463 void ignoreReturn(string str) 3464 { 3465 if (str != "return") 3466 { 3467 // don't write 'ref' for ctors 3468 if ((ident == Id.ctor) && str == "ref") 3469 return; 3470 buf.writestring(str); 3471 buf.writeByte(' '); 3472 } 3473 } 3474 t.attributesApply(&ignoreReturn); 3475 3476 if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen) 3477 { 3478 linkageToBuffer(buf, t.linkage); 3479 buf.writeByte(' '); 3480 } 3481 if (ident && ident.toHChars2() != ident.toChars()) 3482 { 3483 // Don't print return type for ctor, dtor, unittest, etc 3484 } 3485 else if (t.next) 3486 { 3487 typeToBuffer(t.next, null, buf, hgs); 3488 if (ident) 3489 buf.writeByte(' '); 3490 } 3491 else if (hgs.ddoc) 3492 buf.writestring("auto "); 3493 if (ident) 3494 buf.writestring(ident.toHChars2()); 3495 if (td) 3496 { 3497 buf.writeByte('('); 3498 foreach (i, p; *td.origParameters) 3499 { 3500 if (i) 3501 buf.writestring(", "); 3502 p.templateParameterToBuffer(buf, hgs); 3503 } 3504 buf.writeByte(')'); 3505 } 3506 parametersToBuffer(t.parameterList, buf, hgs); 3507 if (t.isreturn) 3508 { 3509 buf.writestring(" return"); 3510 } 3511 t.inuse--; 3512 } 3513 3514 3515 private void initializerToBuffer(Initializer inx, OutBuffer* buf, HdrGenState* hgs) 3516 { 3517 void visitError(ErrorInitializer iz) 3518 { 3519 buf.writestring("__error__"); 3520 } 3521 3522 void visitVoid(VoidInitializer iz) 3523 { 3524 buf.writestring("void"); 3525 } 3526 3527 void visitStruct(StructInitializer si) 3528 { 3529 //printf("StructInitializer::toCBuffer()\n"); 3530 buf.writeByte('{'); 3531 foreach (i, const id; si.field) 3532 { 3533 if (i) 3534 buf.writestring(", "); 3535 if (id) 3536 { 3537 buf.writestring(id.toString()); 3538 buf.writeByte(':'); 3539 } 3540 if (auto iz = si.value[i]) 3541 initializerToBuffer(iz, buf, hgs); 3542 } 3543 buf.writeByte('}'); 3544 } 3545 3546 void visitArray(ArrayInitializer ai) 3547 { 3548 buf.writeByte('['); 3549 foreach (i, ex; ai.index) 3550 { 3551 if (i) 3552 buf.writestring(", "); 3553 if (ex) 3554 { 3555 ex.expressionToBuffer(buf, hgs); 3556 buf.writeByte(':'); 3557 } 3558 if (auto iz = ai.value[i]) 3559 initializerToBuffer(iz, buf, hgs); 3560 } 3561 buf.writeByte(']'); 3562 } 3563 3564 void visitExp(ExpInitializer ei) 3565 { 3566 ei.exp.expressionToBuffer(buf, hgs); 3567 } 3568 3569 final switch (inx.kind) 3570 { 3571 case InitKind.error: return visitError (inx.isErrorInitializer ()); 3572 case InitKind.void_: return visitVoid (inx.isVoidInitializer ()); 3573 case InitKind.struct_: return visitStruct(inx.isStructInitializer()); 3574 case InitKind.array: return visitArray (inx.isArrayInitializer ()); 3575 case InitKind.exp: return visitExp (inx.isExpInitializer ()); 3576 } 3577 } 3578 3579 3580 private void typeToBufferx(Type t, OutBuffer* buf, HdrGenState* hgs) 3581 { 3582 void visitType(Type t) 3583 { 3584 printf("t = %p, ty = %d\n", t, t.ty); 3585 assert(0); 3586 } 3587 3588 void visitError(TypeError t) 3589 { 3590 buf.writestring("_error_"); 3591 } 3592 3593 void visitBasic(TypeBasic t) 3594 { 3595 //printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod); 3596 buf.writestring(t.dstring); 3597 } 3598 3599 void visitTraits(TypeTraits t) 3600 { 3601 //printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod); 3602 t.exp.expressionToBuffer(buf, hgs); 3603 } 3604 3605 void visitVector(TypeVector t) 3606 { 3607 //printf("TypeVector::toCBuffer2(t.mod = %d)\n", t.mod); 3608 buf.writestring("__vector("); 3609 visitWithMask(t.basetype, t.mod, buf, hgs); 3610 buf.writestring(")"); 3611 } 3612 3613 void visitSArray(TypeSArray t) 3614 { 3615 visitWithMask(t.next, t.mod, buf, hgs); 3616 buf.writeByte('['); 3617 sizeToBuffer(t.dim, buf, hgs); 3618 buf.writeByte(']'); 3619 } 3620 3621 void visitDArray(TypeDArray t) 3622 { 3623 Type ut = t.castMod(0); 3624 if (hgs.declstring) 3625 goto L1; 3626 if (ut.equals(Type.tstring)) 3627 buf.writestring("string"); 3628 else if (ut.equals(Type.twstring)) 3629 buf.writestring("wstring"); 3630 else if (ut.equals(Type.tdstring)) 3631 buf.writestring("dstring"); 3632 else 3633 { 3634 L1: 3635 visitWithMask(t.next, t.mod, buf, hgs); 3636 buf.writestring("[]"); 3637 } 3638 } 3639 3640 void visitAArray(TypeAArray t) 3641 { 3642 visitWithMask(t.next, t.mod, buf, hgs); 3643 buf.writeByte('['); 3644 visitWithMask(t.index, 0, buf, hgs); 3645 buf.writeByte(']'); 3646 } 3647 3648 void visitPointer(TypePointer t) 3649 { 3650 //printf("TypePointer::toCBuffer2() next = %d\n", t.next.ty); 3651 if (t.next.ty == Tfunction) 3652 visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "function", buf, hgs); 3653 else 3654 { 3655 visitWithMask(t.next, t.mod, buf, hgs); 3656 buf.writeByte('*'); 3657 } 3658 } 3659 3660 void visitReference(TypeReference t) 3661 { 3662 visitWithMask(t.next, t.mod, buf, hgs); 3663 buf.writeByte('&'); 3664 } 3665 3666 void visitFunction(TypeFunction t) 3667 { 3668 //printf("TypeFunction::toCBuffer2() t = %p, ref = %d\n", t, t.isref); 3669 visitFuncIdentWithPostfix(t, null, buf, hgs); 3670 } 3671 3672 void visitDelegate(TypeDelegate t) 3673 { 3674 visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "delegate", buf, hgs); 3675 } 3676 3677 void visitTypeQualifiedHelper(TypeQualified t) 3678 { 3679 foreach (id; t.idents) 3680 { 3681 if (id.dyncast() == DYNCAST.dsymbol) 3682 { 3683 buf.writeByte('.'); 3684 TemplateInstance ti = cast(TemplateInstance)id; 3685 ti.dsymbolToBuffer(buf, hgs); 3686 } 3687 else if (id.dyncast() == DYNCAST.expression) 3688 { 3689 buf.writeByte('['); 3690 (cast(Expression)id).expressionToBuffer(buf, hgs); 3691 buf.writeByte(']'); 3692 } 3693 else if (id.dyncast() == DYNCAST.type) 3694 { 3695 buf.writeByte('['); 3696 typeToBufferx(cast(Type)id, buf, hgs); 3697 buf.writeByte(']'); 3698 } 3699 else 3700 { 3701 buf.writeByte('.'); 3702 buf.writestring(id.toString()); 3703 } 3704 } 3705 } 3706 3707 void visitIdentifier(TypeIdentifier t) 3708 { 3709 buf.writestring(t.ident.toString()); 3710 visitTypeQualifiedHelper(t); 3711 } 3712 3713 void visitInstance(TypeInstance t) 3714 { 3715 t.tempinst.dsymbolToBuffer(buf, hgs); 3716 visitTypeQualifiedHelper(t); 3717 } 3718 3719 void visitTypeof(TypeTypeof t) 3720 { 3721 buf.writestring("typeof("); 3722 t.exp.expressionToBuffer(buf, hgs); 3723 buf.writeByte(')'); 3724 visitTypeQualifiedHelper(t); 3725 } 3726 3727 void visitReturn(TypeReturn t) 3728 { 3729 buf.writestring("typeof(return)"); 3730 visitTypeQualifiedHelper(t); 3731 } 3732 3733 void visitEnum(TypeEnum t) 3734 { 3735 buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars()); 3736 } 3737 3738 void visitStruct(TypeStruct t) 3739 { 3740 // https://issues.dlang.org/show_bug.cgi?id=13776 3741 // Don't use ti.toAlias() to avoid forward reference error 3742 // while printing messages. 3743 TemplateInstance ti = t.sym.parent ? t.sym.parent.isTemplateInstance() : null; 3744 if (ti && ti.aliasdecl == t.sym) 3745 buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars()); 3746 else 3747 buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars()); 3748 } 3749 3750 void visitClass(TypeClass t) 3751 { 3752 // https://issues.dlang.org/show_bug.cgi?id=13776 3753 // Don't use ti.toAlias() to avoid forward reference error 3754 // while printing messages. 3755 TemplateInstance ti = t.sym.parent.isTemplateInstance(); 3756 if (ti && ti.aliasdecl == t.sym) 3757 buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars()); 3758 else 3759 buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars()); 3760 } 3761 3762 void visitTuple(TypeTuple t) 3763 { 3764 parametersToBuffer(ParameterList(t.arguments, VarArg.none), buf, hgs); 3765 } 3766 3767 void visitSlice(TypeSlice t) 3768 { 3769 visitWithMask(t.next, t.mod, buf, hgs); 3770 buf.writeByte('['); 3771 sizeToBuffer(t.lwr, buf, hgs); 3772 buf.writestring(" .. "); 3773 sizeToBuffer(t.upr, buf, hgs); 3774 buf.writeByte(']'); 3775 } 3776 3777 void visitNull(TypeNull t) 3778 { 3779 buf.writestring("typeof(null)"); 3780 } 3781 3782 void visitMixin(TypeMixin t) 3783 { 3784 buf.writestring("mixin("); 3785 argsToBuffer(t.exps, buf, hgs, null); 3786 buf.writeByte(')'); 3787 } 3788 3789 switch (t.ty) 3790 { 3791 default: return t.isTypeBasic() ? 3792 visitBasic(cast(TypeBasic)t) : 3793 visitType(t); 3794 3795 case Terror: return visitError(cast(TypeError)t); 3796 case Ttraits: return visitTraits(cast(TypeTraits)t); 3797 case Tvector: return visitVector(cast(TypeVector)t); 3798 case Tsarray: return visitSArray(cast(TypeSArray)t); 3799 case Tarray: return visitDArray(cast(TypeDArray)t); 3800 case Taarray: return visitAArray(cast(TypeAArray)t); 3801 case Tpointer: return visitPointer(cast(TypePointer)t); 3802 case Treference: return visitReference(cast(TypeReference)t); 3803 case Tfunction: return visitFunction(cast(TypeFunction)t); 3804 case Tdelegate: return visitDelegate(cast(TypeDelegate)t); 3805 case Tident: return visitIdentifier(cast(TypeIdentifier)t); 3806 case Tinstance: return visitInstance(cast(TypeInstance)t); 3807 case Ttypeof: return visitTypeof(cast(TypeTypeof)t); 3808 case Treturn: return visitReturn(cast(TypeReturn)t); 3809 case Tenum: return visitEnum(cast(TypeEnum)t); 3810 case Tstruct: return visitStruct(cast(TypeStruct)t); 3811 case Tclass: return visitClass(cast(TypeClass)t); 3812 case Ttuple: return visitTuple (cast(TypeTuple)t); 3813 case Tslice: return visitSlice(cast(TypeSlice)t); 3814 case Tnull: return visitNull(cast(TypeNull)t); 3815 case Tmixin: return visitMixin(cast(TypeMixin)t); 3816 } 3817 }