]> granicus.if.org Git - python/commitdiff
Allow 'continue' inside 'try' clause
authorJeremy Hylton <jeremy@alum.mit.edu>
Thu, 1 Feb 2001 22:48:12 +0000 (22:48 +0000)
committerJeremy Hylton <jeremy@alum.mit.edu>
Thu, 1 Feb 2001 22:48:12 +0000 (22:48 +0000)
SF patch 102989 by Thomas Wouters

Doc/ref/ref7.tex
Include/opcode.h
Lib/dis.py
Lib/test/output/test_exceptions
Lib/test/output/test_grammar
Lib/test/test_exceptions.py
Lib/test/test_grammar.py
Python/ceval.c
Python/compile.c

index d5db0a85f1abd60c96efd702386f8b85ef687e2a..b8fac0b81cfd08f6432bb0500ebdb54a1cb3c731 100644 (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}
index 89813ef0fa1e1d7b2845772169a1482c3a3aacb5..546ad08856079183b1123ebcdca9224888efcfe7 100644 (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     /* "" */
index 269304eefdaeaa9b3ca93e52c633ebd4874c83db..2dcecdb3bd26ffe1dfa66890c9f79a01e75f6614 100644 (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)   # ""
index 8ce0154b9d6137f445b7776b936369cdeebe5b6f..e1e146ab3610973be8dcbd15aeba1a22f49b7a71 100644 (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
index 172a597467f93f750a28dfccd4c8c4556c570be4..319177c22c72956a4957560d650a88e805bb0e09 100644 (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
index 73c2489022c2a82a8d59cf33df8beb568b15fc39..9f42659adc527da6c026f52ae93da8c47a4567c2 100644 (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
-'''
-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
index 6e0fe91b66dd9bc0740ebb4729c5e7a2d4a419be..b7af64a256259f9ac29781a8809a8e735f6874a6 100644 (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
index 8eaa8bdbf5050f32f00fcb8c063b751aa8bb865a..264ba30a759f37e2a2488aaa2a965ea2c4ec0b7d 100644 (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);
index 68f9e7f98c16fdf5e1795cc9bb3ec45a1d212124..3dae4c85d0cd0a939bfe8c1a1be01dc8268b3459 100644 (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,