# HG changeset patch # User paulb@localhost.localdomain # Date 1182714951 -7200 # Node ID 65bcf80d443255c4d200f95c04bb4b428352aa1d # Parent baa3d42674f9e6b9dc3d5cd6aa1c9a19d94166c7 Replaced the generic tuple/list assignment mechanism with specific access to a special __value__ attributes, providing improved precision in programs which employ such sequence assignments. Added tests of such assignments. diff -r baa3d42674f9 -r 65bcf80d4432 simplify/annotate.py --- a/simplify/annotate.py Sun Jun 24 20:06:24 2007 +0200 +++ b/simplify/annotate.py Sun Jun 24 21:55:51 2007 +0200 @@ -751,10 +751,11 @@ # NOTE: This is dependent on the tuple definition in the builtins. - for node in maketuple.nodes: + for i, node in enumerate(maketuple.nodes): self.dispatch(node) for t in tuples: t.type.namespace.add("value", self.namespace.types) + t.type.namespace.add("__value__%d" % i, self.namespace.types) self.namespace.set_types(tuples) self.annotate(maketuple) @@ -976,7 +977,7 @@ # Utility methods. def get_builtin_instances(self, node, name): - return set([Attribute(None, self.new_instance(node, attr.type)) for attr in self.builtins.namespace[name]]) + return set([Attribute(None, self.new_instance(node, attr.type)) for attr in self.builtins_namespace[name]]) def new_instance(self, node, type): diff -r baa3d42674f9 -r 65bcf80d4432 simplify/ast.py --- a/simplify/ast.py Sun Jun 24 20:06:24 2007 +0200 +++ b/simplify/ast.py Sun Jun 24 21:55:51 2007 +0200 @@ -5,6 +5,12 @@ this module processes AST trees originating from the compiler module and produces a result tree consisting of instruction-oriented program nodes. +Some of the simplified nodes will be altered by the fixnames module, principally +LoadName and StoreName nodes which, in the case of globals and builtins, will be +changed to LoadAttr and StoreAttr respectively. + +-------- + Copyright (C) 2006, 2007 Paul Boddie This software is free software; you can redistribute it and/or @@ -225,8 +231,8 @@ # Assignments. - def visitAssAttr(self, assattr, in_sequence=0): - expr = self._visitAssNameOrAttr(assattr, in_sequence) + def visitAssAttr(self, assattr, element=None): + expr = self._visitAssNameOrAttr(assattr, element) lvalue = self.dispatch(assattr.expr) result = StoreAttr(assattr, 1, name=assattr.attrname, lvalue=lvalue, expr=expr) return result @@ -235,30 +241,42 @@ result = Assign(assign, 1) store = StoreTemp(expr=self.dispatch(assign.expr)) release = ReleaseTemp() - result.code = [store] + self.dispatches(assign.nodes, 0) + [release] + result.code = [store] + self.dispatches(assign.nodes) + [release] return result - def visitAssList(self, asslist, in_sequence=0): - if not in_sequence: + def visitAssList(self, asslist, element=None): + if element is None: expr = LoadTemp() else: - expr = InvokeFunction(asslist, expr=LoadAttr(expr=LoadTemp(), name="next")) + expr = LoadAttr(expr=LoadTemp(), name=("__value__%d" % element)) result = Assign(asslist, 1) - store = StoreTemp(expr=InvokeFunction(asslist, expr=LoadAttr(name="__iter__", expr=expr))) - release = ReleaseTemp() - result.code = [store] + self.dispatches(asslist.nodes, 1) + [release] + result.code = [StoreTemp(expr=expr)] + for i, node in enumerate(asslist.nodes): + result.code.append(self.dispatch(node, i)) + result.code.append(ReleaseTemp()) return result visitAssTuple = visitAssList - def _visitAssNameOrAttr(self, node, in_sequence): - if not in_sequence: + def _visitAssNameOrAttr(self, node, element=None): + + "Produce a suitable value for assignment from the given 'node'." + + if element is None: return LoadTemp() else: - return InvokeFunction(node, expr=LoadAttr(expr=LoadTemp(), name="next")) + return LoadAttr(expr=LoadTemp(), name=("__value__%d" % element)) + + def visitAssName(self, assname, element=None): - def visitAssName(self, assname, in_sequence=0): - expr = self._visitAssNameOrAttr(assname, in_sequence) + """ + Visit the 'assname' node, producing an appropriate StoreName simplified + node which if 'element' is None will store a temporary value; otherwise, + a special attribute will be obtained from the current temporary value in + order to attempt to support optimised sequence assignment. + """ + + expr = self._visitAssNameOrAttr(assname, element) result = StoreName(assname, 1, name=assname.name, expr=expr) return result @@ -1494,9 +1512,9 @@ return result - def visitSlice(self, slice, in_sequence=0): + def visitSlice(self, slice, element=None): return self._visitSlice(slice, self.dispatch(slice.expr), self.dispatch_or_none(slice.lower), - self.dispatch_or_none(slice.upper), slice.flags, self._visitAssNameOrAttr(slice, in_sequence)) + self.dispatch_or_none(slice.upper), slice.flags, self._visitAssNameOrAttr(slice, element)) def visitSliceobj(self, sliceobj): return InvokeFunction(sliceobj, 1, @@ -1561,10 +1579,10 @@ dstar=None ) - def visitSubscript(self, subscript, in_sequence=0): + def visitSubscript(self, subscript, element=None): return self._visitSubscript( subscript, self.dispatch(subscript.expr), self._visitSubscriptSubs(subscript, subscript.subs), subscript.flags, - self._visitAssNameOrAttr(subscript, in_sequence) + self._visitAssNameOrAttr(subscript, element) ) def visitTryExcept(self, tryexcept): diff -r baa3d42674f9 -r 65bcf80d4432 tests/assign.py --- a/tests/assign.py Sun Jun 24 20:06:24 2007 +0200 +++ b/tests/assign.py Sun Jun 24 21:55:51 2007 +0200 @@ -1,6 +1,21 @@ class A: pass a = A() + a.x = 1, 2, 3 +a.y = "1", 1, 1.1 +a.z = 1, a.y, "1" + c = b = a.x +e = d = a.y +g = f = a.z + [x, y, z] = c x, y, z = c + +[p, q, r] = e +p, q, r = e + +[l, m, n] = g +l, m, n = g + +l, (m1, m2, m3), n = g