Author: Philip Jenvey <[email protected]>
Branch: py3k
Changeset: r63079:6cded36a0209
Date: 2013-04-05 17:25 -0700
http://bitbucket.org/pypy/pypy/changeset/6cded36a0209/
Log: match cpython's stricter handling of extended unpacking
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
@@ -6,6 +6,7 @@
# help the annotator. To it, unfortunately, everything is not so obvious. If
# you figure out a way to remove them, great, but try a translation first,
# please.
+import struct
from pypy.interpreter.astcompiler import ast, assemble, symtable, consts, misc
from pypy.interpreter.astcompiler import optimize # For side effects
@@ -13,6 +14,7 @@
from pypy.tool import stdlib_opcode as ops
from pypy.interpreter.error import OperationError
+C_INT_MAX = (2 ** (struct.calcsize('i') * 8)) / 2 - 1
def compile_ast(space, module, info):
"""Generate a code object from AST."""
@@ -771,6 +773,9 @@
return False
for target in targets:
if not isinstance(target, ast.Name):
+ if isinstance(target, ast.Starred):
+ # these require extra checks
+ return False
break
else:
self.visit_sequence(values)
@@ -935,28 +940,24 @@
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(elts):
- if isinstance(elt, ast.Starred):
- if star_pos != -1:
- msg = "too many starred expressions in assignment"
- self.error(msg, node)
- star_pos = i
- if star_pos != -1:
- self.emit_op_arg(ops.UNPACK_EX, star_pos |
(elt_count-star_pos-1)<<8)
- else:
+ seen_star = False
+ for i in range(elt_count):
+ elt = elts[i]
+ is_starred = isinstance(elt, ast.Starred)
+ if is_starred and not seen_star:
+ if i >= 1 << 8 or elt_count - i - 1 >= (C_INT_MAX >> 8):
+ self.error("too many expressions in star-unpacking "
+ "assignment", node)
+ self.emit_op_arg(ops.UNPACK_EX,
+ i + ((elt_count - i - 1) << 8))
+ seen_star = True
+ elts[i] = elt.value
+ elif is_starred:
+ self.error("two starred expressions in assignment", node)
+ if not seen_star:
self.emit_op_arg(ops.UNPACK_SEQUENCE, 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)
+ self.visit_sequence(elts)
if ctx == ast.Load:
self.emit_op_arg(op, elt_count)
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
@@ -884,12 +884,30 @@
return a, b, c
"""
yield self.st, func, "f()", (1, [2, 3], 4)
- 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)
+
+ def test_extended_unpacking_fail(self):
+ exc = py.test.raises(SyntaxError, self.simple_test, "*a, *b = [1, 2]",
+ None, None).value
+ assert exc.msg == "two starred expressions in assignment"
+ exc = py.test.raises(SyntaxError, self.simple_test,
+ "[*b, *c] = range(10)", None, None).value
+ assert exc.msg == "two starred expressions in assignment"
+
+ exc = py.test.raises(SyntaxError, self.simple_test, "a = [*b, c]",
+ None, None).value
+ assert exc.msg == "can use starred expression only as assignment
target"
+ exc = py.test.raises(SyntaxError, self.simple_test, "for *a in x:
pass",
+ None, None).value
+ assert exc.msg == "starred assignment target must be in a list or
tuple"
+
+ s = ", ".join("a%d" % i for i in range(1<<8)) + ", *rest = range(1<<8
+ 1)"
+ exc = py.test.raises(SyntaxError, self.simple_test, s, None,
+ None).value
+ assert exc.msg == "too many expressions in star-unpacking assignment"
+ s = ", ".join("a%d" % i for i in range(1<<8 + 1)) + ", *rest =
range(1<<8 + 2)"
+ exc = py.test.raises(SyntaxError, self.simple_test, s, None,
+ None).value
+ assert exc.msg == "too many expressions in star-unpacking assignment"
class AppTestCompiler:
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit