Modules | Files | Inheritance Tree | Inheritance Graph | Name Index | Config
File: Synopsis/Formatter/HTML/ASTFormatter.py
    1| # $Id: ASTFormatter.py,v 1.32 2003/01/20 06:43:02 chalky Exp $
    2| #
    3| # This file is a part of Synopsis.
    4| # Copyright (C) 2000, 2001 Stephen Davies
    5| # Copyright (C) 2000, 2001 Stefan Seefeld
    6| #
    7| # Synopsis is free software; you can redistribute it and/or modify it
    8| # under the terms of the GNU General Public License as published by
    9| # the Free Software Foundation; either version 2 of the License, or
   10| # (at your option) any later version.
   11| #
   12| # This program is distributed in the hope that it will be useful,
   13| # but WITHOUT ANY WARRANTY; without even the implied warranty of
   14| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15| # General Public License for more details.
   16| #
   17| # You should have received a copy of the GNU General Public License
   18| # along with this program; if not, write to the Free Software
   19| # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   20| # 02111-1307, USA.
   21| #
   22| # $Log: ASTFormatter.py,v $
   23| # Revision 1.32  2003/01/20 06:43:02  chalky
   24| # Refactored comment processing. Added AST.CommentTag. Linker now determines
   25| # comment summary and extracts tags. Increased AST version number.
   26| #
   27| # Revision 1.31  2002/11/01 07:21:15  chalky
   28| # More HTML formatting fixes eg: ampersands and stuff
   29| #
   30| # Revision 1.30  2002/11/01 03:39:20  chalky
   31| # Cleaning up HTML after using 'htmltidy'
   32| #
   33| # Revision 1.29  2002/10/28 08:16:52  chalky
   34| # Undo previous table change. Put non-breaking spaces in first column instead
   35| #
   36| # Revision 1.28  2002/10/28 06:13:49  chalky
   37| # Fix summary display: templates use special div, use nested table to fix
   38| # formatting of first column
   39| #
   40| # Revision 1.27  2002/10/27 12:05:17  chalky
   41| # Support putting the identifier in the right place in funcptr parameters.
   42| #
   43| # Revision 1.26  2002/10/27 08:40:36  chalky
   44| # Oops, broke the templates on their own line thing
   45| #
   46| # Revision 1.25  2002/10/26 04:20:35  chalky
   47| # Oops, limit constructor detection to functions
   48| #
   49| # Revision 1.24  2002/10/26 04:17:58  chalky
   50| # Show templates on previous line. Hide constructors in base class. Commas
   51| # between inherited members
   52| #
   53| # Revision 1.23  2002/10/20 15:38:08  chalky
   54| # Much improved template support, including Function Templates.
   55| #
   56| # Revision 1.22  2002/03/14 00:19:47  chalky
   57| # Added demo of template specializations, and fixed HTML formatter to deal with
   58| # angle brackets in class names :)
   59| #
   60| # Revision 1.21  2001/07/19 04:03:05  chalky
   61| # New .syn file format.
   62| #
   63| # Revision 1.20  2001/07/17 01:49:44  chalky
   64| # Fixed names of strategies for defaults
   65| #
   66| # Revision 1.19  2001/07/15 08:28:43  chalky
   67| # Added 'Inheritance' page Part
   68| #
   69| # Revision 1.18  2001/07/15 06:41:57  chalky
   70| # Factored summarizer and detailer into 'Parts', and added a separate one for
   71| # the top of the page (Heading)
   72| #
   73| # Revision 1.17  2001/07/10 05:08:28  chalky
   74| # Refactored ASTFormatters into FormatStrategies, and simplified names all round
   75| #
   76| # Revision 1.16  2001/07/10 02:55:51  chalky
   77| # Better comments in some files, and more links work with the nested layout
   78| #
   79| # Revision 1.15  2001/07/05 05:39:58  stefan
   80| # advanced a lot in the refactoring of the HTML module.
   81| # Page now is a truely polymorphic (abstract) class. Some derived classes
   82| # implement the 'filename()' method as a constant, some return a variable
   83| # dependent on what the current scope is...
   84| #
   85| # Revision 1.14  2001/07/04 08:17:16  uid20151
   86| # Change the strategies to return just one string, and insert their own <TD>
   87| # when necessary
   88| #
   89| # Revision 1.13  2001/06/28 07:22:18  stefan
   90| # more refactoring/cleanup in the HTML formatter
   91| #
   92| # Revision 1.12  2001/06/26 04:32:15  stefan
   93| # A whole slew of changes mostly to fix the HTML formatter's output generation,
   94| # i.e. to make the output more robust towards changes in the layout of files.
   95| #
   96| # the rpm script now works, i.e. it generates source and binary packages.
   97| #
   98| # Revision 1.11  2001/06/11 10:37:49  chalky
   99| # Better grouping support
  100| #
  101| # Revision 1.10  2001/06/08 21:04:38  stefan
  102| # more work on grouping
  103| #
  104| # Revision 1.9  2001/04/05 09:58:14  chalky
  105| # More comments, and use config object exclusively with basePackage support
  106| #
  107| # Revision 1.8  2001/03/29 14:06:41  chalky
  108| # Skip boring graphs (ie, no sub or super classes)
  109| #
  110| # Revision 1.7  2001/02/16 06:59:32  chalky
  111| # ScopePage summaries link to source
  112| #
  113| # Revision 1.6  2001/02/13 06:55:23  chalky
  114| # Made synopsis -l work again
  115| #
  116| # Revision 1.5  2001/02/12 04:08:09  chalky
  117| # Added config options to HTML and Linker. Config demo has doxy and synopsis styles.
  118| #
  119| # Revision 1.4  2001/02/02 02:01:01  stefan
  120| # synopsis now supports inlined inheritance tree generation
  121| #
  122| # Revision 1.3  2001/02/01 15:23:24  chalky
  123| # Copywritten brown paper bag edition.
  124| #
  125| #
  126| """AST Formatting classes.
  127| 
  128| This module contains classes for formatting parts of a scope page (class,
  129| module, etc with methods, variables etc. The actual formatting of the
  130| declarations is delegated to multiple strategies for each part of the page,
  131| and are defined in the FormatStrategy module.
  132| """
  133| # System modules
  134| import types, os
  135| 
  136| # Synopsis modules
  137| from Synopsis.Core import AST, Type, Util
  138| 
  139| # HTML modules
  140| import Tags, core, FormatStrategy
  141| from core import config, DeclStyle
  142| from Tags import *
  143| 
  144| class Part(Type.Visitor, AST.Visitor):
  145|     """Base class for formatting a Part of a Scope Page.
  146|     
  147|     This class contains functionality for modularly formatting an AST node and
  148|     its children for display. It is typically used to contruct Heading,
  149|     Summary and Detail formatters. Strategy objects are added according to
  150|     configuration, and this base class  then checks which format methods each
  151|     strategy implements. For each AST declaration visited, the Part asks all
  152|     Strategies which implement the appropriate format method to generate
  153|     output for that declaration. The final writing of the formatted html is
  154|     delegated to the writeSectionStart, writeSectionEnd, and writeSectionItem
  155|     methods, which myst be implemented in a subclass.
  156|     """
  157|     def __init__(self, page):
  158|         self.__page = page
  159|         self.__formatters = []
  160|         self.__id_holder = None
  161|         # Lists of format methods for each AST type
  162|         self.__formatdict = {
  163|             'formatDeclaration':[], 'formatForward':[], 'formatGroup':[], 'formatScope':[],
  164|             'formatModule':[], 'formatMetaModule':[], 'formatClass':[],
  165|             'formatTypedef':[], 'formatEnum':[], 'formatVariable':[],
  166|             'formatConst':[], 'formatFunction':[], 'formatOperation':[], 
  167|         }
  168|     
  169|     def page(self): return self.__page
  170|     def filename(self): return self.__page.filename()
  171|     def os(self): return self.__page.os()
  172|     def scope(self): return self.__page.scope()
  173|     def write(self, text): self.os().write(text)
  174| 
  175|     def _init_formatters(self, config_option, type_msg):
  176|         """Loads strategies from config file"""
  177|         base = 'Synopsis.Formatter.HTML.FormatStrategy.'
  178|         try:
  179|             config_obj = getattr(config.obj.ScopePages, config_option)
  180|             if type(config_obj) not in (types.ListType, types.TupleType):
  181|                raise TypeError, "ScopePages.%s must be a list or tuple of modules"%config_option
  182|             for formatter in config_obj:
  183|                clas = core.import_object(formatter, basePackage=base)
  184|                if config.verbose > 1: print "Using %s formatter:"%type_msg,clas
  185|                self.addFormatter(clas)
  186|         except AttributeError:
  187|             # Some defaults if config fails
  188|             self._init_default_formatters()
  189| 
  190|     def addFormatter(self, formatterClass):
  191|         """Adds the given formatter Class. An object is instantiated from the
  192|         class passing self to the constructor. Stores the object, and stores
  193|         which format methods it overrides"""
  194|         formatter = formatterClass(self)
  195|         self.__formatters.append(formatter)
  196|         # For each method name:
  197|         for method in self.__formatdict.keys():
  198|             no_func = getattr(FormatStrategy.Strategy, method).im_func
  199|             method_obj = getattr(formatter, method)
  200|             # If it was overridden in formatter
  201|             if method_obj.im_func is not no_func:
  202|                # Add to the dictionary
  203|                self.__formatdict[method].append(method_obj)
  204|     
  205|     # Access to generated values
  206|     def type_ref(self): return self.__type_ref
  207|     def type_label(self): return self.__type_label
  208|     def declarator(self): return self.__declarator
  209|     def parameter(self): return self.__parameter
  210|     
  211|     def reference(self, name, label=None, **keys):
  212|         """Returns a reference to the given name. The name is a scoped name,
  213|         and the optional label is an alternative name to use as the link text.
  214|         The name is looked up in the TOC so the link may not be local. The
  215|         optional keys are appended as attributes to the A tag."""
  216|         if not label: label = anglebrackets(Util.ccolonName(name, self.scope()))
  217|         entry = config.toc[name]
  218|         if entry: return apply(href, (rel(self.filename(), entry.link), label), keys)
  219|         return label or ''
  220| 
  221|     def label(self, name, label=None):
  222|         """Create a label for the given name. The label is an anchor so it can
  223|         be referenced by other links. The name of the label is derived by
  224|         looking up the name in the TOC and using the link in the TOC entry.
  225|         The optional label is an alternative name to use as the displayed
  226|         name. If the name is not found in the TOC then the name is not
  227|         anchored and just label is returned (or name if no label is given).
  228|         """
  229|         if label is None: label = name
  230|         # some labels are templates with <>'s
  231|         entry = config.toc[name]
  232|         label = anglebrackets(Util.ccolonName(label, self.scope()))
  233|         if entry is None: return label
  234|         location = entry.link
  235|         index = string.find(location, '#')
  236|         if index >= 0: location = location[index+1:]
  237|         return location and Tags.name(location, label) or label
  238| 
  239| 
  240|     def formatDeclaration(self, decl, method):
  241|         """Format decl using named method of each formatter. Each formatter
  242|         returns two strings - type and name. All the types are joined and all
  243|         the names are joined separately. The consolidated type and name
  244|         strings are then passed to writeSectionItem."""
  245|         # TODO - investigate quickest way of doing this. I tried.
  246|         # A Lambda that calls the given function with decl
  247|         format = lambda func, decl=decl: func(decl)
  248|         # Get a list of 2tuples [('type','name'),('type','name'),...]
  249|         type_name = map(format, self.__formatdict[method])
  250|         if not len(type_name): return
  251|         # NEW CODE:
  252|         text = string.strip(string.join(type_name))
  253|         self.writeSectionItem(text)
  254|         return
  255| 
  256|     def process(self, decl):
  257|         """Formats the given decl, creating the output for this Part of the
  258|         page. This method is implemented in various subclasses in different
  259|         ways, for example Summary and Detail iterate through the children of
  260|         'decl' section by section, whereas Heading only formats decl itself.
  261|         """
  262|         pass
  263|         
  264|     #################### AST Visitor ############################################
  265|     def visitDeclaration(self, decl):   self.formatDeclaration(decl, 'formatDeclaratio
  266|     def visitForward(self, decl):       self.formatDeclaration(decl, 'formatFo
  267|     def visitGroup(self, decl):         self.formatDeclaration(decl, 'formatGroup')
  268|     def visitScope(self, decl):        self.formatDeclaration(decl, 'forma
  269|     def visitModule(self, decl):        self.formatDeclaration(decl, 'format
  270|     def visitMetaModule(self, decl):    self.formatDeclaration(decl, 'formatMetaModu
  271|     def visitClass(self, decl):        self.formatDeclaration(decl, 'forma
  272|     def visitTypedef(self, decl):       self.formatDeclaration(decl, 'formatTy
  273|     def visitEnum(self, decl):         self.formatDeclaration(decl, 'for
  274|     def visitVariable(self, decl):      self.formatDeclaration(decl, 'formatVari
  275|     def visitConst(self, decl):        self.formatDeclaration(decl, 'forma
  276|     def visitFunction(self, decl):      self.formatDeclaration(decl, 'formatFunc
  277|     def visitOperation(self, decl):     self.formatDeclaration(decl, 'formatOperat
  278| 
  279| 
  280|     #################### Type Formatter/Visitor #################################
  281|     def formatType(self, typeObj, id_holder = None):
  282|         "Returns a reference string for the given type object"
  283|         if typeObj is None: return "(unknown)"
  284|         if id_holder:
  285|             save_id = self.__id_holder
  286|             self.__id_holder = id_holder
  287|         typeObj.accept(self)
  288|         if id_holder:
  289|             self.__id_holder = save_id
  290|         return self.__type_label
  291| 
  292|     def visitBaseType(self, type):
  293|         "Sets the label to be a reference to the type's name"
  294|         self.__type_label = self.reference(type.name())
  295|         
  296|     def visitUnknown(self, type):
  297|         "Sets the label to be a reference to the type's link"
  298|         self.__type_label = self.reference(type.link())
  299|         
  300|     def visitDeclared(self, type):
  301|         "Sets the label to be a reference to the type's name"
  302|         self.__type_label = self.reference(type.name())
  303| 
  304|     def visitDependent(self, type):
  305|         "Sets the label to be the type's name (which has no proper scope)"
  306|         self.__type_label = type.name()[-1]
  307|         
  308|     def visitModifier(self, type):
  309|         "Adds modifiers to the formatted label of the modifier's alias"
  310|         alias = self.formatType(type.alias())
  311|         def amp(x):
  312|             if x == '&': return '&amp;'
  313|             return x
  314|         pre = string.join(map(lambda x:x+"&nbsp;", map(amp, type.premod())), '')
  315|         post = string.join(map(amp, type.postmod()), '')
  316|         self.__type_label = "%s%s%s"%(pre,alias,post)
  317|             
  318|     def visitParametrized(self, type):
  319|         "Adds the parameters to the template name in angle brackets"
  320|         if type.template():
  321|             type_label = self.reference(type.template().name())
  322|         else:
  323|             type_label = "(unknown)"
  324|         params = map(self.formatType, type.parameters())
  325|         self.__type_label = "%s&lt;%s&gt;"%(type_label,string.join(params, ", "))
  326| 
  327|     def visitTemplate(self, type):
  328|         "Labs the template with the parameters"
  329|         self.__type_label = "template&lt;%s&gt;"%(
  330|             string.join(map(lambda x:"typename "+x, map(self.formatType, type.parameters())), ",")
  331|         )
  332| 
  333|     def visitFunctionType(self, type):
  334|         "Labels the function type with return type, name and parameters"
  335|         ret = self.formatType(type.returnType())
  336|         params = map(self.formatType, type.parameters())
  337|         pre = string.join(type.premod(), '')
  338|         if self.__id_holder:
  339|             ident = self.__id_holder[0]
  340|             del self.__id_holder[0]
  341|         else:
  342|             ident = ''
  343|         self.__type_label = "%s(%s%s)(%s)"%(ret,pre,ident,string.join(params,", "))
  344| 
  345| 
  346| 
  347|     # These are overridden in {Summary,Detail}Formatter
  348|     def write_start(self):
  349|         "Abstract method to start the output, eg table headings"
  350|         pass
  351|     def writeSectionStart(self, heading):
  352|         "Abstract method to start a section of declaration types"
  353|         pass
  354|     def writeSectionEnd(self, heading):
  355|         "Abstract method to end a section of declaration types"
  356|         pass
  357|     def writeSectionItem(self, text):
  358|         "Abstract method to write the output of one formatted declaration"
  359|         pass
  360|     def write_end(self):
  361|         "Abstract method to end the output, eg close the table"
  362|         pass
  363| 
  364| class Heading(Part):
  365|     """Heading page part. Displays a header for the page -- its strategies are
  366|     only passed the object that the page is for; ie a Class or Module"""
  367|     def __init__(self, page):
  368|         Part.__init__(self, page)
  369|         self._init_formatters('heading_formatters', 'heading')
  370| 
  371|     def _init_default_formatters(self):
  372|         self.addFormatter( FormatStrategy.Heading )
  373|         self.addFormatter( FormatStrategy.ClassHierarchyGraph )
  374|         self.addFormatter( FormatStrategy.DetailCommenter )
  375| 
  376|     def writeSectionItem(self, text):
  377|         """Writes text and follows with a horizontal rule"""
  378|         self.write(text + '\n<hr>\n')
  379| 
  380|     def process(self, decl):
  381|         """Process this Part by formatting only the given decl"""
  382|         decl.accept(self)
  383| 
  384| class Summary(Part):
  385|     """Formatting summary visitor. This formatter displays a summary for each
  386|     declaration, with links to the details if there is one. All of this is
  387|     controlled by the ASTFormatters."""
  388|     def __init__(self, page):
  389|         Part.__init__(self, page)
  390|         self.__link_detail = 0
  391|         self._init_formatters('summary_formatters', 'summary')
  392| 
  393|     def _init_default_formatters(self):
  394|         self.addFormatter( FormatStrategy.SummaryAST )
  395|         self.addFormatter( FormatStrategy.SummaryCommenter )
  396| 
  397|     def set_link_detail(self, boolean):
  398|         """Sets link_detail flag to given value.
  399|         @see label()"""
  400|         self.__link_detail = boolean
  401|         config.link_detail = boolean
  402| 
  403|     def label(self, ref, label=None):
  404|         """Override to check link_detail flag. If it's set, returns a reference
  405|         instead - which will be to the detailed info"""
  406|         if label is None: label = ref
  407|         if self.__link_detail:
  408|             # Insert a reference instead
  409|             return span('name',self.reference(ref, Util.ccolonName(label, self.scope())))
  410|         return Part.label(self, ref, label)
  411|         
  412|     def writeSectionStart(self, heading):
  413|         """Starts a table entity. The heading is placed in a row in a td with
  414|         the class 'heading'."""
  415|         self.write('<table width="100%%" summary="%s">\n'%heading)
  416|         self.write('<col><col width="100%%">')
  417|         self.write('<tr><td class="heading" colspan="2">' + heading + '</td></tr>\n')
  418| 
  419|     def writeSectionEnd(self, heading):
  420|         """Closes the table entity and adds a break."""
  421|         self.write('</table>\n<br>\n')
  422| 
  423|     def writeSectionItem(self, text):
  424|         """Adds a table row"""
  425|         if text[:22] == '<td class="summ-start"':
  426|             # text provided its own TD element
  427|             self.write('<tr>' + text + '</td></tr>\n')
  428|         else:
  429|             self.write('<tr><td class="summ-start">' + text + '</td></tr>\n')
  430| 
  431|     def process(self, decl):
  432|         "Print out the summaries from the given decl"
  433|         decl_style = config.decl_style
  434|         SUMMARY = DeclStyle.SUMMARY
  435|         config.link_detail = 0
  436|         
  437|         config.sorter.set_scope(decl)
  438|         config.sorter.sort_section_names()
  439| 
  440|         self.write_start()
  441|         for section in config.sorter.sections():
  442|             # Write a header for this section
  443|             if section[-1] == 's': heading = section+'es Summary:'
  444|             else: heading = section+'s Summary:'
  445|             self.writeSectionStart(heading)
  446|             # Iterate through the children in this section
  447|             for child in config.sorter.children(section):
  448|                # Check if need to add to detail list
  449|                if decl_style[child] != SUMMARY:
  450|                    # Setup the linking stuff
  451|                    self.set_link_detail(1)
  452|                    child.accept(self)
  453|                    self.set_link_detail(0)
  454|         else:
  455|                 # Just do it
  456|                    child.accept(self)
  457|             # Finish off this section
  458|             self.writeSectionEnd(heading)
  459|         self.write_end()
  460| 
  461| 
  462| class Detail(Part):
  463|     def __init__(self, page):
  464|         Part.__init__(self, page)
  465|         self._init_formatters('detail_formatters', 'detail')
  466| 
  467|     def _init_default_formatters(self):
  468|         self.addFormatter( FormatStrategy.DetailAST )
  469|         #self.addFormatter( ClassHierarchySimple )
  470|         self.addFormatter( FormatStrategy.DetailCommenter )
  471| 
  472|     def writeSectionStart(self, heading):
  473|         """Creates a table with one row. The row has a td of class 'heading'
  474|         containing the heading string"""
  475|         self.write('<table width="100%%" summary="%s">\n'%heading)
  476|         self.write('<tr><td colspan="2" class="heading">' + heading + '</td></tr>\n')
  477|         self.write('</table>')
  478| 
  479|     def writeSectionItem(self, text):
  480|         """Writes text and follows with a horizontal rule"""
  481|         self.write(text + '\n<hr>\n')
  482| 
  483|     def process(self, decl):
  484|         "Print out the details for the children of the given decl"
  485|         decl_style = config.decl_style
  486|         SUMMARY = DeclStyle.SUMMARY
  487| 
  488|         config.sorter.set_scope(decl)
  489|         config.sorter.sort_section_names()
  490| 
  491|         # Iterate through the sections with details
  492|         self.write_start()
  493|         for section in config.sorter.sections():
  494|             # Write a heading
  495|             heading = section+' Details:'
  496|             started = 0 # Lazy section start incase no details for this section
  497|             # Iterate through the children in this section
  498|             for child in config.sorter.children(section):
  499|                # Check if need to add to detail list
  500|                if decl_style[child] == SUMMARY:
  501|                continue
  502|                # Check section heading
  503|                if not started:
  504|                started = 1
  505|                    self.writeSectionStart(heading)
  506|                child.accept(self)
  507|             # Finish the section
  508|             if started: self.writeSectionEnd(heading)
  509|         self.write_end()
  510|      
  511| class Inheritance (Part):
  512|     def __init__(self, page):
  513|         Part.__init__(self, page)
  514|         self._init_formatters('inheritance_formatters', 'inheritance')
  515|         self.__start_list = 0
  516| 
  517|     def _init_default_formatters(self):
  518|         self.addFormatter( FormatStrategy.Inheritance )
  519| 
  520|     def process(self, decl):
  521|         "Walk the hierarchy to find inherited members to print."
  522|         if not isinstance(decl, AST.Class): return
  523|         self.write_start()
  524|         names = decl.declarations()
  525|         names = map(self._short_name, names)
  526|         self._process_superclasses(decl, names)
  527|         self.write_end()
  528| 
  529|     def _process_class(self, clas, names):
  530|         "Prints info for the given class, and calls _process_superclasses after"
  531|         config.sorter.set_scope(clas)
  532|         config.sorter.sort_section_names()
  533|         child_names = []
  534| 
  535|         # Iterate through the sections
  536|         for section in config.sorter.sections():
  537|             # Write a heading
  538|             heading = section+'s Inherited from '+ Util.ccolonName(clas.name(), self.scope())
  539|             started = 0 # Lazy section start incase no details for this section
  540|             # Iterate through the children in this section
  541|             for child in config.sorter.children(section):
  542|                child_name = self._short_name(child)
  543|                if child_name in names:
  544|                continue
  545|                # FIXME: This doesn't account for the inheritance type
  546|                # (private etc)
  547|                if child.accessibility() == AST.PRIVATE:
  548|                continue
  549|                # Don't include constructors and destructors!
  550|                if isinstance(child, AST.Function) and child.language() == 'C++' and len(child.realname())>1:
  551|                    if child.realname()[-1] == child.realname()[-2]: continue
  552|                    elif child.realname()[-1] == "~"+child.realname()[-2]: continue
  553|                # FIXME: skip overriden declarations
  554|                child_names.append(child_name)
  555|                # Check section heading
  556|                if not started:
  557|                started = 1
  558|                    self.writeSectionStart(heading)
  559|                child.accept(self)
  560|             # Finish the section
  561|             if started: self.writeSectionEnd(heading)
  562|         
  563|         self._process_superclasses(clas, names + child_names)
  564|     
  565|     def _short_name(self, decl):
  566|         if isinstance(decl, AST.Function):
  567|             return decl.realname()[-1]
  568|         return decl.name()[-1]
  569|     
  570|     def _process_superclasses(self, clas, names):
  571|         """Iterates through the superclasses of clas and calls _process_clas for
  572|         each"""
  573|         for inheritance in clas.parents():
  574|             parent = inheritance.parent()
  575|             if isinstance(parent, Type.Declared):
  576|                parent = parent.declaration()
  577|                if isinstance(parent, AST.Class):
  578|                    self._process_class(parent, names)
  579|                continue
  580|             #print "Ignoring", parent.__class__.__name__, "parent of", clas.name()
  581|             pass #ignore
  582|      
  583|     def writeSectionStart(self, heading):
  584|         """Creates a table with one row. The row has a td of class 'heading'
  585|         containing the heading string"""
  586|         self.write('<table width="100%%" summary="%s">\n'%heading)
  587|         self.write('<tr><td colspan="2" class="heading">' + heading + '</td></tr>\n')
  588|         self.write('<tr><td class="inherited">')
  589|         self.__start_list = 1
  590| 
  591|     def writeSectionItem(self, text):
  592|         """Adds a table row"""
  593|         if self.__start_list:
  594|             self.write(text)
  595|             self.__start_list = 0
  596|         else:
  597|             self.write(',\n'+text)
  598| 
  599|     def writeSectionEnd(self, heading):
  600|         """Closes the table entity and adds a break."""
  601|         self.write('</td></tr></table>\n<br>\n')
  602| 
  603|