Skip to content

Commit 3078552

Browse files
committed
Generator, List, Set and Dictionary comprehensions
1 parent 817f25d commit 3078552

File tree

3 files changed

+97
-12
lines changed

3 files changed

+97
-12
lines changed

parser/grammar.y

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func tupleOrExpr(pos ast.Pos, elts []ast.Expr, optional_comma bool) ast.Expr {
104104
%type <stmt> compound_stmt small_stmt expr_stmt del_stmt pass_stmt flow_stmt import_stmt global_stmt nonlocal_stmt assert_stmt break_stmt continue_stmt return_stmt raise_stmt yield_stmt
105105
%type <op> augassign
106106
%type <expr> expr_or_star_expr expr star_expr xor_expr and_expr shift_expr arith_expr term factor power trailer atom test_or_star_expr test not_test lambdef test_nocond lambdef_nocond or_test and_test comparison testlist testlist_star_expr yield_expr_or_testlist yield_expr yield_expr_or_testlist_star_expr dictorsetmaker
107-
%type <exprs> exprlist testlistraw
107+
%type <exprs> exprlist testlistraw comp_if comp_iter
108108
%type <exprsStack> expr_or_star_exprs test_or_star_exprs tests test_colon_tests
109109
%type <trailers> trailers
110110
%type <cmpop> comp_op
@@ -1103,9 +1103,7 @@ atom:
11031103
}
11041104
| '(' test_or_star_expr comp_for ')'
11051105
{
1106-
// FIXME
1107-
panic("not implemented")
1108-
$$ = nil
1106+
$$ = &ast.GeneratorExp{ExprBase: ast.ExprBase{$<pos>$}, Elt: $2, Generators: $3}
11091107
}
11101108
| '(' test_or_star_exprs optional_comma ')'
11111109
{
@@ -1117,9 +1115,7 @@ atom:
11171115
}
11181116
| '[' test_or_star_expr comp_for ']'
11191117
{
1120-
// FIXME
1121-
panic("not implemented")
1122-
$$ = nil
1118+
$$ = &ast.ListComp{ExprBase: ast.ExprBase{$<pos>$}, Elt: $2, Generators: $3}
11231119
}
11241120
| '[' test_or_star_exprs optional_comma ']'
11251121
{
@@ -1244,6 +1240,7 @@ exprlist:
12441240
expr_or_star_exprs optional_comma
12451241
{
12461242
$$ = $1.Pop()
1243+
$<comma>$ = $2
12471244
}
12481245

12491246
testlist:
@@ -1329,23 +1326,50 @@ argument:
13291326

13301327
comp_iter:
13311328
comp_for
1329+
{
1330+
$<comprehensions>$ = $1
1331+
$$ = nil
1332+
}
13321333
| comp_if
1334+
{
1335+
$<comprehensions>$ = $<comprehensions>1
1336+
$$ = $1
1337+
}
13331338

13341339
comp_for:
13351340
FOR exprlist IN or_test
13361341
{
1337-
// FIXME
1338-
$$ = nil
1342+
c := ast.Comprehension{
1343+
Target: tupleOrExpr($<pos>$, $2, $<comma>2),
1344+
Iter: $4,
1345+
}
1346+
c.Target.(ast.SetCtxer).SetCtx(ast.Store)
1347+
$$ = []ast.Comprehension{c}
13391348
}
13401349
| FOR exprlist IN or_test comp_iter
13411350
{
1342-
// FIXME
1343-
$$ = nil
1351+
c := ast.Comprehension{
1352+
Target: tupleOrExpr($<pos>$, $2, $<comma>2),
1353+
Iter: $4,
1354+
Ifs: $5,
1355+
}
1356+
c.Target.(ast.SetCtxer).SetCtx(ast.Store)
1357+
$$ = []ast.Comprehension{c}
1358+
$$ = append($$, $<comprehensions>5...)
13441359
}
13451360

13461361
comp_if:
13471362
IF test_nocond
1363+
{
1364+
$$ = []ast.Expr{$2}
1365+
$<comprehensions>$ = nil
1366+
}
13481367
| IF test_nocond comp_iter
1368+
{
1369+
$$ = []ast.Expr{$2}
1370+
$$ = append($$, $3...)
1371+
$<comprehensions>$ = $<comprehensions>3
1372+
}
13491373

13501374
// not used in grammar, but may appear in "node" passed from Parser to Compiler
13511375
// encoding_decl: NAME

parser/grammar_test.go

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,34 @@ func TestGrammar(t *testing.T) {
5959
{"[1,]", "eval", "Expression(body=List(elts=[Num(n=1)], ctx=Load()))"},
6060
{"[1,2]", "eval", "Expression(body=List(elts=[Num(n=1), Num(n=2)], ctx=Load()))"},
6161
{"[1,2,]", "eval", "Expression(body=List(elts=[Num(n=1), Num(n=2)], ctx=Load()))"},
62+
{"( a for a in ab )", "eval", "Expression(body=GeneratorExp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[])]))"},
63+
{"( a for a, in ab )", "eval", "Expression(body=GeneratorExp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Tuple(elts=[Name(id='a', ctx=Store())], ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[])]))"},
64+
{"( a for a, b in ab )", "eval", "Expression(body=GeneratorExp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Tuple(elts=[Name(id='a', ctx=Store()), Name(id='b', ctx=Store())], ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[])]))"},
65+
{"( a for a in ab if a )", "eval", "Expression(body=GeneratorExp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[Name(id='a', ctx=Load())])]))"},
66+
{"( a for a in ab if a if b if c )", "eval", "Expression(body=GeneratorExp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[Name(id='a', ctx=Load()), Name(id='b', ctx=Load()), Name(id='c', ctx=Load())])]))"},
67+
{"( a for a in ab for A in AB )", "eval", "Expression(body=GeneratorExp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[]), comprehension(target=Name(id='A', ctx=Store()), iter=Name(id='AB', ctx=Load()), ifs=[])]))"},
68+
{"( a for a in ab if a if b for A in AB if c )", "eval", "Expression(body=GeneratorExp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[Name(id='a', ctx=Load()), Name(id='b', ctx=Load())]), comprehension(target=Name(id='A', ctx=Store()), iter=Name(id='AB', ctx=Load()), ifs=[Name(id='c', ctx=Load())])]))"},
69+
{"[ a for a in ab ]", "eval", "Expression(body=ListComp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[])]))"},
70+
{"[ a for a, in ab ]", "eval", "Expression(body=ListComp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Tuple(elts=[Name(id='a', ctx=Store())], ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[])]))"},
71+
{"[ a for a, b in ab ]", "eval", "Expression(body=ListComp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Tuple(elts=[Name(id='a', ctx=Store()), Name(id='b', ctx=Store())], ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[])]))"},
72+
{"[ a for a in ab if a ]", "eval", "Expression(body=ListComp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[Name(id='a', ctx=Load())])]))"},
73+
{"[ a for a in ab if a if b if c ]", "eval", "Expression(body=ListComp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[Name(id='a', ctx=Load()), Name(id='b', ctx=Load()), Name(id='c', ctx=Load())])]))"},
74+
{"[ a for a in ab for A in AB ]", "eval", "Expression(body=ListComp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[]), comprehension(target=Name(id='A', ctx=Store()), iter=Name(id='AB', ctx=Load()), ifs=[])]))"},
75+
{"[ a for a in ab if a if b for A in AB if c ]", "eval", "Expression(body=ListComp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[Name(id='a', ctx=Load()), Name(id='b', ctx=Load())]), comprehension(target=Name(id='A', ctx=Store()), iter=Name(id='AB', ctx=Load()), ifs=[Name(id='c', ctx=Load())])]))"},
76+
{"{ a for a in ab }", "eval", "Expression(body=SetComp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[])]))"},
77+
{"{ a for a, in ab }", "eval", "Expression(body=SetComp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Tuple(elts=[Name(id='a', ctx=Store())], ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[])]))"},
78+
{"{ a for a, b in ab }", "eval", "Expression(body=SetComp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Tuple(elts=[Name(id='a', ctx=Store()), Name(id='b', ctx=Store())], ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[])]))"},
79+
{"{ a for a in ab if a }", "eval", "Expression(body=SetComp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[Name(id='a', ctx=Load())])]))"},
80+
{"{ a for a in ab if a if b if c }", "eval", "Expression(body=SetComp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[Name(id='a', ctx=Load()), Name(id='b', ctx=Load()), Name(id='c', ctx=Load())])]))"},
81+
{"{ a for a in ab for A in AB }", "eval", "Expression(body=SetComp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[]), comprehension(target=Name(id='A', ctx=Store()), iter=Name(id='AB', ctx=Load()), ifs=[])]))"},
82+
{"{ a for a in ab if a if b for A in AB if c }", "eval", "Expression(body=SetComp(elt=Name(id='a', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[Name(id='a', ctx=Load()), Name(id='b', ctx=Load())]), comprehension(target=Name(id='A', ctx=Store()), iter=Name(id='AB', ctx=Load()), ifs=[Name(id='c', ctx=Load())])]))"},
83+
{"{ a:b for a in ab }", "eval", "Expression(body=DictComp(key=Name(id='a', ctx=Load()), value=Name(id='b', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[])]))"},
84+
{"{ a:b for a, in ab }", "eval", "Expression(body=DictComp(key=Name(id='a', ctx=Load()), value=Name(id='b', ctx=Load()), generators=[comprehension(target=Tuple(elts=[Name(id='a', ctx=Store())], ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[])]))"},
85+
{"{ a:b for a, b in ab }", "eval", "Expression(body=DictComp(key=Name(id='a', ctx=Load()), value=Name(id='b', ctx=Load()), generators=[comprehension(target=Tuple(elts=[Name(id='a', ctx=Store()), Name(id='b', ctx=Store())], ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[])]))"},
86+
{"{ a:b for a in ab if a }", "eval", "Expression(body=DictComp(key=Name(id='a', ctx=Load()), value=Name(id='b', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[Name(id='a', ctx=Load())])]))"},
87+
{"{ a:b for a in ab if a if b if c }", "eval", "Expression(body=DictComp(key=Name(id='a', ctx=Load()), value=Name(id='b', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[Name(id='a', ctx=Load()), Name(id='b', ctx=Load()), Name(id='c', ctx=Load())])]))"},
88+
{"{ a:b for a in ab for A in AB }", "eval", "Expression(body=DictComp(key=Name(id='a', ctx=Load()), value=Name(id='b', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[]), comprehension(target=Name(id='A', ctx=Store()), iter=Name(id='AB', ctx=Load()), ifs=[])]))"},
89+
{"{ a:b for a in ab if a if b for A in AB if c }", "eval", "Expression(body=DictComp(key=Name(id='a', ctx=Load()), value=Name(id='b', ctx=Load()), generators=[comprehension(target=Name(id='a', ctx=Store()), iter=Name(id='ab', ctx=Load()), ifs=[Name(id='a', ctx=Load()), Name(id='b', ctx=Load())]), comprehension(target=Name(id='A', ctx=Store()), iter=Name(id='AB', ctx=Load()), ifs=[Name(id='c', ctx=Load())])]))"},
6290
// END TESTS
6391
} {
6492
Ast, err := ParseString(test.in, test.mode)
@@ -67,7 +95,7 @@ func TestGrammar(t *testing.T) {
6795
} else {
6896
out := ast.Dump(Ast)
6997
if out != test.out {
70-
t.Errorf("Parse(%q) expecting %q actual %q", test.in, test.out, out)
98+
t.Errorf("Parse(%q)\nwant> %q\n got> %q\n", test.in, test.out, out)
7199
}
72100
}
73101
}

parser/make_grammar_test.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,39 @@
4646
("[1,]", "eval"),
4747
("[1,2]", "eval"),
4848
("[1,2,]", "eval"),
49+
("( a for a in ab )", "eval"),
50+
("( a for a, in ab )", "eval"),
51+
("( a for a, b in ab )", "eval"),
52+
("( a for a in ab if a )", "eval"),
53+
("( a for a in ab if a if b if c )", "eval"),
54+
("( a for a in ab for A in AB )", "eval"),
55+
("( a for a in ab if a if b for A in AB if c )", "eval"),
56+
57+
("[ a for a in ab ]", "eval"),
58+
("[ a for a, in ab ]", "eval"),
59+
("[ a for a, b in ab ]", "eval"),
60+
("[ a for a in ab if a ]", "eval"),
61+
("[ a for a in ab if a if b if c ]", "eval"),
62+
("[ a for a in ab for A in AB ]", "eval"),
63+
("[ a for a in ab if a if b for A in AB if c ]", "eval"),
64+
65+
("{ a for a in ab }", "eval"),
66+
("{ a for a, in ab }", "eval"),
67+
("{ a for a, b in ab }", "eval"),
68+
("{ a for a in ab if a }", "eval"),
69+
("{ a for a in ab if a if b if c }", "eval"),
70+
("{ a for a in ab for A in AB }", "eval"),
71+
("{ a for a in ab if a if b for A in AB if c }", "eval"),
72+
73+
("{ a:b for a in ab }", "eval"),
74+
("{ a:b for a, in ab }", "eval"),
75+
("{ a:b for a, b in ab }", "eval"),
76+
("{ a:b for a in ab if a }", "eval"),
77+
("{ a:b for a in ab if a if b if c }", "eval"),
78+
("{ a:b for a in ab for A in AB }", "eval"),
79+
("{ a:b for a in ab if a if b for A in AB if c }", "eval"),
80+
81+
# ("del a,b", "exec"),
4982
]
5083

5184
def dump(source, mode):

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy