Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3faa52e

Browse files
committed
Allow 'continue' inside 'try' clause
SF patch 102989 by Thomas Wouters
1 parent 1bbc048 commit 3faa52e

9 files changed

Lines changed: 74 additions & 45 deletions

File tree

Doc/ref/ref7.tex

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -260,17 +260,19 @@ \section{The \keyword{try} statement\label{try}}
260260
\keyword{try} clause, the exception is temporarily saved, the
261261
\keyword{finally} clause is executed, and then the saved exception is
262262
re-raised. If the \keyword{finally} clause raises another exception or
263-
executes a \keyword{return}, \keyword{break} or \keyword{continue} statement,
264-
the saved exception is lost. The exception information is not
265-
available to the program during execution of the \keyword{finally}
266-
clause.
263+
executes a \keyword{return} or \keyword{break} statement, the saved
264+
exception is lost. A \keyword{continue} statement is illegal in the
265+
\keyword{finally} clause. (The reason is a problem with the current
266+
implementation -- thsi restriction may be lifted in the future). The
267+
exception information is not available to the program during execution of
268+
the \keyword{finally} clause.
267269
\kwindex{finally}
268270

269-
When a \keyword{return} or \keyword{break} statement is executed in the
270-
\keyword{try} suite of a \keyword{try}...\keyword{finally} statement, the
271-
\keyword{finally} clause is also executed `on the way out.' A
272-
\keyword{continue} statement is illegal in the \keyword{try} clause. (The
273-
reason is a problem with the current implementation --- this
271+
When a \keyword{return}, \keyword{break} or \keyword{continue} statement is
272+
executed in the \keyword{try} suite of a \keyword{try}...\keyword{finally}
273+
statement, the \keyword{finally} clause is also executed `on the way out.' A
274+
\keyword{continue} statement is illegal in the \keyword{finally} clause.
275+
(The reason is a problem with the current implementation --- this
274276
restriction may be lifted in the future).
275277
\stindex{return}
276278
\stindex{break}

Include/opcode.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ extern "C" {
104104

105105
#define LOAD_GLOBAL 116 /* Index in name list */
106106

107+
#define CONTINUE_LOOP 119 /* Start of loop (absolute) */
107108
#define SETUP_LOOP 120 /* Target address (absolute) */
108109
#define SETUP_EXCEPT 121 /* "" */
109110
#define SETUP_FINALLY 122 /* "" */

Lib/dis.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ def jabs_op(name, op):
259259

260260
name_op('LOAD_GLOBAL', 116) # Index in name list
261261

262+
jabs_op('CONTINUE_LOOP', 119) # Target address
262263
jrel_op('SETUP_LOOP', 120) # Distance to target address
263264
jrel_op('SETUP_EXCEPT', 121) # ""
264265
jrel_op('SETUP_FINALLY', 122) # ""

Lib/test/output/test_exceptions

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,7 @@ RuntimeError
2727
(not used any more?)
2828
spam
2929
SyntaxError
30-
'continue' not supported inside 'try' clause
31-
ok
32-
'continue' not supported inside 'try' clause
33-
ok
34-
'continue' not supported inside 'try' clause
30+
'continue' not supported inside 'finally' clause
3531
ok
3632
'continue' not properly in loop
3733
ok

Lib/test/output/test_grammar

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ pass_stmt
3333
flow_stmt
3434
break_stmt
3535
continue_stmt
36+
continue + try/except ok
37+
continue + try/finally ok
3638
return_stmt
3739
raise_stmt
3840
import_stmt

Lib/test/test_exceptions.py

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -104,28 +104,11 @@ def ckmsg(src, msg):
104104
s = '''\
105105
while 1:
106106
try:
107-
continue
108-
except:
109-
pass
110-
'''
111-
ckmsg(s, "'continue' not supported inside 'try' clause")
112-
s = '''\
113-
while 1:
114-
try:
115-
continue
116-
finally:
117107
pass
118-
'''
119-
ckmsg(s, "'continue' not supported inside 'try' clause")
120-
s = '''\
121-
while 1:
122-
try:
123-
if 1:
124-
continue
125108
finally:
126-
pass
109+
continue
127110
'''
128-
ckmsg(s, "'continue' not supported inside 'try' clause")
111+
ckmsg(s, "'continue' not supported inside 'finally' clause")
129112
s = '''\
130113
try:
131114
continue

Lib/test/test_grammar.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,25 @@ def tellme(file=None):
349349
i = 1
350350
while i: i = 0; continue
351351

352+
msg = ""
353+
while not msg:
354+
msg = "continue + try/except ok"
355+
try:
356+
continue
357+
msg = "continue failed to continue inside try"
358+
except:
359+
msg = "continue inside try called except block"
360+
print msg
361+
362+
msg = ""
363+
while not msg:
364+
msg = "finally block not called"
365+
try:
366+
continue
367+
finally:
368+
msg = "continue + try/finally ok"
369+
print msg
370+
352371
print 'return_stmt' # 'return' [testlist]
353372
def g1(): return
354373
def g2(): return 1

Python/ceval.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,8 @@ enum why_code {
322322
WHY_EXCEPTION, /* Exception occurred */
323323
WHY_RERAISE, /* Exception re-raised by 'finally' */
324324
WHY_RETURN, /* 'return' statement */
325-
WHY_BREAK /* 'break' statement */
325+
WHY_BREAK, /* 'break' statement */
326+
WHY_CONTINUE, /* 'continue' statement */
326327
};
327328

328329
static enum why_code do_raise(PyObject *, PyObject *, PyObject *);
@@ -1357,6 +1358,11 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
13571358
case BREAK_LOOP:
13581359
why = WHY_BREAK;
13591360
break;
1361+
1362+
case CONTINUE_LOOP:
1363+
retval = PyInt_FromLong(oparg);
1364+
why = WHY_CONTINUE;
1365+
break;
13601366

13611367
case RAISE_VARARGS:
13621368
u = v = w = NULL;
@@ -1419,7 +1425,8 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
14191425
v = POP();
14201426
if (PyInt_Check(v)) {
14211427
why = (enum why_code) PyInt_AsLong(v);
1422-
if (why == WHY_RETURN)
1428+
if (why == WHY_RETURN ||
1429+
why == CONTINUE_LOOP)
14231430
retval = POP();
14241431
}
14251432
else if (PyString_Check(v) || PyClass_Check(v)) {
@@ -1834,7 +1841,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
18341841
case SETUP_EXCEPT:
18351842
case SETUP_FINALLY:
18361843
PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg,
1837-
STACK_LEVEL());
1844+
STACK_LEVEL());
18381845
continue;
18391846

18401847
case SET_LINENO:
@@ -2110,6 +2117,18 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
21102117

21112118
while (why != WHY_NOT && f->f_iblock > 0) {
21122119
PyTryBlock *b = PyFrame_BlockPop(f);
2120+
2121+
if (b->b_type == SETUP_LOOP && why == WHY_CONTINUE) {
2122+
/* For a continue inside a try block,
2123+
don't pop the block for the loop. */
2124+
PyFrame_BlockSetup(f, b->b_type, b->b_level,
2125+
b->b_handler);
2126+
why = WHY_NOT;
2127+
JUMPTO(PyInt_AS_LONG(retval));
2128+
Py_DECREF(retval);
2129+
break;
2130+
}
2131+
21132132
while (STACK_LEVEL() > b->b_level) {
21142133
v = POP();
21152134
Py_XDECREF(v);
@@ -2145,7 +2164,8 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
21452164
PUSH(exc);
21462165
}
21472166
else {
2148-
if (why == WHY_RETURN)
2167+
if (why == WHY_RETURN ||
2168+
why == CONTINUE_LOOP)
21492169
PUSH(retval);
21502170
v = PyInt_FromLong((long)why);
21512171
PUSH(v);

Python/compile.c

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
XXX add __doc__ attribute == co_doc to code object attributes?
66
XXX (it's currently the first item of the co_const tuple)
77
XXX Generate simple jump for break/return outside 'try...finally'
8-
XXX Allow 'continue' inside try-finally
8+
XXX Allow 'continue' inside finally clause of try-finally
99
XXX New opcode for loading the initial index for a for loop
1010
XXX other JAR tricks?
1111
*/
@@ -3247,19 +3247,24 @@ com_continue_stmt(struct compiling *c, node *n)
32473247
}
32483248
else {
32493249
int j;
3250-
for (j = 0; j <= i; ++j) {
3250+
for (j = i-1; j >= 0; --j) {
32513251
if (c->c_block[j] == SETUP_LOOP)
32523252
break;
32533253
}
3254-
if (j < i+1) {
3254+
if (j >= 0) {
32553255
/* there is a loop, but something interferes */
3256-
for (++j; j <= i; ++j) {
3257-
if (c->c_block[i] == SETUP_EXCEPT
3258-
|| c->c_block[i] == SETUP_FINALLY) {
3259-
com_error(c, PyExc_SyntaxError,
3260-
"'continue' not supported inside 'try' clause");
3256+
for (; i > j; --i) {
3257+
if (c->c_block[i] == SETUP_EXCEPT ||
3258+
c->c_block[i] == SETUP_FINALLY) {
3259+
com_addoparg(c, CONTINUE_LOOP,
3260+
c->c_begin);
32613261
return;
32623262
}
3263+
if (c->c_block[i] == END_FINALLY) {
3264+
com_error(c, PyExc_SyntaxError,
3265+
"'continue' not supported inside 'finally' clause");
3266+
return;
3267+
}
32633268
}
32643269
}
32653270
com_error(c, PyExc_SyntaxError,

0 commit comments

Comments
 (0)