1 /** 2 * This module contains the implementation of the C++ header generation available through 3 * the command line switch -Hc. 4 * 5 * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, 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: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtohd, _dtoh.d) 9 * Documentation: https://dlang.org/phobos/dmd_dtoh.html 10 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dtoh.d 11 */ 12 module dmd.dtoh; 13 14 import core.stdc.stdio; 15 import core.stdc.string; 16 import core.stdc.ctype; 17 18 import dmd.astcodegen; 19 import dmd.arraytypes; 20 import dmd.globals; 21 import dmd.identifier; 22 import dmd.root.filename; 23 import dmd.visitor; 24 import dmd.tokens; 25 26 import dmd.root.outbuffer; 27 import dmd.utils; 28 29 //debug = Debug_DtoH; 30 enum isBuildingCompiler = false; 31 32 private struct DMDType 33 { 34 __gshared Identifier c_long; 35 __gshared Identifier c_ulong; 36 __gshared Identifier c_longlong; 37 __gshared Identifier c_ulonglong; 38 __gshared Identifier c_long_double; 39 __gshared Identifier c_wchar_t; 40 __gshared Identifier AssocArray; 41 __gshared Identifier Array; 42 43 static void _init() 44 { 45 c_long = Identifier.idPool("__c_long"); 46 c_ulong = Identifier.idPool("__c_ulong"); 47 c_longlong = Identifier.idPool("__c_longlong"); 48 c_ulonglong = Identifier.idPool("__c_ulonglong"); 49 c_long_double = Identifier.idPool("__c_long_double"); 50 c_wchar_t = Identifier.idPool("__c_wchar_t"); 51 52 if (isBuildingCompiler) 53 { 54 AssocArray = Identifier.idPool("AssocArray"); 55 Array = Identifier.idPool("Array"); 56 } 57 58 } 59 } 60 61 private struct DMDModule 62 { 63 __gshared Identifier identifier; 64 __gshared Identifier root; 65 __gshared Identifier visitor; 66 __gshared Identifier parsetimevisitor; 67 __gshared Identifier permissivevisitor; 68 __gshared Identifier strictvisitor; 69 __gshared Identifier transitivevisitor; 70 __gshared Identifier dmd; 71 static void _init() 72 { 73 identifier = Identifier.idPool("identifier"); 74 root = Identifier.idPool("root"); 75 visitor = Identifier.idPool("visitor"); 76 parsetimevisitor = Identifier.idPool("parsetimevisitor"); 77 permissivevisitor = Identifier.idPool("permissivevisitor"); 78 strictvisitor = Identifier.idPool("strictvisitor"); 79 transitivevisitor = Identifier.idPool("transitivevisitor"); 80 dmd = Identifier.idPool("dmd"); 81 } 82 } 83 84 private struct DMDClass 85 { 86 __gshared Identifier ID; ////Identifier 87 __gshared Identifier Visitor; 88 __gshared Identifier ParseTimeVisitor; 89 static void _init() 90 { 91 ID = Identifier.idPool("Identifier"); 92 Visitor = Identifier.idPool("Visitor"); 93 ParseTimeVisitor = Identifier.idPool("ParseTimeVisitor"); 94 } 95 96 } 97 98 private bool isIdentifierClass(ASTCodegen.ClassDeclaration cd) 99 { 100 return (cd.ident == DMDClass.ID && 101 cd.parent !is null && 102 cd.parent.ident == DMDModule.identifier && 103 cd.parent.parent && cd.parent.parent.ident == DMDModule.dmd && 104 !cd.parent.parent.parent); 105 } 106 107 private bool isVisitorClass(ASTCodegen.ClassDeclaration cd) 108 { 109 for (auto cdb = cd; cdb; cdb = cdb.baseClass) 110 { 111 if (cdb.ident == DMDClass.Visitor || 112 cdb.ident == DMDClass.ParseTimeVisitor) 113 return true; 114 } 115 return false; 116 } 117 118 private bool isIgnoredModule(ASTCodegen.Module m) 119 { 120 if (!m) 121 return true; 122 123 // Ignore dmd.root 124 if (m.parent && m.parent.ident == DMDModule.root && 125 m.parent.parent && m.parent.parent.ident == DMDModule.dmd && 126 !m.parent.parent.parent) 127 { 128 return true; 129 } 130 131 // Ignore dmd.visitor and derivatives 132 if ((m.ident == DMDModule.visitor || 133 m.ident == DMDModule.parsetimevisitor || 134 m.ident == DMDModule.permissivevisitor || 135 m.ident == DMDModule.strictvisitor || 136 m.ident == DMDModule.transitivevisitor) && 137 m.parent && m.parent.ident == DMDModule.dmd && 138 !m.parent.parent) 139 { 140 return true; 141 } 142 return false; 143 } 144 145 private bool isFrontendModule(ASTCodegen.Module m) 146 { 147 if (!m || !m.parent) 148 return false; 149 150 // Ignore dmd.root 151 if (m.parent.ident == DMDModule.root && 152 m.parent.parent && m.parent.parent.ident == DMDModule.dmd && 153 !m.parent.parent.parent) 154 { 155 return false; 156 } 157 158 // Ignore dmd.visitor and derivatives 159 if ((m.ident == DMDModule.visitor || 160 m.ident == DMDModule.parsetimevisitor || 161 m.ident == DMDModule.permissivevisitor || 162 m.ident == DMDModule.strictvisitor || 163 m.ident == DMDModule.transitivevisitor) && 164 m.parent && m.parent.ident == DMDModule.dmd && 165 !m.parent.parent) 166 { 167 return false; 168 } 169 return ((m.parent.ident == DMDModule.dmd && !m.parent.parent) || 170 (m.parent.parent.ident == DMDModule.dmd && !m.parent.parent.parent)); 171 } 172 173 private void initialize() 174 { 175 __gshared bool initialized; 176 177 if (!initialized) 178 { 179 initialized = true; 180 181 DMDType._init(); 182 if (isBuildingCompiler) 183 { 184 DMDModule._init(); 185 DMDClass._init(); 186 } 187 } 188 } 189 190 void hashIf(ref OutBuffer buf, string content) 191 { 192 buf.writestring("#if "); 193 buf.writestringln(content); 194 } 195 196 void hashElIf(ref OutBuffer buf, string content) 197 { 198 buf.writestring("#elif "); 199 buf.writestringln(content); 200 } 201 202 void hashEndIf(ref OutBuffer buf) 203 { 204 buf.writestringln("#endif"); 205 } 206 207 void hashDefine(ref OutBuffer buf, string content) 208 { 209 buf.writestring("# define "); 210 buf.writestringln(content); 211 } 212 213 void hashInclude(ref OutBuffer buf, string content) 214 { 215 buf.writestring("#include "); 216 buf.writestringln(content); 217 } 218 219 220 221 extern(C++) void genCppHdrFiles(ref Modules ms) 222 { 223 initialize(); 224 225 OutBuffer fwd; 226 OutBuffer check; 227 OutBuffer done; 228 OutBuffer decl; 229 230 // enable indent by spaces on buffers 231 fwd.doindent = true; 232 fwd.spaces = true; 233 decl.doindent = true; 234 decl.spaces = true; 235 check.doindent = true; 236 check.spaces = true; 237 238 scope v = new ToCppBuffer(&check, &fwd, &done, &decl); 239 240 OutBuffer buf; 241 buf.doindent = true; 242 buf.spaces = true; 243 244 foreach (m; ms) 245 m.accept(v); 246 247 if (global.params.doCxxHdrGeneration == CxxHeaderMode.verbose) 248 buf.printf("// Automatically generated by %s Compiler v%d", global.vendor.ptr, global.versionNumber()); 249 else 250 buf.printf("// Automatically generated by %s Compiler", global.vendor.ptr); 251 252 buf.writenl(); 253 buf.writenl(); 254 buf.writestringln("#pragma once"); 255 buf.writenl(); 256 // buf.writestring("#include <assert.h>\n"); 257 hashInclude(buf, "<stddef.h>"); 258 hashInclude(buf, "<stdint.h>"); 259 // buf.writestring(buf, "#include <stdio.h>\n"); 260 // buf.writestring("#include <string.h>\n"); 261 buf.writenl(); 262 if (v.hasReal) 263 { 264 hashIf(buf, "!defined(_d_real)"); 265 { 266 hashDefine(buf, "_d_real long double"); 267 } 268 hashEndIf(buf); 269 } 270 buf.writenl(); 271 272 buf.write(&fwd); 273 if (fwd.length > 0) 274 buf.writenl(); 275 276 buf.write(&done); 277 buf.write(&decl); 278 279 debug (Debug_DtoH) 280 { 281 buf.writestring(` 282 #if OFFSETS 283 template <class T> 284 size_t getSlotNumber(int dummy, ...) 285 { 286 T c; 287 va_list ap; 288 va_start(ap, dummy); 289 290 void *f = va_arg(ap, void*); 291 for (size_t i = 0; ; i++) 292 { 293 if ( (*(void***)&c)[i] == f) 294 return i; 295 } 296 va_end(ap); 297 } 298 299 void testOffsets() 300 { 301 `); 302 buf.write(&check); 303 buf.writestring(` 304 } 305 #endif 306 `); 307 } 308 309 if (global.params.cxxhdrname is null) 310 { 311 // Write to stdout; assume it succeeds 312 size_t n = fwrite(buf[].ptr, 1, buf.length, stdout); 313 assert(n == buf.length); // keep gcc happy about return values 314 } 315 else 316 { 317 const(char)[] name = FileName.combine(global.params.cxxhdrdir, global.params.cxxhdrname); 318 writeFile(Loc.initial, name, buf[]); 319 } 320 } 321 322 /**************************************************** 323 */ 324 extern(C++) final class ToCppBuffer : Visitor 325 { 326 alias visit = Visitor.visit; 327 public: 328 enum EnumKind 329 { 330 Int, 331 Numeric, 332 String, 333 Enum, 334 Other 335 } 336 337 alias AST = ASTCodegen; 338 339 bool[void*] visited; 340 bool[void*] forwarded; 341 OutBuffer* fwdbuf; 342 OutBuffer* checkbuf; 343 OutBuffer* donebuf; 344 OutBuffer* buf; 345 AST.AggregateDeclaration adparent; 346 AST.ClassDeclaration cdparent; 347 AST.TemplateDeclaration tdparent; 348 Identifier ident; 349 LINK linkage = LINK.d; 350 bool forwardedAA; 351 AST.Type* origType; 352 353 bool hasReal; 354 const bool printIgnored; 355 356 this(OutBuffer* checkbuf, OutBuffer* fwdbuf, OutBuffer* donebuf, OutBuffer* buf) 357 { 358 this.checkbuf = checkbuf; 359 this.fwdbuf = fwdbuf; 360 this.donebuf = donebuf; 361 this.buf = buf; 362 this.printIgnored = global.params.doCxxHdrGeneration == CxxHeaderMode.verbose; 363 } 364 365 private EnumKind getEnumKind(AST.Type type) 366 { 367 if (type) switch (type.ty) 368 { 369 case AST.Tint32: 370 return EnumKind.Int; 371 case AST.Tbool, 372 AST.Tchar, AST.Twchar, AST.Tdchar, 373 AST.Tint8, AST.Tuns8, 374 AST.Tint16, AST.Tuns16, 375 AST.Tuns32, 376 AST.Tint64, AST.Tuns64: 377 return EnumKind.Numeric; 378 case AST.Tarray: 379 if (type.isString()) 380 return EnumKind.String; 381 break; 382 case AST.Tenum: 383 return EnumKind.Enum; 384 default: 385 break; 386 } 387 return EnumKind.Other; 388 } 389 390 private void writeEnumTypeName(AST.Type type) 391 { 392 if (auto arr = type.isTypeDArray()) 393 { 394 switch (arr.next.ty) 395 { 396 case AST.Tchar: buf.writestring("const char*"); return; 397 case AST.Twchar: buf.writestring("const char16_t*"); return; 398 case AST.Tdchar: buf.writestring("const char32_t*"); return; 399 default: break; 400 } 401 } 402 type.accept(this); 403 } 404 405 void writeDeclEnd() 406 { 407 buf.writestringln(";"); 408 409 if (!adparent) 410 buf.writenl(); 411 } 412 413 override void visit(AST.Dsymbol s) 414 { 415 debug (Debug_DtoH) 416 { 417 printf("[AST.Dsymbol enter] %s\n", s.toChars()); 418 import dmd.asttypename; 419 printf("[AST.Dsymbol enter] %s\n", s.astTypeName().ptr); 420 scope(exit) printf("[AST.Dsymbol exit] %s\n", s.toChars()); 421 } 422 423 if (isBuildingCompiler && s.getModule() && s.getModule().isFrontendModule()) 424 { 425 if (printIgnored) 426 { 427 buf.printf("// ignored %s %s", s.kind(), s.toPrettyChars()); 428 buf.writenl(); 429 } 430 } 431 } 432 433 override void visit(AST.Import i) 434 { 435 debug (Debug_DtoH) 436 { 437 printf("[AST.Import enter] %s\n", i.toChars()); 438 scope(exit) printf("[AST.Import exit] %s\n", i.toChars()); 439 } 440 } 441 442 override void visit(AST.AttribDeclaration pd) 443 { 444 debug (Debug_DtoH) 445 { 446 printf("[AST.AttribDeclaration enter] %s\n", pd.toChars()); 447 scope(exit) printf("[AST.AttribDeclaration exit] %s\n", pd.toChars()); 448 } 449 Dsymbols* decl = pd.include(null); 450 if (!decl) 451 return; 452 453 foreach (s; *decl) 454 { 455 if (adparent || s.prot().kind >= AST.Prot.Kind.public_) 456 s.accept(this); 457 } 458 } 459 460 override void visit(AST.LinkDeclaration ld) 461 { 462 debug (Debug_DtoH) 463 { 464 printf("[AST.LinkDeclaration enter] %s\n", ld.toChars()); 465 scope(exit) printf("[AST.LinkDeclaration exit] %s\n", ld.toChars()); 466 } 467 auto save = linkage; 468 linkage = ld.linkage; 469 if (ld.linkage != LINK.c && ld.linkage != LINK.cpp) 470 { 471 if (printIgnored) 472 { 473 buf.printf("// ignoring %s block because of linkage", ld.toPrettyChars()); 474 buf.writenl(); 475 } 476 } 477 else 478 { 479 visit(cast(AST.AttribDeclaration)ld); 480 } 481 linkage = save; 482 } 483 484 override void visit(AST.CPPMangleDeclaration md) 485 { 486 const oldLinkage = this.linkage; 487 this.linkage = LINK.cpp; 488 visit(cast(AST.AttribDeclaration) md); 489 this.linkage = oldLinkage; 490 } 491 492 override void visit(AST.Module m) 493 { 494 debug (Debug_DtoH) 495 { 496 printf("[AST.Module enter] %s\n", m.toChars()); 497 scope(exit) printf("[AST.Module exit] %s\n", m.toChars()); 498 } 499 foreach (s; *m.members) 500 { 501 if (s.prot().kind < AST.Prot.Kind.public_) 502 continue; 503 s.accept(this); 504 } 505 } 506 507 override void visit(AST.FuncDeclaration fd) 508 { 509 debug (Debug_DtoH) 510 { 511 printf("[AST.FuncDeclaration enter] %s\n", fd.toChars()); 512 scope(exit) printf("[AST.FuncDeclaration exit] %s\n", fd.toChars()); 513 } 514 if (cast(void*)fd in visited) 515 return; 516 if (isBuildingCompiler && fd.getModule() && fd.getModule().isIgnoredModule()) 517 return; 518 519 // printf("FuncDeclaration %s %s\n", fd.toPrettyChars(), fd.type.toChars()); 520 visited[cast(void*)fd] = true; 521 522 auto tf = cast(AST.TypeFunction)fd.type; 523 if (!tf || !tf.deco) 524 { 525 if (printIgnored) 526 { 527 buf.printf("// ignoring function %s because semantic hasn't been run", fd.toPrettyChars()); 528 buf.writenl(); 529 } 530 return; 531 } 532 if (tf.linkage != LINK.c && tf.linkage != LINK.cpp) 533 { 534 if (printIgnored) 535 { 536 buf.printf("// ignoring function %s because of linkage", fd.toPrettyChars()); 537 buf.writenl(); 538 } 539 return; 540 } 541 if (!adparent && !fd.fbody) 542 { 543 if (printIgnored) 544 { 545 buf.printf("// ignoring function %s because it's extern", fd.toPrettyChars()); 546 buf.writenl(); 547 } 548 return; 549 } 550 551 if (tf.linkage == LINK.c) 552 buf.writestring("extern \"C\" "); 553 else if (!adparent) 554 buf.writestring("extern "); 555 if (adparent && fd.isStatic()) 556 buf.writestring("static "); 557 if (adparent && fd.vtblIndex != -1) 558 { 559 if (!fd.isOverride()) 560 buf.writestring("virtual "); 561 562 auto s = adparent.search(Loc.initial, fd.ident); 563 if (!(adparent.storage_class & AST.STC.abstract_) && 564 !(cast(AST.ClassDeclaration)adparent).isAbstract() && 565 s is fd && !fd.overnext) 566 { 567 const cn = adparent.ident.toChars(); 568 const fn = fd.ident.toChars(); 569 const vi = fd.vtblIndex; 570 571 checkbuf.printf("assert(getSlotNumber <%s>(0, &%s::%s) == %d);", 572 cn, cn, fn, vi); 573 checkbuf.writenl(); 574 } 575 } 576 577 if (adparent && fd.isDisabled && global.params.cplusplus < CppStdRevision.cpp11) 578 buf.printf("private: "); 579 funcToBuffer(tf, fd); 580 if (adparent && tf.isConst()) 581 { 582 bool fdOverridesAreConst = true; 583 foreach (fdv; fd.foverrides) 584 { 585 auto tfv = cast(AST.TypeFunction)fdv.type; 586 if (!tfv.isConst()) 587 { 588 fdOverridesAreConst = false; 589 break; 590 } 591 } 592 593 buf.writestring(fdOverridesAreConst ? " const" : " /* const */"); 594 } 595 if (adparent && fd.isAbstract()) 596 buf.writestring(" = 0"); 597 if (adparent && fd.isDisabled && global.params.cplusplus >= CppStdRevision.cpp11) 598 buf.writestring(" = delete"); 599 buf.writestringln(";"); 600 if (adparent && fd.isDisabled && global.params.cplusplus < CppStdRevision.cpp11) 601 buf.writestringln("public:"); 602 603 if (!adparent) 604 buf.writenl(); 605 606 } 607 608 override void visit(AST.UnitTestDeclaration utd) 609 { 610 debug (Debug_DtoH) 611 { 612 printf("[AST.UnitTestDeclaration enter] %s\n", utd.toChars()); 613 scope(exit) printf("[AST.UnitTestDeclaration exit] %s\n", utd.toChars()); 614 } 615 } 616 617 override void visit(AST.VarDeclaration vd) 618 { 619 debug (Debug_DtoH) 620 { 621 printf("[AST.VarDeclaration enter] %s\n", vd.toChars()); 622 scope(exit) printf("[AST.VarDeclaration exit] %s\n", vd.toChars()); 623 } 624 if (cast(void*)vd in visited) 625 return; 626 if (isBuildingCompiler && vd.getModule() && vd.getModule().isIgnoredModule()) 627 return; 628 629 visited[cast(void*)vd] = true; 630 631 if (vd.type == AST.Type.tsize_t) 632 origType = &vd.originalType; 633 scope(exit) origType = null; 634 635 if (vd.alignment != STRUCTALIGN_DEFAULT) 636 { 637 buf.printf("// Ignoring var %s alignment %u", vd.toChars(), vd.alignment); 638 buf.writenl(); 639 } 640 641 if (vd.storage_class & AST.STC.manifest && 642 vd._init && vd._init.isExpInitializer() && vd.type !is null) 643 { 644 AST.Type type = vd.type; 645 EnumKind kind = getEnumKind(type); 646 enum ProtPublic = AST.Prot(AST.Prot.Kind.public_); 647 if (vd.protection.isMoreRestrictiveThan(ProtPublic)) { 648 if (printIgnored) 649 { 650 buf.printf("// ignoring enum `%s` because it is `%s`.", vd.toPrettyChars(), AST.protectionToChars(vd.protection.kind)); 651 buf.writenl; 652 } 653 return; 654 } 655 656 final switch (kind) 657 { 658 case EnumKind.Int, EnumKind.Numeric: 659 buf.writestring("enum : "); 660 writeEnumTypeName(type); 661 buf.printf(" { %s = ", vd.ident.toChars()); 662 auto ie = AST.initializerToExpression(vd._init).isIntegerExp(); 663 visitInteger(ie.toInteger(), type); 664 buf.writestring(" };"); 665 break; 666 667 case EnumKind.String, EnumKind.Enum: 668 buf.writestring("static "); 669 writeEnumTypeName(type); 670 buf.printf(" const %s = ", vd.ident.toChars()); 671 auto e = AST.initializerToExpression(vd._init); 672 e.accept(this); 673 buf.writestring(";"); 674 break; 675 676 case EnumKind.Other: 677 if (printIgnored) 678 { 679 buf.printf("// ignoring enum `%s` because type `%s` is currently not supported for enum constants.", vd.toPrettyChars(), type.toChars()); 680 buf.writenl; 681 } 682 return; 683 } 684 buf.writenl(); 685 buf.writenl(); 686 return; 687 } 688 689 if (tdparent && vd.type && !vd.type.deco) 690 { 691 if (linkage != LINK.c && linkage != LINK.cpp) 692 { 693 if (printIgnored) 694 { 695 buf.printf("// ignoring variable %s because of linkage", vd.toPrettyChars()); 696 buf.writenl(); 697 } 698 return; 699 } 700 typeToBuffer(vd.type, vd.ident); 701 buf.writestringln(";"); 702 return; 703 } 704 705 if (vd.storage_class & (AST.STC.static_ | AST.STC.extern_ | AST.STC.tls | AST.STC.gshared) || 706 vd.parent && vd.parent.isModule()) 707 { 708 if (vd.linkage != LINK.c && vd.linkage != LINK.cpp) 709 { 710 if (printIgnored) 711 { 712 buf.printf("// ignoring variable %s because of linkage", vd.toPrettyChars()); 713 buf.writenl(); 714 } 715 return; 716 } 717 if (vd.storage_class & AST.STC.tls) 718 { 719 if (printIgnored) 720 { 721 buf.printf("// ignoring variable %s because of thread-local storage", vd.toPrettyChars()); 722 buf.writenl(); 723 } 724 return; 725 } 726 if (vd.linkage == LINK.c) 727 buf.writestring("extern \"C\" "); 728 else if (!adparent) 729 buf.writestring("extern "); 730 if (adparent) 731 buf.writestring("static "); 732 typeToBuffer(vd.type, vd.ident); 733 writeDeclEnd(); 734 return; 735 } 736 737 if (adparent && vd.type && vd.type.deco) 738 { 739 auto save = cdparent; 740 cdparent = vd.isField() ? adparent.isClassDeclaration() : null; 741 typeToBuffer(vd.type, vd.ident); 742 cdparent = save; 743 buf.writestringln(";"); 744 745 if (auto t = vd.type.isTypeStruct()) 746 includeSymbol(t.sym); 747 748 checkbuf.level++; 749 const pn = adparent.ident.toChars(); 750 const vn = vd.ident.toChars(); 751 const vo = vd.offset; 752 checkbuf.printf("assert(offsetof(%s, %s) == %d);", 753 pn, vn, vo); 754 checkbuf.writenl(); 755 checkbuf.level--; 756 return; 757 } 758 759 visit(cast(AST.Dsymbol)vd); 760 } 761 762 override void visit(AST.TypeInfoDeclaration tid) 763 { 764 debug (Debug_DtoH) 765 { 766 printf("[AST.TypeInfoDeclaration enter] %s\n", tid.toChars()); 767 scope(exit) printf("[AST.TypeInfoDeclaration exit] %s\n", tid.toChars()); 768 } 769 } 770 771 override void visit(AST.AliasDeclaration ad) 772 { 773 debug (Debug_DtoH) 774 { 775 printf("[AST.AliasDeclaration enter] %s\n", ad.toChars()); 776 scope(exit) printf("[AST.AliasDeclaration exit] %s\n", ad.toChars()); 777 } 778 if (isBuildingCompiler && ad.getModule() && ad.getModule().isIgnoredModule()) 779 return; 780 781 if (auto t = ad.type) 782 { 783 if (t.ty == AST.Tdelegate) 784 { 785 visit(cast(AST.Dsymbol)ad); 786 return; 787 } 788 789 // for function pointers we need to original type 790 if (ad.type.ty == AST.Tpointer && 791 (cast(AST.TypePointer)t).nextOf.ty == AST.Tfunction) 792 { 793 origType = &ad.originalType; 794 } 795 scope(exit) origType = null; 796 797 buf.writestring("typedef "); 798 typeToBuffer(origType ? *origType : t, ad.ident); 799 writeDeclEnd(); 800 return; 801 } 802 if (!ad.aliassym) 803 { 804 assert(0); 805 } 806 if (auto ti = ad.aliassym.isTemplateInstance()) 807 { 808 visitTi(ti); 809 return; 810 } 811 if (auto sd = ad.aliassym.isStructDeclaration()) 812 { 813 buf.writestring("typedef "); 814 sd.type.accept(this); 815 buf.writestring(" "); 816 buf.writestring(ad.ident.toChars()); 817 writeDeclEnd(); 818 return; 819 } 820 if (ad.aliassym.isDtorDeclaration()) 821 { 822 // Ignore. It's taken care of while visiting FuncDeclaration 823 return; 824 } 825 826 if (printIgnored) 827 { 828 buf.printf("// ignored %s %s", ad.aliassym.kind(), ad.aliassym.toPrettyChars()); 829 buf.writenl(); 830 } 831 } 832 833 override void visit(AST.Nspace ns) 834 { 835 handleNspace(ns.ident, ns.members); 836 } 837 838 override void visit(AST.CPPNamespaceDeclaration ns) 839 { 840 handleNspace(ns.ident, ns.decl); 841 } 842 843 void handleNspace(Identifier name, Dsymbols* members) 844 { 845 buf.printf("namespace %s", name.toChars()); 846 buf.writenl(); 847 buf.writestring("{"); 848 buf.writenl(); 849 buf.level++; 850 foreach(decl;(*members)) 851 { 852 decl.accept(this); 853 } 854 buf.level--; 855 buf.writestring("}"); 856 buf.writenl(); 857 } 858 859 override void visit(AST.AnonDeclaration ad) 860 { 861 debug (Debug_DtoH) 862 { 863 printf("[AST.AnonDeclaration enter] %s\n", ad.toChars()); 864 scope(exit) printf("[AST.AnonDeclaration exit] %s\n", ad.toChars()); 865 } 866 867 buf.writestringln(ad.isunion ? "union" : "struct"); 868 buf.writestringln("{"); 869 buf.level++; 870 foreach (s; *ad.decl) 871 { 872 s.accept(this); 873 } 874 buf.level--; 875 buf.writestringln("};"); 876 } 877 878 private bool memberField(AST.VarDeclaration vd) 879 { 880 if (!vd.type || !vd.type.deco || !vd.ident) 881 return false; 882 if (!vd.isField()) 883 return false; 884 if (vd.type.ty == AST.Tfunction) 885 return false; 886 if (vd.type.ty == AST.Tsarray) 887 return false; 888 return true; 889 } 890 891 override void visit(AST.StructDeclaration sd) 892 { 893 debug (Debug_DtoH) 894 { 895 printf("[AST.StructDeclaration enter] %s\n", sd.toChars()); 896 scope(exit) printf("[AST.StructDeclaration exit] %s\n", sd.toChars()); 897 } 898 if (sd.isInstantiated()) 899 return; 900 if (cast(void*)sd in visited) 901 return; 902 if (!sd.type || !sd.type.deco) 903 return; 904 if (isBuildingCompiler && sd.getModule() && sd.getModule().isIgnoredModule()) 905 return; 906 907 visited[cast(void*)sd] = true; 908 if (linkage != LINK.c && linkage != LINK.cpp) 909 { 910 if (printIgnored) 911 { 912 buf.printf("// ignoring non-cpp struct %s because of linkage", sd.toChars()); 913 buf.writenl(); 914 } 915 return; 916 } 917 918 pushAlignToBuffer(sd.alignment); 919 920 const structAsClass = sd.cppmangle == CPPMANGLE.asClass; 921 if (sd.isUnionDeclaration()) 922 buf.writestring("union "); 923 else 924 buf.writestring(structAsClass ? "class " : "struct "); 925 926 buf.writestring(sd.ident.toChars()); 927 if (!sd.members) 928 { 929 buf.writestringln(";"); 930 buf.writenl(); 931 return; 932 } 933 934 buf.writenl(); 935 buf.writestring("{"); 936 937 if (structAsClass) 938 { 939 buf.writenl(); 940 buf.writestring("public:"); 941 } 942 943 buf.level++; 944 buf.writenl(); 945 auto save = adparent; 946 adparent = sd; 947 948 foreach (m; *sd.members) 949 { 950 m.accept(this); 951 } 952 buf.level--; 953 adparent = save; 954 // Generate default ctor 955 if (!sd.noDefaultCtor) 956 { 957 buf.level++; 958 buf.printf("%s()", sd.ident.toChars()); 959 size_t varCount; 960 bool first = true; 961 buf.level++; 962 foreach (m; *sd.members) 963 { 964 if (auto vd = m.isVarDeclaration()) 965 { 966 if (!memberField(vd)) 967 continue; 968 varCount++; 969 970 if (!vd._init && !vd.type.isTypeBasic() && !vd.type.isTypePointer && !vd.type.isTypeStruct && 971 !vd.type.isTypeClass && !vd.type.isTypeDArray && !vd.type.isTypeSArray) 972 { 973 continue; 974 } 975 if (vd._init && vd._init.isVoidInitializer()) 976 continue; 977 978 if (first) 979 { 980 buf.writestringln(" :"); 981 first = false; 982 } 983 else 984 { 985 buf.writestringln(","); 986 } 987 buf.printf("%s(", vd.ident.toChars()); 988 989 if (vd._init) 990 { 991 AST.initializerToExpression(vd._init).accept(this); 992 } 993 buf.printf(")"); 994 } 995 } 996 buf.level--; 997 buf.writenl(); 998 buf.writestringln("{"); 999 buf.writestringln("}"); 1000 buf.level--; 1001 } 1002 1003 version (none) 1004 { 1005 if (varCount) 1006 { 1007 buf.printf(" %s(", sd.ident.toChars()); 1008 bool first = true; 1009 foreach (m; *sd.members) 1010 { 1011 if (auto vd = m.isVarDeclaration()) 1012 { 1013 if (!memberField(vd)) 1014 continue; 1015 if (first) 1016 first = false; 1017 else 1018 buf.writestring(", "); 1019 assert(vd.type); 1020 assert(vd.ident); 1021 typeToBuffer(vd.type, vd.ident); 1022 } 1023 } 1024 buf.printf(") {"); 1025 foreach (m; *sd.members) 1026 { 1027 if (auto vd = m.isVarDeclaration()) 1028 { 1029 if (!memberField(vd)) 1030 continue; 1031 buf.printf(" this->%s = %s;", vd.ident.toChars(), vd.ident.toChars()); 1032 } 1033 } 1034 buf.printf(" }"); 1035 buf.writenl(); 1036 } 1037 } 1038 buf.writestringln("};"); 1039 1040 popAlignToBuffer(sd.alignment); 1041 buf.writenl(); 1042 1043 checkbuf.level++; 1044 const sn = sd.ident.toChars(); 1045 const sz = sd.size(Loc.initial); 1046 checkbuf.printf("assert(sizeof(%s) == %llu);", sn, sz); 1047 checkbuf.writenl(); 1048 checkbuf.level--; 1049 } 1050 1051 private void pushAlignToBuffer(uint alignment) 1052 { 1053 // DMD ensures alignment is a power of two 1054 //assert(alignment > 0 && ((alignment & (alignment - 1)) == 0), 1055 // "Invalid alignment size"); 1056 1057 // When no alignment is specified, `uint.max` is the default 1058 if (alignment == STRUCTALIGN_DEFAULT) 1059 { 1060 return; 1061 } 1062 1063 buf.printf("#pragma pack(push, %d)", alignment); 1064 buf.writenl(); 1065 } 1066 1067 private void popAlignToBuffer(uint alignment) 1068 { 1069 if (alignment == STRUCTALIGN_DEFAULT) 1070 return; 1071 1072 buf.writestringln("#pragma pack(pop)"); 1073 } 1074 1075 private void includeSymbol(AST.Dsymbol ds) 1076 { 1077 debug (Debug_DtoH) 1078 { 1079 printf("[includeSymbol(AST.Dsymbol) enter] %s\n", ds.toChars()); 1080 scope(exit) printf("[includeSymbol(AST.Dsymbol) exit] %s\n", ds.toChars()); 1081 } 1082 if (cast(void*) ds in visited) 1083 return; 1084 1085 OutBuffer decl; 1086 decl.doindent = true; 1087 decl.spaces = true; 1088 auto save = buf; 1089 buf = &decl; 1090 ds.accept(this); 1091 buf = save; 1092 donebuf.writestring(decl.peekChars()); 1093 } 1094 1095 override void visit(AST.ClassDeclaration cd) 1096 { 1097 debug (Debug_DtoH) 1098 { 1099 printf("[AST.ClassDeclaration enter] %s\n", cd.toChars()); 1100 scope(exit) printf("[AST.ClassDeclaration exit] %s\n", cd.toChars()); 1101 } 1102 if (cast(void*)cd in visited) 1103 return; 1104 if (isBuildingCompiler) 1105 { 1106 if (cd.getModule() && cd.getModule().isIgnoredModule()) 1107 return; 1108 if (cd.isVisitorClass()) 1109 return; 1110 } 1111 1112 visited[cast(void*)cd] = true; 1113 if (!cd.isCPPclass()) 1114 { 1115 if (printIgnored) 1116 buf.printf("// ignoring non-cpp class %s\n", cd.toChars()); 1117 return; 1118 } 1119 1120 const classAsStruct = cd.cppmangle == CPPMANGLE.asStruct; 1121 buf.writestring(classAsStruct ? "struct " : "class "); 1122 buf.writestring(cd.ident.toChars()); 1123 if (cd.baseClass) 1124 { 1125 buf.writestring(" : public "); 1126 buf.writestring(cd.baseClass.ident.toChars()); 1127 1128 includeSymbol(cd.baseClass); 1129 } 1130 if (!cd.members) 1131 { 1132 buf.writestring(";"); 1133 buf.writenl(); 1134 buf.writenl(); 1135 return; 1136 } 1137 1138 buf.writenl(); 1139 buf.writestringln("{"); 1140 if (!classAsStruct) 1141 buf.writestringln("public:"); 1142 1143 auto save = adparent; 1144 adparent = cd; 1145 buf.level++; 1146 foreach (m; *cd.members) 1147 { 1148 m.accept(this); 1149 } 1150 buf.level--; 1151 adparent = save; 1152 1153 // Generate special static inline function. 1154 if (isBuildingCompiler && cd.isIdentifierClass()) 1155 { 1156 buf.writestringln("static inline Identifier *idPool(const char *s) { return idPool(s, strlen(s)); }"); 1157 } 1158 1159 buf.writestringln("};"); 1160 buf.writenl(); 1161 } 1162 1163 override void visit(AST.EnumDeclaration ed) 1164 { 1165 debug (Debug_DtoH) 1166 { 1167 printf("[AST.EnumDeclaration enter] %s\n", ed.toChars()); 1168 scope(exit) printf("[AST.EnumDeclaration exit] %s\n", ed.toChars()); 1169 } 1170 if (cast(void*)ed in visited) 1171 return; 1172 1173 if (isBuildingCompiler && ed.getModule() && ed.getModule().isIgnoredModule()) 1174 return; 1175 1176 visited[cast(void*)ed] = true; 1177 1178 //if (linkage != LINK.c && linkage != LINK.cpp) 1179 //{ 1180 //if (printIgnored) 1181 //buf.printf("// ignoring non-cpp enum %s because of linkage\n", ed.toChars()); 1182 //return; 1183 //} 1184 1185 // we need to know a bunch of stuff about the enum... 1186 bool isAnonymous = ed.ident is null; 1187 AST.Type type = ed.memtype; 1188 if (!type) 1189 { 1190 // check all keys have matching type 1191 foreach (_m; *ed.members) 1192 { 1193 auto m = _m.isEnumMember(); 1194 if (!type) 1195 type = m.type; 1196 else if (m.type !is type) 1197 { 1198 type = null; 1199 break; 1200 } 1201 } 1202 } 1203 EnumKind kind = getEnumKind(type); 1204 1205 // determine if this is an enum, or just a group of manifest constants 1206 bool manifestConstants = !type || (isAnonymous && kind == EnumKind.Other); 1207 assert(!manifestConstants || isAnonymous); 1208 1209 // write the enum header 1210 if (!manifestConstants) 1211 { 1212 if (kind == EnumKind.Int || kind == EnumKind.Numeric) 1213 { 1214 buf.writestring("enum"); 1215 if (!isAnonymous) 1216 { 1217 buf.writestring(" class "); 1218 buf.writestring(ed.ident.toString()); 1219 } 1220 if (kind == EnumKind.Numeric) 1221 { 1222 buf.writestring(" : "); 1223 writeEnumTypeName(type); 1224 } 1225 } 1226 else 1227 { 1228 buf.writestring("namespace"); 1229 if(!isAnonymous) 1230 { 1231 buf.writestring(" "); 1232 buf.writestring(ed.ident.toString()); 1233 } 1234 } 1235 buf.writenl(); 1236 buf.writestringln("{"); 1237 } 1238 1239 // emit constant for each member 1240 if (!manifestConstants) 1241 buf.level++; 1242 1243 foreach (_m; *ed.members) 1244 { 1245 auto m = _m.isEnumMember(); 1246 AST.Type memberType = type ? type : m.type; 1247 const EnumKind memberKind = type ? kind : getEnumKind(memberType); 1248 1249 if (!manifestConstants && (kind == EnumKind.Int || kind == EnumKind.Numeric)) 1250 { 1251 buf.printf("%s = ", m.ident.toChars()); 1252 auto ie = cast(AST.IntegerExp)m.value; 1253 visitInteger(ie.toInteger(), memberType); 1254 buf.writestring(","); 1255 } 1256 else if (manifestConstants && (memberKind == EnumKind.Int || memberKind == EnumKind.Numeric)) 1257 { 1258 buf.writestring("enum : "); 1259 writeEnumTypeName(memberType); 1260 buf.printf(" { %s = ", m.ident.toChars()); 1261 auto ie = cast(AST.IntegerExp)m.value; 1262 visitInteger(ie.toInteger(), memberType); 1263 buf.writestring(" };"); 1264 } 1265 else 1266 { 1267 buf.writestring("static "); 1268 writeEnumTypeName(memberType); 1269 buf.printf(" const %s = ", m.ident.toChars()); 1270 m.value.accept(this); 1271 buf.writestring(";"); 1272 } 1273 buf.writenl(); 1274 } 1275 1276 if (!manifestConstants) 1277 buf.level--; 1278 // write the enum tail 1279 if (!manifestConstants) 1280 buf.writestring("};"); 1281 buf.writenl(); 1282 buf.writenl(); 1283 } 1284 1285 override void visit(AST.EnumMember em) 1286 { 1287 assert(false, "This node type should be handled in the EnumDeclaration"); 1288 } 1289 1290 private void typeToBuffer(AST.Type t, Identifier ident) 1291 { 1292 debug (Debug_DtoH) 1293 { 1294 printf("[typeToBuffer(AST.Type) enter] %s ident %s\n", t.toChars(), ident.toChars()); 1295 scope(exit) printf("[typeToBuffer(AST.Type) exit] %s ident %s\n", t.toChars(), ident.toChars()); 1296 } 1297 1298 this.ident = ident; 1299 origType ? origType.accept(this) : t.accept(this); 1300 if (this.ident) 1301 { 1302 buf.writeByte(' '); 1303 buf.writestring(ident.toChars()); 1304 } 1305 this.ident = null; 1306 if (auto tsa = t.isTypeSArray()) 1307 { 1308 buf.writeByte('['); 1309 tsa.dim.accept(this); 1310 buf.writeByte(']'); 1311 } 1312 } 1313 1314 override void visit(AST.Type t) 1315 { 1316 debug (Debug_DtoH) 1317 { 1318 printf("[AST.Type enter] %s\n", t.toChars()); 1319 scope(exit) printf("[AST.Type exit] %s\n", t.toChars()); 1320 } 1321 printf("Invalid type: %s\n", t.toPrettyChars()); 1322 assert(0); 1323 } 1324 1325 override void visit(AST.TypeIdentifier t) 1326 { 1327 debug (Debug_DtoH) 1328 { 1329 printf("[AST.TypeIdentifier enter] %s\n", t.toChars()); 1330 scope(exit) printf("[AST.TypeIdentifier exit] %s\n", t.toChars()); 1331 } 1332 buf.writestring(t.ident.toChars()); 1333 } 1334 1335 override void visit(AST.TypeBasic t) 1336 { 1337 debug (Debug_DtoH) 1338 { 1339 printf("[AST.TypeBasic enter] %s\n", t.toChars()); 1340 scope(exit) printf("[AST.TypeBasic exit] %s\n", t.toChars()); 1341 } 1342 if (!cdparent && t.isConst()) 1343 buf.writestring("const "); 1344 string typeName; 1345 switch (t.ty) 1346 { 1347 case AST.Tvoid: typeName = "void"; break; 1348 case AST.Tbool: typeName = "bool"; break; 1349 case AST.Tchar: typeName = "char"; break; 1350 case AST.Twchar: typeName = "char16_t"; break; 1351 case AST.Tdchar: typeName = "char32_t"; break; 1352 case AST.Tint8: typeName = "int8_t"; break; 1353 case AST.Tuns8: typeName = "uint8_t"; break; 1354 case AST.Tint16: typeName = "int16_t"; break; 1355 case AST.Tuns16: typeName = "uint16_t"; break; 1356 case AST.Tint32: typeName = "int32_t"; break; 1357 case AST.Tuns32: typeName = "uint32_t"; break; 1358 case AST.Tint64: typeName = "int64_t"; break; 1359 case AST.Tuns64: typeName = "uint64_t"; break; 1360 case AST.Tfloat32: typeName = "float"; break; 1361 case AST.Tfloat64: typeName = "double"; break; 1362 case AST.Tfloat80: 1363 typeName = "_d_real"; 1364 hasReal = true; 1365 break; 1366 default: 1367 //t.print(); 1368 assert(0); 1369 } 1370 buf.writestring(typeName); 1371 } 1372 1373 override void visit(AST.TypePointer t) 1374 { 1375 debug (Debug_DtoH) 1376 { 1377 printf("[AST.TypePointer enter] %s\n", t.toChars()); 1378 scope(exit) printf("[AST.TypePointer exit] %s\n", t.toChars()); 1379 } 1380 auto ts = t.next.isTypeStruct(); 1381 if (ts && !strcmp(ts.sym.ident.toChars(), "__va_list_tag")) 1382 { 1383 buf.writestring("va_list"); 1384 return; 1385 } 1386 t.next.accept(this); 1387 if (t.next.ty != AST.Tfunction) 1388 buf.writeByte('*'); 1389 if (!cdparent && t.isConst()) 1390 buf.writestring(" const"); 1391 } 1392 1393 override void visit(AST.TypeSArray t) 1394 { 1395 debug (Debug_DtoH) 1396 { 1397 printf("[AST.TypeSArray enter] %s\n", t.toChars()); 1398 scope(exit) printf("[AST.TypeSArray exit] %s\n", t.toChars()); 1399 } 1400 t.next.accept(this); 1401 } 1402 1403 override void visit(AST.TypeAArray t) 1404 { 1405 debug (Debug_DtoH) 1406 { 1407 printf("[AST.TypeAArray enter] %s\n", t.toChars()); 1408 scope(exit) printf("[AST.TypeAArray exit] %s\n", t.toChars()); 1409 } 1410 AST.Type.tvoidptr.accept(this); 1411 } 1412 1413 override void visit(AST.TypeFunction tf) 1414 { 1415 debug (Debug_DtoH) 1416 { 1417 printf("[AST.TypeFunction enter] %s\n", tf.toChars()); 1418 scope(exit) printf("[AST.TypeFunction exit] %s\n", tf.toChars()); 1419 } 1420 tf.next.accept(this); 1421 buf.writeByte('('); 1422 buf.writeByte('*'); 1423 if (ident) 1424 buf.writestring(ident.toChars()); 1425 ident = null; 1426 buf.writeByte(')'); 1427 buf.writeByte('('); 1428 foreach (i, fparam; tf.parameterList) 1429 { 1430 if (i) 1431 buf.writestring(", "); 1432 fparam.accept(this); 1433 } 1434 if (tf.parameterList.varargs) 1435 { 1436 if (tf.parameterList.parameters.dim && tf.parameterList.varargs == 1) 1437 buf.writestring(", "); 1438 buf.writestring("..."); 1439 } 1440 buf.writeByte(')'); 1441 } 1442 1443 private void enumToBuffer(AST.EnumDeclaration ed) 1444 { 1445 debug (Debug_DtoH) 1446 { 1447 printf("[enumToBuffer(AST.EnumDeclaration) enter] %s\n", ed.toChars()); 1448 scope(exit) printf("[enumToBuffer(AST.EnumDeclaration) exit] %s\n", ed.toChars()); 1449 } 1450 if (ed.isSpecial()) 1451 { 1452 if (ed.ident == DMDType.c_long) 1453 buf.writestring("long"); 1454 else if (ed.ident == DMDType.c_ulong) 1455 buf.writestring("unsigned long"); 1456 else if (ed.ident == DMDType.c_longlong) 1457 buf.writestring("long long"); 1458 else if (ed.ident == DMDType.c_ulonglong) 1459 buf.writestring("unsigned long long"); 1460 else if (ed.ident == DMDType.c_long_double) 1461 buf.writestring("long double"); 1462 else if (ed.ident == DMDType.c_wchar_t) 1463 buf.writestring("wchar_t"); 1464 else 1465 { 1466 //ed.print(); 1467 assert(0); 1468 } 1469 return; 1470 } 1471 1472 buf.writestring(ed.toChars()); 1473 } 1474 1475 override void visit(AST.TypeEnum t) 1476 { 1477 debug (Debug_DtoH) 1478 { 1479 printf("[AST.TypeEnum enter] %s\n", t.toChars()); 1480 scope(exit) printf("[AST.TypeEnum exit] %s\n", t.toChars()); 1481 } 1482 if (cast(void*)t.sym !in forwarded) 1483 { 1484 forwarded[cast(void*)t.sym] = true; 1485 auto save = buf; 1486 buf = fwdbuf; 1487 //printf("Visiting enum %s from module %s %s\n", t.sym.toPrettyChars(), t.toChars(), t.sym.loc.toChars()); 1488 t.sym.accept(this); 1489 buf = save; 1490 } 1491 if (!cdparent && t.isConst()) 1492 buf.writestring("const "); 1493 enumToBuffer(t.sym); 1494 } 1495 1496 override void visit(AST.TypeStruct t) 1497 { 1498 debug (Debug_DtoH) 1499 { 1500 printf("[AST.TypeStruct enter] %s\n", t.toChars()); 1501 scope(exit) printf("[AST.TypeStruct exit] %s\n", t.toChars()); 1502 } 1503 if (cast(void*)t.sym !in forwarded && !t.sym.parent.isTemplateInstance()) 1504 { 1505 forwarded[cast(void*)t.sym] = true; 1506 fwdbuf.writestring(t.sym.isUnionDeclaration() ? "union " : "struct "); 1507 fwdbuf.writestring(t.sym.toChars()); 1508 fwdbuf.writestringln(";"); 1509 } 1510 1511 if (!cdparent && t.isConst()) 1512 buf.writestring("const "); 1513 if (auto ti = t.sym.parent.isTemplateInstance()) 1514 { 1515 visitTi(ti); 1516 return; 1517 } 1518 buf.writestring(t.sym.toChars()); 1519 } 1520 1521 override void visit(AST.TypeDArray t) 1522 { 1523 debug (Debug_DtoH) 1524 { 1525 printf("[AST.TypeDArray enter] %s\n", t.toChars()); 1526 scope(exit) printf("[AST.TypeDArray exit] %s\n", t.toChars()); 1527 } 1528 if (!cdparent && t.isConst()) 1529 buf.writestring("const "); 1530 buf.writestring("DArray< "); 1531 t.next.accept(this); 1532 buf.writestring(" >"); 1533 } 1534 1535 private void visitTi(AST.TemplateInstance ti) 1536 { 1537 debug (Debug_DtoH) 1538 { 1539 printf("[visitTi(AST.TemplateInstance) enter] %s\n", ti.toChars()); 1540 scope(exit) printf("[visitTi(AST.TemplateInstance) exit] %s\n", ti.toChars()); 1541 } 1542 1543 // FIXME: Restricting this to DMD seems wrong ... 1544 if (isBuildingCompiler) 1545 { 1546 if (ti.tempdecl.ident == DMDType.AssocArray) 1547 { 1548 if (!forwardedAA) 1549 { 1550 forwardedAA = true; 1551 fwdbuf.writestring("struct AA;\n"); 1552 } 1553 buf.writestring("AA*"); 1554 return; 1555 } 1556 if (ti.tempdecl.ident == DMDType.Array) 1557 { 1558 buf.writestring("Array"); 1559 } 1560 else 1561 goto LprintTypes; 1562 } 1563 else 1564 { 1565 LprintTypes: 1566 foreach (o; *ti.tiargs) 1567 { 1568 if (!AST.isType(o)) 1569 return; 1570 } 1571 buf.writestring(ti.tempdecl.ident.toChars()); 1572 } 1573 buf.writeByte('<'); 1574 foreach (i, o; *ti.tiargs) 1575 { 1576 if (i) 1577 buf.writestring(", "); 1578 if (auto tt = AST.isType(o)) 1579 { 1580 tt.accept(this); 1581 } 1582 else 1583 { 1584 //ti.print(); 1585 //o.print(); 1586 assert(0); 1587 } 1588 } 1589 buf.writeByte('>'); 1590 } 1591 1592 override void visit(AST.TemplateDeclaration td) 1593 { 1594 debug (Debug_DtoH) 1595 { 1596 printf("[AST.TemplateDeclaration enter] %s\n", td.toChars()); 1597 scope(exit) printf("[AST.TemplateDeclaration exit] %s\n", td.toChars()); 1598 } 1599 if (cast(void*)td in visited) 1600 return; 1601 visited[cast(void*)td] = true; 1602 1603 if (isBuildingCompiler && td.getModule() && td.getModule().isIgnoredModule()) 1604 return; 1605 1606 if (!td.parameters || !td.onemember || !td.onemember.isStructDeclaration()) 1607 { 1608 visit(cast(AST.Dsymbol)td); 1609 return; 1610 } 1611 1612 // Explicitly disallow templates with non-type parameters or specialization. 1613 foreach (p; *td.parameters) 1614 { 1615 if (!p.isTemplateTypeParameter() || p.specialization()) 1616 { 1617 visit(cast(AST.Dsymbol)td); 1618 return; 1619 } 1620 } 1621 1622 if (linkage != LINK.c && linkage != LINK.cpp) 1623 { 1624 if (printIgnored) 1625 { 1626 buf.printf("// ignoring template %s because of linkage", td.toPrettyChars()); 1627 buf.writenl(); 1628 } 1629 return; 1630 } 1631 1632 auto sd = td.onemember.isStructDeclaration(); 1633 auto save = tdparent; 1634 tdparent = td; 1635 1636 buf.writestring("template <"); 1637 bool first = true; 1638 foreach (p; *td.parameters) 1639 { 1640 if (first) 1641 first = false; 1642 else 1643 buf.writestring(", "); 1644 buf.writestring("typename "); 1645 buf.writestring(p.ident.toChars()); 1646 } 1647 buf.writestringln(">"); 1648 1649 // TODO replace this block with a sd.accept 1650 { 1651 buf.writestring(sd.isUnionDeclaration() ? "union " : "struct "); 1652 buf.writestring(sd.ident.toChars()); 1653 if (sd.members) 1654 { 1655 buf.writenl(); 1656 buf.writestringln("{"); 1657 auto savex = adparent; 1658 adparent = sd; 1659 buf.level++; 1660 foreach (m; *sd.members) 1661 { 1662 m.accept(this); 1663 } 1664 buf.level--; 1665 adparent = savex; 1666 buf.writestringln("};"); 1667 buf.writenl(); 1668 } 1669 else 1670 { 1671 buf.writestringln(";"); 1672 buf.writenl(); 1673 } 1674 } 1675 1676 tdparent = save; 1677 } 1678 1679 override void visit(AST.TypeClass t) 1680 { 1681 debug (Debug_DtoH) 1682 { 1683 printf("[AST.TypeClass enter] %s\n", t.toChars()); 1684 scope(exit) printf("[AST.TypeClass exit] %s\n", t.toChars()); 1685 } 1686 if (cast(void*)t.sym !in forwarded) 1687 { 1688 forwarded[cast(void*)t.sym] = true; 1689 fwdbuf.writestring("class "); 1690 fwdbuf.writestring(t.sym.toChars()); 1691 fwdbuf.writestringln(";"); 1692 } 1693 1694 if (!cdparent && t.isConst()) 1695 buf.writestring("const "); 1696 buf.writestring(t.sym.toChars()); 1697 buf.writeByte('*'); 1698 if (!cdparent && t.isConst()) 1699 buf.writestring(" const"); 1700 } 1701 1702 private void funcToBuffer(AST.TypeFunction tf, AST.FuncDeclaration fd) 1703 { 1704 debug (Debug_DtoH) 1705 { 1706 printf("[funcToBuffer(AST.TypeFunction) enter] %s\n", tf.toChars()); 1707 scope(exit) printf("[funcToBuffer(AST.TypeFunction) exit] %s\n", tf.toChars()); 1708 } 1709 1710 Identifier ident = fd.ident; 1711 auto originalType = cast(AST.TypeFunction)fd.originalType; 1712 1713 assert(tf.next); 1714 1715 if (fd.isCtorDeclaration() || fd.isDtorDeclaration()) 1716 { 1717 if (fd.isDtorDeclaration()) 1718 { 1719 buf.writeByte('~'); 1720 } 1721 buf.writestring(adparent.toChars()); 1722 } 1723 else 1724 { 1725 tf.next == AST.Type.tsize_t ? originalType.next.accept(this) : tf.next.accept(this); 1726 if (tf.isref) 1727 buf.writeByte('&'); 1728 buf.writeByte(' '); 1729 buf.writestring(ident.toChars()); 1730 } 1731 1732 buf.writeByte('('); 1733 foreach (i, fparam; tf.parameterList) 1734 { 1735 if (i) 1736 buf.writestring(", "); 1737 if (fparam.type == AST.Type.tsize_t && originalType) 1738 { 1739 fparam = originalType.parameterList[i]; 1740 } 1741 fparam.accept(this); 1742 } 1743 if (tf.parameterList.varargs) 1744 { 1745 if (tf.parameterList.parameters.dim && tf.parameterList.varargs == 1) 1746 buf.writestring(", "); 1747 buf.writestring("..."); 1748 } 1749 buf.writeByte(')'); 1750 } 1751 1752 override void visit(AST.Parameter p) 1753 { 1754 debug (Debug_DtoH) 1755 { 1756 printf("[AST.Parameter enter] %s\n", p.toChars()); 1757 scope(exit) printf("[AST.Parameter exit] %s\n", p.toChars()); 1758 } 1759 ident = p.ident; 1760 p.type.accept(this); 1761 if (p.storageClass & AST.STC.ref_) 1762 buf.writeByte('&'); 1763 buf.writeByte(' '); 1764 if (ident) 1765 buf.writestring(ident.toChars()); 1766 ident = null; 1767 version (all) 1768 { 1769 if (p.defaultArg && p.defaultArg.op >= TOK.int32Literal && p.defaultArg.op < TOK.struct_) 1770 { 1771 //printf("%s %d\n", p.defaultArg.toChars, p.defaultArg.op); 1772 buf.writestring(" = "); 1773 buf.writestring(p.defaultArg.toChars()); 1774 } 1775 } 1776 else 1777 { 1778 if (p.defaultArg) 1779 { 1780 //printf("%s %d\n", p.defaultArg.toChars, p.defaultArg.op); 1781 //return; 1782 buf.writestring("/*"); 1783 buf.writestring(" = "); 1784 buf.writestring(p.defaultArg.toChars()); 1785 //p.defaultArg.accept(this); 1786 buf.writestring("*/"); 1787 } 1788 } 1789 } 1790 1791 override void visit(AST.Expression e) 1792 { 1793 debug (Debug_DtoH) 1794 { 1795 printf("[AST.Expression enter] %s\n", e.toChars()); 1796 scope(exit) printf("[AST.Expression exit] %s\n", e.toChars()); 1797 } 1798 assert(0); 1799 } 1800 1801 override void visit(AST.NullExp e) 1802 { 1803 debug (Debug_DtoH) 1804 { 1805 printf("[AST.NullExp enter] %s\n", e.toChars()); 1806 scope(exit) printf("[AST.NullExp exit] %s\n", e.toChars()); 1807 } 1808 buf.writestring("nullptr"); 1809 } 1810 1811 override void visit(AST.ArrayLiteralExp e) 1812 { 1813 debug (Debug_DtoH) 1814 { 1815 printf("[AST.ArrayLiteralExp enter] %s\n", e.toChars()); 1816 scope(exit) printf("[AST.ArrayLiteralExp exit] %s\n", e.toChars()); 1817 } 1818 buf.writestring("arrayliteral"); 1819 } 1820 1821 override void visit(AST.StringExp e) 1822 { 1823 debug (Debug_DtoH) 1824 { 1825 printf("[AST.StringExp enter] %s\n", e.toChars()); 1826 scope(exit) printf("[AST.StringExp exit] %s\n", e.toChars()); 1827 } 1828 if (e.sz == 2) 1829 buf.writeByte('u'); 1830 else if (e.sz == 4) 1831 buf.writeByte('U'); 1832 buf.writeByte('"'); 1833 1834 for (size_t i = 0; i < e.len; i++) 1835 { 1836 uint c = e.charAt(i); 1837 switch (c) 1838 { 1839 case '"': 1840 case '\\': 1841 buf.writeByte('\\'); 1842 goto default; 1843 default: 1844 if (c <= 0xFF) 1845 { 1846 if (c >= 0x20 && c < 0x80) 1847 buf.writeByte(c); 1848 else 1849 buf.printf("\\x%02x", c); 1850 } 1851 else if (c <= 0xFFFF) 1852 buf.printf("\\u%04x", c); 1853 else 1854 buf.printf("\\U%08x", c); 1855 break; 1856 } 1857 } 1858 buf.writeByte('"'); 1859 } 1860 1861 override void visit(AST.RealExp e) 1862 { 1863 debug (Debug_DtoH) 1864 { 1865 printf("[AST.RealExp enter] %s\n", e.toChars()); 1866 scope(exit) printf("[AST.RealExp exit] %s\n", e.toChars()); 1867 } 1868 1869 // TODO: Needs to implemented, properly switching on the e.type 1870 buf.printf("%ff", cast(double)e.value); 1871 } 1872 1873 override void visit(AST.IntegerExp e) 1874 { 1875 debug (Debug_DtoH) 1876 { 1877 printf("[AST.IntegerExp enter] %s\n", e.toChars()); 1878 scope(exit) printf("[AST.IntegerExp exit] %s\n", e.toChars()); 1879 } 1880 visitInteger(e.toInteger, e.type); 1881 } 1882 1883 private void visitInteger(dinteger_t v, AST.Type t) 1884 { 1885 debug (Debug_DtoH) 1886 { 1887 printf("[visitInteger(AST.Type) enter] %s\n", t.toChars()); 1888 scope(exit) printf("[visitInteger(AST.Type) exit] %s\n", t.toChars()); 1889 } 1890 switch (t.ty) 1891 { 1892 case AST.Tenum: 1893 auto te = cast(AST.TypeEnum)t; 1894 buf.writestring("("); 1895 enumToBuffer(te.sym); 1896 buf.writestring(")"); 1897 visitInteger(v, te.sym.memtype); 1898 break; 1899 case AST.Tbool: 1900 buf.writestring(v ? "true" : "false"); 1901 break; 1902 case AST.Tint8: 1903 buf.printf("%d", cast(byte)v); 1904 break; 1905 case AST.Tuns8: 1906 buf.printf("%uu", cast(ubyte)v); 1907 break; 1908 case AST.Tint16: 1909 buf.printf("%d", cast(short)v); 1910 break; 1911 case AST.Tuns16: 1912 case AST.Twchar: 1913 buf.printf("%uu", cast(ushort)v); 1914 break; 1915 case AST.Tint32: 1916 case AST.Tdchar: 1917 buf.printf("%d", cast(int)v); 1918 break; 1919 case AST.Tuns32: 1920 buf.printf("%uu", cast(uint)v); 1921 break; 1922 case AST.Tint64: 1923 buf.printf("%lldLL", v); 1924 break; 1925 case AST.Tuns64: 1926 buf.printf("%lluLLU", v); 1927 break; 1928 case AST.Tchar: 1929 if (v > 0x20 && v < 0x80) 1930 buf.printf("'%c'", cast(int)v); 1931 else 1932 buf.printf("%uu", cast(ubyte)v); 1933 break; 1934 default: 1935 //t.print(); 1936 assert(0); 1937 } 1938 } 1939 1940 override void visit(AST.StructLiteralExp sle) 1941 { 1942 debug (Debug_DtoH) 1943 { 1944 printf("[AST.StructLiteralExp enter] %s\n", sle.toChars()); 1945 scope(exit) printf("[AST.StructLiteralExp exit] %s\n", sle.toChars()); 1946 } 1947 buf.writestring(sle.sd.ident.toChars()); 1948 buf.writeByte('('); 1949 foreach(i, e; *sle.elements) 1950 { 1951 if (i) 1952 buf.writestring(", "); 1953 e.accept(this); 1954 } 1955 buf.writeByte(')'); 1956 } 1957 }