-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3162 from tanmaykm/typetree
Fixes #3133 : print unexported types also
- Loading branch information
Showing
1 changed file
with
97 additions
and
103 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,125 +1,119 @@ | ||
## | ||
# | ||
# (spaghetti) Code to create a text graphic of the Julia type tree | ||
# Used to generate https://github.com/JuliaLang/julia/wiki/Types-Hierarchy | ||
# | ||
# Generate a text graphic of Julia modules type tree | ||
## | ||
|
||
function list_all(T::Type, modules::Array{Module}, f::Function) | ||
a = Dict{String, T}() | ||
for m = modules | ||
sm = string(m) | ||
for s = names(m,true) | ||
try | ||
t = eval(m,s) | ||
if f(t) | ||
a[string(s)] = t | ||
end | ||
end | ||
end | ||
end | ||
a | ||
# The node type holds the type of the cuurent node and a dict of subtypes | ||
type TTNode | ||
strname::String | ||
typ::Type | ||
subtypes::Dict{String, TTNode} | ||
|
||
TTNode(sname::String, t::Type) = new(sname, t, Dict{String, TTNode}()) | ||
end | ||
|
||
function to_array{T}(s::Set{T}) | ||
a = Array(T, length(s)) | ||
i = 1 | ||
for ele = s | ||
a[i] = ele | ||
i += 1 | ||
end | ||
a | ||
# Add a node to a dict if not added | ||
function add_ttnode(subtypes::Dict{String, TTNode}, sname::String, tnode::TTNode) | ||
ret = get(subtypes, sname, nothing) | ||
(nothing == ret) && (ret = subtypes[sname] = tnode) | ||
ret | ||
end | ||
|
||
function mk_tree() | ||
for (x,t) in all_types | ||
add_type(x,t,true) | ||
end | ||
function add_ttnode(subtypes::Dict{String, TTNode}, sname::String, t::Type) | ||
ret = get(subtypes, sname, nothing) | ||
(nothing == ret) && (subtypes[sname] = ret = TTNode(sname, t)) | ||
ret | ||
end | ||
extra = Dict{String, String}() | ||
function insert_type(m,s,x,ex) | ||
try | ||
ms = m[s] | ||
add!(ms, x) | ||
catch | ||
m[s] = Set{String}(x) | ||
|
||
# Get a string name for the type | ||
typ_name(t::UnionType) = string(t) | ||
typ_name(t::TypeConstructor) = string(t) | ||
typ_name(t) = string(t.name) | ||
|
||
# Store a type and its type hierarchy chain | ||
# Recurse till we reach the top level type | ||
function store_type(sname::String, t::UnionType) | ||
suptype = UnionType | ||
tnode = TTNode(sname, t) | ||
|
||
# store unions under UnionType type | ||
subtypes = store_type(typ_name(suptype), suptype) | ||
add_ttnode(subtypes, sname, tnode) | ||
|
||
# unions are also in a sense related to the types of their components | ||
for suptype = t.types | ||
subtypes = store_type(typ_name(suptype), suptype) | ||
add_ttnode(subtypes, sname, tnode) | ||
end | ||
extra[x] = ex | ||
|
||
return tnode.subtypes | ||
end | ||
|
||
function add_type(x,t,sup) | ||
if isa(t, DataType) | ||
s = sup ? super(t) : t | ||
s_param = "" | ||
if x != string(t.name) | ||
s_param *= " = " * string(t.name) | ||
elseif length(s.parameters) != 0 | ||
s_param *= " (=" * string(s.name) * "{" * join(s.parameters, ", ") * "})" | ||
end | ||
insert_type(children_map, string(s.name), x, s_param) | ||
elseif isa(t, UnionType) | ||
for c in t.types | ||
add_type(x, c, false) | ||
end | ||
insert_type(children_map, "UnionType", x, " = " * string(t)) | ||
elseif isa(t, TypeConstructor) | ||
add_type(x, t.body, false) | ||
#println(typeof(t.body)) | ||
insert_type(children_map, "TypeConstructor", x, " = " * string(t)) | ||
else | ||
function store_type(sname::String, t::TypeConstructor) | ||
suptype = t.body | ||
subtypes = store_type(typ_name(suptype), suptype) | ||
tnode = add_ttnode(subtypes, sname, t) | ||
return tnode.subtypes | ||
end | ||
|
||
function store_type(sname::String, t::DataType) | ||
suptype = super(t) | ||
subtypes = (suptype != t) ? store_type(typ_name(suptype), suptype) : types_tree | ||
tnode = add_ttnode(subtypes, sname, t) | ||
return tnode.subtypes | ||
end | ||
|
||
function store_type(sname::String, t::Tuple) | ||
tnode = add_ttnode(types_tree, sname, t) | ||
return tnode.subtypes | ||
end | ||
|
||
function store_type(sname::String, t) | ||
suptype = super(t) | ||
subtypes = (suptype != t) ? store_type(typ_name(suptype), suptype) : types_tree | ||
tnode = add_ttnode(subtypes, sname, t) | ||
return tnode.subtypes | ||
end | ||
|
||
# examine all symbols in module and store those that are types | ||
function store_all_from(m::Module) | ||
for expr = names(m,true) | ||
try | ||
print("unknown -> ") | ||
print(x) | ||
print(" ") | ||
print(typeof(t)) | ||
print(" ") | ||
print(t.name) | ||
t = eval(m,expr) | ||
isa(t, Type) && store_type(string(expr), t) | ||
#catch ex | ||
# println("Error adding ", string(expr), " ", t, " ", m, " (", ex, ")") | ||
end | ||
println(t) | ||
end | ||
end | ||
|
||
function show_tree(root, prefix, norm_ex) | ||
r = root | ||
t = all_types[root] | ||
try | ||
if length(t.parameters) != 0 | ||
root *= "{" * join(t.parameters, ", ") * "}" | ||
end | ||
end | ||
ex = extra[r] | ||
if ex != norm_ex | ||
root *= ex | ||
end | ||
println(prefix[1:end-1] * "+- " * root) | ||
norm_ex = "" | ||
try | ||
norm_ex = " (=" * r * "{" * join(t.parameters, ", ") * "})" | ||
end | ||
children = get(children_map, r, None) | ||
if children != None | ||
ch = to_array(children) | ||
sort!(ch) | ||
delete!(children_map, r) | ||
iter = start(ch) | ||
cpre = prefix * " +" | ||
dpre = prefix * " " | ||
while !done(ch, iter) | ||
c,iter = next(ch, iter) | ||
if c != root | ||
show_tree(c, done(ch, iter) ? dpre : cpre, norm_ex) | ||
end | ||
|
||
type_props(typ) = "" | ||
type_props(typ::DataType) = string("<<", | ||
typ.abstract ? " abstract" : " concrete", | ||
typ.mutable ? " mutable" : " immutable", | ||
typ.pointerfree ? " pointerfree" : "", | ||
" size:", typ.size, | ||
" >>") | ||
|
||
function print_tree(subtypes::Dict{String, TTNode}, pfx::String="") | ||
for (n,v) in subtypes | ||
if(n == string(v.typ)) | ||
println(pfx, "+- ", n, " ", type_props(v.typ)) | ||
else | ||
println(pfx, "+- ", n, " = ", v.typ, " ", type_props(v.typ)) | ||
end | ||
print_tree(v.subtypes, pfx * ". ") | ||
end | ||
end | ||
|
||
show_tree(root) = show_tree(root, "", "") | ||
|
||
## main ## | ||
all_types = list_all(Type, [Core, Base, Main], (x)->isa(x, Type)) | ||
children_map = Dict{String, Set{String}}() | ||
mk_tree() | ||
println("\n\nType Tree:") | ||
show_tree("Any") #todo: generalize this to be every item without a parent in all_types | ||
# TODO: optionally take module names in command line | ||
# TODO: sort output | ||
# TODO: option to list subtrees of type tree, or other symbol types | ||
const types_tree = Dict{String, TTNode}() | ||
|
||
for m = [Base, Core, Main] | ||
store_all_from(m) | ||
end | ||
|
||
print_tree(types_tree) | ||
|