Modules |
Files |
Inheritance Tree |
Inheritance Graph |
Name Index |
Config
File: Synopsis/Formatter/HTML_Simple.py
1| # $Id: HTML_Simple.py,v 1.14 2001/07/19 04:03:05 chalky Exp $
2| #
3| # This file is a part of Synopsis.
4| # Copyright (C) 2000, 2001 Stefan Seefeld
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: HTML_Simple.py,v $
22| # Revision 1.14 2001/07/19 04:03:05 chalky
23| # New .syn file format.
24| #
25| # Revision 1.13 2001/06/08 04:50:13 stefan
26| # add grouping support
27| #
28| # Revision 1.12 2001/05/25 13:45:49 stefan
29| # fix problem with getopt error reporting
30| #
31| # Revision 1.11 2001/05/13 02:46:41 stefan
32| # more fixes from oxygene
33| #
34| # Revision 1.10 2001/02/13 06:55:23 chalky
35| # Made synopsis -l work again
36| #
37| # Revision 1.9 2001/01/31 06:51:24 stefan
38| # add support for '-v' to all modules; modified toc lookup to use additional url as prefix
39| #
40| # Revision 1.8 2001/01/25 01:10:59 chalky
41| # Fixed html_simple
42| #
43| # Revision 1.7 2001/01/24 01:38:36 chalky
44| # Added docstrings to all modules
45| #
46| # Revision 1.6 2001/01/22 19:54:41 stefan
47| # better support for help message
48| #
49| # Revision 1.5 2001/01/22 17:06:15 stefan
50| # added copyright notice, and switched on logging
51| #
52| """
53| Simpler one-page HTML output
54| """
55| # THIS-IS-A-FORMATTER
56|
57| import sys, getopt, os, os.path, string
58| from Synopsis.Core import AST, Type, Util
59|
60| verbose = 0
61|
62| def entity(type, body): return "<" + type + "> " + body + "</" + type + ">"
63| def href(ref, label): return "<a href=" + ref + ">" + label + "</a>"
64| def name(ref, label): return "<a name=" + ref + ">" + label + "</a>"
65| def span(clas, body): return "<span class=\"" + clas + "\">" + body + "</span>"
66| def div(clas, body): return "<div class=\"" + clas + "\">" + body + "</div>"
67| def desc(text):
68| block = filter(lambda s: s.text()[0:3] == "//.", text)
69| if not len(block): return ""
70| block = map(lambda s: s.text()[3:], block)
71| return "<div class=\"desc\">" + string.join(block, '\n') + "</div>"
72|
73| class TableOfContents(AST.Visitor):
74| """
75| generate a dictionary of all declarations which can be looked up to create
76| cross references. Names are fully scoped."""
77| def __init__(self): self.__toc__ = {}
78| def write(self, os):
79| keys = self.__toc__.keys()
80| keys.sort()
81| for key in keys:
82| os.write(href("#" + self.__toc__[key], key) + "<br>\n")
83|
84| def lookup(self, name):
85| if self.__toc__.has_key(name): return self.__toc__[name]
86| else: return ""
87|
88| def insert(self, name):
89| self.__toc__[Util.ccolonName(name)] = Util.dotName(name)
90|
91| def visitAST(self, node):
92| for d in node.declarations: d.accept(this)
93|
94| def visitDeclarator(self, node):
95| self.insert(node.name())
96|
97| def visitGroup(self, group):
98| for declaration in group.declarations():
99| declaration.accept(self)
100|
101| def visitModule(self, module):
102| self.insert(module.name())
103| for declaration in module.declarations():
104| declaration.accept(self)
105|
106| def visitClass(self, clas):
107| self.insert(clas.name())
108| for declaration in clas.declarations():
109| declaration.accept(self)
110|
111| def visitTypedef(self, typedef):
112| self.insert(typedef.name())
113| def visitEnumerator(self, enumerator):
114| self.insert(enumerator.name())
115| def visitEnum(self, enum):
116| self.insert(enum.name())
117| for e in enum.enumerators(): e.accept(self)
118|
119| def visitVariable(self, variable):
120| self.insert(variable.name())
121| def visitConst(self, const):
122| self.insert(const.name())
123| def visitParameter(self, parameter): pass
124| def visitFunction(self, function):
125| self.insert(function.name())
126|
127| def visitOperation(self, operation):
128| self.insert(operation.name())
129| for parameter in operation.parameters(): parameter.accept(self)
130|
131|
132| class HTMLFormatter (Type.Visitor, AST.Visitor):
133| """
134| The type visitors should generate names relative to the current scope.
135| The generated references however are fully scoped names
136| """
137| def __init__(self, os, toc):
138| self.__os = os
139| self.__toc = toc
140| self.__scope = []
141|
142| def scope(self): return self.__scope
143| def write(self, text): self.__os.write(text)
144|
145| def reference(self, ref, label):
146| """reference takes two strings, a reference (used to look up the symbol and generated the reference),
147| and the label (used to actually write it)"""
148| location = self.__toc.lookup(ref)
149| if location != "": return href("#" + location, label)
150| else: return span("type", str(label))
151|
152| def label(self, ref):
153| location = self.__toc.lookup(Util.ccolonName(ref))
154| ref = Util.ccolonName(ref, self.scope())
155| if location != "": return name("\"" + location + "\"", ref)
156| else: return ref
157|
158| #################### Type Visitor ###########################################
159|
160| def visitBaseType(self, type):
161| self.__type_ref = Util.ccolonName(type.name())
162| self.__type_label = Util.ccolonName(type.name())
163|
164| def visitUnknown(self, type):
165| self.__type_ref = Util.ccolonName(type.name())
166| self.__type_label = Util.ccolonName(type.name(), self.scope())
167|
168| def visitDeclared(self, type):
169| self.__type_label = Util.ccolonName(type.name(), self.scope())
170| self.__type_ref = Util.ccolonName(type.name())
171|
172| def visitModifier(self, type):
173| type.alias().accept(self)
174| self.__type_ref = string.join(type.premod()) + " " + self.__type_ref + " " + string.join(type.postmod())
175| self.__type_label = string.join(type.premod()) + " " + self.__type_label + " " + string.join(type.postmod())
176|
177| def visitParametrized(self, type):
178| type.template().accept(self)
179| type_ref = self.__type_ref + "<"
180| type_label = self.__type_label + "<"
181| parameters_ref = []
182| parameters_label = []
183| for p in type.parameters():
184| p.accept(self)
185| parameters_ref.append(self.__type_ref)
186| parameters_label.append(self.reference(self.__type_ref, self.__type_label))
187| self.__type_ref = type_ref + string.join(parameters_ref, ", ") + ">"
188| self.__type_label = type_label + string.join(parameters_label, ", ") + ">"
189|
190| def visitFunctionType(self, type):
191| # TODO: this needs to be implemented
192| self.__type_ref = 'function_type'
193| self.__type_label = 'function_type'
194|
195|
196| #################### AST Visitor ############################################
197|
198| def visitDeclarator(self, node):
199| self.__declarator = node.name()
200| for i in node.sizes():
201| self.__declarator[-1] = self.__declarator[-1] + "[" + str(i) + "]"
202|
203| def visitTypedef(self, typedef):
204| self.write(span("keyword", typedef.type()) + " ")
205| typedef.alias().accept(self)
206| self.write(self.reference(self.__type_ref, self.__type_label) + " ")
207| self.write(self.label(typedef.name()))
208| if len(typedef.comments()): self.write("\n" + desc(typedef.comments()) + "\n")
209|
210| def visitVariable(self, variable):
211| variable.vtype().accept(self)
212| self.write(self.reference(self.__type_ref, self.__type_label) + " ")
213| self.write(self.label(variable.name()))
214| if len(variable.comments()): self.write("\n" + desc(variable.comments()) + "\n")
215|
216| def visitConst(self, const):
217| const.ctype().accept(self)
218| self.write(span("keyword", const.type()) + " " + self.reference(self.__type_ref, self.__type_label) + " ")
219| self.write(self.label(const.name()) + " = " + const.value())
220| if len(const.comments()): self.write("\n" + desc(const.comments()) + "\n")
221|
222| def visitGroup(self, group):
223| self.write(span("keyword", group.type()) + "\n")
224| if len(group.comments()): self.write("\n" + desc(group.comments()) + "\n")
225| self.write("<div class=\"group\">\n")
226| for declaration in group.declarations():
227| declaration.accept(self)
228| self.write("<br>\n")
229| self.write("</div>\n")
230|
231| def visitModule(self, module):
232| self.write(span("keyword", module.type()) + " " + self.label(module.name()) + "\n")
233| if len(module.comments()): self.write("\n" + desc(module.comments()) + "\n")
234| self.write("<div class=\"module\">\n")
235| self.scope().append(module.name()[-1])
236| for declaration in module.declarations():
237| declaration.accept(self)
238| self.write("<br>\n")
239| self.scope().pop()
240| self.write("</div>\n")
241|
242| def visitClass(self, clas):
243| self.write(span("keyword", clas.type()) + " " + self.label(clas.name()) + "\n")
244| if len(clas.parents()):
245| self.write("<div class=\"parents\">\n")
246| self.write(entity("b", "parents:") + "\n")
247| self.write("<div class=\"inheritance\">\n")
248| for parent in clas.parents():
249| parent.accept(self)
250| self.write("<br>\n")
251| self.write("</div>\n")
252| self.write("</div>\n")
253| self.scope().append(clas.name()[-1])
254| if len(clas.comments()): self.write("\n" + desc(clas.comments()) + "\n")
255| if len(clas.declarations()):
256| self.write("<div class=\"declarations\">\n")
257| for d in clas.declarations():
258| d.accept(self)
259| self.write("<br>\n")
260| self.write("</div>\n")
261| self.scope().pop()
262|
263| def visitInheritance(self, inheritance):
264| for attribute in inheritance.attributes(): self.write(span("keywords", attribute) + " ")
265| inheritance.parent().accept(self)
266| self.write(self.reference(self.__type_ref, self.__type_label))
267|
268| def visitParameter(self, parameter):
269| for m in parameter.premodifier(): self.write(span("keyword", m) + " ")
270| parameter.type().accept(self)
271| self.write(self.reference(self.__type_ref, self.__type_label) + " ")
272| for m in parameter.postmodifier(): self.write(span("keyword", m) + " ")
273| if len(parameter.identifier()) != 0:
274| self.write(span("variable", parameter.identifier()))
275| if len(parameter.value()) != 0:
276| self.write(" = " + span("value", parameter.value()))
277|
278| def visitFunction(self, function):
279| for modifier in operation.premodifier(): self.write(span("keyword", modifier) + " ")
280| operation.returnType().accept(self)
281| self.write(self.reference(self.__type_ref, self.__type_label) + " ")
282| self.write(self.label(function.realname()) + "(")
283| parameters = function.parameters()
284| if len(parameters): parameters[0].accept(self)
285| for parameter in parameters[1:]:
286| self.write(", ")
287| parameter.accept(self)
288| self.write(")")
289| for modifier in operation.postmodifier(): self.write(span("keyword", modifier) + " ")
290| self.write("\n")
291| if len(operation.exceptions()):
292| self.write(span("keyword", "raises") + "\n")
293| exceptions = []
294| for exception in operation.exceptions():
295| exceptions.append(self.reference(Util.ccolonName(exception.name()), Util.ccolonName(exception.name(), self.scope())))
296| self.write("(" + span("raises", string.join(exceptions, ", ")) + ")")
297| self.write("\n")
298| if len(function.comments()): self.write("\n" + desc(function.comments()) + "\n")
299|
300| def visitOperation(self, operation):
301| for modifier in operation.premodifier(): self.write(span("keyword", modifier) + " ")
302| if operation.returnType():
303| operation.returnType().accept(self)
304| self.write(self.reference(self.__type_ref, self.__type_label) + " ")
305| if operation.language() == "IDL" and operation.type() == "attribute":
306| self.write(span("keyword", "attribute") + " ")
307| self.write(self.label(operation.realname()) + "(")
308| parameters = operation.parameters()
309| if len(parameters): parameters[0].accept(self)
310| for parameter in parameters[1:]:
311| self.write(", ")
312| parameter.accept(self)
313| self.write(")")
314| for modifier in operation.postmodifier(): self.write(span("keyword", modifier) + " ")
315| self.write("\n")
316| if len(operation.exceptions()):
317| self.write(span("keyword", "raises") + "\n")
318| exceptions = []
319| for exception in operation.exceptions():
320| exceptions.append(self.reference(Util.ccolonName(exception.name()), Util.ccolonName(exception.name(), self.scope())))
321| self.write("(" + span("raises", string.join(exceptions, ", ")) + ")")
322| self.write("\n")
323| if len(operation.comments()): self.write("\n" + desc(operation.comments()) + "\n")
324|
325| def visitEnumerator(self, enumerator):
326| self.write(self.label(enumerator.name()))
327| if len(enumerator.value()):
328| self.write(" = " + span("value", enumerator.value()))
329|
330| def visitEnum(self, enum):
331| self.write(span("keyword", "enum ") + self.label(enum.name()) + "\n")
332| self.write("<div class=\"enum\">\n")
333| for enumerator in enum.enumerators():
334| enumerator.accept(self)
335| self.write("<br>\n")
336| self.write("</div>\n")
337| if len(enum.comments()): self.write("\n" + desc(enum.comments()) + "\n")
338|
339| def usage():
340| """Print usage to stdout"""
341| print \
342| """
343| -o <filename> Output filename
344| -s <filename> Filename of stylesheet"""
345|
346| def __parseArgs(args):
347| global output, stylesheet, verbose
348| output = sys.stdout
349| stylesheet = ""
350| try:
351| opts,remainder = getopt.getopt(args, "o:s:v")
352| except getopt.error, e:
353| sys.stderr.write("Error in arguments: " + str(e) + "\n")
354| sys.exit(1)
355|
356| for opt in opts:
357| o,a = opt
358| if o == "-o": output = open(a, "w")
359| elif o == "-s": stylesheet = a
360| elif o == "-v": verbose = 1
361|
362| def format(args, ast, config_obj):
363| global output, stylesheet
364| __parseArgs(args)
365| output.write("<html>\n")
366| output.write("<head>\n")
367| if len(stylesheet):
368| output.write("<link rel=\"stylesheet\" href=\"" + stylesheet + "\">\n")
369| output.write("</head>\n")
370| output.write("<body>\n")
371| toc = TableOfContents()
372| for d in ast.declarations():
373| d.accept(toc)
374| output.write(entity("h1", "Reference") + "\n")
375| formatter = HTMLFormatter(output, toc)
376| for d in ast.declarations():
377| d.accept(formatter)
378| output.write(entity("h1", "Index") + "\n")
379| toc.write(output)
380| output.write("</body>\n")
381| output.write("</html>\n")