Skip to content

Commit 60dd952

Browse files
committed
Make Iter() and Iterator type and implement GET_ITER, FOR_ITER, BUILD_LIST/TUPLE
1 parent acc6057 commit 60dd952

File tree

6 files changed

+109
-8
lines changed

6 files changed

+109
-8
lines changed

py/arithmetic.go

+16
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,22 @@ func MakeFloat(a Object) Object {
133133
panic(fmt.Sprintf("TypeError: unsupported operand type(s) for float: '%s'", a.Type().Name))
134134
}
135135

136+
// Iter the python Object returning an Object
137+
//
138+
// Will raise TypeError if Iter can't be run on this object
139+
func Iter(a Object) Object {
140+
141+
if A, ok := a.(I__iter__); ok {
142+
res := A.M__iter__()
143+
if res != NotImplemented {
144+
return res
145+
}
146+
}
147+
148+
// FIXME should be TypeError
149+
panic(fmt.Sprintf("TypeError: unsupported operand type(s) for iter: '%s'", a.Type().Name))
150+
}
151+
136152
// Add two python objects together returning an Object
137153
//
138154
// Will raise TypeError if can't be add can't be run on these objects

py/gen.go

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ var data = Data{
4040
{Name: "complex", Title: "MakeComplex", Operator: "complex", Unary: true, Conversion: "Complex"},
4141
{Name: "int", Title: "MakeInt", Operator: "int", Unary: true, Conversion: "Int"},
4242
{Name: "float", Title: "MakeFloat", Operator: "float", Unary: true, Conversion: "Float"},
43+
{Name: "iter", Title: "Iter", Operator: "iter", Unary: true},
4344
},
4445
BinaryOps: Ops{
4546
{Name: "add", Title: "Add", Operator: "+", Binary: true},

py/list.go

+22
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,25 @@ type List []Object
1010
func (o List) Type() *Type {
1111
return ListType
1212
}
13+
14+
func (t List) M__len__() Object {
15+
return Int(len(t))
16+
}
17+
18+
func (t List) M__bool__() Object {
19+
if len(t) > 0 {
20+
return True
21+
}
22+
return False
23+
}
24+
25+
func (t List) M__iter__() Object {
26+
return NewIterator(t)
27+
}
28+
29+
// Check interface is satisfied
30+
var _ I__len__ = List(nil)
31+
var _ I__bool__ = List(nil)
32+
var _ I__iter__ = List(nil)
33+
34+
// var _ richComparison = List(nil)

py/py.go

+11
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,17 @@ type I__iter__ interface {
546546
M__iter__() Object
547547
}
548548

549+
// The next method for iterators
550+
type I__next__ interface {
551+
M__next__() Object
552+
}
553+
554+
// Interface all iterators must satisfy
555+
type I_iterator interface {
556+
I__iter__
557+
I__next__
558+
}
559+
549560
// Called (if present) by the reversed() built-in to implement reverse
550561
// iteration. It should return a new iterator object that iterates
551562
// over all the objects in the container in reverse order.

py/tuple.go

+22
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,25 @@ type Tuple []Object
1010
func (o Tuple) Type() *Type {
1111
return TupleType
1212
}
13+
14+
func (t Tuple) M__len__() Object {
15+
return Int(len(t))
16+
}
17+
18+
func (t Tuple) M__bool__() Object {
19+
if len(t) > 0 {
20+
return True
21+
}
22+
return False
23+
}
24+
25+
func (t Tuple) M__iter__() Object {
26+
return NewIterator(t)
27+
}
28+
29+
// Check interface is satisfied
30+
var _ I__len__ = Tuple(nil)
31+
var _ I__bool__ = Tuple(nil)
32+
var _ I__iter__ = Tuple(nil)
33+
34+
// var _ richComparison = Tuple(nil)

vm/eval.go

+37-8
Original file line numberDiff line numberDiff line change
@@ -87,27 +87,27 @@ func do_DUP_TOP_TWO(vm *Vm, arg int32) {
8787

8888
// Implements TOS = +TOS.
8989
func do_UNARY_POSITIVE(vm *Vm, arg int32) {
90-
vm.PUSH(py.Pos(vm.POP()))
90+
vm.SET_TOP(py.Pos(vm.TOP()))
9191
}
9292

9393
// Implements TOS = -TOS.
9494
func do_UNARY_NEGATIVE(vm *Vm, arg int32) {
95-
vm.PUSH(py.Neg(vm.POP()))
95+
vm.SET_TOP(py.Neg(vm.TOP()))
9696
}
9797

9898
// Implements TOS = not TOS.
9999
func do_UNARY_NOT(vm *Vm, arg int32) {
100-
vm.PUSH(py.Not(vm.POP()))
100+
vm.SET_TOP(py.Not(vm.TOP()))
101101
}
102102

103103
// Implements TOS = ~TOS.
104104
func do_UNARY_INVERT(vm *Vm, arg int32) {
105-
vm.PUSH(py.Invert(vm.POP()))
105+
vm.SET_TOP(py.Invert(vm.TOP()))
106106
}
107107

108108
// Implements TOS = iter(TOS).
109109
func do_GET_ITER(vm *Vm, arg int32) {
110-
vm.NotImplemented("GET_ITER", arg)
110+
vm.SET_TOP(py.Iter(vm.TOP()))
111111
}
112112

113113
// Binary operations remove the top of the stack (TOS) and the second
@@ -315,7 +315,10 @@ func do_PRINT_EXPR(vm *Vm, arg int32) {
315315

316316
// Terminates a loop due to a break statement.
317317
func do_BREAK_LOOP(vm *Vm, arg int32) {
318+
// Jump
318319
vm.frame.Lasti = vm.frame.Block.Handler
320+
// Reset the stack (FIXME?)
321+
vm.stack = vm.stack[:vm.frame.Block.Level]
319322
vm.frame.PopBlock()
320323
}
321324

@@ -505,7 +508,13 @@ func do_LOAD_NAME(vm *Vm, namei int32) {
505508
// Creates a tuple consuming count items from the stack, and pushes
506509
// the resulting tuple onto the stack.
507510
func do_BUILD_TUPLE(vm *Vm, count int32) {
508-
vm.NotImplemented("BUILD_TUPLE", count)
511+
tuple := make(py.Tuple, count)
512+
p := len(vm.stack) - int(count)
513+
for i := range tuple {
514+
tuple[i] = vm.stack[p+i]
515+
}
516+
vm.DROPN(int(count))
517+
vm.PUSH(tuple)
509518
}
510519

511520
// Works as BUILD_TUPLE, but creates a set.
@@ -515,7 +524,13 @@ func do_BUILD_SET(vm *Vm, count int32) {
515524

516525
// Works as BUILD_TUPLE, but creates a list.
517526
func do_BUILD_LIST(vm *Vm, count int32) {
518-
vm.NotImplemented("BUILD_LIST", count)
527+
list := make(py.List, count)
528+
p := len(vm.stack) - int(count)
529+
for i := range list {
530+
list[i] = vm.stack[p+i]
531+
}
532+
vm.DROPN(int(count))
533+
vm.PUSH(list)
519534
}
520535

521536
// Pushes a new dictionary object onto the stack. The dictionary is
@@ -619,7 +634,21 @@ func do_JUMP_ABSOLUTE(vm *Vm, target int32) {
619634
// iterator indicates it is exhausted TOS is popped, and the bytecode
620635
// counter is incremented by delta.
621636
func do_FOR_ITER(vm *Vm, delta int32) {
622-
vm.NotImplemented("FOR_ITER", delta)
637+
defer func() {
638+
if r := recover(); r != nil {
639+
if ex, ok := r.(*py.Exception); ok && ex == py.StopIteration {
640+
// StopIteration raised
641+
vm.DROP()
642+
vm.frame.Lasti += delta
643+
} else {
644+
// re-raise the panic
645+
panic(r)
646+
}
647+
}
648+
}()
649+
it := vm.TOP().(*py.Iterator)
650+
r := it.M__next__()
651+
vm.PUSH(r)
623652
}
624653

625654
// Loads the global named co_names[namei] onto the stack.

0 commit comments

Comments
 (0)