summaryrefslogtreecommitdiffstats
path: root/Python/compile.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/compile.c')
-rw-r--r--Python/compile.c73
1 files changed, 9 insertions, 64 deletions
diff --git a/Python/compile.c b/Python/compile.c
index c78949d..490137f 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -761,6 +761,8 @@ opcode_stack_effect(int opcode, int oparg)
return -1;
case BREAK_LOOP:
return 0;
+ case SETUP_WITH:
+ return 7;
case WITH_CLEANUP:
return -1; /* XXX Sometimes more */
case STORE_LOCALS:
@@ -3085,85 +3087,31 @@ expr_constant(expr_ty e)
static int
compiler_with(struct compiler *c, stmt_ty s)
{
- static identifier enter_attr, exit_attr;
basicblock *block, *finally;
- identifier tmpvalue = NULL, tmpexit = NULL;
assert(s->kind == With_kind);
- if (!enter_attr) {
- enter_attr = PyUnicode_InternFromString("__enter__");
- if (!enter_attr)
- return 0;
- }
- if (!exit_attr) {
- exit_attr = PyUnicode_InternFromString("__exit__");
- if (!exit_attr)
- return 0;
- }
-
block = compiler_new_block(c);
finally = compiler_new_block(c);
if (!block || !finally)
return 0;
- if (s->v.With.optional_vars) {
- /* Create a temporary variable to hold context.__enter__().
- We need to do this rather than preserving it on the stack
- because SETUP_FINALLY remembers the stack level.
- We need to do the assignment *inside* the try/finally
- so that context.__exit__() is called when the assignment
- fails. But we need to call context.__enter__() *before*
- the try/finally so that if it fails we won't call
- context.__exit__().
- */
- tmpvalue = compiler_new_tmpname(c);
- if (tmpvalue == NULL)
- return 0;
- PyArena_AddPyObject(c->c_arena, tmpvalue);
- }
- tmpexit = compiler_new_tmpname(c);
- if (tmpexit == NULL)
- return 0;
- PyArena_AddPyObject(c->c_arena, tmpexit);
-
/* Evaluate EXPR */
VISIT(c, expr, s->v.With.context_expr);
+ ADDOP_JREL(c, SETUP_WITH, finally);
- /* Squirrel away context.__exit__ by stuffing it under context */
- ADDOP(c, DUP_TOP);
- ADDOP_O(c, LOAD_ATTR, exit_attr, names);
- if (!compiler_nameop(c, tmpexit, Store))
- return 0;
-
- /* Call context.__enter__() */
- ADDOP_O(c, LOAD_ATTR, enter_attr, names);
- ADDOP_I(c, CALL_FUNCTION, 0);
-
- if (s->v.With.optional_vars) {
- /* Store it in tmpvalue */
- if (!compiler_nameop(c, tmpvalue, Store))
- return 0;
- }
- else {
- /* Discard result from context.__enter__() */
- ADDOP(c, POP_TOP);
- }
-
- /* Start the try block */
- ADDOP_JREL(c, SETUP_FINALLY, finally);
-
+ /* SETUP_WITH pushes a finally block. */
compiler_use_next_block(c, block);
if (!compiler_push_fblock(c, FINALLY_TRY, block)) {
return 0;
}
if (s->v.With.optional_vars) {
- /* Bind saved result of context.__enter__() to VAR */
- if (!compiler_nameop(c, tmpvalue, Load) ||
- !compiler_nameop(c, tmpvalue, Del))
- return 0;
- VISIT(c, expr, s->v.With.optional_vars);
+ VISIT(c, expr, s->v.With.optional_vars);
+ }
+ else {
+ /* Discard result from context.__enter__() */
+ ADDOP(c, POP_TOP);
}
/* BLOCK code */
@@ -3181,9 +3129,6 @@ compiler_with(struct compiler *c, stmt_ty s)
/* Finally block starts; context.__exit__ is on the stack under
the exception or return information. Just issue our magic
opcode. */
- if (!compiler_nameop(c, tmpexit, Load) ||
- !compiler_nameop(c, tmpexit, Del))
- return 0;
ADDOP(c, WITH_CLEANUP);
/* Finally block ends. */