PEP 308 implementation, including minor refdocs and some testcases. It

breaks the parser module, because it adds the if/else construct as well as
two new grammar rules for backward compatibility. If no one else fixes
parsermodule, I guess I'll go ahead and fix it later this week.

The TeX code was checked with texcheck.py, but not rendered. There is
actually a slight incompatibility:

>>> (x for x in lambda:0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: iteration over non-sequence

changes into

>>> (x for x in lambda: 0)
  File "<stdin>", line 1
    (x for x in lambda: 0)
                     ^
SyntaxError: invalid syntax

Since there's no way the former version can be useful, it's probably a
bugfix ;)
This commit is contained in:
Thomas Wouters 2006-02-27 00:24:13 +00:00
parent d3a5f53a27
commit dca3b9c797
11 changed files with 878 additions and 642 deletions

View file

@ -151,6 +151,12 @@ char *Lambda_fields[]={
"args",
"body",
};
PyTypeObject *IfExp_type;
char *IfExp_fields[]={
"test",
"body",
"orelse",
};
PyTypeObject *Dict_type;
char *Dict_fields[]={
"keys",
@ -431,6 +437,7 @@ static int init_types(void)
BinOp_type = make_type("BinOp", expr_type, BinOp_fields, 3);
UnaryOp_type = make_type("UnaryOp", expr_type, UnaryOp_fields, 2);
Lambda_type = make_type("Lambda", expr_type, Lambda_fields, 2);
IfExp_type = make_type("IfExp", expr_type, IfExp_fields, 3);
Dict_type = make_type("Dict", expr_type, Dict_fields, 2);
ListComp_type = make_type("ListComp", expr_type, ListComp_fields, 2);
GeneratorExp_type = make_type("GeneratorExp", expr_type,
@ -1137,6 +1144,38 @@ Lambda(arguments_ty args, expr_ty body, int lineno, PyArena *arena)
return p;
}
expr_ty
IfExp(expr_ty test, expr_ty body, expr_ty orelse, int lineno, PyArena *arena)
{
expr_ty p;
if (!test) {
PyErr_SetString(PyExc_ValueError,
"field test is required for IfExp");
return NULL;
}
if (!body) {
PyErr_SetString(PyExc_ValueError,
"field body is required for IfExp");
return NULL;
}
if (!orelse) {
PyErr_SetString(PyExc_ValueError,
"field orelse is required for IfExp");
return NULL;
}
p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
if (!p) {
PyErr_NoMemory();
return NULL;
}
p->kind = IfExp_kind;
p->v.IfExp.test = test;
p->v.IfExp.body = body;
p->v.IfExp.orelse = orelse;
p->lineno = lineno;
return p;
}
expr_ty
Dict(asdl_seq * keys, asdl_seq * values, int lineno, PyArena *arena)
{
@ -2077,6 +2116,25 @@ ast2obj_expr(void* _o)
goto failed;
Py_DECREF(value);
break;
case IfExp_kind:
result = PyType_GenericNew(IfExp_type, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(o->v.IfExp.test);
if (!value) goto failed;
if (PyObject_SetAttrString(result, "test", value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(o->v.IfExp.body);
if (!value) goto failed;
if (PyObject_SetAttrString(result, "body", value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(o->v.IfExp.orelse);
if (!value) goto failed;
if (PyObject_SetAttrString(result, "orelse", value) == -1)
goto failed;
Py_DECREF(value);
break;
case Dict_kind:
result = PyType_GenericNew(Dict_type, NULL, NULL);
if (!result) goto failed;

View file

@ -847,6 +847,25 @@ ast_for_lambdef(struct compiling *c, const node *n)
return Lambda(args, expression, LINENO(n), c->c_arena);
}
static expr_ty
ast_for_ifexpr(struct compiling *c, const node *n)
{
/* test: or_test 'if' or_test 'else' test */
expr_ty expression, body, orelse;
assert(NCH(n) >= 3);
body = ast_for_expr(c, CHILD(n, 0));
if (!body)
return NULL;
expression = ast_for_expr(c, CHILD(n, 2));
if (!expression)
return NULL;
orelse = ast_for_expr(c, CHILD(n, 4));
if (!orelse)
return NULL;
return IfExp(expression, body, orelse, LINENO(n), c->c_arena);
}
/* Count the number of 'for' loop in a list comprehension.
Helper for ast_for_listcomp().
@ -1456,7 +1475,8 @@ static expr_ty
ast_for_expr(struct compiling *c, const node *n)
{
/* handle the full range of simple expressions
test: and_test ('or' and_test)* | lambdef
test: or_test ['if' or_test 'else' test] | lambdef
or_test: and_test ('or' and_test)*
and_test: not_test ('and' not_test)*
not_test: 'not' not_test | comparison
comparison: expr (comp_op expr)*
@ -1468,6 +1488,15 @@ ast_for_expr(struct compiling *c, const node *n)
term: factor (('*'|'/'|'%'|'//') factor)*
factor: ('+'|'-'|'~') factor | power
power: atom trailer* ('**' factor)*
As well as modified versions that exist for backward compatibility,
to explicitly allow:
[ x for x in lambda: 0, lambda: 1 ]
(which would be ambiguous without these extra rules)
old_test: or_test | old_lambdef
old_lambdef: 'lambda' [vararglist] ':' old_test
*/
asdl_seq *seq;
@ -1476,9 +1505,14 @@ ast_for_expr(struct compiling *c, const node *n)
loop:
switch (TYPE(n)) {
case test:
if (TYPE(CHILD(n, 0)) == lambdef)
case old_test:
if (TYPE(CHILD(n, 0)) == lambdef ||
TYPE(CHILD(n, 0)) == old_lambdef)
return ast_for_lambdef(c, CHILD(n, 0));
/* Fall through to and_test */
else if (NCH(n) > 1)
return ast_for_ifexpr(c, n);
/* Fallthrough */
case or_test:
case and_test:
if (NCH(n) == 1) {
n = CHILD(n, 0);

View file

@ -2009,6 +2009,30 @@ compiler_class(struct compiler *c, stmt_ty s)
return 1;
}
static int
compiler_ifexp(struct compiler *c, expr_ty e)
{
basicblock *end, *next;
assert(e->kind == IfExp_kind);
end = compiler_new_block(c);
if (end == NULL)
return 0;
next = compiler_new_block(c);
if (next == NULL)
return 0;
VISIT(c, expr, e->v.IfExp.test);
ADDOP_JREL(c, JUMP_IF_FALSE, next);
ADDOP(c, POP_TOP);
VISIT(c, expr, e->v.IfExp.body);
ADDOP_JREL(c, JUMP_FORWARD, end);
compiler_use_next_block(c, next);
ADDOP(c, POP_TOP);
VISIT(c, expr, e->v.IfExp.orelse);
compiler_use_next_block(c, end);
return 1;
}
static int
compiler_lambda(struct compiler *c, expr_ty e)
{
@ -3290,6 +3314,8 @@ compiler_visit_expr(struct compiler *c, expr_ty e)
break;
case Lambda_kind:
return compiler_lambda(c, e);
case IfExp_kind:
return compiler_ifexp(c, e);
case Dict_kind:
/* XXX get rid of arg? */
ADDOP_I(c, BUILD_MAP, 0);

File diff suppressed because it is too large Load diff

View file

@ -1084,6 +1084,11 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
return 0;
break;
}
case IfExp_kind:
VISIT(st, expr, e->v.IfExp.test);
VISIT(st, expr, e->v.IfExp.body);
VISIT(st, expr, e->v.IfExp.orelse);
break;
case Dict_kind:
VISIT_SEQ(st, expr, e->v.Dict.keys);
VISIT_SEQ(st, expr, e->v.Dict.values);