Skip to content

Commit 344a390

Browse files
authored
builtin: Implement builtin_iter (#54)
1 parent 05fb6f3 commit 344a390

File tree

4 files changed

+150
-1
lines changed

4 files changed

+150
-1
lines changed

builtin/builtin.go

+34-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func init() {
4444
// py.MustNewMethod("input", builtin_input, 0, input_doc),
4545
// py.MustNewMethod("isinstance", builtin_isinstance, 0, isinstance_doc),
4646
// py.MustNewMethod("issubclass", builtin_issubclass, 0, issubclass_doc),
47-
// py.MustNewMethod("iter", builtin_iter, 0, iter_doc),
47+
py.MustNewMethod("iter", builtin_iter, 0, iter_doc),
4848
py.MustNewMethod("len", builtin_len, 0, len_doc),
4949
py.MustNewMethod("locals", py.InternalMethodLocals, 0, locals_doc),
5050
py.MustNewMethod("max", builtin_max, 0, max_doc),
@@ -762,6 +762,39 @@ object.
762762
The globals and locals are dictionaries, defaulting to the current
763763
globals and locals. If only globals is given, locals defaults to it.`
764764

765+
const iter_doc = `iter(iterable) -> iterator
766+
iter(callable, sentinel) -> iterator
767+
768+
Get an iterator from an object. In the first form, the argument must
769+
supply its own iterator, or be a sequence.
770+
In the second form, the callable is called until it returns the sentinel.
771+
`
772+
773+
func builtin_iter(self py.Object, args py.Tuple) (py.Object, error) {
774+
nArgs := len(args)
775+
if nArgs < 1 {
776+
return nil, py.ExceptionNewf(py.TypeError,
777+
"iter expected at least 1 arguments, got %d",
778+
nArgs)
779+
} else if nArgs > 2 {
780+
return nil, py.ExceptionNewf(py.TypeError,
781+
"iter expected at most 2 arguments, got %d",
782+
nArgs)
783+
}
784+
785+
v := args[0]
786+
if nArgs == 1 {
787+
return py.Iter(v)
788+
}
789+
_, ok := v.(*py.Function)
790+
sentinel := args[1]
791+
if !ok {
792+
return nil, py.ExceptionNewf(py.TypeError,
793+
"iter(v, w): v must be callable")
794+
}
795+
return py.NewCallIterator(v, sentinel), nil
796+
}
797+
765798
// For code see vm/builtin.go
766799

767800
const len_doc = `len(object) -> integer

builtin/tests/builtin.py

+44
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,50 @@ def func(p):
132132
ok = True
133133
assert ok, "ValueError not raised"
134134

135+
doc="iter"
136+
cnt = 0
137+
def f():
138+
global cnt
139+
cnt += 1
140+
return cnt
141+
142+
l = list(iter(f,20))
143+
assert len(l) == 19
144+
for idx, v in enumerate(l):
145+
assert idx + 1 == v
146+
147+
words1 = ['g', 'p', 'y', 't', 'h', 'o', 'n']
148+
words2 = list(iter(words1))
149+
for w1, w2 in zip(words1, words2):
150+
assert w1 == w2
151+
152+
ok = False
153+
try:
154+
iter()
155+
except TypeError:
156+
ok = True
157+
finally:
158+
assert ok, "TypeError not raised"
159+
ok = False
160+
161+
try:
162+
l = [1, 2, 3]
163+
iter(l, 2)
164+
except TypeError:
165+
ok = True
166+
finally:
167+
assert ok, "TypeError not raised"
168+
ok = False
169+
170+
try:
171+
iter(f, 2, 3)
172+
except TypeError:
173+
ok = True
174+
finally:
175+
assert ok, "TypeError not raised"
176+
ok = False
177+
178+
135179
doc="next no default"
136180
def gen():
137181
yield 1

py/call_iterator.go

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2019 The go-python Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// CallIterator objects
6+
7+
package py
8+
9+
// A python CallIterator object
10+
type CallIterator struct {
11+
callable Object
12+
sentinel Object
13+
}
14+
15+
var CallIteratorType = NewType("callable_iterator", "callable_iterator type")
16+
17+
// Type of this object
18+
func (o *CallIterator) Type() *Type {
19+
return CallIteratorType
20+
}
21+
22+
func (cit *CallIterator) M__iter__() (Object, error) {
23+
return cit, nil
24+
}
25+
26+
// Get next one from the iteration
27+
func (cit *CallIterator) M__next__() (Object, error) {
28+
value, err := Call(cit.callable, nil, nil)
29+
30+
if err != nil {
31+
return nil, err
32+
}
33+
34+
if value == cit.sentinel {
35+
return nil, StopIteration
36+
}
37+
38+
return value, nil
39+
}
40+
41+
// Define a new CallIterator
42+
func NewCallIterator(callable Object, sentinel Object) *CallIterator {
43+
c := &CallIterator{
44+
callable: callable,
45+
sentinel: sentinel,
46+
}
47+
return c
48+
}
49+
50+
// Check interface is satisfied
51+
var _ I_iterator = (*CallIterator)(nil)

py/tests/iter.py

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright 2019 The go-python Authors. All rights reserved.
2+
# Use of this source code is governed by a BSD-style
3+
# license that can be found in the LICENSE file.
4+
5+
doc="iter"
6+
cnt = 0
7+
def f():
8+
global cnt
9+
cnt += 1
10+
return cnt
11+
12+
l = list(iter(f,20))
13+
assert len(l) == 19
14+
for idx, v in enumerate(l):
15+
assert idx + 1 == v
16+
17+
words1 = ['g', 'p', 'y', 't', 'h', 'o', 'n']
18+
words2 = list(iter(words1))
19+
for w1, w2 in zip(words1, words2):
20+
assert w1 == w2
21+
doc="finished"

0 commit comments

Comments
 (0)