Skip to content

Commit 669e0e4

Browse files
committed
compile: implement for loop
1 parent 50cdc44 commit 669e0e4

File tree

4 files changed

+81
-6
lines changed

4 files changed

+81
-6
lines changed

compile/compile.go

+24-4
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ func (c *compiler) NewLabel() *Label {
236236
// Compiles a jump instruction
237237
func (c *compiler) Jump(Op byte, Dest *Label) {
238238
switch Op {
239-
case vm.JUMP_IF_FALSE_OR_POP, vm.JUMP_IF_TRUE_OR_POP, vm.JUMP_ABSOLUTE, vm.POP_JUMP_IF_FALSE, vm.POP_JUMP_IF_TRUE: // Absolute
239+
case vm.JUMP_IF_FALSE_OR_POP, vm.JUMP_IF_TRUE_OR_POP, vm.JUMP_ABSOLUTE, vm.POP_JUMP_IF_FALSE, vm.POP_JUMP_IF_TRUE, vm.CONTINUE_LOOP: // Absolute
240240
c.OpCodes.Add(&JumpAbs{OpArg: OpArg{Op: Op}, Dest: Dest})
241241
case vm.JUMP_FORWARD, vm.SETUP_WITH, vm.FOR_ITER, vm.SETUP_LOOP, vm.SETUP_EXCEPT, vm.SETUP_FINALLY:
242242
c.OpCodes.Add(&JumpRel{OpArg: OpArg{Op: Op}, Dest: Dest})
@@ -338,7 +338,26 @@ func (c *compiler) Stmt(stmt ast.Stmt) {
338338
// Iter Expr
339339
// Body []Stmt
340340
// Orelse []Stmt
341-
panic("FIXME compile: For not implemented")
341+
endfor := new(Label)
342+
endpopblock := new(Label)
343+
c.Jump(vm.SETUP_LOOP, endpopblock)
344+
c.Expr(node.Iter)
345+
c.Op(vm.GET_ITER)
346+
forloop := c.NewLabel()
347+
c.loops.Push(loop{Start: forloop, End: endpopblock, IsForLoop: true})
348+
c.Jump(vm.FOR_ITER, endfor)
349+
c.Expr(node.Target)
350+
for _, stmt := range node.Body {
351+
c.Stmt(stmt)
352+
}
353+
c.Jump(vm.JUMP_ABSOLUTE, forloop)
354+
c.Label(endfor)
355+
c.Op(vm.POP_BLOCK)
356+
c.loops.Pop()
357+
for _, stmt := range node.Orelse {
358+
c.Stmt(stmt)
359+
}
360+
c.Label(endpopblock)
342361
case *ast.While:
343362
// Test Expr
344363
// Body []Stmt
@@ -449,8 +468,9 @@ func (c *compiler) Stmt(stmt ast.Stmt) {
449468
panic(py.ExceptionNewf(py.SyntaxError, "'continue' not properly in loop"))
450469
}
451470
if l.IsForLoop {
452-
panic(py.ExceptionNewf(py.SyntaxError, "FIXME continue in for loop not implemented", stmt))
453-
c.OpArg(vm.CONTINUE_LOOP, 0)
471+
// FIXME when do we use CONTINUE_LOOP?
472+
c.Jump(vm.JUMP_ABSOLUTE, l.Start)
473+
//c.Jump(vm.CONTINUE_LOOP, l.Start)
454474
} else {
455475
c.Jump(vm.JUMP_ABSOLUTE, l.Start)
456476
}

compile/compile_data_test.go

+52-1
Original file line numberDiff line numberDiff line change
@@ -1151,7 +1151,7 @@ var compileTestData = []struct {
11511151
Name: "<module>",
11521152
Firstlineno: 1,
11531153
Lnotab: "",
1154-
}, " 1 0 LOAD_CONST 0 (<code object <lambda> at 0x7f3037488db0, file \"<string>\", line 1>)\n 3 LOAD_CONST 1 ('<lambda>')\n 6 MAKE_FUNCTION 0\n 9 RETURN_VALUE\n", nil, ""},
1154+
}, " 1 0 LOAD_CONST 0 (<code object <lambda> at 0x7f37b1535db0, file \"<string>\", line 1>)\n 3 LOAD_CONST 1 ('<lambda>')\n 6 MAKE_FUNCTION 0\n 9 RETURN_VALUE\n", nil, ""},
11551155
{"pass", "exec", &py.Code{
11561156
Argcount: 0,
11571157
Kwonlyargcount: 0,
@@ -1681,4 +1681,55 @@ var compileTestData = []struct {
16811681
}, " 1 0 SETUP_LOOP 28 (to 31)\n >> 3 LOAD_NAME 0 (a)\n 6 POP_JUMP_IF_FALSE 30\n\n 2 9 LOAD_NAME 1 (b)\n 12 POP_JUMP_IF_FALSE 21\n 15 JUMP_ABSOLUTE 3\n 18 JUMP_FORWARD 0 (to 21)\n\n 3 >> 21 LOAD_NAME 2 (c)\n 24 STORE_NAME 1 (b)\n 27 JUMP_ABSOLUTE 3\n >> 30 POP_BLOCK\n >> 31 LOAD_CONST 0 (None)\n 34 RETURN_VALUE\n", nil, ""},
16821682
{"continue", "exec", nil, "", py.SyntaxError, "'continue' not properly in loop"},
16831683
{"break", "exec", nil, "", py.SyntaxError, "'break' outside loop"},
1684+
{"for a in b: pass", "exec", &py.Code{
1685+
Argcount: 0,
1686+
Kwonlyargcount: 0,
1687+
Nlocals: 0,
1688+
Stacksize: 2,
1689+
Flags: 64,
1690+
Code: "\x78\x0e\x00\x65\x00\x00\x44\x5d\x06\x00\x5a\x01\x00\x71\x07\x00\x57\x64\x00\x00\x53",
1691+
Consts: []py.Object{py.None},
1692+
Names: []string{"b", "a"},
1693+
Varnames: []string{},
1694+
Freevars: []string{},
1695+
Cellvars: []string{},
1696+
Filename: "<string>",
1697+
Name: "<module>",
1698+
Firstlineno: 1,
1699+
Lnotab: "\x0d\x00",
1700+
}, " 1 0 SETUP_LOOP 14 (to 17)\n 3 LOAD_NAME 0 (b)\n 6 GET_ITER\n >> 7 FOR_ITER 6 (to 16)\n 10 STORE_NAME 1 (a)\n 13 JUMP_ABSOLUTE 7\n >> 16 POP_BLOCK\n >> 17 LOAD_CONST 0 (None)\n 20 RETURN_VALUE\n", nil, ""},
1701+
{"for a in b:\n if a:\n break\n c = e\nelse: c = d\n", "exec", &py.Code{
1702+
Argcount: 0,
1703+
Kwonlyargcount: 0,
1704+
Nlocals: 0,
1705+
Stacksize: 2,
1706+
Flags: 64,
1707+
Code: "\x78\x24\x00\x65\x00\x00\x44\x5d\x16\x00\x5a\x01\x00\x65\x01\x00\x72\x17\x00\x50\x6e\x00\x00\x65\x02\x00\x5a\x03\x00\x71\x07\x00\x57\x65\x04\x00\x5a\x03\x00\x64\x00\x00\x53",
1708+
Consts: []py.Object{py.None},
1709+
Names: []string{"b", "a", "e", "c", "d"},
1710+
Varnames: []string{},
1711+
Freevars: []string{},
1712+
Cellvars: []string{},
1713+
Filename: "<string>",
1714+
Name: "<module>",
1715+
Firstlineno: 1,
1716+
Lnotab: "\x0d\x01\x06\x01\x04\x01\x0a\x01",
1717+
}, " 1 0 SETUP_LOOP 36 (to 39)\n 3 LOAD_NAME 0 (b)\n 6 GET_ITER\n >> 7 FOR_ITER 22 (to 32)\n 10 STORE_NAME 1 (a)\n\n 2 13 LOAD_NAME 1 (a)\n 16 POP_JUMP_IF_FALSE 23\n\n 3 19 BREAK_LOOP\n 20 JUMP_FORWARD 0 (to 23)\n\n 4 >> 23 LOAD_NAME 2 (e)\n 26 STORE_NAME 3 (c)\n 29 JUMP_ABSOLUTE 7\n >> 32 POP_BLOCK\n\n 5 33 LOAD_NAME 4 (d)\n 36 STORE_NAME 3 (c)\n >> 39 LOAD_CONST 0 (None)\n 42 RETURN_VALUE\n", nil, ""},
1718+
{"for a in b:\n if a:\n continue\n c = e\nelse: c = d\n", "exec", &py.Code{
1719+
Argcount: 0,
1720+
Kwonlyargcount: 0,
1721+
Nlocals: 0,
1722+
Stacksize: 2,
1723+
Flags: 64,
1724+
Code: "\x78\x26\x00\x65\x00\x00\x44\x5d\x18\x00\x5a\x01\x00\x65\x01\x00\x72\x19\x00\x71\x07\x00\x6e\x00\x00\x65\x02\x00\x5a\x03\x00\x71\x07\x00\x57\x65\x04\x00\x5a\x03\x00\x64\x00\x00\x53",
1725+
Consts: []py.Object{py.None},
1726+
Names: []string{"b", "a", "e", "c", "d"},
1727+
Varnames: []string{},
1728+
Freevars: []string{},
1729+
Cellvars: []string{},
1730+
Filename: "<string>",
1731+
Name: "<module>",
1732+
Firstlineno: 1,
1733+
Lnotab: "\x0d\x01\x06\x01\x06\x01\x0a\x01",
1734+
}, " 1 0 SETUP_LOOP 38 (to 41)\n 3 LOAD_NAME 0 (b)\n 6 GET_ITER\n >> 7 FOR_ITER 24 (to 34)\n 10 STORE_NAME 1 (a)\n\n 2 13 LOAD_NAME 1 (a)\n 16 POP_JUMP_IF_FALSE 25\n\n 3 19 JUMP_ABSOLUTE 7\n 22 JUMP_FORWARD 0 (to 25)\n\n 4 >> 25 LOAD_NAME 2 (e)\n 28 STORE_NAME 3 (c)\n 31 JUMP_ABSOLUTE 7\n >> 34 POP_BLOCK\n\n 5 35 LOAD_NAME 4 (d)\n 38 STORE_NAME 3 (c)\n >> 41 LOAD_CONST 0 (None)\n 44 RETURN_VALUE\n", nil, ""},
16841735
}

compile/compile_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ func TestCompile(t *testing.T) {
8989
defer func() {
9090
if r := recover(); r != nil {
9191
if test.exceptionType == nil {
92-
t.Errorf("%s: Got exception %v when not expecting one", test.in)
92+
t.Errorf("%s: Got exception %v when not expecting one", test.in, r)
9393
return
9494
}
9595
exc, ok := r.(*py.Exception)

compile/make_compile_test.py

+4
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@
140140
('''while a:\n if b: continue\n b = c\n''', "exec"),
141141
('''continue''', "exec", SyntaxError),
142142
('''break''', "exec", SyntaxError),
143+
# for
144+
('''for a in b: pass''', "exec"),
145+
('''for a in b:\n if a:\n break\n c = e\nelse: c = d\n''', "exec"),
146+
('''for a in b:\n if a:\n continue\n c = e\nelse: c = d\n''', "exec"),
143147

144148
]
145149

0 commit comments

Comments
 (0)