Modules |
Files |
Inheritance Tree |
Inheritance Graph |
Name Index |
Config
File: Synopsis/Formatter/BoostBook.py
1| # $Id: BoostBook.py,v 1.1 2003/03/06 10:02:28 chalky Exp $
2| #
3| # This file is a part of Synopsis.
4| # Copyright (C) 2003 by Stephen Davies
5| #
6| # Synopsis is free software; you can redistribute it and/or modify it
7| # under the terms of the GNU General Public License as published by
8| # the Free Software Foundation; either version 2 of the License, or
9| # (at your option) any later version.
10| #
11| # This program is distributed in the hope that it will be useful,
12| # but WITHOUT ANY WARRANTY; without even the implied warranty of
13| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14| # General Public License for more details.
15| #
16| # You should have received a copy of the GNU General Public License
17| # along with this program; if not, write to the Free Software
18| # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19| # 02111-1307, USA.
20| #
21| # $Log: BoostBook.py,v $
22| # Revision 1.1 2003/03/06 10:02:28 chalky
23| # First cut at a BoostBook formatter
24| #
25|
26| """a BoostBook formatter"""
27| # THIS-IS-A-FORMATTER
28|
29| import sys, getopt, os, os.path, string, re
30| from Synopsis.Core import AST, Type, Util
31|
32| verbose = 0
33|
34| languages = {
35| 'IDL': 'idl',
36| 'C++': 'cxx',
37| 'Python': 'python'
38| }
39|
40| class Formatter (Type.Visitor, AST.Visitor):
41| """
42| The type visitors should generate names relative to the current scope.
43| The generated references however are fully scoped names
44| """
45| def __init__(self, os):
46| self.__os = os
47| self.__scope = ()
48| self.__scopestack = []
49| self.__indent = 0
50|
51| def scope(self): return self.__scope
52| def push_scope(self, newscope):
53| self.__scopestack.append(self.__scope)
54| self.__scope = newscope
55| def pop_scope(self):
56| self.__scope = self.__scopestack[-1]
57| del self.__scopestack[-1]
58| def write(self, text):
59| """Write some text to the output stream, replacing \n's with \n's and
60| indents."""
61| indent = ' ' * self.__indent
62| self.__os.write(text.replace('\n', '\n'+indent))
63| def start_entity(self, __type, **__params):
64| """Write the start of an entity, ending with a newline"""
65| param_text = ""
66| if __params: param_text = " " + string.join(map(lambda p:'%s="%s"'%(p[0].lower(), p[1]), __params.items()))
67| self.write("<" + __type + param_text + ">")
68| self.__indent = self.__indent + 2
69| self.write("\n")
70| def end_entity(self, type):
71| """Write the end of an entity, starting with a newline"""
72| self.__indent = self.__indent - 2
73| self.write("\n</" + type + ">")
74| def write_entity(self, __type, __body, **__params):
75| """Write a single entity on one line (though body may contain
76| newlines)"""
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| def entity(self, __type, __body, **__params):
85| """Return but do not write the text for an entity on one line"""
86| param_text = ""
87| if __params: param_text = " " + string.join(map(lambda p:'%s="%s"'%(p[0].lower(), p[1]), __params.items()))
88| return "<%s%s>%s</%s>"%(__type, param_text, __body, __type)
89|
90| def reference(self, ref, label):
91| """reference takes two strings, a reference (used to look up the symbol and generated the reference),
92| and the label (used to actually write it)"""
93| location = self.__toc.lookup(ref)
94| if location != "": return href("#" + location, label)
95| else: return span("type", str(label))
96|
97| def label(self, ref):
98| location = self.__toc.lookup(Util.ccolonName(ref))
99| ref = Util.ccolonName(ref, self.scope())
100| if location != "": return name("\"" + location + "\"", ref)
101| else: return ref
102|
103| def type_label(self): return self.__type_label
104| #################### Type Visitor ###########################################
105|
106| def visitBaseType(self, type):
107| self.__type_ref = Util.ccolonName(type.name())
108| self.__type_label = Util.ccolonName(type.name())
109|
110| def visitUnknown(self, type):
111| self.__type_ref = Util.ccolonName(type.name())
112| self.__type_label = Util.ccolonName(type.name(), self.scope())
113|
114| def visitDeclared(self, type):
115| self.__type_label = Util.ccolonName(type.name(), self.scope())
116| self.__type_ref = Util.ccolonName(type.name())
117|
118| def visitModifier(self, type):
119| type.alias().accept(self)
120| self.__type_ref = string.join(type.premod()) + " " + self.__type_ref + " " + string.join(type.postmod())
121| self.__type_label = string.join(type.premod()) + " " + self.__type_label + " " + string.join(type.postmod())
122|
123| def visitParametrized(self, type):
124| type.template().accept(self)
125| type_label = self.__type_label + "<"
126| parameters_label = []
127| for p in type.parameters():
128| p.accept(self)
129| parameters_label.append(self.__type_label)
130| self.__type_label = type_label + string.join(parameters_label, ", ") + ">"
131|
132| def formatType(self, type):
133| type.accept(self)
134| return self.__type_label
135|
136| def visitFunctionType(self, type):
137| # TODO: this needs to be implemented
138| self.__type_ref = 'function_type'
139| self.__type_label = 'function_type'
140|
141| def visitComment(self, comment):
142| text = comment.text()
143| text = text.replace('\n\n', '</para><para>')
144| self.write(self.entity("para", text)+'\n')
145|
146| #################### AST Visitor ############################################
147|
148| def visitDeclarator(self, node):
149| self.__declarator = node.name()
150| for i in node.sizes():
151| self.__declarator[-1] = self.__declarator[-1] + "[" + str(i) + "]"
152|
153| def visitTypedef(self, typedef):
154| self.start_entity("typedef", name=Util.ccolonName(self.scope(), typedef.name()))
155| self.write_entity("type", self.formatType(typedef.alias()))
156| self.end_entity("typedef")
157|
158| def visitVariable(self, variable):
159| self.start_entity("fieldsynopsis")
160| variable.vtype().accept(self)
161| self.entity("type", self.type_label())
162| self.entity("varname", variable.name()[-1])
163| self.end_entity("fieldsynopsis")
164|
165| def visitConst(self, const):
166| print "sorry, <const> not implemented"
167|
168| def visitModule(self, module):
169| self.start_entity("namespace", name=Util.ccolonName(self.scope(), module.name()))
170| self.write("\n")
171| map(self.visitComment, module.comments())
172| self.push_scope(module.name())
173| for declaration in module.declarations(): declaration.accept(self)
174| self.pop_scope()
175| self.end_entity("namespace")
176|
177| def visitClass(self, clas):
178| self.start_entity("class", name=Util.ccolonName(self.scope(), clas.name()))
179| # clas.type()
180| if len(clas.parents()):
181| for parent in clas.parents(): parent.accept(self)
182| self.push_scope(clas.name())
183| if clas.comments():
184| self.start_entity("purpose")
185| map(self.visitComment, clas.comments())
186| self.end_entity("purpose")
187| for declaration in clas.declarations():
188| declaration.accept(self)
189| self.pop_scope()
190| self.end_entity("class")
191|
192| def visitInheritance(self, inheritance):
193| if len(inheritance.attributes()):
194| self.start_entity("inherit", access=inheritance.attributes()[0])
195| else:
196| self.start_entity("inherit")
197| self.write_entity("classname", self.formatType(inheritance.parent()))
198| self.end_entity("inherit")
199|
200| def visitParameter(self, parameter):
201| self.start_entity("parameter", name=parameter.identifier())
202| self.write_entity("param_type", self.formatType(parameter.type()))
203| #map(lambda m, this=self: this.write_entity("modifier", m), parameter.premodifier())
204| #map(lambda m, this=self: this.write_entity("modifier", m), parameter.postmodifier())
205| self.end_entity("parameter")
206| self.write("\n")
207|
208| def visitFunction(self, function):
209| self.start_entity("function", name=Util.ccolonName(self.scope(), function.realname()))
210| self.do_function(function)
211| self.end_entity("function")
212| self.write("\n")
213|
214| def visitOperation(self, operation):
215| name = operation.name()
216| tag = None
217| if len(name) > 1:
218| if name[-1] == name[-2]:
219| tag = "constructor"
220| self.start_entity(tag)
221| elif name[-1] == "~"+name[-2]:
222| tag = "destructor"
223| self.start_entity(tag)
224| if tag is None:
225| tag = "method"
226| self.start_entity(tag, name=Util.ccolonName(self.scope(), operation.realname()))
227| self.do_function(operation)
228| self.end_entity(tag)
229| self.write("\n")
230|
231| def do_function(self, func):
232| """Stuff common to functions and methods, contructors, destructors"""
233| for parameter in func.parameters(): parameter.accept(self)
234| if func.returnType():
235| self.write_entity("type", self.formatType(func.returnType()))
236| self.write("\n")
237| if func.comments():
238| self.start_entity("purpose")
239| map(self.visitComment, func.comments())
240| self.end_entity("purpose")
241| self.write("\n")
242|
243| if func.exceptions():
244| self.start_entity("throws")
245| for ex in func.exceptions():
246| self.write_entity("simpara", ex)
247| self.end_entity("throws")
248| self.write("\n")
249|
250| def visitEnumerator(self, enumerator):
251| print "sorry, <enumerator> not implemented"
252| def visitEnum(self, enum):
253| print "sorry, <enum> not implemented"
254|
255| def usage():
256| """Print usage to stdout"""
257| print \
258| """
259| -v Verbose mode
260| -o <filename> Output filename
261| -d Don't oupu
262|
263| def __parseArgs(args):
264| global output, verbose, no_doctype, is_manual
265| output = sys.stdout
266| no_doctype = 0
267| is_manual = 0
268| try:
269| opts,remainder = getopt.getopt(args, "o:vdm")
270| except getopt.error, e:
271| sys.stderr.write("Error in arguments: " + str(e) + "\n")
272| sys.exit(1)
273|
274| for opt in opts:
275| o,a = opt
276| if o == "-o": output = open(a, "w")
277| elif o == "-v": verbose = 1
278| elif o == "-d": no_doctype = 1
279| elif o == "-m": is_manual = 1
280|
281| def format(args, ast, config):
282| global output
283| __parseArgs(args)
284| #if not no_doctype:
285| # output.write("<!DOCTYPE classsynopsis PUBLIC \"-//OASIS//DTD DocBook V4.2//EN\">\
286| formatter = Formatter(output)
287| for d in ast.declarations():
288| d.accept(formatter)
289|
290| if output is not sys.stdout:
291| output.close()