Lichen

Changeset

835:4bf5180fbfee
2018-07-02 Paul Boddie raw files shortlog changelog graph Added missing sequence length check when unpacking sequences.
common.py (file) inspector.py (file) lib/__builtins__/sequence.py (file) tests/tuple.py (file) translator.py (file)
     1.1 --- a/common.py	Mon Jul 02 17:53:15 2018 +0200
     1.2 +++ b/common.py	Mon Jul 02 19:19:54 2018 +0200
     1.3 @@ -4,7 +4,7 @@
     1.4  Common functions.
     1.5  
     1.6  Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013,
     1.7 -              2014, 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
     1.8 +              2014, 2015, 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
     1.9  
    1.10  This program is free software; you can redistribute it and/or modify it under
    1.11  the terms of the GNU General Public License as published by the Free Software
    1.12 @@ -433,7 +433,7 @@
    1.13          variable.
    1.14          """
    1.15  
    1.16 -        assignments = []
    1.17 +        statements = []
    1.18  
    1.19          # Employ existing names to access the sequence.
    1.20          # Literal sequences do not provide names of accessible objects.
    1.21 @@ -447,19 +447,25 @@
    1.22              temp = self.get_temporary_name()
    1.23              self.next_temporary()
    1.24  
    1.25 -            assignments.append(
    1.26 +            statements.append(
    1.27                  compiler.ast.Assign([compiler.ast.AssName(temp, "OP_ASSIGN")], expr)
    1.28                  )
    1.29  
    1.30 +        # Generate a test for the length of the expression object.
    1.31 +
    1.32 +        statements.append(compiler.ast.Discard(
    1.33 +            compiler.ast.CallFunc(compiler.ast.Name("$seq_test_length"),
    1.34 +                [compiler.ast.Name(temp), compiler.ast.Const(len(n.nodes))])))
    1.35 +
    1.36          # Assign the items to the target nodes.
    1.37  
    1.38          for i, node in enumerate(n.nodes):
    1.39 -            assignments.append(
    1.40 +            statements.append(
    1.41                  compiler.ast.Assign([node], compiler.ast.Subscript(
    1.42                      compiler.ast.Name(temp), "OP_APPLY", [compiler.ast.Const(i, str(i))]))
    1.43                  )
    1.44  
    1.45 -        return self.process_structure_node(compiler.ast.Stmt(assignments))
    1.46 +        return self.process_structure_node(compiler.ast.Stmt(statements))
    1.47  
    1.48      def process_literal_sequence_items(self, n, name_ref):
    1.49  
     2.1 --- a/inspector.py	Mon Jul 02 17:53:15 2018 +0200
     2.2 +++ b/inspector.py	Mon Jul 02 19:19:54 2018 +0200
     2.3 @@ -873,6 +873,15 @@
     2.4              self.set_special(n.name, value)
     2.5              return value
     2.6  
     2.7 +        # Special case for sequence length testing.
     2.8 +
     2.9 +        elif n.name.startswith("$seq"):
    2.10 +            op = n.name[len("$seq"):]
    2.11 +            ref = self.import_name_from_module(op, "__builtins__.sequence")
    2.12 +            value = ResolvedNameRef(n.name, ref)
    2.13 +            self.set_special(n.name, value)
    2.14 +            return value
    2.15 +
    2.16          # Special case for print operations.
    2.17  
    2.18          elif n.name.startswith("$print"):
     3.1 --- a/lib/__builtins__/sequence.py	Mon Jul 02 17:53:15 2018 +0200
     3.2 +++ b/lib/__builtins__/sequence.py	Mon Jul 02 19:19:54 2018 +0200
     3.3 @@ -3,7 +3,7 @@
     3.4  """
     3.5  Sequence operations.
     3.6  
     3.7 -Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
     3.8 +Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
     3.9  
    3.10  This program is free software; you can redistribute it and/or modify it under
    3.11  the terms of the GNU General Public License as published by the Free Software
    3.12 @@ -267,4 +267,11 @@
    3.13      else:
    3.14          return index
    3.15  
    3.16 +def _test_length(seq, length):
    3.17 +
    3.18 +    "Helper function for asserting that 'seq' is of the given 'length'."
    3.19 +
    3.20 +    if len(seq) != length:
    3.21 +        raise ValueError, length
    3.22 +
    3.23  # vim: tabstop=4 expandtab shiftwidth=4
     4.1 --- a/tests/tuple.py	Mon Jul 02 17:53:15 2018 +0200
     4.2 +++ b/tests/tuple.py	Mon Jul 02 19:19:54 2018 +0200
     4.3 @@ -23,3 +23,11 @@
     4.4      print t[-5]         # should raise an exception
     4.5  except IndexError, exc:
     4.6      print "t[-5]: failed with argument", exc.index
     4.7 +
     4.8 +a, b, c, d = l
     4.9 +print a, b, c, d        # 1 2 3 "four"
    4.10 +
    4.11 +try:
    4.12 +    a, b, c = l
    4.13 +except ValueError, exc:
    4.14 +    print "a, b, c = l: failed with length", exc.value
     5.1 --- a/translator.py	Mon Jul 02 17:53:15 2018 +0200
     5.2 +++ b/translator.py	Mon Jul 02 19:19:54 2018 +0200
     5.3 @@ -1564,7 +1564,7 @@
     5.4          # function names to references.
     5.5  
     5.6          elif n.name.startswith("$L") or n.name.startswith("$op") or \
     5.7 -             n.name.startswith("$print"):
     5.8 +             n.name.startswith("$seq") or n.name.startswith("$print"):
     5.9  
    5.10              ref, paths = self.importer.get_module(self.name).special[n.name]
    5.11              return TrResolvedNameRef(n.name, ref)