Modules |
Files |
Inheritance Tree |
Inheritance Graph |
Name Index |
Config
File: Synopsis/Linker/Linker.py
1| # $Id: Linker.py,v 1.56 2003/02/01 23:57:08 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: Linker.py,v $
23| # Revision 1.56 2003/02/01 23:57:08 chalky
24| # Remove obsolete option that was blocking the real -p
25| #
26| # Revision 1.55 2003/02/01 05:40:48 chalky
27| # Remove the old config_obj handlers since they're no longer used, but added
28| # backward compat for old 'mappers' option (it's now called mapper_list).
29| #
30| # Revision 1.54 2003/01/20 07:00:43 chalky
31| # Use summary comment_processor by default
32| #
33| # Revision 1.53 2002/10/29 06:56:52 chalky
34| # Fixes to work on cygwin
35| #
36| # Revision 1.52 2002/10/28 16:30:05 chalky
37| # Trying to fix some bugs in the unduplication/stripping stages. Needs more work
38| #
39| # Revision 1.51 2002/10/11 05:57:17 chalky
40| # Support suspect comments
41| #
42| # Revision 1.50 2002/08/23 04:37:26 chalky
43| # Huge refactoring of Linker to make it modular, and use a config system similar
44| # to the HTML package
45| #
46| # Revision 1.49 2002/07/11 09:29:32 chalky
47| # Huge speed improvement O(n^2) -> O(n) in unduplicator, eg: 230sec -> 9sec
48| #
49| # Revision 1.48 2002/01/09 11:43:41 chalky
50| # Inheritance pics
51| #
52| # Revision 1.47 2001/07/26 08:21:58 chalky
53| # Fixes bug caused by bad template support
54| #
55| # Revision 1.46 2001/07/19 08:11:38 chalky
56| # Typo
57| #
58| # Revision 1.45 2001/07/19 07:57:52 chalky
59| # Bug fixes
60| #
61| # Revision 1.44 2001/07/19 03:59:56 chalky
62| # New .syn file format. Added EmptyNS to remove empty namespaces
63| #
64| # Revision 1.43 2001/06/15 18:27:08 stefan
65| # some cleanup; debugged and refactored the various stages such as prefix stripping, unduplicating, prefixing; some renaming (we ought to put some naming conventions into place...
66| #
67| # Revision 1.42 2001/06/13 13:13:16 chalky
68| # Realnames dont need mapping anymore since they are built from name()
69| # dynamically
70| #
71| # Revision 1.41 2001/06/05 10:01:28 chalky
72| # Can set (string)type of mapped decl names (eg: Package)
73| #
74| # Revision 1.40 2001/05/25 13:45:49 stefan
75| # fix problem with getopt error reporting
76| #
77| # Revision 1.39 2001/04/17 15:47:26 chalky
78| # Added declaration name mapper, and changed refmanual to use it instead of the
79| # old language mapping
80| #
81| # Revision 1.38 2001/04/06 02:35:39 chalky
82| # Parse config object
83| #
84| # Revision 1.37 2001/04/05 16:21:44 chalky
85| # Check for type with no name, ie: dummy enumerator
86| #
87| # Revision 1.36 2001/03/28 12:53:32 chalky
88| # Made module comments carry through into meta-module comments
89| #
90| # Revision 1.35 2001/02/13 06:55:23 chalky
91| # Made synopsis -l work again
92| #
93| # Revision 1.34 2001/02/13 06:36:46 chalky
94| # Added -a flag to strip decls with greater access
95| #
96| # Revision 1.33 2001/02/12 04:08:09 chalky
97| # Added config options to HTML and Linker. Config demo has doxy and synopsis styles.
98| #
99| # Revision 1.32 2001/02/11 05:39:33 stefan
100| # first try at a more powerful config framework for synopsis
101| #
102| # Revision 1.31 2001/02/06 17:37:20 chalky
103| # Reorder languagize to before unduplicator to prevent module conflicts
104| #
105| # Revision 1.30 2001/02/06 06:54:27 chalky
106| # Added comment processing to Linker..
107| #
108|
109| # THIS-IS-A-LINKER
110|
111| import sys, getopt, os, os.path, string, types
112| from Synopsis.Core import Util, Type, AST
113|
114| from Synopsis.Core.Util import import_object
115|
116| pyTypes = types
117| del types
118| strip = []
119| mapperList = []
120| verbose = 0
121| max_access = None
122|
123| def usage():
124| print \
125| """
126| -s <scope> Select only the named scope.
127| -m <mapper> Use a mapper plugin to map unresolved types new names
128| -M <mapper> Use a std mapper (part of the Linker module) to map unresolved types new names.
129| Currently the C++toIDL mapper is supported
130| -a <access level> Removes all declarations
131| access level than that given.
132| 1==public only, 2==protected or public
133| """
134| class Config:
135| """Central configuration repository for Linker."""
136| def __init__(self):
137| """Constructor - initialise objects to None."""
138| self.ast = None
139| self.strip = []
140| self.mapper_list = []
141| self.types = None # Filled in first thing in resolve()
142| self.max_access = None
143| self.map_declaration_names = None
144| self.map_declaration_type = 'Language'
145| self.operations = [
146| 'Unduplicator', 'Stripper', 'NameMapper',
147| 'Comments', 'EmptyNS', 'AccessRestrictor'
148| ] # Off by default: 'LanguageMapper',
149| self.verbose = 0
150| self.comment_processors = ['summary']
151|
152| def use_config(self, obj):
153| """Extracts useful attributes from 'obj' and stores them. The object
154| itself is also stored as config.obj"""
155| # obj.pages is a list of module names
156| self.obj = obj
157| options = ('verbose', 'strip', 'mappers', 'mapper_list', 'max_access',
158| 'operations', 'map_declaration_names', 'map_declaration_type',
159| 'comment_processors')
160| for option in options:
161| if hasattr(obj, option):
162| getattr(self, '_config_'+option)(getattr(obj, option))
163| elif self.verbose: print "Option",option,"not found in config."
164|
165| def _config_verbose(self, verbose):
166| "Configures from the given verbose boolean"
167| self.verbose = verbose
168|
169| def _config_strip(self, strip):
170| "Configures from the given list of strip"
171| if type(strip) != pyTypes.ListType:
172| raise TypeError, "Linker.strip must be a list of strings."
173| if self.verbose: print "Using strip:", strip
174| self.strip = strip
175|
176|
177| def _config_mapper_list(self, mapper_list):
178| "Configures from the given list of mapper_list"
179| if type(mapper_list) != pyTypes.ListType:
180| raise TypeError, "Linker.mapper_list must be a list of strings."
181| if self.verbose: print "Using mapper_list:", mapper_list
182| for mapper in mapper_list:
183| if type(mapper) is pyTypes.StringType:
184| self.mapper_list.append(mappers[mapper]())
185| else:
186| self.mapper_list.append(getattr(Util._import(mapper[0]), mapper[1])())
187|
188| # mappers is the old config name
189| _config_mappers = _config_mapper_list
190|
191| def _config_operations(self, operations):
192| "Configures from the given list of operations"
193| if type(operations) != pyTypes.ListType:
194| raise TypeError, "Linker.operations must be a list."
195| if self.verbose: print "Using operations:", operations
196| self.operations = operations
197|
198| def _config_max_access(self, access):
199| if self.verbose: print "Using max_access:",access
200| self.max_access = access
201|
202| def _config_map_declaration_names(self, names):
203| if not names: return
204| if self.verbose: print "Using map_declaration_names:", names
205| self.map_declaration_names = tuple(string.split(names[0], '::'))
206| self.map_declaration_type = names[1]
207|
208| def _config_map_declaration_type(self, typename):
209| if self.verbose: print "Using map_declaration_type:", typename
210| self.max_declaration_type = typename
211|
212| def _config_comment_processors(self, processors):
213| if self.verbose: print "Using comment_processors:", processors
214| self.comment_processors = processors
215|
216| # Instantiate a global config object in this module
217| config = Config()
218|
219| class Operation:
220| """The base class for Linker operations. The linker executes a number of
221| operations, depending on the config option 'operations'. Each operation
222| may use other config options"""
223| def execute(self):
224| """Executes this operation"""
225| pass
226|
227| class CXX2IDL:
228| """this function maps a C++ external reference to an IDL interface if the name either
229| starts with 'POA_' or ends in '_ptr'"""
230| def __init__(self): pass
231| def map(self, unknown):
232| global verbose
233| import __builtin__
234| name = unknown.name()
235| language = unknown.language()
236| if language != "C++": return
237| if name[0][0:4] == "POA_":
238| interface = __builtin__.map(None, name)
239| interface[0] = interface[0][4:]
240| unknown.resolve("IDL", name, tuple(interface))
241| if verbose: print "mapping", string.join(name, "::"), "to", string.join(interface, "::")
242| elif name[-1][-4:] == "_ptr":
243| interface = __builtin__.map(None, name)
244| interface[-1] = interface[-1][:-4]
245| unknown.resolve("IDL", name, tuple(interface))
246| if verbose: print "mapping", string.join(name, "::"), "to", string.join(interface, "::")
247|
248| mappers = {
249| 'C++toIDL' : CXX2IDL,
250| }
251|
252| def __parseArgs(args, config_obj):
253| global strip, mapperList, verbose, languagize, processor_args, max_access
254| global map_decl_names, map_decl_name_type
255| languagize = 0
256| processor_args = []
257| map_decl_names = None
258| map_decl_name_type = "scope"
259|
260| # Use config first
261| config.use_config(config_obj)
262|
263| # Now parse args
264| try:
265| opts,remainder = getopt.getopt(args, "s:m:M:vlp:a:d:")
266| except getopt.error, e:
267| sys.stderr.write("Error in arguments: " + str(e) + "\n")
268| sys.exit(1)
269|
270| for opt in opts:
271| o,a = opt
272|
273| if o == "-s": config.strip.append(a)
274| elif o == "-m":
275| config.mapper_list.append(Util._import(a))
276| elif o == "-M":
277| if mappers.has_key(a): config.mapper_list.append(mappers[a]())
278| else:
279| print "Error: Unknown mapper. Available mappers are:",string.join(mappers.keys(), ', ')
280| sys.exit(1)
281| elif o == "-v": config.verbose = 1
282| elif o == '-l': languagize = 1
283| elif o == '-a': max_access = int(a)
284| elif o == '-d':
285| map_decl_names, map_decl_name_type = string.split(a, '=')
286| map_decl_names = string.split(map_decl_names, '::')
287| elif o == '-p':
288| if not hasattr(config, 'comment_processors'):
289| config.comment_processors = []
290| config.comment_processors.append(a)
291|
292| class Mapper(Type.Visitor):
293| """allow user to supply a mapping functor that is applied to Unknown types.
294| This is useful for linking to externally defined types, such as when cross-
295| referencing modules written in different languages"""
296| def __init__(self, mappers):
297| self.__mappers = mappers
298| def visitUnknown(self, unknown):
299| for mapper in self.__mappers:
300| mapper.map(unknown)
301|
302|
303| def mapTypes(m):
304| if len(m):
305| mapper = Mapper(m)
306| for type in types.values():
307| type.accept(mapper)
308|
309| def resolve(args, ast, config_obj):
310| global types, mapperList
311| types = ast.types()
312| declarations = ast.declarations()
313|
314| config.types = ast.types()
315|
316| __parseArgs(args, config_obj)
317|
318| def_attr = 'linkerOperation'
319| base_path = 'Synopsis.Linker.'
320| for op_spec in config.operations:
321| oper_class = import_object(op_spec, def_attr, base_path)
322| oper = oper_class()
323| oper.execute(ast)
324|
325| # apply user supplied mapping of external types (Type.Unknown)
326| mapTypes(config.mapper_list)
327|