Modules | Files | Inheritance Tree | Inheritance Graph | Name Index | Config
File: Synopsis/Linker/Stripper.py
    1| # $Id: Stripper.py,v 1.4 2002/10/29 06:56:52 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: Stripper.py,v $
   23| # Revision 1.4  2002/10/29 06:56:52  chalky
   24| # Fixes to work on cygwin
   25| #
   26| # Revision 1.3  2002/10/28 16:30:05  chalky
   27| # Trying to fix some bugs in the unduplication/stripping stages. Needs more work
   28| #
   29| # Revision 1.2  2002/10/11 05:57:17  chalky
   30| # Support suspect comments
   31| #
   32| # Revision 1.1  2002/08/23 04:37:26  chalky
   33| # Huge refactoring of Linker to make it modular, and use a config system similar
   34| # to the HTML package
   35| #
   36| 
   37| import string
   38| 
   39| from Synopsis.Core import AST, Type, Util
   40| 
   41| from Linker import config, Operation
   42| 
   43| def filterName(name, prefixes):
   44|     if not prefixes: return 1
   45|     for prefix in prefixes:
   46|         if Util.ccolonName(name)[:len(prefix)] == prefix:
   47|             return 1
   48|     return 0
   49| 
   50| class Stripper(Operation, AST.Visitor):
   51|     """Strip common prefix from the declaration's name.
   52|     Keep a list of root nodes, such that children whos parent
   53|     scopes are not accepted but which themselfs are correct can
   54|     be maintained as new root nodes."""
   55|     def __init__(self):
   56|         self.__strip = config.strip
   57|         splitter = lambda x: tuple(string.split(x, "::"))
   58|         self.__scopes = map(splitter, self.__strip)
   59|         self.__root = []
   60|         self.__in = 0
   61| 
   62|     def execute(self, ast):
   63|         if not self.__strip: return
   64| 
   65|         # strip prefixes and remove non-matching declarations
   66|         self.stripDeclarations(ast.declarations())
   67| 
   68|         # Remove types not in strip
   69|         self.stripTypes(ast.types())
   70| 
   71|     def _stripName(self, name):
   72|         for scope in self.__scopes:
   73|             depth = len(scope)
   74|             if name[0:depth] == scope:
   75|                if len(name) == depth: return None
   76|                return name[depth:]
   77|         return None
   78|     def stripDeclarations(self, declarations):
   79|         for decl in declarations:
   80|             decl.accept(self)
   81|         declarations[:] = self.declarations()
   82|         
   83|     def stripTypes(self, types):
   84|         prefixes = self.__strip
   85|         # Remove the empty type (caused by C++ with extract_tails)
   86|         if types.has_key(()): del types[()]
   87|         if not prefixes: return
   88|         for name, type in types.items():
   89|         try:
   90|                del types[name]
   91|                name = self._stripName(name)
   92|                if name:
   93|                    type.set_name(name)
   94|                    types[name] = type
   95|            except:
   96|                print "ERROR Processing:",name,types[name]
   97|         raise
   98| 
   99|     def declarations(self): return self.__root
  100| 
  101|     def strip(self, declaration):
  102|         """test whether the declaration matches one of the prefixes, strip
  103|         it off, and return success. Success means that the declaration matches
  104|         the prefix set and thus should not be removed from the AST."""
  105|         passed = 0
  106|         if not self.__scopes: return 1
  107|         for scope in self.__scopes:
  108|             depth = len(scope)
  109|             name = declaration.name()
  110|             if name[0:depth] == scope:
  111|                 if len(name) == depth: break
  112|                 if config.verbose: print "symbol", string.join(name, "::"),
  113|                 declaration.set_name(name[depth:])
  114|                 if config.verbose: print "stripped to", string.join(name, "::")
  115|                 passed = 1
  116|             else: break
  117|         if config.verbose and not passed: print "symbol", string.join(declaration.name(), "::"), "removed"
  118|         return passed
  119| 
  120|     def visitScope(self, scope):
  121|         root = self.strip(scope) and not self.__in
  122|         if root:
  123|             self.__in = 1
  124|             self.__root.append(scope)
  125|         for declaration in scope.declarations():
  126|             declaration.accept(self)
  127|         if root: self.__in = 0
  128| 
  129|     def visitClass(self, clas):
  130|         self.visitScope(clas)
  131|         templ = clas.template()
  132|         if templ:
  133|             name = self._stripName(templ.name())
  134|             if name: templ.set_name(name)
  135| 
  136|     def visitDeclaration(self, decl):
  137|         if self.strip(decl) and not self.__in:
  138|             self.__root.append(decl)
  139| 
  140|     def visitEnumerator(self, enumerator):
  141|          self.strip(enumerator)
  142| 
  143|     def visitEnum(self, enum):
  144|         self.visitDeclaration(enum)
  145|         for e in enum.enumerators():
  146|             e.accept(self)
  147| 
  148|     def visitFunction(self, function):
  149|         self.visitDeclaration(function)
  150|         for parameter in function.parameters():
  151|             parameter.accept(self)
  152|         templ = function.template()
  153|         if templ:
  154|             name = self._stripName(templ.name())
  155|             if name: templ.set_name(name)
  156| 
  157|     def visitOperation(self, operation):
  158|         self.visitFunction(operation)
  159| 
  160|     def visitMetaModule(self, module):
  161|         self.visitScope(module)
  162|         for decl in module.module_declarations():
  163|             name = self._stripName(decl.name())
  164|             if name: decl.set_name(name)
  165| 
  166| linkerOperation = Stripper