Mercurial > projects > qtd
annotate d2/qtd/meta/Compiletime.d @ 366:da4235301224
Fixed VoidFunc. Updated to dmd.2.047.
author | Max Samukha <maxter@spambox.com> |
---|---|
date | Wed, 23 Jun 2010 21:34:43 +0300 |
parents | 958e8b9a89bd |
children | a032df77b6ab |
rev | line source |
---|---|
351 | 1 /************************************************************************** |
2 Copyright: QtD Team, 2010 | |
3 Authors: Max Samukha, Eldar Insafutdinov | |
4 License: Boost Software License 1.0 | |
5 **************************************************************************/ | |
6 module qtd.meta.Compiletime; | |
7 | |
8 import | |
366
da4235301224
Fixed VoidFunc. Updated to dmd.2.047.
Max Samukha <maxter@spambox.com>
parents:
365
diff
changeset
|
9 qtd.String, |
365
958e8b9a89bd
Changeset a084e2df3776 is broken. Backing out.
Max Samukha <maxter@spambox.com>
parents:
364
diff
changeset
|
10 std.traits, |
351 | 11 std.conv, |
12 std.variant, | |
13 std.typetuple; | |
14 | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
15 /** |
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
16 */ |
351 | 17 enum standardNamespace = "qtd"; |
18 | |
19 template Alias(A...) if (A.length == 1) | |
20 { | |
21 static if (__traits(compiles, { alias A[0] x; })) | |
22 alias A[0] Alias; | |
23 else | |
24 enum Alias = A[0]; | |
25 } | |
26 | |
27 /** | |
28 Encapsulates a static tuple. Useful for preventing tuples from | |
29 flattening when they are passed to a variadic template. | |
30 */ | |
31 template TypeTupleWrapper(A...) | |
32 { | |
33 alias A tuple; | |
34 } | |
35 | |
36 | |
37 /** | |
38 Returns a tuple with T repeated count times. | |
39 */ | |
40 // TODO: generalize to accept any symbol | |
41 template Repeat(T, size_t count) | |
42 { | |
43 static if (count) | |
44 alias TypeTuple!(count, Repeat!(T, count - 1)) Repeat; | |
45 else | |
46 alias TypeTuple!() Repeat; | |
47 } | |
48 | |
49 /** | |
50 Returns the required number of function arguments, optional arguments excluded | |
51 */ | |
52 int requiredArgCount(alias fn)() { | |
53 alias ParameterTypeTuple!(typeof(&fn)) P; | |
54 P p; | |
55 static if (P.length == 0) | |
56 return 0; | |
57 | |
58 foreach(i, _; P) | |
59 { | |
60 static if (!__traits(compiles, fn(p[0..$-i-1]))) | |
61 { | |
62 return p.length - i; | |
63 } | |
64 } | |
65 return 0; | |
66 } | |
67 | |
68 /** | |
69 Returns true if is a delegate type. | |
70 */ | |
71 template isDelegate(T) | |
72 { | |
73 enum isDelegate = is(T == delegate); | |
74 } | |
75 | |
76 /** | |
77 Returns true if T is a function pointer type. | |
78 */ | |
79 template isFunctionPointer(T) | |
80 { | |
81 enum isFuntionPointer = is(typeof(*T.init) == function); | |
82 } | |
83 | |
84 /** | |
85 Returns true if entity is a function or function type. | |
86 */ | |
87 template isFunction(alias entity) | |
88 { | |
89 static if (is(entity)) | |
90 alias isFunction!(entity, void) isFunction; | |
91 else | |
92 enum isFunction = is(typeof(entity) == function); | |
93 } | |
94 | |
95 template isFunction(T, Dummy = void) | |
96 { | |
97 enum isFunction = is(T == function); | |
98 } | |
99 | |
100 | |
101 //TODO: hack | |
102 uint isModule(string str) | |
103 { | |
104 return startsWith(str, "module "); | |
105 } | |
106 | |
107 | |
108 template qualifiedCppName(T) | |
109 { | |
110 static if(!isModule(__traits(parent, T).stringof)) | |
111 enum qualifiedCppName = qualifiedCppName!(__traits(parent, T)) ~ "::" ~ T.stringof; | |
112 else | |
113 enum qualifiedCppName = T.stringof; | |
114 } | |
115 | |
116 template qualifiedName(T) | |
117 { | |
118 static if (!isModule(__traits(parent, T).stringof)) | |
119 enum qualifiedName = qualifiedName!(__traits(parent, T)) ~ "." ~ T.stringof; | |
120 else | |
121 enum qualifiedName = T.stringof; | |
122 } | |
123 | |
124 template fullName(T) | |
125 { | |
126 static if (is(T == enum)) | |
127 enum fullName = qualifiedName!T; | |
128 else | |
129 enum fullName = T.stringof; | |
130 } | |
131 | |
132 /** | |
133 */ | |
134 enum AttributeOptions | |
135 { | |
136 /** | |
137 */ | |
138 none, | |
139 | |
140 /** | |
141 Allows multiple equally named attributes to be associated with the symbol. | |
142 */ | |
143 allowMultiple = 0x0000_0001, | |
144 | |
145 /* internal */ inner = 0x0000_0002, | |
146 } | |
147 | |
148 /** | |
149 When mixed in an aggregate, converts a compile-time tuple to | |
150 members of that aggregate. | |
151 */ | |
152 mixin template tupleToMembers(string nameSpace, size_t index, A...) | |
153 { | |
154 static if (index < A.length) | |
155 { | |
156 enum indexStr = to!string(index); | |
157 | |
158 static if (is(typeof( { typeof(A[index]) x; }() ))) | |
159 mixin("typeof(A[" ~ indexStr ~ "]) " ~ nameSpace ~ indexStr ~ " = A[" ~ indexStr ~"];\n"); | |
160 else | |
161 mixin("alias Alias!(A[" ~ indexStr ~ "]) " ~ nameSpace ~ indexStr ~ ";\n"); | |
162 | |
163 mixin tupleToMembers!(nameSpace, index + 1, A); | |
164 } | |
165 } | |
166 | |
167 /** | |
168 When mixed in an aggregate, converts a compile-time tuple of name-value pairs to | |
169 members of that aggregate. | |
170 */ | |
171 mixin template NameValueTupleToFields(A...) | |
172 { | |
173 | |
174 } | |
175 | |
176 version (QtdUnittest) | |
177 { | |
178 unittest | |
179 { | |
180 static int foo() | |
181 { | |
182 return 42; | |
183 } | |
184 | |
185 static struct S | |
186 { | |
187 mixin tupleToMembers!("member", 0, | |
188 int, | |
189 "a", | |
190 22, | |
191 foo); | |
192 } | |
193 | |
194 static assert(is(S.member0 == int)); | |
195 S s; | |
196 assert(s.member1 == "a"); | |
197 assert(s.member2 == 22); | |
198 assert(S.member3() == 42); | |
199 } | |
200 } | |
201 | |
202 private template attributeId(alias symbol, uint index = 0) | |
203 { | |
204 enum attributeId = standardNamespace ~ "_attr_" ~ uniqueId!symbol ~ "_" ~ to!string(index); | |
205 } | |
206 | |
207 /** | |
208 Attributes allow to associate arbitrary compile-time data | |
209 with a declaration and optionaly make that data available at run-time. | |
210 | |
211 ---- | |
212 class A | |
213 { | |
214 } | |
215 mixin Attribute!(C, "someAttribute", "B"); | |
216 ---- | |
217 | |
218 The example above associates the string "B" with class A under the attribute name "someAttribute". | |
219 Multiple attributes with the same name can be associated with a single declaration. | |
220 | |
221 ---- | |
222 class A | |
223 { | |
224 } | |
225 mixin Attribute!(C, "someAttribute", "B"); | |
226 mixin Attribute!(C, "someAttribute", AttributeOptions.allowMultiple, "C"); | |
227 ---- | |
228 | |
229 Attributes can be accessed at compile-time as follows: | |
230 | |
231 ---- | |
232 alias GetAttributes!(C, "someAttribute") attrs; | |
233 ---- | |
234 | |
235 GetAttribute returns a static tuple, which contains "someAttribute" attributes in the form | |
236 of TypeTupleWrapper instances. The wrapped tuples have the following layout: | |
237 | |
238 [0] - attribute name | |
239 [1] - attribute options | |
240 [2..$] - attribute data | |
241 | |
242 ---- | |
243 alias attrs[0] attr0; | |
244 alias attrs[1] attr1; | |
245 | |
246 static assert(attrs0.tuple[0] == "someAttribute" && attrs0.tuple[2] == "B"); | |
247 static assert(attrs1.tuple[0] == "someAttribute" && attrs1.tuple[2] == "C"); | |
248 ---- | |
249 | |
250 Attributes can be inserted inside the body of a declaration. | |
251 ---- | |
252 class A | |
253 { | |
254 mixin Attribute!("someAttribute", "B"); | |
255 } | |
256 ---- | |
257 | |
258 Attributes can be made available at run time by means of the declaration's meta-object | |
259 ---- | |
260 // prints names of all attributes associated with class A | |
261 auto a = new A; | |
262 foreach (attr; a.metaObject.attributes) | |
263 writeln(attr.name); | |
264 ---- | |
265 | |
266 Attributes can be specialized | |
267 | |
268 ---- | |
269 mixin template DbFieldAttribute(alias prop, string columnName) | |
270 { | |
271 mixin Attribute!(prop, "DbFieldAttribute", columnName); | |
272 } | |
273 | |
274 class A | |
275 { | |
276 int value; | |
277 mixin DbFieldAttribute!(value, "Value"); | |
278 | |
279 int anotherValue; | |
280 mixin DbFieldAttribute!(anotherValue, "Value2"); | |
281 } | |
282 | |
283 assert(GetAttributes!(A.value, "DbFieldAttribute")[0].tuple[1] == "Value"); | |
284 assert(GetAttributes!(A.anotherValue, "DbFieldAttribute")[0].tuple[1] == "Value2"); | |
285 ---- | |
286 | |
287 */ | |
288 mixin template Attribute(alias symbol, string attrClass, A...) | |
289 { | |
290 mixin Attribute!(symbol, attrClass, AttributeOptions.none, A); | |
291 } | |
292 | |
293 /// ditto | |
294 mixin template Attribute(alias symbol, string attrClass, AttributeOptions opts, A...) | |
295 { | |
296 mixin AttributeImpl!(symbol, attrClass, opts, 0, A); | |
297 } | |
298 | |
299 | |
300 /// ditto | |
301 // TODO: probably make this an overload of Attribute | |
302 mixin template InnerAttribute(string attrClass, AttributeOptions opts, A...) | |
303 { | |
304 // BUG: needs to be generalized to accept any parent | |
305 mixin Attribute!(typeof(this), attrClass, opts | AttributeOptions.inner, A); | |
306 } | |
307 | |
308 /// ditto | |
309 mixin template InnerAttribute(string attrClass, A...) | |
310 { | |
311 mixin InnerAttribute!(attrClass, AttributeOptions.none, A); | |
312 } | |
313 | |
314 private mixin template AttributeImpl(alias symbol, string attrClass, AttributeOptions opts, size_t index, A...) | |
315 { | |
316 private enum attrId = attributeId!(symbol, index) ~ (opts & AttributeOptions.inner ? "_inner" : ""); | |
317 | |
318 static if (is(typeof(mixin(attrId)))) | |
319 { | |
320 mixin ("alias " ~ attrId ~ " attr;"); | |
321 static if (!(opts & AttributeOptions.allowMultiple)) | |
322 { | |
323 static assert (attr[0] != attrClass, "Multiple " ~ attrClass ~ " attributes are not allowed for " | |
324 ~ __traits(parent, symbol).stringof ~ "." ~ stringOf!symbol); | |
325 } | |
326 | |
327 mixin AttributeImpl!(symbol, attrClass, opts, index + 1, A); | |
328 } | |
329 else | |
330 { | |
331 mixin ("alias TypeTuple!(attrClass, opts, A) " ~ attrId ~ ";"); | |
332 } | |
333 } | |
334 | |
335 private string stringOfFunction(alias symbol)() | |
336 { | |
337 auto ptrType = typeof(&symbol).stringof; | |
338 auto paramList = ParameterTypeTuple!(symbol).stringof; | |
339 | |
340 string result = ReturnType!(symbol).stringof ~ " " ~ __traits(identifier, symbol) ~ paramList; | |
341 | |
342 if (ptrType[$ - 1] != ')') | |
343 { | |
344 for (size_t i = ptrType.length - 2;; --i) | |
345 { | |
346 if (ptrType[i] == ')') | |
347 { | |
348 result ~= ptrType[i + 1..$]; | |
349 break; | |
350 } | |
351 } | |
352 } | |
353 | |
354 return result; | |
355 } | |
356 | |
357 /** | |
358 String of any symbol, including functions | |
359 */ | |
360 template stringOf(alias symbol) | |
361 { | |
362 static if (isFunction!symbol) | |
363 enum stringOf = stringOfFunction!symbol; | |
364 else | |
365 enum stringOf = symbol.stringof; | |
366 } | |
367 | |
368 /** | |
369 Returns the string uniquely identifying the | |
370 symbol in its container. | |
371 */ | |
372 template uniqueName(alias symbol) | |
373 { | |
374 enum uniqueName = stringOf!symbol; | |
375 } | |
376 | |
377 // TODO: works only for simple types. implement | |
378 string uniqueIdImpl(string symbol) | |
379 { | |
380 char[] r = symbol.dup; | |
381 foreach (i, c; symbol) | |
382 { | |
383 if (c == '(' || c == ')' || c == ' ') | |
384 r[i] = '_'; | |
385 } | |
386 | |
387 return cast(immutable)r; | |
388 } | |
389 | |
390 /** | |
391 Returns a valid D identifier uniquely | |
392 identifying symbol in its container. | |
393 */ | |
394 template uniqueId(alias symbol) | |
395 { | |
396 enum uniqueId = uniqueIdImpl(stringOf!symbol); | |
397 } | |
398 | |
399 version (QtdUnittest) | |
400 { | |
401 unittest | |
402 { | |
403 static class C | |
404 { | |
405 void foo() const {}; | |
406 bool bar(int) { return true; }; | |
407 int x; | |
408 static assert (stringOf!foo == "void foo() const"); | |
409 static assert (uniqueName!foo == "void foo() const"); | |
410 static assert (stringOf!bar == "bool bar(int)"); | |
411 static assert (uniqueName!bar == "bool bar(int)"); | |
412 static assert (stringOf!x == "x"); | |
413 static assert (uniqueName!x == "x"); | |
414 } | |
415 | |
416 static assert (stringOf!(C.foo) == "void foo() const"); | |
417 static assert (uniqueName!(C.foo) == "void foo() const"); | |
418 static assert (stringOf!(C.bar) == "bool bar(int)"); | |
419 static assert (uniqueName!(C.bar) == "bool bar(int)"); | |
420 | |
421 static assert (stringOf!(C.x) == "x"); | |
422 static assert (uniqueName!(C.x) == "x"); | |
423 } | |
424 } | |
425 | |
426 /** | |
427 Predicate that always evaluates to true regardless of arguments. | |
428 */ | |
429 template truePred(A...) | |
430 { | |
431 enum truePred = true; | |
432 } | |
433 | |
434 private template attrNamePred(string name) | |
435 { | |
436 template attrNamePred(A...) | |
437 { | |
438 enum attrNamePred = A[0] == name; | |
439 } | |
440 } | |
441 | |
442 /** | |
443 Returns a compile-time tuple of attributes that | |
444 match pred. | |
445 */ | |
446 template GetAttributes(alias symbol, alias pred = truePred) | |
447 { | |
448 alias GetAttributesImpl!(symbol, 0, pred).result GetAttributes; | |
449 } | |
450 | |
451 /** | |
452 Returns a compile-time tuple of attributes | |
453 matching the specified attribute name. | |
454 */ | |
455 template GetAttributes(alias symbol, string attrName) | |
456 { | |
457 alias GetAttributes!(symbol, attrNamePred!attrName) GetAttributes; | |
458 } | |
459 | |
460 | |
461 template GetAttributesImpl(alias symbol, size_t index, alias pred) | |
462 { | |
463 //pragma(msg, mixin("symbol." ~ attributeId!(symbol, index) ~ "_inner").stringof); | |
464 static if (is(typeof(mixin("__traits(parent, symbol)." ~ attributeId!(symbol, index))))) | |
465 mixin ("alias Alias!(__traits(parent, symbol))." ~ attributeId!(symbol, index) ~ " attr;"); | |
466 else static if (is(typeof(mixin("symbol." ~ attributeId!(symbol, index) ~ "_inner")))) | |
467 mixin ("alias symbol." ~ attributeId!(symbol, index) ~ "_inner attr;"); | |
468 | |
469 static if (is(typeof(attr))) | |
470 { | |
471 alias GetAttributesImpl!(symbol, index + 1, pred).result next; | |
472 | |
473 static if (pred!attr) | |
474 alias TypeTuple!(TypeTupleWrapper!attr, next) result; | |
475 else | |
476 alias next result; | |
477 } | |
478 else | |
479 alias TypeTuple!() result; | |
480 } | |
481 | |
482 version (QtdUnittest) | |
483 { | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
484 mixin template QtdCustomAttribute(alias symbol, A...) |
351 | 485 { |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
486 mixin Attribute!(symbol, "QtdCustomAttribute", AttributeOptions.allowMultiple, A); |
351 | 487 } |
488 | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
489 mixin template QtdCustomInnerAttribute(string name, alias value) |
351 | 490 { |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
491 mixin InnerAttribute!("QtdCustomInnerAttribute", AttributeOptions.allowMultiple, name, value); |
351 | 492 } |
493 | |
494 unittest | |
495 { | |
496 static class C | |
497 { | |
498 // inner C attributes | |
499 mixin InnerAttribute!("Inner", 33); // generic | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
500 mixin QtdCustomInnerAttribute!("version", 123); |
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
501 mixin QtdCustomInnerAttribute!("author", "James Bond"); |
351 | 502 |
503 | |
504 void foo() {}; | |
505 // foo attributes | |
506 mixin Attribute!(foo, "SomeAttribute", 42); | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
507 mixin QtdCustomAttribute!(foo, 1, 2); |
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
508 mixin QtdCustomAttribute!(foo, 3, 4); |
351 | 509 |
510 alias GetAttributes!(typeof(this), "Inner") innerAttrs; | |
511 static assert(innerAttrs[0].tuple[0] == "Inner"); | |
512 } | |
513 // outer C attribute | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
514 mixin QtdCustomAttribute!(C, 24); |
351 | 515 |
516 alias GetAttributes!(C, "Inner") innerAttrs; | |
517 static assert(innerAttrs[0].tuple[0] == "Inner" && innerAttrs[0].tuple[2] == 33); | |
518 | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
519 alias GetAttributes!(C, "QtdCustomInnerAttribute") ciAttrs; |
351 | 520 static assert(ciAttrs[0].tuple[2] == "version" && ciAttrs[0].tuple[3] == 123); |
521 | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
522 /+ Fails on Windows but passes on Linux |
351 | 523 alias GetAttributes!(C.foo, "SomeAttribute") someAttr; |
524 static assert(someAttr.length == 1); | |
525 static assert(someAttr[0].tuple[0] == "SomeAttribute"); | |
526 | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
527 alias GetAttributes!(C.foo, "QtdCustomAttribute") myAttrs; |
351 | 528 |
529 //COMPILER BUG: cannot 'alias myAttrs[0].tuple myAttrs_0'; | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
530 |
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
531 static assert(myAttrs[0].tuple[0] == "QtdCustomAttribute"); |
351 | 532 static assert(myAttrs[0].tuple[2] == 1 && myAttrs[0].tuple[3] == 2); |
533 | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
534 static assert(myAttrs[1].tuple[0] == "QtdCustomAttribute"); |
351 | 535 static assert(myAttrs[1].tuple[2] == 3 && myAttrs[1].tuple[3] == 4); |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
536 +/ |
351 | 537 |
538 /+ BUG: Fails: local declarations cannot be accessed as parent.localDecl | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
539 alias GetAttributes!(C, "QtdCustomAttribute") myAttrs2; |
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
540 static assert(myAttrs2[0].tuple[0] == "QtdCustomAttribute"); |
351 | 541 static assert(myAttrs2[0].tuple[1] == 24); |
542 +/ | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
543 |
351 | 544 } |
545 } |