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

Commit 8f34cf7

Browse files
committed
Add builtin filter function
1 parent 6bdfc4b commit 8f34cf7

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

runtime/builtin_types.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package grumpy
1616

1717
import (
18+
"bytes"
1819
"fmt"
1920
"math"
2021
"math/big"
@@ -248,6 +249,82 @@ func builtinMapFn(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
248249
return NewList(result...).ToObject(), nil
249250
}
250251

252+
func builtinFilter(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
253+
argc := len(args)
254+
if argc < 2 {
255+
return nil, f.RaiseType(TypeErrorType, fmt.Sprintf("filter expected 2 arguments, got %d", argc))
256+
}
257+
fn := args[0]
258+
l := args[1]
259+
switch {
260+
case l.isInstance(TupleType):
261+
result := make([]*Object, 0)
262+
for _, item := range toTupleUnsafe(l).elems {
263+
if fn == None {
264+
if ret, raised := IsTrue(f, item); raised != nil {
265+
return nil, raised
266+
} else if ret {
267+
result = append(result, item)
268+
}
269+
} else {
270+
ret, raised := args[0].Call(f, []*Object{item}, nil)
271+
if raised != nil {
272+
return nil, raised
273+
}
274+
if ret, raised := IsTrue(f, ret); raised != nil {
275+
return nil, raised
276+
} else if ret {
277+
result = append(result, item)
278+
}
279+
}
280+
}
281+
return NewTuple(result...).ToObject(), nil
282+
case l.isInstance(StrType):
283+
if fn == None {
284+
return l, nil
285+
}
286+
var result bytes.Buffer
287+
for _, item := range toStrUnsafe(l).Value() {
288+
ret, raised := fn.Call(f, []*Object{NewStr(string(item)).ToObject()}, nil)
289+
if raised != nil {
290+
return nil, raised
291+
}
292+
if ret, raised := IsTrue(f, ret); raised != nil {
293+
return nil, raised
294+
} else if ret {
295+
result.WriteRune(item)
296+
}
297+
}
298+
return NewStr(result.String()).ToObject(), nil
299+
default:
300+
result := make([]*Object, 0)
301+
raised := seqForEach(f, l, func(item *Object) (raised *BaseException) {
302+
if fn == None {
303+
if ret, raised := IsTrue(f, item); raised != nil {
304+
return raised
305+
} else if ret {
306+
result = append(result, item)
307+
}
308+
} else {
309+
ret, raised := fn.Call(f, []*Object{item}, nil)
310+
if raised != nil {
311+
return raised
312+
}
313+
if ret, raised := IsTrue(f, ret); raised != nil {
314+
return raised
315+
} else if ret {
316+
result = append(result, item)
317+
}
318+
}
319+
return nil
320+
})
321+
if raised != nil {
322+
return nil, raised
323+
}
324+
return NewList(result...).ToObject(), nil
325+
}
326+
}
327+
251328
func builtinAll(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
252329
if raised := checkFunctionArgs(f, "all", args, ObjectType); raised != nil {
253330
return nil, raised
@@ -768,6 +845,7 @@ func init() {
768845
"divmod": newBuiltinFunction("divmod", builtinDivMod).ToObject(),
769846
"Ellipsis": Ellipsis,
770847
"False": False.ToObject(),
848+
"filter": newBuiltinFunction("filter", builtinFilter).ToObject(),
771849
"getattr": newBuiltinFunction("getattr", builtinGetAttr).ToObject(),
772850
"globals": newBuiltinFunction("globals", builtinGlobals).ToObject(),
773851
"hasattr": newBuiltinFunction("hasattr", builtinHasAttr).ToObject(),

runtime/builtin_types_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,11 @@ func TestBuiltinFuncs(t *testing.T) {
186186
{f: "divmod", args: wrapArgs(-3.25, -1.0), want: NewTuple2(NewFloat(3.0).ToObject(), NewFloat(-0.25).ToObject()).ToObject()},
187187
{f: "divmod", args: wrapArgs(NewStr("a"), NewStr("b")), wantExc: mustCreateException(TypeErrorType, "unsupported operand type(s) for divmod(): 'str' and 'str'")},
188188
{f: "divmod", args: wrapArgs(), wantExc: mustCreateException(TypeErrorType, "'divmod' requires 2 arguments")},
189+
{f: "filter", args: wrapArgs(None, NewTuple2(NewInt(0).ToObject(), NewInt(1).ToObject())), want: NewTuple1(NewInt(1).ToObject()).ToObject()},
190+
{f: "filter", args: wrapArgs(BoolType, NewTuple2(NewInt(0).ToObject(), NewInt(1).ToObject())), want: NewTuple1(NewInt(1).ToObject()).ToObject()},
191+
{f: "filter", args: wrapArgs(IntType, "012"), want: NewStr("12").ToObject()},
192+
{f: "filter", args: wrapArgs(None, newTestList(1, 0, 3)), want: newTestList(1, 3).ToObject()},
193+
{f: "filter", args: wrapArgs(IntType, newTestList("1", "0", "3")), want: newTestList("1", "3").ToObject()},
189194
{f: "getattr", args: wrapArgs(None, NewStr("foo").ToObject(), NewStr("bar").ToObject()), want: NewStr("bar").ToObject()},
190195
{f: "getattr", args: wrapArgs(None, NewStr("foo").ToObject()), wantExc: mustCreateException(AttributeErrorType, "'NoneType' object has no attribute 'foo'")},
191196
{f: "hasattr", args: wrapArgs(newObject(ObjectType), NewStr("foo").ToObject()), want: False.ToObject()},

0 commit comments

Comments
 (0)