Commit c59e2200 authored by Jeremy Hylton's avatar Jeremy Hylton

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()
parent e7d83226
...@@ -39,3 +39,26 @@ class Stack: ...@@ -39,3 +39,26 @@ class Stack:
self.stack.append(elt) self.stack.append(elt)
def top(self): def top(self):
return self.stack[-1] 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)
...@@ -117,9 +117,6 @@ def is_constant_false(node): ...@@ -117,9 +117,6 @@ def is_constant_false(node):
return 1 return 1
return 0 return 0
def mangle(name):
return name
class CodeGenerator: class CodeGenerator:
"""Defines basic code generator for Python bytecode """Defines basic code generator for Python bytecode
...@@ -136,6 +133,7 @@ class CodeGenerator: ...@@ -136,6 +133,7 @@ class CodeGenerator:
optimized = 0 # is namespace access optimized? optimized = 0 # is namespace access optimized?
__initialized = None __initialized = None
class_name = None # provide default for instance variable
def __init__(self, filename): def __init__(self, filename):
if self.__initialized is None: if self.__initialized is None:
...@@ -175,6 +173,12 @@ class CodeGenerator: ...@@ -175,6 +173,12 @@ class CodeGenerator:
"""Return a code object""" """Return a code object"""
return self.graph.getCode() 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 # Next five methods handle name access
def isLocalName(self, name): def isLocalName(self, name):
...@@ -190,6 +194,7 @@ class CodeGenerator: ...@@ -190,6 +194,7 @@ class CodeGenerator:
self._nameOp('DELETE', name) self._nameOp('DELETE', name)
def _nameOp(self, prefix, name): def _nameOp(self, prefix, name):
name = self.mangle(name)
if not self.optimized: if not self.optimized:
self.emit(prefix + '_NAME', name) self.emit(prefix + '_NAME', name)
return return
...@@ -258,7 +263,8 @@ class CodeGenerator: ...@@ -258,7 +263,8 @@ class CodeGenerator:
self._visitFuncOrLambda(node, isLambda=1) self._visitFuncOrLambda(node, isLambda=1)
def _visitFuncOrLambda(self, node, isLambda=0): 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) walk(node.code, gen)
gen.finish() gen.finish()
self.set_lineno(node) self.set_lineno(node)
...@@ -645,7 +651,7 @@ class CodeGenerator: ...@@ -645,7 +651,7 @@ class CodeGenerator:
def visitGetattr(self, node): def visitGetattr(self, node):
self.visit(node.expr) self.visit(node.expr)
self.emit('LOAD_ATTR', node.attrname) self.emit('LOAD_ATTR', self.mangle(node.attrname))
# next five implement assignments # next five implement assignments
...@@ -671,9 +677,9 @@ class CodeGenerator: ...@@ -671,9 +677,9 @@ class CodeGenerator:
def visitAssAttr(self, node): def visitAssAttr(self, node):
self.visit(node.expr) self.visit(node.expr)
if node.flags == 'OP_ASSIGN': if node.flags == 'OP_ASSIGN':
self.emit('STORE_ATTR', node.attrname) self.emit('STORE_ATTR', self.mangle(node.attrname))
elif node.flags == 'OP_DELETE': elif node.flags == 'OP_DELETE':
self.emit('DELETE_ATTR', node.attrname) self.emit('DELETE_ATTR', self.mangle(node.attrname))
else: else:
print "warning: unexpected flags:", node.flags print "warning: unexpected flags:", node.flags
print node print node
...@@ -728,10 +734,10 @@ class CodeGenerator: ...@@ -728,10 +734,10 @@ class CodeGenerator:
if mode == "load": if mode == "load":
self.visit(node.expr) self.visit(node.expr)
self.emit('DUP_TOP') self.emit('DUP_TOP')
self.emit('LOAD_ATTR', node.attrname) self.emit('LOAD_ATTR', self.mangle(node.attrname))
elif mode == "store": elif mode == "store":
self.emit('ROT_TWO') self.emit('ROT_TWO')
self.emit('STORE_ATTR', node.attrname) self.emit('STORE_ATTR', self.mangle(node.attrname))
def visitAugSlice(self, node, mode): def visitAugSlice(self, node, mode):
if mode == "load": if mode == "load":
...@@ -987,6 +993,7 @@ class NestedScopeCodeGenerator(CodeGenerator): ...@@ -987,6 +993,7 @@ class NestedScopeCodeGenerator(CodeGenerator):
self.__super_visitModule(node) self.__super_visitModule(node)
def _nameOp(self, prefix, name): def _nameOp(self, prefix, name):
name = self.mangle(name)
scope = self.scope.check_name(name) scope = self.scope.check_name(name)
if scope == SC_LOCAL: if scope == SC_LOCAL:
if not self.optimized: if not self.optimized:
...@@ -1002,7 +1009,8 @@ class NestedScopeCodeGenerator(CodeGenerator): ...@@ -1002,7 +1009,8 @@ class NestedScopeCodeGenerator(CodeGenerator):
(name, scope) (name, scope)
def _visitFuncOrLambda(self, node, isLambda=0): 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) walk(node.code, gen)
gen.finish() gen.finish()
self.set_lineno(node) self.set_lineno(node)
...@@ -1079,7 +1087,8 @@ class AbstractFunctionCode: ...@@ -1079,7 +1087,8 @@ class AbstractFunctionCode:
optimized = 1 optimized = 1
lambdaCount = 0 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: if isLambda:
klass = FunctionCodeGenerator klass = FunctionCodeGenerator
name = "<lambda.%d>" % klass.lambdaCount name = "<lambda.%d>" % klass.lambdaCount
...@@ -1142,10 +1151,10 @@ class NestedFunctionCodeGenerator(AbstractFunctionCode, ...@@ -1142,10 +1151,10 @@ class NestedFunctionCodeGenerator(AbstractFunctionCode,
super_init = NestedScopeCodeGenerator.__init__ # call be other init super_init = NestedScopeCodeGenerator.__init__ # call be other init
__super_init = AbstractFunctionCode.__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.scopes = scopes
self.scope = scopes[func] 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.setFreeVars(self.scope.get_free_vars())
self.graph.setCellVars(self.scope.get_cell_vars()) self.graph.setCellVars(self.scope.get_cell_vars())
## self.graph.setFlag(CO_NESTED) ## self.graph.setFlag(CO_NESTED)
...@@ -1153,6 +1162,7 @@ class NestedFunctionCodeGenerator(AbstractFunctionCode, ...@@ -1153,6 +1162,7 @@ class NestedFunctionCodeGenerator(AbstractFunctionCode,
class AbstractClassCode: class AbstractClassCode:
def __init__(self, klass, filename, scopes): def __init__(self, klass, filename, scopes):
self.class_name = klass.name
self.graph = pyassem.PyFlowGraph(klass.name, filename, self.graph = pyassem.PyFlowGraph(klass.name, filename,
optimized=0) optimized=0)
self.super_init(filename) self.super_init(filename)
...@@ -1163,6 +1173,7 @@ class AbstractClassCode: ...@@ -1163,6 +1173,7 @@ class AbstractClassCode:
self.setDocstring(klass.doc) self.setDocstring(klass.doc)
def _nameOp(self, prefix, name): def _nameOp(self, prefix, name):
name = self.mangle(name)
# Class namespaces are always unoptimized # Class namespaces are always unoptimized
self.emit(prefix + '_NAME', name) self.emit(prefix + '_NAME', name)
......
...@@ -2,8 +2,10 @@ ...@@ -2,8 +2,10 @@
from compiler import ast from compiler import ast
from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL, SC_UNKNOWN from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL, SC_UNKNOWN
from compiler.misc import mangle
import types import types
import sys import sys
MANGLE_LEN = 256 MANGLE_LEN = 256
...@@ -36,13 +38,7 @@ class Scope: ...@@ -36,13 +38,7 @@ class Scope:
def mangle(self, name): def mangle(self, name):
if self.klass is None: if self.klass is None:
return name return name
if not name.startswith('__'): return mangle(name, self.klass)
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): def add_def(self, name):
self.defs[self.mangle(name)] = 1 self.defs[self.mangle(name)] = 1
......
...@@ -39,3 +39,26 @@ class Stack: ...@@ -39,3 +39,26 @@ class Stack:
self.stack.append(elt) self.stack.append(elt)
def top(self): def top(self):
return self.stack[-1] 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)
...@@ -117,9 +117,6 @@ def is_constant_false(node): ...@@ -117,9 +117,6 @@ def is_constant_false(node):
return 1 return 1
return 0 return 0
def mangle(name):
return name
class CodeGenerator: class CodeGenerator:
"""Defines basic code generator for Python bytecode """Defines basic code generator for Python bytecode
...@@ -136,6 +133,7 @@ class CodeGenerator: ...@@ -136,6 +133,7 @@ class CodeGenerator:
optimized = 0 # is namespace access optimized? optimized = 0 # is namespace access optimized?
__initialized = None __initialized = None
class_name = None # provide default for instance variable
def __init__(self, filename): def __init__(self, filename):
if self.__initialized is None: if self.__initialized is None:
...@@ -175,6 +173,12 @@ class CodeGenerator: ...@@ -175,6 +173,12 @@ class CodeGenerator:
"""Return a code object""" """Return a code object"""
return self.graph.getCode() 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 # Next five methods handle name access
def isLocalName(self, name): def isLocalName(self, name):
...@@ -190,6 +194,7 @@ class CodeGenerator: ...@@ -190,6 +194,7 @@ class CodeGenerator:
self._nameOp('DELETE', name) self._nameOp('DELETE', name)
def _nameOp(self, prefix, name): def _nameOp(self, prefix, name):
name = self.mangle(name)
if not self.optimized: if not self.optimized:
self.emit(prefix + '_NAME', name) self.emit(prefix + '_NAME', name)
return return
...@@ -258,7 +263,8 @@ class CodeGenerator: ...@@ -258,7 +263,8 @@ class CodeGenerator:
self._visitFuncOrLambda(node, isLambda=1) self._visitFuncOrLambda(node, isLambda=1)
def _visitFuncOrLambda(self, node, isLambda=0): 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) walk(node.code, gen)
gen.finish() gen.finish()
self.set_lineno(node) self.set_lineno(node)
...@@ -645,7 +651,7 @@ class CodeGenerator: ...@@ -645,7 +651,7 @@ class CodeGenerator:
def visitGetattr(self, node): def visitGetattr(self, node):
self.visit(node.expr) self.visit(node.expr)
self.emit('LOAD_ATTR', node.attrname) self.emit('LOAD_ATTR', self.mangle(node.attrname))
# next five implement assignments # next five implement assignments
...@@ -671,9 +677,9 @@ class CodeGenerator: ...@@ -671,9 +677,9 @@ class CodeGenerator:
def visitAssAttr(self, node): def visitAssAttr(self, node):
self.visit(node.expr) self.visit(node.expr)
if node.flags == 'OP_ASSIGN': if node.flags == 'OP_ASSIGN':
self.emit('STORE_ATTR', node.attrname) self.emit('STORE_ATTR', self.mangle(node.attrname))
elif node.flags == 'OP_DELETE': elif node.flags == 'OP_DELETE':
self.emit('DELETE_ATTR', node.attrname) self.emit('DELETE_ATTR', self.mangle(node.attrname))
else: else:
print "warning: unexpected flags:", node.flags print "warning: unexpected flags:", node.flags
print node print node
...@@ -728,10 +734,10 @@ class CodeGenerator: ...@@ -728,10 +734,10 @@ class CodeGenerator:
if mode == "load": if mode == "load":
self.visit(node.expr) self.visit(node.expr)
self.emit('DUP_TOP') self.emit('DUP_TOP')
self.emit('LOAD_ATTR', node.attrname) self.emit('LOAD_ATTR', self.mangle(node.attrname))
elif mode == "store": elif mode == "store":
self.emit('ROT_TWO') self.emit('ROT_TWO')
self.emit('STORE_ATTR', node.attrname) self.emit('STORE_ATTR', self.mangle(node.attrname))
def visitAugSlice(self, node, mode): def visitAugSlice(self, node, mode):
if mode == "load": if mode == "load":
...@@ -987,6 +993,7 @@ class NestedScopeCodeGenerator(CodeGenerator): ...@@ -987,6 +993,7 @@ class NestedScopeCodeGenerator(CodeGenerator):
self.__super_visitModule(node) self.__super_visitModule(node)
def _nameOp(self, prefix, name): def _nameOp(self, prefix, name):
name = self.mangle(name)
scope = self.scope.check_name(name) scope = self.scope.check_name(name)
if scope == SC_LOCAL: if scope == SC_LOCAL:
if not self.optimized: if not self.optimized:
...@@ -1002,7 +1009,8 @@ class NestedScopeCodeGenerator(CodeGenerator): ...@@ -1002,7 +1009,8 @@ class NestedScopeCodeGenerator(CodeGenerator):
(name, scope) (name, scope)
def _visitFuncOrLambda(self, node, isLambda=0): 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) walk(node.code, gen)
gen.finish() gen.finish()
self.set_lineno(node) self.set_lineno(node)
...@@ -1079,7 +1087,8 @@ class AbstractFunctionCode: ...@@ -1079,7 +1087,8 @@ class AbstractFunctionCode:
optimized = 1 optimized = 1
lambdaCount = 0 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: if isLambda:
klass = FunctionCodeGenerator klass = FunctionCodeGenerator
name = "<lambda.%d>" % klass.lambdaCount name = "<lambda.%d>" % klass.lambdaCount
...@@ -1142,10 +1151,10 @@ class NestedFunctionCodeGenerator(AbstractFunctionCode, ...@@ -1142,10 +1151,10 @@ class NestedFunctionCodeGenerator(AbstractFunctionCode,
super_init = NestedScopeCodeGenerator.__init__ # call be other init super_init = NestedScopeCodeGenerator.__init__ # call be other init
__super_init = AbstractFunctionCode.__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.scopes = scopes
self.scope = scopes[func] 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.setFreeVars(self.scope.get_free_vars())
self.graph.setCellVars(self.scope.get_cell_vars()) self.graph.setCellVars(self.scope.get_cell_vars())
## self.graph.setFlag(CO_NESTED) ## self.graph.setFlag(CO_NESTED)
...@@ -1153,6 +1162,7 @@ class NestedFunctionCodeGenerator(AbstractFunctionCode, ...@@ -1153,6 +1162,7 @@ class NestedFunctionCodeGenerator(AbstractFunctionCode,
class AbstractClassCode: class AbstractClassCode:
def __init__(self, klass, filename, scopes): def __init__(self, klass, filename, scopes):
self.class_name = klass.name
self.graph = pyassem.PyFlowGraph(klass.name, filename, self.graph = pyassem.PyFlowGraph(klass.name, filename,
optimized=0) optimized=0)
self.super_init(filename) self.super_init(filename)
...@@ -1163,6 +1173,7 @@ class AbstractClassCode: ...@@ -1163,6 +1173,7 @@ class AbstractClassCode:
self.setDocstring(klass.doc) self.setDocstring(klass.doc)
def _nameOp(self, prefix, name): def _nameOp(self, prefix, name):
name = self.mangle(name)
# Class namespaces are always unoptimized # Class namespaces are always unoptimized
self.emit(prefix + '_NAME', name) self.emit(prefix + '_NAME', name)
......
...@@ -2,8 +2,10 @@ ...@@ -2,8 +2,10 @@
from compiler import ast from compiler import ast
from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL, SC_UNKNOWN from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL, SC_UNKNOWN
from compiler.misc import mangle
import types import types
import sys import sys
MANGLE_LEN = 256 MANGLE_LEN = 256
...@@ -36,13 +38,7 @@ class Scope: ...@@ -36,13 +38,7 @@ class Scope:
def mangle(self, name): def mangle(self, name):
if self.klass is None: if self.klass is None:
return name return name
if not name.startswith('__'): return mangle(name, self.klass)
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): def add_def(self, name):
self.defs[self.mangle(name)] = 1 self.defs[self.mangle(name)] = 1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment