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()
This commit is contained in:
Jeremy Hylton 2001-08-27 22:56:16 +00:00
parent e7d8322630
commit c59e220000
6 changed files with 100 additions and 40 deletions

View File

@ -39,3 +39,26 @@ def push(self, elt):
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)

View File

@ -117,9 +117,6 @@ def is_constant_false(node):
return 1
return 0
def mangle(name):
return name
class CodeGenerator:
"""Defines basic code generator for Python bytecode
@ -136,6 +133,7 @@ class CodeGenerator:
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 @@ def getCode(self):
"""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 @@ def delName(self, name):
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 @@ def visitLambda(self, node):
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 _resolveDots(self, name):
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 visitAssName(self, node):
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 @@ def visitAugGetattr(self, node, mode):
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 @@ def visitModule(self, node):
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 @@ def _nameOp(self, prefix, name):
(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 @@ class AbstractFunctionCode:
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 @@ class NestedFunctionCodeGenerator(AbstractFunctionCode,
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 @@ def __init__(self, func, filename, scopes, isLambda):
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 @@ def __init__(self, klass, filename, scopes):
self.setDocstring(klass.doc)
def _nameOp(self, prefix, name):
name = self.mangle(name)
# Class namespaces are always unoptimized
self.emit(prefix + '_NAME', name)

View File

@ -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 __repr__(self):
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

View File

@ -39,3 +39,26 @@ def push(self, elt):
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)

View File

@ -117,9 +117,6 @@ def is_constant_false(node):
return 1
return 0
def mangle(name):
return name
class CodeGenerator:
"""Defines basic code generator for Python bytecode
@ -136,6 +133,7 @@ class CodeGenerator:
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 @@ def getCode(self):
"""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 @@ def delName(self, name):
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 @@ def visitLambda(self, node):
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 _resolveDots(self, name):
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 visitAssName(self, node):
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 @@ def visitAugGetattr(self, node, mode):
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 @@ def visitModule(self, node):
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 @@ def _nameOp(self, prefix, name):
(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 @@ class AbstractFunctionCode:
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 @@ class NestedFunctionCodeGenerator(AbstractFunctionCode,
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 @@ def __init__(self, func, filename, scopes, isLambda):
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 @@ def __init__(self, klass, filename, scopes):
self.setDocstring(klass.doc)
def _nameOp(self, prefix, name):
name = self.mangle(name)
# Class namespaces are always unoptimized
self.emit(prefix + '_NAME', name)

View File

@ -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 __repr__(self):
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