Commit 3faa52ec authored by Jeremy Hylton's avatar Jeremy Hylton

Allow 'continue' inside 'try' clause

SF patch 102989 by Thomas Wouters
parent 1bbc0483
......@@ -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
'''
ckmsg(s, "'continue' not supported inside 'try' clause")
s = '''\
while 1:
try:
if 1:
continue
finally:
pass
continue
'''
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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment