1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
|
module TypeTrees
##
# Generate a text graphic of Julia modules type tree
##
# 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
# 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 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
# 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
return tnode.subtypes
end
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
t = eval(m,expr)
isa(t, Type) && store_type(string(expr), t)
#catch ex
# println("Error adding ", string(expr), m, " (", ex, ")")
end
end
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 in sort!([keys(subtypes)...])
v = subtypes[n]
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
# 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 in (Base, Core, Main)
store_all_from(m)
end
# print_tree(types_tree)
end # module
|