File: Synopsis/Processors/Linker.py 1
2
3
4
5
6
7
8
9from Synopsis.Processor import Composite, Parameter
10from Synopsis import ASG
11from Synopsis.QualifiedName import *
12
13class Linker(Composite, ASG.Visitor):
14 """Visitor that removes duplicate declarations"""
15
16 remove_empty_modules = Parameter(True, 'Remove empty modules.')
17 sort_modules = Parameter(True, 'Sort module content alphabetically.')
18 sxr_prefix = Parameter('', 'Compile sxr data, if defined.')
19
20 def process(self, ir, **kwds):
21
22 self.set_parameters(kwds)
23 self.ir = self.merge_input(ir)
24
25 root = ASG.MetaModule("", QualifiedName())
26 self.__scopes = [root]
27 global_dict = {}
28 self.__dict_map = {id(root) : global_dict}
29 self.__dicts = [global_dict]
30
31 self.types = self.ir.asg.types
32
33 try:
34 for d in self.ir.asg.declarations:
35 d.accept(self)
36 self.ir.asg.declarations = root.declarations
37 except TypeError, e:
38 import traceback
39 traceback.print_exc()
40 print 'linker error :', e
41
42 for file in self.ir.files.values():
43 self.visit_source_file(file)
44
45 if self.remove_empty_modules:
46 import ModuleFilter
47 self.ir = ModuleFilter.ModuleFilter().process(self.ir)
48
49 if self.sort_modules:
50 import ModuleSorter
51 self.ir = ModuleSorter.ModuleSorter().process(self.ir)
52
53 if self.sxr_prefix:
54 import SXRCompiler
55 self.ir = SXRCompiler.SXRCompiler(prefix=self.sxr_prefix).process(self.ir)
56
57
58 output = self.output
59 self.ir = Composite.process(self, self.ir, input=[], output='')
60 self.output = output
61
62 return self.output_and_return_ir()
63
64 def lookup(self, name):
65 """look whether the current scope already contains
66 a declaration with the given name"""
67
68 return self.__dicts[-1].get(name)
69
70 def append(self, declaration):
71 """append declaration to the current scope"""
72
73 self.__scopes[-1].declarations.append(declaration)
74 self.__dicts[-1][declaration.name] = declaration
75
76 def push(self, scope):
77 """push new scope on the stack"""
78
79 self.__scopes.append(scope)
80 dict = self.__dict_map.setdefault(id(scope), {})
81 self.__dicts.append(dict)
82
83 def pop(self):
84 """restore the previous scope"""
85
86 del self.__scopes[-1]
87 del self.__dicts[-1]
88
89 def top(self):
90
91 return self.__scopes[-1]
92
93 def top_dict(self):
94
95 return self.__dicts[-1]
96
97 def link_type(self, type):
98 "Returns the same or new proxy type"
99
100 self.__type = type
101 if type is not None: type.accept(self)
102 return self.__type
103
104
105
106 def visit_builtin_type_id(self, type):
107
108 if self.types.has_key(type.name):
109 self.__type = self.types[type.name]
110
111 def visit_unknown_type_id(self, type):
112
113 if self.types.has_key(type.name):
114 self.__type = self.types[type.name]
115
116 def visit_declared_type_id(self, type):
117
118 if self.types.has_key(type.name):
119 self.__type = self.types[type.name]
120 else:
121 print "Couldn't find declared type-id:",type.name
122
123 def visit_template_id(self, type):
124
125
126 if not self.types.has_key(type.name):
127 return
128 declared = self.types[type.name]
129 if isinstance(declared, ASG.UnknownTypeId):
130
131 return
132 elif not isinstance(declared, ASG.DeclaredTypeId):
133 print "Warning: template declaration was not a declaration:",type.name,declared.__class__.__name__
134 return
135 decl = declared.declaration
136 if not hasattr(decl, 'template'):
137
138 return
139 if decl.template:
140 self.__type = decl.template
141 else:
142 print "Warning: template type disappeared:",type.name
143
144 def visit_modifier_type_id(self, type):
145
146 alias = self.link_type(type.alias)
147 if alias is not type.alias:
148 type.alias = alias
149 self.__type = type
150
151 def visit_array_type_id(self, type):
152
153 alias = self.link_type(type.alias)
154 if alias is not type.alias:
155 type.alias = alias
156 self.__type = type
157
158 def visit_parametrized_type_id(self, type):
159
160 templ = self.link_type(type.template)
161 if templ is not type.template:
162 type.template = templ
163 type.parameters = [self.link_type(p) for p in type.parameters]
164 self.__type = type
165
166 def visit_function_type_id(self, type):
167
168 ret = self.link_type(type.return_type)
169 if ret is not type.return_type:
170 type.return_type = ret
171 type.parameters = [self.link_type(p) for p in type.parameters]
172 self.__type = type
173
174
175
176 def visit_source_file(self, file):
177 """Resolves any duplicates in the list of declarations from this
178 file"""
179
180 types = self.types
181
182
183 declarations = file.declarations
184 file.declarations = []
185
186 for d in declarations:
187
188
189 if types.has_key(d.name):
190 declared = types[d.name]
191 if isinstance(declared, ASG.DeclaredTypeId):
192 d = declared.declaration
193
194 if d not in file.declarations:
195 file.declarations.append(d)
196
197
198
199 def visit_module(self, module):
200
201
202 metamodule = self.lookup(module.name)
203 if metamodule is None:
204 metamodule = ASG.MetaModule(module.type,module.name)
205 self.append(metamodule)
206 elif not isinstance(metamodule, ASG.MetaModule):
207 raise TypeError, 'symbol type mismatch: Synopsis.ASG.Module and %s both match "%s"'%(metamodule.__class__, str(module.name))
208
209 metamodule.module_declarations.append(module)
210
211
212 self.merge_comments(metamodule, module)
213
214 self.push(metamodule)
215 for d in module.declarations:
216 d.accept(self)
217 module.declarations = []
218 self.pop()
219
220
221 def visit_group(self, group):
222
223 previous = self.lookup(group.name)
224 if not previous:
225 self.append(group)
226 elif isinstance(previous, ASG.Group):
227 previous.declarations.append(group.declarations)
228 self.merge_comments(previous, group)
229 group = previous
230 else:
231 raise TypeError, 'symbol type mismatch: Synopsis.ASG.Group and %s both match "%s"'%(previous.__class__, str(previous.name))
232
233 self.push(group)
234 for d in group.declarations:
235 d.accept(self)
236 self.pop()
237
238
239 def merge_comments(self, metamodule, module):
240 """Append the module comments into the metamodule."""
241
242 if module.annotations.has_key('comments'):
243 new_comments = module.annotations['comments']
244 metamodule.annotations.setdefault('comments', [])
245 comments = metamodule.annotations['comments']
246 if comments[-len(new_comments):] != new_comments:
247 comments.extend(new_comments)
248
249
250 def visit_meta_module(self, module):
251
252
253 metamodule = self.lookup(module.name)
254 if metamodule is None:
255 metamodule = ASG.MetaModule(module.type,module.name)
256 self.append(metamodule)
257 elif not isinstance(metamodule, ASG.MetaModule):
258 raise TypeError, 'symbol type mismatch: Synopsis.ASG.MetaModule and %s both match "%s"'%(metamodule.__class__, '::'.join(module.name))
259
260 metamodule.module_declarations.extend(module.module_declarations)
261 self.merge_comments(metamodule, module)
262 self.push(metamodule)
263 for d in module.declarations:
264 d.accept(self)
265 module.declarations = []
266 self.pop()
267
268
269 def add_declaration(self, decl):
270 """Adds a declaration to the current (top) scope.
271 If there is already a Forward declaration, then this replaces it
272 unless this is also a Forward.
273 """
274
275 name = decl.name
276 dict = self.__dicts[-1]
277 decls = self.top().declarations
278 if dict.has_key(name):
279 prev = dict[name]
280 if not isinstance(prev, ASG.Forward):
281 return
282 if not isinstance(decl, ASG.Forward):
283 decls.remove(prev)
284 decls.append(decl)
285 dict[name] = decl
286 return
287 decls.append(decl)
288 dict[name] = decl
289
290 def visit_builtin(self, builtin):
291 """preserve builtins unconditionally"""
292
293 self.top().declarations.append(builtin)
294
295 def visit_named_type(self, decl):
296
297 name = decl.name
298 if self.lookup(decl.name): return
299 self.add_declaration(decl)
300
301 visit_declaration = add_declaration
302 visit_forward = add_declaration
303 visit_enum = add_declaration
304
305 def visit_function(self, func):
306 if not isinstance(self.top(), (ASG.Class, ASG.ClassTemplate)):
307 for d in self.top().declarations:
308 if not isinstance(d, ASG.Function): continue
309 if func.name == d.name:
310 return
311 ret = self.link_type(func.return_type)
312 if ret is not func.return_type:
313 func.return_type = ret
314 for param in func.parameters:
315 self.visit_parameter(param)
316 self.top().declarations.append(func)
317
318
319 visit_operation = visit_function
320
321 def visit_variable(self, var):
322
323
324 vt = self.link_type(var.vtype)
325 if vt is not var.vtype:
326 var.vtype = vt
327 self.add_declaration(var)
328
329 def visit_typedef(self, tdef):
330
331 alias = self.link_type(tdef.alias)
332 if alias is not tdef.alias:
333 tdef.alias = alias
334 self.add_declaration(tdef)
335
336 def visit_class(self, class_):
337
338 prev = self.lookup(class_.name)
339 if prev:
340 if isinstance(prev, ASG.Forward):
341
342 self.top().declarations.remove(prev)
343 del self.top_dict()[class_.name]
344 elif isinstance(prev, (ASG.Class, ASG.ClassTemplate)):
345
346
347
348 self.push(prev)
349 for d in class_.declarations:
350 if isinstance(d, (ASG.Class, ASG.ClassTemplate)):
351 d.accept(self)
352 self.pop()
353 return
354 else:
355 raise TypeError, 'symbol type mismatch: Synopsis.ASG.Class and %s both match "%s"'%(prev.__class__, '::'.join(class_.name))
356 self.add_declaration(class_)
357 for p in class_.parents:
358 p.accept(self)
359 declarations = class_.declarations
360 class_.declarations = []
361 self.push(class_)
362 for d in declarations:
363 d.accept(self)
364 self.pop()
365
366 def visit_inheritance(self, parent):
367
368 type = parent.parent
369 if isinstance(type, (ASG.DeclaredTypeId, ASG.UnknownTypeId)):
370 ltype = self.link_type(type)
371 if ltype is not type:
372 parent.parent = ltype
373 elif isinstance(type, ASG.ParametrizedTypeId):
374 ltype = self.link_type(type.template)
375 if ltype is not type.template:
376
377 if not isinstance(ltype, ASG.DeclaredTypeId):
378
379 return
380 decl = ltype.declaration
381 if isinstance(decl, ASG.ClassTemplate):
382 type.template = decl.template
383 else:
384
385 pass
386
387 def visit_parameter(self, param):
388
389 type = self.link_type(param.type)
390 if type is not param.type:
391 param.type = type
392
393 def visit_const(self, const):
394
395 ct = self.link_type(const.ctype)
396 if ct is not const.ctype:
397 const.ctype = ct
398 self.add_declaration(const)
399
Generated on Wed Mar 19 02:48:18 2008 by
synopsis (version 0.10)