1 /**************************************************************************** 2 ** 3 ** DQt - D bindings for the Qt Toolkit 4 ** 5 ** GNU Lesser General Public License Usage 6 ** This file may be used under the terms of the GNU Lesser 7 ** General Public License version 3 as published by the Free Software 8 ** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 ** packaging of this file. Please review the following information to 10 ** ensure the GNU Lesser General Public License version 3 requirements 11 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 ** 13 ****************************************************************************/ 14 module qt.helpers; 15 16 import std.traits; 17 import std.conv; 18 import std.array; 19 20 private string nextCodePart(string code) 21 { 22 size_t i; 23 char c = code[0]; 24 if(c == '"' || c == '\'') 25 { 26 char stringDelim = c; 27 i++; 28 while(i < code.length && code[i] != stringDelim) 29 { 30 if(code[i] == '\\') 31 i++; 32 i++; 33 } 34 } 35 else if(c == '/' && i + 1 < code.length && code[i + 1] == '/') 36 { 37 i++; 38 i++; 39 while(i < code.length && code[i] != '\n') 40 i++; 41 } 42 else if(c == '/' && i + 1 < code.length && code[i + 1] == '*') 43 { 44 i++; 45 i++; 46 while(i < code.length) 47 { 48 if(i + 1 < code.length && code[i] == '*' && code[i+1] == '/') 49 { 50 i++; 51 break; 52 } 53 i++; 54 } 55 } 56 else if(c == '/' && i + 1 < code.length && code[i + 1] == '+') 57 { 58 i++; 59 i++; 60 size_t nesting = 1; 61 while(i < code.length && nesting) 62 { 63 if(i + 1 < code.length && code[i] == '+' && code[i+1] == '/') 64 { 65 nesting--; 66 i++; 67 if(nesting == 0) 68 break; 69 } 70 else if(i + 1 < code.length && code[i] == '/' && code[i+1] == '+') 71 { 72 nesting++; 73 i++; 74 } 75 i++; 76 } 77 } 78 i++; 79 return code[0..i]; 80 } 81 82 string interpolateMixin(string code) 83 { 84 string r = "\""; 85 for(size_t i=0; i<code.length;) 86 { 87 string part = nextCodePart(code[i..$]); 88 if(i < code.length + 1 && code[i] == '$' && code[i+1] == '(') 89 { 90 r ~= "\" ~ "; 91 i += 2; 92 size_t numParens = 1; 93 while(i < code.length) 94 { 95 if(i + 1 < code.length && code[i] == 'q' && code[i+1] == '{') 96 { 97 i += 2; 98 size_t start = i; 99 size_t numBraces = 1; 100 while(i < code.length) 101 { 102 string part2 = nextCodePart(code[i..$]); 103 if(code[i] == '{') 104 numBraces++; 105 else if(code[i] == '}') 106 { 107 numBraces--; 108 if(numBraces == 0) 109 { 110 r ~= interpolateMixin(code[start..i]); 111 i++; 112 break; 113 } 114 } 115 i += part2.length; 116 } 117 continue; 118 } 119 if(code[i] == ')') 120 { 121 numParens--; 122 if(numParens == 0) 123 { 124 i++; 125 break; 126 } 127 } 128 else if(code[i] == '(') 129 numParens++; 130 string part2 = nextCodePart(code[i..$]); 131 r ~= part2; 132 i += part2.length; 133 } 134 r ~= " ~ \""; 135 continue; 136 } 137 else 138 { 139 foreach(char c; part) 140 { 141 if(c == '\\') 142 r ~= "\\\\"; 143 else if(c == '"') 144 r ~= "\\\""; 145 else 146 r ~= c; 147 } 148 } 149 i += part.length; 150 } 151 r ~= "\""; 152 return r; 153 } 154 155 string stringifyMacroParameter(string s) 156 { 157 string r = "\""; 158 bool hasWS; 159 for(size_t i=0; i<s.length;) 160 { 161 string part = nextCodePart(s[i..$]); 162 if(part[0] == ' ' || part[0] == '\t' || part[0] == '\r' || part[0] == '\n' 163 || (part.length >= 2 && part[0] == '/' && (part[1] == '/' || part[1] == '*'))) 164 hasWS = true; 165 else 166 { 167 if(r.length > 1 && hasWS) 168 r ~= " "; 169 hasWS = false; 170 foreach(char c; part) 171 { 172 if(c == '\"') 173 r ~= "\\\""; 174 else if(c == '\\') 175 r ~= "\\\\"; 176 else 177 r ~= c; 178 } 179 } 180 i += part.length; 181 } 182 r ~= "\""; 183 return r; 184 } 185 186 template ExternCFunc(F)// if(is(F == function)) 187 { 188 static if(variadicFunctionStyle!F == Variadic.c) 189 alias ExternCFunc = extern(C) ReturnType!F function(ParameterTypeTuple!F, ...); 190 else 191 alias ExternCFunc = extern(C) ReturnType!F function(ParameterTypeTuple!F); 192 } 193 194 template ExternCPPFunc(F)// if(is(F == function)) 195 { 196 static if(variadicFunctionStyle!F == Variadic.c) 197 alias ExternCPPFunc = extern(C++) ReturnType!F function(ParameterTypeTuple!F, ...); 198 else 199 alias ExternCPPFunc = extern(C++) ReturnType!F function(ParameterTypeTuple!F); 200 } 201 202 T static_cast(T, S)(S x) 203 { 204 static if(isCallable!T && isCallable!S) 205 { 206 static assert(functionLinkage!T == functionLinkage!S); 207 } 208 return cast(T)x; 209 } 210 211 T reinterpret_cast(T, S)(S x) 212 { 213 return cast(T)x; 214 } 215 216 T const_cast(T, S)(S x) 217 { 218 return cast(T)x; 219 } 220 221 private template globalInitVarImpl(T) 222 { 223 immutable __gshared T globalInitVar = immutable(T).init; 224 shared static this() 225 { 226 (*cast(T*)&globalInitVar).rawConstructor; 227 } 228 } 229 230 template globalInitVar(T) 231 { 232 static if(__traits(hasMember, T, "rawConstructor")) 233 { 234 version(Windows) 235 alias globalInitVar = globalInitVarImpl!T.globalInitVar; 236 else 237 static assert(0, "globalInitVar!"~T.stringof~" needs complex construction"); 238 } 239 else static if(__traits(compiles, {T x;})) 240 immutable __gshared T globalInitVar/* = immutable(T).init*/; 241 else 242 static assert(false, T.stringof); 243 } 244 245 alias defaultConstructorMangling = function string(string name) 246 { 247 version(Windows) 248 static if(size_t.sizeof == 8) 249 return "??0" ~ name ~ "@@QEAA@XZ"; 250 else 251 return "??0" ~ name ~ "@@QAE@XZ"; 252 else 253 return text("_ZN", name.length, name, "C1Ev"); 254 }; 255 256 alias mangleWindows = function string(string mangling, string code) 257 { 258 version(Windows) 259 static if(size_t.sizeof == 8) 260 return "pragma(mangle, \"" ~ mangling ~ "\") " ~ code; 261 else 262 return "pragma(mangle, \"" 263 ~ mangling.replace("@@QEBAKPE", "@@QBEKP") 264 .replace("@@QEBAJPE", "@@QBEJP") 265 .replace("@@QEBAHPE", "@@QBEHP") 266 .replace("@@QEBAPEB", "@@QBEPB") 267 .replace("@@MEAA_NPE", "@@MAE_NP") 268 .replace("@@MEAA_NHHPE", "@@MAE_NHHP") 269 .replace("@@MEAA_NHPE", "@@MAE_NHP") 270 .replace("@@UEAA_NAE", "@@UAE_NA") 271 .replace("@@MEBA_NPE", "@@MBE_NP") 272 .replace("@@UEAAXPEA", "@@UAEXPA") 273 .replace("@@MEAAXPE", "@@MAEXP") 274 .replace("@@UEAA_NPE", "@@UAE_NP") 275 .replace("@@UEAA", "@@UAE") 276 .replace("@@QEBA", "@@QBE") 277 .replace("@@MEBA", "@@MBE") 278 .replace("@@0PEAV1@EA", "@@0PAV1@A") 279 .replace("@@PEBV1@PEAPEAX01PE", "@@PBV1@PAPAX01P") 280 .replace("@@PEBHPE", "@@PBHP") 281 .replace("@@MEAA_NAE", "@@MAE_NA") 282 .replace("@@MEAA", "@@MAE") 283 .replace("@@PEAXPE", "@@PAXP") 284 .replace("@@UEBA_NPE", "@@UBE_NP") 285 .replace("@@UEBA", "@@UBE") 286 .replace("@@AEBV", "@@ABV") 287 .replace("@@HPE", "@@HP") 288 .replace("@@EEAAXPE", "@@EAEXP") 289 .replace("@@PE", "@@P") 290 .replace("@@HHAE", "@@HHA") 291 ~ "\") " ~ code; 292 else 293 return code; 294 }; 295 296 alias mangleOpLess = function string(string name) 297 { 298 version(Windows) 299 static if(size_t.sizeof == 8) 300 return "??M" ~ name ~ "@@UEBA_NAEBV0@@Z"; 301 else 302 return "??M" ~ name ~ "@@UBE_NABV0@@Z"; 303 else 304 return text("_ZNK", name.length, name, "ltERKS_"); 305 }; 306 307 // Workaround for https://issues.dlang.org/show_bug.cgi?id=19660, which can be removed later. 308 version(Windows) 309 enum exportOnWindows = " export "; 310 else 311 enum exportOnWindows = ""; 312 313 // TODO: can be removed when a released dmd contains imported. 314 static if(!__traits(compiles, imported)) 315 template imported(string moduleName) 316 { 317 mixin("import imported = " ~ moduleName ~ ";"); 318 }