Synopsis - Synopsis/Processors/Linker.py

File: Synopsis/Processors/Linker.py

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

Generated on Thu Apr 16 16:27:13 2009 by
synopsis (version devel)