default: PyErr_SetString(PyExc_SystemError, "param invalid for global variable"); return 0; } break; case OP_NAME: switch (ctx) { case Load: op = LOAD_NAME; break; case Store: op = STORE_NAME; break; case Del: op = DELETE_NAME; break; case AugLoad: case AugStore: break; case Param: default: PyErr_SetString(PyExc_SystemError, "param invalid for name variable"); return 0; } break; } assert(op); arg = compiler_add_o(c, dict, mangled); Py_DECREF(mangled); if (arg < 0) return 0; return compiler_addop_i(c, op, arg);} static intcompiler_boolop(struct compiler *c, expr_ty e){ basicblock *end; int jumpi, i, n; asdl_seq *s; assert(e->kind == BoolOp_kind); if (e->v.BoolOp.op == And) jumpi = JUMP_IF_FALSE; else jumpi = JUMP_IF_TRUE; end = compiler_new_block(c); if (end == NULL) return 0; s = e->v.BoolOp.values; n = asdl_seq_LEN(s) - 1; assert(n >= 0); for (i = 0; i < n; ++i) { VISIT(c, expr, (expr_ty)asdl_seq_GET(s, i)); ADDOP_JREL(c, jumpi, end); ADDOP(c, POP_TOP) } VISIT(c, expr, (expr_ty)asdl_seq_GET(s, n)); compiler_use_next_block(c, end); return 1;} static intcompiler_list(struct compiler *c, expr_ty e){ int n = asdl_seq_LEN(e->v.List.elts); if (e->v.List.ctx == Store) { ADDOP_I(c, UNPACK_SEQUENCE, n); } VISIT_SEQ(c, expr, e->v.List.elts); if (e->v.List.ctx == Load) { ADDOP_I(c, BUILD_LIST, n); } return 1;} static intcompiler_tuple(struct compiler *c, expr_ty e){ int n = asdl_seq_LEN(e->v.Tuple.elts); if (e->v.Tuple.ctx == Store) { ADDOP_I(c, UNPACK_SEQUENCE, n); } VISIT_SEQ(c, expr, e->v.Tuple.elts); if (e->v.Tuple.ctx == Load) { ADDOP_I(c, BUILD_TUPLE, n); } return 1;} static intcompiler_compare(struct compiler *c, expr_ty e){ int i, n; basicblock *cleanup = NULL; /* XXX the logic can be cleaned up for 1 or multiple comparisons */ VISIT(c, expr, e->v.Compare.left); n = asdl_seq_LEN(e->v.Compare.ops); assert(n > 0); if (n > 1) { cleanup = compiler_new_block(c); if (cleanup == NULL) return 0; VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, 0)); } for (i = 1; i < n; i++) { ADDOP(c, DUP_TOP); ADDOP(c, ROT_THREE); ADDOP_I(c, COMPARE_OP, cmpop((cmpop_ty)(asdl_seq_GET( e->v.Compare.ops, i - 1)))); ADDOP_JREL(c, JUMP_IF_FALSE, cleanup); NEXT_BLOCK(c); ADDOP(c, POP_TOP); if (i < (n - 1)) VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); } VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n - 1)); ADDOP_I(c, COMPARE_OP, cmpop((cmpop_ty)(asdl_seq_GET(e->v.Compare.ops, n - 1)))); if (n > 1) { basicblock *end = compiler_new_block(c); if (end == NULL) return 0; ADDOP_JREL(c, JUMP_FORWARD, end); compiler_use_next_block(c, cleanup); ADDOP(c, ROT_TWO); ADDOP(c, POP_TOP); compiler_use_next_block(c, end); } return 1;}#undef CMPCAST static intcompiler_call(struct compiler *c, expr_ty e){ int n, code = 0; VISIT(c, expr, e->v.Call.func); n = asdl_seq_LEN(e->v.Call.args); VISIT_SEQ(c, expr, e->v.Call.args); if (e->v.Call.keywords) { VISIT_SEQ(c, keyword, e->v.Call.keywords); n |= asdl_seq_LEN(e->v.Call.keywords) << 8; } if (e->v.Call.starargs) { VISIT(c, expr, e->v.Call.starargs); code |= 1; } if (e->v.Call.kwargs) { VISIT(c, expr, e->v.Call.kwargs); code |= 2; } switch (code) { case 0: ADDOP_I(c, CALL_FUNCTION, n); break; case 1: ADDOP_I(c, CALL_FUNCTION_VAR, n); break; case 2: ADDOP_I(c, CALL_FUNCTION_KW, n); break; case 3: ADDOP_I(c, CALL_FUNCTION_VAR_KW, n); break; } return 1;} static intcompiler_listcomp_generator(struct compiler *c, PyObject *tmpname, asdl_seq *generators, int gen_index, expr_ty elt){ /* generate code for the iterator, then each of the ifs, and then write to the element */ comprehension_ty l; basicblock *start, *anchor, *skip, *if_cleanup; int i, n; start = compiler_new_block(c); skip = compiler_new_block(c); if_cleanup = compiler_new_block(c); anchor = compiler_new_block(c); if (start == NULL || skip == NULL || if_cleanup == NULL || anchor == NULL) return 0; l = (comprehension_ty)asdl_seq_GET(generators, gen_index); VISIT(c, expr, l->iter); ADDOP(c, GET_ITER); compiler_use_next_block(c, start); ADDOP_JREL(c, FOR_ITER, anchor); NEXT_BLOCK(c); VISIT(c, expr, l->target); /* XXX this needs to be cleaned up...a lot! */ n = asdl_seq_LEN(l->ifs); for (i = 0; i < n; i++) { expr_ty e = (expr_ty)asdl_seq_GET(l->ifs, i); VISIT(c, expr, e); ADDOP_JREL(c, JUMP_IF_FALSE, if_cleanup); NEXT_BLOCK(c); ADDOP(c, POP_TOP); } if (++gen_index < asdl_seq_LEN(generators)) if (!compiler_listcomp_generator(c, tmpname, generators, gen_index, elt)) return 0; /* only append after the last for generator */ if (gen_index >= asdl_seq_LEN(generators)) { if (!compiler_nameop(c, tmpname, Load)) return 0; VISIT(c, expr, elt); ADDOP(c, LIST_APPEND); compiler_use_next_block(c, skip); } for (i = 0; i < n; i++) { ADDOP_I(c, JUMP_FORWARD, 1); if (i == 0) compiler_use_next_block(c, if_cleanup); ADDOP(c, POP_TOP); } ADDOP_JABS(c, JUMP_ABSOLUTE, start); compiler_use_next_block(c, anchor); /* delete the append method added to locals */ if (gen_index == 1) if (!compiler_nameop(c, tmpname, Del)) return 0; return 1;} static intcompiler_listcomp(struct compiler *c, expr_ty e){ identifier tmp; int rc = 0; static identifier append; asdl_seq *generators = e->v.ListComp.generators; assert(e->kind == ListComp_kind); if (!append) { append = PyString_InternFromString("append"); if (!append) return 0; } tmp = compiler_new_tmpname(c); if (!tmp) return 0; ADDOP_I(c, BUILD_LIST, 0); ADDOP(c, DUP_TOP); if (compiler_nameop(c, tmp, Store)) rc = compiler_listcomp_generator(c, tmp, generators, 0, e->v.ListComp.elt); Py_DECREF(tmp); return rc;} static intcompiler_genexp_generator(struct compiler *c, asdl_seq *generators, int gen_index, expr_ty elt){ /* generate code for the iterator, then each of the ifs, and then write to the element */ comprehension_ty ge; basicblock *start, *anchor, *skip, *if_cleanup, *end; int i, n; start = compiler_new_block(c); skip = compiler_new_block(c); if_cleanup = compiler_new_block(c); anchor = compiler_new_block(c); end = compiler_new_block(c); if (start == NULL || skip == NULL || if_cleanup == NULL || anchor == NULL || end == NULL) return 0; ge = (comprehension_ty)asdl_seq_GET(generators, gen_index); ADDOP_JREL(c, SETUP_LOOP, end); if (!compiler_push_fblock(c, LOOP, start)) return 0; if (gen_index == 0) { /* Receive outermost iter as an implicit argument */ c->u->u_argcount = 1; ADDOP_I(c, LOAD_FAST, 0); } else { /* Sub-iter - calculate on the fly */ VISIT(c, expr, ge->iter); ADDOP(c, GET_ITER); } compiler_use_next_block(c, start); ADDOP_JREL(c, FOR_ITER, anchor); NEXT_BLOCK(c); VISIT(c, expr, ge->target); /* XXX this needs to be cleaned up...a lot! */ n = asdl_seq_LEN(ge->ifs); for (i = 0; i < n; i++) { expr_ty e = (expr_ty)asdl_seq_GET(ge->ifs, i); VISIT(c, expr, e); ADDOP_JREL(c, JUMP_IF_FALSE, if_cleanup); NEXT_BLOCK(c); ADDOP(c, POP_TOP); } if (++gen_index < asdl_seq_LEN(generators)) if (!compiler_genexp_generator(c, generators, gen_index, elt)) return 0; /* only append after the last 'for' generator */ if (gen_index >= asdl_seq_LEN(generators)) { VISIT(c, expr, elt); ADDOP(c, YIELD_VALUE); ADDOP(c, POP_TOP); compiler_use_next_block(c, skip); } for (i = 0; i < n; i++) { ADDOP_I(c, JUMP_FORWARD, 1); if (i == 0) compiler_use_next_block(c, if_cleanup); ADDOP(c, POP_TOP); } ADDOP_JABS(c, JUMP_ABSOLUTE, start); compiler_use_next_block(c, anchor); ADDOP(c, POP_BLOCK); compiler_pop_fblock(c, LOOP, start); compiler_use_next_block(c, end); return 1;} static intcompiler_genexp(struct compiler *c, expr_ty e){ static identifier name; PyCodeObject *co; expr_ty outermost_iter = ((comprehension_ty) (asdl_seq_GET(e->v.GeneratorExp.generators, 0)))->iter; if (!name) { name = PyString_FromString("<genexpr>"); if (!name) return 0; } if (!compiler_enter_scope(c, name, (void *)e, e->lineno)) return 0; compiler_genexp_generator(c, e->v.GeneratorExp.generators, 0, e->v.GeneratorExp.elt); co = assemble(c, 1); compiler_exit_scope(c); if (co == NULL) return 0; compiler_make_closure(c, co, 0); Py_DECREF(co); VISIT(c, expr, outermost_iter); ADDOP(c, GET_ITER); ADDOP_I(c, CALL_FUNCTION, 1); return 1;} static intcompiler_visit_keyword(struct compiler *c, keyword_ty k){ ADDOP_O(c, LOAD_CONST, k->arg, consts); VISIT(c, expr, k->value); return 1;} /* Test whether expression is constant. For constants, report whether they are true or false. Return values: 1 for true, 0 for false, -1 for non-constant. */ static intexpr_constant(expr_ty e){ switch (e->kind) { case Num_kind: return PyObject_IsTrue(e->v.Num.n); case Str_kind: return PyObject_IsTrue(e->v.Str.s); case Name_kind: /* __debug__ is not assignable, so we can optimize * it away in if and while statements */ if (strcmp(PyString_AS_STRING(e->v.Name.id), "__debug__") == 0) return ! Py_OptimizeFlag; /* fall through */ default: return -1; }} /* Implements the with statement from PEP 343. The semantics outlined in that PEP are as follows: with EXPR as VAR: BLOCK It is implemented roughly as: context = EXPR exit = context.__exit__ # not calling it value = context.__enter__() try: VAR = value # if VAR present in the syntax BLOCK finally: if an exception was raised: exc = copy of (exception, instance, traceback) else: exc = (None, None, None) exit(*exc) */static intcompiler_with(struct compiler *c, stmt_ty s){ static identifier enter_attr, exit_attr; basicblock *block, *finally; identifier tmpexit, tmpvalue = NULL; assert(s->kind == With_kind); if (!enter_attr) { enter_attr = PyString_InternFromString("__enter__"); if (!enter_attr) return 0; } if (!exit_attr) { exit_attr = PyString_InternFromString("__exit__"); if (!exit_attr) return 0; } block = compiler_new_block(c); finally = compiler_new_block(c); if (!block || !finally) return 0; /* Create a temporary variable to hold context.__exit__ */ tmpexit = compiler_new_tmpname(c); if (tmpexit == NULL) return 0; PyArena_AddPyObject(c->c_arena, tmpexit); 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); } /* Evaluate EXPR */ VISIT(c, expr, s->v.With.context_expr); /* Squirrel away context.__exit__ */ 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))Lines 3001–3500 of 4570. Previous lines Load more
default: PyErr_SetString(PyExc_SystemError, "param invalid for global variable"); return 0; } break; case OP_NAME: switch (ctx) { case Load: op = LOAD_NAME; break; case Store: op = STORE_NAME; break; case Del: op = DELETE_NAME; break; case AugLoad: case AugStore: break; case Param: default: PyErr_SetString(PyExc_SystemError, "param invalid for name variable"); return 0; } break; } assert(op); arg = compiler_add_o(c, dict, mangled); Py_DECREF(mangled); if (arg < 0) return 0; return compiler_addop_i(c, op, arg); } static int compiler_boolop(struct compiler *c, expr_ty e) { basicblock *end; int jumpi, i, n; asdl_seq *s; assert(e->kind == BoolOp_kind); if (e->v.BoolOp.op == And) jumpi = JUMP_IF_FALSE; else jumpi = JUMP_IF_TRUE; end = compiler_new_block(c); if (end == NULL) return 0; s = e->v.BoolOp.values; n = asdl_seq_LEN(s) - 1; assert(n >= 0); for (i = 0; i < n; ++i) { VISIT(c, expr, (expr_ty)asdl_seq_GET(s, i)); ADDOP_JREL(c, jumpi, end); ADDOP(c, POP_TOP) } VISIT(c, expr, (expr_ty)asdl_seq_GET(s, n)); compiler_use_next_block(c, end); return 1; } static int compiler_list(struct compiler *c, expr_ty e) { int n = asdl_seq_LEN(e->v.List.elts); if (e->v.List.ctx == Store) { ADDOP_I(c, UNPACK_SEQUENCE, n); } VISIT_SEQ(c, expr, e->v.List.elts); if (e->v.List.ctx == Load) { ADDOP_I(c, BUILD_LIST, n); } return 1; } static int compiler_tuple(struct compiler *c, expr_ty e) { int n = asdl_seq_LEN(e->v.Tuple.elts); if (e->v.Tuple.ctx == Store) { ADDOP_I(c, UNPACK_SEQUENCE, n); } VISIT_SEQ(c, expr, e->v.Tuple.elts); if (e->v.Tuple.ctx == Load) { ADDOP_I(c, BUILD_TUPLE, n); } return 1; } static int compiler_compare(struct compiler *c, expr_ty e) { int i, n; basicblock *cleanup = NULL; /* XXX the logic can be cleaned up for 1 or multiple comparisons */ VISIT(c, expr, e->v.Compare.left); n = asdl_seq_LEN(e->v.Compare.ops); assert(n > 0); if (n > 1) { cleanup = compiler_new_block(c); if (cleanup == NULL) return 0; VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, 0)); } for (i = 1; i < n; i++) { ADDOP(c, DUP_TOP); ADDOP(c, ROT_THREE); ADDOP_I(c, COMPARE_OP, cmpop((cmpop_ty)(asdl_seq_GET( e->v.Compare.ops, i - 1)))); ADDOP_JREL(c, JUMP_IF_FALSE, cleanup); NEXT_BLOCK(c); ADDOP(c, POP_TOP); if (i < (n - 1)) VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); } VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n - 1)); ADDOP_I(c, COMPARE_OP, cmpop((cmpop_ty)(asdl_seq_GET(e->v.Compare.ops, n - 1)))); if (n > 1) { basicblock *end = compiler_new_block(c); if (end == NULL) return 0; ADDOP_JREL(c, JUMP_FORWARD, end); compiler_use_next_block(c, cleanup); ADDOP(c, ROT_TWO); ADDOP(c, POP_TOP); compiler_use_next_block(c, end); } return 1; } #undef CMPCAST static int compiler_call(struct compiler *c, expr_ty e) { int n, code = 0; VISIT(c, expr, e->v.Call.func); n = asdl_seq_LEN(e->v.Call.args); VISIT_SEQ(c, expr, e->v.Call.args); if (e->v.Call.keywords) { VISIT_SEQ(c, keyword, e->v.Call.keywords); n |= asdl_seq_LEN(e->v.Call.keywords) << 8; } if (e->v.Call.starargs) { VISIT(c, expr, e->v.Call.starargs); code |= 1; } if (e->v.Call.kwargs) { VISIT(c, expr, e->v.Call.kwargs); code |= 2; } switch (code) { case 0: ADDOP_I(c, CALL_FUNCTION, n); break; case 1: ADDOP_I(c, CALL_FUNCTION_VAR, n); break; case 2: ADDOP_I(c, CALL_FUNCTION_KW, n); break; case 3: ADDOP_I(c, CALL_FUNCTION_VAR_KW, n); break; } return 1; } static int compiler_listcomp_generator(struct compiler *c, PyObject *tmpname, asdl_seq *generators, int gen_index, expr_ty elt) { /* generate code for the iterator, then each of the ifs, and then write to the element */ comprehension_ty l; basicblock *start, *anchor, *skip, *if_cleanup; int i, n; start = compiler_new_block(c); skip = compiler_new_block(c); if_cleanup = compiler_new_block(c); anchor = compiler_new_block(c); if (start == NULL || skip == NULL || if_cleanup == NULL || anchor == NULL) return 0; l = (comprehension_ty)asdl_seq_GET(generators, gen_index); VISIT(c, expr, l->iter); ADDOP(c, GET_ITER); compiler_use_next_block(c, start); ADDOP_JREL(c, FOR_ITER, anchor); NEXT_BLOCK(c); VISIT(c, expr, l->target); /* XXX this needs to be cleaned up...a lot! */ n = asdl_seq_LEN(l->ifs); for (i = 0; i < n; i++) { expr_ty e = (expr_ty)asdl_seq_GET(l->ifs, i); VISIT(c, expr, e); ADDOP_JREL(c, JUMP_IF_FALSE, if_cleanup); NEXT_BLOCK(c); ADDOP(c, POP_TOP); } if (++gen_index < asdl_seq_LEN(generators)) if (!compiler_listcomp_generator(c, tmpname, generators, gen_index, elt)) return 0; /* only append after the last for generator */ if (gen_index >= asdl_seq_LEN(generators)) { if (!compiler_nameop(c, tmpname, Load)) return 0; VISIT(c, expr, elt); ADDOP(c, LIST_APPEND); compiler_use_next_block(c, skip); } for (i = 0; i < n; i++) { ADDOP_I(c, JUMP_FORWARD, 1); if (i == 0) compiler_use_next_block(c, if_cleanup); ADDOP(c, POP_TOP); } ADDOP_JABS(c, JUMP_ABSOLUTE, start); compiler_use_next_block(c, anchor); /* delete the append method added to locals */ if (gen_index == 1) if (!compiler_nameop(c, tmpname, Del)) return 0; return 1; } static int compiler_listcomp(struct compiler *c, expr_ty e) { identifier tmp; int rc = 0; static identifier append; asdl_seq *generators = e->v.ListComp.generators; assert(e->kind == ListComp_kind); if (!append) { append = PyString_InternFromString("append"); if (!append) return 0; } tmp = compiler_new_tmpname(c); if (!tmp) return 0; ADDOP_I(c, BUILD_LIST, 0); ADDOP(c, DUP_TOP); if (compiler_nameop(c, tmp, Store)) rc = compiler_listcomp_generator(c, tmp, generators, 0, e->v.ListComp.elt); Py_DECREF(tmp); return rc; } static int compiler_genexp_generator(struct compiler *c, asdl_seq *generators, int gen_index, expr_ty elt) { /* generate code for the iterator, then each of the ifs, and then write to the element */ comprehension_ty ge; basicblock *start, *anchor, *skip, *if_cleanup, *end; int i, n; start = compiler_new_block(c); skip = compiler_new_block(c); if_cleanup = compiler_new_block(c); anchor = compiler_new_block(c); end = compiler_new_block(c); if (start == NULL || skip == NULL || if_cleanup == NULL || anchor == NULL || end == NULL) return 0; ge = (comprehension_ty)asdl_seq_GET(generators, gen_index); ADDOP_JREL(c, SETUP_LOOP, end); if (!compiler_push_fblock(c, LOOP, start)) return 0; if (gen_index == 0) { /* Receive outermost iter as an implicit argument */ c->u->u_argcount = 1; ADDOP_I(c, LOAD_FAST, 0); } else { /* Sub-iter - calculate on the fly */ VISIT(c, expr, ge->iter); ADDOP(c, GET_ITER); } compiler_use_next_block(c, start); ADDOP_JREL(c, FOR_ITER, anchor); NEXT_BLOCK(c); VISIT(c, expr, ge->target); /* XXX this needs to be cleaned up...a lot! */ n = asdl_seq_LEN(ge->ifs); for (i = 0; i < n; i++) { expr_ty e = (expr_ty)asdl_seq_GET(ge->ifs, i); VISIT(c, expr, e); ADDOP_JREL(c, JUMP_IF_FALSE, if_cleanup); NEXT_BLOCK(c); ADDOP(c, POP_TOP); } if (++gen_index < asdl_seq_LEN(generators)) if (!compiler_genexp_generator(c, generators, gen_index, elt)) return 0; /* only append after the last 'for' generator */ if (gen_index >= asdl_seq_LEN(generators)) { VISIT(c, expr, elt); ADDOP(c, YIELD_VALUE); ADDOP(c, POP_TOP); compiler_use_next_block(c, skip); } for (i = 0; i < n; i++) { ADDOP_I(c, JUMP_FORWARD, 1); if (i == 0) compiler_use_next_block(c, if_cleanup); ADDOP(c, POP_TOP); } ADDOP_JABS(c, JUMP_ABSOLUTE, start); compiler_use_next_block(c, anchor); ADDOP(c, POP_BLOCK); compiler_pop_fblock(c, LOOP, start); compiler_use_next_block(c, end); return 1; } static int compiler_genexp(struct compiler *c, expr_ty e) { static identifier name; PyCodeObject *co; expr_ty outermost_iter = ((comprehension_ty) (asdl_seq_GET(e->v.GeneratorExp.generators, 0)))->iter; if (!name) { name = PyString_FromString("<genexpr>"); if (!name) return 0; } if (!compiler_enter_scope(c, name, (void *)e, e->lineno)) return 0; compiler_genexp_generator(c, e->v.GeneratorExp.generators, 0, e->v.GeneratorExp.elt); co = assemble(c, 1); compiler_exit_scope(c); if (co == NULL) return 0; compiler_make_closure(c, co, 0); Py_DECREF(co); VISIT(c, expr, outermost_iter); ADDOP(c, GET_ITER); ADDOP_I(c, CALL_FUNCTION, 1); return 1; } static int compiler_visit_keyword(struct compiler *c, keyword_ty k) { ADDOP_O(c, LOAD_CONST, k->arg, consts); VISIT(c, expr, k->value); return 1; } /* Test whether expression is constant. For constants, report whether they are true or false. Return values: 1 for true, 0 for false, -1 for non-constant. */ static int expr_constant(expr_ty e) { switch (e->kind) { case Num_kind: return PyObject_IsTrue(e->v.Num.n); case Str_kind: return PyObject_IsTrue(e->v.Str.s); case Name_kind: /* __debug__ is not assignable, so we can optimize * it away in if and while statements */ if (strcmp(PyString_AS_STRING(e->v.Name.id), "__debug__") == 0) return ! Py_OptimizeFlag; /* fall through */ default: return -1; } } /* Implements the with statement from PEP 343. The semantics outlined in that PEP are as follows: with EXPR as VAR: BLOCK It is implemented roughly as: context = EXPR exit = context.__exit__ # not calling it value = context.__enter__() try: VAR = value # if VAR present in the syntax BLOCK finally: if an exception was raised: exc = copy of (exception, instance, traceback) else: exc = (None, None, None) exit(*exc) */ static int compiler_with(struct compiler *c, stmt_ty s) { static identifier enter_attr, exit_attr; basicblock *block, *finally; identifier tmpexit, tmpvalue = NULL; assert(s->kind == With_kind); if (!enter_attr) { enter_attr = PyString_InternFromString("__enter__"); if (!enter_attr) return 0; } if (!exit_attr) { exit_attr = PyString_InternFromString("__exit__"); if (!exit_attr) return 0; } block = compiler_new_block(c); finally = compiler_new_block(c); if (!block || !finally) return 0; /* Create a temporary variable to hold context.__exit__ */ tmpexit = compiler_new_tmpname(c); if (tmpexit == NULL) return 0; PyArena_AddPyObject(c->c_arena, tmpexit); 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); } /* Evaluate EXPR */ VISIT(c, expr, s->v.With.context_expr); /* Squirrel away context.__exit__ */ 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))