1 module dpp.runtime.namespace; 2 3 /** 4 Uses a template mixin hack to "reopen" C++ namespace declarations in D 5 */ 6 struct Namespace { 7 static struct Symbol { 8 string namespace; 9 string name; 10 } 11 12 enum indentationSpaces = " "; 13 private int _index; 14 private string[] _nestedNamespaces; 15 private Symbol[] _symbols; 16 private string _mixinName; 17 18 string[] push(in string name) @safe pure { 19 import std.conv: text; 20 string[] lines; 21 22 if(_nestedNamespaces.length == 0) { 23 _mixinName = text("_CppNamespace", _index); 24 lines ~= text("mixin template ", _mixinName, "() {"); 25 } 26 27 lines ~= indentationSpaces ~ text("extern(C++, ", name, ") {"); 28 _nestedNamespaces ~= name; 29 30 return lines; 31 } 32 33 string[] pop() @safe pure { 34 35 _nestedNamespaces = _nestedNamespaces[0 .. $-1]; 36 auto lines = [indentationSpaces ~ "}"]; 37 38 if(_nestedNamespaces.length == 0) { 39 lines ~= finish; 40 } 41 42 return lines; 43 } 44 45 void addSymbol(in string symbol) @safe pure { 46 import std.array: join; 47 if(symbol != "") 48 _symbols ~= Symbol(_nestedNamespaces.join("."), symbol); 49 } 50 51 private string[] finish() @safe pure { 52 import std.conv: text; 53 import std.algorithm: map, uniq; 54 import std.array: array; 55 56 auto lines = ["}", ""]; 57 58 const varName = text("_cppNamespace_", _index); 59 lines ~= text("mixin ", _mixinName, "!() ", varName, ";"); 60 61 string aliasText(in Symbol s) { 62 return text("alias ", s.name, " = ", varName, ".", s.namespace, ".", s.name, `;`); 63 } 64 65 lines ~= _symbols 66 .uniq!((a, b) => a.name == b.name) 67 .map!(s => `static if(is(typeof({ ` ~ aliasText(s) ~ ` }))) ` ~ aliasText(s) ~ `;`) 68 .array 69 ; 70 71 reset; 72 73 return lines; 74 } 75 76 private void reset() @safe pure { 77 _mixinName = ""; 78 _index++; 79 _symbols = []; 80 } 81 }