Commit c2e20744 authored by Guido van Rossum's avatar Guido van Rossum

PEP 343 -- the with-statement.

This was started by Mike Bland and completed by Guido
(with help from Neal).

This still needs a __future__ statement added;
Thomas is working on Michael's patch for that aspect.

There's a small amount of code cleanup and refactoring
in ast.c, compile.c and ceval.c (I fixed the lltrace
behavior when EXT_POP is used -- however I had to make
lltrace a static global).
parent 5fec904f
...@@ -272,6 +272,11 @@ ...@@ -272,6 +272,11 @@
\lineiii{}{\member{else_}}{} \lineiii{}{\member{else_}}{}
\hline \hline
\lineiii{With}{\member{expr}}{}
\lineiii{}{\member{vars&}}{}
\lineiii{}{\member{body}}{}
\hline
\lineiii{Yield}{\member{value}}{} \lineiii{Yield}{\member{value}}{}
\hline \hline
......
...@@ -308,6 +308,12 @@ section~\ref{exceptions}, and information on using the \keyword{raise} ...@@ -308,6 +308,12 @@ section~\ref{exceptions}, and information on using the \keyword{raise}
statement to generate exceptions may be found in section~\ref{raise}. statement to generate exceptions may be found in section~\ref{raise}.
\section{The \keyword{with} statement\label{with}}
\stindex{with}
The \keyword{with} statement specifies
\section{Function definitions\label{function}} \section{Function definitions\label{function}}
\indexii{function}{definition} \indexii{function}{definition}
\stindex{def} \stindex{def}
......
...@@ -70,7 +70,7 @@ global_stmt: 'global' NAME (',' NAME)* ...@@ -70,7 +70,7 @@ global_stmt: 'global' NAME (',' NAME)*
exec_stmt: 'exec' expr ['in' test [',' test]] exec_stmt: 'exec' expr ['in' test [',' test]]
assert_stmt: 'assert' test [',' test] assert_stmt: 'assert' test [',' test]
compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
while_stmt: 'while' test ':' suite ['else' ':' suite] while_stmt: 'while' test ':' suite ['else' ':' suite]
for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]
...@@ -79,6 +79,8 @@ try_stmt: ('try' ':' suite ...@@ -79,6 +79,8 @@ try_stmt: ('try' ':' suite
['else' ':' suite] ['else' ':' suite]
['finally' ':' suite] | ['finally' ':' suite] |
'finally' ':' suite)) 'finally' ':' suite))
with_stmt: 'with' test [ with_var ] ':' suite
with_var: NAME expr
# NB compile.c makes sure that the default except clause is last # NB compile.c makes sure that the default except clause is last
except_clause: 'except' [test [',' test]] except_clause: 'except' [test [',' test]]
suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
......
...@@ -61,11 +61,11 @@ struct _mod { ...@@ -61,11 +61,11 @@ struct _mod {
struct _stmt { struct _stmt {
enum { FunctionDef_kind=1, ClassDef_kind=2, Return_kind=3, enum { FunctionDef_kind=1, ClassDef_kind=2, Return_kind=3,
Delete_kind=4, Assign_kind=5, AugAssign_kind=6, Print_kind=7, Delete_kind=4, Assign_kind=5, AugAssign_kind=6, Print_kind=7,
For_kind=8, While_kind=9, If_kind=10, Raise_kind=11, For_kind=8, While_kind=9, If_kind=10, With_kind=11,
TryExcept_kind=12, TryFinally_kind=13, Assert_kind=14, Raise_kind=12, TryExcept_kind=13, TryFinally_kind=14,
Import_kind=15, ImportFrom_kind=16, Exec_kind=17, Assert_kind=15, Import_kind=16, ImportFrom_kind=17,
Global_kind=18, Expr_kind=19, Pass_kind=20, Break_kind=21, Exec_kind=18, Global_kind=19, Expr_kind=20, Pass_kind=21,
Continue_kind=22 } kind; Break_kind=22, Continue_kind=23 } kind;
union { union {
struct { struct {
identifier name; identifier name;
...@@ -124,6 +124,12 @@ struct _stmt { ...@@ -124,6 +124,12 @@ struct _stmt {
asdl_seq *orelse; asdl_seq *orelse;
} If; } If;
struct {
expr_ty context_expr;
expr_ty optional_vars;
asdl_seq *body;
} With;
struct { struct {
expr_ty type; expr_ty type;
expr_ty inst; expr_ty inst;
...@@ -355,6 +361,8 @@ stmt_ty While(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, ...@@ -355,6 +361,8 @@ stmt_ty While(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno,
PyArena *arena); PyArena *arena);
stmt_ty If(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, stmt_ty If(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno,
PyArena *arena); PyArena *arena);
stmt_ty With(expr_ty context_expr, expr_ty optional_vars, asdl_seq * body, int
lineno, PyArena *arena);
stmt_ty Raise(expr_ty type, expr_ty inst, expr_ty tback, int lineno, PyArena stmt_ty Raise(expr_ty type, expr_ty inst, expr_ty tback, int lineno, PyArena
*arena); *arena);
stmt_ty TryExcept(asdl_seq * body, asdl_seq * handlers, asdl_seq * orelse, int stmt_ty TryExcept(asdl_seq * body, asdl_seq * handlers, asdl_seq * orelse, int
......
...@@ -38,45 +38,47 @@ ...@@ -38,45 +38,47 @@
#define while_stmt 293 #define while_stmt 293
#define for_stmt 294 #define for_stmt 294
#define try_stmt 295 #define try_stmt 295
#define except_clause 296 #define with_stmt 296
#define suite 297 #define with_var 297
#define testlist_safe 298 #define except_clause 298
#define old_test 299 #define suite 299
#define old_lambdef 300 #define testlist_safe 300
#define test 301 #define old_test 301
#define or_test 302 #define old_lambdef 302
#define and_test 303 #define test 303
#define not_test 304 #define or_test 304
#define comparison 305 #define and_test 305
#define comp_op 306 #define not_test 306
#define expr 307 #define comparison 307
#define xor_expr 308 #define comp_op 308
#define and_expr 309 #define expr 309
#define shift_expr 310 #define xor_expr 310
#define arith_expr 311 #define and_expr 311
#define term 312 #define shift_expr 312
#define factor 313 #define arith_expr 313
#define power 314 #define term 314
#define atom 315 #define factor 315
#define listmaker 316 #define power 316
#define testlist_gexp 317 #define atom 317
#define lambdef 318 #define listmaker 318
#define trailer 319 #define testlist_gexp 319
#define subscriptlist 320 #define lambdef 320
#define subscript 321 #define trailer 321
#define sliceop 322 #define subscriptlist 322
#define exprlist 323 #define subscript 323
#define testlist 324 #define sliceop 324
#define dictmaker 325 #define exprlist 325
#define classdef 326 #define testlist 326
#define arglist 327 #define dictmaker 327
#define argument 328 #define classdef 328
#define list_iter 329 #define arglist 329
#define list_for 330 #define argument 330
#define list_if 331 #define list_iter 331
#define gen_iter 332 #define list_for 332
#define gen_for 333 #define list_if 333
#define gen_if 334 #define gen_iter 334
#define testlist1 335 #define gen_for 335
#define encoding_decl 336 #define gen_if 336
#define yield_expr 337 #define testlist1 337
#define encoding_decl 338
#define yield_expr 339
...@@ -72,13 +72,12 @@ extern "C" { ...@@ -72,13 +72,12 @@ extern "C" {
#define INPLACE_XOR 78 #define INPLACE_XOR 78
#define INPLACE_OR 79 #define INPLACE_OR 79
#define BREAK_LOOP 80 #define BREAK_LOOP 80
#define WITH_CLEANUP 81
#define LOAD_LOCALS 82 #define LOAD_LOCALS 82
#define RETURN_VALUE 83 #define RETURN_VALUE 83
#define IMPORT_STAR 84 #define IMPORT_STAR 84
#define EXEC_STMT 85 #define EXEC_STMT 85
#define YIELD_VALUE 86 #define YIELD_VALUE 86
#define POP_BLOCK 87 #define POP_BLOCK 87
#define END_FINALLY 88 #define END_FINALLY 88
#define BUILD_CLASS 89 #define BUILD_CLASS 89
......
...@@ -553,7 +553,7 @@ class Function(Node): ...@@ -553,7 +553,7 @@ class Function(Node):
self.varargs = 1 self.varargs = 1
if flags & CO_VARKEYWORDS: if flags & CO_VARKEYWORDS:
self.kwargs = 1 self.kwargs = 1
def getChildren(self): def getChildren(self):
...@@ -584,7 +584,7 @@ class GenExpr(Node): ...@@ -584,7 +584,7 @@ class GenExpr(Node):
self.lineno = lineno self.lineno = lineno
self.argnames = ['[outmost-iterable]'] self.argnames = ['[outmost-iterable]']
self.varargs = self.kwargs = None self.varargs = self.kwargs = None
def getChildren(self): def getChildren(self):
...@@ -763,7 +763,7 @@ class Lambda(Node): ...@@ -763,7 +763,7 @@ class Lambda(Node):
self.varargs = 1 self.varargs = 1
if flags & CO_VARKEYWORDS: if flags & CO_VARKEYWORDS:
self.kwargs = 1 self.kwargs = 1
def getChildren(self): def getChildren(self):
...@@ -1297,6 +1297,31 @@ class While(Node): ...@@ -1297,6 +1297,31 @@ class While(Node):
def __repr__(self): def __repr__(self):
return "While(%s, %s, %s)" % (repr(self.test), repr(self.body), repr(self.else_)) return "While(%s, %s, %s)" % (repr(self.test), repr(self.body), repr(self.else_))
class With(Node):
def __init__(self, expr, vars, body, lineno=None):
self.expr = expr
self.vars = vars
self.body = body
self.lineno = lineno
def getChildren(self):
children = []
children.append(self.expr)
children.append(self.vars)
children.append(self.body)
return tuple(children)
def getChildNodes(self):
nodelist = []
nodelist.append(self.expr)
if self.vars is not None:
nodelist.append(self.vars)
nodelist.append(self.body)
return tuple(nodelist)
def __repr__(self):
return "With(%s, %s, %s)" % (repr(self.expr), repr(self.vars), repr(self.body))
class Yield(Node): class Yield(Node):
def __init__(self, value, lineno=None): def __init__(self, value, lineno=None):
self.value = value self.value = value
......
...@@ -41,6 +41,7 @@ def jabs_op(name, op): ...@@ -41,6 +41,7 @@ def jabs_op(name, op):
hasjabs.append(op) hasjabs.append(op)
# Instruction opcodes for compiled code # Instruction opcodes for compiled code
# Blank lines correspond to available opcodes
def_op('STOP_CODE', 0) def_op('STOP_CODE', 0)
def_op('POP_TOP', 1) def_op('POP_TOP', 1)
...@@ -59,7 +60,6 @@ def_op('UNARY_INVERT', 15) ...@@ -59,7 +60,6 @@ def_op('UNARY_INVERT', 15)
def_op('LIST_APPEND', 18) def_op('LIST_APPEND', 18)
def_op('BINARY_POWER', 19) def_op('BINARY_POWER', 19)
def_op('BINARY_MULTIPLY', 20) def_op('BINARY_MULTIPLY', 20)
def_op('BINARY_DIVIDE', 21) def_op('BINARY_DIVIDE', 21)
def_op('BINARY_MODULO', 22) def_op('BINARY_MODULO', 22)
...@@ -70,7 +70,6 @@ def_op('BINARY_FLOOR_DIVIDE', 26) ...@@ -70,7 +70,6 @@ def_op('BINARY_FLOOR_DIVIDE', 26)
def_op('BINARY_TRUE_DIVIDE', 27) def_op('BINARY_TRUE_DIVIDE', 27)
def_op('INPLACE_FLOOR_DIVIDE', 28) def_op('INPLACE_FLOOR_DIVIDE', 28)
def_op('INPLACE_TRUE_DIVIDE', 29) def_op('INPLACE_TRUE_DIVIDE', 29)
def_op('SLICE+0', 30) def_op('SLICE+0', 30)
def_op('SLICE+1', 31) def_op('SLICE+1', 31)
def_op('SLICE+2', 32) def_op('SLICE+2', 32)
...@@ -93,7 +92,6 @@ def_op('INPLACE_DIVIDE', 58) ...@@ -93,7 +92,6 @@ def_op('INPLACE_DIVIDE', 58)
def_op('INPLACE_MODULO', 59) def_op('INPLACE_MODULO', 59)
def_op('STORE_SUBSCR', 60) def_op('STORE_SUBSCR', 60)
def_op('DELETE_SUBSCR', 61) def_op('DELETE_SUBSCR', 61)
def_op('BINARY_LSHIFT', 62) def_op('BINARY_LSHIFT', 62)
def_op('BINARY_RSHIFT', 63) def_op('BINARY_RSHIFT', 63)
def_op('BINARY_AND', 64) def_op('BINARY_AND', 64)
...@@ -113,13 +111,12 @@ def_op('INPLACE_AND', 77) ...@@ -113,13 +111,12 @@ def_op('INPLACE_AND', 77)
def_op('INPLACE_XOR', 78) def_op('INPLACE_XOR', 78)
def_op('INPLACE_OR', 79) def_op('INPLACE_OR', 79)
def_op('BREAK_LOOP', 80) def_op('BREAK_LOOP', 80)
def_op('WITH_CLEANUP', 81)
def_op('LOAD_LOCALS', 82) def_op('LOAD_LOCALS', 82)
def_op('RETURN_VALUE', 83) def_op('RETURN_VALUE', 83)
def_op('IMPORT_STAR', 84) def_op('IMPORT_STAR', 84)
def_op('EXEC_STMT', 85) def_op('EXEC_STMT', 85)
def_op('YIELD_VALUE', 86) def_op('YIELD_VALUE', 86)
def_op('POP_BLOCK', 87) def_op('POP_BLOCK', 87)
def_op('END_FINALLY', 88) def_op('END_FINALLY', 88)
def_op('BUILD_CLASS', 89) def_op('BUILD_CLASS', 89)
...@@ -171,7 +168,6 @@ def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3) ...@@ -171,7 +168,6 @@ def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3)
def_op('CALL_FUNCTION', 131) # #args + (#kwargs << 8) def_op('CALL_FUNCTION', 131) # #args + (#kwargs << 8)
def_op('MAKE_FUNCTION', 132) # Number of args with default values def_op('MAKE_FUNCTION', 132) # Number of args with default values
def_op('BUILD_SLICE', 133) # Number of items def_op('BUILD_SLICE', 133) # Number of items
def_op('MAKE_CLOSURE', 134) def_op('MAKE_CLOSURE', 134)
def_op('LOAD_CLOSURE', 135) def_op('LOAD_CLOSURE', 135)
hasfree.append(135) hasfree.append(135)
...@@ -183,7 +179,6 @@ hasfree.append(137) ...@@ -183,7 +179,6 @@ hasfree.append(137)
def_op('CALL_FUNCTION_VAR', 140) # #args + (#kwargs << 8) def_op('CALL_FUNCTION_VAR', 140) # #args + (#kwargs << 8)
def_op('CALL_FUNCTION_KW', 141) # #args + (#kwargs << 8) def_op('CALL_FUNCTION_KW', 141) # #args + (#kwargs << 8)
def_op('CALL_FUNCTION_VAR_KW', 142) # #args + (#kwargs << 8) def_op('CALL_FUNCTION_VAR_KW', 142) # #args + (#kwargs << 8)
def_op('EXTENDED_ARG', 143) def_op('EXTENDED_ARG', 143)
EXTENDED_ARG = 143 EXTENDED_ARG = 143
......
...@@ -50,48 +50,50 @@ if_stmt = 292 ...@@ -50,48 +50,50 @@ if_stmt = 292
while_stmt = 293 while_stmt = 293
for_stmt = 294 for_stmt = 294
try_stmt = 295 try_stmt = 295
except_clause = 296 with_stmt = 296
suite = 297 with_var = 297
testlist_safe = 298 except_clause = 298
old_test = 299 suite = 299
old_lambdef = 300 testlist_safe = 300
test = 301 old_test = 301
or_test = 302 old_lambdef = 302
and_test = 303 test = 303
not_test = 304 or_test = 304
comparison = 305 and_test = 305
comp_op = 306 not_test = 306
expr = 307 comparison = 307
xor_expr = 308 comp_op = 308
and_expr = 309 expr = 309
shift_expr = 310 xor_expr = 310
arith_expr = 311 and_expr = 311
term = 312 shift_expr = 312
factor = 313 arith_expr = 313
power = 314 term = 314
atom = 315 factor = 315
listmaker = 316 power = 316
testlist_gexp = 317 atom = 317
lambdef = 318 listmaker = 318
trailer = 319 testlist_gexp = 319
subscriptlist = 320 lambdef = 320
subscript = 321 trailer = 321
sliceop = 322 subscriptlist = 322
exprlist = 323 subscript = 323
testlist = 324 sliceop = 324
dictmaker = 325 exprlist = 325
classdef = 326 testlist = 326
arglist = 327 dictmaker = 327
argument = 328 classdef = 328
list_iter = 329 arglist = 329
list_for = 330 argument = 330
list_if = 331 list_iter = 331
gen_iter = 332 list_for = 332
gen_for = 333 list_if = 333
gen_if = 334 gen_iter = 334
testlist1 = 335 gen_for = 335
encoding_decl = 336 gen_if = 336
yield_expr = 337 testlist1 = 337
encoding_decl = 338
yield_expr = 339
#--end constants-- #--end constants--
sym_name = {} sym_name = {}
......
class GeneratorContextManager(object):
def __init__(self, gen):
self.gen = gen
def __context__(self):
return self
def __enter__(self):
try:
return self.gen.next()
except StopIteration:
raise RuntimeError("generator didn't yield")
def __exit__(self, type, value, traceback):
if type is None:
try:
self.gen.next()
except StopIteration:
return
else:
raise RuntimeError("generator didn't stop")
else:
try:
self.gen.throw(type, value, traceback)
except (type, StopIteration):
return
else:
raise RuntimeError("generator caught exception")
def contextmanager(func):
def helper(*args, **kwds):
return GeneratorContextManager(func(*args, **kwds))
return helper
import sys
from collections import deque
class nested(object):
def __init__(self, *contexts):
self.contexts = contexts
self.entered = None
def __context__(self):
return self
def __enter__(self):
if self.entered is not None:
raise RuntimeError("Context is not reentrant")
self.entered = deque()
vars = []
try:
for context in self.contexts:
mgr = context.__context__()
vars.append(mgr.__enter__())
self.entered.appendleft(mgr)
except:
self.__exit__(*sys.exc_info())
raise
return vars
def __exit__(self, *exc_info):
# Behave like nested with statements
# first in, last out
# New exceptions override old ones
ex = exc_info
for mgr in self.entered:
try:
mgr.__exit__(*ex)
except:
ex = sys.exc_info()
self.entered = None
if ex is not exc_info:
raise ex[0], ex[1], ex[2]
This diff is collapsed.
...@@ -62,6 +62,7 @@ Dominic Binks ...@@ -62,6 +62,7 @@ Dominic Binks
Philippe Biondi Philippe Biondi
Stuart Bishop Stuart Bishop
Roy Bixler Roy Bixler
Mike Bland
Martin Bless Martin Bless
Pablo Bleyer Pablo Bleyer
Erik van Blokland Erik van Blokland
......
...@@ -19,6 +19,8 @@ Core and builtins ...@@ -19,6 +19,8 @@ Core and builtins
- dict.__getitem__ now looks for a __missing__ hook before raising - dict.__getitem__ now looks for a __missing__ hook before raising
KeyError. KeyError.
- PEP 343: with statement implemented.
- Fix the encodings package codec search function to only search - Fix the encodings package codec search function to only search
inside its own package. Fixes problem reported in patch #1433198. inside its own package. Fixes problem reported in patch #1433198.
......
...@@ -25,6 +25,7 @@ module Python ...@@ -25,6 +25,7 @@ module Python
| For(expr target, expr iter, stmt* body, stmt* orelse) | For(expr target, expr iter, stmt* body, stmt* orelse)
| While(expr test, stmt* body, stmt* orelse) | While(expr test, stmt* body, stmt* orelse)
| If(expr test, stmt* body, stmt* orelse) | If(expr test, stmt* body, stmt* orelse)
| With(expr context_expr, expr? optional_vars, stmt* body)
-- 'type' is a bad name -- 'type' is a bad name
| Raise(expr? type, expr? inst, expr? tback) | Raise(expr? type, expr? inst, expr? tback)
......
...@@ -84,6 +84,12 @@ char *If_fields[]={ ...@@ -84,6 +84,12 @@ char *If_fields[]={
"body", "body",
"orelse", "orelse",
}; };
PyTypeObject *With_type;
char *With_fields[]={
"context_expr",
"optional_vars",
"body",
};
PyTypeObject *Raise_type; PyTypeObject *Raise_type;
char *Raise_fields[]={ char *Raise_fields[]={
"type", "type",
...@@ -465,6 +471,8 @@ static int init_types(void) ...@@ -465,6 +471,8 @@ static int init_types(void)
if (!While_type) return 0; if (!While_type) return 0;
If_type = make_type("If", stmt_type, If_fields, 3); If_type = make_type("If", stmt_type, If_fields, 3);
if (!If_type) return 0; if (!If_type) return 0;
With_type = make_type("With", stmt_type, With_fields, 3);
if (!With_type) return 0;
Raise_type = make_type("Raise", stmt_type, Raise_fields, 3); Raise_type = make_type("Raise", stmt_type, Raise_fields, 3);
if (!Raise_type) return 0; if (!Raise_type) return 0;
TryExcept_type = make_type("TryExcept", stmt_type, TryExcept_fields, 3); TryExcept_type = make_type("TryExcept", stmt_type, TryExcept_fields, 3);
...@@ -999,6 +1007,29 @@ If(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, PyArena *arena) ...@@ -999,6 +1007,29 @@ If(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, PyArena *arena)
return p; return p;
} }
stmt_ty
With(expr_ty context_expr, expr_ty optional_vars, asdl_seq * body, int lineno,
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) {
PyErr_NoMemory();
return NULL;
}
p->kind = With_kind;
p->v.With.context_expr = context_expr;
p->v.With.optional_vars = optional_vars;
p->v.With.body = body;
p->lineno = lineno;
return p;
}
stmt_ty stmt_ty
Raise(expr_ty type, expr_ty inst, expr_ty tback, int lineno, PyArena *arena) Raise(expr_ty type, expr_ty inst, expr_ty tback, int lineno, PyArena *arena)
{ {
...@@ -2062,6 +2093,26 @@ ast2obj_stmt(void* _o) ...@@ -2062,6 +2093,26 @@ ast2obj_stmt(void* _o)
goto failed; goto failed;
Py_DECREF(value); Py_DECREF(value);
break; break;
case With_kind:
result = PyType_GenericNew(With_type, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(o->v.With.context_expr);
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)
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;
case Raise_kind: case Raise_kind:
result = PyType_GenericNew(Raise_type, NULL, NULL); result = PyType_GenericNew(Raise_type, NULL, NULL);
if (!result) goto failed; if (!result) goto failed;
...@@ -2922,6 +2973,7 @@ init_ast(void) ...@@ -2922,6 +2973,7 @@ init_ast(void)
if(PyDict_SetItemString(d, "For", (PyObject*)For_type) < 0) return; if(PyDict_SetItemString(d, "For", (PyObject*)For_type) < 0) return;
if(PyDict_SetItemString(d, "While", (PyObject*)While_type) < 0) return; if(PyDict_SetItemString(d, "While", (PyObject*)While_type) < 0) return;
if(PyDict_SetItemString(d, "If", (PyObject*)If_type) < 0) return; if(PyDict_SetItemString(d, "If", (PyObject*)If_type) < 0) return;
if(PyDict_SetItemString(d, "With", (PyObject*)With_type) < 0) return;
if(PyDict_SetItemString(d, "Raise", (PyObject*)Raise_type) < 0) return; if(PyDict_SetItemString(d, "Raise", (PyObject*)Raise_type) < 0) return;
if(PyDict_SetItemString(d, "TryExcept", (PyObject*)TryExcept_type) < 0) if(PyDict_SetItemString(d, "TryExcept", (PyObject*)TryExcept_type) < 0)
return; return;
......
...@@ -314,7 +314,7 @@ get_operator(const node *n) ...@@ -314,7 +314,7 @@ get_operator(const node *n)
} }
} }
/* Set the context ctx for expr_ty e returning 0 on success, -1 on error. /* Set the context ctx for expr_ty e returning 1 on success, 0 on error.
Only sets context for expr kinds that "can appear in assignment context" Only sets context for expr kinds that "can appear in assignment context"
(according to ../Parser/Python.asdl). For other expr kinds, it sets (according to ../Parser/Python.asdl). For other expr kinds, it sets
...@@ -339,7 +339,7 @@ set_context(expr_ty e, expr_context_ty ctx, const node *n) ...@@ -339,7 +339,7 @@ set_context(expr_ty e, expr_context_ty ctx, const node *n)
a little more complex than necessary as a result. It also means a little more complex than necessary as a result. It also means
that expressions in an augmented assignment have no context. that expressions in an augmented assignment have no context.
Consider restructuring so that augmented assignment uses Consider restructuring so that augmented assignment uses
set_context(), too set_context(), too.
*/ */
assert(ctx != AugStore && ctx != AugLoad); assert(ctx != AugStore && ctx != AugLoad);
...@@ -2713,6 +2713,46 @@ ast_for_try_stmt(struct compiling *c, const node *n) ...@@ -2713,6 +2713,46 @@ ast_for_try_stmt(struct compiling *c, const node *n)
return TryFinally(body, finally, LINENO(n), c->c_arena); return TryFinally(body, finally, LINENO(n), c->c_arena);
} }
static expr_ty
ast_for_with_var(struct compiling *c, const node *n)
{
REQ(n, with_var);
if (strcmp(STR(CHILD(n, 0)), "as") != 0) {
ast_error(n, "expected \"with [expr] as [var]\"");
return NULL;
}
return ast_for_expr(c, CHILD(n, 1));
}
/* with_stmt: 'with' test [ with_var ] ':' suite */
static stmt_ty
ast_for_with_stmt(struct compiling *c, const node *n)
{
expr_ty context_expr, optional_vars = NULL;
int suite_index = 3; /* skip 'with', test, and ':' */
asdl_seq *suite_seq;
assert(TYPE(n) == with_stmt);
context_expr = ast_for_expr(c, CHILD(n, 1));
if (TYPE(CHILD(n, 2)) == with_var) {
optional_vars = ast_for_with_var(c, CHILD(n, 2));
if (!optional_vars) {
return NULL;
}
if (!set_context(optional_vars, Store, n)) {
return NULL;
}
suite_index = 4;
}
suite_seq = ast_for_suite(c, CHILD(n, suite_index));
if (!suite_seq) {
return NULL;
}
return With(context_expr, optional_vars, suite_seq, LINENO(n), c->c_arena);
}
static stmt_ty static stmt_ty
ast_for_classdef(struct compiling *c, const node *n) ast_for_classdef(struct compiling *c, const node *n)
{ {
...@@ -2813,6 +2853,8 @@ ast_for_stmt(struct compiling *c, const node *n) ...@@ -2813,6 +2853,8 @@ ast_for_stmt(struct compiling *c, const node *n)
return ast_for_for_stmt(c, ch); return ast_for_for_stmt(c, ch);
case try_stmt: case try_stmt:
return ast_for_try_stmt(c, ch); return ast_for_try_stmt(c, ch);
case with_stmt:
return ast_for_with_stmt(c, ch);
case funcdef: case funcdef:
return ast_for_funcdef(c, ch); return ast_for_funcdef(c, ch);
case classdef: case classdef:
......
...@@ -97,6 +97,7 @@ static PyObject *load_args(PyObject ***, int); ...@@ -97,6 +97,7 @@ static PyObject *load_args(PyObject ***, int);
#define CALL_FLAG_KW 2 #define CALL_FLAG_KW 2
#ifdef LLTRACE #ifdef LLTRACE
static int lltrace;
static int prtrace(PyObject *, char *); static int prtrace(PyObject *, char *);
#endif #endif
static int call_trace(Py_tracefunc, PyObject *, PyFrameObject *, static int call_trace(Py_tracefunc, PyObject *, PyFrameObject *,
...@@ -540,9 +541,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throw) ...@@ -540,9 +541,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throw)
unsigned char *first_instr; unsigned char *first_instr;
PyObject *names; PyObject *names;
PyObject *consts; PyObject *consts;
#ifdef LLTRACE
int lltrace;
#endif
#if defined(Py_DEBUG) || defined(LLTRACE) #if defined(Py_DEBUG) || defined(LLTRACE)
/* Make it easier to find out where we are with a debugger */ /* Make it easier to find out where we are with a debugger */
char *filename; char *filename;
...@@ -661,10 +659,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throw) ...@@ -661,10 +659,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throw)
#define STACKADJ(n) { (void)(BASIC_STACKADJ(n), \ #define STACKADJ(n) { (void)(BASIC_STACKADJ(n), \
lltrace && prtrace(TOP(), "stackadj")); \ lltrace && prtrace(TOP(), "stackadj")); \
assert(STACK_LEVEL() <= f->f_stacksize); } assert(STACK_LEVEL() <= f->f_stacksize); }
#define EXT_POP(STACK_POINTER) (lltrace && prtrace(*(STACK_POINTER), "ext_pop"), *--(STACK_POINTER))
#else #else
#define PUSH(v) BASIC_PUSH(v) #define PUSH(v) BASIC_PUSH(v)
#define POP() BASIC_POP() #define POP() BASIC_POP()
#define STACKADJ(n) BASIC_STACKADJ(n) #define STACKADJ(n) BASIC_STACKADJ(n)
#define EXT_POP(STACK_POINTER) (*--(STACK_POINTER))
#endif #endif
/* Local variable macros */ /* Local variable macros */
...@@ -2172,6 +2172,43 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throw) ...@@ -2172,6 +2172,43 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throw)
STACK_LEVEL()); STACK_LEVEL());
continue; continue;
case WITH_CLEANUP:
{
/* TOP is the context.__exit__ bound method.
Below that are 1-3 values indicating how/why
we entered the finally clause:
- SECOND = None
- (SECOND, THIRD) = (WHY_RETURN or WHY_CONTINUE), retval
- SECOND = WHY_*; no retval below it
- (SECOND, THIRD, FOURTH) = exc_info()
In the last case, we must call
TOP(SECOND, THIRD, FOURTH)
otherwise we must call
TOP(None, None, None)
but we must preserve the stack entries below TOP.
The code here just sets the stack up for the call;
separate CALL_FUNCTION(3) and POP_TOP opcodes are
emitted by the compiler.
*/
x = TOP();
u = SECOND();
if (PyInt_Check(u) || u == Py_None) {
u = v = w = Py_None;
}
else {
v = THIRD();
w = FOURTH();
}
Py_INCREF(u);
Py_INCREF(v);
Py_INCREF(w);
PUSH(u);
PUSH(v);
PUSH(w);
break;
}
case CALL_FUNCTION: case CALL_FUNCTION:
{ {
PyObject **sp; PyObject **sp;
...@@ -2511,9 +2548,9 @@ fast_yield: ...@@ -2511,9 +2548,9 @@ fast_yield:
return retval; return retval;
} }
/* this is gonna seem *real weird*, but if you put some other code between /* This is gonna seem *real weird*, but if you put some other code between
PyEval_EvalFrame() and PyEval_EvalCodeEx() you will need to adjust PyEval_EvalFrame() and PyEval_EvalCodeEx() you will need to adjust
the test in the if statement in Misc/gdbinit:pystack* */ the test in the if statements in Misc/gdbinit (pystack and pystackv). */
PyObject * PyObject *
PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
...@@ -3473,8 +3510,6 @@ PyEval_GetFuncDesc(PyObject *func) ...@@ -3473,8 +3510,6 @@ PyEval_GetFuncDesc(PyObject *func)
} }
} }
#define EXT_POP(STACK_POINTER) (*--(STACK_POINTER))
static void static void
err_args(PyObject *func, int flags, int nargs) err_args(PyObject *func, int flags, int nargs)
{ {
......
...@@ -191,6 +191,8 @@ static void compiler_pop_fblock(struct compiler *, enum fblocktype, ...@@ -191,6 +191,8 @@ static void compiler_pop_fblock(struct compiler *, enum fblocktype,
static int inplace_binop(struct compiler *, operator_ty); static int inplace_binop(struct compiler *, operator_ty);
static int expr_constant(expr_ty e); static int expr_constant(expr_ty e);
static int compiler_with(struct compiler *, stmt_ty);
static PyCodeObject *assemble(struct compiler *, int addNone); static PyCodeObject *assemble(struct compiler *, int addNone);
static PyObject *__doc__; static PyObject *__doc__;
...@@ -289,6 +291,7 @@ PyAST_Compile(mod_ty mod, const char *filename, PyCompilerFlags *flags, ...@@ -289,6 +291,7 @@ PyAST_Compile(mod_ty mod, const char *filename, PyCompilerFlags *flags,
error: error:
compiler_free(&c); compiler_free(&c);
assert(!PyErr_Occurred());
return co; return co;
} }
...@@ -1157,6 +1160,18 @@ compiler_exit_scope(struct compiler *c) ...@@ -1157,6 +1160,18 @@ compiler_exit_scope(struct compiler *c)
} }
/* Allocate a new "anonymous" local variable.
Used by list comprehensions and with statements.
*/
static PyObject *
compiler_new_tmpname(struct compiler *c)
{
char tmpname[256];
PyOS_snprintf(tmpname, sizeof(tmpname), "_[%d]", ++c->u->u_tmpname);
return PyString_FromString(tmpname);
}
/* Allocate a new block and return a pointer to it. /* Allocate a new block and return a pointer to it.
Returns NULL on error. Returns NULL on error.
*/ */
...@@ -1360,7 +1375,8 @@ opcode_stack_effect(int opcode, int oparg) ...@@ -1360,7 +1375,8 @@ opcode_stack_effect(int opcode, int oparg)
return -1; return -1;
case BREAK_LOOP: case BREAK_LOOP:
return 0; return 0;
case WITH_CLEANUP:
return 3;
case LOAD_LOCALS: case LOAD_LOCALS:
return 1; return 1;
case RETURN_VALUE: case RETURN_VALUE:
...@@ -2663,6 +2679,8 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s) ...@@ -2663,6 +2679,8 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s)
break; break;
case Continue_kind: case Continue_kind:
return compiler_continue(c); return compiler_continue(c);
case With_kind:
return compiler_with(c, s);
} }
return 1; return 1;
} }
...@@ -3124,7 +3142,6 @@ compiler_listcomp_generator(struct compiler *c, PyObject *tmpname, ...@@ -3124,7 +3142,6 @@ compiler_listcomp_generator(struct compiler *c, PyObject *tmpname,
static int static int
compiler_listcomp(struct compiler *c, expr_ty e) compiler_listcomp(struct compiler *c, expr_ty e)
{ {
char tmpname[256];
identifier tmp; identifier tmp;
int rc = 0; int rc = 0;
static identifier append; static identifier append;
...@@ -3136,8 +3153,7 @@ compiler_listcomp(struct compiler *c, expr_ty e) ...@@ -3136,8 +3153,7 @@ compiler_listcomp(struct compiler *c, expr_ty e)
if (!append) if (!append)
return 0; return 0;
} }
PyOS_snprintf(tmpname, sizeof(tmpname), "_[%d]", ++c->u->u_tmpname); tmp = compiler_new_tmpname(c);
tmp = PyString_FromString(tmpname);
if (!tmp) if (!tmp)
return 0; return 0;
ADDOP_I(c, BUILD_LIST, 0); ADDOP_I(c, BUILD_LIST, 0);
...@@ -3291,6 +3307,148 @@ expr_constant(expr_ty e) ...@@ -3291,6 +3307,148 @@ expr_constant(expr_ty e)
} }
} }
/*
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).__context__()
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 context_attr, enter_attr, exit_attr;
basicblock *block, *finally;
identifier tmpexit, tmpvalue = NULL;
assert(s->kind == With_kind);
if (!context_attr) {
context_attr = PyString_InternFromString("__context__");
if (!context_attr)
return 0;
}
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).__context__() */
VISIT(c, expr, s->v.With.context_expr);
ADDOP_O(c, LOAD_ATTR, context_attr, names);
ADDOP_I(c, CALL_FUNCTION, 0);
/* 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))
return 0;
}
else {
/* Discard result from context.__enter__() */
ADDOP(c, POP_TOP);
}
/* Start the try block */
ADDOP_JREL(c, SETUP_FINALLY, finally);
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);
}
/* BLOCK code */
VISIT_SEQ(c, stmt, s->v.With.body);
/* 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))
return 0;
/* Finally block starts; push tmpexit and issue our magic opcode. */
if (!compiler_nameop(c, tmpexit, Load) ||
!compiler_nameop(c, tmpexit, Del))
return 0;
ADDOP(c, WITH_CLEANUP);
ADDOP_I(c, CALL_FUNCTION, 3);
ADDOP(c, POP_TOP);
/* Finally block ends. */
ADDOP(c, END_FINALLY);
compiler_pop_fblock(c, FINALLY_END, finally);
return 1;
}
static int static int
compiler_visit_expr(struct compiler *c, expr_ty e) compiler_visit_expr(struct compiler *c, expr_ty e)
{ {
......
This diff is collapsed.
...@@ -54,9 +54,10 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *); ...@@ -54,9 +54,10 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *);
Python 2.4b1: 62061 Python 2.4b1: 62061
Python 2.5a0: 62071 Python 2.5a0: 62071
Python 2.5a0: 62081 (ast-branch) Python 2.5a0: 62081 (ast-branch)
Python 2.5a0: 62091 (with)
. .
*/ */
#define MAGIC (62081 | ((long)'\r'<<16) | ((long)'\n'<<24)) #define MAGIC (62091 | ((long)'\r'<<16) | ((long)'\n'<<24))
/* Magic word as global; note that _PyImport_Init() can change the /* Magic word as global; note that _PyImport_Init() can change the
value of this global to accommodate for alterations of how the value of this global to accommodate for alterations of how the
......
...@@ -890,6 +890,21 @@ error: ...@@ -890,6 +890,21 @@ error:
} \ } \
} }
static int
symtable_new_tmpname(struct symtable *st)
{
char tmpname[256];
identifier tmp;
PyOS_snprintf(tmpname, sizeof(tmpname), "_[%d]",
++st->st_cur->ste_tmpname);
tmp = PyString_InternFromString(tmpname);
if (!symtable_add_def(st, tmp, DEF_LOCAL))
return 0;
Py_DECREF(tmp);
return 1;
}
static int static int
symtable_visit_stmt(struct symtable *st, stmt_ty s) symtable_visit_stmt(struct symtable *st, stmt_ty s)
{ {
...@@ -1051,6 +1066,17 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) ...@@ -1051,6 +1066,17 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
case Continue_kind: case Continue_kind:
/* nothing to do here */ /* nothing to do here */
break; break;
case With_kind:
if (!symtable_new_tmpname(st))
return 0;
VISIT(st, expr, s->v.With.context_expr);
if (s->v.With.optional_vars) {
if (!symtable_new_tmpname(st))
return 0;
VISIT(st, expr, s->v.With.optional_vars);
}
VISIT_SEQ(st, stmt, s->v.With.body);
break;
} }
return 1; return 1;
} }
...@@ -1093,26 +1119,16 @@ symtable_visit_expr(struct symtable *st, expr_ty e) ...@@ -1093,26 +1119,16 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
VISIT_SEQ(st, expr, e->v.Dict.keys); VISIT_SEQ(st, expr, e->v.Dict.keys);
VISIT_SEQ(st, expr, e->v.Dict.values); VISIT_SEQ(st, expr, e->v.Dict.values);
break; break;
case ListComp_kind: { case ListComp_kind:
char tmpname[256]; if (!symtable_new_tmpname(st))
identifier tmp;
PyOS_snprintf(tmpname, sizeof(tmpname), "_[%d]",
++st->st_cur->ste_tmpname);
tmp = PyString_InternFromString(tmpname);
if (!symtable_add_def(st, tmp, DEF_LOCAL))
return 0; return 0;
Py_DECREF(tmp);
VISIT(st, expr, e->v.ListComp.elt); VISIT(st, expr, e->v.ListComp.elt);
VISIT_SEQ(st, comprehension, e->v.ListComp.generators); VISIT_SEQ(st, comprehension, e->v.ListComp.generators);
break; break;
} case GeneratorExp_kind:
case GeneratorExp_kind: { if (!symtable_visit_genexp(st, e))
if (!symtable_visit_genexp(st, e)) {
return 0; return 0;
}
break; break;
}
case Yield_kind: case Yield_kind:
if (e->v.Yield.value) if (e->v.Yield.value)
VISIT(st, expr, e->v.Yield.value); VISIT(st, expr, e->v.Yield.value);
......
...@@ -20,6 +20,7 @@ Break: ...@@ -20,6 +20,7 @@ Break:
Continue: Continue:
For: assign, list, body, else_& For: assign, list, body, else_&
While: test, body, else_& While: test, body, else_&
With: expr, vars&, body
If: tests!, else_& If: tests!, else_&
Exec: expr, locals&, globals& Exec: expr, locals&, globals&
From: modname*, names* From: modname*, names*
...@@ -42,7 +43,7 @@ AssAttr: expr, attrname*, flags* ...@@ -42,7 +43,7 @@ AssAttr: expr, attrname*, flags*
ListComp: expr, quals! ListComp: expr, quals!
ListCompFor: assign, list, ifs! ListCompFor: assign, list, ifs!
ListCompIf: test ListCompIf: test
GenExpr: code GenExpr: code
GenExprInner: expr, quals! GenExprInner: expr, quals!
GenExprFor: assign, iter, ifs! GenExprFor: assign, iter, ifs!
GenExprIf: test GenExprIf: test
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment