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
diff --git a/Lib/compiler/symbols.py b/Lib/compiler/symbols.py
index 1f107fe..872f174 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 @@
         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 @@
     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 @@
         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 @@
         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 @@
     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)
diff --git a/Tools/compiler/compiler/symbols.py b/Tools/compiler/compiler/symbols.py
index 1f107fe..872f174 100644
--- a/Tools/compiler/compiler/symbols.py
+++ b/Tools/compiler/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 @@
         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 @@
     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 @@
         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 @@
         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 @@
     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)