1 module glued.codescan.unrollscan; 2 3 import std.conv: to; 4 import std.traits; 5 import std.meta; 6 import std..string; 7 8 import glued.mirror; 9 import glued.utils; 10 11 public import glued.codescan.scannable; 12 13 //DEV NOTE ON VISIBILITY LEVELS 14 // 15 //following functions are called statically during the mixin; because of that 16 //they need to be public, to be available on mixin point; 17 //if they are private, then module mixing them in won't be able to resolve 18 //them, even though they are in the same module as mixin (since mixins are 19 //evaluated at mixin point, not declaration point) 20 21 string scanModule(string name, alias aggregateConsumer)(){ 22 StringBuilder builder; 23 mixin("static import "~name~";"); 24 mixin("alias mod_ = "~name~";"); 25 static foreach (alias mem; __traits(allMembers, mod_)){ 26 static if (__traits(compiles, __traits(getMember, mod_, mem))){ 27 static if (is(__traits(getMember, mod_, mem))){ 28 // if we encounter enum of form "enum Name;" (or "enum Name: int;") 29 // we get: 30 // Error: enum ...Name is forward referenced looking for base type 31 // or: 32 // Error: enum ...Name is forward referenced when looking for stringof 33 // etc 34 // To avoid that we filter out enums without members, which loosely relates to aforementioned situations 35 //todo investigate how loosely 36 static if ( 37 !is(__traits(getMember, mod_, mem) == enum) || 38 EnumMembers!(__traits(getMember, mod_, mem)).length > 0 39 ) 40 builder.append(aggregateConsumer!(name, mem)); 41 } 42 } 43 } 44 return builder.result; 45 } 46 47 enum NoOp(T...) = ""; 48 49 string scanIndexModule(string index, alias scannable, alias aggregateConsumer, alias bundleConsumer)(){ 50 StringBuilder builder; 51 mixin("static import "~index~";"); 52 mixin("alias mod_ = "~index~";"); 53 static if (mod_.Index.hasBundle){ 54 builder.append( 55 bundleConsumer!(mod_.Index.bundleModule) 56 ); 57 } 58 static if (mod_.Index.importablePackage) 59 builder.append( 60 scanModule!(mod_.Index.packageName, aggregateConsumer)() 61 ); 62 static foreach (string submodule; EnumMembers!(mod_.Index.submodules)){ 63 builder.append( 64 scanModule!(submodule, aggregateConsumer)() 65 ); 66 } 67 static foreach (string subpackage; EnumMembers!(mod_.Index.subpackages)){ 68 builder.append( 69 prepareScan!( 70 scannable.withRoot(subpackage), 71 "", 72 aggregateConsumer, 73 bundleConsumer, 74 "" 75 )()); //todo qualifiers 76 } 77 return builder.result; 78 } 79 80 string prepareScan(alias scannable, string setup, alias aggregateConsumer, alias bundleConsumer, string teardown)(){ 81 StringBuilder builder; 82 builder.append(setup); 83 84 builder.append( 85 scanIndexModule!( 86 scannable.root~"."~scannable.prefix~"_index", 87 scannable, 88 aggregateConsumer, 89 bundleConsumer 90 )() 91 ); 92 93 version(unittest){ 94 builder.append( 95 scanIndexModule!( 96 scannable.root~"."~scannable.testPrefix~"_index", 97 scannable, 98 aggregateConsumer, 99 bundleConsumer 100 )() 101 ); 102 } 103 104 builder.append(teardown); 105 builder.removeEmptyLines(); 106 return builder.result; 107 } 108 109 mixin template unrollLoopThrough(alias scannable, string setup, alias aggregateConsumer, alias bundleConsumer, string teardown, 110 string f=__FILE__, int l=__LINE__, string m=__MODULE__, string foo=__FUNCTION__, string prettyFoo=__PRETTY_FUNCTION__) 111 if (isScannable!(scannable)) 112 { 113 import glued.logging; 114 mixin CreateLogger!(); 115 mixin( 116 Logger.logged!(f, l, m, foo, prettyFoo)().value!( 117 prepareScan!( 118 scannable, 119 setup, 120 aggregateConsumer, 121 bundleConsumer, 122 teardown 123 )() 124 ) 125 ); 126 }