From c59e22000082722655517942d7662eec5a4a70ce Mon Sep 17 00:00:00 2001 From: Jeremy Hylton Date: Mon, 27 Aug 2001 22:56:16 +0000 Subject: [PATCH] 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() --- Lib/compiler/misc.py | 23 +++++++++++++++++ Lib/compiler/pycodegen.py | 37 ++++++++++++++++++---------- Lib/compiler/symbols.py | 10 +++----- Tools/compiler/compiler/misc.py | 23 +++++++++++++++++ Tools/compiler/compiler/pycodegen.py | 37 ++++++++++++++++++---------- Tools/compiler/compiler/symbols.py | 10 +++----- 6 files changed, 100 insertions(+), 40 deletions(-) diff --git a/Lib/compiler/misc.py b/Lib/compiler/misc.py index 29ff8667802..b834a2e677c 100644 --- a/Lib/compiler/misc.py +++ b/Lib/compiler/misc.py @@ -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) diff --git a/Lib/compiler/pycodegen.py b/Lib/compiler/pycodegen.py index 37b51bf44d4..ced0f07d425 100644 --- a/Lib/compiler/pycodegen.py +++ b/Lib/compiler/pycodegen.py @@ -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 = "" % 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) diff --git a/Lib/compiler/symbols.py b/Lib/compiler/symbols.py index 0ef0d12f03b..40fd127bfd1 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 __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 diff --git a/Tools/compiler/compiler/misc.py b/Tools/compiler/compiler/misc.py index 29ff8667802..b834a2e677c 100644 --- a/Tools/compiler/compiler/misc.py +++ b/Tools/compiler/compiler/misc.py @@ -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) diff --git a/Tools/compiler/compiler/pycodegen.py b/Tools/compiler/compiler/pycodegen.py index 37b51bf44d4..ced0f07d425 100644 --- a/Tools/compiler/compiler/pycodegen.py +++ b/Tools/compiler/compiler/pycodegen.py @@ -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 = "" % 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) diff --git a/Tools/compiler/compiler/symbols.py b/Tools/compiler/compiler/symbols.py index 0ef0d12f03b..40fd127bfd1 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 __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