Mercurial > projects > qtd
comparison d2/qtd/MOC.d @ 344:96a75b1e5b26
project structure changes
author | Max Samukha <maxter@spambox.com> |
---|---|
date | Fri, 14 May 2010 12:14:37 +0300 |
parents | qt/qtd/MOC.d@4e31cbd9e20c |
children | 970332a88b72 |
comparison
equal
deleted
inserted
replaced
343:552647ec0f82 | 344:96a75b1e5b26 |
---|---|
1 module qtd.MOC; | |
2 | |
3 import std.typetuple; | |
4 | |
5 import qt.QGlobal; | |
6 import qtd.Signal; | |
7 import qtd.MetaMarshall; | |
8 import qtd.Meta; | |
9 import qtd.ctfe.Format; | |
10 | |
11 public import qt.core.QString; | |
12 | |
13 public import std.traits; | |
14 /** | |
15 Utils. | |
16 */ | |
17 | |
18 bool is_digit_char(const char s) | |
19 { | |
20 return (s >= '0' && s <= '9'); | |
21 } | |
22 | |
23 bool is_octal_char(const char s) | |
24 { | |
25 return (s >= '0' && s <= '7'); | |
26 } | |
27 | |
28 bool is_hex_char(const char s) | |
29 { | |
30 return ((s >= 'a' && s <= 'f') | |
31 || (s >= 'A' && s <= 'F') | |
32 || (s >= '0' && s <= '9') | |
33 ); | |
34 } | |
35 | |
36 int lastIndexOf(T)(T[] haystack, T[] needle, int from = -1) | |
37 { | |
38 auto l = haystack.length; | |
39 auto ol = needle.length; | |
40 int delta = l - ol; | |
41 if (from < 0) | |
42 from = delta; | |
43 if (from < 0 || from > l) | |
44 return -1; | |
45 if (from > delta) | |
46 from = delta; | |
47 | |
48 while(from >= 0) | |
49 { | |
50 if (haystack[from..from+ol] == needle) | |
51 return from; | |
52 from--; | |
53 } | |
54 return -1; | |
55 } | |
56 | |
57 | |
58 T[] newArray(T)(size_t len, T[] from = []) | |
59 { | |
60 if (len == from.length) | |
61 return from; | |
62 | |
63 if (!from.length) | |
64 from = [T.init]; | |
65 | |
66 if (from.length < len) | |
67 return newArray!T(len, from ~ from); | |
68 | |
69 return from[0..len]; | |
70 } | |
71 | |
72 string replicate(int n, char value) | |
73 { | |
74 char[] ret = "".dup; | |
75 if (n > 0) | |
76 { | |
77 // ret = newArray!char(n); | |
78 for(int i = 0; i < n; i++) | |
79 ret ~= value; | |
80 } | |
81 return cast(string)ret; | |
82 } | |
83 | |
84 /** | |
85 CTFE MOC port. | |
86 */ | |
87 | |
88 enum MethodFlags { | |
89 AccessPrivate = 0x00, | |
90 AccessProtected = 0x01, | |
91 AccessPublic = 0x02, | |
92 MethodMethod = 0x00, | |
93 MethodSignal = 0x04, | |
94 MethodSlot = 0x08, | |
95 MethodConstructor = 0x0c, | |
96 MethodCompatibility = 0x10, | |
97 MethodCloned = 0x20, | |
98 MethodScriptable = 0x40 | |
99 } | |
100 | |
101 enum Access { Private, Protected, Public } | |
102 | |
103 struct FunctionDef | |
104 { | |
105 /* FunctionDef(): returnTypeIsVolatile(false), access(Private), isConst(false), isVirtual(false), | |
106 inlineCode(false), wasCloned(false), isCompat(false), isInvokable(false), | |
107 isScriptable(false), isSlot(false), isSignal(false), | |
108 isConstructor(false), isDestructor(false), isAbstract(false) {} | |
109 */ | |
110 // Type type; | |
111 // string normalizedType; | |
112 // string tag; | |
113 // string name; | |
114 string sig; | |
115 string arguments; | |
116 Access access; | |
117 /* bool returnTypeIsVolatile; | |
118 | |
119 QList<ArgumentDef> arguments; | |
120 | |
121 enum Access { Private, Protected, Public }; | |
122 bool isConst; | |
123 bool isVirtual; | |
124 bool inlineCode; | |
125 bool wasCloned; | |
126 | |
127 QByteArray inPrivateClass; | |
128 bool isCompat; | |
129 bool isInvokable; | |
130 bool isScriptable; | |
131 bool isSlot; | |
132 bool isSignal; | |
133 bool isConstructor; | |
134 bool isDestructor; | |
135 bool isAbstract; | |
136 */ | |
137 } | |
138 | |
139 FunctionDef newSlot(string sig, string args) | |
140 { | |
141 return FunctionDef(sig, args, Access.Public); | |
142 } | |
143 | |
144 FunctionDef newSignal(string sig, string args) | |
145 { | |
146 return FunctionDef(sig, args, Access.Protected); | |
147 } | |
148 | |
149 struct Generator | |
150 { | |
151 string output; | |
152 string[] strings; | |
153 // QByteArray purestSuperClass; | |
154 // QList<QByteArray> metaTypes; | |
155 } | |
156 | |
157 int lengthOfEscapeSequence(string s, uint i) | |
158 { | |
159 if (s[i] != '\\' || i >= s.length - 1) | |
160 return 1; | |
161 const int startPos = i; | |
162 ++i; | |
163 auto ch = s[i]; | |
164 if (ch == 'x') { | |
165 ++i; | |
166 while (i < s.length && is_hex_char(s[i])) | |
167 ++i; | |
168 } else if (is_octal_char(ch)) { | |
169 while (i < startPos + 4 | |
170 && i < s.length | |
171 && is_octal_char(s[i])) { | |
172 ++i; | |
173 } | |
174 } else { // single character escape sequence | |
175 i = qMin(i + 1, s.length); | |
176 } | |
177 return i - startPos; | |
178 } | |
179 | |
180 int strreg(ref Generator gen, string s) | |
181 { | |
182 int idx = 0; | |
183 foreach (str; gen.strings) { | |
184 if (str == s) | |
185 return idx; | |
186 idx += str.length + 1; | |
187 foreach (i, c; str) { | |
188 if (c == '\\') { | |
189 int cnt = lengthOfEscapeSequence(str, i) - 1; | |
190 idx -= cnt; | |
191 i += cnt; | |
192 } | |
193 } | |
194 } | |
195 gen.strings ~= s; | |
196 return idx; | |
197 } | |
198 | |
199 void generateFunctions(ref Generator gen, FunctionDef[] list, string functype, byte type) | |
200 { | |
201 if (!list.length) | |
202 return; | |
203 gen.output ~= format_ctfe("\n // ${}s: signature, parameters, type, tag, flags\n", functype); | |
204 | |
205 foreach (i, f; list) { | |
206 byte flags = type; | |
207 | |
208 if (f.access == Access.Private) | |
209 flags |= MethodFlags.AccessPrivate; | |
210 else if (f.access == Access.Public) | |
211 flags |= MethodFlags.AccessPublic; | |
212 else if (f.access == Access.Protected) | |
213 flags |= MethodFlags.AccessProtected; | |
214 | |
215 gen.output ~= format_ctfe(" ${}, ${}, ${}, ${}, 0x${:x},\n", strreg(gen, f.sig), | |
216 strreg(gen, f.arguments), strreg(gen, ""/*f.normalizedType*/), strreg(gen, ""/*f.tag*/), flags); | |
217 } | |
218 } | |
219 | |
220 string generateCode(string className, FunctionDef[] signalList, FunctionDef[] slotList) | |
221 { | |
222 auto gen = Generator("", []); | |
223 | |
224 /* bool isQt = (cdef->classname == "Qt"); | |
225 bool isQObject = (cdef->classname == "QObject"); | |
226 bool isConstructible = !cdef->constructorList.isEmpty(); | |
227 | |
228 // | |
229 // build the data array | |
230 // | |
231 int i = 0; | |
232 | |
233 | |
234 // filter out undeclared enumerators and sets | |
235 { | |
236 QList<EnumDef> enumList; | |
237 for (i = 0; i < cdef->enumList.count(); ++i) { | |
238 EnumDef def = cdef->enumList.at(i); | |
239 if (cdef->enumDeclarations.contains(def.name)) { | |
240 enumList += def; | |
241 } | |
242 QByteArray alias = cdef->flagAliases.value(def.name); | |
243 if (cdef->enumDeclarations.contains(alias)) { | |
244 def.name = alias; | |
245 enumList += def; | |
246 } | |
247 } | |
248 cdef->enumList = enumList; | |
249 } | |
250 | |
251 | |
252 QByteArray qualifiedClassNameIdentifier = cdef->qualified; | |
253 qualifiedClassNameIdentifier.replace(':', '_'); | |
254 */ | |
255 bool isConstructible = false; | |
256 | |
257 FunctionDef[] propertyList, enumList, constructorList; | |
258 int index = 12; | |
259 gen.output ~= format_ctfe("static const uint[] qt_meta_data_${} = [\n", className); | |
260 gen.output ~= format_ctfe("\n // content:\n"); | |
261 gen.output ~= format_ctfe(" ${}, // revision\n", 2); | |
262 gen.output ~= format_ctfe(" ${}, // classname\n", strreg(gen, className)); | |
263 gen.output ~= format_ctfe(" ${}, ${}, // classinfo\n", 0, 0); | |
264 // index += cdef->classInfoList.count() * 2; | |
265 | |
266 int methodCount = signalList.length + slotList.length;// + cdef->methodList.count(); | |
267 gen.output ~= format_ctfe(" ${}, ${}, // methods\n", methodCount, methodCount ? index : 0); | |
268 index += methodCount * 5; | |
269 gen.output ~= format_ctfe(" ${}, ${}, // properties\n", propertyList.length, propertyList.length ? index : 0); | |
270 index += propertyList.length * 3; | |
271 // if(cdef->notifyableProperties) | |
272 // index += cdef->propertyList.count(); | |
273 gen.output ~= format_ctfe(" ${}, ${}, // enums/sets\n", enumList.length, enumList.length ? index : 0); | |
274 | |
275 // int enumsIndex = index; | |
276 // for (i = 0; i < cdef->enumList.count(); ++i) | |
277 // index += 4 + (cdef->enumList.at(i).values.count() * 2); | |
278 gen.output ~= format_ctfe(" ${}, ${}, // constructors\n", isConstructible ? constructorList.length : 0, | |
279 isConstructible ? index : 0); | |
280 | |
281 // | |
282 // Build classinfo array | |
283 // | |
284 // generateClassInfos(); | |
285 | |
286 // | |
287 // Build signals array first, otherwise the signal indices would be wrong | |
288 // | |
289 generateFunctions(gen, signalList, "signal", MethodFlags.MethodSignal); | |
290 | |
291 // | |
292 // Build slots array | |
293 // | |
294 generateFunctions(gen, slotList, "slot", MethodFlags.MethodSlot); | |
295 | |
296 // | |
297 // Build method array | |
298 // | |
299 // generateFunctions(cdef->methodList, "method", MethodMethod); | |
300 | |
301 | |
302 // | |
303 // Build property array | |
304 // | |
305 // generateProperties(); | |
306 | |
307 // | |
308 // Build enums array | |
309 // | |
310 // generateEnums(enumsIndex); | |
311 | |
312 // | |
313 // Build constructors array | |
314 // | |
315 // if (isConstructible) | |
316 // generateFunctions(cdef->constructorList, "constructor", MethodConstructor); | |
317 | |
318 // | |
319 // Terminate data array | |
320 // | |
321 gen.output ~= format_ctfe("\n 0 // eod\n];\n\n"); | |
322 | |
323 // | |
324 // Build stringdata array | |
325 // | |
326 gen.output ~= format_ctfe("static const string qt_meta_stringdata_${} = \n", className); | |
327 gen.output ~= format_ctfe(" \""); | |
328 int col = 0; | |
329 int len = 0; | |
330 foreach (i, s; gen.strings) { | |
331 len = s.length; | |
332 if (col && col + len >= 72) { | |
333 gen.output ~= format_ctfe("\"\n \""); | |
334 col = 0; | |
335 } else if (len && s[0] >= '0' && s[0] <= '9') { | |
336 gen.output ~= format_ctfe("\"\""); | |
337 len += 2; | |
338 } | |
339 int idx = 0; | |
340 while (idx < s.length) { | |
341 if (idx > 0) { | |
342 col = 0; | |
343 gen.output ~= format_ctfe("\"\n \""); | |
344 } | |
345 int spanLen = qMin(cast(uint)70, s.length - idx); | |
346 // don't cut escape sequences at the end of a line | |
347 int backSlashPos = s.lastIndexOf("\\", idx + spanLen - 1); | |
348 if (backSlashPos >= idx) { | |
349 int escapeLen = lengthOfEscapeSequence(s, backSlashPos); | |
350 spanLen = qBound(spanLen, backSlashPos + escapeLen - idx, cast(int)(s.length - idx)); | |
351 } | |
352 gen.output ~= s[idx..idx+spanLen]; | |
353 idx += spanLen; | |
354 col += spanLen; | |
355 } | |
356 | |
357 gen.output ~= "\\0"; | |
358 col += len + 2; | |
359 } | |
360 gen.output ~= "\";\n\n"; | |
361 | |
362 return gen.output; | |
363 } | |
364 | |
365 string metaCallArgs(Args...)() | |
366 { | |
367 string res; | |
368 foreach(i, _; Args) { | |
369 if (i > 0) | |
370 res ~= ","; | |
371 res ~= metaCallArgument!(Args[i])("_a[" ~ __toString(i+1) ~ "]"); | |
372 } | |
373 return res; | |
374 } | |
375 | |
376 string qtDeclArgs(Args...)() | |
377 { | |
378 string ret; | |
379 foreach(i, _; Args) | |
380 { | |
381 if(i > 0) | |
382 ret ~= ","; | |
383 ret ~= qtDeclArg!(Args[i]); | |
384 } | |
385 return ret; | |
386 } | |
387 | |
388 string generate_qt_metacall(alias Signals, alias Slots)() | |
389 { | |
390 string res = " | |
391 protected int qt_metacall(QMetaObject.Call _c, int _id, void **_a) | |
392 { | |
393 _id = super.qt_metacall(_c, _id, _a); | |
394 if (_id < 0) | |
395 return _id;\n"; | |
396 | |
397 alias TypeTuple!(Signals.at, Slots.at) Methods; | |
398 enum methodCount = Methods.length; | |
399 if(methodCount) | |
400 { | |
401 res ~= " | |
402 if (_c == QMetaObject.Call.InvokeMetaMethod) { | |
403 switch (_id) {"; | |
404 foreach(i, _; Repeat!(void, methodCount)) { | |
405 res ~= " | |
406 case " ~ __toString(i) ~ ": " ~ MetaEntryName!(Methods[i].at) ~ "(" ~ metaCallArgs!(MetaEntryArgs!(Methods[i].at))() ~ "); break;"; | |
407 } | |
408 res ~= "\n default: ;\n }\n"; | |
409 res ~= " _id -= " ~ __toString(methodCount) ~ ";"; | |
410 res ~= "\n }"; | |
411 } | |
412 | |
413 res ~= "\n return _id; | |
414 }"; | |
415 return res; | |
416 } | |
417 | |
418 string dDeclArgs(Args...)() | |
419 { | |
420 string ret; | |
421 foreach(i, _; Args) | |
422 { | |
423 if (i > 0) | |
424 ret ~= ", "; | |
425 ret ~= fullDName!(Args[i]); | |
426 } | |
427 return ret; | |
428 } | |
429 string genMetaMethodsConstr(alias Funcs)(string className) | |
430 { | |
431 string res; | |
432 enum funcsCount = Funcs.at.length; | |
433 foreach(i, bogus; Repeat!(void, funcsCount)) | |
434 { | |
435 res ~= " index++;\n" ~ | |
436 " _staticMetaObject.addMethod(new " ~ className ~ "(signature!(" ~ dDeclArgs!(MetaEntryArgs!(Funcs.at[i].at))()~ ")(\"" ~ MetaEntryName!(Funcs.at[i].at) ~ "\"), index));\n\n"; | |
437 } | |
438 return res; | |
439 } | |
440 string generateMetaObjectConstruction(alias Signals, alias Slots)() | |
441 { | |
442 string res; | |
443 res ~= "\n | |
444 private static void _populateMetaInfo() { | |
445 alias BaseClassesTuple!(typeof(this))[0] BaseClass; | |
446 int index = BaseClass.staticMetaObject().methodCount() - 1;\n\n"; | |
447 | |
448 res ~= genMetaMethodsConstr!(Signals)("QMetaSignal"); | |
449 res ~= genMetaMethodsConstr!(Slots)("QMetaSlot"); | |
450 | |
451 res ~= " | |
452 }\n"; | |
453 return res; | |
454 } | |
455 | |
456 string generateQMetaObject(string className) | |
457 { | |
458 string res; | |
459 res ~= " | |
460 public QMetaObject metaObject() { return staticMetaObject(); } | |
461 private static __gshared QMetaObject _staticMetaObject; | |
462 private static __gshared QMetaObjectNative _nativeStaticMetaObject; | |
463 public static QMetaObject staticMetaObject() | |
464 { | |
465 if(!_staticMetaObject) | |
466 createStaticMetaObject(); | |
467 return _staticMetaObject; | |
468 } | |
469 protected static void createStaticMetaObject() { | |
470 assert(!_staticMetaObject); | |
471 alias BaseClassesTuple!(typeof(this))[0] BaseClass; | |
472 if (!BaseClass._staticMetaObject) | |
473 BaseClass.createStaticMetaObject; | |
474 auto base = BaseClass._staticMetaObject; | |
475 _nativeStaticMetaObject = QMetaObjectNative(base.nativeId, qt_meta_stringdata_" ~ className ~ ".ptr, | |
476 qt_meta_data_" ~ className ~ ".ptr, null ); | |
477 | |
478 _staticMetaObject = new QMetaObject(&_nativeStaticMetaObject, base); | |
479 // _staticMetaObject.construct!(typeof(this)); | |
480 _populateMetaInfo(); | |
481 }\n\n"; | |
482 return res; | |
483 } | |
484 | |
485 size_t commaCount(int argCount) | |
486 { | |
487 size_t ret = 0; | |
488 if(argCount > 1) | |
489 ret = argCount - 1; | |
490 return ret; | |
491 } | |
492 | |
493 FunctionDef[] genFuncDefs(alias Funcs, alias newFunc)() | |
494 { | |
495 typeof(return) res; | |
496 enum funcsCount = Funcs.at.length; | |
497 foreach(i, bogus; Repeat!(void, funcsCount)) | |
498 { | |
499 string args = replicate(commaCount((MetaEntryArgs!(Funcs.at[i].at)).length), ','); | |
500 string funcSig = MetaEntryName!(Funcs.at[i].at) ~ "(" ~ qtDeclArgs!(MetaEntryArgs!(Funcs.at[i].at))() ~ ")"; | |
501 res ~= newFunc(funcSig, args); | |
502 } | |
503 return res; | |
504 } | |
505 | |
506 template Q_OBJECT_BIND() | |
507 { | |
508 } | |
509 | |
510 // ------------------------------------------------------------------------------------------ | |
511 | |
512 string generateSignalEmitters(alias Funcs)() | |
513 { | |
514 string res; | |
515 enum funcsCount = Funcs.at.length; | |
516 foreach(i, bogus; Repeat!(void, funcsCount)) | |
517 { | |
518 res ~= SignalEmitter!(MetaEntryArgs!(Funcs.at[i].at))(SignalType.NewSignal, MetaEntryName!(Funcs.at[i].at), cast(string[])[], i); | |
519 } | |
520 return res; | |
521 } | |
522 | |
523 string generateSlotAliases(alias Funcs)() | |
524 { | |
525 string res; | |
526 enum funcsCount = Funcs.at.length; | |
527 foreach(i, bogus; Repeat!(void, funcsCount)) | |
528 { | |
529 string name = MetaEntryName!(Funcs.at[i].at); | |
530 res ~= format_ctfe(" alias slot_${} ${};\n", name, name); | |
531 } | |
532 return res; | |
533 } | |
534 | |
535 | |
536 string generateMetaInfo(T, alias Signals, alias Slots)() | |
537 { | |
538 string res = ""; | |
539 auto signalList = genFuncDefs!(Signals, newSignal)(); | |
540 auto slotList = genFuncDefs!(Slots, newSlot)(); | |
541 res ~= generateSignalEmitters!(Signals)(); | |
542 res ~= generateSlotAliases!(Slots)(); | |
543 res ~= generateCode(T.stringof, signalList, slotList); | |
544 res ~= generate_qt_metacall!(Signals, Slots); | |
545 res ~= generateMetaObjectConstruction!(Signals, Slots); | |
546 res ~= generateQMetaObject(T.stringof); | |
547 return res; | |
548 } | |
549 | |
550 template Q_OBJECT() | |
551 { | |
552 alias findSignals!(typeof(this)) SignalFuncs; | |
553 alias toMetaEntries!(SignalFuncs) SignalMetaEntries; | |
554 alias findSlots!(typeof(this)) SlotFuncs; | |
555 alias toMetaEntries!(SlotFuncs) SlotMetaEntries; | |
556 | |
557 mixin(generateMetaInfo!(typeof(this), SignalMetaEntries, SlotMetaEntries)()); | |
558 // debug output | |
559 // pragma(msg, generateMetaInfo!(typeof(this), SignalMetaEntries, SlotMetaEntries)()); | |
560 } |