From b012e1e5f699f02eb537a92b80bc524f79851a1c Mon Sep 17 00:00:00 2001 From: kayomn Date: Sat, 12 Aug 2023 14:11:19 +0100 Subject: [PATCH] Re-implement native function binding / calling --- debug/app.ona | 2 +- source/ona/kym.zig | 78 +++++++++++++++++++++++++++++++++++++--------- source/ona/ona.zig | 6 ++-- 3 files changed, 68 insertions(+), 18 deletions(-) diff --git a/debug/app.ona b/debug/app.ona index 1cdb540..ea265f4 100644 --- a/debug/app.ona +++ b/debug/app.ona @@ -8,6 +8,6 @@ options = { .tick_rate = 60, } -# @log_info(options.title) +@log_info(options.title) return options diff --git a/source/ona/kym.zig b/source/ona/kym.zig index f3f224e..0ee0442 100644 --- a/source/ona/kym.zig +++ b/source/ona/kym.zig @@ -27,7 +27,7 @@ pub const RuntimeEnv = struct { interned_symbols: SymbolSet, allocator: coral.io.Allocator, error_handler: ErrorHandler, - syscallables: RefTable, + system_bindings: RefTable, locals: RefList, frames: FrameStack, @@ -348,7 +348,7 @@ pub const RuntimeEnv = struct { }, .push_system => |push_system| { - if (self.env.syscallables.lookup(self.constants.values[push_system])) |syscallable| { + if (self.env.system_bindings.lookup(self.constants.values[push_system])) |syscallable| { try self.env.locals.push_one(try self.env.acquire(syscallable)); } else { try self.env.locals.push_one(null); @@ -413,12 +413,20 @@ pub const RuntimeEnv = struct { try self.env.set(indexable, index, value); }, - .object_call => { + .object_call => |object_call| { const result = call: { const callable = try self.env.expect(try self.pop_local()); defer self.env.discard(callable); + try self.env.frames.push_one(.{ + .name = "", + .arg_count = object_call, + .locals_top = self.env.locals.values.len, + }); + + defer coral.debug.assert(self.env.frames.pop() != null); + break: call try switch (callable.object().payload) { .dynamic => |dynamic| dynamic.typeinfo().call(.{ .userdata = dynamic.userdata(), @@ -429,6 +437,12 @@ pub const RuntimeEnv = struct { }; }; + for (0 .. object_call) |_| { + if (try self.pop_local()) |popped_arg| { + self.env.discard(popped_arg); + } + } + errdefer { if (result) |ref| { self.env.discard(ref); @@ -901,8 +915,19 @@ pub const RuntimeEnv = struct { return null; } - pub fn bind_syscaller(_: *RuntimeEnv, comptime _: []const coral.io.Byte, _: Caller) RuntimeError!void { + pub fn bind_system(self: *RuntimeEnv, name: []const coral.io.Byte, value: *const RuntimeRef) RuntimeError!void { + const name_symbol = try self.new_symbol(name); + errdefer self.discard(name_symbol); + + const acquired_value = try self.acquire(value); + + errdefer self.discard(acquired_value); + + if (try self.system_bindings.replace(name_symbol, acquired_value)) |replaced| { + self.discard(replaced.key); + self.discard(replaced.value); + } } pub fn call(self: *RuntimeEnv, callable: *RuntimeRef, args: []const *RuntimeRef) RuntimeError!?*RuntimeRef { @@ -1006,16 +1031,17 @@ pub const RuntimeEnv = struct { } { - var iterable = self.syscallables.as_iterable(); + var iterable = self.system_bindings.as_iterable(); while (iterable.next()) |entry| { + self.discard(entry.key); self.discard(entry.value); } } self.frames.free(); self.locals.free(); - self.syscallables.free(); + self.system_bindings.free(); self.interned_symbols.free(); } @@ -1042,7 +1068,7 @@ pub const RuntimeEnv = struct { return RuntimeEnv{ .locals = RefList.make(allocator), .frames = FrameStack.make(allocator), - .syscallables = RefTable.make(allocator, .{}), + .system_bindings = RefTable.make(allocator, .{}), .interned_symbols = SymbolSet.make(allocator, .{}), .error_handler = error_handler, .allocator = allocator, @@ -1056,13 +1082,17 @@ pub const RuntimeEnv = struct { }); } - pub fn new_dynamic(self: *RuntimeEnv, typeinfo: *const Typeinfo) RuntimeError!*RuntimeRef { + pub fn new_dynamic( + self: *RuntimeEnv, + userdata: [*]const coral.io.Byte, + typeinfo: *const Typeinfo, + ) RuntimeError!*RuntimeRef { const dynamic = try self.allocator.reallocate(null, @sizeOf(usize) + typeinfo.size); errdefer self.allocator.deallocate(dynamic); coral.io.copy(dynamic, coral.io.bytes_of(&typeinfo)); - coral.io.zero(dynamic[@sizeOf(usize) ..]); + coral.io.copy(dynamic[@sizeOf(usize) ..], userdata[0 .. typeinfo.size]); return RuntimeRef.allocate(self.allocator, .{ .ref_count = 1, @@ -1134,17 +1164,13 @@ pub const RuntimeEnv = struct { table.contiguous.free(); } - const newed = try self.new_dynamic(&.{ + return try self.new_dynamic(coral.io.bytes_of(&table).ptr, &.{ .name = "table", .size = @sizeOf(Table), .destruct = Table.typeinfo_destruct, .get = Table.typeinfo_get, .set = Table.typeinfo_set, }); - - coral.io.copy(self.unbox_dynamic(newed) catch unreachable, coral.io.bytes_of(&table)); - - return newed; } pub fn raise(self: *RuntimeEnv, error_value: RuntimeError, message: []const coral.io.Byte) RuntimeError { @@ -1364,3 +1390,27 @@ pub const Typeinfo = struct { return method.env.raise(error.TypeMismatch, "object is not index-settable"); } }; + +pub fn bind_syscaller(env: *RuntimeEnv, name: []const coral.io.Byte, caller: Caller) RuntimeError!void { + const callable = try new_caller(env, caller); + + defer env.discard(callable); + + try env.bind_system(name, callable); +} + +pub fn new_caller(env: *RuntimeEnv, value: Caller) RuntimeError!*RuntimeRef { + const Callable = struct { + fn call(method: Typeinfo.Method) RuntimeError!?*RuntimeRef { + coral.debug.assert(method.userdata.len == @sizeOf(Caller)); + + return @as(*Caller, @ptrCast(@alignCast(method.userdata))).invoke(method.env); + } + }; + + return env.new_dynamic(coral.io.bytes_of(&value).ptr, &.{ + .name = "", + .size = @sizeOf(Caller), + .call = Callable.call, + }); +} diff --git a/source/ona/ona.zig b/source/ona/ona.zig index 28807b4..ee81b03 100644 --- a/source/ona/ona.zig +++ b/source/ona/ona.zig @@ -75,15 +75,15 @@ pub fn run_app(file_access: file.Access) void { defer script_env.free(); - script_env.bind_syscaller("log_info", kym.Caller.from(kym_log_info)) catch { + kym.bind_syscaller(&script_env, "log_info", kym.Caller.from(kym_log_info)) catch { return app.log_fail("failed to bind `log_info` syscall"); }; - script_env.bind_syscaller("log_warn", kym.Caller.from(kym_log_warn)) catch { + kym.bind_syscaller(&script_env, "log_warn", kym.Caller.from(kym_log_warn)) catch { return app.log_fail("failed to bind `log_warn` syscall"); }; - script_env.bind_syscaller("log_fail", kym.Caller.from(kym_log_fail)) catch { + kym.bind_syscaller(&script_env, "log_fail", kym.Caller.from(kym_log_fail)) catch { return app.log_fail("failed to bind `log_fail` syscall"); };