File: Synopsis/Formatters/BoostBook.py
  1#
  2# Copyright (C) 2000 Stefan Seefeld
  3# Copyright (C) 2000 Stephen Davies
  4# All rights reserved.
  5# Licensed to the public under the terms of the GNU LGPL (>= 2),
  6# see the file COPYING for details.
  7#
  8
  9"""a BoostBook formatter"""
 10
 11from Synopsis.Processor import Processor, Parameter
 12from Synopsis import ASG
 13
 14import sys, getopt, os, os.path
 15
 16class Formatter(Processor, ASG.Visitor):
 17   """
 18   The type visitors should generate names relative to the current scope.
 19   The generated references however are fully scoped names
 20   """
 21
 22   def process(self, ir, **kwds):
 23
 24      self.set_parameters(kwds)
 25      self.ir = self.merge_input(ir)
 26
 27      self.__os = open(self.output, 'w')
 28      self.__scope = ()
 29      self.__scopestack = []
 30      self.__indent = 0
 31      self.__type_label = ''
 32
 33      for d in ir.asg.declarations:
 34         d.accept(self)
 35
 36      self.__os.close()
 37
 38      return self.ir
 39
 40   def scope(self): return self.__scope
 41   def push_scope(self, newscope):
 42
 43      self.__scopestack.append(self.__scope)
 44      self.__scope = newscope
 45
 46   def pop_scope(self):
 47
 48      self.__scope = self.__scopestack[-1]
 49      del self.__scopestack[-1]
 50
 51   def write(self, text):
 52      """Write some text to the output stream, replacing \n's with \n's and
 53      indents."""
 54
 55      indent = ' ' * self.__indent
 56      self.__os.write(text.replace('\n', '\n'+indent))
 57
 58   def start_entity(self, __type, **__params):
 59      """Write the start of an entity, ending with a newline"""
 60
 61      param_text = ""
 62      if __params: param_text = " " + string.join(map(lambda p:'%s="%s"'%(p[0].lower(), p[1]), __params.items()))
 63      self.write("<" + __type + param_text + ">")
 64      self.__indent = self.__indent + 2
 65      self.write("\n")
 66
 67   def end_entity(self, type):
 68      """Write the end of an entity, starting with a newline"""
 69
 70      self.__indent = self.__indent - 2
 71      self.write("\n</" + type + ">")
 72
 73   def write_entity(self, __type, __body, **__params):
 74      """Write a single entity on one line (though body may contain
 75      newlines)"""
 76
 77      param_text = ""
 78      if __params: param_text = " " + string.join(map(lambda p:'%s="%s"'%(p[0].lower(), p[1]), __params.items()))
 79      self.write("<" + __type + param_text + ">")
 80      self.__indent = self.__indent + 2
 81      self.write(__body)
 82      self.__indent = self.__indent - 2
 83      self.write("</" + __type + ">")
 84
 85   def entity(self, __type, __body, **__params):
 86      """Return but do not write the text for an entity on one line"""
 87
 88      param_text = ""
 89      if __params: param_text = " " + string.join(map(lambda p:'%s="%s"'%(p[0].lower(), p[1]), __params.items()))
 90      return "<%s%s>%s</%s>"%(__type, param_text, __body, __type)
 91
 92   def reference(self, ref, label):
 93      """reference takes two strings, a reference (used to look up the symbol and generated the reference),
 94      and the label (used to actually write it)"""
 95
 96      location = self.__toc.lookup(ref)
 97      if location != "": return href("#" + location, label)
 98      else: return span("type", str(label))
 99
100   def label(self, ref):
101
102      location = self.__toc.lookup(str(ref))
103      ref = str(self.scope().prune(ref))
104      if location != "": return name("\"" + location + "\"", ref)
105      else: return ref
106
107   def type_label(self): return self.__type_label
108   #################### Type Visitor ##########################################
109
110   def visit_builtin_type_id(self, type):
111
112      self.__type_ref = str(type.name)
113      self.__type_label = str(type.name)
114
115   def visit_unknown_type_id(self, type):
116
117      self.__type_ref = str(type.name)
118      self.__type_label = str(self.scope().prune(type.name))
119
120   def visit_declared_type_id(self, type):
121
122      self.__type_label = str(self.scope().prune(type.name))
123      self.__type_ref = str(type.name)
124
125   def visit_modifier_type_id(self, type):
126
127      type.alias.accept(self)
128      self.__type_ref = ''.join(type.premod) + ' ' + self.__type_ref + ' ' + ''.join(type.postmod)
129      self.__type_label = ''.join(type.premod) + ' ' + self.__type_label + ' ' + ''.join(type.postmod)
130
131   def visit_parametrized_type_id(self, type):
132
133      type.template.accept(self)
134      type_label = self.__type_label + "&lt;"
135      parameters_label = []
136      for p in type.parameters:
137         p.accept(self)
138         parameters_label.append(self.__type_label)
139      self.__type_label = type_label + ', '.join(parameters_label) + '&gt;'
140
141   def format_type(self, type):
142
143      type.accept(self)
144      return self.__type_label
145
146   def visit_function_type_id(self, type):
147
148      # TODO: this needs to be implemented
149      self.__type_ref = 'function_type'
150      self.__type_label = 'function_type'
151
152   def process_doc(self, doc):
153
154      text = doc.replace('\n\n', '</para><para>')
155      self.write(self.entity("para", text)+'\n')
156
157   #################### ASG Visitor ###########################################
158
159   def visit_declarator(self, node):
160      self.__declarator = node.name
161      for i in node.sizes:
162         self.__declarator[-1] = self.__declarator[-1] + '[%d]'%i
163
164   def visit_typedef(self, typedef):
165
166      self.start_entity("typedef", name=str(self.scope().prune(typedef.name)))
167      self.write_entity("type", self.format_type(typedef.alias))
168      self.end_entity("typedef")
169
170   def visit_variable(self, variable):
171
172      self.start_entity("fieldsynopsis")
173      variable.vtype.accept(self)
174      self.entity("type", self.type_label())
175      self.entity("varname", variable.name[-1])
176      self.end_entity("fieldsynopsis")
177
178   def visit_const(self, const):
179
180      print "sorry, <const> not implemented"
181
182   def visit_module(self, module):
183
184      self.start_entity("namespace", name=str(self.scope().prune(module.name)))
185      self.write("\n")
186      self.process_doc(module.annotations.get('doc', ''))
187      self.push_scope(module.name)
188      for declaration in module.declarations: declaration.accept(self)
189      self.pop_scope()
190      self.end_entity("namespace")
191
192   def visit_class(self, class_):
193
194      self.start_entity("class", name=str(self.scope().prune(class_.name)))
195      # class_.type
196      for p in class_.parents:
197         p.accept(self)
198      self.push_scope(class_.name)
199      if class_.annotations.has_key('doc'):
200         self.start_entity("purpose")
201         self.process_doc(class_.annotations.get['doc'])
202         self.end_entity("purpose")
203      for d in class_.declarations:
204         d.accept(self)
205      self.pop_scope()
206      self.end_entity("class")
207
208   def visit_inheritance(self, inheritance):
209
210      if len(inheritance.attributes()):
211         self.start_entity("inherit", access=inheritance.attributes()[0])
212      else:
213         self.start_entity("inherit")
214      self.write_entity("classname", self.format_type(inheritance.parent()))
215      self.end_entity("inherit")
216
217   def visit_parameter(self, parameter):
218
219      self.start_entity("parameter", name=parameter.name)
220      self.write_entity("param_type", self.format_type(parameter.type))
221      #map(lambda m, this=self: this.write_entity("modifier", m), parameter.premodifier)
222      #map(lambda m, this=self: this.write_entity("modifier", m), parameter.postmodifier)
223      self.end_entity("parameter")
224      self.write("\n")
225
226   def visit_function(self, function):
227
228      self.start_entity("function", name=str(self.scope().prune(function.real_name)))
229      self.do_function(function)
230      self.end_entity("function")
231      self.write("\n")
232
233   def visit_operation(self, operation):
234
235      name = operation.name
236      tag = None
237      if len(name) > 1:
238         if name[-1] == name[-2]:
239            tag = "constructor"
240            self.start_entity(tag)
241         elif name[-1] == "~"+name[-2]:
242            tag = "destructor"
243            self.start_entity(tag)
244      if tag is None:
245         tag = "method"
246         self.start_entity(tag, name=str(self.scope().prune(operation.real_name)))
247      self.do_function(operation)
248      self.end_entity(tag)
249      self.write("\n")
250
251   def do_function(self, func):
252      """Stuff common to functions and methods, contructors, destructors"""
253
254      for parameter in func.parameters: parameter.accept(self)
255      if func.return_type:
256         self.write_entity("type", self.format_type(func.return_type))
257         self.write("\n")
258      if func.annotations.has_key('doc'):
259         self.start_entity("purpose")
260         self.process_doc(func.annotations['doc'])
261         self.end_entity("purpose")
262         self.write("\n")
263
264      if func.exceptions:
265         self.start_entity("throws")
266         for ex in func.exceptions:
267            self.write_entity("simpara", ex)
268         self.end_entity("throws")
269         self.write("\n")
270
271   def visit_enumerator(self, enumerator):
272
273      print "sorry, <enumerator> not implemented"
274
275   def visit_enum(self, enum):
276
277      print "sorry, <enum> not implemented"
278
279