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