Skip to content

Commit

Permalink
feat: list.forEach (#110)
Browse files Browse the repository at this point in the history
  • Loading branch information
giann committed Dec 8, 2022
1 parent 6864aac commit 949a0b9
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 6 deletions.
8 changes: 4 additions & 4 deletions src/buzz_api.zig
Original file line number Diff line number Diff line change
Expand Up @@ -507,15 +507,15 @@ export fn bz_interpret(self: *VM, function: *ObjFunction) bool {
return true;
}

export fn bz_call(self: *VM, closure: *ObjClosure, arguments: [*]Value, len: usize, catch_value: ?*Value) void {
self.push(closure);
pub export fn bz_call(self: *VM, closure: *ObjClosure, arguments: [*]const *const Value, len: u8, catch_value: ?*Value) void {
self.push(closure.toValue());
var i: usize = 0;
while (i < len) : (i += 1) {
self.push(arguments[i]);
self.push(arguments[i].*);
}

// TODO: catch properly
self.callValue(closure, len, catch_value) catch unreachable;
self.callValue(closure.toValue(), len, if (catch_value) |v| v.* else null) catch unreachable;

self.run();
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/buzz_api.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub const VM = opaque {
pub extern fn bz_deinitVM(self: *VM) void;
pub extern fn bz_compile(self: *VM, source: ?[*]const u8, source_len: usize, file_name: ?[*]const u8, file_name_len: usize) ?*ObjFunction;
pub extern fn bz_interpret(self: *VM, function: *ObjFunction) bool;
pub extern fn bz_call(self: *VM, closure: *ObjClosure, arguments: [*]Value, len: usize, catch_value: ?*Value) void;
pub extern fn bz_call(self: *VM, closure: *ObjClosure, arguments: [*]const *const Value, len: usize, catch_value: ?*Value) void;
pub extern fn bz_push(self: *VM, value: *Value) void;
pub extern fn bz_pop(self: *VM) *Value;
pub extern fn bz_peek(self: *VM, distance: u32) *Value;
Expand Down
80 changes: 80 additions & 0 deletions src/obj.zig
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const _value = @import("./value.zig");
const Token = @import("./token.zig").Token;
const BuildOptions = @import("build_options");
const CodeGen = @import("./codegen.zig").CodeGen;
const buzz_api = @import("./buzz_api.zig");

pub const pcre = @import("./pcre.zig").pcre;

Expand Down Expand Up @@ -1719,6 +1720,8 @@ pub const ObjList = struct {
nativeFn = insert;
} else if (mem.eql(u8, method.string, "pop")) {
nativeFn = pop;
} else if (mem.eql(u8, method.string, "forEach")) {
nativeFn = forEach;
}

if (nativeFn) |unativeFn| {
Expand Down Expand Up @@ -1752,6 +1755,28 @@ pub const ObjList = struct {
try gc.markObjDirty(&self.obj);
}

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

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

args.append(&item) catch unreachable;

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

return 0;
}

fn append(vm: *VM) c_int {
var list_value: Value = vm.peek(1);
var list: *ObjList = ObjList.cast(list_value.Obj).?;
Expand Down Expand Up @@ -2338,6 +2363,61 @@ pub const ObjList = struct {

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

return native_type;
} else if (mem.eql(u8, method, "forEach")) {
// 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 = .Void }),
.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("forEach"),
.parameters = parameters,
.defaults = std.AutoArrayHashMap(*ObjString, Value).init(parser.gc.allocator),
.return_type = try parser.gc.type_registry.getTypeDef(.{ .def_type = .Void }),
.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("forEach", native_type);

return native_type;
}

Expand Down
2 changes: 1 addition & 1 deletion src/vm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3339,7 +3339,7 @@ pub const VM = struct {
);
}

fn run(self: *Self) void {
pub fn run(self: *Self) void {
const next_current_frame: *CallFrame = self.currentFrame().?;
const next_full_instruction: u32 = self.readInstruction();
const next_instruction: OpCode = getCode(next_full_instruction);
Expand Down
12 changes: 12 additions & 0 deletions tests/051-functional.buzz
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import "lib/std";

test "forEach" {
[int] data = [1, 2, 3, 4];

int sum = 0;
data.forEach(fun (int element) > void {
sum = sum + element;
});

assert(sum == 10, message: "Could use forEach");
}

0 comments on commit 949a0b9

Please sign in to comment.