Skip to content

Commit 6e9db42

Browse files
committed
py: fix iterable object
1 parent acd458b commit 6e9db42

File tree

10 files changed

+118
-49
lines changed

10 files changed

+118
-49
lines changed

py/arithmetic.go

-18
Original file line numberDiff line numberDiff line change
@@ -147,24 +147,6 @@ func MakeFloat(a Object) (Object, error) {
147147
return nil, ExceptionNewf(TypeError, "unsupported operand type(s) for float: '%s'", a.Type().Name)
148148
}
149149

150-
// Iter the python Object returning an Object
151-
//
152-
// Will raise TypeError if Iter can't be run on this object
153-
func Iter(a Object) (Object, error) {
154-
155-
if A, ok := a.(I__iter__); ok {
156-
res, err := A.M__iter__()
157-
if err != nil {
158-
return nil, err
159-
}
160-
if res != NotImplemented {
161-
return res, nil
162-
}
163-
}
164-
165-
return nil, ExceptionNewf(TypeError, "unsupported operand type(s) for iter: '%s'", a.Type().Name)
166-
}
167-
168150
// Add two python objects together returning an Object
169151
//
170152
// Will raise TypeError if can't be add can't be run on these objects

py/dict.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func init() {
3636
return nil, err
3737
}
3838
sMap := self.(StringDict)
39-
o := make([]Object, 0, len(sMap))
39+
o := make(Tuple, 0, len(sMap))
4040
for k, v := range sMap {
4141
o = append(o, Tuple{String(k), v})
4242
}
@@ -49,7 +49,7 @@ func init() {
4949
return nil, err
5050
}
5151
sMap := self.(StringDict)
52-
o := make([]Object, 0, len(sMap))
52+
o := make(Tuple, 0, len(sMap))
5353
for k := range sMap {
5454
o = append(o, String(k))
5555
}
@@ -62,7 +62,7 @@ func init() {
6262
return nil, err
6363
}
6464
sMap := self.(StringDict)
65-
o := make([]Object, 0, len(sMap))
65+
o := make(Tuple, 0, len(sMap))
6666
for _, v := range sMap {
6767
o = append(o, v)
6868
}
@@ -204,7 +204,7 @@ func (a StringDict) M__repr__() (Object, error) {
204204

205205
// Returns a list of keys from the dict
206206
func (d StringDict) M__iter__() (Object, error) {
207-
o := make([]Object, 0, len(d))
207+
o := make(Tuple, 0, len(d))
208208
for k := range d {
209209
o = append(o, String(k))
210210
}

py/exception.go

+2
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,8 @@ func ExceptionGivenMatches(err, exc Object) bool {
336336
func IsException(exception *Type, r interface{}) bool {
337337
var t *Type
338338
switch ex := r.(type) {
339+
case ExceptionInfo:
340+
t = ex.Type
339341
case *Exception:
340342
t = ex.Type()
341343
case *Type:

py/gen.go

-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ var data = Data{
4545
{Name: "complex", Title: "MakeComplex", Operator: "complex", Unary: true, Conversion: "Complex"},
4646
{Name: "int", Title: "MakeInt", Operator: "int", Unary: true, Conversion: "Int"},
4747
{Name: "float", Title: "MakeFloat", Operator: "float", Unary: true, Conversion: "Float"},
48-
{Name: "iter", Title: "Iter", Operator: "iter", Unary: true},
4948
},
5049
BinaryOps: Ops{
5150
{Name: "add", Title: "Add", Operator: "+", Binary: true},

py/internal.go

+17
Original file line numberDiff line numberDiff line change
@@ -430,3 +430,20 @@ func ReprAsString(self Object) (string, error) {
430430
}
431431
return string(str), nil
432432
}
433+
434+
// Returns an iterator object
435+
//
436+
// Call __Iter__ Returns an iterator object
437+
//
438+
// If object is sequence object, create an iterator
439+
func Iter(self Object) (res Object, err error) {
440+
if I, ok := self.(I__iter__); ok {
441+
return I.M__iter__()
442+
} else if res, ok, err = TypeCall0(self, "__iter__"); ok {
443+
return res, err
444+
}
445+
if ObjectIsSequence(self) {
446+
return NewIterator(self), nil
447+
}
448+
return nil, ExceptionNewf(TypeError, "'%s' object is not iterable", self.Type().Name)
449+
}

py/iterator.go

+26-10
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ package py
88

99
// A python Iterator object
1010
type Iterator struct {
11-
Pos int
12-
Objs []Object
11+
Pos int
12+
Seq Object
1313
}
1414

1515
var IteratorType = NewType("iterator", "iterator type")
@@ -20,10 +20,10 @@ func (o *Iterator) Type() *Type {
2020
}
2121

2222
// Define a new iterator
23-
func NewIterator(Objs []Object) *Iterator {
23+
func NewIterator(Seq Object) *Iterator {
2424
m := &Iterator{
25-
Pos: 0,
26-
Objs: Objs,
25+
Pos: 0,
26+
Seq: Seq,
2727
}
2828
return m
2929
}
@@ -33,13 +33,29 @@ func (it *Iterator) M__iter__() (Object, error) {
3333
}
3434

3535
// Get next one from the iteration
36-
func (it *Iterator) M__next__() (Object, error) {
37-
if it.Pos >= len(it.Objs) {
38-
return nil, StopIteration
36+
func (it *Iterator) M__next__() (res Object, err error) {
37+
if tuple, ok := it.Seq.(Tuple); ok {
38+
if it.Pos >= len(tuple) {
39+
return nil, StopIteration
40+
}
41+
res = tuple[it.Pos]
42+
it.Pos++
43+
return res, nil
44+
}
45+
index := Int(it.Pos)
46+
if I, ok := it.Seq.(I__getitem__); ok {
47+
res, err = I.M__getitem__(index)
48+
} else if res, ok, err = TypeCall1(it.Seq, "__getitem__", index); !ok {
49+
return nil, ExceptionNewf(TypeError, "'%s' object is not iterable", it.Type().Name)
50+
}
51+
if err != nil {
52+
if IsException(IndexError, err) {
53+
return nil, StopIteration
54+
}
55+
return nil, err
3956
}
40-
r := it.Objs[it.Pos]
4157
it.Pos++
42-
return r, nil
58+
return res, nil
4359
}
4460

4561
// Check interface is satisfied

py/list.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ func (l *List) M__bool__() (Object, error) {
186186
}
187187

188188
func (l *List) M__iter__() (Object, error) {
189-
return NewIterator(l.Items), nil
189+
return NewIterator(Tuple(l.Items)), nil
190190
}
191191

192192
func (l *List) M__getitem__(key Object) (Object, error) {
@@ -496,7 +496,11 @@ func SortInPlace(l *List, kwargs StringDict, funcName string) error {
496496
reverse = False
497497
}
498498
// FIXME: requires the same bool-check like CPython (or better "|$Op" that doesn't panic on nil).
499-
s := ptrSortable{&sortable{l, keyFunc, ObjectIsTrue(reverse), nil}}
499+
ok, err := ObjectIsTrue(reverse)
500+
if err != nil {
501+
return err
502+
}
503+
s := ptrSortable{&sortable{l, keyFunc, ok, nil}}
500504
sort.Stable(s)
501505
return s.s.firstErr
502506
}

py/object.go

+41-12
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,53 @@ func ObjectRepr(o Object) Object {
2323
}
2424

2525
// Return whether the object is True or not
26-
func ObjectIsTrue(o Object) bool {
27-
if o == True {
28-
return true
26+
func ObjectIsTrue(o Object) (cmp bool, err error) {
27+
switch o {
28+
case True:
29+
return true, nil
30+
case False:
31+
return false, nil
32+
case None:
33+
return false, nil
34+
}
35+
36+
var res Object
37+
switch t := o.(type) {
38+
case I__bool__:
39+
res, err = t.M__bool__()
40+
case I__len__:
41+
res, err = t.M__len__()
42+
case *Type:
43+
var ok bool
44+
if res, ok, err = TypeCall0(o, "__bool__"); ok {
45+
break
46+
}
47+
if res, ok, err = TypeCall0(o, "__len__"); ok {
48+
break
49+
}
50+
_ = ok // pass static-check
2951
}
30-
if o == False {
31-
return false
52+
if err != nil {
53+
return false, err
3254
}
3355

34-
if o == None {
35-
return false
56+
switch t := res.(type) {
57+
case Bool:
58+
return t == True, nil
59+
case Int:
60+
return t > 0, nil
3661
}
62+
return true, nil
63+
}
3764

38-
if I, ok := o.(I__bool__); ok {
39-
cmp, err := I.M__bool__()
40-
if err == nil && cmp == True {
65+
// Return whether the object is True or not
66+
func ObjectIsSequence(o Object) bool {
67+
switch t := o.(type) {
68+
case I__getitem__:
69+
return true
70+
case *Type:
71+
if t.GetAttrOrNil("__getitem__") != nil {
4172
return true
42-
} else if err == nil && cmp == False {
43-
return false
4473
}
4574
}
4675
return false

py/tests/iter.py

+12
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,16 @@ def f():
1818
words2 = list(iter(words1))
1919
for w1, w2 in zip(words1, words2):
2020
assert w1 == w2
21+
22+
class SequenceClass:
23+
def __init__(self, n):
24+
self.n = n
25+
def __getitem__(self, i):
26+
if 0 <= i < self.n:
27+
return i
28+
else:
29+
raise IndexError
30+
31+
assert list(iter(SequenceClass(5))) == [0, 1, 2, 3, 4]
32+
2133
doc="finished"

stdlib/builtin/builtin.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,11 @@ func builtin_all(self, seq py.Object) (py.Object, error) {
292292
}
293293
return nil, err
294294
}
295-
if !py.ObjectIsTrue(item) {
295+
ok, err := py.ObjectIsTrue(item)
296+
if err != nil {
297+
return nil, err
298+
}
299+
if !ok {
296300
return py.False, nil
297301
}
298302
}
@@ -317,7 +321,11 @@ func builtin_any(self, seq py.Object) (py.Object, error) {
317321
}
318322
return nil, err
319323
}
320-
if py.ObjectIsTrue(item) {
324+
ok, err := py.ObjectIsTrue(item)
325+
if err != nil {
326+
return nil, err
327+
}
328+
if ok {
321329
return py.True, nil
322330
}
323331
}

0 commit comments

Comments
 (0)