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