Handle private names

(Hard to believe these were never handled before)

Add misc.mangle() that mangles based on the rules in compile.c.
XXX Need to test the corner cases

Update CodeGenerator with a class_name attribute bound to None.  If a
particular instance is created within a class scope, the instance's
class_name is bound to that class's name.

Add mangle() method to CodeGenerator that mangles if the class_name
has a class_name in it.

Modify the FunctionCodeGenerator family to handle an extra argument--
the class_name.

Wrap all name ops and attrnames in calls to self.mangle()
diff --git a/Lib/compiler/misc.py b/Lib/compiler/misc.py
index 29ff866..b834a2e 100644
--- a/Lib/compiler/misc.py
+++ b/Lib/compiler/misc.py
@@ -39,3 +39,26 @@
         self.stack.append(elt)
     def top(self):
         return self.stack[-1]
+
+MANGLE_LEN = 256 # magic constant from compile.c
+
+def mangle(name, klass):
+    if not name.startswith('__'):
+        return name
+    if len(name) + 2 >= MANGLE_LEN:
+        return name
+    if name.endswith('__'):
+        return name
+    try:
+        i = 0
+        while klass[i] == '_':
+            i = i + 1
+    except IndexError:
+        return name
+    klass = klass[i:]
+
+    tlen = len(klass) + len(name)
+    if tlen > MANGLE_LEN:
+        klass = klass[:MANGLE_LEN-tlen]
+
+    return "_%s%s" % (klass, name)
diff --git a/Lib/compiler/pycodegen.py b/Lib/compiler/pycodegen.py
index 37b51bf..ced0f07 100644
--- a/Lib/compiler/pycodegen.py
+++ b/Lib/compiler/pycodegen.py
@@ -117,9 +117,6 @@
             return 1
     return 0
 
-def mangle(name):
-    return name
-
 class CodeGenerator:
     """Defines basic code generator for Python bytecode
 
@@ -136,6 +133,7 @@
 
     optimized = 0 # is namespace access optimized?
     __initialized = None
+    class_name = None # provide default for instance variable
 
     def __init__(self, filename):
         if self.__initialized is None:
@@ -175,6 +173,12 @@
         """Return a code object"""
         return self.graph.getCode()
 
+    def mangle(self, name):
+        if self.class_name is not None:
+            return misc.mangle(name, self.class_name)
+        else:
+            return name
+
     # Next five methods handle name access
 
     def isLocalName(self, name):
@@ -190,6 +194,7 @@
         self._nameOp('DELETE', name)
 
     def _nameOp(self, prefix, name):
+        name = self.mangle(name)
         if not self.optimized:
             self.emit(prefix + '_NAME', name)
             return
@@ -258,7 +263,8 @@
         self._visitFuncOrLambda(node, isLambda=1)
 
     def _visitFuncOrLambda(self, node, isLambda=0):
-        gen = self.FunctionGen(node, self.filename, self.scopes, isLambda)
+        gen = self.FunctionGen(node, self.filename, self.scopes, isLambda,
+                               self.class_name)
         walk(node.code, gen)
         gen.finish()
         self.set_lineno(node)
@@ -645,7 +651,7 @@
 
     def visitGetattr(self, node):
         self.visit(node.expr)
-        self.emit('LOAD_ATTR', node.attrname)
+        self.emit('LOAD_ATTR', self.mangle(node.attrname))
 
     # next five implement assignments
 
@@ -671,9 +677,9 @@
     def visitAssAttr(self, node):
         self.visit(node.expr)
         if node.flags == 'OP_ASSIGN':
-            self.emit('STORE_ATTR', node.attrname)
+            self.emit('STORE_ATTR', self.mangle(node.attrname))
         elif node.flags == 'OP_DELETE':
-            self.emit('DELETE_ATTR', node.attrname)
+            self.emit('DELETE_ATTR', self.mangle(node.attrname))
         else:
             print "warning: unexpected flags:", node.flags
             print node
@@ -728,10 +734,10 @@
         if mode == "load":
             self.visit(node.expr)
             self.emit('DUP_TOP')
-            self.emit('LOAD_ATTR', node.attrname)
+            self.emit('LOAD_ATTR', self.mangle(node.attrname))
         elif mode == "store":
             self.emit('ROT_TWO')
-            self.emit('STORE_ATTR', node.attrname)
+            self.emit('STORE_ATTR', self.mangle(node.attrname))
 
     def visitAugSlice(self, node, mode):
         if mode == "load":
@@ -987,6 +993,7 @@
         self.__super_visitModule(node)
 
     def _nameOp(self, prefix, name):
+        name = self.mangle(name)
         scope = self.scope.check_name(name)
         if scope == SC_LOCAL:
             if not self.optimized:
@@ -1002,7 +1009,8 @@
                   (name, scope)
 
     def _visitFuncOrLambda(self, node, isLambda=0):
-        gen = self.FunctionGen(node, self.filename, self.scopes, isLambda)
+        gen = self.FunctionGen(node, self.filename, self.scopes, isLambda,
+                               self.class_name)
         walk(node.code, gen)
         gen.finish()
         self.set_lineno(node)
@@ -1079,7 +1087,8 @@
     optimized = 1
     lambdaCount = 0
 
-    def __init__(self, func, filename, scopes, isLambda):
+    def __init__(self, func, filename, scopes, isLambda, class_name):
+        self.class_name = class_name
         if isLambda:
             klass = FunctionCodeGenerator
             name = "<lambda.%d>" % klass.lambdaCount
@@ -1142,10 +1151,10 @@
     super_init = NestedScopeCodeGenerator.__init__ # call be other init
     __super_init = AbstractFunctionCode.__init__
 
-    def __init__(self, func, filename, scopes, isLambda):
+    def __init__(self, func, filename, scopes, isLambda, class_name):
         self.scopes = scopes
         self.scope = scopes[func]
-        self.__super_init(func, filename, scopes, isLambda)
+        self.__super_init(func, filename, scopes, isLambda, class_name)
         self.graph.setFreeVars(self.scope.get_free_vars())
         self.graph.setCellVars(self.scope.get_cell_vars())
 ##        self.graph.setFlag(CO_NESTED)
@@ -1153,6 +1162,7 @@
 class AbstractClassCode:
 
     def __init__(self, klass, filename, scopes):
+        self.class_name = klass.name
         self.graph = pyassem.PyFlowGraph(klass.name, filename,
                                            optimized=0)
         self.super_init(filename)
@@ -1163,6 +1173,7 @@
             self.setDocstring(klass.doc)
 
     def _nameOp(self, prefix, name):
+        name = self.mangle(name)
         # Class namespaces are always unoptimized
         self.emit(prefix + '_NAME', name)
 
diff --git a/Lib/compiler/symbols.py b/Lib/compiler/symbols.py
index 0ef0d12..40fd127 100644
--- a/Lib/compiler/symbols.py
+++ b/Lib/compiler/symbols.py
@@ -2,8 +2,10 @@
 
 from compiler import ast
 from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL, SC_UNKNOWN
+from compiler.misc import mangle
 import types
 
+
 import sys
 
 MANGLE_LEN = 256
@@ -36,13 +38,7 @@
     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)
+        return mangle(name, self.klass)
 
     def add_def(self, name):
         self.defs[self.mangle(name)] = 1
diff --git a/Tools/compiler/compiler/misc.py b/Tools/compiler/compiler/misc.py
index 29ff866..b834a2e 100644
--- a/Tools/compiler/compiler/misc.py
+++ b/Tools/compiler/compiler/misc.py
@@ -39,3 +39,26 @@
         self.stack.append(elt)
     def top(self):
         return self.stack[-1]
+
+MANGLE_LEN = 256 # magic constant from compile.c
+
+def mangle(name, klass):
+    if not name.startswith('__'):
+        return name
+    if len(name) + 2 >= MANGLE_LEN:
+        return name
+    if name.endswith('__'):
+        return name
+    try:
+        i = 0
+        while klass[i] == '_':
+            i = i + 1
+    except IndexError:
+        return name
+    klass = klass[i:]
+
+    tlen = len(klass) + len(name)
+    if tlen > MANGLE_LEN:
+        klass = klass[:MANGLE_LEN-tlen]
+
+    return "_%s%s" % (klass, name)
diff --git a/Tools/compiler/compiler/pycodegen.py b/Tools/compiler/compiler/pycodegen.py
index 37b51bf..ced0f07 100644
--- a/Tools/compiler/compiler/pycodegen.py
+++ b/Tools/compiler/compiler/pycodegen.py
@@ -117,9 +117,6 @@
             return 1
     return 0
 
-def mangle(name):
-    return name
-
 class CodeGenerator:
     """Defines basic code generator for Python bytecode
 
@@ -136,6 +133,7 @@
 
     optimized = 0 # is namespace access optimized?
     __initialized = None
+    class_name = None # provide default for instance variable
 
     def __init__(self, filename):
         if self.__initialized is None:
@@ -175,6 +173,12 @@
         """Return a code object"""
         return self.graph.getCode()
 
+    def mangle(self, name):
+        if self.class_name is not None:
+            return misc.mangle(name, self.class_name)
+        else:
+            return name
+
     # Next five methods handle name access
 
     def isLocalName(self, name):
@@ -190,6 +194,7 @@
         self._nameOp('DELETE', name)
 
     def _nameOp(self, prefix, name):
+        name = self.mangle(name)
         if not self.optimized:
             self.emit(prefix + '_NAME', name)
             return
@@ -258,7 +263,8 @@
         self._visitFuncOrLambda(node, isLambda=1)
 
     def _visitFuncOrLambda(self, node, isLambda=0):
-        gen = self.FunctionGen(node, self.filename, self.scopes, isLambda)
+        gen = self.FunctionGen(node, self.filename, self.scopes, isLambda,
+                               self.class_name)
         walk(node.code, gen)
         gen.finish()
         self.set_lineno(node)
@@ -645,7 +651,7 @@
 
     def visitGetattr(self, node):
         self.visit(node.expr)
-        self.emit('LOAD_ATTR', node.attrname)
+        self.emit('LOAD_ATTR', self.mangle(node.attrname))
 
     # next five implement assignments
 
@@ -671,9 +677,9 @@
     def visitAssAttr(self, node):
         self.visit(node.expr)
         if node.flags == 'OP_ASSIGN':
-            self.emit('STORE_ATTR', node.attrname)
+            self.emit('STORE_ATTR', self.mangle(node.attrname))
         elif node.flags == 'OP_DELETE':
-            self.emit('DELETE_ATTR', node.attrname)
+            self.emit('DELETE_ATTR', self.mangle(node.attrname))
         else:
             print "warning: unexpected flags:", node.flags
             print node
@@ -728,10 +734,10 @@
         if mode == "load":
             self.visit(node.expr)
             self.emit('DUP_TOP')
-            self.emit('LOAD_ATTR', node.attrname)
+            self.emit('LOAD_ATTR', self.mangle(node.attrname))
         elif mode == "store":
             self.emit('ROT_TWO')
-            self.emit('STORE_ATTR', node.attrname)
+            self.emit('STORE_ATTR', self.mangle(node.attrname))
 
     def visitAugSlice(self, node, mode):
         if mode == "load":
@@ -987,6 +993,7 @@
         self.__super_visitModule(node)
 
     def _nameOp(self, prefix, name):
+        name = self.mangle(name)
         scope = self.scope.check_name(name)
         if scope == SC_LOCAL:
             if not self.optimized:
@@ -1002,7 +1009,8 @@
                   (name, scope)
 
     def _visitFuncOrLambda(self, node, isLambda=0):
-        gen = self.FunctionGen(node, self.filename, self.scopes, isLambda)
+        gen = self.FunctionGen(node, self.filename, self.scopes, isLambda,
+                               self.class_name)
         walk(node.code, gen)
         gen.finish()
         self.set_lineno(node)
@@ -1079,7 +1087,8 @@
     optimized = 1
     lambdaCount = 0
 
-    def __init__(self, func, filename, scopes, isLambda):
+    def __init__(self, func, filename, scopes, isLambda, class_name):
+        self.class_name = class_name
         if isLambda:
             klass = FunctionCodeGenerator
             name = "<lambda.%d>" % klass.lambdaCount
@@ -1142,10 +1151,10 @@
     super_init = NestedScopeCodeGenerator.__init__ # call be other init
     __super_init = AbstractFunctionCode.__init__
 
-    def __init__(self, func, filename, scopes, isLambda):
+    def __init__(self, func, filename, scopes, isLambda, class_name):
         self.scopes = scopes
         self.scope = scopes[func]
-        self.__super_init(func, filename, scopes, isLambda)
+        self.__super_init(func, filename, scopes, isLambda, class_name)
         self.graph.setFreeVars(self.scope.get_free_vars())
         self.graph.setCellVars(self.scope.get_cell_vars())
 ##        self.graph.setFlag(CO_NESTED)
@@ -1153,6 +1162,7 @@
 class AbstractClassCode:
 
     def __init__(self, klass, filename, scopes):
+        self.class_name = klass.name
         self.graph = pyassem.PyFlowGraph(klass.name, filename,
                                            optimized=0)
         self.super_init(filename)
@@ -1163,6 +1173,7 @@
             self.setDocstring(klass.doc)
 
     def _nameOp(self, prefix, name):
+        name = self.mangle(name)
         # Class namespaces are always unoptimized
         self.emit(prefix + '_NAME', name)
 
diff --git a/Tools/compiler/compiler/symbols.py b/Tools/compiler/compiler/symbols.py
index 0ef0d12..40fd127 100644
--- a/Tools/compiler/compiler/symbols.py
+++ b/Tools/compiler/compiler/symbols.py
@@ -2,8 +2,10 @@
 
 from compiler import ast
 from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL, SC_UNKNOWN
+from compiler.misc import mangle
 import types
 
+
 import sys
 
 MANGLE_LEN = 256
@@ -36,13 +38,7 @@
     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)
+        return mangle(name, self.klass)
 
     def add_def(self, name):
         self.defs[self.mangle(name)] = 1