Author: Benjamin Peterson <benja...@python.org>
Branch: py3k
Changeset: r53622:3661bb9780f8
Date: 2012-03-14 18:02 -0500
http://bitbucket.org/pypy/pypy/changeset/3661bb9780f8/

Log:    complete extended unpacking implementation

diff --git a/pypy/interpreter/astcompiler/codegen.py 
b/pypy/interpreter/astcompiler/codegen.py
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -883,36 +883,46 @@
         ifexp.orelse.walkabout(self)
         self.use_next_block(end)
 
-    def visit_Tuple(self, tup):
-        self.update_position(tup.lineno)
-        elt_count = len(tup.elts) if tup.elts is not None else 0
-        if tup.ctx == ast.Store:
-            star_pos = -1
+    def _visit_list_or_tuple(self, node, elts, ctx, op):
+        elt_count = len(elts) if elts else 0
+        star_pos = -1
+        if ctx == ast.Store:
             if elt_count > 0:
-                for i, elt in enumerate(tup.elts):
+                for i, elt in enumerate(elts):
                     if isinstance(elt, ast.Starred):
                         if star_pos != -1:
-                            self.error("two starred expressions in 
assignment", tup)
+                            msg = "too many starred expressions in assignment"
+                            self.error(msg, node)
                         star_pos = i
-            if star_pos > -1:
+            if star_pos != -1:
                 self.emit_op_arg(ops.UNPACK_EX, star_pos | 
(elt_count-star_pos-1)<<8)
             else:
                 self.emit_op_arg(ops.UNPACK_SEQUENCE, elt_count)
-        self.visit_sequence(tup.elts)
-        if tup.ctx == ast.Load:
-            self.emit_op_arg(ops.BUILD_TUPLE, elt_count)
+        if elt_count > 0:
+            if star_pos != -1:
+                for elt in elts:
+                    if isinstance(elt, ast.Starred):
+                        elt.value.walkabout(self)
+                    else:
+                        elt.walkabout(self)
+            else:
+                self.visit_sequence(elts)
+        if ctx == ast.Load:
+            self.emit_op_arg(op, elt_count)
 
     def visit_Starred(self, star):
-        star.value.walkabout(self)
+        if star.ctx != ast.Store:
+            self.error("can use starred expression only as assignment target",
+                       star)
+        self.error("starred assignment must be in list or tuple", star)
+
+    def visit_Tuple(self, tup):
+        self.update_position(tup.lineno)
+        self._visit_list_or_tuple(tup, tup.elts, tup.ctx, ops.BUILD_TUPLE)
 
     def visit_List(self, l):
         self.update_position(l.lineno)
-        elt_count = len(l.elts) if l.elts is not None else 0
-        if l.ctx == ast.Store:
-            self.emit_op_arg(ops.UNPACK_SEQUENCE, elt_count)
-        self.visit_sequence(l.elts)
-        if l.ctx == ast.Load:
-            self.emit_op_arg(ops.BUILD_LIST, elt_count)
+        self._visit_list_or_tuple(l, l.elts, l.ctx, ops.BUILD_LIST)
 
     def visit_Dict(self, d):
         self.update_position(d.lineno)
diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py 
b/pypy/interpreter/astcompiler/test/test_compiler.py
--- a/pypy/interpreter/astcompiler/test/test_compiler.py
+++ b/pypy/interpreter/astcompiler/test/test_compiler.py
@@ -827,12 +827,29 @@
         yield self.st, test, "f()", 42
     # This line is needed for py.code to find the source.
 
-    def test_tuple_unpacking(self):
+    def test_extended_unpacking(self):
         func = """def f():
             (a, *b, c) = 1, 2, 3, 4, 5
             return a, b, c
         """
         yield self.st, func, "f()", (1, [2, 3, 4], 5)
+        func = """def f():
+            [a, *b, c] = 1, 2, 3, 4, 5
+            return a, b, c
+        """
+        yield self.st, func, "f()", (1, [2, 3, 4], 5)
+        func = """def f():
+            *a, = [1, 2, 3]
+            return a
+        """
+        yield self.st, func, "f()", [1, 2, 3]
+        py.test.raises(SyntaxError, self.simple_test, "*a, *b = [1, 2]",
+                       None, None)
+        py.test.raises(SyntaxError, self.simple_test, "a = [*b, c]",
+                       None, None)
+        py.test.raises(SyntaxError, self.simple_test, "for *a in x: pass",
+                       None, None)
+
 
 class AppTestCompiler:
 
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to