Allow 'continue' inside 'try' clause

SF patch 102989 by Thomas Wouters
This commit is contained in:
Jeremy Hylton 2001-02-01 22:48:12 +00:00
parent 1bbc048310
commit 3faa52ecc4
9 changed files with 74 additions and 45 deletions

View File

@ -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}

View File

@ -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 /* "" */

View File

@ -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) # ""

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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,