1 /**
2    This module provides the template metaprogramming variant of compile-time
3    reflection, allowing client code to do type-level computations on the
4    contents of a D module.
5  */
6 module mirror.meta;
7 
8 
9 /**
10    Compile-time information on a D module.
11  */
12 template Module(string moduleName) {
13     import std.meta: Filter, staticMap, Alias, AliasSeq;
14 
15     mixin(`import `, moduleName, `;`);
16     private alias mod = Alias!(mixin(moduleName));
17 
18     private alias memberNames = __traits(allMembers, mod);
19 
20     private template member(string name) {
21         import std.meta: Alias, AliasSeq;
22 
23         enum identifier = name;
24 
25         static if(__traits(compiles, Alias!(__traits(getMember, mod, name))))
26             alias symbol = Alias!(__traits(getMember, mod, name));
27         else
28             alias symbol = AliasSeq!();
29     }
30     private alias members = staticMap!(member, memberNames);
31 
32     private template notPrivate(alias member) {
33         // If a module contains an alias to a basic type, e.g. `alias L = long;`,
34         // then __traits(getProtection, member) fails to compile
35         static if(__traits(compiles, __traits(getProtection, member.symbol)))
36             enum notPrivate = __traits(getProtection, member.symbol) != "private";
37         else
38             enum notPrivate = false;
39     }
40 
41     private alias publicMembers = Filter!(notPrivate, members);
42 
43 
44     // User-defined types
45     private template isMemberType(alias member) {
46         import std.traits: isType;
47         enum isMemberType = isType!(member.symbol);
48     }
49     private alias symbolOf(alias member) = member.symbol;
50     alias Aggregates = staticMap!(symbolOf, Filter!(isMemberType, publicMembers));
51 
52 
53     // Global variables
54     private enum isVariable(alias member) = is(typeof(member.symbol));
55     private enum toVariable(alias member) = Variable!(typeof(member.symbol))(__traits(identifier, member.symbol));
56     alias Variables = staticMap!(toVariable, Filter!(isVariable, publicMembers));
57 
58 
59     // Function definitions
60     private template isMemberSomeFunction(alias member) {
61         import std.traits: isSomeFunction;
62         enum isMemberSomeFunction = isSomeFunction!(member.symbol);
63     }
64     private alias functionMembers = Filter!(isMemberSomeFunction, publicMembers);
65     private enum toFunction(alias member) = Function!(mod, member.symbol, member.identifier)();
66     alias Functions = staticMap!(toFunction, functionMembers);
67 }
68 
69 
70 /**
71    A global variable.
72  */
73 struct Variable(T) {
74     alias Type = T;
75     string name;
76 }
77 
78 
79 /**
80    A function.
81  */
82 struct Function(alias M, alias F, string I = __traits(identifier, F)) {
83 
84     alias module_ = M;
85     alias symbol = F;
86     enum identifier = I;
87     alias overloads = __traits(getOverloads, module_, identifier);
88 
89     string protection = __traits(getProtection, symbol);
90     string linkage = __traits(getLinkage, symbol);
91 
92     string toString() @safe pure nothrow {
93         import std.conv: text;
94         import std.traits: fullyQualifiedName;
95         return text(`Function(`, fullyQualifiedName!symbol, ", ", protection, ", ", linkage, ")");
96     }
97 }
98 
99 
100 /// Usable as a predicate to std.meta.Filter
101 enum isEnum(T) = is(T == enum);
102 
103 /// Usable as a predicate to std.meta.Filter
104 enum isStruct(T) = is(T == struct);
105 
106 /// Usable as a predicate to std.meta.Filter
107 enum isInterface(T) = is(T == interface);
108 
109 /// Usable as a predicate to std.meta.Filter
110 enum isClass(T) = is(T == class);
111 
112 /**
113    If a type is a class or an interface.
114    Usable as a predicate to std.meta.Filter
115 */
116 enum isOOP(T) = is(T == class) || is(T == interface);