From f870c952f96c72cc23fa75a1ce48418c71fbf76e Mon Sep 17 00:00:00 2001 From: Jeremy Hylton Date: Mon, 9 Apr 2001 13:57:32 +0000 Subject: [PATCH] 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 --- Lib/compiler/symbols.py | 116 +++++++++++++++++++++++------ Tools/compiler/compiler/symbols.py | 116 +++++++++++++++++++++++------ 2 files changed, 184 insertions(+), 48 deletions(-) diff --git a/Lib/compiler/symbols.py b/Lib/compiler/symbols.py index 1f107fe5df3..872f174a05d 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 @@ class Scope: 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 @@ class SymbolVisitor: 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 @@ class SymbolVisitor: 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 @@ class SymbolVisitor: 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 @@ if __name__ == "__main__": 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 1f107fe5df3..872f174a05d 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 @@ class Scope: 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 @@ class SymbolVisitor: 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 @@ class SymbolVisitor: 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 @@ class SymbolVisitor: 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 @@ if __name__ == "__main__": 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)