File: Synopsis/Formatters/Dump.py
  1#
  2# Copyright (C) 2003 Stefan Seefeld
  3# All rights reserved.
  4# Licensed to the public under the terms of the GNU LGPL (>= 2),
  5# see the file COPYING for details.
  6#
  7
  8"""
  9Verbose attribute-oriented xml dump of ASG, useful for validation,
 10introspection, and debugging.
 11"""
 12
 13from Synopsis import config
 14from Synopsis.Processor import *
 15from Synopsis.SourceFile import SourceFile
 16from Synopsis.DocString import DocString
 17from Synopsis.QualifiedName import *
 18
 19import sys, getopt, os, os.path, string, types
 20from xml.dom.minidom import getDOMImplementation
 21
 22dom = getDOMImplementation().createDocument(None, 'dump', None)
 23
 24class Formatter(Processor):
 25
 26    show_ids = Parameter(True, 'output object ids as attributes')
 27    show_declarations = Parameter(True, 'output declarations')
 28    show_types = Parameter(True, 'output types')
 29    show_files = Parameter(True, 'output files')
 30    stylesheet = Parameter(config.datadir + '/dump.css', 'stylesheet to be referenced for rendering')
 31
 32    def process(self, ir, **kwds):
 33
 34        self.set_parameters(kwds)
 35        if not self.output: raise MissingArgument('output')
 36        self.ir = self.merge_input(ir)
 37
 38        self.handlers = {type(None) : self.visit_none,
 39                         type : self.visit_type,
 40                         int : self.visit_string,
 41                         long : self.visit_string,
 42                         float : self.visit_string,
 43                         str : self.visit_string,
 44                         bool : self.visit_string,
 45                         tuple : self.visit_tuple,
 46                         list : self.visit_list,
 47                         dict : self.visit_dict,
 48                         types.InstanceType : self.visit_instance,
 49                         QualifiedName : self.visit_string,
 50                         QualifiedCxxName : self.visit_string,
 51                         QualifiedPythonName : self.visit_string,
 52                         SourceFile : self.visit_sourcefile,
 53                         DocString : self.visit_docstring}
 54        self.visited = []
 55
 56        self.os = open(self.output, 'w')
 57        self.os.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n')
 58        if self.stylesheet:
 59            self.os.write('<?xml-stylesheet href="%s" type="text/css"?>\n'%self.stylesheet)
 60
 61        self.os.write('<ir>\n')
 62        self.os.write('<asg>\n')
 63
 64        if self.show_declarations:
 65            self.write_declarations(self.ir.asg.declarations)
 66
 67        if self.show_types:
 68            self.write_types(self.ir.asg.types)
 69        self.os.write('</asg>\n')
 70
 71        if self.show_files:
 72            self.write_files(self.ir.files)
 73
 74        self.os.write('</ir>\n')
 75
 76        return self.ir
 77
 78    def push(self, name):
 79
 80        element = dom.createElement(name)
 81        self.node.appendChild(element)
 82        self.node = element
 83
 84    def pop(self):
 85
 86        self.node = self.node.parentNode
 87
 88    def add_text(self, text):
 89
 90        node = dom.createTextNode(text)
 91        self.node.appendChild(node)
 92
 93    def visit(self, obj):
 94        i,t = id(obj), type(obj)
 95        if i in self.visited:
 96            if self.show_ids:
 97                self.node.setAttribute('xref', str(i))
 98            return
 99        if self.handlers.has_key(t):
100            self.handlers[t](obj)
101        elif issubclass(t, object):
102            self.visit_instance(obj)
103        else:
104            print 'Unknown type %s for object: "%s"'%(t,obj)
105
106    def visit_none(self, obj): pass
107    def visit_string(self, obj): self.add_text(str(obj))
108    def visit_type(self, obj): self.write(obj) # where is that used ??
109
110    def visit_tuple(self, obj):
111
112        if len(obj) == 0: return
113        for i in obj:
114            self.push('item')
115            self.visit(i)
116            self.pop()
117
118    def visit_list(self, obj):
119
120        if len(obj) == 0: return
121        for i in obj:
122            self.push('item')
123            self.visit(i)
124            self.pop()
125
126    def visit_dict(self, dict):
127
128        items = dict.items()
129        if len(items) == 0: return
130        items.sort()
131        for i in items:
132            self.push('key')
133            self.visit(i[0])
134            self.pop()
135            self.push('value')
136            self.visit(i[1])
137            self.pop()
138
139
140    def visit_sourcefile(self, obj):
141
142        self.node.setAttribute('name', obj.name)
143        self.node.setAttribute('language', obj.annotations.get('language', ''))
144        self.node.setAttribute('primary', str(obj.annotations.get('primary', False)))
145
146        includes = getattr(obj, 'includes')
147        if includes:
148            self.push('includes')
149            self.visit(includes)
150            self.pop()
151
152        if self.show_declarations:
153            for name in ['declarations', 'macro_calls']:
154                self.push(name)
155                self.visit(getattr(obj, name))
156                self.pop()
157
158    def visit_docstring(self, obj):
159
160        self.node.setAttribute('markup', obj.markup)
161        self.push('text')
162        self.visit(obj.text)
163        self.pop()
164
165
166    def visit_instance(self, obj):
167        self.visited.append(id(obj))
168        self.push('instance')
169        self.node.setAttribute('class', '%s.%s'%(obj.__class__.__module__,obj.__class__.__name__))
170        if self.show_ids:
171            self.node.setAttribute('id', str(id(obj)))
172        if self.handlers.has_key(obj.__class__):
173            self.handlers[obj.__class__](obj)
174        else:
175            attrs = obj.__dict__.items()
176            attrs.sort()
177            for name, value in attrs:
178                # ignore None values
179                if value in (None, [], ()):
180                    continue
181                # ignore private attributes
182                if name[0] == '_':
183                    continue
184
185                # String attributes map to xml attributes.
186                if self.handlers.get(type(value)) == self.visit_string:
187                    self.node.setAttribute(name, str(value))
188                    # Everything else maps to sub-elements.
189                else:
190                    self.push(name)
191                    self.visit(value)
192                    self.pop()
193        self.pop()
194
195    def write_declarations(self, declarations):
196
197        self.node = dom.createElement('declarations')
198        for d in declarations:
199            self.push('item')
200            self.visit(d)
201            self.pop()
202        self.node.writexml(self.os, indent=' ', addindent=' ', newl='\n')
203        self.node.unlink()
204        del self.node
205
206    def write_types(self, types):
207
208        self.node = dom.createElement('types')
209        values = types.values()
210        values.sort()
211        for t in values: self.visit(t)
212        self.node.writexml(self.os, indent=' ', addindent=' ', newl='\n')
213        self.node.unlink()
214        del self.node
215
216    def write_files(self, files):
217
218        self.node = dom.createElement('files')
219        for f in files: self.visit(files[f])
220        self.node.writexml(self.os, indent=' ', addindent=' ', newl='\n')
221        self.node.unlink()
222        del self.node
223
224