Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit dca3b9c

Browse files
committed
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 ;)
1 parent d3a5f53 commit dca3b9c

11 files changed

Lines changed: 803 additions & 567 deletions

File tree

Doc/ref/ref5.tex

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,7 @@ \subsection{List displays\label{lists}}
155155

156156
\begin{productionlist}
157157
\production{test}
158-
{\token{and_test} ( "or" \token{and_test} )*
159-
| \token{lambda_form}}
158+
{\token{or_test} | \token{lambda_form}}
160159
\production{testlist}
161160
{\token{test} ( "," \token{test} )* [ "," ]}
162161
\production{list_display}
@@ -1017,7 +1016,8 @@ \section{Boolean operations\label{Booleans}}
10171016
10181017
\begin{productionlist}
10191018
\production{expression}
1020-
{\token{or_test} | \token{lambda_form}}
1019+
{\token{or_test} [\token{if} \token{or_test} \token{else}
1020+
\token{test}] | \token{lambda_form}}
10211021
\production{or_test}
10221022
{\token{and_test} | \token{or_test} "or" \token{and_test}}
10231023
\production{and_test}
@@ -1036,6 +1036,11 @@ \section{Boolean operations\label{Booleans}}
10361036
\code{False} otherwise.
10371037
\opindex{not}
10381038
1039+
The expression \code{\var{x} if \var{C} else \var{y}} first evaluates
1040+
\var{C} (\emph{not} \var{x}); if \var{C} is true, \var{x} is evaluated and
1041+
its value is returned; otherwise, \var{y} is evaluated and its value is
1042+
returned.
1043+
10391044
The expression \code{\var{x} and \var{y}} first evaluates \var{x}; if
10401045
\var{x} is false, its value is returned; otherwise, \var{y} is
10411046
evaluated and the resulting value is returned.

Grammar/Grammar

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,17 @@ try_stmt: ('try' ':' suite
8383
except_clause: 'except' [test [',' test]]
8484
suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
8585

86-
test: and_test ('or' and_test)* | lambdef
86+
# Backward compatibility cruft to support:
87+
# [ x for x in lambda: True, lambda: False if x() ]
88+
# even while also allowing:
89+
# lambda x: 5 if x else 2
90+
# (But not a mix of the two)
91+
testlist_safe: old_test [(',' old_test)+ [',']]
92+
old_test: or_test | old_lambdef
93+
old_lambdef: 'lambda' [varargslist] ':' old_test
94+
95+
test: or_test ['if' or_test 'else' test] | lambdef
96+
or_test: and_test ('or' and_test)*
8797
and_test: not_test ('and' not_test)*
8898
not_test: 'not' not_test | comparison
8999
comparison: expr (comp_op expr)*
@@ -110,7 +120,6 @@ subscript: '.' '.' '.' | test | [test] ':' [test] [sliceop]
110120
sliceop: ':' [test]
111121
exprlist: expr (',' expr)* [',']
112122
testlist: test (',' test)* [',']
113-
testlist_safe: test [(',' test)+ [',']]
114123
dictmaker: test ':' test (',' test ':' test)* [',']
115124

116125
classdef: 'class' NAME ['(' [testlist] ')'] ':' suite
@@ -123,7 +132,7 @@ list_for: 'for' exprlist 'in' testlist_safe [list_iter]
123132
list_if: 'if' test [list_iter]
124133

125134
gen_iter: gen_for | gen_if
126-
gen_for: 'for' exprlist 'in' test [gen_iter]
135+
gen_for: 'for' exprlist 'in' or_test [gen_iter]
127136
gen_if: 'if' test [gen_iter]
128137

129138
testlist1: test (',' test)*

Include/Python-ast.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,10 @@ struct _stmt {
175175

176176
struct _expr {
177177
enum { BoolOp_kind=1, BinOp_kind=2, UnaryOp_kind=3, Lambda_kind=4,
178-
Dict_kind=5, ListComp_kind=6, GeneratorExp_kind=7, Yield_kind=8,
179-
Compare_kind=9, Call_kind=10, Repr_kind=11, Num_kind=12,
180-
Str_kind=13, Attribute_kind=14, Subscript_kind=15, Name_kind=16,
181-
List_kind=17, Tuple_kind=18 } kind;
178+
IfExp_kind=5, Dict_kind=6, ListComp_kind=7, GeneratorExp_kind=8,
179+
Yield_kind=9, Compare_kind=10, Call_kind=11, Repr_kind=12,
180+
Num_kind=13, Str_kind=14, Attribute_kind=15, Subscript_kind=16,
181+
Name_kind=17, List_kind=18, Tuple_kind=19 } kind;
182182
union {
183183
struct {
184184
boolop_ty op;
@@ -201,6 +201,12 @@ struct _expr {
201201
expr_ty body;
202202
} Lambda;
203203

204+
struct {
205+
expr_ty test;
206+
expr_ty body;
207+
expr_ty orelse;
208+
} IfExp;
209+
204210
struct {
205211
asdl_seq *keys;
206212
asdl_seq *values;
@@ -371,6 +377,8 @@ expr_ty BinOp(expr_ty left, operator_ty op, expr_ty right, int lineno, PyArena
371377
*arena);
372378
expr_ty UnaryOp(unaryop_ty op, expr_ty operand, int lineno, PyArena *arena);
373379
expr_ty Lambda(arguments_ty args, expr_ty body, int lineno, PyArena *arena);
380+
expr_ty IfExp(expr_ty test, expr_ty body, expr_ty orelse, int lineno, PyArena
381+
*arena);
374382
expr_ty Dict(asdl_seq * keys, asdl_seq * values, int lineno, PyArena *arena);
375383
expr_ty ListComp(expr_ty elt, asdl_seq * generators, int lineno, PyArena
376384
*arena);

Include/graminit.h

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -40,40 +40,43 @@
4040
#define try_stmt 295
4141
#define except_clause 296
4242
#define suite 297
43-
#define test 298
44-
#define and_test 299
45-
#define not_test 300
46-
#define comparison 301
47-
#define comp_op 302
48-
#define expr 303
49-
#define xor_expr 304
50-
#define and_expr 305
51-
#define shift_expr 306
52-
#define arith_expr 307
53-
#define term 308
54-
#define factor 309
55-
#define power 310
56-
#define atom 311
57-
#define listmaker 312
58-
#define testlist_gexp 313
59-
#define lambdef 314
60-
#define trailer 315
61-
#define subscriptlist 316
62-
#define subscript 317
63-
#define sliceop 318
64-
#define exprlist 319
65-
#define testlist 320
66-
#define testlist_safe 321
67-
#define dictmaker 322
68-
#define classdef 323
69-
#define arglist 324
70-
#define argument 325
71-
#define list_iter 326
72-
#define list_for 327
73-
#define list_if 328
74-
#define gen_iter 329
75-
#define gen_for 330
76-
#define gen_if 331
77-
#define testlist1 332
78-
#define encoding_decl 333
79-
#define yield_expr 334
43+
#define testlist_safe 298
44+
#define old_test 299
45+
#define old_lambdef 300
46+
#define test 301
47+
#define or_test 302
48+
#define and_test 303
49+
#define not_test 304
50+
#define comparison 305
51+
#define comp_op 306
52+
#define expr 307
53+
#define xor_expr 308
54+
#define and_expr 309
55+
#define shift_expr 310
56+
#define arith_expr 311
57+
#define term 312
58+
#define factor 313
59+
#define power 314
60+
#define atom 315
61+
#define listmaker 316
62+
#define testlist_gexp 317
63+
#define lambdef 318
64+
#define trailer 319
65+
#define subscriptlist 320
66+
#define subscript 321
67+
#define sliceop 322
68+
#define exprlist 323
69+
#define testlist 324
70+
#define dictmaker 325
71+
#define classdef 326
72+
#define arglist 327
73+
#define argument 328
74+
#define list_iter 329
75+
#define list_for 330
76+
#define list_if 331
77+
#define gen_iter 332
78+
#define gen_for 333
79+
#define gen_if 334
80+
#define testlist1 335
81+
#define encoding_decl 336
82+
#define yield_expr 337

Lib/test/test_grammar.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,3 +798,28 @@ def test_nested_front():
798798
x = 10; t = False; g = ((i,j) for i in range(x) if t for j in range(x))
799799
x = 5; t = True;
800800
verify([(i,j) for i in range(10) for j in range(5)] == list(g))
801+
802+
# Test ifelse expressions in various cases
803+
def _checkeval(msg, ret):
804+
"helper to check that evaluation of expressions is done correctly"
805+
print x
806+
return ret
807+
808+
verify([ x() for x in lambda: True, lambda: False if x() ] == [True])
809+
verify([ x() for x in (lambda: True, lambda: False) if x() ] == [True])
810+
verify([ x(False) for x in (lambda x: False if x else True, lambda x: True if x else False) if x(False) ] == [True])
811+
verify((5 if 1 else _checkeval("check 1", 0)) == 5)
812+
verify((_checkeval("check 2", 0) if 0 else 5) == 5)
813+
verify((5 and 6 if 0 else 1) == 1)
814+
verify(((5 and 6) if 0 else 1) == 1)
815+
verify((5 and (6 if 1 else 1)) == 6)
816+
verify((0 or _checkeval("check 3", 2) if 0 else 3) == 3)
817+
verify((1 or _checkeval("check 4", 2) if 1 else _checkeval("check 5", 3)) == 1)
818+
verify((0 or 5 if 1 else _checkeval("check 6", 3)) == 5)
819+
verify((not 5 if 1 else 1) == False)
820+
verify((not 5 if 0 else 1) == 1)
821+
verify((6 + 1 if 1 else 2) == 7)
822+
verify((6 - 1 if 1 else 2) == 5)
823+
verify((6 * 2 if 1 else 4) == 12)
824+
verify((6 / 2 if 1 else 3) == 3)
825+
verify((6 < 4 if 0 else 2) == 2)

Parser/Python.asdl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ module Python
5252
| BinOp(expr left, operator op, expr right)
5353
| UnaryOp(unaryop op, expr operand)
5454
| Lambda(arguments args, expr body)
55+
| IfExp(expr test, expr body, expr orelse)
5556
| Dict(expr* keys, expr* values)
5657
| ListComp(expr elt, comprehension* generators)
5758
| GeneratorExp(expr elt, comprehension* generators)

Python/Python-ast.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ char *Lambda_fields[]={
151151
"args",
152152
"body",
153153
};
154+
PyTypeObject *IfExp_type;
155+
char *IfExp_fields[]={
156+
"test",
157+
"body",
158+
"orelse",
159+
};
154160
PyTypeObject *Dict_type;
155161
char *Dict_fields[]={
156162
"keys",
@@ -431,6 +437,7 @@ static int init_types(void)
431437
BinOp_type = make_type("BinOp", expr_type, BinOp_fields, 3);
432438
UnaryOp_type = make_type("UnaryOp", expr_type, UnaryOp_fields, 2);
433439
Lambda_type = make_type("Lambda", expr_type, Lambda_fields, 2);
440+
IfExp_type = make_type("IfExp", expr_type, IfExp_fields, 3);
434441
Dict_type = make_type("Dict", expr_type, Dict_fields, 2);
435442
ListComp_type = make_type("ListComp", expr_type, ListComp_fields, 2);
436443
GeneratorExp_type = make_type("GeneratorExp", expr_type,
@@ -1137,6 +1144,38 @@ Lambda(arguments_ty args, expr_ty body, int lineno, PyArena *arena)
11371144
return p;
11381145
}
11391146

1147+
expr_ty
1148+
IfExp(expr_ty test, expr_ty body, expr_ty orelse, int lineno, PyArena *arena)
1149+
{
1150+
expr_ty p;
1151+
if (!test) {
1152+
PyErr_SetString(PyExc_ValueError,
1153+
"field test is required for IfExp");
1154+
return NULL;
1155+
}
1156+
if (!body) {
1157+
PyErr_SetString(PyExc_ValueError,
1158+
"field body is required for IfExp");
1159+
return NULL;
1160+
}
1161+
if (!orelse) {
1162+
PyErr_SetString(PyExc_ValueError,
1163+
"field orelse is required for IfExp");
1164+
return NULL;
1165+
}
1166+
p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
1167+
if (!p) {
1168+
PyErr_NoMemory();
1169+
return NULL;
1170+
}
1171+
p->kind = IfExp_kind;
1172+
p->v.IfExp.test = test;
1173+
p->v.IfExp.body = body;
1174+
p->v.IfExp.orelse = orelse;
1175+
p->lineno = lineno;
1176+
return p;
1177+
}
1178+
11401179
expr_ty
11411180
Dict(asdl_seq * keys, asdl_seq * values, int lineno, PyArena *arena)
11421181
{
@@ -2077,6 +2116,25 @@ ast2obj_expr(void* _o)
20772116
goto failed;
20782117
Py_DECREF(value);
20792118
break;
2119+
case IfExp_kind:
2120+
result = PyType_GenericNew(IfExp_type, NULL, NULL);
2121+
if (!result) goto failed;
2122+
value = ast2obj_expr(o->v.IfExp.test);
2123+
if (!value) goto failed;
2124+
if (PyObject_SetAttrString(result, "test", value) == -1)
2125+
goto failed;
2126+
Py_DECREF(value);
2127+
value = ast2obj_expr(o->v.IfExp.body);
2128+
if (!value) goto failed;
2129+
if (PyObject_SetAttrString(result, "body", value) == -1)
2130+
goto failed;
2131+
Py_DECREF(value);
2132+
value = ast2obj_expr(o->v.IfExp.orelse);
2133+
if (!value) goto failed;
2134+
if (PyObject_SetAttrString(result, "orelse", value) == -1)
2135+
goto failed;
2136+
Py_DECREF(value);
2137+
break;
20802138
case Dict_kind:
20812139
result = PyType_GenericNew(Dict_type, NULL, NULL);
20822140
if (!result) goto failed;

Python/ast.c

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,25 @@ ast_for_lambdef(struct compiling *c, const node *n)
847847
return Lambda(args, expression, LINENO(n), c->c_arena);
848848
}
849849

850+
static expr_ty
851+
ast_for_ifexpr(struct compiling *c, const node *n)
852+
{
853+
/* test: or_test 'if' or_test 'else' test */
854+
expr_ty expression, body, orelse;
855+
856+
assert(NCH(n) >= 3);
857+
body = ast_for_expr(c, CHILD(n, 0));
858+
if (!body)
859+
return NULL;
860+
expression = ast_for_expr(c, CHILD(n, 2));
861+
if (!expression)
862+
return NULL;
863+
orelse = ast_for_expr(c, CHILD(n, 4));
864+
if (!orelse)
865+
return NULL;
866+
return IfExp(expression, body, orelse, LINENO(n), c->c_arena);
867+
}
868+
850869
/* Count the number of 'for' loop in a list comprehension.
851870
852871
Helper for ast_for_listcomp().
@@ -1456,7 +1475,8 @@ static expr_ty
14561475
ast_for_expr(struct compiling *c, const node *n)
14571476
{
14581477
/* handle the full range of simple expressions
1459-
test: and_test ('or' and_test)* | lambdef
1478+
test: or_test ['if' or_test 'else' test] | lambdef
1479+
or_test: and_test ('or' and_test)*
14601480
and_test: not_test ('and' not_test)*
14611481
not_test: 'not' not_test | comparison
14621482
comparison: expr (comp_op expr)*
@@ -1468,6 +1488,15 @@ ast_for_expr(struct compiling *c, const node *n)
14681488
term: factor (('*'|'/'|'%'|'//') factor)*
14691489
factor: ('+'|'-'|'~') factor | power
14701490
power: atom trailer* ('**' factor)*
1491+
1492+
As well as modified versions that exist for backward compatibility,
1493+
to explicitly allow:
1494+
[ x for x in lambda: 0, lambda: 1 ]
1495+
(which would be ambiguous without these extra rules)
1496+
1497+
old_test: or_test | old_lambdef
1498+
old_lambdef: 'lambda' [vararglist] ':' old_test
1499+
14711500
*/
14721501

14731502
asdl_seq *seq;
@@ -1476,9 +1505,14 @@ ast_for_expr(struct compiling *c, const node *n)
14761505
loop:
14771506
switch (TYPE(n)) {
14781507
case test:
1479-
if (TYPE(CHILD(n, 0)) == lambdef)
1508+
case old_test:
1509+
if (TYPE(CHILD(n, 0)) == lambdef ||
1510+
TYPE(CHILD(n, 0)) == old_lambdef)
14801511
return ast_for_lambdef(c, CHILD(n, 0));
1481-
/* Fall through to and_test */
1512+
else if (NCH(n) > 1)
1513+
return ast_for_ifexpr(c, n);
1514+
/* Fallthrough */
1515+
case or_test:
14821516
case and_test:
14831517
if (NCH(n) == 1) {
14841518
n = CHILD(n, 0);

0 commit comments

Comments
 (0)