| 1 |
module tools.cpp; |
|---|
| 2 |
|
|---|
| 3 |
import tools.base; |
|---|
| 4 |
|
|---|
| 5 |
alias tools.base.Ret Ret; |
|---|
| 6 |
alias tools.base.Params Params; |
|---|
| 7 |
|
|---|
| 8 |
private template Select(alias Cond, T...) { |
|---|
| 9 |
static if (!T.length) alias Tuple!() Select; |
|---|
| 10 |
else static if (Cond!(T[0])) alias Tuple!(T[0], Select!(Cond, T[1..$])) Select; |
|---|
| 11 |
else alias Select!(Cond, T[1..$]) Select; |
|---|
| 12 |
} |
|---|
| 13 |
|
|---|
| 14 |
private template SelectOne(alias Cond, T...) { |
|---|
| 15 |
static if (!T.length) static assert(false, "Cannot select via "~Cond.stringof); |
|---|
| 16 |
else static if (Cond!(T[0])) alias T[0] SelectOne; |
|---|
| 17 |
else alias SelectOne!(Cond, T[1..$]) SelectOne; |
|---|
| 18 |
} |
|---|
| 19 |
|
|---|
| 20 |
private template HasOne(alias Cond, T...) { |
|---|
| 21 |
static if (!T.length) const bool HasOne = false; |
|---|
| 22 |
else static if (Cond!(T[0])) const bool HasOne = true; |
|---|
| 23 |
else const bool HasOne = HasOne!(Cond, T[1..$]); |
|---|
| 24 |
} |
|---|
| 25 |
|
|---|
| 26 |
private template SelectOneParameterized(alias Cond, Param, T...) { |
|---|
| 27 |
static if (!T.length) static assert(false, "Cannot select one via "~Cond.stringof); |
|---|
| 28 |
else static if (Cond!(Param.Tuple, T[0])) alias T[0] SelectOneParameterized; |
|---|
| 29 |
else alias SelectOneParameterized!(Cond, Param, T[1..$]) SelectOneParameterized; |
|---|
| 30 |
} |
|---|
| 31 |
|
|---|
| 32 |
private template SelectIndexParameterized(alias Cond, Param, T...) { |
|---|
| 33 |
static if (!T.length) static assert(false, "Cannot select one via "~Cond.stringof); |
|---|
| 34 |
else static if (Cond!(Param.Tuple, T[0])) const int SelectIndexParameterized = 0; |
|---|
| 35 |
else const int SelectIndexParameterized = SelectIndexParameterized!(Cond, Param, T[1..$]) + 1; |
|---|
| 36 |
} |
|---|
| 37 |
|
|---|
| 38 |
private template HasOneParameterized(alias Cond, Param, T...) { |
|---|
| 39 |
static if (!T.length) const bool HasOneParameterized = false; |
|---|
| 40 |
else static if (Cond!(Param.Tuple, T[0])) const bool HasOneParameterized = true; |
|---|
| 41 |
else const bool HasOneParameterized = HasOneParameterized!(Cond, Param, T[1..$]); |
|---|
| 42 |
} |
|---|
| 43 |
|
|---|
| 44 |
static if (size_t.sizeof == 4) { |
|---|
| 45 |
alias int C_int; |
|---|
| 46 |
alias uint C_uint; |
|---|
| 47 |
alias int C_long; |
|---|
| 48 |
alias uint C_ulong; |
|---|
| 49 |
} else static if (size_t.sizeof == 8) { |
|---|
| 50 |
alias int C_int; |
|---|
| 51 |
alias uint C_uint; |
|---|
| 52 |
alias long C_long; |
|---|
| 53 |
alias ulong C_ulong; |
|---|
| 54 |
} |
|---|
| 55 |
|
|---|
| 56 |
template derefPointer(T: T*) { alias T derefPointer; } |
|---|
| 57 |
|
|---|
| 58 |
template isFunction(T) { |
|---|
| 59 |
const bool isFunction = is(Ref!(T)) && is(Params!(T)); |
|---|
| 60 |
} |
|---|
| 61 |
|
|---|
| 62 |
template TypeMatches(S, T) { const bool TypeMatches = is(S == T); } |
|---|
| 63 |
|
|---|
| 64 |
template CppMangle(Substs, T) { |
|---|
| 65 |
// only substitute "long" types |
|---|
| 66 |
static if ((is(typeof(T.Name): string) || isPointer!(T)) && HasOneParameterized!(TypeMatches, TW!(T), Substs.Tuple)) { |
|---|
| 67 |
// pragma(msg, "backref to ", T.stringof, " in ", Substs.stringof, " at ", ctToString(SelectIndexParameterized!(TypeMatches, TW!(T), Substs.Tuple))); |
|---|
| 68 |
/*static if (!SelectIndexParameterized!(TypeMatches, TW!(T), Substs.Tuple)) { |
|---|
| 69 |
const string CppMangle = "S_"; |
|---|
| 70 |
} else {*/ |
|---|
| 71 |
const string CppMangle = "S"~ctToString(SelectIndexParameterized!(TypeMatches, TW!(T), Substs.Tuple))~"_"; |
|---|
| 72 |
/*}*/ |
|---|
| 73 |
} |
|---|
| 74 |
else static if (is(T == void)) const string CppMangle = "v"; |
|---|
| 75 |
else static if (is(T == wchar)) const string CppMangle = "w"; |
|---|
| 76 |
else static if (is(T == bool)) const string CppMangle = "b"; |
|---|
| 77 |
else static if (is(T == char)) const string CppMangle = "c"; |
|---|
| 78 |
else static if (is(T == byte)) const string CppMangle = "a"; |
|---|
| 79 |
else static if (is(T == ubyte)) const string CppMangle = "h"; |
|---|
| 80 |
else static if (is(T == short)) const string CppMangle = "s"; |
|---|
| 81 |
else static if (is(T == ushort)) const string CppMangle = "t"; |
|---|
| 82 |
else static if (is(T == long)) const string CppMangle = "x"; |
|---|
| 83 |
else static if (is(T == ulong)) const string CppMangle = "y"; |
|---|
| 84 |
else static if (is(T == C_int)) const string CppMangle = "i"; |
|---|
| 85 |
else static if (is(T == C_uint)) const string CppMangle = "j"; |
|---|
| 86 |
else static if (is(T == C_long)) const string CppMangle = "l"; |
|---|
| 87 |
else static if (is(T == C_ulong)) const string CppMangle = "m"; |
|---|
| 88 |
else static if (is(T == float)) const string CppMangle = "f"; |
|---|
| 89 |
else static if (is(T == double)) const string CppMangle = "d"; |
|---|
| 90 |
else static if (is(T == real)) const string CppMangle = "e"; |
|---|
| 91 |
else static if (isPointer!(T)) const string CppMangle = "P" ~ CppMangle!(Substs, derefPointer!(T)); |
|---|
| 92 |
else static if (isFunction!(T)) const string CppMangle = |
|---|
| 93 |
"F" ~ CppMangle!(Substs, Ret!(T))~CppMangleParams!(Refs!(T), true, Params!(T)) ~ "E"; |
|---|
| 94 |
else static if (is(T.isConst)) { |
|---|
| 95 |
static if (is(typeof(T.Name): string)) |
|---|
| 96 |
const string CppMangle = "K"~ctToString(T.Name.length)~T.Name; |
|---|
| 97 |
else |
|---|
| 98 |
const string CppMangle = "K"~CppMangle!(Substs, typeof(T.value)); |
|---|
| 99 |
} else static if (is(typeof(T.Name) : string)) { |
|---|
| 100 |
const string CppMangle = ctToString(T.Name.length)~T.Name; |
|---|
| 101 |
} else { |
|---|
| 102 |
pragma(msg, "Type "~T.stringof~" unmangled. "); |
|---|
| 103 |
const string CppMangle = "unknown"; |
|---|
| 104 |
} |
|---|
| 105 |
} |
|---|
| 106 |
|
|---|
| 107 |
// I shall do science to it! |
|---|
| 108 |
template DoScience(T, char Ref) { |
|---|
| 109 |
static if (isPointer!(T) && !is(derefPointer!(T) == void)) |
|---|
| 110 |
alias Tuple!(DoScience!(derefPointer!(T), Ref), T) DoScience; |
|---|
| 111 |
else static if (is(T.isConst)) |
|---|
| 112 |
alias Tuple!(T.Type, Repeat!(Filler, Ref == 't'), T) DoScience; |
|---|
| 113 |
else |
|---|
| 114 |
alias Tuple!(Repeat!(Filler, Ref == 't'), T) DoScience; |
|---|
| 115 |
} |
|---|
| 116 |
|
|---|
| 117 |
template CppMangleParams(string Refs, bool First, Substs, T...) { |
|---|
| 118 |
static if (!T.length) const string CppMangleParams = First?"v":""; |
|---|
| 119 |
else static if (CppMangle!(Substs, T[0])[0] == 'S') |
|---|
| 120 |
const string CppMangleParams = |
|---|
| 121 |
CppMangle!(Substs, T[0]) ~ |
|---|
| 122 |
CppMangleParams!(Refs[1 .. $], false, TW!(Substs.Tuple, DoScience!(T[0], Refs[0])), T[1 .. $]); |
|---|
| 123 |
else |
|---|
| 124 |
const string CppMangleParams = |
|---|
| 125 |
(Refs[0]=='t'?"R":"") ~ |
|---|
| 126 |
CppMangle!(Substs, T[0]) ~ |
|---|
| 127 |
CppMangleParams!(Refs[1 .. $], false, TW!(Substs.Tuple, DoScience!(T[0], Refs[0])), T[1 .. $]); |
|---|
| 128 |
} |
|---|
| 129 |
|
|---|
| 130 |
struct Filler { } // manually pad the substitution cache |
|---|
| 131 |
|
|---|
| 132 |
template FunMangle(string Name, T) { |
|---|
| 133 |
static if (Name.length > 4 && Name[0 .. 4] == "this") { |
|---|
| 134 |
const string FunMangle = "C"~Name[4 .. $] |
|---|
| 135 |
~"E"~CppMangleParams!(isRef!(T)[1..$], true, TW!(), Params!(T)[1..$]); |
|---|
| 136 |
} else { |
|---|
| 137 |
const string FunMangle = |
|---|
| 138 |
ctToString(Name.length)~Name |
|---|
| 139 |
// skip 'this' pointer |
|---|
| 140 |
~"E"~CppMangleParams!(isRef!(T)[1..$], true, TW!(), Params!(T)[1..$]); |
|---|
| 141 |
} |
|---|
| 142 |
} |
|---|
| 143 |
|
|---|
| 144 |
alias TupleWrapper TW; |
|---|
| 145 |
|
|---|
| 146 |
// bind to the G++ ABI |
|---|
| 147 |
|
|---|
| 148 |
struct VirtualMethod(alias _Fn, string _Name) { |
|---|
| 149 |
alias _Fn Fn; |
|---|
| 150 |
const value = &Fn; |
|---|
| 151 |
const string Name = _Name; |
|---|
| 152 |
alias void isVirtual; |
|---|
| 153 |
alias void isMethod; |
|---|
| 154 |
} |
|---|
| 155 |
|
|---|
| 156 |
Ret!(T) abstr(T, string Name)(Params!(T) params) { |
|---|
| 157 |
throw new Exception(Name~" not implemented! "); |
|---|
| 158 |
} |
|---|
| 159 |
|
|---|
| 160 |
struct AbstractMethod(T, string _Name) { |
|---|
| 161 |
alias abstr!(T, _Name) Fn; |
|---|
| 162 |
const value = &Fn; |
|---|
| 163 |
const string Name = _Name; |
|---|
| 164 |
alias void isVirtual; |
|---|
| 165 |
} |
|---|
| 166 |
|
|---|
| 167 |
struct Method(alias _Fn, string _Name) { |
|---|
| 168 |
alias _Fn Fn; |
|---|
| 169 |
const value = &Fn; |
|---|
| 170 |
alias typeof(value) Type; |
|---|
| 171 |
const string Name = _Name; |
|---|
| 172 |
alias void isMethod; |
|---|
| 173 |
} |
|---|
| 174 |
|
|---|
| 175 |
template thunkcall(int D, alias Sup) { |
|---|
| 176 |
mixin(`Ret!(typeof(&Sup)) |
|---|
| 177 |
call(`~refToParamList("Params!(typeof(&Sup))", isRef!(typeof(&Sup)))~`) { |
|---|
| 178 |
param_0 = cast(typeof(param_0)) (cast(void*) param_0 - D); |
|---|
| 179 |
return Sup(`~refToValueList(isRef!(typeof(&Sup)))~`); |
|---|
| 180 |
}`); |
|---|
| 181 |
} |
|---|
| 182 |
|
|---|
| 183 |
struct ThunkedMethod(alias _Fn, int Offs, string _Name) { |
|---|
| 184 |
alias thunkcall!(Offs, _Fn).call Fn; |
|---|
| 185 |
const value = &Fn; |
|---|
| 186 |
const string Name = _Name; |
|---|
| 187 |
mixin(`const string Mangle="`~Name~`_`~ctToString(Offs)~`_?"; `); |
|---|
| 188 |
alias void isMethod; |
|---|
| 189 |
} |
|---|
| 190 |
|
|---|
| 191 |
struct Member(T, string _Name, string _Init = "") { |
|---|
| 192 |
const string Name = _Name; |
|---|
| 193 |
const string Init = _Init; |
|---|
| 194 |
static T value; // bogus to work around a gdc bug |
|---|
| 195 |
alias T Type; |
|---|
| 196 |
alias void isMember; |
|---|
| 197 |
} |
|---|
| 198 |
|
|---|
| 199 |
template MemberVars(T...) { |
|---|
| 200 |
static if (T.length) { |
|---|
| 201 |
static if (T[0].Init.length) |
|---|
| 202 |
mixin("typeof(T[0].value) "~T[0].Name~" = "~T[0].Init~"; "); |
|---|
| 203 |
else mixin("typeof(T[0].value) "~T[0].Name~"; "); |
|---|
| 204 |
// yes the extra check is necessary |
|---|
| 205 |
// no don't ask me why |
|---|
| 206 |
static if (T.length > 1) mixin MemberVars!(T[1..$]); |
|---|
| 207 |
} |
|---|
| 208 |
} |
|---|
| 209 |
|
|---|
| 210 |
template isVirtual(T) { const bool isVirtual = is(T.isVirtual); } |
|---|
| 211 |
template isMethod(T) { const bool isMethod = is(T.isMethod); } |
|---|
| 212 |
template isMethodNotVirtual(T) { const bool isMethodNotVirtual = isMethod!(T) && !isVirtual!(T); } |
|---|
| 213 |
template isMember(T) { const bool isMember = is(T.isMember); } |
|---|
| 214 |
template isClass(T) { const bool isClass = is(T.ClassMarker); } |
|---|
| 215 |
template isVirtualClass(T) { const bool isVirtualClass = isClass!(T) && is(typeof(T.vtable)); } |
|---|
| 216 |
// T is in some way related to vtables |
|---|
| 217 |
template stuffVTable(T) { const bool stuffVTable = isVirtual!(T) || isVirtualClass!(T); } |
|---|
| 218 |
|
|---|
| 219 |
template isName(string S, T) { |
|---|
| 220 |
static if (is(T.CppClass)) const bool isName = false; |
|---|
| 221 |
else const bool isName = T.Name == S; |
|---|
| 222 |
} |
|---|
| 223 |
|
|---|
| 224 |
import tools.ctfe; |
|---|
| 225 |
string vtableGen(int len, bool type) { |
|---|
| 226 |
string res = ""; |
|---|
| 227 |
for (int i = 0; i < len; ++i) { |
|---|
| 228 |
|
|---|
| 229 |
if (type) res ~= ` |
|---|
| 230 |
static if (is(typeof(Virtuals[!!].isClassInfo))) { |
|---|
| 231 |
mixin("typeof(Virtuals[!!].value) classinfo_" ~ Virtuals[!!].Name ~ "; "); |
|---|
| 232 |
// pragma(msg, "!! typeof(Virtuals[!!].value) classinfo_" ~ Virtuals[!!].Name ~ "; "); |
|---|
| 233 |
} else { |
|---|
| 234 |
mixin("typeof(Virtuals[!!].value) " ~ Virtuals[!!].Name ~ "_!!; "); |
|---|
| 235 |
// pragma(msg, "!! typeof(Virtuals[!!].value) " ~ Virtuals[!!].Name ~ "_!!; "); |
|---|
| 236 |
} |
|---|
| 237 |
// static if (is(typeof(Virtuals[!!].Fn))) pragma(msg, "being ", Virtuals[!!].value.stringof); |
|---|
| 238 |
`.ctReplace("!!", ctToString(i)); |
|---|
| 239 |
else { |
|---|
| 240 |
if (res.length) res ~= ", "; |
|---|
| 241 |
res ~= "Virtuals[!].value".ctReplace("!", ctToString(i)); |
|---|
| 242 |
} |
|---|
| 243 |
} |
|---|
| 244 |
if (type) return res; |
|---|
| 245 |
else return "{"~res~"}"; |
|---|
| 246 |
} |
|---|
| 247 |
|
|---|
| 248 |
struct VTableType(Virtuals...) { |
|---|
| 249 |
// pragma(msg, "VTableType: ", vtableGen(Virtuals.length, true), " for ", Virtuals.stringof); |
|---|
| 250 |
mixin(vtableGen(Virtuals.length, true)); |
|---|
| 251 |
} |
|---|
| 252 |
|
|---|
| 253 |
template VTableData(Virtuals...) { |
|---|
| 254 |
mixin("VTableType!(Virtuals) data = "~vtableGen(Virtuals.length, false)~"; "); |
|---|
| 255 |
} |
|---|
| 256 |
|
|---|
| 257 |
string effs(int i) { |
|---|
| 258 |
string res; |
|---|
| 259 |
while (i--) |
|---|
| 260 |
res ~= 'f'; |
|---|
| 261 |
return res; |
|---|
| 262 |
} |
|---|
| 263 |
|
|---|
| 264 |
string enable(int id, string s) { |
|---|
| 265 |
s[id] = 't'; |
|---|
| 266 |
return s; |
|---|
| 267 |
} |
|---|
| 268 |
|
|---|
| 269 |
string unify(string s, string t) { |
|---|
| 270 |
assert(s.length == t.length); |
|---|
| 271 |
for (int i = 0; i < s.length; ++i) { |
|---|
| 272 |
if (t[i] == 't') |
|---|
| 273 |
s[i] = 't'; |
|---|
| 274 |
} |
|---|
| 275 |
return s; |
|---|
| 276 |
} |
|---|
| 277 |
|
|---|
| 278 |
template UpdateWithThunks(int Offset, VTable, Members...) { |
|---|
| 279 |
// pragma(msg, "UWT: members ", Members.stringof, " to fix up vtable ", VTable.stringof); |
|---|
| 280 |
static if (!VTable.Tuple.length) { |
|---|
| 281 |
alias Tuple!() thunks; |
|---|
| 282 |
const string mask = effs(Members.length); |
|---|
| 283 |
} else { |
|---|
| 284 |
static if (HasOneParameterized!(isName, TW!(VTable.Tuple[0].Name), Members)) { |
|---|
| 285 |
alias Tuple!(ThunkedMethod!( |
|---|
| 286 |
SelectOneParameterized!(isName, TW!(VTable.Tuple[0].Name), Members).Fn, |
|---|
| 287 |
Offset, |
|---|
| 288 |
VTable.Tuple[0].Name |
|---|
| 289 |
), UpdateWithThunks!(Offset, TW!(Tuple!(VTable.Tuple)[1 .. $]), Members).thunks) thunks; |
|---|
| 290 |
const string mask = enable( |
|---|
| 291 |
SelectIndexParameterized!(isName, TW!(VTable.Tuple[0].Name), Members), |
|---|
| 292 |
UpdateWithThunks!(Offset, TW!(Tuple!(VTable.Tuple)[1 .. $]), Members).mask |
|---|
| 293 |
); |
|---|
| 294 |
} else { |
|---|
| 295 |
alias Tuple!( |
|---|
| 296 |
Tuple!(VTable.Tuple[0])[0], |
|---|
| 297 |
Tuple!(UpdateWithThunks!(Offset, TW!(Tuple!(VTable.Tuple)[1 .. $]), Members).thunks) |
|---|
| 298 |
) thunks; |
|---|
| 299 |
const string mask = UpdateWithThunks!(Offset, TW!(Tuple!(VTable.Tuple)[1 .. $]), Members).mask; |
|---|
| 300 |
} |
|---|
| 301 |
} |
|---|
| 302 |
} |
|---|
| 303 |
|
|---|
| 304 |
struct SuppressClassinfo { alias void suppressClassinfo; } |
|---|
| 305 |
template isSuppr(T) { const bool isSuppr = is(T.suppressClassinfo); } |
|---|
| 306 |
|
|---|
| 307 |
template useClassinfo(T...) { const bool useClassinfo = !Select!(isSuppr, T).length; } |
|---|
| 308 |
|
|---|
| 309 |
struct Classinfo(string _Name) { |
|---|
| 310 |
const string Name = _Name; |
|---|
| 311 |
alias void* Type; |
|---|
| 312 |
const void* value = null; |
|---|
| 313 |
const isClassInfo = true; |
|---|
| 314 |
} |
|---|
| 315 |
|
|---|
| 316 |
// fill in virtuals with thunk |
|---|
| 317 |
template FixSuperClass(Class, int Offset, int TableOffset, VTable, Members...) { |
|---|
| 318 |
static assert(TableOffset != -1); |
|---|
| 319 |
alias Class.Virtuals Virtuals; |
|---|
| 320 |
// pragma(msg, "FixSuperClass(", Class.Name, "; vtable ", VTable.stringof, " at offset ", TableOffset.stringof, ")"); |
|---|
| 321 |
static if (Class.hasVTable) { |
|---|
| 322 |
mixin(`void* vtable_`~Class.Name~` = |
|---|
| 323 |
cast(void*) &VTableData!(VTable.Tuple).data.classinfo_`~Class.Name~` + 4; |
|---|
| 324 |
alias typeof(VTableData!(VTable.Tuple).data) VTable_`~Class.Name~`; |
|---|
| 325 |
`); |
|---|
| 326 |
} |
|---|
| 327 |
mixin CppClassMembers!( |
|---|
| 328 |
Class.hasVTable * 4 + Offset, |
|---|
| 329 |
Class.hasClassinfo * 4 + TableOffset, |
|---|
| 330 |
TW!(Class.Members), |
|---|
| 331 |
TW!(Members), |
|---|
| 332 |
VTable |
|---|
| 333 |
); |
|---|
| 334 |
mixin(`Class* cast_`~Class.Name~`() { return cast(Class*) (cast(void*) this + `~ctToString(Offset)~`); } `); |
|---|
| 335 |
mixin(`const offset_`~Class.Name~` = `~ctToString(Offset)~`; `); |
|---|
| 336 |
static if (Class.hasClassinfo) |
|---|
| 337 |
mixin(`static void fixup_classinfo_`~Class.Name~`(void* p) { |
|---|
| 338 |
VTableData!(VTable.Tuple).data.classinfo_`~Class.Name~` = p; |
|---|
| 339 |
}`); |
|---|
| 340 |
// pragma(msg, `Class* cast_`~Class.Name~`() { return cast(Class*) (cast(void*) this + `~ctToString(Offset)~`); } `); |
|---|
| 341 |
} |
|---|
| 342 |
|
|---|
| 343 |
struct Str(alias A, P...) { |
|---|
| 344 |
mixin A!(P); |
|---|
| 345 |
} |
|---|
| 346 |
|
|---|
| 347 |
template Size(alias A, P...) { |
|---|
| 348 |
const int Size = Init!(Str!(A, P)).sizeof; |
|---|
| 349 |
} |
|---|
| 350 |
|
|---|
| 351 |
template SuperClasses(Members, int DataOffs, int TableOffs, VTable, Classes...) { |
|---|
| 352 |
static if (Classes.length) { |
|---|
| 353 |
mixin FixSuperClass!(Classes[0], DataOffs, TableOffs, VTable, Members.Tuple); |
|---|
| 354 |
mixin SuperClasses!( |
|---|
| 355 |
Members, |
|---|
| 356 |
DataOffs + Size!(FixSuperClass, Classes[0], DataOffs, TableOffs, VTable, Members.Tuple), |
|---|
| 357 |
TableOffs + Classes[0].FixedVTable.length * 4 + Classes[0].hasClassinfo * 4, |
|---|
| 358 |
VTable, Classes[1 ..$] |
|---|
| 359 |
); |
|---|
| 360 |
} |
|---|
| 361 |
} |
|---|
| 362 |
|
|---|
| 363 |
template CppClassMembers(int DataOffs, int VTableOffs, UsedMembers, AllMembers, VTable) { |
|---|
| 364 |
mixin SuperClasses!(UsedMembers, DataOffs, VTableOffs, VTable, Select!(isClass, UsedMembers.Tuple)); |
|---|
| 365 |
mixin MemberVars!(Select!(isMember, UsedMembers.Tuple)); |
|---|
| 366 |
} |
|---|
| 367 |
|
|---|
| 368 |
template DeepSuperNames(Members...) { |
|---|
| 369 |
static if (!Members.length) const string DeepSuperNames = ""; |
|---|
| 370 |
else { |
|---|
| 371 |
static if (isClass!(Tuple!(Members)[0])) { |
|---|
| 372 |
static if (is(typeof(Tuple!(Members)[0].vtable))) |
|---|
| 373 |
const string DeepSuperNames = |
|---|
| 374 |
Members[0].Name |
|---|
| 375 |
~","~DeepSuperNames!(Tuple!(Members)[0].Members) |
|---|
| 376 |
~","~DeepSuperNames!(Tuple!(Members)[1 .. $]); |
|---|
| 377 |
else |
|---|
| 378 |
const string DeepSuperNames = |
|---|
| 379 |
DeepSuperNames!(Tuple!(Members)[0].Members) |
|---|
| 380 |
~","~DeepSuperNames!(Tuple!(Members)[1 .. $]); |
|---|
| 381 |
} else const string DeepSuperNames = DeepSuperNames!(Tuple!(Members)[1 .. $]); |
|---|
| 382 |
} |
|---|
| 383 |
} |
|---|
| 384 |
|
|---|
| 385 |
template FirstClass(Members...) { |
|---|
| 386 |
static if (!Members.length) alias Tuple!() FirstClass; |
|---|
| 387 |
else static if (isClass!(Tuple!(Members)[0])) { |
|---|
| 388 |
static if (FirstClass!(Members[0].Members).length) alias FirstClass!(Members[0].Members) FirstClass; |
|---|
| 389 |
else alias Tuple!(Members[0]) FirstClass; |
|---|
| 390 |
} else alias FirstClass!(Members[1 .. $]) FirstClass; |
|---|
| 391 |
} |
|---|
| 392 |
|
|---|
| 393 |
string gen_fixups(string basename, string param, string bases) { |
|---|
| 394 |
string res = ""; |
|---|
| 395 |
while (bases.length) { |
|---|
| 396 |
auto base = bases.ctSlice(","); |
|---|
| 397 |
if (!base.length) continue; |
|---|
| 398 |
res ~= "static if (is(typeof(&"~basename~"_"~base~"))) |
|---|
| 399 |
"~basename~"_"~base~"("~param~"); "; |
|---|
| 400 |
} |
|---|
| 401 |
return res; |
|---|
| 402 |
} |
|---|
| 403 |
|
|---|
| 404 |
template CombineUpdateVTables(Members, int Offset, Classes...) { |
|---|
| 405 |
static if (!Classes.length) { |
|---|
| 406 |
alias Tuple!() table; |
|---|
| 407 |
const string mask = effs(Members.Tuple.length); |
|---|
| 408 |
} else { |
|---|
| 409 |
// pragma(msg, "[] ", Offset.stringof, ", ", Classes[0].Name, ", ", Classes[0].FixedVTable.stringof); |
|---|
| 410 |
alias Tuple!( |
|---|
| 411 |
UpdateWithThunks!(Offset, TW!(Classes[0].FixedVTable), Members.Tuple).thunks, |
|---|
| 412 |
CombineUpdateVTables!(Members, Offset + Classes[0].sizeof, Classes[1 .. $]).table |
|---|
| 413 |
) table; |
|---|
| 414 |
const string mask = unify( |
|---|
| 415 |
UpdateWithThunks!(Offset, TW!(Classes[0].FixedVTable), Members.Tuple).mask, |
|---|
| 416 |
CombineUpdateVTables!(Members, Offset + Classes[0].sizeof, Classes[1 .. $]).mask |
|---|
| 417 |
); |
|---|
| 418 |
} |
|---|
| 419 |
} |
|---|
| 420 |
|
|---|
| 421 |
template GenVirtualCalls(T, FixedVTable, int Offs) { |
|---|
| 422 |
static if (T.Tuple.length) { |
|---|
| 423 |
// pragma(msg, ":virtual:", T.Tuple[0].Name); |
|---|
| 424 |
static if (Params!(typeof(T.Tuple[0].value)).length > 1) { |
|---|
| 425 |
mixin(`Ret!(typeof(T.Tuple[0].value)) `~T.Tuple[0].Name~`(` |
|---|
| 426 |
~refToParamList(`Params!(typeof(T.Tuple[0].value))[1..$]`, isRef!(typeof(T.Tuple[0].value))[1..$])~`) { |
|---|
| 427 |
// the vtable member is omitted when it's present in a first superclass |
|---|
| 428 |
auto vtable = *cast(void**) this; |
|---|
| 429 |
auto vtd = cast(typeof(VTableData!(FixedVTable.Tuple).data)*) (vtable - 4); |
|---|
| 430 |
return vtd.`~T.Tuple[0].Name~`_`~ctToString(Offs)~`( |
|---|
| 431 |
this, `~refToValueList(isRef!(typeof(T.Tuple[0].value))[1..$])~` |
|---|
| 432 |
); |
|---|
| 433 |
}`); |
|---|
| 434 |
} else { |
|---|
| 435 |
mixin(`Ret!(typeof(T.Tuple[0].value)) `~T.Tuple[0].Name~`(` |
|---|
| 436 |
~refToParamList(`Params!(typeof(T.Tuple[0].value))[1..$]`, isRef!(typeof(T.Tuple[0].value))[1..$])~`) { |
|---|
| 437 |
auto vtable = *cast(void**) this; |
|---|
| 438 |
auto vtd = cast(typeof(VTableData!(FixedVTable.Tuple).data)*) (vtable - 4); |
|---|
| 439 |
return vtd.`~T.Tuple[0].Name~`_`~ctToString(Offs)~`(this); |
|---|
| 440 |
}`); |
|---|
| 441 |
} |
|---|
| 442 |
mixin GenVirtualCalls!(TW!(T.Tuple[1 .. $]), FixedVTable, Offs + 1); |
|---|
| 443 |
} |
|---|
| 444 |
} |
|---|
| 445 |
|
|---|
| 446 |
template GenLocalCalls(T...) { |
|---|
| 447 |
static if (T.length) { |
|---|
| 448 |
// pragma(msg, ":local:", T[0].Name); |
|---|
| 449 |
static if (Params!(typeof(T[0].value)).length > 1) { |
|---|
| 450 |
mixin(`Ret!(typeof(T[0].value)) `~T[0].Name~`(` |
|---|
| 451 |
~refToParamList(`Params!(typeof(T[0].value))[1..$]`, isRef!(typeof(T[0].value))[1..$])~`) { |
|---|
| 452 |
return T[0].Fn( |
|---|
| 453 |
this, `~refToValueList(isRef!(typeof(T[0].value))[1..$])~` |
|---|
| 454 |
); |
|---|
| 455 |
}`); |
|---|
| 456 |
} else { |
|---|
| 457 |
mixin(`Ret!(typeof(T[0].value)) `~T[0].Name~`(` |
|---|
| 458 |
~refToParamList(`Params!(typeof(T[0].value))[1..$]`, isRef!(typeof(T[0].value))[1..$])~`) { |
|---|
| 459 |
return T[0].Fn(this); |
|---|
| 460 |
}`); |
|---|
| 461 |
} |
|---|
| 462 |
static if (T.length > 1) |
|---|
| 463 |
mixin GenLocalCalls!(T[1 .. $]); |
|---|
| 464 |
} |
|---|
| 465 |
} |
|---|
| 466 |
|
|---|
| 467 |
template MaskSelect(string S, T...) { |
|---|
| 468 |
static if (!T.length) { |
|---|
| 469 |
alias Tuple!() MaskSelect; |
|---|
| 470 |
} else { |
|---|
| 471 |
static if (S[0] == 'f') // not used to override |
|---|
| 472 |
alias Tuple!(T[0], MaskSelect!(S[1..$], T[1..$])) MaskSelect; |
|---|
| 473 |
else // overrid, omit |
|---|
| 474 |
alias Tuple!(MaskSelect!(S[1..$], T[1..$])) MaskSelect; |
|---|
| 475 |
} |
|---|
| 476 |
} |
|---|
| 477 |
|
|---|
| 478 |
extern(C) struct CppClass(string _Name, _Members...) { |
|---|
| 479 |
alias _Name Name; |
|---|
| 480 |
alias _Members Members; |
|---|
| 481 |
static if (HasOne!(isClass, Members)) { |
|---|
| 482 |
const bool hasVTable = HasOne!(stuffVTable, Members) |
|---|
| 483 |
&& !FirstClass!(Select!(isClass, Members))[0].hasVTable; |
|---|
| 484 |
const bool hasClassinfo = !SelectOne!(isClass, Members).hasVTable; |
|---|
| 485 |
} else { |
|---|
| 486 |
const bool hasVTable = HasOne!(stuffVTable, Members); |
|---|
| 487 |
const bool hasClassinfo = true; |
|---|
| 488 |
} |
|---|
| 489 |
|
|---|
| 490 |
alias CombineUpdateVTables!(TW!(Select!(isMethod, Members)), hasVTable * 4, Select!(isClass, Members)).table ParentalVTable; |
|---|
| 491 |
const MethodMask = CombineUpdateVTables!(TW!(Select!(isMethod, Members)), hasVTable * 4, Select!(isClass, Members)).mask; |
|---|
| 492 |
alias Select!(isVirtual, MaskSelect!(MethodMask, Select!(isMethod, Members))) Virtuals; |
|---|
| 493 |
|
|---|
| 494 |
static if (hasClassinfo) |
|---|
| 495 |
alias Tuple!(Classinfo!(Name)) _CI; |
|---|
| 496 |
else alias Tuple!() _CI; |
|---|
| 497 |
alias Tuple!(_CI, |
|---|
| 498 |
ParentalVTable, |
|---|
| 499 |
Virtuals |
|---|
| 500 |
) FixedVTable; |
|---|
| 501 |
const int OwnVtableOffset = _CI.length + ParentalVTable.length; |
|---|
| 502 |
mixin GenVirtualCalls!(TW!(Virtuals), TW!(FixedVTable), OwnVtableOffset); |
|---|
| 503 |
static if (hasVTable) { |
|---|
| 504 |
void* vtable = cast(void*) &VTableData!(FixedVTable).data + 4; |
|---|
| 505 |
// pragma(msg, "CppClass(", Name, ": vtable ", FixedVTable.stringof, ")"); |
|---|
| 506 |
mixin(`static void fixup_classinfo_`~Name~`(void* p) { |
|---|
| 507 |
VTableData!(FixedVTable).data.classinfo_`~Name~` = p; |
|---|
| 508 |
}`); |
|---|
| 509 |
static void fixup_classinfo(void* p) { |
|---|
| 510 |
mixin(gen_fixups("fixup_classinfo", "p", Name~","~DeepSuperNames!(Members))); |
|---|
| 511 |
} |
|---|
| 512 |
T get_type_info(T)() { |
|---|
| 513 |
return *cast(T*) (vtable - 4); |
|---|
| 514 |
} |
|---|
| 515 |
} else { |
|---|
| 516 |
static void fixup_classinfo(void* p) { |
|---|
| 517 |
mixin(gen_fixups("fixup_classinfo", "p", DeepSuperNames!(Members))); |
|---|
| 518 |
} |
|---|
| 519 |
T get_type_info(T)() { |
|---|
| 520 |
// try to use the first eligible child's vtable instead |
|---|
| 521 |
static if (HasOne!(stuffVTable, Members)) { |
|---|
| 522 |
return mixin(`*cast(T*) (vtable_`~SuperOrder!(Members)[0].Name~` - 4)`); |
|---|
| 523 |
} else { |
|---|
| 524 |
static assert(false, "No VTable in "~Name); |
|---|
| 525 |
} |
|---|
| 526 |
} |
|---|
| 527 |
} |
|---|
| 528 |
mixin GenLocalCalls!(Select!(isMethodNotVirtual, Members)); |
|---|
| 529 |
mixin CppClassMembers!(hasVTable * 4, hasClassinfo * 4, TW!(Members), TW!(Members), TW!(FixedVTable)); |
|---|
| 530 |
alias void ClassMarker; |
|---|
| 531 |
} |
|---|
| 532 |
|
|---|
| 533 |
int readSymbolInt(string s, int i) { |
|---|
| 534 |
i = s.idxStripL(i); |
|---|
| 535 |
while (i < s.length) { |
|---|
| 536 |
char c = s[i]; |
|---|
| 537 |
if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' |
|---|
| 538 |
|| c == '_' || c == '.') { |
|---|
| 539 |
i++; |
|---|
| 540 |
} else { |
|---|
| 541 |
return s.idxStripL(i); |
|---|
| 542 |
} |
|---|
| 543 |
} |
|---|
| 544 |
assert(false, "String terminated by symbol. Oops. "); |
|---|
| 545 |
} |
|---|
| 546 |
|
|---|
| 547 |
string readSymbol(string s, ref int i) { |
|---|
| 548 |
auto start = i; |
|---|
| 549 |
i = s.readSymbolInt(i); |
|---|
| 550 |
return s[start .. i]; |
|---|
| 551 |
} |
|---|
| 552 |
|
|---|
| 553 |
// read until closing " or ` |
|---|
| 554 |
string readString(ref string s, char marker) { |
|---|
| 555 |
auto backup = s; |
|---|
| 556 |
while (s.length) { |
|---|
| 557 |
if (s[0] == marker) { |
|---|
| 558 |
s = s[1 .. $]; |
|---|
| 559 |
return backup[0 .. $ - s.length - 1]; |
|---|
| 560 |
} |
|---|
| 561 |
if (s[0] == '\\' && marker == '"') s = s[1 .. $]; // skip |
|---|
| 562 |
s = s[1 .. $]; |
|---|
| 563 |
} |
|---|
| 564 |
assert(false, "String literal not closed! "); |
|---|
| 565 |
} |
|---|
| 566 |
|
|---|
| 567 |
int readString(string s, int i, char marker) { |
|---|
| 568 |
while (i < s.length) { |
|---|
| 569 |
if (s[i] == marker) { |
|---|
| 570 |
return i + 1; |
|---|
| 571 |
} |
|---|
| 572 |
if (s[i] == '\\' && marker == '"') i++; |
|---|
| 573 |
i++; |
|---|
| 574 |
} |
|---|
| 575 |
assert(false, "String literal not closed! "); |
|---|
| 576 |
} |
|---|
| 577 |
|
|---|
| 578 |
void eatCComment(ref string s) { |
|---|
| 579 |
s.ctSlice("*/"); |
|---|
| 580 |
assert(s, "Closing comment */ not found! "); |
|---|
| 581 |
} |
|---|
| 582 |
|
|---|
| 583 |
void eatDComment(ref string s) { |
|---|
| 584 |
int depth = 1; |
|---|
| 585 |
while (s.length) { |
|---|
| 586 |
size_t pos1 = s.ctFind("/+"), pos2 = s.ctFind("+/"); |
|---|
| 587 |
assert(pos1 != pos2, "Closing comment +/ not found! "); |
|---|
| 588 |
if (pos1 < pos2) { |
|---|
| 589 |
s = s[pos1+2 .. $]; |
|---|
| 590 |
depth++; |
|---|
| 591 |
} else { |
|---|
| 592 |
s = s[pos2+2 .. $]; |
|---|
| 593 |
depth--; |
|---|
| 594 |
if (!depth) return; |
|---|
| 595 |
} |
|---|
| 596 |
} |
|---|
| 597 |
assert(false); |
|---|
| 598 |
} |
|---|
| 599 |
|
|---|
| 600 |
string eatComments(string s) { |
|---|
| 601 |
string res; |
|---|
| 602 |
int len; |
|---|
| 603 |
while (len + 1 < s.length) { |
|---|
| 604 |
auto ch = s[len]; |
|---|
| 605 |
if (ch == '"' || ch == '`') { |
|---|
| 606 |
res ~= s[0 .. len]; s = s[len + 1 .. $]; len = 0; |
|---|
| 607 |
res ~= ch ~ s.readString(ch) ~ ch; |
|---|
| 608 |
continue; |
|---|
| 609 |
} |
|---|
| 610 |
if (s[len .. len + 2] == "/*") { |
|---|
| 611 |
res ~= s[0 .. len]; s = s[len + 2 .. $]; len = 0; |
|---|
| 612 |
s.eatCComment(); |
|---|
| 613 |
continue; |
|---|
| 614 |
} |
|---|
| 615 |
if (s[len .. len + 2] == "/+") { |
|---|
| 616 |
res ~= s[0 .. len]; s = s[len + 2 .. $]; len = 0; |
|---|
| 617 |
s.eatDComment(); |
|---|
| 618 |
continue; |
|---|
| 619 |
} |
|---|
| 620 |
if (s[len .. len + 2] == "//") { |
|---|
| 621 |
res ~= s[0 .. len]; s = s[len + 2 .. $]; len = 0; |
|---|
| 622 |
s.ctSlice("\n"); |
|---|
| 623 |
continue; |
|---|
| 624 |
} |
|---|
| 625 |
len ++; |
|---|
| 626 |
} |
|---|
| 627 |
res ~= s[0 .. len + 1]; |
|---|
| 628 |
return res; |
|---|
| 629 |
} |
|---|
| 630 |
|
|---|
| 631 |
int readBrackets(string s, int i, char open, char close) { |
|---|
| 632 |
int count = 1; |
|---|
| 633 |
assert(s[i] == open, "Expected "~open~"; found "~s); |
|---|
| 634 |
i++; |
|---|
| 635 |
while (i < s.length) { |
|---|
| 636 |
auto ch = s[i]; |
|---|
| 637 |
if (ch == open) count ++; |
|---|
| 638 |
if (ch == close) count --; |
|---|
| 639 |
if (ch == '"' || ch == '`') { |
|---|
| 640 |
i = s.readString(i+1, ch); |
|---|
| 641 |
continue; |
|---|
| 642 |
} |
|---|
| 643 |
if (!count) { |
|---|
| 644 |
return i + 1; |
|---|
| 645 |
} |
|---|
| 646 |
i++; |
|---|
| 647 |
} |
|---|
| 648 |
assert(false, "Closing bracket not found in "~s~"!"); |
|---|
| 649 |
} |
|---|
| 650 |
|
|---|
| 651 |
string readBracketsStr(string s, ref int i, char open, char close) { |
|---|
| 652 |
auto start = i; |
|---|
| 653 |
i = s.readBrackets(i, open, close); |
|---|
| 654 |
return s[start .. i]; |
|---|
| 655 |
} |
|---|
| 656 |
|
|---|
| 657 |
int idxStripL(string s, int i) { |
|---|
| 658 |
while (i < s.length && (s[i] == ' ' || s[i] == '\t' || s[i] == '\n' || s[i] == '\r')) |
|---|
| 659 |
i++; |
|---|
| 660 |
return i; |
|---|
| 661 |
} |
|---|
| 662 |
|
|---|
| 663 |
string readType(string s, ref int i) { |
|---|
| 664 |
auto start = i; |
|---|
| 665 |
i = s.readSymbolInt(i); |
|---|
| 666 |
int failsafe; |
|---|
| 667 |
while (true) { |
|---|
| 668 |
failsafe ++; |
|---|
| 669 |
if (failsafe > 100) { |
|---|
| 670 |
assert(false, "Parser hanging? "~s); |
|---|
| 671 |
} |
|---|
| 672 |
i = s.idxStripL(i); |
|---|
| 673 |
if (i < s.length && s[i] == '!') { |
|---|
| 674 |
i++; |
|---|
| 675 |
} |
|---|
| 676 |
if (i < s.length && s[i] == '(') { |
|---|
| 677 |
i = s.readBrackets(i, '(', ')'); |
|---|
| 678 |
continue; |
|---|
| 679 |
} |
|---|
| 680 |
if (i < s.length && s[i] == '*') { |
|---|
| 681 |
i++; |
|---|
| 682 |
continue; |
|---|
| 683 |
} |
|---|
| 684 |
if (i < s.length && s[i] == '[') { |
|---|
| 685 |
i = s.readBrackets(i, '[', ']'); |
|---|
| 686 |
continue; |
|---|
| 687 |
} |
|---|
| 688 |
if (i < s.length - 8 && s[i .. i+8] == "function") { |
|---|
| 689 |
i = s.idxStripL(i+8); |
|---|
| 690 |
i = s.readBrackets(i, '(', ')'); |
|---|
| 691 |
continue; |
|---|
| 692 |
} |
|---|
| 693 |
break; |
|---|
| 694 |
} |
|---|
| 695 |
return s[start .. i]; |
|---|
| 696 |
} |
|---|
| 697 |
|
|---|
| 698 |
string readInitializer(string s, ref int i) { |
|---|
| 699 |
i = s.idxStripL(i); |
|---|
| 700 |
if (s[i] != '=') return ""; |
|---|
| 701 |
i++; |
|---|
| 702 |
auto start = i; |
|---|
| 703 |
int pos1 = s[i .. $].ctFind(","), pos2 = s[i .. $].ctFind(";"); |
|---|
| 704 |
if (pos1 == pos2) assert(false, "Initializer not closed in "~s); |
|---|
| 705 |
int sep = pos1; |
|---|
| 706 |
if (pos2 < sep) sep = pos2; |
|---|
| 707 |
i += sep; |
|---|
| 708 |
return s[start .. i]; |
|---|
| 709 |
} |
|---|
| 710 |
|
|---|
| 711 |
string haaax(string s) { |
|---|
| 712 |
return s.eatComments().haaax_main(); |
|---|
| 713 |
} |
|---|
| 714 |
|
|---|
| 715 |
string ctSlice(string s, ref int i, string m) { |
|---|
| 716 |
auto pos = s[i .. $].ctFind(m); |
|---|
| 717 |
assert(pos != -1); |
|---|
| 718 |
auto res = s[i .. i+pos]; |
|---|
| 719 |
i += pos + m.length; |
|---|
| 720 |
return res; |
|---|
| 721 |
} |
|---|
| 722 |
|
|---|
| 723 |
string ctSlice(ref string s, string m) { return tools.ctfe.ctSlice(s, m); } |
|---|
| 724 |
|
|---|
| 725 |
// parse a pseudocode C++ class declaration |
|---|
| 726 |
string haaax_main(string s, int i = 0) { |
|---|
| 727 |
string res, fndefs; |
|---|
| 728 |
auto info = s.ctSlice(i, "{"); |
|---|
| 729 |
auto name = info.ctSlice(":").ctStrip(); |
|---|
| 730 |
info = info.ctStrip(); |
|---|
| 731 |
res ~= "alias CppClass!(\""~name~"\","; |
|---|
| 732 |
while (info.length) { |
|---|
| 733 |
auto supclass = info.ctSlice(","); |
|---|
| 734 |
info = info.ctStrip(); |
|---|
| 735 |
res ~= supclass~","; |
|---|
| 736 |
} |
|---|
| 737 |
i = s.idxStripL(i); |
|---|
| 738 |
int num = 0; |
|---|
| 739 |
while (i < s.length) { |
|---|
| 740 |
num ++; |
|---|
| 741 |
if (s[i] == '}') { i++; break; } |
|---|
| 742 |
bool virtual = false; |
|---|
| 743 |
if (i + 7 < s.length && s[i .. i+7] == "virtual") { |
|---|
| 744 |
i = s.idxStripL(i+7); |
|---|
| 745 |
virtual = true; |
|---|
| 746 |
} |
|---|
| 747 |
string mname; |
|---|
| 748 |
if (s[i .. i+8] == "mangleto") { |
|---|
| 749 |
i = s.idxStripL(i+8); |
|---|
| 750 |
mname = "\"" ~ s.readBracketsStr(i, '(', ')')[1 .. $-1] ~ "\""; |
|---|
| 751 |
i = s.idxStripL(i); |
|---|
| 752 |
} |
|---|
| 753 |
auto t = s.readType(i), n = s.readSymbol(i), init = s.readInitializer(i); |
|---|
| 754 |
i = s.idxStripL(i); |
|---|
| 755 |
if (s[i] == '(') { |
|---|
| 756 |
auto fnparams = s.readBracketsStr(i, '(', ')').ctStrip()[1 .. $-1].ctStrip(); |
|---|
| 757 |
if (fnparams.length) fnparams = "(void *_self, "~fnparams~")"; |
|---|
| 758 |
else fnparams = "(void *_self)"; |
|---|
| 759 |
|
|---|
| 760 |
i = s.idxStripL(i); |
|---|
| 761 |
bool constfun = false; |
|---|
| 762 |
if (i + 5 < s.length && s[i .. i+5] == "const") { |
|---|
| 763 |
i = s.idxStripL(i + 5); |
|---|
| 764 |
constfun = true; |
|---|
| 765 |
} |
|---|
| 766 |
auto type = t~" function "~fnparams; |
|---|
| 767 |
if (!mname.length) |
|---|
| 768 |
mname = `"_ZN`~(constfun?"K":"")~ctToString(name.length)~name~`"~FunMangle!("`~n~`", `~type~`)`; |
|---|
| 769 |
auto nice_name = `__cpp_`~name~`_`~n~`_`~ctToString(num)~`__`; |
|---|
| 770 |
auto fn = t~` `~nice_name; |
|---|
| 771 |
bool exportExtern = false; |
|---|
| 772 |
if (s[i] == ';') { |
|---|
| 773 |
fndefs ~= `pragma(msg, `~mname~`);`~'\n'; |
|---|
| 774 |
fndefs ~= `mixin("extern(C) `~t~` "~`~mname~`~"`~fnparams.ctReplace(`"`, `\"`)~`; ");`~'\n'~ |
|---|
| 775 |
`mixin("`~fn~`("~refToParamList("Params!(typeof(&"~`~mname~`~"))", isRef!(typeof(mixin("&"~`~mname~`))))~") { |
|---|
| 776 |
return "~`~mname~`~"("~refToValueList(isRef!(typeof(mixin("&"~`~mname~`))))~"); |
|---|
| 777 |
} |
|---|
| 778 |
"); `~'\n'; |
|---|
| 779 |
res ~= (virtual?`VirtualMethod`:`Method`)~`!(`~nice_name~`, "`~n~`"),`; |
|---|
| 780 |
i ++; |
|---|
| 781 |
} else if (s[i] == '{') { |
|---|
| 782 |
fndefs ~= fn~fnparams~`{ auto self = cast(`~name~`*) _self; with (*self) ` ~ s.readBracketsStr(i, '{', '}')[0 .. $]~" } \n"; |
|---|
| 783 |
exportExtern = true; |
|---|
| 784 |
res ~= (virtual?`VirtualMethod`:`Method`)~`!(`~nice_name~`, "`~n~`"),`; |
|---|
| 785 |
} else if (s[i] == '=') { |
|---|
| 786 |
i = s.idxStripL(i+1); |
|---|
| 787 |
assert(s[i] == '0', "Invalid semantics: virtual method = <anything but null> is not permissible! "); |
|---|
| 788 |
i = s.idxStripL(i+1); |
|---|
| 789 |
assert(s[i] == ';', "Missing semicolon after =0! "); |
|---|
| 790 |
i ++; |
|---|
| 791 |
fndefs ~= fn~fnparams~`{ throw new Exception("`~name~`::`~n~` not implemented! "); }`~'\n'; |
|---|
| 792 |
res ~= `VirtualMethod!(`~nice_name~`, "`~n~`"),`; |
|---|
| 793 |
exportExtern = true; |
|---|
| 794 |
} else assert(false, "!! "~s[i .. $]); |
|---|
| 795 |
if (exportExtern) |
|---|
| 796 |
fndefs ~= `mixin("extern(C) `~t~` "~`~mname~`~"("~refToParamList("Params!(typeof(&`~nice_name~`))", |
|---|
| 797 |
isRef!(typeof(&`~nice_name~`)))~") { |
|---|
| 798 |
return `~nice_name~`("~refToValueList(isRef!(typeof(&`~nice_name~`)))~"); |
|---|
| 799 |
}"); `~'\n'; |
|---|
| 800 |
} else if (s[i] == ';') { |
|---|
| 801 |
i ++; |
|---|
| 802 |
res ~= `Member!(`~t~`, "`~n~`", "`~init~`"),`; |
|---|
| 803 |
} else if (s[i] == ',') { |
|---|
| 804 |
do { |
|---|
| 805 |
i ++; |
|---|
| 806 |
res ~= `Member!(`~t~`, "`~n~`", "`~init~`"),`; |
|---|
| 807 |
n = s.readSymbol(i); |
|---|
| 808 |
init = s.readInitializer(i); |
|---|
| 809 |
i = s.idxStripL(i); |
|---|
| 810 |
} while (s[i] == ','); |
|---|
| 811 |
assert(s[i] == ';', "Not terminated: "~s); |
|---|
| 812 |
i ++; |
|---|
| 813 |
res ~= `Member!(`~t~`, "`~n~`", "`~init~`"),`; |
|---|
| 814 |
} else assert(false, "Parser was confused by unexpected data: "~s[i .. $]); |
|---|
| 815 |
i = s.idxStripL(i); |
|---|
| 816 |
} |
|---|
| 817 |
i = s.idxStripL(i); |
|---|
| 818 |
res = res[0 .. $-1]; // eat trailing comma |
|---|
| 819 |
res ~= ") "~name~";\n"; |
|---|
| 820 |
if (i < s.length) return fndefs ~ res ~ s.haaax_main(i); |
|---|
| 821 |
else return fndefs ~ res; |
|---|
| 822 |
} |
|---|