# HG changeset patch # User paulb@jeremy # Date 1154217633 -7200 # Node ID ace370706a11ef83bdb605caf7388bd444e68380 # Parent 33af8e19a3f86ee346f22263f419dee1b5155c73 Introduced separate Namespace classes for the annotate and fixnames modules. Introduced tentative support for operators, starting with the Add AST node and introducing the Choices program node. Changed StoreGlobal to merge the stored value types into the global namespace. Changed the merge method naming in annotate.Namespace. Added the start of an operators test. Removed handlers from TryFinally program nodes. diff -r 33af8e19a3f8 -r ace370706a11 annotate.py --- a/annotate.py Fri Jul 28 00:20:57 2006 +0200 +++ b/annotate.py Sun Jul 30 02:00:33 2006 +0200 @@ -46,6 +46,39 @@ # Namespaces and related abstractions. +class Namespace: + + """ + A local namespace which may either relate to a genuine set of function + locals or the initialisation of a structure. + """ + + def __init__(self, structure=None): + self.structure = structure + self.names = {} + + def store(self, name, types): + self.names[name] = types + + def load(self, name): + return self.names[name] + + def merge(self, name, types): + if not self.names.has_key(name): + self.names[name] = types + else: + existing = self.names[name] + for type in types: + if type not in existing: + existing.append(type) + + def merge_namespace(self, namespace): + self.merge_items(namespace.names.items()) + + def merge_items(self, items): + for name, types in items: + self.merge(name, types) + class Attribute: """ @@ -94,7 +127,7 @@ self.namespace = Namespace(structure=getattr(node, "structure", None)) if locals is not None: - self.namespace.merge(locals) + self.namespace.merge_namespace(locals) # Determine the global namespace. @@ -153,11 +186,6 @@ def dispatch(self, node, *args): return Visitor.dispatch(self, node, *args) - def visitGlobal(self, global_): - for name in global_.names: - self.namespace.make_global(name) - return global_ - def visitLoadRef(self, loadref): self.types = [loadref.ref] self.annotate(loadref) @@ -181,10 +209,7 @@ def visitStoreGlobal(self, storeglobal): storeglobal.expr = self.dispatch(storeglobal.expr) - - # NOTE: This may always be a merge operation. - - self.global_namespace.store(storeglobal.name, self.types) + self.global_namespace.merge(storeglobal.name, self.types) return storeglobal def visitLoadTemp(self, loadtemp): diff -r 33af8e19a3f8 -r ace370706a11 fixnames.py --- a/fixnames.py Fri Jul 28 00:20:57 2006 +0200 +++ b/fixnames.py Sun Jul 30 02:00:33 2006 +0200 @@ -98,7 +98,7 @@ value = getattr(node, attr, None) if value is not None: setattr(node, attr, self.dispatch(value)) - for attr in ("body", "else_", "finally_", "code"): + for attr in ("body", "else_", "finally_", "code", "choices"): value = getattr(node, attr, None) if value is not None: setattr(node, attr, self.dispatches(value)) @@ -133,4 +133,48 @@ self.namespace.store(storename.name) return storename +class Namespace: + + """ + A local namespace which may either relate to a genuine set of function + locals or the initialisation of a structure. + """ + + def __init__(self, structure=None): + self.structure = structure + if structure is not None: + self.local = "structure" + else: + self.local = "local" + self.names = {} + self.not_local = [] + + def make_global(self, name): + if name not in self.not_local: + self.not_local.append(name) + + 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 store(self, name, types=None): + if name not in self.not_local: + self.names[name] = types + else: + raise KeyError, name + + def load(self, name): + if name in self.not_local or not self.names.has_key(name): + raise KeyError, name + else: + return self.names[name] + # vim: tabstop=4 expandtab shiftwidth=4 diff -r 33af8e19a3f8 -r ace370706a11 simplified.py --- a/simplified.py Fri Jul 28 00:20:57 2006 +0200 +++ b/simplified.py Sun Jul 30 02:00:33 2006 +0200 @@ -75,6 +75,7 @@ else_ Any conditional code depending on the failure of a test. finally_ Any code which will be executed regardless. code Any unconditional code. + choices Any choices which may be included in the final program. """ def __init__(self, original=None, **kw): @@ -122,7 +123,7 @@ self._pprint(indent + 2, "( ", "structure '%s'" % self.structure.name) if hasattr(self, "test"): self.test.pprint(indent + 2, "? ") - for attr in "code", "body", "else_", "finally_": + for attr in "code", "body", "else_", "finally_", "choices": if hasattr(self, attr) and getattr(self, attr): self._pprint(indent, "", "{ (%s)" % attr) for node in getattr(self, attr): @@ -169,6 +170,7 @@ class Try(Node): "A try...except...else...finally grouping node." class Raise(Node): "An exception raising node." class Not(Node): "A negation of an expression." +class Choice(Node): "A special node which indicates a choice of expressions." # Special non-program nodes. @@ -190,61 +192,4 @@ class Instance(Structure): "An instance." class Constant(Instance): "A constant." -class Namespace: - - """ - A local namespace which may either relate to a genuine set of function - locals or the initialisation of a structure. - """ - - def __init__(self, structure=None): - self.structure = structure - if structure is not None: - self.local = "structure" - else: - self.local = "local" - self.names = {} - self.not_local = [] - - def make_global(self, name): - if name not in self.not_local: - self.not_local.append(name) - - 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 store(self, name, types=None): - if name not in self.not_local: - self.names[name] = types - else: - raise KeyError, name - - def load(self, name): - if name in self.not_local or not self.names.has_key(name): - raise KeyError, name - else: - return self.names[name] - - def merge(self, namespace): - self.merge_items(namespace.names.items()) - - def merge_items(self, items): - for name, types in items: - if not self.names.has_key(name): - self.names[name] = types - else: - existing = self.names[name] - for type in types: - if type not in existing: - existing.append(type) - # vim: tabstop=4 expandtab shiftwidth=4 diff -r 33af8e19a3f8 -r ace370706a11 simplify.py --- a/simplify.py Fri Jul 28 00:20:57 2006 +0200 +++ b/simplify.py Sun Jul 30 02:00:33 2006 +0200 @@ -415,6 +415,17 @@ def visitInvert(self, invert): return Invoke(invert, expr=LoadAttr(expr=self.dispatch(invert.expr), name="__invert__"), args=[]) + def visitAdd(self, add): + + # NOTE: Strictly one of the choices must be evaluated, never more than one. + + result = Choice(add) + result.choices = [ + Invoke(expr=LoadAttr(expr=self.dispatch(add.left), name="__add__"), args=[self.dispatch(add.right)]), + Invoke(expr=LoadAttr(expr=self.dispatch(add.right), name="__radd__"), args=[self.dispatch(add.left)]) + ] + return result + # Assignments. augassign_methods = { @@ -776,7 +787,7 @@ # Exception node transformations. def visitTryFinally(self, tryfinally): - result = Try(tryfinally, body=[], handlers=[], else_=[], finally_=[]) + result = Try(tryfinally, body=[], else_=[], finally_=[]) if tryfinally.body is not None: result.body = self.dispatch(tryfinally.body) if tryfinally.final is not None: diff -r 33af8e19a3f8 -r ace370706a11 tests/operators.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/operators.py Sun Jul 30 02:00:33 2006 +0200 @@ -0,0 +1,2 @@ +a = 1 + 1.1 +b = a + 2