Modules | Files | Inheritance Tree | Inheritance Graph | Name Index | Config
File: Synopsis/Core/AST.py
    1| # $Id: AST.py,v 1.27 2003/01/27 06:53:36 chalky Exp $
    2| #
    3| # This file is a part of Synopsis.
    4| # Copyright (C) 2000, 2001 Stefan Seefeld
    5| # Copyright (C) 2000, 2001 Stephen Davies
    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: AST.py,v $
   23| # Revision 1.27  2003/01/27 06:53:36  chalky
   24| # Added macro support for C++.
   25| #
   26| # Revision 1.26  2003/01/20 06:43:02  chalky
   27| # Refactored comment processing. Added AST.CommentTag. Linker now determines
   28| # comment summary and extracts tags. Increased AST version number.
   29| #
   30| # Revision 1.25  2003/01/16 17:14:10  chalky
   31| # Increase AST version number. SourceFiles store full filename. Executor/Project
   32| # uses it to check timestamp for all included files when deciding whether to
   33| # reparse input files.
   34| #
   35| # Revision 1.24  2002/12/12 17:25:32  chalky
   36| # Implemented Include support for C++ parser. A few other minor fixes.
   37| #
   38| # Revision 1.23  2002/12/09 04:00:57  chalky
   39| # Added multiple file support to parsers, changed AST datastructure to handle
   40| # new information, added a demo to demo/C++. AST Declarations now have a
   41| # reference to a SourceFile (which includes a filename) instead of a filename.
   42| #
   43| # Revision 1.22  2002/10/11 05:56:38  chalky
   44| # Added 'suspect' flag for comments
   45| #
   46| # Revision 1.21  2002/07/11 09:28:23  chalky
   47| # Fixes. Implement Cache Executor
   48| #
   49| # Revision 1.20  2002/06/22 06:54:53  chalky
   50| # Fixed default-value bug
   51| #
   52| # Revision 1.19  2002/04/26 01:21:13  chalky
   53| # Bugs and cleanups
   54| #
   55| # Revision 1.18  2001/11/07 05:58:21  chalky
   56| # Reorganised UI, opening a .syn file now builds a simple project to view it
   57| #
   58| # Revision 1.17  2001/07/19 04:03:05  chalky
   59| # New .syn file format.
   60| #
   61| # Revision 1.16  2001/07/03 01:58:56  chalky
   62| # Remove duplicate set_name method
   63| #
   64| # Revision 1.15  2001/06/15 17:46:49  stefan
   65| # set_realname is no longer needed since realname is computed from name
   66| #
   67| # Revision 1.14  2001/06/13 01:55:11  stefan
   68| # modify the realName member to contain only the unscoped name. This has the nice effect that pruning the scope will affect the name and realname at once, since the realName() method computes the scoped name tuple on-the-fly
   69| #
   70| # Revision 1.13  2001/06/08 21:04:38  stefan
   71| # more work on grouping
   72| #
   73| # Revision 1.12  2001/06/05 10:03:35  chalky
   74| # Fixed subtle bug.. s/__type/__returnType/ !!!! bad python! bad!
   75| #
   76| # Revision 1.11  2001/04/17 15:47:26  chalky
   77| # Added declaration name mapper, and changed refmanual to use it instead of the
   78| # old language mapping
   79| #
   80| # Revision 1.10  2001/04/11 04:27:47  stefan
   81| # start working on a Group class
   82| #
   83| # Revision 1.9  2001/02/07 09:56:59  chalky
   84| # Support for "previous comments" in C++ parser and Comments linker.
   85| #
   86| # Revision 1.8  2001/01/25 18:27:47  stefan
   87| # added Type.Array type and removed AST.Declarator. Adjusted the IDL parser to that.
   88| #
   89| # Revision 1.7  2001/01/24 12:47:28  chalky
   90| # Reapplied old behaviour of Visitor of passing the call up to visitDeclaration
   91| # so that all the places that broke work again.
   92| #
   93| # Revision 1.6  2001/01/23 19:47:45  stefan
   94| # fix Visitor class such that only desired methods need to be redefined
   95| #
   96| # Revision 1.5  2001/01/22 17:06:15  stefan
   97| # added copyright notice, and switched on logging
   98| #
   99| 
  100| """Abstract Syntax Tree classes.
  101| 
  102| This file contains classes which encapsulate nodes in the AST. The base class
  103| is the Declaration class that encapsulates a named declaration. All names used
  104| are scoped tuples.
  105| 
  106| Also defined in module scope are the constants DEFAULT, PUBLIC, PROTECTED and
  107| PRIVATE.
  108| """
  109| 
  110| import string, sys, cPickle, types, stat, statcache
  111| import Util, Type
  112| 
  113| # The version of the file format - this should be increased everytime
  114| # incompatible changes are made to the AST or Type classes
  115| FILE_VERSION = 5
  116| 
  117| # Accessibility constants
  118| DEFAULT = 0
  119| PUBLIC = 1
  120| PROTECTED = 2
  121| PRIVATE = 3
  122| 
  123| def ccmp(a,b):
  124|     """Compares classes of two objects"""
  125|     return cmp(type(a),type(b)) or cmp(a.__class__,b.__class__)
  126| 
  127| def load(filename):
  128|     """Loads an AST object from the given filename"""
  129|     try:
  130|         file = open(filename, "r")
  131|         unpickler = cPickle.Unpickler(file)
  132|         version = unpickler.load()
  133|         if version is not FILE_VERSION:
  134|             file.close()
  135|             raise Exception, 'Wrong file version'
  136|         deps = unpickler.load() # ignored here
  137|         ast = unpickler.load()
  138|         file.close()
  139|         return ast
  140|     except:
  141|         exc, msg = sys.exc_info()[0:2]
  142|         if exc is Exception:
  143|             raise Exception, "Loading AST from '%s': %s"%(filename, msg)
  144|         raise Exception, "Loading AST from '%s', %s: %s"%(filename, exc, msg)
  145| 
  146| def load_deps(filename):
  147|     """Loads a dependencies object from the given filename. The file will be
  148|     an AST save file (usually *.syn), but this method only reads up to the
  149|     dependencies object stored before the actual AST. The object returned is a
  150|     list of (filename, timestamp) pairs."""
  151|     try:
  152|         file = open(filename, "r")
  153|         unpickler = cPickle.Unpickler(file)
  154|         version = unpickler.load()
  155|         if version is not FILE_VERSION:
  156|             file.close()
  157|             raise Exception, 'Wrong file version'
  158|         deps = unpickler.load()
  159|         # stop here, before loading the (probably huge) AST object
  160|         file.close()
  161|         return deps
  162|     except:
  163|         exc, msg = sys.exc_info()[0:2]
  164|         if exc is Exception:
  165|             raise Exception, "Loading dependencies from '%s': %s"%(filename, msg)
  166|         raise Exception, "Loading dependencies from '%s', %s: %s"%(filename, exc, msg)
  167| 
  168| def save(filename, ast):
  169|     """Saves an AST object to the given filename"""
  170|     try:
  171|         deps = make_deps(ast)
  172|         file = open(filename, "w")
  173|         pickler = cPickle.Pickler(file, 1)
  174|         pickler.dump(FILE_VERSION)
  175|         pickler.dump(deps)
  176|         pickler.dump(ast)
  177|         file.close()
  178|     except:
  179|         exc, msg = sys.exc_info()[0:2]
  180|         raise Exception, "Saving '%s', %s: %s"%(filename, exc, msg)
  181| 
  182| def make_deps(ast):
  183|     """Creates the dependencies object to save in the .syn file from the given
  184|     AST. The dependencies are a list of (filename, timestamp) pairs, extracted
  185|     from ast.files()"""
  186|     deps = []
  187|     for file in ast.files().values():
  188|         filename = file.full_filename()
  189|         try:
  190|             info = statcache.stat(filename)
  191|         except:
  192|             # Ignore any file we can't stat
  193|             continue
  194|         time = info[stat.ST_MTIME]
  195|         deps.append( (filename, time) )
  196|     return deps
  197| 
  198| class AST:
  199|     """Top-level Abstract Syntax Tree.
  200|     The AST represents the whole AST for a file or group of files as a list of
  201|     declarations and a types dictionary.
  202|     """
  203| 
  204|     def __init__(self, files=None, declarations=None, typedict=None):
  205|         """Constructor"""
  206|         if files is None: files = {}
  207|         if declarations is None: declarations = []
  208|         if type(files) is not types.DictType: raise TypeError, "files parameter must be a dict of SourceFile objects"
  209|         if type(declarations) != type([]): raise TypeError, "declarations parameter must be a list of declarations"
  210|         if typedict is None: typedict = Type.Dictionary()
  211|         elif not isinstance(typedict, Type.Dictionary): raise TypeError, "types must be an instance of Type.Dictionary"
  212|         self.__files        = f
  213|         self.__declarations = list(declarations)
  214|         self.__types       = typed
  215|     def files(self):
  216|         """The files this AST represents. Returns a dictionary mapping
  217|         filename to SourceFile objects."""     
  218|         return self.__files
  219|     def declarations(self):
  220|         """List of Declaration objects. These are the declarations at file scope"""
  221|         return self.__declarations
  222|     def types(self):
  223|         """Dictionary of types. This is a Type.Dictionary object"""
  224|         return self.__types
  225|     def accept(self, visitor):
  226|         """Accept the given visitor"""
  227|         visitor.visitAST(self)
  228|     def merge(self, other_ast):
  229|         """Merges another AST. Files and declarations are appended to those in
  230|         this AST, and types are merged by overwriting existing types -
  231|         Unduplicator is responsible for sorting out the mess this may cause :)"""
  232|         self.__types.merge(other_ast.types())
  233|         self.__declarations.extend(other_ast.declarations())
  234|         # Do a basic job of merging the SourceFiles, trying not to lose
  235|         # anything (even though duplicates are created at this stage - they
  236|         # will be cleaned up by the Linker)
  237|         for filename, file in other_ast.files().items():
  238|             if not self.__files.has_key(filename):
  239|                self.__files[filename] = file
  240|                continue
  241|             myfile = self.__files[filename]
  242|             myfile.set_is_main(myfile.is_main() or file.is_main())
  243|             myfile.declarations().extend(file.declarations())
  244|             myfile.includes().extend(file.includes())
  245| 
  246| class Include:
  247|     """Information about an include directive in a SourceFile.
  248|     If the include directive required a macro expansion to get the filename,
  249|     the is_macro will return true. If the include directive was actually an
  250|     include_next, then is_next will return true.
  251|     """
  252|     def __init__(self, target, is_macro, is_next):
  253|         if not isinstance(target, SourceFile): raise TypeError, "target parameter must be a SourceFile"
  254|         self.__target = target
  255|         self.__is_macro = is_macro
  256|         self.__is_next = is_next
  257| 
  258|     def target(self):
  259|         return self.__target
  260| 
  261|     def set_target(self, target):
  262|         self.__target = target
  263| 
  264|     def is_macro(self):
  265|         return self.__is_macro
  266| 
  267|     def is_next(self):
  268|         return self.__is_next
  269| 
  270| class SourceFile:
  271|     """The information about a file that the AST was generated from.
  272|     Contains filename, all declarations from this file (even nested ones) and
  273|     includes (aka imports) from this file."""
  274| 
  275|     def __init__(self, filename, full_filename, language):
  276|         """Constructor"""
  277|         if type(filename) is not types.StringType: raise TypeError, "filename parameter must be a string filename"
  278|         if type(full_filename) is not types.StringType: raise TypeError, "full_filename parameter must be a string filename"
  279|         if type(language) is not types.StringType: raise TypeError, "language parameter must be a string language"
  280|         self.__filename = filename
  281|         self.__full_filename = full_filename
  282|         self.__language = language
  283|         self.__includes = []
  284|         self.__declarations = []
  285|         self.__is_main = 0
  286| 
  287|     def is_main(self):
  288|         """Returns whether this was a main file. A source file is a main file
  289|         if it was parsed directly or as an extra file. A source file is not a
  290|         main file if it was just included. A source file that had no actual
  291|         declarations but was given to the parser as either the main source
  292|         file or an extra file is still a main file."""
  293|         return self.__is_main
  294| 
  295|     def set_is_main(self, value):
  296|         """Sets the is_main flag. Typically only called once, and then may by
  297|         the linker if it discovers that a file is actually a main file
  298|         elsewhere."""
  299|         self.__is_main = value
  300| 
  301|     def filename(self):
  302|         """Returns the filename of this file. The filename can be absolute or
  303|         relative, depending on the settings for the Parser"""
  304|         return self.__filename
  305| 
  306|     def full_filename(self):
  307|         """Returns the full_filename of this file. The filename can be absolute or
  308|         relative, depending on the filename given to the Parser. This filename
  309|         does not have any basename stripped from it, and should be accessible
  310|         from the current directory as is whether absolute or relative."""
  311|         return self.__full_filename
  312| 
  313|     def language(self):
  314|         """Returns the language for this file as a string"""
  315|         return self.__language
  316| 
  317|     def declarations(self):
  318|         """Returns a list of declarations declared in this file"""
  319|         return self.__declarations
  320| 
  321|     def includes(self):
  322|         """Returns a the files included by this file. These may be
  323|         absolute or relative, depending on the settings for the Parser. This
  324|         may also include system files. The return value is a list of tuples,
  325|         with each tuple being a pair (included-from-filename,
  326|         include-filename). This allows distinction of files directly included
  327|         (included-from-filename == self.filename()) but also allows dependency
  328|         tracking since *all* files read while parsing this file are included
  329|         in the list (even system files)."""
  330|         return self.__includes
  331|     
  332| class Declaration:
  333|     """Declaration base class. Every declaration has a name, comments,
  334|     accessibility and type. The default accessibility is DEFAULT except for
  335|     C++ where the Parser always sets it to one of the other three. """
  336|     
  337|     def __init__(self, file, line, language, strtype, name):
  338|         if file is not None:
  339|             if type(file) is not types.InstanceType or not isinstance(file, SourceFile):
  340|                raise TypeError, "file must be a SourceFile object"
  341|         self.__file  = file
  342|         self.__line  = line
  343|         self.__language = language
  344|         self.__name = tuple(name)
  345|         self.__type = strtype
  346|         self.__comments = []
  347|         self.__accessibility = DEFAULT
  348|     def file(self):
  349|         """The SourceFile this declaration appeared in"""
  350|         return self.__file
  351|     def line(self):
  352|         """The line of the file this declaration started at"""
  353|         return self.__line
  354|     def language(self):
  355|         """The language this declaration is in"""
  356|         return self.__language
  357|     def type(self):
  358|         """A string name of the type of this declaration"""
  359|         return self.__type
  360|     def name(self):
  361|         """The scoped tuple name of this declaration"""
  362|         return self.__name
  363|     def comments(self):
  364|         """A list of Comment objects"""
  365|         return self.__comments
  366|     def accept(self, visitor):
  367|         """Visit the given visitor"""
  368|         visitor.visitDeclaration(self)
  369|     def accessibility(self):
  370|         """One of the accessibility constants.
  371|         This may be one of DEFAULT, PUBLIC, PROTECTED or PRIVATE, which are
  372|         defined at module scope (Synopsis.AST)"""
  373|         return self.__accessibility
  374| 
  375|     def set_name(self, name):
  376|         """Change the name of the declaration. If you do want to change the
  377|         name (and you probably don't!) then make sure you update your 'types'
  378|         dictionary too!"""
  379|         self.__name = tuple(name)
  380|     def set_accessibility(self, axs):
  381|         """Change the accessibility"""
  382|         self.__accessibility = axs
  383| 
  384| class Macro (Declaration):
  385|     """A preprocessor macro. Note that macros are not strictly part of the
  386|     AST, and as such are always in the global scope. A macro is "temporary" if
  387|     it was #undefined in the same file it was #defined in."""
  388| 
  389|     def __init__(self, file, line, language, type, name, parameters, text):
  390|         """Constructor"""
  391|         Declaration.__init__(self, file, line, language, type, name)
  392|         self.__parameters = parameters
  393|         self.__text = text
  394| 
  395|     def parameters(self):
  396|         """Returns a list of parameter names (strings) for this macro if it
  397|         has any. Note that if the macro is not a function-like macro, this
  398|         method will return None. If it is a function-like macro but with no
  399|         parameters, an empty list will be returned."""
  400|         return self.__parameters
  401| 
  402|     def text(self):
  403|         """Returns the replacement text for this macro as a string"""
  404|         return self.__text
  405| 
  406|     def accept(self, visitor): visitor.visitMacro(self)
  407| 
  408| class Forward (Declaration):
  409|     """Forward declaration"""
  410| 
  411|     def __init__(self, file, line, language, type, name):
  412|         Declaration.__init__(self, file, line, language, type, name)
  413|     def accept(self, visitor): visitor.visitForward(self)
  414| 
  415| class Group (Declaration):
  416|     """Base class for groups which contain declarations.
  417|     This class doesn't correspond to any language construct.
  418|     Rather, it may be used with comment-embedded grouping tags
  419|     to regroup declarations that are to appear together in the
  420|     manual."""
  421| 
  422|     def __init__(self, file, line, language, type, name):
  423|         Declaration.__init__(self, file, line, language, type, name)
  424|         self.__declarations = []
  425|     def declarations(self):
  426|         """The list of declarations in this group"""
  427|         return self.__declarations
  428|     def accept(self, visitor):
  429|         #print "group accept", visitor
  430|         visitor.visitGroup(self)
  431| 
  432| class Scope (Group):
  433|     """Base class for scopes (named groups)."""
  434| 
  435|     def __init__(self, file, line, language, type, name):
  436|         Group.__init__(self, file, line, language, type, name)
  437|     def accept(self, visitor): visitor.visitScope(self)
  438| 
  439| class Module (Scope):
  440|     """Module class"""
  441|     def __init__(self, file, line, language, type, name):
  442|         Scope.__init__(self, file, line, language, type, name)
  443|     def accept(self, visitor): visitor.visitModule(self)
  444| 
  445| class MetaModule (Module):
  446|     """Module Class that references all places where this Module occurs"""
  447|     def __init__(self, lang, type, name):
  448|         Scope.__init__(self, None, "", lang, type, name)
  449|         self.__module_declarations = []
  450|     def module_declarations(self):
  451|         """The module declarations this metamodule subsumes"""
  452|         return self.__module_declarations
  453|     def accept(self, visitor): visitor.visitMetaModule(self)
  454| 
  455| 
  456| class Inheritance:
  457|     """Inheritance class. This class encapsulates the information about an
  458|     inheritance, such as attributes like 'virtual' and 'public' """
  459|     def __init__(self, type, parent, attributes):
  460|         self.__type = type
  461|         self.__parent = parent
  462|         self.__attributes = attributes
  463|     def type(self):
  464|         """The type of inheritance ('implements', 'extends' etc)"""
  465|         return self.__type
  466|     def parent(self):
  467|         """The parent class or typedef declaration"""
  468|         return self.__parent
  469|     def attributes(self):
  470|         """Attributes such as 'virtual', 'public' etc"""
  471|         return self.__attributes
  472|     def accept(self, visitor): visitor.visitInheritance(self)
  473| 
  474|     def set_parent(self, parent): self.__parent = parent
  475| 
  476| 
  477| class Class (Scope):
  478|     """Class class."""
  479| 
  480|     def __init__(self, file, line, language, type, name):
  481|         Scope.__init__(self, file, line, language, type, name)
  482|         self.__parents = []
  483|         self.__template = None
  484|     def parents(self):
  485|         """The list of Inheritance objects representing base classes"""
  486|         return self.__parents
  487|     def template(self):
  488|         """The Template Type if this is a template, or None"""
  489|         return self.__template
  490|     def set_template(self, template):
  491|         self.__template = template
  492|     def accept(self, visitor): visitor.visitClass(self)
  493| 
  494| class Typedef (Declaration):
  495|     """Typedef class.
  496| 
  497|   alias()           -- the type object referenced by this alias
  498|   constr()          -- boolean: true if the alias type was constructed within this typedef declaration."""
  499|     def __init__(self, file, line, language, type, name, alias, constr):
  500|         Declaration.__init__(self, file, line, language, type, name)
  501|         self.__alias = alias
  502|         self.__constr = constr
  503|     def alias(self):
  504|         """The Type object aliased by this typedef"""
  505|         return self.__alias
  506|     def constr(self):
  507|         """True if alias type was constructed here.
  508|         For example, typedef struct _Foo {} Foo;"""
  509|         return self.__constr
  510|     def accept(self, visitor): visitor.visitTypedef(self)
  511| 
  512|     def set_alias(self, type): self.__alias = type
  513| 
  514| class Enumerator (Declaration):
  515|     """Enumerator of an Enum. Enumerators represent the individual names and
  516|     values in an enum."""
  517| 
  518|     def __init__(self, file, line, language, name, value):
  519|         Declaration.__init__(self, file, line, language, "enumerator", name)
  520|         self.__value = value
  521|     def value(self):
  522|         """The string value of this enumerator"""
  523|         return self.__value
  524|     def accept(self, visitor): visitor.visitEnumerator(self)
  525| 
  526| class Enum (Declaration):
  527|     """Enum declaration. The actual names and values are encapsulated by
  528|     Enumerator objects."""
  529| 
  530|     def __init__(self, file, line, language, name, enumerators):
  531|         Declaration.__init__(self, file, line, language, "enum", name)
  532|         self.__enumerators = enumerators
  533|     def enumerators(self):
  534|         """List of Enumerator objects"""
  535|         return self.__enumerators
  536|     def accept(self, visitor): visitor.visitEnum(self)
  537| 
  538| class Variable (Declaration):
  539|     """Variable definition"""
  540| 
  541|     def __init__(self, file, line, language, type, name, vtype, constr):
  542|         Declaration.__init__(self, file, line, language, type, name)
  543|         self.__vtype  = vtype
  544|         self.__constr  = constr
  545| 
  546|     def vtype(self):
  547|         """The Type object for this variable"""
  548|         return self.__vtype
  549|     def constr(self):
  550|         """True if the type was constructed here.
  551|         For example: struct Foo {} myFoo;"""
  552|         return self.__constr
  553|     def accept(self, visitor): visitor.visitVariable(self)
  554| 
  555|     def set_vtype(self, vtype): self.__vtype = vtype
  556|     
  557| 
  558| class Const (Declaration):
  559|     """Constant declaration. A constant is a name with a type and value."""
  560| 
  561|     def __init__(self, file, line, language, type, ctype, name, value):
  562|         Declaration.__init__(self, file, line, language, type, name)
  563|         self.__ctype  = ctype
  564|         self.__value = value
  565| 
  566|     def ctype(self):
  567|         """Type object for this const"""
  568|         return self.__ctype
  569|     def value(self):
  570|         """The string value of this type"""
  571|         return self.__value
  572|     def accept(self, visitor): visitor.visitConst(self)
  573| 
  574|     def set_ctype(self, ctype): self.__ctype = ctype
  575|     
  576| 
  577| class Parameter:
  578|     """Function Parameter"""
  579| 
  580|     def __init__(self, premod, type, postmod, identifier='', value=''):
  581|         self.__premodifier = premod
  582|         self.__type = type
  583|         self.__postmodifier = postmod
  584|         self.__identifier = identifier
  585|         self.__value = value
  586|     def premodifier(self):
  587|         """List of premodifiers such as 'in' or 'out'"""
  588|         return self.__premodifier
  589|     def type(self):
  590|         """The Type object"""
  591|         return self.__type
  592|     def postmodifier(self):
  593|         """Post modifiers..."""
  594|         return self.__postmodifier
  595|     def identifier(self):
  596|         """The string name of this parameter"""
  597|         return self.__identifier
  598|     def value(self):
  599|         """The string value of this parameter"""
  600|         return self.__value
  601|     def accept(self, visitor): visitor.visitParameter(self)
  602| 
  603|     def set_type(self, type): self.__type = type
  604| 
  605|     def __cmp__(self, other):
  606|         "Comparison operator"
  607|         #print "Parameter.__cmp__"
  608|         return cmp(self.type(),other.type())
  609|     def __str__(self):
  610|         return "%s%s%s"%(self.__premodifier,str(self.__type),self.__postmodifier)
  611| 
  612| class Function (Declaration):
  613|     """Function declaration.
  614|     Note that function names are stored in mangled form to allow overriding.
  615|     Formatters should use the realname() method to extract the unmangled name."""
  616| 
  617|     def __init__(self, file, line, language, type, premod, returnType, name, realname):
  618|         Declaration.__init__(self, file, line, language, type, name)
  619|         self.__realname = realname
  620|         self.__premodifier = premod
  621|         self.__returnType = returnType
  622|         self.__parameters = []
  623|         self.__postmodifier = []
  624|         self.__exceptions = []
  625|         self.__template = None
  626|     def premodifier(self):
  627|         """List of premodifiers such as 'oneway'"""
  628|         return self.__premodifier
  629|     def returnType(self):
  630|         """Type object for the return type of this function"""
  631|         return self.__returnType
  632|     def realname(self):
  633|         """The unmangled scoped name tuple of this function"""
  634|         name = list(self.name())
  635|         name[-1] = self.__realname
  636|         return tuple(name)
  637|     def parameters(self):
  638|         """The list of Parameter objects of this function"""
  639|         return self.__parameters
  640|     def postmodifier(self):
  641|         """The list of postmodifier strings"""
  642|         return self.__postmodifier
  643|     def exceptions(self):
  644|         """The list of exception Types"""
  645|         return self.__exceptions
  646|     def template(self):
  647|         """The Template Type if this is a template, or None"""
  648|         return self.__template
  649|     def set_template(self, template):
  650|         self.__template = template
  651|     def accept(self, visitor): visitor.visitFunction(self)
  652| 
  653|     def set_returnType(self, type): self.__returnType = type
  654| 
  655|     def __cmp__(self, other):
  656|         "Recursively compares the typespec of the function"
  657|         return ccmp(self,other) or cmp(self.parameters(), other.parameters())
  658| 
  659| class Operation (Function):
  660|     """Operation class. An operation is related to a Function and is currently
  661|     identical.
  662|     """
  663|     def __init__(self, file, line, language, type, premod, returnType, name, realname):
  664|         Function.__init__(self, file, line, language, type, premod, returnType, name, realname)
  665|     def accept(self, visitor): visitor.visitOperation(self)
  666| 
  667| class CommentTag:
  668|     """Information about a tag in a comment. Tags can represent meta-information
  669|     about a comment or extra attributes related to a declaration. For example,
  670|     some tags can nominate a comment as belonging to another declaration,
  671|     while others indicate information such as parameter and return type
  672|     descriptions."""
  673| 
  674|     def __init__(self, name, text):
  675|         """Constructor. Name is the name of tag, eg: 'class', 'param'. Text is
  676|         the rest of the text for a tag."""
  677|         self.__name = name
  678|         self.__text = text
  679| 
  680|     def name(self):
  681|         """Returns the name of this tag"""
  682|         return self.__name
  683| 
  684|     def text(self):
  685|         """Returns the text of this tag"""
  686|         return self.__text
  687| 
  688| class Comment:
  689|     """Information about a comment related to a declaration.
  690|     The comments are extracted verbatim by the parsers, and various Linker
  691|     CommentProcessors can select comments with appropriate formatting (eg: /**
  692|     style comments, //. style comments, or all // style comments).
  693|     The text field is text of the comment, less any tags that have been
  694|     extracted.
  695|     The summary field contains a summary of the comment, which may be equal to
  696|     the comment text if there is no extra detail. The summary field is only
  697|     set by Linker.Comments.Summarizer, which also ensures that there is only
  698|     one comment for the declaration first.
  699|     The list of tags in a comment can be extracted by a Linker
  700|     CommentProcessor, or is an empty list if not set.
  701|     C++ Comments may be suspect, which means that they were not immediately
  702|     before a declaration, but the extract_tails option was set so they were
  703|     kept for the Linker to deal with.
  704|     """
  705|     
  706|     def __init__(self, text, file, line, suspect=0):
  707|         self.__file = file
  708|         self.__line = line
  709|         self.__text = text
  710|         self.__summary = None
  711|         self.__tags = []
  712|         self.__suspect = suspect
  713| 
  714|     def text(self):
  715|         """The text of the comment"""
  716|         return self.__text
  717|     def set_text(self, text):
  718|         """Changes the text"""
  719|         self.__text = text
  720|     def summary(self):
  721|         """The summary of the comment"""
  722|         return self.__summary
  723|     def set_summary(self, summary):
  724|         """Changes the summary"""
  725|         self.__summary = summary
  726|     def tags(self):
  727|         """The tags of the comment. Only CommentTag instances should be added
  728|         to this list."""
  729|         return self.__tags
  730|     def __str__(self):
  731|         """Returns the text of the comment"""
  732|         return self.__text
  733|     def file(self):
  734|         """The file it was defined in"""
  735|         return self.__file
  736|     def line(self):
  737|         """The line it was defined at"""
  738|         return self.__line
  739|     def is_suspect(self):
  740|         """Returns true if the comment is suspect"""
  741|         return self.__suspect
  742|     def set_suspect(self, suspect):
  743|         """Sets whether the comment is suspect"""
  744|         self.__suspect = suspect
  745| 
  746| class Visitor :
  747|     """Visitor for AST nodes"""
  748|     def visitAST(self, node):
  749|         for declaration in node.declarations(): declaration.accept(self)
  750|     def visitDeclaration(self, node): return
  751|     def visitMacro(self, node): self.visitDeclaration(node)
  752|     def visitForward(self, node): self.visitDeclaration(node)
  753|     def visitGroup(self, node):
  754|         self.visitDeclaration(node)
  755|         for declaration in node.declarations(): declaration.accept(self)
  756|     def visitScope(self, node): self.visitGroup(node)
  757|     def visitModule(self, node): self.visitScope(node)
  758|     def visitMetaModule(self, node): self.visitModule(node)
  759|     def visitClass(self, node): self.visitScope(node)
  760|     def visitTypedef(self, node): self.visitDeclaration(node)
  761|     def visitEnumerator(self, node): self.visitDeclaration(node)
  762|     def visitEnum(self, node):
  763|         self.visitDeclaration(node)
  764|         for enum in node.enumerators(): enum.accept(self)
  765|     def visitVariable(self, node): self.visitDeclaration(node)
  766|     def visitConst(self, node): self.visitDeclaration(node)
  767|     def visitFunction(self, node):
  768|         self.visitDeclaration(node)
  769|         for parameter in node.parameters(): parameter.accept(self)
  770|     def visitOperation(self, node): self.visitFunction(node)
  771|     def visitParameter(self, node): return
  772|     def visitComment(self, node): return
  773|     def visitInheritance(self, node): return