Last active
December 24, 2016 20:11
-
-
Save dhasenan/681b5178672556aa0e5ec8fb4c9eae7e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import | |
std.stdio, | |
std.file, | |
std.regex, | |
std.json, | |
std.algorithm, | |
std.range, | |
std.array, | |
std.traits, | |
std.format; | |
void main() | |
{ | |
SourceFile[] sources; | |
foreach (e; dirEntries("phobos/std", SpanMode.depth, false)) | |
{ | |
if (!e.isFile) continue; | |
if (!e.name.endsWith(".json")) continue; | |
sources ~= new SourceFile(e.name); | |
} | |
SourceFile[string] byModule; | |
foreach (s; sources) | |
{ | |
s.parse(); | |
byModule[s.moduleName] = s; | |
if (s.moduleName.endsWith(".package")) | |
{ | |
byModule[s.moduleName.replace(".package", "")] = s; | |
} | |
} | |
writeln("Constraints by module:"); | |
foreach (s; sources) | |
{ | |
if (s.constraints.length > 0) | |
writefln("\t%s: %s", s.moduleName, s.constraints); | |
} | |
writeln("Unique constraints:"); | |
auto uniques = sources.map!(s => s.constraints.byKey).joiner.array.sort.uniq.array; | |
foreach (u; uniques) | |
writeln("\t", u); | |
writeln("Cross-module dependencies:"); | |
auto uses = sources.map!(s => s.findExternalUsages(byModule)).joiner.array; | |
foreach (u; uses) | |
writeln("\t", u); | |
} | |
class SourceFile | |
{ | |
bool[string] templates; | |
bool[string] constraints; | |
bool[string] imports; | |
string file; | |
string moduleName; | |
this(string file) | |
{ | |
this.file = file; | |
} | |
void parse() | |
{ | |
auto j = readText(file).parseJSON; | |
moduleName = j[0]["name"].str; | |
j.visit!((v) { | |
if ("constraint" in v) | |
{ | |
foreach (m; matchAll(v["constraint"].str, templ)) | |
{ | |
constraints[m[1]] = true; | |
} | |
} | |
}); | |
j.visit!((v) { | |
if (v["kind"].str == "template") { | |
templates[v["name"].str] = true; | |
} | |
}); | |
j.visit!((v) { | |
auto kind = v["kind"].str; | |
if (kind == "import" || kind == "static import") | |
{ | |
imports[v["name"].str] = true; | |
} | |
}); | |
bool[string] filteredConstraints; | |
foreach (c, _; constraints) | |
{ | |
if (c !in templates) | |
{ | |
filteredConstraints[c] = true; | |
} | |
} | |
constraints = filteredConstraints; | |
} | |
auto findExternalUsages(SourceFile[string] byModule) | |
{ | |
auto imp = imports.byKey.filter!(x => x in byModule).array; | |
//writeln(imports.byKey.filter!(x => x !in byModule).array); | |
//writefln("finding usages: %s", moduleName); | |
if (constraints.length == 0 || imports.length == 0) return null; | |
return constraints | |
.byKey | |
.map!((x) => Usage( | |
this, | |
x, | |
imp | |
.map!(y => byModule[y]) | |
.filter!(s => x in s.templates) | |
.firstOr)) | |
//.filter!(x => x.definition !is null) | |
.array; | |
} | |
override string toString() { return moduleName; } | |
private: | |
auto templ = regex(`\b([a-zA-Z0-9_]+)\s*!\s*\(`); | |
} | |
struct Usage | |
{ | |
SourceFile usage; | |
string name; | |
SourceFile definition; | |
string toString() | |
{ | |
return "%s => %s.%s".format(usage, definition, name); | |
} | |
} | |
auto firstOr(TRange)(TRange r) | |
{ | |
typeof(r.front()) v; | |
if (!r.empty) | |
{ | |
v = r.front; | |
} | |
return v; | |
} | |
void visit(alias fn)(JSONValue v) | |
{ | |
if (v.type == JSON_TYPE.ARRAY) | |
{ | |
foreach (size_t i, JSONValue child; v) | |
{ | |
visit!fn(child); | |
} | |
} | |
else if (v.type == JSON_TYPE.OBJECT) | |
{ | |
fn(v); | |
if ("members" in v) | |
{ | |
visit!fn(v["members"]); | |
} | |
} | |
} | |
/* output: | |
Constraints by module: | |
std.algorithm.setops: ["anySatisfy":true, "CommonType":true, "staticMap":true, "allSatisfy":true] | |
std.algorithm.comparison: ["CommonType":true, "allSatisfy":true] | |
std.algorithm.iteration: ["isInputRange":true, "Parameters":true, "isBidirectionalRange":true, "ElementType":true, "isIterable":true] | |
std.algorithm.mutation: ["isOutputRange":true, "isNarrowString":true] | |
std.algorithm.searching: ["isInputRange":true, "isForwardRange":true, "ifTestable":true, "CommonType":true, "allSatisfy":true] | |
std.algorithm.sorting: ["isIntegral":true, "CommonType":true, "staticMap":true, "allSatisfy":true] | |
std.container.array: ["isImplicitlyConvertible":true] | |
std.container.binaryheap: ["isRandomAccessRange":true] | |
std.container.dlist: ["isImplicitlyConvertible":true] | |
std.container.rbtree: ["isImplicitlyConvertible":true, "allSatisfy":true] | |
std.container.slist: ["isImplicitlyConvertible":true] | |
std.digest.digest: ["allSatisfy":true] | |
std.digest.hmac: ["allSatisfy":true] | |
std.experimental.logger.core: ["isOutputRange":true, "Unqual":true] | |
std.experimental.ndslice.internal: ["allSatisfy":true] | |
std.experimental.ndslice.selection: ["Slice":true] | |
std.experimental.ndslice.slice: ["anySatisfy":true, "isDynamicArray":true, "DynamicArrayDimensionsCount":true, "allSatisfy":true] | |
std.experimental.typecons: ["Bind":true, "allSatisfy":true] | |
std.internal.math.biguintcore: ["isSomeChar":true] | |
std.internal.cstring: ["isSomeChar":true] | |
std.net.isemail: ["Unqual":true] | |
std.range.interfaces: ["isInputRange":true] | |
std.range: ["isInfinite":true, "isFloatingPoint":true, "isRandomAccessRange":true, "isPointer":true, "hasSlicing":true, "allSatisfy":true, "isInputRange":true, "isIntegral":true, "isBidirectionalRange":true, "hasLength":true, "staticMap":true, "CommonType":true, "isOutputRange":true, "ElementType":true] | |
std.range.primitives: ["isNarrowString":true] | |
std.regex: ["ElementEncodingType":true, "isOutputRange":true] | |
std.base64: ["isOutputRange":true] | |
std.bigint: ["isSomeChar":true] | |
std.bitmanip: ["isOutputRange":true] | |
std.complex: ["isOutputRange":true] | |
std.csv: ["isOutputRange":true, "Unqual":true, "isSomeString":true] | |
std.datetime: ["Unqual":true, "isSafe":true] | |
std.encoding: ["Unqual":true, "isNativeOutputRange":true] | |
std.file: ["isSomeChar":true] | |
std.parallelism: ["isArray":true, "isRandomAccessRange":true] | |
std.stdio: ["isSomeChar":true, "Unqual":true] | |
std.utf: ["isSomeChar":true, "Unqual":true] | |
std.uuid: ["isSomeChar":true, "isIntegral":true, "Unqual":true, "allSatisfy":true] | |
std.variant: ["allSatisfy":true] | |
std.array: ["isDynamicArray":true, "isSomeString":true, "allSatisfy":true, "isInputRange":true, "hasIndirections":true, "Unqual":true, "isOutputRange":true, "ElementType":true] | |
std.conv: ["isFloatingPoint":true, "isSomeChar":true, "isSomeString":true, "isIntegral":true, "Unqual":true, "isImplicitlyConvertible":true, "staticIndexOf":true, "isOutputRange":true] | |
std.format: ["isSomeChar":true, "Unqual":true] | |
std.numeric: ["isFloatingPoint":true, "staticIndexOf":true, "CommonType":true] | |
std.path: ["anySatisfy":true, "isSomeChar":true, "Unqual":true, "isSomeString":true] | |
std.random: ["isIntegral":true, "isSomeChar":true, "CommonType":true, "Unqual":true, "isNumeric":true, "isFloatingPoint":true] | |
std.string: ["isSomeChar":true, "isOutputRange":true, "Unqual":true, "staticIndexOf":true] | |
std.typecons: ["isImplicitlyConvertible":true, "allSatisfy":true] | |
std.uni: ["isSomeChar":true, "isOutputRange":true, "Unqual":true] | |
Unique constraints: | |
Bind | |
CommonType | |
DynamicArrayDimensionsCount | |
ElementEncodingType | |
ElementType | |
Parameters | |
Slice | |
Unqual | |
allSatisfy | |
anySatisfy | |
hasIndirections | |
hasLength | |
hasSlicing | |
ifTestable | |
isArray | |
isBidirectionalRange | |
isDynamicArray | |
isFloatingPoint | |
isForwardRange | |
isImplicitlyConvertible | |
isInfinite | |
isInputRange | |
isIntegral | |
isIterable | |
isNarrowString | |
isNativeOutputRange | |
isNumeric | |
isOutputRange | |
isPointer | |
isRandomAccessRange | |
isSafe | |
isSomeChar | |
isSomeString | |
staticIndexOf | |
staticMap | |
Cross-module dependencies: | |
std.algorithm.setops => std.meta.anySatisfy | |
std.algorithm.setops => std.traits.CommonType | |
std.algorithm.setops => std.meta.staticMap | |
std.algorithm.setops => std.meta.allSatisfy | |
std.algorithm.comparison => std.traits.CommonType | |
std.algorithm.comparison => std.meta.allSatisfy | |
std.algorithm.iteration => std.range.primitives.isInputRange | |
std.algorithm.iteration => std.traits.Parameters | |
std.algorithm.iteration => std.range.primitives.isBidirectionalRange | |
std.algorithm.iteration => std.range.primitives.ElementType | |
std.algorithm.iteration => std.traits.isIterable | |
std.algorithm.mutation => std.range.primitives.isOutputRange | |
std.algorithm.mutation => std.traits.isNarrowString | |
std.algorithm.searching => std.range.primitives.isInputRange | |
std.algorithm.searching => std.range.primitives.isForwardRange | |
std.algorithm.searching => std.traits.ifTestable | |
std.algorithm.searching => std.traits.CommonType | |
std.algorithm.searching => std.meta.allSatisfy | |
std.algorithm.sorting => std.traits.isIntegral | |
std.algorithm.sorting => std.traits.CommonType | |
std.algorithm.sorting => std.meta.staticMap | |
std.algorithm.sorting => std.meta.allSatisfy | |
std.container.array => std.traits.isImplicitlyConvertible | |
std.container.binaryheap => std.range.primitives.isRandomAccessRange | |
std.container.dlist => std.traits.isImplicitlyConvertible | |
std.container.rbtree => std.traits.isImplicitlyConvertible | |
std.container.rbtree => std.meta.allSatisfy | |
std.container.slist => std.traits.isImplicitlyConvertible | |
std.digest.digest => std.meta.allSatisfy | |
std.digest.hmac => std.meta.allSatisfy | |
std.experimental.logger.core => null.isOutputRange | |
std.experimental.logger.core => std.traits.Unqual | |
std.experimental.ndslice.internal => std.meta.allSatisfy | |
std.experimental.ndslice.selection => std.experimental.ndslice.slice.Slice | |
std.experimental.ndslice.slice => std.meta.anySatisfy | |
std.experimental.ndslice.slice => std.traits.isDynamicArray | |
std.experimental.ndslice.slice => std.experimental.ndslice.internal.DynamicArrayDimensionsCount | |
std.experimental.ndslice.slice => std.meta.allSatisfy | |
std.experimental.typecons => std.typecons.Bind | |
std.experimental.typecons => std.meta.allSatisfy | |
std.internal.math.biguintcore => std.traits.isSomeChar | |
std.internal.cstring => std.traits.isSomeChar | |
std.net.isemail => std.traits.Unqual | |
std.range.interfaces => std.range.primitives.isInputRange | |
std.range => std.range.primitives.isInfinite | |
std.range => std.traits.isFloatingPoint | |
std.range => std.range.primitives.isRandomAccessRange | |
std.range => std.traits.isPointer | |
std.range => std.range.primitives.hasSlicing | |
std.range => std.meta.allSatisfy | |
std.range => std.range.primitives.isInputRange | |
std.range => std.traits.isIntegral | |
std.range => std.range.primitives.isBidirectionalRange | |
std.range => std.range.primitives.hasLength | |
std.range => std.meta.staticMap | |
std.range => std.traits.CommonType | |
std.range => std.range.primitives.isOutputRange | |
std.range => std.range.primitives.ElementType | |
std.range.primitives => std.traits.isNarrowString | |
std.regex => std.range.primitives.ElementEncodingType | |
std.regex => std.range.primitives.isOutputRange | |
std.base64 => std.range.primitives.isOutputRange | |
std.bigint => std.traits.isSomeChar | |
std.bitmanip => std.range.primitives.isOutputRange | |
std.complex => std.range.primitives.isOutputRange | |
std.csv => std.range.primitives.isOutputRange | |
std.csv => std.traits.Unqual | |
std.csv => std.traits.isSomeString | |
std.datetime => std.traits.Unqual | |
std.datetime => std.traits.isSafe | |
std.encoding => std.traits.Unqual | |
std.encoding => std.range.primitives.isNativeOutputRange | |
std.file => std.traits.isSomeChar | |
std.parallelism => std.traits.isArray | |
std.parallelism => null.isRandomAccessRange | |
std.stdio => std.traits.isSomeChar | |
std.stdio => std.traits.Unqual | |
std.utf => std.traits.isSomeChar | |
std.utf => std.traits.Unqual | |
std.uuid => std.traits.isSomeChar | |
std.uuid => std.traits.isIntegral | |
std.uuid => std.traits.Unqual | |
std.uuid => std.meta.allSatisfy | |
std.variant => std.meta.allSatisfy | |
std.array => std.traits.isDynamicArray | |
std.array => std.traits.isSomeString | |
std.array => std.meta.allSatisfy | |
std.array => std.range.primitives.isInputRange | |
std.array => std.traits.hasIndirections | |
std.array => std.traits.Unqual | |
std.array => std.range.primitives.isOutputRange | |
std.array => std.range.primitives.ElementType | |
std.conv => std.traits.isFloatingPoint | |
std.conv => std.traits.isSomeChar | |
std.conv => std.traits.isSomeString | |
std.conv => std.traits.isIntegral | |
std.conv => std.traits.Unqual | |
std.conv => std.traits.isImplicitlyConvertible | |
std.conv => std.meta.staticIndexOf | |
std.conv => std.range.primitives.isOutputRange | |
std.format => std.traits.isSomeChar | |
std.format => std.traits.Unqual | |
std.numeric => std.traits.isFloatingPoint | |
std.numeric => std.meta.staticIndexOf | |
std.numeric => std.traits.CommonType | |
std.path => std.meta.anySatisfy | |
std.path => std.traits.isSomeChar | |
std.path => std.traits.Unqual | |
std.path => std.traits.isSomeString | |
std.random => std.traits.isIntegral | |
std.random => std.traits.isSomeChar | |
std.random => std.traits.CommonType | |
std.random => std.traits.Unqual | |
std.random => std.traits.isNumeric | |
std.random => std.traits.isFloatingPoint | |
std.string => std.traits.isSomeChar | |
std.string => std.range.primitives.isOutputRange | |
std.string => std.traits.Unqual | |
std.string => std.meta.staticIndexOf | |
std.typecons => std.traits.isImplicitlyConvertible | |
std.typecons => std.meta.allSatisfy | |
std.uni => std.traits.isSomeChar | |
std.uni => std.range.primitives.isOutputRange | |
std.uni => std.traits.Unqual | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment