File: Synopsis/Formatters/HTML/Part.py
  1#
  2# Copyright (C) 2000 Stephen Davies
  3# Copyright (C) 2000 Stefan Seefeld
  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"""ASG Formatting classes.
 10
 11This module contains classes for formatting parts of a scope view (class,
 12module, etc with methods, variables etc. The actual formatting of the
 13declarations is delegated to multiple strategies for each part of the view,
 14and are defined in the FormatStrategy module.
 15"""
 16
 17from Synopsis.Processor import Parametrized, Parameter
 18from Synopsis import ASG
 19from Fragment import Fragment
 20import Tags # need both because otherwise 'Tags.name' would be ambiguous
 21from Tags import *
 22
 23class Part(Parametrized, ASG.Visitor):
 24    """Base class for formatting a Part of a Scope View.
 25    
 26    This class contains functionality for modularly formatting an ASG node and
 27    its children for display. It is typically used to construct Heading,
 28    Summary and Detail formatters. Strategy objects are added according to
 29    configuration, and this base class  then checks which format methods each
 30    strategy implements. For each ASG declaration visited, the Part asks all
 31    Strategies which implement the appropriate format method to generate
 32    output for that declaration. The final writing of the formatted html is
 33    delegated to the write_section_start, write_section_end, and write_section_item
 34    methods, which must be implemented in a subclass.
 35    """
 36
 37    fragments = Parameter([], "list of Fragments")
 38
 39    def register(self, view):
 40
 41        self.processor = view.processor
 42        self.__view = view
 43        self.__fragments = []
 44        self.__id_holder = None
 45        # Lists of format methods for each ASG type
 46        self.__formatdict = {'format_declaration':[],
 47                             'format_forward':[],
 48                             'format_group':[],
 49                             'format_scope':[],
 50                             'format_module':[],
 51                             'format_meta_module':[],
 52                             'format_class':[],
 53                             'format_class_template':[],
 54                             'format_typedef':[],
 55                             'format_enum':[],
 56                             'format_variable':[],
 57                             'format_const':[],
 58                             'format_function':[],
 59                             'format_function_template':[],
 60                             'format_operation':[],
 61                             'format_operation_template':[]}
 62
 63        for fragment in self.fragments:
 64            fragment.register(self)
 65            for method in self.__formatdict.keys():
 66                no_func = getattr(Fragment, method).im_func
 67                method_obj = getattr(fragment, method)
 68                # If it was overridden in fragment
 69                if method_obj.im_func is not no_func:
 70                    # Add to the dictionary
 71                    self.__formatdict[method].append(method_obj)
 72
 73    def view(self): return self.__view
 74    def filename(self): return self.__view.filename()
 75    def os(self): return self.__view.os()
 76    def scope(self): return self.__view.scope()
 77    def write(self, text): self.os().write(text)
 78
 79    # Access to generated values
 80    def type_ref(self): return self.__type_ref
 81    def type_label(self): return self.__type_label
 82    def declarator(self): return self.__declarator
 83    def parameter(self): return self.__parameter
 84
 85    def reference(self, name, label=None, **keys):
 86        """Returns a reference to the given name. The name is a scoped name,
 87        and the optional label is an alternative name to use as the link text.
 88        The name is looked up in the TOC so the link may not be local. The
 89        optional keys are appended as attributes to the A tag."""
 90
 91        if not label: label = escape(str(self.scope().prune(name)))
 92        entry = self.processor.toc[name]
 93        if entry: return href(rel(self.filename(), entry.link), label, **keys)
 94        else: return label or ''
 95
 96    def label(self, name, label=None):
 97        """Create a label for the given name. The label is an anchor so it can
 98        be referenced by other links. The name of the label is derived by
 99        looking up the name in the TOC and using the link in the TOC entry.
100        The optional label is an alternative name to use as the displayed
101        name. If the name is not found in the TOC then the name is not
102        anchored and just label is returned (or name if no label is given).
103        """
104
105        if label is None: label = name
106        # some labels are templates with <>'s
107        entry = self.processor.toc[name]
108        label = escape(str(self.scope().prune(label)))
109        if entry is None: return label
110        location = entry.link
111        index = location.find('#')
112        if index >= 0: location = location[index+1:]
113        return location and Tags.name(location, label) or label
114
115
116    def format_declaration(self, decl, method):
117        """Format decl using named method of each fragment. Each fragment
118        returns two strings - type and name. All the types are joined and all
119        the names are joined separately. The consolidated type and name
120        strings are then passed to write_section_item."""
121
122        type_name = [f(decl) for f in self.__formatdict[method]]
123        if type_name:
124            text = ' '.join(type_name).strip()
125            self.write_section_item(text)
126
127    def process(self, decl):
128        """Formats the given decl, creating the output for this Part of the
129        view. This method is implemented in various subclasses in different
130        ways, for example Summary and Detail iterate through the children of
131        'decl' section by section, whereas Heading only formats decl itself.
132        """
133
134        pass
135
136    #################### ASG Visitor ############################################
137    def visit_declaration(self, decl): self.format_declaration(decl, 'format_declaration')
138    def visit_forward(self, decl): self.format_declaration(decl, 'format_forward')
139    def visit_group(self, decl): self.format_declaration(decl, 'format_group')
140    def visit_scope(self, decl): self.format_declaration(decl, 'format_scope')
141    def visit_module(self, decl): self.format_declaration(decl, 'format_module')
142    def visit_meta_module(self, decl): self.format_declaration(decl, 'format_meta_module')
143    def visit_class(self, decl): self.format_declaration(decl, 'format_class')
144    def visit_class_template(self, decl): self.format_declaration(decl, 'format_class_template')
145    def visit_typedef(self, decl): self.format_declaration(decl, 'format_typedef')
146    def visit_enum(self, decl): self.format_declaration(decl, 'format_enum')
147    def visit_variable(self, decl): self.format_declaration(decl, 'format_variable')
148    def visit_const(self, decl): self.format_declaration(decl, 'format_const')
149    def visit_function(self, decl): self.format_declaration(decl, 'format_function')
150    def visit_function_template(self, decl): self.format_declaration(decl, 'format_function_template')
151    def visit_operation(self, decl): self.format_declaration(decl, 'format_operation')
152    def visit_operation_template(self, decl): self.format_declaration(decl, 'format_operation_template')
153
154
155    #################### Type Formatter/Visitor #################################
156    def format_type(self, typeObj, id_holder = None):
157        "Returns a reference string for the given type object"
158
159        if typeObj is None: return "(unknown)"
160        if id_holder:
161            save_id = self.__id_holder
162            self.__id_holder = id_holder
163        typeObj.accept(self)
164        if id_holder:
165            self.__id_holder = save_id
166        return self.__type_label
167
168    def visit_builtin_type_id(self, type):
169        "Sets the label to be a reference to the type's name"
170
171        self.__type_label = self.reference(type.name)
172
173    def visit_unknown_type_id(self, type):
174        "Sets the label to be a reference to the type's link"
175
176        self.__type_label = self.reference(type.link)
177
178    def visit_declared_type_id(self, type):
179        "Sets the label to be a reference to the type's name"
180
181        self.__type_label = self.reference(type.name)
182
183    def visit_dependent_type_id(self, type):
184        "Sets the label to be the type's name (which has no proper scope)"
185
186        self.__type_label = type.name[-1]
187
188    def visit_modifier_type_id(self, type):
189        "Adds modifiers to the formatted label of the modifier's alias"
190
191        alias = self.format_type(type.alias)
192        def amp(x):
193            if x == '&': return '&amp;'
194            return x
195        pre = ''.join(['%s&#160;'%amp(x) for x in type.premod])
196        post = ''.join([amp(x) for x in type.postmod])
197        self.__type_label = "%s%s%s"%(pre,alias,post)
198
199    def visit_parametrized_type_id(self, type):
200        "Adds the parameters to the template name in angle brackets"
201
202        if type.template:
203            type_label = self.reference(type.template.name)
204        else:
205            type_label = "(unknown)"
206        parameters = [self.format_type(p) for p in type.parameters]
207        self.__type_label = "%s&lt;%s&gt;"%(type_label,', '.join(parameters))
208
209    def visit_template_id(self, type):
210        "Labs the template with the parameters"
211
212        self.__type_label = "template&lt;%s&gt;"%','.join(['typename %s'%self.format_type(p)
213                                                           for p in type.parameters])
214
215    def visit_function_type_id(self, type):
216        "Labels the function type with return type, name and parameters"
217
218        ret = self.format_type(type.return_type)
219        params = map(self.format_type, type.parameters)
220        pre = ''.join(type.premod)
221        if self.__id_holder:
222            ident = self.__id_holder[0]
223            del self.__id_holder[0]
224        else:
225            ident = ''
226        self.__type_label = "%s(%s%s)(%s)"%(ret,pre,ident,', '.join(params))
227
228
229    # These are overridden in {Summary,Detail}Formatter
230    def write_start(self):
231        "Abstract method to start the output, eg table headings"
232
233        self.write('<!-- this part was generated by ' + self.__class__.__name__ + ' -->\n')
234
235    def write_section_start(self, heading):
236        "Abstract method to start a section of declaration types"
237
238        pass
239
240    def write_section_end(self, heading):
241        "Abstract method to end a section of declaration types"
242
243        pass
244
245    def write_section_item(self, text):
246        "Abstract method to write the output of one formatted declaration"
247
248        pass
249
250    def write_end(self):
251        "Abstract method to end the output, eg close the table"
252
253        pass
254