Skip to content

Instantly share code, notes, and snippets.

@dhasenan
Last active December 24, 2016 20:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dhasenan/681b5178672556aa0e5ec8fb4c9eae7e to your computer and use it in GitHub Desktop.
Save dhasenan/681b5178672556aa0e5ec8fb4c9eae7e to your computer and use it in GitHub Desktop.
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