Skip to content

Commit a27bc28

Browse files
committed
Implement For and If
1 parent b685896 commit a27bc28

File tree

3 files changed

+103
-11
lines changed

3 files changed

+103
-11
lines changed

parser/grammar.y

+42-11
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,14 @@ func applyTrailers(expr ast.Expr, trailers []ast.Expr) ast.Expr {
6464
alias *ast.Alias
6565
aliases []*ast.Alias
6666
identifiers []ast.Identifier
67+
ifstmt *ast.If
68+
lastif *ast.If
6769
}
6870

6971
%type <obj> strings
7072
%type <mod> inputs file_input single_input eval_input
71-
%type <stmts> simple_stmt stmt nl_or_stmt small_stmts stmts
72-
%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 import_name import_from
73+
%type <stmts> simple_stmt stmt nl_or_stmt small_stmts stmts suite optional_else
74+
%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 import_name import_from while_stmt if_stmt for_stmt
7375
%type <op> augassign
7476
%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 sliceop arglist
7577
%type <exprs> exprlist testlistraw comp_if comp_iter expr_or_star_exprs test_or_star_exprs tests test_colon_tests trailers
@@ -83,6 +85,7 @@ func applyTrailers(expr ast.Expr, trailers []ast.Expr) ast.Expr {
8385
%type <identifiers> names
8486
%type <alias> dotted_as_name import_as_name
8587
%type <aliases> dotted_as_names import_as_names import_from_arg
88+
%type <ifstmt> elifs
8689

8790
%token NEWLINE
8891
%token ENDMARKER
@@ -932,7 +935,7 @@ compound_stmt:
932935
}
933936
| while_stmt
934937
{
935-
// FIXME
938+
$$ = $1
936939
}
937940
| for_stmt
938941
{
@@ -961,38 +964,63 @@ compound_stmt:
961964

962965
elifs:
963966
{
964-
// FIXME
967+
$$ = nil
968+
$<lastif>$ = nil
965969
}
966970
| elifs ELIF test ':' suite
967971
{
968-
// FIXME
972+
elifs := $$
973+
newif := &ast.If{StmtBase: ast.StmtBase{$<pos>$}, Test: $3, Body: $5}
974+
if elifs == nil {
975+
$$ = newif
976+
} else {
977+
$<lastif>$.Orelse = []ast.Stmt{newif}
978+
}
979+
$<lastif>$ = newif
969980
}
970981

971982
optional_else:
972983
{
973-
// FIXME
984+
$$ = nil
974985
}
975986
| ELSE ':' suite
976987
{
977-
// FIXME
988+
$$ = $3
978989
}
979990

980991
if_stmt:
981992
IF test ':' suite elifs optional_else
982993
{
983-
// FIXME
994+
newif := &ast.If{StmtBase: ast.StmtBase{$<pos>$}, Test: $2, Body: $4}
995+
$$ = newif
996+
elifs := $5
997+
optional_else := $6
998+
if len(optional_else) != 0 {
999+
if elifs != nil {
1000+
$<lastif>5.Orelse = optional_else
1001+
newif.Orelse = []ast.Stmt{elifs}
1002+
} else {
1003+
newif.Orelse = optional_else
1004+
}
1005+
} else {
1006+
if elifs != nil {
1007+
newif.Orelse = []ast.Stmt{elifs}
1008+
}
1009+
}
9841010
}
9851011

9861012
while_stmt:
9871013
WHILE test ':' suite optional_else
9881014
{
989-
// FIXME
1015+
$$ = &ast.While{StmtBase: ast.StmtBase{$<pos>$}, Test: $2, Body: $4, Orelse: $5}
9901016
}
9911017

9921018
for_stmt:
9931019
FOR exprlist IN testlist ':' suite optional_else
9941020
{
995-
// FIXME
1021+
target := tupleOrExpr($<pos>$, $2, false)
1022+
target.(ast.SetCtxer).SetCtx(ast.Store)
1023+
$$ = &ast.For{StmtBase: ast.StmtBase{$<pos>$}, Target: target, Iter: $4, Body: $6, Orelse: $7}
9961024
}
9971025

9981026
except_clauses:
@@ -1076,9 +1104,12 @@ stmts:
10761104

10771105
suite:
10781106
simple_stmt
1107+
{
1108+
$$ = $1
1109+
}
10791110
| NEWLINE INDENT stmts DEDENT
10801111
{
1081-
// stmts
1112+
$$ = $3
10821113
}
10831114

10841115
test:

parser/grammar_test.go

+12
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,18 @@ func TestGrammar(t *testing.T) {
196196
{"assert True", "exec", "Module(body=[Assert(test=NameConstant(value=True), msg=None)])"},
197197
{"assert True, 'Bang'", "exec", "Module(body=[Assert(test=NameConstant(value=True), msg=Str(s='Bang'))])"},
198198
{"assert a == b, 'Bang'", "exec", "Module(body=[Assert(test=Compare(left=Name(id='a', ctx=Load()), ops=[Eq()], comparators=[Name(id='b', ctx=Load())]), msg=Str(s='Bang'))])"},
199+
{"while True: pass", "exec", "Module(body=[While(test=NameConstant(value=True), body=[Pass()], orelse=[])])"},
200+
{"while True:\n pass\n", "exec", "Module(body=[While(test=NameConstant(value=True), body=[Pass()], orelse=[])])"},
201+
{"while True:\n pass\nelse:\n return\n", "exec", "Module(body=[While(test=NameConstant(value=True), body=[Pass()], orelse=[Return(value=None)])])"},
202+
{"if True: pass", "exec", "Module(body=[If(test=NameConstant(value=True), body=[Pass()], orelse=[])])"},
203+
{"if True:\n pass\n", "exec", "Module(body=[If(test=NameConstant(value=True), body=[Pass()], orelse=[])])"},
204+
{"if True:\n pass\n continue\nelse:\n break\n pass\n", "exec", "Module(body=[If(test=NameConstant(value=True), body=[Pass(), Continue()], orelse=[Break(), Pass()])])"},
205+
{"if a:\n continue\nelif b:\n break\nelif c:\n pass\nelif c:\n continue\n pass\n", "exec", "Module(body=[If(test=Name(id='a', ctx=Load()), body=[Continue()], orelse=[If(test=Name(id='b', ctx=Load()), body=[Break()], orelse=[If(test=Name(id='c', ctx=Load()), body=[Pass()], orelse=[If(test=Name(id='c', ctx=Load()), body=[Continue(), Pass()], orelse=[])])])])])"},
206+
{"if a:\n continue\nelif b:\n break\nelse:\n continue\n pass\n", "exec", "Module(body=[If(test=Name(id='a', ctx=Load()), body=[Continue()], orelse=[If(test=Name(id='b', ctx=Load()), body=[Break()], orelse=[Continue(), Pass()])])])"},
207+
{"if a:\n continue\nelif b:\n break\nelif c:\n pass\nelse:\n continue\n pass\n", "exec", "Module(body=[If(test=Name(id='a', ctx=Load()), body=[Continue()], orelse=[If(test=Name(id='b', ctx=Load()), body=[Break()], orelse=[If(test=Name(id='c', ctx=Load()), body=[Pass()], orelse=[Continue(), Pass()])])])])"},
208+
{"for a in b: pass", "exec", "Module(body=[For(target=Name(id='a', ctx=Store()), iter=Name(id='b', ctx=Load()), body=[Pass()], orelse=[])])"},
209+
{"for a, b in b: pass", "exec", "Module(body=[For(target=Tuple(elts=[Name(id='a', ctx=Store()), Name(id='b', ctx=Store())], ctx=Store()), iter=Name(id='b', ctx=Load()), body=[Pass()], orelse=[])])"},
210+
{"for a, b in b:\n pass\nelse: break\n", "exec", "Module(body=[For(target=Tuple(elts=[Name(id='a', ctx=Store()), Name(id='b', ctx=Store())], ctx=Store()), iter=Name(id='b', ctx=Load()), body=[Pass()], orelse=[Break()])])"},
199211
// END TESTS
200212
} {
201213
Ast, err := ParseString(test.in, test.mode)

parser/make_grammar_test.py

+49
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,55 @@
203203
("assert True", "exec"),
204204
("assert True, 'Bang'", "exec"),
205205
("assert a == b, 'Bang'", "exec"),
206+
207+
# Compound statements
208+
("while True: pass", "exec"),
209+
("while True:\n pass\n", "exec"),
210+
("while True:\n pass\nelse:\n return\n", "exec"),
211+
("if True: pass", "exec"),
212+
("if True:\n pass\n", "exec"),
213+
("""\
214+
if True:
215+
pass
216+
continue
217+
else:
218+
break
219+
pass
220+
""", "exec"),
221+
("""\
222+
if a:
223+
continue
224+
elif b:
225+
break
226+
elif c:
227+
pass
228+
elif c:
229+
continue
230+
pass
231+
""", "exec"),
232+
("""\
233+
if a:
234+
continue
235+
elif b:
236+
break
237+
else:
238+
continue
239+
pass
240+
""", "exec"),
241+
("""\
242+
if a:
243+
continue
244+
elif b:
245+
break
246+
elif c:
247+
pass
248+
else:
249+
continue
250+
pass
251+
""", "exec"),
252+
("for a in b: pass", "exec"),
253+
("for a, b in b: pass", "exec"),
254+
("for a, b in b:\n pass\nelse: break\n", "exec"),
206255
]
207256

208257
def dump(source, mode):

0 commit comments

Comments
 (0)