summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Grammar/Grammar3
-rw-r--r--Lib/test/test_exception_variations.py180
-rw-r--r--Misc/ACKS1
-rw-r--r--Python/ast.c112
-rw-r--r--Python/graminit.c24
5 files changed, 263 insertions, 57 deletions
diff --git a/Grammar/Grammar b/Grammar/Grammar
index d8106e9719..0239413dae 100644
--- a/Grammar/Grammar
+++ b/Grammar/Grammar
@@ -67,8 +67,7 @@ compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
while_stmt: 'while' test ':' suite ['else' ':' suite]
for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]
-try_stmt: ('try' ':' suite (except_clause ':' suite)+ #diagram:break
- ['else' ':' suite] | 'try' ':' suite 'finally' ':' suite)
+try_stmt: 'try' ':' suite ((except_clause ':' suite)+ ['else' ':' suite] ['finally' ':' suite] | 'finally' ':' suite)
# NB compile.c makes sure that the default except clause is last
except_clause: 'except' [test [',' test]]
suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
diff --git a/Lib/test/test_exception_variations.py b/Lib/test/test_exception_variations.py
new file mode 100644
index 0000000000..297a6c9ed5
--- /dev/null
+++ b/Lib/test/test_exception_variations.py
@@ -0,0 +1,180 @@
+
+from test.test_support import run_unittest
+import unittest
+
+class ExceptionTestCase(unittest.TestCase):
+ def test_try_except_else_finally(self):
+ hit_except = False
+ hit_else = False
+ hit_finally = False
+
+ try:
+ raise Exception, 'nyaa!'
+ except:
+ hit_except = True
+ else:
+ hit_else = True
+ finally:
+ hit_finally = True
+
+ self.assertTrue(hit_except)
+ self.assertTrue(hit_finally)
+ self.assertFalse(hit_else)
+
+ def test_try_except_else_finally_no_exception(self):
+ hit_except = False
+ hit_else = False
+ hit_finally = False
+
+ try:
+ pass
+ except:
+ hit_except = True
+ else:
+ hit_else = True
+ finally:
+ hit_finally = True
+
+ self.assertFalse(hit_except)
+ self.assertTrue(hit_finally)
+ self.assertTrue(hit_else)
+
+ def test_try_except_finally(self):
+ hit_except = False
+ hit_finally = False
+
+ try:
+ raise Exception, 'yarr!'
+ except:
+ hit_except = True
+ finally:
+ hit_finally = True
+
+ self.assertTrue(hit_except)
+ self.assertTrue(hit_finally)
+
+ def test_try_except_finally_no_exception(self):
+ hit_except = False
+ hit_finally = False
+
+ try:
+ pass
+ except:
+ hit_except = True
+ finally:
+ hit_finally = True
+
+ self.assertFalse(hit_except)
+ self.assertTrue(hit_finally)
+
+ def test_try_except(self):
+ hit_except = False
+
+ try:
+ raise Exception, 'ahoy!'
+ except:
+ hit_except = True
+
+ self.assertTrue(hit_except)
+
+ def test_try_except_no_exception(self):
+ hit_except = False
+
+ try:
+ pass
+ except:
+ hit_except = True
+
+ self.assertFalse(hit_except)
+
+ def test_try_except_else(self):
+ hit_except = False
+ hit_else = False
+
+ try:
+ raise Exception, 'foo!'
+ except:
+ hit_except = True
+ else:
+ hit_else = True
+
+ self.assertFalse(hit_else)
+ self.assertTrue(hit_except)
+
+ def test_try_except_else_no_exception(self):
+ hit_except = False
+ hit_else = False
+
+ try:
+ pass
+ except:
+ hit_except = True
+ else:
+ hit_else = True
+
+ self.assertFalse(hit_except)
+ self.assertTrue(hit_else)
+
+ def test_try_finally_no_exception(self):
+ hit_finally = False
+
+ try:
+ pass
+ finally:
+ hit_finally = True
+
+ self.assertTrue(hit_finally)
+
+ def test_nested(self):
+ hit_finally = False
+ hit_inner_except = False
+ hit_inner_finally = False
+
+ try:
+ try:
+ raise Exception, 'inner exception'
+ except:
+ hit_inner_except = True
+ finally:
+ hit_inner_finally = True
+ finally:
+ hit_finally = True
+
+ self.assertTrue(hit_inner_except)
+ self.assertTrue(hit_inner_finally)
+ self.assertTrue(hit_finally)
+
+ def test_nested_else(self):
+ hit_else = False
+ hit_finally = False
+ hit_except = False
+ hit_inner_except = False
+ hit_inner_else = False
+
+ try:
+ try:
+ pass
+ except:
+ hit_inner_except = True
+ else:
+ hit_inner_else = True
+
+ raise Exception, 'outer exception'
+ except:
+ hit_except = True
+ else:
+ hit_else = True
+ finally:
+ hit_finally = True
+
+ self.assertFalse(hit_inner_except)
+ self.assertTrue(hit_inner_else)
+ self.assertFalse(hit_else)
+ self.assertTrue(hit_finally)
+ self.assertTrue(hit_except)
+
+def test_main():
+ run_unittest(ExceptionTestCase)
+
+if __name__ == '__main__':
+ test_main()
diff --git a/Misc/ACKS b/Misc/ACKS
index a87cdd861a..ef26294c6a 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -357,6 +357,7 @@ Chris Lawrence
Christopher Lee
Inyeol Lee
John J. Lee
+Thomas Lee
Luc Lefebvre
Kip Lehman
Joerg Lehmann
diff --git a/Python/ast.c b/Python/ast.c
index 6585c8fa8f..e56d1651d6 100644
--- a/Python/ast.c
+++ b/Python/ast.c
@@ -2597,66 +2597,78 @@ ast_for_except_clause(struct compiling *c, const node *exc, node *body)
static stmt_ty
ast_for_try_stmt(struct compiling *c, const node *n)
{
+ const int nch = NCH(n);
+ int n_except = (nch - 3)/3;
+ asdl_seq *body, *orelse = NULL, *finally = NULL;
+
REQ(n, try_stmt);
- if (TYPE(CHILD(n, 3)) == NAME) {/* must be 'finally' */
- /* try_stmt: 'try' ':' suite 'finally' ':' suite) */
- asdl_seq *s1, *s2;
- s1 = ast_for_suite(c, CHILD(n, 2));
- if (!s1)
- return NULL;
- s2 = ast_for_suite(c, CHILD(n, 5));
- if (!s2) {
- return NULL;
- }
-
- return TryFinally(s1, s2, LINENO(n), c->c_arena);
- }
- else if (TYPE(CHILD(n, 3)) == except_clause) {
- /* try_stmt: ('try' ':' suite (except_clause ':' suite)+
- ['else' ':' suite]
- */
- asdl_seq *suite_seq1, *suite_seq2;
- asdl_seq *handlers;
- int i, has_else = 0, n_except = NCH(n) - 3;
- if (TYPE(CHILD(n, NCH(n) - 3)) == NAME) {
- has_else = 1;
- n_except -= 3;
- }
- n_except /= 3;
- handlers = asdl_seq_new(n_except, c->c_arena);
- if (!handlers)
- return NULL;
- for (i = 0; i < n_except; i++) {
- excepthandler_ty e = ast_for_except_clause(c,
- CHILD(n, 3 + i * 3),
- CHILD(n, 5 + i * 3));
- if (!e) {
+ body = ast_for_suite(c, CHILD(n, 2));
+ if (body == NULL)
+ return NULL;
+
+ if (TYPE(CHILD(n, nch - 3)) == NAME) {
+ if (strcmp(STR(CHILD(n, nch - 3)), "finally") == 0) {
+ if (nch >= 9 && TYPE(CHILD(n, nch - 6)) == NAME) {
+ /* we can assume it's an "else",
+ because nch >= 9 for try-else-finally and
+ it would otherwise have a type of except_clause */
+ orelse = ast_for_suite(c, CHILD(n, nch - 4));
+ if (orelse == NULL)
+ return NULL;
+ n_except--;
+ }
+
+ finally = ast_for_suite(c, CHILD(n, nch - 1));
+ if (finally == NULL)
return NULL;
- }
- asdl_seq_SET(handlers, i, e);
+ n_except--;
}
-
- suite_seq1 = ast_for_suite(c, CHILD(n, 2));
- if (!suite_seq1) {
- return NULL;
- }
- if (has_else) {
- suite_seq2 = ast_for_suite(c, CHILD(n, NCH(n) - 1));
- if (!suite_seq2) {
+ else {
+ /* we can assume it's an "else",
+ otherwise it would have a type of except_clause */
+ orelse = ast_for_suite(c, CHILD(n, nch - 1));
+ if (orelse == NULL)
return NULL;
- }
+ n_except--;
}
- else
- suite_seq2 = NULL;
-
- return TryExcept(suite_seq1, handlers, suite_seq2, LINENO(n),
- c->c_arena);
}
- else {
+ else if (TYPE(CHILD(n, nch - 3)) != except_clause) {
ast_error(n, "malformed 'try' statement");
return NULL;
}
+
+ if (n_except > 0) {
+ int i;
+ stmt_ty except_st;
+ /* process except statements to create a try ... except */
+ asdl_seq *handlers = asdl_seq_new(n_except, c->c_arena);
+ if (handlers == NULL)
+ return NULL;
+
+ for (i = 0; i < n_except; i++) {
+ excepthandler_ty e = ast_for_except_clause(c, CHILD(n, 3 + i * 3),
+ CHILD(n, 5 + i * 3));
+ if (!e)
+ return NULL;
+ asdl_seq_SET(handlers, i, e);
+ }
+
+ except_st = TryExcept(body, handlers, orelse, LINENO(n), c->c_arena);
+ if (!finally)
+ return except_st;
+
+ /* if a 'finally' is present too, we nest the TryExcept within a
+ TryFinally to emulate try ... except ... finally */
+ body = asdl_seq_new(1, c->c_arena);
+ if (body == NULL)
+ return NULL;
+ asdl_seq_SET(body, 0, except_st);
+ }
+
+ /* must be a try ... finally (except clauses are in body, if any exist) */
+ assert(finally != NULL);
+ return TryFinally(body, finally, LINENO(n), c->c_arena);
}
static stmt_ty
diff --git a/Python/graminit.c b/Python/graminit.c
index 769532a16b..a5bf3a491b 100644
--- a/Python/graminit.c
+++ b/Python/graminit.c
@@ -841,15 +841,26 @@ static arc arcs_39_6[1] = {
static arc arcs_39_7[1] = {
{22, 9},
};
-static arc arcs_39_8[3] = {
+static arc arcs_39_8[4] = {
{95, 4},
- {91, 5},
+ {91, 10},
+ {96, 5},
{0, 8},
};
static arc arcs_39_9[1] = {
{0, 9},
};
-static state states_39[10] = {
+static arc arcs_39_10[1] = {
+ {21, 11},
+};
+static arc arcs_39_11[1] = {
+ {22, 12},
+};
+static arc arcs_39_12[2] = {
+ {96, 5},
+ {0, 12},
+};
+static state states_39[13] = {
{1, arcs_39_0},
{1, arcs_39_1},
{1, arcs_39_2},
@@ -858,8 +869,11 @@ static state states_39[10] = {
{1, arcs_39_5},
{1, arcs_39_6},
{1, arcs_39_7},
- {3, arcs_39_8},
+ {4, arcs_39_8},
{1, arcs_39_9},
+ {1, arcs_39_10},
+ {1, arcs_39_11},
+ {2, arcs_39_12},
};
static arc arcs_40_0[1] = {
{97, 1},
@@ -1754,7 +1768,7 @@ static dfa dfas[79] = {
"\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000"},
{294, "for_stmt", 0, 10, states_38,
"\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\000"},
- {295, "try_stmt", 0, 10, states_39,
+ {295, "try_stmt", 0, 13, states_39,
"\000\000\000\000\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\000\000"},
{296, "except_clause", 0, 5, states_40,
"\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000"},