# HG changeset patch # User paulb@jeremy # Date 1155401225 -7200 # Node ID 7a364038f7828ed52a04fba85542e3c404279fe3 # Parent a7a001e803a3f744a06b08b21d8665f1955842e0 Removed LoadGlobal, LoadBuiltin and StoreGlobal, replacing them with LoadAttr and StoreAttr nodes in generated programs. Improved scope detection in the fixnames module. Added more comments and docstrings. diff -r a7a001e803a3 -r 7a364038f782 fixnames.py --- a/fixnames.py Sat Aug 12 01:46:35 2006 +0200 +++ b/fixnames.py Sat Aug 12 18:47:05 2006 +0200 @@ -21,6 +21,22 @@ License along with this library; see the file LICENCE.txt If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +-------- + +To use this module, first instantiate a Fixer object: + +fixer = Fixer() + +Then, apply the fixer to an existing Simplifier object: + +simplifier = ... +fixer.process(simplifier) + +If an existing simplifier has been used to process a module containing built-in +classes and functions, apply the fixer as follows: + +fixer.process(simplifier, builtins_simplifier) """ from simplified import * @@ -46,9 +62,12 @@ self.visitor = self - def process(self, visitor): + def process(self, visitor, builtins_visitor=None): - "Process the resources of the given 'visitor'." + """ + Process the resources of the given 'visitor' optionally using a + 'builtins_visitor' to reference built-in objects. + """ self.subprograms = [] self.current_subprograms = [] @@ -58,7 +77,12 @@ # defined at that level. self.global_namespace = None - visitor.result = self.process_node(visitor.result) + self.module = visitor.result + if builtins_visitor is not None: + self.builtins_module = builtins_visitor.result + else: + self.builtins_module = None + self.process_node(visitor.result) # Then, process all functions and methods, providing a global namespace. @@ -174,7 +198,7 @@ "Transform the 'loadname' node to a specific, scope-sensitive node." - scope = self.namespace.find_for_load(loadname.name) + scope = self.namespace.find(loadname.name) # For structure namespaces, load an attribute. @@ -188,25 +212,25 @@ # Where a distinct global namespace exists, examine it. if self.global_namespace is not None: - scope = self.global_namespace.find_for_load(loadname.name) + scope = self.global_namespace.find(loadname.name) # Where the name is outside the global namespace, it must be a # built-in. if scope == "global": - result = self.dispatch(LoadBuiltin(name=loadname.name)) + result = self.dispatch(LoadAttr(expr=LoadRef(ref=self.builtins_module), name=loadname.name)) # Otherwise, it is within the global namespace and must be a # global. else: - result = self.dispatch(LoadGlobal(name=loadname.name)) + result = self.dispatch(LoadAttr(expr=LoadRef(ref=self.module), name=loadname.name)) # Where no global namespace exists, we are at the module level and # must be accessing a built-in. else: - result = self.dispatch(LoadBuiltin(name=loadname.name)) + result = self.dispatch(LoadAttr(expr=LoadRef(ref=self.builtins_module), name=loadname.name)) # For local accesses... @@ -221,7 +245,7 @@ # module level). else: - result = self.dispatch(LoadGlobal(name=loadname.name)) + result = self.dispatch(LoadAttr(expr=LoadRef(ref=self.module), name=loadname.name)) return result @@ -229,7 +253,7 @@ "Transform the 'storename' node to a specific, scope-sensitive node." - scope = self.namespace.find_for_store(storename.name) + scope = self.namespace.find(storename.name) # For structure namespaces, store an attribute. @@ -240,7 +264,7 @@ # assignment and store the name globally. elif scope == "global": - return self.dispatch(StoreGlobal(name=storename.name, expr=storename.expr)) + return self.dispatch(StoreAttr(lvalue=LoadRef(ref=self.module), name=storename.name, expr=storename.expr)) # For local namespace accesses... @@ -256,7 +280,7 @@ # considered global. else: - return self.dispatch(StoreGlobal(name=storename.name, expr=storename.expr)) + return self.dispatch(StoreAttr(lvalue=LoadRef(ref=self.module), name=storename.name, expr=storename.expr)) def visitInvoke(self, invoke): @@ -273,6 +297,9 @@ else: return self.default(invoke) +class ScopeMismatch(Exception): + pass + class NameOrganiser: """ @@ -281,52 +308,46 @@ """ def __init__(self, structure=None): + + "Initialise the namespace with an optional 'structure'." + self.structure = structure if structure is not None: self.local = "structure" else: self.local = "local" + + # Names may be self.local or "global". + self.names = {} - self.not_local = [] def make_global(self, name): - if name not in self.not_local: - self.not_local.append(name) + if not self.names.has_key(name): + self.names[name] = "global" + elif self.names[name] == self.local: + raise ScopeMismatch, "Name '%s' already considered as %s." % (name, self.local) - def find_for_store(self, name): - if name not in self.not_local: - return self.local - else: - return "global" - - def find_for_load(self, name): - if name not in self.not_local and self.names.has_key(name): - return self.local - else: - return "global" + def find(self, name): + return self.names.get(name, "global") def store(self, name): - if name not in self.not_local: - self.names[name] = None + if self.names.get(name) != "global": + self.names[name] = self.local else: - raise KeyError, name + raise ScopeMismatch, "Name '%s' already considered as global." % name - def load(self, name): - if name in self.not_local or not self.names.has_key(name): - raise KeyError, name + def merge(self, name, scope): + if self.names.get(name) in (None, scope): + self.names[name] = scope else: - return self.names[name] - - def merge(self, name): - if not self.names.has_key(name): - self.names[name] = None + raise ScopeMismatch, "Name '%s' already considered as %s." % (name, self.names[name]) def merge_namespace(self, namespace): - self.merge_names(namespace.names.keys()) + self.merge_items(namespace.names.items()) - def merge_names(self, names): - for name in names: - self.merge(name) + def merge_items(self, items): + for name, scope in items: + self.merge(name, scope) def __repr__(self): return repr(self.names) diff -r a7a001e803a3 -r 7a364038f782 simplified.py --- a/simplified.py Sat Aug 12 01:46:35 2006 +0200 +++ b/simplified.py Sat Aug 12 18:47:05 2006 +0200 @@ -163,14 +163,11 @@ class Import(Node): "A module import operation." class LoadTemp(Node): "Load a previously-stored temporary value." class LoadName(Node): "Load a named object." -class LoadGlobal(Node): "Load a named global object." -class LoadBuiltin(Node): "Load a named built-in object." class LoadAttr(Node): "Load an object attribute." class LoadRef(Node): "Load a reference, typically a subprogram or a constant." class LoadExc(Node): "Load a handled exception." class StoreTemp(Node): "Store a temporary value." class StoreName(Node): "Associate a name with an object." -class StoreGlobal(Node): "Associate a name with an object in the global namespace." class StoreAttr(Node): "Associate an object's attribute with a value." class ReleaseTemp(Node): "Release a temporary value." class Conditional(Node): "A conditional node consisting of a test and outcomes." diff -r a7a001e803a3 -r 7a364038f782 simplify.py --- a/simplify.py Sat Aug 12 01:46:35 2006 +0200 +++ b/simplify.py Sat Aug 12 18:47:05 2006 +0200 @@ -21,6 +21,17 @@ License along with this library; see the file LICENCE.txt If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +-------- + +To use this module, first instantiate a Simplifier object: + +simplifier = Simplifier() + +Then, apply the simplifier to an AST tree: + +module = compiler.parseFile(...) +simplifier.process(module) """ from simplified import * @@ -45,6 +56,13 @@ """ def __init__(self, builtins=0): + + """ + Initialise the simplifier with the optional 'builtins' parameter + indicating whether the module contains the built-in classes and + functions. + """ + Visitor.__init__(self) self.result = None # The resulting tree. self.subprograms = [] # Subprograms outside the tree. @@ -77,6 +95,12 @@ # Relatively trivial transformations. def visitModule(self, module): + + """ + Process the given 'module', producing a Module object which contains the + resulting program nodes. + """ + self.result = Module(module) module_code = self.dispatch(module.node) @@ -709,10 +733,25 @@ return result def _visitFunction(self, function, subprogram): - if function.flags & 4 != 0: has_star = 1 - else: has_star = 0 - if function.flags & 8 != 0: has_dstar = 1 - else: has_dstar = 0 + + """ + A common function generator which transforms the given 'function' node + and initialises the given 'subprogram' appropriately. + """ + + # Discover star and dstar parameters. + + if function.flags & 4 != 0: + has_star = 1 + else: + has_star = 0 + if function.flags & 8 != 0: + has_dstar = 1 + else: + has_dstar = 0 + + # Discover the number of defaults and positional parameters. + ndefaults = len(function.defaults) npositional = len(function.argnames) - has_star - has_dstar diff -r a7a001e803a3 -r 7a364038f782 test.py --- a/test.py Sat Aug 12 01:46:35 2006 +0200 +++ b/test.py Sat Aug 12 18:47:05 2006 +0200 @@ -12,6 +12,6 @@ builtins_fixer = fixnames.Fixer() builtins_fixer.process(builtins_simplifier) module_fixer = fixnames.Fixer() -module_fixer.process(module_simplifier) +module_fixer.process(module_simplifier, builtins_simplifier) rb = builtins_simplifier.result r = module_simplifier.result