1 /+ 2 + Copyright 2022 – 2024 Aya Partridge 3 + Distributed under the Boost Software License, Version 1.0. 4 + (See accompanying file LICENSE_1_0.txt or copy at 5 + http://www.boost.org/LICENSE_1_0.txt) 6 +/ 7 module bindbc.common.codegen; 8 9 import bindbc.common.versions; 10 11 ///TODO: split into codegen.fn, codegen.enum_, and codegen.util 12 13 /** 14 Data for function bindings. 15 16 Only the locations of the first 3 fields (`retn`, `iden`, and `params`) should be 17 relied on. Every other field should always be written/read by using its identifier. 18 Example: 19 ```d 20 FnBbind one = {q{void}, q{someCppFn}, q{int si, uint ui}, ext: `C++`}; //OK 21 FnBbind two = {q{void}, q{someCppFn}, q{uint ui, int si}, `C++`}; //`ext` was not specified by identifier; might break in the future! 22 ``` 23 24 Never place whitespace around strings provided to FnBind, as it may cause incorrect binding generation. 25 */ 26 struct FnBind{ 27 /** 28 Return type. 29 Passing `const char*` instead of '`const(char)*` to a member function will 30 erroneously cause the function to be `const`. You should use `attrib` for this instead. 31 Must be void for constructors and destructors. 32 Must be non-null, except where it is ignored. 33 */ 34 string retn; 35 36 /** 37 The identifier of the function in the library you are binding. 38 Use `this` when binding a constructor, `~this` when binding a destructor. 39 Must be non-null. 40 */ 41 string iden; 42 43 /** 44 Comma-separated named function parameters. 45 Constructors can have no parameters. Constructors with all-default parameters will not currently work! 46 47 Default: no parameters 48 */ 49 string params = ""; 50 51 /** 52 Specifies which `extern` linkage to use. 53 | Support status | Input | Generated code | 54 |-------------------|-----------------|-------------------------| 55 | Fully supported | `C` | `extern(C)` | 56 | Mostly supported | `C++` | `extern(C++)` | 57 | Mostly supported | `C++. "name"` | `extern(C++, "name")` | 58 | Mostly supported | `C++. "a", "b"` | `extern(C++, "a", "b")` | 59 | Not yet supported | `Objective-C` | `extern(Objective-C)` | 60 61 Default: C 62 */ 63 string ext = `C`; 64 65 /** 66 Whether or not a member function is static. Should not be `true` for non-member functions. 67 */ 68 bool isStatic = false; 69 70 /** 71 Optional: Function attributes. `pure` will be removed from dynamic bindings. 72 */ 73 string attr; 74 75 /** 76 Optional: If populated, `iden` will be private, and a public alias with the name `pubIden` will be created. 77 */ 78 string pubIden; 79 80 /** 81 Optional: Member function attributes. 82 */ 83 string memAttr; 84 85 /** 86 Optional: 87 Anything to be placed immediately before the public version of the function, like `deprecated`, etc. 88 */ 89 string pfix; 90 91 /** 92 Optional: A list of identifiers to be aliases of the function. 93 */ 94 string[] aliases; 95 } 96 97 /** 98 Returns: A mixin string with code for creating function bindings. 99 100 Params: 101 staticBinding = Whether the functions generate static bindings, or otherwise dynamic ones. 102 version = The version of BindBC-Common that your code is written for. 103 */ 104 enum makeFnBindFns = (bool staticBinding, Version version_=Version(0,1,1)) nothrow pure @safe{ 105 if(version_ >= Version(0,1,1) && version_ <= bindBCCommonVersion){ 106 return 107 "alias joinFnBinds = bindbc.common.codegen.joinFnBinds!" ~ (staticBinding ? "true" : "false") ~ "; 108 alias FnBind = bindbc.common.codegen.FnBind;"; 109 }else assert(0, "Invalid version supplied."); 110 }; 111 112 /* 113 Regex sub: 114 ^[ \t]*([A-Za-z0-9_()*\[\]]+) (\w+) ?\(([A-Za-z0-9_()*, .=\[\]]*)\); 115 with: 116 \t\t{q{$1}, q{$2}, q{$3}}, 117 */ 118 enum joinFnBinds(bool staticBinding) = (FnBind[] fns, string membersWithFns=null) nothrow pure @safe{ 119 string ret; 120 121 static if(staticBinding){ 122 ret ~= "nothrow @nogc{\n"; 123 foreach(fn; fns){ 124 string pfix = (fn.pfix.length ? fn.pfix~" " : "") ~ (fn.pubIden.length ? "package " : "") ~ "extern("~fn.ext~") "; 125 if(fn.isStatic){ 126 pfix ~= "static "; 127 } 128 string attr = (fn.attr.length ? " "~fn.attr : ""); 129 string memAttr = (fn.memAttr.length ? " "~fn.memAttr : ""); 130 131 if(fn.iden == "this"){ 132 if(fn.params.length){ 133 ret ~= "\t" ~ pfix ~ "this("~fn.params~")" ~ memAttr ~ attr ~ ";\n"; 134 }else{ 135 ret ~= "\t\timport bindbc.common.codegen: mangleofCppDefaultCtor;\n"; 136 ret ~= "\t" ~ pfix ~ "pragma(mangle, [__traits(getCppNamespaces, typeof(this)), __traits(identifier, typeof(this))].mangleofCppDefaultCtor()) this(int _)" ~ (fn.memAttr.length ? " "~fn.memAttr : "") ~ ";\n"; 137 } 138 }else{ 139 ret ~= "\t" ~ pfix ~ fn.retn ~ " " ~ fn.iden ~ "("~fn.params~")" ~ memAttr ~ attr ~ ";\n"; 140 } 141 142 if(fn.pubIden.length){ 143 ret ~= "\talias " ~ fn.pubIden ~ " = " ~ fn.iden ~ ";\n"; 144 } 145 foreach(alias_; fn.aliases){ 146 ret ~= "\talias " ~ alias_ ~ " = " ~ fn.iden ~ ";\n"; 147 } 148 } 149 ret ~= "}"; 150 }else{ 151 string types = "private nothrow @nogc{\n"; 152 string ptrs = "__gshared nothrow @nogc{\n"; 153 string dyn = 154 `import bindbc.loader: SharedLib, bindSymbol; 155 static void bindModuleSymbols(SharedLib lib) nothrow @nogc{ 156 alias here = ` ~ makeOuterScope() ~ `;`; 157 158 //Helps us see if functions have overloads. 159 uint[string] usedIdens; 160 foreach(fn; fns){ 161 if(fn.ext != "C"){ //Could this function have overloads? 162 if(auto num = fn.iden in usedIdens){ 163 (*num) = 1; 164 }else{ 165 usedIdens[fn.iden] = 0; 166 } 167 } 168 } 169 170 foreach(fn; fns){ 171 //Are there overloads of this function? 172 uint overload = 0; 173 if(fn.ext != "C"){ 174 if(auto num = fn.iden in usedIdens){ 175 overload = *num; 176 (*num)++; 177 } 178 } 179 180 string ext = "extern("~fn.ext~") "; 181 string pfix = (fn.pfix.length ? fn.pfix~" " : "") ~ (fn.pubIden.length ? "package " : "") ~ ext; 182 if(fn.isStatic){ 183 pfix ~= "static "; 184 } 185 186 string memAttr = (fn.memAttr.length ? " "~fn.memAttr : ""); 187 string attr = (fn.attr.length ? " "~fn.attr : ""); 188 //remove `pure` for function wrapper 189 string wrapAttr = attr; 190 if(fn.attr.length >= 4){ 191 foreach(ind; 0..fn.attr.length-3){ 192 if(fn.attr[ind..ind+4] == q{pure}){ 193 wrapAttr = " "~fn.attr[0..ind] ~ fn.attr[ind+4..$]; 194 break; 195 } 196 } 197 } 198 199 //Is this a variadic function? 200 bool variadic = fn.params.length > 3 && fn.params[$-3..$] == "..."; 201 //Is this a member function? 202 bool memberFn = membersWithFns is null && fn.ext != "C"; 203 204 //`iden` is either the identifier for this function, or an internal name if the function identifier is special (e.g. `this`) 205 string iden = (){ 206 switch(fn.iden){ 207 case "this": return "__ctor"; 208 case "~this": return "__dtor"; 209 default: return fn.iden; 210 } 211 }(); 212 //Whether a special identifier (`__ctor`/`__dtor`) is in-use. 213 //bool specialIden = iden != fn.iden; 214 215 //The function pointer's parameters, and how to call it from the public function. 216 string ptrParams = fn.params; 217 string ptrCall = "__traits(parameters)"; 218 if(memberFn && !fn.isStatic){ 219 if(fn.params.length){ 220 ptrParams = "ref inout(typeof(this)) this_, " ~ ptrParams; 221 ptrCall = "this, " ~ ptrCall; 222 }else{ 223 ptrParams = "ref inout(typeof(this)) this_"; 224 ptrCall = "this"; 225 } 226 ptrParams = (fn.memAttr.length ? fn.memAttr~" " : "") ~ ptrParams; 227 } 228 229 string ptrIden = "_"~iden; 230 string typeIden = "_p"~iden; 231 string typeExt = "extern("~((fn.ext.length > 3 && fn.ext[0..3] == "C++") ? "C++" : fn.ext)~") "; 232 233 if(overload){ 234 string overloadStr = overload.toStrCT(); 235 ptrIden ~= overloadStr; 236 typeIden ~= overloadStr; 237 //if(!specialIden){ 238 //iden ~= "_"~overloadStr; 239 //pfix = "package " ~ pfix; 240 //} 241 }else if(variadic){ 242 types ~= "\talias " ~ typeIden ~ " = " ~ typeExt ~ fn.retn ~ " function(" ~ ptrParams ~ ")" ~ attr ~ ";\n"; 243 ptrs ~= "\t" ~ typeIden ~ " " ~ iden ~ ";\n"; 244 } 245 246 ptrCall = ptrIden ~ "("~ptrCall~");"; 247 248 if(overload){ 249 dyn ~= ` 250 { 251 alias FnCmp = void(`~fn.params~`); 252 static if(is(FnCmp ArgsCmp == function)){ 253 static foreach(Fn; __traits(getOverloads, here, "` ~ iden ~ `")){{ 254 static if(is(typeof(Fn) Args == function)){ 255 static if(is(Args == ArgsCmp)){ 256 lib.bindSymbol(cast(void**)&` ~ ptrIden ~ `, Fn.mangleof); 257 } 258 }else static assert(0); 259 }} 260 }else static assert(0); 261 }`; 262 }else if(variadic){ 263 if((fn.ext.length >= 3 && fn.ext[0..3] == "C++") || fn.ext == "Objective-C"){ 264 //Variadic functions always act like they're overloaded and return no mangled parameters. :( 265 dyn ~= ` 266 { 267 alias FnCmp = void(`~fn.params~`); 268 static if(is(FnCmp ArgsCmp == function)){ 269 static foreach(Fn; __traits(getOverloads, here, "` ~ iden ~ `")){{ 270 static if(is(typeof(Fn) Args == function)){ 271 static if(is(Args == ArgsCmp)){ 272 lib.bindSymbol(cast(void**)&` ~ iden ~ `, Fn.mangleof); 273 } 274 }else static assert(0); 275 }} 276 }else static assert(0); 277 }`; 278 }else{ 279 dyn ~= ` 280 lib.bindSymbol(cast(void**)&` ~ iden ~ `, "` ~ iden ~ `");`; 281 } 282 continue; 283 284 }else{ 285 dyn ~= ` 286 lib.bindSymbol(cast(void**)&` ~ ptrIden ~ `, here.` ~ iden ~ `.mangleof);`; 287 288 } 289 290 //We separate the type so that the compiler doesn't extern our function pointer; only makes the function pointer type extern. 291 types ~= "\talias " ~ typeIden ~ " = " ~ typeExt ~ fn.retn ~ " function(" ~ ptrParams ~ ")" ~ attr ~ ";\n"; 292 //Private function pointer declaration. 293 ptrs ~= "\tpackage " ~ typeIden ~ " " ~ ptrIden ~ ";\n"; 294 295 //Function wrapper delcaration. 296 string fnParams = fn.params; 297 if(variadic && overload){ 298 fnParams = "T...)("~fnParams[0..$-3]~"T _variadics"; 299 } 300 if(fn.iden == "this"){ //Constructor. 301 if(fn.params.length){ 302 //TODO: Check if the parameters are all defaults here :( 303 ptrs ~= "\t" ~ pfix ~ "this("~fnParams~")" ~ memAttr ~ wrapAttr ~ "{ " ~ ptrCall ~ " }\n"; 304 }else if(fn.ext.length >= 3 && fn.ext[0..3] == "C++"){ //Default constructor; must have no parameters. 305 ptrs ~= "\timport bindbc.common.codegen: mangleofCppDefaultCtor;\n"; 306 ptrs ~= "\t" ~ pfix ~ "pragma(mangle, [__traits(getCppNamespaces, typeof(this)), __traits(identifier, typeof(this))].mangleofCppDefaultCtor()) this(int _)" ~ memAttr ~ attr ~ "{ " ~ ptrCall ~ " }\n"; 307 }else assert(0, "Default constructor mangling for extern("~fn.ext~") is unknown."); 308 }else if(fn.iden == "~this"){ //Destructor. 309 ptrs ~= "\t" ~ pfix ~ "~this("~fnParams~")" ~ memAttr ~ wrapAttr ~ "{ " ~ ptrCall ~ " }\n"; 310 }else{ 311 if(fn.retn != "void"){ 312 ptrCall = "return " ~ ptrCall; 313 } 314 ptrs ~= "\t" ~ pfix ~ fn.retn ~ " " ~ fn.iden ~ "("~fnParams~")" ~ memAttr ~ wrapAttr ~ "{ " ~ ptrCall ~ " }\n"; 315 } 316 317 if(fn.pubIden.length){ 318 ptrs ~= "\talias " ~ fn.pubIden ~ " = " ~ iden ~ ";\n"; 319 } 320 foreach(aliasIden; fn.aliases){ 321 ptrs ~= "\talias " ~ aliasIden ~ " = " ~ iden ~ ";"; 322 } 323 } 324 325 if(membersWithFns.length){ 326 //This method is easier to rewrite to use __traits(allMembers) later 327 dyn ~= ` 328 alias AliasSeq(T...) = T; 329 static foreach(item; AliasSeq!(` ~ membersWithFns ~ `)){ 330 static assert((is(item == struct) || is(item == class)) && (__traits(getLinkage, item) == "C++" || __traits(getLinkage, item) == "Objective-C") && __traits(hasMember, item, "bindModuleSymbols")); 331 mixin(__traits(fullyQualifiedName, item),".bindModuleSymbols(lib);"); 332 }`; 333 } 334 335 ret = types ~ "}\n" ~ ptrs ~ "}\n\n" ~ dyn ~ "\n}"; 336 } 337 return ret; 338 }; 339 340 /*//TODO: some time after __traits(allMembers) is fixed, remove "membersWithFns" and check over each type it returns automatically! :) 341 enum joinFnBinds = (string[][] list, string membersWithFns="") nothrow pure @safe{; 342 static if(staticBinding){ 343 string joined = "{"; 344 }else{ 345 string joined = "\n@nogc nothrow __gshared{";; 346 } 347 foreach(item; list){ 348 joined ~= item[0]; 349 } 350 joined ~= "\n}";; 351 352 static if(!staticBinding){ 353 joined ~= "\n\nimport bindbc.loader: SharedLib, bindSymbol;\nstatic void bindModuleSymbols(SharedLib lib) @nogc nothrow{"; 354 foreach(item; list){ 355 if(item[2] == "this") item[2] = "__ctor"; 356 if(item[3].length > 0){ 357 joined ~= " 358 static if("~((item[3].length > 3 && item[3][$-3..$] == "...") ? "true" : "false")~" || __traits(getOverloads, "~outerScope~", \""~item[2]~"\").length > 0){ 359 static foreach(Fn; __traits(getOverloads, "~outerScope~", \""~item[2]~"\")){ 360 { 361 void Fn2("~item[3]~"){} 362 static if(is(typeof(Fn) Args1 == __parameters) && is(typeof(Fn2) Args2 == __parameters)){ 363 static if(is(Args1 == Args2)){ 364 lib.bindSymbol(cast(void**)&"~item[1]~", Fn.mangleof); 365 } 366 }else static assert(0); 367 } 368 } 369 }else{ 370 lib.bindSymbol(cast(void**)&"~item[1]~", "~outerScope~"."~item[2]~".mangleof); 371 }"; 372 }else{ 373 joined ~= "\n\tlib.bindSymbol(cast(void**)&"~item[1]~", "~outerScope~"."~item[2]~".mangleof);"; 374 } 375 } 376 if(membersWithFns.length > 0){ 377 joined ~= q{ 378 alias AliasSeq(T...) = T; 379 static foreach(member; AliasSeq!(}~membersWithFns~q{)){ 380 static if( (is(member == struct) || is(member == class) || is(member == struct)) && (__traits(getLinkage, member) == "C++" || __traits(getLinkage, member) == "Objective-C") ){ 381 mixin(member,".bindModuleSymbols(lib);"); 382 } 383 } 384 }; 385 } 386 joined ~= "\n}";; 387 } 388 389 return joined; 390 };*/ 391 392 ///For internal use only. 393 enum makeIsMember = () nothrow pure @safe{ 394 return "__traits(compiles, typeof(this))"; 395 }; 396 unittest{ 397 static assert(mixin(makeIsMember()) == false); 398 struct XXX{ 399 static assert(mixin(makeIsMember()) == true); 400 } 401 } 402 403 ///For internal use only. 404 package enum makeOuterScope = () nothrow pure @safe{ 405 return 406 "mixin((string mod=__MODULE__){ 407 static if(__traits(compiles, typeof(this))) return __traits(identifier, typeof(this)); 408 else return mod; 409 }())"; 410 }; 411 unittest{ 412 static assert(__traits(isSame, mixin(makeOuterScope()), bindbc.common.codegen)); 413 struct XXX{ 414 static assert(is(mixin(makeOuterScope()) == XXX)); 415 } 416 } 417 418 ///For internal use only. 419 enum mangleofCppDefaultCtor = (string[] syms) nothrow pure @safe{ 420 static if((){ 421 version(CppRuntime_Clang) return true; 422 else version(CppRuntime_Gcc) return true; 423 else version(Android) return true; 424 else version(WebAssembly) return true; 425 else return false; 426 }()){ 427 string ret = "_ZN"; 428 foreach(sym; syms){ 429 ret ~= toStrCT(sym.length) ~ sym; 430 } 431 return ret ~ "C1Ev"; 432 }else static if((){ 433 version(CppRuntime_Microsoft) return true; 434 else version(CppRuntime_DigitalMars) return true; 435 else return false; 436 }()){ 437 string ret = "??0"; 438 foreach(sym; syms){ 439 ret ~= sym ~ "@"; 440 } 441 version(D_X32){ 442 return ret ~ "@QAE@XZ"; 443 }else{ 444 return ret ~ "@QEAA@XZ"; 445 } 446 }else static assert(0, "Unknown runtime, not sure what mangling to use. Please check how your compiler mangles C++ struct constructors and add a case for it to `bindbc.common.codegen.mangleofCppDefaultCtor`."); 447 }; 448 unittest{ 449 static if((){ 450 version(CppRuntime_Clang) return true; 451 else version(CppRuntime_Gcc) return true; 452 else return false; 453 }()){ 454 static assert(["ImGuiListClipper"].mangleofCppDefaultCtor() == "_ZN16ImGuiListClipperC1Ev"); 455 static assert(["bgfx", "Init"].mangleofCppDefaultCtor() == "_ZN4bgfx4InitC1Ev"); 456 }else static if((){ 457 version(CppRuntime_Microsoft) return true; 458 else version(CppRuntime_DigitalMars) return true; 459 else return false; 460 }()){ 461 version(D_X32){ 462 static assert(["ImGuiListClipper"].mangleofCppDefaultCtor() == "??0ImGuiListClipper@@QAE@XZ"); 463 static assert(["bgfx", "Init"].mangleofCppDefaultCtor() == "??0Init@bgfx@@QAE@XZ"); 464 }else{ 465 static assert(["ImGuiListClipper"].mangleofCppDefaultCtor() == "??0ImGuiListClipper@@QEAA@XZ"); 466 static assert(["bgfx", "Init"].mangleofCppDefaultCtor() == "??0Init@bgfx@@QEAA@XZ"); 467 } 468 }else static assert(0); 469 } 470 471 ///For internal use only. 472 size_t badHash(string s) nothrow pure @safe{ 473 size_t ret = 0; 474 for(size_t i = 0; i < s.length; i += 2){ 475 ret += s[i]; //yes, this is a *really* bad hashing algorithm! 476 } 477 return ret * s.length; 478 } 479 unittest{ 480 static assert(badHash("const(void)* ptr") != badHash("char alpha")); 481 static assert(badHash("const(void)* ptr") != badHash("const(void)* chr")); 482 static assert(badHash("ubyte id, size_t ind, char* buf") != badHash("wchar utf16, char* utf8")); 483 static assert(badHash("dchar utf16, char* utf8, bool er") != badHash("wchar utf16, char* utf8, bool er")); 484 } 485 486 ///For internal use only. 487 enum toStrCT = (size_t val) nothrow pure @safe{ 488 enum base = 10; 489 490 if(!val) return "0"; 491 492 string ret; 493 while(val > 0){ 494 ret = cast(char)('0' + (val % base)) ~ ret; 495 val /= base; 496 } 497 return ret; 498 }; 499 unittest{ 500 static assert(0.toStrCT() == "0"); 501 static assert(4.toStrCT() == "4"); 502 static assert(120.toStrCT() == "120"); 503 static assert(589_000.toStrCT() == "589000"); 504 static assert(9_396_460_865_079_328.toStrCT() == "9396460865079328"); 505 static assert(1_046_259_925_731_862_221.toStrCT() == "1046259925731862221"); 506 } 507 508 /** 509 Data for a member of an enum binding. 510 511 Only the locations of the first 2 fields (`iden`, and `val`) should be 512 relied on. Every other field should always be written/read by using its identifier. 513 */ 514 struct EnumMember{ 515 EnumIden iden; 516 517 /** 518 Optional: The value of both versions of the enum member. 519 */ 520 string val; 521 522 /** 523 Optional: A list of identifiers to be aliases of the member. 524 */ 525 EnumIden[] aliases; 526 } 527 528 struct EnumIden{ 529 /** 530 The identifier for a D-style version of this enum member. 531 For example: `mouseButtonDown` for an enum named `SDLEvent` 532 Must be non-null, except in `aliases`. 533 */ 534 string d; 535 536 /** 537 The identifier for a C-style version of this enum member. 538 For example: `SDL_EVENT_MOUSE_BUTTON_DOWN` 539 Must be non-null, except in `aliases`. 540 */ 541 string c; 542 } 543 544 /** 545 Returns: A mixin string with code for creating enum bindings. 546 547 Params: 548 cStyle = Whether or not to generate C-style 549 version = The version of BindBC-Common that your code is written for. 550 */ 551 enum makeEnumBindFns = (bool cStyle, bool dStyle) nothrow pure @safe{ 552 return 553 "alias makeEnumBind = bindbc.common.codegen.makeEnumBind!(" ~ 554 (cStyle ? "true" : "false") ~ ", " ~ 555 (dStyle ? "true" : "false") ~ 556 "); 557 alias EnumMember = bindbc.common.codegen.EnumMember; 558 alias EnumIden = bindbc.common.codegen.EnumIden;"; 559 }; 560 561 /** 562 Create an enum with optional D-style and C-style versions. 563 564 Only the first two parameters (`dIden`, and `baseType`) should be 565 supplied sequentially. The rest should be called using named parameters. 566 567 Params: 568 dIden = An identifer for the D-style version of this enum. (i.e. `enum TypeIdentifier{`) 569 baseType = (Optional) A base type for both versions of the enum. (i.e. `enum MyEnum: BaseType{`) 570 aliases = (Optional) Aliases to the D-style version of this enum. 571 members = Each member of the enum. 572 */ 573 enum makeEnumBind(bool cStyle, bool dStyle) = (string dIden, string baseType=null, string[] aliases=null, EnumMember[] members, string fullModule=__MODULE__) nothrow pure @safe{ 574 string dRet; 575 static if(!dStyle) 576 dRet ~= "package "; 577 dRet ~= "enum " ~ dIden; 578 if(baseType) 579 dRet ~= ": " ~ baseType; 580 dRet ~= "{\n"; 581 582 string cRet; 583 static if(cStyle){ 584 cRet ~= "enum: " ~ fullModule~"."~dIden ~ "{\n"; 585 } 586 587 foreach(member; members){ 588 dRet ~= "\t" ~ member.iden.d; 589 if(member.val) 590 dRet ~= " = " ~ member.val; 591 dRet ~= ",\n"; 592 593 static if(cStyle){ 594 if(member.iden.c){ 595 cRet ~= "\t" ~ member.iden.c ~ " = " ~ fullModule~"."~dIden~"."~member.iden.d; 596 cRet ~= ",\n"; 597 } 598 } 599 600 foreach(aliasIden; member.aliases){ 601 if(aliasIden.d) 602 dRet ~= "\t" ~ aliasIden.d ~ " = " ~ member.iden.d ~ ",\n"; 603 604 static if(cStyle){ 605 if(aliasIden.c) 606 cRet ~= "\t" ~ aliasIden.c ~ " = " ~ member.iden.c ~ ",\n"; 607 } 608 } 609 } 610 611 dRet ~= "}\n"; 612 foreach(dAlias; aliases){ 613 static if(!dStyle) 614 dRet ~= "package "; 615 dRet ~= "alias "~dAlias~" = "~fullModule~"."~dIden~";\n"; 616 } 617 618 return dRet ~ cRet ~ "}"; 619 }; 620 621 /** 622 A workaround that BindBC used to use for C-style enums. 623 It is included here mostly for preservation. 624 */ 625 enum makeExpandedEnum(Enum) = () nothrow pure @safe{ 626 string ret; 627 foreach(member; __traits(allMembers, Enum)){ 628 ret ~= "\nenum "~member~" = "~Enum.stringof~"."~member~";"; 629 } 630 return ret; 631 }();