Skip to content

Commit

Permalink
feat: list.filter (#110)
Browse files Browse the repository at this point in the history
  • Loading branch information
giann committed Dec 10, 2022
1 parent 39248a1 commit 2e3694c
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 1 deletion.
94 changes: 94 additions & 0 deletions src/obj.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1724,6 +1724,8 @@ pub const ObjList = struct {
nativeFn = forEach;
} else if (mem.eql(u8, method.string, "map")) {
nativeFn = map;
} else if (mem.eql(u8, method.string, "filter")) {
nativeFn = filter;
}

if (nativeFn) |unativeFn| {
Expand Down Expand Up @@ -1780,6 +1782,43 @@ pub const ObjList = struct {
return 0;
}

fn filter(vm: *VM) c_int {
var list = ObjList.cast(vm.peek(1).Obj).?;
var closure = ObjClosure.cast(vm.peek(0).Obj).?;

var new_list: *ObjList = vm.gc.allocateObject(
ObjList,
ObjList.init(
vm.gc.allocator,
list.type_def.resolved_type.?.List.item_type,
),
) catch unreachable; // TODO: handle error

for (list.items.items) |item| {
var args = std.ArrayList(*const Value).init(vm.gc.allocator);
defer args.deinit();

// TODO: handle error
args.append(&item) catch unreachable;

buzz_api.bz_call(
vm,
closure,
@ptrCast([*]const *const Value, args.items),
@intCast(u8, args.items.len),
null,
);

if (vm.pop().Boolean) {
new_list.rawAppend(vm.gc, item) catch unreachable;
}
}

vm.push(new_list.toValue());

return 1;
}

fn map(vm: *VM) c_int {
var list = ObjList.cast(vm.peek(1).Obj).?;
var closure = ObjClosure.cast(vm.peek(0).Obj).?;
Expand Down Expand Up @@ -2542,6 +2581,61 @@ pub const ObjList = struct {

try self.methods.put("map", native_type);

return native_type;
} else if (mem.eql(u8, method, "filter")) {
// We omit first arg: it'll be OP_SWAPed in and we already parsed it
// It's always the list.

var callback_parameters = std.AutoArrayHashMap(*ObjString, *ObjTypeDef).init(parser.gc.allocator);

// TODO: index parameter?
try callback_parameters.put(try parser.gc.copyString("element"), self.item_type);

var callback_method_def = ObjFunction.FunctionDef{
.id = ObjFunction.FunctionDef.nextId(),
// TODO: is this ok?
.script_name = try parser.gc.copyString("builtin"),
.name = try parser.gc.copyString("anonymous"),
.parameters = callback_parameters,
.defaults = std.AutoArrayHashMap(*ObjString, Value).init(parser.gc.allocator),
.return_type = try parser.gc.type_registry.getTypeDef(.{ .def_type = .Bool }),
.yield_type = try parser.gc.type_registry.getTypeDef(.{ .def_type = .Void }),
.generic_types = std.AutoArrayHashMap(*ObjString, *ObjTypeDef).init(parser.gc.allocator),
};

var callback_resolved_type: ObjTypeDef.TypeUnion = .{ .Function = callback_method_def };

var callback_type = try parser.gc.type_registry.getTypeDef(
ObjTypeDef{
.def_type = .Function,
.resolved_type = callback_resolved_type,
},
);

var parameters = std.AutoArrayHashMap(*ObjString, *ObjTypeDef).init(parser.gc.allocator);

try parameters.put(
try parser.gc.copyString("callback"),
callback_type,
);

var method_def = ObjFunction.FunctionDef{
.id = ObjFunction.FunctionDef.nextId(),
.script_name = try parser.gc.copyString("builtin"),
.name = try parser.gc.copyString("filter"),
.parameters = parameters,
.defaults = std.AutoArrayHashMap(*ObjString, Value).init(parser.gc.allocator),
.return_type = obj_list,
.yield_type = try parser.gc.type_registry.getTypeDef(.{ .def_type = .Void }),
.generic_types = std.AutoArrayHashMap(*ObjString, *ObjTypeDef).init(parser.gc.allocator),
};

var resolved_type: ObjTypeDef.TypeUnion = .{ .Function = method_def };

var native_type = try parser.gc.type_registry.getTypeDef(ObjTypeDef{ .def_type = .Function, .resolved_type = resolved_type });

try self.methods.put("filter", native_type);

return native_type;
}

Expand Down
10 changes: 9 additions & 1 deletion tests/051-functional.buzz
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,13 @@ test "list.map" {

[str] mapped = data.map(<str>, fun (int element) -> "{element}");

print(mapped.join(", "));
assert(mapped.join(", ") == "1, 2, 3, 4", message: "could use map");
}

test "list.filter" {
[int] data = [1, 2, 3, 4];

[int] odd = data.filter(fun (int element) -> element % 2 != 0);

assert(odd.join(", ") == "1, 3", message: "could use filter");
}

0 comments on commit 2e3694c

Please sign in to comment.