1 module autowrap.csharp.dlang; 2 3 import autowrap.reflection : isModule; 4 import std.ascii : newline; 5 import std.meta : allSatisfy; 6 7 enum string methodSetup = " thread_attachThis(); 8 rt_moduleTlsCtor(); 9 scope(exit) rt_moduleTlsDtor(); 10 scope(exit) thread_detachThis();"; 11 12 // Wrap global functions from multiple modules 13 public string wrapDLang(Modules...)() if(allSatisfy!(isModule, Modules)) { 14 import autowrap.csharp.common : getDLangInterfaceName; 15 import autowrap.reflection : AllAggregates; 16 import std.traits : fullyQualifiedName, moduleName; 17 import std.meta : AliasSeq; 18 19 string ret = string.init; 20 ret ~= "import core.thread : thread_attachThis, thread_detachThis;" ~ newline; 21 ret ~= "extern(C) void rt_moduleTlsCtor();" ~ newline; 22 ret ~= "extern(C) void rt_moduleTlsDtor();" ~ newline; 23 foreach(mod; Modules) { 24 ret ~= "import " ~ mod.name ~ ";" ~ newline; 25 } 26 ret ~= newline; 27 28 static foreach(t; AliasSeq!(string, wstring, dstring, bool, byte, ubyte, short, ushort, int, uint, long, ulong, float, double)) { 29 ret ~= generateSliceMethods!t(); 30 } 31 32 foreach(agg; AllAggregates!Modules) { 33 alias modName = moduleName!agg; 34 alias fqn = fullyQualifiedName!agg; 35 36 ret ~= generateSliceMethods!agg(); 37 38 ret ~= generateConstructors!agg(); 39 40 ret ~= generateMethods!agg(); 41 42 ret ~= generateFields!agg(); 43 } 44 45 ret ~= generateFunctions!Modules(); 46 47 return ret; 48 } 49 50 private string generateConstructors(T)() { 51 import autowrap.csharp.common : getDLangInterfaceName; 52 import std.traits : fullyQualifiedName, hasMember, Parameters, ParameterIdentifierTuple; 53 import std.meta : AliasSeq; 54 55 string ret = string.init; 56 alias fqn = fullyQualifiedName!T; 57 static if(hasMember!(T, "__ctor")) { 58 alias constructors = AliasSeq!(__traits(getOverloads, T, "__ctor")); 59 } else { 60 alias constructors = AliasSeq!(); 61 } 62 63 //Generate constructor methods 64 foreach(c; constructors) { 65 alias paramNames = ParameterIdentifierTuple!c; 66 alias paramTypes = Parameters!c; 67 string exp = "extern(C) export "; 68 const string interfaceName = getDLangInterfaceName(fqn, "__ctor"); 69 70 exp ~= "returnValue!(" ~ fqn ~ ")"; 71 exp ~= " " ~ interfaceName ~ "("; 72 73 static foreach(pc; 0..paramNames.length) { 74 exp ~= fullyQualifiedName!(paramTypes[pc]) ~ " " ~ paramNames[pc] ~ ", "; 75 } 76 if (paramTypes.length > 0) { 77 exp = exp[0..$-2]; 78 } 79 exp ~= ") nothrow {" ~ newline; 80 exp ~= " try {" ~ newline; 81 exp ~= methodSetup ~ newline; 82 if (is(T == class)) { 83 exp ~= " import std.stdio : writeln;" ~ newline; 84 exp ~= " " ~ fqn ~ " __temp__ = new " ~ fqn ~ "("; 85 static foreach(pc; 0..paramNames.length) { 86 exp ~= paramNames[pc] ~ ", "; 87 } 88 if (paramTypes.length > 0) { 89 exp = exp[0..$-2]; 90 } 91 exp ~= ");" ~ newline; 92 exp ~= " pinPointer(cast(void*)__temp__);" ~ newline; 93 exp ~= " return returnValue!(" ~ fqn ~ ")(__temp__);" ~ newline; 94 } else if (is(T == struct)) { 95 exp ~= " return " ~ fqn ~ "("; 96 foreach(pn; paramNames) { 97 exp ~= pn ~ ", "; 98 } 99 if (paramTypes.length > 0) { 100 exp = exp[0..$-2]; 101 } 102 exp ~= ");" ~ newline; 103 } 104 exp ~= " } catch (Exception __ex__) {" ~ newline; 105 exp ~= " return returnValue!(" ~ fqn ~ ")(__ex__);" ~ newline; 106 exp ~= " }" ~ newline; 107 exp ~= "}" ~ newline; 108 ret ~= exp; 109 } 110 111 return ret; 112 } 113 114 private string generateMethods(T)() { 115 import autowrap.csharp.common : getDLangInterfaceName; 116 import std.traits : isFunction, fullyQualifiedName, ReturnType, Parameters, ParameterIdentifierTuple; 117 import std.conv : to; 118 119 string ret = string.init; 120 alias fqn = fullyQualifiedName!T; 121 foreach(m; __traits(allMembers, T)) { 122 if (m == "__ctor" || m == "toHash" || m == "opEquals" || m == "opCmp" || m == "factory") { 123 continue; 124 } 125 126 static if (is(typeof(__traits(getMember, T, m)))) { 127 foreach(oc, mo; __traits(getOverloads, T, m)) { 128 const bool isMethod = isFunction!mo; 129 130 static if(isMethod) { 131 string exp = string.init; 132 const string interfaceName = getDLangInterfaceName(fqn, m); 133 134 alias returnType = ReturnType!mo; 135 alias returnTypeStr = fullyQualifiedName!returnType; 136 alias paramTypes = Parameters!mo; 137 alias paramNames = ParameterIdentifierTuple!mo; 138 139 exp ~= "extern(C) export "; 140 if (!is(returnType == void)) { 141 exp ~= "returnValue!(" ~ returnTypeStr ~ ")"; 142 } else { 143 exp ~= "returnVoid"; 144 } 145 exp ~= " " ~ interfaceName ~ to!string(oc) ~ "("; 146 if (is(T == struct)) { 147 exp ~= "ref " ~ fqn ~ " __obj__, "; 148 } else { 149 exp ~= fqn ~ " __obj__, "; 150 } 151 static foreach(pc; 0..paramNames.length) { 152 exp ~= fullyQualifiedName!(paramTypes[pc]) ~ " " ~ paramNames[pc] ~ ", "; 153 } 154 exp = exp[0..$-2]; 155 exp ~= ") nothrow {" ~ newline; 156 exp ~= " try {" ~ newline; 157 exp ~= methodSetup ~ newline; 158 exp ~= " "; 159 if (!is(returnType == void)) { 160 exp ~= "auto __result__ = "; 161 } 162 exp ~= "__obj__." ~ m ~ "("; 163 static foreach(pc; 0..paramNames.length) { 164 exp ~= paramNames[pc] ~ ", "; 165 } 166 if (paramNames.length > 0) { 167 exp = exp[0..$-2]; 168 } 169 exp ~= ");" ~ newline; 170 if (!is(returnType == void)) { 171 exp ~= " return returnValue!(" ~ returnTypeStr ~ ")(__result__);" ~ newline; 172 } else { 173 exp ~= " return returnVoid();" ~ newline; 174 } 175 exp ~= " } catch (Exception __ex__) {" ~ newline; 176 if (!is(returnType == void)) { 177 exp ~= " return returnValue!(" ~ returnTypeStr ~ ")(__ex__);" ~ newline; 178 } else { 179 exp ~= " return returnVoid(__ex__);" ~ newline; 180 } 181 exp ~= " }" ~ newline; 182 exp ~= "}" ~ newline; 183 ret ~= exp; 184 } 185 } 186 } 187 } 188 189 return ret; 190 } 191 192 private string generateFields(T)() { 193 import autowrap.csharp.common : getDLangInterfaceName; 194 import std.traits : fullyQualifiedName, Fields, FieldNameTuple; 195 196 string ret = string.init; 197 alias fqn = fullyQualifiedName!T; 198 if (is(T == class) || is(T == interface)) { 199 alias fieldTypes = Fields!T; 200 alias fieldNames = FieldNameTuple!T; 201 static foreach(fc; 0..fieldTypes.length) { 202 static if (is(typeof(__traits(getMember, T, fieldNames[fc])))) { 203 ret ~= "extern(C) export returnValue!(" ~ fullyQualifiedName!(fieldTypes[fc]) ~ ") " ~ getDLangInterfaceName(fqn, fieldNames[fc] ~ "_get") ~ "(" ~ fqn ~ " __obj__) nothrow {" ~ newline; 204 ret ~= generateMethodErrorHandling(" return returnValue!(" ~ fullyQualifiedName!(fieldTypes[fc]) ~ ")(__obj__." ~ fieldNames[fc] ~ ");", "returnValue!(" ~ fullyQualifiedName!(fieldTypes[fc]) ~ ")"); 205 ret ~= "}" ~ newline; 206 ret ~= "extern(C) export returnVoid " ~ getDLangInterfaceName(fqn, fieldNames[fc] ~ "_set") ~ "(" ~ fqn ~ " __obj__, " ~ fullyQualifiedName!(fieldTypes[fc]) ~ " value) nothrow {" ~ newline; 207 ret ~= generateMethodErrorHandling(" __obj__." ~ fieldNames[fc] ~ " = value;" ~ newline ~ " return returnVoid();", "returnVoid"); 208 ret ~= "}" ~ newline; 209 } 210 } 211 } 212 return ret; 213 } 214 215 private string generateFunctions(Modules...)() if(allSatisfy!(isModule, Modules)) { 216 import autowrap.csharp.common : getDLangInterfaceName; 217 import autowrap.reflection: AllFunctions; 218 import std.traits : fullyQualifiedName, hasMember, functionAttributes, FunctionAttribute, ReturnType, Parameters, ParameterIdentifierTuple; 219 220 string ret = string.init; 221 foreach(func; AllFunctions!Modules) { 222 alias modName = func.moduleName; 223 alias funcName = func.name; 224 225 alias returnType = ReturnType!(__traits(getMember, func.module_, func.name)); 226 alias returnTypeStr = fullyQualifiedName!(ReturnType!(__traits(getMember, func.module_, func.name))); 227 alias paramTypes = Parameters!(__traits(getMember, func.module_, func.name)); 228 alias paramNames = ParameterIdentifierTuple!(__traits(getMember, func.module_, func.name)); 229 const string interfaceName = getDLangInterfaceName(modName, null, funcName); 230 string retType = string.init; 231 string funcStr = "extern(C) export "; 232 233 if (!is(returnType == void)) { 234 retType = retType ~ "returnValue!(" ~ returnTypeStr ~ ")"; 235 } else { 236 retType = retType ~ "returnVoid"; 237 } 238 239 funcStr ~= retType ~ " " ~ interfaceName ~ "("; 240 static foreach(pc; 0..paramNames.length) { 241 funcStr ~= fullyQualifiedName!(paramTypes[pc]) ~ " " ~ paramNames[pc] ~ ", "; 242 } 243 if(paramNames.length > 0) { 244 funcStr = funcStr[0..$-2]; 245 } 246 funcStr ~= ") nothrow {" ~ newline; 247 funcStr ~= " try {" ~ newline; 248 funcStr ~= methodSetup ~ newline; 249 if (!is(returnType == void)) { 250 funcStr ~= " return " ~ retType ~ "(" ~ func.name ~ "("; 251 foreach(pName; paramNames) { 252 funcStr ~= pName ~ ", "; 253 } 254 if(paramNames.length > 0) { 255 funcStr = funcStr[0..$-2]; 256 } 257 funcStr ~= "));" ~ newline; 258 } else { 259 funcStr ~= func.name ~ "("; 260 static foreach(pc; 0..paramNames.length) { 261 funcStr ~= paramNames[pc] ~ ", "; 262 } 263 if(paramNames.length > 0) { 264 funcStr = funcStr[0..$-2]; 265 } 266 funcStr ~= ");" ~ newline; 267 funcStr ~= " return returnVoid();" ~ newline; 268 } 269 funcStr ~= " } catch (Exception __ex__) {" ~ newline; 270 funcStr ~= " return " ~ retType ~ "(__ex__);" ~ newline; 271 funcStr ~= " }" ~ newline; 272 funcStr ~= "}" ~ newline; 273 274 ret ~= funcStr; 275 } 276 277 return ret; 278 } 279 280 private string generateSliceMethods(T)() { 281 import autowrap.csharp.common : getDLangSliceInterfaceName; 282 import std.traits : fullyQualifiedName; 283 string ret = string.init; 284 alias fqn = fullyQualifiedName!T; 285 286 //Generate slice creation method 287 ret ~= "extern(C) export returnValue!(" ~ fqn ~ "[]) " ~ getDLangSliceInterfaceName(fqn, "Create") ~ "(size_t capacity) nothrow {" ~ newline; 288 ret ~= generateMethodErrorHandling(" " ~ fqn ~ "[] __temp__; 289 __temp__.reserve(capacity); 290 pinPointer(cast(void*)__temp__.ptr); 291 return returnValue!(" ~ fqn ~ "[])(__temp__);", "returnValue!(" ~ fqn ~ "[])"); 292 ret ~= "}" ~ newline; 293 294 //Generate slice method 295 ret ~= "extern(C) export returnValue!(" ~ fqn ~ "[]) " ~ getDLangSliceInterfaceName(fqn, "Slice") ~ "(" ~ fqn ~ "[] slice, size_t begin, size_t end) nothrow {" ~ newline; 296 ret ~= generateMethodErrorHandling(" " ~ fqn ~ "[] __temp__ = slice[begin..end]; 297 pinPointer(cast(void*)__temp__.ptr); 298 return returnValue!(" ~ fqn ~ "[])(__temp__);", "returnValue!(" ~ fqn ~ "[])"); 299 ret ~= "}" ~ newline; 300 301 //Generate get method 302 ret ~= "extern(C) export returnValue!(" ~ fqn ~ ") " ~ getDLangSliceInterfaceName(fqn, "Get") ~ "(" ~ fqn ~ "[] slice, size_t index) nothrow {" ~ newline; 303 ret ~= generateMethodErrorHandling(" return returnValue!(" ~ fqn ~ ")(slice[index]);", "returnValue!(" ~ fqn ~ ")"); 304 ret ~= "}" ~ newline; 305 306 //Generate set method 307 ret ~= "extern(C) export returnVoid " ~ getDLangSliceInterfaceName(fqn, "Set") ~ "(" ~ fqn ~ "[] slice, size_t index, " ~ fqn ~ " set) nothrow {" ~ newline; 308 ret ~= generateMethodErrorHandling(" slice[index] = set;" ~ newline ~ " return returnVoid();", "returnVoid"); 309 ret ~= "}" ~ newline; 310 311 //Generate item append method 312 ret ~= "extern(C) export returnValue!(" ~ fqn ~ "[]) " ~ getDLangSliceInterfaceName(fqn, "AppendValue") ~ "(" ~ fqn ~ "[] slice, " ~ fqn ~ " append) nothrow {" ~ newline; 313 ret ~= generateMethodErrorHandling(" return returnValue!(" ~ fqn ~ "[])(slice ~= append);", "returnValue!(" ~ fqn ~ "[])"); 314 ret ~= "}" ~ newline; 315 316 //Generate slice append method 317 ret ~= "extern(C) export returnValue!(" ~ fqn ~ "[]) " ~ getDLangSliceInterfaceName(fqn, "AppendSlice") ~ "(" ~ fqn ~ "[] slice, " ~ fqn ~ "[] append) nothrow {" ~ newline; 318 ret ~= generateMethodErrorHandling(" return returnValue!(" ~ fqn ~ "[])(slice ~= append);", "returnValue!(" ~ fqn ~ "[])"); 319 ret ~= "}" ~ newline; 320 321 return ret; 322 } 323 324 private string generateMethodErrorHandling(string insideCode, string returnType) { 325 string ret = string.init; 326 ret ~= " try {" ~ newline; 327 ret ~= methodSetup ~ newline; 328 ret ~= insideCode ~ newline; 329 ret ~= " } catch (Exception __ex__) {" ~ newline; 330 ret ~= " return " ~ returnType ~ "(__ex__);" ~ newline; 331 ret ~= " }" ~ newline; 332 return ret; 333 }