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

Commit

Permalink
Add support for the any builtin (#54) (#63)
Browse files Browse the repository at this point in the history
Implement the `any` as defined here:

    * https://docs.python.org/2/library/functions.html#any

Note that a new helper function `seqFindFirst` was added that
is used to implement `builtinAll`, `builtinAny`, and `seqContains`.
  • Loading branch information
meadori authored and trotterdylan committed Jan 9, 2017
1 parent 47e0e02 commit 2050551
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 19 deletions.
32 changes: 22 additions & 10 deletions runtime/builtin_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,25 +194,36 @@ 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])
pred := func(o *Object) (bool, *BaseException) {
ret, raised := IsTrue(f, o)
if raised != nil {
return false, raised
}
return !ret, nil
}
foundFalseItem, raised := seqFindFirst(f, args[0], pred)
if raised != nil {
return nil, raised
}
o, raised := Next(f, iter)
for ; raised == nil; o, raised = Next(f, iter) {
return GetBool(!foundFalseItem).ToObject(), raised
}

func builtinAny(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
if raised := checkFunctionArgs(f, "any", args, ObjectType); raised != nil {
return nil, raised
}
pred := func(o *Object) (bool, *BaseException) {
ret, raised := IsTrue(f, o)
if raised != nil {
return nil, raised
}
if !ret {
return False.ToObject(), nil
return false, raised
}
return ret, nil
}
if !raised.isInstance(StopIterationType) {
foundTrueItem, raised := seqFindFirst(f, args[0], pred)
if raised != nil {
return nil, raised
}
f.RestoreExc(nil, nil)
return True.ToObject(), nil
return GetBool(foundTrueItem).ToObject(), raised
}

func builtinBin(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
Expand Down Expand Up @@ -509,6 +520,7 @@ func init() {
"__frame__": newBuiltinFunction("__frame__", builtinFrame).ToObject(),
"abs": newBuiltinFunction("abs", builtinAbs).ToObject(),
"all": newBuiltinFunction("all", builtinAll).ToObject(),
"any": newBuiltinFunction("any", builtinAny).ToObject(),
"bin": newBuiltinFunction("bin", builtinBin).ToObject(),
"callable": newBuiltinFunction("callable", builtinCallable).ToObject(),
"chr": newBuiltinFunction("chr", builtinChr).ToObject(),
Expand Down
8 changes: 8 additions & 0 deletions runtime/builtin_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@ func TestBuiltinFuncs(t *testing.T) {
{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: "any", args: wrapArgs(newTestList()), want: False.ToObject()},
{f: "any", args: wrapArgs(newTestList(1, 2, 3)), want: True.ToObject()},
{f: "any", args: wrapArgs(newTestList(1, 0, 1)), want: True.ToObject()},
{f: "any", args: wrapArgs(newTestList(0, 0, 0)), want: False.ToObject()},
{f: "any", args: wrapArgs(newTestList(False.ToObject(), False.ToObject())), want: False.ToObject()},
{f: "any", args: wrapArgs(13), wantExc: mustCreateException(TypeErrorType, "'int' object is not iterable")},
{f: "any", args: wrapArgs(newTestList(newObject(badNonZeroType))), wantExc: mustCreateException(RuntimeErrorType, "foo")},
{f: "any", 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
2 changes: 1 addition & 1 deletion runtime/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func listAppend(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
}

func listContains(f *Frame, l, v *Object) (*Object, *BaseException) {
return seqContains(f, toListUnsafe(l).elems, v)
return seqContains(f, l, v)
}

func listEq(f *Frame, v, w *Object) (*Object, *BaseException) {
Expand Down
38 changes: 31 additions & 7 deletions runtime/seq.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,21 +108,45 @@ func seqClampIndex(i, seqLen int) int {
return i
}

func seqContains(f *Frame, elems []*Object, v *Object) (*Object, *BaseException) {
for _, i := range elems {
eq, raised := Eq(f, v, i)
func seqContains(f *Frame, iterable *Object, v *Object) (*Object, *BaseException) {
pred := func(o *Object) (bool, *BaseException) {
eq, raised := Eq(f, v, o)
if raised != nil {
return nil, raised
return false, raised
}
ret, raised := IsTrue(f, eq)
if raised != nil {
return nil, raised
return false, raised
}
return ret, nil
}
foundEqItem, raised := seqFindFirst(f, iterable, pred)
if raised != nil {
return nil, raised
}
return GetBool(foundEqItem).ToObject(), raised
}

func seqFindFirst(f *Frame, iterable *Object, pred func(*Object) (bool, *BaseException)) (bool, *BaseException) {
iter, raised := Iter(f, iterable)
if raised != nil {
return false, raised
}
item, raised := Next(f, iter)
for ; raised == nil; item, raised = Next(f, iter) {
ret, raised := pred(item)
if raised != nil {
return false, raised
}
if ret {
return True.ToObject(), nil
return true, nil
}
}
return False.ToObject(), nil
if !raised.isInstance(StopIterationType) {
return false, raised
}
f.RestoreExc(nil, nil)
return false, nil
}

func seqForEach(f *Frame, iterable *Object, callback func(*Object) *BaseException) *BaseException {
Expand Down
2 changes: 1 addition & 1 deletion runtime/tuple.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func tupleAdd(f *Frame, v, w *Object) (*Object, *BaseException) {
}

func tupleContains(f *Frame, t, v *Object) (*Object, *BaseException) {
return seqContains(f, toTupleUnsafe(t).elems, v)
return seqContains(f, t, v)
}

func tupleEq(f *Frame, v, w *Object) (*Object, *BaseException) {
Expand Down
23 changes: 23 additions & 0 deletions testing/builtin_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,29 @@
else:
raise AssertionError('this was supposed to raise an exception')


# any(iterable)

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

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

assert not any('')
assert any('abc')

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


# callable(x)

assert not callable(1)
Expand Down

0 comments on commit 2050551

Please sign in to comment.