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 import mirror.traits: moduleOf; 10 11 12 /** 13 Compile-time information on a D module. 14 */ 15 template Module(string moduleName) { 16 17 import mirror.traits: RecursiveTypeTree, RecursiveFieldTypes, FundamentalType, PublicMembers; 18 import std.meta: Alias; 19 20 mixin(`import `, moduleName, `;`); 21 private alias mod = Alias!(mixin(moduleName)); 22 23 private alias publicMembers = PublicMembers!mod; 24 25 /// User-defined structs/classes 26 alias Aggregates = aggregates!publicMembers; 27 28 /// User-defined structs/classes and all types contained in them 29 alias AggregatesTree = RecursiveTypeTree!Aggregates; 30 31 /// Global variables/enums 32 alias Variables = variables!publicMembers; 33 34 /// List of functions by symbol - contains overloads for each entry 35 alias FunctionsBySymbol = functionsBySymbol!(mod, publicMembers); 36 37 /// List of functions by overload - each overload is a separate entry 38 alias FunctionsByOverload = functionsByOverload!(mod, publicMembers); 39 40 alias AllFunctionReturnTypes = allFunctionReturnTypes!FunctionsByOverload; 41 alias AllFunctionReturnTypesTree = RecursiveTypeTree!AllFunctionReturnTypes; 42 43 alias AllFunctionParameterTypes = allFunctionParameterTypes!FunctionsByOverload; 44 alias AllFunctionParameterTypesTree = RecursiveTypeTree!AllFunctionParameterTypes; 45 } 46 47 48 package template allFunctionReturnTypes(functions...) { 49 50 import mirror.traits: FundamentalType; 51 import std.traits: ReturnType; 52 import std.meta: staticMap, NoDuplicates; 53 54 private alias symbol(alias F) = F.symbol; 55 56 alias allFunctionReturnTypes = 57 NoDuplicates!(staticMap!(FundamentalType, 58 staticMap!(ReturnType, 59 staticMap!(symbol, functions)))); 60 } 61 62 package template allFunctionParameterTypes(functions...) { 63 64 import mirror.traits: FundamentalType; 65 import std.traits: Parameters; 66 import std.meta: staticMap, NoDuplicates; 67 68 private alias symbol(alias F) = F.symbol; 69 70 alias allFunctionParameterTypes = 71 NoDuplicates!(staticMap!(FundamentalType, 72 staticMap!(Parameters, 73 staticMap!(symbol, functions)))); 74 } 75 76 77 // User-defined types 78 package template aggregates(publicMembers...) { 79 80 import std.meta: staticMap, Filter; 81 82 private template memberIsType(alias member) { 83 import std.traits: isType; 84 enum memberIsType = isType!(member.symbol); 85 } 86 87 private alias symbolOf(alias member) = member.symbol; 88 89 alias aggregates = staticMap!(symbolOf, Filter!(memberIsType, publicMembers)); 90 } 91 92 // Global variables 93 private template variables(publicMembers...) { 94 import std.meta: staticMap, Filter; 95 96 private enum isVariable(alias member) = is(typeof(member.symbol)); 97 private alias toVariable(alias member) = Variable!(typeof(member.symbol), __traits(identifier, member.symbol)); 98 alias variables = staticMap!(toVariable, Filter!(isVariable, publicMembers)); 99 } 100 101 /** 102 A global variable. 103 */ 104 template Variable(T, string N) { 105 alias Type = T; 106 enum name = N; 107 } 108 109 110 private template functionsBySymbol(alias mod, publicMembers...) { 111 112 import mirror.traits: memberIsRegularFunction; 113 import std.meta: Filter, staticMap; 114 115 private alias functionMembers = Filter!(memberIsRegularFunction, publicMembers); 116 117 private alias toFunction(alias member) = FunctionSymbol!( 118 member.symbol, 119 __traits(getProtection, member.symbol).toProtection, 120 __traits(getLinkage, member.symbol).toLinkage, 121 member.identifier, 122 mod, 123 ); 124 125 alias functionsBySymbol = staticMap!(toFunction, functionMembers); 126 } 127 128 129 /** 130 A function symbol with nested overloads. 131 */ 132 template FunctionSymbol( 133 alias F, 134 Protection P = __traits(getProtection, F).toProtection, 135 Linkage L = __traits(getLinkage, F).toLinkage, 136 string I = __traits(identifier, F), 137 alias Parent = moduleOf!F 138 ) 139 { 140 import std.meta: staticMap; 141 142 alias symbol = F; 143 enum identifier = I; 144 alias parent = Parent; 145 146 private alias toOverload(alias symbol) = FunctionOverload!( 147 symbol, 148 __traits(getProtection, symbol).toProtection, 149 __traits(getLinkage, symbol).toLinkage, 150 identifier, 151 parent, 152 ); 153 154 alias overloads = staticMap!(toOverload, __traits(getOverloads, parent, identifier)); 155 156 string toString() @safe pure { 157 import std.conv: text; 158 return text(`Function(`, overloads.stringof, ")"); 159 } 160 } 161 162 163 package template functionsByOverload(alias parent, publicMembers...) { 164 165 import mirror.traits: memberIsRegularFunction; 166 import std.meta: Filter, staticMap; 167 168 private alias functionMembers = Filter!(memberIsRegularFunction, publicMembers); 169 170 private template overload(alias S, string I) { 171 alias symbol = S; 172 enum identifier = I; 173 } 174 175 private template memberToOverloads(alias member) { 176 private alias overloadSymbols = __traits(getOverloads, parent, member.identifier); 177 private alias toOverload(alias symbol) = overload!(symbol, member.identifier); 178 alias memberToOverloads = staticMap!(toOverload, overloadSymbols); 179 } 180 181 private alias toFunction(alias overload) = FunctionOverload!( 182 overload.symbol, 183 __traits(getProtection, overload.symbol).toProtection, 184 __traits(getLinkage, overload.symbol).toLinkage, 185 overload.identifier, 186 parent, 187 ); 188 189 alias functionsByOverload = staticMap!(toFunction, staticMap!(memberToOverloads, functionMembers)); 190 } 191 192 193 /** 194 A specific overload of a function. In most cases it will be 195 synonymous with the function symbol since most functions aren't 196 overloaded. 197 */ 198 template FunctionOverload( 199 alias F, 200 Protection P = __traits(getProtection, F).toProtection, 201 Linkage L = __traits(getLinkage, F).toLinkage, 202 string I = __traits(identifier, F), 203 alias Parent = moduleOf!F 204 ) 205 { 206 import std.traits: RT = ReturnType; 207 208 alias symbol = F; 209 alias protection = P; 210 alias linkage = L; 211 enum identifier = I; 212 alias parent = Parent; 213 214 alias ReturnType = RT!symbol; 215 216 private template parametersImpl() { 217 import std.traits: Parameters, ParameterIdentifierTuple, ParameterDefaults; 218 import std.meta: staticMap, aliasSeqOf; 219 import std.range: iota; 220 221 alias parameter(size_t i) = 222 Parameter!(Parameters!symbol[i], ParameterDefaults!symbol[i], ParameterIdentifierTuple!symbol[i]); 223 alias parametersImpl = staticMap!(parameter, aliasSeqOf!(Parameters!F.length.iota)); 224 } 225 226 alias parameters = parametersImpl!(); 227 228 string toString() @safe pure { 229 import std.conv: text; 230 import std.traits: fullyQualifiedName; 231 return text(`Function(`, fullyQualifiedName!symbol, ", ", protection, ", ", linkage, ")"); 232 } 233 } 234 235 236 template Parameter(T, alias D, string I) { 237 alias Type = T; 238 alias Default = D; 239 enum identifier = I; 240 } 241 242 243 /// Visibilty/protection 244 enum Protection { 245 private_, 246 protected_, 247 public_, 248 export_, 249 package_, 250 } 251 252 253 Protection toProtection(in string str) @safe pure { 254 import std.conv: to; 255 return (str ~ "_").to!Protection; 256 } 257 258 259 /// 260 enum Linkage { 261 D, 262 C, 263 Cpp, 264 Windows, 265 ObjectiveC, 266 System, 267 } 268 269 270 Linkage toLinkage(in string str) @safe pure { 271 import std.conv: to; 272 if(str == "C++") return Linkage.Cpp; 273 return str.to!Linkage; 274 }