Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

root/trunk/tools/tools/cpp.d

Revision 673, 27.5 kB (checked in by FeepingCreature, 15 years ago)
  • Made more deletes dependent on "non-fucked GC" version flag
Line 
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 }
Note: See TracBrowser for help on using the browser.