mirror of https://github.com/python/cpython
Allow 'continue' inside 'try' clause
SF patch 102989 by Thomas Wouters
This commit is contained in:
parent
1bbc048310
commit
3faa52ecc4
|
@ -260,17 +260,19 @@ The \keyword{try}...\keyword{finally} form specifies a `cleanup' handler. The
|
|||
\keyword{try} clause, the exception is temporarily saved, the
|
||||
\keyword{finally} clause is executed, and then the saved exception is
|
||||
re-raised. If the \keyword{finally} clause raises another exception or
|
||||
executes a \keyword{return}, \keyword{break} or \keyword{continue} statement,
|
||||
the saved exception is lost. The exception information is not
|
||||
available to the program during execution of the \keyword{finally}
|
||||
clause.
|
||||
executes a \keyword{return} or \keyword{break} statement, the saved
|
||||
exception is lost. A \keyword{continue} statement is illegal in the
|
||||
\keyword{finally} clause. (The reason is a problem with the current
|
||||
implementation -- thsi restriction may be lifted in the future). The
|
||||
exception information is not available to the program during execution of
|
||||
the \keyword{finally} clause.
|
||||
\kwindex{finally}
|
||||
|
||||
When a \keyword{return} or \keyword{break} statement is executed in the
|
||||
\keyword{try} suite of a \keyword{try}...\keyword{finally} statement, the
|
||||
\keyword{finally} clause is also executed `on the way out.' A
|
||||
\keyword{continue} statement is illegal in the \keyword{try} clause. (The
|
||||
reason is a problem with the current implementation --- this
|
||||
When a \keyword{return}, \keyword{break} or \keyword{continue} statement is
|
||||
executed in the \keyword{try} suite of a \keyword{try}...\keyword{finally}
|
||||
statement, the \keyword{finally} clause is also executed `on the way out.' A
|
||||
\keyword{continue} statement is illegal in the \keyword{finally} clause.
|
||||
(The reason is a problem with the current implementation --- this
|
||||
restriction may be lifted in the future).
|
||||
\stindex{return}
|
||||
\stindex{break}
|
||||
|
|
|
@ -104,6 +104,7 @@ extern "C" {
|
|||
|
||||
#define LOAD_GLOBAL 116 /* Index in name list */
|
||||
|
||||
#define CONTINUE_LOOP 119 /* Start of loop (absolute) */
|
||||
#define SETUP_LOOP 120 /* Target address (absolute) */
|
||||
#define SETUP_EXCEPT 121 /* "" */
|
||||
#define SETUP_FINALLY 122 /* "" */
|
||||
|
|
|
@ -259,6 +259,7 @@ jrel_op('FOR_LOOP', 114) # Number of bytes to skip
|
|||
|
||||
name_op('LOAD_GLOBAL', 116) # Index in name list
|
||||
|
||||
jabs_op('CONTINUE_LOOP', 119) # Target address
|
||||
jrel_op('SETUP_LOOP', 120) # Distance to target address
|
||||
jrel_op('SETUP_EXCEPT', 121) # ""
|
||||
jrel_op('SETUP_FINALLY', 122) # ""
|
||||
|
|
|
@ -27,11 +27,7 @@ RuntimeError
|
|||
(not used any more?)
|
||||
spam
|
||||
SyntaxError
|
||||
'continue' not supported inside 'try' clause
|
||||
ok
|
||||
'continue' not supported inside 'try' clause
|
||||
ok
|
||||
'continue' not supported inside 'try' clause
|
||||
'continue' not supported inside 'finally' clause
|
||||
ok
|
||||
'continue' not properly in loop
|
||||
ok
|
||||
|
|
|
@ -33,6 +33,8 @@ pass_stmt
|
|||
flow_stmt
|
||||
break_stmt
|
||||
continue_stmt
|
||||
continue + try/except ok
|
||||
continue + try/finally ok
|
||||
return_stmt
|
||||
raise_stmt
|
||||
import_stmt
|
||||
|
|
|
@ -104,28 +104,11 @@ def ckmsg(src, msg):
|
|||
s = '''\
|
||||
while 1:
|
||||
try:
|
||||
continue
|
||||
except:
|
||||
pass
|
||||
'''
|
||||
ckmsg(s, "'continue' not supported inside 'try' clause")
|
||||
s = '''\
|
||||
while 1:
|
||||
try:
|
||||
continue
|
||||
finally:
|
||||
pass
|
||||
continue
|
||||
'''
|
||||
ckmsg(s, "'continue' not supported inside 'try' clause")
|
||||
s = '''\
|
||||
while 1:
|
||||
try:
|
||||
if 1:
|
||||
continue
|
||||
finally:
|
||||
pass
|
||||
'''
|
||||
ckmsg(s, "'continue' not supported inside 'try' clause")
|
||||
ckmsg(s, "'continue' not supported inside 'finally' clause")
|
||||
s = '''\
|
||||
try:
|
||||
continue
|
||||
|
|
|
@ -349,6 +349,25 @@ print 'continue_stmt' # 'continue'
|
|||
i = 1
|
||||
while i: i = 0; continue
|
||||
|
||||
msg = ""
|
||||
while not msg:
|
||||
msg = "continue + try/except ok"
|
||||
try:
|
||||
continue
|
||||
msg = "continue failed to continue inside try"
|
||||
except:
|
||||
msg = "continue inside try called except block"
|
||||
print msg
|
||||
|
||||
msg = ""
|
||||
while not msg:
|
||||
msg = "finally block not called"
|
||||
try:
|
||||
continue
|
||||
finally:
|
||||
msg = "continue + try/finally ok"
|
||||
print msg
|
||||
|
||||
print 'return_stmt' # 'return' [testlist]
|
||||
def g1(): return
|
||||
def g2(): return 1
|
||||
|
|
|
@ -322,7 +322,8 @@ enum why_code {
|
|||
WHY_EXCEPTION, /* Exception occurred */
|
||||
WHY_RERAISE, /* Exception re-raised by 'finally' */
|
||||
WHY_RETURN, /* 'return' statement */
|
||||
WHY_BREAK /* 'break' statement */
|
||||
WHY_BREAK, /* 'break' statement */
|
||||
WHY_CONTINUE, /* 'continue' statement */
|
||||
};
|
||||
|
||||
static enum why_code do_raise(PyObject *, PyObject *, PyObject *);
|
||||
|
@ -1357,6 +1358,11 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
|||
case BREAK_LOOP:
|
||||
why = WHY_BREAK;
|
||||
break;
|
||||
|
||||
case CONTINUE_LOOP:
|
||||
retval = PyInt_FromLong(oparg);
|
||||
why = WHY_CONTINUE;
|
||||
break;
|
||||
|
||||
case RAISE_VARARGS:
|
||||
u = v = w = NULL;
|
||||
|
@ -1419,7 +1425,8 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
|||
v = POP();
|
||||
if (PyInt_Check(v)) {
|
||||
why = (enum why_code) PyInt_AsLong(v);
|
||||
if (why == WHY_RETURN)
|
||||
if (why == WHY_RETURN ||
|
||||
why == CONTINUE_LOOP)
|
||||
retval = POP();
|
||||
}
|
||||
else if (PyString_Check(v) || PyClass_Check(v)) {
|
||||
|
@ -1834,7 +1841,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
|||
case SETUP_EXCEPT:
|
||||
case SETUP_FINALLY:
|
||||
PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg,
|
||||
STACK_LEVEL());
|
||||
STACK_LEVEL());
|
||||
continue;
|
||||
|
||||
case SET_LINENO:
|
||||
|
@ -2110,6 +2117,18 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
|||
|
||||
while (why != WHY_NOT && f->f_iblock > 0) {
|
||||
PyTryBlock *b = PyFrame_BlockPop(f);
|
||||
|
||||
if (b->b_type == SETUP_LOOP && why == WHY_CONTINUE) {
|
||||
/* For a continue inside a try block,
|
||||
don't pop the block for the loop. */
|
||||
PyFrame_BlockSetup(f, b->b_type, b->b_level,
|
||||
b->b_handler);
|
||||
why = WHY_NOT;
|
||||
JUMPTO(PyInt_AS_LONG(retval));
|
||||
Py_DECREF(retval);
|
||||
break;
|
||||
}
|
||||
|
||||
while (STACK_LEVEL() > b->b_level) {
|
||||
v = POP();
|
||||
Py_XDECREF(v);
|
||||
|
@ -2145,7 +2164,8 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
|||
PUSH(exc);
|
||||
}
|
||||
else {
|
||||
if (why == WHY_RETURN)
|
||||
if (why == WHY_RETURN ||
|
||||
why == CONTINUE_LOOP)
|
||||
PUSH(retval);
|
||||
v = PyInt_FromLong((long)why);
|
||||
PUSH(v);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
XXX add __doc__ attribute == co_doc to code object attributes?
|
||||
XXX (it's currently the first item of the co_const tuple)
|
||||
XXX Generate simple jump for break/return outside 'try...finally'
|
||||
XXX Allow 'continue' inside try-finally
|
||||
XXX Allow 'continue' inside finally clause of try-finally
|
||||
XXX New opcode for loading the initial index for a for loop
|
||||
XXX other JAR tricks?
|
||||
*/
|
||||
|
@ -3247,19 +3247,24 @@ com_continue_stmt(struct compiling *c, node *n)
|
|||
}
|
||||
else {
|
||||
int j;
|
||||
for (j = 0; j <= i; ++j) {
|
||||
for (j = i-1; j >= 0; --j) {
|
||||
if (c->c_block[j] == SETUP_LOOP)
|
||||
break;
|
||||
}
|
||||
if (j < i+1) {
|
||||
if (j >= 0) {
|
||||
/* there is a loop, but something interferes */
|
||||
for (++j; j <= i; ++j) {
|
||||
if (c->c_block[i] == SETUP_EXCEPT
|
||||
|| c->c_block[i] == SETUP_FINALLY) {
|
||||
com_error(c, PyExc_SyntaxError,
|
||||
"'continue' not supported inside 'try' clause");
|
||||
for (; i > j; --i) {
|
||||
if (c->c_block[i] == SETUP_EXCEPT ||
|
||||
c->c_block[i] == SETUP_FINALLY) {
|
||||
com_addoparg(c, CONTINUE_LOOP,
|
||||
c->c_begin);
|
||||
return;
|
||||
}
|
||||
if (c->c_block[i] == END_FINALLY) {
|
||||
com_error(c, PyExc_SyntaxError,
|
||||
"'continue' not supported inside 'finally' clause");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
com_error(c, PyExc_SyntaxError,
|
||||
|
|
Loading…
Reference in New Issue