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