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-2021 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 foreach (const pid; imp.packages) 866 { 867 buf.printf("%s.", pid.toChars()); 868 } 869 buf.writestring(imp.id.toString()); 870 if (imp.names.dim) 871 { 872 buf.writestring(" : "); 873 foreach (const i, const name; imp.names) 874 { 875 if (i) 876 buf.writestring(", "); 877 const _alias = imp.aliases[i]; 878 if (_alias) 879 buf.printf("%s = %s", _alias.toChars(), name.toChars()); 880 else 881 buf.writestring(name.toChars()); 882 } 883 } 884 buf.writeByte(';'); 885 buf.writenl(); 886 } 887 888 override void visit(AliasThis d) 889 { 890 buf.writestring("alias "); 891 buf.writestring(d.ident.toString()); 892 buf.writestring(" this;\n"); 893 } 894 895 override void visit(AttribDeclaration d) 896 { 897 if (!d.decl) 898 { 899 buf.writeByte(';'); 900 buf.writenl(); 901 return; 902 } 903 if (d.decl.dim == 0 || (hgs.hdrgen && d.decl.dim == 1 && (*d.decl)[0].isUnitTestDeclaration())) 904 { 905 // hack for bugzilla 8081 906 buf.writestring("{}"); 907 } 908 else if (d.decl.dim == 1) 909 { 910 (*d.decl)[0].accept(this); 911 return; 912 } 913 else 914 { 915 buf.writenl(); 916 buf.writeByte('{'); 917 buf.writenl(); 918 buf.level++; 919 foreach (de; *d.decl) 920 de.accept(this); 921 buf.level--; 922 buf.writeByte('}'); 923 } 924 buf.writenl(); 925 } 926 927 override void visit(StorageClassDeclaration d) 928 { 929 if (stcToBuffer(buf, d.stc)) 930 buf.writeByte(' '); 931 visit(cast(AttribDeclaration)d); 932 } 933 934 override void visit(DeprecatedDeclaration d) 935 { 936 buf.writestring("deprecated("); 937 d.msg.expressionToBuffer(buf, hgs); 938 buf.writestring(") "); 939 visit(cast(AttribDeclaration)d); 940 } 941 942 override void visit(LinkDeclaration d) 943 { 944 buf.writestring("extern ("); 945 buf.writestring(linkageToString(d.linkage)); 946 buf.writestring(") "); 947 visit(cast(AttribDeclaration)d); 948 } 949 950 override void visit(CPPMangleDeclaration d) 951 { 952 string s; 953 final switch (d.cppmangle) 954 { 955 case CPPMANGLE.asClass: 956 s = "class"; 957 break; 958 case CPPMANGLE.asStruct: 959 s = "struct"; 960 break; 961 case CPPMANGLE.def: 962 break; 963 } 964 buf.writestring("extern (C++, "); 965 buf.writestring(s); 966 buf.writestring(") "); 967 visit(cast(AttribDeclaration)d); 968 } 969 970 override void visit(VisibilityDeclaration d) 971 { 972 visibilityToBuffer(buf, d.visibility); 973 buf.writeByte(' '); 974 AttribDeclaration ad = cast(AttribDeclaration)d; 975 if (ad.decl.dim == 1 && (*ad.decl)[0].isVisibilityDeclaration) 976 visit(cast(AttribDeclaration)(*ad.decl)[0]); 977 else 978 visit(cast(AttribDeclaration)d); 979 } 980 981 override void visit(AlignDeclaration d) 982 { 983 buf.writestring("align "); 984 if (d.ealign) 985 { 986 buf.printf("(%s)", d.ealign.toChars()); 987 AttribDeclaration ad = cast(AttribDeclaration)d; 988 if (ad.decl && ad.decl.dim < 2) 989 buf.writeByte(' '); 990 } 991 992 visit(cast(AttribDeclaration)d); 993 } 994 995 override void visit(AnonDeclaration d) 996 { 997 buf.writestring(d.isunion ? "union" : "struct"); 998 buf.writenl(); 999 buf.writestring("{"); 1000 buf.writenl(); 1001 buf.level++; 1002 if (d.decl) 1003 { 1004 foreach (de; *d.decl) 1005 de.accept(this); 1006 } 1007 buf.level--; 1008 buf.writestring("}"); 1009 buf.writenl(); 1010 } 1011 1012 override void visit(PragmaDeclaration d) 1013 { 1014 buf.writestring("pragma ("); 1015 buf.writestring(d.ident.toString()); 1016 if (d.args && d.args.dim) 1017 { 1018 buf.writestring(", "); 1019 argsToBuffer(d.args, buf, hgs); 1020 } 1021 buf.writeByte(')'); 1022 visit(cast(AttribDeclaration)d); 1023 } 1024 1025 override void visit(ConditionalDeclaration d) 1026 { 1027 d.condition.conditionToBuffer(buf, hgs); 1028 if (d.decl || d.elsedecl) 1029 { 1030 buf.writenl(); 1031 buf.writeByte('{'); 1032 buf.writenl(); 1033 buf.level++; 1034 if (d.decl) 1035 { 1036 foreach (de; *d.decl) 1037 de.accept(this); 1038 } 1039 buf.level--; 1040 buf.writeByte('}'); 1041 if (d.elsedecl) 1042 { 1043 buf.writenl(); 1044 buf.writestring("else"); 1045 buf.writenl(); 1046 buf.writeByte('{'); 1047 buf.writenl(); 1048 buf.level++; 1049 foreach (de; *d.elsedecl) 1050 de.accept(this); 1051 buf.level--; 1052 buf.writeByte('}'); 1053 } 1054 } 1055 else 1056 buf.writeByte(':'); 1057 buf.writenl(); 1058 } 1059 1060 override void visit(StaticForeachDeclaration s) 1061 { 1062 void foreachWithoutBody(ForeachStatement s) 1063 { 1064 buf.writestring(Token.toString(s.op)); 1065 buf.writestring(" ("); 1066 foreach (i, p; *s.parameters) 1067 { 1068 if (i) 1069 buf.writestring(", "); 1070 if (stcToBuffer(buf, p.storageClass)) 1071 buf.writeByte(' '); 1072 if (p.type) 1073 typeToBuffer(p.type, p.ident, buf, hgs); 1074 else 1075 buf.writestring(p.ident.toString()); 1076 } 1077 buf.writestring("; "); 1078 s.aggr.expressionToBuffer(buf, hgs); 1079 buf.writeByte(')'); 1080 buf.writenl(); 1081 } 1082 1083 void foreachRangeWithoutBody(ForeachRangeStatement s) 1084 { 1085 /* s.op ( prm ; lwr .. upr ) 1086 */ 1087 buf.writestring(Token.toString(s.op)); 1088 buf.writestring(" ("); 1089 if (s.prm.type) 1090 typeToBuffer(s.prm.type, s.prm.ident, buf, hgs); 1091 else 1092 buf.writestring(s.prm.ident.toString()); 1093 buf.writestring("; "); 1094 s.lwr.expressionToBuffer(buf, hgs); 1095 buf.writestring(" .. "); 1096 s.upr.expressionToBuffer(buf, hgs); 1097 buf.writeByte(')'); 1098 buf.writenl(); 1099 } 1100 1101 buf.writestring("static "); 1102 if (s.sfe.aggrfe) 1103 { 1104 foreachWithoutBody(s.sfe.aggrfe); 1105 } 1106 else 1107 { 1108 assert(s.sfe.rangefe); 1109 foreachRangeWithoutBody(s.sfe.rangefe); 1110 } 1111 buf.writeByte('{'); 1112 buf.writenl(); 1113 buf.level++; 1114 visit(cast(AttribDeclaration)s); 1115 buf.level--; 1116 buf.writeByte('}'); 1117 buf.writenl(); 1118 1119 } 1120 1121 override void visit(CompileDeclaration d) 1122 { 1123 buf.writestring("mixin("); 1124 argsToBuffer(d.exps, buf, hgs, null); 1125 buf.writestring(");"); 1126 buf.writenl(); 1127 } 1128 1129 override void visit(UserAttributeDeclaration d) 1130 { 1131 buf.writestring("@("); 1132 argsToBuffer(d.atts, buf, hgs); 1133 buf.writeByte(')'); 1134 visit(cast(AttribDeclaration)d); 1135 } 1136 1137 override void visit(TemplateDeclaration d) 1138 { 1139 version (none) 1140 { 1141 // Should handle template functions for doc generation 1142 if (onemember && onemember.isFuncDeclaration()) 1143 buf.writestring("foo "); 1144 } 1145 if ((hgs.hdrgen || hgs.fullDump) && visitEponymousMember(d)) 1146 return; 1147 if (hgs.ddoc) 1148 buf.writestring(d.kind()); 1149 else 1150 buf.writestring("template"); 1151 buf.writeByte(' '); 1152 buf.writestring(d.ident.toString()); 1153 buf.writeByte('('); 1154 visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters); 1155 buf.writeByte(')'); 1156 visitTemplateConstraint(d.constraint); 1157 if (hgs.hdrgen || hgs.fullDump) 1158 { 1159 hgs.tpltMember++; 1160 buf.writenl(); 1161 buf.writeByte('{'); 1162 buf.writenl(); 1163 buf.level++; 1164 foreach (s; *d.members) 1165 s.accept(this); 1166 buf.level--; 1167 buf.writeByte('}'); 1168 buf.writenl(); 1169 hgs.tpltMember--; 1170 } 1171 } 1172 1173 bool visitEponymousMember(TemplateDeclaration d) 1174 { 1175 if (!d.members || d.members.dim != 1) 1176 return false; 1177 Dsymbol onemember = (*d.members)[0]; 1178 if (onemember.ident != d.ident) 1179 return false; 1180 if (FuncDeclaration fd = onemember.isFuncDeclaration()) 1181 { 1182 assert(fd.type); 1183 if (stcToBuffer(buf, fd.storage_class)) 1184 buf.writeByte(' '); 1185 functionToBufferFull(cast(TypeFunction)fd.type, buf, d.ident, hgs, d); 1186 visitTemplateConstraint(d.constraint); 1187 hgs.tpltMember++; 1188 bodyToBuffer(fd); 1189 hgs.tpltMember--; 1190 return true; 1191 } 1192 if (AggregateDeclaration ad = onemember.isAggregateDeclaration()) 1193 { 1194 buf.writestring(ad.kind()); 1195 buf.writeByte(' '); 1196 buf.writestring(ad.ident.toString()); 1197 buf.writeByte('('); 1198 visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters); 1199 buf.writeByte(')'); 1200 visitTemplateConstraint(d.constraint); 1201 visitBaseClasses(ad.isClassDeclaration()); 1202 hgs.tpltMember++; 1203 if (ad.members) 1204 { 1205 buf.writenl(); 1206 buf.writeByte('{'); 1207 buf.writenl(); 1208 buf.level++; 1209 foreach (s; *ad.members) 1210 s.accept(this); 1211 buf.level--; 1212 buf.writeByte('}'); 1213 } 1214 else 1215 buf.writeByte(';'); 1216 buf.writenl(); 1217 hgs.tpltMember--; 1218 return true; 1219 } 1220 if (VarDeclaration vd = onemember.isVarDeclaration()) 1221 { 1222 if (d.constraint) 1223 return false; 1224 if (stcToBuffer(buf, vd.storage_class)) 1225 buf.writeByte(' '); 1226 if (vd.type) 1227 typeToBuffer(vd.type, vd.ident, buf, hgs); 1228 else 1229 buf.writestring(vd.ident.toString()); 1230 buf.writeByte('('); 1231 visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters); 1232 buf.writeByte(')'); 1233 if (vd._init) 1234 { 1235 buf.writestring(" = "); 1236 ExpInitializer ie = vd._init.isExpInitializer(); 1237 if (ie && (ie.exp.op == TOK.construct || ie.exp.op == TOK.blit)) 1238 (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs); 1239 else 1240 vd._init.initializerToBuffer(buf, hgs); 1241 } 1242 buf.writeByte(';'); 1243 buf.writenl(); 1244 return true; 1245 } 1246 return false; 1247 } 1248 1249 void visitTemplateParameters(TemplateParameters* parameters) 1250 { 1251 if (!parameters || !parameters.dim) 1252 return; 1253 foreach (i, p; *parameters) 1254 { 1255 if (i) 1256 buf.writestring(", "); 1257 p.templateParameterToBuffer(buf, hgs); 1258 } 1259 } 1260 1261 void visitTemplateConstraint(Expression constraint) 1262 { 1263 if (!constraint) 1264 return; 1265 buf.writestring(" if ("); 1266 constraint.expressionToBuffer(buf, hgs); 1267 buf.writeByte(')'); 1268 } 1269 1270 override void visit(TemplateInstance ti) 1271 { 1272 buf.writestring(ti.name.toChars()); 1273 tiargsToBuffer(ti, buf, hgs); 1274 1275 if (hgs.fullDump) 1276 { 1277 buf.writenl(); 1278 dumpTemplateInstance(ti, buf, hgs); 1279 } 1280 } 1281 1282 override void visit(TemplateMixin tm) 1283 { 1284 buf.writestring("mixin "); 1285 typeToBuffer(tm.tqual, null, buf, hgs); 1286 tiargsToBuffer(tm, buf, hgs); 1287 if (tm.ident && memcmp(tm.ident.toChars(), cast(const(char)*)"__mixin", 7) != 0) 1288 { 1289 buf.writeByte(' '); 1290 buf.writestring(tm.ident.toString()); 1291 } 1292 buf.writeByte(';'); 1293 buf.writenl(); 1294 if (hgs.fullDump) 1295 dumpTemplateInstance(tm, buf, hgs); 1296 } 1297 1298 override void visit(EnumDeclaration d) 1299 { 1300 auto oldInEnumDecl = hgs.inEnumDecl; 1301 scope(exit) hgs.inEnumDecl = oldInEnumDecl; 1302 hgs.inEnumDecl = d; 1303 buf.writestring("enum "); 1304 if (d.ident) 1305 { 1306 buf.writestring(d.ident.toString()); 1307 buf.writeByte(' '); 1308 } 1309 if (d.memtype) 1310 { 1311 buf.writestring(": "); 1312 typeToBuffer(d.memtype, null, buf, hgs); 1313 } 1314 if (!d.members) 1315 { 1316 buf.writeByte(';'); 1317 buf.writenl(); 1318 return; 1319 } 1320 buf.writenl(); 1321 buf.writeByte('{'); 1322 buf.writenl(); 1323 buf.level++; 1324 foreach (em; *d.members) 1325 { 1326 if (!em) 1327 continue; 1328 em.accept(this); 1329 buf.writeByte(','); 1330 buf.writenl(); 1331 } 1332 buf.level--; 1333 buf.writeByte('}'); 1334 buf.writenl(); 1335 } 1336 1337 override void visit(Nspace d) 1338 { 1339 buf.writestring("extern (C++, "); 1340 buf.writestring(d.ident.toString()); 1341 buf.writeByte(')'); 1342 buf.writenl(); 1343 buf.writeByte('{'); 1344 buf.writenl(); 1345 buf.level++; 1346 foreach (s; *d.members) 1347 s.accept(this); 1348 buf.level--; 1349 buf.writeByte('}'); 1350 buf.writenl(); 1351 } 1352 1353 override void visit(StructDeclaration d) 1354 { 1355 buf.writestring(d.kind()); 1356 buf.writeByte(' '); 1357 if (!d.isAnonymous()) 1358 buf.writestring(d.toChars()); 1359 if (!d.members) 1360 { 1361 buf.writeByte(';'); 1362 buf.writenl(); 1363 return; 1364 } 1365 buf.writenl(); 1366 buf.writeByte('{'); 1367 buf.writenl(); 1368 buf.level++; 1369 foreach (s; *d.members) 1370 s.accept(this); 1371 buf.level--; 1372 buf.writeByte('}'); 1373 buf.writenl(); 1374 } 1375 1376 override void visit(ClassDeclaration d) 1377 { 1378 if (!d.isAnonymous()) 1379 { 1380 buf.writestring(d.kind()); 1381 buf.writeByte(' '); 1382 buf.writestring(d.ident.toString()); 1383 } 1384 visitBaseClasses(d); 1385 if (d.members) 1386 { 1387 buf.writenl(); 1388 buf.writeByte('{'); 1389 buf.writenl(); 1390 buf.level++; 1391 foreach (s; *d.members) 1392 s.accept(this); 1393 buf.level--; 1394 buf.writeByte('}'); 1395 } 1396 else 1397 buf.writeByte(';'); 1398 buf.writenl(); 1399 } 1400 1401 void visitBaseClasses(ClassDeclaration d) 1402 { 1403 if (!d || !d.baseclasses.dim) 1404 return; 1405 if (!d.isAnonymous()) 1406 buf.writestring(" : "); 1407 foreach (i, b; *d.baseclasses) 1408 { 1409 if (i) 1410 buf.writestring(", "); 1411 typeToBuffer(b.type, null, buf, hgs); 1412 } 1413 } 1414 1415 override void visit(AliasDeclaration d) 1416 { 1417 if (d.storage_class & STC.local) 1418 return; 1419 buf.writestring("alias "); 1420 if (d.aliassym) 1421 { 1422 buf.writestring(d.ident.toString()); 1423 buf.writestring(" = "); 1424 if (stcToBuffer(buf, d.storage_class)) 1425 buf.writeByte(' '); 1426 d.aliassym.accept(this); 1427 } 1428 else if (d.type.ty == Tfunction) 1429 { 1430 if (stcToBuffer(buf, d.storage_class)) 1431 buf.writeByte(' '); 1432 typeToBuffer(d.type, d.ident, buf, hgs); 1433 } 1434 else if (d.ident) 1435 { 1436 hgs.declstring = (d.ident == Id..string || d.ident == Id.wstring || d.ident == Id.dstring); 1437 buf.writestring(d.ident.toString()); 1438 buf.writestring(" = "); 1439 if (stcToBuffer(buf, d.storage_class)) 1440 buf.writeByte(' '); 1441 typeToBuffer(d.type, null, buf, hgs); 1442 hgs.declstring = false; 1443 } 1444 buf.writeByte(';'); 1445 buf.writenl(); 1446 } 1447 1448 override void visit(AliasAssign d) 1449 { 1450 buf.writestring(d.ident.toString()); 1451 buf.writestring(" = "); 1452 if (d.aliassym) 1453 d.aliassym.accept(this); 1454 else // d.type 1455 typeToBuffer(d.type, null, buf, hgs); 1456 buf.writeByte(';'); 1457 buf.writenl(); 1458 } 1459 1460 override void visit(VarDeclaration d) 1461 { 1462 if (d.storage_class & STC.local) 1463 return; 1464 visitVarDecl(d, false); 1465 buf.writeByte(';'); 1466 buf.writenl(); 1467 } 1468 1469 void visitVarDecl(VarDeclaration v, bool anywritten) 1470 { 1471 if (anywritten) 1472 { 1473 buf.writestring(", "); 1474 buf.writestring(v.ident.toString()); 1475 } 1476 else 1477 { 1478 if (stcToBuffer(buf, v.storage_class)) 1479 buf.writeByte(' '); 1480 if (v.type) 1481 typeToBuffer(v.type, v.ident, buf, hgs); 1482 else 1483 buf.writestring(v.ident.toString()); 1484 } 1485 if (v._init) 1486 { 1487 buf.writestring(" = "); 1488 auto ie = v._init.isExpInitializer(); 1489 if (ie && (ie.exp.op == TOK.construct || ie.exp.op == TOK.blit)) 1490 (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs); 1491 else 1492 v._init.initializerToBuffer(buf, hgs); 1493 } 1494 } 1495 1496 override void visit(FuncDeclaration f) 1497 { 1498 //printf("FuncDeclaration::toCBuffer() '%s'\n", f.toChars()); 1499 if (stcToBuffer(buf, f.storage_class)) 1500 buf.writeByte(' '); 1501 auto tf = cast(TypeFunction)f.type; 1502 typeToBuffer(tf, f.ident, buf, hgs); 1503 1504 if (hgs.hdrgen) 1505 { 1506 // if the return type is missing (e.g. ref functions or auto) 1507 if (!tf.next || f.storage_class & STC.auto_) 1508 { 1509 hgs.autoMember++; 1510 bodyToBuffer(f); 1511 hgs.autoMember--; 1512 } 1513 else if (hgs.tpltMember == 0 && global.params.hdrStripPlainFunctions) 1514 { 1515 buf.writeByte(';'); 1516 buf.writenl(); 1517 } 1518 else 1519 bodyToBuffer(f); 1520 } 1521 else 1522 bodyToBuffer(f); 1523 } 1524 1525 void bodyToBuffer(FuncDeclaration f) 1526 { 1527 if (!f.fbody || (hgs.hdrgen && global.params.hdrStripPlainFunctions && !hgs.autoMember && !hgs.tpltMember)) 1528 { 1529 buf.writeByte(';'); 1530 buf.writenl(); 1531 return; 1532 } 1533 const savetlpt = hgs.tpltMember; 1534 const saveauto = hgs.autoMember; 1535 hgs.tpltMember = 0; 1536 hgs.autoMember = 0; 1537 buf.writenl(); 1538 bool requireDo = false; 1539 // in{} 1540 if (f.frequires) 1541 { 1542 foreach (frequire; *f.frequires) 1543 { 1544 buf.writestring("in"); 1545 if (auto es = frequire.isExpStatement()) 1546 { 1547 assert(es.exp && es.exp.op == TOK.assert_); 1548 buf.writestring(" ("); 1549 (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); 1550 buf.writeByte(')'); 1551 buf.writenl(); 1552 requireDo = false; 1553 } 1554 else 1555 { 1556 buf.writenl(); 1557 frequire.statementToBuffer(buf, hgs); 1558 requireDo = true; 1559 } 1560 } 1561 } 1562 // out{} 1563 if (f.fensures) 1564 { 1565 foreach (fensure; *f.fensures) 1566 { 1567 buf.writestring("out"); 1568 if (auto es = fensure.ensure.isExpStatement()) 1569 { 1570 assert(es.exp && es.exp.op == TOK.assert_); 1571 buf.writestring(" ("); 1572 if (fensure.id) 1573 { 1574 buf.writestring(fensure.id.toString()); 1575 } 1576 buf.writestring("; "); 1577 (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); 1578 buf.writeByte(')'); 1579 buf.writenl(); 1580 requireDo = false; 1581 } 1582 else 1583 { 1584 if (fensure.id) 1585 { 1586 buf.writeByte('('); 1587 buf.writestring(fensure.id.toString()); 1588 buf.writeByte(')'); 1589 } 1590 buf.writenl(); 1591 fensure.ensure.statementToBuffer(buf, hgs); 1592 requireDo = true; 1593 } 1594 } 1595 } 1596 if (requireDo) 1597 { 1598 buf.writestring("do"); 1599 buf.writenl(); 1600 } 1601 buf.writeByte('{'); 1602 buf.writenl(); 1603 buf.level++; 1604 f.fbody.statementToBuffer(buf, hgs); 1605 buf.level--; 1606 buf.writeByte('}'); 1607 buf.writenl(); 1608 hgs.tpltMember = savetlpt; 1609 hgs.autoMember = saveauto; 1610 } 1611 1612 override void visit(FuncLiteralDeclaration f) 1613 { 1614 if (f.type.ty == Terror) 1615 { 1616 buf.writestring("__error"); 1617 return; 1618 } 1619 if (f.tok != TOK.reserved) 1620 { 1621 buf.writestring(f.kind()); 1622 buf.writeByte(' '); 1623 } 1624 TypeFunction tf = cast(TypeFunction)f.type; 1625 1626 if (!f.inferRetType && tf.next) 1627 typeToBuffer(tf.next, null, buf, hgs); 1628 parametersToBuffer(tf.parameterList, buf, hgs); 1629 1630 // https://issues.dlang.org/show_bug.cgi?id=20074 1631 void printAttribute(string str) 1632 { 1633 buf.writeByte(' '); 1634 buf.writestring(str); 1635 } 1636 tf.attributesApply(&printAttribute); 1637 1638 1639 CompoundStatement cs = f.fbody.isCompoundStatement(); 1640 Statement s1; 1641 if (f.semanticRun >= PASS.semantic3done && cs) 1642 { 1643 s1 = (*cs.statements)[cs.statements.dim - 1]; 1644 } 1645 else 1646 s1 = !cs ? f.fbody : null; 1647 ReturnStatement rs = s1 ? s1.endsWithReturnStatement() : null; 1648 if (rs && rs.exp) 1649 { 1650 buf.writestring(" => "); 1651 rs.exp.expressionToBuffer(buf, hgs); 1652 } 1653 else 1654 { 1655 hgs.tpltMember++; 1656 bodyToBuffer(f); 1657 hgs.tpltMember--; 1658 } 1659 } 1660 1661 override void visit(PostBlitDeclaration d) 1662 { 1663 if (stcToBuffer(buf, d.storage_class)) 1664 buf.writeByte(' '); 1665 buf.writestring("this(this)"); 1666 bodyToBuffer(d); 1667 } 1668 1669 override void visit(DtorDeclaration d) 1670 { 1671 if (d.storage_class & STC.trusted) 1672 buf.writestring("@trusted "); 1673 if (d.storage_class & STC.safe) 1674 buf.writestring("@safe "); 1675 if (d.storage_class & STC.nogc) 1676 buf.writestring("@nogc "); 1677 if (d.storage_class & STC.live) 1678 buf.writestring("@live "); 1679 if (d.storage_class & STC.disable) 1680 buf.writestring("@disable "); 1681 1682 buf.writestring("~this()"); 1683 bodyToBuffer(d); 1684 } 1685 1686 override void visit(StaticCtorDeclaration d) 1687 { 1688 if (stcToBuffer(buf, d.storage_class & ~STC.static_)) 1689 buf.writeByte(' '); 1690 if (d.isSharedStaticCtorDeclaration()) 1691 buf.writestring("shared "); 1692 buf.writestring("static this()"); 1693 if (hgs.hdrgen && !hgs.tpltMember) 1694 { 1695 buf.writeByte(';'); 1696 buf.writenl(); 1697 } 1698 else 1699 bodyToBuffer(d); 1700 } 1701 1702 override void visit(StaticDtorDeclaration d) 1703 { 1704 if (stcToBuffer(buf, d.storage_class & ~STC.static_)) 1705 buf.writeByte(' '); 1706 if (d.isSharedStaticDtorDeclaration()) 1707 buf.writestring("shared "); 1708 buf.writestring("static ~this()"); 1709 if (hgs.hdrgen && !hgs.tpltMember) 1710 { 1711 buf.writeByte(';'); 1712 buf.writenl(); 1713 } 1714 else 1715 bodyToBuffer(d); 1716 } 1717 1718 override void visit(InvariantDeclaration d) 1719 { 1720 if (hgs.hdrgen) 1721 return; 1722 if (stcToBuffer(buf, d.storage_class)) 1723 buf.writeByte(' '); 1724 buf.writestring("invariant"); 1725 if(auto es = d.fbody.isExpStatement()) 1726 { 1727 assert(es.exp && es.exp.op == TOK.assert_); 1728 buf.writestring(" ("); 1729 (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); 1730 buf.writestring(");"); 1731 buf.writenl(); 1732 } 1733 else 1734 { 1735 bodyToBuffer(d); 1736 } 1737 } 1738 1739 override void visit(UnitTestDeclaration d) 1740 { 1741 if (hgs.hdrgen) 1742 return; 1743 if (stcToBuffer(buf, d.storage_class)) 1744 buf.writeByte(' '); 1745 buf.writestring("unittest"); 1746 bodyToBuffer(d); 1747 } 1748 1749 override void visit(NewDeclaration d) 1750 { 1751 if (stcToBuffer(buf, d.storage_class & ~STC.static_)) 1752 buf.writeByte(' '); 1753 buf.writestring("new"); 1754 parametersToBuffer(d.parameterList, buf, hgs); 1755 bodyToBuffer(d); 1756 } 1757 1758 override void visit(Module m) 1759 { 1760 moduleToBuffer2(m, buf, hgs); 1761 } 1762 } 1763 1764 private extern (C++) final class ExpressionPrettyPrintVisitor : Visitor 1765 { 1766 alias visit = Visitor.visit; 1767 public: 1768 OutBuffer* buf; 1769 HdrGenState* hgs; 1770 1771 extern (D) this(OutBuffer* buf, HdrGenState* hgs) 1772 { 1773 this.buf = buf; 1774 this.hgs = hgs; 1775 } 1776 1777 //////////////////////////////////////////////////////////////////////////// 1778 override void visit(Expression e) 1779 { 1780 buf.writestring(Token.toString(e.op)); 1781 } 1782 1783 override void visit(IntegerExp e) 1784 { 1785 const dinteger_t v = e.toInteger(); 1786 if (e.type) 1787 { 1788 Type t = e.type; 1789 L1: 1790 switch (t.ty) 1791 { 1792 case Tenum: 1793 { 1794 TypeEnum te = cast(TypeEnum)t; 1795 auto sym = te.sym; 1796 if (sym && sym.members && (!hgs.inEnumDecl || hgs.inEnumDecl != sym)) 1797 { 1798 foreach (em; *sym.members) 1799 { 1800 if ((cast(EnumMember)em).value.toInteger == v) 1801 { 1802 buf.printf("%s.%s", sym.toChars(), em.ident.toChars()); 1803 return ; 1804 } 1805 } 1806 } 1807 1808 buf.printf("cast(%s)", te.sym.toChars()); 1809 t = te.sym.memtype; 1810 goto L1; 1811 } 1812 case Twchar: 1813 // BUG: need to cast(wchar) 1814 case Tdchar: 1815 // BUG: need to cast(dchar) 1816 if (cast(uinteger_t)v > 0xFF) 1817 { 1818 buf.printf("'\\U%08llx'", cast(long)v); 1819 break; 1820 } 1821 goto case; 1822 case Tchar: 1823 { 1824 size_t o = buf.length; 1825 if (v == '\'') 1826 buf.writestring("'\\''"); 1827 else if (isprint(cast(int)v) && v != '\\') 1828 buf.printf("'%c'", cast(int)v); 1829 else 1830 buf.printf("'\\x%02x'", cast(int)v); 1831 if (hgs.ddoc) 1832 escapeDdocString(buf, o); 1833 break; 1834 } 1835 case Tint8: 1836 buf.writestring("cast(byte)"); 1837 goto L2; 1838 case Tint16: 1839 buf.writestring("cast(short)"); 1840 goto L2; 1841 case Tint32: 1842 L2: 1843 buf.printf("%d", cast(int)v); 1844 break; 1845 case Tuns8: 1846 buf.writestring("cast(ubyte)"); 1847 goto case Tuns32; 1848 case Tuns16: 1849 buf.writestring("cast(ushort)"); 1850 goto case Tuns32; 1851 case Tuns32: 1852 buf.printf("%uu", cast(uint)v); 1853 break; 1854 case Tint64: 1855 buf.printf("%lldL", v); 1856 break; 1857 case Tuns64: 1858 buf.printf("%lluLU", v); 1859 break; 1860 case Tbool: 1861 buf.writestring(v ? "true" : "false"); 1862 break; 1863 case Tpointer: 1864 buf.writestring("cast("); 1865 buf.writestring(t.toChars()); 1866 buf.writeByte(')'); 1867 if (target.ptrsize == 8) 1868 goto case Tuns64; 1869 else if (target.ptrsize == 4 || 1870 target.ptrsize == 2) 1871 goto case Tuns32; 1872 else 1873 assert(0); 1874 1875 case Tvoid: 1876 buf.writestring("cast(void)0"); 1877 break; 1878 1879 default: 1880 /* This can happen if errors, such as 1881 * the type is painted on like in fromConstInitializer(). 1882 */ 1883 if (!global.errors) 1884 { 1885 assert(0); 1886 } 1887 break; 1888 } 1889 } 1890 else if (v & 0x8000000000000000L) 1891 buf.printf("0x%llx", v); 1892 else 1893 buf.print(v); 1894 } 1895 1896 override void visit(ErrorExp e) 1897 { 1898 buf.writestring("__error"); 1899 } 1900 1901 override void visit(VoidInitExp e) 1902 { 1903 buf.writestring("__void"); 1904 } 1905 1906 void floatToBuffer(Type type, real_t value) 1907 { 1908 .floatToBuffer(type, value, buf, hgs.hdrgen); 1909 } 1910 1911 override void visit(RealExp e) 1912 { 1913 floatToBuffer(e.type, e.value); 1914 } 1915 1916 override void visit(ComplexExp e) 1917 { 1918 /* Print as: 1919 * (re+imi) 1920 */ 1921 buf.writeByte('('); 1922 floatToBuffer(e.type, creall(e.value)); 1923 buf.writeByte('+'); 1924 floatToBuffer(e.type, cimagl(e.value)); 1925 buf.writestring("i)"); 1926 } 1927 1928 override void visit(IdentifierExp e) 1929 { 1930 if (hgs.hdrgen || hgs.ddoc) 1931 buf.writestring(e.ident.toHChars2()); 1932 else 1933 buf.writestring(e.ident.toString()); 1934 } 1935 1936 override void visit(DsymbolExp e) 1937 { 1938 buf.writestring(e.s.toChars()); 1939 } 1940 1941 override void visit(ThisExp e) 1942 { 1943 buf.writestring("this"); 1944 } 1945 1946 override void visit(SuperExp e) 1947 { 1948 buf.writestring("super"); 1949 } 1950 1951 override void visit(NullExp e) 1952 { 1953 buf.writestring("null"); 1954 } 1955 1956 override void visit(StringExp e) 1957 { 1958 buf.writeByte('"'); 1959 const o = buf.length; 1960 for (size_t i = 0; i < e.len; i++) 1961 { 1962 const c = e.charAt(i); 1963 switch (c) 1964 { 1965 case '"': 1966 case '\\': 1967 buf.writeByte('\\'); 1968 goto default; 1969 default: 1970 if (c <= 0xFF) 1971 { 1972 if (c <= 0x7F && isprint(c)) 1973 buf.writeByte(c); 1974 else 1975 buf.printf("\\x%02x", c); 1976 } 1977 else if (c <= 0xFFFF) 1978 buf.printf("\\x%02x\\x%02x", c & 0xFF, c >> 8); 1979 else 1980 buf.printf("\\x%02x\\x%02x\\x%02x\\x%02x", c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24); 1981 break; 1982 } 1983 } 1984 if (hgs.ddoc) 1985 escapeDdocString(buf, o); 1986 buf.writeByte('"'); 1987 if (e.postfix) 1988 buf.writeByte(e.postfix); 1989 } 1990 1991 override void visit(ArrayLiteralExp e) 1992 { 1993 buf.writeByte('['); 1994 argsToBuffer(e.elements, buf, hgs, e.basis); 1995 buf.writeByte(']'); 1996 } 1997 1998 override void visit(AssocArrayLiteralExp e) 1999 { 2000 buf.writeByte('['); 2001 foreach (i, key; *e.keys) 2002 { 2003 if (i) 2004 buf.writestring(", "); 2005 expToBuffer(key, PREC.assign, buf, hgs); 2006 buf.writeByte(':'); 2007 auto value = (*e.values)[i]; 2008 expToBuffer(value, PREC.assign, buf, hgs); 2009 } 2010 buf.writeByte(']'); 2011 } 2012 2013 override void visit(StructLiteralExp e) 2014 { 2015 buf.writestring(e.sd.toChars()); 2016 buf.writeByte('('); 2017 // CTFE can generate struct literals that contain an AddrExp pointing 2018 // to themselves, need to avoid infinite recursion: 2019 // struct S { this(int){ this.s = &this; } S* s; } 2020 // const foo = new S(0); 2021 if (e.stageflags & stageToCBuffer) 2022 buf.writestring("<recursion>"); 2023 else 2024 { 2025 const old = e.stageflags; 2026 e.stageflags |= stageToCBuffer; 2027 argsToBuffer(e.elements, buf, hgs); 2028 e.stageflags = old; 2029 } 2030 buf.writeByte(')'); 2031 } 2032 2033 override void visit(TypeExp e) 2034 { 2035 typeToBuffer(e.type, null, buf, hgs); 2036 } 2037 2038 override void visit(ScopeExp e) 2039 { 2040 if (e.sds.isTemplateInstance()) 2041 { 2042 e.sds.dsymbolToBuffer(buf, hgs); 2043 } 2044 else if (hgs !is null && hgs.ddoc) 2045 { 2046 // fixes bug 6491 2047 if (auto m = e.sds.isModule()) 2048 buf.writestring(m.md.toChars()); 2049 else 2050 buf.writestring(e.sds.toChars()); 2051 } 2052 else 2053 { 2054 buf.writestring(e.sds.kind()); 2055 buf.writeByte(' '); 2056 buf.writestring(e.sds.toChars()); 2057 } 2058 } 2059 2060 override void visit(TemplateExp e) 2061 { 2062 buf.writestring(e.td.toChars()); 2063 } 2064 2065 override void visit(NewExp e) 2066 { 2067 if (e.thisexp) 2068 { 2069 expToBuffer(e.thisexp, PREC.primary, buf, hgs); 2070 buf.writeByte('.'); 2071 } 2072 buf.writestring("new "); 2073 if (e.newargs && e.newargs.dim) 2074 { 2075 buf.writeByte('('); 2076 argsToBuffer(e.newargs, buf, hgs); 2077 buf.writeByte(')'); 2078 } 2079 typeToBuffer(e.newtype, null, buf, hgs); 2080 if (e.arguments && e.arguments.dim) 2081 { 2082 buf.writeByte('('); 2083 argsToBuffer(e.arguments, buf, hgs); 2084 buf.writeByte(')'); 2085 } 2086 } 2087 2088 override void visit(NewAnonClassExp e) 2089 { 2090 if (e.thisexp) 2091 { 2092 expToBuffer(e.thisexp, PREC.primary, buf, hgs); 2093 buf.writeByte('.'); 2094 } 2095 buf.writestring("new"); 2096 if (e.newargs && e.newargs.dim) 2097 { 2098 buf.writeByte('('); 2099 argsToBuffer(e.newargs, buf, hgs); 2100 buf.writeByte(')'); 2101 } 2102 buf.writestring(" class "); 2103 if (e.arguments && e.arguments.dim) 2104 { 2105 buf.writeByte('('); 2106 argsToBuffer(e.arguments, buf, hgs); 2107 buf.writeByte(')'); 2108 } 2109 if (e.cd) 2110 e.cd.dsymbolToBuffer(buf, hgs); 2111 } 2112 2113 override void visit(SymOffExp e) 2114 { 2115 if (e.offset) 2116 buf.printf("(& %s%+lld)", e.var.toChars(), e.offset); 2117 else if (e.var.isTypeInfoDeclaration()) 2118 buf.writestring(e.var.toChars()); 2119 else 2120 buf.printf("& %s", e.var.toChars()); 2121 } 2122 2123 override void visit(VarExp e) 2124 { 2125 buf.writestring(e.var.toChars()); 2126 } 2127 2128 override void visit(OverExp e) 2129 { 2130 buf.writestring(e.vars.ident.toString()); 2131 } 2132 2133 override void visit(TupleExp e) 2134 { 2135 if (e.e0) 2136 { 2137 buf.writeByte('('); 2138 e.e0.accept(this); 2139 buf.writestring(", tuple("); 2140 argsToBuffer(e.exps, buf, hgs); 2141 buf.writestring("))"); 2142 } 2143 else 2144 { 2145 buf.writestring("tuple("); 2146 argsToBuffer(e.exps, buf, hgs); 2147 buf.writeByte(')'); 2148 } 2149 } 2150 2151 override void visit(FuncExp e) 2152 { 2153 e.fd.dsymbolToBuffer(buf, hgs); 2154 //buf.writestring(e.fd.toChars()); 2155 } 2156 2157 override void visit(DeclarationExp e) 2158 { 2159 /* Normal dmd execution won't reach here - regular variable declarations 2160 * are handled in visit(ExpStatement), so here would be used only when 2161 * we'll directly call Expression.toChars() for debugging. 2162 */ 2163 if (e.declaration) 2164 { 2165 if (auto var = e.declaration.isVarDeclaration()) 2166 { 2167 // For debugging use: 2168 // - Avoid printing newline. 2169 // - Intentionally use the format (Type var;) 2170 // which isn't correct as regular D code. 2171 buf.writeByte('('); 2172 2173 scope v = new DsymbolPrettyPrintVisitor(buf, hgs); 2174 v.visitVarDecl(var, false); 2175 2176 buf.writeByte(';'); 2177 buf.writeByte(')'); 2178 } 2179 else e.declaration.dsymbolToBuffer(buf, hgs); 2180 } 2181 } 2182 2183 override void visit(TypeidExp e) 2184 { 2185 buf.writestring("typeid("); 2186 objectToBuffer(e.obj, buf, hgs); 2187 buf.writeByte(')'); 2188 } 2189 2190 override void visit(TraitsExp e) 2191 { 2192 buf.writestring("__traits("); 2193 if (e.ident) 2194 buf.writestring(e.ident.toString()); 2195 if (e.args) 2196 { 2197 foreach (arg; *e.args) 2198 { 2199 buf.writestring(", "); 2200 objectToBuffer(arg, buf, hgs); 2201 } 2202 } 2203 buf.writeByte(')'); 2204 } 2205 2206 override void visit(HaltExp e) 2207 { 2208 buf.writestring("halt"); 2209 } 2210 2211 override void visit(IsExp e) 2212 { 2213 buf.writestring("is("); 2214 typeToBuffer(e.targ, e.id, buf, hgs); 2215 if (e.tok2 != TOK.reserved) 2216 { 2217 buf.printf(" %s %s", Token.toChars(e.tok), Token.toChars(e.tok2)); 2218 } 2219 else if (e.tspec) 2220 { 2221 if (e.tok == TOK.colon) 2222 buf.writestring(" : "); 2223 else 2224 buf.writestring(" == "); 2225 typeToBuffer(e.tspec, null, buf, hgs); 2226 } 2227 if (e.parameters && e.parameters.dim) 2228 { 2229 buf.writestring(", "); 2230 scope v = new DsymbolPrettyPrintVisitor(buf, hgs); 2231 v.visitTemplateParameters(e.parameters); 2232 } 2233 buf.writeByte(')'); 2234 } 2235 2236 override void visit(UnaExp e) 2237 { 2238 buf.writestring(Token.toString(e.op)); 2239 expToBuffer(e.e1, precedence[e.op], buf, hgs); 2240 } 2241 2242 override void visit(BinExp e) 2243 { 2244 expToBuffer(e.e1, precedence[e.op], buf, hgs); 2245 buf.writeByte(' '); 2246 buf.writestring(Token.toString(e.op)); 2247 buf.writeByte(' '); 2248 expToBuffer(e.e2, cast(PREC)(precedence[e.op] + 1), buf, hgs); 2249 } 2250 2251 override void visit(CommaExp e) 2252 { 2253 // CommaExp is generated by the compiler so it shouldn't 2254 // appear in error messages or header files. 2255 // For now, this treats the case where the compiler 2256 // generates CommaExp for temporaries by calling 2257 // the `sideeffect.copyToTemp` function. 2258 auto ve = e.e2.isVarExp(); 2259 2260 // not a CommaExp introduced for temporaries, go on 2261 // the old path 2262 if (!ve || !(ve.var.storage_class & STC.temp)) 2263 { 2264 visit(cast(BinExp)e); 2265 return; 2266 } 2267 2268 // CommaExp that contain temporaries inserted via 2269 // `copyToTemp` are usually of the form 2270 // ((T __temp = exp), __tmp). 2271 // Asserts are here to easily spot 2272 // missing cases where CommaExp 2273 // are used for other constructs 2274 auto vd = ve.var.isVarDeclaration(); 2275 assert(vd && vd._init); 2276 2277 if (auto ei = vd._init.isExpInitializer()) 2278 { 2279 Expression commaExtract; 2280 auto exp = ei.exp; 2281 if (auto ce = exp.isConstructExp()) 2282 commaExtract = ce.e2; 2283 else if (auto se = exp.isStructLiteralExp()) 2284 commaExtract = se; 2285 2286 if (commaExtract) 2287 { 2288 expToBuffer(commaExtract, precedence[exp.op], buf, hgs); 2289 return; 2290 } 2291 } 2292 2293 // not one of the known cases, go on the old path 2294 visit(cast(BinExp)e); 2295 return; 2296 } 2297 2298 override void visit(MixinExp e) 2299 { 2300 buf.writestring("mixin("); 2301 argsToBuffer(e.exps, buf, hgs, null); 2302 buf.writeByte(')'); 2303 } 2304 2305 override void visit(ImportExp e) 2306 { 2307 buf.writestring("import("); 2308 expToBuffer(e.e1, PREC.assign, buf, hgs); 2309 buf.writeByte(')'); 2310 } 2311 2312 override void visit(AssertExp e) 2313 { 2314 buf.writestring("assert("); 2315 expToBuffer(e.e1, PREC.assign, buf, hgs); 2316 if (e.msg) 2317 { 2318 buf.writestring(", "); 2319 expToBuffer(e.msg, PREC.assign, buf, hgs); 2320 } 2321 buf.writeByte(')'); 2322 } 2323 2324 override void visit(DotIdExp e) 2325 { 2326 expToBuffer(e.e1, PREC.primary, buf, hgs); 2327 buf.writeByte('.'); 2328 buf.writestring(e.ident.toString()); 2329 } 2330 2331 override void visit(DotTemplateExp e) 2332 { 2333 expToBuffer(e.e1, PREC.primary, buf, hgs); 2334 buf.writeByte('.'); 2335 buf.writestring(e.td.toChars()); 2336 } 2337 2338 override void visit(DotVarExp e) 2339 { 2340 expToBuffer(e.e1, PREC.primary, buf, hgs); 2341 buf.writeByte('.'); 2342 buf.writestring(e.var.toChars()); 2343 } 2344 2345 override void visit(DotTemplateInstanceExp e) 2346 { 2347 expToBuffer(e.e1, PREC.primary, buf, hgs); 2348 buf.writeByte('.'); 2349 e.ti.dsymbolToBuffer(buf, hgs); 2350 } 2351 2352 override void visit(DelegateExp e) 2353 { 2354 buf.writeByte('&'); 2355 if (!e.func.isNested() || e.func.needThis()) 2356 { 2357 expToBuffer(e.e1, PREC.primary, buf, hgs); 2358 buf.writeByte('.'); 2359 } 2360 buf.writestring(e.func.toChars()); 2361 } 2362 2363 override void visit(DotTypeExp e) 2364 { 2365 expToBuffer(e.e1, PREC.primary, buf, hgs); 2366 buf.writeByte('.'); 2367 buf.writestring(e.sym.toChars()); 2368 } 2369 2370 override void visit(CallExp e) 2371 { 2372 if (e.e1.op == TOK.type) 2373 { 2374 /* Avoid parens around type to prevent forbidden cast syntax: 2375 * (sometype)(arg1) 2376 * This is ok since types in constructor calls 2377 * can never depend on parens anyway 2378 */ 2379 e.e1.accept(this); 2380 } 2381 else 2382 expToBuffer(e.e1, precedence[e.op], buf, hgs); 2383 buf.writeByte('('); 2384 argsToBuffer(e.arguments, buf, hgs); 2385 buf.writeByte(')'); 2386 } 2387 2388 override void visit(PtrExp e) 2389 { 2390 buf.writeByte('*'); 2391 expToBuffer(e.e1, precedence[e.op], buf, hgs); 2392 } 2393 2394 override void visit(DeleteExp e) 2395 { 2396 buf.writestring("delete "); 2397 expToBuffer(e.e1, precedence[e.op], buf, hgs); 2398 } 2399 2400 override void visit(CastExp e) 2401 { 2402 buf.writestring("cast("); 2403 if (e.to) 2404 typeToBuffer(e.to, null, buf, hgs); 2405 else 2406 { 2407 MODtoBuffer(buf, e.mod); 2408 } 2409 buf.writeByte(')'); 2410 expToBuffer(e.e1, precedence[e.op], buf, hgs); 2411 } 2412 2413 override void visit(VectorExp e) 2414 { 2415 buf.writestring("cast("); 2416 typeToBuffer(e.to, null, buf, hgs); 2417 buf.writeByte(')'); 2418 expToBuffer(e.e1, precedence[e.op], buf, hgs); 2419 } 2420 2421 override void visit(VectorArrayExp e) 2422 { 2423 expToBuffer(e.e1, PREC.primary, buf, hgs); 2424 buf.writestring(".array"); 2425 } 2426 2427 override void visit(SliceExp e) 2428 { 2429 expToBuffer(e.e1, precedence[e.op], buf, hgs); 2430 buf.writeByte('['); 2431 if (e.upr || e.lwr) 2432 { 2433 if (e.lwr) 2434 sizeToBuffer(e.lwr, buf, hgs); 2435 else 2436 buf.writeByte('0'); 2437 buf.writestring(".."); 2438 if (e.upr) 2439 sizeToBuffer(e.upr, buf, hgs); 2440 else 2441 buf.writeByte('$'); 2442 } 2443 buf.writeByte(']'); 2444 } 2445 2446 override void visit(ArrayLengthExp e) 2447 { 2448 expToBuffer(e.e1, PREC.primary, buf, hgs); 2449 buf.writestring(".length"); 2450 } 2451 2452 override void visit(IntervalExp e) 2453 { 2454 expToBuffer(e.lwr, PREC.assign, buf, hgs); 2455 buf.writestring(".."); 2456 expToBuffer(e.upr, PREC.assign, buf, hgs); 2457 } 2458 2459 override void visit(DelegatePtrExp e) 2460 { 2461 expToBuffer(e.e1, PREC.primary, buf, hgs); 2462 buf.writestring(".ptr"); 2463 } 2464 2465 override void visit(DelegateFuncptrExp e) 2466 { 2467 expToBuffer(e.e1, PREC.primary, buf, hgs); 2468 buf.writestring(".funcptr"); 2469 } 2470 2471 override void visit(ArrayExp e) 2472 { 2473 expToBuffer(e.e1, PREC.primary, buf, hgs); 2474 buf.writeByte('['); 2475 argsToBuffer(e.arguments, buf, hgs); 2476 buf.writeByte(']'); 2477 } 2478 2479 override void visit(DotExp e) 2480 { 2481 expToBuffer(e.e1, PREC.primary, buf, hgs); 2482 buf.writeByte('.'); 2483 expToBuffer(e.e2, PREC.primary, buf, hgs); 2484 } 2485 2486 override void visit(IndexExp e) 2487 { 2488 expToBuffer(e.e1, PREC.primary, buf, hgs); 2489 buf.writeByte('['); 2490 sizeToBuffer(e.e2, buf, hgs); 2491 buf.writeByte(']'); 2492 } 2493 2494 override void visit(PostExp e) 2495 { 2496 expToBuffer(e.e1, precedence[e.op], buf, hgs); 2497 buf.writestring(Token.toString(e.op)); 2498 } 2499 2500 override void visit(PreExp e) 2501 { 2502 buf.writestring(Token.toString(e.op)); 2503 expToBuffer(e.e1, precedence[e.op], buf, hgs); 2504 } 2505 2506 override void visit(RemoveExp e) 2507 { 2508 expToBuffer(e.e1, PREC.primary, buf, hgs); 2509 buf.writestring(".remove("); 2510 expToBuffer(e.e2, PREC.assign, buf, hgs); 2511 buf.writeByte(')'); 2512 } 2513 2514 override void visit(CondExp e) 2515 { 2516 expToBuffer(e.econd, PREC.oror, buf, hgs); 2517 buf.writestring(" ? "); 2518 expToBuffer(e.e1, PREC.expr, buf, hgs); 2519 buf.writestring(" : "); 2520 expToBuffer(e.e2, PREC.cond, buf, hgs); 2521 } 2522 2523 override void visit(DefaultInitExp e) 2524 { 2525 buf.writestring(Token.toString(e.op)); 2526 } 2527 2528 override void visit(ClassReferenceExp e) 2529 { 2530 buf.writestring(e.value.toChars()); 2531 } 2532 } 2533 2534 /** 2535 * Formats `value` as a literal of type `type` into `buf`. 2536 * 2537 * Params: 2538 * type = literal type (e.g. Tfloat) 2539 * value = value to print 2540 * buf = target buffer 2541 * allowHex = whether hex floating point literals may be used 2542 * for greater accuracy 2543 */ 2544 void floatToBuffer(Type type, const real_t value, OutBuffer* buf, const bool allowHex) 2545 { 2546 /** sizeof(value)*3 is because each byte of mantissa is max 2547 of 256 (3 characters). The string will be "-M.MMMMe-4932". 2548 (ie, 8 chars more than mantissa). Plus one for trailing \0. 2549 Plus one for rounding. */ 2550 const(size_t) BUFFER_LEN = value.sizeof * 3 + 8 + 1 + 1; 2551 char[BUFFER_LEN] buffer; 2552 CTFloat.sprint(buffer.ptr, 'g', value); 2553 assert(strlen(buffer.ptr) < BUFFER_LEN); 2554 if (allowHex) 2555 { 2556 real_t r = CTFloat.parse(buffer.ptr); 2557 if (r != value) // if exact duplication 2558 CTFloat.sprint(buffer.ptr, 'a', value); 2559 } 2560 buf.writestring(buffer.ptr); 2561 if (buffer.ptr[strlen(buffer.ptr) - 1] == '.') 2562 buf.remove(buf.length() - 1, 1); 2563 2564 if (type) 2565 { 2566 Type t = type.toBasetype(); 2567 switch (t.ty) 2568 { 2569 case Tfloat32: 2570 case Timaginary32: 2571 case Tcomplex32: 2572 buf.writeByte('F'); 2573 break; 2574 case Tfloat80: 2575 case Timaginary80: 2576 case Tcomplex80: 2577 buf.writeByte('L'); 2578 break; 2579 default: 2580 break; 2581 } 2582 if (t.isimaginary()) 2583 buf.writeByte('i'); 2584 } 2585 } 2586 2587 private void templateParameterToBuffer(TemplateParameter tp, OutBuffer* buf, HdrGenState* hgs) 2588 { 2589 scope v = new TemplateParameterPrettyPrintVisitor(buf, hgs); 2590 tp.accept(v); 2591 } 2592 2593 private extern (C++) final class TemplateParameterPrettyPrintVisitor : Visitor 2594 { 2595 alias visit = Visitor.visit; 2596 public: 2597 OutBuffer* buf; 2598 HdrGenState* hgs; 2599 2600 extern (D) this(OutBuffer* buf, HdrGenState* hgs) 2601 { 2602 this.buf = buf; 2603 this.hgs = hgs; 2604 } 2605 2606 override void visit(TemplateTypeParameter tp) 2607 { 2608 buf.writestring(tp.ident.toString()); 2609 if (tp.specType) 2610 { 2611 buf.writestring(" : "); 2612 typeToBuffer(tp.specType, null, buf, hgs); 2613 } 2614 if (tp.defaultType) 2615 { 2616 buf.writestring(" = "); 2617 typeToBuffer(tp.defaultType, null, buf, hgs); 2618 } 2619 } 2620 2621 override void visit(TemplateThisParameter tp) 2622 { 2623 buf.writestring("this "); 2624 visit(cast(TemplateTypeParameter)tp); 2625 } 2626 2627 override void visit(TemplateAliasParameter tp) 2628 { 2629 buf.writestring("alias "); 2630 if (tp.specType) 2631 typeToBuffer(tp.specType, tp.ident, buf, hgs); 2632 else 2633 buf.writestring(tp.ident.toString()); 2634 if (tp.specAlias) 2635 { 2636 buf.writestring(" : "); 2637 objectToBuffer(tp.specAlias, buf, hgs); 2638 } 2639 if (tp.defaultAlias) 2640 { 2641 buf.writestring(" = "); 2642 objectToBuffer(tp.defaultAlias, buf, hgs); 2643 } 2644 } 2645 2646 override void visit(TemplateValueParameter tp) 2647 { 2648 typeToBuffer(tp.valType, tp.ident, buf, hgs); 2649 if (tp.specValue) 2650 { 2651 buf.writestring(" : "); 2652 tp.specValue.expressionToBuffer(buf, hgs); 2653 } 2654 if (tp.defaultValue) 2655 { 2656 buf.writestring(" = "); 2657 tp.defaultValue.expressionToBuffer(buf, hgs); 2658 } 2659 } 2660 2661 override void visit(TemplateTupleParameter tp) 2662 { 2663 buf.writestring(tp.ident.toString()); 2664 buf.writestring("..."); 2665 } 2666 } 2667 2668 private void conditionToBuffer(Condition c, OutBuffer* buf, HdrGenState* hgs) 2669 { 2670 scope v = new ConditionPrettyPrintVisitor(buf, hgs); 2671 c.accept(v); 2672 } 2673 2674 private extern (C++) final class ConditionPrettyPrintVisitor : Visitor 2675 { 2676 alias visit = Visitor.visit; 2677 public: 2678 OutBuffer* buf; 2679 HdrGenState* hgs; 2680 2681 extern (D) this(OutBuffer* buf, HdrGenState* hgs) 2682 { 2683 this.buf = buf; 2684 this.hgs = hgs; 2685 } 2686 2687 override void visit(DebugCondition c) 2688 { 2689 buf.writestring("debug ("); 2690 if (c.ident) 2691 buf.writestring(c.ident.toString()); 2692 else 2693 buf.print(c.level); 2694 buf.writeByte(')'); 2695 } 2696 2697 override void visit(VersionCondition c) 2698 { 2699 buf.writestring("version ("); 2700 if (c.ident) 2701 buf.writestring(c.ident.toString()); 2702 else 2703 buf.print(c.level); 2704 buf.writeByte(')'); 2705 } 2706 2707 override void visit(StaticIfCondition c) 2708 { 2709 buf.writestring("static if ("); 2710 c.exp.expressionToBuffer(buf, hgs); 2711 buf.writeByte(')'); 2712 } 2713 } 2714 2715 void toCBuffer(const Statement s, OutBuffer* buf, HdrGenState* hgs) 2716 { 2717 scope v = new StatementPrettyPrintVisitor(buf, hgs); 2718 (cast() s).accept(v); 2719 } 2720 2721 void toCBuffer(const Type t, OutBuffer* buf, const Identifier ident, HdrGenState* hgs) 2722 { 2723 typeToBuffer(cast() t, ident, buf, hgs); 2724 } 2725 2726 void toCBuffer(Dsymbol s, OutBuffer* buf, HdrGenState* hgs) 2727 { 2728 scope v = new DsymbolPrettyPrintVisitor(buf, hgs); 2729 s.accept(v); 2730 } 2731 2732 // used from TemplateInstance::toChars() and TemplateMixin::toChars() 2733 void toCBufferInstance(const TemplateInstance ti, OutBuffer* buf, bool qualifyTypes = false) 2734 { 2735 HdrGenState hgs; 2736 hgs.fullQual = qualifyTypes; 2737 scope v = new DsymbolPrettyPrintVisitor(buf, &hgs); 2738 v.visit(cast() ti); 2739 } 2740 2741 void toCBuffer(const Initializer iz, OutBuffer* buf, HdrGenState* hgs) 2742 { 2743 initializerToBuffer(cast() iz, buf, hgs); 2744 } 2745 2746 bool stcToBuffer(OutBuffer* buf, StorageClass stc) 2747 { 2748 bool result = false; 2749 if ((stc & (STC.return_ | STC.scope_)) == (STC.return_ | STC.scope_)) 2750 stc &= ~STC.scope_; 2751 if (stc & STC.scopeinferred) 2752 stc &= ~(STC.scope_ | STC.scopeinferred); 2753 while (stc) 2754 { 2755 const s = stcToString(stc); 2756 if (!s.length) 2757 break; 2758 if (result) 2759 buf.writeByte(' '); 2760 result = true; 2761 buf.writestring(s); 2762 } 2763 return result; 2764 } 2765 2766 /************************************************* 2767 * Pick off one of the storage classes from stc, 2768 * and return a string representation of it. 2769 * stc is reduced by the one picked. 2770 */ 2771 string stcToString(ref StorageClass stc) 2772 { 2773 static struct SCstring 2774 { 2775 StorageClass stc; 2776 string id; 2777 } 2778 2779 // Note: The identifier needs to be `\0` terminated 2780 // as some code assumes it (e.g. when printing error messages) 2781 static immutable SCstring[] table = 2782 [ 2783 SCstring(STC.auto_, Token.toString(TOK.auto_)), 2784 SCstring(STC.scope_, Token.toString(TOK.scope_)), 2785 SCstring(STC.static_, Token.toString(TOK.static_)), 2786 SCstring(STC.extern_, Token.toString(TOK.extern_)), 2787 SCstring(STC.const_, Token.toString(TOK.const_)), 2788 SCstring(STC.final_, Token.toString(TOK.final_)), 2789 SCstring(STC.abstract_, Token.toString(TOK.abstract_)), 2790 SCstring(STC.synchronized_, Token.toString(TOK.synchronized_)), 2791 SCstring(STC.deprecated_, Token.toString(TOK.deprecated_)), 2792 SCstring(STC.override_, Token.toString(TOK.override_)), 2793 SCstring(STC.lazy_, Token.toString(TOK.lazy_)), 2794 SCstring(STC.alias_, Token.toString(TOK.alias_)), 2795 SCstring(STC.out_, Token.toString(TOK.out_)), 2796 SCstring(STC.in_, Token.toString(TOK.in_)), 2797 SCstring(STC.manifest, Token.toString(TOK.enum_)), 2798 SCstring(STC.immutable_, Token.toString(TOK.immutable_)), 2799 SCstring(STC.shared_, Token.toString(TOK.shared_)), 2800 SCstring(STC.nothrow_, Token.toString(TOK.nothrow_)), 2801 SCstring(STC.wild, Token.toString(TOK.inout_)), 2802 SCstring(STC.pure_, Token.toString(TOK.pure_)), 2803 SCstring(STC.ref_, Token.toString(TOK.ref_)), 2804 SCstring(STC.return_, Token.toString(TOK.return_)), 2805 SCstring(STC.tls, "__thread"), 2806 SCstring(STC.gshared, Token.toString(TOK.gshared)), 2807 SCstring(STC.nogc, "@nogc"), 2808 SCstring(STC.live, "@live"), 2809 SCstring(STC.property, "@property"), 2810 SCstring(STC.safe, "@safe"), 2811 SCstring(STC.trusted, "@trusted"), 2812 SCstring(STC.system, "@system"), 2813 SCstring(STC.disable, "@disable"), 2814 SCstring(STC.future, "@__future"), 2815 SCstring(STC.local, "__local"), 2816 ]; 2817 foreach (ref entry; table) 2818 { 2819 const StorageClass tbl = entry.stc; 2820 assert(tbl & STCStorageClass); 2821 if (stc & tbl) 2822 { 2823 stc &= ~tbl; 2824 return entry.id; 2825 } 2826 } 2827 //printf("stc = %llx\n", stc); 2828 return null; 2829 } 2830 2831 /// Ditto 2832 extern (D) string trustToString(TRUST trust) pure nothrow 2833 { 2834 final switch (trust) 2835 { 2836 case TRUST.default_: 2837 return null; 2838 case TRUST.system: 2839 return "@system"; 2840 case TRUST.trusted: 2841 return "@trusted"; 2842 case TRUST.safe: 2843 return "@safe"; 2844 } 2845 } 2846 2847 private void linkageToBuffer(OutBuffer* buf, LINK linkage) 2848 { 2849 const s = linkageToString(linkage); 2850 if (s.length) 2851 { 2852 buf.writestring("extern ("); 2853 buf.writestring(s); 2854 buf.writeByte(')'); 2855 } 2856 } 2857 2858 const(char)* linkageToChars(LINK linkage) 2859 { 2860 /// Works because we return a literal 2861 return linkageToString(linkage).ptr; 2862 } 2863 2864 string linkageToString(LINK linkage) pure nothrow 2865 { 2866 final switch (linkage) 2867 { 2868 case LINK.default_: 2869 return null; 2870 case LINK.d: 2871 return "D"; 2872 case LINK.c: 2873 return "C"; 2874 case LINK.cpp: 2875 return "C++"; 2876 case LINK.windows: 2877 return "Windows"; 2878 case LINK.objc: 2879 return "Objective-C"; 2880 case LINK.system: 2881 return "System"; 2882 } 2883 } 2884 2885 void visibilityToBuffer(OutBuffer* buf, Visibility vis) 2886 { 2887 buf.writestring(visibilityToString(vis.kind)); 2888 if (vis.kind == Visibility.Kind.package_ && vis.pkg) 2889 { 2890 buf.writeByte('('); 2891 buf.writestring(vis.pkg.toPrettyChars(true)); 2892 buf.writeByte(')'); 2893 } 2894 } 2895 2896 /** 2897 * Returns: 2898 * a human readable representation of `kind` 2899 */ 2900 const(char)* visibilityToChars(Visibility.Kind kind) 2901 { 2902 // Null terminated because we return a literal 2903 return visibilityToString(kind).ptr; 2904 } 2905 2906 /// Ditto 2907 extern (D) string visibilityToString(Visibility.Kind kind) nothrow pure 2908 { 2909 final switch (kind) 2910 { 2911 case Visibility.Kind.undefined: 2912 return null; 2913 case Visibility.Kind.none: 2914 return "none"; 2915 case Visibility.Kind.private_: 2916 return "private"; 2917 case Visibility.Kind.package_: 2918 return "package"; 2919 case Visibility.Kind.protected_: 2920 return "protected"; 2921 case Visibility.Kind.public_: 2922 return "public"; 2923 case Visibility.Kind.export_: 2924 return "export"; 2925 } 2926 } 2927 2928 // Print the full function signature with correct ident, attributes and template args 2929 void functionToBufferFull(TypeFunction tf, OutBuffer* buf, const Identifier ident, HdrGenState* hgs, TemplateDeclaration td) 2930 { 2931 //printf("TypeFunction::toCBuffer() this = %p\n", this); 2932 visitFuncIdentWithPrefix(tf, ident, td, buf, hgs); 2933 } 2934 2935 // ident is inserted before the argument list and will be "function" or "delegate" for a type 2936 void functionToBufferWithIdent(TypeFunction tf, OutBuffer* buf, const(char)* ident, bool isStatic) 2937 { 2938 HdrGenState hgs; 2939 visitFuncIdentWithPostfix(tf, ident.toDString(), buf, &hgs, isStatic); 2940 } 2941 2942 void toCBuffer(const Expression e, OutBuffer* buf, HdrGenState* hgs) 2943 { 2944 scope v = new ExpressionPrettyPrintVisitor(buf, hgs); 2945 (cast() e).accept(v); 2946 } 2947 2948 /************************************************** 2949 * Write out argument types to buf. 2950 */ 2951 void argExpTypesToCBuffer(OutBuffer* buf, Expressions* arguments) 2952 { 2953 if (!arguments || !arguments.dim) 2954 return; 2955 HdrGenState hgs; 2956 foreach (i, arg; *arguments) 2957 { 2958 if (i) 2959 buf.writestring(", "); 2960 typeToBuffer(arg.type, null, buf, &hgs); 2961 } 2962 } 2963 2964 void toCBuffer(const TemplateParameter tp, OutBuffer* buf, HdrGenState* hgs) 2965 { 2966 scope v = new TemplateParameterPrettyPrintVisitor(buf, hgs); 2967 (cast() tp).accept(v); 2968 } 2969 2970 void arrayObjectsToBuffer(OutBuffer* buf, Objects* objects) 2971 { 2972 if (!objects || !objects.dim) 2973 return; 2974 HdrGenState hgs; 2975 foreach (i, o; *objects) 2976 { 2977 if (i) 2978 buf.writestring(", "); 2979 objectToBuffer(o, buf, &hgs); 2980 } 2981 } 2982 2983 /************************************************************* 2984 * Pretty print function parameters. 2985 * Params: 2986 * pl = parameter list to print 2987 * Returns: Null-terminated string representing parameters. 2988 */ 2989 extern (C++) const(char)* parametersTypeToChars(ParameterList pl) 2990 { 2991 OutBuffer buf; 2992 HdrGenState hgs; 2993 parametersToBuffer(pl, &buf, &hgs); 2994 return buf.extractChars(); 2995 } 2996 2997 /************************************************************* 2998 * Pretty print function parameter. 2999 * Params: 3000 * parameter = parameter to print. 3001 * tf = TypeFunction which holds parameter. 3002 * fullQual = whether to fully qualify types. 3003 * Returns: Null-terminated string representing parameters. 3004 */ 3005 const(char)* parameterToChars(Parameter parameter, TypeFunction tf, bool fullQual) 3006 { 3007 OutBuffer buf; 3008 HdrGenState hgs; 3009 hgs.fullQual = fullQual; 3010 3011 parameterToBuffer(parameter, &buf, &hgs); 3012 3013 if (tf.parameterList.varargs == VarArg.typesafe && parameter == tf.parameterList[tf.parameterList.parameters.dim - 1]) 3014 { 3015 buf.writestring("..."); 3016 } 3017 return buf.extractChars(); 3018 } 3019 3020 3021 /************************************************* 3022 * Write ParameterList to buffer. 3023 * Params: 3024 * pl = parameter list to serialize 3025 * buf = buffer to write it to 3026 * hgs = context 3027 */ 3028 3029 private void parametersToBuffer(ParameterList pl, OutBuffer* buf, HdrGenState* hgs) 3030 { 3031 buf.writeByte('('); 3032 foreach (i; 0 .. pl.length) 3033 { 3034 if (i) 3035 buf.writestring(", "); 3036 pl[i].parameterToBuffer(buf, hgs); 3037 } 3038 final switch (pl.varargs) 3039 { 3040 case VarArg.none: 3041 break; 3042 3043 case VarArg.variadic: 3044 if (pl.length) 3045 buf.writestring(", "); 3046 3047 if (stcToBuffer(buf, pl.stc)) 3048 buf.writeByte(' '); 3049 goto case VarArg.typesafe; 3050 3051 case VarArg.typesafe: 3052 buf.writestring("..."); 3053 break; 3054 } 3055 buf.writeByte(')'); 3056 } 3057 3058 3059 /*********************************************************** 3060 * Write parameter `p` to buffer `buf`. 3061 * Params: 3062 * p = parameter to serialize 3063 * buf = buffer to write it to 3064 * hgs = context 3065 */ 3066 private void parameterToBuffer(Parameter p, OutBuffer* buf, HdrGenState* hgs) 3067 { 3068 if (p.userAttribDecl) 3069 { 3070 buf.writeByte('@'); 3071 3072 bool isAnonymous = p.userAttribDecl.atts.dim > 0 && (*p.userAttribDecl.atts)[0].op != TOK.call; 3073 if (isAnonymous) 3074 buf.writeByte('('); 3075 3076 argsToBuffer(p.userAttribDecl.atts, buf, hgs); 3077 3078 if (isAnonymous) 3079 buf.writeByte(')'); 3080 buf.writeByte(' '); 3081 } 3082 if (p.storageClass & STC.auto_) 3083 buf.writestring("auto "); 3084 if (p.storageClass & STC.return_) 3085 buf.writestring("return "); 3086 3087 if (p.storageClass & STC.in_) 3088 buf.writestring("in "); 3089 else if (global.params.previewIn && p.storageClass & STC.ref_) 3090 buf.writestring("ref "); 3091 else if (p.storageClass & STC.out_) 3092 buf.writestring("out "); 3093 else if (p.storageClass & STC.lazy_) 3094 buf.writestring("lazy "); 3095 else if (p.storageClass & STC.alias_) 3096 buf.writestring("alias "); 3097 3098 if (!global.params.previewIn && p.storageClass & STC.ref_) 3099 buf.writestring("ref "); 3100 3101 StorageClass stc = p.storageClass; 3102 if (p.type && p.type.mod & MODFlags.shared_) 3103 stc &= ~STC.shared_; 3104 3105 if (stcToBuffer(buf, stc & (STC.const_ | STC.immutable_ | STC.wild | STC.shared_ | STC.scope_ | STC.scopeinferred))) 3106 buf.writeByte(' '); 3107 3108 if (p.storageClass & STC.alias_) 3109 { 3110 if (p.ident) 3111 buf.writestring(p.ident.toString()); 3112 } 3113 else if (p.type.ty == Tident && 3114 (cast(TypeIdentifier)p.type).ident.toString().length > 3 && 3115 strncmp((cast(TypeIdentifier)p.type).ident.toChars(), "__T", 3) == 0) 3116 { 3117 // print parameter name, instead of undetermined type parameter 3118 buf.writestring(p.ident.toString()); 3119 } 3120 else 3121 { 3122 typeToBuffer(p.type, p.ident, buf, hgs, (stc & STC.in_) ? MODFlags.const_ : 0); 3123 } 3124 3125 if (p.defaultArg) 3126 { 3127 buf.writestring(" = "); 3128 p.defaultArg.expToBuffer(PREC.assign, buf, hgs); 3129 } 3130 } 3131 3132 3133 /************************************************** 3134 * Write out argument list to buf. 3135 */ 3136 private void argsToBuffer(Expressions* expressions, OutBuffer* buf, HdrGenState* hgs, Expression basis = null) 3137 { 3138 if (!expressions || !expressions.dim) 3139 return; 3140 version (all) 3141 { 3142 foreach (i, el; *expressions) 3143 { 3144 if (i) 3145 buf.writestring(", "); 3146 if (!el) 3147 el = basis; 3148 if (el) 3149 expToBuffer(el, PREC.assign, buf, hgs); 3150 } 3151 } 3152 else 3153 { 3154 // Sparse style formatting, for debug use only 3155 // [0..dim: basis, 1: e1, 5: e5] 3156 if (basis) 3157 { 3158 buf.writestring("0.."); 3159 buf.print(expressions.dim); 3160 buf.writestring(": "); 3161 expToBuffer(basis, PREC.assign, buf, hgs); 3162 } 3163 foreach (i, el; *expressions) 3164 { 3165 if (el) 3166 { 3167 if (basis) 3168 { 3169 buf.writestring(", "); 3170 buf.print(i); 3171 buf.writestring(": "); 3172 } 3173 else if (i) 3174 buf.writestring(", "); 3175 expToBuffer(el, PREC.assign, buf, hgs); 3176 } 3177 } 3178 } 3179 } 3180 3181 private void sizeToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs) 3182 { 3183 if (e.type == Type.tsize_t) 3184 { 3185 Expression ex = (e.op == TOK.cast_ ? (cast(CastExp)e).e1 : e); 3186 ex = ex.optimize(WANTvalue); 3187 const dinteger_t uval = ex.op == TOK.int64 ? ex.toInteger() : cast(dinteger_t)-1; 3188 if (cast(sinteger_t)uval >= 0) 3189 { 3190 dinteger_t sizemax = void; 3191 if (target.ptrsize == 8) 3192 sizemax = 0xFFFFFFFFFFFFFFFFUL; 3193 else if (target.ptrsize == 4) 3194 sizemax = 0xFFFFFFFFU; 3195 else if (target.ptrsize == 2) 3196 sizemax = 0xFFFFU; 3197 else 3198 assert(0); 3199 if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFUL) 3200 { 3201 buf.print(uval); 3202 return; 3203 } 3204 } 3205 } 3206 expToBuffer(e, PREC.assign, buf, hgs); 3207 } 3208 3209 private void expressionToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs) 3210 { 3211 scope v = new ExpressionPrettyPrintVisitor(buf, hgs); 3212 e.accept(v); 3213 } 3214 3215 /************************************************** 3216 * Write expression out to buf, but wrap it 3217 * in ( ) if its precedence is less than pr. 3218 */ 3219 private void expToBuffer(Expression e, PREC pr, OutBuffer* buf, HdrGenState* hgs) 3220 { 3221 debug 3222 { 3223 if (precedence[e.op] == PREC.zero) 3224 printf("precedence not defined for token '%s'\n", Token.toChars(e.op)); 3225 } 3226 if (e.op == 0xFF) 3227 { 3228 buf.writestring("<FF>"); 3229 return; 3230 } 3231 assert(precedence[e.op] != PREC.zero); 3232 assert(pr != PREC.zero); 3233 /* Despite precedence, we don't allow a<b<c expressions. 3234 * They must be parenthesized. 3235 */ 3236 if (precedence[e.op] < pr || (pr == PREC.rel && precedence[e.op] == pr) 3237 || (pr >= PREC.or && pr <= PREC.and && precedence[e.op] == PREC.rel)) 3238 { 3239 buf.writeByte('('); 3240 e.expressionToBuffer(buf, hgs); 3241 buf.writeByte(')'); 3242 } 3243 else 3244 { 3245 e.expressionToBuffer(buf, hgs); 3246 } 3247 } 3248 3249 3250 /************************************************** 3251 * An entry point to pretty-print type. 3252 */ 3253 private void typeToBuffer(Type t, const Identifier ident, OutBuffer* buf, HdrGenState* hgs, 3254 ubyte modMask = 0) 3255 { 3256 if (auto tf = t.isTypeFunction()) 3257 { 3258 visitFuncIdentWithPrefix(tf, ident, null, buf, hgs); 3259 return; 3260 } 3261 visitWithMask(t, modMask, buf, hgs); 3262 if (ident) 3263 { 3264 buf.writeByte(' '); 3265 buf.writestring(ident.toString()); 3266 } 3267 } 3268 3269 private void visitWithMask(Type t, ubyte modMask, OutBuffer* buf, HdrGenState* hgs) 3270 { 3271 // Tuples and functions don't use the type constructor syntax 3272 if (modMask == t.mod || t.ty == Tfunction || t.ty == Ttuple) 3273 { 3274 typeToBufferx(t, buf, hgs); 3275 } 3276 else 3277 { 3278 ubyte m = t.mod & ~(t.mod & modMask); 3279 if (m & MODFlags.shared_) 3280 { 3281 MODtoBuffer(buf, MODFlags.shared_); 3282 buf.writeByte('('); 3283 } 3284 if (m & MODFlags.wild) 3285 { 3286 MODtoBuffer(buf, MODFlags.wild); 3287 buf.writeByte('('); 3288 } 3289 if (m & (MODFlags.const_ | MODFlags.immutable_)) 3290 { 3291 MODtoBuffer(buf, m & (MODFlags.const_ | MODFlags.immutable_)); 3292 buf.writeByte('('); 3293 } 3294 typeToBufferx(t, buf, hgs); 3295 if (m & (MODFlags.const_ | MODFlags.immutable_)) 3296 buf.writeByte(')'); 3297 if (m & MODFlags.wild) 3298 buf.writeByte(')'); 3299 if (m & MODFlags.shared_) 3300 buf.writeByte(')'); 3301 } 3302 } 3303 3304 3305 private void dumpTemplateInstance(TemplateInstance ti, OutBuffer* buf, HdrGenState* hgs) 3306 { 3307 buf.writeByte('{'); 3308 buf.writenl(); 3309 buf.level++; 3310 3311 if (ti.aliasdecl) 3312 { 3313 ti.aliasdecl.dsymbolToBuffer(buf, hgs); 3314 buf.writenl(); 3315 } 3316 else if (ti.members) 3317 { 3318 foreach(m;*ti.members) 3319 m.dsymbolToBuffer(buf, hgs); 3320 } 3321 3322 buf.level--; 3323 buf.writeByte('}'); 3324 buf.writenl(); 3325 3326 } 3327 3328 private void tiargsToBuffer(TemplateInstance ti, OutBuffer* buf, HdrGenState* hgs) 3329 { 3330 buf.writeByte('!'); 3331 if (ti.nest) 3332 { 3333 buf.writestring("(...)"); 3334 return; 3335 } 3336 if (!ti.tiargs) 3337 { 3338 buf.writestring("()"); 3339 return; 3340 } 3341 if (ti.tiargs.dim == 1) 3342 { 3343 RootObject oarg = (*ti.tiargs)[0]; 3344 if (Type t = isType(oarg)) 3345 { 3346 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)) 3347 { 3348 buf.writestring(t.toChars()); 3349 return; 3350 } 3351 } 3352 else if (Expression e = isExpression(oarg)) 3353 { 3354 if (e.op == TOK.int64 || e.op == TOK.float64 || e.op == TOK.null_ || e.op == TOK.string_ || e.op == TOK.this_) 3355 { 3356 buf.writestring(e.toChars()); 3357 return; 3358 } 3359 } 3360 } 3361 buf.writeByte('('); 3362 ti.nestUp(); 3363 foreach (i, arg; *ti.tiargs) 3364 { 3365 if (i) 3366 buf.writestring(", "); 3367 objectToBuffer(arg, buf, hgs); 3368 } 3369 ti.nestDown(); 3370 buf.writeByte(')'); 3371 } 3372 3373 /**************************************** 3374 * This makes a 'pretty' version of the template arguments. 3375 * It's analogous to genIdent() which makes a mangled version. 3376 */ 3377 private void objectToBuffer(RootObject oarg, OutBuffer* buf, HdrGenState* hgs) 3378 { 3379 //printf("objectToBuffer()\n"); 3380 /* The logic of this should match what genIdent() does. The _dynamic_cast() 3381 * function relies on all the pretty strings to be unique for different classes 3382 * See https://issues.dlang.org/show_bug.cgi?id=7375 3383 * Perhaps it would be better to demangle what genIdent() does. 3384 */ 3385 if (auto t = isType(oarg)) 3386 { 3387 //printf("\tt: %s ty = %d\n", t.toChars(), t.ty); 3388 typeToBuffer(t, null, buf, hgs); 3389 } 3390 else if (auto e = isExpression(oarg)) 3391 { 3392 if (e.op == TOK.variable) 3393 e = e.optimize(WANTvalue); // added to fix https://issues.dlang.org/show_bug.cgi?id=7375 3394 expToBuffer(e, PREC.assign, buf, hgs); 3395 } 3396 else if (Dsymbol s = isDsymbol(oarg)) 3397 { 3398 const p = s.ident ? s.ident.toChars() : s.toChars(); 3399 buf.writestring(p); 3400 } 3401 else if (auto v = isTuple(oarg)) 3402 { 3403 auto args = &v.objects; 3404 foreach (i, arg; *args) 3405 { 3406 if (i) 3407 buf.writestring(", "); 3408 objectToBuffer(arg, buf, hgs); 3409 } 3410 } 3411 else if (auto p = isParameter(oarg)) 3412 { 3413 parameterToBuffer(p, buf, hgs); 3414 } 3415 else if (!oarg) 3416 { 3417 buf.writestring("NULL"); 3418 } 3419 else 3420 { 3421 debug 3422 { 3423 printf("bad Object = %p\n", oarg); 3424 } 3425 assert(0); 3426 } 3427 } 3428 3429 3430 private void visitFuncIdentWithPostfix(TypeFunction t, const char[] ident, OutBuffer* buf, HdrGenState* hgs, bool isStatic) 3431 { 3432 if (t.inuse) 3433 { 3434 t.inuse = 2; // flag error to caller 3435 return; 3436 } 3437 t.inuse++; 3438 if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen) 3439 { 3440 linkageToBuffer(buf, t.linkage); 3441 buf.writeByte(' '); 3442 } 3443 if (t.linkage == LINK.objc && isStatic) 3444 buf.write("static "); 3445 if (t.next) 3446 { 3447 typeToBuffer(t.next, null, buf, hgs); 3448 if (ident) 3449 buf.writeByte(' '); 3450 } 3451 else if (hgs.ddoc) 3452 buf.writestring("auto "); 3453 if (ident) 3454 buf.writestring(ident); 3455 parametersToBuffer(t.parameterList, buf, hgs); 3456 /* Use postfix style for attributes 3457 */ 3458 if (t.mod) 3459 { 3460 buf.writeByte(' '); 3461 MODtoBuffer(buf, t.mod); 3462 } 3463 3464 void dg(string str) 3465 { 3466 buf.writeByte(' '); 3467 buf.writestring(str); 3468 } 3469 t.attributesApply(&dg); 3470 3471 t.inuse--; 3472 } 3473 3474 private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, TemplateDeclaration td, 3475 OutBuffer* buf, HdrGenState* hgs) 3476 { 3477 if (t.inuse) 3478 { 3479 t.inuse = 2; // flag error to caller 3480 return; 3481 } 3482 t.inuse++; 3483 3484 /* Use 'storage class' (prefix) style for attributes 3485 */ 3486 if (t.mod) 3487 { 3488 MODtoBuffer(buf, t.mod); 3489 buf.writeByte(' '); 3490 } 3491 3492 void ignoreReturn(string str) 3493 { 3494 if (str != "return") 3495 { 3496 // don't write 'ref' for ctors 3497 if ((ident == Id.ctor) && str == "ref") 3498 return; 3499 buf.writestring(str); 3500 buf.writeByte(' '); 3501 } 3502 } 3503 t.attributesApply(&ignoreReturn); 3504 3505 if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen) 3506 { 3507 linkageToBuffer(buf, t.linkage); 3508 buf.writeByte(' '); 3509 } 3510 if (ident && ident.toHChars2() != ident.toChars()) 3511 { 3512 // Don't print return type for ctor, dtor, unittest, etc 3513 } 3514 else if (t.next) 3515 { 3516 typeToBuffer(t.next, null, buf, hgs); 3517 if (ident) 3518 buf.writeByte(' '); 3519 } 3520 else if (hgs.ddoc) 3521 buf.writestring("auto "); 3522 if (ident) 3523 buf.writestring(ident.toHChars2()); 3524 if (td) 3525 { 3526 buf.writeByte('('); 3527 foreach (i, p; *td.origParameters) 3528 { 3529 if (i) 3530 buf.writestring(", "); 3531 p.templateParameterToBuffer(buf, hgs); 3532 } 3533 buf.writeByte(')'); 3534 } 3535 parametersToBuffer(t.parameterList, buf, hgs); 3536 if (t.isreturn) 3537 { 3538 buf.writestring(" return"); 3539 } 3540 t.inuse--; 3541 } 3542 3543 3544 private void initializerToBuffer(Initializer inx, OutBuffer* buf, HdrGenState* hgs) 3545 { 3546 void visitError(ErrorInitializer iz) 3547 { 3548 buf.writestring("__error__"); 3549 } 3550 3551 void visitVoid(VoidInitializer iz) 3552 { 3553 buf.writestring("void"); 3554 } 3555 3556 void visitStruct(StructInitializer si) 3557 { 3558 //printf("StructInitializer::toCBuffer()\n"); 3559 buf.writeByte('{'); 3560 foreach (i, const id; si.field) 3561 { 3562 if (i) 3563 buf.writestring(", "); 3564 if (id) 3565 { 3566 buf.writestring(id.toString()); 3567 buf.writeByte(':'); 3568 } 3569 if (auto iz = si.value[i]) 3570 initializerToBuffer(iz, buf, hgs); 3571 } 3572 buf.writeByte('}'); 3573 } 3574 3575 void visitArray(ArrayInitializer ai) 3576 { 3577 buf.writeByte('['); 3578 foreach (i, ex; ai.index) 3579 { 3580 if (i) 3581 buf.writestring(", "); 3582 if (ex) 3583 { 3584 ex.expressionToBuffer(buf, hgs); 3585 buf.writeByte(':'); 3586 } 3587 if (auto iz = ai.value[i]) 3588 initializerToBuffer(iz, buf, hgs); 3589 } 3590 buf.writeByte(']'); 3591 } 3592 3593 void visitExp(ExpInitializer ei) 3594 { 3595 ei.exp.expressionToBuffer(buf, hgs); 3596 } 3597 3598 final switch (inx.kind) 3599 { 3600 case InitKind.error: return visitError (inx.isErrorInitializer ()); 3601 case InitKind.void_: return visitVoid (inx.isVoidInitializer ()); 3602 case InitKind.struct_: return visitStruct(inx.isStructInitializer()); 3603 case InitKind.array: return visitArray (inx.isArrayInitializer ()); 3604 case InitKind.exp: return visitExp (inx.isExpInitializer ()); 3605 } 3606 } 3607 3608 3609 private void typeToBufferx(Type t, OutBuffer* buf, HdrGenState* hgs) 3610 { 3611 void visitType(Type t) 3612 { 3613 printf("t = %p, ty = %d\n", t, t.ty); 3614 assert(0); 3615 } 3616 3617 void visitError(TypeError t) 3618 { 3619 buf.writestring("_error_"); 3620 } 3621 3622 void visitBasic(TypeBasic t) 3623 { 3624 //printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod); 3625 buf.writestring(t.dstring); 3626 } 3627 3628 void visitTraits(TypeTraits t) 3629 { 3630 //printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod); 3631 t.exp.expressionToBuffer(buf, hgs); 3632 } 3633 3634 void visitVector(TypeVector t) 3635 { 3636 //printf("TypeVector::toCBuffer2(t.mod = %d)\n", t.mod); 3637 buf.writestring("__vector("); 3638 visitWithMask(t.basetype, t.mod, buf, hgs); 3639 buf.writestring(")"); 3640 } 3641 3642 void visitSArray(TypeSArray t) 3643 { 3644 visitWithMask(t.next, t.mod, buf, hgs); 3645 buf.writeByte('['); 3646 sizeToBuffer(t.dim, buf, hgs); 3647 buf.writeByte(']'); 3648 } 3649 3650 void visitDArray(TypeDArray t) 3651 { 3652 Type ut = t.castMod(0); 3653 if (hgs.declstring) 3654 goto L1; 3655 if (ut.equals(Type.tstring)) 3656 buf.writestring("string"); 3657 else if (ut.equals(Type.twstring)) 3658 buf.writestring("wstring"); 3659 else if (ut.equals(Type.tdstring)) 3660 buf.writestring("dstring"); 3661 else 3662 { 3663 L1: 3664 visitWithMask(t.next, t.mod, buf, hgs); 3665 buf.writestring("[]"); 3666 } 3667 } 3668 3669 void visitAArray(TypeAArray t) 3670 { 3671 visitWithMask(t.next, t.mod, buf, hgs); 3672 buf.writeByte('['); 3673 visitWithMask(t.index, 0, buf, hgs); 3674 buf.writeByte(']'); 3675 } 3676 3677 void visitPointer(TypePointer t) 3678 { 3679 //printf("TypePointer::toCBuffer2() next = %d\n", t.next.ty); 3680 if (t.next.ty == Tfunction) 3681 visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "function", buf, hgs, false); 3682 else 3683 { 3684 visitWithMask(t.next, t.mod, buf, hgs); 3685 buf.writeByte('*'); 3686 } 3687 } 3688 3689 void visitReference(TypeReference t) 3690 { 3691 visitWithMask(t.next, t.mod, buf, hgs); 3692 buf.writeByte('&'); 3693 } 3694 3695 void visitFunction(TypeFunction t) 3696 { 3697 //printf("TypeFunction::toCBuffer2() t = %p, ref = %d\n", t, t.isref); 3698 visitFuncIdentWithPostfix(t, null, buf, hgs, false); 3699 } 3700 3701 void visitDelegate(TypeDelegate t) 3702 { 3703 visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "delegate", buf, hgs, false); 3704 } 3705 3706 void visitTypeQualifiedHelper(TypeQualified t) 3707 { 3708 foreach (id; t.idents) 3709 { 3710 if (id.dyncast() == DYNCAST.dsymbol) 3711 { 3712 buf.writeByte('.'); 3713 TemplateInstance ti = cast(TemplateInstance)id; 3714 ti.dsymbolToBuffer(buf, hgs); 3715 } 3716 else if (id.dyncast() == DYNCAST.expression) 3717 { 3718 buf.writeByte('['); 3719 (cast(Expression)id).expressionToBuffer(buf, hgs); 3720 buf.writeByte(']'); 3721 } 3722 else if (id.dyncast() == DYNCAST.type) 3723 { 3724 buf.writeByte('['); 3725 typeToBufferx(cast(Type)id, buf, hgs); 3726 buf.writeByte(']'); 3727 } 3728 else 3729 { 3730 buf.writeByte('.'); 3731 buf.writestring(id.toString()); 3732 } 3733 } 3734 } 3735 3736 void visitIdentifier(TypeIdentifier t) 3737 { 3738 buf.writestring(t.ident.toString()); 3739 visitTypeQualifiedHelper(t); 3740 } 3741 3742 void visitInstance(TypeInstance t) 3743 { 3744 t.tempinst.dsymbolToBuffer(buf, hgs); 3745 visitTypeQualifiedHelper(t); 3746 } 3747 3748 void visitTypeof(TypeTypeof t) 3749 { 3750 buf.writestring("typeof("); 3751 t.exp.expressionToBuffer(buf, hgs); 3752 buf.writeByte(')'); 3753 visitTypeQualifiedHelper(t); 3754 } 3755 3756 void visitReturn(TypeReturn t) 3757 { 3758 buf.writestring("typeof(return)"); 3759 visitTypeQualifiedHelper(t); 3760 } 3761 3762 void visitEnum(TypeEnum t) 3763 { 3764 buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars()); 3765 } 3766 3767 void visitStruct(TypeStruct t) 3768 { 3769 // https://issues.dlang.org/show_bug.cgi?id=13776 3770 // Don't use ti.toAlias() to avoid forward reference error 3771 // while printing messages. 3772 TemplateInstance ti = t.sym.parent ? t.sym.parent.isTemplateInstance() : null; 3773 if (ti && ti.aliasdecl == t.sym) 3774 buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars()); 3775 else 3776 buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars()); 3777 } 3778 3779 void visitClass(TypeClass t) 3780 { 3781 // https://issues.dlang.org/show_bug.cgi?id=13776 3782 // Don't use ti.toAlias() to avoid forward reference error 3783 // while printing messages. 3784 TemplateInstance ti = t.sym.parent.isTemplateInstance(); 3785 if (ti && ti.aliasdecl == t.sym) 3786 buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars()); 3787 else 3788 buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars()); 3789 } 3790 3791 void visitTuple(TypeTuple t) 3792 { 3793 parametersToBuffer(ParameterList(t.arguments, VarArg.none), buf, hgs); 3794 } 3795 3796 void visitSlice(TypeSlice t) 3797 { 3798 visitWithMask(t.next, t.mod, buf, hgs); 3799 buf.writeByte('['); 3800 sizeToBuffer(t.lwr, buf, hgs); 3801 buf.writestring(" .. "); 3802 sizeToBuffer(t.upr, buf, hgs); 3803 buf.writeByte(']'); 3804 } 3805 3806 void visitNull(TypeNull t) 3807 { 3808 buf.writestring("typeof(null)"); 3809 } 3810 3811 void visitMixin(TypeMixin t) 3812 { 3813 buf.writestring("mixin("); 3814 argsToBuffer(t.exps, buf, hgs, null); 3815 buf.writeByte(')'); 3816 } 3817 3818 void visitNoreturn(TypeNoreturn t) 3819 { 3820 buf.writestring("noreturn"); 3821 } 3822 3823 3824 switch (t.ty) 3825 { 3826 default: return t.isTypeBasic() ? 3827 visitBasic(cast(TypeBasic)t) : 3828 visitType(t); 3829 3830 case Terror: return visitError(cast(TypeError)t); 3831 case Ttraits: return visitTraits(cast(TypeTraits)t); 3832 case Tvector: return visitVector(cast(TypeVector)t); 3833 case Tsarray: return visitSArray(cast(TypeSArray)t); 3834 case Tarray: return visitDArray(cast(TypeDArray)t); 3835 case Taarray: return visitAArray(cast(TypeAArray)t); 3836 case Tpointer: return visitPointer(cast(TypePointer)t); 3837 case Treference: return visitReference(cast(TypeReference)t); 3838 case Tfunction: return visitFunction(cast(TypeFunction)t); 3839 case Tdelegate: return visitDelegate(cast(TypeDelegate)t); 3840 case Tident: return visitIdentifier(cast(TypeIdentifier)t); 3841 case Tinstance: return visitInstance(cast(TypeInstance)t); 3842 case Ttypeof: return visitTypeof(cast(TypeTypeof)t); 3843 case Treturn: return visitReturn(cast(TypeReturn)t); 3844 case Tenum: return visitEnum(cast(TypeEnum)t); 3845 case Tstruct: return visitStruct(cast(TypeStruct)t); 3846 case Tclass: return visitClass(cast(TypeClass)t); 3847 case Ttuple: return visitTuple (cast(TypeTuple)t); 3848 case Tslice: return visitSlice(cast(TypeSlice)t); 3849 case Tnull: return visitNull(cast(TypeNull)t); 3850 case Tmixin: return visitMixin(cast(TypeMixin)t); 3851 case Tnoreturn: return visitNoreturn(cast(TypeNoreturn)t); 3852 } 3853 }