diff --git a/Include/Python-ast.h b/Include/Python-ast.h --- a/Include/Python-ast.h +++ b/Include/Python-ast.h @@ -31,16 +31,18 @@ typedef struct _excepthandler *excepthan typedef struct _arguments *arguments_ty; typedef struct _arg *arg_ty; typedef struct _keyword *keyword_ty; typedef struct _alias *alias_ty; +typedef struct _withitem *withitem_ty; + enum _mod_kind {Module_kind=1, Interactive_kind=2, Expression_kind=3, Suite_kind=4}; struct _mod { enum _mod_kind kind; union { struct { asdl_seq *body; @@ -123,18 +125,17 @@ struct _stmt { struct { expr_ty test; asdl_seq *body; asdl_seq *orelse; } If; struct { - expr_ty context_expr; - expr_ty optional_vars; + asdl_seq *items; asdl_seq *body; } With; struct { expr_ty exc; expr_ty cause; } Raise; @@ -378,16 +379,30 @@ struct _keyword { expr_ty value; }; struct _alias { identifier name; identifier asname; }; +enum _withitem_kind {WithItem_kind=1}; +struct _withitem { + enum _withitem_kind kind; + union { + struct { + expr_ty context_expr; + expr_ty optional_vars; + } WithItem; + + } v; + int lineno; + int col_offset; +}; + #define Module(a0, a1) _Py_Module(a0, a1) mod_ty _Py_Module(asdl_seq * body, PyArena *arena); #define Interactive(a0, a1) _Py_Interactive(a0, a1) mod_ty _Py_Interactive(asdl_seq * body, PyArena *arena); #define Expression(a0, a1) _Py_Expression(a0, a1) mod_ty _Py_Expression(expr_ty body, PyArena *arena); #define Suite(a0, a1) _Py_Suite(a0, a1) @@ -416,19 +431,19 @@ stmt_ty _Py_AugAssign(expr_ty target, op stmt_ty _Py_For(expr_ty target, expr_ty iter, asdl_seq * body, asdl_seq * orelse, int lineno, int col_offset, PyArena *arena); #define While(a0, a1, a2, a3, a4, a5) _Py_While(a0, a1, a2, a3, a4, a5) stmt_ty _Py_While(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, int col_offset, PyArena *arena); #define If(a0, a1, a2, a3, a4, a5) _Py_If(a0, a1, a2, a3, a4, a5) stmt_ty _Py_If(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, int col_offset, PyArena *arena); -#define With(a0, a1, a2, a3, a4, a5) _Py_With(a0, a1, a2, a3, a4, a5) -stmt_ty _Py_With(expr_ty context_expr, expr_ty optional_vars, asdl_seq * body, - int lineno, int col_offset, PyArena *arena); +#define With(a0, a1, a2, a3, a4) _Py_With(a0, a1, a2, a3, a4) +stmt_ty _Py_With(asdl_seq * items, asdl_seq * body, int lineno, int col_offset, + PyArena *arena); #define Raise(a0, a1, a2, a3, a4) _Py_Raise(a0, a1, a2, a3, a4) stmt_ty _Py_Raise(expr_ty exc, expr_ty cause, int lineno, int col_offset, PyArena *arena); #define TryExcept(a0, a1, a2, a3, a4, a5) _Py_TryExcept(a0, a1, a2, a3, a4, a5) stmt_ty _Py_TryExcept(asdl_seq * body, asdl_seq * handlers, asdl_seq * orelse, int lineno, int col_offset, PyArena *arena); #define TryFinally(a0, a1, a2, a3, a4) _Py_TryFinally(a0, a1, a2, a3, a4) stmt_ty _Py_TryFinally(asdl_seq * body, asdl_seq * finalbody, int lineno, int @@ -542,12 +557,15 @@ arguments_ty _Py_arguments(asdl_seq * ar kwarg, expr_ty kwargannotation, asdl_seq * defaults, asdl_seq * kw_defaults, PyArena *arena); #define arg(a0, a1, a2) _Py_arg(a0, a1, a2) arg_ty _Py_arg(identifier arg, expr_ty annotation, PyArena *arena); #define keyword(a0, a1, a2) _Py_keyword(a0, a1, a2) keyword_ty _Py_keyword(identifier arg, expr_ty value, PyArena *arena); #define alias(a0, a1, a2) _Py_alias(a0, a1, a2) alias_ty _Py_alias(identifier name, identifier asname, PyArena *arena); +#define WithItem(a0, a1, a2, a3, a4) _Py_WithItem(a0, a1, a2, a3, a4) +withitem_ty _Py_WithItem(expr_ty context_expr, expr_ty optional_vars, int + lineno, int col_offset, PyArena *arena); PyObject* PyAST_mod2obj(mod_ty t); mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode); int PyAST_Check(PyObject* obj); diff --git a/Parser/Python.asdl b/Parser/Python.asdl --- a/Parser/Python.asdl +++ b/Parser/Python.asdl @@ -23,17 +23,17 @@ module Python | Delete(expr* targets) | Assign(expr* targets, expr value) | AugAssign(expr target, operator op, expr value) -- use 'orelse' because else is a keyword in target languages | For(expr target, expr iter, stmt* body, stmt* orelse) | While(expr test, stmt* body, stmt* orelse) | If(expr test, stmt* body, stmt* orelse) - | With(expr context_expr, expr? optional_vars, stmt* body) + | With(withitem* items, stmt* body) | Raise(expr? exc, expr? cause) | TryExcept(stmt* body, excepthandler* handlers, stmt* orelse) | TryFinally(stmt* body, stmt* finalbody) | Assert(expr test, expr? msg) | Import(alias* names) | ImportFrom(identifier? module, alias* names, int? level) @@ -110,10 +110,13 @@ module Python expr* kw_defaults) arg = (identifier arg, expr? annotation) -- keyword arguments supplied to call keyword = (identifier arg, expr value) -- import name with optional 'as' alias. alias = (identifier name, identifier? asname) + + withitem = WithItem(expr context_expr, expr? optional_vars) + attributes (int lineno, int col_offset) } diff --git a/Python/Python-ast.c b/Python/Python-ast.c --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -90,18 +90,17 @@ static char *While_fields[]={ static PyTypeObject *If_type; static char *If_fields[]={ "test", "body", "orelse", }; static PyTypeObject *With_type; static char *With_fields[]={ - "context_expr", - "optional_vars", + "items", "body", }; static PyTypeObject *Raise_type; static char *Raise_fields[]={ "exc", "cause", }; static PyTypeObject *TryExcept_type; @@ -387,16 +386,27 @@ static char *keyword_fields[]={ "value", }; static PyTypeObject *alias_type; static PyObject* ast2obj_alias(void*); static char *alias_fields[]={ "name", "asname", }; +static PyTypeObject *withitem_type; +static char *withitem_attributes[] = { + "lineno", + "col_offset", +}; +static PyObject* ast2obj_withitem(void*); +static PyTypeObject *WithItem_type; +static char *WithItem_fields[]={ + "context_expr", + "optional_vars", +}; static int ast_type_init(PyObject *self, PyObject *args, PyObject *kw) { Py_ssize_t i, numfields = 0; int res = -1; PyObject *key, *value, *fields; @@ -675,17 +685,17 @@ static int init_types(void) AugAssign_type = make_type("AugAssign", stmt_type, AugAssign_fields, 3); if (!AugAssign_type) return 0; For_type = make_type("For", stmt_type, For_fields, 4); if (!For_type) return 0; While_type = make_type("While", stmt_type, While_fields, 3); if (!While_type) return 0; If_type = make_type("If", stmt_type, If_fields, 3); if (!If_type) return 0; - With_type = make_type("With", stmt_type, With_fields, 3); + With_type = make_type("With", stmt_type, With_fields, 2); if (!With_type) return 0; Raise_type = make_type("Raise", stmt_type, Raise_fields, 2); if (!Raise_type) return 0; TryExcept_type = make_type("TryExcept", stmt_type, TryExcept_fields, 3); if (!TryExcept_type) return 0; TryFinally_type = make_type("TryFinally", stmt_type, TryFinally_fields, 2); if (!TryFinally_type) return 0; @@ -933,16 +943,22 @@ static int init_types(void) arguments_type = make_type("arguments", &AST_type, arguments_fields, 8); if (!arguments_type) return 0; arg_type = make_type("arg", &AST_type, arg_fields, 2); if (!arg_type) return 0; keyword_type = make_type("keyword", &AST_type, keyword_fields, 2); if (!keyword_type) return 0; alias_type = make_type("alias", &AST_type, alias_fields, 2); if (!alias_type) return 0; + withitem_type = make_type("withitem", &AST_type, NULL, 0); + if (!withitem_type) return 0; + if (!add_attributes(withitem_type, withitem_attributes, 2)) return 0; + WithItem_type = make_type("WithItem", withitem_type, WithItem_fields, + 2); + if (!WithItem_type) return 0; initialized = 1; return 1; } static int obj2ast_mod(PyObject* obj, mod_ty* out, PyArena* arena); static int obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena); static int obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena); static int obj2ast_expr_context(PyObject* obj, expr_context_ty* out, PyArena* @@ -955,16 +971,17 @@ static int obj2ast_cmpop(PyObject* obj, static int obj2ast_comprehension(PyObject* obj, comprehension_ty* out, PyArena* arena); static int obj2ast_excepthandler(PyObject* obj, excepthandler_ty* out, PyArena* arena); static int obj2ast_arguments(PyObject* obj, arguments_ty* out, PyArena* arena); static int obj2ast_arg(PyObject* obj, arg_ty* out, PyArena* arena); static int obj2ast_keyword(PyObject* obj, keyword_ty* out, PyArena* arena); static int obj2ast_alias(PyObject* obj, alias_ty* out, PyArena* arena); +static int obj2ast_withitem(PyObject* obj, withitem_ty* out, PyArena* arena); mod_ty Module(asdl_seq * body, PyArena *arena) { mod_ty p; p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; @@ -1220,31 +1237,25 @@ If(expr_ty test, asdl_seq * body, asdl_s p->v.If.body = body; p->v.If.orelse = orelse; p->lineno = lineno; p->col_offset = col_offset; return p; } stmt_ty -With(expr_ty context_expr, expr_ty optional_vars, asdl_seq * body, int lineno, - int col_offset, PyArena *arena) +With(asdl_seq * items, asdl_seq * body, int lineno, int col_offset, PyArena + *arena) { stmt_ty p; - if (!context_expr) { - PyErr_SetString(PyExc_ValueError, - "field context_expr is required for With"); - return NULL; - } p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = With_kind; - p->v.With.context_expr = context_expr; - p->v.With.optional_vars = optional_vars; + p->v.With.items = items; p->v.With.body = body; p->lineno = lineno; p->col_offset = col_offset; return p; } stmt_ty Raise(expr_ty exc, expr_ty cause, int lineno, int col_offset, PyArena *arena) @@ -2130,16 +2141,37 @@ alias(identifier name, identifier asname p = (alias_ty)PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->name = name; p->asname = asname; return p; } +withitem_ty +WithItem(expr_ty context_expr, expr_ty optional_vars, int lineno, int + col_offset, PyArena *arena) +{ + withitem_ty p; + if (!context_expr) { + PyErr_SetString(PyExc_ValueError, + "field context_expr is required for WithItem"); + return NULL; + } + p = (withitem_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = WithItem_kind; + p->v.WithItem.context_expr = context_expr; + p->v.WithItem.optional_vars = optional_vars; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + PyObject* ast2obj_mod(void* _o) { mod_ty o = (mod_ty)_o; PyObject *result = NULL, *value = NULL; if (!o) { Py_INCREF(Py_None); @@ -2385,25 +2417,19 @@ ast2obj_stmt(void* _o) if (!value) goto failed; if (PyObject_SetAttrString(result, "orelse", value) == -1) goto failed; Py_DECREF(value); break; case With_kind: result = PyType_GenericNew(With_type, NULL, NULL); if (!result) goto failed; - value = ast2obj_expr(o->v.With.context_expr); + value = ast2obj_list(o->v.With.items, ast2obj_withitem); if (!value) goto failed; - if (PyObject_SetAttrString(result, "context_expr", value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.With.optional_vars); - if (!value) goto failed; - if (PyObject_SetAttrString(result, "optional_vars", value) == - -1) + if (PyObject_SetAttrString(result, "items", value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(o->v.With.body, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttrString(result, "body", value) == -1) goto failed; Py_DECREF(value); break; @@ -3365,16 +3391,60 @@ ast2obj_alias(void* _o) Py_DECREF(value); return result; failed: Py_XDECREF(value); Py_XDECREF(result); return NULL; } +PyObject* +ast2obj_withitem(void* _o) +{ + withitem_ty o = (withitem_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + switch (o->kind) { + case WithItem_kind: + result = PyType_GenericNew(WithItem_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.WithItem.context_expr); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "context_expr", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.WithItem.optional_vars); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "optional_vars", value) == + -1) + goto failed; + Py_DECREF(value); + break; + } + value = ast2obj_int(o->lineno); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "lineno", value) < 0) + goto failed; + Py_DECREF(value); + value = ast2obj_int(o->col_offset); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "col_offset", value) < 0) + goto failed; + Py_DECREF(value); + return result; +failed: + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; +} + int obj2ast_mod(PyObject* obj, mod_ty* out, PyArena* arena) { int isinstance; PyObject *tmp = NULL; @@ -4205,43 +4275,44 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out if (*out == NULL) goto failed; return 0; } isinstance = PyObject_IsInstance(obj, (PyObject*)With_type); if (isinstance == -1) { return 1; } if (isinstance) { - expr_ty context_expr; - expr_ty optional_vars; + asdl_seq* items; asdl_seq* body; - if (PyObject_HasAttrString(obj, "context_expr")) { + if (PyObject_HasAttrString(obj, "items")) { int res; - tmp = PyObject_GetAttrString(obj, "context_expr"); + Py_ssize_t len; + Py_ssize_t i; + tmp = PyObject_GetAttrString(obj, "items"); if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &context_expr, arena); - if (res != 0) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "With field \"items\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + items = asdl_seq_new(len, arena); + if (items == NULL) goto failed; + for (i = 0; i < len; i++) { + withitem_ty value; + res = obj2ast_withitem(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(items, i, value); + } Py_XDECREF(tmp); tmp = NULL; } else { - PyErr_SetString(PyExc_TypeError, "required field \"context_expr\" missing from With"); + PyErr_SetString(PyExc_TypeError, "required field \"items\" missing from With"); return 1; } - if (PyObject_HasAttrString(obj, "optional_vars")) { - int res; - tmp = PyObject_GetAttrString(obj, "optional_vars"); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &optional_vars, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - optional_vars = NULL; - } if (PyObject_HasAttrString(obj, "body")) { int res; Py_ssize_t len; Py_ssize_t i; tmp = PyObject_GetAttrString(obj, "body"); if (tmp == NULL) goto failed; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "With field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); @@ -4257,18 +4328,17 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out asdl_seq_SET(body, i, value); } Py_XDECREF(tmp); tmp = NULL; } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from With"); return 1; } - *out = With(context_expr, optional_vars, body, lineno, - col_offset, arena); + *out = With(items, body, lineno, col_offset, arena); if (*out == NULL) goto failed; return 0; } isinstance = PyObject_IsInstance(obj, (PyObject*)Raise_type); if (isinstance == -1) { return 1; } if (isinstance) { @@ -6718,16 +6788,96 @@ obj2ast_alias(PyObject* obj, alias_ty* o } *out = alias(name, asname, arena); return 0; failed: Py_XDECREF(tmp); return 1; } +int +obj2ast_withitem(PyObject* obj, withitem_ty* out, PyArena* arena) +{ + int isinstance; + + PyObject *tmp = NULL; + int lineno; + int col_offset; + + if (obj == Py_None) { + *out = NULL; + return 0; + } + if (PyObject_HasAttrString(obj, "lineno")) { + int res; + tmp = PyObject_GetAttrString(obj, "lineno"); + if (tmp == NULL) goto failed; + res = obj2ast_int(tmp, &lineno, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from withitem"); + return 1; + } + if (PyObject_HasAttrString(obj, "col_offset")) { + int res; + tmp = PyObject_GetAttrString(obj, "col_offset"); + if (tmp == NULL) goto failed; + res = obj2ast_int(tmp, &col_offset, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from withitem"); + return 1; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)WithItem_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty context_expr; + expr_ty optional_vars; + + if (PyObject_HasAttrString(obj, "context_expr")) { + int res; + tmp = PyObject_GetAttrString(obj, "context_expr"); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &context_expr, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"context_expr\" missing from WithItem"); + return 1; + } + if (PyObject_HasAttrString(obj, "optional_vars")) { + int res; + tmp = PyObject_GetAttrString(obj, "optional_vars"); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &optional_vars, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + optional_vars = NULL; + } + *out = WithItem(context_expr, optional_vars, lineno, + col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of withitem, but got %R", obj); + failed: + Py_XDECREF(tmp); + return 1; +} + static struct PyModuleDef _astmodule = { PyModuleDef_HEAD_INIT, "_ast" }; PyMODINIT_FUNC PyInit__ast(void) { PyObject *m, *d; @@ -6935,16 +7085,20 @@ PyInit__ast(void) if (PyDict_SetItemString(d, "arguments", (PyObject*)arguments_type) < 0) return NULL; if (PyDict_SetItemString(d, "arg", (PyObject*)arg_type) < 0) return NULL; if (PyDict_SetItemString(d, "keyword", (PyObject*)keyword_type) < 0) return NULL; if (PyDict_SetItemString(d, "alias", (PyObject*)alias_type) < 0) return NULL; + if (PyDict_SetItemString(d, "withitem", (PyObject*)withitem_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "WithItem", (PyObject*)WithItem_type) < 0) + return NULL; return m; } PyObject* PyAST_mod2obj(mod_ty t) { init_types(); return ast2obj_mod(t); diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -2962,18 +2962,18 @@ ast_for_try_stmt(struct compiling *c, co } /* must be a try ... finally (except clauses are in body, if any exist) */ assert(finally != NULL); return TryFinally(body, finally, LINENO(n), n->n_col_offset, c->c_arena); } /* with_item: test ['as' expr] */ -static stmt_ty -ast_for_with_item(struct compiling *c, const node *n, asdl_seq *content) +static withitem_ty +ast_for_with_item(struct compiling *c, const node *n) { expr_ty context_expr, optional_vars = NULL; REQ(n, with_item); context_expr = ast_for_expr(c, CHILD(n, 0)); if (!context_expr) return NULL; if (NCH(n) == 3) { @@ -2982,53 +2982,43 @@ ast_for_with_item(struct compiling *c, c if (!optional_vars) { return NULL; } if (!set_context(c, optional_vars, Store, n)) { return NULL; } } - return With(context_expr, optional_vars, content, LINENO(n), - n->n_col_offset, c->c_arena); + return WithItem(context_expr, optional_vars, LINENO(n), n->n_col_offset, + c->c_arena); } /* with_stmt: 'with' with_item (',' with_item)* ':' suite */ static stmt_ty ast_for_with_stmt(struct compiling *c, const node *n) { - int i; - stmt_ty ret; - asdl_seq *inner; + int i, n_items; + asdl_seq *items, *body; REQ(n, with_stmt); - /* process the with items inside-out */ - i = NCH(n) - 1; - /* the suite of the innermost with item is the suite of the with stmt */ - inner = ast_for_suite(c, CHILD(n, i)); - if (!inner) + n_items = (NCH(n) - 2) / 2; + items = asdl_seq_new(n_items, c->c_arena); + for (i = 1; i < NCH(n) - 2; i += 2) { + withitem_ty item = ast_for_with_item(c, CHILD(n, i)); + if (!item) + return NULL; + asdl_seq_SET(items, (i - 1) / 2, item); + } + + body = ast_for_suite(c, CHILD(n, NCH(n) - 1)); + if (!body) return NULL; - for (;;) { - i -= 2; - ret = ast_for_with_item(c, CHILD(n, i), inner); - if (!ret) - return NULL; - /* was this the last item? */ - if (i == 1) - break; - /* if not, wrap the result so far in a new sequence */ - inner = asdl_seq_new(1, c->c_arena); - if (!inner) - return NULL; - asdl_seq_SET(inner, 0, ret); - } - - return ret; + return With(items, body, LINENO(n), n->n_col_offset, c->c_arena); } static stmt_ty ast_for_classdef(struct compiling *c, const node *n, asdl_seq *decorator_seq) { /* classdef: 'class' NAME ['(' arglist ')'] ':' suite */ PyObject *classname; asdl_seq *s; diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -173,17 +173,17 @@ static int compiler_push_fblock(struct c static void compiler_pop_fblock(struct compiler *, enum fblocktype, basicblock *); /* Returns true if there is a loop on the fblock stack. */ static int compiler_in_loop(struct compiler *); static int inplace_binop(struct compiler *, operator_ty); static int expr_constant(struct compiler *, expr_ty); -static int compiler_with(struct compiler *, stmt_ty); +static int compiler_with(struct compiler *, stmt_ty, int); static int compiler_call_helper(struct compiler *c, int n, asdl_seq *args, asdl_seq *keywords, expr_ty starargs, expr_ty kwargs); static PyCodeObject *assemble(struct compiler *, int addNone); static PyObject *__doc__; @@ -2330,17 +2330,17 @@ compiler_visit_stmt(struct compiler *c, case Break_kind: if (!compiler_in_loop(c)) return compiler_error(c, "'break' outside loop"); ADDOP(c, BREAK_LOOP); break; case Continue_kind: return compiler_continue(c); case With_kind: - return compiler_with(c, s); + return compiler_with(c, s, 0); } return 1; } static int unaryop(unaryop_ty op) { switch (op) { @@ -3057,47 +3057,52 @@ expr_constant(struct compiler *c, expr_t 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) +compiler_with(struct compiler *c, stmt_ty s, int pos) { basicblock *block, *finally; + withitem_ty item = asdl_seq_GET(s->v.With.items, pos); assert(s->kind == With_kind); block = compiler_new_block(c); finally = compiler_new_block(c); if (!block || !finally) return 0; /* Evaluate EXPR */ - VISIT(c, expr, s->v.With.context_expr); + VISIT(c, expr, item->v.WithItem.context_expr); ADDOP_JREL(c, SETUP_WITH, 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) { - VISIT(c, expr, s->v.With.optional_vars); + if (item->v.WithItem.optional_vars) { + VISIT(c, expr, item->v.WithItem.optional_vars); } else { /* Discard result from context.__enter__() */ ADDOP(c, POP_TOP); } - /* BLOCK code */ - VISIT_SEQ(c, stmt, s->v.With.body); + pos++; + if (pos == asdl_seq_LEN(s->v.With.items)) + /* BLOCK code */ + VISIT_SEQ(c, stmt, s->v.With.body) + else if (!compiler_with(c, s, pos)) + return 0; /* End of try block; start the finally block */ ADDOP(c, POP_BLOCK); compiler_pop_fblock(c, FINALLY_TRY, block); ADDOP_O(c, LOAD_CONST, Py_None, consts); compiler_use_next_block(c, finally); if (!compiler_push_fblock(c, FINALLY_END, finally)) diff --git a/Python/symtable.c b/Python/symtable.c --- a/Python/symtable.c +++ b/Python/symtable.c @@ -180,16 +180,17 @@ static int symtable_visit_excepthandler( static int symtable_visit_alias(struct symtable *st, alias_ty); static int symtable_visit_comprehension(struct symtable *st, comprehension_ty); static int symtable_visit_keyword(struct symtable *st, keyword_ty); static int symtable_visit_slice(struct symtable *st, slice_ty); static int symtable_visit_params(struct symtable *st, asdl_seq *args); static int symtable_visit_argannotations(struct symtable *st, asdl_seq *args); static int symtable_implicit_arg(struct symtable *st, int pos); static int symtable_visit_annotations(struct symtable *st, stmt_ty s); +static int symtable_visit_withitem(struct symtable *st, withitem_ty item); static identifier top = NULL, lambda = NULL, genexpr = NULL, listcomp = NULL, setcomp = NULL, dictcomp = NULL, __class__ = NULL, __locals__ = NULL; #define GET_IDENTIFIER(VAR) \ ((VAR) ? (VAR) : ((VAR) = PyUnicode_InternFromString(# VAR))) @@ -1300,20 +1301,17 @@ symtable_visit_stmt(struct symtable *st, VISIT(st, expr, s->v.Expr.value); break; case Pass_kind: case Break_kind: case Continue_kind: /* nothing to do here */ break; case With_kind: - VISIT(st, expr, s->v.With.context_expr); - if (s->v.With.optional_vars) { - VISIT(st, expr, s->v.With.optional_vars); - } + VISIT_SEQ(st, withitem, s->v.With.items); VISIT_SEQ(st, stmt, s->v.With.body); break; } return 1; } static int symtable_visit_expr(struct symtable *st, expr_ty e) @@ -1535,16 +1533,26 @@ symtable_visit_excepthandler(struct symt VISIT(st, expr, eh->v.ExceptHandler.type); if (eh->v.ExceptHandler.name) if (!symtable_add_def(st, eh->v.ExceptHandler.name, DEF_LOCAL)) return 0; VISIT_SEQ(st, stmt, eh->v.ExceptHandler.body); return 1; } +static int +symtable_visit_withitem(struct symtable *st, withitem_ty item) +{ + VISIT(st, expr, item->v.WithItem.context_expr); + if (item->v.WithItem.optional_vars) { + VISIT(st, expr, item->v.WithItem.optional_vars); + } + return 1; +} + static int symtable_visit_alias(struct symtable *st, alias_ty a) { /* Compute store_name, the name actually bound by the import operation. It is different than a->name when a->name is a dotted package name (e.g. spam.eggs) */