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