# HG changeset patch # User Paul Boddie # Date 1530551994 -7200 # Node ID 4bf5180fbfeea4f4d505238f0f688ea306db1f95 # Parent 1b1c1664e7749321fc00bf1e5153730145894c18 Added missing sequence length check when unpacking sequences. diff -r 1b1c1664e774 -r 4bf5180fbfee common.py --- a/common.py Mon Jul 02 17:53:15 2018 +0200 +++ b/common.py Mon Jul 02 19:19:54 2018 +0200 @@ -4,7 +4,7 @@ Common functions. Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, - 2014, 2015, 2016, 2017 Paul Boddie + 2014, 2015, 2016, 2017, 2018 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -433,7 +433,7 @@ variable. """ - assignments = [] + statements = [] # Employ existing names to access the sequence. # Literal sequences do not provide names of accessible objects. @@ -447,19 +447,25 @@ temp = self.get_temporary_name() self.next_temporary() - assignments.append( + statements.append( compiler.ast.Assign([compiler.ast.AssName(temp, "OP_ASSIGN")], expr) ) + # Generate a test for the length of the expression object. + + statements.append(compiler.ast.Discard( + compiler.ast.CallFunc(compiler.ast.Name("$seq_test_length"), + [compiler.ast.Name(temp), compiler.ast.Const(len(n.nodes))]))) + # Assign the items to the target nodes. for i, node in enumerate(n.nodes): - assignments.append( + statements.append( compiler.ast.Assign([node], compiler.ast.Subscript( compiler.ast.Name(temp), "OP_APPLY", [compiler.ast.Const(i, str(i))])) ) - return self.process_structure_node(compiler.ast.Stmt(assignments)) + return self.process_structure_node(compiler.ast.Stmt(statements)) def process_literal_sequence_items(self, n, name_ref): diff -r 1b1c1664e774 -r 4bf5180fbfee inspector.py --- a/inspector.py Mon Jul 02 17:53:15 2018 +0200 +++ b/inspector.py Mon Jul 02 19:19:54 2018 +0200 @@ -873,6 +873,15 @@ self.set_special(n.name, value) return value + # Special case for sequence length testing. + + elif n.name.startswith("$seq"): + op = n.name[len("$seq"):] + ref = self.import_name_from_module(op, "__builtins__.sequence") + value = ResolvedNameRef(n.name, ref) + self.set_special(n.name, value) + return value + # Special case for print operations. elif n.name.startswith("$print"): diff -r 1b1c1664e774 -r 4bf5180fbfee lib/__builtins__/sequence.py --- a/lib/__builtins__/sequence.py Mon Jul 02 17:53:15 2018 +0200 +++ b/lib/__builtins__/sequence.py Mon Jul 02 19:19:54 2018 +0200 @@ -3,7 +3,7 @@ """ Sequence operations. -Copyright (C) 2015, 2016, 2017 Paul Boddie +Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -267,4 +267,11 @@ else: return index +def _test_length(seq, length): + + "Helper function for asserting that 'seq' is of the given 'length'." + + if len(seq) != length: + raise ValueError, length + # vim: tabstop=4 expandtab shiftwidth=4 diff -r 1b1c1664e774 -r 4bf5180fbfee tests/tuple.py --- a/tests/tuple.py Mon Jul 02 17:53:15 2018 +0200 +++ b/tests/tuple.py Mon Jul 02 19:19:54 2018 +0200 @@ -23,3 +23,11 @@ print t[-5] # should raise an exception except IndexError, exc: print "t[-5]: failed with argument", exc.index + +a, b, c, d = l +print a, b, c, d # 1 2 3 "four" + +try: + a, b, c = l +except ValueError, exc: + print "a, b, c = l: failed with length", exc.value diff -r 1b1c1664e774 -r 4bf5180fbfee translator.py --- a/translator.py Mon Jul 02 17:53:15 2018 +0200 +++ b/translator.py Mon Jul 02 19:19:54 2018 +0200 @@ -1564,7 +1564,7 @@ # function names to references. elif n.name.startswith("$L") or n.name.startswith("$op") or \ - n.name.startswith("$print"): + n.name.startswith("$seq") or n.name.startswith("$print"): ref, paths = self.importer.get_module(self.name).special[n.name] return TrResolvedNameRef(n.name, ref)