Skip to content
This repository has been archived by the owner on Mar 23, 2023. It is now read-only.

Add support for the all builtin #54

Merged
merged 1 commit into from
Jan 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions runtime/builtin_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,31 @@ func builtinAbs(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
return Abs(f, args[0])
}

func builtinAll(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
if raised := checkFunctionArgs(f, "all", args, ObjectType); raised != nil {
return nil, raised
}
iter, raised := Iter(f, args[0])
if raised != nil {
return nil, raised
}
o, raised := Next(f, iter)
for ; raised == nil; o, raised = Next(f, iter) {
ret, raised := IsTrue(f, o)
if raised != nil {
return nil, raised
}
if !ret {
return False.ToObject(), nil
}
}
if !raised.isInstance(StopIterationType) {
return nil, raised
}
f.RestoreExc(nil, nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's unfortunate that there's so much boilerplate for iterating over a sequence. seqForEach almost does what you want but doesn't support breaking out of the loop early. We could add support for that by returning an additional bool value from the callback which signals whether to continue. Might be messy though. I'll leave it up to you whether you want to try something like that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will try and see if it gets messy. Thanks for the review!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another issue is that seqForEach itself only returns the exception. It would have to be modified to return an *Object as well. Worse than that really -- an object for the false case and one from the true case (and those would probably need to be parameters as well).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh. Yeah. I think I remember trying to do this at some point and ran into the same thing. Let's leave things as-is and address this down the road with a more general mechanism.

return True.ToObject(), nil
}

func builtinBin(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
if raised := checkFunctionArgs(f, "bin", args, ObjectType); raised != nil {
return nil, raised
Expand Down Expand Up @@ -472,6 +497,7 @@ func init() {
builtinMap := map[string]*Object{
"__frame__": newBuiltinFunction("__frame__", builtinFrame).ToObject(),
"abs": newBuiltinFunction("abs", builtinAbs).ToObject(),
"all": newBuiltinFunction("all", builtinAll).ToObject(),
"bin": newBuiltinFunction("bin", builtinBin).ToObject(),
"chr": newBuiltinFunction("chr", builtinChr).ToObject(),
"dir": newBuiltinFunction("dir", builtinDir).ToObject(),
Expand Down
21 changes: 21 additions & 0 deletions runtime/builtin_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,21 @@ func TestBuiltinFuncs(t *testing.T) {
return NewInt(123).ToObject(), nil
}).ToObject(),
}))
badNonZeroType := newTestClass("BadNonZeroType", []*Type{ObjectType}, newStringDict(map[string]*Object{
"__nonzero__": newBuiltinFunction("__nonzero__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
return nil, f.RaiseType(RuntimeErrorType, "foo")
}).ToObject(),
}))
badNextType := newTestClass("BadNextType", []*Type{ObjectType}, newStringDict(map[string]*Object{
"next": newBuiltinFunction("next", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
return nil, f.RaiseType(RuntimeErrorType, "foo")
}).ToObject(),
}))
badIterType := newTestClass("BadIterType", []*Type{ObjectType}, newStringDict(map[string]*Object{
"__iter__": newBuiltinFunction("__iter__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
return newObject(badNextType), nil
}).ToObject(),
}))
cases := []struct {
f string
args Args
Expand All @@ -65,6 +80,12 @@ func TestBuiltinFuncs(t *testing.T) {
{f: "abs", args: wrapArgs(NewFloat(-3.4)), want: NewFloat(3.4).ToObject()},
{f: "abs", args: wrapArgs(MinInt), want: NewLong(big.NewInt(MinInt).Neg(minIntBig)).ToObject()},
{f: "abs", args: wrapArgs(NewStr("a")), wantExc: mustCreateException(TypeErrorType, "bad operand type for abs(): 'str'")},
{f: "all", args: wrapArgs(newTestList()), want: True.ToObject()},
{f: "all", args: wrapArgs(newTestList(1, 2, 3)), want: True.ToObject()},
{f: "all", args: wrapArgs(newTestList(1, 0, 1)), want: False.ToObject()},
{f: "all", args: wrapArgs(13), wantExc: mustCreateException(TypeErrorType, "'int' object is not iterable")},
{f: "all", args: wrapArgs(newTestList(newObject(badNonZeroType))), wantExc: mustCreateException(RuntimeErrorType, "foo")},
{f: "all", args: wrapArgs(newObject(badIterType)), wantExc: mustCreateException(RuntimeErrorType, "foo")},
{f: "bin", args: wrapArgs(64 + 8 + 1), want: NewStr("0b1001001").ToObject()},
{f: "bin", args: wrapArgs(MinInt), want: NewStr(fmt.Sprintf("-0b%b0", -(MinInt >> 1))).ToObject()},
{f: "bin", args: wrapArgs(0), want: NewStr("0b0").ToObject()},
Expand Down
20 changes: 20 additions & 0 deletions testing/builtin_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,23 @@
assert str(e) == "bad operand type for abs(): 'str'"
else:
raise AssertionError('this was supposed to raise an exception')


# all(iterable)

assert all([1, 2, 3])
assert all([])
assert not all([1, 1, 1, 0, 1])

assert all([True, True])
assert not all([False, True, True])

assert all('')
assert all('abc')

try:
all(13)
except TypeError as e:
assert str(e) == "'int' object is not iterable"
else:
raise AssertionError('this was supposed to raise an exception')