File: Synopsis/Formatters/Texinfo.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 TexInfo formatter """
 10
 11from Synopsis.Processor import *
 12from Synopsis import ASG
 13from Synopsis.DocString import DocString
 14import sys, os, re
 15
 16
 17_tags = re.compile(r'@(?!(table|item|samp|end))')
 18def escape(text):
 19
 20   return _tags.sub('@@', text).replace('{', '@{').replace('}', '@}')
 21
 22
 23class MenuMaker(ASG.Visitor):
 24   """generate a texinfo menu for the declarations of a given scope"""
 25
 26   def __init__(self, scope, os):
 27
 28      self.scope = scope
 29      self.os = os
 30
 31   def write(self, text): self.os.write(text)
 32   def start(self): self.write('@menu\n')
 33   def end(self): self.write('@end menu\n')
 34   def visit_declaration(self, node):
 35
 36      name = escape(str(self.scope.prune(node.name)))
 37      self.write('* ' + name + '::\t' + node.type + '\n')
 38
 39   visit_group = visit_declaration
 40   visit_enum = visit_declaration
 41
 42class Formatter(Processor, ASG.Visitor):
 43   """The type visitors should generate names relative to the current scope.
 44   The generated references however are fully scoped names."""
 45
 46   def process(self, ir, **kwds):
 47
 48      self.set_parameters(kwds)
 49      if not self.output: raise MissingArgument('output')
 50      self.ir = self.merge_input(ir)
 51
 52      self.os = open(self.output, 'w+')
 53      self.scope = ()
 54      for d in self.ir.asg.declarations:
 55         d.accept(self)
 56
 57      return self.ir
 58
 59   def write(self, text): self.os.write(text)
 60
 61   def type_label(self): return escape(self.__type_label)
 62
 63   def decl_label(self, decl): return escape(decl[-1])
 64
 65   def format_type(self, type):
 66      "Returns a reference string for the given type object"
 67
 68      if type is None: return "(unknown)"
 69      type.accept(self)
 70      return self.type_label()
 71
 72   def format_comments(self, decl):
 73
 74      doc = decl.annotations.get('doc', DocString('', ''))
 75      # TODO: implement markup formatters for e.g. javadoc and rst
 76      self.write(escape(doc.text) + '\n')
 77
 78   #################### Type Visitor ###########################################
 79
 80   def visit_builtin_type_id(self, type):
 81
 82      self.__type_ref = str(type.name)
 83      self.__type_label = str(type.name)
 84
 85   def visit_unknown_type_id(self, type):
 86
 87      self.__type_ref = str(type.name)
 88      self.__type_label = str(self.scope.prune(type.name))
 89
 90   def visit_declared_type_id(self, type):
 91
 92      self.__type_label = str(self.scope.prune(type.name))
 93      self.__type_ref = str(type.name)
 94
 95   def visit_modifier_type_id(self, type):
 96
 97      type.alias.accept(self)
 98      self.__type_ref = ''.join(type.premod) + ' ' + self.__type_ref + ' ' + ''.join(type.postmod)
 99      self.__type_label = ''.join(type.premod) + ' ' + self.__type_label + ' ' + ''.join(type.postmod)
100
101   def visit_parametrized_type_id(self, type):
102
103      if type.template:
104         type.template.accept(self)
105         type_label = self.__type_label + '<'
106      else: type_label = '(unknown)<'
107      parameters_label = []
108      for p in type.parameters:
109         p.accept(self)
110         parameters_label.append(self.__type_label)
111      self.__type_label = type_label + ', '.join(parameters_label) + '>'
112
113   def visit_function_type_id(self, type):
114
115      # TODO: this needs to be implemented
116      self.__type_ref = 'function_type'
117      self.__type_label = 'function_type'
118
119   #################### ASG Visitor ############################################
120
121   def visit_declarator(self, node):
122
123      self.__declarator = node.name
124      for i in node.sizes:
125         self.__declarator[-1] = self.__declarator[-1] + '[%d]'%i
126
127   def visit_typedef(self, typedef):
128
129      #self.write('@node ' + self.decl_label(typedef.name) + '\n')
130      self.write('@deftp ' + typedef.type + ' {' + self.format_type(typedef.alias) + '} {' + self.decl_label(typedef.name) + '}\n')
131      self.format_comments(typedef)
132      self.write('@end deftp\n')
133
134   def visit_variable(self, variable):
135
136      #self.write('@node ' + self.decl_label(variable.name) + '\n')
137      self.write('@deftypevr {' + variable.type + '} {' + self.format_type(variable.vtype) + '} {' + self.decl_label(variable.name) + '}\n')
138      #FIXME !: how can values be represented in texinfo ?
139      self.format_comments(variable)
140      self.write('@end deftypevr\n')
141
142   def visit_const(self, const):
143
144      print "sorry, <const> not implemented"
145
146   def visit_module(self, module):
147
148      #self.write('@node ' + self.decl_label(module.name) + '\n')
149      self.write('@deftp ' + module.type + ' ' + self.decl_label(module.name) + '\n')
150      self.format_comments(module)
151      old_scope = self.scope
152      self.scope = module.name
153      #menu = MenuMaker(str(self.scope), self.os)
154      #menu.start()
155      #for declaration in module.declarations: declaration.accept(menu)
156      #menu.end()
157      for declaration in module.declarations: declaration.accept(self)
158      self.scope = old_scope
159      self.write('@end deftp\n')
160
161   def visit_class(self, class_):
162
163      #self.write('@node ' + self.decl_label(clas.name) + '\n')
164      self.write('@deftp ' + class_.type + ' ' + self.decl_label(class_.name) + '\n')
165      if len(class_.parents):
166         self.write('parents:')
167         first = 1
168         for parent in class_.parents:
169            if not first: self.write(', ')
170            else: self.write(' ')
171            parent.accept(self)
172         self.write('\n')
173      self.format_comments(class_)
174      old_scope = self.scope
175      self.scope = class_.name
176      #menu = MenuMaker(str(self.scope), self.os)
177      #menu.start()
178      #for d in class_.declarations: d.accept(menu)
179      #menu.end()
180      for d in class_.declarations:
181         d.accept(self)
182      self.scope = old_scope
183      self.write('@end deftp\n')
184
185   def visit_inheritance(self, inheritance):
186
187      self.write('parent class')
188
189   def visit_parameter(self, parameter):
190
191      parameter.type.accept(self)
192      label = self.write('{' + self.type_label() + '}')
193      label = self.write(' @var{' + parameter.name + '}')
194
195   def visit_function(self, function):
196
197      ret = function.return_type
198      if ret:
199         ret.accept(self)
200         ret_label = '{' + self.type_label() + '}'
201      else:
202         ret_label = '{}'
203      self.write('@deftypefn ' + function.type + ' ' + ret_label + ' ' + self.decl_label(function.real_name) + ' (')
204      first = 1
205      for parameter in function.parameters:
206         if not first: self.write(', ')
207         else: self.write(' ')
208         parameter.accept(self)
209         first = 0
210      self.write(')\n')
211      #    map(lambda e, this=self: this.entity("exceptionname", e), operation.exceptions)
212      self.format_comments(function)
213      self.write('@end deftypefn\n')
214
215   def visit_operation(self, operation):
216
217      ret = operation.return_type
218      if ret:
219         ret.accept(self)
220         ret_label = '{' + self.type_label() + '}'
221      else:
222         ret_label = '{}'
223      try:
224         #self.write('@node ' + self.decl_label(operation.name) + '\n')
225         self.write('@deftypeop ' + operation.type + ' ' + self.decl_label(self.scope) + ' ' + ret_label + ' ' + self.decl_label(operation.real_name) + ' (')
226      except:
227         print operation.real_name
228         sys.exit(0)
229      first = 1
230      for parameter in operation.parameters:
231         if not first: self.write(', ')
232         else: self.write(' ')
233         parameter.accept(self)
234         first = 0
235      self.write(')\n')
236      #    map(lambda e, this=self: this.entity("exceptionname", e), operation.exceptions)
237      self.format_comments(operation)
238      self.write('@end deftypeop\n')
239
240   def visit_enumerator(self, enumerator):
241
242      self.write('@deftypevr {' + enumerator.type + '} {} {' + self.decl_label(enumerator.name) + '}')
243      #FIXME !: how can values be represented in texinfo ?
244      if enumerator.value: self.write('\n')
245      else: self.write('\n')
246      self.format_comments(enumerator)
247      self.write('@end deftypevr\n')
248
249   def visit_enum(self, enum):
250      #self.write('@node ' + self.decl_label(enum.name) + '\n')
251      self.write('@deftp ' + enum.type + ' ' + self.decl_label(enum.name) + '\n')
252      self.format_comments(enum)
253      for enumerator in enum.enumerators:
254         enumerator.accept(self)
255      self.write('@end deftp\n')
256