paul@149 | 1 | #!/usr/bin/env python |
paul@149 | 2 | |
paul@149 | 3 | """ |
paul@149 | 4 | A module providing elementary graph support for programs. |
paul@149 | 5 | |
paul@149 | 6 | Copyright (C) 2008 Paul Boddie <paul@boddie.org.uk> |
paul@149 | 7 | |
paul@149 | 8 | This program is free software; you can redistribute it and/or modify it under |
paul@149 | 9 | the terms of the GNU General Public License as published by the Free Software |
paul@149 | 10 | Foundation; either version 3 of the License, or (at your option) any later |
paul@149 | 11 | version. |
paul@149 | 12 | |
paul@149 | 13 | This program is distributed in the hope that it will be useful, but WITHOUT |
paul@149 | 14 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
paul@149 | 15 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
paul@149 | 16 | details. |
paul@149 | 17 | |
paul@149 | 18 | You should have received a copy of the GNU General Public License along with |
paul@149 | 19 | this program. If not, see <http://www.gnu.org/licenses/>. |
paul@149 | 20 | """ |
paul@149 | 21 | |
paul@149 | 22 | import micropython.inspect |
paul@149 | 23 | import micropython.common |
paul@149 | 24 | import micropython.data |
paul@149 | 25 | import sys |
paul@149 | 26 | |
paul@149 | 27 | def get_graph(importer, out=None, with_builtins=0): |
paul@149 | 28 | |
paul@149 | 29 | """ |
paul@149 | 30 | Using the program maintained by the given 'importer', write out the graph |
paul@149 | 31 | definition for consumption by the Graphviz tools such as the dot program. |
paul@149 | 32 | If the optional 'out' parameter is set to a stream, that stream will be |
paul@149 | 33 | used to write out the graph definition; otherwise, standard output will be |
paul@149 | 34 | used. If 'with_builtins' is set to a true value, the module providing the |
paul@149 | 35 | built-in classes and functions will also be represented in the graph. |
paul@149 | 36 | """ |
paul@149 | 37 | |
paul@149 | 38 | out = out or sys.stdout |
paul@149 | 39 | print >>out, 'digraph G {' |
paul@149 | 40 | print >>out, ' ratio=auto;' |
paul@149 | 41 | print >>out, ' center=true;' |
paul@149 | 42 | print >>out, ' rankdir=LR;' |
paul@149 | 43 | for module in importer.modules_ordered: |
paul@149 | 44 | if not with_builtins and module.name == "__builtins__": |
paul@149 | 45 | continue |
paul@149 | 46 | |
paul@149 | 47 | print >>out, ' subgraph "%s" {' % module.full_name() |
paul@149 | 48 | print >>out, ' label="%s";' % module.full_name() |
paul@149 | 49 | for obj in module.all_objects: |
paul@149 | 50 | |
paul@149 | 51 | if isinstance(obj, micropython.inspect.Class): |
paul@149 | 52 | print >>out, ' "%s" [' % obj.full_name(), |
paul@149 | 53 | print >>out, 'shape=record,', |
paul@149 | 54 | print >>out, 'label="{<%s> %s|{' % (obj.full_name(), obj.full_name()), |
paul@149 | 55 | first = 1 |
paul@149 | 56 | for attr in obj.all_attributes().values(): |
paul@149 | 57 | if not first: |
paul@149 | 58 | print >>out, '|', |
paul@149 | 59 | print >>out, '<%s> %s' % (attr.name, attr.name), |
paul@149 | 60 | first = 0 |
paul@149 | 61 | print >>out, '}}"];' |
paul@149 | 62 | |
paul@149 | 63 | elif isinstance(obj, micropython.inspect.Function): |
paul@149 | 64 | print >>out, ' "%s" [' % obj.full_name(), |
paul@149 | 65 | print >>out, 'shape=record,', |
paul@149 | 66 | print >>out, 'label="{<%s> %s|{' % (obj.full_name(), obj.full_name()), |
paul@149 | 67 | first = 1 |
paul@149 | 68 | for attr in obj.all_locals().values(): |
paul@149 | 69 | if not first: |
paul@149 | 70 | print >>out, '|', |
paul@149 | 71 | print >>out, '<%s> %s' % (attr.name, attr.name), |
paul@149 | 72 | first = 0 |
paul@149 | 73 | print >>out, '}}"];' |
paul@149 | 74 | |
paul@149 | 75 | print >>out, ' }' |
paul@149 | 76 | |
paul@149 | 77 | for module in importer.modules_ordered: |
paul@149 | 78 | if not with_builtins and module.name == "__builtins__": |
paul@149 | 79 | continue |
paul@149 | 80 | |
paul@149 | 81 | print >>out, ' {' |
paul@149 | 82 | for obj in module.all_objects: |
paul@149 | 83 | if isinstance(obj, micropython.inspect.Class): |
paul@149 | 84 | for attr in obj.all_attributes().values(): |
paul@195 | 85 | for value in attr.get_values(): |
paul@195 | 86 | if value is not None: |
paul@195 | 87 | print >>out, ' "%s":%s -> "%s";' % (obj.full_name(), attr.name, get_name(value)) |
paul@149 | 88 | elif isinstance(obj, micropython.inspect.Function): |
paul@149 | 89 | for attr in obj.all_locals().values(): |
paul@195 | 90 | for value in attr.get_values(): |
paul@195 | 91 | if value is not None: |
paul@195 | 92 | print >>out, ' "%s":%s -> "%s";' % (obj.full_name(), attr.name, get_name(value)) |
paul@149 | 93 | print >>out, ' }' |
paul@149 | 94 | |
paul@149 | 95 | print >>out, "}" |
paul@149 | 96 | |
paul@149 | 97 | def get_name(obj): |
paul@201 | 98 | if isinstance(obj, micropython.data.Naming): |
paul@149 | 99 | return obj.full_name() |
paul@149 | 100 | elif isinstance(obj, micropython.data.Const): |
paul@149 | 101 | return obj.value_type_name() |
paul@149 | 102 | else: |
paul@149 | 103 | return "<None>" |
paul@149 | 104 | |
paul@149 | 105 | # vim: tabstop=4 expandtab shiftwidth=4 |