1 #!/usr/bin/env python 2 3 """ 4 A module providing elementary graph support for programs. 5 6 Copyright (C) 2008, 2009, 2010, 2011 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 """ 21 22 from micropython.common import TableError 23 from micropython.data import Class, Function 24 import sys 25 26 def get_graph(program, out=None): 27 28 """ 29 Using the importer maintained by the given 'program', write out the graph 30 definition for consumption by the Graphviz tools such as the dot program. 31 If the optional 'out' parameter is set to a stream, that stream will be 32 used to write out the graph definition; otherwise, standard output will be 33 used. 34 35 A command line like the following can be used to produce viewable graph 36 files: 37 38 dot -T svg -o output.svg output.dot 39 """ 40 41 importer = program.get_importer() 42 objtable = program.get_object_table() 43 44 out = out or sys.stdout 45 print >>out, 'digraph G {' 46 print >>out, ' ratio=auto;' 47 print >>out, ' center=true;' 48 print >>out, ' rankdir=LR;' 49 50 for from_name, attributes in importer.inferred_name_references.items(): 51 from_attribute = get_unit(objtable, from_name) 52 if from_attribute: 53 for objname, attrname in attributes: 54 if not have_unit(objtable, objname, attrname): 55 continue 56 colour = get_colour(from_name, objname, attrname, importer) 57 print >>out, ' "%s" -> "%s.%s" [color="%s"];' % (from_name, objname, attrname, colour) 58 59 print >>out, "}" 60 61 def get_colour(from_name, objname, attrname, importer): 62 try: 63 if (objname, attrname) in importer.specific_name_references[from_name]: 64 return "red" 65 except KeyError: 66 pass 67 return "black" 68 69 def get_unit(objtable, attribute): 70 t = attribute.rsplit(".", 1) 71 try: 72 objname, attrname = t 73 if not have_unit(objtable, objname, attrname, Function): 74 return None 75 return attribute 76 except ValueError: 77 return t[0] 78 79 def have_unit(objtable, objname, attrname, allowed_types=None): 80 allowed_types = allowed_types or (Class, Function) 81 try: 82 attr = objtable.access(objname, attrname) 83 except TableError: 84 #print >>sys.stderr, "%s.%s not found!" % (objname, attrname) 85 return 0 86 87 for value in attr.get_values(): 88 if isinstance(value, allowed_types): 89 return 1 90 return 0 91 92 # vim: tabstop=4 expandtab shiftwidth=4