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