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