# HG changeset patch # User Paul Boddie # Date 1548353549 -3600 # Node ID d2c64260113c9c96ab3e2ab1e5243a51f02cc83a # Parent d3a602461439eab5d14d27485bc1df18a92b1815 Fixed loop termination by using a dedicated exception instead of StopIteration. diff -r d3a602461439 -r d2c64260113c common.py --- a/common.py Thu Jan 24 18:28:15 2019 +0100 +++ b/common.py Thu Jan 24 19:12:29 2019 +0100 @@ -579,10 +579,14 @@ # = .next # try: # while True: - # ... = () - # ... - # except StopIteration: + # try: + # ... = () + # except StopIteration: + # raise LoopExit + # {n.body} + # except LoopExit: # {n.else_} + # pass compiler.ast.Assign( [compiler.ast.AssName(t2, "OP_ASSIGN")], @@ -592,15 +596,18 @@ compiler.ast.While( compiler.ast.Name("True"), compiler.ast.Stmt([ - compiler.ast.Assign( - [n.assign], - compiler.ast.CallFunc( - compiler.ast.Name(t2), - [] - )), + compiler.ast.TryExcept( + compiler.ast.Assign( + [n.assign], + compiler.ast.CallFunc( + compiler.ast.Name(t2), + [])), + [(compiler.ast.Name("StopIteration"), None, + compiler.ast.Raise(compiler.ast.Name("LoopExit")))], + None), n.body]), None), - [(compiler.ast.Name("StopIteration"), None, n.else_ or compiler.ast.Pass())], + [(compiler.ast.Name("LoopExit"), None, n.else_ or compiler.ast.Pass())], None) ]) diff -r d3a602461439 -r d2c64260113c lib/__builtins__/__init__.py --- a/lib/__builtins__/__init__.py Thu Jan 24 18:28:15 2019 +0100 +++ b/lib/__builtins__/__init__.py Thu Jan 24 19:12:29 2019 +0100 @@ -3,7 +3,7 @@ """ Simple built-in classes and functions. -Copyright (C) 2015, 2016, 2017 Paul Boddie +Copyright (C) 2015, 2016, 2017, 2019 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 @@ -35,6 +35,7 @@ IndentationError, IndexError, IOError, + LoopExit, KeyError, KeyboardInterrupt, NotImplementedError, diff -r d3a602461439 -r d2c64260113c lib/__builtins__/exception/__init__.py --- a/lib/__builtins__/exception/__init__.py Thu Jan 24 18:28:15 2019 +0100 +++ b/lib/__builtins__/exception/__init__.py Thu Jan 24 19:12:29 2019 +0100 @@ -3,7 +3,7 @@ """ Exception objects. -Copyright (C) 2015, 2016, 2017 Paul Boddie +Copyright (C) 2015, 2016, 2017, 2019 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 @@ -25,6 +25,7 @@ from __builtins__.exception.base import ( IndexError, + LoopExit, KeyError, NotImplementedError, RuntimeError, diff -r d3a602461439 -r d2c64260113c lib/__builtins__/exception/base.py --- a/lib/__builtins__/exception/base.py Thu Jan 24 18:28:15 2019 +0100 +++ b/lib/__builtins__/exception/base.py Thu Jan 24 19:12:29 2019 +0100 @@ -3,7 +3,7 @@ """ Base exception objects. See __builtins__.core for the core exceptions. -Copyright (C) 2015, 2016, 2018 Paul Boddie +Copyright (C) 2015, 2016, 2018, 2019 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 @@ -61,6 +61,12 @@ pass +class LoopExit(Exception): + + "An exception signalling the end of iteration in a loop." + + pass + class StopIteration(Exception): "An exception signalling the end of iteration." diff -r d3a602461439 -r d2c64260113c tests/for.py --- a/tests/for.py Thu Jan 24 18:28:15 2019 +0100 +++ b/tests/for.py Thu Jan 24 19:12:29 2019 +0100 @@ -1,5 +1,7 @@ l = [1, 2, 3] +# Test else clause. + for i in l: print i # 1 # 2 @@ -7,6 +9,8 @@ else: print 4 # 4 +# Test break versus else clause. + for i in l: print i # 1 # 2 @@ -14,3 +18,17 @@ break else: print 3 + +# Test StopIteration in loop. + +try: + for i in l: + print i # 1 + # 2 + if i == 2: + raise StopIteration + else: + print 3 + +except StopIteration: + print "stopped" # stopped