diff options
| author | Jeremy Hylton <jeremy@alum.mit.edu> | 2001-04-09 13:57:32 +0000 | 
|---|---|---|
| committer | Jeremy Hylton <jeremy@alum.mit.edu> | 2001-04-09 13:57:32 +0000 | 
| commit | f870c952f96c72cc23fa75a1ce48418c71fbf76e (patch) | |
| tree | 203aebb3e93b39be39eeb71107f7ddcff145520b /Lib/compiler/symbols.py | |
| parent | 8b966dcf0328c20e58a728f8ade279543c40dbc4 (diff) | |
| download | cpython-git-f870c952f96c72cc23fa75a1ce48418c71fbf76e.tar.gz | |
Add two arguments to Scope constructor, module scope and class name
Add mangling support
Add get_children() and add_child() methods to Scope
Skip nodes when If test is a false constant
Add test code that checks results against symtable module
Diffstat (limited to 'Lib/compiler/symbols.py')
| -rw-r--r-- | Lib/compiler/symbols.py | 116 | 
1 files changed, 92 insertions, 24 deletions
| diff --git a/Lib/compiler/symbols.py b/Lib/compiler/symbols.py index 1f107fe5df..872f174a05 100644 --- a/Lib/compiler/symbols.py +++ b/Lib/compiler/symbols.py @@ -1,37 +1,59 @@  """Module symbol-table generator"""  from compiler import ast +import types -module_scope = None +MANGLE_LEN = 256  class Scope:      # XXX how much information do I need about each name? -    def __init__(self, name): +    def __init__(self, name, module, klass=None):          self.name = name +        self.module = module          self.defs = {}          self.uses = {}          self.globals = {}          self.params = {} +        self.children = [] +        self.klass = None +        if klass is not None: +            for i in range(len(klass)): +                if klass[i] != '_': +                    self.klass = klass[i:] +                    break      def __repr__(self):          return "<%s: %s>" % (self.__class__.__name__, self.name) +    def mangle(self, name): +        if self.klass is None: +            return name +        if not name.startswith('__'): +            return name +        if len(name) + 2 >= MANGLE_LEN: +            return name +        if name.endswith('__'): +            return name +        return "_%s%s" % (self.klass, name) +      def add_def(self, name): -        self.defs[name] = 1 +        self.defs[self.mangle(name)] = 1      def add_use(self, name): -        self.uses[name] = 1 +        self.uses[self.mangle(name)] = 1      def add_global(self, name): +        name = self.mangle(name)          if self.uses.has_key(name) or self.defs.has_key(name):              pass # XXX warn about global following def/use          if self.params.has_key(name):              raise SyntaxError, "%s in %s is global and parameter" % \                    (name, self.name)          self.globals[name] = 1 -        module_scope.add_def(name) +        self.module.add_def(name)      def add_param(self, name): +        name = self.mangle(name)          self.defs[name] = 1          self.params[name] = 1 @@ -41,46 +63,53 @@ class Scope:          d.update(self.uses)          return d.keys() +    def add_child(self, child): +        self.children.append(child) + +    def get_children(self): +        return self.children +  class ModuleScope(Scope):      __super_init = Scope.__init__      def __init__(self): -        self.__super_init("global") -        global module_scope -        assert module_scope is None  -        module_scope = self +        self.__super_init("global", self)  class LambdaScope(Scope):      __super_init = Scope.__init__      __counter = 1 -    def __init__(self): +    def __init__(self, module, klass=None):          i = self.__counter          self.__counter += 1 -        self.__super_init("lambda.%d" % i) +        self.__super_init("lambda.%d" % i, module, klass)  class FunctionScope(Scope):      pass  class ClassScope(Scope): -    pass +    __super_init = Scope.__init__ + +    def __init__(self, name, module): +        self.__super_init(name, module, name)  class SymbolVisitor:      def __init__(self):          self.scopes = {} - +        self.klass = None +              # node that define new scopes      def visitModule(self, node): -        scope = self.scopes[node] = ModuleScope() +        scope = self.module = self.scopes[node] = ModuleScope()          self.visit(node.node, scope)      def visitFunction(self, node, parent):          parent.add_def(node.name)          for n in node.defaults:              self.visit(n, parent) -        scope = FunctionScope(node.name) +        scope = FunctionScope(node.name, self.module, self.klass)          self.scopes[node] = scope          for name in node.argnames:              scope.add_param(name) @@ -89,7 +118,7 @@ class SymbolVisitor:      def visitLambda(self, node, parent):          for n in node.defaults:              self.visit(n, parent) -        scope = LambdaScope() +        scope = LambdaScope(self.module, self.klass)          self.scopes[node] = scope          for name in node.argnames:              scope.add_param(name) @@ -99,9 +128,12 @@ class SymbolVisitor:          parent.add_def(node.name)          for n in node.bases:              self.visit(n, parent) -        scope = ClassScope(node.name) +        scope = ClassScope(node.name, self.module)          self.scopes[node] = scope +        prev = self.klass +        self.klass = node.name          self.visit(node.code, scope) +        self.klass = prev      # name can be a def or a use @@ -155,6 +187,21 @@ class SymbolVisitor:          for name in node.names:              scope.add_global(name) +    # prune if statements if tests are false + +    _const_types = types.StringType, types.IntType, types.FloatType + +    def visitIf(self, node, scope): +        for test, body in node.tests: +            if isinstance(test, ast.Const): +                if type(test.value) in self._const_types: +                    if not test.value: +                        continue +            self.visit(test, scope) +            self.visit(body, scope) +        if node.else_: +            self.visit(node.else_, scope) +  def sort(l):      l = l[:]      l.sort() @@ -168,26 +215,47 @@ if __name__ == "__main__":      from compiler import parseFile, walk      import symtable +    def get_names(syms): +        return [s for s in [s.get_name() for s in syms.get_symbols()] +                if not s.startswith('_[')]         +          for file in sys.argv[1:]:          print file          f = open(file)          buf = f.read()          f.close()          syms = symtable.symtable(buf, file, "exec") -        mod_names = [s for s in [s.get_name() -                                 for s in syms.get_symbols()] -                     if not s.startswith('_[')] +        mod_names = get_names(syms)          tree = parseFile(file)          s = SymbolVisitor()          walk(tree, s) -        for node, scope in s.scopes.items(): -            print node.__class__.__name__, id(node) -            print scope -            print scope.get_names() +        # compare module-level symbols          names2 = s.scopes[tree].get_names() +          if not list_eq(mod_names, names2): +            print              print "oops", file              print sort(mod_names)              print sort(names2)              sys.exit(-1) + +        d = {} +        d.update(s.scopes) +        del d[tree] +        scopes = d.values() +        del d + +        for s in syms.get_symbols(): +            if s.is_namespace(): +                l = [sc for sc in scopes +                     if sc.name == s.get_name()] +                if len(l) > 1: +                    print "skipping", s.get_name() +                else: +                    if not list_eq(get_names(s.get_namespace()), +                                   l[0].get_names()): +                        print s.get_name() +                        print get_names(s.get_namespace()) +                        print l[0].get_names() +                        sys.exit(-1) | 
